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.

1030 lines
30 KiB

  1. #include "stdinc.h"
  2. static const char File[] = __FILE__;
  3. #include "delayload_tool.h"
  4. #include "fusionstring.h"
  5. #include "setfilepointerex.c"
  6. #include "getfilesizeex.c"
  7. #include <assert.h>
  8. #include "delayimp.h"
  9. #include "imagehlp.h"
  10. #define BITS_OF(x) (sizeof(x) * 8)
  11. String_t GetErrorString(DWORD Error);
  12. //
  13. // delayimp.h doesn't work when tool bitness != image bitness
  14. //
  15. typedef ULONG32 PImgThunkData32;
  16. typedef ULONG32 PCImgThunkData32;
  17. typedef ULONG32 LPCSTR32;
  18. typedef ULONG32 PHMODULE32;
  19. typedef ULONG64 PImgThunkData64;
  20. typedef ULONG64 PCImgThunkData64;
  21. typedef ULONG64 LPCSTR64;
  22. typedef ULONG64 PHMODULE64;
  23. typedef struct ImgDelayDescrV1_32 {
  24. DWORD grAttrs; // attributes
  25. LPCSTR32 szName; // pointer to dll name
  26. PHMODULE32 phmod; // address of module handle
  27. PImgThunkData32 pIAT; // address of the IAT
  28. PCImgThunkData32 pINT; // address of the INT
  29. PCImgThunkData32 pBoundIAT; // address of the optional bound IAT
  30. PCImgThunkData32 pUnloadIAT; // address of optional copy of original IAT
  31. DWORD dwTimeStamp; // 0 if not bound,
  32. // O.W. date/time stamp of DLL bound to (Old BIND)
  33. } ImgDelayDescrV1_32, * PImgDelayDescrV1_32;
  34. typedef struct ImgDelayDescrV1_64 {
  35. DWORD grAttrs; // attributes
  36. LPCSTR64 szName; // pointer to dll name
  37. PHMODULE64 phmod; // address of module handle
  38. PImgThunkData64 pIAT; // address of the IAT
  39. PCImgThunkData64 pINT; // address of the INT
  40. PCImgThunkData64 pBoundIAT; // address of the optional bound IAT
  41. PCImgThunkData64 pUnloadIAT; // address of optional copy of original IAT
  42. DWORD dwTimeStamp; // 0 if not bound,
  43. // O.W. date/time stamp of DLL bound to (Old BIND)
  44. } ImgDelayDescrV1_64, * PImgDelayDescrV1_64;
  45. //
  46. // get msvcrt.dll wildcard processing on the command line
  47. //
  48. extern "C" { int _dowildcard = 1; }
  49. void Spinner()
  50. {
  51. static char s[] = "-\\|/";
  52. static unsigned i;
  53. fprintf(stderr, "%c\r", s[i++ % (sizeof(s) - 1)]);
  54. }
  55. void Throw(PCWSTR s)
  56. {
  57. if (::IsDebuggerPresent())
  58. {
  59. DbgPrint("Throw(%ls)\n", s);
  60. DebugBreak();
  61. }
  62. throw (s);
  63. }
  64. void F::ThrowHresult(HRESULT hr)
  65. {
  66. if (::IsDebuggerPresent())
  67. {
  68. DbgPrint("ThrowHresult:0x%lx|%ld|%ls\n", hr, (hr & 0xffff), GetErrorString(hr).c_str());
  69. DebugBreak();
  70. }
  71. throw (hr);
  72. }
  73. void ThrowLastWin32Error()
  74. {
  75. DWORD dw = GetLastError();
  76. if (::IsDebuggerPresent())
  77. {
  78. DbgPrint("ThrowLastWin32Error:0x%lx|%ld|%ls\n", dw, dw, GetErrorString(dw).c_str());
  79. DebugBreak();
  80. }
  81. throw (dw);
  82. }
  83. void
  84. CollectDirectoryPathsNonRecursively(
  85. const String_t& directory,
  86. StringVector_t& paths
  87. )
  88. {
  89. WIN32_FIND_DATAW wfd;
  90. DFindFile FindFile;
  91. HRESULT hr = 0;
  92. String_t directory_slash_star = directory + L"\\*";
  93. if (FAILED(hr = FindFile.HrCreate(directory_slash_star, &wfd)))
  94. {
  95. FindFirstFileError_t err;
  96. err.m_hresult = hr;
  97. err.m_dwLastError = GetLastError();
  98. std::swap(err.m_strParameter, directory_slash_star);
  99. throw err;
  100. }
  101. directory_slash_star.clear();
  102. do
  103. {
  104. if (FusionpIsDotOrDotDot(wfd.cFileName))
  105. {
  106. continue;
  107. }
  108. if ((wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
  109. {
  110. paths.insert(paths.end(), directory + L"\\" + wfd.cFileName);
  111. }
  112. } while (::FindNextFileW(FindFile, &wfd));
  113. }
  114. typedef BOOL (CALLBACK * PFN_COLLECTION_FILE_PATHS_RECURSIVELY_FILTER)(PVOID FilterContext, PCWSTR Directory, WIN32_FIND_DATAW * wfd);
  115. void
  116. CollectFilePathsRecursivelyHelper(
  117. const String_t& directory,
  118. StringVector_t& paths,
  119. PFN_COLLECTION_FILE_PATHS_RECURSIVELY_FILTER Filter,
  120. PVOID FilterContext,
  121. WIN32_FIND_DATAW& wfd
  122. )
  123. {
  124. DFindFile FindFile;
  125. HRESULT hr = 0;
  126. String_t directory_slash_star = directory + L"\\*";
  127. if (FAILED(hr = FindFile.HrCreate(directory_slash_star, &wfd)))
  128. {
  129. FindFirstFileError_t err;
  130. err.m_hresult = hr;
  131. err.m_dwLastError = GetLastError();
  132. std::swap(err.m_strParameter, directory_slash_star);
  133. throw err;
  134. }
  135. directory_slash_star.clear();
  136. do
  137. {
  138. if (FusionpIsDotOrDotDot(wfd.cFileName))
  139. {
  140. continue;
  141. }
  142. if ((wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
  143. {
  144. if (Filter == NULL || (*Filter)(FilterContext, directory, &wfd))
  145. {
  146. CollectFilePathsRecursivelyHelper(directory + L"\\" + wfd.cFileName, paths, Filter, FilterContext, wfd);
  147. }
  148. }
  149. else
  150. {
  151. if (Filter == NULL || (*Filter)(FilterContext, directory, &wfd))
  152. {
  153. paths.insert(paths.end(), directory + L"\\" + wfd.cFileName);
  154. }
  155. }
  156. } while (::FindNextFileW(FindFile, &wfd));
  157. }
  158. void
  159. CollectFilePathsRecursively(
  160. const String_t& directory,
  161. StringVector_t& paths,
  162. PFN_COLLECTION_FILE_PATHS_RECURSIVELY_FILTER Filter,
  163. PVOID FilterContext
  164. )
  165. {
  166. WIN32_FIND_DATAW wfd;
  167. CollectFilePathsRecursivelyHelper(directory, paths, Filter, FilterContext, wfd);
  168. }
  169. void DelayloadToolAssertFailed(const char* Expression, const char* File, unsigned long Line)
  170. {
  171. fprintf(stderr, "ASSERTION FAILURE: File %s, Line %lu, Expression %s\n", File, Line, Expression);
  172. abort();
  173. }
  174. void DelayloadToolInternalErrorCheckFailed(const char* Expression, const char* File, unsigned long Line)
  175. {
  176. fprintf(stderr, "INTERNAL ERROR: File %s, Line %lu, Expression %s\n", File, Line, Expression);
  177. abort();
  178. }
  179. String_t NumberToString(ULONG Number, PCWSTR Format)
  180. {
  181. // the size needed is really dependent on Format..
  182. WCHAR NumberAsString[BITS_OF(Number) + 5];
  183. _snwprintf(NumberAsString, NUMBER_OF(NumberAsString), Format, Number);
  184. NumberAsString[NUMBER_OF(NumberAsString) - 1] = 0;
  185. return NumberAsString;
  186. }
  187. String_t GetErrorString(DWORD Error)
  188. {
  189. PWSTR s = NULL;
  190. String_t ErrorString = NumberToString(Error, L"%lu");
  191. PWSTR FormatMessageAllocatedBuffer = NULL;
  192. if (!FormatMessageW(
  193. FORMAT_MESSAGE_ALLOCATE_BUFFER
  194. | FORMAT_MESSAGE_FROM_SYSTEM
  195. | FORMAT_MESSAGE_IGNORE_INSERTS,
  196. NULL,
  197. Error,
  198. 0,
  199. reinterpret_cast<PWSTR>(&FormatMessageAllocatedBuffer),
  200. 100,
  201. NULL
  202. )
  203. || FormatMessageAllocatedBuffer == NULL
  204. )
  205. {
  206. goto Exit;
  207. }
  208. if (FormatMessageAllocatedBuffer[0] == 0)
  209. {
  210. goto Exit;
  211. }
  212. //
  213. // Error messages often end with vertical whitespce, remove it.
  214. //
  215. s = FormatMessageAllocatedBuffer + StringLength(FormatMessageAllocatedBuffer) - 1;
  216. while (s != FormatMessageAllocatedBuffer && (*s == '\n' || *s == '\r'))
  217. *s-- = 0;
  218. ErrorString = ErrorString + L" (" + FormatMessageAllocatedBuffer + L")";
  219. Exit:
  220. LocalFree(FormatMessageAllocatedBuffer);
  221. return ErrorString;
  222. }
  223. String_t GetLastErrorString()
  224. {
  225. return GetErrorString(GetLastError());
  226. }
  227. String_t RemoveOptionChar(const String_t& s)
  228. {
  229. if (s.Length() != 0)
  230. {
  231. if (s[0] == '-')
  232. return s.substr(1);
  233. else if (s[0] == '/')
  234. return s.substr(1);
  235. else if (s[0] == ':') // hacky..
  236. return s.substr(1);
  237. else if (s[0] == '=') // hacky..
  238. return s.substr(1);
  239. }
  240. return s;
  241. }
  242. void __cdecl Error(const wchar_t* s, ...)
  243. {
  244. printf("%s\n", s);
  245. exit(EXIT_FAILURE);
  246. }
  247. String_t GetEnv(PCWSTR Name)
  248. {
  249. DWORD LengthIn = 64;
  250. DWORD LengthOut = 0;
  251. std::vector<WCHAR> Buffer;
  252. while (true)
  253. {
  254. Buffer.resize(LengthIn);
  255. Buffer[0] = 0;
  256. LengthOut = GetEnvironmentVariableW(Name, &Buffer[0], LengthIn);
  257. if (LengthOut < LengthIn)
  258. {
  259. break;
  260. }
  261. LengthIn = 1 + std::max(2 * LengthIn, LengthOut);
  262. }
  263. return &Buffer[0];
  264. }
  265. String_t FindLatestReleaseOnServer(const String_t& Server)
  266. {
  267. StringVector_t Releases;
  268. String_t ServerRelease;
  269. ServerRelease += L"\\\\";
  270. ServerRelease += Server;
  271. ServerRelease += L"\\release";
  272. CollectDirectoryPathsNonRecursively(ServerRelease, Releases);
  273. std::sort(Releases.begin(), Releases.end());
  274. return Releases.back();
  275. }
  276. BOOL DelayloadTool_Filter(PVOID FilterContext, PCWSTR Directory, WIN32_FIND_DATAW * wfd)
  277. {
  278. const static UNICODE_STRING directoriesToIgnore[] =
  279. {
  280. #define X(x) RTL_CONSTANT_STRING(x)
  281. X(L"pro"), X(L"srv"), X(L"ads"), X(L"dtc"), X(L"bla"), X(L"per"),
  282. X(L"sbs"),
  283. X(L"proinf"), X(L"srvinf"), X(L"adsinf"), X(L"dtcinf"), X(L"blainf"), X(L"perinf"),
  284. X(L"procd1"), X(L"procd2"),
  285. X(L"ifs_cd"), X(L"symbols"), X(L"ifs_flat"), X(L"build_logs"),
  286. X(L"symbols.pri"), X(L"processor_cd"), X(L"processor_flat"),
  287. X(L"asmscab"),
  288. X(L"ddk_flat"),
  289. X(L"scp_wpa"),
  290. X(L"hu"),
  291. X(L"ara"), X(L"br"), X(L"chs"), X(L"cht"), X(L"cs"), X(L"da"), X(L"el"), X(L"es"),
  292. X(L"euq"), X(L"fi"), X(L"fr"), X(L"ger"), X(L"heb"), X(L"hun"), X(L"it"), X(L"jpn"),
  293. X(L"kor"), X(L"nl"), X(L"no"), X(L"pl"), X(L"pt"), X(L"ru"), X(L"sky"), X(L"slv"),
  294. X(L"sv"), X(L"tr"), X(L"usa"),
  295. X(L"congeal_scripts"),
  296. X(L"lanman"),
  297. X(L"dos"), X(L"lanman.os2"), X(L"tcp32wfw"), X(L"update.wfw"), X(L"msclient"),
  298. X(L"bootfloppy"),
  299. X(L"opk"),
  300. X(L"winpe"),
  301. X(L"presign"),
  302. X(L"prerebase"),
  303. };
  304. const static UNICODE_STRING extensionsToIgnore[] =
  305. {
  306. X(L"txt"), X(L"htm"), X(L"gif"), X(L"bmp"), X(L"pdb"),
  307. X(L"inf"), X(L"sif"), X(L"pnf"), X(L"png"),
  308. X(L"sys"), X(L"ttf"), X(L"vbs"), X(L"hlp"), X(L"ini"), X(L"cat"),
  309. X(L"cab"), X(L"nls"), X(L"gpd"), X(L"chm"), X(L"cur"), X(L"jpg"),
  310. X(L"cer"), X(L"ani"), X(L"fon"), X(L"css"), X(L"hash"),
  311. X(L"lst"), X(L"icm"), X(L"msg"), X(L"386"),
  312. X(L"ico"), X(L"dos"), X(L"asp"), X(L"sld"),
  313. X(L"pif"), X(L"cnt"), X(L"mof"), X(L"man"), X(L"msm"),
  314. X(L"cdf"), X(L"img"), X(L"doc"), X(L"dns"), X(L"cpx"), X(L"mib"), X(L"ppd")
  315. X(L"map"), X(L"sym")
  316. #undef X
  317. };
  318. CUnicodeString cFileName(wfd->cFileName);
  319. SIZE_T i;
  320. if ((wfd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
  321. {
  322. Spinner();
  323. //fprintf(stderr, "%wZ\n", &cFileName);
  324. for (i = 0 ; i != RTL_NUMBER_OF(directoriesToIgnore) ; ++i)
  325. {
  326. if (FusionpEqualStringsI(&directoriesToIgnore[i], &cFileName))
  327. return FALSE;
  328. }
  329. }
  330. else
  331. {
  332. PCWSTR dot;
  333. if (RTL_STRING_GET_LAST_CHAR(&cFileName) == L'_')
  334. return FALSE;
  335. if (RTL_STRING_GET_LAST_CHAR(&cFileName) == L'$')
  336. return FALSE;
  337. dot = wcsrchr(wfd->cFileName, '.');
  338. if (dot != NULL && wcslen(dot + 1) == 3)
  339. {
  340. CUnicodeString dotString(dot + 1);
  341. for (i = 0 ; i != RTL_NUMBER_OF(extensionsToIgnore) ; ++i)
  342. {
  343. if (FusionpEqualStringsI(&extensionsToIgnore[i], &dotString))
  344. return FALSE;
  345. }
  346. }
  347. }
  348. _wcslwr(wfd->cFileName);
  349. return TRUE;
  350. }
  351. void
  352. SeekTo(
  353. HANDLE FileHandle,
  354. ULONG64 Offset
  355. )
  356. {
  357. LARGE_INTEGER liOffset;
  358. liOffset.QuadPart = Offset;
  359. if (!FusionpSetFilePointerEx(FileHandle, liOffset, NULL, FILE_BEGIN))
  360. {
  361. DbgPrint("SeekTo:0x%I64x failing\n", Offset);
  362. ThrowLastWin32Error();
  363. }
  364. }
  365. void
  366. SeekBackward(
  367. HANDLE FileHandle,
  368. LONG64 Offset
  369. )
  370. {
  371. LARGE_INTEGER liOffset;
  372. liOffset.QuadPart = -Offset;
  373. if (!FusionpSetFilePointerEx(FileHandle, liOffset, NULL, FILE_CURRENT))
  374. ThrowLastWin32Error();
  375. }
  376. ULONG64
  377. GetCurrentSeekPointer(
  378. HANDLE FileHandle
  379. )
  380. {
  381. LARGE_INTEGER li;
  382. LARGE_INTEGER li2;
  383. li.QuadPart = 0;
  384. li2.QuadPart = 0;
  385. if (!FusionpSetFilePointerEx(FileHandle, li, &li2, FILE_CURRENT))
  386. ThrowLastWin32Error();
  387. return li2.QuadPart;
  388. }
  389. void
  390. SeekForward(
  391. HANDLE FileHandle,
  392. ULONG64 Offset
  393. )
  394. {
  395. LARGE_INTEGER liOffset;
  396. liOffset.QuadPart = Offset;
  397. if (!FusionpSetFilePointerEx(FileHandle, liOffset, NULL, FILE_CURRENT))
  398. ThrowLastWin32Error();
  399. }
  400. PBYTE
  401. FindRunOfZeros(
  402. PBYTE pb,
  403. PBYTE pbEnd,
  404. SIZE_T elementSize
  405. )
  406. {
  407. SIZE_T k = 0;
  408. SIZE_T mod = ((pbEnd - pb) % elementSize);
  409. assert(mod == 0);
  410. if (mod != 0)
  411. {
  412. return pbEnd;
  413. }
  414. if (pb + elementSize >= pbEnd)
  415. return pbEnd;
  416. for ( ; pb != pbEnd ; pb += elementSize)
  417. {
  418. for (k = 0 ; k != elementSize ; ++k)
  419. {
  420. if (pb[k] != 0)
  421. {
  422. break;
  423. }
  424. }
  425. if (k == elementSize)
  426. {
  427. break;
  428. }
  429. }
  430. return pb;
  431. }
  432. void
  433. ReadImportFunctionNames(
  434. HANDLE File,
  435. SIZE_T SizeOfPointer,
  436. const std::vector<ULONG64>& IatRvas
  437. std::vector<String_t>& IatRvas
  438. )
  439. {
  440. }
  441. void
  442. ReadIatRvas(
  443. HANDLE File,
  444. SIZE_T SizeOfPointer,
  445. std::vector<ULONG64>& Iat
  446. )
  447. //
  448. // This leaves the seek pointer in an arbitrary location.
  449. //
  450. {
  451. union
  452. {
  453. ULONG32 Iat32[64];
  454. ULONG64 Iat64[32];
  455. BYTE Bytes[64 * 4];
  456. } u;
  457. ULONG BytesRead;
  458. ULONG Mod;
  459. Iat.resize(0);
  460. assert(SizeOfPointer == 4 || SizeOfPointer == 8);
  461. while (true)
  462. {
  463. BytesRead = 0;
  464. if (!ReadFile(File, &u, sizeof(u), &BytesRead, NULL))
  465. ThrowLastWin32Error(/*"ReadFile"*/);
  466. Mod = (BytesRead % SizeOfPointer);
  467. if (Mod != 0)
  468. {
  469. SeekBackward(File, Mod);
  470. BytesRead -= Mod;
  471. }
  472. if (BytesRead == 0)
  473. {
  474. Throw(L"end of file without nul terminal\n");
  475. }
  476. PBYTE pb = FindRunOfZeros(u.Bytes, u.Bytes + BytesRead, SizeOfPointer);
  477. switch (SizeOfPointer)
  478. {
  479. case 4:
  480. std::copy(u.Iat32, reinterpret_cast<ULONG32*>(pb), std::inserter(Iat.end()));
  481. break;
  482. case 8:
  483. std::copy(u.Iat64, reinterpret_cast<ULONG64*>(pb), std::inserter(Iat.end()));
  484. break;
  485. default:
  486. Throw("unknown sizeof pointer");
  487. break;
  488. }
  489. if (pb != u.Bytes + BytesRead)
  490. {
  491. break;
  492. }
  493. }
  494. }
  495. String_t
  496. ReadDllName(
  497. HANDLE File
  498. )
  499. //
  500. // This leaves the seek pointer in an arbitrary location.
  501. //
  502. {
  503. String_t Result;
  504. CHAR BufferA[65];
  505. WCHAR BufferW[65];
  506. DWORD BytesRead = 0;
  507. BufferA[NUMBER_OF(BufferA) - 1] = 0;
  508. BufferW[NUMBER_OF(BufferW) - 1] = 0;
  509. while (true)
  510. {
  511. BytesRead = 0;
  512. if (!ReadFile(File, &BufferA[0], (NUMBER_OF(BufferA) - 1) * sizeof(BufferA[0]), &BytesRead, NULL))
  513. ThrowLastWin32Error(/*"ReadFile"*/);
  514. if (BytesRead == 0)
  515. {
  516. Throw(L"end of file without nul terminal\n");
  517. }
  518. _strlwr(BufferA);
  519. for (ULONG i = 0 ; i != BytesRead ; ++i)
  520. {
  521. if ((BufferW[i] = BufferA[i]) == 0)
  522. {
  523. Result += BufferW;
  524. return Result;
  525. }
  526. }
  527. Result += BufferW;
  528. }
  529. }
  530. void
  531. Read(
  532. HANDLE FileHandle,
  533. VOID * Buffer,
  534. ULONG BytesToRead
  535. )
  536. {
  537. DWORD BytesRead;
  538. if (!ReadFile(FileHandle, Buffer, BytesToRead, &BytesRead, NULL))
  539. ThrowLastWin32Error(/*"ReadFile"*/);
  540. if (BytesToRead != BytesRead)
  541. {
  542. Throw(L"wrong number of bytes read");
  543. }
  544. }
  545. void DelayloadTool_t::ProcessBuild(const BuildFlavor_t& b)
  546. {
  547. FilePaths_t FilePaths;
  548. CollectFilePathsRecursively(*b.ActualRoot, FilePaths, DelayloadTool_Filter);
  549. for (FilePaths_t::const_iterator i = FilePaths.begin() ; i != FilePaths.end() ; ++i)
  550. {
  551. ProcessFile(*b.ActualRoot, *i);
  552. Spinner();
  553. }
  554. }
  555. String_t
  556. DelayloadTool_t::ReadOneDelayload(
  557. HANDLE File
  558. )
  559. {
  560. ImgDelayDescrV1_32 delay1_32 = { 0 };
  561. ImgDelayDescrV1_64 delay1_64 = { 0 };
  562. ImgDelayDescrV2 delay2 = { 0 };
  563. LONG64 FileOffsetToDelayLoadedName = 0;
  564. DWORD dwDelayFlags = 0;
  565. Read(File, &dwDelayFlags, 4);
  566. SeekBackward(File, 4);
  567. bool rvaFlag = ((dwDelayFlags & dlattrRva) != 0);
  568. if (rvaFlag)
  569. {
  570. Read(File, &delay2, sizeof(delay2));
  571. }
  572. else
  573. {
  574. if (m_OptionalHeader32 != NULL)
  575. {
  576. Read(File, &delay1_32, sizeof(delay1_32));
  577. if (delay1_32.szName == 0)
  578. {
  579. delay2.rvaDLLName = 0;
  580. }
  581. else
  582. {
  583. delay2.rvaDLLName = static_cast<RVA>(delay1_32.szName - m_OptionalHeader32->ImageBase);
  584. }
  585. }
  586. else if (m_OptionalHeader64 != NULL)
  587. {
  588. Read(File, &delay1_64, sizeof(delay1_64));
  589. if (delay1_64.szName == 0)
  590. {
  591. delay2.rvaDLLName = 0;
  592. }
  593. else
  594. {
  595. delay2.rvaDLLName = static_cast<RVA>(delay1_64.szName - m_OptionalHeader64->ImageBase);
  596. }
  597. }
  598. else
  599. {
  600. Throw(L"unknown image format");
  601. }
  602. }
  603. if (delay2.rvaDLLName == 0)
  604. {
  605. FileOffsetToDelayLoadedName = 0;
  606. }
  607. else
  608. {
  609. PBYTE pb = reinterpret_cast<PBYTE>(ImageRvaToVa(GetNtHeaders(), GetMappedBase(), delay2.rvaDLLName, &m_HintSection));
  610. FileOffsetToDelayLoadedName = (pb - &m_HeadersBuffer[0]);
  611. }
  612. if (FileOffsetToDelayLoadedName == 0)
  613. {
  614. return L"";
  615. }
  616. ULONG64 CurrentOffset = GetCurrentSeekPointer(File);
  617. SeekTo(File, FileOffsetToDelayLoadedName);
  618. String_t DllName = ReadDllName(File);
  619. SeekTo(File, CurrentOffset);
  620. return DllName;
  621. }
  622. void DelayloadTool_t::ProcessFile(const FilePath_t & RootPath, const FilePath_t & FilePath)
  623. {
  624. DFile File;
  625. Image_t Image;
  626. LARGE_INTEGER FileSize = { 0 };
  627. PIMAGE_FILE_HEADER FileHeader = 0;
  628. m_OptionalHeader32 = 0;
  629. m_OptionalHeader64 = 0;
  630. PIMAGE_SECTION_HEADER SectionHeaders = 0;
  631. PIMAGE_DATA_DIRECTORY DelayloadDataDirectory = 0;
  632. HRESULT hr = 0;
  633. m_OffsetToPe = 0;
  634. ULONG OffsetToFileHeader = 0;
  635. ULONG OffsetToOptionalHeader = 0;
  636. ULONG OffsetToSectionHeaders = 0;
  637. ULONG SizeOfOptionalHeader = 0;
  638. ULONG SizeofSectionHeaders = 0;
  639. ULONG NumberOfSections = 0;
  640. m_HintSection = 0;
  641. String_t DllName;
  642. struct
  643. {
  644. IMAGE_IMPORT_DESCRIPTOR RawDescriptor;
  645. String_t DllName;
  646. std::vector<ULONG64> Iat;
  647. std::vector<String_t> FunctionNames;
  648. } Import;
  649. Image.m_FullPath = FilePath;
  650. if (RootPath.GetLength() != 0)
  651. {
  652. assert(RootPath.GetLength() > Image.m_FullPath.GetLength());
  653. Image.m_RelativePath = Image.m_FullPath.substr(1 + RootPath.GetLength());
  654. }
  655. else
  656. {
  657. Image.m_RelativePath = L"";
  658. }
  659. Image.m_LeafPath = Image.m_FullPath.substr(1 + Image.m_FullPath.find_last_of(L"\\/"));
  660. //fprintf(stderr, "\n%ls", Image.m_RelativePath.c_str());
  661. hr = File.HrCreate(FilePath, GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING);
  662. if (FAILED(hr))
  663. {
  664. goto Error;
  665. }
  666. if (!FusionpGetFileSizeEx(File, &FileSize))
  667. {
  668. goto Error;
  669. }
  670. if (FileSize.QuadPart < 64)
  671. {
  672. goto NotAnImage;
  673. }
  674. m_HeadersBuffer.resize(64);
  675. Read(File, &m_HeadersBuffer[0], 2);
  676. if (memcmp(&m_HeadersBuffer[0], "MZ", 2) != 0)
  677. goto NotAnImage;
  678. SeekTo(File, 60);
  679. Read(File, &m_HeadersBuffer[60], 4);
  680. m_OffsetToPe = *reinterpret_cast<ULONG*>(&m_HeadersBuffer[60]);
  681. OffsetToFileHeader = m_OffsetToPe + 4;
  682. OffsetToOptionalHeader = OffsetToFileHeader + sizeof(IMAGE_FILE_HEADER);
  683. if (m_OffsetToPe > MAXULONG - 4)
  684. goto NotAnImage;
  685. if (m_OffsetToPe + 4 > FileSize.QuadPart)
  686. goto NotAnImage;
  687. SeekTo(File, m_OffsetToPe);
  688. m_HeadersBuffer.resize(m_OffsetToPe + 4 + sizeof(IMAGE_FILE_HEADER));
  689. Read(File, &m_HeadersBuffer[m_OffsetToPe], 4);
  690. if (memcmp(&m_HeadersBuffer[m_OffsetToPe], "PE\0\0", 4) != 0)
  691. goto NotAnImage;
  692. Read(File, &m_HeadersBuffer[OffsetToFileHeader], sizeof(IMAGE_FILE_HEADER));
  693. FileHeader = reinterpret_cast<PIMAGE_FILE_HEADER>(&m_HeadersBuffer[OffsetToFileHeader]);
  694. SizeOfOptionalHeader = FileHeader->SizeOfOptionalHeader;
  695. NumberOfSections = FileHeader->NumberOfSections;
  696. OffsetToSectionHeaders = OffsetToOptionalHeader + SizeOfOptionalHeader;
  697. SizeofSectionHeaders = NumberOfSections * sizeof(IMAGE_SECTION_HEADER);
  698. m_HeadersBuffer.resize(OffsetToOptionalHeader + SizeOfOptionalHeader + SizeofSectionHeaders);
  699. Read(File, &m_HeadersBuffer[OffsetToOptionalHeader], SizeOfOptionalHeader + SizeofSectionHeaders);
  700. FileHeader = reinterpret_cast<PIMAGE_FILE_HEADER>(&m_HeadersBuffer[OffsetToFileHeader]);
  701. m_OptionalHeader32 = reinterpret_cast<PIMAGE_OPTIONAL_HEADER32>(&m_HeadersBuffer[OffsetToOptionalHeader]);
  702. m_OptionalHeader64 = reinterpret_cast<PIMAGE_OPTIONAL_HEADER64>(&m_HeadersBuffer[OffsetToOptionalHeader]);
  703. SectionHeaders = reinterpret_cast<PIMAGE_SECTION_HEADER>(&m_HeadersBuffer[SizeofSectionHeaders]);
  704. switch (m_OptionalHeader32->Magic)
  705. {
  706. case IMAGE_NT_OPTIONAL_HDR32_MAGIC:
  707. m_OptionalHeader64 = NULL;
  708. break;
  709. case IMAGE_NT_OPTIONAL_HDR64_MAGIC:
  710. m_OptionalHeader32 = NULL;
  711. break;
  712. case IMAGE_ROM_OPTIONAL_HDR_MAGIC:
  713. goto IgnoreRomImages;
  714. break;
  715. default:
  716. goto UnrecognizableImage;
  717. }
  718. if (GET_OPTIONAL_HEADER_FIELD(m_OptionalHeader32, m_OptionalHeader64, NumberOfRvaAndSizes)
  719. < IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT)
  720. {
  721. goto NoDelayloads;
  722. }
  723. DelayloadDataDirectory = &GET_OPTIONAL_HEADER_FIELD(m_OptionalHeader32, m_OptionalHeader64, DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT]);
  724. if (DelayloadDataDirectory->VirtualAddress == NULL)
  725. {
  726. goto NoDelayloads;
  727. }
  728. if (DelayloadDataDirectory->Size == NULL)
  729. {
  730. goto NoDelayloads;
  731. }
  732. fprintf(stderr, "\r%ls\n", Image.m_RelativePath.c_str());
  733. PBYTE pb;
  734. pb = reinterpret_cast<PBYTE>(ImageRvaToVa(GetNtHeaders(), GetMappedBase(), DelayloadDataDirectory->VirtualAddress, &m_HintSection));
  735. LONG64 OffsetToDelayloads;
  736. OffsetToDelayloads = pb - &m_HeadersBuffer[0];
  737. SeekTo(File, OffsetToDelayloads);
  738. DllName = ReadOneDelayload(File);
  739. if (DllName == L"")
  740. {
  741. goto NoDelayloads;
  742. }
  743. if (GET_OPTIONAL_HEADER_FIELD(m_OptionalHeader32, m_OptionalHeader64, NumberOfRvaAndSizes)
  744. < IMAGE_DIRECTORY_ENTRY_IMPORT)
  745. {
  746. goto NoImports;
  747. }
  748. ImportDataDirectory = &GET_OPTIONAL_HEADER_FIELD(m_OptionalHeader32, m_OptionalHeader64, DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]);
  749. if (ImportDataDirectory->VirtualAddress == NULL)
  750. {
  751. goto NoImports;
  752. }
  753. if (ImportDataDirectory->Size == NULL)
  754. {
  755. goto NoImports;
  756. }
  757. pb = reinterpret_cast<PBYTE>(ImageRvaToVa(GetNtHeaders(), GetMappedBase(), ImportDataDirectory->VirtualAddress, &m_HintSection));
  758. LONG64 OffsetToImport;
  759. OffsetToImport = pb - &m_HeadersBuffer[0];
  760. SeekTo(File, OffsetToImport);
  761. Read(File, &Import.RawDescriptor, sizeof(Import.RawDescriptor));
  762. OffsetToImport += sizeof(ImportDescriptor);
  763. SeekTo(File, Import.RawDescriptor.Name);
  764. Import.DllName = ReadDllName(File);
  765. SeekTo(File, Import.RawDescriptor.OriginalFirstThunk);
  766. ReadIatRvas(File, GetSizeOfPointer(), Import.Iat);
  767. ReadImportFunctionNames(File, GetSizeOfPointer(), Import.Iat, Import.FunctionNames);
  768. NoImports:
  769. m_XmlWriter.startElement(L"file");
  770. m_XmlWriter.startElement(L"type");
  771. m_XmlWriter.characters(L"pe/coff image");
  772. m_XmlWriter.endElement(L"type");
  773. m_XmlWriter.startElement(L"full-path");
  774. m_XmlWriter.characters(Image.m_FullPath);
  775. m_XmlWriter.endElement(L"full-path");
  776. if (Image.m_RelativePath != L"")
  777. {
  778. m_XmlWriter.startElement(L"relative-path");
  779. m_XmlWriter.characters(Image.m_RelativePath);
  780. m_XmlWriter.endElement(L"relative-path");
  781. }
  782. m_XmlWriter.startElement(L"leaf-path");
  783. m_XmlWriter.characters(Image.m_LeafPath);
  784. m_XmlWriter.endElement(L"leaf-path");
  785. m_XmlWriter.startElement(L"delay-loads");
  786. for ( ; DllName != L""; DllName = ReadOneDelayload(File) )
  787. {
  788. m_XmlWriter.startElement(L"delay-load");
  789. m_XmlWriter.characters(DllName);
  790. m_XmlWriter.endElement(L"delay-load");
  791. }
  792. m_XmlWriter.endElement(L"delay-loads");
  793. m_XmlWriter.endElement(L"file");
  794. return;
  795. /*
  796. BytesReadError;
  797. Image.m_Error = L"bad number of bytes read";
  798. return;
  799. */
  800. Error:
  801. Image.m_Error = GetLastErrorString();
  802. fprintf(stderr, "%ls", Image.m_Error.c_str());
  803. return;
  804. UnrecognizableImage:
  805. Image.m_Error = L" unrecognizable image";
  806. fprintf(stderr, " unrecognizable image");
  807. return;
  808. IgnoreRomImages:
  809. fprintf(stderr, " ignore rom image");
  810. return;
  811. NoDelayloads:
  812. //fprintf(stderr, " no delayloads");
  813. return;
  814. NotAnImage:
  815. //fprintf(stderr, " not an image");
  816. return;
  817. }
  818. void DelayloadTool_t::Main(const StringVector_t& args)
  819. {
  820. typedef std::vector<FilePath_t> Files_t;
  821. Files_t Files;
  822. typedef std::vector<BuildFlavor_t> Builds_t;
  823. Builds_t Builds;
  824. String_t Nttree = GetEnv(L"_Nttree");
  825. BuildFlavor_t localBuild = { L"", L"", L"", L"" };
  826. localBuild.ActualRoot = &Nttree;
  827. BuildFlavor_t buildFlavors[] =
  828. {
  829. { L"x86fre", L"x86", L"fre", L"robsvbl11" },
  830. { L"x86chk", L"x86", L"chk", L"robsvbl2" },
  831. { L"ia64fre", L"ia64", L"fre", L"robsvbl3" },
  832. { L"ia64chk", L"ia64", L"chk", L"robsvbl4" },
  833. //{ L"amd64fre", "amd64", L"fre", L"robsvbl5" },
  834. //{ L"amd64chk", "amd64", L"chk", L"robsvbl6" },
  835. };
  836. std::vector<String_t> ActualRoots;
  837. ActualRoots.reserve(NUMBER_OF(buildFlavors));
  838. for (StringVector_t::const_iterator i = args.begin() ; i != args.end() ; ++i)
  839. {
  840. String_t arg = *i;
  841. if (arg == L"checkall")
  842. {
  843. SIZE_T j;
  844. for (j = 0 ; j != NUMBER_OF(buildFlavors); ++j)
  845. {
  846. if (buildFlavors[j].ActualRoot == NULL)
  847. {
  848. ActualRoots.insert(ActualRoots.end(), FindLatestReleaseOnServer(buildFlavors[j].ReleaseServer));
  849. buildFlavors[j].ActualRoot = &ActualRoots.back();
  850. Builds.insert(Builds.end(), buildFlavors[j]);
  851. }
  852. }
  853. }
  854. else if (arg == L"checklocal")
  855. {
  856. if (Nttree == L"")
  857. {
  858. Error(L"nttree not set\n");
  859. }
  860. Builds.insert(Builds.end(), localBuild);
  861. }
  862. else if (arg == L"dlllist")
  863. {
  864. //
  865. // feedback loop optimization..
  866. //
  867. }
  868. else
  869. {
  870. SIZE_T k;
  871. for (k = 0 ; k != NUMBER_OF(buildFlavors) ; ++k)
  872. {
  873. if (arg == buildFlavors[k].Name)
  874. {
  875. if (buildFlavors[k].ActualRoot == NULL)
  876. {
  877. ActualRoots.insert(ActualRoots.end(), FindLatestReleaseOnServer(buildFlavors[k].ReleaseServer));
  878. buildFlavors[k].ActualRoot = &ActualRoots.back();
  879. Builds.insert(Builds.end(), buildFlavors[k]);
  880. }
  881. break;
  882. }
  883. }
  884. if (k == NUMBER_OF(buildFlavors))
  885. {
  886. DWORD dw = GetFileAttributesW(arg);
  887. if (dw != 0xFFFFFFFF && (dw & FILE_ATTRIBUTE_DIRECTORY) == 0)
  888. {
  889. Files.insert(Files.end(), arg);
  890. }
  891. }
  892. }
  893. }
  894. this->m_XmlWriter.encoding = L"ISO-8859-1";
  895. this->m_XmlWriter.output = static_cast<IStream*>(&this->m_OutFileStream);
  896. this->m_XmlWriter.indent = VARIANT_TRUE;
  897. if (!m_OutFileStream.OpenForWrite(
  898. L"c:\\delayload_out.xml",
  899. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  900. CREATE_ALWAYS,
  901. FILE_ATTRIBUTE_NORMAL
  902. ))
  903. {
  904. ThrowLastWin32Error();
  905. }
  906. this->m_XmlWriter.startDocument();
  907. this->m_XmlWriter.startElement(L"files");
  908. for (Builds_t::const_iterator m = Builds.begin() ; m != Builds.end() ; ++m)
  909. {
  910. ProcessBuild(*m);
  911. }
  912. for (Files_t::const_iterator n = Files.begin() ; n != Files.end() ; ++n)
  913. {
  914. ProcessFile(L"", *n);
  915. }
  916. this->m_XmlWriter.endElement(L"files");
  917. this->m_XmlWriter.endDocument();
  918. //Exit:
  919. return;
  920. }
  921. extern "C"
  922. {
  923. void __cdecl mainCRTStartup(void);
  924. void __cdecl wmainCRTStartup(void);
  925. }
  926. int __cdecl main(int argc, char** argv)
  927. {
  928. wmainCRTStartup();
  929. return 0;
  930. }
  931. extern "C" int __cdecl wmain(int argc, wchar_t** argv)
  932. {
  933. CoInitialize(NULL);
  934. FusionpInitializeHeap(GetModuleHandleW(NULL));
  935. DelayloadTool_t tool;
  936. StringVector_t args;
  937. args.reserve(argc);
  938. std::copy(argv + 1, argv + argc, std::back_inserter(args));
  939. tool.Main(args);
  940. return 0;
  941. }