APK或DEX已经被JEB识别以后,接下来真正花时间的是读代码。反编译窗口里的Java代码方便梳理逻辑,但它并不是原始源码的直接还原,类名混淆、编译优化、动态调用和复杂控制流都会影响最终显示。有时候某个类只能看到一部分方法,或者Java视图里缺少成员,也不一定代表APK中的代码真的少了。碰到这种情况,把反编译视图、DEX反汇编和工程分析状态放在一起看,会比反复重新打开文件更容易判断问题出在哪里。
一、JEB Decompiler怎么查看反编译代码
JEB分析APK后,会在Project Explorer中建立APK、DEX以及其他资源对应的分析单元。查看应用代码时,通常先找到目标DEX中的类,再在反汇编和反编译结果之间切换。
1、从工程树找到需要查看的类
先从APK包含的DEX入手,应用存在多个DEX时,不要只盯着第一个代码单元。
①、打开已经分析完成的【JEB工程】。
②、在【Project Explorer】中展开APK对应的项目节点。
③、找到需要查看的【DEX】单元。
④、继续展开包名和目标【Class】。
⑤、双击类节点打开代码视图。
⑥、在【Assembly】中定位需要分析的方法。
2、切换到Java形式的反编译结果
①、把光标放到目标【Class】或方法代码中。
②、执行【Action】→【Decompile】。
③、也可以在代码位置按【Tab】切换到反编译视图。
④、在生成的Java代码中找到目标【Method】。
⑤、需要核对DEX指令时再次按【Tab】返回【Assembly】。
JEB的反编译视图更适合顺着调用关系阅读代码,Assembly则保留了更接近DEX字节码的信息。碰到条件判断看起来奇怪时,两边来回看通常更容易弄清控制关系。
3、单独重新反编译某个类或方法
①、返回目标类的【Assembly】视图。
②、把光标定位到需要重新处理的【Method】。
③、执行【Action】→【Decompile with Options】。
④、查看当前反编译选项。
⑤、只想处理单个方法时,取消顶层类整体反编译相关选项。
⑥、重新执行【Decompile】。
二、JEB Decompiler反编译结果不完整如何排查
所谓“结果不完整”要先分清具体表现。有的是方法存在,但Java视图没有正常还原,有的是synthetic成员默认没有显示,还有的是APK包含多个DEX,目标代码其实在另一个单元里。先确定少的是哪一类内容,后面不用把整个工程重新分析一遍。
1、先确认代码是否真的存在于DEX中
如果Java视图没有看到目标方法,先回Assembly确认,避免把显示问题当成文件缺失。
①、在【Project Explorer】中打开对应【DEX】。
②、进入目标【Class】。
③、切换到【Assembly】。
④、搜索需要确认的【Method】或字段。
⑤、检查方法对应的DEX指令是否存在。
⑥、存在时再执行一次【Decompile with Options】。
如果Assembly里有完整指令,而Java视图缺少对应结构,排查方向就应该放到反编译过程,而不是APK解析。
2、检查synthetic字段和方法有没有被隐藏
JEB默认可能不会把所有编译器生成的synthetic成员都显示出来。这类成员在内部类、编译转换后的代码里比较容易遇到。
①、打开目标类的反编译视图。
②、在代码窗口中点击右键。
③、进入【Rendering Options】。
④、启用【Generate synthetic fields】。
⑤、继续启用【Generate synthetic methods】。
⑥、重新查看当前类的代码内容。
3、重新生成异常类的反编译结果
①、切换回目标类的【Assembly】。
②、执行【Action】→【Decompile with Options】。
③、查看当前启用的反编译选项。
④、调整与代码优化、结构恢复有关的可用设置。
⑤、重新反编译当前【Class】。
⑥、把新结果和【Assembly】中的控制流进行对照。
混淆或编译器优化比较重时,同一段DEX转换成Java结构并不总是十分自然。只要Assembly能够正常读取,底层代码仍然可以继续分析。
4、检查APK是不是包含多个DEX
①、返回【Project Explorer】。
②、展开APK下全部代码单元。
③、检查是否同时存在多个【DEX】。
④、分别打开各个DEX中的包和类列表。
⑤、搜索目标【Class】名称。
⑥、确认需要分析的代码到底位于哪个DEX。
JEB支持多DEX分析,所以目标类没有出现在当前代码单元时,先看看其他DEX,比不断修改反编译参数更直接。
三、JEB Decompiler反编译结果怎么进一步核对
反编译代码已经能正常显示以后,关键方法仍然建议和底层指令对照。Java视图适合阅读,Assembly和控制流图则更适合确认跳转、返回值以及复杂分支有没有被理解错。
1、用Assembly和控制流图对照关键逻辑
①、在反编译代码中定位目标【Method】。
②、按【Tab】返回对应【Assembly】。
③、检查条件跳转和方法调用。
④、按【Space】切换到【Control Flow Graph】。
⑤、查看各基本块之间的跳转关系。
⑥、再次返回反编译视图核对Java结构。
2、把已经整理好的分析结果保存下来
①、对重要【Class】和【Method】进行必要的重命名。
②、保存当前【JEB工程】。
③、需要保存反编译代码时进入【File】→【Export】。
④、选择需要导出的反编译内容。
⑤、保留当前工程文件供后续继续分析。
工程里已经完成的重命名和代码整理留住以后,再次查看同一APK时不用重新从混淆名称开始梳理。JEB也支持从导出菜单保存部分或全部反编译结果。
总结
JEB Decompiler里看到的Java代码更适合帮助我们读懂程序逻辑,但遇到某段代码少了、方法没有显示或者结构看着不顺时,别急着认定反编译失败。先回DEX的Assembly里确认代码还在不在,再检查多DEX、synthetic成员和当前反编译设置,通常更容易找到原因。对于真正关键的方法,多看一眼底层指令和控制流图也很有必要,这样后面整理调用关系时会少一些误判。
