handle delayLoad failure in Addresser::followThunkFunction

This commit is contained in:
matcool 2024-06-01 14:16:40 -03:00
parent 68732ebe57
commit cf111ca000

View file

@ -69,12 +69,26 @@ Addresser::MultipleInheritance* Addresser::instance() {
#ifdef GEODE_IS_WINDOWS
#include <delayimp.h>
extern "C" FARPROC WINAPI __delayLoadHelper2(PCImgDelayDescr pidd, FARPROC* ppfnIATEntry); // NOLINT(*-reserved-identifier)
FARPROC WINAPI delayLoadHook(unsigned dliNotify, PDelayLoadInfo pdli) {
switch (dliNotify) {
case dliFailLoadLib:
case dliFailGetProc:
// incase the delayload helper fails at all (missing symbol, or library entirely),
// return -1, so we can more easily handle it below
return (FARPROC)(-1);
default:
return NULL;
}
}
extern "C" const PfnDliHook __pfnDliFailureHook2 = delayLoadHook;
#endif
intptr_t Addresser::followThunkFunction(intptr_t address) {
#ifdef GEODE_IS_WINDOWS32
// if theres a jmp at the start
if (*reinterpret_cast<uint8_t*>(address) == 0xE9) {
if (address && *reinterpret_cast<uint8_t*>(address) == 0xE9) {
auto relative = *reinterpret_cast<uint32_t*>(address + 1);
auto newAddress = address + relative + 5;
// and if that jmp leads to a jmp dword ptr, only then follow it,
@ -87,7 +101,7 @@ intptr_t Addresser::followThunkFunction(intptr_t address) {
}
// check if first instruction is a jmp dword ptr [....], i.e. if the func is a thunk
if (*reinterpret_cast<uint8_t*>(address) == 0xFF && *reinterpret_cast<uint8_t*>(address + 1) == 0x25) {
if (address && *reinterpret_cast<uint8_t*>(address) == 0xFF && *reinterpret_cast<uint8_t*>(address + 1) == 0x25) {
// read where the jmp reads from
address = *reinterpret_cast<uint32_t*>(address + 2);
// that then contains the actual address of the func
@ -95,7 +109,7 @@ intptr_t Addresser::followThunkFunction(intptr_t address) {
}
// if it starts with mov eax,..., it's a delay loaded func
if (*reinterpret_cast<uint8_t*>(address) == 0xB8) {
if (address && *reinterpret_cast<uint8_t*>(address) == 0xB8) {
// follow the jmp to the tailMerge func and grab the ImgDelayDescr pointer from there
// do it this way instead of grabbing it from the NT header ourselves because
// we don't know the dll name
@ -110,6 +124,11 @@ intptr_t Addresser::followThunkFunction(intptr_t address) {
// get the address of the function, loading the library if needed
address = reinterpret_cast<intptr_t>(__delayLoadHelper2(idd, imp));
// if the helper failed, it will return -1, so we can handle it here
if (address == -1) {
address = 0;
}
}
#endif
#ifdef GEODE_IS_WINDOWS64
@ -124,7 +143,7 @@ intptr_t Addresser::followThunkFunction(intptr_t address) {
// check if first instruction is a jmp qword ptr [rip + ...], i.e. if the func is a thunk
// FF 25 xxxxxxxx
if (checkByteSequence(address, {0xFF, 0x25})) {
if (address && checkByteSequence(address, {0xFF, 0x25})) {
const auto offset = *reinterpret_cast<int32_t*>(address + 2);
// rip is at address + 6 (size of the instruction)
address = *reinterpret_cast<uintptr_t*>(address + 6 + offset);
@ -132,7 +151,7 @@ intptr_t Addresser::followThunkFunction(intptr_t address) {
// if it starts with lea eax,..., it's a delay loaded func
// 48 8D 05 xxxxxxxx
if (checkByteSequence(address, {0x48, 0x8d, 0x05})) {
if (address && checkByteSequence(address, {0x48, 0x8d, 0x05})) {
// follow the jmp to the tailMerge func and grab the ImgDelayDescr pointer from there
// do it this way instead of grabbing it from the NT header ourselves because
// we don't know the dll name
@ -140,17 +159,22 @@ intptr_t Addresser::followThunkFunction(intptr_t address) {
auto jmpOffset = *reinterpret_cast<int32_t*>(address + 7 + 1);
auto tailMergeAddr = address + 7 + jmpOffset + 5;
// this is quite a scary offset, but let's hope it works
auto leaAddr = tailMergeAddr + 51;
// make sure leaAddr is pointing to a lea rcx, [rip + ...]
if (checkByteSequence(leaAddr, {0x48, 0x8d, 0x0d})) {
auto offset = *reinterpret_cast<int32_t*>(leaAddr + 3);
auto did = reinterpret_cast<PCImgDelayDescr>(leaAddr + 7 + offset);
address = reinterpret_cast<intptr_t>(__delayLoadHelper2(did, reinterpret_cast<FARPROC*>(leaAddress)));
if (address == -1) {
address = 0;
}
}
}
// if theres a jmp at the start
if (*reinterpret_cast<uint8_t*>(address) == 0xE9) {
if (address && *reinterpret_cast<uint8_t*>(address) == 0xE9) {
auto relative = *reinterpret_cast<uint32_t*>(address + 1);
auto newAddress = address + relative + 5;
address = newAddress;