This page looks best with JavaScript enabled

Debugger breakpoint detection

 ·  ☕ 2 min read  ·  🦉 Aidan

Overview

This article goes over a method to detect debuggers by looking for breakpoints in executable machine code loaded in memory.
It’s naive because the notion that a program’s .text section will only contain 0xCC when there’s a breakpoint is not true.
Regardless, this is a decent starting point to illustrate the concept of breakpoint detection.

Code

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#include <stdio.h>
#include <stdbool.h>

bool check_method(void* method, unsigned char start[], unsigned char stop[]);

#define BP_CHECKABLE(func_name) __attribute__((noinline, section(func_name "_bounds")))
#define BP_CHECK_PRE(func) \
    extern unsigned char __start_##func##_bounds[]; \
    extern unsigned char __stop_##func##_bounds[];
#define BP_CHECK(func) check_method(func, __start_##func##_bounds, __stop_##func##_bounds)

// True if there's a breakpoint
bool check_method(void* method, unsigned char start[], unsigned char stop[])
{
	void* start_ptr = (void *)start;
	void* stop_ptr = (void *)stop;
	size_t size = stop_ptr - start_ptr;
	for (long bytecode = (long)start_ptr; bytecode < (long)stop_ptr; bytecode++)
	{
		unsigned char op = *((unsigned char* )bytecode);
		if (op == 0xCC)
		{
			return true;
		}
	}
	return false;
}

BP_CHECKABLE("checkme") void checkme()
{
	printf("I'm doing something\n");
}

BP_CHECKABLE ("main") int main()
{
	BP_CHECK_PRE(checkme);
	if (BP_CHECK(checkme))
	{
		printf("Breakpoints found in checkme\n");
	} else {
		printf("No breakpoints found in checkme\n");
	}

	BP_CHECK_PRE(main);
	if (BP_CHECK(main))
	{
		printf("Breakpoints found in main\n");
	} else {
		printf("No breakpoints found in main\n");
	}
}

Explanation

Macro weirdness

There are 3 macros, BP_CHECKABLE, BP_CHECK_PRE, and BP_CHECK.

  • BP_CHECKABLE indicates that a function can be checked later. It does 2 things, makes it so that the compiler and linker cannot optimize the function by inlining it, and declares a section around the function, which is stored in the program headers. This means you can actually see the sections with something like readelf -S (see below).
Share on

Aidan M.
WRITTEN BY
Aidan
Intern