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就能定位到线程环境块TEBBeingDebugged的标志,此处的标志位如果为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的更多相关文章

  1. 【系统篇】从int 3探索Windows应用程序调试原理

    探索调试器下断点的原理 在Windows上做开发的程序猿们都知道,x86架构处理器有一条特殊的指令——int 3,也就是机器码0xCC,用于调试所用,当程序执行到int 3的时候会中断到调试器,如果程 ...

  2. Google之Chromium浏览器源码学习——base公共通用库(四)

    本文将介绍debug调试相关的内容,包括调试器.性能分析.堆跟踪.跟踪事件等: alias.h:Alias函数,提供防止载微软的编译器优化某参数变量的操作,内部通过#pragma optimize(& ...

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

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

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

    1.程序窗口[chuang kou]句柄[ju bing]检测原理:用FindWindow函数[han shu]查找[cha zhao]具有相同窗口[chuang kou]类名和标题的窗口[chuan ...

  5. 关于《加密与解密》的读后感----对dump脱壳的一点思考

    偶然翻了一下手机日历,原来今天是夏至啊,时间过的真快.ISCC的比赛已经持续了2个多月了,我也跟着比赛的那些题目学了2个月.......虽然过程很辛苦,但感觉还是很幸运的,能在大三的时候遇到ISCC, ...

  6. 枚举PEB获取进程模块列表

    枚举进程模块的方法有很多种,常见的有枚举PEB和内存搜索法,今天,先来看看实现起来最简单的枚举PEB实现获取进程模块列表. 首先,惯例是各种繁琐的结构体定义.需要包含 ntifs.h 和 WinDef ...

  7. Windows x86/ x64 Ring3层注入Dll总结

    欢迎转载,转载请注明出处:http://www.cnblogs.com/uAreKongqi/p/6012353.html 0x00.前言 提到Dll的注入,立马能够想到的方法就有很多,比如利用远程线 ...

  8. KPROCESS IDT PEB Ldr 《寒江独钓》内核学习笔记(3)

    继续上一篇(2)未完成的研究,我们接下来学习 KPROCESS这个数据结构. 1. 相关阅读材料 <深入理解计算机系统(原书第2版)> 二. KPROCESS KPROCESS,也叫内核进 ...

  9. 利用windbg探索进程和进程上下文

    1.列出所有活动进程 使用!process命令可以打印出活动进程的信息.第一个参数是要打印的EPROCESS的地址,如果指定为0则表示打印所有的进程.第二个参数用于说明打印进程信息的详细级别.指定0则 ...

  10. 旧书重温:0day2【3】 详细解读PEB法 查找kener32地址

    题外话:上一篇文章中的 PEB法查找kerner32地址的方法 对TEB.PEB .PE结构 知识要求很高,确实在写汇编代码时候小编 感觉自己能力,信手啪啪一顿乱撸,结果一运行,非法访问了,没办法翻阅 ...

随机推荐

  1. Python time strftime() 方法的使用

    1.描述 strftime() 用于格式化时间,返回以可读字符串表示的时间,格式自定义. 2.说明 python中日期和时间的格式化符号有很多,下面列举常用的符号:  %y 两位数的年份表示(00-9 ...

  2. 三分钟快速了解什么是MES系统

    大家好,我是Edison. 近日我打算系统学习和整理一下MES/MOM系统相关的领域知识,从而构建我的业务域知识背景.万丈高楼平地起,我们先从快速了解什么是MES系统开始吧! 作为IT技术从业者,特别 ...

  3. Java CAS:AtomicInteger、AtomicReference、AtomicStampedReference

    Java CAS:AtomicInteger.AtomicReference.AtomicStampedReference 什么是CAS? 什么是CAS? 即比较并替换,实现并发算法时常用到的一种技术 ...

  4. 3. AOP

    1. 代理模式 1.1 概念 ① 介绍 二十三种设计模式中的一种,属于结构型模式.它的作用就是通过提供一个代理类,让我们在调用目标方法的时候,不再是直接对目标方法进行调用,而是通过代理类间接调用.让不 ...

  5. celery笔记九之task运行结果查看

    本文首发于公众号:Hunter后端 原文链接:celery笔记九之task运行结果查看 这一篇笔记介绍一下 celery 的 task 运行之后结果的查看. 前面我们使用的配置是这样的: # sett ...

  6. 微型神经网络库MicroGrad-基于标量自动微分的类pytorch接口的深度学习框架

    一.MicroGrad MicroGrad是大牛Andrej Karpathy写的一个非常轻量级别的神经网络库(框架),其基本构成为一个90行python代码的标量反向传播(自动微分)引擎,以及在此基 ...

  7. 【笔试实战】LeetCode题单刷题-编程基础 0 到 1【二】

    1822. 数组元素积的符号 题目链接 1822. 数组元素积的符号 题目描述 已知函数 signFunc(x) 将会根据 x 的正负返回特定值: 如果 x 是正数,返回 1 . 如果 x 是负数,返 ...

  8. 一个高性能、低内存文件上传流.Net组件

    推荐一个用于轻松实现文件上传功能的组件. 项目简介 一个基于 .NET 平台的开源项目,提供了一个简单易用的 API,可以在 Web 应用程序中快速集成文件上传功能. 优化多部分流式文件上传性能:减少 ...

  9. SSE图像算法优化系列三十一:RGB2HSL/RGB2HSV及HSL2RGB/HSV2RGB的指令集优化-上。

    RGB和HSL/HSV颜色空间的相互转换在我们的图像处理中是有着非常广泛的应用的,无论是是图像调节,还是做一些肤色算法,HSL/HSV颜色空间都非常有用,他提供了RGB颜色空间不具有的一些独特的特性, ...

  10. Raw数据相关概念

    什么是"RAW"? 维基百科的字面解释是:原始图像文件包含从数码相机.扫描器或电影胶片扫描仪的图像传感器所处理数据.RAW文件包含创建一个可视图像所必须的相机传感器数据信息. 通俗 ...