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

我想获得另一个进程命令行(在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后,我得到了我的进程的命令行,没有要求一个。

我也使用ReadProcessMemore&NtQueryInformationProcess,但得到相同的结果。

任何人都可以帮忙吗?

这里http://forum.sysinternals.com/get-commandline-of-running-processes_topic6510_page1.html被说成是这个代码的作品。 不幸的是,我无法在这个论坛上发帖询问自己。

重复如何查询正在运行的进程的参数列表? (Windows,C ++) ,所以我只是从那里复制我的答案在这里:

你不能可靠地得到这些信息。 有各种各样的技巧来尝试和检索它,但是不能保证目标进程还没有改变这部分内存。 陈先生一会儿讨论这个旧新事物 。

它看起来像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&Qt来做同样的事情。 我遇到了“未定义的引用CLSID_WbemLocator”的问题。 经过一番研究,似乎我的版本的mingw中包含的libwbemuuid.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); } 

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

 LIBS += -lole32 -lwbemuuid 

你需要更严格的检查返回码。 这可能是因为你的ZwReadVirtualMemory调用中的任何一个ZwReadVirtualMemory产生一个错误代码,这个错误代码指向了正确的方向。

特别是, ProcList.proc_id_as_numbers[i]部分表明你正在循环中执行这个代码。 机会是procPeb.ProcessParameters结构仍然填充了一个较早的循环迭代的值 – 并且由于ZwReadVirtualMemory调用在目标进程上失败,您将看到先前查询的任何进程的命令行。

您不必读取目标进程的虚拟机来执行此操作。 只要确保您拥有目标进程的正确进程ID。

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