用Python和Smali模拟器搞定一个加混淆、防篡改的APK逆向

ChiConnery 8年前
   <p>这个周末我和好友聊天时,他向我求助修改一个他正在编写Python脚本。他试图通过解混淆一个APK,来理解该APK的混淆基址和防篡改保护机制。同我以往的APK逆向过程(dex2jar->jd-gui->done)相比,这是一个很有挑战性同时充满趣味的工作。同时,这个逆向过程我编写了一个我认为比较酷比较独特的工具。</p>    <h2>怪异的字符串</h2>    <p>同其他有过APK反编译工作经验的逆向工作者一样,我已经很习惯程序中的类和名字被ProGuard混淆(或者被DexGuard混淆字符串等),这对我来说不是什么困难。但是当我使用apktool打开这个应用的时候还是大吃一惊:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/9512c2db7cee46d33cf6c0d71a2b970d.jpg"></p>    <p>大部分的类和方法名都是很怪异的字符串,这几乎没法让我使用一个单独的工具或者编辑器来查看这些文件。所以目前最首要的步骤就是修复(坦诚的说应该是从头开始写)Matteo写的python脚本,这个脚本试图重新命名所有的混淆入口,脚本本身工作流程比较简单:</p>    <p>遍历所有名称为不能打印字符的smali文件</p>    <p>使用ClassXXX替代混淆的类名字(XXX是一个自增的数字)</p>    <p>重命名文件</p>    <p>查找所有引用这些类的地方并使用新的名称替代(正则匹配)</p>    <p>在.field文件夹(类变量,方法等)中重复这个操作</p>    <p>这个过程结束之后,最终获得了一个可以浏览的文件夹和可读的smali文件:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/d042935bf36b7c9857ef543f53a4cc47.jpg"></p>    <p>但是这离完成还有很远的距离。</p>    <h2>反篡改</h2>    <p>在我继续进行之前,我先需要指出两点,以便你能够理解我这么做背后的理由:</p>    <p>1. 这个应用使用了很奇怪的反篡改(很大可能是反调试之类的措施)保护,因此,使用注入代码的方式将smali代码重新打包成APK是不可行的,同样调试也是不行的</p>    <p>2. 这样的保护措施不仅阻止了代码注入/修改,同时也会在检测到这种篡改后卸载软件</p>    <p>所以代码注入(XPosed也不行)、调试都无法使用,基本我通常的标准逆向方式都无法使用。</p>    <h2>加密字符串</h2>    <p>作为一个懒惰(或者说是聪明)的逆向者,我不想先去理解其中的逻辑,相反,我试图发现那些能够给我一些提示的、有意义的字符串,帮助我发现这个app在做些什么,但是我再次被震惊到了。</p>    <p>所有的字符串都进过了传统的加密算法加密,基本上所有引用字符串的地方都被如下的方式进行了替换:</p>    <p>Stringdecrypted = Class623 :: method5 (new int []{-12, 44,-35,…}, 52);  </p>    <p>函数的参数仅仅是一个整形数组和其他的一些数字作为第二个参数(或许是某种形式的密钥?)</p>    <p>通常我遇到这种情况的做法是:</p>    <p>1. 反编译APK到Java(使用dex2jar+jd-gui或者仅仅是jadx)</p>    <p>2. 获取到解密的java代码,并将其粘贴到一个独立的java控制台</p>    <p>3. 对加密的东西执行解密例程从而获得明文结果</p>    <p>然而。。。任何工具都无法正确的将Class623::method5 的smali代码转换成</p>    <p>java代码,这些工具获得的输出都是无意义的东西,不起作用。但是目前我并不是很擅长阅读smali代码(这个解密程序本身也十分复杂,至少对我来说很复杂)…但是我不能就这么放弃。</p>    <h2>所有的都让Smali模拟器来搞定吧</h2>    <p>我当然可以利用Class623::method5的smali代码,创建一个新的安卓APP,然后使用apktool反编译,在这个方法的输出中注入代码,插入一个调用该函数代码的调用到app中,重新构建这个app并且运行它。但是:</p>    <p>1. 同样,我是一个懒惰的人</p>    <p>2. 这个实现方式并不优雅</p>    <p>3. 我头脑里闪现出一个很酷的想法,我必须尝试一下!</p>    <p>长话短说,我要做的是:“写一个smali解析器和模拟器,然后加载这个函数例程,最终它将输出所有我需要的明文!”。</p>    <p>于是我开始阅读Dalvik操作码说明,整合了一些代码,经过几个小时,我完成了这个简单的pyhon 脚本用于测试:</p>    <p>from smali . emulator import Emulator</p>    <p>emu = Emulator ()</p>    <p># The smali file to emulate.</p>    <p>filename ='decryptor.smali'  </p>    <p># Arguments for the method.</p>    <p>args ={  </p>    <p>'p0':(-62,-99,-106,-125,-123,-105,-98,-37,-105,-97,-103,-41,-118,-97,-113,-103,-109,-104,-115,111,98,103,35,52),</p>    <p>'p1':19</p>    <p>}</p>    <p>ret = emu . run ( filename , args )</p>    <p>print emu . stats</p>    <p>print"RESULT:\n"</p>    <p>print"'%s'"% ret </p>    <p>而且,运行结果如下:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/9b12ad4483111e86aedd1ea993593b6a.jpg"></p>    <p>成功了!</p>    <p>我对所有的加密字符串执行该脚本,模拟器也能正确的解析和执行解密例程的smali代码,并解密所有我从反编译程序中抽取的每一个条目。从现在开始,所有的工作就是使用明文替换所有的加密条目,从而这个逆向过程易如反掌。</p>    <p>via: <a href="/misc/goto?guid=4959673047884518216" rel="nofollow">http://www.freebuf.com/articles/web/103980.html</a></p>