对虚构的Android社交平台接口分析

 

以下情景均基于杜撰的应用。

工具

  • 抓包工具Fiddler
  • IDA64
  • JADX

抓包

模拟器设置好Fiddler代理,进行登录,输入手机验证码,发送消息,退出应用再重新进入并刷新主界面的操作, 分析抓到的数据。

登录验证

使用密码登录的请求如下。 登录接口

其中c为client标识符,不会变化; u为登录界面输入的用户名或邮箱; p为通过公钥rsa加密后的密码; from为客户端标识id; 值得注意的是said的取值。

正常响应的内容应包含用户信息,cookies及gsid。 对于账户初次登录的设备,将有如下返回,需要使用errurl跳转至网页获取手机验证码。

手机验证码

成功后,从返回值中获取alt

手机验证成功

重新使用如下图的请求,通过alt值登录并获取gsid

使用alt登录

二次登录通过gsiduid即可更新cookies等。

gsid登录

此处注意到s值发生了变化,从8个1变为了8个2。

aid的获取

注意到,首次打开应用时,软件通过/guest/login接口,获取到了aid,请求如下。

游客登录

其中appkey很显然为固定值,需要分析其余参数如何生成。

反编译apk

这里使用整合的onekey-decompile-apk,将应用apk文件拖入,进行一键反编译。 通过搜索mfp,很轻松地找到了guestLogin方法。 guestLogin

很显然,uid就是imei值,这里似乎是我没有给电话的权限所以为空,但uid为空不影响aid的获取。 而i的值,调用了boSecurityUtils.getIValue方法,找到此函数,发现为常量”1234567”。

getIValue

checktoken则为拼接字符串{uid}/{did}/obiew的md5值。 重点在于didmfp的取得。

找到generateDidgenerateMfp方法,发现均为native函数。

反编译lib.so

使用ida pro反编译apk解包后的libnative-lib.so文件。 反编译完成后,CTRL+F9(File->Load File->Parse C Header File..),导入 jni_all.h 头文件。 在左侧找到对应的函数,在右侧按F5将汇编转换为C代码。点选参数a1,并单击键盘Y键,将类型更改为JNIENV *,使得代码更易读。

generateDid

可以发现,其可以直接返回一个值,且在guestLogin中只取前32位,猜测仅为设备标识符,不做深入分析。

对于函数generateMfp,可以看到,其将公钥传入了aaa函数中。

generateMfp

在函数aaa中,利用公钥通过RSA加密了genMfpString返回的字符串。

aaa

查看genMfpString,发现其会返回一个包含各种设备信息的JSON字符串,且可能为空。 genMfpString

查看encryptRsa,发现其在生成的字符串前添加了"01"encryptRsa

由此使用generateMfp中的公钥加含有设备信息的JSON字符串,即可获得最终mfp值。

综上可正常获得aid。

s值的计算

注意到,应用使用refreshToken更新登录相关值,查找其调用。

refreshToken

可以发现,登录时传入了登录的用户名/邮箱/手机号与密码明文的拼接,及fromc的值。

loginActivity

分析本函数可以发现,其最终会走入红框中的分支,需要了解Pin值。

calculateS

取得Pin值

再次来到ida pro,根据输入902784192发现其会走入红框中的分支,得到Pin值。

Pin

回到calculateS发现用户名密码的组合,Pin,from902784192被传入generateS中,其为native方法。 generateS

再次来到ida pro,结合前人经验,最终进入toSecurityValue函数。

generateS2

aa4

toSecurityValue

综合上述分析,写成python形式为

import hashlib


def convert_byte_to_int(b):
  if b - 48 <= 9: return b - 48
  if b - 65 > 5: return b - 87
  return b - 55


def calculate_s(content, g_from, g_pin):
  key1 = g_pin + content + g_from
  key2 = g_from
  key1_s = hashlib.sha512(key1.encode('utf-8')).hexdigest()
  key2_s = hashlib.sha512(key2.encode('utf-8')).hexdigest()
  ret = ""
  j = 0
  for _ in range(8):
    k = convert_byte_to_int(ord(key2_s[j]))
    j += k
    ret += key1_s[j]
  return ret

登录时,content为用户名+明文密码的拼接,登录后为uid

DEMO

Done

参考文章

https://www.52pojie.cn/thread-1370540-1-1.html

https://zhuanlan.zhihu.com/p/98691781