Rva转Foa的过程 
1.判断Rva减去imagebase对比sizeofheader的大小,如果比这个小,那说明这个Rva减去imagebase对比sizeofheader就是foa
2.如果上述不成立,则遍历节表的virtualaddress,看位于哪2个节表之间,判断成功后用节表的pointtoraw+rva-virtualaddress,就是得到的foa
  foa转rva 
反过来就行,先看这个foa在那个节,计算与这个节pointtoraw地址的偏移,然后加上这个节的virtualaddress
代码待补充
  动态链接库测试 
  隐式链接 
vs创建dll项目,pch.cpp和pch.h如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 #include  "pch.h"  int  __stdcall Plus (int  x, int  y)  { 	return  x + y; }int  __stdcall Sub (int  x, int  y)  { 	return  x - y; }int  __stdcall Mul (int  x, int  y)  { 	return  x * y; }int  __stdcall Div (int  x, int  y)  { 	return  x / y; }
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 extern  "C"  int  _declspec(dllexport) __stdcall  Plus (int  x, int  y)  ;extern  "C"  int  _declspec(dllexport) __stdcall Sub (int  x, int  y)  ;extern  "C"  int  _declspec(dllexport) __stdcall Mul (int  x, int  y)  ;extern  "C"  int  _declspec(dllexport) __stdcall  Div (int  x, int  y)  ;#ifndef  PCH_H #define  PCH_H #include  "framework.h"  #endif   
 
把生成的dll,pch.h,framkwork.h,lib拷贝到测试项目里
 
测试项目加入
1 2 3 4 5 6 7 #pragma  comment(lib, "Dll1.lib" ) extern  "C"  __declspec(dllimport) int  __stdcall  Plus (int  x, int  y)  ;extern  "C"  __declspec(dllimport) int  __stdcall  Sub (int  x, int  y)  ;extern  "C"  __declspec(dllimport) int  __stdcall  Mul (int  x, int  y)  ;extern  "C"  __declspec(dllimport) int  __stdcall  Div (int  x, int  y)  ;
 
编译即可
  函数无名字导出 
新建立一个模块
输入如下
1 2 3 4 5 6 7 8 LIBRARY EXPORTS	 		 Plus   	@12  Sub	@15  NONAME  Mul    	@13  Div    	@16 
 
  导出表 
 
1 2 3 4 5 6 7    DWORD   NumberOfFunctions;     根据导出函数的序号最大的减最小+1 的得出,所以不一定是真实的个数 DWORD   AddressOfFunctions;     //   导出函数地址表RVA 有可能是空的->指这个地方无对应序号的函数 DWORD   Base; 此数据加上(DWORD   AddressOfNameOrdinals;  //  导出函数序号表RVA)里的序号   才是导出时函数的序号
 
  按名字找函数 
DWORD   AddressOfNames; ->找到名字,然后根据找到的函数对应的下标->DWORD   AddressOfNameOrdinals;对应的下标找到序号->到DWORD   AddressOfFunctions;表里找到对应此下标的函数
  序号查找 
给出的序号减去DWORD   Base;,根据下标到AddressOfNames;寻找地址即可
给的图例:
 
 
名字表的索引是用来定位序号表的序号:名字表[2]->序号表[2]->取出序号 
!!序号对应地址表的索引,如果是无名的函数,序号应该是地址表的下标加base 
  写的程序 
我觉得我写的有点乱,看网上是最好根据函数地址表 来查另外两个表然后定位和输出
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 void  showEXPORT_DIRECTORY (LPVOID pFileBuffer)   { 	PIMAGE_NT_HEADERS pNtHeaders = NULL ; 	PIMAGE_EXPORT_DIRECTORY exportDIRECTORY = NULL ; 	pNtHeaders = FileToNtHeader (pFileBuffer); 	exportDIRECTORY = (PIMAGE_EXPORT_DIRECTORY) pNtHeaders->OptionalHeader.DataDirectory[0 ].VirtualAddress; 	exportDIRECTORY = (PIMAGE_EXPORT_DIRECTORY) RVAtoFOA ((DWORD)exportDIRECTORY, pFileBuffer); 	printf ("******************************\n" ); 	printf ("导出表文件地址:%x\n" , exportDIRECTORY); 	PIMAGE_EXPORT_DIRECTORY exportDIRECTORYfilebuffer = (PIMAGE_EXPORT_DIRECTORY)((BYTE*)exportDIRECTORY + (DWORD)pFileBuffer); 	printf ("导出表函数个数:%x\n" , exportDIRECTORYfilebuffer->NumberOfFunctions); 	printf ("导出表有名字的函数个数:%x\n" , exportDIRECTORYfilebuffer->NumberOfNames); 	printf ("******************************\n" ); 	printf ("导出表函数地址表文件地址:%x\n" , RVAtoFOA (exportDIRECTORYfilebuffer->AddressOfFunctions,pFileBuffer)); 	for  (int  i = 0 ; i < exportDIRECTORYfilebuffer->NumberOfFunctions; i++) { 		DWORD* tureAddressOfFunctions = (DWORD*)((DWORD)pFileBuffer + RVAtoFOA (exportDIRECTORYfilebuffer->AddressOfFunctions, pFileBuffer)) + i; 		printf ("导出表函数地址表文件地址%x:%x\n" , i,(DWORD)RVAtoFOA ((DWORD)tureAddressOfFunctions- (DWORD)pFileBuffer,pFileBuffer)); 	} 	printf ("******************************\n" ); 	printf ("导出表函数名字表文件地址:%x\n" , RVAtoFOA (exportDIRECTORYfilebuffer->AddressOfNames, pFileBuffer)); 	for  (int  i = 0 ; i < exportDIRECTORYfilebuffer->NumberOfNames; i++) { 	DWORD* tureAddressOfNames = (DWORD*)((DWORD)pFileBuffer + RVAtoFOA (exportDIRECTORYfilebuffer->AddressOfNames, pFileBuffer))+i; 	printf ("导出表函数名字表文件中地址的值:%x\n" , *tureAddressOfNames); 	printf ("导出表函数名字表文件地址:%x\n" , RVAtoFOA ((DWORD)*tureAddressOfNames,pFileBuffer)); 		PCHAR Nameaddr = (PCHAR)((BYTE*)RVAtoFOA ((DWORD)*tureAddressOfNames, pFileBuffer) + (DWORD)pFileBuffer); 		printf ("导出表函数%x名字:%s\n" ,i,Nameaddr ); 	} 	printf ("******************************\n" ); 	printf ("导出表函数序号表base:%x\n" , exportDIRECTORYfilebuffer->Base); 	printf ("导出表函数序号表文件地址:%x\n" , RVAtoFOA (exportDIRECTORYfilebuffer->AddressOfNameOrdinals, pFileBuffer)); 	for  (int  i = 0 ; i < exportDIRECTORYfilebuffer->NumberOfNames; i++) { 		WORD* tureAddressOfxvhao = (WORD*)((DWORD)pFileBuffer + RVAtoFOA (exportDIRECTORYfilebuffer->AddressOfNameOrdinals, pFileBuffer)) + i; 		printf ("导出表函数序号表序号[%x]的值:%x\n" , i,*tureAddressOfxvhao); 		 		 		 	} }	
 
 
  重定位表 
数据目录的第六个结构,用来定位需要修改的地址位置(程序加载dll的时候,如果dll加载的基址不是imagebase,则根据此表偏移依次修改此表中指向的地址)
 
  内容说明 
 
  自己写的程序解析 
写了之后,感觉清楚挺多了,就是还不知道这个表修改的过程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 void  showRELOCATIONsetion (DWORD numofsetion,WORD* start,DWORD addrbase, LPVOID pFileBuffer)  { 	for  (DWORD i = 0 ;i < numofsetion;i++) 	{ 		WORD time = *start; 		DWORD addradd = (time & 0xFFF )+addrbase; 		if  (((time & 0xF000 ) >> 12 ) == 3 ) 		{ 			printf ("块需要修改,块高4位%x,后12位%x,RVA的值%x,,FOA值%x\n" , ((time & 0xF000 ) >> 12 ),(time & 0xFFF ),addradd,RVAtoFOA (addradd,pFileBuffer)); 		} 		else  { 			printf ("块不需要修改,块高4位%x,后12位%x,RVA的值%x,FOA值%x\n" , ((time & 0xF000 ) >> 12 ), (time & 0xFFF ),addradd, RVAtoFOA (addradd, pFileBuffer)); 		} 		 		start = start + 1 ; 	} }void  showRELOCATION (LPVOID pFileBuffer)   { 	PIMAGE_NT_HEADERS pNtHeaders = NULL ; 	PIMAGE_BASE_RELOCATION pRELOCATIONDIRECTORY = NULL ; 	PIMAGE_BASE_RELOCATION pnextRELOCATIONDIRECTORY = NULL ; 	DWORD lastRELOCATIONDIRECTORYaddr = 1 ; 	DWORD lastvirtualaddr = 1 ; 	int  kuai = 0 ; 	pNtHeaders = FileToNtHeader (pFileBuffer); 	 	pRELOCATIONDIRECTORY = PIMAGE_BASE_RELOCATION (RVAtoFOA (pNtHeaders->OptionalHeader.DataDirectory[5 ].VirtualAddress, pFileBuffer)+ (DWORD)pFileBuffer); 	pnextRELOCATIONDIRECTORY = pRELOCATIONDIRECTORY; 	printf ("******************************\n" ); 	printf ("重定位表内容\n" ); 	 	while  (lastvirtualaddr > 0 )  	{ 		kuai++; 		pRELOCATIONDIRECTORY = pnextRELOCATIONDIRECTORY; 		DWORD numofsetion = (pRELOCATIONDIRECTORY->SizeOfBlock - 8 ) / 2 ; 		printf ("块%x的地址是%x,大小是%x,块的数量是%x\n" , kuai,pRELOCATIONDIRECTORY->VirtualAddress,pRELOCATIONDIRECTORY->SizeOfBlock,numofsetion); 		showRELOCATIONsetion (numofsetion, (WORD*)((DWORD)pRELOCATIONDIRECTORY + 8 ), (DWORD)pRELOCATIONDIRECTORY->VirtualAddress,pFileBuffer); 		lastRELOCATIONDIRECTORYaddr = (DWORD)pRELOCATIONDIRECTORY+ pRELOCATIONDIRECTORY->SizeOfBlock; 		pnextRELOCATIONDIRECTORY = (PIMAGE_BASE_RELOCATION)lastRELOCATIONDIRECTORYaddr; 		lastvirtualaddr = pnextRELOCATIONDIRECTORY->VirtualAddress; 		 	} 	 }
 
 
完全一致,说明应该没问题
 
  重定位表和导出表的迁移 
步骤其实就是这样
 
不过程序写的时候比较蛋疼,调了好几次都没成功:
1.注意rva的转换,主要是注意函数使用的是内存空间,要计算foa就得减去指针开始的地方。 
2.注意rva的计算,因为表里存放的都是rva,反正是在最后一个节之后添加的的节,可以用最后一个节的VirtualAddress 加上文件地址和最后一个节文件地址PointerToRawData的相对偏移。 
这个和肝了我好久
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 LPVOID removeDIRECTORY (LPVOID  pFileBuffer)   { 	PIMAGE_NT_HEADERS pNtHeaders = NULL ; 	PIMAGE_SECTION_HEADER pSectionHeaderBase = NULL ; 	LPVOID start = NULL ; 	PIMAGE_EXPORT_DIRECTORY exportDIRECTORY = NULL ; 	pNtHeaders = FileToNtHeader (pFileBuffer); 	pSectionHeaderBase = LocateSectionBase (pFileBuffer); 	DWORD addrofnamervafirst = 0 ; 	exportDIRECTORY = (PIMAGE_EXPORT_DIRECTORY)pNtHeaders->OptionalHeader.DataDirectory[0 ].VirtualAddress; 	exportDIRECTORY = (PIMAGE_EXPORT_DIRECTORY)RVAtoFOA ((DWORD)exportDIRECTORY, pFileBuffer); 	 	PIMAGE_EXPORT_DIRECTORY exportDIRECTORYfilebuffer = (PIMAGE_EXPORT_DIRECTORY)((BYTE*)exportDIRECTORY + (DWORD)pFileBuffer); 	 	 	PIMAGE_SECTION_HEADER pLaswSectionHeaderBase = PIMAGE_SECTION_HEADER ((BYTE*)pSectionHeaderBase + (DWORD)(0x28  * (pNtHeaders->FileHeader.NumberOfSections - 1 ))); 	 	start = (LPVOID)(pLaswSectionHeaderBase->PointerToRawData + (DWORD)pFileBuffer); 	LPVOID starttest = (LPVOID)(pLaswSectionHeaderBase->PointerToRawData + (DWORD)pFileBuffer); 	 	DWORD AddressOfFunctionssize = exportDIRECTORYfilebuffer->NumberOfFunctions * 4 ; 	 	DWORD AddressOfFunctionsrva = (DWORD)pLaswSectionHeaderBase->VirtualAddress + (DWORD)start - (DWORD)starttest; 	 	DWORD* tureAddressOfFunctions = (DWORD*)((DWORD)pFileBuffer + RVAtoFOA (exportDIRECTORYfilebuffer->AddressOfFunctions, pFileBuffer)); 	memcpy (start, tureAddressOfFunctions, AddressOfFunctionssize); 	 	start = (LPVOID)((DWORD)start + AddressOfFunctionssize); 	DWORD AddressOfNameOrdinalsrva = (DWORD)pLaswSectionHeaderBase->VirtualAddress + (DWORD)start - (DWORD)starttest; 	DWORD AddressOfNameOrdinalssize = exportDIRECTORYfilebuffer->NumberOfNames * 2 ; 	 	WORD* tureAddressOfNameOrdinals = (WORD*)((DWORD)pFileBuffer + RVAtoFOA (exportDIRECTORYfilebuffer->AddressOfNameOrdinals, pFileBuffer)); 	memcpy (start, tureAddressOfNameOrdinals, AddressOfNameOrdinalssize); 	 	start = (LPVOID)((DWORD)start + AddressOfNameOrdinalssize); 	DWORD AddressOfNamesrva = (DWORD)pLaswSectionHeaderBase->VirtualAddress + (DWORD)start - (DWORD)starttest; 	LPVOID namneaddrstart = start; 	DWORD AddressOfNamessize = exportDIRECTORYfilebuffer->NumberOfNames * 4 ; 	 	DWORD* tureAddressOfNames = (DWORD*)((DWORD)pFileBuffer + RVAtoFOA (exportDIRECTORYfilebuffer->AddressOfNames, pFileBuffer)); 	memcpy (start, tureAddressOfNames, AddressOfNamessize); 	 	start = (LPVOID)((DWORD)start + AddressOfNamessize); 	printf ("******************************拷贝名字表的名字\n" ); 	for  (int  i = 0 ; i < exportDIRECTORYfilebuffer->NumberOfNames; i++) { 		DWORD* tureAddressOfNames = (DWORD*)((DWORD)pFileBuffer + RVAtoFOA (exportDIRECTORYfilebuffer->AddressOfNames, pFileBuffer)) + i; 		DWORD* tureAddressOfNames2 = (DWORD*)((DWORD)namneaddrstart) + i; 		printf ("导出表函数名字表文件中地址的值:%x,拷贝后的表里地址的值%x\n" , *tureAddressOfNames, *tureAddressOfNames2); 		printf ("导出表函数名字表文件地址:%x\n" , RVAtoFOA ((DWORD)*tureAddressOfNames, pFileBuffer)); 		PCHAR Nameaddr = (PCHAR)((BYTE*)RVAtoFOA ((DWORD)*tureAddressOfNames, pFileBuffer) + (DWORD)pFileBuffer); 		 		memcpy (start, Nameaddr, strlen (Nameaddr)); 		 		DWORD namestartyz = (DWORD)start - (DWORD)pFileBuffer; 		 		DWORD addrofnamerva = (DWORD)pLaswSectionHeaderBase->VirtualAddress + (DWORD)start - (DWORD)starttest; 		*tureAddressOfNames2 = addrofnamerva; 		start = (LPVOID)((DWORD)start + strlen (Nameaddr)); 		if  (i == 0 ) 		{ 			addrofnamervafirst = addrofnamerva; 		} 		memset (start, 0x00 , 1 ); 		start = (LPVOID)((DWORD)start + 1 ); 		printf ("导出表函数大小%x的%x名字:%s,验证修改后的foa正确性%x,对比现在的foa:%x\n" , strlen (Nameaddr),i, Nameaddr,RVAtoFOA (*tureAddressOfNames2,pFileBuffer), namestartyz); 	} 	printf ("******************************\n" ); 	 	PIMAGE_EXPORT_DIRECTORY exportDIRECTORYfilebuffercopy = (PIMAGE_EXPORT_DIRECTORY) start; 	memcpy (start, (LPVOID)exportDIRECTORYfilebuffer, sizeof  (IMAGE_EXPORT_DIRECTORY)); 	start = (LPVOID)((DWORD)start + sizeof  (IMAGE_EXPORT_DIRECTORY)); 	 	 	 	exportDIRECTORYfilebuffercopy->AddressOfFunctions = AddressOfFunctionsrva; 	exportDIRECTORYfilebuffercopy->AddressOfNameOrdinals = AddressOfNameOrdinalsrva; 	exportDIRECTORYfilebuffercopy->AddressOfNames = AddressOfNamesrva; 	 	 	pNtHeaders->OptionalHeader.DataDirectory[0 ].VirtualAddress = (DWORD)pLaswSectionHeaderBase->VirtualAddress+(DWORD)exportDIRECTORYfilebuffercopy -(DWORD)starttest; 	return  pFileBuffer; }
 
效果
 
这个移动后是可以正常调用的
  导入表和IAT表 
导入表结构
1 2 3 4 5 6 7 8 9 10 11 12 	typedef  struct  _IMAGE_IMPORT_DESCRIPTOR  { 							 	    union  { 							 	        DWORD   Characteristics;           							 	        DWORD   OriginalFirstThunk;     	    };							 	    DWORD   TimeDateStamp;         	    DWORD   ForwarderChain;          	    DWORD   Name;							 	    DWORD   FirstThunk;            	} IMAGE_IMPORT_DESCRIPTOR;							 	typedef  IMAGE_IMPORT_DESCRIPTOR UNALIGNED *PIMAGE_IMPORT_DESCRIPTOR;							 `
 
OriginalFirstThunk,FirstThunk是指向第一个IMAGE_THUNK_DATA32的rva,遍历到0算此dll结束 
MAGE_THUNK_DATA32结构,4字节,看成一个dword就行
1 2 3 4 5 6 7 8 9 10 typedef  struct  _IMAGE_THUNK_DATA32  { 									     union  { 						         PBYTE  ForwarderString;									         PDWORD Function;									         DWORD Ordinal;						         PIMAGE_IMPORT_BY_NAME  AddressOfData;						     } u1;									 } IMAGE_THUNK_DATA32;									typedef  IMAGE_THUNK_DATA32 * PIMAGE_THUNK_DATA32;									
 
IMAGE_IMPORT_BY_NAME结构
1 2 3 4 5 6 typedef  struct  _IMAGE_IMPORT_BY_NAME  { 												     WORD    Hint;						     BYTE    Name[1 ];						 } IMAGE_IMPORT_BY_NAME, *PIMAGE_IMPORT_BY_NAME;												 												
 
  程序解析 
流程-通过可选头的数据目录的第二个[1]找到其数据目录数据->找到Virtualaddressrva(转换foa)->找到导入表起始地址->遍历导入表->主要遍历导入表的Name,OriginalFirstThunk,FirstThunk,遍历OriginalFirstThunk,FirstThunk时,先转foa,这个foa指向的位置是_IMAGE_THUNK_DATA32结构,看成DWORD即可->判断高位,为0则是指向IMAGE_IMPORT_BY_NAME结构的rva,需要转foa
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 void  showDESCRIPTOR (LPVOID pFileBuffer)  { 	PIMAGE_IMPORT_DESCRIPTOR pDescriptor = NULL ; 	PIMAGE_NT_HEADERS pNtHeaders = NULL ; 	PIMAGE_IMPORT_BY_NAME pImportbyname = NULL ; 	PIMAGE_IMPORT_DESCRIPTOR pDescriptorture = NULL ; 	PIMAGE_IMPORT_BY_NAME namefuction = NULL ; 	pNtHeaders = FileToNtHeader (pFileBuffer); 	 	pDescriptor = (PIMAGE_IMPORT_DESCRIPTOR) pNtHeaders->OptionalHeader.DataDirectory[1 ].VirtualAddress; 	 	pDescriptorture = PIMAGE_IMPORT_DESCRIPTOR  (RVAtoFOA ((DWORD)pDescriptor,pFileBuffer)+(DWORD)pFileBuffer); 	 	 	while  (*((DWORD*)pDescriptorture) != 0 ) 	{ 		printf ("******************************\n" ); 		 		printf ("dll名字为%s\n" , (RVAtoFOA (pDescriptorture->Name, pFileBuffer) + (DWORD)pFileBuffer)); 		 		 		DWORD* startThunk =(DWORD*) (RVAtoFOA ((DWORD)pDescriptorture->OriginalFirstThunk, pFileBuffer) + (DWORD)pFileBuffer); 		printf ("OriginalFirstThunk内容:\n" ); 		while  (*startThunk != 0 ) 		{ 			if  ((* startThunk & 0x80000000 ) == 0 ) 			{ 				namefuction = (PIMAGE_IMPORT_BY_NAME)(RVAtoFOA (*startThunk, pFileBuffer)+(DWORD)pFileBuffer); 				PCHAR Namefu = (PCHAR)namefuction->Name; 				printf ("IMAGE_IMPORT_BY_NAME地址%x,函数名字:%s\n" , *startThunk,Namefu); 			} 			else  { 				printf ("函数的序号%x\n" , *startThunk & 0x7FFFFFFF ); 			} 			 			startThunk = startThunk + 1 ; 		} 		 		DWORD* startFirstThunk = (DWORD*)(RVAtoFOA ((DWORD)pDescriptorture->FirstThunk, pFileBuffer) + (DWORD)pFileBuffer); 		printf ("FirstThunk内容:\n" ); 		while  (*startFirstThunk != 0 ) 		{ 			if  ((*startFirstThunk & 0x80000000 ) == 0 ) 			{ 				namefuction = (PIMAGE_IMPORT_BY_NAME)(RVAtoFOA (*startFirstThunk, pFileBuffer) + (DWORD)pFileBuffer); 				PCHAR Namefu = (PCHAR)namefuction->Name; 				printf ("IMAGE_IMPORT_BY_NAME地址%x,函数名字:%s\n" , *startFirstThunk, Namefu); 			} 			else  { 				printf ("函数的序号%x\n" , *startFirstThunk & 0x7FFFFFFF ); 			} 			 			startFirstThunk = startFirstThunk + 1 ; 		} 		pDescriptorture = pDescriptorture + 1 ; 	} }
 
 
  绑定导入表 
PE加载EXE相关的DLL时,首先会根据IMAGE_IMPORT_DESCRIPTOR结构 中的TimeDateStamp来判断是否要重新										 
计算IAT表中的地址。											 
TimeDateStamp == 0  未绑定										 
TimeDateStamp == -1 已绑定 真正的绑定时间为IMAGE_BOUND_IMPORT_DESCRIPTOR的TimeDateStamp
绑定导入表内的时间戳用于判断dll是否已经更新,如果时间戳和dll的不一样,则重新计算IAT表
结构
1 2 3 4 5 6 7 8 9 10 11 12 13 14 typedef  struct  _IMAGE_BOUND_IMPORT_DESCRIPTOR  { 								     DWORD   TimeDateStamp;								     WORD    OffsetModuleName;     WORD    NumberOfModuleForwarderRefs;								 } IMAGE_BOUND_IMPORT_DESCRIPTOR,  *PIMAGE_BOUND_IMPORT_DESCRIPTOR;								 								typedef  struct  _IMAGE_BOUND_FORWARDER_REF  { 								     DWORD   TimeDateStamp;								     WORD    OffsetModuleName;								     WORD    Reserved;								 } IMAGE_BOUND_FORWARDER_REF, *PIMAGE_BOUND_FORWARDER_REF;								 								
 
代码编写
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 void  showBOUND_IMPORT_DESCRIPTOR (LPVOID pFileBuffer)  { 	PIMAGE_NT_HEADERS pNtHeaders = NULL ; 	PIMAGE_BOUND_IMPORT_DESCRIPTOR pDESCRIPTOR = NULL ; 	PIMAGE_BOUND_FORWARDER_REF pFORWARDER_REF = NULL ; 	printf ("******************************\n" ); 	printf ("********绑定导入表解析********\n" ); 	pNtHeaders = FileToNtHeader (pFileBuffer); 	if  (pNtHeaders->OptionalHeader.DataDirectory[11 ].VirtualAddress == 0 ) { 		return ; 	} 	pDESCRIPTOR = (PIMAGE_BOUND_IMPORT_DESCRIPTOR)(RVAtoFOA (pNtHeaders->OptionalHeader.DataDirectory[11 ].VirtualAddress, pFileBuffer)+(DWORD)pFileBuffer); 	DWORD startoffer = (DWORD)pDESCRIPTOR; 	PCHAR name = NULL ; 	while  (*(DWORD*)pDESCRIPTOR != 0 ) 	{ 		name = (PCHAR)startoffer + pDESCRIPTOR->OffsetModuleName; 		printf ("时间戳%x名字%s,NumberOfModule数量%x\n" , pDESCRIPTOR->TimeDateStamp,name,pDESCRIPTOR->NumberOfModuleForwarderRefs); 		if  (pDESCRIPTOR->NumberOfModuleForwarderRefs != 0 ) 		{ 			printf ("存在NumberOfModuleForwarderRefs结构:\n" ); 			pDESCRIPTOR = pDESCRIPTOR + 1 ; 			for  (int  i= 0 ; i < pDESCRIPTOR->NumberOfModuleForwarderRefs; i++) 			{ 				PIMAGE_BOUND_FORWARDER_REF pFORWARDER_REF = (PIMAGE_BOUND_FORWARDER_REF)pDESCRIPTOR; 				name = (PCHAR)startoffer + pFORWARDER_REF->OffsetModuleName; 				printf ("时间戳%x名字%s\n" , pFORWARDER_REF->TimeDateStamp, name); 				pDESCRIPTOR = pDESCRIPTOR + 1 ; 			} 			printf ("NumberOfModuleForwarderRefs结构结束\n" ); 		} 		pDESCRIPTOR = pDESCRIPTOR + 1 ; 	} 	 	 }
 
 
  导入表注入 
dll的main方法是添加和去除时调用,使用一个在加载和退出时调用的messagebox函数的dll验证注入是否成功
此处使用的dll名字InjectDll.dll,函数名字:ExportFunction,git目录中有这个dll
注意修改int表,iat表,导入表的结尾,要多一个这个结构,并且全是0,特别是导入表,注意大小是0x14h 
步骤:
1.新加一个节(可以找节的空白处添加,注意计算添加数据大小,这里我直接添加新节了)
2.把所有导入表copy到这个节数据端,**(这里有坑,如果按照OptionalHeader.DataDirectory[1].Size的大小复制导入表,因为这个大小其实是最后一个导入表+0x14个00的大小,所以复制的位置应该是size-0x14的位置,复制完后再填充一个0x14的00)**然后新加一个导入表结构,
3.新加IAT,INT表结构,因为这里函数名只有一个,所以这两个结构都要加8字节就行(最后4个字节是00),记得赋值给OriginalFirstThunk和FirstThunk 
4.新加IMAGE_IMPORT_BY_NAME结构,函数名字拷贝到IMAGE_IMPORT_BY_NAME->Name,这个结构的起始地址赋值给IAT,INT表。
5.复制dll名字,起始地址**(rva)**赋值给新加的导入表->Name。
6.修正修正IMAGE_DATA_DIRECTORY结构的VirtualAddress 和Size 
程序实现,虽然好像写的很拉,调了2小时,最后还是成功了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 LPVOID injectDESCRIPTOR (LPVOID pFileBuffer)   { 	PIMAGE_IMPORT_DESCRIPTOR pDescriptor = NULL ; 	PIMAGE_NT_HEADERS pNtHeaders = NULL ; 	PIMAGE_IMPORT_BY_NAME pImportbyname = NULL ; 	PIMAGE_IMPORT_DESCRIPTOR pDescriptorture = NULL ; 	PIMAGE_IMPORT_BY_NAME namefuction = NULL ; 	pNtHeaders = FileToNtHeader (pFileBuffer); 	 	 	pNtHeaders = FileToNtHeader (pFileBuffer); 	DWORD sizeofDescriper = pNtHeaders->OptionalHeader.DataDirectory[1 ].Size; 	 	pDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)pNtHeaders->OptionalHeader.DataDirectory[1 ].VirtualAddress; 	 	pDescriptorture = PIMAGE_IMPORT_DESCRIPTOR (RVAtoFOA ((DWORD)pDescriptor, pFileBuffer) + (DWORD)pFileBuffer); 	 	 	 	 	 	 	PIMAGE_SECTION_HEADER pSectionHeaderBase = NULL ; 	LPVOID start = NULL ; 	PIMAGE_EXPORT_DIRECTORY exportDIRECTORY = NULL ; 	pNtHeaders = FileToNtHeader (pFileBuffer); 	pSectionHeaderBase = LocateSectionBase (pFileBuffer); 	 	 	PIMAGE_SECTION_HEADER pLaswSectionHeaderBase = PIMAGE_SECTION_HEADER ((BYTE*)pSectionHeaderBase + (DWORD)(0x28  * (pNtHeaders->FileHeader.NumberOfSections - 1 ))); 	 	start = (LPVOID)(pLaswSectionHeaderBase->PointerToRawData + (DWORD)pFileBuffer); 	LPVOID starttest = (LPVOID)(pLaswSectionHeaderBase->PointerToRawData + (DWORD)pFileBuffer); 	 	memcpy (start, pDescriptorture, sizeofDescriper); 	start = (LPVOID)((DWORD)start + sizeofDescriper); 	start = (LPVOID)((DWORD)start - 0x14 ); 	 	PIMAGE_IMPORT_DESCRIPTOR pNewdescripitor = (PIMAGE_IMPORT_DESCRIPTOR)start; 	memcpy (start,starttest,0x14 ); 	start = (LPVOID)((DWORD)start + 2 *0x14 ); 	 	 	DWORD* startINT = (DWORD*)start; 	pNewdescripitor->OriginalFirstThunk = (DWORD)pLaswSectionHeaderBase->VirtualAddress + (DWORD)start - (DWORD)starttest; 	start = startINT + 2 ; 	 	DWORD* startIAT = (DWORD*)start; 	pNewdescripitor->FirstThunk = (DWORD)pLaswSectionHeaderBase->VirtualAddress + (DWORD)start - (DWORD)starttest; 	start = startIAT + 2 ; 	 	PIMAGE_IMPORT_BY_NAME Importbyname = (PIMAGE_IMPORT_BY_NAME)start; 	DWORD ImportbynameRva = (DWORD)pLaswSectionHeaderBase->VirtualAddress + (DWORD)start - (DWORD)starttest; 	 	*startINT = ImportbynameRva; 	*startIAT = ImportbynameRva; 	 	memcpy (Importbyname->Name, "ExportFunction" , sizeof  ("ExportFunction" )); 	 	start = (LPVOID)((DWORD)start + 2  + sizeof  ("ExportFunction" ) ); 	const  char * dllname =NULL ; 	dllname = "InjectDll.dll" ; 	 	PCHAR dllName = (PCHAR)start; 	memcpy (dllName, "InjectDll.dll" , sizeof  ("InjectDll.dll" )); 	DWORD dllnameRva = (DWORD)pLaswSectionHeaderBase->VirtualAddress + (DWORD)start - (DWORD)starttest; 	start = (LPVOID)((DWORD)start  + sizeof  ("InjectDll.dll" ) ); 	 	pNewdescripitor->Name = dllnameRva; 	 	pNtHeaders->OptionalHeader.DataDirectory[1 ].VirtualAddress = (DWORD)starttest-(DWORD)pFileBuffer; 	pNtHeaders->OptionalHeader.DataDirectory[1 ].Size = sizeofDescriper + sizeof  (_IMAGE_EXPORT_DIRECTORY); 	 	 	return  pFileBuffer; }