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.

320 lines
9.1 KiB

  1. /*++
  2. Copyright (c) 2000-2002 Microsoft Corporation
  3. Module Name:
  4. HoyleGames.cpp
  5. Abstract:
  6. All Hoyle apps have one common problem and that is a hard
  7. coded "C:\" in its data section of the image.The apps crash
  8. because of this if installed and run from any other drive
  9. other than C:\.
  10. This shim goes through the image of the app searching
  11. for the hardcoded string and replaces them if found. This
  12. shim replaces all the existing app specific shims for
  13. Hoyle Games.
  14. This is an app specific shim.
  15. History:
  16. 04/17/2001 Prashkud Created
  17. --*/
  18. #include "precomp.h"
  19. IMPLEMENT_SHIM_BEGIN(HoyleGames)
  20. #include "ShimHookMacro.h"
  21. APIHOOK_ENUM_BEGIN
  22. APIHOOK_ENUM_ENTRY(GetPrivateProfileStringA)
  23. APIHOOK_ENUM_END
  24. // Max Virtual address replacements in all sections
  25. #define MAX_VA 50
  26. // Global array to hold the replacement VA
  27. DWORD g_ReplaceVA[MAX_VA];
  28. // Replacement count
  29. int g_ReplaceCnt;
  30. /*++
  31. Parse the Section and fill in the location index into the
  32. SECTION structure. This function also fills in the number
  33. of occurences of the hard-coded "C:\" string in this section.
  34. --*/
  35. BOOL
  36. GetReplacementLocations(
  37. DWORD dwSecPtr,
  38. DWORD dwSize
  39. )
  40. {
  41. BYTE *pbFilePtr = (BYTE*)dwSecPtr;
  42. BOOL bRet = FALSE;
  43. for (DWORD i = 0; i < dwSize - 2 && g_ReplaceCnt < MAX_VA; i++)
  44. {
  45. if ((BYTE)*(pbFilePtr + i) == 'c')
  46. {
  47. if((BYTE)*(pbFilePtr + i + 1) == ':' &&
  48. (BYTE)*(pbFilePtr + i + 2) == '\\')
  49. {
  50. g_ReplaceVA[g_ReplaceCnt++] = dwSecPtr + i;
  51. bRet = TRUE;
  52. }
  53. }
  54. }
  55. return bRet;
  56. }
  57. /*++
  58. This function loops through each section looking for a Initialized Data
  59. section. Once it gets the Initialized Data section, it calls the helper
  60. function GetReplacementLocations() to get the offset from the base of the
  61. section. It then calculates the Virtual Address at which the replacement
  62. should occur.
  63. --*/
  64. BOOL
  65. GetInitializedDataSection()
  66. {
  67. PIMAGE_NT_HEADERS NtHeader;
  68. PIMAGE_FILE_HEADER FileHeader;
  69. PIMAGE_OPTIONAL_HEADER OptionalHeader;
  70. PIMAGE_SECTION_HEADER NtSection;
  71. DWORD dwSectionVA = 0, dwSize = 0;
  72. BOOL bRet = FALSE;
  73. // Get the module base address
  74. PUCHAR Base = (PUCHAR)GetModuleHandle(NULL);
  75. if ((ULONG_PTR)Base & 0x00000001)
  76. {
  77. Base = (PUCHAR)((ULONG_PTR)Base & ~0x1);
  78. }
  79. NtHeader = RtlpImageNtHeader(Base);
  80. if (NtHeader)
  81. {
  82. FileHeader = &NtHeader->FileHeader;
  83. OptionalHeader = &NtHeader->OptionalHeader;
  84. }
  85. else
  86. {
  87. // Handle case where Image passed in doesn't have a dos stub (ROM images for instance);
  88. FileHeader = (PIMAGE_FILE_HEADER)Base;
  89. OptionalHeader = (PIMAGE_OPTIONAL_HEADER) ((ULONG_PTR)Base + IMAGE_SIZEOF_FILE_HEADER);
  90. }
  91. NtSection = (PIMAGE_SECTION_HEADER)((ULONG_PTR)OptionalHeader +
  92. FileHeader->SizeOfOptionalHeader);
  93. for (DWORD i=0; i<FileHeader->NumberOfSections; i++)
  94. {
  95. // Check whether the section is a Initialized Data Section
  96. if (NtSection->Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA)
  97. {
  98. // Size of the Section to search
  99. dwSize = NtSection->SizeOfRawData;
  100. // Get the Section's Virtual address
  101. dwSectionVA = (DWORD)(Base + NtSection->VirtualAddress);
  102. __try
  103. {
  104. if(GetReplacementLocations(dwSectionVA, dwSize))
  105. {
  106. bRet = TRUE;
  107. }
  108. DPFN( eDbgLevelError, "Replacing was successful");
  109. }
  110. __except(EXCEPTION_EXECUTE_HANDLER)
  111. {
  112. DPFN( eDbgLevelError, "Replacing crashed");
  113. goto Exit;
  114. }
  115. }
  116. ++NtSection;
  117. }
  118. return bRet;
  119. Exit:
  120. return FALSE;
  121. }
  122. /*++
  123. This function hooks GetVersion (called early on by Hoyle Board Games)
  124. and replaces the hard coded 'c's with the correct install drive letter
  125. that it looks up in the registry.
  126. It uses g_HoyleWordGames_bPatched to patch only once.
  127. --*/
  128. BOOL
  129. NOTIFY_FUNCTION(
  130. DWORD fdwReason
  131. )
  132. {
  133. if (fdwReason == SHIM_STATIC_DLLS_INITIALIZED)
  134. {
  135. CHAR szProgFilesDir[MAX_PATH]; // Added by Noah Young on 1/26/01
  136. DWORD cch = ARRAYSIZE(szProgFilesDir);
  137. HKEY hKey = 0;
  138. DWORD dwOldProtect = 0;
  139. // Fix problem where Program Files dir isn't on same drive as BOARD3.EXE
  140. if( ERROR_SUCCESS == RegOpenKeyExA(HKEY_LOCAL_MACHINE,
  141. "SOFTWARE\\Microsoft\\Windows\\CurrentVersion",
  142. 0,
  143. KEY_QUERY_VALUE,
  144. &hKey) )
  145. {
  146. if( ERROR_SUCCESS == RegQueryValueExA(hKey,
  147. "ProgramFilesDir",
  148. NULL,
  149. NULL, // REG_SZ
  150. (LPBYTE)szProgFilesDir,
  151. &cch) )
  152. {
  153. // Scan the image's initialized data section....
  154. char szModule[MAX_PATH];
  155. cch = GetModuleFileNameA(NULL, szModule, ARRAYSIZE(szModule));
  156. if( cch > 0 && cch < ARRAYSIZE(szModule) )
  157. {
  158. // Get the Virtual adresses that need to be replaced
  159. if(GetInitializedDataSection())
  160. {
  161. long PATCH_LENGTH = g_ReplaceVA[ g_ReplaceCnt - 1] - g_ReplaceVA[0] + 1;
  162. // Make the memory page writable
  163. if( VirtualProtect( (PVOID) g_ReplaceVA[0],
  164. PATCH_LENGTH,
  165. PAGE_READWRITE,
  166. &dwOldProtect ) )
  167. {
  168. for (int i=0; i< g_ReplaceCnt; i++)
  169. {
  170. // Make sure it's what we expect
  171. if( 'c' == *((CHAR*) g_ReplaceVA[i]) )
  172. {
  173. if (i==0)
  174. {
  175. *((CHAR*) g_ReplaceVA[i]) = szProgFilesDir[0];
  176. }
  177. else
  178. {
  179. *((CHAR*) g_ReplaceVA[i]) = szModule[0];
  180. }
  181. }
  182. }
  183. }
  184. } else {
  185. DPFN( eDbgLevelError, "No patching done!");
  186. }
  187. } else {
  188. DPFN( eDbgLevelError, "GetModuleFileNameA failed!");
  189. }
  190. } else {
  191. DPFN( eDbgLevelError, "Failed to query \"ProgramFilesDir\"!");
  192. }
  193. RegCloseKey(hKey);
  194. } else {
  195. DPFN( eDbgLevelError, "Failed to open key \"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\"!");
  196. }
  197. }
  198. return TRUE;
  199. }
  200. /*++
  201. Very specific hack to return a good FaceMaker path, so the app doesn't fail
  202. when it is installed on the wrong drive.
  203. --*/
  204. DWORD
  205. APIHOOK(GetPrivateProfileStringA)(
  206. LPCSTR lpAppName,
  207. LPCSTR lpKeyName,
  208. LPCSTR lpDefault,
  209. LPSTR lpReturnedString,
  210. DWORD nSize,
  211. LPCSTR lpFileName
  212. )
  213. {
  214. CSTRING_TRY
  215. {
  216. CString csApp = lpAppName;
  217. CString csKey = lpKeyName;
  218. CString csFile = lpFileName;
  219. if ((csApp.Compare(L"Settings") == 0) &&
  220. (csKey.Compare(L"FaceMakerPath") == 0) &&
  221. (csFile.Find(L"CARDGAME.INI") > -1)) {
  222. DWORD dwRet = ORIGINAL_API(GetPrivateProfileStringA)(lpAppName, lpKeyName,
  223. lpDefault, lpReturnedString, nSize, lpFileName);
  224. if (!dwRet) {
  225. // Substitute the right path
  226. CString csPath = L"%ProgramFiles%\\WON\\FaceMaker";
  227. csPath.ExpandEnvironmentStringsW();
  228. if (lpReturnedString && ((int)nSize > csPath.GetLength())) {
  229. LOGN(eDbgLevelError, "[GetPrivateProfileStringA] Forced correct FaceMaker path");
  230. strncpy(lpReturnedString, csPath.GetAnsi(), nSize);
  231. dwRet = csPath.GetLength();
  232. }
  233. }
  234. return dwRet;
  235. }
  236. }
  237. CSTRING_CATCH
  238. {
  239. // fall through
  240. }
  241. return ORIGINAL_API(GetPrivateProfileStringA)(lpAppName, lpKeyName,
  242. lpDefault, lpReturnedString, nSize, lpFileName);
  243. }
  244. /*++
  245. Register hooked functions
  246. --*/
  247. HOOK_BEGIN
  248. CALL_NOTIFY_FUNCTION
  249. APIHOOK_ENTRY(KERNEL32.DLL, GetPrivateProfileStringA)
  250. HOOK_END
  251. IMPLEMENT_SHIM_END