ProcessHeap 是Windows进程的默认堆,每个进程都有一个默认的堆,用于在进程地址空间中分配内存空间。默认情况下ProcessHeap由内核进行初始化,该堆中存在一个未公开的属性,它被设置为加载器为进程分配的第一个堆的位置(进程堆标志),ProcessHeap标志位于PEB结构中偏移为0x18处,第一个堆头部有一个属性字段,这个属性叫做ForceFlags属性偏移为0x44,该属性为0说明程序没有被调试,非0说明被调试,另外的Flags属性为2说明被调试,不为2则说明没有被调试。

0:000> dt !_peb
ntdll!_PEB
+0x000 InheritedAddressSpace : UChar
+0x001 ReadImageFileExecOptions : UChar
+0x002 BeingDebugged : UChar
+0x018 ProcessHeap : Ptr32 Void // 找到Process偏移地址 0:000> !heap // 找出堆区首地址
Heap Address NT/Segment Heap
1270000 NT Heap 0:000> !heap -a 1270000 // 查询heep的内存
Index Address Name Debugging options enabled
1: 01270000
Segment at 01270000 to 0136f000 (00006000 bytes committed)
Flags: 40000062
ForceFlags: 40000060
Granularity: 8 bytes
Segment Reserve: 00100000
Segment Commit: 00002000 0:000> dt _HEAP 1270000 // 找到ForceFlags标志的偏移地址
ntdll!_HEAP
+0x000 Segment : _HEAP_SEGMENT
+0x000 Entry : _HEAP_ENTRY
+0x040 Flags : 0x40000062
+0x044 ForceFlags : 0x40000060

这里需要注意一点,堆区在不同系统中偏移值是不同的,在Windows10系统中ForceFlags属性位于堆头部偏移量为0x44处,而默认情况如果被调试则ForceFlags属性为0x40000060,而Flags标志为0x40000062,有了这些参考那么通过汇编语言实现将变得很容易,如下代码则是通过汇编分别读取这两个堆头参数;

#include <stdio.h>
#include <windows.h> // 两种方式输出
int IsDebug(DWORD x)
{
DWORD Debug = 0; if (x == 1)
{
__asm
{
mov eax, fs:[0x18] // TED基地址
mov eax, [eax + 0x30] // PEB基地址
mov eax, [eax + 0x18] // 定位 ProcessHeap
mov eax, [eax + 0x44] // 定位到 ForceFlags
mov Debug, eax
}
}
if (x == 2)
{
__asm
{
mov eax, fs:[0x18] // TED基地址
mov eax, [eax + 0x30] // PEB基地址
mov eax, [eax + 0x18] // 定位 ProcessHeap
mov eax, [eax + 0x40] // 定位到 Flags
mov Debug, eax
}
} return Debug;
} int main(int argc, char * argv[])
{
if (IsDebug(1) && IsDebug(2))
{
printf("[-] 进程正在被调试 \n");
}
else
{
printf("[*] 进程正常 \n");
} system("pause");
return 0;
}

另一种通过C语言实现的反调试版本,其反调试原理与上方相同,只不过此处我们使用了系统的API来完成检测标志位的。

#include <stdio.h>
#include <windows.h>
#include <winternl.h> typedef NTSTATUS(NTAPI *typedef_ZwQueryInformationProcess)(
IN HANDLE ProcessHandle,
IN PROCESSINFOCLASS ProcessInformationClass,
OUT PVOID ProcessInformation,
IN ULONG ProcessInformationLength,
OUT PULONG ReturnLength OPTIONAL
); BOOL IsDebug()
{
HANDLE hProcess = NULL;
DWORD ProcessId = 0;
PROCESS_BASIC_INFORMATION Pbi;
typedef_ZwQueryInformationProcess pZwQueryInformationProcess = NULL;
ProcessId = GetCurrentProcessId();
hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, ProcessId);
if (hProcess != NULL)
{
HMODULE hModule = LoadLibrary("ntdll.dll");
pZwQueryInformationProcess = (typedef_ZwQueryInformationProcess)GetProcAddress(hModule, "ZwQueryInformationProcess"); NTSTATUS Status = pZwQueryInformationProcess(hProcess, ProcessBasicInformation, &Pbi, sizeof(PROCESS_BASIC_INFORMATION), NULL);
if (NT_SUCCESS(Status))
{
DWORD ByteRead = 0;
DWORD ProcessHeap = 0;
ULONG PebBase = (ULONG)Pbi.PebBaseAddress;
DWORD ForceFlagsValue = 1; ReadProcessMemory(hProcess, (LPCVOID)(PebBase + 0x18), &ProcessHeap, 2, &ByteRead);
ReadProcessMemory(hProcess, (LPCVOID)(ProcessHeap + 0x40), &ForceFlagsValue, 4, &ByteRead); if (ForceFlagsValue != 0)
{
return TRUE;
}
}
CloseHandle(hProcess);
}
return FALSE;
} int main(int argc, char * argv[])
{
if (IsDebug())
{
printf("[-] 正在被调试 \n");
} system("pause");
return 0;
}

8.4 ProcessHeap的更多相关文章

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

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

  2. windows进程中的内存结构[转载]

    在阅读本文之前,如果你连堆栈是什么多不知道的话,请先阅读文章后面的基础知识. 接触过编程的人都知道,高级语言都能通过变量名来访问内存中的数据.那么这些变量在内存中是如何存放的呢?程序又是如何使用这些变 ...

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

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

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

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

  5. java\c程序的内存分配

    JAVA 文件编译执行与虚拟机(JVM)介绍 Java 虚拟机(JVM)是可运行Java代码的假想计算机.只要根据JVM规格描述将解释器移植到特定的计算机上,就能保证经过编译的任何Java代码能够在该 ...

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

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

  7. 旧书重温:0day2【2】 实验:三种获取kernel32.dll基址的方法

    0x01 找kernel32基地址的方法一般有三种: 暴力搜索法.异常处理链表搜索法.PEB法. 0x02 基本原理 暴力搜索法是最早的动态查找kernel32基地址的方法.它的原理是几乎所有的win ...

  8. [c++]堆和栈的区别

    堆和栈的区别一.预备知识—程序的内存分配一个由c/C++编译的程序占用的内存分为以下几个部分1.栈区(stack)— 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等.其操作方式类似于数据结构 ...

  9. windows进程中的内存结构(好多API,而且VC最聪明)

    在阅读本文之前,如果你连堆栈是什么多不知道的话,请先阅读文章后面的基础知识.   接触过编程的人都知道,高级语言都能通过变量名来访问内存中的数据.那么这些变量在内存中是如何存放的呢?程序又是如何使用这 ...

  10. 堆和栈的区别【zz】

    一.预备知识—程序的内存分配一个由c/C++编译的程序占用的内存分为以下几个部分1.栈区(stack)— 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等.其操作方式类似于数据结构中的栈.2. ...

随机推荐

  1. Educational Codeforces Round 80 A - D题题解(又是卡很久的一场比赛)

    第八场 CodeForces - 1288A. Deadline Example input 3 1 1 4 5 5 11 output YES YES NO Note In the first te ...

  2. 智慧地产-售楼中心 3D 沙盘可视化

    前言 随着"互联网+房地产"走入全国各大地产项目,房企依托互联网将房地产从传统地产转向智慧地产已然是眼下用户最欢迎的转型模式.智慧地产是由智慧社区.智慧园区.智慧公寓及智能家居等组 ...

  3. ECharts大屏数据可视化展板项目 适配rem

    1.在utils文件夹里新建一个rem.js 2.main.js中引入rem.js 3.vscode中下载cssrem插件,配置Root Font Size大小,为1920/20 = 96. 重启vs ...

  4. watch监听对象遇坑

    当以下数据,有一个变化,就重新调接口.  formInline: {         needTrain: '',         trainResult: '',         userNameS ...

  5. 使用 Sealos 将 ChatGLM3 接入 FastGPT,打造完全私有化 AI 客服

    FastGPT 是一款专为客服问答场景而定制的开箱即用的 AI 知识库问答系统.该系统具备可视化工作流功能,允许用户灵活地设计复杂的问答流程,几乎能满足各种客服需求. 在国内市场环境下,离线部署对于企 ...

  6. C# 排序算法2:选择排序

    选择排序法 ,是在要排序的一组数中,选出最小(或最大)的一个数与第一个位置的数交换:在剩下的数当中找最小的与第二个位置的数交换,即顺序放在已排好序的数列的最后,如此循环,直到全部数据元素排完为止. 原 ...

  7. windows10/liunx创建空大文件

    1.windows10创建空大文件打开cmd命令,进入需要创建文件的目录,使用以下命令创建 fsutil file createnew test001.txt 1073741824 最后的数字代表文件 ...

  8. PMP项目变更管理及变更流程总结

    转载请注明出处: 1. 变更管理流程 2.变更管理流程十步: 0 预防--1发起变更请求--2分析影响--3备选方案--4CCB批准--5更新项目管理计划--6沟通干系人--7执行--8检查--9总结 ...

  9. 使用命令行方式搭建uni-app + Vue3 + Typescript + Pinia + Vite + Tailwind CSS + uv-ui开发脚手架

    .markdown-body { line-height: 1.75; font-weight: 400; font-size: 16px; overflow-x: hidden; color: rg ...

  10. 【LINT】cpplint 分析笔记

    cpplint 分析笔记 · [前提得看下google规范] @2022-1-13 20:44:48 error message formate: [filename] [linenum] [mess ...