代码之家  ›  专栏  ›  技术社区  ›  Baiyan Huang

如何从32位WOW进程枚举64位进程中的模块

  •  18
  • Baiyan Huang  · 技术社区  · 14 年前

    我需要在Windows中检索32位WOW进程中64位进程的所有模块, EnumProcessModules 会出现如下所述的故障:

    以便枚举ProcessModuleSex和CreateToolhelp32Snapshot。

    谢谢。

    3 回复  |  直到 13 年前
        1
  •  18
  •   Chris Schmich    9 年前

    如果不使用非文档化的api,就无法做到这一点。一般来说,由于地址空间的差异,从32位进程读取64位进程的内存将无法工作。

    EnumProcessModulesEx LIST_MODULES_32BIT LIST_MODULES_64BIT 过滤标志,有这样的意思:

    此函数主要用于64位应用程序。如果在WOW64下运行的32位应用程序调用该函数,则会忽略dwFilterFlag选项,并且该函数提供与EnumProcessModules函数相同的结果。

    DLL surrogate ),或者有一个单独的进程与您进行通信。或者,根据进程相对于目标进程的启动时间,可以使用WMI获取模块加载事件。看到了吗 Win32_ModuleLoadTrace 事件。

    Process Explorer ,一个32位的exe,可以向您显示32位和64位进程的模块,但它实际上是冒烟和镜像:32位的exe包含一个64位版本的自身,可以写入磁盘并在64位机器上执行。

        2
  •  5
  •   greenpiece    8 年前

    reading x64 process memory from x86 process . 主要是要注意功能 NtWow64QueryInformationProcess64 NtWow64ReadVirtualMemory64 在x86中存在 ntdll.dll 和专门用于从x86进程获取有关x64进程的信息。

    我们还应该了解操作系统结构之间的一些依赖关系。

    PROCESS_BASIC_INFORMATION 包含的地址 PEB PEB公司 表示进程环境块。它包含的地址 PEB_LDR_DATA 结构。它依次包含第一个 LDR_DATA_TABLE_ENTRY LIST_ENTRY 链条。 LDR\数据\表格\条目 LDR\数据\表格\条目

    在WinDbg中检查此信息的示例:

    0:000> !peb
    PEB at 000007fffffdb000
    ...
    
    0:000> dt ntdll!_peb 000007fffffdb000
    ...
    +0x018 Ldr              : 0x00000000`76fbd640 _PEB_LDR_DATA
    ...
    
    0:000> dt ntdll!_PEB_LDR_DATA 76fbd640
    ...
    +0x010 InLoadOrderModuleList : _LIST_ENTRY [ 0x00000000`00415bb0 - 0x00000000`070eb9c0 ]
    ...
    
    0:000> dt ntdll!_LDR_DATA_TABLE_ENTRY 00415bb0
    +0x000 InLoadOrderLinks : _LIST_ENTRY [ 0x00000000`00415ca0 - 0x00000000`76fbd650 ]
    ...
    +0x030 DllBase          : 0x00000001`3f4d0000 Void
    ...
    +0x058 BaseDllName      : _UNICODE_STRING "procexp64.exe"
    ...
    
    0:000> dt ntdll!_LDR_DATA_TABLE_ENTRY 00415ca0
    +0x000 InLoadOrderLinks : _LIST_ENTRY [ 0x00000000`00416020 - 0x00000000`00415bb0 ]
    ...
    +0x030 DllBase          : 0x00000000`76e90000 Void
    ...
    +0x058 BaseDllName      : _UNICODE_STRING "ntdll.dll"
    ...
    

    1. 通过对的常规调用获取进程句柄 OpenProcess 功能。
    2. 处理基本信息 带调用的结构 NTWOW64查询信息处理64 .
    3. 处理基本信息 结构。
    4. 阅读 带调用的结构 NTWOW64读取虚拟内存64 .
    5. PEB\U LDR\U数据 结构。
    6. 阅读 LDR\数据\表格\条目 元素。
    7. LDR\数据\表格\条目 元素,而下一个元素的地址不等于第一个元素的地址。

    UNICODE_STRING (位于 )获取当前模块名。

    代码如下所示。它由两个文件组成, main.cpp os_structs.hpp

    主.cpp :

    #include "os_structs.hpp"
    
    #include <algorithm>
    #include <codecvt>
    #include <cstdint>
    #include <iostream>
    #include <stdexcept>
    #include <string>
    #include <vector>
    
    #ifndef WIN32
    #   error "This application must be built as an x86 executable"
    #endif
    
    #define GET_FUNC_ADDR(name) _##name name = (_##name)::GetProcAddress(::GetModuleHandleA("ntdll.dll"), #name)
    
    #define IS_TRUE(clause, msg) if (!(clause)) { throw std::runtime_error(msg); }
    
    namespace
    {
    
    struct close_on_exit
    {
        close_on_exit(HANDLE ptr)
            : ptr_(ptr)
        { };
    
        ~close_on_exit()
        {
            if (ptr_)
            {
                ::CloseHandle(ptr_);
                ptr_ = nullptr;
            }
        }
    
    private:
        HANDLE ptr_;
    };
    
    // Names of modules 
    std::string convert_unicode_to_utf8(std::vector<uint8_t> &raw_bytes)
    {
        std::vector<uint16_t> unicode(raw_bytes.size() >> 1, 0);
        memcpy(unicode.data(), raw_bytes.data(), raw_bytes.size());
    
        std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;
    
        const std::wstring wide_string(unicode.begin(), unicode.end());
        const std::string utf8_string = converter.to_bytes(wide_string);
    
        return utf8_string;
    }
    
    void *get_handle(uint32_t id)
    {
        HANDLE handle = ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, id);
    
        std::cout << "Opening target process...";
    
        IS_TRUE(NULL != handle, "OpenProcess failed");
    
        std::cout << " ok" << std::endl;
    
        return handle;
    }
    
    void check_if_process_is_x64(HANDLE handle)
    {
        BOOL is_wow64_process = TRUE;
        IS_TRUE(::IsWow64Process(handle, &is_wow64_process), "IsWow64Process failed");
        IS_TRUE(FALSE == is_wow64_process, "Target process is not x64 one");
    }
    
    std::vector<uint8_t> read_mem(HANDLE handle, uint64_t address, uint32_t length)
    {
        IS_TRUE(handle, "No process handle obtained");
    
        std::vector<uint8_t> data(length, 0);
    
        GET_FUNC_ADDR(NtWow64ReadVirtualMemory64);
    
        NTSTATUS status = NtWow64ReadVirtualMemory64(handle, address, data.data(), data.size(), FALSE);
    
        IS_TRUE(NT_SUCCESS(status), "NtWow64ReadVirtualMemory64 failed");
    
        return data;
    }
    
    void read_pbi(HANDLE handle, sys::PROCESS_BASIC_INFORMATION64 &pbi)
    {
        IS_TRUE(handle, "No process handle obtained");
    
        GET_FUNC_ADDR(NtWow64QueryInformationProcess64);
    
        NTSTATUS status = NtWow64QueryInformationProcess64(handle, sys::ProcessBasicInformation, &pbi, sizeof(pbi), NULL);
    
        IS_TRUE(NT_SUCCESS(status), "NtQueryInformationProcess failed");
    }
    
    std::vector<uint8_t> read_peb_data(HANDLE handle)
    {
        sys::PROCESS_BASIC_INFORMATION64 pbi = { 0 };
        read_pbi(handle, pbi);
    
        return read_mem(handle, pbi.PebBaseAddress, sizeof(sys::PEB64));
    }
    
    bool get_modules_load_order_via_peb(HANDLE handle)
    {
        std::cout << "Getting module load order...\n" << std::endl;
    
        std::vector<uint8_t> read_peb = read_peb_data(handle);
        sys::PEB64 *peb = (sys::PEB64 *)read_peb.data();
    
        // ------------------------------------------------------------------------
        // Read memory from pointer to loader data structures.
        // ------------------------------------------------------------------------
        std::vector<uint8_t> read_peb_ldr_data = read_mem(handle, (uintptr_t)peb->LoaderData, sizeof(sys::PEB_LDR_DATA64));
        sys::PEB_LDR_DATA64 *peb_ldr_data = (sys::PEB_LDR_DATA64 *)read_peb_ldr_data.data();
        sys::PEB_LDR_DATA64 *loader_data = (sys::PEB_LDR_DATA64 *)peb->LoaderData;
    
        const uintptr_t addr_of_ptr_to_first_ldr_module = (uintptr_t)loader_data
            + ((uintptr_t)&loader_data->InLoadOrderModuleList - (uintptr_t)&loader_data->Length);
    
        ULONGLONG address = peb_ldr_data->InLoadOrderModuleList.Flink;
    
        uint32_t counter = 1;
    
        // ------------------------------------------------------------------------
        // Traversing loader data structures.
        // ------------------------------------------------------------------------
        do
        {
            std::vector<uint8_t> read_ldr_table_entry = read_mem(handle, address, sizeof(sys::LDR_DATA_TABLE_ENTRY64));
    
            sys::LDR_DATA_TABLE_ENTRY64 *ldr_table_entry = (sys::LDR_DATA_TABLE_ENTRY64 *)read_ldr_table_entry.data();
    
            std::vector<uint8_t> unicode_name = read_mem(handle, ldr_table_entry->BaseDllName.Buffer, ldr_table_entry->BaseDllName.MaximumLength);
            std::string name = convert_unicode_to_utf8(unicode_name);
    
            std::cout << "Module: " << name << std::endl;
            std::cout << "  Image base: 0x" << std::hex << ldr_table_entry->BaseAddress << std::endl;
    
            ldr_table_entry = (sys::LDR_DATA_TABLE_ENTRY64 *)read_ldr_table_entry.data();
            address = (uintptr_t)ldr_table_entry->InLoadOrderModuleList.Flink;
        } while (addr_of_ptr_to_first_ldr_module != address);
    
        std::cout << "\nEnumeration finished" << std::endl;
    
        return true;
    }
    
    }  // namespace
    
    int main()
    {
        try
        {
            HANDLE handle = get_handle(16944);
            close_on_exit auto_close_handle(handle);
    
            check_if_process_is_x64(handle);
            get_modules_load_order_via_peb(handle);
        }
        catch (const std::runtime_error &e)
        {
            std::cerr << "\n----------------------------------------------------\n";
            std::cerr << "Exception occurred: " << e.what();
            std::cerr << "\n----------------------------------------------------\n";
        }
    
        return 0;
    }
    

    :

    #pragma once
    
    #include <windows.h>
    
    #define NT_SUCCESS(x) ((x) >= 0)
    
    // Namespace is present Not to collide with "winbase.h"
    // definition of PROCESS_INFORMATION_CLASS and others.
    namespace sys
    {
    
    typedef enum _PROCESS_INFORMATION_CLASS {
        ProcessBasicInformation,
        ProcessQuotaLimits,
        ProcessIoCounters,
        ProcessVmCounters,
        ProcessTimes,
        ProcessBasePriority,
        ProcessRaisePriority,
        ProcessDebugPort,
        ProcessExceptionPort,
        ProcessAccessToken,
        ProcessLdtInformation,
        ProcessLdtSize,
        ProcessDefaultHardErrorMode,
        ProcessIoPortHandlers,
        ProcessPooledUsageAndLimits,
        ProcessWorkingSetWatch,
        ProcessUserModeIOPL,
        ProcessEnableAlignmentFaultFixup,
        ProcessPriorityClass,
        ProcessWx86Information,
        ProcessHandleCount,
        ProcessAffinityMask,
        ProcessPriorityBoost,
        MaxProcessInfoClass
    } PROCESS_INFORMATION_CLASS, *PPROCESS_INFORMATION_CLASS;
    
    // ------------------------------------------------------------------------
    // Structs.
    // ------------------------------------------------------------------------
    
    typedef struct _PROCESS_BASIC_INFORMATION64 {
        ULONGLONG Reserved1;
        ULONGLONG PebBaseAddress;
        ULONGLONG Reserved2[2];
        ULONGLONG UniqueProcessId;
        ULONGLONG Reserved3;
    } PROCESS_BASIC_INFORMATION64;
    
    typedef struct _PEB_LDR_DATA64 {
        ULONG Length;
        BOOLEAN Initialized;
        ULONGLONG SsHandle;
        LIST_ENTRY64 InLoadOrderModuleList;
        LIST_ENTRY64 InMemoryOrderModuleList;
        LIST_ENTRY64 InInitializationOrderModuleList;
    } PEB_LDR_DATA64, *PPEB_LDR_DATA64;
    
    // Structure is cut down to ProcessHeap.
    typedef struct _PEB64 {
        BOOLEAN InheritedAddressSpace;
        BOOLEAN ReadImageFileExecOptions;
        BOOLEAN BeingDebugged;
        BOOLEAN Spare;
        ULONGLONG Mutant;
        ULONGLONG ImageBaseAddress;
        ULONGLONG LoaderData;
        ULONGLONG ProcessParameters;
        ULONGLONG SubSystemData;
        ULONGLONG ProcessHeap;
    } PEB64;
    
    typedef struct _UNICODE_STRING64 {
        USHORT Length;
        USHORT MaximumLength;
        ULONGLONG Buffer;
    } UNICODE_STRING64;
    
    typedef struct _LDR_DATA_TABLE_ENTRY64 {
        LIST_ENTRY64 InLoadOrderModuleList;
        LIST_ENTRY64 InMemoryOrderModuleList;
        LIST_ENTRY64 InInitializationOrderModuleList;
        ULONGLONG BaseAddress;
        ULONGLONG EntryPoint;
        DWORD64 SizeOfImage;
        UNICODE_STRING64 FullDllName;
        UNICODE_STRING64 BaseDllName;
        ULONG Flags;
        SHORT LoadCount;
        SHORT TlsIndex;
        LIST_ENTRY64 HashTableEntry;
        ULONGLONG TimeDateStamp;
    } LDR_DATA_TABLE_ENTRY64, *PLDR_DATA_TABLE_ENTRY64;
    
    }  // namespace sys
    
    // ------------------------------------------------------------------------
    // Function prototypes.
    // ------------------------------------------------------------------------
    
    typedef NTSTATUS(NTAPI *_NtWow64QueryInformationProcess64)(
        IN HANDLE ProcessHandle,
        ULONG ProcessInformationClass,
        OUT PVOID ProcessInformation,
        IN ULONG ProcessInformationLength,
        OUT PULONG ReturnLength OPTIONAL);
    
    typedef NTSTATUS(NTAPI *_NtWow64ReadVirtualMemory64)(
        IN HANDLE ProcessHandle,
        IN DWORD64 BaseAddress,
        OUT PVOID Buffer,
        IN ULONG64 Size,
        OUT PDWORD64 NumberOfBytesRead);
    

    如果您对初始结构定义感兴趣-我找到的最佳方法是下载WinDbg的符号,然后在此调试器中查看结构的布局。你可以在上面的帖子中看到这个例子。

        3
  •  1
  •   Patrick Timmermans    9 年前

    function GetProcessCount(const aFileName: string): Integer;
    var
      lValue: LongWord;
      lWMIService: OleVariant;
      lWMIItems: OleVariant;
      lWMIItem: OleVariant;
      lWMIEnum: IEnumVariant;
    begin
      Result := -1;
      lWMIService := GetWMIObject('winmgmts:\\.\root\CIMV2'); { Do not localize. }
      if (TVarData(lWMIService).VType = varDispatch) and (TVarData(lWMIService).VDispatch <> nil) then
      begin
        Result := 0;
        lWMIItems := lWMIService.ExecQuery(Format('SELECT * FROM Win32_Process WHERE Name=''%s''', [ExtractFileName(aFileName)])); { Do not localize. }
        lWMIEnum := IUnknown(lWMIItems._NewEnum) as IEnumVariant;
        while lWMIEnum.Next(1, lWMIItem, lValue) = 0 do
        begin
          Inc(Result);
        end;
      end;
    end;