Skip to content

Commit 17d1c5b

Browse files
archeYRbinarymasterHBelusca
authored
[APPHELP] Handle PE images without an import name table (reactos#8507)
* [APPHELP] Handle PE images without an import name table This splits the import lookup code in SeiHookImports into two helper functions - SeiPatchImportsByName and SeiPatchImportsByAddress. Some PEs (eg. compiled with Borland toolchain or compressed with UPX) may not contain an import name table, so we use an alternative method (SeiPatchImportsByAddress) to find the imports we want to hook to by comparing the original pointers of the registered shim functions against those in IAT. --------- Co-authored-by: Stanislav Motylkov <[email protected]> Co-authored-by: Hermès BÉLUSCA - MAÏTO <[email protected]>
1 parent d6bf163 commit 17d1c5b

File tree

1 file changed

+65
-32
lines changed

1 file changed

+65
-32
lines changed

dll/appcompat/apphelp/shimeng.c

Lines changed: 65 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -954,9 +954,56 @@ VOID SeiBuildInclExclList(PDB pdb, TAGID ShimTag, PSHIMINFO pShimInfo)
954954
SeiReadInExclude(pdb, ShimTag, &pShimInfo->InExclude);
955955
}
956956

957+
DWORD SeiPatchImportsByName(PIMAGE_THUNK_DATA OriginalThunk, PIMAGE_THUNK_DATA FirstThunk, PHOOKAPIEX HookApi, PLDR_DATA_TABLE_ENTRY LdrEntry)
958+
{
959+
DWORD dwFound = 0;
960+
961+
for (; OriginalThunk->u1.AddressOfData && FirstThunk->u1.Function; OriginalThunk++, FirstThunk++)
962+
{
963+
if (!IMAGE_SNAP_BY_ORDINAL(OriginalThunk->u1.Function) && !SeiIsOrdinalName(HookApi->FunctionName))
964+
{
965+
PIMAGE_IMPORT_BY_NAME ImportName;
966+
967+
ImportName = (PIMAGE_IMPORT_BY_NAME)((PBYTE)LdrEntry->DllBase + OriginalThunk->u1.Function);
968+
if (!strcmp((PCSTR)ImportName->Name, HookApi->FunctionName))
969+
{
970+
SeiPatchNewImport(FirstThunk, HookApi, LdrEntry);
971+
dwFound++;
972+
}
973+
}
974+
else
975+
{
976+
if (SeiIsOrdinalName(HookApi->FunctionName) && ((PCSTR)IMAGE_ORDINAL(OriginalThunk->u1.Function) == HookApi->FunctionName))
977+
{
978+
SeiPatchNewImport(FirstThunk, HookApi, LdrEntry);
979+
dwFound++;
980+
}
981+
}
982+
}
983+
984+
return dwFound;
985+
}
986+
987+
DWORD SeiPatchImportsByAddress(PIMAGE_THUNK_DATA FirstThunk, PHOOKAPIEX HookApi, PLDR_DATA_TABLE_ENTRY LdrEntry)
988+
{
989+
DWORD dwFound = 0;
990+
991+
for (; FirstThunk->u1.Function; FirstThunk++)
992+
{
993+
if ((PULONG_PTR)FirstThunk->u1.Function == HookApi->OriginalFunction)
994+
{
995+
SeiPatchNewImport(FirstThunk, HookApi, LdrEntry);
996+
dwFound++;
997+
}
998+
}
999+
1000+
return dwFound;
1001+
}
1002+
9571003
/* Given one loaded module, redirect (hook) all functions from the iat that are registered by shims */
9581004
VOID SeiHookImports(PLDR_DATA_TABLE_ENTRY LdrEntry)
9591005
{
1006+
BOOLEAN HasImportNameTable;
9601007
ULONG Size;
9611008
PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor;
9621009
PBYTE DllBase = LdrEntry->DllBase;
@@ -984,7 +1031,15 @@ VOID SeiHookImports(PLDR_DATA_TABLE_ENTRY LdrEntry)
9841031

9851032
SHIMENG_INFO("Hooking module 0x%p \"%wZ\"\n", LdrEntry->DllBase, &LdrEntry->BaseDllName);
9861033

987-
for ( ;ImportDescriptor->Name && ImportDescriptor->OriginalFirstThunk; ImportDescriptor++)
1034+
HasImportNameTable = ImportDescriptor->OriginalFirstThunk;
1035+
if (!HasImportNameTable)
1036+
{
1037+
/* Some PEs (eg. built with Borland toolchain or compressed with UPX) may not have an import name table.
1038+
* In that case we have to rely solely on an import address table. */
1039+
SHIMENG_INFO("Module 0x%p \"%wZ\" does not have an import name table\n", LdrEntry->DllBase, &LdrEntry->BaseDllName);
1040+
}
1041+
1042+
for ( ;ImportDescriptor->Name && (HasImportNameTable ? ImportDescriptor->OriginalFirstThunk : ImportDescriptor->FirstThunk); ImportDescriptor++)
9881043
{
9891044
PHOOKMODULEINFO HookModuleInfo;
9901045

@@ -998,7 +1053,7 @@ VOID SeiHookImports(PLDR_DATA_TABLE_ENTRY LdrEntry)
9981053

9991054
for (n = 0; n < ARRAY_Size(&HookModuleInfo->HookApis); ++n)
10001055
{
1001-
DWORD dwFound = 0;
1056+
DWORD dwFound;
10021057
PHOOKAPIEX HookApi = *ARRAY_At(&HookModuleInfo->HookApis, PHOOKAPIEX, n);
10031058

10041059
/* Check if this module should be excluded from being hooked (system32/winsxs, global or shim exclude) */
@@ -1007,41 +1062,19 @@ VOID SeiHookImports(PLDR_DATA_TABLE_ENTRY LdrEntry)
10071062
continue;
10081063
}
10091064

1010-
OriginalThunk = (PIMAGE_THUNK_DATA)(DllBase + ImportDescriptor->OriginalFirstThunk);
10111065
FirstThunk = (PIMAGE_THUNK_DATA)(DllBase + ImportDescriptor->FirstThunk);
10121066

1013-
/* Walk all imports */
1014-
for (;OriginalThunk->u1.AddressOfData && FirstThunk->u1.Function; OriginalThunk++, FirstThunk++)
1067+
if (HasImportNameTable)
10151068
{
1016-
if (!IMAGE_SNAP_BY_ORDINAL(OriginalThunk->u1.Function))
1017-
{
1018-
if (!SeiIsOrdinalName(HookApi->FunctionName))
1019-
{
1020-
PIMAGE_IMPORT_BY_NAME ImportName;
1021-
1022-
ImportName = (PIMAGE_IMPORT_BY_NAME)(DllBase + OriginalThunk->u1.Function);
1023-
if (!strcmp((PCSTR)ImportName->Name, HookApi->FunctionName))
1024-
{
1025-
SeiPatchNewImport(FirstThunk, HookApi, LdrEntry);
1026-
1027-
/* Sadly, iat does not have to be sorted, and can even contain duplicate entries. */
1028-
dwFound++;
1029-
}
1030-
}
1031-
}
1032-
else
1033-
{
1034-
if (SeiIsOrdinalName(HookApi->FunctionName))
1035-
{
1036-
if ((PCSTR)IMAGE_ORDINAL(OriginalThunk->u1.Function) == HookApi->FunctionName)
1037-
{
1038-
SeiPatchNewImport(FirstThunk, HookApi, LdrEntry);
1039-
dwFound++;
1040-
}
1041-
}
1042-
}
1069+
OriginalThunk = (PIMAGE_THUNK_DATA)(DllBase + ImportDescriptor->OriginalFirstThunk);
1070+
dwFound = SeiPatchImportsByName(OriginalThunk, FirstThunk, HookApi, LdrEntry);
1071+
}
1072+
else
1073+
{
1074+
dwFound = SeiPatchImportsByAddress(FirstThunk, HookApi, LdrEntry);
10431075
}
10441076

1077+
/* Sadly, IAT does not have to be sorted, and can even contain duplicate entries. */
10451078
if (dwFound != 1)
10461079
{
10471080
char szOrdProcFmt[10];

0 commit comments

Comments
 (0)