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.

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