虽然我以往的文章中都有穿插此内容,但没有专门来说明(x86和x64专门来汇编说明)。虽然此篇老外文很基础,但却讲得颇为详细。
在 shellcode 能够定位或使用任何 Windows api 之前,必须定位 kernel32.dll 的基地址。该方法使用 Win32线程信息块(TIB)定位程序环境块(PEB)来定位 InInitializationOrderModuleList,它包含 kernel32.dll 的基地址作为它的第二个列表条目。
32位版本
此方法适用于所有版本的 Windows。
以下代码将定位 Kernel32 的基地址:
1234567891011
mov eax,[fs:0x30] ; Get the memory address of the PEB; structure and store it in EAXmov eax,[eax+0x0C] ; Get the memory address of the PEB_LDR_DATA; structure and store it in EAXmov esi,[eax+0x1C] ; Get the memory address of the first; LIST_ENTRY structure stored in the; InInitializationOrderModuleList and store; it in ESIlodsd ; Loads the memory address of the cond ; LIST_ENTRY structuremov ebx,[eax+0x08] ; Save the ba address of kernel32.dll in EBX
1、第一条MOV指令将PEB结构的地址保存在EAX 中。Windows 使用FS寄存器来存储TIB结构的地址,PEB结构的地址位于偏移量0x30字节处。该FS包含地址0x7FFDE000:
B.如果我们查看内存转储中的那个位置,我们可以看到PEB的地址位于偏移量0x30(48 字节)处,在此示例中其值为0x7FFDF000:
图2: PEB 地址0x30
2、第二条MOV指令将PEB_LDR_DATA结构的地址保存在EAX 中。该PEB_LDR_DATA结构位于一个偏移0x0C字节的PEB结构,它的值是0x00341EA0在这个例子中:
图 3:偏移 0x0C 处的 PEB_LDR_DATA 结构地址
3、第三条MOV指令将InInitializationOrderModuleList列表的地址保存在ESI 中。此列表包含已加载模块的列表。第一个条目是ntdll.dll,第二个是kernel32.dll,这就是我们所追求的。第一个列表条目地址位于0x1C(28 字节)的偏移量处,在本例中它的值为0x00341F58:
图 4:偏移 0xC1 处的 InInitializationOrderModuleList 列表地址
4、该LODSD指令增量ESI,其中包含第一模块的地址,一个让现在指向kernel32.dll中录入并保存在地址EAX,它的值是0x00342020在这个例子:
图 5:LOSD 指令递增 ESI 以指向下一个列表条目
5、最后的MOV指令将kernel32.dll的基地址保存在EBX 中。距该位置0x08(8 个字节)的偏移量是kernel32.dll的基地址所在的位置,在此示例中其值为0x7C800000:
图 6:位于偏移 0x08 处的 Kernel32.dll 的基地址
64 位版本现在,在 64 位系统上尝试同样的事情。我将尝试 32 位代码,看看它是否有效。马上,问题来了:
图 7:fs:[0x30] 无效
在FS:[0x30]值指向未知的记忆,这是不会帮助我们。在参考维基百科上的Win32 线程信息块(TIB,又名线程环境块( TEB ))信息后,似乎在 64 位系统上,进程环境块( PEB ) 位于gs:[0x60] 处。在我们继续之前,让我们看看还有什么变化。我决定切换到WinDBG进行更多探索。
检查 TIB(TEB) 结构在WinDBG 中,让我们使用!teb命令获取TEB的基地址:
图 8:查找 TEB 的基地址
接下来,使用基地址,我们可以使用以下命令检查TEB结构:
dt _TEB 000007fffffde000
我们可以确认PEB结构位于偏移量0x60 处。
图 9:PEB 结构位于 TEB 的偏移 0x60
检查 PEB 结构在WinDBG 中,可以使用以下命令转储PEB结构:
dt _PEB 000007fffffd9000
从结果中我们看到,LDR结构是在一个偏移量为0x18的的PEB结构的基址。
图 10:LDR 结构位于 PEB 的偏移量 0x18
检查 PEB_LDR_DATA 列表结构我们知道在 32 位工作时,PEB_LDR_DATA结构的第一个列表项应该包含有关正在运行的程序的信息,ntdll作为第二个列表项,第三个应该包含有关kernel32 的信息。我们现在将尝试验证它对于 64 位系统是否相同。首先,要查看列表,以下命令:
dt _PEB_LDR_DATA 000000007723d640
迭代 LDR 数据表以查找 Kernel32我们对偏移量0x20处的InMemoryOrderModuleList感兴趣。我们将首先看看那里有什么。
图 11:检查 PEB_LDR_DATA 结构
要查看列表中的第一个条目指向什么,我们将通过发出以下命令来检查LDR_DATA_TABLE_ENTRY结构内容:
dt _LDR_DATA_TABLE_ENTRY poi(000000007723d640+0x20)
正如我们在图 12 中看到的,第一个条目是当前进程。在这个例子中恰好是notepad.exe。
图 12:查看第一个 LDR 数据表条目
我们需要查看000000007723d640+0x20指向的内容。由于我们正在查看一个双向链表,这应该将我们带到下一个条目。以下命令将查看该值:
? poi(000000007723d640+0x20)
图 13:查看下一个 LDR 数据表条目的指针
使用计算值,我们现在可以通过以下命令查看下一个LDR_DATA_TABLE_ENTRY:
dt _LDR_DATA_TABLE_ENTRY poi(00000000003c34e0)
下一个入口指向ntdll.dll。这可能很有用。不需要知道最终 shellcode 的这个地址,但是,我们可以注意到它在列表中的位置。
图 14:第二个 LDR 数据表条目指向 ntdll.dll
要查看列表中的下一个条目,我们需要计算下一个条目的地址。LDR_DATA_TABLE_ENTRY结构的第一个元素是一个双向链表。要找到FLink,我们只需要找到计算指针,然后我们就可以查看下一个条目。执行此操作的命令是:
? poi(00000000003c34e0)dt _LDR_DATA_TABLE_ENTRY poi(00000000003c35f0)
太好了,我们找到了kernel32.dll的条目。
图 15:第三个 LDR 数据表条目指向 kernel32.dll
把它放在一起现在我们知道如何找到包含kernel32.dll模块详细信息的 LDR 数据表条目,是时候编写一些程序集来复制我们在上一节中所做的工作,以便我们可以定位和存储基地址的KERNEL32,以便它可以被用来定位的Win32 API。
我们首先列出我们在WinDBG 中执行的查找kernel32基地址的步骤。
找到PEB结构的地址。
找到PEB_LDR_DATA结构的地址。
找到InMemoryOrderModuleList列表的地址。
迭代到第三个InMemoryOrderModuleList条目。
存储kernel32.dll的基地址。
1:找到PEB结构的地址根据维基百科文章,线程信息块存储在gs寄存器中,PEB位于偏移量0x60 处。有了这些信息,下面的汇编指令应该将PEB的地址存储在RAX寄存器中:
mov rax, [gs:0x60]
2:找到PEB_LDR_DATA结构的地址该PEB_LDR_DATA结构位于一个偏移为0x18从基地址PEB。下面的指令应该将PEB_LDR_DATA结构的地址存储在RAX寄存器中。
mov rax, [rax+0x18]
3:找到InMemoryOrderModuleList列表的地址所述InMemoryOrderModuleList是在的偏移为0x20的的PEB_LDR_DATA结构。以下程序集将地址存储在RAX寄存器中:
mov rax, [rax+0x20]
4:迭代到第三个 InMemoryOrderModuleList 条目该InMemoryOrderModuleList是一个双向链表。每个列表的第一个元素是FLink,因此我们可以使用它通过加载第一个指针两次来快速迭代到列表中的第三个条目。以下代码将在RAX寄存器中保留第三个条目的地址:
mov rax, [rax]mov rax, [rax]
5:保存Kernel32的基地址最后一步是将kernel32.dll的基地址保存在某处,以便我们以后可以使用它来检索其他 Win32 函数。根据Microsoft 的 x64 调用约定,R12-R15寄存器是调用者/被调用者保存的寄存器。这意味着我们应该能够保留这些寄存器之一来为我们的 shellcode 的其余部分存储kernel32.dll的基地址。基地址位于距列表条目开头0x20的偏移量处。将基地址存储在R12寄存器中的代码是:
mov r12, [rax+0x20]
完整的组装综上所述,查找kernel32.dll基地址并存入R12寄存器的汇编程序如下:
12345678910111213
[SECTION .text]BITS 64global _start_start:mov rax, [gs:0x60]mov rax, [rax+0x18]mov rax, [rax+0x20]mov rax, [rax]mov rax, [rax]mov r12, [rax+0x20]
正如您在图 16 中看到的,kernel32.dll的基地址已成功存储在R12 中。
图 16:Kernel32.dll 的基地址存储在 R12 中
或者,如果您还需要保存ntdll.dll的基地址,您可以使用一个轻微的变体,这个变体会将ntdll.dll的基址存储在R13寄存器中:
1234567891011121314
[SECTION .text]BITS 64global _start_start:mov rax, [gs:0x60]mov rax, [rax+0x18]mov rax, [rax+0x20]mov rax, [rax]mov r13, [rax+0x20]mov rax, [rax]mov r12, [rax+0x20]
结论学习了如何使用 x86 和 x64 汇编代码查找kernel32.dll的基地址。找到kernel32.dll基地址的能力很重要,因为它可以用来调用LoadLibrary Win32 函数来定位其他有趣的 Win32 函数的地址,甚至加载其他 DLL 以添加附加功能。就像添加ws2_32.dll以提供对以下函数的访问:accept、bind、socket、WSASocket 和 WSAStartup。
本文发布于:2023-02-28 20:01:00,感谢您对本站的认可!
本文链接:https://www.wtabcd.cn/zhishi/a/167764964976579.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文word下载地址:kernel32(kernel32.dll动态链接库报错解决方法).doc
本文 PDF 下载地址:kernel32(kernel32.dll动态链接库报错解决方法).pdf
留言与评论(共有 0 条评论) |