Home > Programming, Reversing, Windows > Custom GetProcAddress Implementation

Custom GetProcAddress Implementation

Had to whip together a custom GetProcAddress due to the problems outlined by Nyaeve in his blog (here). Because its probably useful to others, here it is:

// Custom GetProcAddress implementation. Needed because of Vista

// doing potential IAT hooks and generally messing things up for the

// rest of us. (AcLayers/ShimEngine)

FARPROC Injector::CustomGetProcAddress(HMODULE Module, const std::string& FunctionName)

{

try

{

// Guard from structured exceptions

SehGuard Guard;

// Get pointer to DOS header

PIMAGE_DOS_HEADER pDosHeader = reinterpret_cast<PIMAGE_DOS_HEADER>(Module);

if (!pDosHeader || pDosHeader->e_magic != IMAGE_DOS_SIGNATURE)

throw InjectorException(”Injector: DOS PE header is invalid.”);

// Get pointer to NT header

PIMAGE_NT_HEADERS pNtHeader = reinterpret_cast<PIMAGE_NT_HEADERS>

(reinterpret_cast<PCHAR>(Module) + pDosHeader->e_lfanew);

if (pNtHeader->Signature != IMAGE_NT_SIGNATURE)

throw InjectorException(”Injector: NT PE header is invalid.”);

// Get pointer to image export directory

PVOID pExportDirTemp = reinterpret_cast<PBYTE>(Module) +

pNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;

PIMAGE_EXPORT_DIRECTORY pExportDir =

reinterpret_cast<PIMAGE_EXPORT_DIRECTORY>(pExportDirTemp);

// Get pointer to export names table

PDWORD pNamesRvas = reinterpret_cast<PDWORD>(reinterpret_cast<PBYTE>(Module)

+ pExportDir->AddressOfNames);

// Get pointer to export ordinal table

PWORD pNameOrdinals = reinterpret_cast<PWORD>(reinterpret_cast<PBYTE>(Module)

+ pExportDir->AddressOfNameOrdinals);

// Get pointer to export address table

PDWORD pFunctionAddresses = reinterpret_cast<PDWORD>(reinterpret_cast<PBYTE>(Module)

+ pExportDir->AddressOfFunctions);

// Walk the array of this module’s function names

for (DWORD n = 0; n < pExportDir->NumberOfNames; n++)

{

// Get the function name

PSTR CurrentNameTemp = reinterpret_cast<PSTR>(reinterpret_cast<PBYTE>(Module)

+ pNamesRvas[n]);

// Create string from c-style string

// Note: Throws an access violation if not a valid string

std::string CurrentName(CurrentNameTemp);

// If not the specified function, try the next function

if (CurrentName != FunctionName) continue;

// We found the specified function

// -> Get this function’s Ordinal value

WORD Ordinal = pNameOrdinals[n];

// Get the address of this function’s address

return reinterpret_cast<FARPROC>(reinterpret_cast<PBYTE>(Module)

+ pFunctionAddresses[Ordinal]);

}

}

// Catch custom SEH-proxy exceptions.

catch (const SehException& e)

{

TDBGOUT(e);

}

// Catch Injector exceptions

catch (const InjectorException& e)

{

CDBGOUT(”InjectorException: ” << e.what() << “. File: ” << __FILE__ <<

“Line: ” << __LINE__ << “.”);

}

// Nothing found, return zero

return NULL;

}

Tested and working on Windows Server 2008 x64 on both IA-32 and AMD64 processes.

Credits: Nyaeve (article), Kynox (some of the code), Windows via C/C++ (some of the code)

  1. amadmonk
    May 15th, 2009 at 06:35 | #1

    So, if I’m reading this correctly, this won’t work if they’re doing EAT hooks as well, right?

    Of course, this begs the question: does any system software or AV software do EAT hooking as well as IAT hooking?

  2. May 15th, 2009 at 07:34 | #2

    @amadmonk
    Correct. This is just designed to bypass the ShimEngine stuff. A more comprehensive implementation would do an on-disk check.

    As for the second part, system software doesn’t, but not sure about AV software, I’d have to check.

  1. No trackbacks yet.