如何运行smali文件?

来源:互联网 发布:北斗测亩仪软件下载 编辑:程序博客网 时间:2024/06/17 02:05


转自:http://www.tuicool.com/articles/Z3i6zq

smali 是Android 应用程序(*.apk)反编译生成的文件格式, 是一种类似于汇编语言的底层计算机语言。阅读和书写smali语法都需要极大的耐心和勇气, 本文将介绍如何反编译和运行第三方的程序(smali)代码。

什么是smali 文件

Android程序文件, 即apk文件, 其实是一个zip压缩包, 其文件结构如下:

Image Title

其中, classes.dex是程序的核心文件,是java语言的代码编译后的二进制字节码程序。这种字节码程序是编译专供机器阅读的, 类似于汇编语言的机器码。然而如果想直接阅读这部分程序, 最好的方法就是将该文件转化为smali文件。

apktool

著名的反编译工具 apktool 就可以完成这部分工作。 它将classes.dex文件反编译成一堆的smali文件, 这些文件按源码的包结构保存在各自的文件夹中。如下所示:

Image Title

另外, apktool 工具强大之处在于它不仅可以反编译apk文件, 而且可以根据现有的smali 文件生成新的apk文件。 这就给汉化apk或者去除apk内嵌广告提供了可能。

smali语法类似于汇编语言的语法, 涉及寄存器的直接操作, 可以直接阅读, 但羞涩难懂, 尤其是在代码混淆之后。

Image Title

dex2jar

有人做了一个专门的工具 dex2jar 将classes.dex 转化为jar 文件, 通过 jd-gui 阅读。

Image Title

但dex2jar 并不健全, 反编译出的java文件大部分都有编译错误。可以简单的阅读和分析, 但若是涉及到很细致的内容, 则还是需要依赖smali。 smali 文件的编辑器推荐使用sublime +sublime-smali , 具体请参考文章 为Sublime Text安装smali代码语法高亮插件 。

smali语法

另外,本文将涉及到smali的一些基础语法, 请参考 Smali--Dalvik虚拟机指令语言-->【android_smali语法学习一】 。

运行smali文件

思路

  1. 反编译目标apk程序(target.apk)。
  2. 确定需要运行的smali文件(target.smali)及依赖文件。
  3. 分析smali文件的类结构, 编写对应的java类文件(proxy.java)。
  4. 编写proxy-project, 生成新的apk程序文件(proxy.apk)。
  5. 反编译proxy-apk文件, 利用target.smali替换相应的smali文件(proxy.java)。
  6. 利用apktool 重新生成apk程序(new-proxy.apk), 安装到手机。 运行,调试。

思路说明

我们都知道, apktool工具既可以将apk文件反编译成smali文件, 也可以将修改后的smali文件build成新的可以运行的apk。 这里, 我们将构造一个代理工程proxy-project, 这个工程将用来调用target.smali文件获取结果。 调用的方式则是构建一个proxy.java 类, 它与target.smali有着相同的函数签名。 将proxy.apk反编译之后, 用target.smali替换proxy.java, 重新生成apk, 进行运行和调试。

举例

1. 构建target.apk

(这里是为了举例的需要, 通常情况下不需要这个步骤。)

首先, 模拟构建一个简单的android应用程序, 该应用程序包含一个特殊的算法函数(本次目标就是运行这个特殊算法函数)。

TargetProject 工程的结构如下:

Image Title

TargetProject工程是利用Android Studio的 Gradle 生成, 与较早的工程结构有所不同, 但应该不会影响理解。

主界面里面的Test按钮点击时, 将运行Target.encode()函数, 并利用Toast显示计算结果。

Target类如下:

Image Title

Target.encode(String str) 函数将输入的str对象进行编码,输出结果。

源码下载地址

配置好gradle 和 Android Studio后, 在工程目录下运行gradle clean build 将会自动生成./TargetProject/build/apk/TargetProject-release.apk。下载

运行 apktool d TargetProject-release.apk release 可在release目录得到反编译后的smali文件。结构如下:

Image Title

因为该apk已经过混淆和签名, 所以smali文件是混淆为a, b ...类型的类。简单的分析就知道, b.smali 就是对应源码里面的Target类。

打开b.smali 文件, 函数

.method public static a(Ljava/lang/String;)Ljava/lang/String;

即对应 Target.encode(String str)

将b.smali文件拷贝出来, 作为待运行的smali文件。 下载

需要注意的是, b.smali文件的包路径是:com.example.targetproject, 这个包路径要跟后续对应的java文件的包路径一致。

2. 编写Proxy-Project

新建工程 ProxyProject , 添加类com.example.targetproject.b, 如下:

package com.example.targetproject;public class b {    public static String a(String str) {        return "";    }}

在MainActivity添加按钮和点击事件。

package com.example.proxyproject;import android.os.Bundle;import android.app.Activity;import android.view.Menu;import android.view.View;import android.widget.Toast;import com.example.targetproject.b;public class MainActivity extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);findViewById(R.id.btnRun).setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {Toast.makeText(MainActivity.this, b.a("反编译"), Toast.LENGTH_LONG).show();}});}}

编译运行, 这时点击按钮是没有内容输出的。得到ProxyProject-debug-unaligned.apk

3. 反编译ProxyProject-debug-unaligned.apk,替换, 重新编译运行。

运行

apktool d ProxyProject-debug-unaligned.apk proxy

替换/proxy/smali/com/example/targetproject/b.smali 为target.apk反编译出的b.smali

运行

apktool b proxy new.apk

这里生成的new.apk文件还没有签名。

网上这样的工具挺多的, 这里用 dodo APK Sign

签名后的文件是 new_signed.apk , 直接安装运行。

点击"运行...", 将弹出输出结果Toast。 大功告成!