Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

978 lines
30 KiB

  1. //////////////////////////////////////////////////////////////////////////////
  2. //
  3. //
  4. // Copyright (C) Microsoft Corporation, 1996-2001.
  5. //
  6. // File: addsect.cpp
  7. //
  8. // Contents: Add a data section to a PE binary.
  9. //
  10. // History: 01-Nov-2000 GalenH Created from Detours setdll.cpp.
  11. //
  12. //////////////////////////////////////////////////////////////////////////////
  13. #define UNICODE
  14. #define _UNICODE
  15. #include <stdio.h>
  16. #include <stdlib.h>
  17. #include <windows.h>
  18. #define arrayof(a) (sizeof(a)/sizeof(a[0]))
  19. ///////////////////////////////////////////////////////////////////////////////
  20. //
  21. class CImage
  22. {
  23. public:
  24. CImage();
  25. ~CImage();
  26. public: // File Functions
  27. BOOL Read(HANDLE hFile);
  28. BOOL Check(PCSTR pszSection);
  29. BOOL Write(HANDLE hFile, PBYTE pbData, UINT cbData,
  30. PCSTR pszSection);
  31. BOOL Close();
  32. public: // Manipulation Functions
  33. PBYTE DataSet(PBYTE pbData, DWORD cbData);
  34. protected:
  35. BOOL CopyFileData(HANDLE hFile, DWORD nOldPos, DWORD cbData);
  36. BOOL ZeroFileData(HANDLE hFile, DWORD cbData);
  37. BOOL AlignFileData(HANDLE hFile);
  38. BOOL SizeOutputBuffer(DWORD cbData);
  39. PBYTE AllocateOutput(DWORD cbData, DWORD *pnVirtAddr);
  40. PVOID RvaToVa(DWORD nRva);
  41. DWORD RvaToFileOffset(DWORD nRva);
  42. DWORD FileAlign(DWORD nAddr);
  43. DWORD SectionAlign(DWORD nAddr);
  44. private:
  45. HANDLE m_hMap; // Read & Write
  46. PBYTE m_pMap; // Read & Write
  47. DWORD m_nNextFileAddr; // Write
  48. DWORD m_nNextVirtAddr; // Write
  49. BOOLEAN m_f64bit;
  50. IMAGE_FILE_HEADER m_FileHeader;
  51. IMAGE_OPTIONAL_HEADER64 m_OptionalHeader;
  52. IMAGE_SECTION_HEADER m_SectionHeaders[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
  53. DWORD m_nFileHeaderOffset;
  54. DWORD m_nOptionalHeaderOffset;
  55. DWORD m_nSectionsOffset;
  56. DWORD m_nSectionsEndOffset;
  57. DWORD m_nSectionsMaxCount;
  58. DWORD m_nExtraOffset;
  59. DWORD m_nFileSize;
  60. PBYTE m_pbOutputBuffer;
  61. DWORD m_cbOutputBuffer;
  62. DWORD m_nOutputVirtAddr;
  63. DWORD m_nOutputVirtSize;
  64. DWORD m_nOutputFileAddr;
  65. };
  66. //////////////////////////////////////////////////////////////////////////////
  67. //
  68. static inline DWORD Max(DWORD a, DWORD b)
  69. {
  70. return a > b ? a : b;
  71. }
  72. static inline DWORD Min(DWORD a, DWORD b)
  73. {
  74. return a < b ? a : b;
  75. }
  76. static inline DWORD Align(DWORD a, DWORD size)
  77. {
  78. size--;
  79. return (a + size) & ~size;
  80. }
  81. static inline DWORD QuadAlign(DWORD a)
  82. {
  83. return Align(a, 8);
  84. }
  85. //////////////////////////////////////////////////////////////////////////////
  86. //
  87. CImage::CImage()
  88. {
  89. m_hMap = NULL;
  90. m_pMap = NULL;
  91. m_nFileHeaderOffset = 0;
  92. m_nSectionsOffset = 0;
  93. m_pbOutputBuffer = NULL;
  94. m_cbOutputBuffer = 0;
  95. }
  96. CImage::~CImage()
  97. {
  98. Close();
  99. }
  100. BOOL CImage::Close()
  101. {
  102. if (m_pMap != NULL) {
  103. UnmapViewOfFile(m_pMap);
  104. m_pMap = NULL;
  105. }
  106. if (m_hMap) {
  107. CloseHandle(m_hMap);
  108. m_hMap = NULL;
  109. }
  110. if (m_pbOutputBuffer) {
  111. delete[] m_pbOutputBuffer;
  112. m_pbOutputBuffer = NULL;
  113. }
  114. return TRUE;
  115. }
  116. //////////////////////////////////////////////////////////////////////////////
  117. //
  118. BOOL CImage::SizeOutputBuffer(DWORD cbData)
  119. {
  120. if (m_cbOutputBuffer < cbData) {
  121. if (cbData < 1024) //65536
  122. cbData = 1024;
  123. cbData = FileAlign(cbData);
  124. PBYTE pOutput = new BYTE [cbData];
  125. if (pOutput == NULL) {
  126. SetLastError(ERROR_OUTOFMEMORY);
  127. return FALSE;
  128. }
  129. if (m_pbOutputBuffer) {
  130. CopyMemory(pOutput, m_pbOutputBuffer, m_cbOutputBuffer);
  131. delete[] m_pbOutputBuffer;
  132. m_pbOutputBuffer = NULL;
  133. }
  134. ZeroMemory(pOutput + m_cbOutputBuffer, cbData - m_cbOutputBuffer),
  135. m_pbOutputBuffer = pOutput;
  136. m_cbOutputBuffer = cbData;
  137. }
  138. return TRUE;
  139. }
  140. PBYTE CImage::AllocateOutput(DWORD cbData, DWORD *pnVirtAddr)
  141. {
  142. cbData = QuadAlign(cbData);
  143. PBYTE pbData = m_pbOutputBuffer + m_nOutputVirtSize;
  144. *pnVirtAddr = m_nOutputVirtAddr + m_nOutputVirtSize;
  145. m_nOutputVirtSize += cbData;
  146. if (m_nOutputVirtSize > m_cbOutputBuffer) {
  147. SetLastError(ERROR_OUTOFMEMORY);
  148. return NULL;
  149. }
  150. ZeroMemory(pbData, cbData);
  151. return pbData;
  152. }
  153. //////////////////////////////////////////////////////////////////////////////
  154. //
  155. DWORD CImage::FileAlign(DWORD nAddr)
  156. {
  157. return Align(nAddr, m_OptionalHeader.FileAlignment);
  158. }
  159. DWORD CImage::SectionAlign(DWORD nAddr)
  160. {
  161. return Align(nAddr, m_OptionalHeader.SectionAlignment);
  162. }
  163. //////////////////////////////////////////////////////////////////////////////
  164. //
  165. PVOID CImage::RvaToVa(DWORD nRva)
  166. {
  167. if (nRva == 0) {
  168. return NULL;
  169. }
  170. for (DWORD n = 0; n < m_FileHeader.NumberOfSections; n++) {
  171. DWORD vaStart = m_SectionHeaders[n].VirtualAddress;
  172. DWORD vaEnd = vaStart + m_SectionHeaders[n].SizeOfRawData;
  173. if (nRva >= vaStart && nRva < vaEnd) {
  174. return (PBYTE)m_pMap
  175. + m_SectionHeaders[n].PointerToRawData
  176. + nRva - m_SectionHeaders[n].VirtualAddress;
  177. }
  178. }
  179. return NULL;
  180. }
  181. DWORD CImage::RvaToFileOffset(DWORD nRva)
  182. {
  183. DWORD n;
  184. for (n = 0; n < m_FileHeader.NumberOfSections; n++) {
  185. DWORD vaStart = m_SectionHeaders[n].VirtualAddress;
  186. DWORD vaEnd = vaStart + m_SectionHeaders[n].SizeOfRawData;
  187. if (nRva >= vaStart && nRva < vaEnd) {
  188. return m_SectionHeaders[n].PointerToRawData
  189. + nRva - m_SectionHeaders[n].VirtualAddress;
  190. }
  191. }
  192. return 0;
  193. }
  194. //////////////////////////////////////////////////////////////////////////////
  195. //
  196. BOOL CImage::CopyFileData(HANDLE hFile, DWORD nOldPos, DWORD cbData)
  197. {
  198. DWORD cbDone = 0;
  199. return WriteFile(hFile, m_pMap + nOldPos, cbData, &cbDone, NULL);
  200. }
  201. BOOL CImage::ZeroFileData(HANDLE hFile, DWORD cbData)
  202. {
  203. if (!SizeOutputBuffer(4096)) {
  204. return FALSE;
  205. }
  206. ZeroMemory(m_pbOutputBuffer, m_cbOutputBuffer);
  207. for (DWORD cbLeft = cbData; cbLeft > 0;) {
  208. DWORD cbStep = cbLeft > m_cbOutputBuffer ? m_cbOutputBuffer : cbLeft;
  209. DWORD cbDone = 0;
  210. if (!WriteFile(hFile, m_pbOutputBuffer, cbStep, &cbDone, NULL)) {
  211. return FALSE;
  212. }
  213. if (cbDone == 0)
  214. break;
  215. cbLeft -= cbDone;
  216. }
  217. return TRUE;
  218. }
  219. BOOL CImage::AlignFileData(HANDLE hFile)
  220. {
  221. DWORD nLastFileAddr = m_nNextFileAddr;
  222. m_nNextFileAddr = FileAlign(m_nNextFileAddr);
  223. m_nNextVirtAddr = SectionAlign(m_nNextVirtAddr);
  224. if (hFile != INVALID_HANDLE_VALUE) {
  225. if (m_nNextFileAddr > nLastFileAddr) {
  226. if (SetFilePointer(hFile, nLastFileAddr, NULL, FILE_BEGIN) == ~0u) {
  227. return FALSE;
  228. }
  229. return ZeroFileData(hFile, m_nNextFileAddr - nLastFileAddr);
  230. }
  231. }
  232. return TRUE;
  233. }
  234. BOOL CImage::Read(HANDLE hFile)
  235. {
  236. DWORD n;
  237. IMAGE_OPTIONAL_HEADER32 oh32;
  238. if (hFile == INVALID_HANDLE_VALUE) {
  239. SetLastError(ERROR_INVALID_HANDLE);
  240. return FALSE;
  241. }
  242. ///////////////////////////////////////////////////////// Create mapping.
  243. //
  244. m_nFileSize = GetFileSize(hFile, NULL);
  245. if (m_nFileSize == ~0ul) {
  246. return FALSE;
  247. }
  248. m_hMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
  249. if (m_hMap == NULL) {
  250. return FALSE;
  251. }
  252. m_pMap = (PBYTE)MapViewOfFile(m_hMap, FILE_MAP_READ, 0, 0, 0);
  253. if (m_pMap == NULL) {
  254. return FALSE;
  255. }
  256. ////////////////////////////////////////////////////// Process DOS Header.
  257. //
  258. PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)m_pMap;
  259. if (pDosHeader->e_magic == IMAGE_DOS_SIGNATURE) {
  260. m_nFileHeaderOffset = pDosHeader->e_lfanew + sizeof(DWORD);
  261. m_nOptionalHeaderOffset = m_nFileHeaderOffset + sizeof(m_FileHeader);
  262. }
  263. else {
  264. m_nFileHeaderOffset = 0;
  265. m_nOptionalHeaderOffset = m_nFileHeaderOffset + sizeof(m_FileHeader);
  266. }
  267. /////////////////////////////////////////////////////// Process PE Header.
  268. //
  269. CopyMemory(&m_FileHeader, m_pMap + m_nFileHeaderOffset, sizeof(m_FileHeader));
  270. if (m_FileHeader.SizeOfOptionalHeader == 0) {
  271. SetLastError(ERROR_EXE_MARKED_INVALID);
  272. return FALSE;
  273. }
  274. ///////////////////////////////////////////////// Process Optional Header.
  275. //
  276. CopyMemory(&oh32, m_pMap + m_nOptionalHeaderOffset, sizeof(oh32));
  277. if (oh32.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)
  278. {
  279. // Convert 32-bit optional header to internal 64-bit optional header
  280. m_f64bit = FALSE;
  281. ZeroMemory(&m_OptionalHeader, sizeof(m_OptionalHeader));
  282. m_OptionalHeader.Magic = oh32.Magic;
  283. m_OptionalHeader.MajorLinkerVersion = oh32.MajorLinkerVersion;
  284. m_OptionalHeader.MinorLinkerVersion = oh32.MinorLinkerVersion;
  285. m_OptionalHeader.SizeOfCode = oh32.SizeOfCode;
  286. m_OptionalHeader.SizeOfInitializedData = oh32.SizeOfInitializedData;
  287. m_OptionalHeader.SizeOfUninitializedData = oh32.SizeOfUninitializedData;
  288. m_OptionalHeader.AddressOfEntryPoint = oh32.AddressOfEntryPoint;
  289. m_OptionalHeader.BaseOfCode = oh32.BaseOfCode;
  290. m_OptionalHeader.ImageBase = oh32.ImageBase;
  291. m_OptionalHeader.SectionAlignment = oh32.SectionAlignment;
  292. m_OptionalHeader.FileAlignment = oh32.FileAlignment;
  293. m_OptionalHeader.MajorOperatingSystemVersion = oh32.MajorOperatingSystemVersion;
  294. m_OptionalHeader.MinorOperatingSystemVersion = oh32.MinorOperatingSystemVersion;
  295. m_OptionalHeader.MajorImageVersion = oh32.MajorImageVersion;
  296. m_OptionalHeader.MinorImageVersion = oh32.MinorImageVersion;
  297. m_OptionalHeader.MajorSubsystemVersion = oh32.MajorSubsystemVersion;
  298. m_OptionalHeader.MinorSubsystemVersion = oh32.MinorSubsystemVersion;
  299. m_OptionalHeader.Win32VersionValue = oh32.Win32VersionValue;
  300. m_OptionalHeader.SizeOfImage = oh32.SizeOfImage;
  301. m_OptionalHeader.SizeOfHeaders = oh32.SizeOfHeaders;
  302. m_OptionalHeader.CheckSum = oh32.CheckSum;
  303. m_OptionalHeader.Subsystem = oh32.Subsystem;
  304. m_OptionalHeader.DllCharacteristics = oh32.DllCharacteristics;
  305. m_OptionalHeader.SizeOfStackReserve = oh32.SizeOfStackReserve;
  306. m_OptionalHeader.SizeOfStackCommit = oh32.SizeOfStackCommit;
  307. m_OptionalHeader.SizeOfHeapReserve = oh32.SizeOfHeapReserve;
  308. m_OptionalHeader.SizeOfHeapCommit = oh32.SizeOfHeapCommit;
  309. m_OptionalHeader.LoaderFlags = oh32.LoaderFlags;
  310. m_OptionalHeader.NumberOfRvaAndSizes = oh32.NumberOfRvaAndSizes;
  311. for (n = 0; n < oh32.NumberOfRvaAndSizes; n++)
  312. {
  313. m_OptionalHeader.DataDirectory[n] = oh32.DataDirectory[n];
  314. }
  315. }
  316. else if (oh32.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)
  317. {
  318. m_f64bit = TRUE;
  319. CopyMemory(&m_OptionalHeader,
  320. m_pMap + m_nOptionalHeaderOffset, sizeof(m_OptionalHeader));
  321. }
  322. else
  323. {
  324. SetLastError(ERROR_EXE_MARKED_INVALID);
  325. return FALSE;
  326. }
  327. m_nSectionsOffset = m_nOptionalHeaderOffset + m_FileHeader.SizeOfOptionalHeader;
  328. ///////////////////////////////////////////////// Process Section Headers.
  329. //
  330. if (m_FileHeader.NumberOfSections > arrayof(m_SectionHeaders)) {
  331. SetLastError(ERROR_EXE_MARKED_INVALID);
  332. return FALSE;
  333. }
  334. CopyMemory(&m_SectionHeaders,
  335. m_pMap + m_nSectionsOffset,
  336. sizeof(m_SectionHeaders[0]) * m_FileHeader.NumberOfSections);
  337. ////////////////////////////////////////////////////////// Parse Sections.
  338. //
  339. m_nSectionsEndOffset = m_nSectionsOffset + sizeof(m_SectionHeaders);
  340. m_nExtraOffset = 0;
  341. for (n = 0; n < m_FileHeader.NumberOfSections; n++) {
  342. m_nExtraOffset = Max(m_SectionHeaders[n].PointerToRawData +
  343. m_SectionHeaders[n].SizeOfRawData,
  344. m_nExtraOffset);
  345. if (m_SectionHeaders[n].PointerToRawData != 0) {
  346. m_nSectionsEndOffset = Min(m_SectionHeaders[n].PointerToRawData,
  347. m_nSectionsEndOffset);
  348. }
  349. }
  350. m_nSectionsMaxCount = (m_nSectionsEndOffset - m_nSectionsOffset)
  351. / sizeof(IMAGE_SECTION_HEADER);
  352. return TRUE;
  353. }
  354. //////////////////////////////////////////////////////////////////////////////
  355. //
  356. BOOL CImage::Check(PCSTR pszSection)
  357. {
  358. CHAR szName[IMAGE_SIZEOF_SHORT_NAME];
  359. ZeroMemory(szName, sizeof(szName));
  360. strncpy(szName, pszSection, sizeof(szName));
  361. if ((DWORD)(m_FileHeader.NumberOfSections + 1) > m_nSectionsMaxCount) {
  362. SetLastError(ERROR_EXE_MARKED_INVALID);
  363. return FALSE;
  364. }
  365. for (DWORD n = 0; n < m_FileHeader.NumberOfSections; n++) {
  366. if (memcmp(szName, m_SectionHeaders[n].Name, sizeof(szName)) == 0)
  367. {
  368. SetLastError(ERROR_DUPLICATE_TAG);
  369. return FALSE;
  370. }
  371. }
  372. return TRUE;
  373. }
  374. //////////////////////////////////////////////////////////////////////////////
  375. //
  376. BOOL CImage::Write(HANDLE hFile, PBYTE pbSectData, UINT cbSectData, PCSTR pszSection)
  377. {
  378. if (hFile == INVALID_HANDLE_VALUE) {
  379. SetLastError(ERROR_INVALID_HANDLE);
  380. return FALSE;
  381. }
  382. //////////////////////////////////////////////////////////////////////////
  383. //
  384. m_nNextFileAddr = 0;
  385. m_nNextVirtAddr = 0;
  386. //////////////////////////////////////////////////////////// Copy Headers.
  387. //
  388. if (SetFilePointer(hFile, 0, NULL, FILE_BEGIN) == ~0u) {
  389. return FALSE;
  390. }
  391. if (!CopyFileData(hFile, 0, m_OptionalHeader.SizeOfHeaders)) {
  392. return FALSE;
  393. }
  394. m_nNextFileAddr = m_OptionalHeader.SizeOfHeaders;
  395. m_nNextVirtAddr = 0;
  396. if (!AlignFileData(hFile)) {
  397. return FALSE;
  398. }
  399. /////////////////////////////////////////////////////////// Copy Sections.
  400. //
  401. for (DWORD n = 0; n < m_FileHeader.NumberOfSections; n++) {
  402. if (m_SectionHeaders[n].SizeOfRawData) {
  403. if (SetFilePointer(hFile,
  404. m_SectionHeaders[n].PointerToRawData,
  405. NULL, FILE_BEGIN) == ~0u) {
  406. return FALSE;
  407. }
  408. if (!CopyFileData(hFile,
  409. m_SectionHeaders[n].PointerToRawData,
  410. m_SectionHeaders[n].SizeOfRawData)) {
  411. return FALSE;
  412. }
  413. }
  414. m_nNextFileAddr = Max(m_SectionHeaders[n].PointerToRawData +
  415. m_SectionHeaders[n].SizeOfRawData,
  416. m_nNextFileAddr);
  417. m_nNextVirtAddr = Max(m_SectionHeaders[n].VirtualAddress +
  418. m_SectionHeaders[n].Misc.VirtualSize,
  419. m_nNextVirtAddr);
  420. m_nExtraOffset = Max(m_nNextFileAddr, m_nExtraOffset);
  421. if (!AlignFileData(hFile)) {
  422. return FALSE;
  423. }
  424. }
  425. /////////////////////////////////////////////////////////////// Old WriteSection
  426. DWORD cbDone;
  427. if (pbSectData) {
  428. /////////////////////////////////////////////////// Insert .detour Section.
  429. //
  430. DWORD nSection = m_FileHeader.NumberOfSections++;
  431. ZeroMemory(&m_SectionHeaders[nSection], sizeof(m_SectionHeaders[nSection]));
  432. strcpy((PCHAR)m_SectionHeaders[nSection].Name, pszSection);
  433. m_SectionHeaders[nSection].Characteristics
  434. = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ;
  435. m_nOutputVirtAddr = m_nNextVirtAddr;
  436. m_nOutputVirtSize = 0;
  437. m_nOutputFileAddr = m_nNextFileAddr;
  438. //////////////////////////////////////////////////////////////////////////
  439. //
  440. if (!SizeOutputBuffer(QuadAlign(cbSectData))) {
  441. return FALSE;
  442. }
  443. DWORD vaData = 0;
  444. PBYTE pbData = NULL;
  445. if ((pbData = AllocateOutput(cbSectData, &vaData)) == NULL) {
  446. return FALSE;
  447. }
  448. CopyMemory(pbData, pbSectData, cbSectData);
  449. //////////////////////////////////////////////////////////////////////////
  450. //
  451. m_nNextVirtAddr += m_nOutputVirtSize;
  452. m_nNextFileAddr += FileAlign(m_nOutputVirtSize);
  453. if (!AlignFileData(hFile)) {
  454. return FALSE;
  455. }
  456. //////////////////////////////////////////////////////////////////////////
  457. //
  458. m_SectionHeaders[nSection].VirtualAddress = m_nOutputVirtAddr;
  459. m_SectionHeaders[nSection].Misc.VirtualSize = m_nOutputVirtSize;
  460. m_SectionHeaders[nSection].PointerToRawData = m_nOutputFileAddr;
  461. m_SectionHeaders[nSection].SizeOfRawData = FileAlign(m_nOutputVirtSize);
  462. m_OptionalHeader
  463. .DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress = 0;
  464. m_OptionalHeader
  465. .DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size = 0;
  466. //////////////////////////////////////////////////////////////////////////
  467. //
  468. if (SetFilePointer(hFile, m_SectionHeaders[nSection].PointerToRawData,
  469. NULL, FILE_BEGIN) == ~0u) {
  470. return FALSE;
  471. }
  472. if (!WriteFile(hFile, pbData, m_SectionHeaders[nSection].SizeOfRawData,
  473. &cbDone, NULL)) {
  474. return FALSE;
  475. }
  476. }
  477. ///////////////////////////////////////////////////// Adjust Extra Data.
  478. //
  479. LONG nExtraAdjust = m_nNextFileAddr - m_nExtraOffset;
  480. for (n = 0; n < m_FileHeader.NumberOfSections; n++) {
  481. if (m_SectionHeaders[n].PointerToRawData > m_nExtraOffset)
  482. m_SectionHeaders[n].PointerToRawData += nExtraAdjust;
  483. if (m_SectionHeaders[n].PointerToRelocations > m_nExtraOffset)
  484. m_SectionHeaders[n].PointerToRelocations += nExtraAdjust;
  485. if (m_SectionHeaders[n].PointerToLinenumbers > m_nExtraOffset)
  486. m_SectionHeaders[n].PointerToLinenumbers += nExtraAdjust;
  487. }
  488. if (m_FileHeader.PointerToSymbolTable > m_nExtraOffset)
  489. m_FileHeader.PointerToSymbolTable += nExtraAdjust;
  490. m_OptionalHeader.CheckSum = 0;
  491. m_OptionalHeader.SizeOfImage = m_nNextVirtAddr;
  492. ////////////////////////////////////////////////// Adjust Debug Directory.
  493. //
  494. DWORD debugAddr = m_OptionalHeader
  495. .DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress;
  496. DWORD debugSize = m_OptionalHeader
  497. .DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size;
  498. if (debugAddr && debugSize) {
  499. DWORD nFileOffset = RvaToFileOffset(debugAddr);
  500. if (SetFilePointer(hFile, nFileOffset, NULL, FILE_BEGIN) == ~0u) {
  501. return FALSE;
  502. }
  503. PIMAGE_DEBUG_DIRECTORY pDir = (PIMAGE_DEBUG_DIRECTORY)RvaToVa(debugAddr);
  504. if (pDir == NULL) {
  505. return FALSE;
  506. }
  507. DWORD nEntries = debugSize / sizeof(*pDir);
  508. for (DWORD n = 0; n < nEntries; n++) {
  509. IMAGE_DEBUG_DIRECTORY dir = pDir[n];
  510. if (dir.PointerToRawData > m_nExtraOffset) {
  511. dir.PointerToRawData += nExtraAdjust;
  512. }
  513. if (!WriteFile(hFile, &dir, sizeof(dir), &cbDone, NULL)) {
  514. return FALSE;
  515. }
  516. }
  517. }
  518. ///////////////////////////////////////////////// Copy Left-over Data.
  519. //
  520. if (m_nFileSize > m_nExtraOffset) {
  521. if (SetFilePointer(hFile, m_nNextFileAddr, NULL, FILE_BEGIN) == ~0u) {
  522. return FALSE;
  523. }
  524. if (!CopyFileData(hFile, m_nExtraOffset, m_nFileSize - m_nExtraOffset)) {
  525. return FALSE;
  526. }
  527. }
  528. //////////////////////////////////////////////////// Finalize Headers.
  529. //
  530. if (SetFilePointer(hFile, m_nFileHeaderOffset, NULL, FILE_BEGIN) == ~0u) {
  531. return FALSE;
  532. }
  533. if (!WriteFile(hFile, &m_FileHeader, sizeof(m_FileHeader), &cbDone, NULL)) {
  534. return FALSE;
  535. }
  536. if (SetFilePointer(hFile, m_nOptionalHeaderOffset, NULL, FILE_BEGIN) == ~0u) {
  537. return FALSE;
  538. }
  539. if (m_f64bit)
  540. {
  541. if (!WriteFile(hFile, &m_OptionalHeader, sizeof(m_OptionalHeader),
  542. &cbDone, NULL)) {
  543. return FALSE;
  544. }
  545. }
  546. else
  547. {
  548. // Convert 32-bit optional header to internal 64-bit optional header
  549. IMAGE_OPTIONAL_HEADER32 oh32;
  550. ZeroMemory(&oh32, sizeof(oh32));
  551. oh32.Magic = m_OptionalHeader.Magic;
  552. oh32.MajorLinkerVersion = m_OptionalHeader.MajorLinkerVersion;
  553. oh32.MinorLinkerVersion = m_OptionalHeader.MinorLinkerVersion;
  554. oh32.SizeOfCode = m_OptionalHeader.SizeOfCode;
  555. oh32.SizeOfInitializedData = m_OptionalHeader.SizeOfInitializedData;
  556. oh32.SizeOfUninitializedData = m_OptionalHeader.SizeOfUninitializedData;
  557. oh32.AddressOfEntryPoint = m_OptionalHeader.AddressOfEntryPoint;
  558. oh32.BaseOfCode = m_OptionalHeader.BaseOfCode;
  559. oh32.ImageBase = (ULONG)m_OptionalHeader.ImageBase;
  560. oh32.SectionAlignment = m_OptionalHeader.SectionAlignment;
  561. oh32.FileAlignment = m_OptionalHeader.FileAlignment;
  562. oh32.MajorOperatingSystemVersion = m_OptionalHeader.MajorOperatingSystemVersion;
  563. oh32.MinorOperatingSystemVersion = m_OptionalHeader.MinorOperatingSystemVersion;
  564. oh32.MajorImageVersion = m_OptionalHeader.MajorImageVersion;
  565. oh32.MinorImageVersion = m_OptionalHeader.MinorImageVersion;
  566. oh32.MajorSubsystemVersion = m_OptionalHeader.MajorSubsystemVersion;
  567. oh32.MinorSubsystemVersion = m_OptionalHeader.MinorSubsystemVersion;
  568. oh32.Win32VersionValue = m_OptionalHeader.Win32VersionValue;
  569. oh32.SizeOfImage = m_OptionalHeader.SizeOfImage;
  570. oh32.SizeOfHeaders = m_OptionalHeader.SizeOfHeaders;
  571. oh32.CheckSum = m_OptionalHeader.CheckSum;
  572. oh32.Subsystem = m_OptionalHeader.Subsystem;
  573. oh32.DllCharacteristics = m_OptionalHeader.DllCharacteristics;
  574. oh32.SizeOfStackReserve = (ULONG)m_OptionalHeader.SizeOfStackReserve;
  575. oh32.SizeOfStackCommit = (ULONG)m_OptionalHeader.SizeOfStackCommit;
  576. oh32.SizeOfHeapReserve = (ULONG)m_OptionalHeader.SizeOfHeapReserve;
  577. oh32.SizeOfHeapCommit = (ULONG)m_OptionalHeader.SizeOfHeapCommit;
  578. oh32.LoaderFlags = m_OptionalHeader.LoaderFlags;
  579. oh32.NumberOfRvaAndSizes = m_OptionalHeader.NumberOfRvaAndSizes;
  580. for (int n = 0; n < IMAGE_NUMBEROF_DIRECTORY_ENTRIES; n++)
  581. {
  582. oh32.DataDirectory[n] = m_OptionalHeader.DataDirectory[n];
  583. }
  584. if (!WriteFile(hFile, &oh32, sizeof(oh32), &cbDone, NULL)) {
  585. return FALSE;
  586. }
  587. }
  588. if (SetFilePointer(hFile, m_nSectionsOffset, NULL, FILE_BEGIN) == ~0u) {
  589. return FALSE;
  590. }
  591. if (!WriteFile(hFile, &m_SectionHeaders,
  592. sizeof(m_SectionHeaders[0])
  593. * m_FileHeader.NumberOfSections,
  594. &cbDone, NULL)) {
  595. return FALSE;
  596. }
  597. return TRUE;
  598. }
  599. //////////////////////////////////////////////////////////////////// CFileMap.
  600. //
  601. class CFileMap
  602. {
  603. public:
  604. CFileMap();
  605. ~CFileMap();
  606. public:
  607. BOOL Load(PCWSTR pszFile);
  608. PBYTE Seek(UINT32 cbPos);
  609. UINT32 Size();
  610. VOID Close();
  611. protected:
  612. PBYTE m_pbData;
  613. UINT32 m_cbData;
  614. };
  615. CFileMap::CFileMap()
  616. {
  617. m_pbData = NULL;
  618. m_cbData = 0;
  619. }
  620. CFileMap::~CFileMap()
  621. {
  622. Close();
  623. }
  624. VOID CFileMap::Close()
  625. {
  626. if (m_pbData) {
  627. UnmapViewOfFile(m_pbData);
  628. m_pbData = NULL;
  629. }
  630. m_cbData = 0;
  631. }
  632. UINT32 CFileMap::Size()
  633. {
  634. return m_cbData;
  635. }
  636. PBYTE CFileMap::Seek(UINT32 cbPos)
  637. {
  638. if (m_pbData && cbPos <= m_cbData) {
  639. return m_pbData + cbPos;
  640. }
  641. return NULL;
  642. }
  643. BOOL CFileMap::Load(PCWSTR pszFile)
  644. {
  645. Close();
  646. HANDLE hFile = CreateFile(pszFile,
  647. GENERIC_READ,
  648. FILE_SHARE_READ,
  649. NULL,
  650. OPEN_EXISTING,
  651. 0,
  652. NULL);
  653. if (hFile == INVALID_HANDLE_VALUE) {
  654. return FALSE;
  655. }
  656. ULONG cbInFileData = GetFileSize(hFile, NULL);
  657. if (cbInFileData == ~0ul) {
  658. CloseHandle(hFile);
  659. return FALSE;
  660. }
  661. HANDLE hInFileMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
  662. CloseHandle(hFile);
  663. if (hInFileMap == NULL) {
  664. return FALSE;
  665. }
  666. m_pbData = (PBYTE)MapViewOfFile(hInFileMap, FILE_MAP_COPY, 0, 0, 0);
  667. CloseHandle(hInFileMap);
  668. if (m_pbData == NULL) {
  669. return FALSE;
  670. }
  671. m_cbData = cbInFileData;
  672. return TRUE;
  673. }
  674. BOOL addsect_files(PCWSTR pszOutput, PCWSTR pszInput, PCWSTR pszData, PCSTR pszSection)
  675. {
  676. HANDLE hInput = INVALID_HANDLE_VALUE;
  677. HANDLE hOutput = INVALID_HANDLE_VALUE;
  678. BOOL bGood = TRUE;
  679. CFileMap cfData;
  680. CImage image;
  681. if (!cfData.Load(pszData)) {
  682. fprintf(stderr, "ADDSECT: Could not open input data file: %ls\n", pszData);
  683. goto end;
  684. }
  685. hInput = CreateFile(pszInput,
  686. GENERIC_READ,
  687. FILE_SHARE_READ,
  688. NULL,
  689. OPEN_EXISTING,
  690. FILE_ATTRIBUTE_NORMAL,
  691. NULL);
  692. if (hInput == INVALID_HANDLE_VALUE) {
  693. printf("ADDSECT: Couldn't open input file: %ls, error: %d\n",
  694. pszInput, GetLastError());
  695. bGood = FALSE;
  696. goto end;
  697. }
  698. hOutput = CreateFile(pszOutput,
  699. GENERIC_WRITE | GENERIC_READ, 0, NULL, CREATE_ALWAYS,
  700. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL);
  701. if (hOutput == INVALID_HANDLE_VALUE) {
  702. printf("ADDSECT: Couldn't open output file: %ls, error: %d\n",
  703. pszOutput, GetLastError());
  704. bGood = FALSE;
  705. goto end;
  706. }
  707. if (!image.Read(hInput)) {
  708. fprintf(stderr, "ADDSECT: Image read failed: %d\n", GetLastError());
  709. bGood = FALSE;
  710. goto end;
  711. }
  712. if (!image.Check(pszSection)) {
  713. fprintf(stderr, "ADDSECT: Can't insert section `%hs' into image: %d\n",
  714. pszSection, GetLastError());
  715. bGood = FALSE;
  716. goto end;
  717. }
  718. if (!image.Write(hOutput, cfData.Seek(0), cfData.Size(), pszSection)) {
  719. fprintf(stderr, "ADDSECT: Image write failed: %d\n", GetLastError());
  720. bGood = FALSE;
  721. }
  722. image.Close();
  723. if (bGood)
  724. {
  725. printf("ADDSECT: Added new section `%hs' of %d bytes to `%ls'.\n",
  726. pszSection, cfData.Size(), pszOutput);
  727. }
  728. end:
  729. if (hOutput != INVALID_HANDLE_VALUE) {
  730. CloseHandle(hOutput);
  731. hOutput = INVALID_HANDLE_VALUE;
  732. }
  733. if (hInput != INVALID_HANDLE_VALUE) {
  734. CloseHandle(hInput);
  735. hInput = INVALID_HANDLE_VALUE;
  736. }
  737. if (!bGood)
  738. {
  739. DeleteFile(pszOutput);
  740. }
  741. return TRUE;
  742. }
  743. int __cdecl wmain(int argc, PWCHAR *argv)
  744. {
  745. BOOL fNeedHelp = FALSE;
  746. PCWSTR pszData = NULL;
  747. PCWSTR pszInput = NULL;
  748. PCWSTR pszOutput = NULL;
  749. CHAR szSection[IMAGE_SIZEOF_SHORT_NAME + 1] = ".ramfs\0\0";
  750. for (int arg = 1; arg < argc; arg++) {
  751. if (argv[arg][0] == '-' || argv[arg][0] == '/') {
  752. PWCHAR argn = argv[arg]+1; // Argument name
  753. PWCHAR argp = argn; // Argument parameter
  754. while (*argp && *argp != ':' && *argp != '=') {
  755. argp++;
  756. }
  757. if (*argp == ':' || *argp == '=')
  758. *argp++ = '\0';
  759. switch (argn[0]) {
  760. case 'd': // Input file.
  761. case 'D':
  762. pszData = argp;
  763. break;
  764. case 'i': // Input file.
  765. case 'I':
  766. pszInput = argp;
  767. break;
  768. case 'o': // Output file.
  769. case 'O':
  770. pszOutput = argp;
  771. break;
  772. case 's': // Section Name.
  773. case 'S':
  774. _snprintf(szSection, arrayof(szSection)-1, "%ls", argp);
  775. szSection[arrayof(szSection)-1] = '\0';
  776. break;
  777. case 'h': // Help
  778. case 'H':
  779. case '?':
  780. fNeedHelp = TRUE;
  781. break;
  782. default:
  783. fprintf(stderr, "ADDSECT: Unknown argument: %ls\n", argv[arg]);
  784. fNeedHelp = TRUE;
  785. break;
  786. }
  787. }
  788. }
  789. if (pszInput == NULL) {
  790. fNeedHelp = TRUE;
  791. }
  792. if (pszOutput == NULL) {
  793. fNeedHelp = TRUE;
  794. }
  795. if (pszData == NULL) {
  796. fNeedHelp = TRUE;
  797. }
  798. if (argc == 1) {
  799. fNeedHelp = TRUE;
  800. }
  801. if (fNeedHelp) {
  802. printf(
  803. "Usage:\n"
  804. " ADDSECT [options] /I:input /O:output /D:data\n"
  805. "Options:\n"
  806. " /O:output Specify output file.\n"
  807. " /I:input Specify input file.\n"
  808. " /D:data Specify data file.\n"
  809. " /S:section Symbol (defaults to .ramfs).\n"
  810. " /H or /? Display this help screen.\n"
  811. "Summary:\n"
  812. " Adds a new section to a PE binary.\n"
  813. );
  814. return 1;
  815. }
  816. if (!addsect_files(pszOutput, pszInput, pszData, szSection))
  817. {
  818. return 2;
  819. }
  820. return 0;
  821. }
  822. //
  823. ///////////////////////////////////////////////////////////////// End of File.