HOWTO: Get the command line of a process(转)
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 */
A 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(转)的更多相关文章
- 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: ...
- 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 ...
- 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 ...
- python click module for command line interface
Click Module(一) ----xiaojikuaipao The following mat ...
- atprogram.exe : Atmel Studio Command Line Interface
C:\Program Files\Atmel\Atmel Studio 6.1\atbackend\atprogram.exe No command specified.Atmel Studio Co ...
- 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( ...
- 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, ...
- [笔记]The Linux command line
Notes on The Linux Command Line (by W. E. Shotts Jr.) edited by Gopher 感觉博客园是不是搞了什么CSS在里头--在博客园显示效果挺 ...
- Linux Command Line(II): Intermediate
Prerequisite: Linux Command Line(I): Beginner ================================ File I/O $ cat > a ...
随机推荐
- 03 Go 1.3 Release Notes
Go 1.3 Release Notes Introduction to Go 1.3 Changes to the supported operating systems and architect ...
- 获取SQL Server的版本信息
微软 SQL Server 版本号 产品名称 发行日期 主版本号 正式版 SP1 SP2 SP3 SP4 SQL Server 2016 2016.06.01 13.00.1601.5 13.00.1 ...
- 缓存数据库-redis安装和配置
一:redis安装 python操作redis分为两部分,一为安装redis程序 二是安装支持python操作redis的模块 1)安装redis redis 官方网站:http://www.redi ...
- 移动端默认meta标签
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><met ...
- git忽略特殊文件或文件夹
1.在项目目录中添加“.gitignore”文件,项目目录就是你存放git工程的目录就是有“.git”目录的目录 vi .gitignore 2.在文件中添加如下内容,其中“/runtime/”是忽略 ...
- No.16 selenium学习之路之异常处理
一.常见的几种异常: SyntaxError:语法错误 NameError:试图访问的变量名不存在 IndexError:索引错误,使用的索引不存在,超出序列范围 KeyError:使用了不存在的关键 ...
- YUI Compressor 压缩 JavaScript 原理-《转载》
YUI Compressor 压缩 JavaScript 的内容包括: 移除注释 移除额外的空格 细微优化 标识符替换(Identifier Replacement) YUI Compressor包括 ...
- ThinkPHP小知识点
ThinkPHP模版中时间戳转换为时间 {$vo.data|date='Y-m-d',###} thinkphp字符截取函数msubstr() ThinkPHP有一个内置字符截取函数mb_substr ...
- SQL SERVER2008 镜像全攻略
--在非域控环境中创建数据库镜像, 我们必须使用证书来创建数据库镜像. 大致的步骤包括: --在为数据库镜像配置的每个服务器实例上执行下列步骤: --在 master 数据库中,创建数据库主密钥. - ...
- 判断一个字符是否为数字的两种方法(C/C++)
在平时,我们经常遇见判断字符是否为数字这种题目,虽然感觉还是很简单,不过我是个更喜欢用函数的人,因为我觉得这样更便捷,所以我更推荐第二种方式. 1.直接判断 #include <stdio.h& ...