Leaked source code of windows server 2003
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.

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