Esempio n. 1
0
bool FunctionAdd(uint Start, uint End, bool Manual)
{
    // CHECK: Export/Command function
    if(!DbgIsDebugging())
        return false;

    // Make sure memory is readable
    if(!MemIsValidReadPtr(Start))
        return false;

    // Fail if boundary exceeds module size
    const uint moduleBase = ModBaseFromAddr(Start);

    if(moduleBase != ModBaseFromAddr(End))
        return false;

    // Fail if 'Start' and 'End' are incompatible
    if(Start > End || FunctionOverlaps(Start, End))
        return false;

    FUNCTIONSINFO function;
    ModNameFromAddr(Start, function.mod, true);
    function.start = Start - moduleBase;
    function.end = End - moduleBase;
    function.manual = Manual;

    // Insert to global table
    EXCLUSIVE_ACQUIRE(LockFunctions);

    functions.insert(std::make_pair(ModuleRange(ModHashFromAddr(moduleBase), Range(function.start, function.end)), function));
    return true;
}
Esempio n. 2
0
bool ArgumentAdd(duint Start, duint End, bool Manual, duint InstructionCount)
{
    // Make sure memory is readable
    if(!MemIsValidReadPtr(Start))
        return false;

    // Fail if boundary exceeds module size
    auto moduleBase = ModBaseFromAddr(Start);

    if(moduleBase != ModBaseFromAddr(End))
        return false;

    // Fail if 'Start' and 'End' are incompatible
    if(Start > End || ArgumentOverlaps(Start, End))
        return false;

    ARGUMENTSINFO argument;
    if(!ModNameFromAddr(Start, argument.mod, true))
        *argument.mod = '\0';
    argument.start = Start - moduleBase;
    argument.end = End - moduleBase;
    argument.manual = Manual;
    argument.instructioncount = InstructionCount;

    return arguments.Add(argument);
}
Esempio n. 3
0
bool LoopAdd(uint Start, uint End, bool Manual)
{
    // CHECK: Export function
    if(!DbgIsDebugging())
        return false;

    // Loop must begin before it ends
    if(Start > End)
        return false;

    // Memory addresses must be valid
    if(!MemIsValidReadPtr(Start) || !MemIsValidReadPtr(End))
        return false;

    // Check if loop boundaries are in the same module range
    const uint moduleBase = ModBaseFromAddr(Start);

    if(moduleBase != ModBaseFromAddr(End))
        return false;

    // Loops cannot overlap other loops
    int finalDepth = 0;

    if(LoopOverlaps(0, Start, End, &finalDepth))
        return false;

    // Fill out loop information structure
    LOOPSINFO loopInfo;
    loopInfo.start = Start - moduleBase;
    loopInfo.end = End - moduleBase;
    loopInfo.depth = finalDepth;
    loopInfo.manual = Manual;
    ModNameFromAddr(Start, loopInfo.mod, true);

    // Link this to a parent loop if one does exist
    if(finalDepth)
        LoopGet(finalDepth - 1, Start, &loopInfo.parent, 0);
    else
        loopInfo.parent = 0;

    EXCLUSIVE_ACQUIRE(LockLoops);

    // Insert into list
    loops.insert(std::make_pair(DepthModuleRange(finalDepth, ModuleRange(ModHashFromAddr(moduleBase), Range(loopInfo.start, loopInfo.end))), loopInfo));
    return true;
}
Esempio n. 4
0
bool disasmispossiblestring(uint addr)
{
    unsigned char data[11];
    memset(data, 0, sizeof(data));
    if(!MemRead((void*)addr, data, sizeof(data) - 3, 0))
        return false;
    uint test = 0;
    memcpy(&test, data, sizeof(uint));
    if(MemIsValidReadPtr(test)) //imports/pointers
        return false;
    if(isasciistring(data, sizeof(data)) or isunicodestring(data, _countof(data)))
        return true;
    return false;
}
Esempio n. 5
0
bool PatchSet(duint Address, unsigned char OldByte, unsigned char NewByte)
{
    ASSERT_DEBUGGING("Export call");

    // Address must be valid
    if(!MemIsValidReadPtr(Address))
        return false;

    // Don't patch anything if the new and old values are the same
    if(OldByte == NewByte)
        return true;

    PATCHINFO newPatch;
    newPatch.addr = Address - ModBaseFromAddr(Address);
    newPatch.oldbyte = OldByte;
    newPatch.newbyte = NewByte;
    ModNameFromAddr(Address, newPatch.mod, true);

    // Generate a key for this address
    const duint key = ModHashFromAddr(Address);

    EXCLUSIVE_ACQUIRE(LockPatches);

    // Find any patch with this specific address
    auto found = patches.find(key);

    if(found != patches.end())
    {
        if(found->second.oldbyte == NewByte)
        {
            // The patch was undone here
            patches.erase(found);
            return true;
        }

        // Keep the original byte from the previous patch
        newPatch.oldbyte = found->second.oldbyte;
        found->second = newPatch;
    }
    else
    {
        // The entry was never found, insert it
        patches.insert(std::make_pair(key, newPatch));
    }

    return true;
}
Esempio n. 6
0
bool LabelSet(uint Address, const char* Text, bool Manual)
{
    // CHECK: Exported/Command function
    if(!DbgIsDebugging())
        return false;

    // A valid memory address must be supplied
    if(!MemIsValidReadPtr(Address))
        return false;

    // Make sure the string is supplied, within bounds, and not a special delimiter
    if(!Text || Text[0] == '\1' || strlen(Text) >= MAX_LABEL_SIZE - 1)
        return false;

    // Labels cannot be "address" of actual variables
    if(strstr(Text, "&"))
        return false;

    // Delete the label if no text was supplied
    if(Text[0] == '\0')
        return LabelDelete(Address);

    // Fill out the structure data
    LABELSINFO labelInfo;
    labelInfo.manual = Manual;
    labelInfo.addr = Address - ModBaseFromAddr(Address);
    strcpy_s(labelInfo.text, Text);
    ModNameFromAddr(Address, labelInfo.mod, true);

    EXCLUSIVE_ACQUIRE(LockLabels);

    // Insert label by key
    const uint key = ModHashFromAddr(Address);

    if(!labels.insert(std::make_pair(ModHashFromAddr(key), labelInfo)).second)
        labels[key] = labelInfo;

    return true;
}
Esempio n. 7
0
bool CommentSet(uint Address, const char* Text, bool Manual)
{
    // CHECK: Exported/Command function
    if(!DbgIsDebugging())
        return false;

    // A valid memory address must be supplied
    if(!MemIsValidReadPtr(Address))
        return false;

    // Make sure the string is supplied, within bounds, and not a special delimiter
    if(!Text || Text[0] == '\1' || strlen(Text) >= MAX_COMMENT_SIZE - 1)
        return false;

    // Delete the comment if no text was supplied
    if(Text[0] == '\0')
        return CommentDelete(Address);

    // Fill out the structure
    COMMENTSINFO comment;
    strcpy_s(comment.text, Text);
    ModNameFromAddr(Address, comment.mod, true);

    comment.manual = Manual;
    comment.addr = Address - ModBaseFromAddr(Address);

    // Key generated from module hash
    const uint key = ModHashFromAddr(Address);

    EXCLUSIVE_ACQUIRE(LockComments);

    // Insert if possible, otherwise replace
    if(!comments.insert(std::make_pair(key, comment)).second)
        comments[key] = comment;

    return true;
}
Esempio n. 8
0
bool stackcommentget(duint addr, STACK_COMMENT* comment)
{
    SHARED_ACQUIRE(LockSehCache);
    const auto found = SehCache.find(addr);
    if(found != SehCache.end())
    {
        *comment = found->second;
        return true;
    }
    SHARED_RELEASE();

    duint data = 0;
    memset(comment, 0, sizeof(STACK_COMMENT));
    MemRead(addr, &data, sizeof(duint));
    if(!MemIsValidReadPtr(data)) //the stack value is no pointer
        return false;

    duint size = 0;
    duint base = MemFindBaseAddr(data, &size);
    duint readStart = data - 16 * 4;
    if(readStart < base)
        readStart = base;
    unsigned char disasmData[256];
    MemRead(readStart, disasmData, sizeof(disasmData));
    duint prev = disasmback(disasmData, 0, sizeof(disasmData), data - readStart, 1);
    duint previousInstr = readStart + prev;

    BASIC_INSTRUCTION_INFO basicinfo;
    bool valid = disasmfast(disasmData + prev, previousInstr, &basicinfo);
    if(valid && basicinfo.call) //call
    {
        char label[MAX_LABEL_SIZE] = "";
        ADDRINFO addrinfo;
        addrinfo.flags = flaglabel;
        if(_dbg_addrinfoget(data, SEG_DEFAULT, &addrinfo))
            strcpy_s(label, addrinfo.label);
        char module[MAX_MODULE_SIZE] = "";
        ModNameFromAddr(data, module, false);
        char returnToAddr[MAX_COMMENT_SIZE] = "";
        if(*module)
            sprintf(returnToAddr, "%s.", module);
        if(!*label)
            sprintf_s(label, "%p", data);
        strcat(returnToAddr, label);

        data = basicinfo.addr;
        if(data)
        {
            *label = 0;
            addrinfo.flags = flaglabel;
            if(_dbg_addrinfoget(data, SEG_DEFAULT, &addrinfo))
                strcpy_s(label, addrinfo.label);
            *module = 0;
            ModNameFromAddr(data, module, false);
            char returnFromAddr[MAX_COMMENT_SIZE] = "";
            if(*module)
                sprintf_s(returnFromAddr, "%s.", module);
            if(!*label)
                sprintf_s(label, "%p", data);
            strcat_s(returnFromAddr, label);
            sprintf_s(comment->comment, GuiTranslateText(QT_TRANSLATE_NOOP("DBG", "return to %s from %s")), returnToAddr, returnFromAddr);
        }
        else
            sprintf_s(comment->comment, GuiTranslateText(QT_TRANSLATE_NOOP("DBG", "return to %s from ???")), returnToAddr);
        strcpy_s(comment->color, "!rtnclr"); // Special token for return address color;
        return true;
    }

    //string
    char string[MAX_STRING_SIZE] = "";
    if(DbgGetStringAt(data, string))
    {
        strncpy_s(comment->comment, string, _TRUNCATE);
        return true;
    }

    //label
    char label[MAX_LABEL_SIZE] = "";
    ADDRINFO addrinfo;
    addrinfo.flags = flaglabel;
    if(_dbg_addrinfoget(data, SEG_DEFAULT, &addrinfo))
        strcpy_s(label, addrinfo.label);
    char module[MAX_MODULE_SIZE] = "";
    ModNameFromAddr(data, module, false);

    if(*module) //module
    {
        if(*label) //+label
            sprintf_s(comment->comment, "%s.%s", module, label);
        else //module only
            sprintf_s(comment->comment, "%s.%p", module, data);
        return true;
    }
    else if(*label) //label only
    {
        sprintf_s(comment->comment, "<%s>", label);
        return true;
    }

    return false;
}
Esempio n. 9
0
void FunctionPass::AnalysisWorker(duint Start, duint End, std::vector<FunctionDef>* Blocks)
{
    //
    // Step 1: Use any defined functions in the PE function table
    //
    FindFunctionWorkerPrepass(Start, End, Blocks);

    //
    // Step 2: for each block that contains a CALL flag,
    // add it to a local function start array
    //
    // NOTE: *Some* indirect calls are included
    auto blockItr = std::next(m_MainBlocks.begin(), Start);

    for(duint i = Start; i < End; i++, ++blockItr)
    {
        if(blockItr->GetFlag(BASIC_BLOCK_FLAG_CALL))
        {
            duint destination = blockItr->Target;

            // Was it a pointer?
            if(blockItr->GetFlag(BASIC_BLOCK_FLAG_INDIRPTR))
            {
                // Read it from memory
                if(!MemRead(destination, &destination, sizeof(duint)))
                    continue;

                // Validity check
                if(!MemIsValidReadPtr(destination))
                    continue;

                dprintf(QT_TRANSLATE_NOOP("DBG", "Indirect pointer: 0x%p 0x%p\n"), blockItr->Target, destination);
            }

            // Destination must be within analysis limits
            if(!ValidateAddress(destination))
                continue;

            Blocks->push_back({ destination, 0, 0, 0, 0 });
        }
    }

    //
    // Step 3: Sort and remove duplicates
    //
    std::sort(Blocks->begin(), Blocks->end());
    Blocks->erase(std::unique(Blocks->begin(), Blocks->end()), Blocks->end());

    //
    // Step 4: Find function ends
    //
    FindFunctionWorker(Blocks);

    //
    // Step 5: Find all orphaned blocks and repeat analysis process
    //
    // Starting from the first global block, scan until an "untouched" block is found
    blockItr = std::next(m_MainBlocks.begin(), Start);

    // Cached final block
    BasicBlock* finalBlock = &m_MainBlocks.back();

    duint virtEnd = 0;
    for(duint i = Start; i < End; i++, ++blockItr)
    {
        if(blockItr->VirtualStart < virtEnd)
            continue;

        // Skip padding
        if(blockItr->GetFlag(BASIC_BLOCK_FLAG_PAD))
            continue;

        // Is the block untouched?
        if(blockItr->GetFlag(BASIC_BLOCK_FLAG_FUNCTION))
            continue;

        // Try to define a function
        FunctionDef def { blockItr->VirtualStart, 0, 0, 0, 0 };

        if(ResolveFunctionEnd(&def, finalBlock))
        {
            Blocks->push_back(def);
            virtEnd = def.VirtualEnd;
        }
    }
}
Esempio n. 10
0
void stackgetcallstack(uint csp, CALLSTACK* callstack)
{
#if 1
    callstack->total = 0;
    if(!DbgIsDebugging() || csp % sizeof(uint)) //alignment problem
        return;
    if(!MemIsValidReadPtr(csp))
        return;
    std::vector<CALLSTACKENTRY> callstackVector;
    uint stacksize = 0;
    uint stackbase = MemFindBaseAddr(csp, &stacksize, false);
    if(!stackbase) //super-fail (invalid stack address)
        return;
    //walk up the stack
    uint i = csp;
    while(i != stackbase + stacksize)
    {
        uint data = 0;
        MemRead(i, &data, sizeof(uint));
        if(MemIsValidReadPtr(data) && MemIsCodePage(data, false)) //the stack value is a pointer to an executable page
        {
            uint size = 0;
            uint base = MemFindBaseAddr(data, &size);
            uint readStart = data - 16 * 4;
            if(readStart < base)
                readStart = base;
            unsigned char disasmData[256];
            MemRead(readStart, disasmData, sizeof(disasmData));
            uint prev = disasmback(disasmData, 0, sizeof(disasmData), data - readStart, 1);
            uint previousInstr = readStart + prev;
            BASIC_INSTRUCTION_INFO basicinfo;
            bool valid = disasmfast(disasmData + prev, previousInstr, &basicinfo);
            if(valid && basicinfo.call) //call
            {
                CALLSTACKENTRY curEntry;
                memset(&curEntry, 0, sizeof(CALLSTACKENTRY));

                StackEntryFromFrame(&curEntry, i, basicinfo.addr, data);
                callstackVector.push_back(curEntry);
            }
        }
        i += sizeof(uint);
    }
    callstack->total = (int)callstackVector.size();
    if(callstack->total)
    {
        callstack->entries = (CALLSTACKENTRY*)BridgeAlloc(callstack->total * sizeof(CALLSTACKENTRY));
        for(int i = 0; i < callstack->total; i++)
        {
            //CALLSTACKENTRY curEntry;
            //memcpy(&curEntry, &callstackVector.at(i), sizeof(CALLSTACKENTRY));
            //dprintf(fhex":" fhex ":" fhex ":%s\n", curEntry.addr, curEntry.to, curEntry.from, curEntry.comment);
            memcpy(&callstack->entries[i], &callstackVector.at(i), sizeof(CALLSTACKENTRY));
        }
    }
#else
    // Gather context data
    CONTEXT context;
    memset(&context, 0, sizeof(CONTEXT));

    context.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER;

    if(SuspendThread(hActiveThread) == -1)
        return;

    if(!GetThreadContext(hActiveThread, &context))
        return;

    if(ResumeThread(hActiveThread) == -1)
        return;

    // Set up all frame data
    STACKFRAME64 frame;
    ZeroMemory(&frame, sizeof(STACKFRAME64));

#ifdef _M_IX86
    DWORD machineType = IMAGE_FILE_MACHINE_I386;
    frame.AddrPC.Offset = context.Eip;
    frame.AddrPC.Mode = AddrModeFlat;
    frame.AddrFrame.Offset = context.Ebp;
    frame.AddrFrame.Mode = AddrModeFlat;
    frame.AddrStack.Offset = csp;
    frame.AddrStack.Mode = AddrModeFlat;
#elif _M_X64
    DWORD machineType = IMAGE_FILE_MACHINE_AMD64;
    frame.AddrPC.Offset = context.Rip;
    frame.AddrPC.Mode = AddrModeFlat;
    frame.AddrFrame.Offset = context.Rsp;
    frame.AddrFrame.Mode = AddrModeFlat;
    frame.AddrStack.Offset = csp;
    frame.AddrStack.Mode = AddrModeFlat;
#endif

    // Container for each callstack entry
    std::vector<CALLSTACKENTRY> callstackVector;

    while(true)
    {
        if(!StackWalk64(
                    machineType,
                    fdProcessInfo->hProcess,
                    hActiveThread,
                    &frame,
                    &context,
                    StackReadProcessMemoryProc64,
                    SymFunctionTableAccess64,
                    StackGetModuleBaseProc64,
                    StackTranslateAddressProc64))
        {
            // Maybe it failed, maybe we have finished walking the stack
            break;
        }

        if(frame.AddrPC.Offset != 0)
        {
            // Valid frame
            CALLSTACKENTRY entry;
            memset(&entry, 0, sizeof(CALLSTACKENTRY));

            StackEntryFromFrame(&entry, (uint)frame.AddrFrame.Offset, (uint)frame.AddrReturn.Offset, (uint)frame.AddrPC.Offset);
            callstackVector.push_back(entry);
        }
        else
        {
            // Base reached
            break;
        }
    }

    // Convert to a C data structure
    callstack->total = (int)callstackVector.size();

    if(callstack->total > 0)
    {
        callstack->entries = (CALLSTACKENTRY*)BridgeAlloc(callstack->total * sizeof(CALLSTACKENTRY));

        // Copy data directly from the vector
        memcpy(callstack->entries, callstackVector.data(), callstack->total * sizeof(CALLSTACKENTRY));
    }
#endif
}
Esempio n. 11
0
bool stackcommentget(uint addr, STACK_COMMENT* comment)
{
    uint data = 0;
    memset(comment, 0, sizeof(STACK_COMMENT));
    MemRead(addr, &data, sizeof(uint));
    if(!MemIsValidReadPtr(data)) //the stack value is no pointer
        return false;

    uint size = 0;
    uint base = MemFindBaseAddr(data, &size);
    uint readStart = data - 16 * 4;
    if(readStart < base)
        readStart = base;
    unsigned char disasmData[256];
    MemRead(readStart, disasmData, sizeof(disasmData));
    uint prev = disasmback(disasmData, 0, sizeof(disasmData), data - readStart, 1);
    uint previousInstr = readStart + prev;

    BASIC_INSTRUCTION_INFO basicinfo;
    bool valid = disasmfast(disasmData + prev, previousInstr, &basicinfo);
    if(valid && basicinfo.call) //call
    {
        char label[MAX_LABEL_SIZE] = "";
        ADDRINFO addrinfo;
        addrinfo.flags = flaglabel;
        if(_dbg_addrinfoget(data, SEG_DEFAULT, &addrinfo))
            strcpy_s(label, addrinfo.label);
        char module[MAX_MODULE_SIZE] = "";
        ModNameFromAddr(data, module, false);
        char returnToAddr[MAX_COMMENT_SIZE] = "";
        if(*module)
            sprintf(returnToAddr, "%s.", module);
        if(!*label)
            sprintf(label, fhex, data);
        strcat(returnToAddr, label);

        data = basicinfo.addr;
        if(data)
        {
            *label = 0;
            addrinfo.flags = flaglabel;
            if(_dbg_addrinfoget(data, SEG_DEFAULT, &addrinfo))
                strcpy_s(label, addrinfo.label);
            *module = 0;
            ModNameFromAddr(data, module, false);
            char returnFromAddr[MAX_COMMENT_SIZE] = "";
            if(*module)
                sprintf(returnFromAddr, "%s.", module);
            if(!*label)
                sprintf(label, fhex, data);
            strcat_s(returnFromAddr, label);
            sprintf_s(comment->comment, "return to %s from %s", returnToAddr, returnFromAddr);
        }
        else
            sprintf_s(comment->comment, "return to %s from ???", returnToAddr);
        strcpy_s(comment->color, "#ff0000");
        return true;
    }

    //string
    STRING_TYPE strtype;
    char string[512] = "";
    if(disasmgetstringat(data, &strtype, string, string, 500))
    {
        if(strtype == str_ascii)
            sprintf(comment->comment, "\"%s\"", string);
        else //unicode
            sprintf(comment->comment, "L\"%s\"", string);
        return true;
    }

    //label
    char label[MAX_LABEL_SIZE] = "";
    ADDRINFO addrinfo;
    addrinfo.flags = flaglabel;
    if(_dbg_addrinfoget(data, SEG_DEFAULT, &addrinfo))
        strcpy_s(label, addrinfo.label);
    char module[MAX_MODULE_SIZE] = "";
    ModNameFromAddr(data, module, false);

    if(*module) //module
    {
        if(*label) //+label
            sprintf(comment->comment, "%s.%s", module, label);
        else //module only
            sprintf(comment->comment, "%s." fhex, module, data);
        return true;
    }
    else if(*label) //label only
    {
        sprintf(comment->comment, "<%s>", label);
        return true;
    }

    return false;
}
Esempio n. 12
0
bool disasmgetstringat(uint addr, STRING_TYPE* type, char* ascii, char* unicode, int maxlen)
{
    if(type)
        *type = str_none;
    if(!disasmispossiblestring(addr))
        return false;
    Memory<unsigned char*> data((maxlen + 1) * 2, "disasmgetstringat:data");
    if(!MemRead(addr, data(), (maxlen + 1) * 2))
        return false;
    uint test = 0;
    memcpy(&test, data(), sizeof(uint));
    if(MemIsValidReadPtr(test))
        return false;
    if(isasciistring(data(), maxlen))
    {
        if(type)
            *type = str_ascii;
        int len = (int)strlen((const char*)data());
        for(int i = 0, j = 0; i < len; i++)
        {
            switch(data()[i])
            {
            case '\t':
                j += sprintf(ascii + j, "\\t");
                break;
            case '\f':
                j += sprintf(ascii + j, "\\f");
                break;
            case '\v':
                j += sprintf(ascii + j, "\\v");
                break;
            case '\n':
                j += sprintf(ascii + j, "\\n");
                break;
            case '\r':
                j += sprintf(ascii + j, "\\r");
                break;
            case '\\':
                j += sprintf(ascii + j, "\\\\");
                break;
            case '\"':
                j += sprintf(ascii + j, "\\\"");
                break;
            default:
                j += sprintf(ascii + j, "%c", data()[i]);
                break;
            }
        }
        return true;
    }
    else if(isunicodestring(data(), maxlen))
    {
        if(type)
            *type = str_unicode;
        int len = (int)wcslen((const wchar_t*)data());
        for(int i = 0, j = 0; i < len * 2; i += 2)
        {
            switch(data()[i])
            {
            case '\t':
                j += sprintf(unicode + j, "\\t");
                break;
            case '\f':
                j += sprintf(unicode + j, "\\f");
                break;
            case '\v':
                j += sprintf(unicode + j, "\\v");
                break;
            case '\n':
                j += sprintf(unicode + j, "\\n");
                break;
            case '\r':
                j += sprintf(unicode + j, "\\r");
                break;
            case '\\':
                j += sprintf(unicode + j, "\\\\");
                break;
            case '\"':
                j += sprintf(unicode + j, "\\\"");
                break;
            default:
                j += sprintf(unicode + j, "%c", data()[i]);
                break;
            }
        }
        return true;
    }
    return false;
}
Esempio n. 13
0
extern "C" DLL_EXPORT bool _dbg_memisvalidreadptr(duint addr)
{
    return MemIsValidReadPtr(addr);
}
Esempio n. 14
0
extern "C" DLL_EXPORT int _dbg_getbplist(BPXTYPE type, BPMAP* bpmap)
{
    if(!bpmap)
        return 0;
    std::vector<BREAKPOINT> list;
    int bpcount = BpGetList(&list);
    if(bpcount == 0)
    {
        bpmap->count = 0;
        return 0;
    }

    int retcount = 0;
    std::vector<BRIDGEBP> bridgeList;
    BRIDGEBP curBp;
    unsigned short slot = 0;
    for(int i = 0; i < bpcount; i++)
    {
        memset(&curBp, 0, sizeof(BRIDGEBP));
        switch(type)
        {
        case bp_none: //all types
            break;
        case bp_normal: //normal
            if(list[i].type != BPNORMAL)
                continue;
            break;
        case bp_hardware: //hardware
            if(list[i].type != BPHARDWARE)
                continue;
            break;
        case bp_memory: //memory
            if(list[i].type != BPMEMORY)
                continue;
            break;
        default:
            return 0;
        }
        switch(list[i].type)
        {
        case BPNORMAL:
            curBp.type = bp_normal;
            break;
        case BPHARDWARE:
            curBp.type = bp_hardware;
            break;
        case BPMEMORY:
            curBp.type = bp_memory;
            break;
        }
        switch(((DWORD)list[i].titantype) >> 8)
        {
        case UE_DR0:
            slot = 0;
            break;
        case UE_DR1:
            slot = 1;
            break;
        case UE_DR2:
            slot = 2;
            break;
        case UE_DR3:
            slot = 3;
            break;
        }
        curBp.addr = list[i].addr;
        curBp.enabled = list[i].enabled;
        //TODO: fix this
        if(MemIsValidReadPtr(curBp.addr))
            curBp.active = true;
        strcpy_s(curBp.mod, list[i].mod);
        strcpy_s(curBp.name, list[i].name);
        curBp.singleshoot = list[i].singleshoot;
        curBp.slot = slot;
        if(curBp.active)
        {
            bridgeList.push_back(curBp);
            retcount++;
        }
    }
    if(!retcount)
    {
        bpmap->count = retcount;
        return retcount;
    }
    bpmap->count = retcount;
    bpmap->bp = (BRIDGEBP*)BridgeAlloc(sizeof(BRIDGEBP) * retcount);
    for(int i = 0; i < retcount; i++)
        memcpy(&bpmap->bp[i], &bridgeList.at(i), sizeof(BRIDGEBP));
    return retcount;
}