RoboDBG
Loading...
Searching...
No Matches
debugger.h
Go to the documentation of this file.
1
6
7#ifndef DEBUGGER_H
8#define DEBUGGER_H
9
10#pragma comment(lib, "Advapi32.lib")
11#pragma comment(lib, "ntdll.lib")
12
13#include <windows.h>
14#include <string>
15#include <vector>
16#include <tlhelp32.h>
17#include <iostream>
18#include <iomanip>
19#include <sstream>
20#include <unordered_map>
21#include <tchar.h>
22#include <stdio.h>
23#include <psapi.h>
24#include <map>
25#include <fstream>
26#include <winternl.h>
27#include <intrin.h>
28
29#include "util.h"
30
31namespace RoboDBG {
32
42
52
57 enum class DRReg {
58 NOP = -1,
59 DR0 = 0,
60 DR1 = 1,
61 DR2 = 2,
62 DR3 = 3
63 };
64
69 enum class BreakpointLength {
70 BYTE = 0,
71 WORD = 1,
72 DWORD = 2,
73 QWORD = 3
74 };
75
80 struct thread_t {
81 HANDLE hThread;
83 LPVOID threadBase;
84 LPVOID startAddress;
85 };
86
98
110
111 #ifdef _WIN64
116 enum class Flags64 : DWORD64 {
117 CF = 1ull << 0,
118 PF = 1ull << 2,
119 AF = 1ull << 4,
120 ZF = 1ull << 6,
121 SF = 1ull << 7,
122 TF = 1ull << 8,
123 IF = 1ull << 9,
124 DF = 1ull << 10,
125 OF = 1ull << 11
126 };
127 #else
132 enum class Flags32 : DWORD {
133 CF = 1 << 0,
134 PF = 1 << 2,
135 AF = 1 << 4,
136 ZF = 1 << 6,
137 SF = 1 << 7,
138 TF = 1 << 8,
139 IF = 1 << 9,
140 DF = 1 << 10,
141 OF = 1 << 11
142 };
143 #endif
144
145 #ifdef _WIN64
150 enum class Register64 {
151 RAX, RBX, RCX, RDX, RSI, RDI, RBP, RSP,
152 R8, R9, R10, R11, R12, R13, R14, R15,
153 RIP
154 };
155 #else
160 enum class Register32 {
161 EAX, EBX, ECX, EDX, ESI, EDI, EBP, ESP,
163 };
164 #endif
165
166
173class Debugger {
174private:
175 LPVOID bpAddrToRestore;
176 bool needToRestoreBreakpoint; // TODO: rename to bpNeedToRestore
177 int lastBpType;
178
179 bool restoreHwBP;
180 hwBp_t hwBPToRestore;
181 HANDLE hwBPThreadToRestore;
182
183 bool dbgLoop = true;
184
185 // internal callbacks. Arent used right now / not implemented.
186 void onPreStart();
187 void onPreAttach();
188
189protected:
190 bool verbose;
191 uintptr_t baseAddressOffset = 0; // TODO: Add a base image address, e.g: 0x00400000U
192
193#ifdef __WIN64
194 uintptr_t baseImageBase = 0x0000000140000000ULL;
195#else
196 uintptr_t baseImageBase = 0x00400000U;
197#endif
198 std::map<LPVOID, BYTE> breakpoints;
199 std::map<LPVOID, hwBp_t> hwBreakpoints;
200 std::map<LPVOID, BYTE> dlls;
201 std::vector<thread_t> threads;
202 int debuggedPid;
203 HANDLE hProcessGlobal = nullptr;
204 HANDLE hThreadGlobal = nullptr;
205
206 // ===== Lifecycle & events =====
207
213 virtual void onStart(uintptr_t imageBase, uintptr_t entryPoint);
214
220 virtual void onEnd(DWORD exitCode, DWORD pid);
221
225 virtual void onAttach();
226
234 virtual void onThreadCreate(HANDLE hThread, DWORD threadId, uintptr_t threadBase, uintptr_t startAddress);
235
240 virtual void onThreadExit(DWORD threadID);
241
249 virtual bool onDLLLoad(uintptr_t address, std::string dllName, uintptr_t entryPoint);
250
256 virtual void onDLLUnload(uintptr_t address, std::string dllName);
257
264 virtual BreakpointAction onBreakpoint(uintptr_t address, HANDLE hThread);
265
273 virtual BreakpointAction onHardwareBreakpoint(uintptr_t address, HANDLE hThread, DRReg reg);
274
280 virtual void onSinglestep(uintptr_t address, HANDLE hThread);
281
286 virtual void onDebugString(std::string dbgString);
287
294 virtual void onAccessViolation(uintptr_t address, uintptr_t faultingAddress, long accessType);
295
300 virtual void onRIPError(const RIP_INFO& rip);
301
307 virtual void onUnknownException(uintptr_t addr, DWORD code);
308
313 virtual void onUnknownDebugEvent(DWORD code);
314
315 // ===== Threading =====
316
320 void actualizeThreadList();
321
322 // ===== Breakpoints (low-level) =====
323
328 void setBreakpoint(LPVOID address);
329
335 DRReg isHardwareBreakpointAt(LPVOID address);
336
341 void restoreBreakpoint(LPVOID address);
342
349
356
361 std::vector<hwBp_t> getHardwareBreakpoints();
362
367 void enableSingleStep(HANDLE hThread);
368
373 void decrementIP(HANDLE hThread);
374
381
388 bool clearHardwareBreakpointOnThread(HANDLE hThread, DRReg reg);
389
396
397 // ===== Memory =====
398
406 bool writeMemory(LPVOID address, const void* buffer, SIZE_T size);
407
415 bool readMemory(LPVOID address, void* buffer, SIZE_T size);
416
424 bool changeMemoryProtection(LPVOID baseAddress, SIZE_T regionSize, DWORD newProtect);
425
431 MemoryRegion_t getPageByAddress(LPVOID baseAddress);
432
437 std::vector<MemoryRegion_t> getMemoryPages();
438
445 bool changeMemoryProtection(MemoryRegion_t page, DWORD newProtect);
446
452 std::vector<uintptr_t> searchInMemory(const std::vector<BYTE>& pattern);
453
454 // ===== Misc =====
455
461 uintptr_t ASLR(LPVOID address);
462
468 uintptr_t ASLR(uintptr_t address);
469
474 bool hideDebugger();
475
480 void printIP(HANDLE hThread);
481
482#ifdef _WIN64
489 bool getFlag(HANDLE hThread, Flags64 flag);
490
497 void setFlag(HANDLE hThread, Flags64 flag, bool enabled);
498
505 int64_t getRegister(HANDLE hThread, Register64 reg);
506
513 void setRegister(HANDLE hThread, Register64 reg, int64_t value);
514#else
521 bool getFlag(HANDLE hThread, Flags32 flag);
522
529 void setFlag(HANDLE hThread, Flags32 flag, bool enabled);
530
537 int32_t getRegister(HANDLE hThread, Register32 reg);
538
545 void setRegister(HANDLE hThread, Register32 reg, int32_t value);
546#endif
547
551 void PrintMemoryPages();
552
553 // ===== Wrappers (inline, app-friendly) =====
554
559 inline void setBreakpoint(uintptr_t address) {
560 setBreakpoint(reinterpret_cast<LPVOID>(address));
561 }
562
568 inline DRReg isHardwareBreakpointAt(uintptr_t address) {
569 return isHardwareBreakpointAt(reinterpret_cast<LPVOID>(address));
570 }
571
577 inline MemoryRegion_t getPageByAddress(uintptr_t baseAddress) {
578 return getPageByAddress(reinterpret_cast<LPVOID>(baseAddress));
579 }
580
585 inline void restoreBreakpoint(uintptr_t address) {
586 restoreBreakpoint(reinterpret_cast<LPVOID>(address));
587 }
588
598 inline bool setHardwareBreakpointOnThread(HANDLE hThread, LPVOID address, DRReg reg, AccessType type, BreakpointLength len) {
599 hwBp_t bp = { hThread, address, reg, type, len };
601 }
602
611 inline bool setHardwareBreakpoint(LPVOID address, DRReg reg, AccessType type, BreakpointLength len) {
612 hwBp_t bp = { (HANDLE)nullptr, address, reg, type, len };
613 return setHardwareBreakpoint(bp);
614 }
615
624 inline bool setHardwareBreakpoint(int address, DRReg reg, AccessType type, BreakpointLength len) {
625 hwBp_t bp = { (HANDLE)nullptr, reinterpret_cast<LPVOID>(static_cast<intptr_t>(address)), reg, type, len };
626 return setHardwareBreakpoint(bp);
627 }
628
636 inline bool changeMemoryProtection(uintptr_t baseAddress, SIZE_T regionSize, DWORD newProtect) {
637 return changeMemoryProtection(reinterpret_cast<LPVOID>(baseAddress), regionSize, newProtect);
638 }
639
647 inline bool writeMemory(uintptr_t address, const void* buffer, SIZE_T size) {
648 return writeMemory(reinterpret_cast<LPVOID>(address), buffer, size);
649 }
650
658 inline bool readMemory(uintptr_t address, void* buffer, SIZE_T size) {
659 return readMemory(reinterpret_cast<LPVOID>(address), buffer, size);
660 }
661
669 template<typename T>
670 bool writeMemory(uintptr_t address, const T& value) {
671 SIZE_T bytesWritten = 0;
672 if (!WriteProcessMemory(hProcessGlobal, reinterpret_cast<LPVOID>(address), &value, sizeof(T), &bytesWritten) || bytesWritten != sizeof(T)) {
673 return false;
674 }
675 FlushInstructionCache(hProcessGlobal, reinterpret_cast<LPVOID>(address), sizeof(T));
676 return true;
677 }
678
685 template<typename T>
686 T readMemory(uintptr_t address) {
687 T value{};
688 SIZE_T bytesRead = 0;
689 if (!ReadProcessMemory(hProcessGlobal, reinterpret_cast<LPCVOID>(address), &value, sizeof(T), &bytesRead) || bytesRead != sizeof(T)) {
690 return T{};
691 }
692 return value;
693 }
694
701 inline bool isEqual(LPVOID a, uintptr_t b) {
702 return a == reinterpret_cast<LPCVOID>(b);
703 }
704
709 inline HANDLE getProcessHandle( )
710 {
711 return hProcessGlobal;
712 }
713public:
717 Debugger();
718
723 Debugger(bool verbose);
724
730 int start(std::string exeName);
731
738 int start(std::string exeName, const std::vector<std::string>& args);
739
745 int attach(std::string exeName);
746
751 int detach();
752
757 int loop();
758};
759
760} // namespace RoboDBG
761
762#endif
int start(std::string exeName)
Starts a process under debugging.
Definition debugger.cpp:87
virtual void onAttach()
Called after successfully attaching to an already running process.
DRReg isHardwareBreakpointAt(LPVOID address)
Checks if a hardware breakpoint exists at an address.
bool setHardwareBreakpoint(LPVOID address, DRReg reg, AccessType type, BreakpointLength len)
Sets a hardware breakpoint process-wide (current/future threads as applicable).
Definition debugger.h:611
void enableSingleStep(HANDLE hThread)
Enables trap flag (single-step) for a thread.
Definition debugger.cpp:148
int32_t getRegister(HANDLE hThread, Register32 reg)
Reads a 32-bit general-purpose register.
int loop()
Main debugger message loop.
Definition debugger.cpp:236
bool changeMemoryProtection(uintptr_t baseAddress, SIZE_T regionSize, DWORD newProtect)
Changes memory protection on a region (uintptr_t overload).
Definition debugger.h:636
int attach(std::string exeName)
Attaches to a running process by name.
Definition debugger.cpp:55
HANDLE getProcessHandle()
Returns HANDLE of debugged process.
Definition debugger.h:709
bool hideDebugger()
Attempts to hide the debugger from basic anti-debug checks.
Definition debugger.cpp:14
uintptr_t ASLR(LPVOID address)
Applies the module ASLR slide to an LPVOID.
Definition debugger.cpp:46
bool clearHardwareBreakpoint(DRReg reg)
Clears a DRx slot across threads.
virtual void onAccessViolation(uintptr_t address, uintptr_t faultingAddress, long accessType)
Called on access violation (AV).
virtual void onThreadExit(DWORD threadID)
Called when a thread exits.
void setFlag(HANDLE hThread, Flags32 flag, bool enabled)
Sets or clears a status flag in EFLAGS.
std::vector< hwBp_t > getHardwareBreakpoints()
Enumerates current hardware breakpoints.
bool writeMemory(uintptr_t address, const void *buffer, SIZE_T size)
Writes raw bytes to target memory (uintptr_t overload).
Definition debugger.h:647
virtual void onEnd(DWORD exitCode, DWORD pid)
Called when the debuggee exits.
bool getFlag(HANDLE hThread, Flags32 flag)
Reads a status flag from EFLAGS.
MemoryRegion_t getPageByAddress(LPVOID baseAddress)
Gets information for the page containing an address.
bool isEqual(LPVOID a, uintptr_t b)
Compares an LPVOID to a uintptr_t for equality.
Definition debugger.h:701
bool setHardwareBreakpointOnThread(hwBp_t bp)
Sets a hardware breakpoint for a specific thread.
virtual void onDLLUnload(uintptr_t address, std::string dllName)
Called when a DLL is unloaded.
virtual void onUnknownException(uintptr_t addr, DWORD code)
Called on unknown exception.
virtual void onStart(uintptr_t imageBase, uintptr_t entryPoint)
Called when a new debuggee process is started.
T readMemory(uintptr_t address)
Reads a POD value from target memory (typed helper).
Definition debugger.h:686
std::vector< uintptr_t > searchInMemory(const std::vector< BYTE > &pattern)
Scans process memory for a byte pattern.
virtual void onThreadCreate(HANDLE hThread, DWORD threadId, uintptr_t threadBase, uintptr_t startAddress)
Called when a thread is created in the debuggee.
int detach()
Detaches from the current debuggee.
Definition debugger.cpp:77
void setBreakpoint(LPVOID address)
Sets a software INT3 breakpoint at an address.
std::vector< MemoryRegion_t > getMemoryPages()
Enumerates readable/committed pages of the process.
bool clearHardwareBreakpointOnThread(HANDLE hThread, DRReg reg)
Clears a DRx slot on a single thread.
hwBp_t getBreakpointByReg(DRReg reg)
Gets the breakpoint definition bound to a DRx register.
void decrementIP(HANDLE hThread)
Moves the instruction pointer one instruction backward (post-breakpoint fixup).
Definition debugger.cpp:158
void PrintMemoryPages()
Prints a formatted list of memory pages (debug helper).
bool readMemory(LPVOID address, void *buffer, SIZE_T size)
Reads raw bytes from target memory.
void setRegister(HANDLE hThread, Register32 reg, int32_t value)
Writes a 32-bit general-purpose register.
virtual void onRIPError(const RIP_INFO &rip)
Called on RIP error (native debug port issues).
virtual bool onDLLLoad(uintptr_t address, std::string dllName, uintptr_t entryPoint)
Called when a DLL is loaded.
void restoreBreakpoint(LPVOID address)
Restores the original byte at a software breakpoint address.
virtual BreakpointAction onBreakpoint(uintptr_t address, HANDLE hThread)
Called on software breakpoint (INT3).
virtual void onDebugString(std::string dbgString)
Called when OutputDebugString is emitted by the debuggee.
void setBreakpoint(uintptr_t address)
Sets a software INT3 breakpoint.
Definition debugger.h:559
bool setHardwareBreakpoint(hwBp_t bp)
Sets a hardware breakpoint for all existing (and future) threads where applicable.
bool setHardwareBreakpointOnThread(HANDLE hThread, LPVOID address, DRReg reg, AccessType type, BreakpointLength len)
Sets a hardware breakpoint on a specific thread.
Definition debugger.h:598
bool writeMemory(uintptr_t address, const T &value)
Writes a POD value to target memory (typed helper).
Definition debugger.h:670
MemoryRegion_t getPageByAddress(uintptr_t baseAddress)
Gets page information for an address.
Definition debugger.h:577
void printIP(HANDLE hThread)
Prints the current instruction pointer (IP/EIP/RIP) of a thread.
Definition debugger.cpp:180
virtual BreakpointAction onHardwareBreakpoint(uintptr_t address, HANDLE hThread, DRReg reg)
Called on hardware breakpoint hit.
DRReg isHardwareBreakpointAt(uintptr_t address)
Checks if a hardware breakpoint exists at an address.
Definition debugger.h:568
bool writeMemory(LPVOID address, const void *buffer, SIZE_T size)
Writes raw bytes to target memory.
bool changeMemoryProtection(LPVOID baseAddress, SIZE_T regionSize, DWORD newProtect)
Changes memory protection on a region.
bool readMemory(uintptr_t address, void *buffer, SIZE_T size)
Reads raw bytes from target memory (uintptr_t overload).
Definition debugger.h:658
void restoreBreakpoint(uintptr_t address)
Restores the original byte at a software breakpoint.
Definition debugger.h:585
virtual void onUnknownDebugEvent(DWORD code)
Called on unhandled/unknown debug events.
Debugger()
Constructs a Debugger with default settings.
Definition debugger.cpp:6
uintptr_t baseImageBase
Typical image base (with ASLR).
Definition debugger.h:196
bool setHardwareBreakpoint(int address, DRReg reg, AccessType type, BreakpointLength len)
Sets a hardware breakpoint using a 32-bit int address (for convenience).
Definition debugger.h:624
void actualizeThreadList()
Refreshes the internal thread list by querying the target process.
Definition debugger.cpp:193
virtual void onSinglestep(uintptr_t address, HANDLE hThread)
Called on single-step exception.
Flags32
x86 CPU status flags.
Definition debugger.h:132
@ AF
Auxiliary Carry Flag.
Definition debugger.h:135
@ PF
Parity Flag.
Definition debugger.h:134
@ CF
Carry Flag.
Definition debugger.h:133
@ OF
Overflow Flag.
Definition debugger.h:141
@ ZF
Zero Flag.
Definition debugger.h:136
@ SF
Sign Flag.
Definition debugger.h:137
@ DF
Direction Flag.
Definition debugger.h:140
@ TF
Trap Flag.
Definition debugger.h:138
@ IF
Interrupt Enable Flag.
Definition debugger.h:139
AccessType
Specifies the type of memory access that triggers a hardware breakpoint.
Definition debugger.h:47
@ READWRITE
Trigger when reading from or writing to the address.
Definition debugger.h:50
@ EXECUTE
Trigger when executing instructions at the address.
Definition debugger.h:48
@ WRITE
Trigger when writing to the address.
Definition debugger.h:49
Register32
32-bit x86 general-purpose registers.
Definition debugger.h:160
@ EIP
Instruction Pointer.
Definition debugger.h:162
BreakpointLength
Length of the hardware breakpoint watch.
Definition debugger.h:69
BreakpointAction
Specifies the action to take when a breakpoint is hit.
Definition debugger.h:37
@ SINGLE_STEP
Perform a single-step execution after hitting the breakpoint.
Definition debugger.h:40
@ RESTORE
Restore the original instruction at the breakpoint.
Definition debugger.h:39
@ BREAK
Stop execution at the breakpoint.
Definition debugger.h:38
DRReg
Hardware debug registers used for breakpoints.
Definition debugger.h:57
@ NOP
No register assigned.
Definition debugger.h:58
@ DR3
Debug register 3.
Definition debugger.h:62
@ DR2
Debug register 2.
Definition debugger.h:61
@ DR1
Debug register 1.
Definition debugger.h:60
@ DR0
Debug register 0.
Definition debugger.h:59
Represents a memory region in a process.
Definition debugger.h:103
DWORD Protect
Protection flags (e.g., PAGE_READWRITE).
Definition debugger.h:107
SIZE_T RegionSize
Size of the memory region in bytes.
Definition debugger.h:105
LPVOID BaseAddress
Base address of the memory region.
Definition debugger.h:104
DWORD Type
Type (MEM_IMAGE, MEM_MAPPED, MEM_PRIVATE).
Definition debugger.h:108
DWORD State
State (MEM_COMMIT, MEM_FREE, MEM_RESERVE).
Definition debugger.h:106
Hardware breakpoint configuration.
Definition debugger.h:91
BreakpointLength len
Length of the watch region.
Definition debugger.h:96
LPVOID address
Address to watch.
Definition debugger.h:93
AccessType type
Type of access that triggers the breakpoint.
Definition debugger.h:95
DRReg reg
Debug register used.
Definition debugger.h:94
HANDLE hThread
Target thread handle.
Definition debugger.h:92
Represents a thread in a debugged process.
Definition debugger.h:80
LPVOID threadBase
Base address of the thread.
Definition debugger.h:83
HANDLE hThread
Thread handle.
Definition debugger.h:81
DWORD threadId
Thread ID.
Definition debugger.h:82
LPVOID startAddress
Start address of the thread.
Definition debugger.h:84
Various high-level Utility functions.