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.

864 lines
24 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. StackSwap.cpp
  5. Abstract:
  6. Some applications make the assumption that Win32 APIs don't use any stack
  7. space. This stems from the architecture of win9x - whereby many APIs
  8. thunked and therefore had there own stack.
  9. Of course on NT this isn't the case and many APIs are normal user mode
  10. functions that don't even call down to kernel. To make matters worse, some
  11. applications depend on *no* stack usage in a number of other ways, for
  12. example:
  13. 1. Sierra Cart racing keeps a pointer in old stack
  14. 2. Baldur's Gate *double* dereferences pointers in old stack
  15. 3. NFL Blitz keeps it's linked lists on the stack and so simply calling
  16. an API causes corruption
  17. 4. NFL Blitz 2000 runs out of stack space calling CreateFile
  18. 5. Interplay EReg has uninitialized variables on the stack which are
  19. normally zeroed on win9x
  20. This shim is parameterized and takes a list of APIs and the behavior of
  21. each. Behavior is defined as the following:
  22. - No stack is used by this API
  23. 0 - After API is called, old stack will be filled with zeroes
  24. 1 - After API is called, old stack will be filled with valid pointers
  25. 2 - After API is called, old stack will be filled with valid pointers
  26. to pointers
  27. The default is that no stack space is used by the API.
  28. Notes:
  29. This is a general purpose shim.
  30. History:
  31. 05/03/2000 linstev Created
  32. 03/12/2001 robkenny Blessed for DBCS
  33. 02/07/2002 astritz Converted to strsafe
  34. --*/
  35. #include "precomp.h"
  36. IMPLEMENT_SHIM_BEGIN(StackSwap)
  37. #include "ShimHookMacro.h"
  38. #include "ShimStack.h"
  39. #include "StackSwap_Exports.h"
  40. #include "StackSwap_Excludes.h"
  41. APIHOOK_ENUM_BEGIN
  42. APIHOOK_ENUM_ENTRY(CreateThread)
  43. APIHOOK_ENUM_ENTRY(TerminateThread)
  44. APIHOOK_ENUM_ENTRY(ExitThread)
  45. APIHOOK_ENUM_END
  46. #define THREAD_VAR Vdm // The TEB variable to overwrite
  47. #define STUB_SIZE 64 // size of stub code in bytes
  48. #define STACK_SIZE 65536 // size of temporary stack
  49. #define STACK_COPY_SIZE 16 // number of dwords to copy from old stack
  50. #define STACK_FILL_SIZE 256 // default number of dwords to fill
  51. #define STACK_GUARD_SIZE 4096 // gaurd page at the top of the stack - must be a multiple of 4096
  52. #define STACK_FILL_NONE -1 // no old stack filling
  53. #define STACK_FILL_ZERO 0 // fill old stack with zeroes
  54. #define STACK_FILL_PTR1 1 // fill old stack with pointers
  55. #define STACK_FILL_PTR2 2 // fill old stack with pointers to pointers
  56. PVOID g_dwZero = 0; // used for pointer to zero
  57. PVOID g_dwPtr = &g_dwPtr; // used for pointer to pointer
  58. PVOID g_arrFill[] =
  59. {
  60. 0,
  61. &g_dwZero,
  62. &g_dwPtr
  63. };
  64. // Store for each hook returned by the parser
  65. struct HOOK
  66. {
  67. char szModule[MAX_PATH]; // Module name
  68. char szFnName[MAX_PATH]; // Function name
  69. PVOID pfnNew; // Pointer to stub
  70. int dwFill; // Stack fill type
  71. DWORD dwFillSize; // Number of dwords to fill
  72. struct HOOK *next;
  73. };
  74. HOOK *g_pHooks = NULL;
  75. HOOK g_AllHooks[] =
  76. {
  77. {"KERNEL32.DLL", "*", NULL, STACK_FILL_NONE},
  78. {"GDI32.DLL", "*", NULL, STACK_FILL_NONE},
  79. {"USER32.DLL", "*", NULL, STACK_FILL_NONE},
  80. {"WINMM.DLL", "*", NULL, STACK_FILL_NONE}
  81. };
  82. DWORD dwStubCount = 0;
  83. // Thread local data
  84. typedef struct _THREAD_DATA
  85. {
  86. PVOID pfnHook; // Address of actual call
  87. PVOID pNewStack; // The new stack
  88. PVOID pOldStack; // The old stack
  89. DWORD dwFill; // Fill method
  90. DWORD dwFillSize; // Number of dwords to fill
  91. ULONG ulCount; // Number of times we've entered
  92. DWORD dwRet; // Return value
  93. DWORD dwEcx, dwEsi, dwEdi; // Tempory storage, since we don't have a stack
  94. } THREAD_DATA;
  95. /*++
  96. This function is called from the stubs. It's purpose is to give the API a new
  97. stack to use. It does this by doing the following:
  98. 1. Copy the original stack to the new stack
  99. 2. Call the original hook
  100. 3. Copy the changed stack back to the original stack
  101. 4. Return control to the original caller
  102. The only tricky things about this routine are that we don't want to use any
  103. stack at all (no push/pop) and we need to calculate how much stack was used
  104. for the parameters - something we don't know because we don't have the proto-
  105. type.
  106. If we really wanted to use push and pop, we could have set up a temporary
  107. stack, but since we only need ecx, esi and edi, there didn't seem to be any
  108. point.
  109. --*/
  110. __declspec(naked)
  111. void
  112. SwapStack()
  113. {
  114. __asm {
  115. inc [eax + THREAD_DATA.ulCount] // increment counter
  116. mov [eax + THREAD_DATA.dwEcx], ecx // backup ecx
  117. mov [eax + THREAD_DATA.dwEsi], esi // backup esi
  118. mov [eax + THREAD_DATA.dwEdi], edi // backup edi
  119. mov ecx, [esp] // retrieve 'Hook' from Stub()
  120. mov [eax + THREAD_DATA.pfnHook], ecx // which we got from the call
  121. add esp, 4 // move the stack up to the return address
  122. mov dword ptr [esp], offset SwapBack // fill in our new return address
  123. lea edi, [esp + 4] // dst = new stack
  124. mov esi, [eax + THREAD_DATA.pOldStack] // src = old stack
  125. add esi, 4 // note the +4s since the first dword is the return address
  126. cld // clear direction flag
  127. mov ecx, STACK_COPY_SIZE - 1 // copy off STACK_COPY_SIZE - 1 bytes
  128. rep movsd // do the copy
  129. mov ecx, [eax + THREAD_DATA.dwEcx] // restore ecx
  130. mov esi, [eax + THREAD_DATA.dwEsi] // restore esi
  131. mov edi, [eax + THREAD_DATA.dwEdi] // restore edi
  132. jmp [eax + THREAD_DATA.pfnHook] // jump back into the stub to do the actual
  133. SwapBack:
  134. mov [esp - 4], eax // unfortunately this is the only way to store the return
  135. mov eax, fs:[0x18] // get the TEB
  136. mov eax, [eax + TEB.THREAD_VAR] // get our thread local pointer
  137. mov [eax + THREAD_DATA.dwEcx], ecx // backup ecx
  138. mov [eax + THREAD_DATA.dwEsi], esi // backup esi
  139. mov [eax + THREAD_DATA.dwEdi], edi // backup edi
  140. mov ecx, [esp - 4] // get return value
  141. mov [eax + THREAD_DATA.dwRet], ecx // store return value for later
  142. mov ecx, esp // this is where we find out how many parameters were passed
  143. sub ecx, [eax + THREAD_DATA.pNewStack] // on the stack - so we get the difference in ecx
  144. mov edi, [eax + THREAD_DATA.pOldStack] // original stack
  145. mov esi, [edi] // read the real return address
  146. add edi, ecx // move the stack up, so we don't copy unnecessay stack
  147. mov [edi - 4], esi // put the return address into edi-4: this is the only time we
  148. // use app stack space at all
  149. mov esp, edi
  150. mov ecx, [eax + THREAD_DATA.dwFill] // test how we're going to fill
  151. cmp ecx, STACK_FILL_NONE
  152. jz FillDone
  153. mov esi, [ecx*4 + g_arrFill] // value to fill with
  154. lea edi, [esp - 8] // we're going to fill backwards, so esp-8 will skip the return address
  155. mov ecx, [eax + THREAD_DATA.dwFillSize] // number of dwords to fill with
  156. FillStack:
  157. mov [edi], esi // store the value
  158. sub edi, 4
  159. dec ecx
  160. jnz FillStack
  161. FillDone:
  162. mov ecx, [eax + THREAD_DATA.dwEcx] // restore ecx
  163. mov esi, [eax + THREAD_DATA.dwEsi] // restore esi
  164. mov edi, [eax + THREAD_DATA.dwEdi] // restore edi
  165. dec [eax + THREAD_DATA.ulCount] // decrement counter
  166. mov eax, [eax + THREAD_DATA.dwRet] // get the return value
  167. jmp dword ptr [esp - 4] // return to original caller
  168. }
  169. }
  170. //
  171. // We need the stub to do a far call to SwapStack since the stub will move, but
  172. // I can't seem to force the far call without this method
  173. //
  174. DWORD_PTR g_pfnStackSwap = (DWORD_PTR)SwapStack;
  175. /*++
  176. This is the stub function that is called by every API. It is copied from here
  177. to blocks of executable memory and the calls and fill types are written to
  178. hard coded addresses within it.
  179. The instuctions:
  180. mov [eax + THREAD_DATA.dwFill], 0xFFFFFFFF is replaced by
  181. mov [eax + THREAD_DATA.dwFill], FILL_TYPE
  182. mov [eax + THREAD_DATA.dwFillSize], 0xFFFFFFFF is replaced by
  183. mov [eax + THREAD_DATA.dwFill], FILL_SIZE
  184. and
  185. call g_pfnStackSwap is replaced by
  186. call g_pAPIHooks[api].pfnOld
  187. --*/
  188. __declspec(naked)
  189. void
  190. Stub()
  191. {
  192. __asm {
  193. mov eax, fs:[0x18] // get the TEB
  194. mov eax, [eax + TEB.THREAD_VAR] // get our thread local pointer
  195. or eax, eax // our pointer is gone
  196. jz Hook // exit gracefully
  197. cmp [eax + THREAD_DATA.ulCount], 0 // have we already swapped the stack
  198. jnz Hook
  199. mov [eax + THREAD_DATA.dwFill], 0xFFFFFFFF // the 0xFFFFFFFF will be replaced by the fill type
  200. mov [eax + THREAD_DATA.dwFillSize], 0xFFFFFFFF // the 0xFFFFFFFF will be replaced by the fill size
  201. mov [eax + THREAD_DATA.pOldStack], esp // backup the old stack
  202. mov esp, [eax + THREAD_DATA.pNewStack] // swap the stack
  203. call g_pfnStackSwap // call into the stack swapping code
  204. Hook:
  205. jmp [g_pHooks] // jump to the hook
  206. }
  207. }
  208. /*++
  209. Create a new stack
  210. --*/
  211. THREAD_DATA *
  212. AllocStack()
  213. {
  214. LPVOID p = VirtualAlloc(
  215. 0,
  216. sizeof(THREAD_DATA) + STACK_SIZE + STACK_GUARD_SIZE,
  217. MEM_COMMIT,
  218. PAGE_READWRITE);
  219. if (p)
  220. {
  221. DWORD dwOld;
  222. if (!VirtualProtect(p, STACK_GUARD_SIZE, PAGE_READONLY | PAGE_GUARD, &dwOld))
  223. {
  224. DPFN( eDbgLevelError, "Failed to place Gaurd page at the top of the stack");
  225. }
  226. THREAD_DATA *pTD = (THREAD_DATA *)((DWORD_PTR)p + STACK_SIZE + STACK_GUARD_SIZE);
  227. pTD->pNewStack = (LPVOID)((DWORD_PTR)pTD - STACK_COPY_SIZE * 4);
  228. return pTD;
  229. }
  230. else
  231. {
  232. DPFN( eDbgLevelError, "Failed to allocate new stack");
  233. return NULL;
  234. }
  235. }
  236. /*++
  237. Free the stack
  238. --*/
  239. BOOL
  240. FreeStack(THREAD_DATA *pTD)
  241. {
  242. BOOL bRet = FALSE;
  243. if (pTD)
  244. {
  245. LPVOID p = (LPVOID)((DWORD_PTR)pTD - STACK_SIZE - STACK_GUARD_SIZE);
  246. bRet = VirtualFree(p, 0, MEM_RELEASE);
  247. }
  248. if (!bRet)
  249. {
  250. DPFN( eDbgLevelError, "Failed to free a stack");
  251. }
  252. return bRet;
  253. }
  254. /*++
  255. Hook CreateThread so we can add our stuff to the TEB.
  256. --*/
  257. HANDLE
  258. APIHOOK(CreateThread)(
  259. LPSECURITY_ATTRIBUTES lpThreadAttributes,
  260. DWORD dwStackSize,
  261. LPTHREAD_START_ROUTINE lpStartAddress,
  262. LPVOID lpParameter,
  263. DWORD dwCreationFlags,
  264. LPDWORD lpThreadId
  265. )
  266. {
  267. HANDLE hRet;
  268. DWORD dwFlags = dwCreationFlags;
  269. NEW_STACK();
  270. hRet = ORIGINAL_API(CreateThread)(
  271. lpThreadAttributes,
  272. dwStackSize,
  273. lpStartAddress,
  274. lpParameter,
  275. dwCreationFlags | CREATE_SUSPENDED,
  276. lpThreadId);
  277. if (hRet)
  278. {
  279. THREAD_BASIC_INFORMATION tbi;
  280. NTSTATUS Status;
  281. Status = NtQueryInformationThread(
  282. hRet,
  283. ThreadBasicInformation,
  284. &tbi,
  285. sizeof(tbi),
  286. NULL);
  287. if ((NT_SUCCESS(Status)) && (tbi.TebBaseAddress))
  288. {
  289. tbi.TebBaseAddress->THREAD_VAR = AllocStack();
  290. }
  291. if (!(dwFlags & CREATE_SUSPENDED))
  292. {
  293. ResumeThread(hRet);
  294. }
  295. }
  296. OLD_STACK();
  297. return hRet;
  298. }
  299. /*++
  300. Hook TerminateThread so we can clean up the thread local data.
  301. --*/
  302. BOOL
  303. APIHOOK(TerminateThread)(
  304. HANDLE hThread,
  305. DWORD dwExitCode
  306. )
  307. {
  308. THREAD_BASIC_INFORMATION tbi;
  309. NTSTATUS Status;
  310. BOOL bRet;
  311. THREAD_DATA *pTD = NULL;
  312. Status = NtQueryInformationThread(
  313. hThread,
  314. ThreadBasicInformation,
  315. &tbi,
  316. sizeof(tbi),
  317. NULL);
  318. if ((NT_SUCCESS(Status)) && (tbi.TebBaseAddress))
  319. {
  320. pTD = (THREAD_DATA *)(tbi.TebBaseAddress->THREAD_VAR);
  321. }
  322. bRet = ORIGINAL_API(TerminateThread)(hThread, dwExitCode);
  323. FreeStack(pTD);
  324. return bRet;
  325. }
  326. /*++
  327. Hook ExitThread so we can clean up the thread local data.
  328. --*/
  329. VOID
  330. APIHOOK(ExitThread)(
  331. DWORD dwExitCode
  332. )
  333. {
  334. NTSTATUS Status;
  335. THREAD_BASIC_INFORMATION tbi;
  336. HANDLE hThread = GetCurrentThread();
  337. Status = NtQueryInformationThread(
  338. hThread,
  339. ThreadBasicInformation,
  340. &tbi,
  341. sizeof(tbi),
  342. NULL);
  343. if ((NT_SUCCESS(Status)) && (tbi.TebBaseAddress))
  344. {
  345. THREAD_DATA *pTD = (THREAD_DATA *)tbi.TebBaseAddress->THREAD_VAR;
  346. // Make sure we don't free it if we're using it
  347. if (pTD && (pTD->ulCount == 0))
  348. {
  349. FreeStack(pTD);
  350. }
  351. }
  352. ORIGINAL_API(ExitThread)(dwExitCode);
  353. }
  354. /*++
  355. Add the specified hook to the linked list - this accepts wildcards.
  356. --*/
  357. VOID
  358. AddHooks(HOOK *pHook)
  359. {
  360. if (strstr(pHook->szFnName, "*") == 0)
  361. {
  362. // Now that we have a hook (not a wild card), we need to make sure it's
  363. // ok to add it to the list. There are some calls that cannot be shimmed
  364. for (int i=0; i<sizeof(Excludes)/sizeof(FNEXCLUDE); i++)
  365. {
  366. if ((_stricmp(pHook->szModule, (LPSTR)Excludes[i].pszModule) == 0) &&
  367. (strcmp(pHook->szFnName, (LPSTR)Excludes[i].pszFnName) == 0))
  368. {
  369. DPFN( eDbgLevelInfo,"Ignoring %s!%s", Excludes[i].pszModule, Excludes[i].pszFnName);
  370. return;
  371. }
  372. }
  373. // The hook passes, so add it to the list.
  374. HOOK *pH = (HOOK *) malloc(sizeof(HOOK));
  375. if (pH)
  376. {
  377. MoveMemory(pH, pHook, sizeof(HOOK));
  378. pH->next = g_pHooks;
  379. g_pHooks = pH;
  380. }
  381. return;
  382. }
  383. // Here we have to look through the exports
  384. LOADED_IMAGE image;
  385. if (!LoadModule(pHook->szModule, &image))
  386. {
  387. DPFN( eDbgLevelError, "Module %s not found", pHook->szModule);
  388. return;
  389. }
  390. EXPORT_ENUM exports;
  391. CHAR szFnName[MAX_PATH];
  392. if( StringCchCopyA(szFnName, MAX_PATH, pHook->szFnName) != S_OK )
  393. {
  394. DPFN(eDbgLevelError, "String Copy failed.");
  395. return;
  396. }
  397. DWORD dwLen = (DWORD)((DWORD_PTR)strstr(pHook->szFnName, "*") - (DWORD_PTR)&pHook->szFnName);
  398. // Enumerate the exports for this module
  399. BOOL bMore = EnumFirstExport(&image, &exports);
  400. while (bMore)
  401. {
  402. if ((dwLen == 0) ||
  403. (strncmp(exports.ExportFunction, szFnName, dwLen) == 0))
  404. {
  405. // We have a match
  406. if( StringCchCopyA(pHook->szFnName, MAX_PATH, exports.ExportFunction) != S_OK )
  407. {
  408. DPFN(eDbgLevelError, "String Copy failed.");
  409. return;
  410. }
  411. AddHooks(pHook);
  412. }
  413. bMore = EnumNextExport(&exports);
  414. }
  415. // Done with this module
  416. UnloadModule(&image);
  417. }
  418. /*++
  419. Parse the command line for APIs to fix stack problems with:
  420. USER32.DLL!GetDC:0; KERNEL32.DLL!CreateFile*
  421. The :X is to define behaviour - so:
  422. :0 fill old stack with zeroes
  423. :1 fill old stack with pointers
  424. :2 fill old stack with pointers to pointers
  425. --*/
  426. DWORD
  427. ParseCommandLineA(
  428. LPCSTR lpCommandLine
  429. )
  430. {
  431. char seps[] = " :,\t;!";
  432. char *token = NULL;
  433. HOOK *pHook = NULL;
  434. DWORD dwState = 0;
  435. HOOK hook;
  436. // Since strtok modifies the string, we need to copy it
  437. LPSTR szCommandLine = (LPSTR) malloc(strlen(lpCommandLine) + 1);
  438. if (!szCommandLine) goto Exit;
  439. if( StringCchCopyA(szCommandLine, strlen(lpCommandLine) + 1, lpCommandLine) != S_OK )
  440. {
  441. DPFN(eDbgLevelError, "String Copy failed.");
  442. goto Exit;
  443. }
  444. //
  445. // See if we need to do all modules
  446. //
  447. if ((strcmp(szCommandLine, "") == 0) || (strcmp(szCommandLine, "*") == 0))
  448. {
  449. for (int i=0; i<sizeof(g_AllHooks)/sizeof(HOOK); i++)
  450. {
  451. AddHooks(&g_AllHooks[i]);
  452. }
  453. goto Exit;
  454. }
  455. //
  456. // Run the string, looking for exception names
  457. //
  458. token = _strtok(szCommandLine, seps);
  459. while (token)
  460. {
  461. switch (dwState)
  462. {
  463. case 2: // handle the :X[(fill size)] case
  464. dwState = 0;
  465. if (token[0] && ((token[1] == '\0') || (token[1] == '(')))
  466. {
  467. switch (token[0])
  468. {
  469. case '0':
  470. hook.dwFill = STACK_FILL_ZERO;
  471. break;
  472. case '1':
  473. hook.dwFill = STACK_FILL_PTR1;
  474. break;
  475. case '2':
  476. hook.dwFill = STACK_FILL_PTR2;
  477. break;
  478. default:
  479. hook.dwFill = STACK_FILL_ZERO;
  480. }
  481. if (token[1] == '(')
  482. {
  483. token+=2; // advance to the beginning of the fill size
  484. token[strlen(token)-1] = '\0'; // null terminate
  485. hook.dwFillSize = atol(token) >> 2; // get fill size in dwords
  486. if (hook.dwFillSize == 0)
  487. {
  488. hook.dwFillSize = STACK_FILL_SIZE;
  489. }
  490. }
  491. // We must be done, so add this hook
  492. AddHooks(&hook);
  493. break;
  494. }
  495. AddHooks(&hook);
  496. case 0: // add a new API module name
  497. ZeroMemory(&hook, sizeof(HOOK));
  498. if( StringCchCopyA(hook.szModule, MAX_PATH, token) != S_OK )
  499. {
  500. DPFN(eDbgLevelError, "String Copy failed.");
  501. goto Exit;
  502. }
  503. hook.dwFill = STACK_FILL_NONE;
  504. hook.dwFillSize = STACK_FILL_SIZE;
  505. dwState++;
  506. break;
  507. case 1: // add a new API function name
  508. dwState++;
  509. if (strlen(hook.szModule) == 0)
  510. {
  511. DPFN( eDbgLevelError, "Parse error with token %s", token);
  512. goto Exit;
  513. }
  514. if( StringCchCopyA(hook.szFnName, MAX_PATH, token) != S_OK )
  515. {
  516. DPFN(eDbgLevelError, "String Copy failed.");
  517. goto Exit;
  518. }
  519. break;
  520. }
  521. // Get the next token
  522. token = _strtok(NULL, seps);
  523. }
  524. if (dwState == 2)
  525. {
  526. AddHooks(&hook);
  527. }
  528. Exit:
  529. if (szCommandLine)
  530. {
  531. free(szCommandLine);
  532. }
  533. if (!g_pHooks)
  534. {
  535. DPFN( eDbgLevelError, "No hooks added");
  536. return 0;
  537. }
  538. //
  539. // Dump results of command line parse
  540. //
  541. DPFN( eDbgLevelInfo, "--------------------------------------------");
  542. DPFN( eDbgLevelInfo, " Stack Swapping the following APIs: ");
  543. DPFN( eDbgLevelInfo, "--------------------------------------------");
  544. DWORD dwCount = 0;
  545. pHook = g_pHooks;
  546. while (pHook)
  547. {
  548. DPFN( eDbgLevelInfo, "%s!%s: Fill=%d, Size=%d", pHook->szModule, pHook->szFnName, pHook->dwFill, pHook->dwFillSize*4);
  549. dwCount++;
  550. pHook = pHook->next;
  551. }
  552. DPFN( eDbgLevelInfo, "--------------------------------------------");
  553. return dwCount;
  554. }
  555. /*++
  556. Builds the stubs for the hooked APIs
  557. --*/
  558. DWORD
  559. BuildStubs()
  560. {
  561. // Count the stubs
  562. DWORD dwCount = 0;
  563. HOOK *pHook = g_pHooks;
  564. while (pHook)
  565. {
  566. dwCount++;
  567. pHook = pHook->next;
  568. }
  569. // Create the stubs
  570. LPBYTE pStub = (LPBYTE) VirtualAlloc(
  571. 0,
  572. STUB_SIZE * dwCount,
  573. MEM_COMMIT,
  574. PAGE_EXECUTE_READWRITE);
  575. if (!pStub)
  576. {
  577. DPFN( eDbgLevelError, "Could not allocate memory for stubs");
  578. return 0;
  579. }
  580. pHook = g_pHooks;
  581. PHOOKAPI pAPIHook = &g_pAPIHooks[APIHOOK_Count];
  582. while (pHook)
  583. {
  584. MoveMemory(pStub, Stub, STUB_SIZE);
  585. LPDWORD p;
  586. p = (LPDWORD)((DWORD_PTR)pStub + 0x19); // fill in the fill type
  587. *p = pHook->dwFill;
  588. p = (LPDWORD)((DWORD_PTR)pStub + 0x19+7); // fill in the fill size
  589. *p = pHook->dwFillSize;
  590. p = (LPDWORD)((DWORD_PTR)pStub + 0x2b+7); // fill in the hook
  591. *p = (DWORD_PTR)&pAPIHook->pfnOld;
  592. ZeroMemory(pAPIHook, sizeof(HOOKAPI));
  593. pAPIHook->pszModule = pHook->szModule;
  594. pAPIHook->pszFunctionName = pHook->szFnName;
  595. pAPIHook->pfnNew = pStub;
  596. DPFN( eDbgLevelSpew, "%08lx %s!%s", pStub, pHook->szModule, pHook->szFnName);
  597. pStub += STUB_SIZE;
  598. pAPIHook++;
  599. pHook = pHook->next;
  600. }
  601. return dwCount;
  602. }
  603. /*++
  604. Free the stub list allocated by ParseCommandLineA
  605. --*/
  606. VOID
  607. FreeStubs()
  608. {
  609. HOOK *pHook = g_pHooks;
  610. while (pHook)
  611. {
  612. pHook = pHook->next;
  613. free(g_pHooks);
  614. g_pHooks = pHook;
  615. }
  616. }
  617. /*++
  618. Register hooked functions
  619. --*/
  620. BOOL
  621. NOTIFY_FUNCTION(DWORD fdwReason)
  622. {
  623. if (fdwReason == DLL_PROCESS_ATTACH)
  624. {
  625. // Run the command line to check for hooks - returns number found
  626. dwStubCount = ParseCommandLineA(COMMAND_LINE);
  627. if (dwStubCount)
  628. {
  629. //
  630. // Increase the hook structure size.
  631. //
  632. g_pAPIHooks = (PHOOKAPI) realloc(g_pAPIHooks,
  633. sizeof(HOOKAPI) * (APIHOOK_Count + dwStubCount));
  634. if (!g_pAPIHooks)
  635. {
  636. DPFN( eDbgLevelError, "Failed to re-allocate hooks");
  637. return FALSE;
  638. }
  639. }
  640. INIT_STACK(1024 * 128, 32);
  641. NtCurrentTeb()->THREAD_VAR = AllocStack();
  642. BuildStubs();
  643. }
  644. else if (fdwReason == DLL_PROCESS_DETACH)
  645. {
  646. // Ignore cleanup
  647. // FreeStubs();
  648. }
  649. return TRUE;
  650. }
  651. HOOK_BEGIN
  652. CALL_NOTIFY_FUNCTION
  653. APIHOOK_ENTRY(KERNEL32.DLL, CreateThread)
  654. APIHOOK_ENTRY(KERNEL32.DLL, TerminateThread)
  655. APIHOOK_ENTRY(KERNEL32.DLL, ExitThread)
  656. if (fdwReason == DLL_PROCESS_ATTACH)
  657. {
  658. // Write out the new size
  659. *pdwHookCount = APIHOOK_Count + dwStubCount;
  660. }
  661. HOOK_END
  662. IMPLEMENT_SHIM_END