Get command line string of 64-bit process from 32-bit process

前端 未结 2 1540
伪装坚强ぢ
伪装坚强ぢ 2021-02-02 01:17

The code below works for me well to get command line string of 32-bit process from a 32-bit app, 64-bit process from a 64-bit app and 32-bit process from 64-bit app. This will b

相关标签:
2条回答
  • 2021-02-02 02:00

    Your 32 bit pointers are not wide enough to store addresses in the 64 bit address space of the target process and will be truncated. Thus, what you are attempting is impossible. This is one of the situations where Raymond Chen would advise you to stop using the emulator.

    Having invoked Raymond Chen's name, I did a quick search to see if he had any useful nuggets. That search turned up this article: Why is there no supported way to get the command line of another process?. The useful nugget is the observation that Win32_Process.CommandLine gives you what you need (somehow). So, my advice is to give WMI a go.

    0 讨论(0)
  • 2021-02-02 02:17

    A bit late answer maybe, but here is a code that does it. It supports 32 or 64 bit process, and 32 bit process on WOW64 (meaning you can compile for Win32 and X64). It uses undocumented functions, so use at your own risk :-)

    GetCmdLine.cpp:

    #include "stdafx.h"
    #include "GetCmdLine.h"
    
    int _tmain(int argc, _TCHAR* argv[])
    {
        if (argc < 2)
        {
            printf("Format is GetCmdLine <process id>\n");
            return 0;
        }
    
        // get process identifier
        DWORD dwId = _wtoi(argv[1]);
    
        // open the process
        HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, dwId);
        DWORD err = 0;
        if (hProcess == NULL)
        {
            printf("OpenProcess %u failed\n", dwId);
            err = GetLastError();
            return -1;
        }
    
        // determine if 64 or 32-bit processor
        SYSTEM_INFO si;
        GetNativeSystemInfo(&si);
    
        // determine if this process is running on WOW64
        BOOL wow;
        IsWow64Process(GetCurrentProcess(), &wow);
    
        // use WinDbg "dt ntdll!_PEB" command and search for ProcessParameters offset to find the truth out
        DWORD ProcessParametersOffset = si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64 ? 0x20 : 0x10;
        DWORD CommandLineOffset = si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64 ? 0x70 : 0x40;
    
        // read basic info to get ProcessParameters address, we only need the beginning of PEB
        DWORD pebSize = ProcessParametersOffset + 8;
        PBYTE peb = (PBYTE)malloc(pebSize);
        ZeroMemory(peb, pebSize);
    
        // read basic info to get CommandLine address, we only need the beginning of ProcessParameters
        DWORD ppSize = CommandLineOffset + 16;
        PBYTE pp = (PBYTE)malloc(ppSize);
        ZeroMemory(pp, ppSize);
    
        PWSTR cmdLine;
    
        if (wow)
        {
            // we're running as a 32-bit process in a 64-bit OS
            PROCESS_BASIC_INFORMATION_WOW64 pbi;
            ZeroMemory(&pbi, sizeof(pbi));
    
            // get process information from 64-bit world
            _NtQueryInformationProcess query = (_NtQueryInformationProcess)GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtWow64QueryInformationProcess64");
            err = query(hProcess, 0, &pbi, sizeof(pbi), NULL);
            if (err != 0)
            {
                printf("NtWow64QueryInformationProcess64 failed\n");
                CloseHandle(hProcess);
                return -1;
            }
    
            // read PEB from 64-bit address space
            _NtWow64ReadVirtualMemory64 read = (_NtWow64ReadVirtualMemory64)GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtWow64ReadVirtualMemory64");
            err = read(hProcess, pbi.PebBaseAddress, peb, pebSize, NULL);
            if (err != 0)
            {
                printf("NtWow64ReadVirtualMemory64 PEB failed\n");
                CloseHandle(hProcess);
                return -1;
            }
    
            // read ProcessParameters from 64-bit address space
            PBYTE* parameters = (PBYTE*)*(LPVOID*)(peb + ProcessParametersOffset); // address in remote process adress space
            err = read(hProcess, parameters, pp, ppSize, NULL);
            if (err != 0)
            {
                printf("NtWow64ReadVirtualMemory64 Parameters failed\n");
                CloseHandle(hProcess);
                return -1;
            }
    
            // read CommandLine
            UNICODE_STRING_WOW64* pCommandLine = (UNICODE_STRING_WOW64*)(pp + CommandLineOffset);
            cmdLine = (PWSTR)malloc(pCommandLine->MaximumLength);
            err = read(hProcess, pCommandLine->Buffer, cmdLine, pCommandLine->MaximumLength, NULL);
            if (err != 0)
            {
                printf("NtWow64ReadVirtualMemory64 Parameters failed\n");
                CloseHandle(hProcess);
                return -1;
            }
        }
        else
        {
            // we're running as a 32-bit process in a 32-bit OS, or as a 64-bit process in a 64-bit OS
            PROCESS_BASIC_INFORMATION pbi;
            ZeroMemory(&pbi, sizeof(pbi));
    
            // get process information
            _NtQueryInformationProcess query = (_NtQueryInformationProcess)GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtQueryInformationProcess");
            err = query(hProcess, 0, &pbi, sizeof(pbi), NULL);
            if (err != 0)
            {
                printf("NtQueryInformationProcess failed\n");
                CloseHandle(hProcess);
                return -1;
            }
    
            // read PEB
            if (!ReadProcessMemory(hProcess, pbi.PebBaseAddress, peb, pebSize, NULL))
            {
                printf("ReadProcessMemory PEB failed\n");
                CloseHandle(hProcess);
                return -1;
            }
    
            // read ProcessParameters
            PBYTE* parameters = (PBYTE*)*(LPVOID*)(peb + ProcessParametersOffset); // address in remote process adress space
            if (!ReadProcessMemory(hProcess, parameters, pp, ppSize, NULL))
            {
                printf("ReadProcessMemory Parameters failed\n");
                CloseHandle(hProcess);
                return -1;
            }
    
            // read CommandLine
            UNICODE_STRING* pCommandLine = (UNICODE_STRING*)(pp + CommandLineOffset);
            cmdLine = (PWSTR)malloc(pCommandLine->MaximumLength);
            if (!ReadProcessMemory(hProcess, pCommandLine->Buffer, cmdLine, pCommandLine->MaximumLength, NULL))
            {
                printf("ReadProcessMemory Parameters failed\n");
                CloseHandle(hProcess);
                return -1;
            }
        }
        printf("%S\n", cmdLine);
        return 0;
    }
    

    GetCmdLine.h:

    #pragma once
    #include "stdafx.h"
    
    // NtQueryInformationProcess for pure 32 and 64-bit processes
    typedef NTSTATUS (NTAPI *_NtQueryInformationProcess)(
        IN HANDLE ProcessHandle,
        ULONG ProcessInformationClass,
        OUT PVOID ProcessInformation,
        IN ULONG ProcessInformationLength,
        OUT PULONG ReturnLength OPTIONAL
        );
    
    typedef NTSTATUS (NTAPI *_NtReadVirtualMemory)(
        IN HANDLE ProcessHandle,
        IN PVOID BaseAddress,
        OUT PVOID Buffer,
        IN SIZE_T Size,
        OUT PSIZE_T NumberOfBytesRead);
    
    // NtQueryInformationProcess for 32-bit process on WOW64
    typedef NTSTATUS (NTAPI *_NtWow64ReadVirtualMemory64)(
        IN HANDLE ProcessHandle,
        IN PVOID64 BaseAddress,
        OUT PVOID Buffer,
        IN ULONG64 Size,
        OUT PULONG64 NumberOfBytesRead);
    
    // PROCESS_BASIC_INFORMATION for pure 32 and 64-bit processes
    typedef struct _PROCESS_BASIC_INFORMATION {
        PVOID Reserved1;
        PVOID PebBaseAddress;
        PVOID Reserved2[2];
        ULONG_PTR UniqueProcessId;
        PVOID Reserved3;
    } PROCESS_BASIC_INFORMATION;
    
    // PROCESS_BASIC_INFORMATION for 32-bit process on WOW64
    // The definition is quite funky, as we just lazily doubled sizes to match offsets...
    typedef struct _PROCESS_BASIC_INFORMATION_WOW64 {
        PVOID Reserved1[2];
        PVOID64 PebBaseAddress;
        PVOID Reserved2[4];
        ULONG_PTR UniqueProcessId[2];
        PVOID Reserved3[2];
    } PROCESS_BASIC_INFORMATION_WOW64;
    
    typedef struct _UNICODE_STRING {
      USHORT Length;
      USHORT MaximumLength;
      PWSTR  Buffer;
    } UNICODE_STRING;
    
    typedef struct _UNICODE_STRING_WOW64 {
      USHORT Length;
      USHORT MaximumLength;
      PVOID64 Buffer;
    } UNICODE_STRING_WOW64;
    
    0 讨论(0)
提交回复
热议问题