如何在Windows XP/7中查找内存中的字节序列?

2 投票
2 回答
1322 浏览
提问于 2025-04-16 16:23

问题:我正在做一个学校的项目(我自己选择的),这个项目是一个程序加载器/DLL注入器。这个想法最初是我在这里找到的,然后我根据自己的需求进行了修改,并把DLL中的汇编部分转换成了可以用GCC编译的扩展汇编,而不是Visual Studio。与其在控制台窗口中打印弹球得分,我加载了一个我自己写的程序,这个程序可以接收用户输入并将其写入文件。加载器会注入一个DLL,这个DLL里面有一个函数,可以把原本要写入文件的用户输入重定向到一个消息框,并且会把我自己的字符串写入文件。

在我的机器上这个程序是能工作的,但我对平台切换有些担心,因为我的教授需要在她的机器上编译这个项目,所以在她的机器上,地址0x004014A6可能不会包含写入文件的指令CALL <某个地址>(实际代码是:ofile << user_input;),而是仍然会有一个调用那个写字符串到文件的函数的指令。

我想做的是动态确定那个地址,而不是硬编码一个固定的地址。我觉得我可以通过使用GetProcAddress来获取被调用函数的地址,然后创建一个数组来保存表示CALL <那个函数>的字节,并在我预期找到那个调用的内存附近逐字节搜索,找到地址后再进行后续操作。

不过,我不太清楚具体该怎么做。

主要问题:我该如何扫描一段内存地址,并将内容与数组中的元素进行比较?

换句话说,我想在我的DLL中包含一个函数,这个函数可以读取内存中任意地址的字节,并将其与预期的字节序列进行比较。我该如何在某个进程中任意读取内存地址的内容?

怀疑:我需要知道原始程序执行的起始和结束地址。我该如何获取起始和结束地址之间的范围?(这似乎是这里真正的难点。我可能只需要知道如何获取进程的起始和结束地址,就能解决其他问题。)

2 个回答

0

如果你在用Python,可能可以试试ptrace。它是跨平台的,可以通过pip安装。这里有一段我在网上找到的Unix系统的代码示例:http://sixserv.org/2010/07/26/memory-debugging-or-a-universal-game-trainer-with-python-and-ptrace/

def search_memory_locations(pid, max_memory, search_value):
    child_pid = os.fork()
    if child_pid == 0: # search within forked process:
        locations = list()
        prev_locations = read_locations()

        dbg = PtraceDebugger()
        process = dbg.addProcess(pid, False)
        memory_mappings = readProcessMappings(process)

        print "\x1B[?25l", # deactivate cursor (^_^)
        for memory_mapping in memory_mappings:
            # only search in read/writable memory areas within range...
            if "rw" in memory_mapping.permissions and memory_mapping.end <= max_memory:
                for loc in range(memory_mapping.start, memory_mapping.end):
                    value = process.readBytes(loc, 1)
                    if value[0] == search_value:
                        print "search memory area[0x%08X-0x%08X] address[0x%08X] value[0x%02X (%03d)]   \r" % (memory_mapping.start, memory_mapping.end, loc, ord(value), ord(value)),

                        if prev_locations and len(prev_locations) > 0 and not loc in prev_locations:
                            continue # skip prev not found locations

                        locations.append(loc)
        print "\x1B[?25h", # activate cursor
        dbg.quit()
        write_locations(locations)
        sys.exit()

    return child_pid # don't really need this

如果你在用C/C++,这里有一个我之前在ITH上用过的专门针对Windows的函数:http://code.google.com/p/interactive-text-hooker/

DWORD SearchPattern(DWORD base, DWORD base_length, LPVOID search, DWORD search_length) //KMP
{
    __asm
    {
        mov eax,search_length
alloc:
        push 0
        sub eax,1
        jnz alloc

        mov edi,search
        mov edx,search_length 
        mov ecx,1
        xor esi,esi
build_table:
        mov al,byte ptr [edi+esi]
        cmp al,byte ptr [edi+ecx]
        sete al
        test esi,esi
        jz pre
        test al,al
        jnz pre
        mov esi,[esp+esi*4-4]
        jmp build_table
pre:
        test al,al
        jz write_table
        inc esi
write_table:
        mov [esp+ecx*4],esi

        inc ecx
        cmp ecx,edx
        jb build_table

        mov esi,base
        xor edx,edx
        mov ecx,edx
matcher:
        mov al,byte ptr [edi+ecx]
        cmp al,byte ptr [esi+edx]
        sete al
        test ecx,ecx
        jz match
        test al,al
        jnz match
        mov ecx, [esp+ecx*4-4]
        jmp matcher
match:
        test al,al
        jz pre2
        inc ecx
        cmp ecx,search_length
        je finish
pre2:
        inc edx
        cmp edx,base_length //search_length
        jb matcher
        mov edx,search_length
        dec edx
finish:
        mov ecx,search_length
        sub edx,ecx
        lea eax,[edx+1]
        lea ecx,[ecx*4]
        add esp,ecx
    }
}
0

如果你要使用的程序版本不久后会改变,你可以通过以下方式获取一个在不同系统下都能用的地址:虚拟地址(VA)等于相对虚拟地址(RVA)加上模块的基地址(这个可以通过 GetModuleHandle 获取)。如果版本会改变,那你就需要用到签名扫描器。不过,签名扫描器并不是万无一失的,因为你要扫描的模式可能会在不同版本之间大幅变化。你需要的任何范围数据都可以从目标应用的PE文件中获取,这样就可以临时给 .code 部分赋予读取权限,让你能高效地遍历它(不那么高效的方法是使用 ReadProcessMemory)。这里有一个小的签名扫描器库,下面还有一个简单签名扫描器的源代码链接:http://www.blizzhackers.cc/viewtopic.php?f=182&t=478228&sid=55fc9a949aa0beb2ca2fb09e933210de

撰写回答