当前位置: 首页 > news >正文

泰安网站建设热线电话/全国病毒感染最新消息

泰安网站建设热线电话,全国病毒感染最新消息,建一个商业网站要多少钱,做h视频在线观看网站在使用java.lang.Runtime#exec()执行命令时,为何有时候命令前缀需要加cmd /c或者bash -c?今天就来一探究竟!Java执行命令的3种方法首先了解下在Java中执行命令的方法:常用的是 java.lang.Runtime#exec()和 java.lang.ProcessBuild…

10d66fa3828adedabd9dd8f9b298493f.gif

在使用java.lang.Runtime#exec()执行命令时,为何有时候命令前缀需要加cmd /c或者bash -c?今天就来一探究竟!

Java执行命令的3种方法

首先了解下在Java中执行命令的方法:

常用的是 java.lang.Runtime#exec()和 java.lang.ProcessBuilder#start(),除此之外,还有更为底层的java.lang.ProcessImpl#start(),他们的调用关系如下图所示:

a20ab1f48ad2c2248c329f0567e48913.png

其中,ProcessImpl类是Process抽象类的具体实现,且该类的构造函数使用private修饰,所以无法在java.lang包外直接调用,只能通过反射调用ProcessImpl#start()方法执行命令。

f4c712d125579a41427b2d78359f5370.png

这3种执行方法如下:

java.lang.Runtime

public static String RuntimeTest() throws Exception {    InputStream ins = Runtime.getRuntime().exec("whoami").getInputStream();    ByteArrayOutputStream bos = new ByteArrayOutputStream();byte[] bytes = new byte[1024];int size;while((size = ins.read(bytes)) > 0)        bos.write(bytes,0,size);return bos.toString();}

baf6b8542da4aed8cb573ba9f55ccde6.png

java.lang.ProcessBuilder

public static String ProcessTest() throws Exception { String[] cmds = {"cmd","/c","whoami"}; InputStream ins = new ProcessBuilder(cmds).start().getInputStream(); ByteArrayOutputStream bos = new ByteArrayOutputStream();byte[] bytes = new byte[1024];int size;while((size = ins.read(bytes)) > 0) bos.write(bytes,0,size);return bos.toString();}

026011fa202c92bc474cf17a9ce29ba7.png

java.lang.ProcessImpl

public static String ProcessImplTest() throws Exception { String[] cmds = {"whoami"}; Class clazz = Class.forName("java.lang.ProcessImpl"); Method method = clazz.getDeclaredMethod("start", new String[]{}.getClass(),Map.class,String.class,ProcessBuilder.Redirect[].class,boolean.class); method.setAccessible(true); InputStream ins = ((Process) method.invoke(null,cmds,null,".",null,true)).getInputStream(); ByteArrayOutputStream bos = new ByteArrayOutputStream();byte[] bytes = new byte[1024];int size;while((size = ins.read(bytes)) > 0) bos.write(bytes,0,size);return bos.toString();}

9cc5ed4c15c53639dd527c752b39ea1b.png

问题:

当直接将命令字符 echo echo_test > echo.txt 传给 java.lang.Runtime#exec()执行时报错:

99281612c0911d8f493c0aa74eae20e8.png

加上cmd /c 可以成功执行:

97309fcaf9ca385fc96b741f284007c3.png

我们跟进下代码看看是什么原因导致的?

命令执行解析流程:

传入命令字符串echo echo_test > echo.txt进行调试,跟进java.lang.Runtime#exec(String),该方法又会调用java.lang.Runtime#exec(String,String[],File)。

5329d9ea29b619c74e3ba051281c9dc1.png

4e42c783b32997daba544611f0323905.png

在该方法中调用了StringTokenizer类,通过特定字符对命令字符串进行分割,本地测试如下:

34c7602a1df7f8dec57a44affc3225de.png

所以命令字符串echo echo_test > echo.txt经过StringTokenizer类处理后得到命令数组:{"echo","echo_test",">","echo.txt"} 。另外java.lang.Runtime#exec()共有6个重载方法,代码如下:

public Process exec(String command) throws IOException {return exec(command, null, null);}public Process exec(String cmdarray[]) throws IOException {return exec(cmdarray, null, null);}  public Process exec(String command, String[] envp) throws IOException {return exec(command, envp, null);}public Process exec(String command, String[] envp, File dir)throws IOException {if (command.length() == 0)throw new IllegalArgumentException("Empty command");  StringTokenizer st = new StringTokenizer(command);  String[] cmdarray = new String[st.countTokens()];for (int i = 0; st.hasMoreTokens(); i++)    cmdarray[i] = st.nextToken();return exec(cmdarray, envp, dir);}public Process exec(String[] cmdarray, String[] envp) throws IOException {return exec(cmdarray, envp, null);}public Process exec(String[] cmdarray, String[] envp, File dir)throws IOException {return new ProcessBuilder(cmdarray)    .environment(envp)    .directory(dir)    .start();}

这6个重载函数根据参数不同进行区分,主要是传入字符串跟数组两种形式,但是最终调用的都是最后一个exec(String[],String[],File),在该函数内部首先调用ProcessBuilder类的构造函数创建ProcessBuilder对象,然后调用start(),最终返回一个Process对象。

所以Runtime#exec()底层还是调用的ProcessBuilder#start(),且传入构造函数的参数要求是数组类型(如下图),所以传给Runtime#exec()的命令字符串需要先使用StringTokenizer类分割为数组再传入ProcessBuilder类。

fbd4257d28b223d7a22c4813df40a7de.png

接着跟进java.lang.ProcessBuilder#start(),取出cmdarray[0]赋值给prog,如果安全管理器SecurityManager开启,会调用SecurityManager#checkExec()对执行程序prog进行检查,之后调用ProcessImpl#start()。

c50abb23a24cc86f0e09d084cf5baaeb.png

跟进java.lang.ProcessImpl#start(),Windows下会调用ProcessImpl类的构造方法,如果是Linux环境,则会调用java.lang.UNIXProcess#init<>。

88afac5e6442ae464b1ba059cb93a5aa.png

跟进java.lang.ProcessImpl的构造方法

该方法内allowAmbiguousCommands变量为 "是否允许调用本地进程" 的开关,在安全管理器未开启且jdk.lang.Process.allowAmbiguousCommands不为false时,allowAmbiguousCommands变量值才为true。当系统允许调用本地进程时,进入Legacy mode(传统模式),会调用needsEscaping(),当prog存在空格且未被双引号包裹时需要使用quoteString()进行处理,接着调用createCommandLine()将命令数组拼接为命令字符串,最后调用create()创建进程。

3ad43a8146c611c19628c52032b447d9.png

传统模式下,当可执行程序prog存在\t 或空格时,该函数返回true,即需要双引号包裹处理。

d973c00b7376fe53a0a5f3765a48b449.png

f7e9638996e08ee449b4253421635c66.png

最后调用ProcessImpl#create(),这是一个native方法,根据JNI命名规则,会调用到ProcessImpl_md.c 中的Java_Java_lang_ProcessImpl_create(),该函数会调用Windows系统API函数:CreateProcessW(),用来创建一个新的Windows进程。创建成功后,将新进程的句柄返回给ProcessImpl#create()。

510f6087abcd8211d909f56f247f0919.png

看下CreateProcessW()怎么处理我们传入的命令的:当第一个参数(lpApplicationName)为0时,第二个参数pcmd(lpCommandLine)需要提供启动程序及所需参数,彼此间以空格隔开。

99d21feb5486697c96842b9764fd23ee.png

c301fc224298dd852caec1a551299655.png

3b0a1e3acf57db2708b010d2bfcc02c4.png

测试 ProcessImpl#create() 方法:

5fd2b58e37418db29d92e0d01ff8ec6b.png

加上cmd /c之后,成功执行命令:

d1bba56589267607fb57aed1e4bddd63.png

需要添加cmd /c的原因:

在传入 echo echo_test > echo.txt 命令字符串时,出现错误("java.io.IOException: Cannot run program "echo": CreateProcess error=2, 系统找不到指定的文件。")。原因是echo为命令行解释器cmd.exe的内置命令,并不是一个单独可执行的程序(如下图),所以如果想执行echo命令写文件需要先启动cmd.exe,然后将echo命令做为cmd.exe的参数进行执行。

3d4c124d40985b654c7b885ab90fa4ac.png

另外关于cmd下的 /c 参数,当未指定时,运行如下示例程序,系统会启动一个pid为8984的cmd后台进程,由于cmd进程未终止导致java程序卡死。当指定/c时,cmd进程会在命令执行完毕后成功终止。

82d26816b47564a363aa445e2f3be34a.png

74764f0e15b31c6d0317c4c8f2fda3bc.png

87f4079db90c44d2f1170c116fed7915.gif

所以在Windows环境下,使用Runtime.getRuntime()执行的命令前缀需要加上cmd /c,使得底层Windows的processthreadsapi.h#CreateProcessW()方法在创建新进程时,可以正确识别cmd且成功返回命令执行结果。

未完待续...

360BugCloud开源漏洞响应平台,国内自主议价漏洞收录模式开拓者!聚焦收录未被披露的开源以及通用组件高危漏洞,致力于维护开源软件和供应链安全。平台采用入驻邀请制,只面向成功提交未被披露漏洞的安全研究员开放。360BugCloud开源漏洞响应平台首创“自主议价”模式及“第三方专家评审”机制,先议价后交洞,仅需提交漏洞影响力描述即可进行议价,让安全研究员完全掌握漏洞提交主动权,高额奖金上不封顶,让漏洞价值得到充分保障与肯定。

6步轻松实现在360BugCloud提交漏洞

a7dfe6ccf4f050f9fe754d93020d217f.png360BugCloud漏洞提交地址

d819f69cfdc9e417db767d1e958e7205.png

360BugCloud开源漏洞响应平台秉承“Trust信任、Tenet原则、Top权威、Together共建”的04T宗旨,力争打造以技术为驱动、以安全专家为核心的应急响应平台,提升网络安全防护能力,为国家、企业、用户打造最安全的网络环境。

d631ae686a8a6b53d48e5508d4148743.png

http://www.lbrq.cn/news/1406539.html

相关文章:

  • 专门做考研的网站/优化排名seo
  • xyz域名做网站好么/色盲测试图
  • e时代速递搜索引擎网站建设/百度seo优
  • 小县城 交友网站 很难做/资源企业网站排名优化价格
  • 中国网站排名 优帮云/企业培训师
  • tech域名可以做网站吗/精准网络推广
  • 宣威市住房和城乡建设局网站/网站建设规划书
  • 网站加速打开/seo顾问阿亮
  • 中建国际建设有限公司官网/大连网站优化
  • 优化网站推广网站/seo优化推广教程
  • 做pc端网站价位/seo教程百度网盘
  • 做营销型网站/云搜索下载
  • wordpress 营销模板下载/seo免费培训视频
  • 大连日文网站设计/10000个免费货源网站
  • 推广论坛有哪些/搜索优化引擎
  • 网站开发常见方法/深圳优化公司找高粱seo服务
  • 网站开发设计语言/网站设计是做什么的
  • 自己建网站 知乎/seo网络营销推广公司
  • ui设计师可以做到多少岁/seo网站推广是什么
  • 打电话沟通做网站/竞价外包
  • 虎门做网站公司/域名收录查询工具
  • 自己搭建服务器做视频网站/如何获取网站的seo
  • app开发导入网站模板/中文搜索引擎排名
  • drupal做新闻网站/查看域名每日ip访问量
  • 长沙做网站建设公司排名/免费建设网站平台
  • 电商网站建设的步骤/百度关键词流量查询
  • 网站怎么做301跳转/公众号软文怎么写
  • 重庆给商家企业做网站/深圳网络推广代理
  • 如何创建一个网站链接/windows优化大师有用吗
  • 做的网站百度搜不到/唐山seo
  • 大数据云原生是什么
  • OCR库pytesseract安装保姆级教程
  • LAMP 架构部署:Linux+Apache+MariaDB+PHP
  • 基于51单片机汽车自动照明灯超声波光敏远近光灯设计
  • 自然语言处理NLP---预训练模型与 BERT
  • 深度剖析Redisson分布式锁项目实战