首页
社区
课程
招聘
[旧帖] [翻译]导入表注入技术详解 0.00雪花
发表于: 2012-4-3 17:44 2419

[旧帖] [翻译]导入表注入技术详解 0.00雪花

2012-4-3 17:44
2419
今日兴之所至翻译一篇国外关于导入表技术的文章,此文章来自大名鼎鼎的The CodeProject网站,对于学习导入表如何在实战中运用是很好的一篇教程。
我会有选择地翻译并扩充部分内容,由于本人很少翻译国外文章,翻译不到位的地方还望大家海涵。
原文出处:http://www.codeproject.com/Articles/14360/Injective-Code-inside-Import-Table
其中源代码也可以从上面的网站下载到,我这里就不添加附件了~

设想一下,我们通过修改导入表结构使得程序的导入函数指向特殊的函数,以完成我们指定的功能。此外,PE文件保护器会使用此技术植入一些保护函数,而一些后门程序也会利用此技术通过木马植入恶意代码。
在逆向工程中,我们描述此技术为“API重定位技术”。不过我不打算在本文中详述此技术的方方面面,我会重点描述本文所提供源代码之外的思想(译者注:这里我会添加对于源代码中一些核心技术的阐释)。我不会发布有恶意代码倾向的商用源代码,然而,我认为此文实际上也可以用来作为此方面的一个介绍。

1.        了解导入表
PE文件结构包含MS-DOS头,NT头,节表和节的映像,参见图1。MS-DOS自DOS时代起一直沿用至Windows时代。NT头是来自Unix系统下的ELF文件格式(Executable and Linkable Format),PE格式实际上可以算作Linux下ELF文件格式的姊妹。PE文件头包含“PE”标记, COFF(Common Object File Format)头,可选头以及各个节表。
图1,PE文件结构

NT头的定义可以在Virtual C++头文件目录下的<winnt.h>头文件中找到。此信息可以通过DbgHelp.dll动态链接库中得ImageNtHeader()函数获取。当然,你也可以通过DOS头来获取NT头,DOS中得e_lfanew字段代表了NT头相对于文件基址的偏移地址。

在PE文件的可选头中,有一些数据目录表,数据目录表划定了当前进程的虚拟内存中的一些基本的信息表的相对位置。这些表记录的信息包括,资源表,导入表,导出表,重定位表,调试表,线程局部存储表,和COM运行时表等,而对于一个PE文件而言,导入表的地位尤其重要,几乎找不到一个没有导入表的PE文件。导入表包含了DLL的名字和函数名,这些信息会在程序调用外部函数的时候通过虚拟地址找到。资源表在Console程序中是没有的,然而在GUI程序中,资源文件就显得比较重要了。导出表在动态链接库和OLE Active-X容器中应用较多。图2中是PE文件中对于数据目录表的一个展示:


只需要几行代码,我们就可以获取导入表的位置和大小等信息。知道了导入表的位置之后,我们就可以检索出DLL的名称和函数信息了,获取导入表详细信息的内容将在后文中详述


2.        深入导入表结构
导入表入口地址引导我们找到位于文件中的导入表位置。对于每一个动态链接库而言,都会有一个称之为“导入表描述符”的结构,此结构包含了FirstThunk地址和OriginalFirstThunk地址以及指向DLL名称的指针。其中FirstThunk所指向的内容会在程序加载时有系统内核的PE加载器初始化。而OriginalFirstThunk所指向的结构提供了Hint数据域和每一个导入函数的名称。
导入表描述符结构可以参见下面的结构体定义:


结构说明:
        OriginalFirstThunk
此字段指向一个IMAGE_THUNK_DATA结构体,其中包含了Hint字段和导入函数的名字。
        TimeDateStamp
如果绑定了的话,此字段含有时间/日期戳。如果此字段为0则表示导入的DLL不含绑定信息,将此值设为0xFFFFFFFF表示绑定发生。(译者注:何为绑定,俺也不懂)
        ForwarderChain
在旧版本的绑定过程中,此字段作为API的前向链表指针,可以设置为0xFFFFFFFF表示不含有前向指针。
        Name
指向DLL名字的相对虚拟地址
        FirstThunk
指向IMAGE_THUNK_DATA的虚拟地址,此结构会被系统加载器重新初始化。


图3. 导入表一览


图4. 带有OriginalFirstThunk的导入表


图5. 被PE加载器修正后的导入表


译者注:图3,图4,图5应该连起来一起看,图3和图4是我们的PE文件在磁盘上保存着的时候的样子,而图5则是用户双击了某个PE文件之后,此PE文件被加载到内存后,由系统的PE加载器修改后的样子。具体的原理,我觉得此文介绍比较浅略,如果不太懂的话,建议看看罗云彬的《Win 32汇编教程》。

接下来就是本文的重点,即导入表的注入技术:
实际上本文算法非常简单,首先在当前进程中建立一块虚拟内存空间,构造一个假的导入表,这个假的导入表只含有几个基本函数如LoadLibrary和GetProcAddress,然后修改PE文件中指向原始导入表的数据目录表指针,使其指向我们的假导入表,这样系统就会将我们的假导入表初始化。然后我们就利用被系统初始化的假导入表中的导入函数地址,初始化原始导入表,在手动初始化的同时进行比对,一旦发现我们要替换的函数地址,就用我们自定义函数地址替换真正的API函数地址,以实现导入表注入。
本文的程序对用户选择的PE文件的导入表进行修改,替换Shell32.dll这个动态链接库中得ShellAbout函数,此函数在用户点击了”About”按钮时被弹出。而经过本文作者写的工具对导入表修正后,当用户点击“About”按钮时会执行另外一个函数(这里是弹出一个提示对话框)
下图是使用此工具对计算器程序进行导入表注入后的示例图:


这样一段描述估计大家还是一头雾水吧,还是直接上代码说明好了:
下面这个函数是
void CPECryptor::CryptFile(int(__cdecl *progress) (unsigned int, unsigned int))
{
        PCHAR ch_temp;
        PIMAGE_SECTION_HEADER pimage_section_header;
        DWORD dwNewSectionSize;
        DWORD dwCodeSize;
        DWORD dwCodeOffset;
        //----------------------------------------
        progress(0,0);
        if((image_nt_headers->FileHeader.Characteristics&IMAGE_FILE_DLL)==IMAGE_FILE_DLL)
        {
                ImportTableMaker = new CITMaker(IMPORT_TABLE_OCX);
        }
        else
        {
                //对EXE文件进行一些初始化的操作:包括将假导入表需要包含的DLL和导入函数字符串信息存入一个全局链表。计算假导入表所需占用的内存,并分配相应内存空间。
                ImportTableMaker = new CITMaker(IMPORT_TABLE_EXE);
        }
        //----------------------------------------
        //ch_temp指向一段汇编代码,这段汇编代码是作者构造的(后面会给出源码),作用就是代替系统PE加载器,加载并初始化原始导入表的所有导入函数,并搜寻并替换shell32.dll中的ShellAbout函数地址。作者在代码中将目标PE文件的入口点指向了这段汇编代码,而此段汇编代码的最后,会跳转到PE文件的原始入口点执行正常的程序流程。DYN_LOADER_START_MAGIC是一个标记,指向了这段汇编代码的开头,此标记长4字节,加上4之后就是跳过标记后的实际功能代码了。--------这段汇编代码,我在后文中会称之为“启动汇编代码”
        ch_temp=(PCHAR)DWORD(ReturnToBytePtr(DynLoader, DYN_LOADER_START_MAGIC))+4;

//dwCodeSize是此段汇编代码的大小,同样地DYN_LOADER_END_MAGIC是标记了此段汇编代码的结尾之处。
        dwCodeSize=DWORD(ReturnToBytePtr(DynLoader, DYN_LOADER_END_MAGIC))-DWORD(ch_temp);

        //dwCodeOffset是伪造的导入表的大小
        dwCodeOffset = ImportTableMaker->dwSize;

        //dwNewSectonSize是包含了假导入表和前面提到的汇编代码的总大小,这两部分内容作者将其合在一起,都写入了一个新添加的段中(.xxx段,详见后文)
        dwNewSectionSize = dwCodeSize + ImportTableMaker->dwSize;
        pNewSection=new TCHAR[dwNewSectionSize];

        //这里先将“启动汇编代码”段写入指定位置
        memcpy(pNewSection+dwCodeOffset, ch_temp, dwCodeSize);
       
//这里就是构造一个新段,段的名字叫.xxx,里面含有两部分内容,首先是构造的假导入表,之后紧接着就是“启动汇编代码”
        pimage_section_header=AddNewSection(".xxx",dwNewSectionSize);

        //CopyData1的作用是将原始PE文件的入口点和原始导入表的偏移地址等信息做一份备份存储到“启动汇编代码”中的尾部,此外,还会保存一些注入程序使用到的api函数的字符串信息(之后会通过LoadLibrary和GetProcAddress手动加载后使用)
        CopyData1(pimage_section_header->VirtualAddress);

        //将存放有伪造导入表dll名称和函数名称的全局链表中的数据按照导入表描述符的结构进行假导入表的构造(实际上就是填充相应的数据结构)
        ImportTableMaker->Build(pimage_section_header->VirtualAddress);// build import table by the current virtual address

        //将在内存中构造的导入表数据复制到新建的.xxx节的内存区域
        memcpy(pNewSection, ImportTableMaker->pMem, ImportTableMaker->dwSize);
       
//将内存中的新建.xxx节数据复制到目标PE文件中相应位置(最后一个节处)
        memcpy(image_section[image_nt_headers->FileHeader.NumberOfSections-1],
                   pNewSection,
                   dwNewSectionSize);

//下面就是修正目标PE文件头的相关内容,将入口点设置为新建节中跳过伪造导入表后的“启动汇编代码“段的开头,将数据目录表中的导入表相对虚拟地址设置为新建节的开头(记得吗?新建节有两部分组成,先是伪造的导入表,后跟“启动汇编代码段”)
        image_nt_headers->OptionalHeader.AddressOfEntryPoint=pimage_section_header->VirtualAddress + dwCodeOffset;
        image_nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress=pimage_section_header->VirtualAddress;
        image_nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size=ImportTableMaker->dwSize;
        image_nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress=0;
        image_nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size=0;
        SetSectionsWritePermission();
        //----------------------------------------
        delete []pNewSection;
        delete ImportTableMaker;
        //----------------------------------------
        progress(100,0);
}

以上便是整体的框架结构,结合代码,大家应该基本可以理解一个大致思路,不过细节的话,还需大家结合源代码看看(最好下载源代码后结合我的说明看看,应该就比较懂了)

下面再详解一下“启动汇编代码”段,这段代码应该算是本程序的精华所在,希望大家慢慢体会。
前面也一再说明,启动汇编代码段是本程序在目标PE中首先执行的,也就是说目标PE文件的代码入口点已经被修改为指向“启动汇编代码”段了。启动汇编代码段主要完成1.原始导入表的手动加载。2. 替换shell32.dll中得shellabout函数在导入表中的绝对地址。 3.将代码跳转回目标PE文件原始入口点继续执行。

void __stdcall  DynLoader()
{
_asm
{
//----------------------------------
        dword_type(DYN_LOADER_START_MAGIC)   //这是一个用来标示位置的标志位,前面也说过
//----------------------------------
_main_0:
        pushad        // save the registers context in stack
        call _main_1
_main_1:       
        pop ebp
        sub ebp,offset _main_1 // get base ebp
        //----------------------------------------------------
        //====================================================
        //---------------- support dll, ocx  -----------------
//下面判断目标文件类型,是否是EXE文件
_support_dll_0:
        jmp _support_dll_1 // nop; nop; // in the secon time OEP
        jmp _support_dll_2
_support_dll_1:
        test [ebp+_p_dwFileType],IMPORT_TABLE_OCX
        jz _no_dll_pe_file_0
                mov eax,[esp+24h]// imagebase
                mov ebx,[esp+30h]// oep
                cmp eax,ebx
                ja _no_dll_pe_file_0
                        cmp word ptr [eax],IMAGE_DOS_SIGNATURE
                        jne _no_dll_pe_file_0
                                mov [ebp+_p_dwImageBase],eax
//如果是EXE文件的话,就从这里开始执行
_no_dll_pe_file_0:
        //----------------------------------------------------
        //====================================================
        mov eax,[ebp+_p_dwImageBase]
        add eax,[eax+03Ch]
        add eax,080h
        mov ecx,[eax]        // image_nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress
        add ecx,[ebp+_p_dwImageBase]
        add ecx,010h        // image_import_descriptor.FirstThunk
        mov eax,[ecx]
        add eax,[ebp+_p_dwImageBase]
        mov ebx,[eax]
        mov [ebp+_p_LoadLibrary],ebx
        add eax,04h
        mov ebx,[eax]
        mov [ebp+_p_GetProcAddress],ebx
        //----------------------------------------------------
        //------- load library and build api call-jmp --------
        call _api_load
//上面是加载一些我们需要的API函数。因为我们的导入表已经经过伪造了,所以PE加载器无法对原始导入表中得函数进行加载,那么我们自己的api也是无法执行的,所以需要首先手动加载几个我们需要的api进来。(加载过程是这样的,我们自己伪造的导入表中含有LoadLibrary和GetProcAddress两个函数信息,这样PE加载器会加载这两个函数的绝对地址,而我们就可以使用这两个函数加载其他的api函数了)
        //----------------------------------------------------
        //====================================================
        //----------- get write access for headers -----------
        mov edi,[ebp+_p_dwImageBase]
        add edi,[edi+03Ch]// edi -> IMAGE_NT_HEADERS
        // get write permission by VirtualProtect()
        lea eax,[ebp+_p_ptempbuffer]
        push eax
        push PAGE_READWRITE
        push [edi+0x54]//IMAGE_NT_HEADERS.OptionalHeader.SizeOfHeaders
        push [ebp+_p_dwImageBase]
        call _jmp_VirtualProtect
        //VirtualProtect(dwImageBase,image_nt_header.OptionalHeader.SizeOfHeaders,PAGE_READWRITE,ptempbuffer);
//这上面是对需要修改的内存位置赋予读写属性
        //----------------------------------------------------
        //----------------------------------------------------
        //--------------- import table fix up ----------------
        lea eax,[ebp+_ShellAbout_NewCode]
        push eax
        lea eax,[ebp+_p_szShellAbout]
        push eax
        lea eax,[ebp+_p_szSHELL32_r]
        push eax
        push [ebp+_p_dwImportVirtualAddress]
        push [ebp+_p_dwImageBase]
        call _it_fixup_1
//_it_fixup_1函数就是执行的手动加载原始导入表函数的过程了,在加载过程中它会搜寻shell32.dll的shellabout函数的绝对地址并进行替换
        //--------------- import table fix up ----------------
        //call _it_fixup
        //----------------------------------------------------
        //====================================================
        //---------------- support dll, ocx  1 ---------------
        //by set second way to oep and relocation table effect
        mov edi,[ebp+_p_dwImageBase]
        add edi,[edi+03Ch]// edi -> IMAGE_NT_HEADERS
        mov ax,word ptr [edi+016h]// edi -> image_nt_headers->FileHeader.Characteristics
        // .IF ((image_nt_headers->FileHeader.Characteristics&IMAGE_FILE_DLL) ==IMAGE_FILE_DLL)
        test ax,IMAGE_FILE_DLL
        jz _no_dll_pe_file_1
                //--------------- relocation fix up --------------
                call _reloc_fixup
                //------------------------------------------------
                mov ax,9090h
                mov word ptr [ebp+_support_dll_0],ax
        // .ENDIF
_no_dll_pe_file_1:
        //----------------------------------------------------
        //====================================================
_support_dll_2:
        //----------------------------------------------------
        //====================================================
        //--------- Prepare the SEH for OEP approach ---------
        mov eax,[ebp+_p_dwImageBase]
        add eax,[ebp+_p_dwOrgEntryPoint]
        mov [esp+10h],eax        // pStack.Ebx <- eax
        lea eax,[ebp+_except_handler1_OEP_Jump]
        mov [esp+1Ch],eax        // pStack.Eax <- eax
        popad        // restore the first registers context from stack
        //----------------------------------------------------
          // the structured exception handler (SEH) installation
        push eax
        xor  eax, eax
        push dword ptr fs:[0]                // NT_TIB32.ExceptionList
        mov fs:[0],esp        // NT_TIB32.ExceptionList <-ESP
        dword_type(0xCCCCCCCC)// raise a (int 3) exception
        //----------------------------------------------------
        //====================================================
//--------------------------------------------------------
//========================================================
//------------- t_size strlen(LPCTSTR lpStr) -------------
//下面是作者自己写的strlen函数,和c语言的函数功能一致,没啥好说的
__strlen:
        push ebp
        mov ebp,esp
        push ecx
        push esi
        push ebx
        mov esi,[ebp+08h]// -> destination
        mov ecx,255// -> length
        xor ebx,ebx
_strlenloop:
                lods byte ptr ds:[esi]
                cmp al,00h
                jz _endbufstrlen
                inc ebx
        loop _strlenloop
_endbufstrlen:
        mov eax,ebx
        inc eax
        pop ebx
        pop esi
        pop ecx
        mov esp,ebp
        pop ebp
        ret
//--------------------------------------------------------
//========================================================
//------------------- fix up relocation ------------------
// I have stolen this reloc fix-up code from Morphine 2.7 !!
// so Thanks Holy_Father && Ratter/29A for it. (www.hxdef.org)
//下面是重定位表的修正过程,实际上就是当PE文件加载到非PE头指定的位置时,会导致PE文件中一些函数的位置发生变化,需要修正。
_reloc_fixup:
        mov eax,[ebp+_p_dwImageBase]
        mov edx,eax
        mov ebx,eax
        add ebx,[ebx+3Ch] // edi -> IMAGE_NT_HEADERS
        mov ebx,[ebx+034h]// edx ->image_nt_headers->OptionalHeader.ImageBase
        sub edx,ebx // edx -> reloc_correction
        je _reloc_fixup_end
        mov ebx,[ebp+_p_dwRelocationVirtualAddress]
        test ebx,ebx
        jz _reloc_fixup_end
        add ebx,eax
_reloc_fixup_block:
        mov eax,[ebx+004h]                        //ImageBaseRelocation.SizeOfBlock
        test eax,eax
        jz _reloc_fixup_end
        lea ecx,[eax-008h]                        //ImageBaseRelocation.SizeOfBlock - sizeof(TImageBaseRelocation)
        shr ecx,001h                                //WORD((ImageBaseRelocation.SizeOfBlock - sizeof(TImageBaseRelocation)) / sizeof(Word))
        lea edi,[ebx+008h]                        //PImageBaseRelocation + sizeof(TImageBaseRelocation)
_reloc_fixup_do_entry:
                movzx eax,word ptr [edi]//Entry
                push edx
                mov edx,eax
                shr eax,00Ch                        //Type = Entry >> 12

                mov esi,[ebp+_p_dwImageBase]//ImageBase
                and dx,00FFFh
                add esi,[ebx]                        //ImageBase + ImageBaseRelocation.VirtualAddress
                add esi,edx                                //ImageBase + ImageBaseRelocation.VirtualAddress+Entry & 0x0FFF
                pop edx
                //------------------------------
                //---- IMAGE_REL_BASED_HIGH ----
_reloc_fixup_HIGH:
                dec eax
                jnz _reloc_fixup_LOW
                        mov eax,edx
                        shr eax,010h                //HIWORD(Delta)
                        jmp _reloc_fixup_LOW_fixup
                //------------------------------
                //---- IMAGE_REL_BASED_LOW -----
_reloc_fixup_LOW:
                        dec eax
                jnz _reloc_fixup_HIGHLOW
                movzx eax,dx                        //LOWORD(Delta)
_reloc_fixup_LOW_fixup:
                        add word ptr [esi],ax
                jmp _reloc_fixup_next_entry
                //------------------------------
                //-- IMAGE_REL_BASED_HIGHLOW ---
_reloc_fixup_HIGHLOW:
                        dec eax
                jnz _reloc_fixup_next_entry
                add [esi],edx
                //------------------------------
_reloc_fixup_next_entry:
                inc edi
                inc edi                                                //Entry++
                loop _reloc_fixup_do_entry
       
_reloc_fixup_next_base:
        add ebx,[ebx+004h]                                //ImageBaseRelocation + ImageBaseRelocation.SizeOfBlock
        jmp _reloc_fixup_block
_reloc_fixup_end:
        // clean relocation table
/*        mov eax,[ebp+_p_dwImageBase]
        add eax,[ebp+_p_dwRelocationVirtualAddress]
        lea edi,[eax]
        xor eax,eax
        add ecx,[ebp+_p_dwRelocationSize]
        rep stos byte  ptr [edi]*/
        ret
//--------------------------------------------------------
//下面就是手动加载原始导入表的过程了,它会模拟PE加载器的操作,遍历导入表信息,查找dll名称和api函数名称,然后利用LoadLibrary和GetProcAddress进行加载
//--------------- fix up the import table ----------------
/*
ebp+18h        [ebp+_ShellAbout_NewCode]
ebp+14h        [ebp+_p_szShellAbout]
ebp+10h        [ebp+_p_szSHELL32_r]
ebp+0ch        _p_dwImportVirtualAddress
ebp+08h        _p_dwImageBase
---------------------------------
ebp-04h                x
ebp-08h                _p_dwThunk
ebp-0ch                _p_dwHintName
ebp-10h                _p_dwLibraryName
ebp-14h                _p_dwAPIaddress
ebp-18h                _p_dwFunctionName
*/
_it_fixup_1:
        push ebp
        mov ebp,esp
        add esp,-18h
        mov ebx,[ebp+0ch]             //ebx = _p_dwImportVirtualAddress
        test ebx,ebx
        jz _it_fixup_1_end
        mov esi,[ebp+08h]               //esi = _p_dwImageBase
        add ebx,esi                                                                        // dwImageBase + dwImportVirtualAddress
_it_fixup_1_get_lib_address_loop:
                mov eax,[ebx+0ch]                                                // image_import_descriptor.Name    eax=dll名称
                test eax,eax
                jz _it_fixup_1_end
               
                mov ecx,[ebx+10h]                                                // ecx = image_import_descriptor.FirstThunk
                add ecx,esi
                mov [ebp-08h],ecx                                                // dwThunk (FirstThunk的绝对地址)
                mov ecx,[ebx]                                                        // ecx = image_import_descriptor.Characteristics
                test ecx,ecx
                jnz _it_fixup_1_table
                        mov ecx,[ebx+10h]
_it_fixup_1_table:
                add ecx,esi
                mov [ebp-0ch],ecx                                                // dwHintName
                add eax,esi                                                                // image_import_descriptor.Name + dwImageBase = ModuleName
                push eax                                                                // lpLibFileName
                mov [ebp-10h],eax
                call _jmp_LoadLibrary                                        // LoadLibrary(lpLibFileName);

                test eax,eax
                jz _it_fixup_1_end
                mov edi,eax                     //edi指向dll加载基址
_it_fixup_1_get_proc_address_loop:
                        mov ecx,[ebp-0ch]                                        // dwHintName
                        mov edx,[ecx]                                                // image_thunk_data.Ordinal
                        test edx,edx
                        jz _it_fixup_1_next_module
                        test edx,080000000h                                        // .IF( import by ordinal )
                        jz _it_fixup_1_by_name
                                and edx,07FFFFFFFh                                // get ordinal
                                jmp _it_fixup_1_get_addr
_it_fixup_1_by_name:
                        add edx,esi                                                        // image_thunk_data.Ordinal + dwImageBase = OrdinalName
                        inc edx
                        inc edx                                                                // OrdinalName.Name
_it_fixup_1_get_addr:
                        push edx                                                        // lpProcName
                        mov [ebp-18h],edx
                        push edi                                                        // hModule                                               
                        call _jmp_GetProcAddress                        // GetProcAddress(hModule, lpProcName);
                        mov [ebp-14h],eax                                        //_p_dwAPIaddress
//上面的代码段就是加载api函数的过程,然后获取的绝对地址暂存在[ebp-14h]中
                        //================================================================
                        //mov [ecx],eax//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
                        push edi
                        push esi
                        push ebx

                        mov ebx,[ebp-10h]
                        push ebx
                        push ebx
                        call _char_upper
                        //上面是把当前正在加载的dll名称转化为全大写,然后和下面的SHELL32.DLL进行字符串匹配,如果匹配的话,就再和shellabout函数进行字符串匹配,全部匹配的话就进行导入表的地址替换操作
                        mov esi,[ebp-10h]
                        mov edi,[ebp+010h]        // [ebp+_p_szShell32]

_it_fixup_1_check_dll_redirected:
                                push edi
                                call __strlen
                                add esp, 4

                                mov ebx,eax
                                mov ecx,eax
                                push edi
                                push esi
                                repe cmps //byte ptr [edi], byte ptr [esi]
                                jz _it_fixup_1_check_func_name
                                jmp _it_fixup_1_no_check_func_name
_it_fixup_1_check_func_name:
                                mov edi,[ebp+014h]        // [ebp+_p_szShellAbout]
                                push edi
                                call __strlen
                                add esp, 4
                                mov ecx,eax
                                mov esi,[ebp-18h]
                                mov edi,[ebp+014h]        // [ebp+_p_szShellAbout]
                                repe cmps //byte ptr [edi], byte ptr [esi]
                                jz _it_fixup_1_do_normal_it_0

//如果不匹配的话就执行下面的代码,直接将当前加载的api函数绝对地址写入原始导入表的FirstThunk域(和系统PE加载的做法一致)
_it_fixup_1_no_check_func_name:
                                pop esi
                                pop edi
                                add edi,ebx
                        cmp byte ptr [edi],0
                        jnz _it_fixup_1_check_dll_redirected
                        mov ecx,[ebp-08h]
                        mov eax,[ebp-014h]
                        mov [ecx],eax
                        jmp _it_fixup_1_do_normal_it_1
//如果匹配的话就执行下面这段,就是将我们自己的代码段替换实际ShellAbout函数的绝对地址,实现导入表的注入。
_it_fixup_1_do_normal_it_0:
                                pop esi
                                pop edi
                                mov ecx,[ebp-08h]
                                mov edi,[ebp+18h]
                                mov [ecx],edi
_it_fixup_1_do_normal_it_1:
                        pop ebx
                        pop esi
                        pop edi
                        //================================================================
                        add dword ptr [ebp-08h],004h        // dwThunk => next dwThunk
                        add dword ptr [ebp-0ch],004h// dwHintName => next dwHintName
                jmp _it_fixup_1_get_proc_address_loop
_it_fixup_1_next_module:
                add ebx,014h                                                        // sizeof(IMAGE_IMPORT_DESCRIPTOR)
        jmp _it_fixup_1_get_lib_address_loop
_it_fixup_1_end:
        mov esp,ebp
        pop ebp
        ret 14h
//--------------------------------------------------------
//========================================================
//-- char_upper(LPCTSTR lpDestination, LPCTSTR lpSource )
_char_upper:
        push ebp
        mov ebp,esp
        push ecx
        push eax
        push esi
        push edi
        mov edi,dword ptr [ebp+08h]// -> Destination
        mov esi,dword ptr [ebp+0Ch]// -> Source
        mov ecx,255// -> Length
        xor eax,eax
__makeupperloop:
                lods byte ptr [esi]//ESI
                cmp al,00h
                jz endofbuffer
                cmp al,60h
                jc notinlowerfield
                cmp al,7bh
                jnc notinlowerfield
                sub al,20h
notinlowerfield:
                stos byte ptr [edi]//EDI
        loop __makeupperloop
endofbuffer:
        pop edi
        pop esi
        pop eax
        pop ecx
        pop ebp
        retn 08h
//--------------------------------------------------------
//========================================================
//------------- load necessary api functions -------------
_api_load:
        lea edi,[ebp+_p_szKernel32]
        lea ebx,[ebp+_p_GetModuleHandle]
        lea ecx,[ebp+_jmp_GetModuleHandle]
        add ecx,02h
_api_get_lib_address_loop:
                push ecx
                //-------------------
                push edi
                mov eax,offset _p_LoadLibrary
                call [ebp+eax]// LoadLibrary(lpLibFileName);
                //-------------------
                pop ecx
                mov esi,eax        // esi -> hModule
                push edi
                call __strlen
                add esp,04h
                add edi,eax
_api_get_proc_address_loop:
                        push ecx
                        //-------------------
                        push edi
                        push esi
                        mov eax,offset _p_GetProcAddress
                        call [ebp+eax]// GetModuleHandle=GetProcAddress(hModule, lpProcName);
                        //--------------------
                        pop ecx
                        mov [ebx],eax
                        mov [ecx],ebx
                        add ebx,04h
                        add ecx,06h
                        push edi
                        call __strlen
                        add esp,04h
                        add edi,eax
                        mov al,byte ptr [edi]
                test al,al
                jnz _api_get_proc_address_loop
                inc edi
                mov al,byte ptr [edi]
        test al,al
        jnz _api_get_lib_address_loop
        ret
//--------------------------------------------------------
//========================================================
//这里就是我们自己的函数了,用来替换ShellAbout函数的,功能就是弹出一个对话框
_ShellAbout_NewCode:
_local_0:
        pushad        // save the registers context in stack
        call _local_1
_local_1:       
        pop ebp
        sub ebp,offset _local_1 // get base ebp
        push MB_OK | MB_ICONINFORMATION
        lea eax,[ebp+_p_szCaption]
        push eax
        lea eax,[ebp+_p_szText]
        push eax
        push NULL
        call _jmp_MessageBox
        // MessageBox(NULL, szText, szCaption, MB_OK | MB_ICONINFORMATION) ;

        //...
        //...
        //...

        // Place your code here ...

        //...
        //...
        //...
        popad  // restore the first registers context from stack
        ret 10h
//----------------------------------------------------------
//--------------------------------------------------------
//========================================================
// -------- exception handler expression filter ----------
//最后跳转到目标PE文件的原始入口点,继续执行
_except_handler1_OEP_Jump:
        push ebp
        mov ebp,esp
        mov eax,[ebp+010h]        // PCONTEXT: pContext <- eax
        //---------------
        push edi
        // restore original SEH
        mov edi,[eax+0C4h]        // pContext.Esp
        push dword ptr ds:[edi]
        pop dword ptr fs:[0]
        add dword ptr [eax+0C4h],8        // pContext.Esp
       
        // set the Eip to the OEP
        mov edi,[eax+0A4h] // edi <- pContext.Ebx
        mov [eax+0B8h],edi // pContext.Eip <- edi
        //
        pop edi
        //---------------
        mov eax, EXCEPTION_CONTINUE_SEARCH
        leave
        ret
//--------------------------------------------------------
//========================================================
//下面是一些“启动汇编代码”段需要用到的常量数据等内容
        dword_type(DYN_LOADER_START_DATA1)
//----------------------------------
_p_dwFileType:                                        dword_type(0xCCCCCCCC)
_p_dwImageBase:                                        dword_type(0xCCCCCCCC)
_p_dwOrgEntryPoint:                                dword_type(0xCCCCCCCC)
_p_dwImportVirtualAddress:                dword_type(0xCCCCCCCC)
_p_dwRelocationVirtualAddress:        dword_type(0xCCCCCCCC)
_p_dwRelocationSize:                        dword_type(0xCCCCCCCC)
//----------------------------------
_tls_dwStartAddressOfRawData:        dword_type(0xCCCCCCCC)
_tls_dwEndAddressOfRawData:                dword_type(0xCCCCCCCC)
_tls_dwAddressOfIndex:                        dword_type(0xCCCCCCCC)
_tls_dwAddressOfCallBacks:                dword_type(0xCCCCCCCC)
_tls_dwSizeOfZeroFill:                        dword_type(0xCCCCCCCC)
_tls_dwCharacteristics:                        dword_type(0xCCCCCCCC)
//----------------------------------
_p_szKernel32:                                //db "Kernel32.dll",0,13
                db db db db db db db db db db db db db
_p_szGetModuleHandle:                //db "GetModuleHandleA",0,17
                db db db db db db db db db db db db db db db db db
_p_szVirtualProtect:                //db "VirtualProtect",0,15
                db db db db db db db db db db db db db db db
_p_szGetModuleFileName:        //db "GetModuleFileNameA",0,19
                db db db db        db db db db        db db db db db db db db db db db
_p_szCreateFile:                        //db "CreateFileA",0,12
                db db db db db db db db db db db db
_p_szGlobalAlloc:                        //db "GlobalAlloc",0,12
                db db db db db db db db db db db db
_p_szVirtualAlloc:                        //db "VirtualAlloc",0,13
                db db db db db db db db db db db db db
_p_szLoadLibrary:                        //db "LoadLibraryA",0,13
                db db db db db db db db db db db db db
_p_szGetProcAddress:                //db "GetProcAddress",0,15
                db db db db db db db db db db db db db db db
                byte_type(0)

_p_szUser32:                                //db "User32.dll",0,11
                db db db db db db db db db db db
_p_szMessageBox:                        //db "MessageBoxA",0,12
                db db db db db db db db db db db db
                byte_type(0)
                byte_type(0)
//----------------------------------
_p_LoadLibrary:                                        dword_type(0xCCCCCCCC)
_p_GetProcAddress:                                dword_type(0xCCCCCCCC)
_p_GetModuleHandle:                       
                                                                dword_type(0xCCCCCCCC)
                                                                dword_type(0xCCCCCCCC)
                                                                dword_type(0xCCCCCCCC)
                                                                dword_type(0xCCCCCCCC)
                                                                dword_type(0xCCCCCCCC)
                                                                dword_type(0xCCCCCCCC)
                                                                dword_type(0xCCCCCCCC)
                                                                dword_type(0xCCCCCCCC)
                                                                dword_type(0xCCCCCCCC)

_jmp_GetModuleHandle:                        __jmp_api        dword_type(0xCCCCCCCC)
_jmp_VirtualProtect:                        __jmp_api        dword_type(0xCCCCCCCC)
_jmp_GetModuleFileName:                        __jmp_api        dword_type(0xCCCCCCCC)
_jmp_CreateFile:                                __jmp_api        dword_type(0xCCCCCCCC)
_jmp_GlobalAlloc:                                __jmp_api        dword_type(0xCCCCCCCC)
_jmp_VirtualAlloc:                                __jmp_api        dword_type(0xCCCCCCCC)
_jmp_LoadLibrary:                                __jmp_api        dword_type(0xCCCCCCCC)
_jmp_GetProcAddress:                        __jmp_api        dword_type(0xCCCCCCCC)

_jmp_MessageBox:                                __jmp_api        dword_type(0xCCCCCCCC)
_p_szSHELL32_r:                               
                //db "SHELL32.DLL",0,12
                bb('S') bb('H') bb('E') bb('L') bb('L') bb('3') bb('2') bb('.') bb('D') bb('L') bb('L') bb(0)
                byte_type(0)
_p_szShellAbout:
                //db "ShellAboutW",0,12
                bb('S') bb('h') bb('e') bb('l') bb('l') bb('A') bb('b') bb('o') bb('u') bb('t') bb('W') bb(0)
_p_szCaption:
bb('A') bb('s') bb('h') bb('k') bb('b') bb('i') bb('z') bb(0)
_p_szText:
bb('T') bb('h') bb('i') bb('s') bb(' ') bb('E') bb('x') bb('a') bb('m') bb('p') bb('l')
bb('e') bb(' ') bb('s') bb('h') bb('o') bb('w') bb('s') bb(' ') bb('h') bb('o') bb('w')
bb(' ') bb('A') bb('P') bb('I') bb(' ') bb('r') bb('e') bb('d') bb('i') bb('r') bb('e')
bb('c') bb('t') bb('i') bb('o') bb('n') bb(' ') bb('t') bb('e') bb('c') bb('h') bb('n')
bb('i') bb('q') bb('u') bb('e') bb(' ') bb('w') bb('o') bb('r') bb('k') bb('s') bb('.')
bb(0)
_p_dwThunk:                                                dword_type(0xCCCCCCCC)
_p_dwHintName:                                        dword_type(0xCCCCCCCC)
_p_ptempbuffer:                                        dword_type(0xCCCCCCCC)
//----------------------------------
        dword_type(DYN_LOADER_END_MAGIC)
//----------------------------------
}
}

[课程]FART 脱壳王!加量不加价!FART作者讲授!

上传的附件:
收藏
免费 0
支持
分享
最新回复 (2)
雪    币: 266
活跃值: (44)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
2
mark
2015-4-20 16:09
0
雪    币: 6890
活跃值: (8944)
能力值: ( LV17,RANK:797 )
在线值:
发帖
回帖
粉丝
3
mark..
2015-4-20 21:30
0
游客
登录 | 注册 方可回帖
返回
//