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.

427 lines
12 KiB

  1. //
  2. // cvtodbg.cpp
  3. //
  4. // Takes a PE file and a file containing CV info, and jams the CV info
  5. // into the PE file (trashing it). However, The Jammed PE File when
  6. // splitsym'ed gives a dbg file, which can be used for debugging.
  7. //
  8. //
  9. #undef UNICODE
  10. #include "windows.h"
  11. #include "imagehlp.h"
  12. #include "stdio.h"
  13. #include "stdlib.h"
  14. ////////////////////////////////////////
  15. //
  16. // Data
  17. //
  18. char szImageName[MAX_PATH];
  19. char szCVName[MAX_PATH];
  20. char szPdbName[MAX_PATH];
  21. char szPdbCurrentPath[MAX_PATH];
  22. HANDLE hFile = INVALID_HANDLE_VALUE;
  23. HANDLE hMappedFile = INVALID_HANDLE_VALUE;
  24. LPVOID pvImageBase = NULL;
  25. BOOL fVerbose = FALSE;
  26. BOOL fForce = FALSE;
  27. typedef struct NB10I // NB10 debug info
  28. {
  29. DWORD nb10; // NB10
  30. DWORD off; // offset, always 0
  31. DWORD sig;
  32. DWORD age;
  33. } NB10I;
  34. typedef struct cvinfo
  35. {
  36. NB10I nb10;
  37. char rgb[0x200 - sizeof(NB10I)];
  38. } CVINFO;
  39. ////////////////////////////////////////
  40. //
  41. // Forward declarations
  42. //
  43. BOOL ParseArgs(int argc, WCHAR* argv[]);
  44. void UpdateCodeViewInfo();
  45. void Usage();
  46. void Message(const char* szFormat, ...);
  47. void Error(const char *sz, ...);
  48. void ErrorThrow(DWORD, const char *sz, ...);
  49. void Throw(DWORD);
  50. void MapImage();
  51. void UnmapImage(BOOL fTouch);
  52. BOOL DebugDirectoryIsUseful(LPVOID, ULONG);
  53. void RecalculateChecksum();
  54. ULONG FileSize(HANDLE);
  55. class FileMapping {
  56. public:
  57. FileMapping()
  58. : hFile(NULL), hMapping(NULL), pView(NULL)
  59. {
  60. }
  61. ~FileMapping()
  62. {
  63. Cleanup();
  64. }
  65. void Cleanup()
  66. {
  67. if (pView != NULL)
  68. UnmapViewOfFile(pView);
  69. if (hMapping != NULL)
  70. CloseHandle(hMapping);
  71. if (hFile != NULL && hFile != INVALID_HANDLE_VALUE)
  72. CloseHandle(hFile);
  73. }
  74. bool Open(LPCTSTR szFile)
  75. {
  76. hFile = CreateFile(szFile,
  77. GENERIC_READ,
  78. FILE_SHARE_READ | FILE_SHARE_WRITE,
  79. NULL,
  80. OPEN_EXISTING,
  81. FILE_ATTRIBUTE_NORMAL,
  82. NULL);
  83. if (hFile != INVALID_HANDLE_VALUE) {
  84. hMapping = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
  85. if (hMapping != NULL) {
  86. pView = MapViewOfFile(hMapping, FILE_MAP_READ, 0, 0, 0);
  87. return true;
  88. }
  89. }
  90. Cleanup();
  91. return false;
  92. }
  93. PVOID GetDataPtr()
  94. {
  95. return pView;
  96. }
  97. DWORD GetSize()
  98. {
  99. return GetFileSize(hFile, NULL);
  100. }
  101. bool IsValid()
  102. {
  103. return (pView != NULL);
  104. }
  105. private:
  106. HANDLE hFile;
  107. HANDLE hMapping;
  108. PVOID pView;
  109. };
  110. ////////////////////////////////////////
  111. //
  112. // Code
  113. //
  114. void __cdecl wmain(int argc, WCHAR* argv[])
  115. // Main entry point
  116. //
  117. {
  118. szPdbName[0] = 0;
  119. szPdbCurrentPath[0] = 0;
  120. if (ParseArgs(argc, argv))
  121. {
  122. __try
  123. {
  124. UpdateCodeViewInfo();
  125. }
  126. __except(EXCEPTION_EXECUTE_HANDLER)
  127. {
  128. // nothing, just don't propagate it higher to the user
  129. }
  130. }
  131. }
  132. // find the code view info;
  133. // if new info fits in old space, rewrite; else append new cv record and fix up
  134. // debug directory to point to the new record; append cv info to file.
  135. void UpdateCodeViewInfo()
  136. {
  137. PIMAGE_NT_HEADERS pntHeaders;
  138. ULONG cbWritten;
  139. MapImage();
  140. FileMapping cvMapping;
  141. if (!cvMapping.Open(szCVName))
  142. ErrorThrow(666, "Couldn't open CV file");
  143. pntHeaders = ImageNtHeader(pvImageBase);
  144. if (pntHeaders)
  145. {
  146. if (pntHeaders->OptionalHeader.MajorLinkerVersion >= 3 ||
  147. pntHeaders->OptionalHeader.MinorLinkerVersion >= 5)
  148. {
  149. // make it non vc generated image, we are trashing the binary anyway
  150. if ( pntHeaders->OptionalHeader.MajorLinkerVersion > 5)
  151. pntHeaders->OptionalHeader.MajorLinkerVersion = 5;
  152. // put dbg info back in if its already stripped.
  153. if (pntHeaders->FileHeader.Characteristics & IMAGE_FILE_DEBUG_STRIPPED)
  154. pntHeaders->FileHeader.Characteristics ^= IMAGE_FILE_DEBUG_STRIPPED;
  155. ULONG ibFileCvStart = FileSize(hFile);
  156. SetFilePointer(hFile, 0, NULL, FILE_END);
  157. while (ibFileCvStart & 7) // Align file length to 8-bytes. Slow, but clearly
  158. { // works! And for 7 bytes, who cares.
  159. BYTE zero = 0;
  160. WriteFile(hFile, &zero, 1, &cbWritten, NULL);
  161. ibFileCvStart++;
  162. }
  163. // Write out the CV info.
  164. WriteFile(hFile, cvMapping.GetDataPtr(), cvMapping.GetSize(), &cbWritten, NULL);
  165. // Make up a debug directory
  166. IMAGE_DEBUG_DIRECTORY dbgdirs[2];
  167. dbgdirs[0].Characteristics = pntHeaders->FileHeader.Characteristics;
  168. dbgdirs[0].TimeDateStamp = pntHeaders->FileHeader.TimeDateStamp;
  169. dbgdirs[0].MajorVersion = 0;
  170. dbgdirs[0].MinorVersion = 0;
  171. dbgdirs[0].Type = IMAGE_DEBUG_TYPE_MISC;
  172. dbgdirs[0].SizeOfData = 0;
  173. dbgdirs[0].AddressOfRawData = ibFileCvStart;
  174. dbgdirs[0].PointerToRawData = ibFileCvStart;
  175. dbgdirs[1].Characteristics = pntHeaders->FileHeader.Characteristics;
  176. dbgdirs[1].TimeDateStamp = pntHeaders->FileHeader.TimeDateStamp;
  177. dbgdirs[1].MajorVersion = 0;
  178. dbgdirs[1].MinorVersion = 0;
  179. dbgdirs[1].Type = IMAGE_DEBUG_TYPE_CODEVIEW;
  180. dbgdirs[1].SizeOfData = cvMapping.GetSize();
  181. dbgdirs[1].AddressOfRawData = ibFileCvStart;
  182. dbgdirs[1].PointerToRawData = ibFileCvStart;
  183. // Find the beginning of the first section and stick the debug directory there
  184. // (did we mention we're trashing the file?)
  185. IMAGE_SECTION_HEADER* pFirstSection = IMAGE_FIRST_SECTION(pntHeaders);
  186. memcpy((PBYTE)((DWORD)pvImageBase + pFirstSection->PointerToRawData), &dbgdirs, sizeof(dbgdirs));
  187. pntHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress = pFirstSection->VirtualAddress;
  188. pntHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size = sizeof(dbgdirs);
  189. }
  190. }
  191. UnmapImage(TRUE);
  192. }
  193. void MapImage()
  194. // Map the image into memory for read-write. Caller MUST call
  195. // Unmapimage to clean up even on failure.
  196. {
  197. if (fForce)
  198. SetFileAttributesA(szImageName, FILE_ATTRIBUTE_NORMAL);
  199. hFile = CreateFileA( szImageName,
  200. GENERIC_READ | GENERIC_WRITE,
  201. FILE_SHARE_READ,
  202. NULL,
  203. OPEN_EXISTING,
  204. 0,
  205. NULL
  206. );
  207. if (hFile == INVALID_HANDLE_VALUE)
  208. {
  209. ErrorThrow(GetLastError(), "unable to open '%s'\n", szImageName);
  210. }
  211. hMappedFile = CreateFileMapping( hFile,
  212. NULL,
  213. PAGE_READWRITE,
  214. 0,
  215. 0,
  216. NULL
  217. );
  218. if (!hMappedFile)
  219. {
  220. ErrorThrow(GetLastError(), "un`able to create file mapping for '%s'\n", szImageName);
  221. }
  222. pvImageBase = MapViewOfFile(hMappedFile, FILE_MAP_WRITE, 0, 0, 0);
  223. if (!pvImageBase)
  224. {
  225. ErrorThrow(GetLastError(), "unable to map view of '%s'\n", szImageName);
  226. }
  227. }
  228. void UnmapImage(BOOL fTouch)
  229. // Clean up whatever MapImage does
  230. {
  231. if (pvImageBase)
  232. {
  233. FlushViewOfFile(pvImageBase, 0);
  234. UnmapViewOfFile(pvImageBase);
  235. pvImageBase = NULL;
  236. }
  237. if (hMappedFile != INVALID_HANDLE_VALUE)
  238. {
  239. CloseHandle(hMappedFile);
  240. hMappedFile = INVALID_HANDLE_VALUE;
  241. }
  242. if (hFile != INVALID_HANDLE_VALUE)
  243. {
  244. if (fTouch)
  245. {
  246. TouchFileTimes(hFile, NULL);
  247. }
  248. CloseHandle(hFile);
  249. hFile = INVALID_HANDLE_VALUE;
  250. }
  251. }
  252. BOOL ParseArgs(int argc, WCHAR* argv[])
  253. // Parse the arguments and set our flags appropriately
  254. {
  255. WCHAR* wszString;
  256. WCHAR c;
  257. szImageName[0] = L'\0';
  258. szCVName[0] = L'\0';
  259. while (--argc)
  260. {
  261. wszString = *++argv;
  262. if (*wszString == L'/' || *wszString == L'-')
  263. {
  264. while ((c = *++wszString) != L'\0')
  265. {
  266. switch (towupper( c ))
  267. {
  268. case L'?':
  269. Usage();
  270. return FALSE;
  271. case L'V':
  272. fVerbose = TRUE;
  273. break;
  274. default:
  275. Error("invalid switch - /%c\n", c );
  276. Usage();
  277. return FALSE;
  278. }
  279. }
  280. }
  281. else
  282. {
  283. if (szImageName[0] == L'\0')
  284. {
  285. wcstombs(szImageName, wszString, MAX_PATH);
  286. }
  287. else if (szCVName[0] == L'\0')
  288. {
  289. wcstombs(szCVName, wszString, MAX_PATH);
  290. }
  291. else
  292. {
  293. Error("too many files specified\n");
  294. Usage();
  295. return FALSE;
  296. }
  297. }
  298. }
  299. if (szImageName==NULL)
  300. {
  301. Error("no image name specified\n");
  302. Usage();
  303. return FALSE;
  304. }
  305. if (szCVName==NULL)
  306. {
  307. Error("no CV filename specified\n");
  308. Usage();
  309. return FALSE;
  310. }
  311. return TRUE;
  312. }
  313. void Usage()
  314. {
  315. fprintf(stderr, "Usage: cvtodbg [options] imageName cvFile\n"
  316. " [-?] display this message\n"
  317. " [-f] overwrite readonly files\n");
  318. }
  319. void Message(const char* szFormat, ...)
  320. {
  321. va_list va;
  322. va_start(va, szFormat);
  323. fprintf (stdout, "resetpdb: ");
  324. vfprintf(stdout, szFormat, va);
  325. va_end(va);
  326. }
  327. void Error(const char* szFormat, ...)
  328. {
  329. va_list va;
  330. va_start(va, szFormat);
  331. fprintf (stderr, "resetpdb: error: ");
  332. vfprintf(stderr, szFormat, va);
  333. va_end(va);
  334. }
  335. void ErrorThrow(DWORD dw, const char* szFormat, ...)
  336. {
  337. va_list va;
  338. va_start(va, szFormat);
  339. fprintf (stderr, "resetpdb: error: ");
  340. vfprintf(stderr, szFormat, va);
  341. va_end(va);
  342. Throw(dw);
  343. }
  344. void Throw(DWORD dw)
  345. {
  346. RaiseException(dw, EXCEPTION_NONCONTINUABLE, 0, NULL);
  347. }
  348. BOOL DebugDirectoryIsUseful(LPVOID Pointer, ULONG Size)
  349. {
  350. return (Pointer != NULL) &&
  351. (Size >= sizeof(IMAGE_DEBUG_DIRECTORY)) &&
  352. ((Size % sizeof(IMAGE_DEBUG_DIRECTORY)) == 0);
  353. }
  354. ULONG FileSize(HANDLE h)
  355. // Answer the size of the file with this handle
  356. {
  357. BY_HANDLE_FILE_INFORMATION info;
  358. GetFileInformationByHandle(h, &info);
  359. return info.nFileSizeLow;
  360. }