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

C++ 在Windows中获取另一个进程命令行,c++,windows,winapi,command-line,process,C++,Windows,Winapi,Command Line,Process,我正在尝试获取另一个进程命令行(在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(h

我正在尝试获取另一个进程命令行(在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是正确的。 但在调用zhreadvirtualmemory之后,我得到了进程的命令行,而不是请求的命令行

我还使用了ReadProcessMemore&NtQueryInformationProcess,但得到了相同的结果

有人能帮忙吗


这里有人说这个代码是有效的。不幸的是,我没有权限在这个论坛上发帖问自己。

你需要更严格地检查返回代码。可能是您的任何
ZwReadVirtualMemory
调用都会产生一个错误代码,将您指向正确的方向


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

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

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

重复,因此我将从这里复制我的答案:


你无法可靠地获得这些信息。有各种各样的技巧来尝试和检索它,但不能保证目标进程没有损坏该部分内存。雷蒙德·陈(Raymond Chen)不久前讨论过这个问题。

看来虚拟记忆只有一次。这还不够。必须为指针间接寻址的每个级别调用它。换句话说,当您检索指针时,它指向其他进程的地址空间。你不能直接读。你得再打电话给Zhreadvirtualmemory。对于这些数据结构,必须调用ZwReadVirtualMemory三次:一次读取PEB(这就是上面的代码所做的),一次读取RTL_用户_进程_参数,一次读取UNICODE_字符串的缓冲区。 以下代码片段适合我(为了清晰起见,省略了错误处理,我使用了有文档记录的ReadProcessMemory API,而不是ZhreadvirtualMemory):


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

我试图用mingw&Qt做同样的事情。我遇到了“对CLSID_WbemLocator的未定义引用”的问题。经过一些研究,我的mingw版本中包含的libwbemuid.a版本似乎只定义了IID_IWbemLocator,而没有定义CLSID_WbemLocator

我发现手动定义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);
}

可能在OpenProcess调用中进程id为0,或者类似的东西?否。HPProcess是正确的,pbi get也是正确的。可能您自己进程的命令行与另一个进程的命令行相同?:-)不,不是。我想从C++程序中找到javw过程。你可能想读一下:我已经把代码编辑到了帖子里。此外,我还标记了失败的第行(第一次调用ZwReadVirtualMemory)。我得到错误代码122(缓冲区不足)。但是BytesNeeded并没有改变它的价值;它询问为什么特定代码不起作用。有意思的是,其他流程PEB中的信息不可靠,但这并不能回答这个问题。我认为旧的新的东西已经过时了。在这里,我读到了相反的内容:原始命令行保留在PEB中,GetCommandLine()只返回它的一个副本!看起来确实需要ZhreadVirtualMemory或类似的东西。谢谢你的帮助,但我已经在另一个问题中找到了解决方案。就我所记得的,你的代码看起来好一点(没有魔法常数等)。这段代码真的很难看和神秘。为什么不使用ProcessBasicInformation而不是zero。为什么不使用sizeof(PROCESS_BASIC_INFORMATION)而不是sizeof(PVOID)*6?请注意:您需要在wBufferCopy中添加终止的
NULL
字符。此代码会错过一些错误检查,并泄漏
命令行
可执行路径
BSTR的内存。但是,使用WMI是获取命令行参数的唯一可靠方法,因此从我这里获得+1。
#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);
}
LIBS += -lole32 -lwbemuuid