针对特定的Windows进程,我想知道它是以哪些命令行参数启动的。Windows任务管理器能够显示这些信息。
针对特定的Windows进程,我想知道它是以哪些命令行参数启动的。Windows任务管理器能够显示这些信息。
ProcessBasicInformation
选项获取进程的PEB - 这包含另一个结构指针,通过它您可以获得命令行。您可以使用远程线程注入,调用GetCommandLine()
,然后将结果返回到IPC。这在Windows XP上可能大多数情况下有效,但在Windows Vista或更高版本上,它不适用于系统和服务进程。这是因为CreateRemoteThread
仅在与调用者相同会话ID的进程中工作 - 在Windows Vista中,服务和其他系统进程在会话0中运行,而用户程序在更高的会话中运行。最好且安全的方式是读取每个Windows进程中存在的结构。
进程环境块(PEB)通常存储在进程内存的高区域,位于0x7ff00000
以上。这些区域还包含线程环境块(TEBs)。 PEB地址对于几乎每个进程都是不同的,因此您不能简单地使用硬编码的常量。
#include <windows.h>
#include <stdio.h>
#include "Winternl.h"
typedef NTSTATUS (NTAPI *_NtQueryInformationProcess)(
HANDLE ProcessHandle,
DWORD ProcessInformationClass,
PVOID ProcessInformation,
DWORD ProcessInformationLength,
PDWORD ReturnLength
);
PVOID GetPebAddress(HANDLE ProcessHandle)
{
_NtQueryInformationProcess NtQueryInformationProcess =
(_NtQueryInformationProcess)GetProcAddress(
GetModuleHandleA("ntdll.dll"), "NtQueryInformationProcess");
PROCESS_BASIC_INFORMATION pbi;
NtQueryInformationProcess(ProcessHandle, 0, &pbi, sizeof(pbi), NULL);
return pbi.PebBaseAddress;
}
int wmain(int argc, WCHAR *argv[])
{
int pid;
HANDLE processHandle;
PVOID pebAddress;
PVOID rtlUserProcParamsAddress;
UNICODE_STRING commandLine;
WCHAR *commandLineContents;
if (argc < 2)
{
printf("Usage: getprocesscommandline [pid]\n");
return 1;
}
pid = _wtoi(argv[1]);
if ((processHandle = OpenProcess(
PROCESS_QUERY_INFORMATION | /* required for NtQueryInformationProcess */
PROCESS_VM_READ, /* required for ReadProcessMemory */
FALSE, pid)) == 0)
{
printf("Could not open process!\n");
return GetLastError();
}
pebAddress = GetPebAddress(processHandle);
/* get the address of ProcessParameters */
if (!ReadProcessMemory(processHandle,
&(((_PEB*) pebAddress)->ProcessParameters),
&rtlUserProcParamsAddress,
sizeof(PVOID), NULL))
{
printf("Could not read the address of ProcessParameters!\n");
return GetLastError();
}
/* read the CommandLine UNICODE_STRING structure */
if (!ReadProcessMemory(processHandle,
&(((_RTL_USER_PROCESS_PARAMETERS*) rtlUserProcParamsAddress)->CommandLine),
&commandLine, sizeof(commandLine), NULL))
{
printf("Could not read CommandLine!\n");
return GetLastError();
}
/* allocate memory to hold the command line */
commandLineContents = (WCHAR *)malloc(commandLine.Length);
/* read the command line */
if (!ReadProcessMemory(processHandle, commandLine.Buffer,
commandLineContents, commandLine.Length, NULL))
{
printf("Could not read the command line string!\n");
return GetLastError();
}
/* print it */
/* the length specifier is in characters, but commandLine.Length is in bytes */
/* a WCHAR is 2 bytes */
printf("%.*S\n", commandLine.Length / 2, commandLineContents);
CloseHandle(processHandle);
free(commandLineContents);
return 0;
}
更多细节,请查看获取进程的命令行
第一位作者说:
CreateRemoteThread
只适用于与调用方相同会话ID的进程——在Windows Vista中,服务和其他系统进程运行在会话0中,而用户程序运行在更高的会话中。最好、最安全的方法是读取每个Windows进程中存在的一个结构。
对于OpenProcess也是同样的情况,你无法打开一个作为服务或者由SYSTEM或LOCAL SERVICE或NETWORK SERVICE打开的进程,如果你是以一个用户(即使是管理员)的身份运行程序。
如果你的程序是服务,那么它可能已经使用local system account运行,所以不需要担心。 但如果不是,一个解决办法是使用psexec来启动它:
- 下载PSEXEC并解压到某个文件夹中。
- 以管理员身份打开提升的CMD提示符。
- 导航到你解压PSEXEC.EXE的文件夹
- 运行:
PSEXEC -i -s -d CMD
- 你将会有一个新的CMD提示符打开。
- 在新的CMD提示符中键入以下内容证明你是谁:
WHOAMI
你应该看到你是SYSTEM,现在你可以启动你的程序并查看所有进程的命令行。
你无法可靠地获取那些信息。有各种技巧可以尝试检索它,但不能保证目标进程没有已经破坏了内存的那一部分。Raymond Chen在The Old New Thing上讨论过这个问题。
GetCommandLine
(链接 ANSI 版本,对于 Unicode/"multibyte"/"wide-char",请按照惯例查看 GetCommandLineW
)是您需要的过程。 - Armen Michaeli