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.

1527 lines
57 KiB

  1. /*++
  2. (C) Copyright Microsoft Corporation 1988-1992
  3. Module Name:
  4. updres.h
  5. Author:
  6. Floyd A Rogers 2/7/92
  7. Revision History:
  8. Floyd Rogers
  9. Created
  10. --*/
  11. #define DPrintf(a)
  12. #define DPrintfn(a)
  13. #define DPrintfu(a)
  14. #define cbPadMax 16L
  15. #define DEFAULT_CODEPAGE 1252
  16. #define MAJOR_RESOURCE_VERSION 4
  17. #define MINOR_RESOURCE_VERSION 0
  18. #define BUTTONCODE 0x80
  19. #define EDITCODE 0x81
  20. #define STATICCODE 0x82
  21. #define LISTBOXCODE 0x83
  22. #define SCROLLBARCODE 0x84
  23. #define COMBOBOXCODE 0x85
  24. #define SEEK_SET 0
  25. #define SEEK_CUR 1
  26. #define SEEK_END 2
  27. #define MAXSTR (256+1)
  28. //
  29. // An ID_WORD indicates the following WORD is an ordinal rather
  30. // than a string
  31. //
  32. #define ID_WORD 0xffff
  33. //typedef WCHAR *PWCHAR;
  34. typedef struct MY_STRING {
  35. ULONG discriminant; // long to make the rest of the struct aligned
  36. union u {
  37. struct {
  38. struct MY_STRING *pnext;
  39. ULONG ulOffsetToString;
  40. USHORT cbD;
  41. USHORT cb;
  42. WCHAR *sz;
  43. } ss;
  44. WORD Ordinal;
  45. } uu;
  46. } SDATA, *PSDATA, **PPSDATA;
  47. #define IS_STRING 1
  48. #define IS_ID 2
  49. // defines to make deferencing easier
  50. #define OffsetToString uu.ss.ulOffsetToString
  51. #define cbData uu.ss.cbD
  52. #define cbsz uu.ss.cb
  53. #define szStr uu.ss.sz
  54. typedef struct _RESNAME {
  55. struct _RESNAME *pnext; // The first three fields should be the
  56. PSDATA Name; // same in both res structures
  57. ULONG OffsetToData;
  58. PSDATA Type;
  59. ULONG SectionNumber;
  60. ULONG DataSize;
  61. ULONG_PTR OffsetToDataEntry;
  62. USHORT ResourceNumber;
  63. USHORT NumberOfLanguages;
  64. WORD LanguageId;
  65. } RESNAME, *PRESNAME, **PPRESNAME;
  66. typedef struct _RESTYPE {
  67. struct _RESTYPE *pnext; // The first three fields should be the
  68. PSDATA Type; // same in both res structures
  69. ULONG OffsetToData;
  70. struct _RESNAME *NameHeadID;
  71. struct _RESNAME *NameHeadName;
  72. ULONG NumberOfNamesID;
  73. ULONG NumberOfNamesName;
  74. } RESTYPE, *PRESTYPE, **PPRESTYPE;
  75. typedef struct _UPDATEDATA {
  76. ULONG cbStringTable;
  77. PSDATA StringHead;
  78. PRESNAME ResHead;
  79. PRESTYPE ResTypeHeadID;
  80. PRESTYPE ResTypeHeadName;
  81. LONG Status;
  82. HANDLE hFileName;
  83. } UPDATEDATA, *PUPDATEDATA;
  84. //
  85. // Round up a byte count to a power of 2:
  86. //
  87. #define ROUNDUP(cbin, align) (((cbin) + (align) - 1) & ~((align) - 1))
  88. //
  89. // Return the remainder, given a byte count and a power of 2:
  90. //
  91. #define REMAINDER(cbin,align) (((align)-((cbin)&((align)-1)))&((align)-1))
  92. #define CBLONG (sizeof(LONG))
  93. #define BUFSIZE (4L * 1024L)
  94. /* functions for adding/deleting resources to update list */
  95. LONG
  96. AddResource(
  97. IN PSDATA Type,
  98. IN PSDATA Name,
  99. IN WORD Language,
  100. IN PUPDATEDATA pupd,
  101. IN PVOID lpData,
  102. IN ULONG cb
  103. );
  104. PSDATA
  105. AddStringOrID(
  106. LPCWSTR lp,
  107. PUPDATEDATA pupd
  108. );
  109. BOOL
  110. InsertResourceIntoLangList(
  111. PUPDATEDATA pUpd,
  112. PSDATA Type,
  113. PSDATA Name,
  114. PRESTYPE pType,
  115. PRESNAME pName,
  116. INT idLang,
  117. INT fName,
  118. INT cb,
  119. PVOID lpData
  120. );
  121. BOOL
  122. DeleteResourceFromList(
  123. PUPDATEDATA pUpd,
  124. PRESTYPE pType,
  125. PRESNAME pName,
  126. INT idLang,
  127. INT fType,
  128. INT fName
  129. );
  130. /* Prototypes for Enumeration done in BeginUpdateResource */
  131. BOOL
  132. EnumTypesFunc(
  133. HANDLE hModule,
  134. LPWSTR lpType,
  135. LPARAM lParam
  136. );
  137. BOOL
  138. EnumNamesFunc(
  139. HANDLE hModule,
  140. LPWSTR lpName,
  141. LPWSTR lpType,
  142. LPARAM lParam
  143. );
  144. BOOL
  145. EnumLangsFunc(
  146. HANDLE hModule,
  147. LPWSTR lpType,
  148. LPWSTR lpName,
  149. WORD languages,
  150. LPARAM lParam
  151. );
  152. /* Prototypes for genral worker functions in updres.c */
  153. LONG
  154. WriteResFile(
  155. IN HANDLE hUpdate,
  156. IN WCHAR *pDstname
  157. );
  158. VOID
  159. FreeData(
  160. PUPDATEDATA pUpd
  161. );
  162. PRESNAME
  163. WriteResSection(
  164. PUPDATEDATA pUpdate,
  165. INT outfh,
  166. ULONG align,
  167. ULONG cbLeft,
  168. PRESNAME pResSave
  169. );
  170. //
  171. // Template for patch debug information function.
  172. //
  173. template<class NT_HEADER_TYPE>
  174. LONG
  175. PatchDebug(
  176. int inpfh,
  177. int outfh,
  178. PIMAGE_SECTION_HEADER pDebugOld,
  179. PIMAGE_SECTION_HEADER pDebugNew,
  180. PIMAGE_SECTION_HEADER pDebugDirOld,
  181. PIMAGE_SECTION_HEADER pDebugDirNew,
  182. NT_HEADER_TYPE *pOld,
  183. NT_HEADER_TYPE *pNew,
  184. ULONG ibMaxDbgOffsetOld,
  185. PULONG pPointerToRawData
  186. )
  187. {
  188. PIMAGE_DEBUG_DIRECTORY pDbgLast;
  189. PIMAGE_DEBUG_DIRECTORY pDbgSave;
  190. PIMAGE_DEBUG_DIRECTORY pDbg;
  191. ULONG ib;
  192. ULONG adjust;
  193. ULONG ibNew;
  194. if (pDebugDirOld == NULL || pNew->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size==0)
  195. return NO_ERROR;
  196. pDbgSave = pDbg = (PIMAGE_DEBUG_DIRECTORY)RtlAllocateHeap(
  197. RtlProcessHeap(), MAKE_TAG( RES_TAG ),
  198. pNew->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size);
  199. if (pDbg == NULL)
  200. return ERROR_NOT_ENOUGH_MEMORY;
  201. if (pDebugOld) {
  202. DPrintf((DebugBuf, "Patching dbg directory: @%#08lx ==> @%#08lx\n",
  203. pDebugOld->PointerToRawData, pDebugNew->PointerToRawData));
  204. } else
  205. adjust = *pPointerToRawData; /* passed in EOF of new file */
  206. ib = pOld->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress - pDebugDirOld->VirtualAddress;
  207. MuMoveFilePos(inpfh, pDebugDirOld->PointerToRawData+ib);
  208. pDbgLast = pDbg + (pNew->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size)/sizeof(IMAGE_DEBUG_DIRECTORY);
  209. MuRead(inpfh, (PUCHAR)pDbg, pNew->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size);
  210. if (pDebugOld == NULL) {
  211. /* find 1st entry - use for offset */
  212. DPrintf((DebugBuf, "Adjust: %#08lx\n",adjust));
  213. for (ibNew=0xffffffff ; pDbg<pDbgLast ; pDbg++)
  214. if (pDbg->PointerToRawData >= ibMaxDbgOffsetOld &&
  215. pDbg->PointerToRawData < ibNew
  216. )
  217. ibNew = pDbg->PointerToRawData;
  218. if (ibNew != 0xffffffff)
  219. *pPointerToRawData = ibNew;
  220. else
  221. *pPointerToRawData = _llseek(inpfh, 0L, SEEK_END);
  222. for (pDbg=pDbgSave ; pDbg<pDbgLast ; pDbg++) {
  223. DPrintf((DebugBuf, "Old debug file offset: %#08lx\n",
  224. pDbg->PointerToRawData));
  225. if (pDbg->PointerToRawData >= ibMaxDbgOffsetOld)
  226. pDbg->PointerToRawData += adjust - ibNew;
  227. DPrintf((DebugBuf, "New debug file offset: %#08lx\n",
  228. pDbg->PointerToRawData));
  229. }
  230. } else {
  231. for ( ; pDbg<pDbgLast ; pDbg++) {
  232. DPrintf((DebugBuf, "Old debug addr: %#08lx, file offset: %#08lx\n",
  233. pDbg->AddressOfRawData,
  234. pDbg->PointerToRawData));
  235. pDbg->AddressOfRawData += pDebugNew->VirtualAddress -
  236. pDebugOld->VirtualAddress;
  237. pDbg->PointerToRawData += pDebugNew->PointerToRawData -
  238. pDebugOld->PointerToRawData;
  239. DPrintf((DebugBuf, "New debug addr: %#08lx, file offset: %#08lx\n",
  240. pDbg->AddressOfRawData,
  241. pDbg->PointerToRawData));
  242. }
  243. }
  244. MuMoveFilePos(outfh, pDebugDirNew->PointerToRawData+ib);
  245. MuWrite(outfh, (PUCHAR)pDbgSave, pNew->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size);
  246. RtlFreeHeap(RtlProcessHeap(), 0, pDbgSave);
  247. return NO_ERROR;
  248. }
  249. //
  250. // Template for patch debug information function.
  251. //
  252. template<class NT_HEADER_TYPE>
  253. LONG
  254. PatchRVAs(
  255. int inpfh,
  256. int outfh,
  257. PIMAGE_SECTION_HEADER po32,
  258. ULONG pagedelta,
  259. NT_HEADER_TYPE *pNew,
  260. ULONG OldSize
  261. )
  262. {
  263. ULONG hdrdelta;
  264. ULONG offset, rvaiat, offiat, iat;
  265. IMAGE_EXPORT_DIRECTORY Exp;
  266. IMAGE_IMPORT_DESCRIPTOR Imp;
  267. ULONG i, cmod, cimp;
  268. hdrdelta = pNew->OptionalHeader.SizeOfHeaders - OldSize;
  269. if (hdrdelta == 0) {
  270. return NO_ERROR;
  271. }
  272. //
  273. // Patch export section RVAs
  274. //
  275. DPrintf((DebugBuf, "Export offset=%08lx, hdrsize=%08lx\n",
  276. pNew->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress,
  277. pNew->OptionalHeader.SizeOfHeaders));
  278. if ((offset = pNew->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress) == 0) {
  279. DPrintf((DebugBuf, "No exports to patch\n"));
  280. } else if (offset >= pNew->OptionalHeader.SizeOfHeaders) {
  281. DPrintf((DebugBuf, "No exports in header to patch\n"));
  282. } else {
  283. MuMoveFilePos(inpfh, offset - hdrdelta);
  284. MuRead(inpfh, (PUCHAR) &Exp, sizeof(Exp));
  285. Exp.Name += hdrdelta;
  286. (ULONG)Exp.AddressOfFunctions += hdrdelta;
  287. (ULONG)Exp.AddressOfNames += hdrdelta;
  288. (ULONG)Exp.AddressOfNameOrdinals += hdrdelta;
  289. MuMoveFilePos(outfh, offset);
  290. MuWrite(outfh, (PUCHAR) &Exp, sizeof(Exp));
  291. }
  292. //
  293. // Patch import section RVAs
  294. //
  295. DPrintf((DebugBuf, "Import offset=%08lx, hdrsize=%08lx\n",
  296. pNew->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress,
  297. pNew->OptionalHeader.SizeOfHeaders));
  298. if ((offset = pNew->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress) == 0) {
  299. DPrintf((DebugBuf, "No imports to patch\n"));
  300. } else if (offset >= pNew->OptionalHeader.SizeOfHeaders) {
  301. DPrintf((DebugBuf, "No imports in header to patch\n"));
  302. } else {
  303. for (cimp = cmod = 0; ; cmod++) {
  304. MuMoveFilePos(inpfh, offset + cmod * sizeof(Imp) - hdrdelta);
  305. MuRead(inpfh, (PUCHAR) &Imp, sizeof(Imp));
  306. if (Imp.FirstThunk == 0) {
  307. break;
  308. }
  309. Imp.Name += hdrdelta;
  310. MuMoveFilePos(outfh, offset + cmod * sizeof(Imp));
  311. MuWrite(outfh, (PUCHAR) &Imp, sizeof(Imp));
  312. rvaiat = (ULONG)Imp.FirstThunk;
  313. DPrintf((DebugBuf, "RVAIAT = %#08lx\n", (ULONG)rvaiat));
  314. for (i = 0; i < pNew->FileHeader.NumberOfSections; i++) {
  315. if (rvaiat >= po32[i].VirtualAddress &&
  316. rvaiat < po32[i].VirtualAddress + po32[i].SizeOfRawData) {
  317. offiat = rvaiat - po32[i].VirtualAddress + po32[i].PointerToRawData;
  318. goto found;
  319. }
  320. }
  321. DPrintf((DebugBuf, "IAT not found\n"));
  322. return ERROR_INVALID_DATA;
  323. found:
  324. DPrintf((DebugBuf, "IAT offset: @%#08lx ==> @%#08lx\n",
  325. offiat - pagedelta,
  326. offiat));
  327. MuMoveFilePos(inpfh, offiat - pagedelta);
  328. MuMoveFilePos(outfh, offiat);
  329. for (;;) {
  330. MuRead(inpfh, (PUCHAR) &iat, sizeof(iat));
  331. if (iat == 0) {
  332. break;
  333. }
  334. if ((iat & IMAGE_ORDINAL_FLAG) == 0) { // if import by name
  335. DPrintf((DebugBuf, "Patching IAT: %08lx + %04lx ==> %08lx\n",
  336. iat,
  337. hdrdelta,
  338. iat + hdrdelta));
  339. iat += hdrdelta;
  340. cimp++;
  341. }
  342. MuWrite(outfh, (PUCHAR) &iat, sizeof(iat)); // Avoids seeking
  343. }
  344. }
  345. DPrintf((DebugBuf, "%u import module name RVAs patched\n", cmod));
  346. DPrintf((DebugBuf, "%u IAT name RVAs patched\n", cimp));
  347. if (cmod == 0) {
  348. DPrintf((DebugBuf, "No import modules to patch\n"));
  349. }
  350. if (cimp == 0) {
  351. DPrintf((DebugBuf, "No import name RVAs to patch\n"));
  352. }
  353. }
  354. return NO_ERROR;
  355. }
  356. //
  357. // Template for write resource function.
  358. //
  359. template<class NT_HEADER_TYPE>
  360. LONG
  361. PEWriteResource(
  362. INT inpfh,
  363. INT outfh,
  364. ULONG cbOldexe,
  365. PUPDATEDATA pUpdate,
  366. NT_HEADER_TYPE *NtHeader
  367. )
  368. {
  369. NT_HEADER_TYPE Old; /* original header */
  370. NT_HEADER_TYPE New; /* working header */
  371. PRESNAME pRes;
  372. PRESNAME pResSave;
  373. PRESTYPE pType;
  374. ULONG clock = 0;
  375. ULONG cbName=0; /* count of bytes in name strings */
  376. ULONG cbType=0; /* count of bytes in type strings */
  377. ULONG cTypeStr=0; /* count of strings */
  378. ULONG cNameStr=0; /* count of strings */
  379. LONG cb; /* temp byte count and file index */
  380. ULONG cTypes = 0L; /* count of resource types */
  381. ULONG cNames = 0L; /* Count of names for multiple languages/name */
  382. ULONG cRes = 0L; /* count of resources */
  383. ULONG cbRestab; /* count of resources */
  384. LONG cbNew = 0L; /* general count */
  385. ULONG ibObjTab;
  386. ULONG ibObjTabEnd;
  387. ULONG ibNewObjTabEnd;
  388. ULONG ibSave;
  389. ULONG adjust=0;
  390. PIMAGE_SECTION_HEADER pObjtblOld,
  391. pObjtblNew,
  392. pObjDebug,
  393. pObjResourceOld,
  394. pObjResourceNew,
  395. pObjResourceOldX,
  396. pObjDebugDirOld,
  397. pObjDebugDirNew,
  398. pObjNew,
  399. pObjOld,
  400. pObjLast;
  401. PUCHAR p;
  402. PIMAGE_RESOURCE_DIRECTORY pResTab;
  403. PIMAGE_RESOURCE_DIRECTORY pResTabN;
  404. PIMAGE_RESOURCE_DIRECTORY pResTabL;
  405. PIMAGE_RESOURCE_DIRECTORY_ENTRY pResDirL;
  406. PIMAGE_RESOURCE_DIRECTORY_ENTRY pResDirN;
  407. PIMAGE_RESOURCE_DIRECTORY_ENTRY pResDirT;
  408. PIMAGE_RESOURCE_DATA_ENTRY pResData;
  409. PUSHORT pResStr;
  410. PUSHORT pResStrEnd;
  411. PSDATA pPreviousName;
  412. LONG nObjResource=-1;
  413. LONG nObjResourceX=-1;
  414. ULONG cbResource;
  415. ULONG cbMustPad = 0;
  416. ULONG ibMaxDbgOffsetOld;
  417. MuMoveFilePos(inpfh, cbOldexe);
  418. MuRead(inpfh, (PUCHAR)&Old, sizeof(NT_HEADER_TYPE));
  419. ibObjTab = cbOldexe + sizeof(NT_HEADER_TYPE);
  420. ibObjTabEnd = ibObjTab + Old.FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER);
  421. ibNewObjTabEnd = ibObjTabEnd;
  422. DPrintfn((DebugBuf, "\n"));
  423. /* New header is like old one. */
  424. RtlCopyMemory(&New, &Old, sizeof(NT_HEADER_TYPE));
  425. /* Read section table */
  426. pObjtblOld = (PIMAGE_SECTION_HEADER)RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( RES_TAG ),
  427. Old.FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER));
  428. if (pObjtblOld == NULL) {
  429. cb = ERROR_NOT_ENOUGH_MEMORY;
  430. goto AbortExit;
  431. }
  432. RtlZeroMemory((PVOID)pObjtblOld, Old.FileHeader.NumberOfSections*sizeof(IMAGE_SECTION_HEADER));
  433. DPrintf((DebugBuf, "Old section table: %#08lx bytes at %#08lx(mem)\n",
  434. Old.FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER),
  435. pObjtblOld));
  436. MuMoveFilePos(inpfh, ibObjTab);
  437. MuRead(inpfh, (PUCHAR)pObjtblOld,
  438. Old.FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER));
  439. pObjLast = pObjtblOld + Old.FileHeader.NumberOfSections;
  440. ibMaxDbgOffsetOld = 0;
  441. for (pObjOld=pObjtblOld ; pObjOld<pObjLast ; pObjOld++) {
  442. if (pObjOld->PointerToRawData > ibMaxDbgOffsetOld) {
  443. ibMaxDbgOffsetOld = pObjOld->PointerToRawData + pObjOld->SizeOfRawData;
  444. }
  445. }
  446. DPrintf((DebugBuf, "Maximum debug offset in old file: %08x\n", ibMaxDbgOffsetOld ));
  447. /*
  448. * First, count up the resources. We need this information
  449. * to discover how much room for header information to allocate
  450. * in the resource section. cRes tells us how
  451. * many language directory entries/tables. cNames and cTypes
  452. * is used for the respective tables and/or entries. cbName totals
  453. * the bytes required to store the alpha names (including the leading
  454. * length word). cNameStr counts these strings.
  455. */
  456. DPrintf((DebugBuf, "Beginning loop to count resources\n"));
  457. /* first, count those in the named type list */
  458. cbResource = 0;
  459. //DPrintf((DebugBuf, "Walk type: NAME list\n"));
  460. pType = pUpdate->ResTypeHeadName;
  461. while (pType != NULL) {
  462. if (pType->NameHeadName != NULL || pType->NameHeadID != NULL) {
  463. //DPrintf((DebugBuf, "Resource type "));
  464. //DPrintfu((pType->Type->szStr));
  465. //DPrintfn((DebugBuf, "\n"));
  466. cTypes++;
  467. cTypeStr++;
  468. cbType += (pType->Type->cbsz + 1) * sizeof(WORD);
  469. //DPrintf((DebugBuf, "Walk name: Alpha list\n"));
  470. pPreviousName = NULL;
  471. pRes = pType->NameHeadName;
  472. while (pRes) {
  473. //DPrintf((DebugBuf, "Resource "));
  474. //DPrintfu((pRes->Name->szStr));
  475. //DPrintfn((DebugBuf, "\n"));
  476. cRes++;
  477. if (pPreviousName == NULL || wcscmp(pPreviousName->szStr, pRes->Name->szStr) != 0) {
  478. cbName += (pRes->Name->cbsz + 1) * sizeof(WORD);
  479. cNameStr++;
  480. cNames++;
  481. }
  482. cbResource += ROUNDUP(pRes->DataSize, CBLONG);
  483. pPreviousName = pRes->Name;
  484. pRes = pRes->pnext;
  485. }
  486. //DPrintf((DebugBuf, "Walk name: ID list\n"));
  487. pPreviousName = NULL;
  488. pRes = pType->NameHeadID;
  489. while (pRes) {
  490. //DPrintf((DebugBuf, "Resource %hu\n", pRes->Name->uu.Ordinal));
  491. cRes++;
  492. if (pPreviousName == NULL ||
  493. pPreviousName->uu.Ordinal != pRes->Name->uu.Ordinal) {
  494. cNames++;
  495. }
  496. cbResource += ROUNDUP(pRes->DataSize, CBLONG);
  497. pPreviousName = pRes->Name;
  498. pRes = pRes->pnext;
  499. }
  500. }
  501. pType = pType->pnext;
  502. }
  503. /* second, count those in the ID type list */
  504. //DPrintf((DebugBuf, "Walk type: ID list\n"));
  505. pType = pUpdate->ResTypeHeadID;
  506. while (pType != NULL) {
  507. if (pType->NameHeadName != NULL || pType->NameHeadID != NULL) {
  508. //DPrintf((DebugBuf, "Resource type %hu\n", pType->Type->uu.Ordinal));
  509. cTypes++;
  510. //DPrintf((DebugBuf, "Walk name: Alpha list\n"));
  511. pPreviousName = NULL;
  512. pRes = pType->NameHeadName;
  513. while (pRes) {
  514. //DPrintf((DebugBuf, "Resource "));
  515. //DPrintfu((pRes->Name->szStr));
  516. //DPrintfn((DebugBuf, "\n"));
  517. cRes++;
  518. if (pPreviousName == NULL || wcscmp(pPreviousName->szStr, pRes->Name->szStr) != 0) {
  519. cNames++;
  520. cbName += (pRes->Name->cbsz + 1) * sizeof(WORD);
  521. cNameStr++;
  522. }
  523. cbResource += ROUNDUP(pRes->DataSize, CBLONG);
  524. pPreviousName = pRes->Name;
  525. pRes = pRes->pnext;
  526. }
  527. //DPrintf((DebugBuf, "Walk name: ID list\n"));
  528. pPreviousName = NULL;
  529. pRes = pType->NameHeadID;
  530. while (pRes) {
  531. //DPrintf((DebugBuf, "Resource %hu\n", pRes->Name->uu.Ordinal));
  532. cRes++;
  533. if (pPreviousName == NULL || pPreviousName->uu.Ordinal != pRes->Name->uu.Ordinal) {
  534. cNames++;
  535. }
  536. cbResource += ROUNDUP(pRes->DataSize, CBLONG);
  537. pPreviousName = pRes->Name;
  538. pRes = pRes->pnext;
  539. }
  540. }
  541. pType = pType->pnext;
  542. }
  543. cb = REMAINDER(cbName + cbType, CBLONG);
  544. /* Add up the number of bytes needed to store the directory. There is
  545. * one type table with cTypes entries. They point to cTypes name tables
  546. * that have a total of cNames entries. Each of them points to a language
  547. * table and there are a total of cRes entries in all the language tables.
  548. * Finally, we have the space needed for the Directory string entries,
  549. * some extra padding to attain the desired alignment, and the space for
  550. * cRes data entry headers.
  551. */
  552. cbRestab = sizeof(IMAGE_RESOURCE_DIRECTORY) + /* root dir (types) */
  553. cTypes * sizeof(IMAGE_RESOURCE_DIRECTORY_ENTRY) +
  554. cTypes * sizeof(IMAGE_RESOURCE_DIRECTORY) + /* subdir2 (names) */
  555. cNames * sizeof(IMAGE_RESOURCE_DIRECTORY_ENTRY) +
  556. cNames * sizeof(IMAGE_RESOURCE_DIRECTORY) + /* subdir3 (langs) */
  557. cRes * sizeof(IMAGE_RESOURCE_DIRECTORY_ENTRY) +
  558. (cbName + cbType) + /* name/type strings */
  559. cb + /* padding */
  560. cRes * sizeof(IMAGE_RESOURCE_DATA_ENTRY); /* data entries */
  561. cbResource += cbRestab; /* add in the resource table */
  562. // Find any current resource sections
  563. pObjResourceOld = FindSection(pObjtblOld, pObjLast, ".rsrc");
  564. pObjResourceOldX = FindSection(pObjtblOld, pObjLast, ".rsrc1");
  565. pObjOld = FindSection(pObjtblOld, pObjLast, ".reloc");
  566. if ((pObjResourceOld == NULL)) {
  567. cb = 0x7fffffff; /* can fill forever */
  568. } else if (pObjResourceOld + 1 == pObjResourceOldX) {
  569. nObjResource = (ULONG)(pObjResourceOld - pObjtblOld);
  570. DPrintf((DebugBuf,"Old Resource section #%lu\n", nObjResource+1));
  571. DPrintf((DebugBuf,"Merging old Resource extra section #%lu\n", nObjResource+2));
  572. cb = 0x7fffffff; /* merge resource sections */
  573. } else if ((pObjResourceOld + 1) >= pObjLast) {
  574. nObjResource = (ULONG)(pObjResourceOld - pObjtblOld);
  575. cb = 0x7fffffff; /* can fill forever (.rsrc is the last entry) */
  576. } else {
  577. nObjResource = (ULONG)(pObjResourceOld - pObjtblOld);
  578. DPrintf((DebugBuf,"Old Resource section #%lu\n", nObjResource+1));
  579. if (pObjOld) {
  580. cb = (pObjResourceOld+1)->VirtualAddress - pObjResourceOld->VirtualAddress;
  581. } else {
  582. cb = 0x7fffffff;
  583. }
  584. if (cbRestab > (ULONG)cb) {
  585. DPrintf((DebugBuf, "Resource Table Too Large\n"));
  586. return ERROR_INVALID_DATA;
  587. }
  588. }
  589. /*
  590. * Discover where the first discardable section is. This is where
  591. * we will stick any new resource section.
  592. *
  593. * Note that we are ignoring discardable sections such as .CRT -
  594. * this is so that we don't cause any relocation problems.
  595. * Let's hope that .reloc is the one we want!!!
  596. */
  597. if (pObjResourceOld != NULL && cbResource > (ULONG)cb) {
  598. if (pObjOld == pObjResourceOld + 1) {
  599. DPrintf((DebugBuf, "Large resource section pushes .reloc\n"));
  600. cb = 0x7fffffff; /* can fill forever */
  601. } else if (pObjResourceOldX == NULL) {
  602. DPrintf((DebugBuf, "Too much resource data for old .rsrc section\n"));
  603. nObjResourceX = (ULONG)(pObjOld - pObjtblOld);
  604. adjust = pObjOld->VirtualAddress - pObjResourceOld->VirtualAddress;
  605. } else { /* have already merged .rsrc & .rsrc1, if possible */
  606. DPrintf((DebugBuf, ".rsrc1 section not empty\n"));
  607. nObjResourceX = (ULONG)(pObjResourceOldX - pObjtblOld);
  608. adjust = pObjResourceOldX->VirtualAddress - pObjResourceOld ->VirtualAddress;
  609. }
  610. }
  611. /*
  612. * Walk the type lists and figure out where the Data entry header will
  613. * go. Keep a running total of the size for each data element so we
  614. * can store this in the section header.
  615. */
  616. DPrintf((DebugBuf, "Beginning loop to assign resources to addresses\n"));
  617. /* first, those in the named type list */
  618. cbResource = cbRestab; /* assign resource table to 1st rsrc section */
  619. /* adjust == offset to .rsrc1 */
  620. /* cb == size availble in .rsrc */
  621. cbNew = 0; /* count of bytes in second .rsrc */
  622. DPrintf((DebugBuf, "Walk type: NAME list\n"));
  623. pType = pUpdate->ResTypeHeadName;
  624. while (pType != NULL) {
  625. if (pType->NameHeadName != NULL || pType->NameHeadID != NULL) {
  626. DPrintf((DebugBuf, "Resource type "));
  627. DPrintfu((pType->Type->szStr));
  628. DPrintfn((DebugBuf, "\n"));
  629. pRes = pType->NameHeadName;
  630. while (pRes) {
  631. DPrintf((DebugBuf, "Resource "));
  632. DPrintfu((pRes->Name->szStr));
  633. DPrintfn((DebugBuf, "\n"));
  634. cbResource = AssignResourceToSection(&pRes, adjust, cbResource, cb, &cbNew);
  635. }
  636. pRes = pType->NameHeadID;
  637. while (pRes) {
  638. DPrintf((DebugBuf, "Resource %hu\n", pRes->Name->uu.Ordinal));
  639. cbResource = AssignResourceToSection(&pRes, adjust, cbResource, cb, &cbNew);
  640. }
  641. }
  642. pType = pType->pnext;
  643. }
  644. /* then, count those in the ID type list */
  645. DPrintf((DebugBuf, "Walk type: ID list\n"));
  646. pType = pUpdate->ResTypeHeadID;
  647. while (pType != NULL) {
  648. if (pType->NameHeadName != NULL || pType->NameHeadID != NULL) {
  649. DPrintf((DebugBuf, "Resource type %hu\n", pType->Type->uu.Ordinal));
  650. pRes = pType->NameHeadName;
  651. while (pRes) {
  652. DPrintf((DebugBuf, "Resource "));
  653. DPrintfu((pRes->Name->szStr));
  654. DPrintfn((DebugBuf, "\n"));
  655. cbResource = AssignResourceToSection(&pRes, adjust, cbResource, cb, &cbNew);
  656. }
  657. pRes = pType->NameHeadID;
  658. while (pRes) {
  659. DPrintf((DebugBuf, "Resource %hu\n", pRes->Name->uu.Ordinal));
  660. cbResource = AssignResourceToSection(&pRes, adjust, cbResource, cb, &cbNew);
  661. }
  662. }
  663. pType = pType->pnext;
  664. }
  665. /*
  666. * At this point:
  667. * cbResource has offset of first byte past the last resource.
  668. * cbNew has the count of bytes in the first resource section,
  669. * if there are two sections.
  670. */
  671. if (cbNew == 0)
  672. cbNew = cbResource;
  673. /*
  674. * Discover where the Debug info is (if any)?
  675. */
  676. pObjDebug = FindSection(pObjtblOld, pObjLast, ".debug");
  677. if (pObjDebug != NULL) {
  678. if (Old.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress == 0) {
  679. DPrintf((DebugBuf, ".debug section but no debug directory\n"));
  680. return ERROR_INVALID_DATA;
  681. }
  682. if (pObjDebug != pObjLast-1) {
  683. DPrintf((DebugBuf, "debug section not last section in file\n"));
  684. return ERROR_INVALID_DATA;
  685. }
  686. DPrintf((DebugBuf, "Debug section: %#08lx bytes @%#08lx\n",
  687. pObjDebug->SizeOfRawData,
  688. pObjDebug->PointerToRawData));
  689. }
  690. pObjDebugDirOld = NULL;
  691. for (pObjOld=pObjtblOld ; pObjOld<pObjLast ; pObjOld++) {
  692. if (Old.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress >= pObjOld->VirtualAddress &&
  693. Old.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress < pObjOld->VirtualAddress+pObjOld->SizeOfRawData) {
  694. pObjDebugDirOld = pObjOld;
  695. break;
  696. }
  697. }
  698. /*
  699. * Discover where the first discardable section is. This is where
  700. * we will stick any new resource section.
  701. *
  702. * Note that we are ignoring discardable sections such as .CRT -
  703. * this is so that we don't cause any relocation problems.
  704. * Let's hope that .reloc is the one we want!!!
  705. */
  706. pObjOld = FindSection(pObjtblOld, pObjLast, ".reloc");
  707. if (nObjResource == -1) { /* no old resource section */
  708. if (pObjOld != NULL)
  709. nObjResource = (ULONG)(pObjOld - pObjtblOld);
  710. else if (pObjDebug != NULL)
  711. nObjResource = (ULONG)(pObjDebug - pObjtblOld);
  712. else
  713. nObjResource = New.FileHeader.NumberOfSections;
  714. New.FileHeader.NumberOfSections++;
  715. }
  716. DPrintf((DebugBuf, "Resources assigned to section #%lu\n", nObjResource+1));
  717. if (nObjResourceX != -1) {
  718. if (pObjResourceOldX != NULL) {
  719. nObjResourceX = (ULONG)(pObjResourceOldX - pObjtblOld);
  720. New.FileHeader.NumberOfSections--;
  721. } else if (pObjOld != NULL)
  722. nObjResourceX = (ULONG)(pObjOld - pObjtblOld);
  723. else if (pObjDebug != NULL)
  724. nObjResourceX = (ULONG)(pObjDebug - pObjtblOld);
  725. else
  726. nObjResourceX = New.FileHeader.NumberOfSections;
  727. New.FileHeader.NumberOfSections++;
  728. DPrintf((DebugBuf, "Extra resources assigned to section #%lu\n", nObjResourceX+1));
  729. } else if (pObjResourceOldX != NULL) { /* Was old .rsrc1 section? */
  730. DPrintf((DebugBuf, "Extra resource section deleted\n"));
  731. New.FileHeader.NumberOfSections--; /* yes, delete it */
  732. }
  733. /*
  734. * If we had to add anything to the header (section table),
  735. * then we have to update the header size and rva's in the header.
  736. */
  737. adjust = (New.FileHeader.NumberOfSections - Old.FileHeader.NumberOfSections) * sizeof(IMAGE_SECTION_HEADER);
  738. cb = Old.OptionalHeader.SizeOfHeaders -
  739. (Old.FileHeader.NumberOfSections*sizeof(IMAGE_SECTION_HEADER) +
  740. sizeof(NT_HEADER_TYPE) + cbOldexe );
  741. if (adjust > (ULONG)cb) {
  742. int i;
  743. adjust -= cb;
  744. DPrintf((DebugBuf, "Adjusting header RVAs by %#08lx\n", adjust));
  745. for (i = 0; i < IMAGE_NUMBEROF_DIRECTORY_ENTRIES ; i++) {
  746. if (New.OptionalHeader.DataDirectory[i].VirtualAddress &&
  747. New.OptionalHeader.DataDirectory[i].VirtualAddress < New.OptionalHeader.SizeOfHeaders) {
  748. DPrintf((DebugBuf, "Adjusting unit[%s] RVA from %#08lx to %#08lx\n",
  749. apszUnit[i],
  750. New.OptionalHeader.DataDirectory[i].VirtualAddress,
  751. New.OptionalHeader.DataDirectory[i].VirtualAddress + adjust));
  752. New.OptionalHeader.DataDirectory[i].VirtualAddress += adjust;
  753. }
  754. }
  755. New.OptionalHeader.SizeOfHeaders += adjust;
  756. } else if (adjust > 0) {
  757. int i;
  758. //
  759. // Loop over DataDirectory entries and look for any entries that point to
  760. // information stored in the 'dead' space after the section table but before
  761. // the SizeOfHeaders length.
  762. //
  763. DPrintf((DebugBuf, "Checking header RVAs for 'dead' space usage\n"));
  764. for (i = 0; i < IMAGE_NUMBEROF_DIRECTORY_ENTRIES ; i++) {
  765. if (New.OptionalHeader.DataDirectory[i].VirtualAddress &&
  766. New.OptionalHeader.DataDirectory[i].VirtualAddress < Old.OptionalHeader.SizeOfHeaders) {
  767. DPrintf((DebugBuf, "Adjusting unit[%s] RVA from %#08lx to %#08lx\n",
  768. apszUnit[i],
  769. New.OptionalHeader.DataDirectory[i].VirtualAddress,
  770. New.OptionalHeader.DataDirectory[i].VirtualAddress + adjust));
  771. New.OptionalHeader.DataDirectory[i].VirtualAddress += adjust;
  772. }
  773. }
  774. }
  775. ibNewObjTabEnd += adjust;
  776. /* Allocate storage for new section table */
  777. cb = New.FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER);
  778. pObjtblNew = (PIMAGE_SECTION_HEADER)RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( RES_TAG ), (short)cb);
  779. if (pObjtblNew == NULL) {
  780. cb = ERROR_NOT_ENOUGH_MEMORY;
  781. goto AbortExit;
  782. }
  783. RtlZeroMemory((PVOID)pObjtblNew, cb);
  784. DPrintf((DebugBuf, "New section table: %#08lx bytes at %#08lx\n", cb, pObjtblNew));
  785. pObjResourceNew = pObjtblNew + nObjResource;
  786. /*
  787. * copy old section table to new
  788. */
  789. adjust = 0; /* adjustment to virtual address */
  790. for (pObjOld=pObjtblOld,pObjNew=pObjtblNew ; pObjOld<pObjLast ; pObjOld++) {
  791. if (pObjOld == pObjResourceOldX) {
  792. if (nObjResourceX == -1) {
  793. // we have to move back all the other section.
  794. // the .rsrc1 is bigger than what we need
  795. // adjust must be a negative number
  796. if (pObjOld+1 < pObjLast) {
  797. adjust -= (pObjOld+1)->VirtualAddress - pObjOld->VirtualAddress;
  798. }
  799. }
  800. continue;
  801. } else if (pObjNew == pObjResourceNew) {
  802. DPrintf((DebugBuf, "Resource Section %i\n", nObjResource+1));
  803. cb = ROUNDUP(cbNew, New.OptionalHeader.FileAlignment);
  804. if (pObjResourceOld == NULL) {
  805. adjust = ROUNDUP(cbNew, New.OptionalHeader.SectionAlignment);
  806. RtlZeroMemory(pObjNew, sizeof(IMAGE_SECTION_HEADER));
  807. strcpy((char *)pObjNew->Name, ".rsrc");
  808. pObjNew->VirtualAddress = pObjOld->VirtualAddress;
  809. pObjNew->PointerToRawData = pObjOld->PointerToRawData;
  810. pObjNew->Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_INITIALIZED_DATA;
  811. pObjNew->SizeOfRawData = cb;
  812. pObjNew->Misc.VirtualSize = cbNew;
  813. } else {
  814. *pObjNew = *pObjOld; /* copy obj table entry */
  815. pObjNew->SizeOfRawData = cb;
  816. pObjNew->Misc.VirtualSize = cbNew;
  817. if (pObjNew->SizeOfRawData == pObjOld->SizeOfRawData) {
  818. adjust = 0;
  819. } else if (pObjNew->SizeOfRawData > pObjOld->SizeOfRawData) {
  820. adjust += ROUNDUP(cbNew, New.OptionalHeader.SectionAlignment);
  821. if (pObjOld+1 < pObjLast) {
  822. // if there are more entries after pObjOld, shift those back as well
  823. adjust -= ((pObjOld+1)->VirtualAddress - pObjOld->VirtualAddress);
  824. }
  825. } else { /* is smaller, but pad so will be valid */
  826. adjust = 0;
  827. pObjNew->SizeOfRawData = pObjResourceOld->SizeOfRawData;
  828. /* if legoized, the VS could be > RawSize !!! */
  829. pObjNew->Misc.VirtualSize = pObjResourceOld->Misc.VirtualSize;
  830. cbMustPad = pObjResourceOld->SizeOfRawData;
  831. }
  832. }
  833. pObjNew++;
  834. if (pObjResourceOld == NULL)
  835. goto rest_of_table;
  836. } else if (nObjResourceX != -1 && pObjNew == pObjtblNew + nObjResourceX) {
  837. DPrintf((DebugBuf, "Additional Resource Section %i\n",
  838. nObjResourceX+1));
  839. RtlZeroMemory(pObjNew, sizeof(IMAGE_SECTION_HEADER));
  840. strcpy((char *)pObjNew->Name, ".rsrc1");
  841. /*
  842. * Before we copy the virtual address we have to move back the
  843. * .reloc * virtual address. Otherwise we will keep moving the
  844. * reloc VirtualAddress forward.
  845. * We will have to move back the address of .rsrc1
  846. */
  847. if (pObjResourceOldX == NULL) {
  848. // This is the first time we have a .rsrc1
  849. pObjNew->VirtualAddress = pObjOld->VirtualAddress;
  850. pObjNew->Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_INITIALIZED_DATA;
  851. adjust = ROUNDUP(cbResource, New.OptionalHeader.SectionAlignment) +
  852. pObjResourceNew->VirtualAddress - pObjNew->VirtualAddress;
  853. DPrintf((DebugBuf, "Added .rsrc1. VirtualAddress %lu\t adjust: %lu\n", pObjNew->VirtualAddress, adjust ));
  854. } else {
  855. // we already have an .rsrc1 use the position of that and
  856. // calculate the new adjust
  857. pObjNew->VirtualAddress = pObjResourceOldX->VirtualAddress;
  858. pObjNew->Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_INITIALIZED_DATA;
  859. DPrintf((DebugBuf, ".rsrc1 Keep old position.\t\tVirtualAddress %lu\t", pObjNew->VirtualAddress ));
  860. // Check if we have enough room in the old .rsrc1
  861. // Include the full size of the section, data + roundup
  862. if (cbResource -
  863. (pObjResourceOldX->VirtualAddress - pObjResourceOld->VirtualAddress) <=
  864. pObjOld->VirtualAddress - pObjNew->VirtualAddress ) {
  865. // we have to move back all the other section.
  866. // the .rsrc1 is bigger than what we need
  867. // adjust must be a negative number
  868. // calc new adjust size
  869. adjust = ROUNDUP(cbResource, New.OptionalHeader.SectionAlignment) +
  870. pObjResourceNew->VirtualAddress -
  871. pObjOld->VirtualAddress;
  872. DPrintf((DebugBuf, "adjust: %ld\tsmall: New %lu\tOld %lu\n", adjust,
  873. cbResource -
  874. (pObjResourceOldX->VirtualAddress - pObjResourceOld->VirtualAddress),
  875. pObjOld->VirtualAddress - pObjNew->VirtualAddress));
  876. } else {
  877. // we have to move the section again.
  878. // The .rsrc1 is too small
  879. adjust = ROUNDUP(cbResource, New.OptionalHeader.SectionAlignment) +
  880. pObjResourceNew->VirtualAddress -
  881. pObjOld->VirtualAddress;
  882. DPrintf((DebugBuf, "adjust: %lu\tsmall: New %lu\tOld %lu\n", adjust,
  883. cbResource -
  884. (pObjResourceOldX->VirtualAddress - pObjResourceOld->VirtualAddress),
  885. pObjOld->VirtualAddress - pObjNew->VirtualAddress));
  886. }
  887. }
  888. pObjNew++;
  889. goto rest_of_table;
  890. } else if (pObjNew < pObjResourceNew) {
  891. DPrintf((DebugBuf, "copying section table entry %i@%#08lx\n",
  892. pObjOld - pObjtblOld + 1, pObjNew));
  893. *pObjNew++ = *pObjOld; /* copy obj table entry */
  894. } else {
  895. rest_of_table:
  896. DPrintf((DebugBuf, "copying section table entry %i@%#08lx\n",
  897. pObjOld - pObjtblOld + 1, pObjNew));
  898. DPrintf((DebugBuf, "adjusting VirtualAddress by %#08lx\n", adjust));
  899. *pObjNew++ = *pObjOld;
  900. (pObjNew-1)->VirtualAddress += adjust;
  901. }
  902. }
  903. pObjNew = pObjtblNew + New.FileHeader.NumberOfSections - 1;
  904. New.OptionalHeader.SizeOfImage = ROUNDUP(pObjNew->VirtualAddress +
  905. pObjNew->SizeOfRawData,
  906. New.OptionalHeader.SectionAlignment);
  907. /* allocate room to build the resource directory/tables in */
  908. pResTab = (PIMAGE_RESOURCE_DIRECTORY)RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( RES_TAG ), cbRestab);
  909. if (pResTab == NULL) {
  910. cb = ERROR_NOT_ENOUGH_MEMORY;
  911. goto AbortExit;
  912. }
  913. /* First, setup the "root" type directory table. It will be followed by */
  914. /* Types directory entries. */
  915. RtlZeroMemory((PVOID)pResTab, cbRestab);
  916. DPrintf((DebugBuf, "resource directory tables: %#08lx bytes at %#08lx(mem)\n", cbRestab, pResTab));
  917. p = (PUCHAR)pResTab;
  918. SetRestab(pResTab, clock, (USHORT)cTypeStr, (USHORT)(cTypes - cTypeStr));
  919. /* Calculate the start of the various parts of the resource table. */
  920. /* We need the start of the Type/Name/Language directories as well */
  921. /* as the start of the UNICODE strings and the actual data nodes. */
  922. pResDirT = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(pResTab + 1);
  923. pResDirN = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(((PUCHAR)pResDirT) +
  924. cTypes * sizeof(IMAGE_RESOURCE_DIRECTORY_ENTRY));
  925. pResDirL = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(((PUCHAR)pResDirN) +
  926. cTypes * sizeof(IMAGE_RESOURCE_DIRECTORY) +
  927. cNames * sizeof(IMAGE_RESOURCE_DIRECTORY_ENTRY));
  928. pResData = (PIMAGE_RESOURCE_DATA_ENTRY)(((PUCHAR)pResDirL) +
  929. cNames * sizeof(IMAGE_RESOURCE_DIRECTORY) +
  930. cRes * sizeof(IMAGE_RESOURCE_DIRECTORY_ENTRY));
  931. pResStr = (PUSHORT)(((PUCHAR)pResData) +
  932. cRes * sizeof(IMAGE_RESOURCE_DATA_ENTRY));
  933. pResStrEnd = (PUSHORT)(((PUCHAR)pResStr) + cbName + cbType);
  934. /*
  935. * Loop over type table, building the PE resource table.
  936. */
  937. /*
  938. * *****************************************************************
  939. * This code doesn't sort the table - the TYPEINFO and RESINFO **
  940. * insertion code in rcp.c (AddResType and SaveResFile) do the **
  941. * insertion by ordinal type and name, so we don't have to sort **
  942. * it at this point. **
  943. * *****************************************************************
  944. */
  945. DPrintf((DebugBuf, "building resource directory\n"));
  946. // First, add all the entries in the Types: Alpha list.
  947. DPrintf((DebugBuf, "Walk the type: Alpha list\n"));
  948. pType = pUpdate->ResTypeHeadName;
  949. while (pType) {
  950. DPrintf((DebugBuf, "resource type "));
  951. DPrintfu((pType->Type->szStr));
  952. DPrintfn((DebugBuf, "\n"));
  953. pResDirT->Name = (ULONG)((((PUCHAR)pResStr) - p) |
  954. IMAGE_RESOURCE_NAME_IS_STRING);
  955. pResDirT->OffsetToData = (ULONG)((((PUCHAR)pResDirN) - p) |
  956. IMAGE_RESOURCE_DATA_IS_DIRECTORY);
  957. pResDirT++;
  958. *pResStr = pType->Type->cbsz;
  959. wcsncpy((WCHAR*)(pResStr+1), pType->Type->szStr, pType->Type->cbsz);
  960. pResStr += pType->Type->cbsz + 1;
  961. pResTabN = (PIMAGE_RESOURCE_DIRECTORY)pResDirN;
  962. SetRestab(pResTabN, clock, (USHORT)pType->NumberOfNamesName, (USHORT)pType->NumberOfNamesID);
  963. pResDirN = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(pResTabN + 1);
  964. pPreviousName = NULL;
  965. pRes = pType->NameHeadName;
  966. while (pRes) {
  967. DPrintf((DebugBuf, "resource "));
  968. DPrintfu((pRes->Name->szStr));
  969. DPrintfn((DebugBuf, "\n"));
  970. if (pPreviousName == NULL || wcscmp(pPreviousName->szStr,pRes->Name->szStr) != 0) {
  971. // Setup a new name directory
  972. pResDirN->Name = (ULONG)((((PUCHAR)pResStr)-p) |
  973. IMAGE_RESOURCE_NAME_IS_STRING);
  974. pResDirN->OffsetToData = (ULONG)((((PUCHAR)pResDirL)-p) |
  975. IMAGE_RESOURCE_DATA_IS_DIRECTORY);
  976. pResDirN++;
  977. // Copy the alpha name to a string entry
  978. *pResStr = pRes->Name->cbsz;
  979. wcsncpy((WCHAR*)(pResStr+1),pRes->Name->szStr,pRes->Name->cbsz);
  980. pResStr += pRes->Name->cbsz + 1;
  981. pPreviousName = pRes->Name;
  982. // Setup the Language table
  983. pResTabL = (PIMAGE_RESOURCE_DIRECTORY)pResDirL;
  984. SetRestab(pResTabL, clock, (USHORT)0, (USHORT)pRes->NumberOfLanguages);
  985. pResDirL = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(pResTabL + 1);
  986. }
  987. // Setup a new Language directory
  988. pResDirL->Name = pRes->LanguageId;
  989. pResDirL->OffsetToData = (ULONG)(((PUCHAR)pResData) - p);
  990. pResDirL++;
  991. // Setup a new resource data entry
  992. SetResdata(pResData,
  993. pRes->OffsetToData+pObjtblNew[nObjResource].VirtualAddress,
  994. pRes->DataSize);
  995. pResData++;
  996. pRes = pRes->pnext;
  997. }
  998. pPreviousName = NULL;
  999. pRes = pType->NameHeadID;
  1000. while (pRes) {
  1001. DPrintf((DebugBuf, "resource %hu\n", pRes->Name->uu.Ordinal));
  1002. if (pPreviousName == NULL || pPreviousName->uu.Ordinal != pRes->Name->uu.Ordinal) {
  1003. // Setup the name directory to point to the next language
  1004. // table
  1005. pResDirN->Name = pRes->Name->uu.Ordinal;
  1006. pResDirN->OffsetToData = (ULONG)((((PUCHAR)pResDirL)-p) |
  1007. IMAGE_RESOURCE_DATA_IS_DIRECTORY);
  1008. pResDirN++;
  1009. pPreviousName = pRes->Name;
  1010. // Init a new Language table
  1011. pResTabL = (PIMAGE_RESOURCE_DIRECTORY)pResDirL;
  1012. SetRestab(pResTabL, clock, (USHORT)0, (USHORT)pRes->NumberOfLanguages);
  1013. pResDirL = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(pResTabL + 1);
  1014. }
  1015. // Setup a new language directory entry to point to the next
  1016. // resource
  1017. pResDirL->Name = pRes->LanguageId;
  1018. pResDirL->OffsetToData = (ULONG)(((PUCHAR)pResData) - p);
  1019. pResDirL++;
  1020. // Setup a new resource data entry
  1021. SetResdata(pResData,
  1022. pRes->OffsetToData+pObjtblNew[nObjResource].VirtualAddress,
  1023. pRes->DataSize);
  1024. pResData++;
  1025. pRes = pRes->pnext;
  1026. }
  1027. pType = pType->pnext;
  1028. }
  1029. // Do the same thing, but this time, use the Types: ID list.
  1030. DPrintf((DebugBuf, "Walk the type: ID list\n"));
  1031. pType = pUpdate->ResTypeHeadID;
  1032. while (pType) {
  1033. DPrintf((DebugBuf, "resource type %hu\n", pType->Type->uu.Ordinal));
  1034. pResDirT->Name = (ULONG)pType->Type->uu.Ordinal;
  1035. pResDirT->OffsetToData = (ULONG)((((PUCHAR)pResDirN) - p) |
  1036. IMAGE_RESOURCE_DATA_IS_DIRECTORY);
  1037. pResDirT++;
  1038. pResTabN = (PIMAGE_RESOURCE_DIRECTORY)pResDirN;
  1039. SetRestab(pResTabN, clock, (USHORT)pType->NumberOfNamesName, (USHORT)pType->NumberOfNamesID);
  1040. pResDirN = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(pResTabN + 1);
  1041. pPreviousName = NULL;
  1042. pRes = pType->NameHeadName;
  1043. while (pRes) {
  1044. DPrintf((DebugBuf, "resource "));
  1045. DPrintfu((pRes->Name->szStr));
  1046. DPrintfn((DebugBuf, "\n"));
  1047. if (pPreviousName == NULL || wcscmp(pPreviousName->szStr,pRes->Name->szStr) != 0) {
  1048. // Setup a new name directory
  1049. pResDirN->Name = (ULONG)((((PUCHAR)pResStr)-p) |
  1050. IMAGE_RESOURCE_NAME_IS_STRING);
  1051. pResDirN->OffsetToData = (ULONG)((((PUCHAR)pResDirL)-p) |
  1052. IMAGE_RESOURCE_DATA_IS_DIRECTORY);
  1053. pResDirN++;
  1054. // Copy the alpha name to a string entry.
  1055. *pResStr = pRes->Name->cbsz;
  1056. wcsncpy((WCHAR*)(pResStr+1),pRes->Name->szStr,pRes->Name->cbsz);
  1057. pResStr += pRes->Name->cbsz + 1;
  1058. pPreviousName = pRes->Name;
  1059. // Setup the Language table
  1060. pResTabL = (PIMAGE_RESOURCE_DIRECTORY)pResDirL;
  1061. SetRestab(pResTabL, clock, (USHORT)0, (USHORT)pRes->NumberOfLanguages);
  1062. pResDirL = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(pResTabL + 1);
  1063. }
  1064. // Setup a new Language directory
  1065. pResDirL->Name = pRes->LanguageId;
  1066. pResDirL->OffsetToData = (ULONG)(((PUCHAR)pResData) - p);
  1067. pResDirL++;
  1068. // Setup a new resource data entry
  1069. SetResdata(pResData,
  1070. pRes->OffsetToData+pObjtblNew[nObjResource].VirtualAddress,
  1071. pRes->DataSize);
  1072. pResData++;
  1073. pRes = pRes->pnext;
  1074. }
  1075. pPreviousName = NULL;
  1076. pRes = pType->NameHeadID;
  1077. while (pRes) {
  1078. DPrintf((DebugBuf, "resource %hu\n", pRes->Name->uu.Ordinal));
  1079. if (pPreviousName == NULL || pPreviousName->uu.Ordinal != pRes->Name->uu.Ordinal) {
  1080. // Setup the name directory to point to the next language
  1081. // table
  1082. pResDirN->Name = pRes->Name->uu.Ordinal;
  1083. pResDirN->OffsetToData = (ULONG)((((PUCHAR)pResDirL)-p) |
  1084. IMAGE_RESOURCE_DATA_IS_DIRECTORY);
  1085. pResDirN++;
  1086. pPreviousName = pRes->Name;
  1087. // Init a new Language table
  1088. pResTabL = (PIMAGE_RESOURCE_DIRECTORY)pResDirL;
  1089. SetRestab(pResTabL, clock, (USHORT)0, (USHORT)pRes->NumberOfLanguages);
  1090. pResDirL = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(pResTabL + 1);
  1091. }
  1092. // Setup a new language directory entry to point to the next
  1093. // resource
  1094. pResDirL->Name = pRes->LanguageId;
  1095. pResDirL->OffsetToData = (ULONG)(((PUCHAR)pResData) - p);
  1096. pResDirL++;
  1097. // Setup a new resource data entry
  1098. SetResdata(pResData,
  1099. pRes->OffsetToData+pObjtblNew[nObjResource].VirtualAddress,
  1100. pRes->DataSize);
  1101. pResData++;
  1102. pRes = pRes->pnext;
  1103. }
  1104. pType = pType->pnext;
  1105. }
  1106. DPrintf((DebugBuf, "Zeroing %u bytes after strings at %#08lx(mem)\n",
  1107. (pResStrEnd - pResStr) * sizeof(*pResStr), pResStr));
  1108. while (pResStr < pResStrEnd) {
  1109. *pResStr++ = 0;
  1110. }
  1111. #if DBG
  1112. {
  1113. USHORT j = 0;
  1114. PUSHORT pus = (PUSHORT)pResTab;
  1115. while (pus < (PUSHORT)pResData) {
  1116. DPrintf((DebugBuf, "%04x\t%04x %04x %04x %04x %04x %04x %04x %04x\n",
  1117. j,
  1118. *pus,
  1119. *(pus + 1),
  1120. *(pus + 2),
  1121. *(pus + 3),
  1122. *(pus + 4),
  1123. *(pus + 5),
  1124. *(pus + 6),
  1125. *(pus + 7)));
  1126. pus += 8;
  1127. j += 16;
  1128. }
  1129. }
  1130. #endif /* DBG */
  1131. /*
  1132. * copy the Old exe header and stub, and allocate room for the PE header.
  1133. */
  1134. DPrintf((DebugBuf, "copying through PE header: %#08lx bytes @0x0\n",
  1135. cbOldexe + sizeof(NT_HEADER_TYPE)));
  1136. MuMoveFilePos(inpfh, 0L);
  1137. MuCopy(inpfh, outfh, cbOldexe + sizeof(NT_HEADER_TYPE));
  1138. /*
  1139. * Copy rest of file header
  1140. */
  1141. DPrintf((DebugBuf, "skipping section table: %#08lx bytes @%#08lx\n",
  1142. New.FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER),
  1143. FilePos(outfh)));
  1144. DPrintf((DebugBuf, "copying hdr data: %#08lx bytes @%#08lx ==> @%#08lx\n",
  1145. Old.OptionalHeader.SizeOfHeaders - ibObjTabEnd,
  1146. ibObjTabEnd,
  1147. ibObjTabEnd + New.OptionalHeader.SizeOfHeaders -
  1148. Old.OptionalHeader.SizeOfHeaders));
  1149. MuMoveFilePos(outfh, ibNewObjTabEnd + New.OptionalHeader.SizeOfHeaders -
  1150. Old.OptionalHeader.SizeOfHeaders);
  1151. MuMoveFilePos(inpfh, ibObjTabEnd);
  1152. MuCopy(inpfh, outfh, Old.OptionalHeader.SizeOfHeaders - ibNewObjTabEnd);
  1153. /*
  1154. * copy existing image sections
  1155. */
  1156. /* Align data sections on sector boundary */
  1157. cb = REMAINDER(New.OptionalHeader.SizeOfHeaders, New.OptionalHeader.FileAlignment);
  1158. New.OptionalHeader.SizeOfHeaders += cb;
  1159. DPrintf((DebugBuf, "padding header with %#08lx bytes @%#08lx\n", cb, FilePos(outfh)));
  1160. while (cb >= cbPadMax) {
  1161. MuWrite(outfh, pchZero, cbPadMax);
  1162. cb -= cbPadMax;
  1163. }
  1164. MuWrite(outfh, pchZero, cb);
  1165. cb = ROUNDUP(Old.OptionalHeader.SizeOfHeaders, Old.OptionalHeader.FileAlignment);
  1166. MuMoveFilePos(inpfh, cb);
  1167. /* copy one section at a time */
  1168. New.OptionalHeader.SizeOfInitializedData = 0;
  1169. for (pObjOld = pObjtblOld , pObjNew = pObjtblNew ;
  1170. pObjOld < pObjLast ;
  1171. pObjNew++) {
  1172. if (pObjOld == pObjResourceOldX)
  1173. pObjOld++;
  1174. if (pObjNew == pObjResourceNew) {
  1175. /* Write new resource section */
  1176. DPrintf((DebugBuf, "Primary resource section %i to %#08lx\n", nObjResource+1, FilePos(outfh)));
  1177. pObjNew->PointerToRawData = FilePos(outfh);
  1178. New.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress = pObjResourceNew->VirtualAddress;
  1179. New.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = cbResource;
  1180. ibSave = FilePos(outfh);
  1181. DPrintf((DebugBuf, "writing resource header data: %#08lx bytes @%#08lx\n", cbRestab, ibSave));
  1182. MuWrite(outfh, (PUCHAR)pResTab, cbRestab);
  1183. pResSave = WriteResSection(pUpdate, outfh,
  1184. New.OptionalHeader.FileAlignment,
  1185. pObjResourceNew->SizeOfRawData-cbRestab,
  1186. NULL);
  1187. cb = FilePos(outfh);
  1188. DPrintf((DebugBuf, "wrote resource data: %#08lx bytes @%#08lx\n",
  1189. cb - ibSave - cbRestab, ibSave + cbRestab));
  1190. if (cbMustPad != 0) {
  1191. cbMustPad -= cb - ibSave;
  1192. DPrintf((DebugBuf, "writing MUNGE pad: %#04lx bytes @%#08lx\n",
  1193. cbMustPad, cb));
  1194. /* assumes that cbMustPad % cbpadMax == 0 */
  1195. while (cbMustPad > 0) {
  1196. MuWrite(outfh, pchZero, cbPadMax);
  1197. cbMustPad -= cbPadMax;
  1198. }
  1199. cb = FilePos(outfh);
  1200. }
  1201. if (nObjResourceX == -1) {
  1202. MuMoveFilePos(outfh, ibSave);
  1203. DPrintf((DebugBuf,
  1204. "re-writing resource directory: %#08x bytes @%#08lx\n",
  1205. cbRestab, ibSave));
  1206. MuWrite(outfh, (PUCHAR)pResTab, cbRestab);
  1207. MuMoveFilePos(outfh, cb);
  1208. cb = FilePos(inpfh);
  1209. MuMoveFilePos(inpfh, cb+pObjOld->SizeOfRawData);
  1210. }
  1211. New.OptionalHeader.SizeOfInitializedData += pObjNew->SizeOfRawData;
  1212. if (pObjResourceOld == NULL) {
  1213. pObjNew++;
  1214. goto next_section;
  1215. } else
  1216. pObjOld++;
  1217. } else if (nObjResourceX != -1 && pObjNew == pObjtblNew + nObjResourceX) {
  1218. /* Write new resource section */
  1219. DPrintf((DebugBuf, "Secondary resource section %i @%#08lx\n", nObjResourceX+1, FilePos(outfh)));
  1220. pObjNew->PointerToRawData = FilePos(outfh);
  1221. (void)WriteResSection(pUpdate, outfh,
  1222. New.OptionalHeader.FileAlignment, 0xffffffff, pResSave);
  1223. cb = FilePos(outfh);
  1224. pObjNew->SizeOfRawData = cb - pObjNew->PointerToRawData;
  1225. pObjNew->Misc.VirtualSize = pObjNew->SizeOfRawData;
  1226. DPrintf((DebugBuf, "wrote resource data: %#08lx bytes @%#08lx\n",
  1227. pObjNew->SizeOfRawData, pObjNew->PointerToRawData));
  1228. MuMoveFilePos(outfh, ibSave);
  1229. DPrintf((DebugBuf,
  1230. "re-writing resource directory: %#08x bytes @%#08lx\n",
  1231. cbRestab, ibSave));
  1232. MuWrite(outfh, (PUCHAR)pResTab, cbRestab);
  1233. MuMoveFilePos(outfh, cb);
  1234. New.OptionalHeader.SizeOfInitializedData += pObjNew->SizeOfRawData;
  1235. pObjNew++;
  1236. goto next_section;
  1237. } else {
  1238. if (pObjNew < pObjResourceNew &&
  1239. pObjOld->PointerToRawData != 0 &&
  1240. pObjOld->PointerToRawData != FilePos(outfh)) {
  1241. MuMoveFilePos(outfh, pObjOld->PointerToRawData);
  1242. }
  1243. next_section:
  1244. DPrintf((DebugBuf, "copying section %i @%#08lx\n", pObjNew-pObjtblNew+1, FilePos(outfh)));
  1245. if (pObjOld->PointerToRawData != 0) {
  1246. pObjNew->PointerToRawData = FilePos(outfh);
  1247. MuMoveFilePos(inpfh, pObjOld->PointerToRawData);
  1248. MuCopy(inpfh, outfh, pObjOld->SizeOfRawData);
  1249. }
  1250. if (pObjOld == pObjDebugDirOld) {
  1251. pObjDebugDirNew = pObjNew;
  1252. }
  1253. if ((pObjNew->Characteristics&IMAGE_SCN_CNT_INITIALIZED_DATA) != 0)
  1254. New.OptionalHeader.SizeOfInitializedData += pObjNew->SizeOfRawData;
  1255. pObjOld++;
  1256. }
  1257. }
  1258. if (pObjResourceOldX != NULL)
  1259. New.OptionalHeader.SizeOfInitializedData -= pObjResourceOldX->SizeOfRawData;
  1260. /* Update the address of the relocation table */
  1261. pObjNew = FindSection(pObjtblNew,
  1262. pObjtblNew+New.FileHeader.NumberOfSections,
  1263. ".reloc");
  1264. if (pObjNew != NULL) {
  1265. New.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = pObjNew->VirtualAddress;
  1266. }
  1267. /*
  1268. * Write new section table out.
  1269. */
  1270. DPrintf((DebugBuf, "Writing new section table: %#08x bytes @%#08lx\n",
  1271. New.FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER),
  1272. ibObjTab));
  1273. MuMoveFilePos(outfh, ibObjTab);
  1274. MuWrite(outfh, (PUCHAR)pObjtblNew, New.FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER));
  1275. /* Seek to end of output file and issue truncating write */
  1276. adjust = _llseek(outfh, 0L, SEEK_END);
  1277. MuWrite(outfh, NULL, 0);
  1278. DPrintf((DebugBuf, "File size is: %#08lx\n", adjust));
  1279. /* If a debug section, fix up the debug table */
  1280. pObjNew = FindSection(pObjtblNew, pObjtblNew+New.FileHeader.NumberOfSections, ".debug");
  1281. cb = PatchDebug(inpfh, outfh, pObjDebug, pObjNew, pObjDebugDirOld, pObjDebugDirNew,
  1282. &Old, &New, ibMaxDbgOffsetOld, &adjust);
  1283. if (cb == NO_ERROR) {
  1284. if (pObjResourceOld == NULL) {
  1285. cb = (LONG)pObjResourceNew->SizeOfRawData;
  1286. } else {
  1287. cb = (LONG)pObjResourceOld->SizeOfRawData - (LONG)pObjResourceNew->SizeOfRawData;
  1288. }
  1289. cb = PatchRVAs(inpfh, outfh, pObjtblNew, cb, &New, Old.OptionalHeader.SizeOfHeaders);
  1290. }
  1291. /* copy NOTMAPPED debug info */
  1292. if ((pObjDebugDirOld != NULL) &&
  1293. (pObjDebug == NULL) &&
  1294. (New.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size != 0)) {
  1295. ULONG ibt;
  1296. ibSave = _llseek(inpfh, 0L, SEEK_END); /* copy debug data */
  1297. ibt = _llseek(outfh, 0L, SEEK_END); /* to EOF */
  1298. if (New.FileHeader.PointerToSymbolTable != 0) {
  1299. New.FileHeader.PointerToSymbolTable += ibt - adjust;
  1300. }
  1301. MuMoveFilePos(inpfh, adjust); /* returned by PatchDebug */
  1302. DPrintf((DebugBuf, "Copying NOTMAPPED Debug Information, %#08lx bytes\n", ibSave-adjust));
  1303. MuCopy(inpfh, outfh, ibSave-adjust);
  1304. }
  1305. //
  1306. // Write updated PE header.
  1307. //
  1308. MuMoveFilePos(outfh, cbOldexe);
  1309. MuWrite(outfh, (char*)&New, sizeof(NT_HEADER_TYPE));
  1310. /* free up allocated memory */
  1311. RtlFreeHeap(RtlProcessHeap(), 0, pObjtblOld);
  1312. RtlFreeHeap(RtlProcessHeap(), 0, pResTab);
  1313. AbortExit:
  1314. RtlFreeHeap(RtlProcessHeap(), 0, pObjtblNew);
  1315. return cb;
  1316. }