最近试了一下Android的逆向,随便写(shui)篇帖子记录一下。
环境搭建
首先说一下Android逆向相关的工具:
- Android Killer:(简称AK)主要用来做apk解包和重打包、重签名等,也可以用来看/改源码、搜索字符串等,可以在52的网盘里下载,另外网盘里也有新版的apktool、dex2jar等工具,虽然AK里面也有,但毕竟AK都有点旧了,对于较新版的AKP还是要用新版的工具的。
- Android Studio:(简称AS)就是Google的Android开发工具,主要可以用来做动态调试,虽然这次用不到hhhh。关于动态调试的方法可以参考这里,主要是找pid做端口转发那一步。
- IDA pro:通常APK解包后都会有一些.so的库,这个就需要用IDA来反编译和patch。
- Android的设备/虚拟机/模拟器:最好能配好adb,我用的是跑在虚拟机的android-x86。
- Java SDK:AK需要用到Java环境,大部分Android程序也需要Java环境,推荐Java8,我用Java10在重打包时翻了车 - -
解包
首先需要搞到apk文件,我弄的是synthesia 10.6版本,当前Google Play上的那个,网上找下也可以搞到。用AK打开后是这样的:
![](https://static-img.0xffff.one/BXHaX5xeEad7qXPOiuN03g1ruqmVVHZ_RjGPE5QBVxc/q:90/w:800/rt:fit/aHR0cHM6Ly9zdGF0/aWMuMHhmZmZmLm9u/ZS9hc3NldHMvZmls/ZXMvMjAyMC0wMi0w/My8xNTgwNzEwMjI3/LTI5MjYxMS1iOGU4/NmI2Ni00Y2JhLTQy/YmItYjNiZS01OTMx/YmUzM2M5NTUucG5n.jpg)
第一次打开可能会提示Java SDK找不到,打开后在配置的Java那里选择JDK路径里的bin目录即可。
由于AK版本的问题,会卡在反编译源码那一步,把AK关掉后重启就可打开,但源码时没有反编译出来的,如果要源码的话可以另外用新版的dex2jar把AK目录里的 project/项目名字的文件夹/ProjectSrc/classes.dex 反编译出来(dex2jar和dex2smali都搞一下,然后把dex2smali搞出来的文件夹重命名smali),看源码时好像还要手动用AK的bin目录里的jd-gui打开。(注意:到这一步只能看到Java的代码,不能反编译.so库文件的代码)
在工具栏的Android里可以对已经连接adb的Android设备进行操作(注意必须先用adb连接,不然设备里没得选,AK的bin里自带adb,连接方法网上一大堆)。然后选项中的编译就是apk的重打包,如果重打包失败的话可以试下在AKPTOOL管理器里添加新版的apktool,另外Java的版本可可能会对编译有影响。
![](https://static-img.0xffff.one/s4l4hp-EA3yllgpaAO6FYNDQl2QjFRZLUGubIGZ_DGw/q:90/w:800/rt:fit/aHR0cHM6Ly9zdGF0/aWMuMHhmZmZmLm9u/ZS9hc3NldHMvZmls/ZXMvMjAyMC0wMi0w/My8xNTgwNzExNDE4/LTM1NzkxMC04YjVm/M2E2Yi05ZjM3LTQ3/YzAtYjk1Mi1jYzg2/NzI3NTFlY2EucG5n.jpg)
![](https://static-img.0xffff.one/Wbe3Eg2FuVpAMxOToiXieYEhqIfx182J_VQEq9soRyw/q:90/w:800/rt:fit/aHR0cHM6Ly9zdGF0/aWMuMHhmZmZmLm9u/ZS9hc3NldHMvZmls/ZXMvMjAyMC0wMi0w/My8xNTgwNzExNTE4/LTQ4MDA0LTY4YTIx/MWQ2LWVjYTAtNGU4/ZC1iNzQ5LTQ0MjQ4/MTUyZWNmMy5wbmc.jpg)
关于Synthesia
Synthesia是一个弹琴的软件(对,虽然我也不知道为什么一个搞PWN的会搞上一个钢琴软件了hhhh),里面大部分功能都需要内购才能用的(虽然这次我搞的不是内购 - -)
![](https://static-img.0xffff.one/0D6ZAN4KK8P2urZFbu1tS91H16R2Z2VvoU6utyTaR7k/q:90/w:800/rt:fit/aHR0cHM6Ly9zdGF0/aWMuMHhmZmZmLm9u/ZS9hc3NldHMvZmls/ZXMvMjAyMC0wMi0w/My8xNTgwNzExODcw/LTY1NTM3Ny12aXJ0/dWFsYm94LWFuZHJv/aWQtOTAtNjR4LTAz/LTAyLTIwMjAtMTQt/MzctMDEucG5n.jpg)
在最新的版本里发现它在 Free Play 里可以有50秒的试用
![](https://static-img.0xffff.one/F-fCfOjraUYZiTuKeJ-N8YcEeleGdiE9w92c5C5UV-c/q:90/w:800/rt:fit/aHR0cHM6Ly9zdGF0/aWMuMHhmZmZmLm9u/ZS9hc3NldHMvZmls/ZXMvMjAyMC0wMi0w/My8xNTgwNzExOTI1/LTYyMDQ4NC12aXJ0/dWFsYm94LWFuZHJv/aWQtOTAtNjR4LTAz/LTAyLTIwMjAtMTQt/MzgtMjcucG5n.jpg)
在右上角会有个倒计时,倒计到0时就会弹出让我内购解锁:
![](https://static-img.0xffff.one/iLhOhG0Q7MSscPO6ShsCzcFKOd8o2kRTZFGqUJq1lfA/q:90/w:800/rt:fit/aHR0cHM6Ly9zdGF0/aWMuMHhmZmZmLm9u/ZS9hc3NldHMvZmls/ZXMvMjAyMC0wMi0w/My8xNTgwNzEyMDc3/LTMyMjM5My12aXJ0/dWFsYm94LWFuZHJv/aWQtOTAtNjR4LTAz/LTAyLTIwMjAtMTQt/NDAtNDEucG5n.jpg)
既然是有倒计时,那么我直接把倒计时设成一个非常大的数不就等于无限试用了,也相当于把 Free Play 这个功能破掉了。
破解过程
用AK瞄了一下后发现没有相关代码,于是就锁定了 libsynthesia.so 这个库,Synthesia做了x86、x86_64、arm_v7、arm_v8这四个库,由于我是用android-x86_64来调试,所以会以x64做例子,其他两个也大同小异。
x86_64
首先要找到对应代码的位置,用字符串查找的方法。首先想到的是“free play”,但没找到什么东西,然后搜"demo"时找到了个“helpDemoLocked”,还无意中发现了“0:%02i”这个字串,这个就是printf里打印时间的格式了,引用的函数也只有一个,所以就可以直接锁定0x1CC150里的那个函数了。
下面说一下函数的大概功能,函数很长,但关注两个片段就好了。首先是大概是0x1CDB3A位置里:
![](https://static-img.0xffff.one/eOhU9zbMOb6-nmIBsJioxpAoC4BjjyR1_2X5iWuNj5Q/q:90/w:800/rt:fit/aHR0cHM6Ly9zdGF0/aWMuMHhmZmZmLm9u/ZS9hc3NldHMvZmls/ZXMvMjAyMC0wMi0w/My8xNTgwNzEyOTA2/LTUyNzc2Mi1kNmQ1/MjFkMy0xMGNiLTQ1/ZTgtYjljYS01NDk1/ZmQ2YjhiY2EucG5n.jpg)
可以大概看出1428行里就是用来计算显示的时间的,51000000就是试用倒计时的51秒,根据上下文可以发现这个计算出来的时间只是用来显示的,实际的时间会在上图的counter的变量里(名字只是我起的),如果找到这个变量改变的地方patch掉就可以了,但是有更简单的方法。
先来看一下第二个地方,大概0x1CDDC0的地方:
![](https://static-img.0xffff.one/jyVNWzqHx-xFze6_OEuIf59IvLnGErqFkiFdQuQczlM/q:90/w:800/rt:fit/aHR0cHM6Ly9zdGF0/aWMuMHhmZmZmLm9u/ZS9hc3NldHMvZmls/ZXMvMjAyMC0wMi0w/My8xNTgwNzEzMjYw/LTQwMjczMi0zMjhi/OGJkZC1hZjk5LTQy/YzUtOWM2Yy00MjA1/MGNhZmVkZGYucG5n.jpg)
上图1511行的那个if就是判断如果时间够了后就弹出让我内购的那个框,如果把if的条件patch成永假(或直接跳转),那就可以跳过内购弹窗了。
patch!
patch的有3个地方,其中2个是为了美观的 - -
第一个地方也就是最主要的是0x1CDDB5里,把“jnz”patch成“jmp”就可以绕过上面那个if条件直接跳转。
patch前:
![](https://static-img.0xffff.one/73RSEoDAboPymSdSz6EMKvX8wG_81h5WzcKcA79FDj4/q:90/w:800/rt:fit/aHR0cHM6Ly9zdGF0/aWMuMHhmZmZmLm9u/ZS9hc3NldHMvZmls/ZXMvMjAyMC0wMi0w/My8xNTgwNzEzNjE0/LTIxMTE1Ni0wNDU3/OWRiYS00MDU0LTQ4/YTUtOWIzMy0zODg0/OTZlODU5YTUucG5n.jpg)
patch后:
![](https://static-img.0xffff.one/voSZYQ5GAKRmCi2U1eLsa3rOxvM2VTz3b3Dtiyj56Cc/q:90/w:800/rt:fit/aHR0cHM6Ly9zdGF0/aWMuMHhmZmZmLm9u/ZS9hc3NldHMvZmls/ZXMvMjAyMC0wMi0w/My8xNTgwNzEzNjUx/LTc2MjIyNi1hMWFm/YmEzMS0xMmYxLTRj/MjktOTUxZS00MGE0/MjlhM2ViZGIucG5n.jpg)
第二、三个地方只是为了右上角那个倒计时好看一点(让它消失有点麻烦,就顺便做成计时的了- -),做成计时器的话首先要让它开始时变成0,把0x1CDB4E里的"30A32C0h"patch成"0"
patch前:
![](https://static-img.0xffff.one/oDA72Qi4-3MJF-EnCHAOk0RJmNtxqAIB5xeobYgZ0Q0/q:90/w:800/rt:fit/aHR0cHM6Ly9zdGF0/aWMuMHhmZmZmLm9u/ZS9hc3NldHMvZmls/ZXMvMjAyMC0wMi0w/My8xNTgwNzEzODcy/LTUzODg5OC00YzMx/NmFiYi0wN2Q4LTQ1/MTEtYmMzNC02MTY4/MWExZGEyMTkucG5n.jpg)
patch后:
![](https://static-img.0xffff.one/galxFSEf7xyj253I_Nw4gjFh9PS5r4Z-uEapdQUkong/q:90/w:800/rt:fit/aHR0cHM6Ly9zdGF0/aWMuMHhmZmZmLm9u/ZS9hc3NldHMvZmls/ZXMvMjAyMC0wMi0w/My8xNTgwNzEzOTQ0/LTM0MjgwMy1hZWZl/ZjZhMC1jNTk2LTRm/MzctODJjNy1kMWM3/ODMyN2E4OWEucG5n.jpg)
最后是把输出美观一些,把0x692FB3里的格式化字符串改一下,原先是"0:%02i"的改成“<%is->”,这个可以自己定制,怎么好看怎么改就好了,但是“%i”好像是一定要有的,不然会闪退。
patch前:
![](https://static-img.0xffff.one/cd09W-g7Sfawchy0c5V0oSk8TTcQmFpETrjgHzXajrg/q:90/w:800/rt:fit/aHR0cHM6Ly9zdGF0/aWMuMHhmZmZmLm9u/ZS9hc3NldHMvZmls/ZXMvMjAyMC0wMi0w/My8xNTgwNzE0MTIx/LTM1NzYwOC0zMDJi/ZDA4ZC1kNDAwLTQ3/MzktYTFjYS04Mzdl/MGQ3NTBkMmQucG5n.jpg)
patch后:
![](https://static-img.0xffff.one/pzRzrKskgxbVRUbl-ZHz3t0jlu0rSxhn4_gB4_0liuc/q:90/w:800/rt:fit/aHR0cHM6Ly9zdGF0/aWMuMHhmZmZmLm9u/ZS9hc3NldHMvZmls/ZXMvMjAyMC0wMi0w/My8xNTgwNzE0MTU3/LTc2NDU2Mi00Y2Yy/MGI5NC0yNzU0LTRj/NmEtYTQwYi1lNjli/NTAwZDcyMWQucG5n.jpg)
说说arm
arm的patch方法也是一样的,只是arm的汇编实在。。。
首先是arm里的"jmp"操作是用"B"指令(v7的在0x115C06),还有mov一次只能16位,v7的要用movw和movt分两次移动,v8的要mov ... , sls #16、mov ... , sls #32等移动
v7
第一张有一个是多余的,主要是跳转那个:
![](https://static-img.0xffff.one/txZU_VYK2pHvY3lClw-5OY3jddxp9pHasu9URHxRnig/q:90/w:800/rt:fit/aHR0cHM6Ly9zdGF0/aWMuMHhmZmZmLm9u/ZS9hc3NldHMvZmls/ZXMvMjAyMC0wMi0w/My8xNTgwNzE0OTcw/LTg5MTUzOC0xLnBu/Zw.jpg)
![](https://static-img.0xffff.one/3sXjzUas_IpBUdbluUIm5LhTeL8pTnHa3GJVzNtm22k/q:90/w:800/rt:fit/aHR0cHM6Ly9zdGF0/aWMuMHhmZmZmLm9u/ZS9hc3NldHMvZmls/ZXMvMjAyMC0wMi0w/My8xNTgwNzE1MDI2/LTEyNDc4NC1kYjVi/YjMyNC02ZWJlLTRm/ZTEtOWI2MS05NmVh/MjA4N2QzMTUucG5n.jpg)
v8
![](https://static-img.0xffff.one/oqf3arW083rHrR6rWwZDvxG6emEGj292iiQtGbqVU4Q/q:90/w:800/rt:fit/aHR0cHM6Ly9zdGF0/aWMuMHhmZmZmLm9u/ZS9hc3NldHMvZmls/ZXMvMjAyMC0wMi0w/My8xNTgwNzE1MTIy/LTI0MTg0MS1iZGNi/N2Y5MC01NjA5LTQ2/MDQtYTE1NC1iMWEy/ODlmOGIxOTIucG5n.jpg)
![](https://static-img.0xffff.one/0fzzrTjE-zu9r-2VKZ94AjQJcjDzBpDXfj2FnzOtua0/q:90/w:800/rt:fit/aHR0cHM6Ly9zdGF0/aWMuMHhmZmZmLm9u/ZS9hc3NldHMvZmls/ZXMvMjAyMC0wMi0w/My8xNTgwNzE1MTU5/LTQ0NzI5LWZhYmI0/NWZmLTZjMDUtNDk5/OS1hYWM1LTdlZmQ2/MTZlMDFhMC5wbmc.jpg)
重打包
重打包用AK,按编译就行(傻子都会hhh,但注意patch后的库要放回project目录下的 Project/lib 对应的文件夹里),编译好的包在对应project目录里的bin目录里,直接安装就好。
结果
最后就多了个计时器,50秒的试用也没了
![](https://static-img.0xffff.one/-HgkS47Z9kaUeGDDr1kVn1VOmkNgF9ZWXWTUMm6XQGM/q:90/w:800/rt:fit/aHR0cHM6Ly9zdGF0/aWMuMHhmZmZmLm9u/ZS9hc3NldHMvZmls/ZXMvMjAyMC0wMi0w/My8xNTgwNzE0NDc2/LTk2MTY1Ny12aXJ0/dWFsYm94LWFuZHJv/aWQtOTAtNjR4LTAz/LTAyLTIwMjAtMTUt/MjAtMzEucG5n.jpg)
最后的最后
仅用于学术交流,请勿用于非法用途 :)
https://drive.google.com/file/d/1L6B7aX0RJ4Zcy9Xgkfwq2ucAVPBiF19J/view?usp=sharing