1 /* 2 * PROJECT: ReactOS Application compatibility module 3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) 4 * PURPOSE: Shim engine core 5 * COPYRIGHT: Copyright 2015-2019 Mark Jansen (mark.jansen@reactos.org) 6 */ 7 8 #define WIN32_NO_STATUS 9 #include "ntndk.h" 10 #define IN_APPHELP 11 #include "shimlib.h" 12 #include <strsafe.h> 13 /* Make sure we don't include apphelp logging */ 14 #define APPHELP_NOSDBPAPI 15 #include "apphelp.h" 16 #include "shimeng.h" 17 18 19 20 FARPROC WINAPI StubGetProcAddress(HINSTANCE hModule, LPCSTR lpProcName); 21 BOOL WINAPI SE_IsShimDll(PVOID BaseAddress); 22 23 24 extern HMODULE g_hInstance; 25 static UNICODE_STRING g_WindowsDirectory; 26 static UNICODE_STRING g_System32Directory; 27 static UNICODE_STRING g_SxsDirectory; 28 static UNICODE_STRING g_LoadingShimDll; 29 ULONG g_ShimEngDebugLevel = 0xffffffff; 30 BOOL g_bComPlusImage = FALSE; 31 BOOL g_bShimDuringInit = FALSE; 32 BOOL g_bInternalHooksUsed = FALSE; 33 static ARRAY g_pShimInfo; /* PSHIMMODULE */ 34 static ARRAY g_pHookArray; /* HOOKMODULEINFO */ 35 static ARRAY g_InExclude; /* INEXCLUDE */ 36 37 /* If we have setup a hook for a function, we should also redirect GetProcAddress for this function */ 38 HOOKAPIEX g_IntHookEx[] = 39 { 40 { 41 "kernel32.dll", /* LibraryName */ 42 "GetProcAddress", /* FunctionName */ 43 StubGetProcAddress, /* ReplacementFunction*/ 44 NULL, /* OriginalFunction */ 45 NULL, /* pShimInfo */ 46 NULL /* Unused */ 47 }, 48 }; 49 50 static inline BOOL ARRAY_InitWorker(PARRAY Array, DWORD ItemSize) 51 { 52 Array->Data__ = NULL; 53 Array->Size__ = Array->MaxSize__ = 0; 54 Array->ItemSize__ = ItemSize; 55 56 return TRUE; 57 } 58 59 static inline BOOL ARRAY_EnsureSize(PARRAY Array, DWORD ItemSize, DWORD GrowWith) 60 { 61 PVOID pNewData; 62 DWORD Count; 63 64 ASSERT(Array); 65 ASSERT(ItemSize == Array->ItemSize__); 66 67 if (Array->MaxSize__ > Array->Size__) 68 return TRUE; 69 70 Count = Array->Size__ + GrowWith; 71 pNewData = SeiAlloc(Count * ItemSize); 72 73 if (!pNewData) 74 { 75 SHIMENG_FAIL("Failed to allocate %d bytes\n", Count * ItemSize); 76 return FALSE; 77 } 78 Array->MaxSize__ = Count; 79 80 if (Array->Data__) 81 { 82 memcpy(pNewData, Array->Data__, Array->Size__ * ItemSize); 83 SeiFree(Array->Data__); 84 } 85 Array->Data__ = pNewData; 86 87 return TRUE; 88 } 89 90 static inline PVOID ARRAY_AppendWorker(PARRAY Array, DWORD ItemSize, DWORD GrowWith) 91 { 92 PBYTE pData; 93 94 if (!ARRAY_EnsureSize(Array, ItemSize, GrowWith)) 95 return NULL; 96 97 pData = Array->Data__; 98 pData += (Array->Size__ * ItemSize); 99 Array->Size__++; 100 101 return pData; 102 } 103 104 static inline PVOID ARRAY_AtWorker(PARRAY Array, DWORD ItemSize, DWORD n) 105 { 106 PBYTE pData; 107 108 ASSERT(Array); 109 ASSERT(ItemSize == Array->ItemSize__); 110 ASSERT(n < Array->Size__); 111 112 pData = Array->Data__; 113 return pData + (n * ItemSize); 114 } 115 116 117 #define ARRAY_Init(Array, TypeOfArray) ARRAY_InitWorker((Array), sizeof(TypeOfArray)) 118 #define ARRAY_Append(Array, TypeOfArray) (TypeOfArray*)ARRAY_AppendWorker((Array), sizeof(TypeOfArray), 5) 119 #define ARRAY_At(Array, TypeOfArray, at) (TypeOfArray*)ARRAY_AtWorker((Array), sizeof(TypeOfArray), at) 120 #define ARRAY_Size(Array) (Array)->Size__ 121 122 123 VOID SeiInitDebugSupport(VOID) 124 { 125 static const UNICODE_STRING DebugKey = RTL_CONSTANT_STRING(L"SHIMENG_DEBUG_LEVEL"); 126 UNICODE_STRING DebugValue; 127 NTSTATUS Status; 128 ULONG NewLevel = SEI_MSG; /* Show some basic info in the logs, unless configured different */ 129 WCHAR Buffer[40]; 130 131 RtlInitEmptyUnicodeString(&DebugValue, Buffer, sizeof(Buffer)); 132 133 Status = RtlQueryEnvironmentVariable_U(NULL, &DebugKey, &DebugValue); 134 135 if (NT_SUCCESS(Status)) 136 { 137 if (!NT_SUCCESS(RtlUnicodeStringToInteger(&DebugValue, 10, &NewLevel))) 138 NewLevel = 0; 139 } 140 g_ShimEngDebugLevel = NewLevel; 141 } 142 143 144 /** 145 * Outputs diagnostic info. 146 * 147 * @param [in] Level The level to log this message with, choose any of [SHIM_ERR, 148 * SHIM_WARN, SHIM_INFO]. 149 * @param [in] FunctionName The function this log should be attributed to. 150 * @param [in] Format The format string. 151 * @param ... Variable arguments providing additional information. 152 * 153 * @return Success: TRUE Failure: FALSE. 154 */ 155 BOOL WINAPIV SeiDbgPrint(SEI_LOG_LEVEL Level, PCSTR Function, PCSTR Format, ...) 156 { 157 char Buffer[512]; 158 char* Current = Buffer; 159 const char* LevelStr; 160 size_t Length = sizeof(Buffer); 161 va_list ArgList; 162 HRESULT hr; 163 164 if (g_ShimEngDebugLevel == 0xffffffff) 165 SeiInitDebugSupport(); 166 167 if (Level > g_ShimEngDebugLevel) 168 return FALSE; 169 170 switch (Level) 171 { 172 case SEI_MSG: 173 LevelStr = "MSG "; 174 break; 175 case SEI_FAIL: 176 LevelStr = "FAIL"; 177 break; 178 case SEI_WARN: 179 LevelStr = "WARN"; 180 break; 181 case SEI_INFO: 182 LevelStr = "INFO"; 183 break; 184 default: 185 LevelStr = "USER"; 186 break; 187 } 188 189 if (Function) 190 hr = StringCchPrintfExA(Current, Length, &Current, &Length, STRSAFE_NULL_ON_FAILURE, "[%s] [%s] ", LevelStr, Function); 191 else 192 hr = StringCchPrintfExA(Current, Length, &Current, &Length, STRSAFE_NULL_ON_FAILURE, "[%s] ", LevelStr); 193 194 if (!SUCCEEDED(hr)) 195 return FALSE; 196 197 va_start(ArgList, Format); 198 hr = StringCchVPrintfExA(Current, Length, &Current, &Length, STRSAFE_NULL_ON_FAILURE, Format, ArgList); 199 va_end(ArgList); 200 if (!SUCCEEDED(hr)) 201 return FALSE; 202 203 DbgPrint("%s", Buffer); 204 return TRUE; 205 } 206 207 208 PVOID SeiGetModuleFromAddress(PVOID addr) 209 { 210 PVOID hModule = NULL; 211 RtlPcToFileHeader(addr, &hModule); 212 return hModule; 213 } 214 215 216 217 /* TODO: Guard against recursive calling / calling init multiple times! */ 218 VOID NotifyShims(DWORD dwReason, PVOID Info) 219 { 220 DWORD n; 221 222 for (n = 0; n < ARRAY_Size(&g_pShimInfo); ++n) 223 { 224 PSHIMMODULE pShimModule = *ARRAY_At(&g_pShimInfo, PSHIMMODULE, n); 225 if (!pShimModule->pNotifyShims) 226 continue; 227 228 pShimModule->pNotifyShims(dwReason, Info); 229 } 230 } 231 232 233 234 VOID SeiCheckComPlusImage(PVOID BaseAddress) 235 { 236 ULONG ComSectionSize; 237 g_bComPlusImage = RtlImageDirectoryEntryToData(BaseAddress, TRUE, IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR, &ComSectionSize) != NULL; 238 239 SHIMENG_INFO("COM+ executable %s\n", g_bComPlusImage ? "TRUE" : "FALSE"); 240 } 241 242 243 PSHIMMODULE SeiGetShimModuleInfo(PVOID BaseAddress) 244 { 245 DWORD n; 246 247 for (n = 0; n < ARRAY_Size(&g_pShimInfo); ++n) 248 { 249 PSHIMMODULE pShimModule = *ARRAY_At(&g_pShimInfo, PSHIMMODULE, n); 250 251 if (pShimModule->BaseAddress == BaseAddress) 252 return pShimModule; 253 } 254 return NULL; 255 } 256 257 PSHIMMODULE SeiCreateShimModuleInfo(PCWSTR DllName, PVOID BaseAddress) 258 { 259 static const ANSI_STRING GetHookAPIs = RTL_CONSTANT_STRING("GetHookAPIs"); 260 static const ANSI_STRING NotifyShims = RTL_CONSTANT_STRING("NotifyShims"); 261 PSHIMMODULE* pData, Data; 262 PVOID pGetHookAPIs, pNotifyShims; 263 264 if (!NT_SUCCESS(LdrGetProcedureAddress(BaseAddress, (PANSI_STRING)&GetHookAPIs, 0, &pGetHookAPIs)) || 265 !NT_SUCCESS(LdrGetProcedureAddress(BaseAddress, (PANSI_STRING)&NotifyShims, 0, &pNotifyShims))) 266 { 267 SHIMENG_WARN("Failed to resolve entry points for %S\n", DllName); 268 return NULL; 269 } 270 271 pData = ARRAY_Append(&g_pShimInfo, PSHIMMODULE); 272 if (!pData) 273 return NULL; 274 275 *pData = SeiAlloc(sizeof(SHIMMODULE)); 276 277 Data = *pData; 278 279 RtlCreateUnicodeString(&Data->Name, DllName); 280 Data->BaseAddress = BaseAddress; 281 282 Data->pGetHookAPIs = pGetHookAPIs; 283 Data->pNotifyShims = pNotifyShims; 284 285 ARRAY_Init(&Data->EnabledShims, PSHIMINFO); 286 287 return Data; 288 } 289 290 PSHIMINFO SeiAppendHookInfo(PSHIMMODULE pShimModuleInfo, PHOOKAPIEX pHookApi, DWORD dwHookCount, PCWSTR ShimName) 291 { 292 PSHIMINFO* pData, Data; 293 294 pData = ARRAY_Append(&pShimModuleInfo->EnabledShims, PSHIMINFO); 295 if (!pData) 296 return NULL; 297 298 *pData = SeiAlloc(sizeof(SHIMINFO)); 299 Data = *pData; 300 301 if (!Data) 302 return NULL; 303 304 Data->ShimName = SdbpStrDup(ShimName); 305 if (!Data->ShimName) 306 return NULL; 307 308 Data->pHookApi = pHookApi; 309 Data->dwHookCount = dwHookCount; 310 Data->pShimModule = pShimModuleInfo; 311 ARRAY_Init(&Data->InExclude, INEXCLUDE); 312 return Data; 313 } 314 315 PHOOKMODULEINFO SeiFindHookModuleInfo(PUNICODE_STRING ModuleName, PVOID BaseAddress) 316 { 317 DWORD n; 318 319 if (ModuleName == NULL && BaseAddress == NULL) 320 { 321 BaseAddress = NtCurrentPeb()->ImageBaseAddress; 322 } 323 324 for (n = 0; n < ARRAY_Size(&g_pHookArray); ++n) 325 { 326 PHOOKMODULEINFO pModuleInfo = ARRAY_At(&g_pHookArray, HOOKMODULEINFO, n); 327 328 if (BaseAddress && BaseAddress == pModuleInfo->BaseAddress) 329 return pModuleInfo; 330 331 if (!BaseAddress && RtlEqualUnicodeString(ModuleName, &pModuleInfo->Name, TRUE)) 332 return pModuleInfo; 333 } 334 335 return NULL; 336 } 337 338 PHOOKMODULEINFO SeiFindHookModuleInfoForImportDescriptor(PBYTE DllBase, PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor) 339 { 340 UNICODE_STRING DllName; 341 PVOID DllHandle; 342 NTSTATUS Success; 343 344 if (!RtlCreateUnicodeStringFromAsciiz(&DllName, (PCSZ)(DllBase + ImportDescriptor->Name))) 345 { 346 SHIMENG_FAIL("Unable to convert dll name to unicode\n"); 347 return NULL; 348 } 349 350 Success = LdrGetDllHandle(NULL, NULL, &DllName, &DllHandle); 351 352 if (!NT_SUCCESS(Success)) 353 { 354 SHIMENG_FAIL("Unable to get module handle for %wZ (%p)\n", &DllName, DllBase); 355 RtlFreeUnicodeString(&DllName); 356 357 return NULL; 358 } 359 RtlFreeUnicodeString(&DllName); 360 361 return SeiFindHookModuleInfo(NULL, DllHandle); 362 } 363 364 static LPCWSTR SeiGetStringPtr(PDB pdb, TAGID tag, TAG type) 365 { 366 TAGID tagEntry = SdbFindFirstTag(pdb, tag, type); 367 if (tagEntry == TAGID_NULL) 368 return NULL; 369 370 return SdbGetStringTagPtr(pdb, tagEntry); 371 } 372 373 static DWORD SeiGetDWORD(PDB pdb, TAGID tag, TAG type) 374 { 375 TAGID tagEntry = SdbFindFirstTag(pdb, tag, type); 376 if (tagEntry == TAGID_NULL) 377 return 0; 378 379 return SdbReadDWORDTag(pdb, tagEntry, 0); 380 } 381 382 static QWORD SeiGetQWORD(PDB pdb, TAGID tag, TAG type) 383 { 384 TAGID tagEntry = SdbFindFirstTag(pdb, tag, type); 385 if (tagEntry == TAGID_NULL) 386 return 0; 387 388 return SdbReadQWORDTag(pdb, tagEntry, 0); 389 } 390 391 static VOID SeiAddShim(TAGREF trShimRef, PARRAY pShimRef) 392 { 393 TAGREF* Data; 394 395 Data = ARRAY_Append(pShimRef, TAGREF); 396 if (!Data) 397 return; 398 399 *Data = trShimRef; 400 } 401 402 static VOID SeiAddFlag(PDB pdb, TAGID tiFlagRef, PFLAGINFO pFlagInfo) 403 { 404 ULARGE_INTEGER Flag; 405 406 /* Resolve the FLAG_REF to the real FLAG node */ 407 TAGID FlagTag = SeiGetDWORD(pdb, tiFlagRef, TAG_FLAG_TAGID); 408 409 if (FlagTag == TAGID_NULL) 410 return; 411 412 pFlagInfo->AppCompatFlags.QuadPart |= SeiGetQWORD(pdb, FlagTag, TAG_FLAG_MASK_KERNEL); 413 pFlagInfo->AppCompatFlagsUser.QuadPart |= SeiGetQWORD(pdb, FlagTag, TAG_FLAG_MASK_USER); 414 Flag.QuadPart = SeiGetQWORD(pdb, FlagTag, TAG_FLAG_PROCESSPARAM); 415 pFlagInfo->ProcessParameters_Flags |= Flag.LowPart; 416 } 417 418 /* Propagate layers to child processes */ 419 static VOID SeiSetLayerEnvVar(LPCWSTR wszLayer) 420 { 421 NTSTATUS Status; 422 UNICODE_STRING VarName = RTL_CONSTANT_STRING(L"__COMPAT_LAYER"); 423 UNICODE_STRING Value; 424 425 RtlInitUnicodeString(&Value, wszLayer); 426 427 Status = RtlSetEnvironmentVariable(NULL, &VarName, &Value); 428 if (NT_SUCCESS(Status)) 429 SHIMENG_INFO("Set env var %wZ=%wZ\n", &VarName, &Value); 430 else 431 SHIMENG_FAIL("Failed to set %wZ: 0x%x\n", &VarName, Status); 432 } 433 434 #define MAX_LAYER_LENGTH 256 435 436 /* Translate all Exe and Layer entries to Shims, and propagate all layers */ 437 static VOID SeiBuildShimRefArray(HSDB hsdb, SDBQUERYRESULT* pQuery, PARRAY pShimRef, PFLAGINFO pFlagInfo) 438 { 439 WCHAR wszLayerEnvVar[MAX_LAYER_LENGTH] = { 0 }; 440 DWORD n; 441 442 for (n = 0; n < pQuery->dwExeCount; ++n) 443 { 444 PDB pdb; 445 TAGID tag; 446 if (SdbTagRefToTagID(hsdb, pQuery->atrExes[n], &pdb, &tag)) 447 { 448 LPCWSTR ExeName = SeiGetStringPtr(pdb, tag, TAG_NAME); 449 TAGID ShimRef = SdbFindFirstTag(pdb, tag, TAG_SHIM_REF); 450 TAGID FlagRef = SdbFindFirstTag(pdb, tag, TAG_FLAG_REF); 451 452 if (ExeName) 453 SeiDbgPrint(SEI_MSG, NULL, "ShimInfo(Exe(%S))\n", ExeName); 454 455 while (ShimRef != TAGID_NULL) 456 { 457 TAGREF trShimRef; 458 if (SdbTagIDToTagRef(hsdb, pdb, ShimRef, &trShimRef)) 459 SeiAddShim(trShimRef, pShimRef); 460 461 ShimRef = SdbFindNextTag(pdb, tag, ShimRef); 462 } 463 464 while (FlagRef != TAGID_NULL) 465 { 466 SeiAddFlag(pdb, FlagRef, pFlagInfo); 467 468 FlagRef = SdbFindNextTag(pdb, tag, FlagRef); 469 } 470 } 471 } 472 473 474 for (n = 0; n < pQuery->dwLayerCount; ++n) 475 { 476 PDB pdb; 477 TAGID tag; 478 if (SdbTagRefToTagID(hsdb, pQuery->atrLayers[n], &pdb, &tag)) 479 { 480 LPCWSTR LayerName = SeiGetStringPtr(pdb, tag, TAG_NAME); 481 TAGID ShimRef = SdbFindFirstTag(pdb, tag, TAG_SHIM_REF); 482 TAGID FlagRef = SdbFindFirstTag(pdb, tag, TAG_FLAG_REF); 483 484 if (LayerName) 485 { 486 HRESULT hr; 487 SeiDbgPrint(SEI_MSG, NULL, "ShimInfo(Layer(%S))\n", LayerName); 488 if (wszLayerEnvVar[0]) 489 StringCchCatW(wszLayerEnvVar, ARRAYSIZE(wszLayerEnvVar), L" "); 490 hr = StringCchCatW(wszLayerEnvVar, ARRAYSIZE(wszLayerEnvVar), LayerName); 491 if (!SUCCEEDED(hr)) 492 { 493 SHIMENG_FAIL("Unable to append %S\n", LayerName); 494 } 495 } 496 497 while (ShimRef != TAGID_NULL) 498 { 499 TAGREF trShimRef; 500 if (SdbTagIDToTagRef(hsdb, pdb, ShimRef, &trShimRef)) 501 SeiAddShim(trShimRef, pShimRef); 502 503 ShimRef = SdbFindNextTag(pdb, tag, ShimRef); 504 } 505 506 while (FlagRef != TAGID_NULL) 507 { 508 SeiAddFlag(pdb, FlagRef, pFlagInfo); 509 510 FlagRef = SdbFindNextTag(pdb, tag, FlagRef); 511 } 512 } 513 } 514 if (wszLayerEnvVar[0]) 515 SeiSetLayerEnvVar(wszLayerEnvVar); 516 } 517 518 /* Given the hooks from one shim, find the relevant modules and store the combination of module + hook */ 519 VOID SeiAddHooks(PHOOKAPIEX hooks, DWORD dwHookCount, PSHIMINFO pShim) 520 { 521 DWORD n, j; 522 UNICODE_STRING UnicodeModName; 523 WCHAR Buf[512]; 524 525 RtlInitEmptyUnicodeString(&UnicodeModName, Buf, sizeof(Buf)); 526 527 for (n = 0; n < dwHookCount; ++n) 528 { 529 ANSI_STRING AnsiString; 530 PVOID DllHandle; 531 PHOOKAPIEX hook = hooks + n; 532 PHOOKAPIEX* pHookApi; 533 PHOOKMODULEINFO HookModuleInfo; 534 535 RtlInitAnsiString(&AnsiString, hook->LibraryName); 536 if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&UnicodeModName, &AnsiString, FALSE))) 537 { 538 SHIMENG_FAIL("Unable to convert %s to Unicode\n", hook->LibraryName); 539 continue; 540 } 541 542 RtlInitAnsiString(&AnsiString, hook->FunctionName); 543 if (NT_SUCCESS(LdrGetDllHandle(NULL, 0, &UnicodeModName, &DllHandle))) 544 { 545 PVOID ProcAddress; 546 547 548 if (!NT_SUCCESS(LdrGetProcedureAddress(DllHandle, &AnsiString, 0, &ProcAddress))) 549 { 550 SHIMENG_FAIL("Unable to retrieve %s!%s\n", hook->LibraryName, hook->FunctionName); 551 continue; 552 } 553 554 HookModuleInfo = SeiFindHookModuleInfo(NULL, DllHandle); 555 hook->OriginalFunction = ProcAddress; 556 } 557 else 558 { 559 HookModuleInfo = SeiFindHookModuleInfo(&UnicodeModName, NULL); 560 DllHandle = NULL; 561 } 562 563 if (!HookModuleInfo) 564 { 565 HookModuleInfo = ARRAY_Append(&g_pHookArray, HOOKMODULEINFO); 566 if (!HookModuleInfo) 567 continue; 568 569 HookModuleInfo->BaseAddress = DllHandle; 570 ARRAY_Init(&HookModuleInfo->HookApis, PHOOKAPIEX); 571 RtlCreateUnicodeString(&HookModuleInfo->Name, UnicodeModName.Buffer); 572 } 573 574 hook->pShimInfo = pShim; 575 576 for (j = 0; j < ARRAY_Size(&HookModuleInfo->HookApis); ++j) 577 { 578 PHOOKAPIEX HookApi = *ARRAY_At(&HookModuleInfo->HookApis, PHOOKAPIEX, j); 579 int CmpResult = strcmp(hook->FunctionName, HookApi->FunctionName); 580 if (CmpResult == 0) 581 { 582 /* Multiple hooks on one function? --> use ApiLink */ 583 SHIMENG_FAIL("Multiple hooks on one API is not yet supported!\n"); 584 ASSERT(0); 585 } 586 } 587 pHookApi = ARRAY_Append(&HookModuleInfo->HookApis, PHOOKAPIEX); 588 if (pHookApi) 589 *pHookApi = hook; 590 } 591 } 592 593 typedef FARPROC(WINAPI* GETPROCADDRESSPROC)(HINSTANCE, LPCSTR); 594 595 /* Check if we should fake the return from GetProcAddress (because we also redirected the iat for this module) */ 596 FARPROC WINAPI StubGetProcAddress(HINSTANCE hModule, LPCSTR lpProcName) 597 { 598 char szOrdProcName[10] = ""; 599 LPCSTR lpPrintName = lpProcName; 600 PVOID Addr = _ReturnAddress(); 601 PHOOKMODULEINFO HookModuleInfo; 602 FARPROC proc = ((GETPROCADDRESSPROC)g_IntHookEx[0].OriginalFunction)(hModule, lpProcName); 603 604 if ((DWORD_PTR)lpProcName <= MAXUSHORT) 605 { 606 sprintf(szOrdProcName, "#%Iu", (DWORD_PTR)lpProcName); 607 lpPrintName = szOrdProcName; 608 } 609 610 Addr = SeiGetModuleFromAddress(Addr); 611 if (SE_IsShimDll(Addr)) 612 { 613 SHIMENG_MSG("Not touching GetProcAddress for shim dll (%p!%s)", hModule, lpPrintName); 614 return proc; 615 } 616 617 SHIMENG_INFO("(GetProcAddress(%p!%s) => %p\n", hModule, lpPrintName, proc); 618 619 HookModuleInfo = SeiFindHookModuleInfo(NULL, hModule); 620 621 /* FIXME: Ordinal not yet supported */ 622 if (HookModuleInfo && HIWORD(lpProcName)) 623 { 624 DWORD n; 625 for (n = 0; n < ARRAY_Size(&HookModuleInfo->HookApis); ++n) 626 { 627 PHOOKAPIEX HookApi = *ARRAY_At(&HookModuleInfo->HookApis, PHOOKAPIEX, n); 628 int CmpResult = strcmp(lpProcName, HookApi->FunctionName); 629 if (CmpResult == 0) 630 { 631 SHIMENG_MSG("Redirecting %p to %p\n", proc, HookApi->ReplacementFunction); 632 proc = HookApi->ReplacementFunction; 633 break; 634 } 635 } 636 } 637 638 return proc; 639 } 640 641 /* Walk all shim modules / enabled shims, and add their hooks */ 642 VOID SeiResolveAPIs(VOID) 643 { 644 DWORD mod, n; 645 646 /* Enumerate all Shim modules */ 647 for (mod = 0; mod < ARRAY_Size(&g_pShimInfo); ++mod) 648 { 649 PSHIMMODULE pShimModule = *ARRAY_At(&g_pShimInfo, PSHIMMODULE, mod); 650 DWORD dwShimCount = ARRAY_Size(&pShimModule->EnabledShims); 651 652 /* Enumerate all Shims */ 653 for (n = 0; n < dwShimCount; ++n) 654 { 655 PSHIMINFO pShim = *ARRAY_At(&pShimModule->EnabledShims, PSHIMINFO, n); 656 657 PHOOKAPIEX hooks = pShim->pHookApi; 658 DWORD dwHookCount = pShim->dwHookCount; 659 660 SeiAddHooks(hooks, dwHookCount, pShim); 661 } 662 } 663 } 664 665 /* If we hooked something, we should also redirect GetProcAddress */ 666 VOID SeiAddInternalHooks(DWORD dwNumHooks) 667 { 668 if (dwNumHooks == 0) 669 { 670 g_bInternalHooksUsed = FALSE; 671 return; 672 } 673 674 SeiAddHooks(g_IntHookEx, ARRAYSIZE(g_IntHookEx), NULL); 675 g_bInternalHooksUsed = TRUE; 676 } 677 678 /* Patch one function in the iat */ 679 VOID SeiPatchNewImport(PIMAGE_THUNK_DATA FirstThunk, PHOOKAPIEX HookApi, PLDR_DATA_TABLE_ENTRY LdrEntry) 680 { 681 ULONG OldProtection = 0; 682 PVOID Ptr; 683 SIZE_T Size; 684 NTSTATUS Status; 685 686 SHIMENG_INFO("Hooking API \"%s!%s\" for DLL \"%wZ\"\n", HookApi->LibraryName, HookApi->FunctionName, &LdrEntry->BaseDllName); 687 688 Ptr = &FirstThunk->u1.Function; 689 Size = sizeof(FirstThunk->u1.Function); 690 Status = NtProtectVirtualMemory(NtCurrentProcess(), &Ptr, &Size, PAGE_EXECUTE_READWRITE, &OldProtection); 691 692 if (!NT_SUCCESS(Status)) 693 { 694 SHIMENG_FAIL("Unable to unprotect 0x%p\n", &FirstThunk->u1.Function); 695 return; 696 } 697 698 SHIMENG_INFO("changing 0x%p to 0x%p\n", FirstThunk->u1.Function, HookApi->ReplacementFunction); 699 #ifdef _WIN64 700 FirstThunk->u1.Function = (ULONGLONG)HookApi->ReplacementFunction; 701 #else 702 FirstThunk->u1.Function = (DWORD)HookApi->ReplacementFunction; 703 #endif 704 705 Size = sizeof(FirstThunk->u1.Function); 706 Status = NtProtectVirtualMemory(NtCurrentProcess(), &Ptr, &Size, OldProtection, &OldProtection); 707 708 if (!NT_SUCCESS(Status)) 709 { 710 SHIMENG_WARN("Unable to reprotect 0x%p\n", &FirstThunk->u1.Function); 711 } 712 } 713 714 715 PINEXCLUDE SeiFindInExclude(PARRAY InExclude, PCUNICODE_STRING DllName) 716 { 717 DWORD n; 718 719 for (n = 0; n < ARRAY_Size(InExclude); ++n) 720 { 721 PINEXCLUDE InEx = ARRAY_At(InExclude, INEXCLUDE, n); 722 723 if (RtlEqualUnicodeString(&InEx->Module, DllName, TRUE)) 724 return InEx; 725 } 726 727 return NULL; 728 } 729 730 BOOL SeiIsExcluded(PLDR_DATA_TABLE_ENTRY LdrEntry, PHOOKAPIEX HookApi) 731 { 732 PSHIMINFO pShimInfo = HookApi->pShimInfo; 733 PINEXCLUDE InExclude; 734 BOOL IsExcluded = FALSE; 735 736 if (!pShimInfo) 737 { 738 /* Internal hook, do not exclude it */ 739 return FALSE; 740 } 741 742 /* By default, everything from System32 or WinSxs is excluded */ 743 if (RtlPrefixUnicodeString(&g_System32Directory, &LdrEntry->FullDllName, TRUE) || 744 RtlPrefixUnicodeString(&g_SxsDirectory, &LdrEntry->FullDllName, TRUE)) 745 IsExcluded = TRUE; 746 747 InExclude = SeiFindInExclude(&pShimInfo->InExclude, &LdrEntry->BaseDllName); 748 if (InExclude) 749 { 750 /* If it is on the 'exclude' list, bail out */ 751 if (!InExclude->Include) 752 { 753 SHIMENG_INFO("Module '%wZ' excluded for shim %S, API '%s!%s', because it on in the exclude list.\n", 754 &LdrEntry->BaseDllName, pShimInfo->ShimName, HookApi->LibraryName, HookApi->FunctionName); 755 756 return TRUE; 757 } 758 /* If it is on the 'include' list, override System32 / Winsxs check. */ 759 if (IsExcluded) 760 { 761 SHIMENG_INFO("Module '%wZ' included for shim %S, API '%s!%s', because it is on the include list.\n", 762 &LdrEntry->BaseDllName, pShimInfo->ShimName, HookApi->LibraryName, HookApi->FunctionName); 763 764 } 765 IsExcluded = FALSE; 766 } 767 768 if (IsExcluded) 769 { 770 SHIMENG_INFO("Module '%wZ' excluded for shim %S, API '%s!%s', because it is in System32/WinSXS.\n", 771 &LdrEntry->BaseDllName, pShimInfo->ShimName, HookApi->LibraryName, HookApi->FunctionName); 772 } 773 774 return IsExcluded; 775 } 776 777 VOID SeiAppendInExclude(PARRAY dest, PCWSTR ModuleName, BOOL IsInclude) 778 { 779 PINEXCLUDE InExclude; 780 UNICODE_STRING ModuleNameU; 781 RtlInitUnicodeString(&ModuleNameU, ModuleName); 782 783 InExclude = SeiFindInExclude(dest, &ModuleNameU); 784 if (InExclude) 785 { 786 InExclude->Include = IsInclude; 787 return; 788 } 789 790 InExclude = ARRAY_Append(dest, INEXCLUDE); 791 if (InExclude) 792 { 793 PCWSTR ModuleNameCopy = SdbpStrDup(ModuleName); 794 RtlInitUnicodeString(&InExclude->Module, ModuleNameCopy); 795 InExclude->Include = IsInclude; 796 } 797 } 798 799 /* Read the INEXCLUD tags from a given parent tag */ 800 VOID SeiReadInExclude(PDB pdb, TAGID parent, PARRAY dest) 801 { 802 TAGID InExcludeTag; 803 804 InExcludeTag = SdbFindFirstTag(pdb, parent, TAG_INEXCLUD); 805 806 while (InExcludeTag != TAGID_NULL) 807 { 808 PCWSTR ModuleName; 809 TAGID ModuleTag = SdbFindFirstTag(pdb, InExcludeTag, TAG_MODULE); 810 TAGID IncludeTag = SdbFindFirstTag(pdb, InExcludeTag, TAG_INCLUDE); 811 812 ModuleName = SdbGetStringTagPtr(pdb, ModuleTag); 813 if (ModuleName) 814 { 815 SeiAppendInExclude(dest, ModuleName, IncludeTag != TAGID_NULL); 816 } 817 else 818 { 819 SHIMENG_WARN("INEXCLUDE without Module: 0x%x\n", InExcludeTag); 820 } 821 822 InExcludeTag = SdbFindNextTag(pdb, parent, InExcludeTag); 823 } 824 } 825 826 VOID SeiBuildGlobalInclExclList(HSDB hsdb) 827 { 828 PDB pdb; 829 TAGREF tr = TAGREF_ROOT; 830 TAGID root, db, library; 831 832 if (!SdbTagRefToTagID(hsdb, tr, &pdb, &root)) 833 { 834 SHIMENG_WARN("Unable to resolve database root\n"); 835 return; 836 } 837 db = SdbFindFirstTag(pdb, root, TAG_DATABASE); 838 if (db == TAGID_NULL) 839 { 840 SHIMENG_WARN("Unable to resolve database\n"); 841 return; 842 } 843 library = SdbFindFirstTag(pdb, db, TAG_LIBRARY); 844 if (library == TAGID_NULL) 845 { 846 SHIMENG_WARN("Unable to resolve library\n"); 847 return; 848 } 849 850 SeiReadInExclude(pdb, library, &g_InExclude); 851 } 852 853 VOID SeiBuildInclExclList(PDB pdb, TAGID ShimTag, PSHIMINFO pShimInfo) 854 { 855 DWORD n; 856 857 /* First duplicate the global in/excludes */ 858 for (n = 0; n < ARRAY_Size(&g_InExclude); ++n) 859 { 860 PINEXCLUDE InEx = ARRAY_At(&g_InExclude, INEXCLUDE, n); 861 SeiAppendInExclude(&pShimInfo->InExclude, InEx->Module.Buffer, InEx->Include); 862 } 863 864 /* Now read this shim's in/excludes (possibly overriding the global ones) */ 865 SeiReadInExclude(pdb, ShimTag, &pShimInfo->InExclude); 866 } 867 868 /* Given one loaded module, redirect (hook) all functions from the iat that are registered by shims */ 869 VOID SeiHookImports(PLDR_DATA_TABLE_ENTRY LdrEntry) 870 { 871 ULONG Size; 872 PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor; 873 PBYTE DllBase = LdrEntry->DllBase; 874 875 if (SE_IsShimDll(DllBase) || g_hInstance == LdrEntry->DllBase || 876 (g_LoadingShimDll.Buffer && RtlEqualUnicodeString(&g_LoadingShimDll, &LdrEntry->BaseDllName, TRUE))) 877 { 878 SHIMENG_INFO("Skipping shim module 0x%p \"%wZ\"\n", LdrEntry->DllBase, &LdrEntry->BaseDllName); 879 return; 880 } 881 882 if (LdrEntry->Flags & LDRP_COMPAT_DATABASE_PROCESSED) 883 { 884 SHIMENG_INFO("Skipping module 0x%p \"%wZ\" because it was already processed\n", LdrEntry->DllBase, &LdrEntry->BaseDllName); 885 return; 886 } 887 888 ImportDescriptor = RtlImageDirectoryEntryToData(DllBase, TRUE, IMAGE_DIRECTORY_ENTRY_IMPORT, &Size); 889 if (!ImportDescriptor) 890 { 891 SHIMENG_INFO("Skipping module 0x%p \"%wZ\" due to no iat found\n", LdrEntry->DllBase, &LdrEntry->BaseDllName); 892 return; 893 } 894 895 SHIMENG_INFO("Hooking module 0x%p \"%wZ\"\n", LdrEntry->DllBase, &LdrEntry->BaseDllName); 896 897 for ( ;ImportDescriptor->Name && ImportDescriptor->OriginalFirstThunk; ImportDescriptor++) 898 { 899 PHOOKMODULEINFO HookModuleInfo; 900 901 /* Do we have hooks for this module? */ 902 HookModuleInfo = SeiFindHookModuleInfoForImportDescriptor(DllBase, ImportDescriptor); 903 904 if (HookModuleInfo) 905 { 906 PIMAGE_THUNK_DATA OriginalThunk, FirstThunk; 907 DWORD n; 908 909 for (n = 0; n < ARRAY_Size(&HookModuleInfo->HookApis); ++n) 910 { 911 DWORD dwFound = 0; 912 PHOOKAPIEX HookApi = *ARRAY_At(&HookModuleInfo->HookApis, PHOOKAPIEX, n); 913 914 /* Check if this module should be excluded from being hooked (system32/winsxs, global or shim exclude) */ 915 if (SeiIsExcluded(LdrEntry, HookApi)) 916 { 917 continue; 918 } 919 920 OriginalThunk = (PIMAGE_THUNK_DATA)(DllBase + ImportDescriptor->OriginalFirstThunk); 921 FirstThunk = (PIMAGE_THUNK_DATA)(DllBase + ImportDescriptor->FirstThunk); 922 923 /* Walk all imports */ 924 for (;OriginalThunk->u1.AddressOfData && FirstThunk->u1.Function; OriginalThunk++, FirstThunk++) 925 { 926 if (!IMAGE_SNAP_BY_ORDINAL32(OriginalThunk->u1.AddressOfData)) 927 { 928 PIMAGE_IMPORT_BY_NAME ImportName; 929 930 ImportName = (PIMAGE_IMPORT_BY_NAME)(DllBase + OriginalThunk->u1.AddressOfData); 931 if (!strcmp((PCSTR)ImportName->Name, HookApi->FunctionName)) 932 { 933 SeiPatchNewImport(FirstThunk, HookApi, LdrEntry); 934 935 /* Sadly, iat does not have to be sorted, and can even contain duplicate entries. */ 936 dwFound++; 937 } 938 } 939 else 940 { 941 SHIMENG_FAIL("Ordinals not yet supported\n"); 942 ASSERT(0); 943 } 944 } 945 946 if (dwFound != 1) 947 { 948 /* One entry not found. */ 949 if (!dwFound) 950 SHIMENG_INFO("Entry \"%s!%s\" not found for \"%wZ\"\n", HookApi->LibraryName, HookApi->FunctionName, &LdrEntry->BaseDllName); 951 else 952 SHIMENG_INFO("Entry \"%s!%s\" found %d times for \"%wZ\"\n", HookApi->LibraryName, HookApi->FunctionName, dwFound, &LdrEntry->BaseDllName); 953 } 954 } 955 } 956 } 957 958 /* Mark this module as processed. */ 959 LdrEntry->Flags |= LDRP_COMPAT_DATABASE_PROCESSED; 960 } 961 962 963 VOID PatchNewModules(PPEB Peb) 964 { 965 PLIST_ENTRY ListHead, ListEntry; 966 PLDR_DATA_TABLE_ENTRY LdrEntry; 967 968 ListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList; 969 ListEntry = ListHead->Flink; 970 971 while (ListHead != ListEntry) 972 { 973 LdrEntry = CONTAINING_RECORD(ListEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks); 974 SeiHookImports(LdrEntry); 975 976 ListEntry = ListEntry->Flink; 977 } 978 } 979 980 981 VOID SeiInitPaths(VOID) 982 { 983 #define SYSTEM32 L"\\system32" 984 #define WINSXS L"\\winsxs" 985 986 PWSTR WindowsDirectory = SdbpStrDup(SharedUserData->NtSystemRoot); 987 RtlInitUnicodeString(&g_WindowsDirectory, WindowsDirectory); 988 989 g_System32Directory.MaximumLength = g_WindowsDirectory.Length + SdbpStrsize(SYSTEM32); 990 g_System32Directory.Buffer = SdbpAlloc(g_System32Directory.MaximumLength); 991 RtlCopyUnicodeString(&g_System32Directory, &g_WindowsDirectory); 992 RtlAppendUnicodeToString(&g_System32Directory, SYSTEM32); 993 994 g_SxsDirectory.MaximumLength = g_WindowsDirectory.Length + SdbpStrsize(WINSXS); 995 g_SxsDirectory.Buffer = SdbpAlloc(g_SxsDirectory.MaximumLength); 996 RtlCopyUnicodeString(&g_SxsDirectory, &g_WindowsDirectory); 997 RtlAppendUnicodeToString(&g_SxsDirectory, WINSXS); 998 999 #undef SYSTEM32 1000 #undef WINSXS 1001 } 1002 1003 VOID SeiInit(PUNICODE_STRING ProcessImage, HSDB hsdb, SDBQUERYRESULT* pQuery) 1004 { 1005 DWORD n; 1006 ARRAY ShimRefArray; 1007 DWORD dwTotalHooks = 0; 1008 FLAGINFO ShimFlags; 1009 1010 PPEB Peb = NtCurrentPeb(); 1011 1012 /* We should only be called once! */ 1013 ASSERT(g_pShimInfo.ItemSize__ == 0); 1014 1015 ARRAY_Init(&ShimRefArray, TAGREF); 1016 ARRAY_Init(&g_pShimInfo, PSHIMMODULE); 1017 ARRAY_Init(&g_pHookArray, HOOKMODULEINFO); 1018 ARRAY_Init(&g_InExclude, INEXCLUDE); 1019 RtlZeroMemory(&ShimFlags, sizeof(ShimFlags)); 1020 1021 SeiInitPaths(); 1022 1023 SeiCheckComPlusImage(Peb->ImageBaseAddress); 1024 1025 /* TODO: 1026 if (pQuery->trApphelp) 1027 SeiDisplayAppHelp(?pQuery->trApphelp?); 1028 */ 1029 1030 SeiDbgPrint(SEI_MSG, NULL, "ShimInfo(ExePath(%wZ))\n", ProcessImage); 1031 SeiBuildShimRefArray(hsdb, pQuery, &ShimRefArray, &ShimFlags); 1032 if (ShimFlags.AppCompatFlags.QuadPart) 1033 { 1034 SeiDbgPrint(SEI_MSG, NULL, "Using KERNEL apphack flags 0x%I64x\n", ShimFlags.AppCompatFlags.QuadPart); 1035 Peb->AppCompatFlags.QuadPart |= ShimFlags.AppCompatFlags.QuadPart; 1036 } 1037 if (ShimFlags.AppCompatFlagsUser.QuadPart) 1038 { 1039 SeiDbgPrint(SEI_MSG, NULL, "Using USER apphack flags 0x%I64x\n", ShimFlags.AppCompatFlagsUser.QuadPart); 1040 Peb->AppCompatFlagsUser.QuadPart |= ShimFlags.AppCompatFlagsUser.QuadPart; 1041 } 1042 if (ShimFlags.ProcessParameters_Flags) 1043 { 1044 SeiDbgPrint(SEI_MSG, NULL, "Using ProcessParameters flags 0x%x\n", ShimFlags.ProcessParameters_Flags); 1045 Peb->ProcessParameters->Flags |= ShimFlags.ProcessParameters_Flags; 1046 } 1047 SeiDbgPrint(SEI_MSG, NULL, "ShimInfo(Complete)\n"); 1048 1049 SHIMENG_INFO("Got %d shims\n", ARRAY_Size(&ShimRefArray)); 1050 SeiBuildGlobalInclExclList(hsdb); 1051 1052 /* Walk all shims referenced (in layers + exes), and load their modules */ 1053 for (n = 0; n < ARRAY_Size(&ShimRefArray); ++n) 1054 { 1055 PDB pdb; 1056 TAGID ShimRef; 1057 1058 TAGREF tr = *ARRAY_At(&ShimRefArray, TAGREF, n); 1059 1060 if (SdbTagRefToTagID(hsdb, tr, &pdb, &ShimRef)) 1061 { 1062 LPCWSTR ShimName, DllName, CommandLine = NULL; 1063 TAGID ShimTag; 1064 WCHAR FullNameBuffer[MAX_PATH]; 1065 UNICODE_STRING UnicodeDllName; 1066 PVOID BaseAddress; 1067 PSHIMMODULE pShimModuleInfo = NULL; 1068 ANSI_STRING AnsiCommandLine = RTL_CONSTANT_STRING(""); 1069 PSHIMINFO pShimInfo = NULL; 1070 PHOOKAPIEX pHookApi; 1071 DWORD dwHookCount; 1072 1073 ShimName = SeiGetStringPtr(pdb, ShimRef, TAG_NAME); 1074 if (!ShimName) 1075 { 1076 SHIMENG_FAIL("Failed to retrieve the name for 0x%x\n", tr); 1077 continue; 1078 } 1079 1080 CommandLine = SeiGetStringPtr(pdb, ShimRef, TAG_COMMAND_LINE); 1081 if (CommandLine && *CommandLine) 1082 { 1083 RtlInitUnicodeString(&UnicodeDllName, CommandLine); 1084 if (NT_SUCCESS(RtlUnicodeStringToAnsiString(&AnsiCommandLine, &UnicodeDllName, TRUE))) 1085 { 1086 SHIMENG_INFO("COMMAND LINE %s for %S", AnsiCommandLine.Buffer, ShimName); 1087 } 1088 else 1089 { 1090 AnsiCommandLine.Buffer = ""; 1091 CommandLine = NULL; 1092 } 1093 } 1094 1095 ShimTag = SeiGetDWORD(pdb, ShimRef, TAG_SHIM_TAGID); 1096 if (!ShimTag) 1097 { 1098 SHIMENG_FAIL("Failed to resolve %S to a shim\n", ShimName); 1099 continue; 1100 } 1101 1102 if (!SUCCEEDED(SdbGetAppPatchDir(NULL, FullNameBuffer, ARRAYSIZE(FullNameBuffer)))) 1103 { 1104 SHIMENG_WARN("Failed to get the AppPatch dir\n"); 1105 continue; 1106 } 1107 1108 DllName = SeiGetStringPtr(pdb, ShimTag, TAG_DLLFILE); 1109 if (DllName == NULL || 1110 !SUCCEEDED(StringCchCatW(FullNameBuffer, ARRAYSIZE(FullNameBuffer), L"\\")) || 1111 !SUCCEEDED(StringCchCatW(FullNameBuffer, ARRAYSIZE(FullNameBuffer), DllName))) 1112 { 1113 SHIMENG_WARN("Failed to build a full path for %S\n", ShimName); 1114 continue; 1115 } 1116 1117 RtlInitUnicodeString(&g_LoadingShimDll, DllName); 1118 RtlInitUnicodeString(&UnicodeDllName, FullNameBuffer); 1119 if (NT_SUCCESS(LdrGetDllHandle(NULL, NULL, &UnicodeDllName, &BaseAddress))) 1120 { 1121 /* This shim dll was already loaded, let's find it */ 1122 pShimModuleInfo = SeiGetShimModuleInfo(BaseAddress); 1123 } 1124 else if (!NT_SUCCESS(LdrLoadDll(NULL, NULL, &UnicodeDllName, &BaseAddress))) 1125 { 1126 SHIMENG_WARN("Failed to load %wZ for %S\n", &UnicodeDllName, ShimName); 1127 continue; 1128 } 1129 RtlInitUnicodeString(&g_LoadingShimDll, NULL); 1130 /* No shim module found (or we just loaded it) */ 1131 if (!pShimModuleInfo) 1132 { 1133 pShimModuleInfo = SeiCreateShimModuleInfo(DllName, BaseAddress); 1134 if (!pShimModuleInfo) 1135 { 1136 SHIMENG_FAIL("Failed to allocate ShimInfo for %S\n", DllName); 1137 continue; 1138 } 1139 } 1140 1141 SHIMENG_INFO("Shim DLL 0x%p \"%wZ\" loaded\n", BaseAddress, &UnicodeDllName); 1142 SHIMENG_INFO("Using SHIM \"%S!%S\"\n", DllName, ShimName); 1143 1144 /* Ask this shim what hooks it needs (and pass along the commandline) */ 1145 pHookApi = pShimModuleInfo->pGetHookAPIs(AnsiCommandLine.Buffer, ShimName, &dwHookCount); 1146 SHIMENG_INFO("GetHookAPIs returns %d hooks for DLL \"%wZ\" SHIM \"%S\"\n", dwHookCount, &UnicodeDllName, ShimName); 1147 if (dwHookCount) 1148 pShimInfo = SeiAppendHookInfo(pShimModuleInfo, pHookApi, dwHookCount, ShimName); 1149 1150 /* If this shim has hooks, create the include / exclude lists */ 1151 if (pShimInfo) 1152 SeiBuildInclExclList(pdb, ShimTag, pShimInfo); 1153 1154 if (CommandLine && *CommandLine) 1155 RtlFreeAnsiString(&AnsiCommandLine); 1156 1157 dwTotalHooks += dwHookCount; 1158 } 1159 } 1160 1161 SeiAddInternalHooks(dwTotalHooks); 1162 SeiResolveAPIs(); 1163 PatchNewModules(Peb); 1164 } 1165 1166 1167 /* Load the database + unpack the shim data (if this process is allowed) */ 1168 BOOL SeiGetShimData(PUNICODE_STRING ProcessImage, PVOID pShimData, HSDB* pHsdb, SDBQUERYRESULT* pQuery) 1169 { 1170 static const UNICODE_STRING ForbiddenShimmingApps[] = { 1171 RTL_CONSTANT_STRING(L"ntsd.exe"), 1172 RTL_CONSTANT_STRING(L"windbg.exe"), 1173 #if WINVER >= 0x600 1174 RTL_CONSTANT_STRING(L"slsvc.exe"), 1175 #endif 1176 }; 1177 static const UNICODE_STRING BackSlash = RTL_CONSTANT_STRING(L"\\"); 1178 static const UNICODE_STRING ForwdSlash = RTL_CONSTANT_STRING(L"/"); 1179 UNICODE_STRING ProcessName; 1180 USHORT Back, Forward; 1181 HSDB hsdb; 1182 DWORD n; 1183 1184 if (!NT_SUCCESS(RtlFindCharInUnicodeString(RTL_FIND_CHAR_IN_UNICODE_STRING_START_AT_END, ProcessImage, &BackSlash, &Back))) 1185 Back = 0; 1186 1187 if (!NT_SUCCESS(RtlFindCharInUnicodeString(RTL_FIND_CHAR_IN_UNICODE_STRING_START_AT_END, ProcessImage, &ForwdSlash, &Forward))) 1188 Forward = 0; 1189 1190 if (Back < Forward) 1191 Back = Forward; 1192 1193 if (Back) 1194 Back += sizeof(WCHAR); 1195 1196 ProcessName.Buffer = ProcessImage->Buffer + Back / sizeof(WCHAR); 1197 ProcessName.Length = ProcessImage->Length - Back; 1198 ProcessName.MaximumLength = ProcessImage->MaximumLength - Back; 1199 1200 for (n = 0; n < ARRAYSIZE(ForbiddenShimmingApps); ++n) 1201 { 1202 if (RtlEqualUnicodeString(&ProcessName, ForbiddenShimmingApps + n, TRUE)) 1203 { 1204 SHIMENG_MSG("Not shimming %wZ\n", ForbiddenShimmingApps + n); 1205 return FALSE; 1206 } 1207 } 1208 1209 /* We should probably load all db's here, but since we do not support that yet... */ 1210 hsdb = SdbInitDatabase(HID_DOS_PATHS | SDB_DATABASE_MAIN_SHIM, NULL); 1211 if (hsdb) 1212 { 1213 if (SdbUnpackAppCompatData(hsdb, ProcessImage->Buffer, pShimData, pQuery)) 1214 { 1215 *pHsdb = hsdb; 1216 return TRUE; 1217 } 1218 SdbReleaseDatabase(hsdb); 1219 } 1220 return FALSE; 1221 } 1222 1223 1224 1225 VOID NTAPI SE_InstallBeforeInit(PUNICODE_STRING ProcessImage, PVOID pShimData) 1226 { 1227 HSDB hsdb = NULL; 1228 SDBQUERYRESULT QueryResult = { { 0 } }; 1229 SHIMENG_INFO("(%wZ, %p)\n", ProcessImage, pShimData); 1230 1231 if (!SeiGetShimData(ProcessImage, pShimData, &hsdb, &QueryResult)) 1232 { 1233 SHIMENG_FAIL("Failed to get shim data\n"); 1234 return; 1235 } 1236 1237 g_bShimDuringInit = TRUE; 1238 SeiInit(ProcessImage, hsdb, &QueryResult); 1239 g_bShimDuringInit = FALSE; 1240 1241 SdbReleaseDatabase(hsdb); 1242 } 1243 1244 VOID NTAPI SE_InstallAfterInit(PUNICODE_STRING ProcessImage, PVOID pShimData) 1245 { 1246 NotifyShims(SHIM_NOTIFY_ATTACH, NULL); 1247 } 1248 1249 VOID NTAPI SE_ProcessDying(VOID) 1250 { 1251 SHIMENG_MSG("()\n"); 1252 NotifyShims(SHIM_NOTIFY_DETACH, NULL); 1253 } 1254 1255 VOID WINAPI SE_DllLoaded(PLDR_DATA_TABLE_ENTRY LdrEntry) 1256 { 1257 SHIMENG_INFO("%sINIT. loading DLL \"%wZ\"\n", g_bShimDuringInit ? "" : "AFTER ", &LdrEntry->BaseDllName); 1258 1259 SeiHookImports(LdrEntry); 1260 1261 NotifyShims(SHIM_REASON_DLL_LOAD, LdrEntry); 1262 } 1263 1264 VOID WINAPI SE_DllUnloaded(PLDR_DATA_TABLE_ENTRY LdrEntry) 1265 { 1266 SHIMENG_INFO("(%p)\n", LdrEntry); 1267 1268 /* Should we unhook here? */ 1269 1270 NotifyShims(SHIM_REASON_DLL_UNLOAD, LdrEntry); 1271 } 1272 1273 BOOL WINAPI SE_IsShimDll(PVOID BaseAddress) 1274 { 1275 SHIMENG_INFO("(%p)\n", BaseAddress); 1276 1277 return SeiGetShimModuleInfo(BaseAddress) != NULL; 1278 } 1279 1280