IAT加密的一些粗浅理解

先上一段代码

void afxiat()
{
    
    PIMAGE_IMPORT_BY_NAME; //名称

    _IMAGE_THUNK_DATA32; //iat
    DWORD ImageBase = g_stubConf.ntheader.OptionalHeader.ImageBase;

    //导入表
    PIMAGE_IMPORT_DESCRIPTOR exeimport = 
        (PIMAGE_IMPORT_DESCRIPTOR)
        (g_stubConf.ntheader.OptionalHeader.DataDirectory[1].VirtualAddress+
        g_stubConf.ntheader.OptionalHeader.ImageBase);

    HANDLE heap = apis.pfnGetProcessHeap();

    //遍历导入表中的INT修复IAT
    while (exeimport->Name != NULL) //遍历模块
    {
        HMODULE h_dllModule = apis.pfnLoadLibraryA((char *)(exeimport->Name + ImageBase));
        PIMAGE_THUNK_DATA  import_Int = (PIMAGE_THUNK_DATA)(exeimport->OriginalFirstThunk+ImageBase);
        PIMAGE_THUNK_DATA  import_IAT = (PIMAGE_THUNK_DATA )(exeimport->FirstThunk+ ImageBase);

        while (import_Int->u1.Ordinal != 0) //遍历函数
        {
            UCHAR *buf = (UCHAR *)apis.pfnHeapAlloc(heap, HEAP_ZERO_MEMORY, 10);            //HeapAlloc的作用有点类似于VIrtualAlloc这个API
            buf[0] = 0xb8;
            buf[5] = 0xff;
            buf[6] = 0xe0;
            //new char[20]{ "\xB8\x00\x00\x00\0x00\0xff\0xe0" };
            DWORD opl = 0;
            apis.pfnVirtualProtect((LPVOID)buf, 20, PAGE_EXECUTE_READWRITE, &opl);
            if (import_Int->u1.Ordinal &0x80000000) //序号导出, 最高位为1,这里是获取最高位,如果最高位为1,就执行下面里面的语句,即
                                    //以序号导入 ,否则以名称导入,执行else中的语句
            {

            
                //获取序号函数
                LPVOID apiaddr =
                    apis.pfnGetProcAddress(h_dllModule, (char *)(import_Int->u1.Ordinal & 0xFFFF));

                *(DWORD*)&buf[1] = (DWORD)apiaddr;  //函数写入shellcode

                //DWORD funaddr = ;
                
            
                apis.pfnVirtualProtect((LPVOID)(import_IAT ), 4, PAGE_EXECUTE_READWRITE, &opl);
                *(DWORD*)((DWORD)import_IAT ) = (DWORD)buf; //将函数写入到iat
            }
            else
            {
                //DWORD Faddr = *(DWORD*)(import_Int->u1.AddressOfData + ImageBase);
                PIMAGE_IMPORT_BY_NAME funname = (PIMAGE_IMPORT_BY_NAME)(import_Int->u1.AddressOfData+ImageBase);
                LPVOID apiaddr =
                    apis.pfnGetProcAddress(h_dllModule, funname->Name);

                *(DWORD*)&buf[1] = (DWORD)apiaddr;  //函数写入shellcode

                apis.pfnVirtualProtect((LPVOID)(import_IAT), 4, PAGE_EXECUTE_READWRITE, &opl);
                *(DWORD*)((DWORD)import_IAT ) = (DWORD)buf; //将函数写入到iat
//              DWORD funaddr =import_IAT->u1.Function  ;  //获取iat地址
// 
//              apis.pfnVirtualProtect((LPVOID)funaddr, 4, PAGE_EXECUTE_READWRITE, &opl);
//              *(DWORD*)(funaddr) = (DWORD)buf; //将函数写入到iat
            }

            import_Int++;
            import_IAT++;

        }
        exeimport++;
    }

}

先叙说一下整个逻辑:
一般IAT的加密是这样的,导入表里面有一个IAT表,一般PE加载的时候会把函数地址填入这个表里面,这里一般用VirtualAlloc(上面这个例子没有用这个API)申请一块内存地址填入IAT表里面,申请的这块空间里面存放的是一段Shellcode,这个shellcode可以存放真正的地址,然后可以对地址进行加密(上面这个例子里面没有进行加密!!!,上面例子中的Shellcode的意思是:mov eax,0xXXXX(函数地址),jmp eax),如果加密了的话,汇编代码可以写成这样:

mov eax,0x90909090(加密后的地址)
xor eax,15151515(通过某个操作数进行异或)     (这一步的作用是得到真正的地址)
jmp eax

然后再将这段汇编代码写成Shellcode即可
IAT不加密的话,IAT表里面存放的是原来的函数地址
IAT加密的话,IAT里面存放的是VirtualAlloc申请出来的那块内存空间的地址,其实到达这个地址之后,可以对地址加密用一些比较复杂的算法,那样就比较难了!

你可能感兴趣的:(IAT加密的一些粗浅理解)