All are pretty self explanatory, if further documentation is needed on them, please post a request for it.
The only struct in this class is used in all the public methods. This struct holds information about the breakpoint. It should not be altered after a breakpoint is set, or before it is restored. The struct is defined like so:
[highlight=cpp]struct Breakpoint
{
unsigned long ulTgtAddress;
char bStolenByte;
HANDLE hThread;
unsigned short bBpClass;
unsigned short bBpType;
unsigned short bDebugRegister;
char bBpSize;
};[/highlight]
ulTargetAddress: Address where the breakpoint will be set.
bStolenByte: This member is not used in hardware breakpoints, however it is used in an INT3 breakpoint. An INT3 breakpoint is a memory breakpoint, and therefore it requires a single byte to represent it's instruction to the processor. However, when you set an INT3 breakpoint, the it will replace the first byte located a the target address with 0xCC(INT3), and store the replaced byte in bStolenByte. When the processor hits this newly written instruction, windows will throw an exception(Read managing the exceptions section) in your program. This exception should be handled by a) restoring the breakpoint, b) pushing EIP back one byte, c) fill in the blank, and then continue execution. This will cause the processor to reprocess the byte, but because you restored the breakpoint, it will be the stolen byte it reprocesses. If you wish, you may reset the breakpoint afterwords.
hThread: Handle to the thread the Breakpoint will be set inside of.
bBpClass: Corresponds to one of the members of the Breakpoin***ass enumerator.
bBpType: Corresponds to one of the members of the BreakpointType enumerator.
bDebugRegister : Corresponds to one of the members of the DebugRegisterIndex enumerator.
bBpSize: Specifies size of the breakpoint. Can be set to one of the following:
[highlight=cpp]
const char CHWBP_BP_SIZE_1B = 0x00;
const char CHWBP_BP_SIZE_2B = 0x01;
const char CHWBP_BP_SIZE_DWORD = 0x02;
const char CHWBP_BP_SIZE_WORD = 0x03;
[/highlight]
The class has three public methods I will explain here. If you have a hard time understanding a portion here, continue reading, it should be answered, otherwise, post your question in this thread.
[highlight=cpp] static int SetBp(Breakpoint* bpInfo);
static int RestoreBp(Breakpoint* bpInfo);
static int RestoreHwBpContext(Breakpoint* bpInfo, CONTEXT& context_inOut);[/highlight]
SetBp(Breakpoint* bpInfo)-The first parameter of this method takes a pointer to a Breakpoint structure, which was descriped in a the Class Structs segmet of this tutorial. Required members for the breakpoint class must be filled, excluding bStolenByte. hThread can be set to 0(the current thread) or otherwise to sepcifie a different thread. This method decides if it should call SetHardwareBreakpoint or SetINT3Breakpoint Return 1 = success, -1 = Fail.
RestoreBp(Breakpoint* bpInfo)-The first parameter of this method takes a pointer to a Breakpoint structure, which was descriped in a the Class Structs segmet of this tutorial. This will, in the case of a hwbp, remove the bp from the debug registers. In the case of an INT3 bp, it will restore the stolen byte. Return 1 = success, -1 = Fail.
RestoreHwBpContext(Breakpoint* bpInfo, CONTEXT& context_inOut)-The first parameter of this method takes a pointer to a Breakpoint structure, which was descriped in a the Class Structs segmet of this tutorial. The second is a context struct. RestoreHwBpContext will modify the param passed in through context_inOut param, removing the hardware breakpoint from the passed in context struct. This is helpful when removing HWBPs in a Exception handler. More explanation is in the Managing Exceptions segment of this tutorial.
Return 1 = success, -1 = Fail.
Class Private Methods
Here I will describe the private members of the class. Please note none of these methods are intended to be used directly by the user.
[highlight=cpp] static int FetchDebugIndex(Breakpoint* bpInfo);
static char GetByteTypeById(int id);
static int SetHardwareBreakpoint(Breakpoint* bpInfo);
static int SetINT3Breakpoint(Breakpoint* bpInfo);
static int RestoreHardwareBreakpoint(Breakpoint* bpInfo);
static int RestoreINT3Breakpoint(Breakpoint* bpInfo);[/highlight]
FetchDebugIndex(Breakpoint* bpInfo)-Returns which debug register is being used by the passed in Breakpoint struct. If it returns -1, it means the index exceeded 4, was below 0, or the passed struct is not a hardware breakpoint. Otherwise it will return 1.
char GetByteTypeById(int id)-The first param can be either of the units in the BreakPointType enumerator. It will return the corresponding byte-code for them.
SetHardwareBreakpoint(Breakpoint* bpInfo)-Sets a Hardware breakpoint corresponding with the passed in information in param 1. This should not be called directly, look at the public member SetBp. Return 1 = success, -1 = Fail.
SetINT3Breakpoint(Breakpoint* bpInfo)-Sets a memory breakpoint corresponding with the passed in information in param 1, and stores the byte it replaces to place an INT3 bp. This should not be called directly, look at the public member SetBp. Return 1 = success, -1 = Fail.
RestoreHardwareBreakpoint(Breakpoint* bpInfo)
-The first parameter of this method takes a pointer to a Breakpoint structure, which was descriped in a the Class Structs segmet of this tutorial. RestoreHwBpContext will modify the CONTEXT struct for the thread bpInfo is assigned to, removing the hardware breakpoint. This should not be called directly, look at the public member RestoreBp. Return 1 = success, -1 = Fail.
RestoreINT3Breakpoint(Breakpoint* bpInfo)-It replaces the byte at ulTgtAddress with the byte it has stolen when it was set(the byte stored in bStolenByte member of the Breakpoint struct). This should not be called directly, look at the public member RestoreBp. Return 1 = success, -1 = Fail.
Some characters may be hidden or removed by php tags. Reffer to actual copy of source provided in download for use.
[highlight=cpp]/* /-------------------------------------------------\
* |Programmed By : Jetamay/Andrew |
* \-------------------------------------------------/
* Notice: Don't redistribute without giving credit, or use in applications that must
* be payed for, unless permission has been given by me directly.
*
* For information on how to use this class, please read the post on *********.com
*
*
* |===========================
* |Enjoy the rest of the day,|
* |=======

Jetamay/Andrew |==
* |==============

*/
#pragma once
#ifndef PC32BIT
#error You must be using a 32bit PC to use this class. If you are, define PC32BIT before including this header.
#endif
#ifndef _WIN32_WINNT
#error _WIN32_WINNT not defined.
#else
#if _WIN32_WINNT < 0x0500
#error _WIN32_WINNT has been defined by the user, but to an unexpected value. Please assure it's defined above 0x0500
#endif
#endif
#include <windows.h>
//BYTE INDEX
#define CHWBP_BYTE_INDEX_DR_BPFLAGS 0
#define CHWBP_BYTE_INDEX_DR_BPTYPE_SIZE 16
//BP Type
const char CHWBP_BP_LOCAL = 0x01;
const char CHWBP_BP_GLOBAL = 0x02;
//BP Break type
const char CHWBP_BP_TYPE_EXECUTION = 0x00;
const char CHWBP_BP_TYPE_WRITE = 0x01;
const char CHWBP_BP_TYPE_RESERVED = 0x02;
const char CHWBP_BP_TYPE_READ_WRITE = 0x03;
//Size of BP
const char CHWBP_BP_SIZE_1B = 0x00;
const char CHWBP_BP_SIZE_2B = 0x01;
const char CHWBP_BP_SIZE_DWORD = 0x02;
const char CHWBP_BP_SIZE_WORD = 0x03;
enum BreakPointType
{
BpType_Execution = 0,
BpType_Write = 1,
BpType_Read_Write = 2,
BpType_Reserved = 3,
};
enum Breakpoin***ass
{
HardwareBreakpoint = 1,
INT3Breakpoint = 2,
};
enum DebugRegisterIndex
{
DbgReg0 = 0,
DbgReg1 = 1,
DbgReg2 = 2,
DbgReg3 = 3,
};
struct Breakpoint
{
unsigned long ulTgtAddress;
char bStolenByte;
HANDLE hThread;
unsigned short bBpClass;
unsigned short bBpType;
unsigned short bDebugRegister;
char bBpSize;
};
class cBreakpoint
{
private:
static int FetchDebugIndex(Breakpoint* bpInfo);
static char GetByteTypeById(int id);
static int SetHardwareBreakpoint(Breakpoint* bpInfo);
static int SetINT3Breakpoint(Breakpoint* bpInfo);
static int RestoreHardwareBreakpoint(Breakpoint* bpInfo);
static int RestoreINT3Breakpoint(Breakpoint* bpInfo);
public:
static int SetBp(Breakpoint* bpInfo);
static int RestoreBp(Breakpoint* bpInfo);
static int RestoreHwBpContext(Breakpoint* bpInfo, CONTEXT& context_inOut);
};[/highlight]
Managing Exceptions
When a breakpoint is hit, an exception is throw, if this exception is not handled, your program will crash with an 'unhandled exception error'. There are various methods to implement an exception handler, for this tutorial I have chosen to use Vectored Exception Handlers. A vectored exception handler is a method that is called upon when an exception occurs, as long as the one before it has passed the exception. The way Vectored Exception Handling works, is like so(pesudo code)
[highlight=cpp]void ExceptionHandler(ExceptionInfo)
{
if(ExceptionInfo->ExceptionErrorCode == Exception_DevisionByZero)
{
MessageBox "I JUST HANDLED THE EXCEPTION"
ManageDevisionByZeroException();
return Excpetion_resume_exectution;
} else {
return Exception_pass_to_next_exception_handler;
}
}
void main
{
PushExceptionHandler(topOfVector, ExceptionHandler);
int i = 0 \ 0;
return;
}
[/highlight]When a devision by 0 occurs, ExceptionHandler will be called, if it can solve the problem, it will continue exection of the thread which threw the exception, otherwise, it will pass it to the exception handler after it. If there is no exception handler after it, you program crashes with an unhandled exception error. I assume you already have a fairly solid understanding of vectored exception handlers(as it was one of the prerequests) so I won't go into much detail.
When an breakpoint is hit, one of the following exceptions will be thrown : EXCEPTION_SINGLE_STEP or EXCEPTION_BREAKPOINT.
Also note, when you're disabling a hardware breakpoint in a exception handler, modify the passed ExceptionInfo->ContextRecord using
cBreakpoint::RestoreHwBpContext to remove it, never call
cBreakpoint::RestoreBp in an exception handler, because the exception handler will just reset the thread's context to ExceptionInfo->ContextRecord, when it has completed. As
cBreakpoint::RestoreBp uses SetThreadContext.
Source Code
Look at attachments
Additional Notes:
Be 100% sure you read the notes above before using this class. Also, I haven't had time go over and fix grammar mistakes I may have made in this thread.
I'm no good at writing understandable or clear tutorials, so forgive me if this one is a bit hard to follow.