Java反编译器剖析(中)-Java开发Java经验技巧_第1页
Java反编译器剖析(中)-Java开发Java经验技巧_第2页
Java反编译器剖析(中)-Java开发Java经验技巧_第3页
Java反编译器剖析(中)-Java开发Java经验技巧_第4页
Java反编译器剖析(中)-Java开发Java经验技巧_第5页
已阅读5页,还剩3页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、java反编译器剖析(中)-编程开发技术java反编译器剖析(中)木文由importnew乌|1柏 翻译自javacodegeekso欢迎加入翻译小纽.。转载请见文末要求。 在上一篇文章中,我们介绍了翻译器的功能、简单的字节码知识回顾、反编译和 栈分析。本文将继续讨论反编译器中对条件表达式、变量类型分析、短路运算符 和方法调用在反编译器屮的处理。条件表达式在这里可以决定我们的代码是否使用了三元运算符(?:):冇一个判断条件,条 件的每个分支都对同一个栈变量sl,2进行一次赋值,赋值后两条路径会进行 合并。-旦确定了这个模式,就可直接使用三元表达式。复制传播后合并三元表达式0145891011讦

2、(vo = 0) goto #8 sl,2 = vlgoto 9sl,2 =v2v3 = s 1,2)return v3v3 = v0!=0? vl : v2return v3值得注意的是,作为转换的一部分,我们对#9处的条件进行了取反。可以看出 javac生成的代码对判断条件取反这一行为是有规律的。因此,如果将转换后的 条件取反,就口j以更加接近原來的代码。画外音:类型是什么?当处理栈值时,jvm使用了一个比java代码更为简单的类型系统。特别是 boolean、char和short的值都被作为int值使用同一指令处理。因此,vo! =0可以翻译成: vo != false ? vl : v

3、2或者vo != 0 ? vl : v2甚至还可以翻译为vo != false ? v1 = true : v2 = true还有很多其它的翻译结果!在这个例子屮,我们很幸运地知道vo的精确类型,这个类型包含在方法描述中: descriptor: (zii)iflags: acc_publtc, acc_stattc方法签名由此可以知形式如下:public static int plus (boolean, int, int)通过签名还可以知道,v3是int型(而不是boolean型)。因为它是返回值,通过描述符已经知道了返回值类型。接下來,还需要翻译:v3 = vo ? vl : v2ret

4、urn v3另外,如果vo是一个本地变量(不是形参),可能无法知道其类型是boolean 而不是into还记得我们之前提到的本地变量表,就是包含了原始本地变量名的 那个表吗?除了变量名,它述记录了有变量的类型。因此,如果编译时带有debug 信息,就可以从本地变量表屮知道变量的类型。此外,还有一张localvariab 1 etypetab 1 e表,此表也包含类似的信息。两者的主要区别在于 local vari abletypetable包含了泛型信息。然而,由于localvariabletypetable中的信息是未经验证的元数据,因此不能完全依赖这 些数据。一些非常规的混淆器(obfus

5、cator)会在这些表小填入假信息,但是修 改后的字节码却依然可以执行!所以请自行决定如何使用这些表。短路运算符(试和,)public staticreturn aboolcan fn(boolcan a, boolcan b, boolcan c) b && c;怎么能更简单呢?不幸的是,关于字节码的理解总是冇一点痛苦字节码栈变量复制传播后0iload_0so = vo1ifne#12if(s() !=() goto #12if(v() !=() goto #124iload_lsl = vl5ifeq #16if (sl = 0) goto #16if (vl = 0) g

6、oto #168iload_2s2 = v29ifeq #16if (s2 = 0) goto #16讦(v2 = 0) goto # 1612iconst_ls3 = 1s3,4) = 113goto #17goto 17goto 1716iconst_0s4 = 0s3,4 =017i returnreturn s3,4return s3,4根据选择的路径不同,位于#17位置的ireturn指令可能返冋s3或者s4o 我们为其分别命名,然后使用复制传播来消除so、si和s2。接下來,在#1、#5和#7位置冇三个连续的条件。如之前提到的那样,条件分 支要么跳转,要么接着执行下一条指令。上面的

7、字节码包含了一组遵循特定的使用模式,这些模式非常实用:条件与(&&)条件或(idtl:tl:讦(cl) goto li讦(cl) goto l2if (c2) goto l2if (c2) goto l2li:li:变成了变成了if (!cl && c2) goto l2if (cl | c2) goto l2li:li: 如果考虑上面表中的临近条件组,#1#5不遵循上面任何一种模式,但#5 #9却是一个条件或(|),因此可以进行如卜转换:1: if (vo !二 0) goto #125: if (vl 二二 0 v2 二二 0) goto #1612:s3,

8、4 = 113: goto #1716:s3, 4 = 017: return s 3,4注意:每次转换都可能引入新的转换。这种情况下,可以应用ii对条件进行重 组。现在可以对# 1#5应用&&模式!通过将这些代码合并为单个条件分支 可以进一步简化方法:1:if (vo = 0 && (vl = 012:s3,4二 113:goto #1716:s3, 4 = 017:return s 3,4v2 = 0) goto #16这是不是看起来和其他地方很类似?是的,现在这个字节码就符合之前的三元操 作符(?:)规则了。我们可以将#1.#16缩减为一个独立的表达式,再

9、使用 复制传播将s3, 4内联到为#17的return语句。v2 = 0) ? 0 : 1;return (v0 = 0 && (vl 二二 0利用方法描述符和木地变量类型表可以推断变量类型,这样缩减后的表达式如 下:v2 = false) ? false : true;return (v0 = false && (vl = false好吧,现在的结果比反编译的内容更加精炼了,但是仍然不够美观。让我们看看 可以做点什么。首先,折叠比较运算符,比如把x二二true和x二二false简写为x 和!xo还可以消除三元操作符,比如把x ? false: true简写为!

10、x。return ! (!v0 && (!vl | !v2);如果你述记得你高屮的离散数学,那么根据徳摩根定理,更进一步可以缩写为:> >- - - 7 7 b b h&& a a z(x /(xi 1 z/( /(x17 17 a ai n /(x z(x因此,return ! ( !v0 && ( !vl!v2 )可以变为,接着变成,return ( vo ! (!vl | !v2 )最终会变成:return ( vo (vl && v2)万岁!处理方法调用我们已经了解调用方法的流程:先将参数“存入”本地数组;要进

11、行方法渤7, 必须将参数推到栈上,并且紧跟一个指向实例方法的this指针。方法调用的字 节码正如你预想的那样:push arg_0push arg_linvokevirtual methodref在上面的代码屮可以看到invokevirtual,该指令可以用来调用大多数的实例方 法。jvm有一组方法调用的指令,每个指令都有特定的功能:1. invokcintcrfacc:调用接口方法。2. invokevirtual:调用使用virtual语义的实例方法,比如调用的方法在运行时 根据重载分派到不同的实例方法。3. invokespecial:调用一个具体的实例方法(非virtual语义)。该指

12、令常用来 调用构造器(constructor),但也町以调用类似super, method ()这样的方法。4. invokestatic:调用静态方法。5. invokedynamic:使用“引导方法”(bootstrap)启动自定义调用点,该命令(在java 中)很少使用。引入该命令是为了支持动态语言,在java8中被用來实现lambda表 达式。反编译器有一个重要细节,class的菖量滋中包含了所冇方法调用的信息,包括 参数的数量、类型和返回值类型。调用的类会记录这些信息,运行时会确保该方 法在调用时已存在,并对方法签名进行检查。如果调用的是第三方代码的函数, 并且函数的签名发生了改变,任何试图对旧版本的调用都会抛出错误(而不是产 生不可预知的行为)。回到上而的例子,从invokevirtual操作码可以得知目标方法是一种实例方法。 因此,需要将this指针作为隐含的第一参数。常量池中的methodref告诉我 们该这个方法有一个形参,所以除了实例方法的指针述需要从栈上弹出一个参 数。接下來代码可以重写为:arg_0. methodref(arg_l)当然,不是所有的字节码看起来都如此“友好”。栈小的参数并不要求一个接一 个排列整齐。假如参数屮有一个三元表达式,那么屮间就会有加载、存储和分支 指令,这些都需

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论