Dalvik的Dex文件格局 深化钻研Android
案例钻研
在这个案例钻研中, 咱们将审核一个 Nexus 银行木马恶意样本(文件 MD5: d87e04db4f4a36df263ecbfe8a8605bd)。Nexus 是在公开论坛上发售的一个框架,它能够从安卓手机上的许多银行运行程序中窃取资金。Cyble 颁布的一份报告提供了有关该框架的更多具体消息以及对样本的彻底剖析。
经常使用 jadx 对样本启动剖析,运行程序中的 AndroidManifest.xml 文件(d87...)显示它恳求访问设施的短信、咨询人、电话通话等敏感消息。AndroidManifest.xml 中的关键优惠在运行程序最后时不会出现,由于它稍后会被解压,但另一个类被提及为 "com.toss.soda.RWzFxGbGeHaKi" 并且裁减了 Application 类,这象征着它将是运行程序中首个运转的类:
在 Application 子类 "com.toss.soda.RWzFxGbGeHaKi" 中的 onCreate() 回调援用了两个额外的方法:melodynight() 和 justclinic(),然后者调用了另一个方法:bleakperfect()。
bleakperfect() 方法以及运行程序中的其他几个方法蕴含少量的死代码,触及将值调配给变量并经常使用多个循环对它们启动算术运算,但最终这些变量从未被经常使用。
此外,该方法用于解码在代码其他位置援用的字符串。这是经过将一个字节数组(编码字符串)与另一个字节数组(XOR 密钥)启动异或操作,并将结果存储在第三个字节数组中,然后将其转换为字符串。
诸如此类的修补方法可以删除冗余代码并用字符串前往交流简短的 XOR 操作,可以使运行程序的剖析变得愈加容易且更高效。为此,咱们必定了解此代码在DEX文件中的出现形式。
DEX概述
Android运行程序关键是用Java编写的。为了在Android设施上运转,Java代码被编译成Java字节码,然后被转换成Dalvik字节码。Dalvik字节码可以在APK的DEX(Dalvik可口头)文件中找到。APK(安卓包文件)实质上是一个蕴含运行程序代码和所需资源的ZIP文件。可以经过提取APK的内容来审核DEX文件。
DEX文件分为几个部分,包括头部、字符串表、类定义、方法代码和其他数据。大少数部分被划分为大小相等的块,这些块中蕴含多个值来定义部分中的名目。为了展如今DEX文件中如何翻译Java中的经常出现概念,例如类或字符串,咱们将经常使用class_defs部分作为示例。
关于类
class_defs部分由class_def_items组成,每个类在运行程序中都是32字节长的。类的称号以以下形式存储:class_def_item蕴含对type_ids部分中的名目标索引(class_idx),而type_ids部分又蕴含对string_ids中的另一个名目标索引(descriptor_idx)。
string_id_item下的值是从文件扫尾的偏移量,它指向蕴含实践类名字符串(data)的string_data_item的扫尾,该字符串前面有其长度(utf16_size)。
class_def_item还有另一个成员(class_data_off),它是指向一个class_data_item的偏移量,该项代表与类相关联的数据。它蕴含了有关类的静态和虚构方法、静态和实例字段的消息,以及每个方法和字段的婚配的encoded_method和encoded_field项。
关于方法
direct_methods和virtual_methods蕴含一系列encoded_method名目。在每个方法类型的第一个encoded_method名目中,method_idx_diff值持有在method_ids部分中婚配名目标索引。
但是,在后续名目中,这个值是相关于前一个名目标差异,并且要计算method_ids索引,必定将差异参与到前一个method_idx_diff值。
最后,method_id_item中的方法称号存储在name_idx下,相似于type_id_item中的类称号,并且经常使用string_id_item索引检索方法称号的字符串值。
在Android运行程序中,每个方法都有一个前言(或许称为code_item),它指定了有关方法大小、输入和输入参数以及意外处置数据的消息。这个前言在DEX文件中的偏移量存储在前面提到的encoded_method项的code_off值中。
前言的前两个字节示意寄存器大小,即字节码经常使用了多少个寄存器,接着是输入和输入参数的字大小,而最后四个字节是字节码大小(或insns_size)。
字节码大小以16位指令单元计算,这象征着要计算字节码中总字节数(8位单位),必定将这个值乘以二。方法的Dalvik字节码间接在前言之后开局。
关于字符串
到目前为止,咱们曾经看到了两个例子中的string_id_items用于从DEX文件中的字符串表中提取类名和方法名。但是,在Dalvik字节码中,string_id_item也十分关键,当在运行程序代码中经常使用字符串值时,它会被援用。
例如,以下字节码序列前往"sampleValue"字符串,其中"0xABCD"是在string_ids部分中的"sampleValue"的string_id_item的索引
这象征着,在对恶意样本的字节码启动修补时,一个阻碍是,解码后应该前往的解密字符串并不存在于DEX文件的字符串表中。同样,它们必定在解码后参与到文件中,以便具备婚配的string_data_item和可以被代码援用的string_id_item索引。
人造地,参与这些字符串会造成文件的部分大小、索引和偏移量出现变动。这会发生另一个阻碍,由于在先前显示的DEX文件中,不同项之间存在多个依赖相关,扭转它们援用的索引或偏移量将造成这些项被失误地解析或具备不正确的成员值。这就是为什么在对方法启动修补时,必定确保DEX文件的其他部分坚持完整。
关于补丁
为了成功这一点,咱们创立了dexmod,这是一个Python辅佐工具,依据用户指定的反混杂逻辑来修补DEX文件。除了修补之外,该工具还允许诸如经常使用字节码形式启动方法查找或参与字符串等操作。dexmod下载地址:
关于Nexus样本中的混杂方法来说,要使其前往解密后的字符串,必定经常使用dexmod解码并将字符串参与到文件中。然后,将在DEX文件中看到的前往字符串的字节码序列搁置在每个混杂方法的字节码扫尾,并与相应的string_id_item索引配对。方法中的任何残余字节都可以用0x00(NOP)交流,以启动额外的代码清算,但这并非必要。
还须要降级每个方法的前言以反映这些更改;寄存器大小减小到1,由于只经常使用了一个寄存器(v0),而字节码大小降级为3,由于如今它只蕴含3个16位指令(6字节)。前言中的其他值可以坚持不变,由于它们示意的项没有遭到影响。
在DEX文件的头部中,校验和和SHA-1签名值也必定降级;否则,文件内容的验证将失败。在经常使用dexmod实施了这些步骤之后,可以经常使用jadx从新审核DEX文件,一旦混杂的函数如今将会移除一切死代码并前往解码后的字符串:
由于Nexus样本中的混杂方法是由另一个方法调用而不是间接调用的,另一种或许性是修补调用者方法并前往一个字符串,从而齐全跳过混杂方法。这样做可以节俭钻研人员在剖析环节中重复跳转方法的时期。
总结
本案例钻研展现了Dalvik字节码修补对钻研人员的用途,以及如何经常使用收费的开源工具来成功。与其他反混杂处置打算面临的疑问相似,打包器和混杂技术经常降级,可怜的是很难找到一个能够长时期内实用于少量运行程序的修补处置打算。此外,只管搜查运行程序的字节码可以高效地识别代码形式,但尝试修正DEX文件而不损坏其中某些部分或许是一项应战。
附录(DexMod)
创立具备以下属性的方法对象:
- methodIdx:method_idx值,在Dalvik字节码中用于调用方法
- offset:方法字节码的文件偏移量
dexmod 工具应用 dexterity(一个解析DEX文件的开源库),并协助将字符串参与到 DEX文件,同时修复对受影响字符串 ID 和其他部分偏移量的援用。dexterity库有一些局限性,它不会一次性修复字节码中援用的字符串索引,并且在本案例钻研时期对其代码启动了一些更改以正确参与字符串。