回到目录
内容总结
- 这个Lab可能是纵观所有Lab中,最无趣的那一个了。不过抛开Lab不谈,这一次课的内容,即反混淆(Deobfuscating),对于实际情况下的逆向还是很重要的。接下去整理一下课件中的重点内容。
常见的、通用的混淆技术包括:布局混淆(Layout Obfuscation)(包括命名混淆等)、数据混淆(Data Obfuscation)、控制混淆(Control Obfuscation)等,以及针对Java的一些语言特性进行的混淆(Java-specific Obfuscation)。
布局混淆,包括删除调试和注释信息、删除无用代码、重命名(变量、类名、包名、方法等)。其中,标识符重命名混淆(Identifier Renaming)和命名重载(Naming Overloading)虽然似乎是最简单、最机械的操作,但往往会给阅读代码增添无法想象的难度。(之后在进行PJ1的时候,可能会去阅读实际应用场景下开发的app,其代码可读性不高的首要原因就是这两点。
数据混淆,包括合并标量(merge scalar variables)、分离变量(split variables)、重构数组(restructure arrays)、字符串加密(string encryption)等等。每一则的例子都在课件中展示得非常清晰,尤其是字符串加密需在之后的Lab和PJ中需要重点关注。
控制混淆,简要地来说就是打碎和重构整个代码或函数的控制流,将一些循环进行展开,将一些分支使用庞大的、扁平的(flattened)switch结构或其他结构进行组织。
针对Java语言特性的混淆,包括类之间的重新组织,以及善用Java提供的一个强大而“隐蔽”的机制——反射(Reflection)。
Lab简介及参考
- 这个Lab一共会分成两个部分,其一是函数匹配,其一是字符串解密:前者需要根据给出的经过混淆的函数,找到经另一个版本的混淆器混淆后的对应的函数;后者需要根据字符串的调用,解出它在加密前的字符串。这个Lab由于每个人分到的内容不完全一致,因此并不记录解题过程了。但是,以下几点是我在这个Lab中收获的一些“门道”:
(1)关键的标识符:这些标识符可能是Java本身带有的,比如说反射相关的类(Method、Class……),也可能是SDK中带有的(比如Service、Handler……)。当要寻找的函数中含有这些标识符,可以试着使用jadx的搜索功能去搜索这些关键词。
(2)常量,特别是字符串:尽管许多字符串都是经过加密的,本身可能从肉眼上看并没有什么明显的含义,但混淆器做的比较有限,可能混淆后得到的字符串会在不同版本下的混淆器生成的代码中对应相等。
(3)函数的参数:尽管许多局部变量和字段的命名不尽相同,但是函数的参数的命名,jadx遵循着一套规则,因此在不引入之前所说的数据混淆的情况下,可以试图通过参数的类型和个数的匹配寻找对应的函数。
(4)import:对于混淆后的代码,由于原先的包和类的结构可能被打破,因此原先同属于一个包内、不需要显式导入的类,在混淆后可能需要显式地导入。对于我们来说,如果之前几个方法都不适用,在被迫需要逐一翻看的窘况下,查看导入包的情况也是有必要的。如果导入差不多位置的大量的包,就要考虑是否会原同属于一个包内了。
(5)jadx自身提供的反混淆功能:这点我试图使用了,但发现效果在大多数情况下并不怎么好。如果实在绝望,兴许通过反混淆选项的勾选与取消定位到一些代码。
- 对于字符串解密来说,更关键的是找出字符串在解密后、使用前都经历了哪些函数调用,把这些代码摘出来,放在IDEA里跑一跑就完事了。也符合助教的评价:Task 2会比Task 1简单许多。