8.4 ProcessHeap
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的更多相关文章
- 关于《加密与解密》的读后感----对dump脱壳的一点思考
偶然翻了一下手机日历,原来今天是夏至啊,时间过的真快.ISCC的比赛已经持续了2个多月了,我也跟着比赛的那些题目学了2个月.......虽然过程很辛苦,但感觉还是很幸运的,能在大三的时候遇到ISCC, ...
- windows进程中的内存结构[转载]
在阅读本文之前,如果你连堆栈是什么多不知道的话,请先阅读文章后面的基础知识. 接触过编程的人都知道,高级语言都能通过变量名来访问内存中的数据.那么这些变量在内存中是如何存放的呢?程序又是如何使用这些变 ...
- 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,也叫内核进 ...
- java\c程序的内存分配
JAVA 文件编译执行与虚拟机(JVM)介绍 Java 虚拟机(JVM)是可运行Java代码的假想计算机.只要根据JVM规格描述将解释器移植到特定的计算机上,就能保证经过编译的任何Java代码能够在该 ...
- 旧书重温:0day2【3】 详细解读PEB法 查找kener32地址
题外话:上一篇文章中的 PEB法查找kerner32地址的方法 对TEB.PEB .PE结构 知识要求很高,确实在写汇编代码时候小编 感觉自己能力,信手啪啪一顿乱撸,结果一运行,非法访问了,没办法翻阅 ...
- 旧书重温:0day2【2】 实验:三种获取kernel32.dll基址的方法
0x01 找kernel32基地址的方法一般有三种: 暴力搜索法.异常处理链表搜索法.PEB法. 0x02 基本原理 暴力搜索法是最早的动态查找kernel32基地址的方法.它的原理是几乎所有的win ...
- [c++]堆和栈的区别
堆和栈的区别一.预备知识—程序的内存分配一个由c/C++编译的程序占用的内存分为以下几个部分1.栈区(stack)— 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等.其操作方式类似于数据结构 ...
- windows进程中的内存结构(好多API,而且VC最聪明)
在阅读本文之前,如果你连堆栈是什么多不知道的话,请先阅读文章后面的基础知识. 接触过编程的人都知道,高级语言都能通过变量名来访问内存中的数据.那么这些变量在内存中是如何存放的呢?程序又是如何使用这 ...
- 堆和栈的区别【zz】
一.预备知识—程序的内存分配一个由c/C++编译的程序占用的内存分为以下几个部分1.栈区(stack)— 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等.其操作方式类似于数据结构中的栈.2. ...
随机推荐
- 【Flask】cbv源码分析 flask模板使用 flask请求与响应 session及源码分析 闪现flash 请求扩展
目录 上节回顾 今日内容 1 cbv分析 1.1 源码分析 2 模板 2.1 app.py 2.2 index.html 3 请求与响应 4 session及源码分析 4.1 session的使用 4 ...
- CentOS7系统上安装升级Vim8
基本步骤 1.卸载旧版vim yum remove vim* -y 2. 到Vim官方Github仓库下载目前最新的Vim Release版本 git clone https://github.com ...
- Educational Codeforces Round 109 (Rated for Div. 2) 个人补题记录(A~D,AB思维,C模拟构造,D题DP)
补题链接:Here 1525A. Potion-making (思维 [题意描述] 作为一个魔法师,现在我想配置一杯药物浓度为 \(k\%\) 的药水, 每次操作能进行添加: 一升水 一升药物精华 作 ...
- java中除法结果不对。
今天遇一个非常简单地计算,计算结果居然是不对0,查了一些前辈们的资料动手实验了一下,实验结果和代码分享给大家.需要计算的公式:(7/10)*0.8 结果居然不是0.56 而是 0,最后找到原因(7/1 ...
- 六、java操作swift对象存储(resultful方式实现)
系列导航 一.swift对象存储环境搭建 二.swift添加存储策略 三.swift大对象--动态大对象 四.swift大对象--静态态大对象 五.java操作swift对象存储(官网样例) 六.ja ...
- vue权限管理
https://www.bilibili.com/video/BV1nq4y1i7BU/?spm_id_from=333.788.recommend_more_video.6&vd_sourc ...
- 二分图的匹配 hdu 1083
***题意:n个学生,p门课,求最大匹配,即p门课是否都有人上*** 匈牙利算法 #include<iostream> #include<cstdio> #include< ...
- Liunx常用操作(四)-快速清空文件内容的方法(baseshell与vim)
一.baseshell下操作 1. $ : > filename #其中的 : 是一个占位符, 不产生任何输出. 2. $ > filename 3. $ echo "" ...
- spring注入的几种方式
本文为博主原创,未经允许不得转载: Spring注入有以下几种方式: 构造方法注入:通过构造方法实现依赖注入.在类的构造方法中使用@Autowired注解注入需要的依赖类. Setter方法注入:通过 ...
- Angular系列教程之变更检测与性能优化
.markdown-body { line-height: 1.75; font-weight: 400; font-size: 16px; overflow-x: hidden; color: rg ...