MemLoadLibrary.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539
  1. #include "StdAfx.h"
  2. #include "MemLoadLibrary.h"
  3. #include "DbgHelp.h"
  4. CMemLoadLibrary::CMemLoadLibrary(void)
  5. {
  6. isLoadOk = FALSE;
  7. pImageBase = NULL;
  8. pDllMain = NULL;
  9. }
  10. CMemLoadLibrary::~CMemLoadLibrary(void)
  11. {
  12. if(isLoadOk)
  13. {
  14. ASSERT(pImageBase != NULL);
  15. ASSERT(pDllMain != NULL);
  16. //脱钩,准备卸载dll
  17. pDllMain((HINSTANCE)pImageBase,DLL_PROCESS_DETACH,0);
  18. VirtualFree((LPVOID)pImageBase, 0, MEM_RELEASE);
  19. }
  20. }
  21. #if 1
  22. //MemLoadLibrary函数从内存缓冲区数据中加载一个dll到当前进程的地址空间,缺省位置0x10000000
  23. //返回值: 成功返回TRUE , 失败返回FALSE
  24. //lpFileData: 存放dll文件数据的缓冲区
  25. //DataLength: 缓冲区中数据的总长度
  26. BOOL CMemLoadLibrary::MemLoadLibrary(void *lpFileData, int DataLength)
  27. {
  28. if (pImageBase != NULL)
  29. {
  30. return FALSE; //已经加载一个dll,还没有释放,不能加载新的dll
  31. }
  32. //检查数据有效性,并初始化
  33. if (!CheckDataValide(lpFileData, DataLength))
  34. {
  35. return FALSE;
  36. }
  37. //计算所需的加载空间
  38. int ImageSize = CalcTotalImageSize();
  39. if (ImageSize == 0)
  40. {
  41. return FALSE;
  42. }
  43. // 分配虚拟内存
  44. void *pMemoryAddress = VirtualAlloc((LPVOID)NULL, ImageSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
  45. if (pMemoryAddress == NULL)
  46. {
  47. return FALSE;
  48. }
  49. else
  50. {
  51. CopyDllDatas(pMemoryAddress, lpFileData); //复制dll数据,并对齐每个段
  52. //重定位信息
  53. if (pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress > 0
  54. && pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size > 0)
  55. {
  56. DoRelocation(pMemoryAddress);
  57. }
  58. //填充引入地址表
  59. if (!FillRavAddress(pMemoryAddress)) //修正引入地址表失败
  60. {
  61. VirtualFree(pMemoryAddress, 0, MEM_RELEASE);
  62. return FALSE;
  63. }
  64. //修改页属性。应该根据每个页的属性单独设置其对应内存页的属性。这里简化一下。
  65. //统一设置成一个属性PAGE_EXECUTE_READWRITE
  66. unsigned long old;
  67. VirtualProtect(pMemoryAddress, ImageSize, PAGE_EXECUTE_READWRITE, &old);
  68. }
  69. //修正基地址
  70. pNTHeader->OptionalHeader.ImageBase = (DWORD)pMemoryAddress;
  71. //接下来要调用一下dll的入口函数,做初始化工作。
  72. pDllMain = (ProcDllMain)(pNTHeader->OptionalHeader.AddressOfEntryPoint + (DWORD) pMemoryAddress);
  73. LPVOID lpReserved = 0;
  74. BOOL InitResult = pDllMain((HINSTANCE)pMemoryAddress, DLL_PROCESS_ATTACH, lpReserved);
  75. if (!InitResult) //初始化失败
  76. {
  77. pDllMain((HINSTANCE)pMemoryAddress, DLL_PROCESS_DETACH, 0);
  78. VirtualFree(pMemoryAddress, 0, MEM_RELEASE);
  79. pDllMain = NULL;
  80. return FALSE;
  81. }
  82. isLoadOk = TRUE;
  83. pImageBase = (DWORD)pMemoryAddress;
  84. return TRUE;
  85. }
  86. //MemGetProcAddress函数从dll中获取指定函数的地址
  87. //返回值: 成功返回函数地址 , 失败返回NULL
  88. //lpProcName: 要查找函数的名字或者序号
  89. FARPROC CMemLoadLibrary::MemGetProcAddress(LPCSTR lpProcName)
  90. {
  91. if (pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress == 0 ||
  92. pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size == 0)
  93. {
  94. return NULL;
  95. }
  96. if (!isLoadOk)
  97. {
  98. return NULL;
  99. }
  100. DWORD OffsetStart = pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
  101. DWORD Size = pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size;
  102. PIMAGE_EXPORT_DIRECTORY pExport = (PIMAGE_EXPORT_DIRECTORY)((DWORD)pImageBase + pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
  103. int iBase = pExport->Base;
  104. int iNumberOfFunctions = pExport->NumberOfFunctions;
  105. int iNumberOfNames = pExport->NumberOfNames; //<= iNumberOfFunctions
  106. LPDWORD pAddressOfFunctions = (LPDWORD)(pExport->AddressOfFunctions + pImageBase);
  107. LPWORD pAddressOfOrdinals = (LPWORD)(pExport->AddressOfNameOrdinals + pImageBase);
  108. LPDWORD pAddressOfNames = (LPDWORD)(pExport->AddressOfNames + pImageBase);
  109. int iOrdinal = -1;
  110. if (((DWORD)lpProcName & 0xFFFF0000) == 0) //IT IS A ORDINAL!
  111. {
  112. iOrdinal = (DWORD)lpProcName & 0x0000FFFF - iBase;
  113. }
  114. else //use name
  115. {
  116. int iFound = -1;
  117. for (int i = 0; i < iNumberOfNames; i++)
  118. {
  119. char *pName = (char * )(pAddressOfNames[i] + pImageBase);
  120. if (strcmp(pName, lpProcName) == 0)
  121. {
  122. iFound = i;
  123. break;
  124. }
  125. }
  126. if (iFound >= 0)
  127. {
  128. iOrdinal = (int)(pAddressOfOrdinals[iFound]);
  129. }
  130. }
  131. if (iOrdinal < 0 || iOrdinal >= iNumberOfFunctions )
  132. {
  133. return NULL;
  134. }
  135. else
  136. {
  137. DWORD pFunctionOffset = pAddressOfFunctions[iOrdinal];
  138. if (pFunctionOffset > OffsetStart && pFunctionOffset < (OffsetStart + Size)) //maybe Export Forwarding
  139. {
  140. return NULL;
  141. }
  142. else
  143. {
  144. return (FARPROC)(pFunctionOffset + pImageBase);
  145. }
  146. }
  147. }
  148. // 重定向PE用到的地址
  149. void CMemLoadLibrary::DoRelocation( void *NewBase)
  150. {
  151. /* 重定位表的结构:
  152. // DWORD sectionAddress, DWORD size (包括本节需要重定位的数据)
  153. // 例如 1000节需要修正5个重定位数据的话,重定位表的数据是
  154. // 00 10 00 00 14 00 00 00 xxxx xxxx xxxx xxxx xxxx 0000
  155. // ----------- ----------- ----
  156. // 给出节的偏移 总尺寸=8+6*2 需要修正的地址 用于对齐4字节
  157. // 重定位表是若干个相连,如果address 和 size都是0 表示结束
  158. // 需要修正的地址是12位的,高4位是形态字,intel cpu下是3
  159. */
  160. //假设NewBase是0x600000,而文件中设置的缺省ImageBase是0x400000,则修正偏移量就是0x200000
  161. DWORD Delta = (DWORD)NewBase - pNTHeader->OptionalHeader.ImageBase;
  162. //注意重定位表的位置可能和硬盘文件中的偏移地址不同,应该使用加载后的地址
  163. PIMAGE_BASE_RELOCATION pLoc = (PIMAGE_BASE_RELOCATION)((unsigned long)NewBase
  164. + pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress);
  165. while ((pLoc->VirtualAddress + pLoc->SizeOfBlock) != 0) //开始扫描重定位表
  166. {
  167. WORD *pLocData = (WORD *)((int)pLoc + sizeof(IMAGE_BASE_RELOCATION));
  168. //计算本节需要修正的重定位项(地址)的数目
  169. int NumberOfReloc = (pLoc->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(WORD);
  170. for ( int i = 0 ; i < NumberOfReloc; i++)
  171. {
  172. if ( (DWORD)(pLocData[i] & 0xF000) == 0x00003000) //这是一个需要修正的地址
  173. {
  174. // 举例:
  175. // pLoc->VirtualAddress = 0x1000;
  176. // pLocData[i] = 0x313E; 表示本节偏移地址0x13E处需要修正
  177. // 因此 pAddress = 基地址 + 0x113E
  178. // 里面的内容是 A1 ( 0c d4 02 10) 汇编代码是: mov eax , [1002d40c]
  179. // 需要修正1002d40c这个地址
  180. DWORD *pAddress = (DWORD *)((unsigned long)NewBase + pLoc->VirtualAddress + (pLocData[i] & 0x0FFF));
  181. *pAddress += Delta;
  182. }
  183. }
  184. //转移到下一个节进行处理
  185. pLoc = (PIMAGE_BASE_RELOCATION)((DWORD)pLoc + pLoc->SizeOfBlock);
  186. }
  187. }
  188. //填充引入地址表
  189. BOOL CMemLoadLibrary::FillRavAddress(void *pImageBase)
  190. {
  191. // 引入表实际上是一个 IMAGE_IMPORT_DESCRIPTOR 结构数组,全部是0表示结束
  192. // 数组定义如下:
  193. //
  194. // DWORD OriginalFirstThunk; // 0表示结束,否则指向未绑定的IAT结构数组
  195. // DWORD TimeDateStamp;
  196. // DWORD ForwarderChain; // -1 if no forwarders
  197. // DWORD Name; // 给出dll的名字
  198. // DWORD FirstThunk; // 指向IAT结构数组的地址(绑定后,这些IAT里面就是实际的函数地址)
  199. int i;
  200. #if 1
  201. // 导入表地址;
  202. unsigned long Offset = pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress ;
  203. if (Offset == 0)
  204. {
  205. return TRUE; //No Import Table
  206. }
  207. // 得到导入表;
  208. PIMAGE_IMPORT_DESCRIPTOR pImportTable = (PIMAGE_IMPORT_DESCRIPTOR)((unsigned long) pImageBase + Offset);
  209. #if 1
  210. while (pImportTable->Characteristics != 0 )
  211. {
  212. PIMAGE_THUNK_DATA pRealIAT = (PIMAGE_THUNK_DATA)((unsigned long)pImageBase + pImportTable->FirstThunk);
  213. PIMAGE_THUNK_DATA pOriginalIAT = (PIMAGE_THUNK_DATA)((unsigned long)pImageBase + pImportTable->OriginalFirstThunk);
  214. //获取dll的名字
  215. TCHAR buf[256]; //dll name;
  216. BYTE *pName = (BYTE *)((unsigned long)pImageBase + pImportTable->Name);
  217. for (i = 0; i < 256; i++)
  218. {
  219. if (pName[i] == 0)
  220. {
  221. break;
  222. }
  223. buf[i] = pName[i];
  224. }
  225. if (i >= 256)
  226. {
  227. return FALSE; // bad dll name
  228. }
  229. else
  230. {
  231. buf[i] = 0;
  232. }
  233. HMODULE hDll = GetModuleHandle(buf);
  234. if (hDll == NULL)
  235. {
  236. hDll = LoadLibrary(buf);
  237. }
  238. if (hDll == NULL)
  239. {
  240. return FALSE; //NOT FOUND DLL
  241. //continue;
  242. }
  243. //获取DLL中每个导出函数的地址,填入IAT
  244. //每个IAT结构是 :
  245. // union { PBYTE ForwarderString;
  246. // PDWORD Function;
  247. // DWORD Ordinal;
  248. // PIMAGE_IMPORT_BY_NAME AddressOfData;
  249. // } u1;
  250. // 长度是一个DWORD ,正好容纳一个地址。
  251. for (i = 0; ; i++)
  252. {
  253. if (pOriginalIAT[i].u1.Function == 0)
  254. {
  255. break;
  256. }
  257. FARPROC lpFunction = NULL;
  258. if (pOriginalIAT[i].u1.Ordinal & IMAGE_ORDINAL_FLAG) //这里的值给出的是导出序号
  259. {
  260. lpFunction = GetProcAddress(hDll, (LPCSTR)(pOriginalIAT[i].u1.Ordinal & 0x0000FFFF));
  261. }
  262. else //按照名字导入
  263. {
  264. //获取此IAT项所描述的函数名称
  265. PIMAGE_IMPORT_BY_NAME pByName = (PIMAGE_IMPORT_BY_NAME)
  266. ((DWORD)pImageBase + (DWORD)(pOriginalIAT[i].u1.AddressOfData));
  267. // if(pByName->Hint !=0)
  268. // lpFunction = GetProcAddress(hDll, (LPCSTR)pByName->Hint);
  269. // else
  270. lpFunction = GetProcAddress(hDll, (char *)pByName->Name);
  271. }
  272. if (lpFunction != NULL) //找到了!
  273. {
  274. pRealIAT[i].u1.Function = (DWORD)lpFunction;//(PDWORD) lpFunction;
  275. }
  276. else
  277. {
  278. return FALSE;
  279. }
  280. }
  281. //move to next
  282. pImportTable = (PIMAGE_IMPORT_DESCRIPTOR)( (DWORD)pImportTable + sizeof(IMAGE_IMPORT_DESCRIPTOR));
  283. }
  284. #else
  285. //现在来到了导入表的面前:IMAGE_IMPORT_DESCRIPTOR 数组(以0元素为终止)
  286. //定义表示数组结尾的null元素!
  287. IMAGE_IMPORT_DESCRIPTOR null_iid;
  288. IMAGE_THUNK_DATA null_thunk;
  289. memset(&null_iid, 0, sizeof(null_iid));
  290. memset(&null_thunk, 0, sizeof(null_thunk));
  291. for ( int i = 0; memcmp(pImportTable + i, &null_iid, sizeof(null_iid)) != NULL; i++ )
  292. {
  293. BYTE *pName = (BYTE *)((unsigned long)pImageBase + pImportTable[i].Name);
  294. HMODULE hDll = GetModuleHandle((LPCTSTR)pName);
  295. if (hDll == NULL)
  296. {
  297. hDll = LoadLibrary((LPCTSTR)pName);
  298. }
  299. if (hDll == NULL)
  300. {
  301. //return FALSE; //NOT FOUND DLL
  302. continue;
  303. }
  304. //LPCSTR: 就是 const char*
  305. LPCSTR szDllName = (LPCSTR)ImageRvaToVa(
  306. pNTHeader,
  307. (PVOID)(unsigned long)pImageBase,
  308. pImportTable[i].Name, //DLL名称的RVA
  309. NULL);
  310. //现在去看看从该DLL中引入了哪些函数
  311. //我们来到该DLL的 IMAGE_TRUNK_DATA 数组(IAT:导入地址表)前面
  312. PIMAGE_THUNK_DATA32 pThunk = (PIMAGE_THUNK_DATA32)ImageRvaToVa(
  313. pNTHeader, (PVOID)(unsigned long)pImageBase,
  314. pImportTable[i].OriginalFirstThunk, //【注意】这里使用的是OriginalFirstThunk
  315. NULL);
  316. for(int j=0; memcmp(pThunk+j, &null_thunk, sizeof(null_thunk))!=0; j++)
  317. {
  318. //这里通过RVA的最高位判断函数的导入方式,
  319. //如果最高位为1,按序号导入,否则按名称导入
  320. if(pThunk[j].u1.AddressOfData & IMAGE_ORDINAL_FLAG32)
  321. {
  322. printf("\t [%d] \t %ld \t 按序号导入\n", j, pThunk[j].u1.AddressOfData & 0xffff);
  323. }
  324. else
  325. {
  326. //按名称导入,我们再次定向到函数序号和名称
  327. //注意其地址不能直接用,因为仍然是RVA!
  328. PIMAGE_IMPORT_BY_NAME pFuncName = (PIMAGE_IMPORT_BY_NAME)ImageRvaToVa(
  329. pNTHeader, (PVOID)(unsigned long)pImageBase,
  330. pThunk[j].u1.AddressOfData,
  331. NULL);
  332. printf("\t [%d] \t %ld \t %s\n", j, pFuncName->Hint, pFuncName->Name);
  333. }
  334. }
  335. }
  336. #endif
  337. #else
  338. // 导出表的虚拟地址;
  339. unsigned long Offset = pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress ;
  340. if (Offset == 0)
  341. { // 没有导出表;
  342. return TRUE;
  343. }
  344. // 得到导出表;
  345. PIMAGE_EXPORT_DIRECTORY pExportTable = (PIMAGE_EXPORT_DIRECTORY)((unsigned long) pImageBase + Offset);
  346. // 得到函数地址列表;
  347. PDWORD arrayOfFunuctionAddress = (PDWORD)((unsigned long)pImageBase + pExportTable->AddressOfFunctions);
  348. // 得到函数名称列表;
  349. PDWORD arrayOfFunuctionNames = (PDWORD)((unsigned long)pImageBase + pExportTable->AddressOfNames);
  350. // 得到函数序号;
  351. PDWORD arrayOfFunctionOrdinals = (PDWORD)((unsigned long)pImageBase + pExportTable->AddressOfNameOrdinals);
  352. // 导出表基址;
  353. DWORD BaseExportTable = pExportTable->Base;
  354. // 循环导出表;
  355. for ( DWORD i = 0; i < pExportTable->NumberOfNames; i++ )
  356. {
  357. // 得到函数名;
  358. CHAR *pfunctionName = (CHAR*)((unsigned long)pImageBase + arrayOfFunuctionNames[i]);
  359. if ( pfunctionName )
  360. {
  361. OutputDebugStringA(pfunctionName);
  362. OutputDebugStringA("\n");
  363. }
  364. }
  365. #endif
  366. return TRUE;
  367. }
  368. //CheckDataValide函数用于检查缓冲区中的数据是否有效的dll文件
  369. //返回值: 是一个可执行的dll则返回TRUE,否则返回FALSE。
  370. //lpFileData: 存放dll数据的内存缓冲区
  371. //DataLength: dll文件的长度
  372. BOOL CMemLoadLibrary::CheckDataValide(void *lpFileData, int DataLength)
  373. {
  374. //检查长度
  375. if (DataLength < sizeof(IMAGE_DOS_HEADER))
  376. {
  377. return FALSE;
  378. }
  379. pDosHeader = (PIMAGE_DOS_HEADER)lpFileData; // DOS头
  380. //检查dos头的标记
  381. if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE)
  382. {
  383. return FALSE; //0x5A4D : MZ
  384. }
  385. //检查长度
  386. if ((DWORD)DataLength < (pDosHeader->e_lfanew + sizeof(IMAGE_NT_HEADERS)) )
  387. {
  388. return FALSE;
  389. }
  390. //取得pe头
  391. pNTHeader = (PIMAGE_NT_HEADERS)( (unsigned long)lpFileData + pDosHeader->e_lfanew); // PE头
  392. //检查pe头的合法性
  393. if (pNTHeader->Signature != IMAGE_NT_SIGNATURE)
  394. {
  395. return FALSE; //0x00004550 : PE00
  396. }
  397. if ((pNTHeader->FileHeader.Characteristics & IMAGE_FILE_DLL) == 0) //0x2000 : File is a DLL
  398. {
  399. return FALSE;
  400. }
  401. if ((pNTHeader->FileHeader.Characteristics & IMAGE_FILE_EXECUTABLE_IMAGE) == 0) //0x0002 : 指出文件可以运行
  402. {
  403. return FALSE;
  404. }
  405. if (pNTHeader->FileHeader.SizeOfOptionalHeader != sizeof(IMAGE_OPTIONAL_HEADER))
  406. {
  407. return FALSE;
  408. }
  409. //取得节表(段表)
  410. pSectionHeader = (PIMAGE_SECTION_HEADER)((int)pNTHeader + sizeof(IMAGE_NT_HEADERS));
  411. //验证每个节表的空间
  412. for (int i = 0; i < pNTHeader->FileHeader.NumberOfSections; i++)
  413. {
  414. if ((pSectionHeader[i].PointerToRawData + pSectionHeader[i].SizeOfRawData) > (DWORD)DataLength)
  415. {
  416. return FALSE;
  417. }
  418. }
  419. return TRUE;
  420. }
  421. //计算对齐边界
  422. int CMemLoadLibrary::GetAlignedSize(int Origin, int Alignment)
  423. {
  424. return (Origin + Alignment - 1) / Alignment * Alignment;
  425. }
  426. //计算整个dll映像文件的尺寸
  427. int CMemLoadLibrary::CalcTotalImageSize()
  428. {
  429. int Size;
  430. if (pNTHeader == NULL)
  431. {
  432. return 0;
  433. }
  434. int nAlign = pNTHeader->OptionalHeader.SectionAlignment; //段对齐字节数
  435. // 计算所有头的尺寸。包括dos, coff, pe头 和 段表的大小
  436. Size = GetAlignedSize(pNTHeader->OptionalHeader.SizeOfHeaders, nAlign);
  437. // 计算所有节的大小
  438. for (int i = 0; i < pNTHeader->FileHeader.NumberOfSections; ++i)
  439. {
  440. //得到该节的大小
  441. int CodeSize = pSectionHeader[i].Misc.VirtualSize ;
  442. int LoadSize = pSectionHeader[i].SizeOfRawData;
  443. int MaxSize = (LoadSize > CodeSize) ? (LoadSize) : (CodeSize);
  444. int SectionSize = GetAlignedSize(pSectionHeader[i].VirtualAddress + MaxSize, nAlign);
  445. if (Size < SectionSize)
  446. {
  447. Size = SectionSize; //Use the Max;
  448. }
  449. }
  450. return Size;
  451. }
  452. //CopyDllDatas函数将dll数据复制到指定内存区域,并对齐所有节
  453. //pSrc: 存放dll数据的原始缓冲区
  454. //pDest:目标内存地址
  455. void CMemLoadLibrary::CopyDllDatas(void *pDest, void *pSrc)
  456. {
  457. // 计算需要复制的PE头+段表字节数
  458. int HeaderSize = pNTHeader->OptionalHeader.SizeOfHeaders;
  459. int SectionSize = pNTHeader->FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER);
  460. int MoveSize = HeaderSize + SectionSize;
  461. //复制头和段信息
  462. memmove(pDest, pSrc, MoveSize);
  463. //复制每个节
  464. for (int i = 0; i < pNTHeader->FileHeader.NumberOfSections; ++i)
  465. {
  466. if (pSectionHeader[i].VirtualAddress == 0 || pSectionHeader[i].SizeOfRawData == 0)
  467. {
  468. continue;
  469. }
  470. // 定位该节在内存中的位置
  471. void *pSectionAddress = (void *)((unsigned long)pDest + pSectionHeader[i].VirtualAddress);
  472. // 复制段数据到虚拟内存
  473. memmove((void *)pSectionAddress,
  474. (void *)((DWORD)pSrc + pSectionHeader[i].PointerToRawData),
  475. pSectionHeader[i].SizeOfRawData);
  476. }
  477. //修正指针,指向新分配的内存
  478. //新的dos头
  479. pDosHeader = (PIMAGE_DOS_HEADER)pDest;
  480. //新的pe头地址
  481. pNTHeader = (PIMAGE_NT_HEADERS)((int)pDest + (pDosHeader->e_lfanew));
  482. //新的节表地址
  483. pSectionHeader = (PIMAGE_SECTION_HEADER)((int)pNTHeader + sizeof(IMAGE_NT_HEADERS));
  484. return ;
  485. }
  486. #endif