先上一段代码
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申请出来的那块内存空间的地址,其实到达这个地址之后,可以对地址加密用一些比较复杂的算法,那样就比较难了!
网友评论