这篇文章其实2个月前就想写了,但我知道并不好写,就懒得写了,所以拖到现在~其实接触smali这门语法是件蛮偶然的事,接触后发现,次奥,这货在某些领域太有用了,至于为什么我想看完这篇文章应该都明白了。
我自己也只是接触了皮毛,大概用了2个礼拜多一点,也不是很系统的学习,写这篇的目的主要还是想把知道的东西记下来,以后好追溯。
Smali是Dalvik的寄存器语言,它与Java的关系,简单理解就是汇编之于C。假如你对汇编有足够的驾驭能力,那你可以通过修改汇编代码来改变C/C++代码的走向。当然,学过汇编的都清楚,汇编比BrainFuck 还难学,更不用说去反编译修改了。
但是Smali有一点不一样,就是它很简单,只有一点点的语法,只要你会java,了解Android的相关知识,那你完全可以通过修改Smali代码来反向修改java代码,虽然绕了一点,但是在某些情况下你不得不这么做。还好,Smali很简单。
说了这么多,还没有说Smali哪来?没错。Smali代码是安卓APK反编译而来的,所以Smali文件和Java文件一一对应。获取Smali文件,我们需要下载一个辅助工具:ApkTool 。apktool这个命令行工具如果详细使用功能参数是比较多的,但是这里我们只需要用到2个最基础的功能:
一个是反编译decode:
apktool d xxx.apk
另一个是打包build:
apktool b
这里要注意的是路径问题,apktool如果没有加入到环境变量中,记得cd到apktool的目录去使用它。另一个是打包,如果只是简单的使用参数b,那要求是要在反编译出来的项目目录下执行,而打包好的文件会保存在这个项目目录下的dist目录。
这是一个HelloWorld的应用程序反编译和打包的目录结构:
这里仍然以一个默认的HelloWorld的应用程序进行解释吧。新建一个HelloWorld安卓项目,在MainActivity中只保留onCreate函数。代码如下:
MainActivity.java |
反编译后的Smali文件如下:
MainActivity.smali |
对比一下,可以比较清楚的看出来,smali代码其实就是对java代码一个翻译,只是没有java看起来那么简单,smali把很多应该复杂的东西还原成复杂的状态了。简单解释下这段代码。
对比了Java代码和Smali代码,可以很清楚的看到,原本只有几行的代码到了Smali,内容被大大扩充了。Smali还原了Java隐藏的东西,同时显式地指定了很多细节。这还只是个最基本的HelloWorld的onCreate函数,如果有内部类,还有分文件显示。
这样看来,其实Smali只能说复杂,不能说难。我这里不打算把Smali的语法再贴一次,这里给出几个链接,算是总结的相对好一点的(其实我都没看到有系统总结的。。。如果你有好的资料,欢迎跟帖分享)
这里顺便提供2个利器:
了解了Smali的基本语法,那我们要动手试一下,Smali能做什么?仍然以HelloWorld为例,假如我们没有Android项目的源代码,只有一个APK,给他加个新功能吧!
这个功能很简单,只是在HelloWorld中输出一个“Hello, Smali”。
(1)第一步还是先使用apktool来反编译HelloWorld.apk。
(2)打开smali下的com/fusijie/helloworld/MainActivity.smali文件。
(3)原本我们在Java中要写的代码是:
Toast |
翻译成Smali就是:
Toast |
(4)最后在插入Smali的时候,我们需要修改2个地方:
(5)使用apktool打包成apk,因为打包完后原有的密钥会丢失,所以需要重新打上我们自己的密钥,可以参考 很早以前我写的一个帖子 。
(6)最后的效果是这样的。
从上面一个例子对Smali的用途就很清楚了,没错,Smali注入。现在常见的除了测试以外的用途,Smali注入明显是带有黑客性质的,小的如破解游戏,替换游戏广告,大的甚至利用漏洞去破解密码,偷窃个人资料,财产等等。对Smali,安卓逆向分析,安卓系统安全比较清楚的,这些事其实都不算事。
我这里以一个实际上线的游戏破解为例,看看我们平时在写代码时要注意哪些问题,避免辛辛苦苦写游戏,却在帮人家数钱。这里的破解不是重点,反破解才是重点。
以市场上很火的一款单机游戏《消灭小星星》为例,下载地址是: http://apk.91.com/Soft/Android/com.brianbaek.popstar-340.html
相同的方法反编译,在/smali/com/zplay/android/sdk/pay/ZplayPay.smali文件的dopay函数开头,注入如下代码:
popstar_crack |
原理很简单,这个游戏使用了Zplay的支付系统,在Java层的处理了支付逻辑,如果觉得Smali读起来费劲,那么直接使用dex2jar就能很清楚的看到,支付提醒甚至是中文的。Java层处理完支付逻辑后会给C++层丢个消息,调用C++层的代码去处理游戏逻辑,比如成功支付,那么幸运星就会相应地增加。这里使用native方法进行处理。
所以注入的代码是,一旦进入支付逻辑,直接返回成功,同时强制返回函数,这就实现了支付的破解。当然作为一个有节操,有逼格的游戏从业者,这里就不放出破解版了(不过说得也够明白了)。查找注入点这东西靠的是耐心,细心和运气。
为了方便,一般会先用正常的java写一些调试类,然后反编译出静态的smali放入目标文件夹中以供调试使用。
再放张图,星星用不完了:
就像上面说的,Smali能做的不仅仅是这些。有兴趣的可以看看这篇文章 《支付宝钱包手势密码破解实战》 ,我没有去验证过真伪,但是如作者所描述的应该是可行无误。这里用到的一个更高级的功能是将支付宝的加密解密逻辑Smali的jar包导入自己新建的工程,进而直接在自己的程序中集成支付宝的加密解密功能。
在逆向分析游戏的过程中,我也发现了几个重要的点能帮助开发者提高自己程序的安全性。
首先,完全避免破解是不可能的,我们能做的工作就是尽最大可能去妨碍破解者破解游戏,提高破解成本。
哈哈,总之,小心你的艳照。。。
哇咔咔,竟然写了快4个小时~