反调试技术揭秘

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

一、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);

}

时间: 2024-08-28 01:15:40

反调试技术揭秘的相关文章

原来... 反调试技术揭秘(转)

在调试一些病毒程序的时候,可能会碰到一些反调试技术,也就是说,被调试的程序可以检测到自己是否被调试器附加了,如果探知自己正在被调试,肯定是有人试图反汇编啦之类的方法破解自己.为了了解如何破解反调试技术,首先我们来看看反调试技术. 一.Windows API方法 Win32提供了两个API, IsDebuggerPresent和CheckRemoteDebuggerPresent可以用来检测当前进程是否正在被调试,以IsDebuggerPresent函数为例,例子如下: BOOL ret = Is

反调试技术

反调试技术在调试一些病毒程序的时候,可能会碰到一些反调试技术,也就是说,被调试的程序可以检测到自己是否被调试器附加了,如果探知自己正在被调试,肯定是有人试图反汇编啦之类的方法破解自己.为了了解如何破解反调试技术,首先我们来看看反调试技术. 一.Windows API方法 Win32提供了两个API, IsDebuggerPresent和CheckRemoteDebuggerPresent可以用来检测当前进程是否正在被调试,以IsDebuggerPresent函数为例,例子如下: BOOL ret

Linux下的反调试技术

Linux下的反调试技术 2014年01月30日 ⁄ 综合 ⁄ 共 2669字 ⁄ 字号 小 中 大 ⁄ 评论关闭 转自  http://wangcong.org/blog/archives/310 如何防止自己的程序被调试器跟踪,这是一个很有趣的话题,也是反逆向工程中的一个重要话题.这里简单介绍一下Linux平台上的反调试技术. (本文主要参考:http://blog.txipinet.com/2006/10/05/37-tecnicas-anti-debugging-sencillas-pa

反调试技术总结

总结了一下网上的反调试技术,记录一下 一.使用WindowsAPI : 1.IsDebuggerPresent 2.CheckRemoteDebuggerPresent ->call NtInformationProcess( 2参数ProcessInformationClass) 3.NTQueryObject(2参数ObjectInformationClass)检查调试对象 4.NTQuerySystemInformation( 1参数SystemInformationClass) 5.Zw

反调试技术常用API,用来对付检测od和自动退出程序

在调试一些病毒程序的时候,可能会碰到一些反调试技术,也就是说,被调试的程序可以检测到自己是否被调试器附加了,如果探知自己正在被调试,肯定是有人试图反汇编啦之类的方法破解自己.为了了解如何破解反调试技术,首先我们来看看反调试技术. 一.Windows API方法 Win32提供了两个API, IsDebuggerPresent和CheckRemoteDebuggerPresent可以用来检测当前进程是否正在被调试,以IsDebuggerPresent函数为例,例子如下: BOOL ret = Is

反调试技术- IsDebuggerPresent,原理 与 反反调试

IsDebuggerPresent 这个函数可以用在程序中,检测当前程序是否正在被调试,从而执行退出等行为,达到反调试的作用. 1.IsDebuggerPresent 这个函数从汇编的角度看,就是一下三句代码.下面依次来分析这三句代码的原理. 75593789 K> 64:A1 18000000 mov eax, dword ptr fs:[18] 7559378F 8B40 30 mov eax, dword ptr [eax+30] 75593792 0FB640 02 movzx eax,

一种基于TLS的高级反调试技术

盗版行为日益猖獗,严重影响到软件开发者和开发商的知识产权及利益,反盗版技术的重要性也越来越引起人们的重视.在反盗版技术中,起最大作用的当属反调试技术.然而传统的反调试技术都存在一个弱点:他们都在程序真正开始执行之后才采取反调试手段.实际上在反调试代码被执行前,调试器有大量的时间来影响程序的执行,甚至可以在程序入口处插入断点命令来调试程序.对于使用C/C++语言编译的程序来说,问题通常会更严重,在执行到main()函数之前,会执行C/C++编译器插入的很大一段代码,这也给调试器带来影响程序执行的机

[转载]Android应用方法隐藏及反调试技术浅析

本文转载自: http://drops.wooyun.org/tips/9471 0x00 前言 Android应用的加固和对抗不断升级,单纯的静态加固效果已无法满足需求,所以出现了隐藏方法加固,运行时动态恢复和反调试等方法来对抗,本文通过实例来分析有哪些对抗和反调试手段. 0x01 对抗反编译 首先使用apktool进行反编译,发现该应用使用的加固方式会让apktool卡死,通过调试apktool源码(如何调试apktool可参见前文<Android应用资源文件格式解析与保护对抗研究>),发

Delphi_OD_代码_调试_Delphi反调试技术(以OD为例附核心原代码) (转)

1.程序窗口[chuang kou]句柄[ju bing]检测原理:用FindWindow函数[han shu]查找[cha zhao]具有相同窗口[chuang kou]类名和标题的窗口[chuang kou],如果找到就说明[shuo ming]有OD在运行[yun hang]//********************************************//通过查找[cha zhao]窗口[chuang kou]类名来实现检测OllyDBG//*****************