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.

376 lines
7.8 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. Settlers3.cpp
  5. Abstract:
  6. The app has a protection system that sets the CPU direction flag and
  7. expects it to be maintained through calls to WaitForSingleObject, SetEvent
  8. and ResetEvent.
  9. We have to patch the import tables manually and pretend to be kernel32 so
  10. the protection system doesn't fail elsewhere.
  11. Notes:
  12. This is an app specific shim.
  13. History:
  14. 07/05/2001 linstev Created
  15. --*/
  16. #include "precomp.h"
  17. #include "LegalStr.h"
  18. IMPLEMENT_SHIM_BEGIN(Settlers3)
  19. #include "ShimHookMacro.h"
  20. APIHOOK_ENUM_BEGIN
  21. APIHOOK_ENUM_END
  22. //
  23. // The real kernel32 handle
  24. //
  25. HINSTANCE g_hinstKernel;
  26. // Functions to hook imports
  27. BOOL HookImports(HMODULE hModule);
  28. //
  29. // List of hooks we'll be patching
  30. //
  31. FARPROC _GetProcAddress(HMODULE hModule, LPCSTR lpProcName);
  32. HINSTANCE _LoadLibraryA(LPCSTR lpLibFileName);
  33. HMODULE _GetModuleHandleA(LPCSTR lpModuleName);
  34. BOOL _ResetEvent(HANDLE hEvent);
  35. BOOL _SetEvent(HANDLE hEvent);
  36. DWORD _WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds);
  37. struct AHOOK {
  38. LPSTR szName;
  39. PVOID pfnOld;
  40. PVOID pfnNew;
  41. };
  42. AHOOK g_HookArray[] = {
  43. { "LoadLibraryA" , 0, _LoadLibraryA },
  44. { "GetProcAddress" , 0, _GetProcAddress },
  45. { "GetModuleHandleA" , 0, _GetModuleHandleA },
  46. { "ResetEvent" , 0, _ResetEvent },
  47. { "SetEvent" , 0, _SetEvent },
  48. { "WaitForSingleObject" , 0, _WaitForSingleObject }
  49. };
  50. DWORD g_dwHookCount = sizeof(g_HookArray) / sizeof(AHOOK);
  51. /*++
  52. Hooks section: each designed to spoof the app into thinking this shim is
  53. kernel32.dll.
  54. --*/
  55. HINSTANCE
  56. _LoadLibraryA(
  57. LPCSTR lpLibFileName
  58. )
  59. {
  60. if (lpLibFileName && stristr(lpLibFileName, "kernel32")) {
  61. return g_hinstDll;
  62. } else {
  63. HINSTANCE hRet = LoadLibraryA(lpLibFileName);
  64. HookImports(GetModuleHandleW(0));
  65. return hRet;
  66. }
  67. }
  68. FARPROC
  69. _GetProcAddress(
  70. HMODULE hModule,
  71. LPCSTR lpProcName
  72. )
  73. {
  74. if (hModule == g_hinstDll) {
  75. hModule = g_hinstKernel;
  76. }
  77. FARPROC lpRet = GetProcAddress(hModule, lpProcName);
  78. //
  79. // Run the list of our hooks to see if we need to spoof them
  80. //
  81. if (lpRet) {
  82. for (UINT i=0; i<g_dwHookCount; i++) {
  83. if (lpRet == g_HookArray[i].pfnOld) {
  84. lpRet = (FARPROC) g_HookArray[i].pfnNew;
  85. break;
  86. }
  87. }
  88. }
  89. return lpRet;
  90. }
  91. HMODULE
  92. _GetModuleHandleA(
  93. LPCSTR lpModuleName
  94. )
  95. {
  96. if (lpModuleName && stristr(lpModuleName, "kernel32")) {
  97. return g_hinstDll;
  98. } else {
  99. return GetModuleHandleA(lpModuleName);
  100. }
  101. }
  102. /*++
  103. These save and restore the state of the direction flag (actually all flags),
  104. before and after each call.
  105. --*/
  106. BOOL
  107. _ResetEvent(
  108. HANDLE hEvent
  109. )
  110. {
  111. DWORD dwFlags;
  112. __asm {
  113. pushfd
  114. pop dwFlags
  115. }
  116. BOOL bRet = ResetEvent(hEvent);
  117. __asm {
  118. push dwFlags
  119. popfd
  120. }
  121. return bRet;
  122. }
  123. BOOL
  124. _SetEvent(
  125. HANDLE hEvent
  126. )
  127. {
  128. DWORD dwFlags;
  129. __asm {
  130. pushfd
  131. pop dwFlags
  132. }
  133. BOOL bRet = SetEvent(hEvent);
  134. __asm {
  135. push dwFlags
  136. popfd
  137. }
  138. return bRet;
  139. }
  140. DWORD
  141. _WaitForSingleObject(
  142. HANDLE hHandle,
  143. DWORD dwMilliseconds
  144. )
  145. {
  146. DWORD dwFlags;
  147. __asm {
  148. pushfd
  149. pop dwFlags
  150. }
  151. DWORD dwRet = WaitForSingleObject(hHandle, dwMilliseconds);
  152. __asm {
  153. push dwFlags
  154. popfd
  155. }
  156. return dwRet;
  157. }
  158. /*++
  159. Patch everyone to point to this dll
  160. --*/
  161. BOOL
  162. HookImports(HMODULE hModule)
  163. {
  164. NTSTATUS status;
  165. BOOL bAnyHooked = FALSE;
  166. PIMAGE_DOS_HEADER pIDH = (PIMAGE_DOS_HEADER) hModule;
  167. PIMAGE_NT_HEADERS pINTH;
  168. PIMAGE_IMPORT_DESCRIPTOR pIID;
  169. DWORD dwImportTableOffset;
  170. DWORD dwOldProtect, dwOldProtect2;
  171. SIZE_T dwProtectSize;
  172. DWORD i, j;
  173. PVOID pfnOld;
  174. LPBYTE pDllBase = (LPBYTE) pIDH;
  175. if (!hModule || (hModule == g_hinstDll) || (hModule == g_hinstKernel)) {
  176. return FALSE;
  177. }
  178. //
  179. // Get the import table.
  180. //
  181. pINTH = (PIMAGE_NT_HEADERS)(pDllBase + pIDH->e_lfanew);
  182. dwImportTableOffset = pINTH->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
  183. if (dwImportTableOffset == 0) {
  184. //
  185. // No import table found. This is probably ntdll.dll
  186. //
  187. return TRUE;
  188. }
  189. pIID = (PIMAGE_IMPORT_DESCRIPTOR)(pDllBase + dwImportTableOffset);
  190. //
  191. // Loop through the import table and search for the APIs that we want to patch
  192. //
  193. while (TRUE) {
  194. LPSTR pszImportEntryModule;
  195. PIMAGE_THUNK_DATA pITDA;
  196. //
  197. // Return if no first thunk (terminating condition).
  198. //
  199. if (pIID->FirstThunk == 0) {
  200. break;
  201. }
  202. pszImportEntryModule = (LPSTR)(pDllBase + pIID->Name);
  203. //
  204. // We have APIs to hook for this module!
  205. //
  206. pITDA = (PIMAGE_THUNK_DATA)(pDllBase + (DWORD)pIID->FirstThunk);
  207. while (TRUE) {
  208. SIZE_T dwFuncAddr;
  209. AHOOK *pHook = NULL;
  210. pfnOld = (PVOID)pITDA->u1.Function;
  211. //
  212. // Done with all the imports from this module? (terminating condition)
  213. //
  214. if (pITDA->u1.Ordinal == 0) {
  215. break;
  216. }
  217. for (i=0; i<g_dwHookCount; i++) {
  218. if (pfnOld == g_HookArray[i].pfnOld) {
  219. pHook = &g_HookArray[i];
  220. break;
  221. }
  222. }
  223. //
  224. // Check if we've found a hook
  225. //
  226. if (!pHook) {
  227. pITDA++;
  228. continue;
  229. }
  230. //
  231. // Make the code page writable and overwrite new function pointer
  232. // in the import table.
  233. //
  234. dwProtectSize = sizeof(DWORD);
  235. dwFuncAddr = (SIZE_T)&pITDA->u1.Function;
  236. status = VirtualProtect((PVOID)dwFuncAddr,
  237. dwProtectSize,
  238. PAGE_READWRITE,
  239. &dwOldProtect);
  240. if (NT_SUCCESS(status)) {
  241. pITDA->u1.Function = (SIZE_T)pHook->pfnNew;
  242. dwProtectSize = sizeof(DWORD);
  243. status = VirtualProtect((PVOID)dwFuncAddr,
  244. dwProtectSize,
  245. dwOldProtect,
  246. &dwOldProtect2);
  247. if (!NT_SUCCESS(status)) {
  248. DPFN(eDbgLevelError, "[HookImports] Failed to change back the protection");
  249. }
  250. } else {
  251. DPFN(eDbgLevelError,
  252. "[HookImports] Failed 0x%X to change protection to PAGE_READWRITE."
  253. " Addr 0x%p\n",
  254. status,
  255. &pITDA->u1.Function);
  256. }
  257. pITDA++;
  258. }
  259. pIID++;
  260. }
  261. return TRUE;
  262. }
  263. /*++
  264. Register hooked functions
  265. --*/
  266. BOOL
  267. NOTIFY_FUNCTION(
  268. DWORD fdwReason
  269. )
  270. {
  271. if (fdwReason == DLL_PROCESS_ATTACH) {
  272. //
  273. // Patch all the import tables of everyone with this module
  274. //
  275. g_hinstKernel = GetModuleHandleW(L"kernel32");
  276. for (UINT i=0; i<g_dwHookCount; i++) {
  277. g_HookArray[i].pfnOld = GetProcAddress(g_hinstKernel, g_HookArray[i].szName);
  278. }
  279. HookImports(GetModuleHandleW(0));
  280. }
  281. return TRUE;
  282. }
  283. HOOK_BEGIN
  284. CALL_NOTIFY_FUNCTION
  285. HOOK_END
  286. IMPLEMENT_SHIM_END