ZwQueryVirtualMemory暴力枚举进程模块
0x01 前言
同学问过我进程体中EPROCESS的三条链断了怎么枚举模块,这也是也腾讯面试题。我当时听到也是懵逼的。
后来在网上看到了一些内存暴力枚举的方法ZwQueryVirtualMemory。
0x02 使用ZwQueryVirtualMemory暴力枚举模块
NTSTATUS
NtQueryVirtualMemory(HANDLE ProcessHandle, //目标进程句柄
PVOID BaseAddress, //查询的基址
MEMORY_INFORMATION_CLASS MemoryInformationClass, //枚举宏
PVOID MemoryInformation, //接收信息的结构体
SIZE_T MemoryInformationLength, //缓冲区大小
PSIZE_T ReturnLength); //返回实际长度 //枚举宏
typedef enum _MEMORY_INFORMATION_CLASS {
MemoryBasicInformation,
MemoryWorkingSetList,
MemorySectionName,
MemoryBasicVlmInformation
} MEMORY_INFORMATION_CLASS;
R0通过遍历SSDT获得函数地址。
我们要枚举进程模块信息, 需要用到两类内存信息MemoryBasicInformation和MemorySectionName,
MemoryBasicInformation的缓冲结构体
typedef struct _MEMORY_BASIC_INFORMATION {
PVOID BaseAddress; //查询内存块所占的第一个页面基地址
PVOID AllocationBase; //内存块所占的第一块区域基地址,小于等于BaseAddress,
DWORD AllocationProtect; //区域被初次保留时赋予的保护属性
SIZE_T RegionSize; //从BaseAddress开始,具有相同属性的页面的大小,
DWORD State; //页面的状态,有三种可能值MEM_COMMIT、MEM_FREE和MEM_RESERVE
DWORD Protect; //页面的属性,其可能的取值与AllocationProtect相同
DWORD Type; //该内存块的类型,有三种可能值:MEM_IMAGE、MEM_MAPPED和MEM_PRIVATE
} MEMORY_BASIC_INFORMATION, *PMEMORY_BASIC_INFORMATION;
MemorySectionName的缓冲结构体为
//MemorySectionName
typedef struct _MEMORY_SECTION_NAME {
UNICODE_STRING Name;
WCHAR Buffer[];
}MEMORY_SECTION_NAME,*PMEMORY_SECTION_NAME;
前者返回内存的基本信息, 比如: 内存区的基址,大小以及页面的各种属性等等, 而后者则返回内存段的名字, 也就是我们所要找的模块名.
利用前者我们可以过滤出类型为MEM_IMAGE的内存段并得到内存段的基址和属性, 利用后者我们可以得到模块名.
代码如下:
VOID ListModuleThread(PVOID Context)
{
NTSTATUS ntStatus = STATUS_UNSUCCESSFUL;
ULONG StepAddress;
ULONG Step2Address;
ULONG BufferSize = 0x200;
ULONG ReturnLength = ;
WCHAR LastImageName[] = { };
HANDLE HandleProcess;
PMEMORY_SECTION_NAME SectionName = NULL;
MEMORY_BASIC_INFORMATION BasicInformation;
PTHREAD_CONTEXT ThreadContext = Context;
PMODULE_INFO FoundModule = NULL;
pFnZwQueryVirtualMemory ZwQueryVirtualMemory = NULL; ZwQueryVirtualMemory = (pFnZwQueryVirtualMemory)
KeServiceDescriptorTable.ServiceTableBase[ServiceId_NtQueryVirtualMemory]; ntStatus = ObOpenObjectByPointer(ThreadContext->Process, OBJ_INHERIT,
NULL, , *PsProcessType,
ExGetPreviousMode(), &HandleProcess);
if (!NT_SUCCESS(ntStatus)) {
ExFreePoolWithTag(g_ModuleListHead, MEM_TAG);
g_ModuleListHead = NULL; goto _End;
} SectionName = ExAllocatePoolWithTag(PagedPool, BufferSize, MEM_TAG); for (StepAddress = ; StepAddress <= 0x7FFFFFFF; StepAddress += 0x10000)
{
ntStatus = ZwQueryVirtualMemory(HandleProcess,
(PVOID)StepAddress,
MemoryBasicInformation,
&BasicInformation,
sizeof(MEMORY_BASIC_INFORMATION),
&ReturnLength); if (!NT_SUCCESS(ntStatus) || BasicInformation.Type != SEC_IMAGE) continue;
_Retry:
ntStatus = ZwQueryVirtualMemory(HandleProcess,
(PVOID)StepAddress,
MemorySectionName,
SectionName,
BufferSize,
&ReturnLength); if (!NT_SUCCESS(ntStatus)) {
if (ntStatus == STATUS_INFO_LENGTH_MISMATCH) {
ExFreePoolWithTag(SectionName, MEM_TAG);
SectionName = ExAllocatePoolWithTag(PagedPool, ReturnLength, MEM_TAG);
goto _Retry;
}
continue;
}
__try {
if (memcmp(LastImageName, SectionName->SectionFileName.Buffer,
SectionName->SectionFileName.Length) &&
SectionName->SectionFileName.Length < ) { memcpy(LastImageName, SectionName->SectionFileName.Buffer,
SectionName->SectionFileName.Length);
LastImageName[SectionName->SectionFileName.Length / ] = L'/0'; //
// Step into and get the image size
//
for (Step2Address = StepAddress + BasicInformation.RegionSize;
Step2Address < 0x7FFFFFFF;
Step2Address += BasicInformation.RegionSize) { ntStatus = ZwQueryVirtualMemory(HandleProcess,
(PVOID)Step2Address,
MemoryBasicInformation,
&BasicInformation,
sizeof(MEMORY_BASIC_INFORMATION),
&ReturnLength);
if (NT_SUCCESS(ntStatus) &&
BasicInformation.Type != SEC_IMAGE) break;
} FoundModule = ExAllocatePoolWithTag(NonPagedPool, sizeof(MODULE_INFO), MEM_TAG);
FoundModule->BaseAddress = StepAddress;
FoundModule->ImageSize = Step2Address - StepAddress;
RtlStringCbPrintfW(FoundModule->ImagePath, , L"%s", LastImageName); InsertTailList(&g_ModuleListHead->ModuleListHead, &FoundModule->ModuleLink);
g_ModuleListHead->NumberOfModules ++;
}
} __except (EXCEPTION_EXECUTE_HANDLER) { continue; }
}
ExFreePoolWithTag(SectionName, MEM_TAG);
ObCloseHandle(HandleProcess, ExGetPreviousMode());
_End:
KeSetEvent(&ThreadContext->SynEvent, IO_NO_INCREMENT, FALSE);
PsTerminateSystemThread(STATUS_SUCCESS);
}
此时的模块名是NT Path需要转成Dos Path,代码如下
BOOLEAN NtPathToDosPathW(WCHAR* wzFullNtPath,WCHAR* wzFullDosPath);
extern
NTSTATUS
NTAPI
ZwQueryDirectoryObject (
__in HANDLE DirectoryHandle,
__out_bcount_opt(Length) PVOID Buffer,
__in ULONG Length,
__in BOOLEAN ReturnSingleEntry,
__in BOOLEAN RestartScan,
__inout PULONG Context,
__out_opt PULONG ReturnLength
); typedef struct _OBJECT_DIRECTORY_INFORMATION
{
UNICODE_STRING Name;
UNICODE_STRING TypeName;
} OBJECT_DIRECTORY_INFORMATION, *POBJECT_DIRECTORY_INFORMATION; ULONG
NtQueryDosDevice(WCHAR* wzDosDevice,WCHAR* wzNtDevice,
ULONG ucchMax);
BOOLEAN NtPathToDosPathW(WCHAR* wzFullNtPath,WCHAR* wzFullDosPath)
{
WCHAR wzDosDevice[] = {};
WCHAR wzNtDevice[] = {};
WCHAR *RetStr = NULL;
size_t NtDeviceLen = ;
short i = ;
if(!wzFullNtPath||!wzFullDosPath)
{
return FALSE;
}
for(i=;i<+;i++)
{
wzDosDevice[] = i;
wzDosDevice[] = L':';
if(NtQueryDosDevice(wzDosDevice,wzNtDevice,))
{
if(wzNtDevice)
{
NtDeviceLen = wcslen(wzNtDevice);
if(!_wcsnicmp(wzNtDevice,wzFullNtPath,NtDeviceLen))
{
wcscpy(wzFullDosPath,wzDosDevice);
wcscat(wzFullDosPath,wzFullNtPath+NtDeviceLen);
return TRUE;
}
}
}
}
} ULONG
NtQueryDosDevice(WCHAR* wzDosDevice,WCHAR* wzNtDevice,
ULONG ucchMax)
{
NTSTATUS Status;
POBJECT_DIRECTORY_INFORMATION ObjectDirectoryInfor;
OBJECT_ATTRIBUTES oa;
UNICODE_STRING uniString;
HANDLE hDirectory;
HANDLE hDevice;
ULONG ulReturnLength;
ULONG ulNameLength;
ULONG ulLength;
ULONG Context;
BOOLEAN bRestartScan;
WCHAR* Ptr = NULL;
UCHAR szBuffer[] = {};
RtlInitUnicodeString (&uniString,L"\\??");
InitializeObjectAttributes(&oa,
&uniString,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
Status = ZwOpenDirectoryObject(&hDirectory,DIRECTORY_QUERY,&oa);
if(!NT_SUCCESS(Status))
{
return ;
}
ulLength = ;
if (wzDosDevice != NULL)
{
RtlInitUnicodeString (&uniString,(PWSTR)wzDosDevice);
InitializeObjectAttributes(&oa,&uniString,OBJ_CASE_INSENSITIVE,hDirectory,NULL);
Status = ZwOpenSymbolicLinkObject(&hDevice,GENERIC_READ,&oa);
if(!NT_SUCCESS (Status))
{
ZwClose(hDirectory);
return ;
}
uniString.Length = ;
uniString.MaximumLength = (USHORT)ucchMax * sizeof(WCHAR);
uniString.Buffer = wzNtDevice;
ulReturnLength = ;
Status = ZwQuerySymbolicLinkObject (hDevice,&uniString,&ulReturnLength);
ZwClose(hDevice);
ZwClose(hDirectory);
if (!NT_SUCCESS (Status))
{
return ;
}
ulLength = uniString.Length / sizeof(WCHAR);
if (ulLength < ucchMax)
{
wzNtDevice[ulLength] = UNICODE_NULL;
ulLength++;
}
else
{
return ;
}
}
else
{
bRestartScan = TRUE;
Context = ;
Ptr = wzNtDevice;
ObjectDirectoryInfor = (POBJECT_DIRECTORY_INFORMATION)szBuffer;
while (TRUE)
{
Status = ZwQueryDirectoryObject(hDirectory,szBuffer,sizeof (szBuffer),TRUE,bRestartScan,&Context,&ulReturnLength);
if(!NT_SUCCESS(Status))
{
if (Status == STATUS_NO_MORE_ENTRIES)
{
*Ptr = UNICODE_NULL;
ulLength++;
Status = STATUS_SUCCESS;
}
else
{
ulLength = ;
}
break;
}
if (!wcscmp (ObjectDirectoryInfor->TypeName.Buffer, L"SymbolicLink"))
{
ulNameLength = ObjectDirectoryInfor->Name.Length / sizeof(WCHAR);
if (ulLength + ulNameLength + >= ucchMax)
{
ulLength = ;
break;
}
memcpy(Ptr,ObjectDirectoryInfor->Name.Buffer,ObjectDirectoryInfor->Name.Length);
Ptr += ulNameLength;
ulLength += ulNameLength;
*Ptr = UNICODE_NULL;
Ptr++;
ulLength++;
}
bRestartScan = FALSE;
}
ZwClose(hDirectory);
}
return ulLength;
}
0x03 参考
http://www.cnblogs.com/kedebug/archive/2010/12/22/2791753.html
ZwQueryVirtualMemory暴力枚举进程模块的更多相关文章
- ZwQueryVirtualMemory枚举进程模块
ZwQueryVirtualMemory算是枚举进程方法中的黑科技吧,主要是该方法可以检测出隐藏的模块(类似IceSword). 代码VS2015测试通过 再次奉上源码链接:https://githu ...
- pikachu学习-暴力破解模块
安装好XAMPP,burpsuite,配置好pikachu我们就可以进行pikachu平台的漏洞学习 我这篇博客主要写暴力破解模块讲解,它分为4个小模块,分别是“基于表单的暴力破解”,“验证码绕过(o ...
- VadRoot枚举进程模块在Windows7下的完整实现
原理小伟的小伟在http://bbs.pediy.com/showthread.php?t=66886说的挺清楚了,Windows7下有一些变化,使用NtQueryVirtualMemory来枚举 ...
- HookSSDT 通过HookOpenProcess函数阻止暴力枚举进程
首先要知道Ring3层调用OpenProcess的流程 //当Ring3调用OpenProcess //1从自己的模块(.exe)的导入表中取值 //2Ntdll.dll模块的导出表中执行ZwOpen ...
- ring0 暴力枚举进程
原理:遍历进程ID,然后openprocess,能打开的都枚举出来 ring0 : #include "EnumProcessByForce.h" extern char* PsG ...
- 由枚举模块到ring0内存结构 (分析NtQueryVirtualMemory)
是由获得进程模块而引发的一系列的问题,首先,在ring3层下枚举进程模块有ToolHelp,Psapi,还可以通过在ntdll中获得ZwQuerySystemInformation的函数地址来枚举,其 ...
- 【旧文章搬运】再谈隐藏进程中的DLL模块
原文发表于百度空间,2009-09-17========================================================================== 相当老的话 ...
- 枚举PEB获取进程模块列表
枚举进程模块的方法有很多种,常见的有枚举PEB和内存搜索法,今天,先来看看实现起来最简单的枚举PEB实现获取进程模块列表. 首先,惯例是各种繁琐的结构体定义.需要包含 ntifs.h 和 WinDef ...
- 【web安全】第五弹:burpsuite proxy模块的一些理解
作为一只小小小白的安全新手,只会简单的用sqlmap扫扫网站,用burpsuite的proxy模块拦截一些请求.最近又对proxy有点儿小理解,记录之. 1. 查看sqlmap注入的语句以及HTTP ...
随机推荐
- vs调试的时候debug和release的区别
今天在VS项目中调式遇到一个问题,断点快速查询变量的发现变两竟然不存在 花了一个小时到处百度也查不出一个所以然,后来请教了大神才知道VS调试有debug和release两个模式, vs中的程序有deb ...
- 21天学通C++学习笔记(一):入门
1. 基础概念 1.1 编程语言 旨在让人更容易得使用计算资源,充分利用电脑,不用人做一些重复劳动或持续参与. 1.2 可执行文件 是可运行的成品,应按程序员希望的那样做. 1.3 生成可执行文件的步 ...
- 快速搭建hadoop,学习使用
1.准备Linux环境 1.0先将虚拟机的网络模式选为NAT 1.1修改主机名 vi /etc/sysconfig/network NETWORKING=yes HOSTNAME=myvm ### 1 ...
- 在didSelectRowAtIndexPath 里面取cell的方法
1.选中了tableview的cell的某一行调用的代理方法 - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(N ...
- 【bzoj3329】Xorequ 矩阵快速幂
Description Input 第一行一个正整数,表示数据组数据 ,接下来T行 每行一个正整数N Output 2T行 第2i-1行表示第i个数据中问题一的解, 第2*i行表示第i个数据中问题二的 ...
- 【Es】jest操作elasticsearch
https://blog.csdn.net/niuchenliang524/article/details/82869319 操作es的客房端有多个,在此例出三种(具体区别自行百度),本文讲的是jes ...
- 消息中间件ActiveMQ、RabbitMQ、RocketMQ、ZeroMQ、Kafka如何选型?
最近要为公司的消息队列中间件进行选型,市面上相关的开源技术又非常多,如ActiveMQ.RabbitMQ.ZeroMQ.Kafka,还有阿里巴巴的RocketMQ等. 这么多技术,如何进行选型呢? 首 ...
- python3入门之字符串
获得更多资料欢迎进入我的网站或者 csdn或者博客园 经过前面的介绍相信大家也对python有了一个初步的了解:本节主要介绍字符串,不管学习什么编语言字符串一定在其中扮演着重要的地位.本节主要讲解,字 ...
- 使用github和hexo搭建静态博客
获得更多资料欢迎进入我的网站或者 csdn或者博客园 终于写这篇文章了,这是我使用github和hexo搭建博客的一些心得,希望能给大家一点帮助.少走点弯路.刚接触github,只是用来存项目的版本, ...
- 修复win10无法双击打开txt文档.reg
Windows Registry Editor Version 5.00[HKEY_CLASSES_ROOT\.txt]@="txtfile""Content Type& ...