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; }