在调试一些病毒程序的时候,可能会碰到一些反调试技术,也就是说,被调试的程序可以检测到自己是否被调试器附加了,如果探知自己正在被调试,肯定是有人试图反汇编啦之类的方法破解自己。为了了解如何破解反调试技术,首先我们来看看反调试技术。
 
一、Windows API方法
 
Win32提供了两个API, IsDebuggerPresent和CheckRemoteDebuggerPresent可以用来检测当前进程是否正在被调试,以IsDebuggerPresent函数为例,例子如下:
 
BOOL ret = IsDebuggerPresent();
printf("ret = %d\n", ret);
 
破解方法很简单,就是在系统里将这两个函数hook掉,让这两个函数一直返回false就可以了,网上有很多做hook API工作的工具,也有很多工具源代码是开放的,所以这里就不细谈了。
 
 
二、查询进程PEB的BeingDebugged标志位
 
当进程被调试器所附加的时候,操作系统会自动设置这个标志位,因此在程序里定期查询这个标志位就可以了,例子如下:
 
bool PebIsDebuggedApproach()
{
       char result = 0;
       __asm
       {
// 进程的PEB地址放在fs这个寄存器位置上
              mov eax, fs:[30h]
// 查询BeingDebugged标志位
              mov al, BYTE PTR [eax + 2] 
              mov result, al
       }
 
       return result != 0;
}
 
 
三、查询进程PEB的NtGlobal标志位 
 
跟第二个方法一样,当进程被调试的时候,操作系统除了修改BeingDebugged这个标志位以外,还会修改其他几个地方,其中NtDll中一些控制堆(Heap)操作的函数的标志位就会被修改,因此也可以查询这个标志位,例子如下:
 
bool PebNtGlobalFlagsApproach()
{
       int result = 0;
 
       __asm
       {
  // 进程的PEB
              mov eax, fs:[30h]
  // 控制堆操作函数的工作方式的标志位
              mov eax, [eax + 68h]
  // 操作系统会加上这些标志位FLG_HEAP_ENABLE_TAIL_CHECK, 
  // FLG_HEAP_ENABLE_FREE_CHECK and FLG_HEAP_VALIDATE_PARAMETERS,
  // 它们的并集就是x70
  //
  // 下面的代码相当于C/C++的
  //     eax = eax & 0x70
              and eax, 0x70
              mov result, eax
       }
 
       return result != 0;
}
 
 
四、查询进程堆的一些标志位
 
这个方法是第三个方法的变种,只要进程被调试,进程在堆上分配的内存,在分配的堆的头信息里,ForceFlags这个标志位会被修改,因此可以通过判断这个标志位的方式来反调试。因为进程可以有很多的堆,因此只要检查任意一个堆的头信息就可以了,所以这个方法貌似很强大,例子如下:
 
bool HeapFlagsApproach()
{
       int result = 0;
 
       __asm
       {
      // 进程的PEB
              mov eax, fs:[30h]
      // 进程的堆,我们随便访问了一个堆,下面是默认的堆
              mov eax, [eax + 18h]
  // 检查ForceFlag标志位,在没有被调试的情况下应该是
              mov eax, [eax + 10h]
              mov result, eax
       }
 
       return result != 0;
}
 
 
五、使用NtQueryInformationProcess函数
 
NtQueryInformationProcess函数是一个未公开的API,它的第二个参数可以用来查询进程的调试端口。如果进程被调试,那么返回的端口值会是-1,否则就是其他的值。由于这个函数是一个未公开的函数,因此需要使用LoadLibrary和GetProceAddress的方法获取调用地址,示例代码如下:
 
// 声明一个函数指针。
typedef NTSTATUS (WINAPI *NtQueryInformationProcessPtr)(
       HANDLE processHandle,
       PROCESSINFOCLASS processInformationClass,
       PVOID processInformation,
       ULONG processInformationLength,
       PULONG returnLength);
 
bool NtQueryInformationProcessApproach()
{
       int debugPort = 0;
       HMODULE hModule = LoadLibrary(TEXT("Ntdll.dll "));
       NtQueryInformationProcessPtr NtQueryInformationProcess = (NtQueryInformationProcessPtr)GetProcAddress(hModule, "NtQueryInformationProcess");
       if ( NtQueryInformationProcess(GetCurrentProcess(), (PROCESSINFOCLASS)7, &debugPort, sizeof(debugPort), NULL) )
              printf("[ERROR NtQueryInformationProcessApproach] NtQueryInformationProcess failed\n");
       else
              return debugPort == -1;
 
       return false;
}
 
 
六、NtSetInformationThread方法
 
这个也是使用Windows的一个未公开函数的方法,你可以在当前线程里调用NtSetInformationThread,调用这个函数时,如果在第二个参数里指定0x11这个值(意思是ThreadHideFromDebugger),等于告诉操作系统,将所有附加的调试器统统取消掉。示例代码:
 
// 声明一个函数指针。
typedef NTSTATUS (*NtSetInformationThreadPtr)(HANDLE threadHandle,
       THREADINFOCLASS threadInformationClass,
       PVOID threadInformation,
       ULONG threadInformationLength);
 
void NtSetInformationThreadApproach()
{
      HMODULE hModule = LoadLibrary(TEXT("ntdll.dll"));
      NtSetInformationThreadPtr NtSetInformationThread = (NtSetInformationThreadPtr)GetProcAddress(hModule, "NtSetInformationThread");
    
      NtSetInformationThread(GetCurrentThread(), (THREADINFOCLASS)0x11, 0, 0);
}
 
 
七、触发异常的方法
 
这个技术的原理是,首先,进程使用SetUnhandledExceptionFilter函数注册一个未处理异常处理函数A,如果进程没有被调试的话,那么触发一个未处理异常,会导致操作系统将控制权交给先前注册的函数A;而如果进程被调试的话,那么这个未处理异常会被调试器捕捉,这样我们的函数A就没有机会运行了。
 
这里有一个技巧,就是触发未处理异常的时候,如果跳转回原来代码继续执行,而不是让操作系统关闭进程。方案是在函数A里修改eip的值,因为在函数A的参数_EXCEPTION_POINTERS里,会保存当时触发异常的指令地址,所以在函数A里根据这个指令地址修改寄存器eip的值就可以了,示例代码如下:
 
// 进程要注册的未处理异常处理程序A
LONG WINAPI MyUnhandledExceptionFilter(struct _EXCEPTION_POINTERS *pei)
{
       SetUnhandledExceptionFilter((LPTOP_LEVEL_EXCEPTION_FILTER)
              pei->ContextRecord->Eax);
       // 修改寄存器eip的值
       pei->ContextRecord->Eip += 2;
       // 告诉操作系统,继续执行进程剩余的指令(指令保存在eip里),而不是关闭进程
       return EXCEPTION_CONTINUE_EXECUTION;
}
 
bool UnhandledExceptionFilterApproach()
{
       SetUnhandledExceptionFilter(MyUnhandledExceptionFilter);
       __asm
       {
              // 将eax清零
              xor eax, eax
              // 触发一个除零异常
              div eax
       }
 
       return false;
}
 
八、调用DeleteFiber函数
 
如果给DeleteFiber函数传递一个无效的参数的话,DeleteFiber函数除了会抛出一个异常以外,还是将进程的LastError值设置为具体出错原因的代号。然而,如果进程正在被调试的话,这个LastError值会被修改,因此如果调试器绕过了第七步里讲的反调试技术的话,我们还可以通过验证LastError值是不是被修改过来检测调试器的存在,示例代码:
 
bool DeleteFiberApproach()
{
       char fib[1024] = {0};
       // 会抛出一个异常并被调试器捕获
       DeleteFiber(fib);
 
       // 0x57的意思是ERROR_INVALID_PARAMETER
       return (GetLastError() != 0x57);
}

windows平台下的反调试技术相关推荐

  1. 详解反调试技术(转)

    反调试技术,恶意代码用它识别是否被调试,或者让调试器失效.恶意代码编写者意识到分析人员经常使用调试器来观察恶意代码的操作,因此他们使用反调试技术尽可能地延长恶意代码的分析时间.为了阻止调试器的分析,当 ...

  2. Windows反调试技术全攻略

    在调试一些病毒程序的时候,可能会碰到一些反调试技术,也就是说,被调试的程序可以检测到自己是否被调试器附加了,如果探知自己正在被调试,肯定是有人试图反汇编啦之类的方法破解自己.为了了解如何破解反调试技术 ...

  3. Windows 平台下面的IOCP技术 Linux下面Epoll 还有FreeBSD下面Kqueue的应用了。跨平台库行业里面最出名的莫过于ACE、ASIO(Boos公司)两大支持库支持IOCP

    http://wenku.baidu.com/view/4117460502020740be1e9b3c.html 游戏服务器集群 自从2003年开发VOIP Radius Server以及修改Gnu ...

  4. 静态反调试技术(2)

    文章目录 NtQueryInformationProcess() `ProcessDebugPort`(0x7) CheckRemoteDebuggerPresent() ProcessDebugOb ...

  5. 静态反调试技术(1)

    文章目录 声明 静态反调试目的 注意 PEB https://blog.csdn.net/CSNN2019/article/details/113113347 BeingDebugged(+0x2) ...

  6. 静态反调试技术(3)

    文章目录 ZwSetInformationThread 破解方法 **调试程序代码**: 利用TLS回调函数(详情通过以下链接查看) ETC 破解之法 **调试程序代码**: 篇章大总结: 反调试技术 ...

  7. 反调试技术揭秘(转)

    在调试一些病毒程序的时候,可能会碰到一些反调试技术,也就是说,被调试的程序可以检测到自己是否被调试器附加了,如果探知自己正在被调试,肯定是有人试图反汇编之类的方法破解自己.为了了解如何破解反调试技术, ...

  8. Windows平台下的内存泄漏检测

    Windows平台下的内存泄漏检测 一.使用_CrtDumpMemoryLeaks定位内存泄露 添加对应的头文件 转储内存泄漏信息 程序任意点退出 指定调试信息输出 二.定位具体内存泄露位置 内存快照 ...

  9. 如何绕过反调试技术——PhantOM插件总结

    PhantOM是OllyDbg的一款插件,可以用来绕过大多数的反调试技术,功能十分强大,所以单独对这个插件进行使用总结.(Ps:现在似乎不怎么常用,在64位下的兼容性比较差,现在比较常用的是sharp ...

最新文章

  1. lucene源码分析的一些资料
  2. php长脚本,长PHP脚本运行多次
  3. Silverlight 4 新特性之Silverlight as Drop Target
  4. C#应用程序单例并激活程序的窗口 使其显示在最前端
  5. [LeetCode] Count Primes - 素数系列问题
  6. 【Linux网络编程】无连接和面向连接协议
  7. redis(2)--数据结构与对象
  8. HBase性能优化方法总结(二):写表操作
  9. 本题要求实现一个用选择法对整数数组进行简单排序的函数。_通俗易懂讲 Python 算法:快速排序...
  10. python idle 中文_Python IDLE 中文乱码问题
  11. python同时注释多行代码_python怎么同时对多行代码进行注释
  12. 【NOIP1997】【Luogu1548】棋盘问题(枚举正方形个数)
  13. OpenCV学习资源
  14. 腾讯教育 App Flutter 跨端点播组件实践
  15. gg修改器修改数值没有用怎么办_GG修改器详细使用教程
  16. 中国音频放大器市场现状研究分析与发展前景分析报告
  17. python入门之运算符的使用的答案_python基础课程 第2章 (运算符)
  18. 我从非科班转到图像算法工程师(图像识别、机器学习、深度学习)(3个月)的经历
  19. 【中级计量经济学】Lecture 5 自相关
  20. 新媒体时代下,用户思维的体现和运用

热门文章

  1. 13 操作系统第三章 内存管理 虚拟内存 请求分页管理方式 页面置换算法 页面分配策略
  2. 软工 课堂作业:选出一个整数组中最大子数组
  3. LeetCode - Partition List
  4. UVA 10173 旋转卡壳
  5. 【知识图谱】一、知识表示与知识建模
  6. MYSQL--一条SQL查询语句是如何执行的?
  7. Leetcode--141. 环形链表
  8. python意外缩进引发逻辑错误_python – IndentationError:意外的缩进错误
  9. php中intval函数用法,php intval函数用法总结
  10. 登录mysql一闪而过_解决MySQL 一闪而过的情况