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入门教程】批量修改文件名,批量移动文件

            Python提供了高效的高级数据结构,还能简单有效地面向对象编程.Python语法和动态类型,以及解释型语言的本质,使它成为多数平台上写脚本和快速开发应用的编程语言.本篇文章是&quo ...

  2. hugp-MemE关键美化

    配置front matter 使用vscode snippet快捷生成front matter 参考博客:vs-code-workflows-for-hugo. markdown-snippets-n ...

  3. Spring Boot实现高质量的CRUD-3

    (续前文) 7.Service接口类 ​ ​ Service类提供业务的实现逻辑,其调用Dao类的方法进行数据存取,并为Controller类提供方法.类似于Dao的接口类,服务层使用接口类,便于代码 ...

  4. 聊一聊 Rust 的 stack overflow

    早上看到了这篇文章 智能指针有可能会让你的应用崩溃, 下面分析一下 会导致 stack overflow 的代码 struct Node<T> { val: T, next: Option ...

  5. 6个常见的IB网络不通问题

    摘要:如果遇到IB网络不通,可以试着从高层往底层逐步分析看看. 本文分享自华为云社区<常见IB网络不通问题记录>,作者: tsjsdbd . 如果遇到IB网络不通,可以试着从高层往底层逐步 ...

  6. 离线安装mysql报错解决方法:/usr/sbin/mysqld: error while loading shared libraries: libaio.so.1: cannot open sha --九五小庞

    Linux:centos 7.6 64位 mysql:5.6使用离线方式安装:rpm -ivh --nodeps mysql* ,执行 systemctl start mysqld.service发现 ...

  7. Vue Router 源码分析💪

    专栏分享:vue2源码专栏,玩具项目专栏,硬核 推荐 欢迎各位 ITer 关注点赞收藏 本篇文章参考版本:vue-router v3.x 最终成果,实现了一个可运行的核心路由工程:柏成/vue-rou ...

  8. Excel 进度图表制作

    Excel 改变图标的形状 最终效果 过程有点杂乱,不再重新整理,基本照着下面的设就完事了. 未完成的想用柱型,和已完成的相结合 右击,更改表类型 选择簇状柱形图.次标轴 注意主.次坐标 进度改为折线 ...

  9. Code Generate 代码生成器 V1.0

    Code Generate V1.0 代码生成器 根据配置的模板,根据建表语句,生成Code. 例如java代码.vue代码.jsp代码以及html代码等等,均可根据自己的代码写作习惯进行配置. 缺点 ...

  10. 现代C++(Modern C++)基本用法实践:五、智能指针

    概述 c++效率较高的一个原因是我们可以自己定制策略手动申请和释放内存,当然,也伴随着开发效率降低和内存泄漏的风险.为了减少手动管理内存带来的困扰,c++提出了智能指针,可以帮助我们进行内存管理,有三 ...