Files
2023-09-03 22:24:44 -03:00

275 lines
7.3 KiB
C

#include "dinvoke.h"
// used by spoof_callstack
PVOID find_dll_by_pointer(
IN PVOID address)
{
PND_PEB Peb = (PND_PEB)READ_MEMLOC(PEB_OFFSET);
PND_PEB_LDR_DATA Ldr = Peb->Ldr;
PVOID FirstEntry = &Ldr->InLoadOrderModuleList.Flink;
PND_LDR_DATA_TABLE_ENTRY Entry = (PND_LDR_DATA_TABLE_ENTRY)Ldr->InLoadOrderModuleList.Flink;
do
{
if ((ULONG_PTR)address >= (ULONG_PTR)Entry->DllBase &&
(ULONG_PTR)address < RVA(ULONG_PTR, Entry->DllBase, Entry->SizeOfImage))
return Entry->DllBase;
Entry = (PND_LDR_DATA_TABLE_ENTRY)Entry->InLoadOrderLinks.Flink;
} while (Entry != FirstEntry);
DPRINT_ERR("Could not find the target DLL from the pointer 0x%p", address);
return NULL;
}
/*
* Check that hLibrary is indeed a DLL and not something else
*/
BOOL is_dll(
IN HMODULE hLibrary)
{
PIMAGE_DOS_HEADER dos;
PIMAGE_NT_HEADERS nt;
if (!hLibrary)
return FALSE;
dos = (PIMAGE_DOS_HEADER)hLibrary;
// check the MZ magic bytes
if (dos->e_magic != MZ)
return FALSE;
nt = RVA(PIMAGE_NT_HEADERS, hLibrary, dos->e_lfanew);
// check the NT_HEADER signature
if (nt->Signature != IMAGE_NT_SIGNATURE)
return FALSE;
// check that it is a DLL and not a PE
USHORT Characteristics = nt->FileHeader.Characteristics;
if ((Characteristics & IMAGE_FILE_DLL) != IMAGE_FILE_DLL)
return FALSE;
return TRUE;
}
/*
* Look among all loaded DLLs for an export with certain function hash
*/
PVOID find_legacy_export(
IN HMODULE hOriginalLibrary,
IN DWORD fhash)
{
PVOID addr;
PND_PEB Peb = (PND_PEB)READ_MEMLOC(PEB_OFFSET);
PND_PEB_LDR_DATA Ldr = Peb->Ldr;
PVOID FirstEntry = &Ldr->InLoadOrderModuleList.Flink;
PND_LDR_DATA_TABLE_ENTRY Entry = (PND_LDR_DATA_TABLE_ENTRY)Ldr->InLoadOrderModuleList.Flink;
for (; Entry != FirstEntry; Entry = (PND_LDR_DATA_TABLE_ENTRY)Entry->InLoadOrderLinks.Flink)
{
// avoid looking in the DLL that brought us here
if (Entry->DllBase == hOriginalLibrary)
continue;
// check if this DLL has an export with the function hash we are looking for
addr = get_function_address(
Entry->DllBase,
fhash,
0);
if (!addr)
continue;
return addr;
}
return NULL;
}
/*
* Follow the reference and return the real address of the function
*/
PVOID resolve_reference(
IN HMODULE hOriginalLibrary,
IN PVOID addr)
{
HANDLE hLibrary;
PVOID new_addr;
LPCSTR api;
// addr points to a string like: NewLibrary.NewFunctionName
api = &strrchr(addr, '.')[1];
DWORD dll_length = (DWORD)((ULONG_PTR)api - (ULONG_PTR)addr);
char dll[MAX_PATH + 1] = {0};
strncpy(dll, (LPCSTR)addr, dll_length);
strncat(dll, "dll", MAX_PATH);
wchar_t wc_dll[MAX_PATH] = {0};
mbstowcs(wc_dll, dll, MAX_PATH);
// try to find the library NewLibrary
hLibrary = get_library_address(wc_dll, FALSE);
if (!hLibrary)
{
// the library is not loaded, meaning it is a legacy DLL
new_addr = find_legacy_export(
hOriginalLibrary,
SW2_HashSyscall(api));
return new_addr;
}
// get the address of NewFunction in NewLibrary
new_addr = get_function_address(
hLibrary,
SW2_HashSyscall(api),
0);
return new_addr;
}
/*
* Find an export in a DLL
*/
PVOID get_function_address(
IN HMODULE hLibrary,
IN DWORD fhash,
IN WORD ordinal)
{
PIMAGE_DOS_HEADER dos;
PIMAGE_NT_HEADERS nt;
PIMAGE_DATA_DIRECTORY data;
PIMAGE_EXPORT_DIRECTORY exp;
DWORD exp_size;
PDWORD adr;
PDWORD sym;
PWORD ord;
LPCSTR api;
PVOID addr;
if (!is_dll(hLibrary))
return NULL;
dos = (PIMAGE_DOS_HEADER)hLibrary;
nt = RVA(PIMAGE_NT_HEADERS, hLibrary, dos->e_lfanew);
data = (PIMAGE_DATA_DIRECTORY)nt->OptionalHeader.DataDirectory;
if (!data->Size || !data->VirtualAddress)
return NULL;
exp = RVA(PIMAGE_EXPORT_DIRECTORY, hLibrary, data->VirtualAddress);
exp_size = data[IMAGE_DIRECTORY_ENTRY_EXPORT].Size;
adr = RVA(PDWORD, hLibrary, exp->AddressOfFunctions);
sym = RVA(PDWORD, hLibrary, exp->AddressOfNames);
ord = RVA(PWORD, hLibrary, exp->AddressOfNameOrdinals);
addr = NULL;
if (fhash)
{
// iterate over all the exports
for (DWORD i = 0; i < exp->NumberOfNames; i++)
{
api = RVA(LPCSTR, hLibrary, sym[i]);
//addr = RVA(PVOID, hLibrary, adr[ord[i]]);
//DPRINT("%lx -> %s -> 0x%llx", fhash, api, (ULONG_PTR)addr-(ULONG_PTR)hLibrary);
if (fhash == SW2_HashSyscall(api))
{
addr = RVA(PVOID, hLibrary, adr[ord[i]]);
break;
}
}
}
else
{
addr = RVA(PVOID, hLibrary, adr[ordinal - exp->Base]);
}
if (!addr)
return NULL;
// check if addr is a pointer to another function in another DLL
if ((ULONG_PTR)addr >= (ULONG_PTR)exp &&
(ULONG_PTR)addr < RVA(ULONG_PTR, exp, exp_size))
{
// the function seems to be defined somewhere else
addr = resolve_reference(
hLibrary,
addr);
}
return addr;
}
/*
* Get the base address of a DLL
*/
HANDLE get_library_address(
IN LPWSTR lib_path,
IN BOOL DoLoad)
{
PND_PEB Peb = (PND_PEB)READ_MEMLOC(PEB_OFFSET);
PND_PEB_LDR_DATA Ldr = Peb->Ldr;
PVOID FirstEntry = &Ldr->InLoadOrderModuleList.Flink;
PND_LDR_DATA_TABLE_ENTRY Entry = (PND_LDR_DATA_TABLE_ENTRY)Ldr->InLoadOrderModuleList.Flink;
BOOL is_full_path = wcsrchr(lib_path, '\\') ? TRUE : FALSE;
do
{
if (is_full_path)
{
// the dll name was provided
if (!_wcsicmp(lib_path, Entry->FullDllName.Buffer))
return Entry->DllBase;
}
else
{
// the full path was provided
if (!_wcsicmp(lib_path, Entry->BaseDllName.Buffer))
return Entry->DllBase;
}
Entry = (PND_LDR_DATA_TABLE_ENTRY)Entry->InLoadOrderLinks.Flink;
} while (Entry != FirstEntry);
if (!DoLoad)
return NULL;
// the library is not currently loaded
// get the address of LdrLoadDll
LdrLoadDll_t LdrLoadDll = (LdrLoadDll_t)(ULONG_PTR)get_function_address(
get_library_address(NTDLL_DLL, FALSE),
LdrLoadDll_SW2_HASH,
0);
if (!LdrLoadDll)
{
api_not_found("LdrLoadDll");
return NULL;
}
// create a UNICODE_STRING with the library name
UNICODE_STRING ModuleFileName = { 0 };
ModuleFileName.Buffer = lib_path;
ModuleFileName.Length = (USHORT)wcsnlen(ModuleFileName.Buffer, MAX_PATH);
ModuleFileName.Length *= 2;
ModuleFileName.MaximumLength = ModuleFileName.Length + 2;
// load the library
HANDLE hLibrary = NULL;
NTSTATUS status = LdrLoadDll(
NULL,
0,
&ModuleFileName,
&hLibrary);
if (!NT_SUCCESS(status))
{
DPRINT_ERR(
"Failed to load %ls, status: 0x%lx\n",
lib_path,
status);
return NULL;
}
DPRINT("Loaded %ls at 0x%p", lib_path, hLibrary);
return hLibrary;
}