在 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() 之后,我得到了我的进程的命令行,而不是请求的命令行。

我也使用 ReadProcessMemory() & NtQueryInformationProcess() ,但得到了相同的结果。

有人可以帮忙吗?

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

原文由 Georg 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.7k
2 个回答

看起来 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,您最终会得到本地进程的命令行。

原文由 glagolig 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题