Yep, another hook post. You read that right. This one is cool, though. I promise.
Before You Read
It is recommended to read these related posts before reading this one, so that you don’t get lost during the discussion of the concepts:
What
You should (hopefully) be familiar with the common function hook types, but this one is a bit fancy as, rather than performing a basic E9 jump detour at the start of the function’s prologue, you have the calling function call your function, rather than have the hooked function jump into your code.
That was a mouthful, but allow me to create an appealing visual representation of what is happening.
Thank you, Canva.
As you can see, you are operating at one step above a function call chain. You are “emplacing” your function into the position of the original function. I call them emplacement hooks, but there might be another name for them as I can’t find anything online about them.
Why
Why would you ever want (or need) to do this? I can think of a few situations.
Signature failure
If you are trying to create a signature for a function but run out of bytes trying to create a unique one, you might be able to deploy an emplacement hook.
By exploring Xrefs to the function you want to hook, you could either calculate the function’s address from the Xref and perform a trampoline hook on it, or you could stick your own function where the original function is from within the Xref’s frame.
Here’s a function. It’s quite small, but let’s at least try to make a signature from it.
I run one of my scripts, and-
Sadly, there is another function (or functions) that have the exact same byte sequence, barring wildcards.
So, all we need to do is find an Xref (which is main() in this case), generate a signature from it, and then emplace our own function where it’s called.
Logical hook
A case when you only want to hook within a certain function call sequence. Let’s say there are 6 functions that call a function you want to hook. Only one of them runs the logic you want before reaching the function you want to hook.
In massively complex programs with huge structures with lots of fields, it could be difficult to “logic” your way into a proper hook environment. An emplacement hook here may be more effective, as you know your hook will only be called when you want it to.
Anti-anti-tamper
This actually happened to me when dealing with a custom anti-tamper solution. Certain functions had “integrity checks”, i.e. they had a checksum for the function and crashed the program if the checksum changed (any bytes in the function were changed, like in a trampoline hook). These functions contained very important and integral code that communicated with a C2 server for commands. A hilarious and simple method of bypassing those integrity checks was to perform an emplacement hook and then call the original function with modified parameters and structure fields. This was much more feasible than trying to manipulate the anti-tamper integrity feature.
Emplacement hooks are only really feasible in x86. Because, a relative call instruction can only call a region within 2 gigabytes of the instruction location.
Think about it for a second, here is an example relative function call in x86/64.
E8 C5 FF FF FF call sub_401250
This was briefly touched on in the Signatures post. Similar to a relative JMP, a relative CALL takes the 4 byte address (C5 FF FF FF) and adds it by the current instruction pointer (ESP/RSP). If the address of that instruction is 0x00401281, and you add it by FFFFFFC5 (remember little endian), which is -59, you reach 0x0040124B. BUT, don’t forget to add the instruction length, which is 5. Therefore, the address of sub_401250 is 0x00401250. Wow, what a convenient name, thanks IDA.
Too many words in that previous paragraph. Let’s simplify it into pseudocode.
func_addr = (curr_addr+5) + *(DWORD *)(curr_addr+1)
Now that that’s explained, I can finally explain why doing this in x64 would be a matter of luck.
Relative call instructions cannot exceed 2 gigabytes in either direction of the current address. If you have an instruction at address 0x7FF780000000, you cannot perform a relative call to any function < 0x7FF700000000 or > 0x7FF87FFFFFFF. The only way to reach functions beyond that range is to MOV the address into a register and then CALL the register (like in a virtual function!). x86 programs are limited to 2 gigabytes in size (because x86 = x32, which is 32 bits/4 bytes and the highest value of a 4 byte integer is 2.147 billion AKA 2 gigabytes). x64 programs can be much larger, so you aren’t guaranteed to have your DLL hook function within 2 gigabytes!
The only way to perform an emplacement hook is to scan for a free page within 2 gigabytes of the address and allocate within it. Then, perform a mid-function hook that jumps into that page, emit the assembly code that was used for the midfunc hook, finally, replace the call instruction with a register call like mentioned in the previous paragraph.
That sounds tedious and would make for a great post topic, but I think you all might be sick of function hooks. If you think there are too many ways to hook functions, just wait until you hear about how many methods there are to inject into a program.
How
That was a very long “why” section, but now we can finally move on to “how”.
The “how” is very straightforward. You just replace the relative function address with our own. You should also keep the original function address so that you can call it if need be.
Methodology
Find a function you want to hook
Utilize an emplacement hook within the target function’s Xref
Execute some code
Call the original function
Requirements
A disassembler
Microsoft Visual Studio
Grab the .zip named “emplaced.zip” under the programs folder on my Tor site, and I shall explain. You don’t really need an example, but why not.
If you run emplaced.exe, it doesn’t do much (this post took too long to write for me to do anything fun/fancy).
You press enter and it prints out some stuff at you. Let’s try to hook the function that prints.
Open the .exe up in IDA and take a look.
The first 2 called functions are std library functions, so let’s check out the last one, sub_401140.
It calls another function.
Which does this:
Clearly the last function is what does the printing. We can try to hook it via a signature, but there’s a problem.
This function doesn’t have a unique signature.
Neither does its Xref.
The only remaining Xref is main(), but hooking main isn’t exactly the easiest thing to do. We will have to deploy an emplacement hook.
(Pretend that we can’t just use file offsets).
Fortunately, there is a pause in the main program which can allow an injection and hook to be created before the remainder of the program executes.
Firstly, you need to generate a signature for the main() function, which is:
\x55\x8B\xEC\x68\x00\x00\x00\x00\x68\x00\x00\x00\x00\xE8\x00\x00\x00\x00
And its mask:
xxxx????x????x????
You will also need a function to sigscan the address range. Here’s one you can use:
DWORD sigscan(DWORD start, DWORD end, const char *sig, size_t siglen, const char *mask)
{
for (DWORD i = start; i < end; i++)
{
bool found = true;
for (size_t j = 0; j < siglen; j++)
{
if (mask[j] == 'x' && *(char *)(i + j) != sig[j])
{
found = false;
break;
}
}
if (found)
return i;
}
return 0;
}
When you scan for main()’s signature, you will end up inside of the start of the main subroutine. But, you need to be at the location of CALL sub_401140. You will have to add the bytes it takes to get from the start of the subroutine (4010D0), to reach the instruction location (40116A). It’s 26 (0x1A), to save you from having to do math.
Let’s set up our DLL.
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
if (fdwReason != DLL_PROCESS_ATTACH)
return TRUE;
DisableThreadLibraryCalls(hinstDLL);
CreateThread(0, 0, [](LPVOID param) -> DWORD
{
// Get base address of module
DWORD base = (DWORD)GetModuleHandle(0);
// Get end address of module
DWORD end = base + ((PIMAGE_NT_HEADERS)(base + ((PIMAGE_DOS_HEADER)base)->e_lfanew))->OptionalHeader.SizeOfImage;
DWORD addr = sigscan(base, end, "\x55\x8B\xEC\x68\x00\x00\x00\x00\x68\x00\x00\x00\x00\xE8\x00\x00\x00\x00", 19, "xxxx????x????x????");
addr += 0x1A;
// Emplace hook here
return TRUE;
},
0, 0, 0);
return TRUE;
}
addr
points to the instruction we want to emplace our hook on. Now, we need to calculate relative offsets to both 1: save the original function, and 2: emplace our function’s relative address onto the CALL instruction.
Firstly, we need to set up our hook function. Note that it has to have the same type declaration as the original function, which fortunately is just void().
We’ll make things easy with a using
statement.
using tHookType = void (*)();
tHookType g_originalFunction{};
void hkHookFunction()
{
AttachConsole(ATTACH_PARENT_PROCESS);
std::cout << "Hooked!" << std::endl;
g_originalFunction();
}
I didn’t realize this was a thing, but you can attach to a parent process’ console with AttachConsole()
:). You can also call the original function, although this isn’t required. You could prevent its execution entirely if you wanted.
Don’t forget to set the proper protections.
DWORD oldprotect;
VirtualProtect((void*)(addr+1), 4, PAGE_EXECUTE_READWRITE, &oldprotect);
Next 2 lines are a bit complex, but I’ll break them each down.
g_originalFunction = (tHookType)(addr + *(DWORD *)(addr + 1) + 5);
The original function’s address is the address of the instruction plus the relative offset of the function (dereferenced at +1 because the address is the 4 bytes after the E8 CALL instruction) plus 5 because the instruction is 5 bytes long.
That is a mouthful, but this is the same arithmetic as mentioned earlier under the Why section.
Next line:
*(DWORD *)(addr + 1) = (DWORD)hkHookFunction - addr + 5;
You are emplacing the relative address of the hook function onto where the original function was. Remember to add +1 to the instruction address because it goes after the E8 CALL instruction. Secondly, you are taking the address of the hook function and subtracting it by the instruction address, rather than adding. Finally, add 5 (the length of the instruction) to reach the correct address.
Your DLLMain function will look like this.
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
if (fdwReason != DLL_PROCESS_ATTACH)
return TRUE;
DisableThreadLibraryCalls(hinstDLL);
CreateThread(0, 0, [](LPVOID param) -> DWORD
{
// Get base address of module
DWORD base = (DWORD)GetModuleHandle(0);
// Get end address of module
DWORD end = base + ((PIMAGE_NT_HEADERS)(base + ((PIMAGE_DOS_HEADER)base)->e_lfanew))->OptionalHeader.SizeOfImage;
DWORD addr = sigscan(base, end, "\x55\x8B\xEC\x68\x00\x00\x00\x00\x68\x00\x00\x00\x00\xE8\x00\x00\x00\x00", 19, "xxxx????x????x????");
addr += 0x1A;
DWORD oldprotect;
VirtualProtect((void*)(addr+1), 4, PAGE_EXECUTE_READWRITE, &oldprotect);
g_originalFunction = (tHookType)(addr + *(DWORD *)(addr + 1) + 5);
*(DWORD *)(addr + 1) = (DWORD)hkHookFunction - addr + 5;
return TRUE;
},
0, 0, 0);
return TRUE;
}
All that is left is to run emplaced.exe and inject!
Tada! You have implemented a very overkill hook method. Pretty cool and difficult to detect!
This post is very, very large. Almost ran out of email space. So, if you made it to the end, thanks for reading! Have a wonderful weekend.
Go!
-BowTiedCrawfish