正在Windows中获取另一个进程命令行

Getting another process command line in Windows

本文关键字:进程 命令行 另一个 获取 Windows 正在      更新时间:2023-10-16

我正在尝试获取另一个进程的命令行参数(在WinXP 32位上(。

我做以下事情:

hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ | PROCESS_TERMINATE, FALSE, ProcList.proc_id_as_numbers[i]);
BytesNeeded = sizeof(PROCESS_BASIC_INFORMATION);
ZwQueryInformationProcess(hProcess, ProcessBasicInformation, UserPool, sizeof(PROCESS_BASIC_INFORMATION), &BytesNeeded);
pbi = (PPROCESS_BASIC_INFORMATION)UserPool;
BytesNeeded = sizeof(PEB);
res = ZwReadVirtualMemory(hProcess, pbi->PebBaseAddress, UserPool, sizeof(PEB), &BytesNeeded);
/* zero value returned */
peb = (PPEB)UserPool;
BytesNeeded = sizeof(RTL_USER_PROCESS_PARAMETERS);
res = ZwReadVirtualMemory(hProcess, peb->ProcessParameters, UserPool, sizeof(RTL_USER_PROCESS_PARAMETERS), &BytesNeeded);
ProcParam = (PRTL_USER_PROCESS_PARAMETERS)UserPool;

在第一次调用之后,pbi.UniqueProcessID是正确的。

但是,在调用ZwReadVirtualMemory()之后,我得到了进程的命令行,而不是请求的命令行。

我还使用了CCD_ 3&NtQueryInformationProcess(),但得到了相同的结果。

有人能帮忙吗?

在这个论坛上,据说这个代码是有效的。不幸的是,我无法在论坛上发帖询问他们。

看起来ZwReadVirtualMemory只被调用一次。这还不够。必须为每个级别的指针间接寻址调用它。换句话说,当您检索一个指针时,它指向其他进程的地址空间。你不能直接阅读。您必须再次调用ZwReadVirtualMemory。对于这些数据结构,ZwReadVirtualMemory必须被调用3次:一次读取PEB(这就是上面的代码所做的(,一次读取RTL_USER_PROCESS_PARAMETERS,以及一次读取UNICODE_STRING的缓冲区。以下代码片段对我有效(为了清楚起见,省略了错误处理,我使用了文档化的ReadProcessMemory API而不是ZwReadVirtualMemory(:

        LONG status = NtQueryInformationProcess(hProcess,
                                                0,
                                                pinfo,
                                                sizeof(PVOID)*6,
                                                NULL);
        PPEB ppeb = (PPEB)((PVOID*)pinfo)[1];
        PPEB ppebCopy = (PPEB)malloc(sizeof(PEB));
        BOOL result = ReadProcessMemory(hProcess,
                                        ppeb,
                                        ppebCopy,
                                        sizeof(PEB),
                                        NULL);
        PRTL_USER_PROCESS_PARAMETERS pRtlProcParam = ppebCopy->ProcessParameters;
        PRTL_USER_PROCESS_PARAMETERS pRtlProcParamCopy =
            (PRTL_USER_PROCESS_PARAMETERS)malloc(sizeof(RTL_USER_PROCESS_PARAMETERS));
        result = ReadProcessMemory(hProcess,
                                   pRtlProcParam,
                                   pRtlProcParamCopy,
                                   sizeof(RTL_USER_PROCESS_PARAMETERS),
                                   NULL);
        PWSTR wBuffer = pRtlProcParamCopy->CommandLine.Buffer;
        USHORT len =  pRtlProcParamCopy->CommandLine.Length;
        PWSTR wBufferCopy = (PWSTR)malloc(len);
        result = ReadProcessMemory(hProcess,
                                   wBuffer,
                                   wBufferCopy, // command line goes here
                                   len,
                                   NULL);

为什么我们看到看到我们自己流程的命令行?这是因为流程的布局方式类似。命令行和PEB相关的结构可能具有相同的地址。所以,如果您错过了ReadProcessMemory,那么您最终会使用本地进程的命令行。

我试着用mingw&问题。我遇到了"未定义对CLSID_WbemLocator的引用"的问题。经过一些研究,我的mingw版本中包含的libwbemuid.a版本似乎只定义了IID_IWbemLocator,而没有定义CLSID_WbemLocation。

我发现手动定义CLSID_WbemLocator是可行的(尽管这可能不是"正确"的做事方式(。

最终工作代码:

#include <QDebug>
#include <QString>
#include <QDir>
#include <QProcess>
#define _WIN32_DCOM
#include <windows.h>
#include "TlHelp32.h"
#include <stdio.h>
#include <tchar.h>
#include <wbemidl.h>
#include <comutil.h>
const GUID CLSID_WbemLocator = { 0x4590F811,0x1D3A,0x11D0,{ 0x89,0x1F,0x00,0xAA,0x00,0x4B,0x2E,0x24 } }; //for some reason CLSID_WbemLocator isn't declared in libwbemuuid.a (although it probably should be).
int getProcessInfo(DWORD pid, QString *commandLine, QString *executable)
{
    HRESULT hr = 0;
    IWbemLocator         *WbemLocator  = NULL;
    IWbemServices        *WbemServices = NULL;
    IEnumWbemClassObject *EnumWbem  = NULL;
    //initializate the Windows security
    hr = CoInitializeEx(0, COINIT_MULTITHREADED);
    hr = CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, NULL);
    hr = CoCreateInstance(CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID *) &WbemLocator);
    //connect to the WMI
    hr = WbemLocator->ConnectServer(L"ROOT\CIMV2", NULL, NULL, NULL, 0, NULL, NULL, &WbemServices);
    //Run the WQL Query
    hr = WbemServices->ExecQuery(L"WQL", L"SELECT ProcessId,CommandLine,ExecutablePath FROM Win32_Process", WBEM_FLAG_FORWARD_ONLY, NULL, &EnumWbem);
    qDebug() << "Got here." << (void*)hr;
    // Iterate over the enumerator
    if (EnumWbem != NULL) {
        IWbemClassObject *result = NULL;
        ULONG returnedCount = 0;
        while((hr = EnumWbem->Next(WBEM_INFINITE, 1, &result, &returnedCount)) == S_OK) {
            VARIANT ProcessId;
            VARIANT CommandLine;
            VARIANT ExecutablePath;
            // access the properties
            hr = result->Get(L"ProcessId", 0, &ProcessId, 0, 0);
            hr = result->Get(L"CommandLine", 0, &CommandLine, 0, 0);
            hr = result->Get(L"ExecutablePath", 0, &ExecutablePath, 0, 0);
            if (ProcessId.uintVal == pid)
            {
                *commandLine = QString::fromUtf16((ushort*)(long)CommandLine.bstrVal);// + sizeof(int)); //bstrs have their length as an integer.
                *executable = QString::fromUtf16((ushort*)(long)ExecutablePath.bstrVal);// + sizeof(int)); //bstrs have their length as an integer.
                qDebug() << *commandLine << *executable;
            }
            result->Release();
        }
    }
    // Release the resources
    EnumWbem->Release();
    WbemServices->Release();
    WbemLocator->Release();
    CoUninitialize();
    //getchar();
    return(0);
}

在我的Qt项目文件(.pro(中,我链接到以下库:

LIBS += -lole32 -lwbemuuid

如何查询正在运行的进程的重复';s参数列表?(windows,C++(,所以我将从这里复制我的答案:

您无法可靠地获取该信息。有各种各样的技巧可以尝试和检索它,但不能保证目标进程没有损坏那部分内存。陈在《新旧事物》上讨论过这个问题。

您需要更加严格地检查返回代码。您的任何ZwReadVirtualMemory调用都可能产生错误代码,从而为您指明正确的方向。

特别是,ProcList.proc_id_as_numbers[i]部分建议您在循环中执行此代码。procPeb.ProcessParameters结构可能仍然充满了早期循环迭代的值,并且由于ZwReadVirtualMemory调用在目标进程上失败,因此您可以看到之前查询的任何进程的命令行。

您不必读取目标进程的VM即可执行此操作。只需确保您拥有目标流程的正确流程ID。

一旦您通过OpenProcess获得了流程句柄,就可以使用NtQueryInformationProcess来获取详细的流程信息。使用ProcessBasicInformation选项获取进程的PEB-它包含另一个结构指针RTL_USER_process_PARAMETERS,通过它可以获取命令行。