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 ...
随机推荐
- angular学习文章
https://www.jianshu.com/p/86c6249a2069 angular.cn https://segmentfault.com/a/1190000008754631
- unix网络编程str_cli使用epoll实现
unix网络编程str_cli使用epoll实现 unix环境高级编程中也有这个函数,都是为了讲解IO多路转接.从本质上来看epoll就是一个改善了的select和poll,本质没发生任何变化,对于构 ...
- rtabmap and rtabmap_ros make error(rtabmap编译错误)
Build from source following README.nd in rtabmap_ros rtabmap make error Error 1 make[2]: *** No rule ...
- soapui
webservice 的请求可使用工具:soapui 天气预报的接口地址:http://www.webxml.com.cn/WebServices/WeatherWebService.asmx?wsd ...
- luoguP2495 [SDOI2011]消耗战
https://www.luogu.org/problemnew/show/P2495 Dp 方程很显然 设 Dp[u] 表示--使 u 不与其子树中任意一个关键点联通的最小代价 设 w[a, b] ...
- 通过html()的方法获取文本内容, form表单组件显示的值与获取到的值不一致的问题
我在通过 html()获取对应节点的内容,发现一个问题,获取到的 form表单组件的内容值是初始加载的值,而不是经过用户修改后的值.例如页面加载时组件<input type="text ...
- 通用动态树(Link-Cut Tree)模板
一个没有维护任何东西的动态树模板 忘了怎么写可以直接来粘 int ch[300010][2], fa[300010], st[300010]; bool lazy[300010]; bool nroo ...
- Mac的Parallels在启动Win的时候让它独立全屏窗口
这里备忘一下,由于经常需要***,Win方法比较多少,所以使用Parallels在Win下***还是很有必要的,为了使用使用方便,一般让Parallels启动系统之后自动生成一个独立的全窗口,方便来回 ...
- js 封装一个均速动画函数
//动画函数---任意一个元素移动到指定的目标位置 //element为元素 target为位置 function carToon(element, target) { //设置一个定时器让他循环去增 ...
- Hadoop Hive概念学习系列之什么是Hive?
参考 <Hadoop大数据分析与挖掘实战>的在线电子书阅读 http://yuedu.baidu.com/ebook/d128cf8e33687e21 ...