Получение другой командной строки процесса в Windows - PullRequest
9 голосов
/ 30 июня 2011

Я пытаюсь получить другую командную строку процесса (на WinXP 32bit).Я делаю следующее:

  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 говорится, что этот код работает.К сожалению, у меня нет доступа к постам на этом форуме, чтобы задать себе вопрос.

Ответы [ 5 ]

9 голосов
/ 16 ноября 2012

Похоже, ZwReadVirtualMemory вызывается только один раз. Этого недостаточно. Он должен вызываться для каждого уровня косвенности указателя. Другими словами, когда вы получаете указатель, он указывает на адресное пространство другого процесса. Вы не можете прочитать это напрямую. Вы должны снова вызвать ZwReadVirtualMemory. В случае этих структур данных ZwReadVirtualMemory должен вызываться 3 раза: один раз для чтения PEB (это то, что делает код выше), один раз для чтения RTL_USER_PROCESS_PARAMETERS и один раз для чтения буфера UNICODE_STRING. Следующий фрагмент кода работал для меня (обработка ошибок опущена для ясности, и я использовал документированный API ReadProcessMemory вместо 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, вы получите именно локальную командную строку.

5 голосов
/ 20 ноября 2013

Я пытался сделать то же самое, используя mingw & Qt.Я столкнулся с проблемой с "неопределенной ссылкой на CLSID_WbemLocator".После некоторого исследования кажется, что версия libwbemuuid.a, которая была включена в мою версию mingw, определяла только 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
4 голосов
/ 01 июля 2011

Дубликат Как запросить запущенный процесс для списка параметров?(windows, C ++) , поэтому я просто скопирую свой ответ оттуда:

Вы не можете надежно получить эту информацию.Существуют различные приемы, чтобы попытаться получить его, но нет никакой гарантии, что целевой процесс еще не исказил этот раздел памяти.Рэймонд Чен некоторое время назад обсуждал это на Старом Новом .

3 голосов
/ 30 июня 2011

Вы должны быть более дисциплинированными с проверкой кодов возврата. Может случиться так, что любой из ваших ZwReadVirtualMemory вызовов даст код ошибки, который укажет вам правильное направление.

В частности, часть ProcList.proc_id_as_numbers[i] предполагает, что вы выполняете этот код в цикле. Скорее всего, структура procPeb.ProcessParameters по-прежнему заполнена значениями более ранней итерации цикла - и поскольку вызов ZwReadVirtualMemory завершается неудачно в целевом процессе, вы видите командную строку того процесса, который был ранее запрошен.

1 голос
/ 30 июня 2011

Вам не нужно читать виртуальную машину целевого процесса, чтобы сделать это.Просто убедитесь, что у вас есть правильный идентификатор процесса для целевого процесса.

Как только вы получите дескриптор процесса через OpenProcess, вы можете использовать NtQueryInformationProcess для получения подробной информации о процессе.Используйте параметр ProcessBasicInformation для получения PEB процесса - он содержит еще один указатель структуры RTL_USER_PROCESS_PARAMETERS , через который вы можете получить командную строку.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...