实战:动态调试APK,以宝宝树为例.
本帖最后由 PoJie_小雨 于 2015-8-6 10:42 编辑作者:adslxyz
#####0x01.准备工具
1. IntelliJ IDEA
2. baksmali
3. AndroidKiller
4. IDA6.6
5. Fiddler
6. 一台Android真机(或者模拟器)
7. eclipse
#####0x02.抓包
手机连上`wifi`,与电脑处于同一局域网,然后设置好Fiddler,具体步骤不详述。
打开`宝宝树孕育6.2.1`版本,进入`登陆`窗口,输入账号密码点登陆,在电脑查看封包。
可以得到请求`URL`:
http://www.babytree.com/api/muser/login
方式:`POST`
参数:
android_id=d77c45cb6182db0e&build_serial=mmmm&local_ts=1438682239&source_channel=pc_pregnancy_tongyong_app_140729&longitude=122.535462&latitude=35.582332&phone_number=buROv8rMh50AdCj7mYdAZwWv9YEpsIR2mClGrO43QK6E5GHko7aEZwtZMT%2F2nvyuUCYsFtx%2Bkz1kwpthbRlpZecGXjkbyaaeIE4ocYjolDyLXLduydRCjnG%2Bk9OEfBr3QCShaiJ2Z%2BeDQIeqgTssdlzZqzFfpHzsg3oWpdF3RbMLF3O93RzGWntJgkgvzjzK7BfwvRF8p8o6Se2l7mX7malpYrn35H2kh4mEAaLaBGoj2naCxcSXCn6X6w9za6hofkhogCtB7PpY6pulzY%2BOhejwG1jdoCpqRxcctRcsFPWNz72SD8Mmqkq6wRVeLYX5ZIoWNafwEJuPobuRtmvhQzg%3D%3D&version=6.2.1&imei=90000451032112&secret=b8a310e750c8af5187197c279a7e0241&email=zLkZURsmEpT8fGCGGNADu2KAZ79zkZI3b%2FMBDh5i1vCAbvFmKoGu7L4nBPsOvnzzsnWtuOJipiITnoRQ5w%2FNTy%2FvEx%2BX%2FO8Ff8jcU2qBAXTzGgd0x1lZ8PsGuan0944ax5n1douoaTC370Hv4A%2F58IhP8rhcQWnO4FzFol8FC%2FXQ%2Fd1%2FoAQOycwdLeBUm0JJ5tRKiaT2nBwD1z7Dn1CShswWCNN2zDCvYgtJ7Ig3JIQipUahL9OaR%2FQnzUzk%2BmaC%2Fm6iRr1q4wkiz9lexJkXFHf1g5VuFqshCNgxdgeDw%2BZHuagedfj5MakZD96Lj%2BtZtRf6GhaLbY29tSL65EdSgsg%3D%3D&password=AhOxbuypr6JYDgpP%2Fw%2BLhVlfzwusSMOaE0137YBOvOAZkk%2BbCHwzfduzqsjasx6zrhZUkZv3aoZ27HDIFAebdgsRS9lh2eeuxXiIxZdkaVPy47UNMdLHo1fFnuUEOCbE144H%2FL%2B2EeY%2BjbE8Ebjg0gXuZ7ziNZ%2Bmrgt4%2FrN8YbizcbyCx7A%2Fue3GD3p58GV3ztnlxWp9d4D1IlMT5V%2B8qxi3VDpQMr0Ghi4MaDTkH%2FV8fcRSCBqutHTDsEs%2F5AfBgksHFT6Dcxl3tpBIIfdgEmU4EZ%2BpqLqVxVFLdjPA0MJOhzE36P8NqTPiKEXzTuJcmaaS5qU34d2dHGYP2wc7Dg%3D%3D&client_type=android&app_id=pregnancy&mac=5c%3A51%5A57%3A55%3A26%3A4d&client_baby_status=1&bpreg_brithday=2100-01-01
分析可知:
`phone_number`,`password`,`email`,`secret`四个参数为加密,其他参数均为固定或者地理位置信息等参数。
所以此次目标就为这`4`个参数
#####0x03分析调试1. 先把apk拖入AndroidKiller进行分析,可知无壳。
2. 根据先前分析,可在AndroidKiller中搜索相应字符串查找我们感兴趣的函数
搜索`muser\login`,可知登陆的函数在`com.babytree.platform.api.muser`中的`login.smali`中。
由图可知http://ww4.sinaimg.cn/large/653328d7gw1euqux5z91aj20w80b675l.jpg
Login.java的父类是ApiBase,可以猜想,所有Api的请求所公共的函数都会在此类中生成。
关键地方找一个就行,本次分析主要还是以动态调试为主.
3. 用baksmali将apk反编译成.smali文件
4. 然后打开IntelliJ IDEA,创建一个java工程.将上一步反编译出的smali文件导入到src文件夹中。如图:
http://ww2.sinaimg.cn/large/653328d7gw1euqv27q97xj20k00sojvq.jpg
5. 然后打开eclipse,切换到DDMS视图,选中手机,查看其端口,如图:
http://ww3.sinaimg.cn/large/653328d7gw1euqv4papq9j20m00osn6b.jpg
图上可以看到,目标应用的端口为8631.
6. 切换到IntelliJ IDEA,选择Run-Configurations.
7. 然后新建一个Remote,填写端口为8631,然后选择source using module's classpath为我们之前创建的项目,点击OK
8. 接下来在IntelliJ IDEA中打开Login.smali,快速浏览一下,选择一个感兴趣的地方下断点,这里我选择.method protected a()Ljava/lang/String;
在函数起始处下断点后,在手机中输入账号密码,点击登陆,可以看到断点成功断下,如图所示:
http://ww4.sinaimg.cn/large/653328d7gw1euqviw3gp1j21kw0tvk7m.jpg
从图中可以看到,左下角为函数的调用堆栈,从 登陆按钮 按下(OnClick),到api.user.login整个的调用过程。
展开右下角的p0,可以看到此时已经生成了3个参数,
http://ww4.sinaimg.cn/large/653328d7gw1euqvjtoupaj21kw0exk0t.jpg
说明在断点之前,参数已经生成好了。
所以我们按照函数的调用栈,挨个查看调用过的函数。
查阅一番后可以发现。Login对象是在
LoginActivity中的.method public a(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V方法创建的。
在new-instance v0, Lcom/babytree/platform/api/muser/Login;处下断点,重新点击登陆按钮,如图:
http://ww3.sinaimg.cn/large/653328d7gw1euqvvm4trmj219g0sawsx.jpg
此时v1.v2.v3寄存器分别出现了加密的结果,由上可知,分别对应`phone_number`,`password`,`email`三个参数。
所以加密的函数应该就在上面。
往上下断点,重新来一次观察一下加密的过程。
可知:
iget-object v0, p0, Lcom/babytree/apps/pregnancy/activity/LoginActivity;->u:Ljava/lang/String;
这一句函数调用之后,v0是一串固定字符串。
invoke-static {p1, v0}, Lcom/babytree/apps/pregnancy/h/a;->a(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
调用之后,v1为加密结果。查看a函数:
http://ww2.sinaimg.cn/large/653328d7gw1euqw0x20ldj21al0wjjvi.jpg
为RSA加密,所以之前的v0就是RSA的pubKey了。
在a函数中下断点,看一看加密的参数是什么:
http://ww1.sinaimg.cn/large/653328d7gw1euqw9q0ix9j21bq0vydrz.jpg
一切尽收眼底。由此可知`phone_number`,`password`,`email`三个参数的算法。
9. 接下来找`secret`的算法。
回到AndroidKiller搜索关键字,定位到com/babytree/platform/api/ApiCommonParams;
大致看一下,这个是API通用参数生成的类。且加载了一个so:api_encrypt.so
在`secret`关键字附近看一下,调用了so的invoke-static {v1, v2}, Lcom/babytree/platform/api/ApiCommonParams;->nativeGetParam(Landroid/content/Context;Ljava/util/List;)Ljava/lang/String;方法。
我们先在这句上面下个断点,看看传给so函数的是什么参数。
断点断下后,看到传递给so的参数是一个List,POST参数中除`secret`之外的所有参数。
参数知道了,调用点知道了。分析一下so,看看需不需要动态调试。
载入ida,找到调用的nativeGetParam函数。大致看一下,发现又调用了java的md5函数,好了,调试so的步骤剩下了。
http://ww3.sinaimg.cn/large/653328d7gw1euqwk057mej215506b0ug.jpg
回到IntelliJ IDEA,在getMD5Str处下断点,继续调试:
http://ww4.sinaimg.cn/large/653328d7gw1euqwlfulvrj20q60v0k0m.jpg
很快我们可以知道,p0中就是进行md5的参数啦。
分析一下可知,`secret`就是 MD5(时间戳+所有参数排序+&asdf12341dfas!@#$%()(Ujjlasdflasdfj;asjdf23412313kljajsdflasjdflasjdflajsdf;lajsdf2342234sdfsdfffds)
#####0x04.总结
动态调试apk的方式让我们了解apk运作的过程,通过动静结合的分析方式,快速找到想要的东西~
老大的沙发我来拿!{:1_918:} 前来学习,很详细 支持{:1_921:} 支持繁华 虽然看不懂 楼主 我不错啊 {:1_903:} 看不懂。出个视频就好了 大神辛苦了,点个大大的赞!~~ 谢谢,又学一课,谢谢 厉害{:1_921:} 感谢转载分享{:300_957:} 老大厉害,学习了