所需工具
- 逍遥模拟器
- lamda
- jadx
- frida
- 一双手
抓包 #
软件有root检测和代理检测,这里不讲绕过。代理不要挂。 安装lamda:
set HTTPS_PROXY=127.0.0.1:7890
git clone https://github.com/rev1si0n/lamda.git
下载lamda-server-x86_64.tar.gz 以及busybox-x86_64
先把模拟器的root打开
# 在你下载好的目录打开终端
adb push lamda-server-x86_64.tar.gz /data/local/tmp
adb push busybox-x86_64 /data/local/tmp
adb shell
# 以下命令都是在adb shell中执行的
su
chmod 755 /data/local/tmp/busybox-x86_64
cd /data
/data/local/tmp/busybox-x86_64 tar -xzf /data/local/tmp/lamda-server-x86_64.tar.gz
rm /data/local/tmp/lamda-server-x864.tar.gz
rm /data/local/tmp/busybox-x86_64
启动lamda
继续上一步结尾
cd /data/local/tmp/server/bin
sh launch.sh
启动完成
ctrl+D退出终端
在你的lamda目录里打开终端
cd tools
python startmitm.py localhost
启动app,记得关掉root再启动,已经可以抓包了
逆向 #
看看抓包
一眼盯帧,是有加密,那么,开始逆向吧 工具jadx,把apk拖进去
X-JSL-API-AUTH #
搜索大法好啊,ctrl+shift+F,直接找关键字 X-JSL-API-AUTH
只有一处
有,直接跟进去,v.a.a
String a = v.a.a(Z.h().u().getPath());
看到MD5关键字
参数基本一目了然
唯一有一个key参数,来自so层,右键这个函数,生成frida hook代码,
frida hook不在此展开,多次hook易得key横不变,为
l8N2iooyp07M9IWa
易得脚本
X-TOKEN #
搜索,只有一个,按x,交叉引用,诶,找不到
但是,我们继续在上面能找到 f.a(com.niming.weipa.b.a.A, com.niming.weipa.utils.b.b(String.valueOf(jSONObject)));
一句
com.niming.weipa.b.a.A
就是 X-TOKEN
,后面是在加密那坨hashmap
看看加密,AES/ECB/PKCS7Padding
,key还是同一个l8N2iooyp07M9IWa
DATA #
直接去搜索data的话,肯定会有很多结果,注意到json中有一个handshake参数,大概是恒固定的,去搜索一下v20200429
只有一个结果,直接定位到加密
发现是使用的是和上面相同的加密方法
hook一下这个加密方法,看看都加密是些什么东西
右键这个方法,复制frida 方法,这里不再展开
邀请好友 #
from hashlib import md5
import time
import requests
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
import base64,json
import random
MODE = AES.MODE_ECB
PAD_STYLE = 'pkcs7'
ENCODING = 'UTF-8'
key='l8N2iooyp07M9IWa'
url='http://apichlove.com'
def encrypt(plaintext: str, key: str) -> str:
key_bytes = key.encode(ENCODING)
cipher = AES.new(key_bytes, MODE)
plaintext_bytes = plaintext.encode(ENCODING)
plaintext_bytes_padded = pad(plaintext_bytes, AES.block_size, PAD_STYLE)
ciphertext_bytes = cipher.encrypt(plaintext_bytes_padded)
ciphertext_base64_bytes = base64.b64encode(ciphertext_bytes)
ciphertext = ciphertext_base64_bytes.decode(ENCODING)
return ciphertext
def decrypt(ciphertext: str, key: str) -> str:
key_bytes = key.encode(ENCODING)
decrypter = AES.new(key_bytes, MODE)
ciphertext_base64_bytes = ciphertext.encode(ENCODING)
ciphertext_bytes = base64.b64decode(ciphertext_base64_bytes)
plaintext_bytes_padded = decrypter.decrypt(ciphertext_bytes)
plaintext_bytes = unpad(plaintext_bytes_padded, AES.block_size, PAD_STYLE)
plaintext = plaintext_bytes.decode(ENCODING)
return plaintext
def x_t(url):
a = []
b = []
# url = 'app/api/auth/login/device'
v1 = str(int(time.time()))
v2 = md5(v1.encode()).hexdigest()[:8]
a.append('md5')
a.append(key)
a.append(v1)
a.append(v2)
a.append(url)
v3 = '|'.join(a)
v3 = md5(v3.encode()).hexdigest()
b.append('md5')
b.append(v1)
b.append(v2)
b.append(v3)
return '|'.join(b)
def getRandom(randomlength=16):
digits='0123456789'
ascii_letters='abcdefghigklmnopqrstuvwxyz'
str_list =[random.choice(digits +ascii_letters) for i in range(randomlength)]
random_str =''.join(str_list)
return random_str
def Token():
device_id='b2ad30fc-0301-3d50-a97f-'+getRandom(12)
data = json.dumps({"channel": "", "code": "", "device_no": device_id,"device_type": "A", "version": "1.0.0"})
data={'data':encrypt(data,key),'handshake':'v20200429'}
header = {'X-JSL-API-AUTH': x_t('/app/api/auth/login/device')}
result = requests.post(url+'/app/api/auth/login/device', json=data, headers=header).json()
msg=decrypt(result['data'],key)
# print(msg)
return json.loads(msg)['auth']['token'],device_id
def x_token(device_id,token):
Json=json.dumps({"device_no":device_id,"device_type":"A","token":token,"version":"1.0.0"})
return encrypt(Json,key)
def parent(code):
token,device_id=Token()
data={'data':encrypt(json.dumps({'code':code}),key),'handshake':'v20200429'}
header={'X-JSL-API-AUTH':x_t('/app/api/user/bindcode'),'X-TOKEN':x_token(device_id=device_id,token=token)}
result=requests.post(url+'/app/api/user/bindcode',json=data,headers=header).json()
print(result)
print(decrypt(result['data'],key))
header['X-JSL-API-AUTH']=x_t('/app/api/user/info')
# 你的X-TOKEN
# header['X-TOKEN']='4LJnAngoza8TZIz2otKTe52PhqbrW8GULUYVUu87AjDKzXQWPzNCDiHTohcbTWRcJ5V+mdgxrLVskUbLae90njTJJk4bG8tqYcgDX/fhwwG0VkkB11CY0wLhlxPfSkfMSlqmArvVTbrJ7UiydzotGh9nUHVrBqxMbDy9+iuhq9pFmucuV1SRKd/1pGxDNI0UX9nA5mpYMfYih0N/vR3A6+AdHQASRqBpeXSfMj3M7fHY/5W4fj0esNHkw93KjsnWM2FJWdNCYrkZC3tHWipUqKTk7zvbx20zaWo/c78VuePh8OeiCV2Htt9ah8+MNvAu+o6TERNF13aavGJkxeptaZs/+PFbBa397NVD4zQ28QDhkuOthPwHbpvOL/cWm9rjoL7TH7BdKGqjbYzHTvUnpWHQtJhGTPXRdNdSklDv4UDW/nsKTVVcv1LQAU1Oo5EnMwfZF2wmTtIRMRTPIi9zYFVhTYlJeFroe2fWrl8H9afzxz+fP+tm5aGSa7Ll0RBitPmN364On3xaWrRIiYGvfYsqckb6+BRQyDMXI+nHUMOAR2EcT6U3BMUCN5VJnkX8atWL76jdqPlFZzS9zyo5yaeiNLnQzVYm9wxNPuzb9ZMgvRQ4TnXfBGE5t8BiE4jAPJczvQhvWseHNy3M3wCd5b7CavKAVznoovCoLaqJpRX+bOWnttUWMLqdYxBnweL3'
# result=requests.post(url+'/app/api/user/info',data='{"handshake":"v20200429"}',headers=header).json()
# print(json.loads(decrypt(result['data'],key))['vip_expired'])
# 邀请码
for i in range(5):
parent('RWK6IF')