读书频道 > 安全 > Android软件安全与逆向分析
2.2.3 分析APK 文件
2012-12-27 14:53:11     我来说两句 
收藏    我要投稿   

本文所属图书 > Android软件安全与逆向分析

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

反编译apk 文件成功后,会在当前的outdir 目录下生成一系列目录与文件。其中 smali目录下存放了程序所有的反汇编代码,res 目录则是程序中所有的资源文件,这些目录的子目录和文件与开发时的源码目录组织结构是一致的。

如何寻找突破口是分析一个程序的关键。对于一般的 Android来说,错误提示信息通常是指引关键代码的风向标,在错误提示附近一般是程序的核心验证代码,分析人员需要阅读这些代码来理解软件的注册流程。

错误提示是Android程序中的字符串资源,开发 Android程序时,这些字符串可能硬编码到源码中,也可能引用自“res\values ”目录下的strings.xml 文件,apk 文件在打包时,strings.xml 中的字符串被加密存储为resources.arsc  文件保存到apk 程序包中,apk 被成功反编译后这个文件也被解密出来了。
 
还记得 2.1.2 小节运行程序时的错误提示吗?在软件注册失败时会Toast弹出“无效用户名或注册码”,我们以此为线索来寻找关键代码。打开“res\values\string.xml ”文件,内容如下:
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="app_name">Crackme0201</string>
    <string name="hello_world">Hello world!</string>
    <string name="menu_settings">Settings</string>
    <string name="title_activity_main">crackme02</string>
    <string name="info">Android程序破解演示实例</string>
    <string name="username">用户名:</string>
    <string name="sn"> 注册码:</string>
    <string name="register">注 册</string>
    <string name="hint_username">请输入用户名</string>
    <string name="hint_sn"> 请输入16位的注册码</string>
    <string name="unregister"> 程序未注册</string>
    <string name="registered"> 程序已注册</string>
    <string name="unsuccessed">无效用户名或注册码</string>
    <string name="successed"> 恭喜您!注册成功</string>
</resources>

开发Android 程序时,String.xml 文件中的所有字符串资源都在“gen/<packagename>/ R.java”文件的 String 类中被标识,每个字符串都有唯一的 int 类型索引值,使用 Apktool反编译apk 文件后,所有的索引值保存在 string.xml文件同目录下的public.xml 文件中。

从上面列表中找到“无效用户名或注册码”的字符串名称为unsuccessed 。打开 public.xml文件,它的内容如下:
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <public type="drawable" name="ic_launcher" id="0x7f020001" />
    <public type="drawable" name="ic_action_search" id="0x7f020000" />
    <public type="layout" name="activity_main" id="0x7f030000" />
    <public type="dimen" name="padding_small" id="0x7f040000" />
    <public type="dimen" name="padding_medium" id="0x7f040001" />
    <public type="dimen" name="padding_large" id="0x7f040002" />
    <public type="string" name="app_name" id="0x7f050000" />
    <public type="string" name="hello_world" id="0x7f050001" />
    <public type="string" name="menu_settings" id="0x7f050002" />
    <public type="string" name="title_activity_main" id="0x7f050003" />
    <public type="string" name="info" id="0x7f050004" />
    <public type="string" name="username" id="0x7f050005" />
    <public type="string" name="sn" id="0x7f050006" />
    <public type="string" name="register" id="0x7f050007" />
    <public type="string" name="hint_username" id="0x7f050008" />
    <public type="string" name="hint_sn" id="0x7f050009" />
    <public type="string" name="unregister" id="0x7f05000a" />
    <public type="string" name="registered" id="0x7f05000b" />
    <public type="string" name="unsuccessed" id="0x7f05000c" />
    <public type="string" name="successed" id="0x7f05000d" />
    <public type="style" name="AppTheme" id="0x7f060000" />
    <public type="menu" name="activity_main" id="0x7f070000" />
    <public type="id" name="textView1" id="0x7f080000" />
    <public type="id" name="edit_username" id="0x7f080001" />
    <public type="id" name="edit_sn" id="0x7f080002" />
    <public type="id" name="button_register" id="0x7f080003" />
    <public type="id" name="menu_settings" id="0x7f080004" />
</resources> 

unsuccessed 的id 值为 0x7f05000c ,在smali 目录中搜索含有内容为0x7f05000c 的文件,最后发现只有MainActivity$1.smali 文件一处调用,代码如下:
# virtual methods
.method public onClick(Landroid/view/View;)V
    .locals 4
    .parameter "v"
    .prologue
    const/4 v3, 0x0
    ……
    .line 32
    #calls:
    Lcom/droider/crackme0201/MainActivity;->checkSN(Ljava/lang/String;
    Ljava/lang/String;)Z
    invoke-static {v0, v1, v2}, Lcom/droider/crackme0201/MainActivity;-> #
    检查注册码是否合法
    access$2(Lcom/droider/crackme0201/MainActivity;Ljava/lang/String;Ljava/
    lang/String;)Z
    move-result v0
    if-nez v0, :cond_0  #如果结果不为0,就跳转到cond_0标号处
    .line 34
    iget-object v0, p0, Lcom/droider/crackme0201/MainActivity$1;->
        this$0:Lcom/droider/crackme0201/MainActivity;
    .line 35
    const v1, 0x7f05000c# unsuccessed 字符串
    .line 34
    invoke-static {v0, v1, v3}, Landroid/widget/Toast;->
        makeText(Landroid/content/Context;II)Landroid/widget/Toast;
    move-result-object v0    
    .line 35
    invoke-virtual {v0}, Landroid/widget/Toast;->show()V
    .line 42
    :goto_0
    return-void
    .line 37
    :cond_0
    iget-object v0, p0, Lcom/droider/crackme0201/MainActivity$1;->
        this$0:Lcom/droider/crackme0201/MainActivity;
    .line 38
    const v1, 0x7f05000d# successed 字符串
    .line 37
    invoke-static {v0, v1, v3}, Landroid/widget/Toast;->
        makeText(Landroid/content/Context;II)Landroid/widget/Toast;
    move-result-object v0
    .line 38
    invoke-virtual {v0}, Landroid/widget/Toast;->show()V
    .line 39
    iget-object v0, p0, Lcom/droider/crackme0201/MainActivity$1;->
        this$0:Lcom/droider/crackme0201/MainActivity;
    #getter for: Lcom/droider/crackme0201/MainActivity;->btn_register:Landroid/
        widget/Button;
    invoke-static {v0}, Lcom/droider/crackme0201/MainActivity;->
         access$3(Lcom/droider/crackme0201/MainActivity;)Landroid/widget
         /Button;
    move-result-object v0
    invoke-virtual {v0, v3}, Landroid/widget/Button;->setEnabled(Z)V
    # 设置注册按钮不可用
    .line 40
    iget-object v0, p0, Lcom/droider/crackme0201/MainActivity$1;->
        this$0:Lcom/droider/crackme0201/MainActivity;
    const v1, 0x7f05000b# registered字符串,模拟注册成功
    invoke-virtual {v0, v1}, Lcom/droider/crackme0201/MainActivity;->
        setTitle(I)V
    goto :goto_0
.end method

Smali 代码中添加的注释使用井号“# ”开头,“.line 32”行调用了 checkSN()函数进行注册码的合法检查,接着下面有如下两行代码:
move-result v0
if-nez v0, :cond_0

checkSN()函数返回Boolean类型的值。这里的第一行代码将返回的结果保存到 v0寄存器中,第二行代码对v0 进行判断,如果v0 的值不为零,即条件为真的情况下,跳转到cond_0标号处,反之,程序顺利向下执行。

如果代码不跳转,会执行如下几行代码:
.line 34
iget-object v0, p0, Lcom/droider/crackme0201/MainActivity$1;->
    this$0:Lcom/droider/crackme0201/MainActivity;
.line 35
const v1, 0x7f05000c  # unsuccessed 字符串
.line 34
invoke-static {v0, v1, v3}, Landroid/widget/Toast;->
    makeText(Landroid/content/Context;II)Landroid/widget/Toast;
move-result-object v0    
.line 35
invoke-virtual {v0}, Landroid/widget/Toast;->show()V
.line 42
:goto_0
return-void

“.line 34 ”行使用 iget-object 指令获取MainActivity实例的引用。代码中的->this$0 是内部类MainActivity$1中的一个 synthetic 字段,存储的是父类 MainActivity的引用,这是 Java语言的一个特性,类似的还有->access$0 ,这一类代码会在本书的第 5 章进行详细介绍。

“.line 35”行将 v1 寄存器传入 unsuccessed 字符串的 id 值,接着调用 Toast;->makeText() 创建字符串,然后调用Toast;->show()V 方法弹出提示,最后.line 40 行调用 return-void 函数返回。

如果代码跳转,会执行如下代码:
:cond_0
iget-object v0, p0, Lcom/droider/crackme0201/MainActivity$1;->
    this$0:Lcom/droider/crackme0201/MainActivity;
.line 38
const v1, 0x7f05000d  # successed字符串
.line 37
invoke-static {v0, v1, v3}, Landroid/widget/Toast;->
    1makeeText(Landroid/content/Context;II)Landroid/widget/Toast;
move-result-object v0
.line 38
invoke-virtual {v0}, Landroid/widget/Toast;->show()V
.line 39
iget-object v0, p0, Lcom/droider/crackme0201/MainActivity$1;->
    this$0:Lcom/droider/crackme0201/MainActivity;
#getter for: Lcom/droider/crackme0201/MainActivity;->btn_register:Landroid/
    widget/Button;
invoke-static {v0}, Lcom/droider/crackme0201/MainActivity;->
    access$3(Lcom/droider/crackme0201/MainActivity;)Landroid/widget/Button;
move-result-object v0
invoke-virtual {v0, v3}, Landroid/widget/Button;->setEnabled(Z)V  #设置注
册按钮不可用
.line 40
iget-object v0, p0, Lcom/droider/crackme0201/MainActivity$1;->
    this$0:Lcom/droider/crackme0201/MainActivity;
const v1, 0x7f05000b  # registered字符串,模拟注册成功
invoke-virtual {v0, v1}, Lcom/droider/crackme0201/MainActivity;->setTitle(I)V
goto :goto_0

这段代码的功能是弹出注册成功提示,也就是说,上面的跳转如果成功意味着程序会成功注册。

注意  Smali 代码的语法与格式会在本书第 3 章进行详细介绍。

点击复制链接 与好友分享!回本站首页
分享到: 更多
您对本文章有什么意见或着疑问吗?请到论坛讨论您的关注和建议是我们前行的参考和动力  
上一篇:2.2.2 反编译APK 文件
下一篇:2.2.4 修改Smali 文件代码
相关文章
图文推荐
2.9.3 静态可信根与
2.8 远程管理
2.7.6 微内核中的安
2.7.3 直通技术
排行
热门
文章
下载
读书

关于我们 | 联系我们 | 广告服务 | 投资合作 | 版权申明 | 在线帮助 | 网站地图 | 作品发布 | Vip技术培训
版权所有: 红黑联盟--致力于做最好的IT技术学习网站