Of course, every debugging is exception driven. At least because a breakpoint generates debug exception wich is passed to debugger. In this article, however, I will refer to regular exceptions.
There are tens if not hundreds of software protectors used by software vendors around the globe. Some are good, some are less good, in either case, vendors rarely use them in a proper way, thinking that simply enabling anti-debugging features, provided by protector of their choice, is enough. I have seen it myself - a widely known commercial application, protected using Themida (which is one of the most complicated protectors) remains SOOO unprotected, that Themida is not even notices during the extraction of relatively sensitive information using the application itself.
However, the purpose of this article is not to discuss pros and cons of Themida or any other protector, nor do I have any intention to disgrace any of the software vendors. The purpose is to describe a relatively easy way of bypassing common anti debugging tricks (including Windows DRM protection) with DLL injection.
As the term "anti debugging" states - such methods target modern debuggers. There are several commonly known tricks:
- IsDebuggerPresent() - you would be surprised to know how many vendors rely on this API alone;
- Additional methods of debugger presence detection;
- IAT modification - which is not really worth trying;
- Redirection of debugging API (e.g. to an infinite loop).
- And some more.
Point #4 does not let you to implement your own debugger in a hope that it would not be noticed by the victim program (many beginners fall out at this point).
Point #3 - how much can you modify the IAT? I mean, system loader has to still be able to parse it, thus, if system loader can - everyone can.
Point #1 is not even worth further mentioning here.
In this article I am going to describe a simple way (although, some may cry and say it is a hard way) to get around most of anti debugging tricks without even noticing their presence by implementing a simple pseudo debugger dll, which is to be injected into the target process.
Step #1. Preparations
In order to use any debugger, you have to know where to set your breakpoints. Otherwise, the whole process is meaningless. But how can you define proper locations if the executable on disc is encrypted (e.g. with Themida) and you still cannot attach a debugger to see what is going on inside?
The solution is quite simple. Simple in deed. Windows provides us with all the instruments to read the memory of another process (given that you have sufficient access rights) with OpenProcess(), ReadProcessMemory() and NtQueryInformationProcess() API functions. Using those, you can simply dump the decrypted executable and any of its modules (DLLs) to a separate file on disc.
NtQueryInformationProcess() provides you with the address of the PEB (see this post for more information on PEB) of the target process. Then you simply parse the linked list of loaded modules, get the base address (module handle) and the image size for each, then use ReadProcessMemory to copy the image to a file. One complication, though, you will have to use ReadProcessMemory in order to access the PEB of the remote process.
Once you have dumped the target image to a file, such file can be easily loaded into IDA Pro, disassembled and researched statically.
Step #2. Injector and DLL
I do not see any reason to describe the DLL injection process here, as it has been described many times, even in this blog. You are free to use standard injection method, advanced DLL injection method or use this method if you have problems with the two previously mentioned.
It is suggested not to perform any heavy action in this function, however, we do not really have a choice (although, you can launch a separate thread). First thing to do is to suspend all running threads (except the current one of course). The problem is that Windows has no API function that would allow you to enumerate threads of a single process, instead, it lets you go through all the threads in the system. See MSDN pages for Thread32First and Thread32Next - there should be a perfect example of getting threads of the current process. Once all the threads are suspended, you are ready to proceed.
Installation of breakpoints
No, we are not going to use regular 0xCC software breakpoints, neither are we going to make any use of hardware breakpoints here. Instead, we are going to place an instruction that would raise an exception to the location of desired breakpoint. To keep such instruction short and to avoid changing the values of the registers, 'AAM 0' seems to be a perfect candidate. It only takes two bytes 0xD4 0x00 and raises the EXCEPTION_INT_DIVIDE_BY_ZERO exception (exception code 0xC0000094).
Use the VirtualProtect() function to change the access rights of the target address, so you can alter its content, backup the original two bytes from that address and overwrite them with 0x00D4.
VirtualProtect((LPVOID)(target & ~0xFFF), 0x1000, PAGE_EXECUTE_READWRITE, (PDWORD)&prevProtect);
*((unsigned short*)target) = 0x00D4;
VirtualProtect((LPVOID)(target & ~0xFFF), 0x1000, prevProtect, (PDWORD)&prevProtect);
Now the victim process is almost ready to be continued. One thing left - exception handler. We will use vectored exception handling mechanism as it allows our handler to be (at least among) the first to handle an exception. Once the handler has been added with AddVectoredExceptionHandler(), you may resume the suspended threads of the process.
One important thing to do once your handler gets control, is to check for the address where the exception occurred and for the exception code, as we have no intention to deal with irrelevant exceptions:
LONG CALLBACK handler(PEXCEPTION_POINTERS ep)
if(ep->ContextRecord->Eip == target && ep->ExceptionRecord->ExceptionCode == 0xC0000094)
// Do your stuff here
// Optionally log other exceptions
One of the parameters you get with your handler is the pointer to the CONTEXT structure, which provides you with the content of all the registers at the time of the exception. Needless to mention, that you have the access to the process' memory as well. Just as you were in a debugger with the only difference - you have to implement the routine that would show you the data you are interested in. Do not forget to emulate the original instruction replaced by the pseudo breakpoint and advance the Eip accordingly before returning from handler.
One more thing to mention - it may be a good idea to suspend all other threads of the victim process while in the 'your stuff' portion of the handler.
I am not claiming this method to be bullet proof and I am more than sure ( I simply know) - there are ways to defeat it, however, personally, I have not yet met such software. In addition - this method is tested and stable.
Hope this article was helpful. See you at the next.
P.S. Lazy guys, nerds, etc., do not cry for sources. This method is really simple. Besides, if copy/paste is the only programming technique you are aware of, then, probably, this blog is not the right place for you.