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.

199 lines
5.2 KiB

  1. /*++
  2. Copyright (c) 2001 Microsoft Corporation
  3. Module Name:
  4. SafeDisc.cpp
  5. Abstract:
  6. Some versions of SafeDisc try to validate kernel32 by checking if certain
  7. APIs fall within a particular area in the PE image. Our BBT process moves
  8. everything around and therefore breaks their checks.
  9. This shim can be used to fix this problems by effectively moving the entry
  10. point of the APIs they test to a jump table located in a 'valid' location.
  11. The valid location itself is an API that isn't used, but does happen to lie
  12. before the export directory.
  13. Notes:
  14. This is an app specific shim.
  15. History:
  16. 06/15/2001 linstev Created
  17. --*/
  18. #include "precomp.h"
  19. IMPLEMENT_SHIM_BEGIN(SafeDisc)
  20. #include "ShimHookMacro.h"
  21. APIHOOK_ENUM_BEGIN
  22. APIHOOK_ENUM_END
  23. #pragma pack(1)
  24. //
  25. // Random API used as a placeholder for a jump table. It's offset must be less
  26. // than the export directory. Also, since it's overwritten with a jump table,
  27. // it should not be an API that is used.
  28. //
  29. CHAR *g_szRandomAPI = "CreateMailslotA";
  30. struct HOOK {
  31. CHAR *szName;
  32. FARPROC lpAddress;
  33. };
  34. HOOK g_aHooks[] = {
  35. { "ReadProcessMemory" , 0 },
  36. { "WriteProcessMemory" , 0 },
  37. { "VirtualProtect" , 0 },
  38. { "CreateProcessA" , 0 },
  39. { "CreateProcessW" , 0 },
  40. { "GetStartupInfoA" , 0 },
  41. { "GetStartupInfoW" , 0 },
  42. { "GetSystemTime" , 0 },
  43. { "GetSystemTimeAsFileTime" , 0 },
  44. { "TerminateProcess" , 0 },
  45. { "Sleep" , 0 }
  46. };
  47. DWORD g_dwHookCount = sizeof(g_aHooks) / sizeof(HOOK);
  48. BOOL Patch()
  49. {
  50. //
  51. // Get the kernel32 image base
  52. //
  53. HMODULE hKernel = GetModuleHandleW(L"kernel32");
  54. if (!hKernel) {
  55. goto Fail;
  56. }
  57. //
  58. // Get the address of the semi-random API where we'll put our jump table
  59. //
  60. FARPROC lpRandomAPI = GetProcAddress(hKernel, g_szRandomAPI);
  61. //
  62. // Get the export directory
  63. //
  64. PIMAGE_DOS_HEADER pIDH = (PIMAGE_DOS_HEADER) hKernel;
  65. PIMAGE_NT_HEADERS pINTH = (PIMAGE_NT_HEADERS)((LPBYTE) hKernel + pIDH->e_lfanew);
  66. DWORD dwExportOffset = pINTH->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
  67. PIMAGE_EXPORT_DIRECTORY lpExportDirectory = (PIMAGE_EXPORT_DIRECTORY)((DWORD_PTR)hKernel + dwExportOffset);
  68. //
  69. // Write out the jump table
  70. //
  71. LPBYTE lpCurrAPI = (LPBYTE) lpRandomAPI;
  72. for (UINT i=0; i<g_dwHookCount; i++) {
  73. //
  74. // Loop through each API and create a jump table entry for it
  75. //
  76. DWORD dwAPIOffset;
  77. g_aHooks[i].lpAddress = GetProcAddress(hKernel, g_aHooks[i].szName);
  78. dwAPIOffset = (DWORD)((DWORD_PTR) g_aHooks[i].lpAddress - (DWORD_PTR) hKernel);
  79. //
  80. // This API will cause problems for SafeDisc if it's after the export directory
  81. //
  82. if (dwAPIOffset > dwExportOffset) {
  83. //
  84. // Each jump table entry has the form: jmp dword ptr [address]
  85. //
  86. struct PATCH {
  87. WORD wJump;
  88. DWORD dwAddress;
  89. };
  90. PATCH patch = { 0x25FF, (DWORD_PTR)&g_aHooks[i].lpAddress };
  91. DWORD dwOldProtect;
  92. DPF("SafeDisc", eDbgLevelWarning, "API %s is being redirected", g_aHooks[i].szName);
  93. //
  94. // Write the jump table entry
  95. //
  96. if (!VirtualProtect(lpCurrAPI, sizeof(PATCH), PAGE_READWRITE, &dwOldProtect)) {
  97. goto Fail;
  98. }
  99. MoveMemory(lpCurrAPI, &patch, sizeof(PATCH));
  100. if (!VirtualProtect(lpCurrAPI, sizeof(PATCH), dwOldProtect, &dwOldProtect)) {
  101. goto Fail;
  102. }
  103. //
  104. // Now patch the export directory
  105. //
  106. LPDWORD lpExportList = (LPDWORD)((DWORD_PTR) hKernel + lpExportDirectory->AddressOfFunctions);
  107. for (UINT j=0; j<lpExportDirectory->NumberOfFunctions; j++) {
  108. if (*lpExportList == dwAPIOffset) {
  109. //
  110. // We've found the offset in the export directory, so patch it with the
  111. // new address
  112. //
  113. DWORD dwNewAPIOffset = (DWORD)((DWORD_PTR) lpCurrAPI - (DWORD_PTR) hKernel);
  114. if (!VirtualProtect(lpExportList, sizeof(DWORD), PAGE_READWRITE, &dwOldProtect)) {
  115. goto Fail;
  116. }
  117. MoveMemory(lpExportList, &dwNewAPIOffset, sizeof(DWORD));
  118. if (!VirtualProtect(lpExportList, sizeof(DWORD), dwOldProtect, &dwOldProtect)) {
  119. goto Fail;
  120. }
  121. break;
  122. }
  123. lpExportList++;
  124. }
  125. lpCurrAPI += sizeof(PATCH);
  126. }
  127. }
  128. return TRUE;
  129. Fail:
  130. return FALSE;
  131. }
  132. /*++
  133. Register hooked functions
  134. --*/
  135. BOOL
  136. NOTIFY_FUNCTION(
  137. DWORD fdwReason)
  138. {
  139. if (fdwReason == DLL_PROCESS_ATTACH) {
  140. CHAR *lpCommandLine = COMMAND_LINE;
  141. if (lpCommandLine && (*lpCommandLine != '\0')) {
  142. g_szRandomAPI = lpCommandLine;
  143. }
  144. Patch();
  145. }
  146. return TRUE;
  147. }
  148. HOOK_BEGIN
  149. CALL_NOTIFY_FUNCTION
  150. HOOK_END
  151. IMPLEMENT_SHIM_END