IsDebuggerPresent的反调试与反反调试
一、调用系统的IsDebuggerPresent函数
(1)实现程序
最简单也是最基础的,Windows提供的API接口:IsDebuggerPresent(),这API实际上就是访问PEB的BeingDebugged标志来判断是否处于调试状态。
使用vs调试此段代码,弹出"检测到调试器"。
#include <stdio.h>
#include <Windows.h> DWORD WINAPI ThreadFunctionCallBack(LPVOID lp)
{
while(true)
{
if (IsDebuggerPresent())
{
printf("检测到调试器\n");
}
}
} int main()
{ CreateThread(NULL, NULL, ThreadFunctionCallBack, NULL, NULL, NULL); // 启动一个线程进行实时检测
while(TRUE)
{
printf("主线程在执行");
}
system("pause");
return 0;
}
(2)分析IsDebuggerPresent原理:
通过dbg进行简单地逆向分析,进入到 IsDebuggerPresent 函数内部。x86下 FS:[30] 指向PEB,访问 PEB 的 BeingDebugged 标志来判断是否处于调试状态。
IsDebuggerPresent:
// x86下PEB结构
NTDLL_Test!_PEB
+0x000 InheritedAddressSpace : UChar
+0x001 ReadImageFileExecOptions : UChar
+0x002 BeingDebugged : UChar // (BOOL)被调试时,被置为1
+0x003 SpareBool : UChar
+0x004 Mutant : Ptr32 Void
+0x008 ImageBaseAddress : Ptr32 Void
+0x00c Ldr : Ptr32 _PEB_LDR_DATA
+0x010 ProcessParameters : Ptr32 _RTL_USER_PROCESS_PARAMETERS
+0x014 SubSystemData : Ptr32 Void
+0x018 ProcessHeap : Ptr32 Void
+0x01c FastPebLock : Ptr32 _RTL_CRITICAL_SECTION
+0x020 SparePtr1 : Ptr32 Void
+0x024 SparePtr2 : Ptr32 Void
+0x028 EnvironmentUpdateCount : Uint4B
+0x02c KernelCallbackTable : Ptr32 Void
+0x030 SystemReserved : [1] Uint4B
+0x034 ExecuteOptions : Pos 0, 2 Bits
+0x034 SpareBits : Pos 2, 30 Bits
+0x038 FreeList : Ptr32 _PEB_FREE_BLOCK
+0x03c TlsExpansionCounter : Uint4B
+0x040 TlsBitmap : Ptr32 Void
+0x044 TlsBitmapBits : [2] Uint4B
+0x04c ReadOnlySharedMemoryBase : Ptr32 Void
+0x050 ReadOnlySharedMemoryHeap : Ptr32 Void
+0x054 ReadOnlyStaticServerData : Ptr32 Ptr32 Void
+0x058 AnsiCodePageData : Ptr32 Void
+0x05c OemCodePageData : Ptr32 Void
+0x060 UnicodeCaseTableData : Ptr32 Void
+0x064 NumberOfProcessors : Uint4B
+0x068 NtGlobalFlag : Uint4B // 被调试时,会被置为x070
+0x070 CriticalSectionTimeout : _LARGE_INTEGER
+0x078 HeapSegmentReserve : Uint4B
+0x07c HeapSegmentCommit : Uint4B
+0x080 HeapDeCommitTotalFreeThreshold : Uint4B
+0x084 HeapDeCommitFreeBlockThreshold : Uint4B
+0x088 NumberOfHeaps : Uint4B
+0x08c MaximumNumberOfHeaps : Uint4B
+0x090 ProcessHeaps : Ptr32 Ptr32 Void
+0x094 GdiSharedHandleTable : Ptr32 Void
+0x098 ProcessStarterHelper : Ptr32 Void
+0x09c GdiDCAttributeList : Uint4B
+0x0a0 LoaderLock : Ptr32 _RTL_CRITICAL_SECTION
+0x0a4 OSMajorVersion : Uint4B
+0x0a8 OSMinorVersion : Uint4B
+0x0ac OSBuildNumber : Uint2B
+0x0ae OSCSDVersion : Uint2B
+0x0b0 OSPlatformId : Uint4B
+0x0b4 ImageSubsystem : Uint4B
+0x0b8 ImageSubsystemMajorVersion : Uint4B
+0x0bc ImageSubsystemMinorVersion : Uint4B
+0x0c0 ImageProcessAffinityMask : Uint4B
+0x0c4 GdiHandleBuffer : [34] Uint4B
+0x14c PostProcessInitRoutine : Ptr32 void
+0x150 TlsExpansionBitmap : Ptr32 Void
+0x154 TlsExpansionBitmapBits : [32] Uint4B
+0x1d4 SessionId : Uint4B
+0x1d8 AppCompatFlags : _ULARGE_INTEGER
+0x1e0 AppCompatFlagsUser : _ULARGE_INTEGER
+0x1e8 pShimData : Ptr32 Void
+0x1ec AppCompatInfo : Ptr32 Void
+0x1f0 CSDVersion : _UNICODE_STRING
+0x1f8 ActivationContextData : Ptr32 _ACTIVATION_CONTEXT_DATA
+0x1fc ProcessAssemblyStorageMap : Ptr32 _ASSEMBLY_STORAGE_MAP
+0x200 SystemDefaultActivationContextData : Ptr32 _ACTIVATION_CONTEXT_DATA
+0x204 SystemAssemblyStorageMap : Ptr32 _ASSEMBLY_STORAGE_MAP
+0x208 MinimumStackCommit : Uint4B
+0x20c FlsCallback : Ptr32 Ptr32 Void
+0x210 FlsListHead : _LIST_ENTRY
+0x218 FlsBitmap : Ptr32 Void
+0x21c FlsBitmapBits : [4] Uint4B
+0x22c FlsHighIndex : Uint4B
(3)IsDebuggerPresent函数的反反调试
方法1: 在dbg中直接对IsDebuggerPresent函数进行修改,让其返回即可。
方法2: 对Kernel32.dll中的IsDebuggerPresent函数实现MiniHook(或InlineHook),在FakeIsDebuggerPresent函数中返回FALSE即可。编写一个dll,在加载到进程时,执行MiniHook。这里因为MiniHook框架太大,就不贴出相关程序了,有需要可以留言,此处只附出DLL的编写。
#include "MiniHook.h" typedef
BOOL
(WINAPI* LPFN_ISDEBUGGERPRESENT)(); LPFN_ISDEBUGGERPRESENT __OriginalIsDebuggerPresent = NULL; BOOL
WINAPI
FakeIsDebuggerPresent(VOID)
{
return FALSE;
} BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
if (SunInitialize() != STATUS_SUCCESS)
{
MessageBox(0,"初始化失败","提示",0);
}
if (SunCreateHook(&IsDebuggerPresent, &FakeIsDebuggerPresent,
reinterpret_cast<LPVOID*>(&__OriginalIsDebuggerPresent)) != STATUS_SUCCESS)
{
MessageBox(0,"初始化Hook失败","提示",0);
}
if (SunEnableHook(&IsDebuggerPresent) != STATUS_SUCCESS)
{
MessageBox(0, "创建Hook失败", "提示", 0);
}
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
//SunRemoveHook(&IsDebuggerPresent);
break;
}
return TRUE;
}
二、自定义实现IsDebuggerPresent函数(x86)
自己用汇编实现实现IsDebuggerPresent,如何获得PEB呢? 在应用层,fs寄存器是指向当前线程的TEB结构的,而在内核层,fs寄存器指向PCR(Processor Control Region)的内存,其数据类型是KPCR。所以可以通过当前线程的TEB获得PEB,再取出BeingDebugged的值。
原理:
mov eax, fs:18h // TEB Self指针
mov eax, [eax+30h] // PEB
movzx eax, [eax+2] // PEB->BeingDebugged
实现:
_asm
{
push eax;
mov eax, fs:[0x30]; // PEB
movzx eax, byte ptr[eax + 2]; //BeingDebugged
mov dword ptr[Value], eax; //取值
pop eax;
} if (Value) //判断
{
MessageBox(0,L"检测到调试器",L"提示",0);
}
else
{
MessageBox(0,L"未检测到调试器",L"提示",0);
}
三、深度解析调试中各标志位的变化
这部分转载于:https://blog.csdn.net/qq_35713009/article/details/86603668/
加密与解密中提供了从外部代码去除某进程BeingDebugged标志的方式,可以作为调试器的插件去除这种反调试方法。但BeingDebugged标记在生成时还留下了一些后患。
那么是否可以简单认为将 PEB 的 BeingDebugged 标志篡改就可以达到越过IsDebuggerPresent函数的目的呢?当然不能。因为调试时不仅仅这一位被置值了,而是连锁反应... ...
(1) PEB 的 BeingDebugged 标志(BOOL型),被修改为1,表示正在被调试
(2)NtGlobalFlag的变化
LdrpInitialize函数是一个新进程的初始线程开始在用户态执行的最早代码,在这个函数内部有一段这样的代码:
if (Peb->BeingDebugged)
{
Peb->NtGlobalFlag |= FLG_HEAP_ENABLE_FREE_CHECK | FLG_HEAP_ENABLE_TAIL_CHECK | FLG_HEAP_VALIDATE_PARAMETERS; }
这说明BeingDebugged被设置为1后,NtGlobalFlag也被设置了一个标记,通过调试可发现这个标记为0x70。
(3)RtlCreateHeap中创建调试堆时的变化
那么 NtGlobalFlag 有没有向 BeingDebugged 一样留下痕迹呢?是有的,在初始化堆的函数 RtlCreateHeap 中可以找到相应代码。
if (RtlpGetMode() == UserMode)
{
/* Also check these flags if in usermode */
if (NtGlobalFlags & FLG_HEAP_VALIDATE_ALL)
Flags |= HEAP_VALIDATE_ALL_ENABLED; if (NtGlobalFlags & FLG_HEAP_VALIDATE_PARAMETERS)
Flags |= HEAP_VALIDATE_PARAMETERS_ENABLED; if (NtGlobalFlags & FLG_USER_STACK_TRACE_DB)
Flags |= HEAP_CAPTURE_STACK_BACKTRACES;
} /* Call special heap */
if (RtlpHeapIsSpecial(Flags))
return RtlDebugCreateHeap(Flags, Addr, TotalSize, CommitSize, Lock, Parameters); FORCEINLINE BOOLEAN
RtlpHeapIsSpecial(ULONG Flags)
{
if (Flags & HEAP_SKIP_VALIDATION_CHECKS) return FALSE; if (Flags & (HEAP_FLAG_PAGE_ALLOCS |
HEAP_VALIDATE_ALL_ENABLED |
HEAP_VALIDATE_PARAMETERS_ENABLED |
HEAP_CAPTURE_STACK_BACKTRACES |
HEAP_CREATE_ENABLE_TRACING))
{
/* This is a special heap */
return TRUE;
} /* No need for a special treatment */
return FALSE;
}
RtlDebugCreateHeap内部实际上又调用了RtlCreateHeap,不过这次Flags参数又多了几个属性,分别是HEAP_SKIP_VALIDATION_CHECKS, HEAP_TAIL_CHECKING_ENABLED, HEAP_FREE_CHECKING_ENABLED。第一个属性使得 RtlCreateHeap和RtlDebugCreateHeap不会再继续重复的相互调用。
/* All validation performed, now call the real routine with skip validation check flag */
Flags |= HEAP_SKIP_VALIDATION_CHECKS |
HEAP_TAIL_CHECKING_ENABLED |
HEAP_FREE_CHECKING_ENABLED; Heap = RtlCreateHeap(Flags, Addr, ReserveSize, CommitSize, Lock, Parameters);
与后两个标记有关的有这样一段代码,
if (Heap->Flags & HEAP_FREE_CHECKING_ENABLED) {
RtlFillMemoryUlong((PCHAR)(BusyBlock + 1), Size & ~0x3, ALLOC_HEAP_FILL); } if (Heap->Flags & HEAP_TAIL_CHECKING_ENABLED) {
RtlFillMemory((PCHAR)ReturnValue + Size, CHECK_HEAP_TAIL_SIZE, CHECK_HEAP_TAIL_FILL) BusyBlock->Flags |= HEAP_ENTRY_FILL_PATTERN; } #define ALLOC_HEAP_FILL 0xBAADF00D #define FREE_HEAP_FILL 0xFEEEFEEE #define CHECK_HEAP_TAIL_FILL 0xAB
意思是会用这3种数据来填堆,即当堆中多次重复出现这3种数据时,就表示在调试状态中。这些东西通常被称为HeapMagic。
除此之外,Flags在RltCreateHeap函数后面还有一些感染操作,使得 Heap->Flags 和 Heap->ForceFlags 都附带了调试信息,通常在程序正常执行的情况下,Flags为2,ForceFlags为0;而在调试状态下,Flags为0x50000062,ForceFlags为0x40000060。
// x86下PEB结构
NTDLL_Test!_PEB
+0x000 InheritedAddressSpace : UChar
+0x001 ReadImageFileExecOptions : UChar
+0x002 BeingDebugged : UChar // (BOOL)被调试时,被置为1
+0x003 SpareBool : UChar
+0x004 Mutant : Ptr32 Void
+0x008 ImageBaseAddress : Ptr32 Void
+0x00c Ldr : Ptr32 _PEB_LDR_DATA
+0x010 ProcessParameters : Ptr32 _RTL_USER_PROCESS_PARAMETERS
+0x014 SubSystemData : Ptr32 Void
+0x018 ProcessHeap : Ptr32 Void
+0x01c FastPebLock : Ptr32 _RTL_CRITICAL_SECTION
+0x020 SparePtr1 : Ptr32 Void
+0x024 SparePtr2 : Ptr32 Void
+0x028 EnvironmentUpdateCount : Uint4B
+0x02c KernelCallbackTable : Ptr32 Void
+0x030 SystemReserved : [1] Uint4B
+0x034 ExecuteOptions : Pos 0, 2 Bits
+0x034 SpareBits : Pos 2, 30 Bits
+0x038 FreeList : Ptr32 _PEB_FREE_BLOCK
+0x03c TlsExpansionCounter : Uint4B
+0x040 TlsBitmap : Ptr32 Void
+0x044 TlsBitmapBits : [2] Uint4B
+0x04c ReadOnlySharedMemoryBase : Ptr32 Void
+0x050 ReadOnlySharedMemoryHeap : Ptr32 Void
+0x054 ReadOnlyStaticServerData : Ptr32 Ptr32 Void
+0x058 AnsiCodePageData : Ptr32 Void
+0x05c OemCodePageData : Ptr32 Void
+0x060 UnicodeCaseTableData : Ptr32 Void
+0x064 NumberOfProcessors : Uint4B
+0x068 NtGlobalFlag : Uint4B // 被调试时,会被置为x070
+0x070 CriticalSectionTimeout : _LARGE_INTEGER
+0x078 HeapSegmentReserve : Uint4B
+0x07c HeapSegmentCommit : Uint4B
+0x080 HeapDeCommitTotalFreeThreshold : Uint4B
+0x084 HeapDeCommitFreeBlockThreshold : Uint4B
+0x088 NumberOfHeaps : Uint4B
+0x08c MaximumNumberOfHeaps : Uint4B
+0x090 ProcessHeaps : Ptr32 Ptr32 Void
+0x094 GdiSharedHandleTable : Ptr32 Void
+0x098 ProcessStarterHelper : Ptr32 Void
+0x09c GdiDCAttributeList : Uint4B
+0x0a0 LoaderLock : Ptr32 _RTL_CRITICAL_SECTION
+0x0a4 OSMajorVersion : Uint4B
+0x0a8 OSMinorVersion : Uint4B
+0x0ac OSBuildNumber : Uint2B
+0x0ae OSCSDVersion : Uint2B
+0x0b0 OSPlatformId : Uint4B
+0x0b4 ImageSubsystem : Uint4B
+0x0b8 ImageSubsystemMajorVersion : Uint4B
+0x0bc ImageSubsystemMinorVersion : Uint4B
+0x0c0 ImageProcessAffinityMask : Uint4B
+0x0c4 GdiHandleBuffer : [34] Uint4B
+0x14c PostProcessInitRoutine : Ptr32 void
+0x150 TlsExpansionBitmap : Ptr32 Void
+0x154 TlsExpansionBitmapBits : [32] Uint4B
+0x1d4 SessionId : Uint4B
+0x1d8 AppCompatFlags : _ULARGE_INTEGER
+0x1e0 AppCompatFlagsUser : _ULARGE_INTEGER
+0x1e8 pShimData : Ptr32 Void
+0x1ec AppCompatInfo : Ptr32 Void
+0x1f0 CSDVersion : _UNICODE_STRING
+0x1f8 ActivationContextData : Ptr32 _ACTIVATION_CONTEXT_DATA
+0x1fc ProcessAssemblyStorageMap : Ptr32 _ASSEMBLY_STORAGE_MAP
+0x200 SystemDefaultActivationContextData : Ptr32 _ACTIVATION_CONTEXT_DATA
+0x204 SystemAssemblyStorageMap : Ptr32 _ASSEMBLY_STORAGE_MAP
+0x208 MinimumStackCommit : Uint4B
+0x20c FlsCallback : Ptr32 Ptr32 Void
+0x210 FlsListHead : _LIST_ENTRY
+0x218 FlsBitmap : Ptr32 Void
+0x21c FlsBitmapBits : [4] Uint4B
+0x22c FlsHighIndex : Uint4B
IsDebuggerPresent的反调试与反反调试的更多相关文章
- 反编译apk + eclipse中调试smali
1.对apk使用apktool反编译出可调试的smali代码到out文件夹 apktool -d d 定点加粉丝_com.mingniu.wxddjfs_440.apk -o out 这里必须使用-d ...
- [Android]反编译apk + eclipse中调试smali
从来没有想过反编译apk是来的如此方便,并且还可以修改后重新编译运行,这比在win下修改pe容易多了,感谢apktool和smali工具的作者提供这么好的工具. 跟踪apk一般的做法是在反编译的sma ...
- Win7 x86内核调试与TP反调试的研究
参考 这两天对某P双机调试的学习及成果 ,非常好的一篇分析贴. 本文在Win7 x86下的分析,在虚拟机中以/DEBUG模式启动TP游戏,系统会自动重启. 0x01 内核调试全局变量 根据软件调试 ...
- 爬虫(Spider),反爬虫(Anti-Spider),反反爬虫(Anti-Anti-Spider)
爬虫(Spider),反爬虫(Anti-Spider),反反爬虫(Anti-Anti-Spider),这之间的斗争恢宏壮阔... Day 1小莫想要某站上所有的电影,写了标准的爬虫(基于HttpCli ...
- Android反编译(二)之反编译XML资源文件
Android反编译(二) 之反编译XML资源文件 [目录] 1.工具 2.反编译步骤 3.重新编译APK 4.实例 5.装X技巧 6.学习总结 1.工具 1).反编译工具 apktool http ...
- Android反编译(一)之反编译JAVA源码
Android反编译(一) 之反编译JAVA源码 [目录] 1.工具 2.反编译步骤 3.实例 4.装X技巧 1.工具 1).dex反编译JAR工具 dex2jar http://code.go ...
- 转 谈谈android反编译和防止反编译的方法
谈谈android反编译和防止反编译的方法 android基于java的,而java反编译工具很强悍,所以对正常apk应用程序基本上可以做到100%反编译还原. 因此开发人员如果不准备开源自己的项 ...
- 谈谈android反编译和防止反编译的方法(转)
谈谈android反编译和防止反编译的方法(转) android基于java的,而java反编译工具很强悍,所以对正常apk应用程序基本上可以做到100%反编译还原. 因此开发人员如果不准备开源自己的 ...
- (转)unity3D 如何提取游戏资源 (反编译)+代码反编译
原帖:http://bbs.9ria.com/thread-401140-1-1.html 首先感谢 雨松MOMO 的一篇帖子 教我们怎么提取 .ipa 中的游戏资源.教我们初步的破解unity3d资 ...
- python爬虫---详解爬虫分类,HTTP和HTTPS的区别,证书加密,反爬机制和反反爬策略,requests模块的使用,常见的问题
python爬虫---详解爬虫分类,HTTP和HTTPS的区别,证书加密,反爬机制和反反爬策略,requests模块的使用,常见的问题 一丶爬虫概述 通过编写程序'模拟浏览器'上网,然后通 ...
随机推荐
- Linux常用性能诊断命令详解
top top命令动态地监视进程活动与系统负载等信息. 使用示例: top 效果如下图: 以上命令输出视图中分为两个区域,一个统计信息区,一个进程信息区. 统计信息区: 第一行信息依次为:系统时间.运 ...
- Docker——时间配置
一.常用时间表示 GMT(Greenwich Mean Time):格林威治时间,格林威治被定义为了\(0^o\)经线开始的地方,地球每15进度分为一个时区,共24个时区,相邻时区相差1个小时.中国位 ...
- tomcat manager status配置
1. 确保tomcat下原来自带的几个项目未被删掉,tomcat启动时localhost:8080能直接访问tomcat主页 2. 修改tomcat下 conf/tomcat-users-xml文件, ...
- VMware安装win7后,安装VMware Tools时报错安装程序无法继续。本程序需要您将此虚拟机上安装的操作系统更新到SP1
具体报错: 倘若你用的是这样的镜像:cn_windows_7_enterprise_x64_dvd_x15-70741.iso 换镜像源.换镜像源.换镜像源! 换成带sp1的iso镜像:cn_wind ...
- Linux系统常用的命令
1.查看本机IP地址:ifconfig 2.查看当前所在路径:pwd 3.查看指定名称线程:ps -ef | grep tomcat 4.查看当前目录结构:ll 或者 ls 5.杀死指定线程:kill ...
- 基于COLA架构的电商财务系统-总
财务 清算-clearing 对账-check 结算-settle 平账-correct 划拨-remit 包划分 按照COLA规则进行划分,综合考虑功能和领域两个维度包结构定义 技术参考 dddpl ...
- 在Spring框架中如何更有效地使用JDBC?
使用SpringJDBC 框架,资源管理和错误处理的代价都会被减轻.所以开发者只需写statements 和 queries从数据存取数据,JDBC也可以在Spring框架提供的模板类的帮助下更有效地 ...
- WebApplicationContext?
WebApplicationContext 继承了ApplicationContext 并增加了一些WEB应用必备的特有功能,它不同于一般的ApplicationContext ,因为它能处理主题, ...
- mq 的缺点?
(1)系统可用性降低 系统引入的外部依赖越多,越容易挂掉,本来你就是 A 系统调用 BCD 三个系统的接口就好了,人 ABCD 四个系统好好的,没啥问题,你偏加个 MQ 进来,万一MQ 挂了咋整?MQ ...
- kafka 为什么那么快?
Cache Filesystem Cache PageCache缓存 顺序写 由于现代的操作系统提供了预读和写技术,磁盘的顺序写大多数情况下比随机写内存还要快. Zero-copy 零拷⻉技术减少拷贝 ...