cxxjackie 发表于 2022-11-4 23:36:30

记一次逆向拆包的过程(一)

最近想做个中国移动APP的签到脚本,研究了一下签到请求发现还挺复杂,涉及各种加密、反编译,遂记录此文,以作参考。
首先是手机抓包,大体流程就是电脑抓包软件设置好代理端口,然后手机wifi连接代理,安装好证书就可以抓包了。详细流程网上都有,可以参考下论坛的[这篇文章](https://bbs.tampermonkey.net.cn/thread-3080-1-1.html)。这里也用Charles这个工具为例进行分析,注意关掉windows代理,只打开代理端口,这样只会抓手机上的包。抓取完整的签到流程后,点击“序列”,让请求按时间排序,从后往前找响应数据,可以看出这个是关键签到请求:
`https://wx.10086.cn/qwhdhub/api/mark/do/mark`
尝试在脚本里复现这个请求,注意尽可能带上一样的header,尤其是User-Agent,cookie我们先不带上。请求发出后,被重定向到下面这个登录请求(最好去脚本管理器的background页看实际请求):
`https://wx.10086.cn/qwhdsso/login?dlwmh=true&actUrl=https%3A%2F%2Fwx.10086.cn%2Fqwhdhub%2Fqwhdmark%2F1021122301`
这说明缺少cookie,服务端认为我们需要登录,而这个登录请求在我们前面抓的包里也能找到,其响应是一个html页面。html的代码里包含了基本的登录逻辑:
!(data/attachment/forum/202211/04/230112zsq6ps600xfbj6vq.png)
大致分析一下,将UID加密后发出一个chinaMobileApp的post请求,猜测该请求起到关键的登录验证。在登录请求和签到请求之间的包里找一找,可以找到这个:
!(data/attachment/forum/202211/04/230641gbaldz1xd960m8qc.png)
请求的响应数据包含了一个新的url,在下方就可以找到访问这个url的请求,其响应是另一个html页面。如果深入研究一下这个html,可以发现签到请求就是这个页面发出的。回到脚本的签到请求,我们可以逐个尝试一下,发现加上SESSION这个cookie以后,可以得到“今日已签”的成功响应。注意反复测试这类有cookie的请求时,最好带上anonymous: true,因为多次测试可能会改变cookie干扰结果,甚至某次失败了写入一个错误的cookie,可能导致后续一直失败无法更新cookie。
在Charles中按ctrl+f搜索,设置如下搜索规则:
!(data/attachment/forum/202211/04/230753axt5x5hoy29xd588.png)
由于cookie不是凭空产生的,通常是由某些响应头的Set-Cookie字段设置,这个搜索的意思就是查找哪个请求设置了SESSION。找到2个结果,注意我们的签到请求作用域是/qwhdhub/,可以确定是这个请求设置了SESSION:
`https://wx.10086.cn/qwhdhub/qwhdmark/1021122301?XXX`
是不是很眼熟?他跟chinaMobileApp响应的那个url非常接近,对比一下发现只多了token,而这个没token的版本,正好重定向到了我们前面的登录页面。至此签到流程可以基本确定为:首先请求1021122301,该请求会设置SESSION(此时这个SESSION还是无效的),然后重定向到登录请求,登录请求的html发出chinaMobileApp,返回一个带token版的1021122301(此时SESSION正式生效),最后发出签到请求。
显然chinaMobileApp是最关键的请求,我们在脚本里尝试复现一下,发现无需cookie也能得到正确结果(很多数据是有时效的,如果间隔时间太长需要重新抓包)。观察html代码,可以看出核心是他的data,其中openid属性明文写在前面的html代码里,mobile是对UID的加密结果,其他属性我们排除法测试一下,发现加不加没有影响。openid可以对html做正则获取,UID的加密由leadeon.encryptString这个函数完成,前后翻一翻发现,页面引入了这个js文件:
`https://app.10086.cn/appother/js/public/leadeon.js`
打开看看源码,确实可以搜索到encryptString,大胆一点,直接在脚本里引入这个js,然后模仿着写一下leadeon.encryptString,运行后报错:newSdkInterface is not defined。在leadeon.js里搜索newSdkInterface,可以大致看出,我们的加密函数在这个对象上,html里找不到该对象的定义,引入的js文件也只剩一个jquery。看起来卡住了,我们换个思路,往Charles里写入一条重写规则:
!(data/attachment/forum/202211/04/231049se5zcgcs5ezctltx.png)
这里的想法是chinaMobileApp这个请求是由登录请求的html发出的,所以我们改写登录请求的响应结果,让其发出的chinaMobileApp额外带上我们需要的数据,从而暴露出加密函数源码,顺便我把UID明文也带上了。手机APP清除一下缓存,然后重新签到抓包,看看这个新的chinaMobileApp。结果发现,fn是,UID倒是带上了。这个native code可能是人为改写的结果,换一种写法试试:
```js
Function.prototype.toString.call(newSdkInterface.encryptString)
```
结果还是没变,说明一个问题:加密函数并非来自js,而是其他语言写的。这不难理解,请求是手机客户端发出的,客户端又不是js写的,关键函数可能会放到客户端内由Java实现。这又涉及客户端反编译的问题了,我这里用的安卓,关于apk反编译的教程网上很多,大致就是解压apk得到classes.dex,dex2jar反编译为jar,再用jd-gui查看源码。至于apktool,那主要是用来修改smali再重新打包回去的,由于我们的目的只是看源码,不关心打包,故可以跳过这一步。
这里额外说一点我的经验,jd-gui的不同版本查看效果是有差异的,最新的1.6.6看有些函数会变成一堆注释,换较低的1.4.0反而能解析出来,而1.4.0看别的有更大概率变注释,也有可能两个版本都解析不出来,具体原理我也不懂,建议多下几个版本换着看。
class.dex有80多M,dex2jar转换后却只有15K,jd-gui查看效果是这个鬼样子:
!(data/attachment/forum/202211/04/231221htnnrbxx9xhzyefr.png)
从包名可以看出,这个dex被加壳了。常见的脱壳方式是安装运行apk,然后从内存里dump出实际的dex。我试过在安卓模拟器里搞这些,但32位和64位的兼容问题相当麻烦,遂放弃,直接在实机上操作。这是我找到的一个工具,特点是无需root,操作简单:
(https://github.com/CodingGay/BlackDex)
中国移动的apk是64位的,要用BlackDex64打开,这个工具不是很完美,每次脱出的dex数量有限,最好多试几次得到尽可能多的dex(数字相同的就是同一个)。最终我得到了19个,可以分别用dex2jar转为jar再全拖进jd-gui里查看,不过可能会出现同一个包分散在不同文件,找起来很不方便,我写了个批处理来合并:
```
rem 这里填d2j-dex2jar路径
set DEX2JAR="D:\dex-tools\d2j-dex2jar.bat"
rem 这里填WinRAR路径
set WINRAR="C:\Program Files (x86)\WinRAR\WinRAR.exe"

for /r %%i in (*.dex) do call %DEX2JAR% "%%i"
if exist package rd /s /q package
if exist package.jar del /q package.jar
md package
for /r %%i in (*.jar) do %WINRAR% x -o+ "%%i" package
%WINRAR% a -afzip -df -ep1 -r -m0 package.jar package\
rd /s /q package
```
使用方法是复制到记事本,改好你自己的dex2jar和WinRAR路径,保存后修改后缀为bat,再放到与dex文件同一目录下运行即可。由于jar的本质就是zip压缩包,合并的原理即解压后合并目录,再重新压缩成一个。如果有配置好java环境,用jar命令也能做,WinRAR的好处是可以指定压缩级别,我设置为存储,这样速度最快,生成的文件也最大(其实就是没压缩)。由于我们不打算打包回去,只要jd-gui能打开就行,所以大小无所谓。如果你使用其他压缩软件,也可以尝试自己改压缩命令。
打开合并后的jar就可以看Java源码了,有Java基础的可以自己先研究一下,篇幅所限,有关加密的分析我们就且听下文分解吧。

李恒道 发表于 2022-11-4 23:51:02

脱壳好像也可以试试反射大师
在对应页面长按导出可以导出全部Class
貌似用反射大师没碰到过导出不全的情况

cxxjackie 发表于 2022-11-5 20:29:30

李恒道 发表于 2022-11-4 23:51
脱壳好像也可以试试反射大师
在对应页面长按导出可以导出全部Class
貌似用反射大师没碰到过导出不全的情况 ...

反射大师需要xposed框架,我手机没root,一开始用模拟器就是root比较方便,可惜兼容问题有点多。

李恒道 发表于 2022-11-5 20:32:08

cxxjackie 发表于 2022-11-5 20:29
反射大师需要xposed框架,我手机没root,一开始用模拟器就是root比较方便,可惜兼容问题有点多。 ...

是,而且好像反射大师还不支持安卓高版本...

mcroxf 发表于 2022-12-14 21:46:35

BlackDex能脱棒棒加固企业版?我草

sam770 发表于 2023-7-19 11:33:30


BlackDex 没能脱到中国移动的壳,我用的反射大师,但包导不全,要一个个导,比较麻烦,另外想问题楼,你JAVA代码全靠分析,没做动态的HOOK? 那脑子要记多少东西啊

sam770 发表于 2023-7-19 18:32:49

中国移动的脱壳JAR能分享一份吗?我的这里不知道是壳得不完整还是什么原因?里面是返回的NULL,但HOOK是有返回的值的 public class b {
    public static String a(String str, String str2) {
      return null;
    }

    public static String b(String str, String str2) {
      return null;
    }
}

cxxjackie 发表于 2023-7-20 22:49:25

sam770 发表于 2023-7-19 18:32
中国移动的脱壳JAR能分享一份吗?我的这里不知道是壳得不完整还是什么原因?里面是返回的NULL,但HOOK是有返 ...

你下的apk是8.0.5的吗?其他版本我没试过不知道行不行,你找找看,豌豆荚我记得可以下历史版本的。jar主要是有点大,不行我再上传一份吧。

cxxjackie 发表于 2023-7-20 23:35:09

sam770 发表于 2023-7-19 18:32
中国移动的脱壳JAR能分享一份吗?我的这里不知道是壳得不完整还是什么原因?里面是返回的NULL,但HOOK是有返 ...

传好了,找了好几个网盘,不是速度慢就是限制100M,要么不让分享jar,吐了:https://pan.quark.cn/s/32cf51a6094b

sam770 发表于 2023-7-21 08:40:13

cxxjackie 发表于 2023-7-20 23:35
传好了,找了好几个网盘,不是速度慢就是限制100M,要么不让分享jar,吐了:https://pan.quark.cn/s/32cf ...

谢谢楼主了{:4_93:}
页: [1] 2
查看完整版本: 记一次逆向拆包的过程(一)