如何从64位应用的反汇编代码中获取目标QWORD对象地址?
问题:从64位汇编地址中获取目标QWORD地址
我有一个可在内存中匹配字节序列的模式:
0x74, 0x26, 0x48, 0x8B, 0x05, 0, 0, 0, 0, 0x48, 0x8D, 0x0D, 0, 0, 0, 0
其中0可匹配任意字节,该模式运行正常。匹配到的反汇编代码如下:
.text:000000014002AD99 74 26 jz short loc_14002ADC1 .text:000000014002AD9B 48 8B 05 86 D1 64 01 mov rax, qword_141677F28
我的问题是:如何从地址0x14002AD99中获取qword_141677F28?
在32位应用中,我可以通过类似0x000000014002AD9B + 2的方式得到所需地址,但64位环境下此方法失效,无法得到正确的qword_141677F28,只会得到错误结果。
内存中qword_后的地址是正确的,请问我需要解析汇编代码,还是有其他方法可获取qword_141677F28?
附相关代码:
DWORD WINAPI thread(_In_ LPVOID core) { AllocConsole(); freopen("CONIN$", "r", stdin); freopen("CONOUT$", "w", stdout); freopen("CONOUT$", "w", stderr); std::vector<BYTE> pattern{ 0x74, 0x26, 0x48, 0x8B, 0x05, 0, 0, 0, 0, 0x48, 0x8D, 0x0D, 0, 0, 0, 0 }; uintptr_t* address = get_address<uintptr_t*>(pattern, "xrEngine.exe"); std::cout << std::hex << address + 5; // wrong result std::cin.get(); FreeLibraryAndExitThread(static_cast<HMODULE>(core), 0); }
解决方案
64位x86架构中,mov rax, qword ptr [rip+offset]这类指令用的是RIP相对寻址,和32位的绝对寻址逻辑完全不同,你之前的32位方法自然失效。
具体计算逻辑
- 先确定
mov rax, qword_141677F28的起始地址:模式匹配到的0x14002AD99是jz指令的地址,mov指令从0x14002AD9B开始(跳过jz的2字节)。 - 这条
mov指令的结构是:0x48 0x8B 0x05(3字节操作码) + 4字节有符号偏移量offset(对应你模式中0x48,0x8B,0x05后面的四个占位0)。 - 目标
qword_141677F28的地址计算公式:
对应你的例子:目标地址 = mov指令起始地址 + 指令总长度(7字节) + offset0x14002AD9B + 7 + 0x0164D186 = 0x141677F28,和反汇编结果一致。
代码修改
调整代码实现上述逻辑:
DWORD WINAPI thread(_In_ LPVOID core) { AllocConsole(); freopen("CONIN$", "r", stdin); freopen("CONOUT$", "w", stdout); freopen("CONOUT$", "w", stderr); std::vector<BYTE> pattern{ 0x74, 0x26, 0x48, 0x8B, 0x05, 0, 0, 0, 0, 0x48, 0x8D, 0x0D, 0, 0, 0, 0 }; // 获取模式匹配到的起始地址(0x14002AD99) uintptr_t match_addr = reinterpret_cast<uintptr_t>(get_address<void*>(pattern, "xrEngine.exe")); // 定位到mov指令的起始地址(跳过jz的2字节) uintptr_t mov_inst_addr = match_addr + 2; // 读取4字节的有符号偏移量 int32_t offset = *reinterpret_cast<int32_t*>(mov_inst_addr + 3); // 计算目标qword地址 uintptr_t qword_addr = mov_inst_addr + 7 + offset; std::cout << std::hex << qword_addr; // 正确结果:0x141677F28 std::cin.get(); FreeLibraryAndExitThread(static_cast<HMODULE>(core), 0); }
关键说明
- 用
int32_t读取偏移量:因为RIP相对偏移是有符号32位整数,能正确处理正向和反向的偏移。 - 指令长度固定:
mov rax, [rip+offset]的总长度是7字节(3字节操作码+4字节偏移),这是x86-64架构的固定编码。
内容的提问来源于stack exchange,提问作者Sora Aoi
相关产品推荐
相关产品推荐

