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. 23 The Laws of Reflection 反射定律:反射包的基本原理

    The Laws of Reflection  反射定律:反射包的基本原理 6 September 2011 Introduction 介绍 Reflection in computing is th ...

  2. tensorflow session 和 graph

    graph即tf.Graph(),session即tf.Session(),很多人经常将两者混淆,其实二者完全不是同一个东西. graph定义了计算方式,是一些加减乘除等运算的组合,类似于一个函数.它 ...

  3. 洛谷P2312解方程

    传送门 思路分析 怎么求解呢? 其实我们可以把左边的式子当成一个算式来计算,从1到 $ m $ 枚举,只要结果是0,那么当前枚举到的值就是这个等式的解了.可以通过编写一个 $ bool $ 函数来判断 ...

  4. thinkphp5高亮当前页(仅针对个人项目记录,不做通用参考)

    <div class="navbg"> <ul class="menu"> <li> <a href="/& ...

  5. Codeforces 931D Peculiar apple-tree(dfs+思维)

    题目链接:http://codeforces.com/contest/931/problem/D 题目大意:给你一颗树,每个节点都会长苹果,然后每一秒钟,苹果往下滚一个.两个两个会抵消苹果.问最后在根 ...

  6. CVE-2010-2553 Microsoft Windows Cinepak 编码解码器解压缩漏洞 分析

      Microsoft Windows是微软发布的非常流行的操作系统.         Microsoft Windows XP SP2和SP3,Windows Vista SP1和SP2,以及Win ...

  7. Firefox地址栏样式设定

    我希望把Firefox的界面调整为chrome-like,一个关键的地方就是地址栏:地址栏和tab之间的距离太大了,地址栏和页面本身之间的距离也太大. 设定方法是在FF中安装stylish插件,然后加 ...

  8. CCF CSP 201703-4 地铁修建

    博客中的文章均为meelo原创,请务必以链接形式注明本文地址 CCF CSP 201703-4 地铁修建   问题描述 A市有n个交通枢纽,其中1号和n号非常重要,为了加强运输能力,A市决定在1号到n ...

  9. 使用PHP写了一个图片分割等份工具,便于前台页面切图时使用。

    目的: 由于网站更新活动较频繁,其大多数以静态图片为主,设计人员在除了设计图后都要给前端制作人员再次切图从而达到页面加载图片缓慢的问题,为了减少工作量做了该工具. 功能: 上传一张图,将其分割成指定等 ...

  10. Linux下Github的使用方法

    1 Linux下Git和GitHub环境的搭建 安装Git, 使用命令sudo apt-get install git 创建GitHub帐号 生成ssh key,使用命令 ssh-keygen -t ...