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[260];  
}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 = 0;
    WCHAR LastImageName[260] = { 0 };
    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, 0, *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 = 0; 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 < 520) {

                memcpy(LastImageName, SectionName->SectionFileName.Buffer,
                       SectionName->SectionFileName.Length);
                LastImageName[SectionName->SectionFileName.Length / 2] = 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, 520, 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[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;
}

 

0x03 參考

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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM