For instance, you write a program that calls "WriteFile" inside of "kernel32.dll". Windows loads the image of your application into memory, then searches your program's Import Address Table and finds that you import "WriteFile" from "kernel32.dll". So it loads kernel32.dll into memory and searches it's Export Address Table for "WriteFile". Once it finds "WriteFile", it updates your program's Import Address Table with the location of "WriteFile" in memory.
Now, if someone hooks "WriteFile" in your Import Address Table, when your application calls "WriteFile" it actually calls their function. This is bad, because you don't necessarily want that. So you use this function called "GetProcAddress" to re-look-up the proper address of "WriteFile". When calling GetProcAddress you will specify two variables:
- HMODULE hModule - This is just a fancy name for image base address of the module (kernel32.dll) in memory.
- LPCSTR lpProcName - A pointer to a string containing the name of the function to look for.
Below is an example of what GetProcAddress does:
As you can see it simply walks the Export Address Table of the image at hModule and searches for a function with the same name that was specified with lpProcName.
Now, you wonder why you would want to hook the Export Address Table? Its so that the function pointer returned by GetProcAddress is a pointer to your function. Sure, sure, you can always just hook GetProcAddress and GetModuleHandleA/W in the Import Address Table and filter the results. That is beside the point.
The only drawback to hooking the EAT is that your function has to be AFTER the module who's EAT you are hooking (in memory order) OR you can just put a small JMP to your code in memory somewhere after the module you are hooking. This is because the EAT, unlike the IAT, uses Relative Virtual Addresses (RVAs) to specify function addresses in memory. These RVAs are 32-bit unsigned integers, so you have up to ~4GB of space after the module in memory to place your function or a jump to it. Unless, of course, the creator of the module has set its base address such that it is right up against the upper memory barrier, then it may get tricky. You will have to find somewhere inside the image to place your jump. Luckily most of the time there is plenty of space to cram more stuff into an image that doesn't belong.
I am currently reconsidering adding Export Address Table hooking to Injex. Primarily because I cannot think of an intuitive way for programmers to interface with this functionality as an API. And I already added Code Overwriting, which does perfectly well at getting around people's use of GetProcAddress to bypass IAT based methods of hooking. Advanced methods of code overwriting that involve trampolines just makes EAT seem so noobish and pointless...
As you can see it simply walks the Export Address Table of the image at hModule and searches for a function with the same name that was specified with lpProcName.
Now, you wonder why you would want to hook the Export Address Table? Its so that the function pointer returned by GetProcAddress is a pointer to your function. Sure, sure, you can always just hook GetProcAddress and GetModuleHandleA/W in the Import Address Table and filter the results. That is beside the point.
The only drawback to hooking the EAT is that your function has to be AFTER the module who's EAT you are hooking (in memory order) OR you can just put a small JMP to your code in memory somewhere after the module you are hooking. This is because the EAT, unlike the IAT, uses Relative Virtual Addresses (RVAs) to specify function addresses in memory. These RVAs are 32-bit unsigned integers, so you have up to ~4GB of space after the module in memory to place your function or a jump to it. Unless, of course, the creator of the module has set its base address such that it is right up against the upper memory barrier, then it may get tricky. You will have to find somewhere inside the image to place your jump. Luckily most of the time there is plenty of space to cram more stuff into an image that doesn't belong.
I am currently reconsidering adding Export Address Table hooking to Injex. Primarily because I cannot think of an intuitive way for programmers to interface with this functionality as an API. And I already added Code Overwriting, which does perfectly well at getting around people's use of GetProcAddress to bypass IAT based methods of hooking. Advanced methods of code overwriting that involve trampolines just makes EAT seem so noobish and pointless...
No comments:
Post a Comment