目录

一、抓包分析

二、Jadx反编译

三、frida hook调试

四、ida动态注册分析

五、算法还原

六、思路总结


一、抓包分析

1、打开我们本次需要抓取的App,使用charles设置代理进行抓包,抓包截图如下所示:

cpython 的so 逆向 .so逆向_爬虫

说明:之所以进行打码处理,也是为了避免不必要的麻烦,希望大家能理解。我们的目的是要学习别人的加固思路而非破解!

2、搜索指定关键字,定位我们想要获取的数据包,然后截图如下所示:

cpython 的so 逆向 .so逆向_游戏_02

总结:观察上图,确定我们本次需要还原的参数authorization后,初步判断该参数后,无法确定使用的什么加密手段;接下来让我们进入反编译调试环节吧!

二、Jadx反编译

1、使用Fart对指定App的apk脱壳后,直接使用jadx打开脱壳后保存的zip包,截图如下所示:

cpython 的so 逆向 .so逆向_python_03

2、等待jadx反编译完毕后,我们使用查找参数名和关键字的方法进行加密位置定位,截图如下所示:

cpython 的so 逆向 .so逆向_游戏_04

温馨提示:此刻如果你电脑内存不够16个G,介意还是换个电脑再来操作,相信我绝对没有错。

3、经过分析及追踪java源代码,最后定位到authorization参数加密的位置如下图所示:

cpython 的so 逆向 .so逆向_cpython 的so 逆向_05

总结:分析上面authorization的加密逻辑,我们需要确定return返回值中包含的多个参数的初始值即可完成对该参数的算法还原,接下来我们一起进入hook调试环节分析一下该算法吧。

三、frida hook调试

1、想要获取加密逻辑,我们首先需要先拿到str、e3、d2、f2的初始值,先hook一下c方法,构建frida代码如下所示:

cpython 的so 逆向 .so逆向_cpython 的so 逆向_06

2、启动frida脚本,执行刚刚写好的hook代码后,刷新手机界面,分析截图如下所示:

cpython 的so 逆向 .so逆向_游戏_07

此刻,我们将charles中的该请求包也截图,进行对比分析,截图如下:

cpython 的so 逆向 .so逆向_安全_08

总结:观察上面两张图的参数值,我们可以清楚地看到入参、出参和charles中的参数一一对应,接下来我们只需要还原每一个参数算法即可。

3、各个参数hook调试分析后,所有参数初判断总结如下:

  • e3  当前unix时间戳,10位
  • d2  五位随机字符,由字母和数字组合。
  • str 40位长度,初步怀疑为sha1加密 待定分析
  • str2 40位长度,初步怀疑为sha1加密 待定分析
  • f2  hmac sha1加密,通过分析java源码得出

3.1  f2 参数 hook代码如下所示:

cpython 的so 逆向 .so逆向_python_09

3.2  终端打印入参及出参输出如下所示:

cpython 的so 逆向 .so逆向_安全_10

4、接下来我们分析下str、str2两个参数的生成规则,只要解决掉这两个参数,我们就可以实现authorization参数的算法还原。经过多次hook,我们发现str、str2的值好像是固定不变的,截图如下所示:

cpython 的so 逆向 .so逆向_安全_11

结论:由于没有突破口,进行app卸载后重新安装,使用frida脚本重新hook,将hook到的str、str2的值进行查找,发现了该值是有新的接口返回的,截图如下所示:

frida hook界面截图如下:

cpython 的so 逆向 .so逆向_cpython 的so 逆向_12

charles定位截图如下:

cpython 的so 逆向 .so逆向_爬虫_13

总结:此刻我们已经知道了str、str2的生成规律,我们只需要还原该接口请求就能实现str、str2的参数生成,接下来我们需要对sign参数进行解密分析。

5、使用jadx查找sign参数,最后定位到该参数位置截图如下所示:

cpython 的so 逆向 .so逆向_游戏_14

5.1  编写frida脚本进行函数hook,代码截图如下:

cpython 的so 逆向 .so逆向_安全_15

5.2  启动刚刚编写的hook脚本,终端输出截图如下:

cpython 的so 逆向 .so逆向_游戏_16

5.3  此刻我们查看charles中的数据包sign截图如下:

cpython 的so 逆向 .so逆向_安全_17

总结:sign参数生成方法定位后,我们只需要还原sign加密方法即可完成所有代码闭环。

6、sign加密方法定位后,我们追踪java代码,最后确定到native层路径,截图如下:

cpython 的so 逆向 .so逆向_游戏_18

总结:加载so、通过native关键字定义了需要调用的方法getSign,也就是说,它这里调用的是so层的加密算法,so是什么?简单来说,它是c/c++编译后的产物。context、bArr变量我们都已经知道明文信息,接下来,我们需要用ida打开so文件,去探索so层对该方法做了哪些加密操作吧。

四、ida动态注册分析

1、两个参数值确定了,下面要做的工作就是分析so层的加密算法获取sign值。我们通过压缩软件打开apk,因为我手机的cpu类型是arm64-v8a, 是向下兼容的,选择使用armeabi-v7a中的so文件是可以的。找到目标文件,使用ida打开后截图如下所示:

cpython 的so 逆向 .so逆向_游戏_19

2、使用ctrl+F查找静态注册的指定方法名,结果无法搜寻到,这个时候可以肯定java调用的方法名在so文件中是动态注册的。找到JNI_Onload,点击该方法,使用F5打开该方法,截图如下所示:

cpython 的so 逆向 .so逆向_安全_20

3、点击v4后面的地址off_5004[0]进入指定代码块进行分析,截图如下所示:

cpython 的so 逆向 .so逆向_安全_21

总结:这个时候我们看到了java层的getSign方法和java层该方法的两个参数类型,接下来我们继续追踪分析so层是如何加密的。

4、点击sub_131c+1地址,然后按F5进入指定代码块,截图如下所示:

cpython 的so 逆向 .so逆向_python_22

说明:这个地方会有签名校验,判断我们是否重新打包。如果为true,则直接返回0,否则执行下面的操作。

5、继续点击sub_1094地址方法,进入新的代码块,最新截图如下图所示:

cpython 的so 逆向 .so逆向_安全_23

总结:这个代码逻辑是拿我们在java native接口函数中传递的字符串与So中的字符串进行比较,然后给v8变量赋值,之后的加密逻辑会使用到v8变量。

6、点击sub_1B04地址进入到最新代码块区域,截图如下所示:

cpython 的so 逆向 .so逆向_python_24

7、点击上图四个常量,然后点击按键H格式化常量值转为16进制,截图如下所示:

cpython 的so 逆向 .so逆向_cpython 的so 逆向_25

总结:看过md5源码的同学,应该对这个四个常量比较熟悉吧,这不就是A、B、C、D四个常量值吗?到这里,我们可以肯定,sign的加密算法就是md5加密;sign值的生成规则其实是指定参数拼接不同包名对应的salt进行md5加密即可。接下来,让我们进入算法还原环节吧!

五、算法还原 

1、sign参数算法还原如下:

import hashlib
def get_sign():
    salt = "PeCkE6Fu0B10Vm9BKfPfANwCUAn5POcs"
    data = f'X-UA=V=1&PN=xxx&VN_CODE=224003000&LOC=CN&LANG=zh_CN&CH=seo-baidu&UID=07e90f02-7def-4f28-a0b4-70098396e1df&NT=1&SR=1080x1794&DEB=Google&DEM=Pixel+2&OSV=10&action=active&android_id=84c16aaccd10a6e5&cpu=arm64-v8a&model=Pixel 2&name=Google&nonce=istb4&pn=0&push_id=6ce79a19f68c48779463dc893589c46c&screen=1080x1794&supplier=1&time=1671172755&uuid=07e90f02-7def-4f28-a0b4-70098396e1df&version=10{salt}'
    sign = hashlib.md5(data.encode(encoding='UTF-8')).hexdigest()
    print("e6a071ae2dc6cd117278b0f9d2fa04b1")
    print(sign)

pycharm终端输出如下:

cpython 的so 逆向 .so逆向_cpython 的so 逆向_26

总结:解决sign参数后,也就意味着str、str2参数我们能够获取到了,接下来我们对authorization参数mac做算法还原。

2、mac参数算法还原如下:

def get_mac():
    data = "1649340509\nhi9b4\nGET\n/landing/v5/timeline-with-device?action=refresh&X-UA=V%3D1%26PN%3D%26VN_CODE%3D224003000%26LOC%3DCN%26LANG%3Dzh_CN%26CH%3Dseo-baidu%26UID%3Dc2ff8daf-08ca-4e54-b051-6c5fde70bdda%26NT%3D1%26SR%3D1080x1794%26DEB%3DGoogle%26DEM%3DPixel%2B2%26OSV%3D10&show_channel_app=1\napi.xxxdada.com\n443\n\n"
    str2 = "d1e76439035449b521ea6c3d27aae758ef05ec65"
    mac = hash_hmac(data, str2)
    print("new--------")
    print(mac)
    print('ori--------')
    print("qrcn7ei6EBAPs/LkBO+undcifsk=")


def hash_hmac(code, key):
    hmac_code = hmac.new(key.encode(), code.encode(), sha1).digest()
    return base64.b64encode(hmac_code).decode()



pycharm终端输出如下:

cpython 的so 逆向 .so逆向_python_27

总结:走到这里所有算法还原就结束了。我们只需要把分析的每个参数进行字符串拼接即可实现对authorization参数的生成!最后一步流程就省略了,结果已经很明朗了,感谢各位读者朋友阅读!