析命令提示符的原理

前言

 

 

 

 

启动命令提示符后,是否有这些疑问:

  1. 为什么执行ipconfig,可以直接查询到IP信息
  2. 为什么执行ping ip,可以查询到对应的主机状态。响应、未响应。
  3. 为什么执行notepad,可以启动记事本。
  4. 为什么执行explorer,可以启动文件管理器。

这些背后的原理会是什么?运作的机制又是什么?为什么输入几个简单的几个字母就能启动外部程序?

 

 

主题

本次分享围绕这以下五个问题开展:

1、在命令提示符里输入 notepad,是哪个位置的记事本被启动了?跟什么有关?

2、如果同一个目录下有两个名为 Testtest的文件,一个是 Testtest.com, 一个是 Testtest.exe。在命令提示符中输入 Testtest会执行哪个?受什么影响?

3、你知道怎么让自己的程序可以直接在命令提示符中被启动吗?像执行 ipconfig 那样。

4、如果 PATH 环境变量是空的,会有什么问题?

5、如果 PATHEXT 变量是空的,会有什么问题?

 

验证方式

(1)PATH验证

例子1:进入指定的文件夹中,在命令提示符输入一条不存在的命令,观察其搜索过程。

首先确定,当前命令提示符的路径在哪?相关的PATH参数。避免找错了目标。

 

 

 

 

 

 

PATH有点多,可以选择将其导出文档中。

命令:echo %PATH% > ./env.txt

 

 

 

 接下来,就通过process monitor捕获的事件,看看命令提示符的搜索路径是怎样的。

 

 

 

 

从上面图中可以看出,蓝色部分就是当前路径相关的事件,其他的都是与PATH环境变量相关的事件。

 

可以得出一个小结论:

  • 在命令提示符中输入命令会先在当前路径下查找,再到 PATH 环境变量指定的路径依次查找。

 

 

例子2:添加一个不存在的路径到PATH环境变量中,再次观察整个过程。

更新PATH环境变量的命令:set PATH=%PATH%E:\NotFolder

 

 

 可以看出,其他路径都没有改变,但PATH中多出一条E:\NotFolder。

 

在命令提示符中,再顺便输入一条命令,查看器搜索过程。

 

 

 是否发现一个奇怪的点,为什么其他目录有3条记录,而最新添加的PATH却只有1条记录?

原因:

  • 已存在的路径,普遍有3条记录。分别是:打开、查询、关闭。
  • 不存在的路径,只有1条记录。只有:打开。因为不存在该路径,所以打开失败,不会再有查询操作了

也可以通过栈的调用过程来观察,如下:

 

 

 结论:

  •  本次的例子2进一步验证了,例子1的结论。 PATH 环境变量是依次查找的。
  •  在开发过程中,某环境变量特别重要,尽可能提前到前几个。

 

回顾下第一个问题:在命令提示符里输入 notepad,是哪个位置的记事本被启动了?跟什么有关?

 

 

例子3:编写一个测试程序(Testtest.exe),放到当前的路径下,通过命令启动,观察正常的启动路径。

测试程序内容:简单打印出当前程序的路径。

 

 

 从上图可知,启动的是 C:\Users\Luojialin\Desktop\Testtest\Testtest.exe,因为在当前路径下就找到了对应的程序,所以并没有到 PATH 环境变量指示的路径中查找。

 

例子4: 删除当前路径下测试程序(C:\Users\Luojialin\Desktop\Testtest\Testtest.exe),并将这个程序移动到C:\windows\下,同时添加环境变量(Testtest,Testtest.exe),再起启动测试程序。

注:如果不添加该环境变量,Testtest将会无法识别。

添加环境变量:set Testtest=Testtest.exe

查询某个环境变量:echo %Testtest%

 

 

 从上图可知,启动的是 C:\Windows\Testtest.exe,在当前路径下没找到,然后依次到 PATH 环境变量指示的路径中查找,在c:\windows\ 下找到了对应的程序。

 

例子3+例子4的结论:

  • 依次从PATH环境变量中查询,一旦查询到对应的名称且是可执行的,立马执行。不会继续往下查询。

 

此处应回顾下第3个问题:你知道怎么让自己的程序可以直接在命令提示符中被启动吗?像执行 ipconfig 那样。

 

例子5:清空 PATH 环境变量,在命令提示符中输入 ipconfig,看看是否能正常运行。

清空环境变量:set PATH=

 

 

 清空环境变量后,结果发现:连ipconfig也无法被执行了,但是ipconfig.exe这个程序是存在的。

 

大结论:

  • 命令提示符中执行一个命令时的查找顺序是:当前路径,PATH 环境变量中指定的路径(按出现顺序进行查找)。
  • 命令提示符依次从PATH环境变量中查询,一旦查询到对应的名称且是可执行的,立马执行。不会继续往下查询。
  • 环境变量可以被清除,命令启动依赖环境变量;一旦清除环境变量后,对应的命令无法被执行。

注:因为是在窗口中执行的清除操作,仅针对当前窗口有效,重启后%PATH%会重置为与system一致。如果清除system下的PATH,就会很严重。

 

此处应回顾下第4个问题:如果 PATH 环境变量是空的,会有什么问题?

 

(2)PATHEXT验证

在上面的例子3中,会先查找 Testtest.COM,没找到才继续查找的 Testtest.exe。为什么是这种行为呢?跟什么有关呢?

查看下PATHEXT环境变量的值,如下图:

 

 

提出疑问:.COM 出现在 .EXE 之前,是不是也是依次查询的呢?

 

例子6:调整PATHEXT的顺序,是否会影响到查询的结果。

调整PATHEXT顺序:set PATHEXT=.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC;.EXE;.COM

再次执行程序,通过Process monitor捕获的事件,观察。

从图中可以看出,PATHEXT的查询顺序被调整了。本来是.COM->.EXE;现在是:.BAT->CMD->.....->.EXE->.COM

 

小结论:

  • PATHEXT的查询顺序可以被调整,可以被修改。

 

 

例子7:清空PATHEXT,再次观察PATHEXT的行为。

清空PATHEXT:set PATHEXT=

通过Process monitor捕获相关的事件:

 

清空PATHEXT后,原以为会向PATH一样,无法执行成功;但Testtest被执行成功,.COM→.EXE。有点像一开始的设置。

会不会是默认的PATHEXT?如果是,那么默认的PATHEXT又是什么?

 

例子8:修改Testtest的扩展名,修改为Testtest.abcd,观察默认的PATHEXT。

注:修改扩展名为了能够通过"Testtest"直接进入搜索,同时又不会启动成功,引起中断。

再次通过Process monitor捕获相关的事件:

与开始的进行比较(例子6的前面截图),完全就是一模一样啊。这不就是默认的PATHEXT咯。

 

小结论:

  • 当 PATHEXT 为空时,默认搜索的扩展名是 .COM;.EXE;.BAT;.CMD;.VBS;.JS;.WS;.MSC。

 

此处就可以回顾下第5个问题:如果 PATHEXT 变量是空的,会有什么问题?

 

例子9:当前目录下同时存在 Testtest.com 和 Testtest.exe 会执行哪个?

单独设置.com与.exe的顺序关系。

如:

set PATHEXT=.COM;.EXE

set PATHEXT=.EXE;.COM

结果如下:

 

procmon 捕获的两次查找过程对比图,PAHTEXT的顺序确实会影响到查询的结果。

 

小结论:

  • 优先查找 PATHEXT 中先出现的后缀名。

 

此处就可以回顾下第2个问题:如果同一个目录下有两个名为 Testtest的文件,一个是 Testtest.com, 一个是 Testtest.exe。在命令提示符中输入 Testtest会执行哪个?受什么影响?

 

 

例子10:如果明确添加了扩展名,即选择绝对路径。

不通过程序名称,直接执行Testtest.exe,使用程序的绝对路径,结果又会是什么?查找路径又会是什么?

注:为了不干扰数据,可以重启机器。使用默认的PATHEXT。

 

从图中可以看出,根本就没有搜索.COM,而是直接找到了.EXE;同时,修改扩展名为Testtest.abc,如果Testtest.exe不存在,就会直接执行失败。

 

小结论:

  • 如果命令中带后缀,那么查找的时候不会依赖 PATHEXT ,会直接执行给定的命令。

 

 

总结论

  1. PATH决定了外部命令所在位置的查找顺序,PATHEXT 决定了外部命令的扩展名查找顺序。
  2. 当我们在命令提示符中输入一个命令时,会先到当前路径(Current Directory)中查找,如果找不到,才会到环境变量PATH 指示的路径中查找。
  3. 如果输入的命令不带后缀,那么会根据PATHEXT 指示的后缀顺序依次拼接成完整名称再查找。
  4. 如果输入的命令带后缀,不会根据PATHEXT 中的后缀查找。
  5. 如果我们想让自己的程序也能直接通过命令提示符启动,我们可以把程序所在路径添加到PATH 环境变量中,位置越靠前,越有可能被执行。
  6. 如果PATHEXT 为空,那么会使用默认的 PATHEXT,默认值是: .COM;.EXE;.BAT;.CMD;.VBS;.JS;.WS;.MSC;。(可能也会根据机器决定的,待验证)

 

 

 

测试程序DEMO

#include <windows.h>
#include <stdio.h>
 
int main(int argc, char* argv[]) {
    char exePath[MAX_PATH] = { 0 };
    ::GetModuleFileNameA(NULL, exePath, MAX_PATH);
    printf("%s\n", exePath);
    system("pause");
    return 0;
}

 

posted @ 2021-07-18 22:46  gd_沐辰  阅读(203)  评论(0编辑  收藏  举报