[PHP底层]命令执行底层分析

Posted Y4tacker

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[PHP底层]命令执行底层分析相关的知识,希望对你有一定的参考价值。

写在前面

新法颁布,很多也不敢发了,就偶尔写一篇有意思的东西吧

命令执行底层分析

注意本篇是基于windows平台进行的分析
环境这方面就不多说了VisualStudio、Vscode、php-src源码编译
插件用了c\\c++、CodeRunner,环境很简单不想多说,直接干活
故事从一个system('whoami');说起,你明天都输入这些函数真的就不好奇干了些什么吗
分析前先给大家看看函数调用栈,很清晰

回到正题

通过全局搜索,我们定位到了ext\\standard\\exec.c第263行

这时候顺便还发现execsystempassthru调用的是同一个函数php_exec_ex


静态调试有限,直接打上断点动态调试,首先是对cmd参数进行初始化处理


这是一个宏定义函数,实际上调用zend_parse_arg_string实际上是对执行的命令检查是否为空并且赋值


接下来,看到这句话我似乎明白了当初的低版本命令执行等骚姿势为什么高版本不行了

接下来调用php_exec

发现函数内部会首先调用VCWD_POPEN()函数去处理cmd指令,可以看到VCWD_POPEN()函数调用会通过相应的平台去执行,不赘述

可以看到通过宏定义,实际上调用了virtual_popen

virtual_popen的核心是popen_ex,对于不同平台实现也不同


继续看看它干了些什么

这里面有个比较关键的分配空间的操作,为什么加一个/c你细品

实际上最终cmd的调用是cmd.exe /c "whoami"是不是和bash -c很像呢,从这里可以看出

进行类型转换

到这里也就会发现system命令执行函数底层都会调用系统终端cmd.exe来执行传入的指令参数,既然要调用cmd,肯定就要启动相应的进程
这里通过Windows系统API来启动cmd.exe进程,通过搜索引擎了解发现
在 Windows 平台上,创建进程有 WinExec,system,_spawn/_wspawn,CreateProcess,ShellExecute 等多种途径,但基本上还是由 CreateProcess 家族封装的。
本文章著作权归作者所有,任何形式的转载都请注明出处。

看看这个函数的函数声明,对照上面参数看一看就ok

WINBASEAPI
BOOL
WINAPI
CreateProcessW(
    LPCWSTR lpApplicationName,    //指向一个NULL结尾的,新进程的可执行文件的名称
    LPWSTR lpCommandLine,          //指向一个NULL结尾的,传给新进程的命令行字符串
    LPSECURITY_ATTRIBUTES lpProcessAttributes,
    //指向一个SECURITY_ATTRIBUTES结构体,分配给新的进程对象
    //SECURITY_ATTRIBUTES结构可以决定是否返回的句柄可以被子进程继承(bInheritHandle )。如果lpProcessAttributes参数为空(NULL),那么句柄不能被继承。
    //SECURITY_ATTRIBUTES结构的lpSecurityDescriptor成员可以指定新进程的安全描述符,如果参数为空,新进程使用默认的安全描述符。
    LPSECURITY_ATTRIBUTES lpThreadAttributes,
    //指向一个SECURITY_ATTRIBUTES结构体,分配给新的线程对象
    BOOL bInheritHandles,
    //标识新进程是否可以从调用进程处继承所有可继承的句柄。被继承的句柄与原进程拥有完全相同的值和访问权限。
    DWORD dwCreationFlags,
    //标识了影响新进程创建方式的标志,多个标志按位或进行组合
    LPVOID lpEnvironment,
    //指向一块内存,其中包含新进程要使用的环境字符串。如果此参数为空,新进程继承父进程的一组环境字符串。
    LPCWSTR lpCurrentDirectory,
    //指向一个以NULL结尾的字符串,用来设置新进程的当前驱动器和目录,这个字符串必须是一个包含驱动器名的绝对路径。如果这个参数为空,新进程将使用与父进程相同的驱动器和目录。
    LPSTARTUPINFOW lpStartupInfo,
    //指向一个用于决定新进程的主窗体如何显示的STARTUPINFO结构体。
    LPPROCESS_INFORMATION lpProcessInformation
    //指向一个用来接收新进程的识别信息的PROCESS_INFORMATION结构体。
    );

因此它最终将进程运行的结果信息以流的形式返回,也就完成了PHP命令执行函数的整个调用过程

后面就是对这个返回的文件流的操作就不分析了

以上是关于[PHP底层]命令执行底层分析的主要内容,如果未能解决你的问题,请参考以下文章

PHP_底层分析

探究PHP底层

图解 Google V8 # 05:函数表达式的底层工作机制

php底层原理

iOS底层探索之dyld:动态链接器流程分析

PHP底层运行原理简括