2025年1月6日 / 5 min read ShellCode学习 shellcode , c++ 开始 遍历PEB 通过fs:[0x30]可以获取到PEB的地址,我们需要遍历PEB的Ldr链表,获取到所有的模块信息。 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: retGetKernel32Base 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: retGetProcAddr 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: retGetLoadLibAddr endp