How would you get the command line of a process? Some people have suggested that you use remote thread injection, call GetCommandLine(), then IPC the result back. This might work most of the time on Windows XP, but on Windows Vista it doesn’t work on system and service processes. This is because CreateRemoteThread only works on processes in the same session ID as the caller – in Windows Vista, services and other system processes run in session 0 while user programs run in higher sessions. The best and safest way is to read a structure present in every Windows process.

The Process Environment Block (PEB) is usually stored in the high regions of process memory, above 0x7ff00000. These regions also contain Thread Environment Blocks (TEBs). The PEB address is different for almost every process, so you can’t simply use a hardcoded constant. There’s only one way (in user mode) to get the PEB address:NtQueryInformationProcess. Its (simplified) function definition is:

NtQueryInformationProcess(
IN HANDLE ProcessHandle,
IN PROCESS_INFORMATION_CLASS ProcessInformationClass,
OUT PVOID ProcessInformation,
IN ULONG ProcessInformationLength,
OUT PULONG ReturnLength
);

The ProcessInformationClass we want to use is the first one, ProcessBasicInformation (with a value of 0). The structure for this is named PROCESS_BASIC_INFORMATION:

typedef struct _PROCESS_BASIC_INFORMATION
{
NTSTATUS ExitStatus;
PVOID PebBaseAddress; /* contains the PEB address! */
ULONG_PTR AffinityMask;
DWORD BasePriority;
HANDLE UniqueProcessId;
HANDLE InheritedFromUniqueProcessId;
} PROCESS_BASIC_INFORMATION, *PPROCESS_BASIC_INFORMATION;

The problem with calling NtQueryInformationProcess is that you’ll have to find the address of it yourself. Here’s some code that finds the PEB address of any process:

typedef NTSTATUS (NTAPI *_NtQueryInformationProcess)(
HANDLE ProcessHandle,
DWORD ProcessInformationClass, /* can't be bothered defining the whole enum */
PVOID ProcessInformation,
DWORD ProcessInformationLength,
PDWORD ReturnLength
); typedef struct _PROCESS_BASIC_INFORMATION
{
...
} PROCESS_BASIC_INFORMATION, *PPROCESS_BASIC_INFORMATION; PVOID GetPebAddress(int pid)
{
_NtQueryInformationProcess NtQueryInformationProcess = (_NtQueryInformationProcess)
GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtQueryInformationProcess");
PROCESS_BASIC_INFORMATION pbi;
HANDLE processHandle = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid); NtQueryInformationProcess(processHandle, , &pbi, sizeof(pbi), NULL);
CloseHandle(processHandle); return pbi.PebBaseAddress;
}

Once you get the address of the PEB, you’ll have to read its contents. This can easily be done using ReadProcessMemory. Inside the PEB, there’s a pointer to a second structure,RTL_USER_PROCESS_PARAMETERS. Here’s some stuff from the the PEB struct definition:

typedef struct _PEB
{
/* +0x0 */ BOOLEAN InheritedAddressSpace; /* BOOLEANs are one byte each */
/* +0x1 */ BOOLEAN ReadImageFileExecOptions;
/* +0x2 */ BOOLEAN BeingDebugged;
/* +0x3 */ BOOLEAN Spare;
/* +0x4 */ HANDLE Mutant;
/* +0x8 */ PVOID ImageBaseAddress;
/* +0xc */ PPEB_LDR_DATA LoaderData;
/* +0x10 */ PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
...

Those comments on the left hand side are offsets from the beginning of the PEB; if we want to get the address of ProcessParameters, we simply read 4 bytes from PEB address + 0x10. For example:

PVOID pebAddress = ...; /* get the PEB address */
PVOID rtlUserProcParamsAddress; ReadProcessMemory(processHandle, /* open the process first... */
(PCHAR)pebAddress + 0x10,
&rtlUserProcParamsAddress, /* we'll just read directly into our variable */
sizeof(PVOID),
NULL
);

So, now we have the address of ProcessParameters. Let’s look inside it:

typedef struct _RTL_USER_PROCESS_PARAMETERS
{
ULONG MaximumLength;
ULONG Length;
ULONG Flags;
ULONG DebugFlags;
PVOID ConsoleHandle;
ULONG ConsoleFlags;
HANDLE StdInputHandle;
HANDLE StdOutputHandle;
HANDLE StdErrorHandle;
/* +0x24 */ UNICODE_STRING CurrentDirectoryPath;
HANDLE CurrentDirectoryHandle;
/* +0x30 */ UNICODE_STRING DllPath;
/* +0x38 */ UNICODE_STRING ImagePathName;
/* +0x40 */ UNICODE_STRING CommandLine;
... /* more stuff you probably won't care about */

UNICODE_STRING is simply a counted Unicode string:

typedef struct _UNICODE_STRING
{
USHORT Length;
USHORT MaximumLength;
PWSTR Buffer;
} UNICODE_STRING, *PUNICODE_STRING;

It’s pretty obvious what you have to do from here on. You have to read the desired UNICODE_STRING structure and then read the contents of Buffer (Length is in bytes, not characters). (Now that you’ve seen the definition of RTL_USER_PROCESS_PARAMETERS, you’ll probably want other strings as well!) A complete sample program is below. Note that the code does not work on x64 due to the hard-coded offsets; you may want to include the structure definitions for the PEB and process parameters and use FIELD_OFFSET to get the correct offsets.

#include <windows.h>
#include <stdio.h> typedef NTSTATUS (NTAPI *_NtQueryInformationProcess)(
HANDLE ProcessHandle,
DWORD ProcessInformationClass,
PVOID ProcessInformation,
DWORD ProcessInformationLength,
PDWORD ReturnLength
); typedef struct _UNICODE_STRING
{
USHORT Length;
USHORT MaximumLength;
PWSTR Buffer;
} UNICODE_STRING, *PUNICODE_STRING; typedef struct _PROCESS_BASIC_INFORMATION
{
LONG ExitStatus;
PVOID PebBaseAddress;
ULONG_PTR AffinityMask;
LONG BasePriority;
ULONG_PTR UniqueProcessId;
ULONG_PTR ParentProcessId;
} PROCESS_BASIC_INFORMATION, *PPROCESS_BASIC_INFORMATION; PVOID GetPebAddress(HANDLE ProcessHandle)
{
_NtQueryInformationProcess NtQueryInformationProcess =
(_NtQueryInformationProcess)GetProcAddress(
GetModuleHandleA("ntdll.dll"), "NtQueryInformationProcess");
PROCESS_BASIC_INFORMATION pbi; NtQueryInformationProcess(ProcessHandle, , &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 < )
{
printf("Usage: getprocesscommandline [pid]\n");
return ;
} pid = _wtoi(argv[]); if ((processHandle = OpenProcess(
PROCESS_QUERY_INFORMATION | /* required for NtQueryInformationProcess */
PROCESS_VM_READ, /* required for ReadProcessMemory */
FALSE, pid)) == )
{
printf("Could not open process!\n");
return GetLastError();
} pebAddress = GetPebAddress(processHandle); /* get the address of ProcessParameters */
if (!ReadProcessMemory(processHandle, (PCHAR)pebAddress + 0x10,
&rtlUserProcParamsAddress, sizeof(PVOID), NULL))
{
printf("Could not read the address of ProcessParameters!\n");
return GetLastError();
} /* read the CommandLine UNICODE_STRING structure */
if (!ReadProcessMemory(processHandle, (PCHAR)rtlUserProcParamsAddress + 0x40,
&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 / , commandLineContents);
CloseHandle(processHandle);
free(commandLineContents); return ;
}

HOWTO: Get the command line of a process(转)的更多相关文章

  1. could not launch process: debugserver or lldb-server not found: install XCode's command line tools or lldb-server

    0x00 事件 VS 调试 go 的时候,发生了这个错误,导致无法调试: could not launch process: debugserver or lldb-server not found: ...

  2. How to build .apk file from command line(转)

    How to build .apk file from command line Created on Wednesday, 29 June 2011 14:32 If you don’t want ...

  3. ubuntu16.04安装virtualbox5.1失败 gcc:error:unrecognized command line option ‘-fstack-protector-strong’

    系统:ubuntu16.04.1 软件:Virtualbox-5.1 编译器:GCC 4.7.4 在如上环境下安装Vbx5.1提示我在终端执行/sbin/vboxconfig命令 照做 出现如下err ...

  4. python click module for command line interface

    Click Module(一)                                                  ----xiaojikuaipao The following mat ...

  5. atprogram.exe : Atmel Studio Command Line Interface

    C:\Program Files\Atmel\Atmel Studio 6.1\atbackend\atprogram.exe No command specified.Atmel Studio Co ...

  6. 10 Interesting Linux Command Line Tricks and Tips Worth Knowing

    I passionately enjoy working with commands as they offer more control over a Linux system than GUIs( ...

  7. Building Xcode iOS projects and creating *.ipa file from the command line

    For our development process of iOS applications, we are using Jenkins set up on the Mac Mini Server, ...

  8. [笔记]The Linux command line

    Notes on The Linux Command Line (by W. E. Shotts Jr.) edited by Gopher 感觉博客园是不是搞了什么CSS在里头--在博客园显示效果挺 ...

  9. Linux Command Line(II): Intermediate

    Prerequisite: Linux Command Line(I): Beginner ================================ File I/O $ cat > a ...

随机推荐

  1. /touch滑屏事件

    //touch滑屏事件     var windowHeight = $(window).height(),     $body = $("body");     $body.cs ...

  2. 正则表达式之你不知道的replace

    我们都知道js内置类String提供了一个replace方法,可以把指定字符串替换为另一个字符串,他的基础用法如下: var str="hello world"; var str= ...

  3. KVM创建虚拟机

    一.复制现有img备份 1.ssh登陆宿主机 我的在 192.168.0.302.复制img 我的虚拟机img文件在 /home/images 我的img模板文件在 /home/tools/kvm/i ...

  4. 网络协议之NAT穿透

    NAT IPv4地址只有32位,最多只能提供大致42.9亿个唯一IP地址,当设备越来越多时,IP地址变得越来越稀缺,不能为每个设备都分配一个IP地址.于是,作为NAT规范就出现了.NAT(Networ ...

  5. javaScript一些需要注意的细节

    变量声明早于代码运行. 函数声明早于变量声明. this指针代表的是执行当前代码的对象的所有者. JavaScript执行完同步,才能执行异步队列.如:alert,for if while 同步执行, ...

  6. delphi TComponent类(1)

    来自:http://blog.csdn.net/lailai186/article/details/7442383 ------------------------------------------ ...

  7. (五)HttpClient 连接超时及读取超时

    第一节: HttpClient 连接超时及读取超时 HttpClient连接超时及读取超时 httpClient在执行具体http请求时候 有一个连接的时间和读取内容的时间: HttpClient连接 ...

  8. Oracle约束

    1.非空约束 DROP TABLE member PURGE; CREATE TABLE member( mid NUMBER, name ) NOT NULL ); 2.唯一约束 DROP TABL ...

  9. 20165203《Java程序设计》第七周Java学习总结

    20165203<Java程序设计>第七周Java学习总结 教材学习内容总结 第11章 JDBC与MySQL数据库 MySQL数据库管理系统 MySQL数据库管理系统,简称MySQL,是世 ...

  10. SCTF 2014 PWN400 分析

    之前没有分析PWN400,现在再开一篇文章分析一下. 这个日志是我做题的一个笔记,就是说我做一步题就记录一下是实时的.所以说可能会有错误之类的. 首先程序是经典的笔记本程序,基本上一看到这种笔记本就知 ...