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结构 知识要求很高,确实在写汇编代码时候小编 感觉自己能力,信手啪啪一顿乱撸,结果一运行,非法访问了,没办法翻阅 ...
随机推荐
- 带你体验AI系列之云原生最佳实践--免费体验GPT-4教程
前言 [GPT-4]是OpenAI最新推出的大型语言模型,它支持图像和文本输入,以文本形式输出.它比GPT-3.5更大.更强.更猛.最重要的是据与研究表明,他在某些场景下,可以通过图灵测试.但是, ...
- S32DS学习日志:debug文件和烧录的.hex文件
工程导入之后先clean一下,重新编译生成的文件默认在Production文件下面,得重新设置 折腾半天用jlink烧录没反应,原来是这里错了. production下的文件是用来用来集成bootlo ...
- CKS 考试题整理 (09)-日志审计 log audit
Task 在cluster中启用审计日志.为此,请启用日志后端,并确保: 日志存储在 /var/log/kubernetes/audit-logs.txt 日志文件能保留 10 天 最多保留 2 个旧 ...
- 【TVM模型编译】0.onnx模型优化流程.md
本文以及后续文章,着重于介绍tvm的完整编译流程. 后续文章将会按照以上流程,介绍tvm源码.其中涉及一些编程技巧.以及tvm概念,不在此部分进行进一步讲解,另有文章进行介绍. 首先介绍一下,从onn ...
- 大数据实战手册-开发篇之RDD:计算 transform->action
2.2 RDD:计算 transform->action 2.2.1 aggregate x = sc.parallelize([2,3,4], 2)[Task不能跨分片,task数为2] ne ...
- 【笔试实战】LeetCode题单刷题-编程基础 0 到 1【三】
682. 棒球比赛 题目链接 682. 棒球比赛 题目描述 你现在是一场采用特殊赛制棒球比赛的记录员.这场比赛由若干回合组成,过去几回合的得分可能会影响以后几回合的得分. 比赛开始时,记录是空白的.你 ...
- GetX 关于报错 Null check operator used on a null value的解决
import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'logic.dart'; class Ge ...
- Redis核心技术与实践 01 | 基本架构:一个键值数据库包含什么?
原文地址:https://time.geekbang.org/column/article/268262 个人博客地址:http://njpkhuan.cn/archives/redis-he-xin ...
- Ubuntu 20.04使用 VNC远程桌面连接避坑指南
Ubuntu 20.04使用 VNC远程桌面连接避坑指南 自从开始使用Ubuntu 20.04搭建深度学习服务器,就想到使用VNC远程桌面连接使用.可是之前一直使用的是Ubuntu18.04,心里想着 ...
- 手摸手带你初探Vue 3.0
1 前言 距离Vue 3.0正式发布已经过去一段时间了,2月7日Vue团队正式宣布Vue 3正式成为新的默认版本.最近接触的新项目也使用Vue 3.0来开发,因此有必要对它进行一波总结和学习. 2 简 ...