8.2 BeingDebugged
BeingDebugged 是Windows
系统PEB
结构体中的一个成员,它是一个标志位,用于标识当前进程是否正在被调试。BeingDebugged的值为0表示当前进程未被调试,值为1表示当前进程正在被调试。由于BeingDebugged
是在PEB
结构体中存储的,因此可以通过访问PEB
结构体来获取BeingDebugged
的值。恶意软件可以使用BeingDebugged
来判断自己是否正在被调试,以此来防止被反病毒工程师或调试程序进行分析。反病毒工程师们也可以通过检查BeingDebugged
的值来判断程序是否正被调试从而进行恶意软件的检测和分析。
进程在运行时,位置FS:[30h]
指向PEB的基地址,为了实现反调试,恶意代码通过这个位置来检查BeingDebugged
标志位是否为1,如果为1则说明进程被调试。
首先我们可以使用dt _teb
命令解析一下TEB
的结构,如下TEB
结构的起始偏移为0x0,而0x30
的位置指向的是ProcessEnvironmentBlock
也就是指向了进程环境块PEB。
0:000> dt _teb
ntdll!_TEB
+0x000 NtTib : _NT_TIB
+0x01c EnvironmentPointer : Ptr32 Void
+0x020 ClientId : _CLIENT_ID
+0x028 ActiveRpcHandle : Ptr32 Void
+0x02c ThreadLocalStoragePointer : Ptr32 Void
+0x030 ProcessEnvironmentBlock : Ptr32 _PEB // PEB 进程环境块
只需要在进程环境块的基础上+0x2
就能定位到线程环境块TEB
中BeingDebugged
的标志,此处的标志位如果为1则说明程序正在被调试,为0则说明没有被调试。
0:000> dt _peb
ntdll!_PEB
+0x000 InheritedAddressSpace : UChar
+0x001 ReadImageFileExecOptions : UChar
+0x002 BeingDebugged : UChar
+0x003 BitField : UChar
+0x003 ImageUsesLargePages : Pos 0, 1 Bit
+0x003 IsProtectedProcess : Pos 1, 1 Bit
我们手动来验证一下,首先线程环境块地址是007f1000
,在此基础上加0x30
即可得到进程环境快的基地址,位置FS:[0x30]
指向PEB的基地址,007ee000
继续加0x2即可得到BeingDebugged
的状态ffff0401
此处我们只需要看byte位是否为1即可。
0:000> r $teb
$teb=007f1000
0:000> dd 007f1000 + 0x30
007f1030 007ee000 00000000 00000000 00000000
007f1040 00000000 00000000 00000000 00000000
0:000> r $peb
$peb=007ee000
0:000> dd 007ee000 + 0x2
007ee002 ffff0401 0000ffff 0c400112 19f0775f
007ee012 0000001b 00000000 09e0001b 0000775f
有了上述知识点的理解,写出一段反调试代码来将变得很容易,如下代码片段所示,如果独立运行则会提示正常程序,一旦进程被调试则会提示异常,此处分别使用三段实现方式,读者可通过向IsDebug()
传入不同的参数启用。
#include <stdio.h>
#include <Windows.h>
// 判断程序是否被调试
int IsDebug(DWORD x)
{
BYTE Debug = 0;
if (x == 1)
{
__asm
{
mov eax, dword ptr fs : [0x30]
mov bl, byte ptr[eax + 0x2]
mov Debug, bl
}
}
if (x == 2)
{
__asm
{
push dword ptr fs : [0x30]
pop edx
mov al, [edx + 2]
mov Debug, al
}
}
if (x == 3)
{
__asm
{
mov eax, fs:[0x18] // TEB Self指针
mov eax, [eax + 0x30] // PEB
movzx eax, [eax + 2] // PEB->BeingDebugged
mov Debug, al
}
}
return Debug;
}
int main(int argc, char* argv[])
{
if (IsDebug(1) && IsDebug(2) && IsDebug(3))
{
printf("[-] 进程正在被调试器调试 \n");
}
else
{
printf("[*] 正常运行 \n");
}
system("pause");
return 0;
}
上述程序被运行,一旦处于调试器模式则会触发被调试的告警,如果恶意代码中使用该种技术阻碍我们正常调试,只需要在x64dbg
的命令行中执行dump fs:[30]+2
来定位到BeingDebugged()
的位置,并将其数值改为0然后运行程序,会发现反调试已经被绕过了。
这里补充一个知识点,通过运用IsDebuggerPresent()
调试函数同样可实现此类功能,IsDebuggerPresent 返回一个布尔值,用于指示调用进程是否正在被调试器调试。该函数不接受参数,并且如果进程正在被调试,则返回 TRUE,否则返回 FALSE。该函数的实现原理同样应用了BeingDebugged
标志位的检测方法。
#include <stdio.h>
#include <Windows.h>
DWORD WINAPI ThreadProc(LPVOID lpParam)
{
while (TRUE)
{
// 检测用ActiveDebugProcess()来创建调试关系
if (IsDebuggerPresent() == TRUE)
{
printf("当前进程正在被调试 \r\n");
// 产生int3异常
DebugBreak();
break;
}
Sleep(1000);
}
return 0;
}
int main(int argc, char * argv[])
{
HANDLE hThread = CreateThread(0, 0, ThreadProc, 0, 0, 0);
if (hThread == NULL)
{
return -1;
}
WaitForSingleObject(hThread, INFINITE);
CloseHandle(hThread);
system("pause");
return 0;
}
上述代码中我们通过使用CreateThread()
函数创建了一个子线程用于每隔1000
毫秒就检测一次是否被调试了,如果被调试则直接产生一个DebugBreak()
也就是int3断点,其反调试效果如下图所示;
本文作者: 王瑞
本文链接: https://www.lyshark.com/post/800bf906.html
版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
8.2 BeingDebugged的更多相关文章
- 【系统篇】从int 3探索Windows应用程序调试原理
探索调试器下断点的原理 在Windows上做开发的程序猿们都知道,x86架构处理器有一条特殊的指令——int 3,也就是机器码0xCC,用于调试所用,当程序执行到int 3的时候会中断到调试器,如果程 ...
- Google之Chromium浏览器源码学习——base公共通用库(四)
本文将介绍debug调试相关的内容,包括调试器.性能分析.堆跟踪.跟踪事件等: alias.h:Alias函数,提供防止载微软的编译器优化某参数变量的操作,内部通过#pragma optimize(& ...
- 反调试技术常用API,用来对付检测od和自动退出程序
在调试一些病毒程序的时候,可能会碰到一些反调试技术,也就是说,被调试的程序可以检测到自己是否被调试器附加了,如果探知自己正在被调试,肯定是有人试图反汇编啦之类的方法破解自己.为了了解如何破解反调试技术 ...
- Delphi_OD_代码_调试_Delphi反调试技术(以OD为例附核心原代码) (转)
1.程序窗口[chuang kou]句柄[ju bing]检测原理:用FindWindow函数[han shu]查找[cha zhao]具有相同窗口[chuang kou]类名和标题的窗口[chuan ...
- 关于《加密与解密》的读后感----对dump脱壳的一点思考
偶然翻了一下手机日历,原来今天是夏至啊,时间过的真快.ISCC的比赛已经持续了2个多月了,我也跟着比赛的那些题目学了2个月.......虽然过程很辛苦,但感觉还是很幸运的,能在大三的时候遇到ISCC, ...
- 枚举PEB获取进程模块列表
枚举进程模块的方法有很多种,常见的有枚举PEB和内存搜索法,今天,先来看看实现起来最简单的枚举PEB实现获取进程模块列表. 首先,惯例是各种繁琐的结构体定义.需要包含 ntifs.h 和 WinDef ...
- Windows x86/ x64 Ring3层注入Dll总结
欢迎转载,转载请注明出处:http://www.cnblogs.com/uAreKongqi/p/6012353.html 0x00.前言 提到Dll的注入,立马能够想到的方法就有很多,比如利用远程线 ...
- KPROCESS IDT PEB Ldr 《寒江独钓》内核学习笔记(3)
继续上一篇(2)未完成的研究,我们接下来学习 KPROCESS这个数据结构. 1. 相关阅读材料 <深入理解计算机系统(原书第2版)> 二. KPROCESS KPROCESS,也叫内核进 ...
- 利用windbg探索进程和进程上下文
1.列出所有活动进程 使用!process命令可以打印出活动进程的信息.第一个参数是要打印的EPROCESS的地址,如果指定为0则表示打印所有的进程.第二个参数用于说明打印进程信息的详细级别.指定0则 ...
- 旧书重温:0day2【3】 详细解读PEB法 查找kener32地址
题外话:上一篇文章中的 PEB法查找kerner32地址的方法 对TEB.PEB .PE结构 知识要求很高,确实在写汇编代码时候小编 感觉自己能力,信手啪啪一顿乱撸,结果一运行,非法访问了,没办法翻阅 ...
随机推荐
- java中基本数据类型和包装数据类型
基本数据类型和包装数据类型在 Java 中有着重要的区别和联系,对于 Java 程序员来说,熟悉这两种数据类型的特点和使用方法是非常必要的. 基本数据类型 Java 中的基本数据类型一共有 8 种,分 ...
- GPT3的技术突破:实现更准确、更真实的语言生成
目录 1. 引言 2. 技术原理及概念 3. 实现步骤与流程 4. 应用示例与代码实现讲解 5. 优化与改进 6. 结论与展望 7. 附录:常见问题与解答 GPT-3 技术突破:实现更准确.更真实的语 ...
- macOS 系统 Kafka 快速入门
Kafka 的核心功能是高性能的消息发送与高性能的消息消费.以下是 Kafka 的快速入门教程. 下载并解压缩 Kafka 二进制代码压缩文件 打开 Kafka 官网的下载地址,可以看到不同版本的 K ...
- 解决Pyonth读取 yaml文件的中文字体,报错UnicodeDecodeError: 'utf-8' codec can't decode byte 0xe5
解决方法: 打开pycharm,点击files>setting 如下 改成UTF-8即可 改完后,之前的yaml文件里面的中文会出现乱码情况 删除后重写 即可
- Centos7 升级 Kubernetes(k8s) 集群
目录 一.系统环境 二.前言 三.Kubernetes(k8s) 集群升级简介 四.升级master主节点 4.1 升级kubeadm 4.2 升级各个组件 4.3 升级 kubelet 和 kube ...
- Day06_Java_作业
A:简答题 1. 类是什么? 对象是什么?举例说明 2. 类由哪些内容组成? 3. 成员变量与局部变量的区别? 4. 什么是匿名对象?什么时候使用匿名对象? 5. 使用面向对象[封装]的好处有哪些? ...
- github上传文件报错failed to push some refs解决
报错内容,不能推送文件到github上 error: failed to push some refs to github地址 原因是github项目与本地文件夹一些关键文件的确实,比如.git,re ...
- NumPy(1)-常用的初始化方法
一.NumPy介绍 NumPy是Python中科学计算的基础包,它是一个Python库,提供多维数组对象,各种派生对象(如掩码数组和矩阵),以及用于数组快速操作的各种API,有包括数学.逻辑.形状操作 ...
- OSS的使用(谷粒商城58-64)
OSS的使用(谷粒商城58-64) 购买之类的就不在这里详述了,阿里云文档几乎都写了 创建bucket 学习阶段,相对独特的点在于我们需要选择公共读 项目开发阶段,不能选择公共读了,要尽量选择私有(代 ...
- wireshark 怎么过滤字符串 和 复制data中的可读文本
设置 首先点击,[捕获]下面的小放大镜 选择 分组字节流 - 窄(UTF-8/ASCII)- 字符串 (注意,要向选择字符串) 效果 复制报文中的可读数据 右键报文,复制,...as Printabl ...