本来想说“用JVM指令编写Java程序”,转念一想,现在已经有不少基于JVM的语言了,比如Groovy、Scala、JRuby和Jython等,它们底层都是以合法JVM执行的。所以,从某种意义上说,用JVM指令写不出Java程序。
这几天一时兴起玩起了逆向工程,看看程序背后的底层指令长成啥样。大学课程学了汇编,对于基本的汇编程序还是能流畅地完成编码、编译链接和反编译调试工作的。而玩了那么久Java却没从字节码的角度了解过JVM工作机制,实在是惭愧。前些天逆向了一个APK,并且在smali中嵌入自己的代码再次编译打包,实现了去广告和改变某些工作逻辑。(是的,没错,改变了程序某些地方的执行流程,比如……)对于Android虚拟机,网上已经有很多现成的工具编译其汇编指令,而纯Java的却很难找到。如今JAR/class已经可以很方便地反编译成Java源文件,或许Java代码比JVM指令更容易修改所以直接用JVM指令编程的需求很少吧。
Dalvik是基于寄存器的虚拟机,而JVM是基于栈的虚拟机。参考http://casper.cii.saxion.nl:8083/~vanleeuw/pse/spanje/jasm.html,文中提到可用Jasmin编译JVM指令,我试了一下,感觉还算简单。因为JVM字节码有很严格的格式和验证机制,而javap反编译出来的纯指令是无法编译成合法的class的,因此Jasmin语法的源文件需要加入一些额外的属性修饰。以下是我参考上文写的Hello类。
.class public Hello .super java/lang/Object.method public <init>()V
aload_0
invokenonvirtual java/lang/Object/<init>()V
return
.end method.method public static main([Ljava/lang/String;)V
.limit stack 2
getstatic java/lang/System/out Ljava/io/PrintStream;
ldc "Hello, World!"
invokevirtual java/io/PrintStream/println(Ljava/lang/String;)V
return
.end method
最小的代码可以连<init>方法都不要,试过可运行。唯一不爽的就是很麻烦地要用“签名”的形式,比如[Ljava/lang/String;。以上Hello类输出Hello, World!。
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于