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.

203 lines
5.5 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. if (lpRandomAPI == NULL)
  62. {
  63. goto Fail;
  64. }
  65. //
  66. // Get the export directory
  67. //
  68. PIMAGE_DOS_HEADER pIDH = (PIMAGE_DOS_HEADER) hKernel;
  69. PIMAGE_NT_HEADERS pINTH = (PIMAGE_NT_HEADERS)((LPBYTE) hKernel + pIDH->e_lfanew);
  70. DWORD dwExportOffset = pINTH->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
  71. PIMAGE_EXPORT_DIRECTORY lpExportDirectory = (PIMAGE_EXPORT_DIRECTORY)((DWORD_PTR)hKernel + dwExportOffset);
  72. //
  73. // Write out the jump table
  74. //
  75. LPBYTE lpCurrAPI = (LPBYTE) lpRandomAPI;
  76. for (UINT i=0; i<g_dwHookCount; i++) {
  77. //
  78. // Loop through each API and create a jump table entry for it
  79. //
  80. DWORD dwAPIOffset;
  81. g_aHooks[i].lpAddress = GetProcAddress(hKernel, g_aHooks[i].szName);
  82. dwAPIOffset = (DWORD)((DWORD_PTR) g_aHooks[i].lpAddress - (DWORD_PTR) hKernel);
  83. //
  84. // This API will cause problems for SafeDisc if it's after the export directory
  85. //
  86. if (dwAPIOffset > dwExportOffset) {
  87. //
  88. // Each jump table entry has the form: jmp dword ptr [address]
  89. //
  90. struct PATCH {
  91. WORD wJump;
  92. DWORD dwAddress;
  93. };
  94. PATCH patch = { 0x25FF, (DWORD_PTR)&g_aHooks[i].lpAddress };
  95. DWORD dwOldProtect;
  96. DPF("SafeDisc", eDbgLevelWarning, "API %s is being redirected", g_aHooks[i].szName);
  97. //
  98. // Write the jump table entry
  99. //
  100. if (!VirtualProtect(lpCurrAPI, sizeof(PATCH), PAGE_READWRITE, &dwOldProtect)) {
  101. goto Fail;
  102. }
  103. MoveMemory(lpCurrAPI, &patch, sizeof(PATCH));
  104. if (!VirtualProtect(lpCurrAPI, sizeof(PATCH), dwOldProtect, &dwOldProtect)) {
  105. goto Fail;
  106. }
  107. //
  108. // Now patch the export directory
  109. //
  110. LPDWORD lpExportList = (LPDWORD)((DWORD_PTR) hKernel + lpExportDirectory->AddressOfFunctions);
  111. for (UINT j=0; j<lpExportDirectory->NumberOfFunctions; j++) {
  112. if (*lpExportList == dwAPIOffset) {
  113. //
  114. // We've found the offset in the export directory, so patch it with the
  115. // new address
  116. //
  117. DWORD dwNewAPIOffset = (DWORD)((DWORD_PTR) lpCurrAPI - (DWORD_PTR) hKernel);
  118. if (!VirtualProtect(lpExportList, sizeof(DWORD), PAGE_READWRITE, &dwOldProtect)) {
  119. goto Fail;
  120. }
  121. MoveMemory(lpExportList, &dwNewAPIOffset, sizeof(DWORD));
  122. if (!VirtualProtect(lpExportList, sizeof(DWORD), dwOldProtect, &dwOldProtect)) {
  123. goto Fail;
  124. }
  125. break;
  126. }
  127. lpExportList++;
  128. }
  129. lpCurrAPI += sizeof(PATCH);
  130. }
  131. }
  132. return TRUE;
  133. Fail:
  134. return FALSE;
  135. }
  136. /*++
  137. Register hooked functions
  138. --*/
  139. BOOL
  140. NOTIFY_FUNCTION(
  141. DWORD fdwReason)
  142. {
  143. if (fdwReason == DLL_PROCESS_ATTACH) {
  144. CHAR *lpCommandLine = COMMAND_LINE;
  145. if (lpCommandLine && (*lpCommandLine != '\0')) {
  146. g_szRandomAPI = lpCommandLine;
  147. }
  148. Patch();
  149. }
  150. return TRUE;
  151. }
  152. HOOK_BEGIN
  153. CALL_NOTIFY_FUNCTION
  154. HOOK_END
  155. IMPLEMENT_SHIM_END