前面的<<HOOK IAT RING3>>文章中使用到了shellcode,那么这个shellcode是怎么制造出来的呢,本文将为你一步一步的解惑

这个shellcode的主要功能是调用MessageBoxA弹出一个空的对话框,注意此时的地址空间是在别的进程,由于不同的操作系统会影响动 态链接库的加载地址,而且不同版本的dll中函数的偏移量RVA也不尽相同,因此写一个通用型的shellcode就显得非常的有必要 

 

那么shellcode要怎么动态去定位API的地址呢,方法还是一样的,首先定位函数所在的模块,然后在EAT里面进行搜索即可,只要找到 Kernel32.dll中的GetProcAddress和LoadLibraryA的地址就可以通过这两个获得其他模块中函数的地址

 

注意:网上的很多此类代码并没有通过搜索kernel32.dll模块,而是直接去寻找 Ldr->InInitializationModuleList的第3个模块,这是有问题的,因为从win7开始引入了MinWin的概念导致 InInitializationModuleList中的第三个模块是KernelBase.dll,第四个才是Kernel32.dll,不过 Ldr->InMemoryOrderModuleList中的第三个模块并没有改变还是Kernel32.dll,为了以防万一还是搜索吧,搜索 的时候用的是比较模块的第七个字符是不是'3’来匹配,因为kernel32.dll的第七个字符就是3,这样就可以不用通过计算哈希值来比较

 

下面贴出内嵌汇编代码,并加了一些注释(winxp,win7x86,win7x64以兼容32位的模式运行,都没问题~)

这个shellcode是我花了一个下午的时间写的,由于是新手,如果下文中有什么纰漏的话欢迎指正!

#include <windows.h>
#include <stdio.h>

void PopMessageBox()
{
    __asm{
        jmp start

find_function:
        push ebp
        mov ebp,esp


        mov eax,fs:[0x30]                //fs points to teb in user mode,get pointer to peb
        mov eax,[eax+0x0c]                //get peb->ldr
        mov eax,[eax+0x14]                //get peb->ldr.InMemoryOrderModuleList.Flink(1st entry)
module_loop:
        mov eax,[eax]                    //skip the first entry or get the next entry
        mov esi,[eax+0x28]                //get the BaseDllName->Buffer
        cmp byte ptr [esi+0x0c],'3'        //test the module's seventh's wchar is '3' or not,kernel32.dll
        jne module_loop

        //====================================
        //find kernel32.dll module
        //====================================
        mov eax,[eax+0x10]                //LDR_DATA_TABLE_ENTRY->DllBase

        //====================================
        //kernel32.dll PE Header
        //====================================
        mov edi,eax
        add edi,[edi+0x3c]                //IMAGE_DOS_HEADER->e_lfanew

        //====================================
        //kernel32.dll export directory table
        //====================================
        mov edi,[edi+0x78]                //IMAGE_NT_HEADERS->OptinalHeader.DataDirectory[EAT].VirtualAddress
        add edi,eax

        mov ebx,edi    // ebx is EAT's virtual address,we’ll use it later

        //====================================
        //kernel32.dll Name Pointer Table
        //====================================
        mov edi,[ebx+0x20]                //IMAGE_EXPORT_DESCRIPTOR->AddressOfNames RVA
        add edi,eax

        xor ecx,ecx                        //NameOrdinals

name_loop:
        mov esi,[edi+ecx*4]
        add esi,eax
        inc ecx
        mov edx,[esp+8]                    //first parameter
        cmp dword ptr [esi],edx
        jne name_loop
        mov edx,[esp+0xc]                //second parameter
        cmp dword ptr [esi+4],edx
        jne name_loop

        //======================================
        //kernel32.dll Ordinal Table
        //======================================
        mov edi,[ebx+0x24]
        add edi,eax
        mov ecx,[edi+ecx*2]
        and ecx,0xFFFF                   //cause ordinal is USHORT of size,so we just use its lower 16-bits

        //======================================
        //kernel32.dll Address Table
        //======================================
        mov edi,[ebx+0x1c]
        add edi,eax
        dec ecx    //subtract ordinal base
        sal ecx,2
        mov edi,[edi+ecx]
        add eax,edi

        pop ebp
        ret 8

start:
        //====================================
        // Get GetProcAddress's address
        //====================================
        push 0x41636f72    //rocA
        push 0x50746547    //Getp
        call find_function

        push eax                        //store GetProcAddress in stack

        //====================================
        //Get LoadLibraryA's address
        //====================================
        push 0x7262694c    //Libr
        push 0x64616f4c    //Load
        call find_function

        push eax                        //store LoadLibraryA in stack

        //            stack snap
        //-----------------------------high address
        //    GetProcAddress's address
        //-----------------------------
        //    LoadLibraryA's address      <-----------------esp
        //-----------------------------low address

        //====================================
        // Get User32.dll's image base
        //====================================
        push 0x3233                        //32
        push 0x72657375                    //user
        push esp                        //lpFileName
        call eax                        //call LoadLibraryA("user32.dll")

        add esp,8                        //cause we push user32 string

        //====================================
        //Get MessageBox's address
        //====================================
        push 0x41786f                    //oxA
        push 0x42656761                    //ageB
        push 0x7373654d                    //Mess
        push esp                        //lpProcName
        push eax                        //hModule
        call [esp+0x18]                    //call GetProcAddress(hModule,"MessageBoxA")

        add esp,0xc                        //cause we push MessageBoxA string

        push 0
        push 0
        push 0
        push 0
        call eax                        //call MessagBoxA(0,0,0,0)

        add esp,8                        //cause we push GetProcAddress and LoadLibrary in stack
    }
}

int main()
{
    PopMessageBox();
    return 0;
}

至于怎么转为shellcode,这里提供一个方法,就是按F10进入VS的调试模式,然后再右键选择查看汇编代码,找到内嵌汇编的开始地址,复制 那个地址处的内容直到内嵌汇编的右大括号,放到十六进制的编辑器中比如NotePad++,然后替换空格为\0x,再稍作修改即可,这里说的比较的模糊, 等有时间的时候再回头过来照顾一下新手吧,先把上面的汇编消化掉~