String cmd = "open /System/Applications/Calculator.app/";
int[] ineEmpty = {-1, -1, -1};
Class clazz = Class.forName("java.lang.UNIXProcess");
Unsafe unsafe = Utils.getUnsafe();
Object obj = unsafe.allocateInstance(clazz);
Field helperpath = clazz.getDeclaredField("helperpath");
helperpath.setAccessible(true);
Object path = helperpath.get(obj);
byte[] prog = "/bin/bash\u0000".getBytes();
String paramCmd = "-c\u0000" + cmd + "\u0000";
byte[] argBlock = paramCmd.getBytes();
int argc = 2;
Method exec = clazz.getDeclaredMethod("forkAndExec", int.class, byte[].class, byte[].class, byte[].class, int.class, byte[].class, int.class, byte[].class, int[].class, boolean.class);
exec.setAccessible(true);
exec.invoke(obj, 2, path, prog, argBlock, argc, null, 0, null, ineEmpty, false);
代码功能概览
- 这段代码尝试在 macOS 系统中调用 Calculator 应用程序 (
Calculator.app
)。 - 它通过使用
Unsafe
类和 Java 反射来访问 Java 的内部UNIXProcess
类,进而执行系统命令。 - 该代码基本上是绕过了 Java 的安全机制,直接与操作系统交互。
代码分步解释
-
定义命令:
String cmd = "open /System/Applications/Calculator.app/";
- 这里定义了要执行的命令,打开 macOS 系统的计算器应用。
-
初始化参数:
int[] ineEmpty = {-1, -1, -1};
ineEmpty
数组用于存储文件描述符,用于重定向输入/输出流。-1
表示不重定向。
-
获取
UNIXProcess
类:Class clazz = Class.forName("java.lang.UNIXProcess");
- 使用
Class.forName()
方法获取java.lang.UNIXProcess
类的引用,这是一个内部类,通常不应该在普通 Java 代码中被访问。
- 使用
-
获取
Unsafe
实例:Unsafe unsafe = Utils.getUnsafe();
Unsafe
类允许直接操作内存和执行低级别操作。正常情况下,这个类是受保护的,但这里使用了某种方式(Utils.getUnsafe()
)绕过了限制。
-
实例化
UNIXProcess
对象:Object obj = unsafe.allocateInstance(clazz);
- 通过
Unsafe
的allocateInstance
方法创建UNIXProcess
的实例,而不调用其构造函数。
- 通过
-
获取
helperpath
字段的值:Field helperpath = clazz.getDeclaredField("helperpath"); helperpath.setAccessible(true); Object path = helperpath.get(obj);
- 这里通过反射获取
UNIXProcess
类的helperpath
字段。这个字段通常用于存储用于执行系统命令的帮助程序路径。
- 这里通过反射获取
-
准备要执行的程序和参数:
byte[] prog = "/bin/bash\u0000".getBytes(); String paramCmd = "-c\u0000" + cmd + "\u0000"; byte[] argBlock = paramCmd.getBytes(); int argc = 2;
prog
是要执行的程序路径 (/bin/bash
)。paramCmd
是实际要传递给bash
的参数,这里使用了-c
来执行cmd
中定义的命令。
-
获取
forkAndExec
方法并执行:Method exec = clazz.getDeclaredMethod("forkAndExec", int.class, byte[].class, byte[].class, byte[].class, int.class, byte[].class, int.class, byte[].class, int[].class, boolean.class); exec.setAccessible(true); exec.invoke(obj, 2, path, prog, argBlock, argc, null, 0, null, ineEmpty, false);
- 这里使用反射获取
UNIXProcess
的forkAndExec
方法,并通过invoke
调用。 forkAndExec
是一个底层方法,用于在 Unix 系统中创建新的进程。这里实际执行的命令是open /System/Applications/Calculator.app/
。
- 这里使用反射获取
总结
- 目的:这段代码的目的是在 macOS 系统上执行特定的 shell 命令,打开计算器应用程序。
- 技术手段:利用 Java 反射和
Unsafe
类来绕过 Java 的安全限制,直接与操作系统交互。这种技术通常被认为是恶意行为的标志,因为它绕过了 Java 的安全沙箱。 - 风险:这类代码有可能被恶意使用,运行未经授权的命令,特别是在用户不知情的情况下。因此,使用
Unsafe
类和反射需要极高的权限,并且可能会被现代 JVM 和安全策略所禁止。
**注意:**此代码片段可能在现代 Java 版本(如 17 或更高版本)中失效,因为 Java 在新版本中加强了安全防护措施,防止未经授权的反射访问。