You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

将获取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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 20:07:18