当前位置: 首页 > article >正文

CTF-RE 从0到N: windows反调试-获取Process Environment Block(PEB)信息来检测调试

在Windows操作系统中,Process Environment Block (PEB,进程环境块) 是一个包含特定进程信息的数据结构。它可以被用于反调试中

如何获取PEB指针?

在Windows操作系统中,获取PEB指针的常见方法主要有以下几种。:

1. 使用 NtCurrentPeb 获取 PEB

NtCurrentPeb 是Windows内核提供的一个函数,它返回当前进程的PEB指针。这个方法通常用于内核模式或通过非公开的API调用。在用户模式中,你可以使用 NtCurrentPeb 来获取PEB指针。

PEB* GetPEB()
{
    return NtCurrentPeb();  // 获取当前进程的PEB指针
}

NtCurrentPeb 是Windows的NT内核函数,通常不公开给用户模式程序直接调用,但可以通过动态加载 ntdll.dll 并使用 GetProcAddress 来调用。

2. 使用 NtQueryInformationProcess 获取 PEB

通过 NtQueryInformationProcess 函数,可以查询关于进程的信息,其中包括PEB的指针。这是通过NT内部函数来实现的。

#include <Windows.h>
#include <winternl.h>

typedef struct _PROCESS_BASIC_INFORMATION {
    ULONG Reserved;
    ULONG PebBaseAddress;  // PEB的地址
    ULONG AffinityMask;
    ULONG BasePriority;
    ULONG UniqueProcessId;
    ULONG InheritedFromUniqueProcessId;
} PROCESS_BASIC_INFORMATION;

typedef NTSTATUS(WINAPI* NtQueryInformationProcess_t)(
    HANDLE ProcessHandle,
    PROCESS_INFORMATION_CLASS ProcessInformationClass,
    PVOID ProcessInformation,
    ULONG ProcessInformationLength,
    PULONG ReturnLength
);

PEB* GetPEB(HANDLE hProcess)
{
    NtQueryInformationProcess_t NtQueryInformationProcess =
        (NtQueryInformationProcess_t)GetProcAddress(GetModuleHandle(L"ntdll.dll"), "NtQueryInformationProcess");

    PROCESS_BASIC_INFORMATION pbi;
    ULONG len = 0;
    NTSTATUS status = NtQueryInformationProcess(hProcess, ProcessBasicInformation, &pbi, sizeof(pbi), &len);
    if (NT_SUCCESS(status))
    {
        return (PEB*)pbi.PebBaseAddress;
    }
    return NULL;
}

:此方法需要依赖动态加载 ntdll.dll,并调用 NtQueryInformationProcess 函数。这个函数是Windows的NT内核接口,返回关于进程的详细信息。

3. 直接通过 NtQueryInformationProcess 查询 PEB 地址

也可以通过调用 NtQueryInformationProcess 来获取进程的PEB地址。你可以查询有关进程的基本信息,其中就包含PEB的地址。

#include <windows.h>
#include <winternl.h>

typedef enum _PROCESSINFOCLASS {
    ProcessBasicInformation = 0
} PROCESSINFOCLASS;

typedef struct _PROCESS_BASIC_INFORMATION {
    ULONG Reserved;
    ULONG PebBaseAddress; // PEB地址
    ULONG AffinityMask;
    ULONG BasePriority;
    ULONG UniqueProcessId;
    ULONG InheritedFromUniqueProcessId;
} PROCESS_BASIC_INFORMATION;

typedef NTSTATUS(WINAPI* NtQueryInformationProcess_t)(
    HANDLE ProcessHandle,
    PROCESSINFOCLASS ProcessInformationClass,
    PVOID ProcessInformation,
    ULONG ProcessInformationLength,
    PULONG ReturnLength
);

PEB* GetPEB(HANDLE processHandle)
{
    PROCESS_BASIC_INFORMATION pbi;
    ULONG len = 0;
    NtQueryInformationProcess_t NtQueryInformationProcess = 
        (NtQueryInformationProcess_t)GetProcAddress(GetModuleHandle(L"ntdll.dll"), "NtQueryInformationProcess");

    NTSTATUS status = NtQueryInformationProcess(processHandle, ProcessBasicInformation, &pbi, sizeof(pbi), &len);
    if (NT_SUCCESS(status))
    {
        return (PEB*)pbi.PebBaseAddress;
    }
    return NULL;
}

检测PEB的哪些位置来检测调试?

  1. 检查BeingDebugged标志:

    • PEB结构中的BeingDebugged字段直接指示进程是否正在被调试。该字段是一个布尔值,当进程在调试器下运行时,它的值为1,否则为0。
    BOOL IsDebuggerPresent()
    {
        PEB* peb = (PEB*)__readfsdword(0x30); // 获取PEB地址
        return peb->BeingDebugged; // 返回BeingDebugged字段的值
    }
    
  2. 检查NtGlobalFlag标志:

    • PEB中的NtGlobalFlag字段包含一些系统标志,其中某些标志在进程被调试器附加时会被设置。例如,FLG_HEAP_ENABLE_TAIL_CHECK, FLG_HEAP_ENABLE_FREE_CHECKFLG_HEAP_VALIDATE_PARAMETERS 会在调试器附加时被设置。
    BOOL CheckNtGlobalFlag()
    {
        PEB* peb = (PEB*)__readfsdword(0x30); // 获取PEB地址
        DWORD NtGlobalFlag = peb->NtGlobalFlag;
        return (NtGlobalFlag & 0x70) != 0; // 检查特定的调试标志
    }
    
  3. 检查Heap Flags和ForceFlags:

    • 调试器通常会修改PEB中的Heap Flags和ForceFlags,以启用更严格的堆检查。在PEB中的ProcessHeap字段指向进程的默认堆,这些标志位于该堆结构中。
    BOOL CheckHeapFlags()
    {
        PEB* peb = (PEB*)__readfsdword(0x30); // 获取PEB地址
        PVOID heap = peb->ProcessHeap; // 获取默认堆地址
        DWORD heapFlags = *(DWORD*)((BYTE*)heap + 0x40);
        DWORD forceFlags = *(DWORD*)((BYTE*)heap + 0x44);
        return (heapFlags & 2) || (forceFlags != 0);
    }
    
  4. 通过PEB中的StartupInfo检查调试器:

    • PEB中的StartupInfo结构包含有关进程启动的详细信息。可以通过检查StartupInfo中的特定字段来判断是否有调试器存在。
    BOOL CheckStartupInfo()
    {
        PEB* peb = (PEB*)__readfsdword(0x30); // 获取PEB地址
        STARTUPINFO* startupInfo = &peb->ProcessParameters->StartupInfo;
        return startupInfo->dwFlags & STARTF_FORCEONFEEDBACK; // 检查特定标志
    }
    

示例crackMe

以下是反调试代码的反编译示例

if ( *((_DWORD *)NtCurrentPeb()->ProcessHeap + 3) != 2 )
    a2[v6] = 34;
if ( (NtCurrentPeb()->NtGlobalFlag & 0x70) != 0 )
    v12 = v10 + v11;
if ( (unsigned __int8)*(_DWORD *)&NtCurrentPeb()->BeingDebugged )
{
    v10 = -83;
    v11 = 43;
}

http://www.kler.cn/a/391638.html

相关文章:

  • Spring MVC 与 JSP 数据传输
  • 使用elementUI实现表格行拖拽改变顺序,无需引入外部库
  • mongoDB的安装及使用
  • 深度学习——权重初始化、评估指标、梯度消失和梯度爆炸
  • PostgreSQL 开启密码验证插件
  • 设备接入到NVR管理平台EasyNVR多品牌NVR管理工具/设备的音视频配置参考
  • 时间序列数据结构、持久数据结构详细解读
  • DHCP与FTP
  • 【设计模式】行为型模式(一):模板方法模式、观察者模式
  • 番外篇 | 关于YOLO11算法的改进点总结
  • 计算机毕业设计Python+大模型动漫推荐系统 动漫视频推荐系统 机器学习 协同过滤推荐算法 bilibili动漫爬虫 数据可视化 数据分析 大数据毕业设计
  • Pytorch实现运动鞋识别
  • KPI绩效系统源码,java版医院绩效核算系统源码,科室绩效考核、奖金核算、审核、发放一体化
  • GIS前后端分离项目展示
  • 电商系统开发:Spring Boot框架的实践
  • Day09 C++ 存储类
  • ubuntu2204部署RAGFlow(非docker)
  • HTTP vs. HTTPS:从基础到安全的全面对比
  • Hadoop + Hive + Apache Ranger 源码编译记录
  • MySql--增删改查表设计总结
  • 区块链技术在供应链管理中的应用
  • LLMs:MindFormers的简介、安装和使用方法、案例应用
  • @RestController 源码解读:解决 Web 开发中 REST 服务的疑难杂症
  • Hbase入门
  • 树莓派安装FreeSWITCH
  • v-html 富文本中图片使用element-ui image-viewer组件实现预览,并且阻止滚动条