Professional Documents
Culture Documents
© 2005 mcMike
Many Thanks to bf194Lover from MPC for showing the path ;)
This tutorial will teach how to use StructuredExceptionHandling and Detours-library for writing
hacks. The hack will be built as a DLL-file and injected into target-process. From there it will add
new UnhandledExceptionFilter and set hardware-breakpoint to branch target-code execution to
our own function.
The Example
As a learning target we use the most hardest , unbreakable, anti-hack-cabable Windows Notepad.
We will render useless it’s feared ability to display About-dialog with single hardware-breakpoint.
Below you see that in the address 0x0100334f the code will set some variables and call
ShellAboutW(). We set breakpoint to that address and make it jump 0x18 bytes forward to skip
that block all together. (similar to many common hacks where you would just NOP some lines).
We don’t actually patch the JMP instruction but set hardware-breakpoint and skip 0x18 bytes by
moving EIP (instruction pointer) forward. The effect is same than with jmp or simply NOPping
those lines.
Page 1 of 10
SimpleSEH © 2005 mcMike
The Background
SEH
SEH stands for Structured Exception Handling. You can think it as Visualbasic’s ON ERROR -
GOTO method of handling runtime errors. There are several types of exceptions from floating-
point errors like division by zero to Access Violation etc. These exceptions also include
breakpoint-exceptions which are set by purpose.
DEBUG-Registers
DEBUG-registers are physical registers inside processor (huh. really?) which provides several
helpful methods to debug programs at runtime. One of these methods is hardware-breakpoints.
See; software breakpoints (int3) are just a single byte written in the target code which will
replace original instruction under it. Because that byte will change the opcode(s) they are easy to
detect by game or external anti-cheat software. Also the debugger needs to handle restoring
those breakpoints at runtime.
Hardware-Breakpoints as name indicates are not written to code but kept in the DEBUG-registers.
There are 4 separate breakpoints available (by chaining you can have more). They are non-
intrusive i.e. do not change the code and therefore are not detected with same methods as
software breakpoints.
To access Debug-registers Windows API provides 2 functions SetThreadContext() and
GetThreadContext(). With first one you set the breakpoints and with latter you can read them.
// Write the values to DEBUG-register. From now on the breakpoints are active
SetThreadContext(GetCurrentThread(), &ctx);
Page 2 of 10
SimpleSEH © 2005 mcMike
Injecting
In order to use SEH and HW-breakpoints we need to write a DLL and get it somehow inside
target-process. There are several methods to do it but here we use tool called winject.exe which
will handle the injecting for us. You can download it from MPC-forums.
Just select “Target Process” and “DLL to Inject” and click Inject –button. The injection is
automaticly verified. After you have injected the DLL you can also manually check that it indeed
is present in target process loaded modules. To do this just click […] –button in the rightside of
Target Process-combo. This will open Process Information –dialog to display some information
about selected process. From Loaded Modules-list you can see that the DLL we injected is loaded
by target.
TIP: With Winject you can also Eject the loaded modules. This is very useful since you don’t have
to terminate or close the target process before reinjecting. (For example while you are
developing new DLL you can have winject running with process and DLL selected. Once you build
new version just click inject and it’s ready to test).
All the magic (the hack) happens inside DLL and the launcher can be closed right after the
injecting is done.
Injecting Theory
Injecting a DLL means that the injector will allocate memory with VirtualAllocEx() inside target-
process for code and data-blocks. Then the function (code) and the data (name of the library to
be loaded) is written to those memory-areas with WriteProcessMemory(). Finally new thread is
started with CreateRemoteThread() and passing the pointer to written function and data.
Fortunately you can skip all this by using winjector but you need to understand the threading
model of it; This new thread will call LoadLibrary() and load our DLL into target-process. The OS-
loader will call our DLLmain() -function after it is loaded. From there our DLL will do some simple
initializing – but only simple. There are only very limited things we can do in DLLmain() for more
information read “DllMain : a horror story” from
http://blogs.msdn.com/oleglv/archive/2003/12/12/43069.aspx
Page 3 of 10
SimpleSEH © 2005 mcMike
Activating SEH
To activate exception handling we just add our new handler (function) to SEH-chain. This is done
with SetUnhandledExceptionFilter(fnName) API-function. The fnName is name of the function that
we provide.
Very simple but unfortunately we can’t simply do this in DLLMain() because we are doing the
injecting with CreateRemoteThread() –method.
Exception handling is per thread basis so we can’t add our new handler from DLLmain().
Remember it is called by OS-loader which is just a function that LoadLibrary() calls. AND we have
initiated Loadlibrary call from separate thread we created. So if we would add SEH from DLLmain
it would handle only exceptions for that thread – not the target process. That would not be very
useful. Also the loader thread is terminated right after the DLL is loaded.
So obviously we need to think something else. We need to force the target process to call a
function in our DLL in order to activate SEH from there. This is where we come to Api-hooking.
Page 4 of 10
SimpleSEH © 2005 mcMike
API-Hooking
So in order to get target-process to call our function let’s pick GetTickCount() –API to hijack and
set our exception handler from there. We only need this “callback” once and after the SEH is set
we instantly remove the hijacking since it is no longer needed. We also hijack
GetThreadContext() to hide our altering of debug-registers (because we know that notepad is
active little devil to check itself for hacks ☺ ). The actual hooking we do with detours-library…
Detours
Detours is a library (detours.lib & detours.h) from Microsoft which provides easy and simple way
to hook (hijack) Windows API-functions. It contains lots of useful functions but here we
concentrate only couple of them. DetourFunction() is used when you simply want to Hijack some
API-function with your own Detour-function. This new function will provide the same functionality
than original did (+ maybe some other “useful” features ☺ ). To hijack GetTickCount() we just:
DetourFunction((PBYTE)GetTickCount,(PBYTE)GetTickCount_Detour);
The GetTickCount_Detour() is the function which we write. It needs to be exactly same type than
the original (i.e. return type, arguments and calling convention). After this hooking if and when
target-application (or we) calls GetTickCount() it will actually land to GetTickCount_Detour().
From there we will set the our SEH.
Unfortunately Detours doesn’t provide function to remove hook if there wasn’t trampoline for it
(at least I’m not aware of it). So we will use our own method to remove it. Before hooking we
just read the 5 first bytes of original function’s entrypoint and store them. After the first call to
our detoured function we write those 5 bytes back to remove the hook.
Page 5 of 10
SimpleSEH © 2005 mcMike
DetourFunctionWithTrampoline() is used if you also wish to call original API-function within your
Detour-function. See; You can’t simply call original function directly from your detour-function
since that would lead to infinite recursive-loop. Thus we need Trampoline-function which is used
as a trampoline to original API (hence the name). Detours-library provides simple MACRO to
automaticly build “invisible” trampoline-function so you don’t actually have to write it by yourself.
We just define:
DETOUR_TRAMPOLINE(BOOL WINAPI GetThreadContext_Trampoline(HANDLE ,LPCONTEXT) ,GetThreadContext);
Whoooops…. That’s it !
We have covered how to use SEH , how to get DLL injected, how to set HW-breakpoints and how
to hijack API-functions. Next we will move to ultimate beginners guide for how to setup the
project in VC6++ and write a DLL.
Page 6 of 10
SimpleSEH © 2005 mcMike
1) Create new Project “Win32 Dynamic-Link Library”. Choose name and location for project and
click OK. Next select “An empty DLL project” and click Finish.
4) Add SEH_example.cpp to your project. Right-click over source-files and choose “Add Files to
Folder”. Pick SEH_example.cpp –file.
Page 7 of 10
SimpleSEH © 2005 mcMike
7) Select build target: “Win32 Release” and build the SimpleSEH.dll from build-button or from
Build-menu “Rebuild all”.
You should now see message in the bottom of visual studio that SimpleSEH.dll is build. By default
it will placed in your project-directory\release –subdir.
8) Start winject and select simple_SEH.dll for “DLL to Inject” also start notepad and select it as
“Target Process”. Click Inject-button and you should see following messagebox popping up. This
indicates that our DLL is loaded in target-
process and our DLLmain() –function has
been called.
9) You propably realized by now that our hardware-breakpoints nor SEH-handler were not set
yet. So you can still launch about-menu as usual. This is because Notepad have not called
GetTickCount() yet. To make it happen
just invoke help from help-menu. You
should see the next message box
popping out telling that it finally has set
the breakpoints and SEH-handler. Now
try again the About-box and see that we
have beaten the feared notepad with our
Structured-Exception- Handling-
Hardware-Breakpoint-API-Hooking-hack.
☺
Page 8 of 10
SimpleSEH © 2005 mcMike
The CODE
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include "detours.h"
// Function defines
LONG WINAPI UnhandlerExceptionFilter(struct _EXCEPTION_POINTERS* ExceptionInfo);
DWORD WINAPI GetTickCount_Detour(void);
BOOL WINAPI GetThreadContext_Detour (HANDLE hThread,LPCONTEXT lpContext);
void Set_SEH_and_BreakPoints(void); // Set the SEH and breakpoints
LPTOP_LEVEL_EXCEPTION_FILTER oldHandler=NULL; // Pointer to existing exception handler
// Detour MACRO
DETOUR_TRAMPOLINE(BOOL WINAPI GetThreadContext_Trampoline(HANDLE ,LPCONTEXT) ,GetThreadContext);
// Global variables
DWORD dwBreakPoint=0x100334f; // The hardware-breakpoint (4 available)
int nBreakPointJump=0x18; // How many bytes we make EIP to skip from this breakpoint
BYTE opcodes[5]; // Original opcodes in GetTickCount() entry-point to be stored for restoring
// Return original bytes to GetTickCount() i.e. unhook it. We only need this "callback" once.
WriteProcessMemory(GetCurrentProcess(),(LPVOID)GetProcAddress(
GetModuleHandle("Kernel32"),"GetTickCount"),&opcodes,5,0);
MessageBox(NULL,"HW-breakpoints are set !","SEH_example",0);
Page 9 of 10
SimpleSEH © 2005 mcMike
// Our ExceptionHandler
// study the ExceptionInfo-struct for stuff you need
LONG WINAPI UnhandlerExceptionFilter(struct _EXCEPTION_POINTERS* ExceptionInfo)
{
// HW-breakpoints DON'T generate EXCEPTION_BREAKPOINT but EXCEPTION_SINGLE_STEP so we check for that
if(ExceptionInfo->ExceptionRecord->ExceptionCode==EXCEPTION_SINGLE_STEP )
{
// Verify that the breakpoint was the one we set
if ((DWORD)ExceptionInfo->ExceptionRecord->ExceptionAddress==dwBreakPoint)
{
// move instruction pointer forward to skip unwanted instructions and let
// the process continue as nothing has happened
ExceptionInfo->ContextRecord->Eip+=nBreakPointJump;
return EXCEPTION_CONTINUE_EXECUTION;
}
}
Page 10 of 10