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