将获取Kernel32基址的MASM代码转为C代码时结果错误
问题
尝试将一段获取Kernel32.dll基址的MASM汇编代码转换为C内嵌汇编,使用i686-w64-mingw32-gcc编译后,返回的地址指向ntdll.dll而非目标Kernel32.dll,结果不符合预期。
原MASM代码
.386 .model flat, stdcall .stack 4096 assume fs:nothing .code main proc mov eax, [fs:30h] ; 指向PEB mov eax, [eax + 0ch] ; 指向Ldr mov eax, [eax + 14h] ; 指向InMemoryOrderModuleList mov eax, [eax] ; 当前程序的模块节点(LIST_ENTRY指针) mov eax, [eax] ; ntdll.dll的模块节点(LIST_ENTRY指针) mov eax, [eax -8h + 18h] ; kernel32.dll的基址 mov ebx, 0 ; 用于设置断点 int 3 main endp end main
自行编写的C内嵌汇编代码
asm("mov %fs:0x30, %eax\n"); // PEB asm("mov 0x0c(%eax), %eax\n"); // LDR asm("mov 0x14(%eax), %eax\n"); // InMemoryOrderModuleList asm("mov %eax, %eax"); // this program's module asm("mov %eax, %eax"); // ntdll module asm("mov -0x8(%eax), %eax"); // kernel32.DllBase asm("mov 0x18(%eax), %eax"); // kernel32.DllBase asm("mov %%eax, %0 \n" : "=r"(i)); asm("int3"); printf("kernel32.DllBase: %p\n", i);
问题分析与修复
你的C内嵌汇编存在两个关键错误:
链表节点取值错误:
原MASM中的mov eax, [eax]是取eax指向的内存值(即链表的下一个节点指针),但你写的mov %eax, %eax只是空操作,没有实际获取下一个模块的节点,导致eax始终停留在当前程序的模块节点上。基址计算错误:
原MASM的mov eax, [eax -8h + 18h]是一次性计算地址偏移(eax + 0x10)并取值,而你拆成mov -0x8(%eax), %eax和mov 0x18(%eax), %eax,变成了先取eax-0x8地址的内容,再取该内容+0x18地址的内容,完全偏离了原逻辑。
另外,分散的asm块可能被编译器插入额外指令干扰寄存器值,建议将所有汇编逻辑放在一个asm块中,并通过约束正确输出结果。
修复后的C代码
#include <stdio.h> int main() { void* kernel32_base; asm volatile ( "mov %%fs:0x30, %%eax\n" // 获取PEB地址 "mov 0x0c(%%eax), %%eax\n" // 获取PEB->Ldr "mov 0x14(%%eax), %%eax\n" // 获取Ldr->InMemoryOrderModuleList "mov (%%eax), %%eax\n" // 当前程序模块的LIST_ENTRY "mov (%%eax), %%eax\n" // ntdll.dll模块的LIST_ENTRY "mov 0x10(%%eax), %%eax\n" // 计算并获取kernel32.dll基址(-0x8+0x18=0x10) "mov %%eax, %0\n" : "=r" (kernel32_base) : : "%eax" // 声明eax被修改,让编译器避免使用该寄存器 ); asm("int3"); printf("kernel32.DllBase: %p\n", kernel32_base); return 0; }
编译命令
使用i686-w64-mingw32-gcc编译时,需指定32位目标:
i686-w64-mingw32-gcc -m32 -o get_kernel32 get_kernel32.c
内容的提问来源于stack exchange,提问作者FAMO4S
相关产品推荐
相关产品推荐

