文章目录
声明
静态反调试目的
被调试的进程用静态反调试技术来侦测自身是否处于被调试状态,若侦测到处于被调试的状态,则执行非常规代码(主要是终止代码)来阻止。具体的实现方法包括调试器检测方法,调试环境检测方法,强制隔离调试器的方法等等。反调试破解方法主要用来从探测代码获取信息,然后修改信息本身使反调试技术失效。
注意
许多静态反调试技术对OS具有很强的依懒性。这意味着静态反调试技术在Windows XP 系统下可以正常使用,而在Windows Vista/7操作系统中可能失效
接下来的东西需要用到以下知识,请自行查看:
PEB
https://blog.csdn.net/CSNN2019/article/details/113113347
+0x002 BeingDebugged : UChar
+0x00c Ldr : Ptr32 _PEB_LDR_DATA
+0x018 ProcessHeap : Ptr32 Void
+0x068 NtGlobalFlag : Uint4B
BeingDebugged(+0x2)
kernel32.dll中有个名Kernel32!IsDebuggerPresent()
的API,但普通的应用程序开发中并不常用:
BOOL WINAPI IsDebuggerPresent()
该API就是用来判断当前进程是否处于调试状态,并返回判断结果。而该API就是通过检测PEB.BeingDebugged成员来确定是否正在调试程序(是,则返回1;否,则返回0)。
老办法,查看一下OD:
代码如下:
75074E80 > 64:A1 30000000 mov eax,dword ptr fs:[0x30]
75074E86 0FB640 02 movzx eax,byte ptr ds:[eax+0x2]
75074E8A C3 retn
提示:
Windows 7中,IsDebuggerPresent()
API是在Kernelbase.dll
中实现的。而在Windows XP 及以前版本的操作系统中,它是在kernel32.dll
中。
先获取FS:[30]地址,即PEB地址,然后通过[PEB+2]访问BeingDebugged
这里取出来的是0的原因呢,是因为吾爱破解OD太强悍了,加了很多插件。。。
慢慢关闭就行,用原版OD或者IDA就能返回1。
破解之法:
用吾爱破解的OD(滑稽。。哈哈),用OD 的编辑功能把BeingDebugged
改为0即可。
Ldr(0xc)
调试进程时,其堆内存区域中就会出现一些特殊标识,表示它正处于被调试状态。其中未使用的堆内存区域全部填充着0xEEFEEEFE
,这证明正在调试进程。利用这点可判断进程正在被调试。
PEB.Ldr成员是一个指向_ PEB_ LDR DATA结构体的指针,而 PEB_ LDR _DATA结构体恰好是在堆里面创建的,所以扫描该区域即了轻松查找是否存在0xEEFEEEFE
区域
PEB起始地址为0x3D2000
,然后指针指向的区域是0x7710DCA0
我看了一下,我的没有。。。有的堆内存中,如果往下拖动滑动条,会看到填充着0xEEFEEEFE
的区域。。
破解之法:
只要将填充着0xEEFEEEFE
值的区域全部覆写为NULL即可
提示:
该方法仅仅适用于Windows XP系统,而在Windows Vista 以后的系统中则无法使用。另外,利用附加功能的将运行中的进程附加调试器时,堆内存中并不出现上述标识
ProcessHeap(+0x18)
PEB.ProcessHeap(+0x18)成员是指向HEAP结构体的指针
+0x000 Entry :_HEAP_ENTRY
+0x008 Signature :Unit4B
+0x00c Flags :Unit4B
+0x010 ForceFlags :Unit4B
+0x014 VirtualMemoryThreshold :Unit4B
+0x018 SegmentReserve :Unit4B
+0x01c SegmentCommit :Unit4B
+0x020 DeCommitFreeBlockThreshold :Unit4B
……………………………………………………………………
以上列出了HEAP结构体的部分成员,进程处于调试状态时,Flags(+0xC)与ForceFlags成员(+0x10)被设置为特定值
GetprocessHeap():
PEB.ProcessHeap
成员(+0x18)既可以从PEB结构体直接获取,也可以通过GetprocessHeap()
API获取。下面看看GetprocessHeap()
API的代码
直接PEB—>PEB.ProcessHeap顺序访问
PEB.ProcessHeap
=0x6B0000
Flags(0xC)&Force Flags(+0x10)
进程正常运行(非调试运行)时,Heap.Flags成员(+0xC)的值02,Heap.ForceFlags成员(+0x10)值为0。进程处于被调试状态时,这些值也会随之改变。
注意:
1.这里我用的是吾爱破解版的OD,插件比较多,内存单元里的值不能作参考。。。
2.该方法仅在Windows XP系统中有效,Windows 7系统则保留ForceFlags属性和Flags属性。此外,将运行中的进程附加到调试器时,也不会出现上述特征。
所以,比较这些值,就可以判断进程是否处于被调试状态。
破解之法:
只要将Heap.Flags成员(+0xC)的值设置成02,Heap.ForceFlags成员(+0x10)值设置成0。
NtGlobalFlag(+0x68)
调试进程时,PEB.NtGlobalFlag成员(+0x68)的值会被设置0x70。所以,检测该成员的值即可判断进程是否处于被调试状态。
NtGlobalFlag 0x70是下列Flags进行bit OR(位或)运算的结果
FLG_HEAP_ENABLE_TAIL_CHECK (0x10)
FLG_HEAP_ENABLE_FREE_CHECK (0x20)
FLG_HEAP_VALIDATE_PARAMETERS (0x40)
被调试进程的堆内存中存在(不同于非调试运行进程的)特别标识,因此在PEB.NtGlobalFlag成员中添加了上述标志。(注意:这个OD的插件太多了。。。)
注意:
将运行的进程附加到调试器时,PEB.NtGlobalFlag的值不变
破解之法
重设PEB.NtGlobalFlag值为0即可(PEB.NtGlobalFlag=0).
strongOD->Options中的HidePEB可以绕过。
调试程序代码
#include "stdio.h"
#include "windows.h"
#include "tchar.h"
void PEB()
{
HMODULE hMod = NULL;
FARPROC pProc = NULL;
LPBYTE pTEB = NULL;
LPBYTE pPEB = NULL;
BOOL bIsDebugging = FALSE;
//<span style="color:#ff0000;">[pPEB+0x2]==0x1</span>
// IsDebuggerPresent()
bIsDebugging = IsDebuggerPresent();
printf("IsDebuggerPresent() = %d\n", bIsDebugging);
if( bIsDebugging ) printf(" => Debugging!!!\n\n");
else printf(" => Not debugging...\n\n");
// Ldr xp特有
pProc = GetProcAddress(GetModuleHandle(L"ntdll.dll"), "NtCurrentTeb");
pTEB = (LPBYTE)(*pProc)(); // address of TEB
pPEB = (LPBYTE)*(LPDWORD)(pTEB+0x30); // address of PEB
printf("PEB.Ldr\n");
DWORD pLdrSig[4] = { 0xEEFEEEFE, 0xEEFEEEFE, 0xEEFEEEFE, 0xEEFEEEFE };
LPBYTE pLdr = (LPBYTE)*(LPDWORD)(<span style="color:#ff0000;">pPEB+0xC</span>);
__try
{
while( TRUE )
{
if( !memcmp(pLdr, pLdrSig, sizeof(pLdrSig)) )
{
printf(" => Debugging!!!\n\n");
break;
}
pLdr++;
}
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
printf(" => Not debugging...\n\n");
}
// Process Heap - Flags xp特有
bIsDebugging = FALSE;
LPBYTE pHeap = (LPBYTE)*(LPDWORD)(<span style="color:#ff0000;">pPEB+0x18</span>);
DWORD dwFlags = *(LPDWORD)(<span style="color:#ff0000;">pHeap+0xC</span>);
printf("PEB.ProcessHeap.Flags = 0x%X\n", dwFlags);
if( dwFlags != 0x2 ) printf(" => Debugging!!!\n\n");
else printf(" => Not debugging...\n\n");
// Process Heap - ForceFlags xp特有
bIsDebugging = FALSE;
DWORD dwForceFlags = *(LPDWORD)(<span style="color:#ff0000;">pHeap+0x10</span>);
printf("PEB.ProcessHeap.ForceFlags = 0x%X\n", dwForceFlags);
if( dwForceFlags != 0x0 ) printf(" => Debugging!!!\n\n");
else printf(" => Not debugging...\n\n");
// NtGlobalFlag
bIsDebugging = FALSE;
DWORD dwNtGlobalFlag = *(LPDWORD)(<span style="color:#ff0000;">pPEB+0x68</span>);
printf("PEB.NtGlobalFlag = 0x%X\n", dwNtGlobalFlag);
if( (dwNtGlobalFlag & 0x70) == 0x70 ) printf(" => Debugging!!!\n\n");
else printf(" => Not debugging...\n\n");
}
int _tmain(int argc, TCHAR* argv[])
{
PEB();
printf("\npress any key to quit...\n");
_gettch();
return 0;
}
反调试技术系列:
静态反调试技术(1)https://blog.csdn.net/CSNN2019/article/details/113105292
静态反调试技术(2)https://blog.csdn.net/CSNN2019/article/details/113147820
静态反调试技术(3)https://blog.csdn.net/CSNN2019/article/details/113178232
动态反调试技术 https://blog.csdn.net/CSNN2019/article/details/113181558
高级反调试技术 https://blog.csdn.net/CSNN2019/article/details/113263215