一、首先准备好一个程序,运行起来,用windbg进行附加调试,由于每个windows下的程序都会加载kernel32.dll,因此,找基址的过程是一样的;

 二、查看PEB地址;

法一、r $peb

法二、通过TEB获取,r $teb

获取到teb地址后,对_TEB结构体解析dt _TEB 3ca000

 

 

法三、通过fs寄存器获取,我们知道fs:[0]就是TEB结构体的首地址,但是,在windbg里dd fs:[0]时,地址却做了隐藏:

那该怎么办呢,其实,这就要看下TEB的结构了

 

在TEB结构的0x18偏移处,存放的其实就是TEB的地址,和fs:[0]是一样的;

另外,在TEB结构的0x30偏移处,存放的就是PEB的地址,我们再来看下:

和上面两种方法,得到的结果都是一致的,这也验证了我们的想法;

 三、接下来,既然PEB的地址找到了,就对PEB进行解析:

首先找到LDR:

接下来,解析LDR:

这里,也许有人会有疑问:那个_LIST_ENTRY后面,怎么有两个值,是什么含义呢?加个-b,就看出来了:

typedef struct _LIST_ENTRY {
   struct _LIST_ENTRY *Flink;
   struct _LIST_ENTRY *Blink;
} LIST_ENTRY, *PLIST_ENTRY, *RESTRICTED_POINTER PRLIST_ENTRY;

其实,内核数据结构中,比较常见,使用的这个双向链表;

我们就选取InLoadOrderModuleList这个链;对它的Flink进行解析,

通过查阅MSDN,知道,这个Flink指向的具体的数据结构类型是:_LDR_DATA_TABLE_ENTRY

继续遍历InLoadOrderLinks的Flink字段:

还不是Kernel32.dll,继续走:

到此,通过遍历InLoadOrderLinks链,我们找到了KERNEL32.DLL,取出基址就比较容易了,在0x18偏移处;

取出这个基址,我们就可以解析PE导出表,找到我们需要的函数的地址了;

四、代码

int GetKernel32Base() {
    int nAddress = 0;
    _asm {
        push eax;
        mov eax, fs:[0x30]; // PEB
        mov eax, [eax + 0xC] // LDR
        mov eax, [eax + 0xC] // InLoadOrderModuleList, exe
        mov eax, [eax]; // nt.dll
        mov eax, [eax]; // kernel32.dll
        mov eax, dword ptr ds:[eax + 0x18]; // BaseAddr;
        mov nAddress, eax;
        pop eax;
    }
    
    return nAddress;
}

 

附录:

参考MSDN:https://msdn.microsoft.com/en-us/library/windows/desktop/aa813708%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396

版权声明:本文为Reginald-S原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/Reginald-S/p/8761150.html