设为首页 - 加入收藏 ASP站长网(Aspzz.Cn)- 科技、建站、经验、云计算、5G、大数据,站长网!
热搜: 创业者 手机 数据
当前位置: 首页 > 运营中心 > 建站资源 > 策划 > 正文

26种对付反调试的方法(11)

发布时间:2019-03-21 12:55 所属栏目:20 来源:luochicun
导读:要注意的是,如果设置了/ INCREMENTAL:NO链接器选项,那么在获取函数地址来计算校验和的情况下,将会得到相对跳转地址: DebuggeeFunction: 013C16DBjmpDebuggeeFunction(013C4950h) g_origCrc全局变量包含已由Cal

要注意的是,如果设置了/ INCREMENTAL:NO链接器选项,那么在获取函数地址来计算校验和的情况下,将会得到相对跳转地址:

  1. DebuggeeFunction: 
  2. 013C16DB  jmp         DebuggeeFunction (013C4950h) 

g_origCrc全局变量包含已由CalcFuncCrc函数计算的crc。为了终止检测函数,我们使用了存根函数的技巧。按着函数代码顺序排列,DebuggeeFunction函数的末尾是DebuggeeFunctionEnd函数的开头。我们还使用#pragma auto_inline(off)指令来防止编译器的嵌入函数。

如何避开软件断点检查

由于目前还没有一个通用的方法,所以为了避开此保护,应该找到代码计算校验和并用常量替换返回的值,以及存储函数校验和的所有变量的值。

硬件断点

在Windows x86架构中,开发人员在检查和调试代码时使用了一组调试寄存器。这些寄存器允许在访问内存读取或写入时中断程序执行并将控制传输到调试器。调试寄存器是一种特权资源,只能在具有特权级别CPL = 0的实模式或安全模式下由程序使用。8字节的调试寄存器DR0-DR7有:

1.DR0-DR3 -断点寄存器

2.DR4,DR5 -储藏

3.DR6 -调试状态

4.DR7 – 调试控制

DR0-DR3包含断点的线性地址,这些地址的比较是在物理地址转换之前进行的。这些断点中的每一个都会在DR7寄存器中被单独描述。 DR6寄存器会指示哪个断点被激活。 DR7通过访问模式定义断点激活模式:读,写,执行。以下是硬件断点检查的示例:

  1. CONTEXT ctx = {}; 
  2. ctx.ContextFlags = CONTEXT_DEBUG_REGISTERS; 
  3. if (GetThreadContext(GetCurrentThread(), &ctx)) 
  4.     if (ctx.Dr0 != 0 || ctx.Dr1 != 0 || ctx.Dr2 != 0 || ctx.Dr3 != 0) 
  5.     { 
  6.         std::cout << "Stop debugging program!" << std::endl; 
  7.         exit(-1); 
  8.     } 

也可以通过SetThreadContext函数重置硬件断点,以下是硬件断点重置示例:

  1. CONTEXT ctx = {}; 
  2. ctx.ContextFlags = CONTEXT_DEBUG_REGISTERS; 
  3. SetThreadContext(GetCurrentThread(), &ctx); 

我们可以看到,所有DRx寄存器都设置为了0。

如何避开硬件断点检查和重置

如果我们看看GetThreadContext函数,我们会明白它调用了NtGetContextThread函数:

  1. 0:000> u KERNELBASE!GetThreadContext L6 
  2. KERNELBASE!GetThreadContext: 
  3. 7538d580 8bff            mov     edi,edi 
  4. 7538d582 55              push    ebp 
  5. 7538d583 8bec            mov     ebp,esp 
  6. 7538d585 ff750c          push    dword ptr [ebp+0Ch] 
  7. 7538d588 ff7508          push    dword ptr [ebp+8] 
  8. 7538d58b ff1504683975    call    dword ptr [KERNELBASE!_imp__NtGetContextThread (75396804)] 

如果反调试保护在Dr0-Dr7中接收到零值,应该在CONTEXT结构的ContextFlags字段中重置CONTEXT_DEBUG_REGISTERS标识,然后在原始的NtGetContextThread函数调用后恢复其值。对于GetThreadContext函数,它在内部调用NtSetContextThread。以下就是避开硬件断点的检查和重置:

  1. typedef NTSTATUS(NTAPI *pfnNtGetContextThread)( 
  2.     _In_  HANDLE             ThreadHandle, 
  3.     _Out_ PCONTEXT           pContext 
  4.     ); 
  5. typedef NTSTATUS(NTAPI *pfnNtSetContextThread)( 
  6.     _In_ HANDLE              ThreadHandle, 
  7.     _In_ PCONTEXT            pContext 
  8.     ); 
  9. pfnNtGetContextThread g_origNtGetContextThread = NULL; 
  10. pfnNtSetContextThread g_origNtSetContextThread = NULL; 
  11. NTSTATUS NTAPI HookNtGetContextThread( 
  12.     _In_  HANDLE              ThreadHandle, 
  13.     _Out_ PCONTEXT            pContext) 
  14.     DWORD backupContextFlags = pContext->ContextFlags; 
  15.     pContext->ContextFlags &= ~CONTEXT_DEBUG_REGISTERS; 
  16.     NTSTATUS status = g_origNtGetContextThread(ThreadHandle, pContext); 
  17.     pContext->ContextFlags = backupContextFlags; 
  18.     return status; 
  19. NTSTATUS NTAPI HookNtSetContextThread( 
  20.     _In_ HANDLE              ThreadHandle, 
  21.     _In_ PCONTEXT            pContext) 
  22.     DWORD backupContextFlags = pContext->ContextFlags; 
  23.     pContext->ContextFlags &= ~CONTEXT_DEBUG_REGISTERS; 
  24.     NTSTATUS status = g_origNtSetContextThread(ThreadHandle, pContext);    
  25.     pContext->ContextFlags = backupContextFlags; 
  26.     return status; 
  27. void HookThreadContext() 
  28. HMODULE hNtDll = LoadLibrary(TEXT("ntdll.dll")); 
  29. g_origNtGetContextThread = (pfnNtGetContextThread)GetProcAddress(hNtDll, "NtGetContextThread"); 
  30. g_origNtSetContextThread = (pfnNtSetContextThread)GetProcAddress(hNtDll, "NtSetContextThread"); 
  31. Mhook_SetHook((PVOID*)&g_origNtGetContextThread, HookNtGetContextThread); 
  32. Mhook_SetHook((PVOID*)&g_origNtSetContextThread, HookNtSetContextThread); 

SEH(结构化异常处理)

(编辑:ASP站长网)

网友评论
推荐文章
    热点阅读