1.png (57.71 KB, 下载次数: 0)
下载附件
2022-7-7 19:36 上传
可以看到一共是三个请求,仔细看看这三个请求pwd这个请求带了5个参数,一看到有加密,瞬间想知道用的什么算法。这个时候看到pwd这个请求里面有一个字段是nonce,正巧上面也有一个请求的名字也是nonce所以就去看看吧。
2.png (72.88 KB, 下载次数: 0)
下载附件
2022-7-7 19:09 上传
这个时候好像发现了一个秘密,这竟然是pwd里的nonce字段那么同样,下面还有一个请求呢,那是不是里面也存在东西
3.png (45.22 KB, 下载次数: 0)
下载附件
2022-7-7 19:09 上传
发现pwd请求中的fdsOtp正是这个请求返回的token,那么这时候暗自窃喜,已经找到两个了, 模拟一下就可以得到,那剩下三个参数不是简简单单。
打开jadx吧
5.png (71.9 KB, 下载次数: 0)
下载附件
2022-7-7 19:09 上传
看到关于登录的就这么多,一个一个看呗,也不多。
6.png (23.65 KB, 下载次数: 0)
下载附件
2022-7-7 19:09 上传
account不是出现在请求中么,先往后看一眼是什么逻辑
7.png (12.73 KB, 下载次数: 0)
下载附件
2022-7-7 19:09 上传
这跟进来看着很清晰啊
8.png (12.43 KB, 下载次数: 0)
下载附件
2022-7-7 19:09 上传
在看看
[color=]ZaZJiHJbQT这个函数的逻辑是什么
9.png (19 KB, 下载次数: 0)
下载附件
2022-7-7 19:09 上传
[color=]哦豁 是个native函数。那打开IDA吧
10.png (22.36 KB, 下载次数: 0)
下载附件
2022-7-7 19:09 上传
看
[color=]起来就一个函数啊,那应该就是这个,加密就在里面快冲
当我双击进去的时候花的时间有点久,我就觉得可能大事不妙
11.png (25.03 KB, 下载次数: 0)
下载附件
2022-7-7 19:09 上传
好家伙,果然。看到这个流程图完全不想看啊。
这时候有一个办法 上unidbg,补环境是一个很头疼的问题。花的时间有点久
12.png (56.8 KB, 下载次数: 0)
下载附件
2022-7-7 19:09 上传
但是我这里不知道是什么原因,结果出不来,那就重头好好看看吧
13.png (257.24 KB, 下载次数: 0)
下载附件
2022-7-7 19:10 上传
嗯.......全是反射,不过上来就看到了RSA往下看也没什么好像就是一个RSA,公钥在第一行也给出来了。那么,账号密码都是RSA加密了,但是每次RSA加密的结果都是不一样的,只能往后模拟一下请求吧。
现在就剩最后一个参数了。
14.png (42.39 KB, 下载次数: 0)
下载附件
2022-7-7 19:10 上传
还是跟刚才一样找关键字呗,到了这个函数的时候一瞬间,这不就是请求的五个参数
15.png (31.09 KB, 下载次数: 0)
下载附件
2022-7-7 19:10 上传
跟到最后发现调用的是RIdAPyTgEt,不用想这个肯定也混淆了。还试试unidbg呗
哦对了忘了说,这个参数如果不知道是什么的话,先用frida看一下
[JavaScript] 纯文本查看 复制代码function hook_native() {
Java.perform(function() {
var i = Java.use("com.ximalaya.ting.android.loginservice.LoginEncryptUtil");
i.RIdAPyTgEt.overload('android.content.Context', 'boolean', 'java.lang.String').implementation = function (arg1,arg2,arg3) {
console.log('RIdAPyTgEt arg1 = ' + arg1)
console.log('RIdAPyTgEt arg2 = ' + arg2)
console.log('RIdAPyTgEt arg3 = ' + arg3)
var ret = this.RIdAPyTgEt(arg1,arg2,arg3)
console.log('RIdAPyTgEt ret = ' + ret)
return ret
}
i.ZaZJiHJbQT.overload('java.lang.String').implementation = function (arg1) {
console.log('ZaZJiHJbQT arg1 = ' + arg1)
// console.log('arg2 = ' + arg2)
var ret = this.ZaZJiHJbQT(arg1)
console.log('ZaZJiHJbQT ret = ' + ret)
return ret
}
});
}
16.png (115.4 KB, 下载次数: 0)
下载附件
2022-7-7 19:10 上传
这样子参数不就很清晰了嘛,就只接用unidbg模拟一下吧
17.png (55.91 KB, 下载次数: 0)
下载附件
2022-7-7 19:10 上传
但是很不幸,死在了系统调用。没有办法,拿出同事的脚本。
18.png (57.22 KB, 下载次数: 0)
下载附件
2022-7-7 19:10 上传
这时候我发现了跟我传进来的格式差不多,但是多了一串东西
19.png (66.7 KB, 下载次数: 0)
下载附件
2022-7-7 19:10 上传
继续往下发现,全大写了。
20.png (19.66 KB, 下载次数: 0)
下载附件
2022-7-7 19:10 上传
紧接着直接做了加密,那么就没错了,那就是传进来的东西拼接一个东西,在做一个加密,那么这个加密是啥啊,40个字节的一个加密,像sha1啊,找个在线的试试去
21.png (41.62 KB, 下载次数: 0)
下载附件
2022-7-7 19:10 上传
一模一样啊,那就是sha1
这个时候算法已经很清晰了啊。
1.先发送一个请求,在服务器返回包中拿到 fdsOtp
2.发送第二个请求,在服务器返回包中拿到nonce
3.在使用ZaZJiHJbQT加密账号密码算法是RSA,加密以后的格式要确保一致
4.用同一个so中的RIdAPyTgEt加密得到signature,在so中拼接了一个字符串,使用sha1加密。
5.上面步骤完成以后才可以正确请求到。写代码写代码。
[Python] 纯文本查看 复制代码# -*- coding:utf-8 -*-
import json
import time
import hashlib
import requests
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5
from base64 import b64decode
from base64 import b64encode
proxy = {'http': 'http://139.155.48.55:1089', 'https': 'http://139.155.48.55:1089'}
def get_nonce():
"""
:return: nonce的值
"""
t = time.time()
data_time = int(round(t * 1000)) # 毫秒级时间戳
url = "https://passport.ximalaya.com/mobile/nonce/" + str(data_time)
header = {
"Cookie": "1&_device=android&59683601-c043-33af-95d4-413ba0788573&9.0.22;channel=Avril22;impl=com.ximalaya.ting.android;osversion=29;fp=009314627x2222q2v644v0500b0000022002000000000000200000000000;device_model=MI+8;XIM=;c-oper=%E6%9C%AA%E7%9F%A5;net-mode=WIFI;freeFlowType=0;res=1080%2C2029;AID=n+Ew49Cv/1Y=;manufacturer=Xiaomi;XD=NSRvWEdehdyqqdzAdbPbJbOfbPFruUAJe3HFBaJ0z438KV7oI/Q/czqtjV2TmpUvQtc0VKk72doYCGDVyUUkqe+kAr9y9XC5FdiYPvv8e66Wf7z4JEulczsJmwNd27g/;umid=0e42f21fc3f4e8704728805785e97255od;xm_grade=0;minorProtectionStatus=0;oaid=5d3cfedc6c1bd5aa;domain=.ximalaya.com;path=/;",
"Cookie2": "$version=1",
"Accept": "*/*",
"user-agent": "ting_9.0.22(MI+8,Android29)",
"x-xuid": "78c5c143-aa52-3f77-b3b6-fb4d0c289c3a",
"Host": "passport.ximalaya.com",
"Connection": "Keep-Alive",
"Accept-Encoding": "gzip"
}
req = requests.get(url, headers=header)
print("nonce响应结果 = ",req.text)
nonce = json.loads(req.text)
nonce = nonce["nonce"]
print('nonce = ', nonce)
return nonce
def get_fdsOtp():
"""
:return: fdsOtp的值
"""
t = time.time()
data_time = int(round(t * 1000)) # 毫秒级时间戳
get_token_url = "https://mobile.ximalaya.com/captcha-web/check/slide/get?bpId=139&sessionId=59683601-c043-33af-95d4-413ba0788573" + str(data_time) + "&requestType=xmClient"
get_token_header = {
"Cookie": "1&_device=android&59683601-c043-33af-95d4-413ba0788573&9.0.22;channel=Avril22;impl=com.ximalaya.ting.android;osversion=29;fp=009314627x2222q2v644v0500b0000022002000000000000200000000000;device_model=MI+8;XIM=;c-oper=%E6%9C%AA%E7%9F%A5;net-mode=WIFI;freeFlowType=0;res=1080%2C2029;AID=n+Ew49Cv/1Y=;manufacturer=Xiaomi;XD=NSRvWEdehdyqqdzAdbPbJbOfbPFruUAJe3HFBaJ0z438KV7oI/Q/czqtjV2TmpUvQtc0VKk72doYCGDVyUUkqe+kAr9y9XC5FdiYPvv8e66Wf7z4JEulczsJmwNd27g/;umid=0e42f21fc3f4e8704728805785e97255od;xm_grade=0;minorProtectionStatus=0;oaid=5d3cfedc6c1bd5aa;domain=.ximalaya.com;path=/;",
"Cookie2": "$version=1",
"Accept": "*/*",
"user-agent": "ting_9.0.22(MI+8,Android29)",
"x-xuid": "78c5c143-aa52-3f77-b3b6-fb4d0c289c3a",
"Accept-Encoding": "gzip"
}
req = requests.get(get_token_url, headers=get_token_header)
print("fdsOtp响应结果 = ",req.text)
fdsOtp = json.loads(req.text)
fdsOtp = fdsOtp['token']
print("fdsOtp = ", fdsOtp)
return fdsOtp
def sha1_secret_str(s):
"""
:param s: 需要加密的字符串
:return: 做完sha1的结果
"""
sha = hashlib.sha1(s.encode('utf-8'))
encrypts = sha.hexdigest()
return encrypts
def login(account,password,fdsOtp,nonce):
"""
:param account: 用户名
:param password: 密码
:param fdsOtp: fdsOtp
:param nonce: nonce
:return:
"""
post_url = "https://passport.ximalaya.com/mobile/login/pwd/v3"
post_header = {
"Cookie": "1&_device=android&59683601-c043-33af-95d4-413ba0788573&9.0.22;channel=Avril22;impl=com.ximalaya.ting.android;osversion=29;fp=009314627x2222q2v644v0500b0000022002000000000000200000000000;device_model=MI+8;XIM=;c-oper=%E6%9C%AA%E7%9F%A5;net-mode=WIFI;freeFlowType=0;res=1080%2C2029;AID=n+Ew49Cv/1Y=;manufacturer=Xiaomi;XD=NSRvWEdehdyqqdzAdbPbJbOfbPFruUAJe3HFBaJ0z438KV7oI/Q/czqtjV2TmpUvQtc0VKk72doYCGDVyUUkqRWBD1AcqgIlS9o5aEQyWw97unfTMyod0vYnavI0Tm/o;umid=0e42f21fc3f4e8704728805785e97255od;xm_grade=0;minorProtectionStatus=0;oaid=5d3cfedc6c1bd5aa;domain=.ximalaya.com;path=/;",
"Cookie2": "$version=1",
"Accept": "*/*",
"user-agent": "ting_9.0.22(MI+8,Android29)",
"x-xuid": "78c5c143-aa52-3f77-b3b6-fb4d0c289c3a",
"Host": "passport.ximalaya.com",
"Content-Type": "application/json; charset=utf-8",
"Accept-Encoding": "gzip",
"Connection": "Keep-Alive"
}
signature = "ACCOUNT=" + account.upper() + "&FDSOTP=" + fdsOtp + "&NONCE=" + nonce.upper() + "&PASSWORD=" + password.upper() + "&MOBILE-V1-PRODUCT-7D74899B338B4F348E2383970CC09991E8E8D8F2BC744EF0BEE94D76D718C089"
print("signature = ", signature)
print("signature sha1 =", sha1_secret_str(signature.upper()))
signature_sha1 = sha1_secret_str(signature)
post_dict = {
"password": password,
"fdsOtp": fdsOtp,
"signature": signature_sha1,
"nonce": nonce,
"account": account
}
print("Body = ",post_dict)
req = requests.post(post_url, data=json.dumps(post_dict).encode("utf-8"), headers=post_header)
print("登录结果 = ",req.text)
def get_end_username(account):
"""
:param account: 没有组成官方格式的用户名
:return: 按照官方格式组成的加密结果
"""
account_1 = account[:76]
account_2 = account[76:152]
account_3 = account[152:]
print("account = ",account)
# print("account_1 = ",account_1)
# print("account_2 = ",account_2)
# print("account_3 = ",account_3)
return account_1 + "\n" + account_2 + "\n" + account_3
def get_end_password(password):
"""
:param password: 没有组成官方格式的密码
:return: 按照官方格式组成的加密结果
"""
password_1 = password[:76]
password_2 = password[76:152]
password_3 = password[152:]
print("password = ", password)
# print("password_1 = ", password_1)
# print("password_2 = ", password_2)
# print("password_3 = ", password_3)
return password_1 + "\n" + password_2 + "\n" + password_3
public_key = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCVhaR3Or7suUlwHUl2Ly36uVmboZ3+HhovogDjLgRE9CbaUokS2eqGaVFfbxAUxFThNDuXq/fBD+SdUgppmcZrIw4HMMP4AtE2qJJQH/KxPWmbXH7Lv+9CisNtPYOlvWJ/GHRqf9x3TBKjjeJ2CjuVxlPBDX63+Ecil2JR9klVawIDAQAB";
def rsa_encrypt(s):
key = b64decode(public_key)
# print(key)
key = RSA.importKey(key)
cipher = PKCS1_v1_5.new(key)
ciphertext = b64encode(cipher.encrypt(bytes(s, "utf-8")))
return ciphertext
def main(event, context):
# 获取fdsOtp
fdsOtp = get_fdsOtp()
# 获取nonce
nonce = get_nonce()
# 账号密码加密
account = rsa_encrypt("xxxxxx").decode()
password = rsa_encrypt("xxxxxx").decode()
# # 重组account
# account = get_end_username(account)
# # password
# password = get_end_password(password)
# print(account)
# print(password)
# 登录
login(account,password,fdsOtp,nonce)
if __name__ == '__main__':
main('','')
21.png (202.86 KB, 下载次数: 0)
下载附件
2022-7-7 19:38 上传
总体来说呢,花的时间有点长了,还是因为太菜了。很多图也是后来补的,大概的一个思路就是这个样子,可能写的不太好,轻喷。
改了代码,Python不用调用java了,但是我这里登陆出现滑块验证了...token拿不到报错了,不知道是为什么。。。。。