接着研究,不是为了对错,而是想弄清楚到底是怎么回事,而且不想误导看帖子的朋友们。
我最初以为下面这条语句不会得到需要的结果,而且很可能会异常:
之所以这样说,是因为XP及以后的系统,NT NATIVE程序的入口函数原型是:
void __stdcall NtProcessStartup(struct _PEB* Peb);
XP上_PEB的定义如下:
Argument->Environment->CommandLine取到的会是什么呢?而根据源程序中native.h定义,Environment在Argument中的偏移是0xc, CommmandLine在Environment中的偏移为0x54。对应到_PEB,_PEB偏移0xC处是struct _PEB_LDR_DATA指针Ldr,因此Argument->Environment实际上是Peb->Ldr; Ldr偏移0x54处是什么?这要看struct _PEB_LDR_DATA的定义了,XP上它定义如下:
可以看到,此结构大小仅为0x28, 偏移0x54在结构定义之外了,因此我写这个帖子时认为:
commandLine = &Argument->Environment->CommandLine
不会得到正确的结果,甚至很可能异常。但2楼回答让我有些意外,于是实际执行了native程序,确实可以显示参数,说明程序得到了执行,且结果是正确的,至此我以为这是微软故意为兼容而设的。
但总觉得此事诡异,今天闲来无事,搭个调试环境,实际跟踪一下,有了如下发现:
&Argument->Environment->CommandLine得到是并不是CommandLine,且看下面WinDbg输出:
WinDbg断在autochk的入口处,看栈:
Argument/Peb=0x7ffda000
Argument->Environment/Peb->Ldr=0x171e90
Argument->Environment->CommandLine/Ldr偏移0x54处的UNICODE_STRING长度为0x44,指向的字符串为:
显然,20534指向的并不是CommandLine,它只是程序的路径,紧邻的下一个字符才是命令行。
那native又是如何得到结果的呢?且看native.cpp:
关键在于while循环上,它并没有检测字符串结束,而是检测空格,从而从20534越到了相邻的下一个字符串,而下一个正好是命令行,因此最终argPtr指向了参数。
如果执行native不加参数执行,则因为找不到空格而导致该程序异常终止。
用Peb如何得到令行参数呢,也很简单,如下:
Peb->ProcessParameters->CommandLine
ProcessParameters结构内偏移0x10,CommandLine结构内偏移0x40,看一下内存:
由于_PEB不同版本不同,可能存在兼容性问题,不过就取CommandLine而言,目前还没有问题,32位的Win7的_PEB定义如下:
相应的_RTL_USER_PROCESS_PARAMETERS定义如下:
XP版
Win7版
可以看到Peb->ProcessParameters->CommandLine是稳定的。
你在程序还可以引用_PEB中的其它项(比如可以引用_PEB中的堆,而不需要自己创建一个),只是要小心兼容性问题。