打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
5.3 smali文件格式

Android软件安全一直是广大开发者与软件用户讨论的话题,但市场上却没有发现类似选题的书籍。本书主要从以下几个方面对Android安全展开探讨:首先是Android程序的反汇编,这一部分是绝大多数开发人员所关心,但大...  立即去当当网订购

使用Apktool反编译apk 文件后,会在反编译工程目录下生成一个smali 文件夹,里面存放着所有反编译出的smali 文件,这些文件会根据程序包的层次结构生成相应的目录,程序中所有的类都会在相应的目录下生成独立的smali 文件。如上一节中程序的主Activity名为com.droider.crackme0502. MainActivity ,就会在smali 目录下依次生成 com\droider\ crackme0502 目录结构,然后在这个目录下生成MainActivity.smali 文件。

smali 文件的代码通常情况下比较长,而且指令繁多,在阅读时很难用肉眼捕捉到重点,如果有阅读工具能够将特殊指令(例如条件跳转指令)高亮显示,势必会让分析工作事半功倍,为此笔者专门为文本编辑器Notepad++编写了 smali 语法文件来支持高亮显示与代码折叠,并以此作为smali 代码的阅读工具。

无论是普通类、抽象类、接口类或者内部类,在反编译出的代码中,它们都以单独的smali文件来存放。每个smali 文件都由若干条语句组成,所有的语句都遵循着一套语法规范。在smali 文件的头3 行描述了当前类的一些信息,格式如下。
.class < 访问权限> [ 修饰关键字] < 类名>
.super < 父类名>
.source <源文件名>

打开MainActivity.smali 文件,头3 行代码如下。
.class public Lcom/droider/crackme0502/MainActivity;
.super Landroid/app/Activity;
.source "MainActivity.java"

第1 行“.class”指令指定了当前类的类名。在本例中,类的访问权限为 public ,类名为“Lcom/droider/crackme0502/MainActivity;”,类名开头的 L 是遵循 Dalvik 字节码的相关约定,表示后面跟随的字符串为一个类。

第2 行的“.super ”指令指定了当前类的父类。本例中的Lcom/droider/crackme0502MainActivity;”的父类为“Landroid/app/Activity;”。

第3 行的“.source ”指令指定了当前类的源文件名。

回想一下,在上一章中讲解 dex 文件格式时介绍的 DexClassDef结构,这个结构描述了一个类的详细信息,该结构的第 1 个字段classIdx就是类的类型索引,第3 个字段 superclassIdx就是指向类的父类类型索引,第5 个字段 sourceFileIdx 就是指向类的源文件名的字符串索引。baksmali 在解析dex 文件时,也是通过这 3 个字段来获取相应的类的值。

注意  经过混淆的 dex 文件,反编译出来的 smali 代码可能没有源文件信息,因此,“.source” 行的代码可能为空。

前3 行代码过后就是类的主体部分了,一个类可以由多个字段或方法组成。smali文件中字段的声明使用“.field”指令。字段有静态字段与实例字段两种。静态字段的声明格式如下。
# static fields
.field < 访问权限> static [ 修饰关键字] < 字段名>:< 字段类型>

baksmali 在生成smali 文件时,会在静态字段声明的起始处添加“static fields ”注释,smali文件中的注释与Dalvik 语法一样,也是以井号“# ”开头。“.field”指令后面跟着的是访问权限,可以是public、private 、protected 之一。修饰关键字描述了字段的其它属性,如synthetic 。指令的最后是字段名与字段类型,使用冒号“:”分隔,语法上与Dalvik 也是一样的。

实例字段的声明与静态字段类似,只是少了static关键字,它的格式如下。
# instance fields
.field < 访问权限> [ 修饰关键字] < 字段名>:< 字段类型>

比如以下的实例字段声明。
# instance fields
.field private btnAnno:Landroid/widget/Button;

第1 行的“instance fields ”是 baksmali 生成的注释,第 2 行表示一个私有字段 btnAnno,它的类型为“Landroid/widget/Button; ”。

如果一个类中含有方法,那么类中必然会有相关方法的反汇编代码,smali 文件中方法的声明使用“.method ”指令。方法有直接方法与虚方法两种。直接方法的声明格式如下。
# direct methods
.method <访问权限> [ 修饰关键字] < 方法原型>
    <.locals>
 [.parameter]
 [.prologue]
 [.line]
<代码体>
.end method

“direct methods”是baksmali 添加的注释,访问权限和修饰关键字与字段的描述相同,方法原型描述了方法的名称、参数与返回值。“.locals ”指定了使用的局部变量的个数。“.parameter”指定了方法的参数,与Dalvik 语法中使用“.parameters ”指定参数个数不同,每个“.parameter”指令表明使用一个参数,比如方法中有使用到 3 个参数,那么就会出现 3条“.parameter”指令。“.prologue ”指定了代码的开始处,混淆过的代码可能去掉了该指令。“.line ”指定了该处指令在源代码中的行号,同样的,混淆过的代码可能去除了行号信息。

虚方法的声明与直接方法相同,只是起始处的注释为“virtual methods”。

如果一个类实现了接口,会在smali 文件中使用“.implements ”指令指出。相应的格式声明如下。
# interfaces
.implements < 接口名>

“# interfaces ”是baksmali 添加的接口注释,“.implements ”是接口关键字,后面的接口名是DexClassDef结构中interfacesOff 字段指定的内容。

如果一个类使用了注解,会在 smali 文件中使用“.annotation ”指令指出。注解的格式声明如下。
# annotations
.annotation [ 注解属性] < 注解类名>
    [ 注解字段 =  值]
.end annotation

注解的作用范围可以是类、方法或字段。如果注解的作用范围是类,“.annotation ”指令会直接定义在smali 文件中,如果是方法或字段,“.annotation ”指令则会包含在方法或字段定义中。例如下面的代码。
# instance fields
.field public sayWhat:Ljava/lang/String;
    .annotation runtime Lcom/droider/anno/MyAnnoField;
        info = "Hello my friend"
    .end annotation
.end field

实例字段sayWhat 为String 类型,它使用了 com.droider.anno.MyAnnoField 注解,注解字段info 值为“Hello my friend”。将其转换为 Java 代码为:
@ com.droider.anno MyAnnoField(info = "Hello my friend")
public String sayWhat;  

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
算法助手使用教程
Android中动态方式破解apk第一篇
APP分分钟被盗版,正当权益谁来保障?
Android安全攻防战,反编译与混淆技术完全解析(上)
记一次安卓微信apk朋友圈逆向
【新提醒】Log工具类(含食用说明和演练)
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服