Back

/ 5 min read

ShellCode学习

开始

遍历PEB

通过fs:[0x30]可以获取到PEB的地址,我们需要遍历PEBLdr链表,获取到所有的模块信息。

GetKernel32Base proc uses ecx edx ebx esi edi
local @buf[18h]: BYTE ; 用来存放 Kernel32.dll 的 BaseDllName
local @index: DWORD
;1. 获取PEB地址
ASSUME FS:NOTHING
mov eax, fs:[30h]
ASSUME FS:ERROR
;2. 获取PEB_LDR_DATA地址
mov eax, [eax + 0Ch]
;3. 获取InLoadOrderModuleList 地址 里面是_LIST_ENTRY结构体
mov edx, [eax + 0Ch]
;4. 遍历LDR_MODULE链表
@@loop:
;5. 获取LDR_MODULE的BaseAddress
mov ebx, [edx + 18h]
;6. 获取LDR_MODULE的BaseDllName的缓冲区地址
; 拷贝 BaseDllName 到 @buf
mov esi, [edx + 30h]
cld
mov ecx, 18h
lea edi, @buf
rep movsb
; 将@buf 中的字符全部转换为小写
lea esi, @buf
mov ecx, 18h
xor eax, eax
@@tolower:
mov al, [esi]
cmp al, 'A'
jb @@next_low
cmp al, 'Z'
ja @@next_low
add al, 20h
mov [esi], al
@@next_low:
inc esi
loop @@tolower
@@complet:
;7. 判断是否为Kernel32.dll
lea eax, @buf
cmp dword ptr [eax], 0065006bh
jne @@next
cmp dword ptr [eax+4], 006e0072h
jne @@next
cmp dword ptr [eax+8], 006c0065h
jne @@next
cmp dword ptr [eax+12], 00320033h
jne @@next
cmp dword ptr [eax+16], 0064002eh
jne @@next
cmp dword ptr [eax+20], 006c006ch
jne @@next
mov eax, ebx
jmp @@ret
@@next:
;9. 获取下一个LDR_MODULE地址
mov edx, [edx+4]
test edx, edx
jnz @@loop
;10. 返回NULL
xor eax, eax
@@ret:
ret
GetKernel32Base endp

获取GetProcAddress函数地址

; 获取GetProcAddress函数的地址
; 参数: kernel32.dll的基址
GetProcAddr proc uses ecx edx ebx esi edi, hModule:DWORD
local @address_of_name_ordinals: DWORD ; 序号表的地址
local @address_of_functions: DWORD ; 函数地址表的地址
mov eax, hModule
;1. 获取PE头
mov edx, [eax + 03Ch]
;2. 获取导入表的 RVA
mov ebx, [eax + edx + 078h]
;3. 获取导入表的地址
add ebx, eax
mov esi, [ebx + 20h] ; 模块名称的 RVA
add esi, eax
mov edi, [ebx + 24h] ; 序号表的 RVA
add edi, eax
mov @address_of_name_ordinals, edi
mov edi, [ebx + 1Ch] ; 函数地址表的 RVA
add edi, eax
mov @address_of_functions, edi
xor edi, edi ; edi用来计数
;4. 遍历导入表
@@loop_export:
; esi
mov ebx, [esi + edi * 4] ; 获取导入函数的 RVA
add ebx, eax ; 获取导入函数名称的地址
; 比较导入函数名称是否为GetProcAddress
cmp dword ptr [ebx], 50746547h ; GetP
jne @@next_export
cmp dword ptr [ebx + 4], 41636f72h ; rocA
jne @@next_export
cmp dword ptr [ebx + 8], 65726464h ; ddre
jne @@next_export
cmp word ptr [ebx + 0Ch], 7373h ; ss
jne @@next_export
; 导入函数名称为GetProcAddress
; 从序号表中获取序号
mov edx, @address_of_name_ordinals
xor ecx, ecx
mov cx, [edx + edi * 2]
; 获取函数地址
mov edx, @address_of_functions
mov eax, [edx + ecx * 4]
add eax, hModule
jmp @@ret
@@next_export:
inc edi
; 不需要判断是否遍历完导入表 因为GetProcAddress一定存在
jmp @@loop_export
@@ret:
ret
GetProcAddr endp

获取LoadLibraryA函数地址

; 获取LoadLibraryA函数的地址
; 参数: kernel32.dll的基址
GetLoadLibAddr proc uses ecx edx ebx esi edi, hModule:DWORD
local @address_of_name_ordinals: DWORD ; 序号表的地址
local @address_of_functions: DWORD ; 函数地址表的地址
mov eax, hModule
;1. 获取PE头
mov edx, [eax + 03Ch]
;2. 获取导入表的 RVA
mov ebx, [eax + edx + 078h]
;3. 获取导入表的地址
add ebx, eax
mov esi, [ebx + 20h] ; 模块名称的 RVA
add esi, eax
mov edi, [ebx + 24h] ; 序号表的 RVA
add edi, eax
mov @address_of_name_ordinals, edi
mov edi, [ebx + 1Ch] ; 函数地址表的 RVA
add edi, eax
mov @address_of_functions, edi
xor edi, edi ; edi用来计数
;4. 遍历导入表
@@loop_export:
; esi
mov ebx, [esi + edi * 4] ; 获取导入函数的 RVA
add ebx, eax ; 获取导入函数名称的地址
; 比较导入函数名称是否为LoadLibraryA
cmp dword ptr [ebx], 64616f4Ch ; Load
jne @@next_export
cmp dword ptr [ebx + 4], 7262694Ch ; Libr
jne @@next_export
cmp dword ptr [ebx + 8], 41797261h ; aryA
jne @@next_export
; 从序号表中获取序号
mov edx, @address_of_name_ordinals
xor ecx, ecx
mov cx, [edx + edi * 2]
; 获取函数地址
mov edx, @address_of_functions
mov eax, [edx + ecx * 4]
add eax, hModule
jmp @@ret
@@next_export:
inc edi
; 不需要判断是否遍历完导入表 因为GetProcAddress一定存在
jmp @@loop_export
@@ret:
ret
GetLoadLibAddr endp