突然看到了一种反调试的手段,检测api函数的首字节是否为0xcc,即int 3类型的断点,来反调试,尝试一下
- #include
- #include
- void fun(int a) {
- a++;
- a--;
- a += 5;
- a -= 5;
- return;
- }
- int main() {
- void (*ptr)(int) = NULL;
- ptr = fun;
- int i =0;
- char *arr=(char*)(ptr);
- for (i = 0; i < 99; i++) {
- printf("0x%2x\t", arr[i]);
- }
- return 0;
- }
最开始的时候就遇到了一个问题,我用的virtual studio ,但是这是c++编译的,导致最后的函数指针不是指向的fun函数,这里可以很清楚的看到。
额,不太清楚编译的原理,那我用纯c,直接用devc++,里面有自带的gcc编译器
然后就和我预想的一样了,fun就是那个函数指针,在fun里多打一点断点(有个问题,为什么fun函数编译出来会有个nop,不是很懂)
执行结果上面就有预期的0xCC了,可见,ida确实是用的int 3断点
这种方法很简单,也很容易绕过,我们来看一下硬件断点,硬件断点基于DRx寄存器,换句话说,可以通过检测DRx寄存器来检测硬件断点
可以通过SetThreadContext直接设置指定线程的调试寄存器
DRx寄存器可以直接操作,但是需要设置特权级CPL等于0,这里采用比较简单的方法,直接用GetThreadContext获取当前线程的上下文
我一共下了3个硬件断点,执行结果如下
可见,确实用DRx寄存器来设置了硬件断点,而该程序正常执行情况(没有断点)如下
- #include
- #include
- #include
- const char *strr = (const char*)"hello touful";
- int main()
- {
- printf("enter\n");
- //获取当前线程的句柄
- HANDLE hThread = GetCurrentThread();
-
- //创建一个CONTEXT结构体
- CONTEXT threadContext;
- threadContext.ContextFlags = CONTEXT_ALL;
-
- //获取当前线程的运行上下文
- if (!GetThreadContext(hThread, &threadContext))
- {
- printf("GetThreadContext failed\n");
- return 0;
- }
- printf("DRO = 0x%x\n", threadContext.Dr0);
- printf("DR1 = 0x%x\n", threadContext.Dr1);
- printf("DR2 = 0x%x\n", threadContext.Dr2);
- printf("DR3 = 0x%x\n", threadContext.Dr3);
- printf("exit\n");
- return 0;
- }
-
-
这里顺便贴出CONTEXT结构体的定义
- typedef struct DECLSPEC_NOINITALL _CONTEXT {
-
- //
- // The flags values within this flag control the contents of
- // a CONTEXT record.
- //
- // If the context record is used as an input parameter, then
- // for each portion of the context record controlled by a flag
- // whose value is set, it is assumed that that portion of the
- // context record contains valid context. If the context record
- // is being used to modify a threads context, then only that
- // portion of the threads context will be modified.
- //
- // If the context record is used as an IN OUT parameter to capture
- // the context of a thread, then only those portions of the thread's
- // context corresponding to set flags will be returned.
- //
- // The context record is never used as an OUT only parameter.
- //
-
- DWORD ContextFlags;
-
- //
- // This section is specified/returned if CONTEXT_DEBUG_REGISTERS is
- // set in ContextFlags. Note that CONTEXT_DEBUG_REGISTERS is NOT
- // included in CONTEXT_FULL.
- //
-
- DWORD Dr0;
- DWORD Dr1;
- DWORD Dr2;
- DWORD Dr3;
- DWORD Dr6;
- DWORD Dr7;
-
- //
- // This section is specified/returned if the
- // ContextFlags word contians the flag CONTEXT_FLOATING_POINT.
- //
-
- FLOATING_SAVE_AREA FloatSave;
-
- //
- // This section is specified/returned if the
- // ContextFlags word contians the flag CONTEXT_SEGMENTS.
- //
-
- DWORD SegGs;
- DWORD SegFs;
- DWORD SegEs;
- DWORD SegDs;
-
- //
- // This section is specified/returned if the
- // ContextFlags word contians the flag CONTEXT_INTEGER.
- //
-
- DWORD Edi;
- DWORD Esi;
- DWORD Ebx;
- DWORD Edx;
- DWORD Ecx;
- DWORD Eax;
-
- //
- // This section is specified/returned if the
- // ContextFlags word contians the flag CONTEXT_CONTROL.
- //
-
- DWORD Ebp;
- DWORD Eip;
- DWORD SegCs; // MUST BE SANITIZED
- DWORD EFlags; // MUST BE SANITIZED
- DWORD Esp;
- DWORD SegSs;
-
- //
- // This section is specified/returned if the ContextFlags word
- // contains the flag CONTEXT_EXTENDED_REGISTERS.
- // The format and contexts are processor specific
- //
-
- BYTE ExtendedRegisters[MAXIMUM_SUPPORTED_EXTENSION];
-
- } CONTEXT;
对于内存断点,是以页的方式添加的,设置页的权限位就行了,最常用的两种断点实现了最常用的检测方式