大数跨境
0
0

x64汇编与 shellcode 入门教程 02

x64汇编与 shellcode 入门教程 02 CppGuide
2025-10-09
1

这是《x64汇编与shellcode入门教程》系列的第2篇,第一篇在这里:

x64汇编与shellcode入门教程 01

我本想在第二部分讨论如何移除空字节(NULL bytes),我保证这部分内容一定会有!但我从x64 shellcode和汇编文章的第一部分收到了一些不错的反馈,还有一些关于计算PE偏移量的问题。所以,我想用第二部分来解释我是如何得出代码中使用的特定偏移量的。让我们开始吧!

首先,我们来获取一个像样的PE查看器。我选择使用Pepper作为查看x64二进制文件的PE查看器:Pepper x64 PE查看器(https://github.com/jovibor/Pepper)。

我将详细讲解PE头的每个部分以及导出表。让我们以本系列文章中的汇编代码作为参考:

mov r8, rbx         ; mov kernel32.dll base addr into r8

在我的案例中,Kernel32的基地址是:00007FFA63570000

所以,00007FFA63570000现在在r8和rbx中

mov ebx, [rbx+0x3C] (move into lower 32 bits of the rbx register, hence why we use ebx)

我们的x64dbg调试器将显示:dword ptr ds:[rbx+3C]=[kernel32.00007FFA6357003C]=F8

这是我们的PE签名偏移量,如下图所示。我们首先获取kernel32.00007FFA6357003C所指向的值,即F8,然后将其添加到kernel32中。

add rbx, r8 = 00007FFA635700F8 (PE header/DOS header)

现在,我们处于[IMAGE_OPTIONAL_HEADER64][IMAGE_DATA_DIRECTORY]中

mov edx, [rbx+0x88]

这是为了获取导出表的偏移量

F8 + 0x88 = 180对我来说,这等于00000000000A3D80,也就是导出表的相对虚拟地址(RVA)。

add rdx, r8

00007FFA63613D80 → RVA导出表的地址

mov r10d, [rdx+0x14]          ; r10d (the lower 32 bits of r10) now holds the function count.


xor r11, r11                  ; Zero R11 before use
mov r11d, [rdx+0x20]          ; r11d (the lower 32 bits of r11) now holds the AddressOfNames RVA

00000000000A5814 在x64dbg中


add r11, r8                   ; AddressOfNames VMA

00007FFA63615814

mov rcx, r10                      ; r10 has our total function count.  Set RCX loop counter

; Loop over Export Address of Names Table to find WinApi names
kernel32findfunction: 
               
    mov ebx, [r11+rcx*4]                 ; EBX = RVA for first AddressOfName
  • r11 = 函数名的相对虚拟地址(RVA)
  • +rcx = 函数列表中的位置
  • 4 = rcx * 4:由于AddressOfNames中的每个RVA都是4字节的条目,将rcx乘以4可得到正确的偏移量,以检索特定函数名的RVA。

循环结束后,我们的函数名就会被找到,并且函数名中的位置将存储在rcx中。

我们将rcx入栈,然后将其弹出到r15中,这就引导我们来到了这里:

OrdinalLookupSetup:  ;We found our target WinApi position in the functions lookup
   pop r15           ;Winexec position
   js OrdinalLookup
   
OrdinalLookup:   
mov rcx, r15                        ;Winexec location in function names
xor r11, r11                        ;clear r11
mov r11d, [rdx+0x24]                ; AddressOfNameOrdinals RVA

X64dbg输出= dword ptr ds:[rdx+24]=[kernel32.00007FFA63613DA4]=A7280


add r11, r8                   ; AddressOfNameOrdinals VMA

添加到kernel32 = 00007FFA63617280

; Get the function ordinal from AddressOfNameOrdinals
inc rcx
mov r13w, [r11+rcx*2]         ; AddressOfNameOrdinals + Counter. RCX = counter

虚拟内存地址 + rcx(1612)× 2(字节)= WinExec的序号值!!!


;With the function ordinal value, we can finally lookup the WinExec address from AddressOfFunctions.
; Get function address from AddressOfFunctions
xor r11, r11                  ; clear r11
mov r11d, [rdx+0x1c]          ; AddressOfFunctions RVA


add r11, r8                   ; AddressOfFunctions VMA in R11. Kernel32+RVA for addressoffunctions
mov eax, [r11+r13*4]        ; Get the function RVA.

R11 = 相对虚拟内存地址

R13 = Winexec序号(0x64C = 十进制1612)

* 4(字节)= 1612 = Winexec

X64dbg = dword ptr ds:[r11+r13*4]=[kernel32.00007FFA636156D8]=608B0


add rax, r8                   ; Found the WinExec WinApi!!!

将kernel32添加到我们的WinExec相对虚拟地址中


RAX现在持有WinExec的实际地址!!!

就是这样!现在你可以根据自己的喜好使用Winexec了,而且你应该也对如何遍历PE文件、解析PE头、查看导出目录信息等有了更清晰的认识。谢谢!



声明

本文介绍的内容纯作为编程技术交流,不得用于任何非法用途,否则后果自负,与本号无关。


推荐阅读

银狐远控问题排查与修复——Viusal Studio集成Google Address Sanitizer排查内存问题
银狐远控代码中差异屏幕bug修复
银狐远程屏幕内存优化方法探究
银狐远程软件bug修复记录 第03篇


【声明】内容源于网络
0
0
CppGuide
专注于高质量高性能C++开发,站点:cppguide.cn
内容 1260
粉丝 0
CppGuide 专注于高质量高性能C++开发,站点:cppguide.cn
总阅读289
粉丝0
内容1.3k