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暴力枚举进程模块的更多相关文章

  1. ZwQueryVirtualMemory枚举进程模块

    ZwQueryVirtualMemory算是枚举进程方法中的黑科技吧,主要是该方法可以检测出隐藏的模块(类似IceSword). 代码VS2015测试通过 再次奉上源码链接:https://githu ...

  2. pikachu学习-暴力破解模块

    安装好XAMPP,burpsuite,配置好pikachu我们就可以进行pikachu平台的漏洞学习 我这篇博客主要写暴力破解模块讲解,它分为4个小模块,分别是“基于表单的暴力破解”,“验证码绕过(o ...

  3. VadRoot枚举进程模块在Windows7下的完整实现

      原理小伟的小伟在http://bbs.pediy.com/showthread.php?t=66886说的挺清楚了,Windows7下有一些变化,使用NtQueryVirtualMemory来枚举 ...

  4. HookSSDT 通过HookOpenProcess函数阻止暴力枚举进程

    首先要知道Ring3层调用OpenProcess的流程 //当Ring3调用OpenProcess //1从自己的模块(.exe)的导入表中取值 //2Ntdll.dll模块的导出表中执行ZwOpen ...

  5. ring0 暴力枚举进程

    原理:遍历进程ID,然后openprocess,能打开的都枚举出来 ring0 : #include "EnumProcessByForce.h" extern char* PsG ...

  6. 由枚举模块到ring0内存结构 (分析NtQueryVirtualMemory)

    是由获得进程模块而引发的一系列的问题,首先,在ring3层下枚举进程模块有ToolHelp,Psapi,还可以通过在ntdll中获得ZwQuerySystemInformation的函数地址来枚举,其 ...

  7. 【旧文章搬运】再谈隐藏进程中的DLL模块

    原文发表于百度空间,2009-09-17========================================================================== 相当老的话 ...

  8. 枚举PEB获取进程模块列表

    枚举进程模块的方法有很多种,常见的有枚举PEB和内存搜索法,今天,先来看看实现起来最简单的枚举PEB实现获取进程模块列表. 首先,惯例是各种繁琐的结构体定义.需要包含 ntifs.h 和 WinDef ...

  9. 【web安全】第五弹:burpsuite proxy模块的一些理解

    作为一只小小小白的安全新手,只会简单的用sqlmap扫扫网站,用burpsuite的proxy模块拦截一些请求.最近又对proxy有点儿小理解,记录之. 1. 查看sqlmap注入的语句以及HTTP ...

随机推荐

  1. RabbitMQ单机集群搭建出现Error: unable to perform an operation on node 'rabbit1@ClusterNode1'

    参考链接:https://www.cnblogs.com/daryl/archive/2017/10/13/7645749.html 全部步骤和参考链接相同. 前八部都正常,在第九步会报错Error: ...

  2. Invoke()的使用

    (最近在看协程) Invoke()方法是一种委托机制 Invoke ( "SendMsg", 3 ), 意思是3秒之后调用 SendMsg() 方法 使用时应该注意以下几点: 1. ...

  3. MVC 登陆鉴权

    public ActionResult Login(string data) { var _params = JsonConvert.DeserializeAnonymousType(data, ne ...

  4. UIButton的几种触发方式

    1.说明 说明:由于是在"iOS 模拟器"中测试的,所以不能用手指,只能用鼠标. 1)UIControlEventTouchDown 指鼠标左键按下(注:只是"按下&qu ...

  5. python3关于date和time的标准库

    python3中关于日期和时间的标准库datetime和time,之前都是用的时候随用随查,今天系统的看一下用这两个库可以做些什么. 1.time标准库 #首先添加一个time对象,看一下该对象的属性 ...

  6. 修改stl::set相关源码,提供有序属性值的查找接口

    普通的stl::set,查找时只能传入key_type. 不能使用属性值查找. 例如: /* an employee record holds its ID, name and age */ clas ...

  7. SDUT OJ 数据结构实验之二叉树一:树的同构

    数据结构实验之二叉树一:树的同构 Time Limit: 1000 ms Memory Limit: 65536 KiB Submit Statistic Discuss Problem Descri ...

  8. json_decode转换数组过程中,结果为null处理办法,百分之百有效

    json_decode这个函数是json_encode的反函数,一般传递数据的时候为了压缩数据,会将数组格式的数据转换成json格式,用到的函数就是json_encode,然后接收到数据之后再用jso ...

  9. iOS如何检测app从后台调回前台

    当按Home键,将应用放在后台之后,然后再次调用回来的时候,回出发AppDelegate里面的一个方法,-(void)applicationWillEnterForeground. 当应用再次回到后台 ...

  10. 3.1、Factorization Machine模型

    Factorization Machine模型 在Logistics Regression算法的模型中使用的是特征的线性组合,最终得到的分隔超平面属于线性模型,其只能处理线性可分的二分类问题,现实生活 ...