一、导入表注入的原理
注入是把DLL加载到另一个进程的4GB地址空间中,实现方式有很多种,导入表注入是我学的第一种注入,是通过修改程序的导入表,把自己的DLL添加到导入表中,来实现这个目的。
导入表是连续存储在节里的,它后面还有其他数据,不能直接追加一个导入表,所以必须找一块足够大的内存,把原来的所有导入表移动过去,再追加我们DLL的导入表。新增节是比较简单的做法,我的代码中也采用新增节。
导入表注入是让系统根据EXE的导入表,帮我们实现加载DLL,需要知道一点,DLL至少要有一个导出函数,系统才会帮我们加载DLL。
新增节存储如下数据(顺序随意安排):
原来的所有导出表 IMAGE_IMPORT_DESCRIPTOR
新增DLL的导出表 IMAGE_IMPORT_DESCRIPTOR
导出表结束标记,sizeof(IMAGE_IMPORT_DESCRIPTOR) 个0
INT表
INT表结束标记
IMPORT_BY_NAME 结构,包括Hint和导出函数名所占的字节数
IAT表
IAT表结束标记
模块名
这些数据都写入到内存中后,根据他们的地址,给其中某些结构的属性赋值
导入表中的FirstThunk,OriginalFirstThunk分别存储INT,IAT的RVA;
导入表的Name存储模块名的RVA;
INT,IAT的值是IMPORT_BY_NAME的RVA;
除此之外,完成了所有结构的属性设置后,不要忘了修改数据目录项,让导入表指向新增节首字节。
二、注入代码和运行结果
// 导入表注入demo,通过修改导入表,将 InjectDll.dll 添加到导入表
// DLL只有一个导出函数 ExportFunction,保证至少有一个导出函数DLL才会被加载
// DLL的主函数在加载和分离时会弹窗
DWORD ImportTableInjectDemo(LPVOID pFileBuffer, LPVOID *pNewFileBuffer, DWORD dwFileSize)
{
PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
PIMAGE_FILE_HEADER pPEHeader = (PIMAGE_FILE_HEADER)(pDosHeader->e_lfanew + (DWORD)pDosHeader + 4);
PIMAGE_OPTIONAL_HEADER32 pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + sizeof(IMAGE_FILE_HEADER));
PIMAGE_SECTION_HEADER pSectionHeader = \
(PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader);
PIMAGE_IMPORT_DESCRIPTOR pImportTable = (PIMAGE_IMPORT_DESCRIPTOR)((DWORD)pFileBuffer + \
RvaToFoa(pFileBuffer, pOptionHeader->DataDirectory[1].VirtualAddress));
// 计算新增节的大小
// 新增节存储的内容有:原来的所有导入表,新导入表,新INT, IAT, 模块名,一个_IMAGE_IMPORT_BY_NAME
// 上述容器按0为结束标记的,也要包含结束标记
DWORD dwNewSectionSize = 0;
DWORD dwNumberOfDll = 0;
while (pImportTable->OriginalFirstThunk || pImportTable-