I'm writing a small tool that should be able to inspect an arbitrary process of interest and check if any of its statically linked functions were trampolined. (An example of a trampoline could be what Microsoft Detours does to a process.)
For that I parse the PE header of the target process and retrieve all of its imported DLLs with all imported functions in them. Then I can compare the following between DLLs on disk and the DLLs loaded in the target process memory:
A. Entries in the Import Address Table
for each imported function.
B. First N bytes of each function's machine code.
And if any of the above do not match, this will most certainly mean that a trampoline
was applied to a particular function (or WinAPI.)
This works well, except of one situation when a target process can import a global variable instead of a function. For example _acmdln
is such global variable. You can still find it in msvcrt.dll
and use it as such:
//I'm not sure why you'd want to do it this way,
//but it will give you the current command line.
//So just to prove the concept ...
HMODULE hMod = ::GetModuleHandle(L"msvcrt.dll");
char* pVar = (char*)::GetProcAddress(hMod, "_acmdln");
char* pCmdLine = pVar ? *(char**)pVar : NULL;
So, what this means for my trampoline checking tool is that I need to differentiate between an imported function (WinAPI) and a global variable. Any idea how?
PS. If I don't do that, my algorithm that I described above will compare a global variable's "code bytes" as if it was a function, which is just a pointer to a command line that will most certainly be different, and then flag it as a trampolined function.
PS2. Not exactly my code, but a similar way to parse PE header can be found here. (Search for DumpImports
function for extracting DLL imports.)