暴力枚举进程模块

同学问过我进程体中EPROCESS的三条链断了怎么枚举模块,这也是也腾讯面试题。我当时听到也是懵逼的。

后来在网上看到了一些内存暴力枚举的方法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[260];
}MEMORY_SECTION_NAME,*PMEMORY_SECTION_NAME;

前者返回内存的基本信息, 比如: 内存区的基址,大小以及页面的各种属性等等, 而后者则返回内存段的名字,  
也就是我们所要找的模块名.

利用前者我们可以过滤出类型为MEM_IMAGE的内存段并得到内存段的基址和属性, 利用后者我们可以得到模块名.

此时的模块名是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[4] = {0};
    WCHAR wzNtDevice[64] = {0};
    WCHAR *RetStr = NULL;
    size_t NtDeviceLen = 0;
    short i = 0;
    if(!wzFullNtPath||!wzFullDosPath)
    {
        return FALSE;
    }
    for(i=65;i<26+65;i++)
    {
        wzDosDevice[0] = i;
        wzDosDevice[1] = L‘:‘;
        if(NtQueryDosDevice(wzDosDevice,wzNtDevice,64))
        {
            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[512] = {0};
    RtlInitUnicodeString (&uniString,L"\\??");
    InitializeObjectAttributes(&oa,
        &uniString,
        OBJ_CASE_INSENSITIVE,
        NULL,
        NULL);
    Status = ZwOpenDirectoryObject(&hDirectory,DIRECTORY_QUERY,&oa);
    if(!NT_SUCCESS(Status))
    {
        return 0;
    }
    ulLength = 0;
    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 0;
        }
        uniString.Length = 0;
        uniString.MaximumLength = (USHORT)ucchMax * sizeof(WCHAR);
        uniString.Buffer = wzNtDevice;
        ulReturnLength = 0;
        Status = ZwQuerySymbolicLinkObject (hDevice,&uniString,&ulReturnLength);
        ZwClose(hDevice);
        ZwClose(hDirectory);
        if (!NT_SUCCESS (Status))
        {
            return 0;
        }
        ulLength = uniString.Length / sizeof(WCHAR);
        if (ulLength < ucchMax)
        {
            wzNtDevice[ulLength] = UNICODE_NULL;
            ulLength++;
        }
        else
        {
            return 0;
        }
    }
    else
    {
        bRestartScan = TRUE;
        Context = 0;
        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 = 0;
                }
                break;
            }
            if (!wcscmp (ObjectDirectoryInfor->TypeName.Buffer, L"SymbolicLink"))
            {
                ulNameLength = ObjectDirectoryInfor->Name.Length / sizeof(WCHAR);
                if (ulLength + ulNameLength + 1 >= ucchMax)
                {
                    ulLength = 0;
                    break;
                }
                memcpy(Ptr,ObjectDirectoryInfor->Name.Buffer,ObjectDirectoryInfor->Name.Length);
                Ptr += ulNameLength;
                ulLength += ulNameLength;
                *Ptr = UNICODE_NULL;
                Ptr++;
                ulLength++;
            }
            bRestartScan = FALSE;
        }
        ZwClose(hDirectory);
    }
    return ulLength;
}

网上都有代码我就不贴了,发个帖记录一下学习

这是别人的代码链接

http://www.cnblogs.com/kedebug/archive/2010/12/22/2791753.html

时间: 2024-08-05 15:20:59

暴力枚举进程模块的相关文章

NtQueryVirtualMemory 枚举进程模块

typedef enum _MEMORY_INFORMATION_CLASS { MemoryBasicInformation, MemoryWorkingSetList, MemorySectionName }MEMORY_INFORMATION_CLASS; typedef struct { UNICODE_STRING SectionFileName; WCHAR NameBuffer[MAX_PATH * 5]; } MEMORY_SECTION_NAME, *PMEMORY_SECTI

ZwQueryVirtualMemory枚举进程模块

ZwQueryVirtualMemory算是枚举进程方法中的黑科技吧,主要是该方法可以检测出隐藏的模块(类似IceSword). 代码VS2015测试通过 再次奉上源码链接:https://github.com/Arsense/WindowsCode/tree/master/ZwQueryVirtualMemory 好的下面我们进入正题 这个没有深入研究 就是简单测试读了下代码 很久了 忘记差不多了 所以只是整理献上一个比较好的其他博友的 1常见的枚举进程模块的方法有 CreateToolhel

暴力枚举进程

进程是操作系统中的一个非常重要的概念,学习的初级阶段可以先想办法枚举出它们,为以后的深入学习奠定基础. 枚举进程有许多方法,比较简单的有快照CreateToolhelp32Snapshot,psapi.dll提供的EnumProcesses()等.我们还可以通过进程ID去暴力枚举,只是可能权限不够,有些得不到,就需要驱动的帮忙了. 应用层: #include <Windows.h>#include <iostream>using namespace std; #define MAX

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

首先要知道Ring3层调用OpenProcess的流程 //当Ring3调用OpenProcess //1从自己的模块(.exe)的导入表中取值 //2Ntdll.dll模块的导出表中执行ZwOpenProcess(取索引 进入Ring0层) //3进入Ring0 从Ntoskernel.exe模块的导出表中执行ZwOpenProcess(取索引 获得SSDT服务地址) //4通过索引在SSDT表中取值(NtOpenProcess的地址) //5真正调用NtOpenProcess函数 我们可以通

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

原理小伟的小伟在http://bbs.pediy.com/showthread.php?t=66886说的挺清楚了,Windows7下有一些变化,使用NtQueryVirtualMemory来枚举模块是一个效率很低的事情,自己枚举VadRoot速度是很快的,有N个子节点时,为log(N),还有我在这里补上的基地址获取和镜像大小获取,废话不多说,完整代码如下,仅给有需要的人参考,大侠飘过-- 代码: typedef struct _MMADDRESS_NODE // 0x14 {     unio

ring0 暴力枚举进程

原理:遍历进程ID,然后openprocess,能打开的都枚举出来 ring0 : #include "EnumProcessByForce.h" extern char* PsGetProcessImageFileName(PEPROCESS EProcess); extern POBJECT_TYPE* PsProcessType; NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegisterP

由枚举模块到ring0内存结构的初步探索

是由获得进程模块而引发的一系列的问题,首先,在ring3层下枚举进程模块有ToolHelp,Psapi,还可以通过在ntdll中获得ZwQuerySystemInformation的函数地址来枚举,其中ZwQueryInformationProcess相当于是调用系统服务函数,其内部实现就是遍历PEB中的Moudle链表, kd> dt _PEB +0x00c Ldr              : Ptr32 _PEB_LDR_DATA kd> dt _PEB_LDR_DATA nt!_PEB

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

作为一只小小小白的安全新手,只会简单的用sqlmap扫扫网站,用burpsuite的proxy模块拦截一些请求.最近又对proxy有点儿小理解,记录之. 1. 查看sqlmap注入的语句以及HTTP request/response信息 sqlmap是很好用的自动测试工具,但有时候想要查看请求具体的内容,也就是payload的内容.sqlmap自带了-v 参数,当-v >= 3的时候会显示注入的payload,但在实际测试过程中页面刷的太快看不清内容,且呈现的效果不易读.可以通过设置proxy参

枚举PEB获取进程模块列表

枚举进程模块的方法有很多种,常见的有枚举PEB和内存搜索法,今天,先来看看实现起来最简单的枚举PEB实现获取进程模块列表. 首先,惯例是各种繁琐的结构体定义.需要包含 ntifs.h 和 WinDef.h, 此处不再列出,各位看官根据情况自行添加. [cpp] view plain copy print? typedef PPEB (__stdcall *PFNPsGetProcessPeb)(PEPROCESS pEProcess); typedef ULONG   PPS_POST_PROC