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.

619 lines
20 KiB

  1. /*++
  2. Copyright (c) 2002 Microsoft Corporation
  3. Module Name:
  4. poolfind.cpp
  5. Abstract:
  6. This module contains the code to find the tags in a driver binary
  7. Author:
  8. Andrew Edwards (andred) Oct-2001
  9. Revision History:
  10. Swetha Narayanaswamy (swethan) 19-Mar-2002
  11. --*/
  12. #if !defined (_WIN64)
  13. #pragma warning(disable: 4514)
  14. #include "windows.h"
  15. #include "msdis.h"
  16. #include <stdlib.h>
  17. #include <stdio.h>
  18. #include <tchar.h>
  19. #include <delayimp.h>
  20. #define TAGSIZE 5
  21. #define DRIVERDIR "\\drivers\\"
  22. #define DRIVERFILEEXT "*.sys"
  23. #define MAXPATH 1024
  24. int __cdecl main(int argc, char** argv);
  25. void ParseImageFile(PTCHAR szImage);
  26. CHAR localTagFile[MAXPATH] = "localtag.txt";
  27. int cSystemDirectory = 0;
  28. //Used to form list of tags used by the same driver
  29. typedef struct _TAGLIST{
  30. TCHAR Tag[TAGSIZE];
  31. struct _TAGLIST *next;
  32. } TAGLIST, *PTAGLIST;
  33. BOOL
  34. GetTagFromCall (
  35. const BYTE *pbCall, // pointer to call instruction
  36. PTCHAR ptchTag, //out param: pointer to tag
  37. DIS *pDis,
  38. int tagLocation) //location of tag in the parameter list
  39. /*++
  40. Routine Description:
  41. This function disassembles the memory allocation function call.
  42. It finds the third push and determines the tag and
  43. places it in the ptchTag return parameter
  44. Return Value:
  45. FALSE: If unable to find tag
  46. TRUE: Otherwise
  47. --*/
  48. {
  49. // try to backup 3 pushes:
  50. // FF /6 + modrm etc
  51. // 50-5F
  52. // 6A <8imm>
  53. // 68 <32imm>
  54. int cbMax = 200;
  55. const BYTE *pb = pbCall;
  56. const BYTE *pTag = NULL;
  57. if ((ptchTag == NULL) || (pbCall == NULL) || (pDis == NULL)) return FALSE;
  58. _tcscpy(ptchTag,"");
  59. while (cbMax--)
  60. {
  61. pb--;
  62. if (pb[0] == 0x68)
  63. {
  64. // disassemble forward
  65. const BYTE *pbInst = pb;
  66. size_t cb = 1;
  67. int cPush = 0;
  68. while (cb && pbInst < pbCall)
  69. {
  70. cb = pDis->CbDisassemble( (DWORD)pbInst,
  71. pbInst, pbCall - pbInst);
  72. if ( (pbInst[0] == 0xFF) &&
  73. ((pbInst[1] & 0x38) == 0x30))
  74. {
  75. // this looks like a push <r/m>
  76. cPush++;
  77. }
  78. else if ((pbInst[0] & 0xF0) == 0x50)
  79. {
  80. // this looks like a push <reg>
  81. cPush++;
  82. }
  83. else if (pbInst[0] == 0x6A)
  84. {
  85. // this looks like a push <byte>
  86. cPush++;
  87. }
  88. else if (pbInst[0] == 0x68)
  89. {
  90. // this looks like a push <dword>
  91. cPush++;
  92. }
  93. pbInst += cb;
  94. }
  95. if (cPush == tagLocation && pbInst == pbCall)
  96. {
  97. _sntprintf(ptchTag,5,"%c%c%c%c",
  98. pb[1],pb[2],pb[3],( 0x7f &pb[4]));
  99. return TRUE;
  100. }
  101. }
  102. }
  103. return FALSE;
  104. }
  105. BOOL
  106. FindTags(
  107. const BYTE *pb,
  108. DWORD addr,
  109. PTAGLIST tagList, // out param: List of tags to append the new tags to
  110. DIS *pDis,
  111. int tagLocation) // tag location
  112. /*++
  113. Routine Description:
  114. This function reads the bytes in the instruction and looks for
  115. indirect/direct calls. The tag is appended to the tagList parameter
  116. Return Value:
  117. FALSE: If there is an exception or lack of memory
  118. TRUE: Otherwise
  119. --*/
  120. {
  121. TCHAR tag[TAGSIZE];
  122. BOOL done = FALSE;
  123. PTAGLIST tempTagNode=NULL, prevTagNode=NULL, newTagNode=NULL;
  124. if ((pb==NULL) || (tagList == NULL) || (pDis == NULL)) return FALSE;
  125. // Get the raw bytes and size of the image
  126. try
  127. {
  128. for(;;)
  129. {
  130. done = FALSE;
  131. if (pb[0] == 0xFF && pb[1] == 0x15)
  132. {
  133. // Indirect call
  134. pb += 2;
  135. if (*(DWORD *)pb == (DWORD)addr)
  136. {
  137. // Found a call
  138. if ((GetTagFromCall(pb-2,tag,pDis, tagLocation)) == FALSE)
  139. {
  140. pb++;
  141. continue;
  142. }
  143. tempTagNode = prevTagNode = tagList;
  144. while (tempTagNode != NULL)
  145. {
  146. if ((_tcscmp(tempTagNode->Tag,"")) == 0)
  147. {
  148. // Insert here
  149. _tcsncpy(tempTagNode->Tag, tag, TAGSIZE);
  150. done = TRUE;
  151. break;
  152. }
  153. else if (!(memcmp(tempTagNode->Tag,tag,TAGSIZE)))
  154. {
  155. //Tag already exists in list
  156. done = TRUE;
  157. break;
  158. }
  159. prevTagNode = tempTagNode;
  160. tempTagNode = tempTagNode->next;
  161. }
  162. if (!done )
  163. {
  164. newTagNode = (PTAGLIST)malloc(sizeof(TAGLIST));
  165. if (!newTagNode)
  166. {
  167. printf("Poolmon: Insufficient memory: %d\n", GetLastError());
  168. return FALSE;
  169. }
  170. //There is at least one node allocated so prevTagNode
  171. //will never be NULL
  172. prevTagNode->next = newTagNode;
  173. // Insert here
  174. _tcsncpy(newTagNode->Tag, tag, TAGSIZE);
  175. newTagNode->next = NULL;
  176. }
  177. }
  178. }
  179. pb++;
  180. }
  181. }
  182. catch (...)
  183. {
  184. return FALSE;
  185. }
  186. return TRUE;
  187. }
  188. unsigned RvaToPtr(unsigned rva, IMAGE_NT_HEADERS *pNtHeader)
  189. {
  190. int iSect = 0;
  191. for (PIMAGE_SECTION_HEADER pSect = IMAGE_FIRST_SECTION(pNtHeader); iSect < pNtHeader->FileHeader.NumberOfSections; pSect++, iSect++)
  192. {
  193. if (rva >= pSect->VirtualAddress &&
  194. rva < pSect->VirtualAddress + pSect->SizeOfRawData)
  195. {
  196. rva -= pSect->VirtualAddress;
  197. rva += pSect->PointerToRawData;
  198. return rva;
  199. }
  200. }
  201. //error case
  202. return 0;
  203. }
  204. void
  205. ParseImageFile(
  206. PTCHAR szImage, PTAGLIST tagList) // Image file name
  207. /*++
  208. Routine Description:
  209. This function opens the binary driver image file, reads it and looks for
  210. a memory allocation call
  211. Return Value:
  212. None
  213. --*/
  214. {
  215. DIS *pDis = NULL;
  216. if ((tagList == NULL) || (szImage == NULL) ) return;
  217. // read szImage into memory
  218. FILE *pf = NULL;
  219. pf = _tfopen(szImage, "rb");
  220. if (!pf) return;
  221. if ((fseek(pf, 0, SEEK_END )) != 0) goto exitParseImageFile;
  222. size_t cbMax = 0;
  223. cbMax = ftell(pf);
  224. if (cbMax == -1) goto exitParseImageFile;
  225. if ((fseek(pf, 0, SEEK_SET )) != 0) goto exitParseImageFile;
  226. BYTE *pbImage = NULL;
  227. pbImage = new BYTE[cbMax];
  228. if (!pbImage) goto exitParseImageFile;
  229. if ((fread( pbImage, cbMax, 1, pf )) <= 0) goto exitParseImageFile;
  230. // find the import table
  231. IMAGE_DOS_HEADER *phdr = (IMAGE_DOS_HEADER *)pbImage;
  232. if (phdr->e_magic != IMAGE_DOS_SIGNATURE)
  233. {
  234. _tprintf("Poolmon: Bad image file %s\n", szImage);
  235. goto exitParseImageFile;
  236. }
  237. if (cbMax < offsetof(IMAGE_DOS_HEADER, e_lfanew) +
  238. sizeof(phdr->e_lfanew) ||phdr->e_lfanew == 0)
  239. {
  240. _tprintf("Poolmon: Bad image file %s\n", szImage);
  241. goto exitParseImageFile;
  242. }
  243. IMAGE_NT_HEADERS *pNtHeader =
  244. (IMAGE_NT_HEADERS *) (pbImage + phdr->e_lfanew);
  245. if (pNtHeader == NULL) goto exitParseImageFile;
  246. if (pNtHeader->Signature != IMAGE_NT_SIGNATURE ||
  247. pNtHeader->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC)
  248. {
  249. _tprintf("Poolmon: Bad image file %s\n", szImage);
  250. goto exitParseImageFile;
  251. }
  252. // Find import tables
  253. IMAGE_DATA_DIRECTORY *pImports =
  254. (IMAGE_DATA_DIRECTORY *)&pNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
  255. if (pImports == NULL) goto exitParseImageFile;
  256. unsigned rva = pImports->VirtualAddress;
  257. // need to adjust from rva to pointer accounting for section alignment
  258. rva = RvaToPtr(rva, pNtHeader);
  259. if (0 == rva) {
  260. goto exitParseImageFile;
  261. }
  262. IMAGE_IMPORT_DESCRIPTOR *pImportDescr =
  263. (IMAGE_IMPORT_DESCRIPTOR *) (pbImage+rva);
  264. if (NULL == pImportDescr)
  265. {
  266. goto exitParseImageFile;
  267. }
  268. //msdis130.dll depends on msvcr70.dll and msvcp70.dll
  269. //Try a loadlibrary on these 2 libraries, and then proceed to delayload msdis130.dll
  270. #pragma prefast(suppress:321, "user guide:Programmers developing on the .NET server can ignore this warning by filtering it out.")
  271. if ((!LoadLibrary("MSVCR70.DLL")) || (!LoadLibrary("MSVCP70.DLL")))
  272. {
  273. printf("Unable to load msvcr70.dll/msvcp70.dll, cannot create local tag file\n");
  274. if (pf) fclose(pf);
  275. if (pbImage) delete[](pbImage);
  276. exit(-1);
  277. }
  278. try {
  279. pDis = DIS::PdisNew( DIS::distX86 );
  280. }
  281. catch (...) {
  282. printf("Poolmon: Unable to load msdis130.dll, cannot create local tag file\n");
  283. if (pf) fclose(pf);
  284. if (pbImage) delete[](pbImage);
  285. exit(-1);
  286. }
  287. if (pDis == NULL)
  288. {
  289. goto exitParseImageFile;
  290. }
  291. // Find the import for ExAllocatePoolWithTag
  292. for (;pImportDescr->Name &&pImportDescr->FirstThunk;pImportDescr++)
  293. {
  294. if (0 == (rva = RvaToPtr(pImportDescr->FirstThunk, pNtHeader))) {
  295. goto exitParseImageFile;
  296. }
  297. IMAGE_THUNK_DATA32 *pIAT = (IMAGE_THUNK_DATA32 *) (pbImage + rva);
  298. if (pIAT == NULL) goto exitParseImageFile;
  299. IMAGE_THUNK_DATA32 *addrIAT =
  300. (IMAGE_THUNK_DATA32 *) (pNtHeader->OptionalHeader.ImageBase + pImportDescr->FirstThunk);
  301. if (addrIAT == NULL) goto exitParseImageFile;
  302. if (0 == (rva = RvaToPtr(pImportDescr->Characteristics, pNtHeader))) {
  303. goto exitParseImageFile;
  304. }
  305. IMAGE_THUNK_DATA32 *pINT= (IMAGE_THUNK_DATA32 *) (pbImage + rva);
  306. if (pINT == NULL) goto exitParseImageFile;
  307. for (;pIAT->u1.Ordinal;)
  308. {
  309. if (IMAGE_SNAP_BY_ORDINAL32(pINT->u1.Ordinal))
  310. {
  311. // by ordinal?
  312. }
  313. else
  314. {
  315. if (0 == (rva = RvaToPtr((int)pINT->u1.AddressOfData, pNtHeader))) {
  316. goto exitParseImageFile;
  317. }
  318. IMAGE_IMPORT_BY_NAME* pIIN = (IMAGE_IMPORT_BY_NAME*) (pbImage + rva);
  319. if (NULL == pIIN) goto exitParseImageFile;
  320. char *name = (char*)pIIN->Name;
  321. if (0 == strcmp( name, "ExAllocatePoolWithTag" ))
  322. {
  323. FindTags(pbImage, (DWORD)addrIAT,tagList, pDis,3);
  324. }
  325. else if (0 == strcmp( name, "ExAllocatePoolWithQuotaTag" ))
  326. {
  327. FindTags(pbImage, (DWORD)addrIAT,tagList,pDis,3);
  328. }
  329. else if (0 == strcmp( name, "ExAllocatePoolWithTagPriority" ))
  330. {
  331. FindTags(pbImage, (DWORD)addrIAT,tagList,pDis,3);
  332. }
  333. //wrapper functions
  334. else if(0 == strcmp(name, "NdisAllocateMemoryWithTag"))
  335. {
  336. FindTags(pbImage, (DWORD)addrIAT,tagList,pDis,3);
  337. }
  338. else if(0 == strcmp(name,"VideoPortAllocatePool"))
  339. {
  340. FindTags(pbImage, (DWORD)addrIAT,tagList,pDis,4);
  341. }
  342. }
  343. addrIAT++;
  344. pIAT++;
  345. pINT++;
  346. }
  347. }
  348. exitParseImageFile:
  349. if (pf) fclose(pf);
  350. if (pbImage) delete[](pbImage);
  351. }
  352. extern "C" BOOL MakeLocalTagFile()
  353. /*++
  354. Routine Description:
  355. This function finds files one by one in the system drivers directory and call ParseImageFile on the image
  356. Return Value:
  357. None
  358. --*/
  359. {
  360. WIN32_FIND_DATA FileData;
  361. HANDLE hSearch=0;
  362. BOOL fFinished = FALSE;
  363. TCHAR sysdir[1024];
  364. PTCHAR filename=NULL;
  365. TCHAR imageName[MAXPATH] = "";
  366. PTAGLIST tagList = NULL;
  367. BOOL ret = TRUE;
  368. FILE *fpLocalTagFile = NULL;
  369. cSystemDirectory = GetSystemDirectory(sysdir, 0);
  370. if(!cSystemDirectory)
  371. {
  372. printf("Poolmon: Unable to get system directory: %d\n", GetLastError());
  373. ret = FALSE;
  374. goto freeall;
  375. }
  376. filename = (PTCHAR)malloc(cSystemDirectory +
  377. (_tcslen(DRIVERDIR) + _tcslen(DRIVERFILEEXT) + 1) * sizeof(TCHAR));
  378. if(!filename)
  379. {
  380. ret = FALSE;
  381. goto freeall;
  382. }
  383. GetSystemDirectory(filename, cSystemDirectory + 1);
  384. _tcscat(filename, DRIVERDIR);
  385. _tcscat(filename, DRIVERFILEEXT);
  386. // Search for .sys files
  387. hSearch = FindFirstFile(filename, &FileData);
  388. if (hSearch == INVALID_HANDLE_VALUE)
  389. {
  390. printf("Poolmon: No .sys files found\n");
  391. ret = FALSE;
  392. goto freeall;
  393. }
  394. _tcsncpy(imageName, filename,MAXPATH);
  395. imageName[MAXPATH-1] = '\0';
  396. tagList = (PTAGLIST)malloc(sizeof(TAGLIST));
  397. if (!tagList)
  398. {
  399. ret = FALSE;
  400. goto freeall;
  401. }
  402. _tcscpy(tagList->Tag,"");
  403. tagList->next = NULL;
  404. int cImagePath = cSystemDirectory+ _tcslen(DRIVERDIR) -1;
  405. while (!fFinished)
  406. {
  407. // Do all the initializations for the next round
  408. // Remove the previous name
  409. imageName[cImagePath] = '\0';
  410. // Initialize existing tagList
  411. PTAGLIST tempTagNode = tagList;
  412. while (tempTagNode != NULL)
  413. {
  414. _tcscpy(tempTagNode->Tag,"");
  415. tempTagNode = tempTagNode->next;
  416. }
  417. try
  418. {
  419. _tcsncat(imageName, FileData.cFileName,MAXPATH-cImagePath);
  420. ParseImageFile(imageName,tagList);
  421. //Remove .sys from szImage
  422. imageName[_tcslen(imageName) - 4] = '\0';
  423. }
  424. catch(...)
  425. {
  426. _tprintf("Poolmon: Could not read tags from %s\n", imageName);
  427. }
  428. if (!fpLocalTagFile)
  429. {
  430. printf("Poolmon: Creating %s in current directory......\n", localTagFile);
  431. fpLocalTagFile = fopen(localTagFile, "w");
  432. if (!fpLocalTagFile)
  433. {
  434. ret = FALSE;
  435. goto freeall;
  436. }
  437. }
  438. tempTagNode = tagList;
  439. while (tempTagNode != NULL)
  440. {
  441. if ((_tcscmp(tempTagNode->Tag,"")))
  442. {
  443. _ftprintf(fpLocalTagFile, "%s - %s\n",
  444. tempTagNode->Tag,imageName + cSystemDirectory + _tcslen(DRIVERDIR) -1);
  445. tempTagNode = tempTagNode->next;
  446. }
  447. else break;
  448. }
  449. if (!FindNextFile(hSearch, &FileData))
  450. {
  451. if (GetLastError() == ERROR_NO_MORE_FILES)
  452. {
  453. fFinished = TRUE;
  454. }
  455. else
  456. {
  457. printf("Poolmon: Cannot find next .sys file\n");
  458. }
  459. }
  460. }
  461. freeall:
  462. // Close the search handle.
  463. if (hSearch)
  464. {
  465. if (!FindClose(hSearch)) {
  466. printf("Poolmon: Unable to close search handle: %d\n", GetLastError());
  467. }
  468. }
  469. if (filename) free(filename);
  470. if (fpLocalTagFile) fclose(fpLocalTagFile);
  471. //Free tagList memory
  472. PTAGLIST tempTagNode = tagList,prevTagNode = tagList;
  473. while (tempTagNode != NULL)
  474. {
  475. tempTagNode = tempTagNode->next;
  476. free(prevTagNode);
  477. prevTagNode = tempTagNode;
  478. }
  479. return ret;
  480. }
  481. FARPROC
  482. WINAPI
  483. PoolmonDLoadErrorHandler (
  484. UINT unReason,
  485. PDelayLoadInfo pDelayInfo
  486. )
  487. {
  488. printf("Poolmon: Unable to load required dlls, cannot create local tag file\n");
  489. exit(-1);
  490. }
  491. PfnDliHook __pfnDliFailureHook2 = PoolmonDLoadErrorHandler;
  492. #endif