Files
Maxime dcb d67acbae19 Arm64
2026-04-29 11:23:06 +02:00

290 lines
8.2 KiB
C++

#include "peb.hpp"
#if _WIN32
#if defined(_M_ARM64)
#define PEB_OFFSET 0x60
#define READ_TEB() ((void*)__getReg(18))
#elif defined(_M_X64)
#define PEB_OFFSET 0x60
#define READ_TEB() ((void*)__readgsqword(0x30))
#elif defined(_M_IX86)
#define PEB_OFFSET 0x30
#define READ_TEB() ((void*)__readfsdword(0x18))
#else
#error Unsupported architecture
#endif
static void* GetPeb(void)
{
unsigned char* teb = (unsigned char*)READ_TEB();
return *(void**)(teb + PEB_OFFSET);
}
// Relative Virtual Address to Virtual Address
#define RVA2VA(type, base, rva) (type)((ULONG_PTR) base + rva)
// find a DLL with a certain export, used by xGetProcAddress and FindExport
LPVOID find_reference(
IN LPVOID original_dll,
IN PCHAR dll_name,
IN PCHAR api_name)
{
PPEB2 peb = NULL;
PPEB_LDR_DATA2 ldr = NULL;
PLDR_DATA_TABLE_ENTRY2 dte = NULL;
LPVOID addr = NULL;
LPVOID base = NULL;
peb = (PPEB2)GetPeb();
ldr = (PPEB_LDR_DATA2)peb->Ldr;
// for each DLL loaded
for (dte=(PLDR_DATA_TABLE_ENTRY2)ldr->InLoadOrderModuleList.Flink;
dte->DllBase != NULL && addr == NULL;
dte=(PLDR_DATA_TABLE_ENTRY2)dte->InLoadOrderLinks.Flink)
{
base = dte->DllBase;
// if this is the dll with the reference, continue
if (base == original_dll) continue;
addr = xGetProcAddress(base, api_name, 0);
}
if (addr == NULL)
{
// we did not find the reference, use LoadLibrary
// DPRINT("Could not find %s, using LoadLibraryA", dll_name);
HMODULE hModule = LoadLibraryA(dll_name);
if (hModule != NULL)
{
// DPRINT("Calling GetProcAddress(%s, %s)", dll_name, api_name);
addr = GetProcAddress(hModule, api_name);
}
}
return addr;
}
// size_t StringLengthA(const char* str)
// {
// if (str == nullptr)
// return 0;
// size_t length = 0;
// while (str[length] != '\0')
// {
// ++length;
// }
// return length;
// }
// search for an export in a DLL
LPVOID xGetProcAddress(
IN LPVOID base,
IN PCHAR api_name,
IN DWORD ordinal)
{
PIMAGE_DOS_HEADER dos = NULL;
PIMAGE_NT_HEADERS nt = NULL;
PIMAGE_DATA_DIRECTORY dir = NULL;
PIMAGE_EXPORT_DIRECTORY exp = NULL;
LPVOID addr = NULL;
DWORD rva = 0;
DWORD cnt = 0;
PDWORD adr = NULL;
PDWORD sym = NULL;
PWORD ord = NULL;
PCHAR api = NULL;
CHAR dll_name[256] = { 0 };
CHAR new_api[256] = { 0 };
DWORD i = 0;
PCHAR p = NULL;
DWORD len = 0;
PVOID newbase = NULL;
if (base == NULL) return NULL;
dos = (PIMAGE_DOS_HEADER)base;
nt = RVA2VA(PIMAGE_NT_HEADERS, base, dos->e_lfanew);
dir = (PIMAGE_DATA_DIRECTORY)nt->OptionalHeader.DataDirectory;
rva = dir[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
// if no export table, return NULL
if (rva == 0) return NULL;
exp = RVA2VA(PIMAGE_EXPORT_DIRECTORY, base, rva);
adr = RVA2VA(PDWORD,base, exp->AddressOfFunctions);
sym = RVA2VA(PDWORD,base, exp->AddressOfNames);
ord = RVA2VA(PWORD, base, exp->AddressOfNameOrdinals);
if (api_name != NULL)
{
// exported by name
cnt = exp->NumberOfNames;
// if no api names, return NULL
if (cnt == 0) return NULL;
do {
api = RVA2VA(PCHAR, base, sym[cnt-1]);
// check if the export name matches the API we are looking for
if (!_stricmp(api, api_name))
{
// get the address of the API
addr = RVA2VA(LPVOID, base, adr[ord[cnt-1]]);
}
} while (--cnt && addr == NULL);
}
else
{
// exported by ordinal
addr = RVA2VA(PVOID, base, adr[ordinal - exp->Base]);
}
// // is this a forward reference?
// if ((PBYTE)addr >= (PBYTE)exp &&
// (PBYTE)addr < (PBYTE)exp +
// dir[IMAGE_DIRECTORY_ENTRY_EXPORT].Size)
// {
// //DPRINT("%s is forwarded to %s", api_name, (char*)addr);
// // copy DLL name to buffer
// p=(char*)addr;
// len=StringLengthA(p);
// for (i=0; p[i] != 0 && i < sizeof(dll_name) - 4; i++)
// {
// dll_name[i] = p[i];
// }
// for (i=len-1; i > 0; i--)
// {
// if(p[i] == '.') break;
// }
// dll_name[i+1] = 'd';
// dll_name[i+2] = 'l';
// dll_name[i+3] = 'l';
// dll_name[i+4] = 0;
// p += i + 1;
// // copy API name to buffer
// for(i = 0; p[i] != 0 && i < sizeof(new_api) - 1; i++)
// {
// new_api[i] = p[i];
// }
// new_api[i] = 0;
// newbase = handle_dependency(NULL, dll_name);
// if (base == newbase)
// {
// /*
// * the api set seems to resolve to itself...
// * lets just iterate over all loaded modules and
// * find a module with the export we are looking for
// */
// addr = find_reference(base, dll_name, new_api);
// }
// else
// {
// /*
// * we got a different DLL, call xGetProcAddress recursively
// */
// addr = xGetProcAddress(newbase, new_api, 0);
// }
// }
return addr;
}
// find a DLL by name, load it if not found
LPVOID xGetLibAddress(
IN PCHAR search,
IN BOOL load,
OUT PBOOL loaded)
{
PPEB2 peb = NULL;
PPEB_LDR_DATA2 ldr = NULL;
PIMAGE_DOS_HEADER dos = NULL;
PIMAGE_NT_HEADERS nt = NULL;
PLDR_DATA_TABLE_ENTRY2 dte = NULL;
PIMAGE_EXPORT_DIRECTORY exp = NULL;
LPVOID addr = NULL;
LPVOID base = NULL;
DWORD rva = 0;
PCHAR name = NULL;
CHAR dll_name[64] = { 0 };
DWORD i = 0;
int correct = -1;
if (loaded)
*loaded = FALSE;
for(i = 0; search[i] != 0 && i < 64; i++)
{
dll_name[i] = search[i];
}
dll_name[i] = 0;
// make sure the name ends with '.dll'
if (dll_name[i-4] != '.')
{
dll_name[i++] = '.';
dll_name[i++] = 'd';
dll_name[i++] = 'l';
dll_name[i++] = 'l';
dll_name[i++] = 0;
}
peb = (PPEB2)GetPeb();
ldr = (PPEB_LDR_DATA2)peb->Ldr;
// for each DLL loaded
for (dte=(PLDR_DATA_TABLE_ENTRY2)ldr->InLoadOrderModuleList.Flink;
correct != 0 && dte->DllBase != NULL && addr == NULL;
dte=(PLDR_DATA_TABLE_ENTRY2)dte->InLoadOrderLinks.Flink)
{
base = dte->DllBase;
dos = (PIMAGE_DOS_HEADER)base;
nt = RVA2VA(PIMAGE_NT_HEADERS, base, dos->e_lfanew);
rva = nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
if (rva == 0) continue;
exp = RVA2VA(PIMAGE_EXPORT_DIRECTORY, base, rva);
name = RVA2VA(PCHAR, base, exp->Name);
correct = _stricmp(dll_name, name);
if (correct == 0) {
addr = base;
}
}
//DPRINT("Address of %s: %p", dll_name, addr);
// if the DLL was not found, load it
if (!addr && load)
{
addr = LoadLibraryA(dll_name);
// DPRINT("Dll not found. Loaded %s via LoadLibrary at 0x%p", dll_name, addr);
if (addr && loaded)
*loaded = TRUE;
}
return addr;
}
#endif