Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

520 lines
12 KiB

  1. #include <windows.h>
  2. #include <string.h>
  3. #include <stdio.h>
  4. #include <tlhelp32.h>
  5. #include "profiler.h"
  6. #include "inject.h"
  7. #include "view.h"
  8. #include "except.h"
  9. #include "thread.h"
  10. #include "dump.h"
  11. #include "shimdb.h"
  12. #include "shim2.h"
  13. #include "hooks.h"
  14. #include "memory.h"
  15. #include "filter.h"
  16. #include "clevel.h"
  17. #include "cap.h"
  18. extern CHAR g_fnFinalizeInjection[MAX_PATH];
  19. extern HINSTANCE g_hProfileDLL;
  20. extern FIXUPRETURN g_fnFixupReturn[1];
  21. extern DWORD g_dwCallArray[2];
  22. extern CAPFILTER g_execFilter;
  23. int
  24. WINAPI
  25. WinMain(
  26. HINSTANCE hInst,
  27. HINSTANCE hInstPrev,
  28. LPSTR lpszCmd,
  29. int swShow)
  30. {
  31. HANDLE hFile = 0;
  32. BOOL bResult = FALSE;
  33. STARTUPINFO sInfo;
  34. PCHAR pszToken;
  35. PCHAR pszEnd;
  36. PROCESS_INFORMATION pInfo;
  37. DWORD dwEntry = 0;
  38. OSVERSIONINFO verInfo;
  39. BOOL bIsWin9X = FALSE;
  40. HANDLE hDevice = INVALID_HANDLE_VALUE;
  41. //
  42. // Get the OS information
  43. //
  44. ZeroMemory(&verInfo, sizeof(OSVERSIONINFO));
  45. verInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  46. bResult = GetVersionExA(&verInfo);
  47. if (FALSE == bResult) {
  48. return -1;
  49. }
  50. if (VER_PLATFORM_WIN32_NT == verInfo.dwPlatformId) {
  51. bIsWin9X = FALSE;
  52. }
  53. else if (VER_PLATFORM_WIN32_WINDOWS == verInfo.dwPlatformId) {
  54. bIsWin9X = TRUE;
  55. }
  56. //
  57. // Initialize my working heap
  58. //
  59. bResult = InitializeHeap();
  60. if (FALSE == bResult) {
  61. return -1;
  62. }
  63. //
  64. // Parse the command line
  65. //
  66. pszToken = strstr(lpszCmd, "\"");
  67. if (pszToken) {
  68. pszToken++;
  69. pszEnd = strstr(pszToken, "\"");
  70. *pszEnd = '\0';
  71. }
  72. if (0 == pszToken) {
  73. pszToken = strstr(lpszCmd, " ");
  74. if (0 == pszToken) {
  75. pszToken = strstr(lpszCmd, "\t");
  76. if (0 == pszToken) {
  77. pszToken = lpszCmd;
  78. }
  79. }
  80. }
  81. //
  82. // Initialize our process information struct
  83. //
  84. ZeroMemory(&sInfo, sizeof(STARTUPINFO));
  85. ZeroMemory(&pInfo, sizeof(PROCESS_INFORMATION));
  86. sInfo.cb = sizeof(STARTUPINFO);
  87. dwEntry = GetExeEntryPoint(pszToken);
  88. if (0 == dwEntry) {
  89. return -1;
  90. }
  91. //
  92. // Get our exe ready for DLL injection
  93. //
  94. bResult = CreateProcessA(0,
  95. pszToken,
  96. 0,
  97. 0,
  98. FALSE,
  99. CREATE_SUSPENDED,
  100. 0,
  101. 0, //should make this a setable param sooner rather than later
  102. &sInfo,
  103. &pInfo);
  104. if (FALSE == bResult) {
  105. return -1;
  106. }
  107. //
  108. // If we're 9x - bring in the VxD
  109. //
  110. if (TRUE == bIsWin9X) {
  111. hDevice = AttachToEXVectorVXD();
  112. if (INVALID_HANDLE_VALUE == hDevice) {
  113. return -1;
  114. }
  115. }
  116. //
  117. // Inject our dll into the target
  118. //
  119. hFile = InjectDLL(dwEntry,
  120. pInfo.hProcess,
  121. NAME_OF_DLL_TO_INJECT);
  122. if (0 == hFile) {
  123. return -1;
  124. }
  125. //
  126. // Turn the process loose
  127. //
  128. bResult = ResumeThread(pInfo.hThread);
  129. if (FALSE == bResult) {
  130. return -1;
  131. }
  132. //
  133. // Wait for target termination
  134. //
  135. WaitForSingleObject(pInfo.hThread,
  136. INFINITE);
  137. //
  138. // If we're 9x - close our handle to the vxd (this will unload the vxd from memory)
  139. //
  140. if (TRUE == bIsWin9X) {
  141. if (INVALID_HANDLE_VALUE != hDevice) {
  142. DetachFromEXVectorVXD(hDevice);
  143. }
  144. }
  145. return 0;
  146. }
  147. DWORD
  148. GetExeEntryPoint(LPSTR pszExePath)
  149. {
  150. PIMAGE_NT_HEADERS pHeaders;
  151. BOOL bResult;
  152. PCHAR pEXEBits = 0;
  153. DWORD dwEntry = 0;
  154. DWORD dwNumberBytesRead;
  155. HANDLE hFile = INVALID_HANDLE_VALUE;
  156. pEXEBits = (PCHAR)AllocMem(4096 * 1); //allocate a page for reading the PE entry point
  157. if (0 == pEXEBits) {
  158. return dwEntry;
  159. }
  160. hFile = CreateFileA(pszExePath,
  161. GENERIC_READ,
  162. FILE_SHARE_READ,
  163. 0,
  164. OPEN_EXISTING,
  165. FILE_ATTRIBUTE_NORMAL,
  166. 0);
  167. if (INVALID_HANDLE_VALUE == hFile) {
  168. goto handleerror;
  169. }
  170. bResult = ReadFile(hFile,
  171. pEXEBits,
  172. 4096, //read one page
  173. &dwNumberBytesRead,
  174. 0);
  175. if (FALSE == bResult) {
  176. goto handleerror;
  177. }
  178. //
  179. // Dig out the PE information
  180. //
  181. pHeaders = ImageNtHeader2((PVOID)pEXEBits);
  182. if (0 == pHeaders) {
  183. goto handleerror;
  184. }
  185. dwEntry = pHeaders->OptionalHeader.ImageBase + pHeaders->OptionalHeader.AddressOfEntryPoint;
  186. handleerror:
  187. if (pEXEBits) {
  188. FreeMem(pEXEBits);
  189. }
  190. if (INVALID_HANDLE_VALUE != hFile) {
  191. CloseHandle(hFile);
  192. }
  193. return dwEntry;
  194. }
  195. PIMAGE_NT_HEADERS
  196. ImageNtHeader2 (PVOID Base)
  197. {
  198. PIMAGE_NT_HEADERS NtHeaders = NULL;
  199. if (Base != NULL && Base != (PVOID)-1) {
  200. if (((PIMAGE_DOS_HEADER)Base)->e_magic == IMAGE_DOS_SIGNATURE) {
  201. NtHeaders = (PIMAGE_NT_HEADERS)((PCHAR)Base + ((PIMAGE_DOS_HEADER)Base)->e_lfanew);
  202. if (NtHeaders->Signature != IMAGE_NT_SIGNATURE) {
  203. NtHeaders = NULL;
  204. }
  205. }
  206. }
  207. return NtHeaders;
  208. }
  209. BOOL
  210. WINAPI
  211. DllMain (
  212. HINSTANCE hinstDLL,
  213. DWORD fdwReason,
  214. LPVOID lpvReserved)
  215. {
  216. PIMAGE_NT_HEADERS pHeaders;
  217. PVOID pBase = 0;
  218. DWORD dwEntryPoint;
  219. BOOL bResult = FALSE;
  220. //
  221. // Return true for everything coming through here
  222. //
  223. if (DLL_PROCESS_ATTACH == fdwReason) {
  224. //
  225. // Initialize my working heap
  226. //
  227. bResult = InitializeHeap();
  228. if (FALSE == bResult) {
  229. return FALSE;
  230. }
  231. //
  232. // Initialize the asm for the fixup return
  233. //
  234. //
  235. // Get the entry point from the headers
  236. //
  237. pBase = (PVOID)GetModuleHandle(0);
  238. if (0 == pBase) {
  239. return FALSE;
  240. }
  241. //
  242. // Dig out the PE information
  243. //
  244. pHeaders = ImageNtHeader2(pBase);
  245. if (0 == pHeaders) {
  246. return FALSE;
  247. }
  248. dwEntryPoint = pHeaders->OptionalHeader.ImageBase + pHeaders->OptionalHeader.AddressOfEntryPoint;
  249. //
  250. // Initialize stub asm for cleanup
  251. //
  252. g_fnFinalizeInjection[0] = 0x90; // int 3
  253. g_fnFinalizeInjection[1] = 0xff; // call dword ptr [xxxxxxxx] - RestoreImageFromInjection
  254. g_fnFinalizeInjection[2] = 0x15;
  255. *(DWORD *)(&(g_fnFinalizeInjection[3])) = (DWORD)g_fnFinalizeInjection + 50;
  256. g_fnFinalizeInjection[7] = 0x83;
  257. g_fnFinalizeInjection[8] = 0xc4;
  258. g_fnFinalizeInjection[9] = 0x04;
  259. g_fnFinalizeInjection[10] = 0x61;
  260. g_fnFinalizeInjection[11] = 0xa1;
  261. *(DWORD *)(&(g_fnFinalizeInjection[12])) = (DWORD)g_fnFinalizeInjection + 54;
  262. g_fnFinalizeInjection[16] = 0xff;
  263. g_fnFinalizeInjection[17] = 0xe0;
  264. *(DWORD *)(&(g_fnFinalizeInjection[50])) = (DWORD)RestoreImageFromInjection;
  265. *(DWORD *)(&(g_fnFinalizeInjection[54])) = dwEntryPoint;
  266. //
  267. // Initialize the call return code
  268. //
  269. g_dwCallArray[0] = (DWORD)PopCaller;
  270. g_dwCallArray[1] = (DWORD)g_fnFixupReturn;
  271. g_fnFixupReturn->PUSHAD = 0x60; //pushad (60)
  272. g_fnFixupReturn->PUSHFD = 0x9c; //pushfd (9c)
  273. g_fnFixupReturn->PUSHDWORDESPPLUS24[0] = 0xff; //push dword ptr [esp+24] (ff 74 24 24)
  274. g_fnFixupReturn->PUSHDWORDESPPLUS24[1] = 0x74;
  275. g_fnFixupReturn->PUSHDWORDESPPLUS24[2] = 0x24;
  276. g_fnFixupReturn->PUSHDWORDESPPLUS24[3] = 0x24;
  277. g_fnFixupReturn->CALLROUTINE[0] = 0xff; //call [address] (ff15 dword address)
  278. g_fnFixupReturn->CALLROUTINE[1] = 0x15;
  279. *(DWORD *)(&(g_fnFixupReturn->CALLROUTINE[2])) = (DWORD)&(g_dwCallArray[0]);
  280. g_fnFixupReturn->MOVESPPLUS24EAX[0] = 0x89; //mov [esp+0x24],eax (89 44 24 24)
  281. g_fnFixupReturn->MOVESPPLUS24EAX[1] = 0x44;
  282. g_fnFixupReturn->MOVESPPLUS24EAX[2] = 0x24;
  283. g_fnFixupReturn->MOVESPPLUS24EAX[3] = 0x24;
  284. g_fnFixupReturn->POPFD = 0x9d; //popfd (9d)
  285. g_fnFixupReturn->POPAD = 0x61; //popad (61)
  286. g_fnFixupReturn->RET = 0xc3; //ret (c3)
  287. //
  288. // Store the DLL base address
  289. //
  290. g_hProfileDLL = hinstDLL;
  291. }
  292. return TRUE;
  293. }
  294. BOOL
  295. InitializeProfiler(VOID)
  296. {
  297. BOOL bResult = TRUE;
  298. PIMAGE_NT_HEADERS pHeaders;
  299. PVOID pBase = 0;
  300. DWORD dwEntryPoint;
  301. PVIEWCHAIN pvTemp;
  302. //
  303. // Get the entry point from the headers
  304. //
  305. pBase = (PVOID)GetModuleHandle(0);
  306. if (0 == pBase) {
  307. return FALSE;
  308. }
  309. //
  310. // Dig out the PE information
  311. //
  312. pHeaders = ImageNtHeader2(pBase);
  313. if (0 == pHeaders) {
  314. return FALSE;
  315. }
  316. dwEntryPoint = pHeaders->OptionalHeader.ImageBase + pHeaders->OptionalHeader.AddressOfEntryPoint;
  317. //
  318. // Tag the entry point so it'll start profiling with the initial view
  319. //
  320. bResult = InitializeViewData();
  321. if (FALSE == bResult) {
  322. //
  323. // Something unexpected happened
  324. //
  325. ExitProcess(-1);
  326. }
  327. //
  328. // Initialize execution filter data
  329. //
  330. ZeroMemory(&g_execFilter, sizeof(CAPFILTER));
  331. //
  332. // Initialize thread context data
  333. //
  334. InitializeThreadData();
  335. //
  336. // Get the debug logging setup
  337. //
  338. bResult = InitializeDumpData();
  339. if (FALSE == bResult) {
  340. //
  341. // Something unexpected happened
  342. //
  343. ExitProcess(-1);
  344. }
  345. //
  346. // Initialize the module filtering
  347. //
  348. bResult = InitializeFilterList();
  349. if (FALSE == bResult) {
  350. //
  351. // Something unexpected happened
  352. //
  353. ExitProcess(-1);
  354. }
  355. //
  356. // Set up exception trap mechanism
  357. //
  358. bResult = HookUnchainableExceptionFilter();
  359. if (FALSE == bResult) {
  360. //
  361. // Something unexpected happened while chaining exception filter
  362. //
  363. ExitProcess(-1);
  364. }
  365. //
  366. // Fixup the module list now that everything is restored
  367. //
  368. //
  369. InitializeBaseHooks(g_hProfileDLL);
  370. //
  371. // Write out import table base info
  372. //
  373. bResult = WriteImportDLLTableInfo();
  374. if (FALSE == bResult) {
  375. ExitProcess(-1);
  376. }
  377. //
  378. // Add our entrypoint to the view monitor
  379. //
  380. pvTemp = AddViewToMonitor(dwEntryPoint,
  381. ThreadStart);
  382. if (0 == pvTemp) {
  383. ExitProcess(-1);
  384. }
  385. //
  386. // We're done
  387. //
  388. return TRUE;
  389. }
  390. BOOL
  391. WriteImportDLLTableInfo(VOID)
  392. {
  393. HANDLE hSnapshot = INVALID_HANDLE_VALUE;
  394. MODULEENTRY32 ModuleEntry32;
  395. BOOL bResult;
  396. hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE,
  397. 0);
  398. if (INVALID_HANDLE_VALUE == hSnapshot) {
  399. return FALSE;
  400. }
  401. //
  402. // Walk the DLL imports
  403. //
  404. ModuleEntry32.dwSize = sizeof(ModuleEntry32);
  405. bResult = Module32First(hSnapshot,
  406. &ModuleEntry32);
  407. if (FALSE == bResult) {
  408. return bResult;
  409. }
  410. while(bResult) {
  411. //
  412. // Dump the module information to disk
  413. //
  414. if ((DWORD)(ModuleEntry32.modBaseAddr) != (DWORD)g_hProfileDLL) {
  415. bResult = WriteDllInfo(ModuleEntry32.szModule,
  416. (DWORD)(ModuleEntry32.modBaseAddr),
  417. (DWORD)(ModuleEntry32.modBaseSize));
  418. if (FALSE == bResult) {
  419. CloseHandle(hSnapshot);
  420. return FALSE;
  421. }
  422. }
  423. bResult = Module32Next(hSnapshot,
  424. &ModuleEntry32);
  425. }
  426. if (INVALID_HANDLE_VALUE != hSnapshot) {
  427. CloseHandle(hSnapshot);
  428. }
  429. return TRUE;
  430. }
  431. HANDLE
  432. AttachToEXVectorVXD(VOID)
  433. {
  434. HANDLE hFile;
  435. hFile = CreateFileA(NAME_OF_EXCEPTION_VXD,
  436. 0,
  437. 0,
  438. 0,
  439. 0,
  440. FILE_FLAG_DELETE_ON_CLOSE,
  441. 0);
  442. return hFile;
  443. }
  444. VOID
  445. DetachFromEXVectorVXD(HANDLE hDevice)
  446. {
  447. CloseHandle(hDevice);
  448. }