大多数APP都对API接口进行了加密,防止第三方随意调用接口,常用的方法是,设置一个key,在调用接口来发送请求时,组合各个参数和key按照一定的规则(排序,MD5等等)生成一个用于验证的token参数,服务端接收到请求后,按照相同的规则组合参数和key去生成token,和收到的token去对比,判断请求是否是第三方伪造发送的。
但是通过抓包和反编译APP,是可以得到key和生成token的规则,来将自己伪装成官方的APP,调用API接口
下面的文章,主要是总结我自己反编译魅族天气的APP来获取API的过程。
工具
- 魅族天气
- dex2jar
- jd-gui
- Android Studio(内置adb,apktool)
- ideasmali(Android Studio插件)
反编译class.dex获取java代码
原理:打包生成apk时,java源代码先被编译成.class文件,然后Android SDK自带的dx工具将这些.class文件转换成classes.dex,所以可以反编译classes.dex来得到java源代码
步骤
- 下载dex2jar.zip和jd-gui,并解压
- 将com.meizu.flyme.weather-2.2.1-2002001.apk重命名为com.meizu.flyme.weather-2.2.1-2002001.zip
- 解压com.meizu.flyme.weather-2.2.1-2002001.zip,在解压得到的目录里找到classes.dex
- 使用dex2jar将classes.dex反编译得到classes-dex2jar.jar
- 使用jd-gui查看classes-dex2jar.jar
操作截图(Mac)
注意:执行反编译指令时,可能会提示d2j_invoke.sh: Permission denied,输入sudo chmod +x d2j_invoke.sh来解决
阅读java代码
这一步要耐心,因为代码一般经过来混淆,生成很难看懂的代码,来到达保护代码的目的
通过抓包,获得了天气信息的请求
然后我观察到sign参数,在每次请求时都会发生变化,它应该就是那个用于验证的参数。
在一堆经过混淆的代码中,会需要比较多的时间,查找到生成验证参数sign的相关代码,这需要耐心。但利用搜索,可以加快查找的速度。
在jd-gui里,File->Save All Sources,将反编译的java文件保存到source文件夹,我们利用请求的url去搜索(代码里的常量字符串一般不会被混淆,利用字符串去搜索,一般都会找到有用的信息,来进一步查找
)
可以看到在source/com/meizu/flyme/weather/common/ad.java有拼接url的代码,这很有可能是我们需要的代码片段
在jd-gui里,打开ad.java
paramAnonymousVarArgs = "cityId=" + paramString + "&bizId=" + "aider_app" + "×tamp=" + l + "&sign=" + ad.a(paramAnonymousVarArgs);
这应该就是我们需要的代码,可以点击ad.a,跳转到函数内部,里面的代码并不复杂。通过阅读代码,可以很容易地得到生成sign的规则(MD5(城市id+"aider_app"+时间戳+"29cc0378-3802-4470-a1e2-07ce9f34b208"))。
反编译APP获取smali代码
Android系统有自己的虚拟机Dalvik,代码编译最终不是采用的java的class,而是使用的smali。我们反编译得到的代码,jar的话可能很多地方无法正确的解释出来,如果我们反编译的是smali则可以正确的理解程序的意思。
在抓取短时预报的请求,就出现了无法解释的情况
通过搜索,最后跳转到下图的方法
这些看起来像伪代码。。。
我们可以利用apktool来反编译App,获取最终的smali代码,解决无法解释的问题
mv com.meizu.flyme.weather-2.2.1-2002001.zip com.meizu.flyme.weather-2.2.1-2002001.apk
apktool -o weather_apktool d com.meizu.flyme.weather-2.2.1-2002001.apk
切换到weather_apktool目录,smali文件夹里就是反编译得到的smali代码,我们找到刚才解释错误的文件
vim weather_apktool/smali/com/moji/mjweather/request/MJWeatherSDK.smali
上图就是代码对应的smali代码,语法有点像汇编,这里有一篇教程(android反编译-smali语法),可以先阅读一遍教程,再去阅读smali代码
利用apktool反编译apk来二次打包
看着smali代码,还是有点懵逼...有没有方法像debug一样,可以随时查看变量的值,一行一行地运行程序呢?
还真有!!!我们可以用Android Studio来动态调试smali代码!!!
我们先用usb连接手机,开启手机的开发者模式,然后打开Android Studio的Android Device Monitor,可以看到我们的手机已经连接上电脑了
但是我们没有看到程序对应的进程。。。
经过google,原来真机上,只有AndroidManifest.xml里设置有android:debuggable="true"时,ADM才会出现对应的进程。那我们要如何添加android:debuggable="true"呢?这就涉及到了apk的二次打包。
我们可以修改程序的smali代码,修改app的行为(例如去掉广告,或者游戏里面增加金币),然后重新打包成apk文件,安装到我们的手机上。看到这里,你当然会想,这样我们不就可以随意修改app了吗?当然不可能这么简单,一般大公司的app都会加入各种机制,来防止用户修改app的行为,二次打包,难以重新打包成功或者运行程序时马上崩溃。这就涉及到了如何防反编译的话题了。
我们拿之前的魅族天气来尝试进行二次打包,这种小的,不涉及到金钱的程序,防反编译的处理都比较弱
我们在之前apktool反编译smali的weather_apktool里,找到AndroidManifest.xml,加入
<application ....
android:debuggable="true">...</application>
重新打包成apk后,还需要加上数字签名,才能安装到手机上,Android系统要求每一个Android应用程序必须要经过数字签名才能够安装到系统中,也就是说如果一个Android应用程序没有经过数字签名,是没有办法安装到系统中的!
我们使用keytool(Java数据证书的管理工具)
来生成数字签名
keytool -genkey -keystore cmd.keystore -keyalg RSA -validity 10000 -alias cmd.keystore
给二次打包的apk加上数字签名
jarsigner -verbose -keystore cmd.keystore -signedjar weather.apk weather.apk cmd.keystore
安装app
adb devices
adb -s 手机编码 install weather.apk
安装过程中,可能会出现Failure [INSTALL_FAILED_UPDATE_INCOMPATIBLE]的错误,这一般是卸载得不干净的原因,可以执行
adb shell pm list packages # 列出手机安装的所有app包名
adb uninstall 包名
然后重新安装,安装成功后,执行
adb shell am start -D -n 包名/MainActivity #(包名和MainActivity可以在AndroidManifest.xml找到)
在debug模式下启动App,成功了!!!
天气的自动定位问题
原因:重新打包后,APK签名文件的sha1与高德地图的key对应的sha1不符合
http://lbs.amap.com/faq/top/hot-questions/249
Android Studio动态调试smali代码
好,我们开始动态调试smali代码,先下载ideasmali,打开Android Studio,安装好ideasmali插件,选择Import project(Eclipse ADT, Gradle, etc.), 选择weather_apktool文件夹,然后一路next
选着smali文件夹,右键Mark Directory As -> Sources Root
配置远程调试的选项,选择Run-->Edit Configurations:增加一个Remote调试的调试选项,端口选择:8700
之后选择File-->Project Structure 配置JDK
查看Android Device Monitor,查看进程的端口
以调试状态启动app,并转发端口
记得关闭Android Device Monitor
下好断点之后Run-->Debug 'remote'
运行起来之后就可以单步执行,查看寄存器的值,慢慢调试了
总结
Android的反编译很有很多内容没有深入了解过,为了能更好地反编译出代码,深入了解Android系统是必要的,推荐一本书,Android软件安全与逆向分析,可以更加系统和深入的学习Android软件的反编译