程序开始运行时,加载程序根据导入表的DLL名字加载DLL。首先在运行目录下查找DLL,如果找到,则把他加载进进程空间。如果没找到则在系统目录下继续寻找。可以通过这一个特点,在原有的导入表后面增加一个导入表结构(INT和IAT表至少有一个函数的名字)。
这就是导入表注入。
自定义的要写入的结构
typedef struct _NEW_IMPORT_TABLE
{
IMAGE_IMPORT_DESCRIPTOR iid;//一个新的导入表结构
IMAGE_IMPORT_DESCRIPTOR zero_iid;//一个全0的导入表结构
DWORD Int;//INT表
DWORD Int_ZERO;//INT表的结束
DWORD Iat;//IAT表
DWORD Iat_zero;//IAT表的结束
WORD Hint;// 取结构体大小时注意结构体对齐问题
}NEW_IMPORT_TABLE, *PNEWIMPORTTABLE;
{
//移动所有导入表
PVOID pOptionHeader = NULL;
GetPEOptionHeader(pImage,&pOptionHeader);
//得到第一个导入表的FOA
DWORD ImportTable_FOA = RVA_To_FOA(pImage,((PIMAGE_OPTIONAL_HEADER32)pOptionHeader)->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
/*
typedef struct _IMAGE_IMPORT_DESCRIPTOR {
DWORD OriginalFirstThunk
DWORD TimeDateStamp; // 0 if not bound,
DWORD ForwarderChain; // -1 if no forwarders
DWORD Name;
DWORD FirstThunk; // RVA to IAT (if bound this IAT has actual addresses)
} IMAGE_IMPORT_DESCRIPTOR;
*/
//遍历导入表得到导入表的大小
DWORD Index = 0;
PIMAGE_IMPORT_DESCRIPTOR pIID=(PIMAGE_IMPORT_DESCRIPTOR)((PCHAR)pImage+ ImportTable_FOA);
while (pIID->FirstThunk&&pIID->OriginalFirstThunk)
{
Index++;
pIID++;
}
//获取新增加节的FOA
PVOID pSectionTable = NULL;
GetPESectionTable(pImage, &pSectionTable, GetNumberOfSections(pImage));
DWORD WriteAddr_FOA =((PIMAGE_SECTION_HEADER)pSectionTable)->PointerToRawData;
//复制原来的导入表
memcpy_s((char*)pImage+ WriteAddr_FOA, Index*sizeof(IMAGE_IMPORT_DESCRIPTOR), (PCHAR)pImage + ImportTable_FOA, Index * sizeof(IMAGE_IMPORT_DESCRIPTOR));
//修改导入表的virtualAddress
((PIMAGE_OPTIONAL_HEADER32)pOptionHeader)->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = FOA_To_RVA(pImage, WriteAddr_FOA);
//构建两个IMAGE_IMPORT_DESCRIPTOR结构 第二个全0结构。
//得到新加入的导入表的FOA
DWORD NewImprtTable_FOA = WriteAddr_FOA + Index * sizeof(IMAGE_IMPORT_DESCRIPTOR);
//新写入开始的指针
PNEWIMPORTTABLE pNewImportTable =(PNEWIMPORTTABLE)((char*)pImage + WriteAddr_FOA + Index * sizeof(IMAGE_IMPORT_DESCRIPTOR));
//需要找到的FOA值: DLL名字的FOA 导入函数名字的FOA
// IAT 表的FOA INT表的FOA 写入 iid OriginalFitstThunk FitstThunk
//注意 IAT表存放的是导入函数名前两个字节的RVA Hint
//iid 的OriginalFitstThunk存放INT表的RVA
//iid 的FitstThunk存放IAT表的RVA
//先写入函数名字和 dll名字 先写入 函数名 再写入dll名
char lpszFuncName[] = "Show";
char lpszDllName[] = "Inject.dll";
//获得函数名的长度 strlen 返回的长度不包括0结尾
DWORD SizofFuncName = strlen(lpszFuncName);
//获得dll名字的长度
DWORD SizeofDllName = strlen(lpszDllName);
// 先写入 函数名
memcpy_s((PCHAR)pNewImportTable+sizeof(NEW_IMPORT_TABLE)-2,
SizofFuncName,
lpszFuncName,
SizofFuncName);
//再写入dll名
memcpy_s((PCHAR)pNewImportTable + sizeof(NEW_IMPORT_TABLE)+ SizofFuncName+1-2,
SizeofDllName,
lpszDllName,
SizeofDllName);
//需要找到的FOA值: 导入函数名字的FOA DLL名字的FOA
DWORD FuncName_FOA = NewImprtTable_FOA + 56;
DWORD DllName_FOA = FuncName_FOA + SizofFuncName + 3;//这里加3的原因是因为FuncName_FOA的位置是在hint索引的两字节位置+上函数的0结尾就是3字节
DWORD INT_FOA = NewImprtTable_FOA + 40;
DWORD IAT_FOA = NewImprtTable_FOA + 48;
pNewImportTable->Int=FOA_To_RVA(pImage, FuncName_FOA);
pNewImportTable->Iat = FOA_To_RVA(pImage, FuncName_FOA);
pNewImportTable->iid.OriginalFirstThunk = FOA_To_RVA(pImage, INT_FOA);
pNewImportTable->iid.FirstThunk = FOA_To_RVA(pImage, IAT_FOA);
pNewImportTable->iid.Name= FOA_To_RVA(pImage, DllName_FOA);
ImageBufferToFile(pImage,"c:/InjectOver.exe");
}