App: fenghuangxinwen
需求: 输入phone_number, 提示是否注册
WX20210819-154225@2x.png
抓包看看,
params里有一个sn(明显是md5), data 里的secure_params和encrypt_key一直变,
WX20210819-152046@2x.png
WX20210819-152353@2x.png
jadx打开发现加固了, 先脱壳
WX20210819-163618.png(Git哈卜搜索frida_dump), 脱完的在手机里, 压缩然后pull到电脑上, 解压......(我有篇文章写脱壳的, 马上写...)
先整体hook, 开启抓包看下:
[图片上传中...(WX20210819-153322@2x.png-729728-1629359095789-0)]找到了, hook, cen.b()
WX20210819-153322@2x.png
结果一样, 是该字符串md5加密结果, 变量是时间戳(params里的st)
st='16293583224531'
str_=f'7.30.0ifengnews2607041332a0adc5f974{st}acF%#*{_b1mQt@..ifvy'
再看data里的参数, jadx 全局搜索参数名, 结果不多, 还是比较容易的:
WX20210819-153713@2x.png WX20210819-153910.png
定位到这里, 很明显可以看到a3,a2就是我们要的结果,
先看a3, secure_params
是cef.a()的结果, hook一下看看:
WX20210819-154055@2x.png
可以看到我们输入的phone和密码, 而且结果和抓包一样, 那我们看看cef.a(),jadx 搜索cef 定位到这里:
WX20210819-155831.png
还有个sign, 看出是md5,但又不是最开始的sn,
WX20210819-160514.png
hook cen.e()看看:
WX20210819-160815@2x.png
变量只有phone 和密码, 然后hook cef构造方法看str, str2是啥:
WX20210819-160120.png
str, str2是一样的, 用python实现DES:
# es模式 填充方式 ECB加密方式
from pyDes import *
def get_md5(_str):
md5 = hashlib.md5()
md5.update(_str.encode('utf_8'))
str_arg = md5.hexdigest()
return str_arg
def des(phone,password,Des_Key,Des_IV):
md5_str=f'account={phone}&deviceid=041332a0adc5f974&gv=9&os=android_28&password={password}&proid=ifengnews54LtlE45%$V9Xcx@'
sign=get_md5(md5_str)
text=f'account={phone}&deviceid=041332a0adc5f974&gv=9&os=android_28&password={password}&proid=ifengnews&sign={sign}'
k = des(Des_Key, CBC, Des_IV, padmode=PAD_PKCS5)
secure_params=base64.b64encode(k.encrypt(text))
return secure_params
再看encrypt_key
WX20210819-161726.png代码里不是很清楚, 不过从上面的步骤看, cep很可疑, 去看看:
WX20210819-161940.png
先看看加密的串:
WX20210819-162138@2x.png
就是这里了, 参数是一个长度8的str, 而com.ifeng.news2.usercenter.utils.UserSecureParam.a() 190行(结尾的地方) 恰好有一行:
WX20210819-162335.png
还有cef.a(int i)这个生成str函数, 也就是说, 服务器通过解析encrypt_key得出这个8位str , 然后通过8位str 解析secure_params里的phone和password, 然后验证是否注册及账密是否正确 , 而随机8位str 有重复的可能, 所以不用改也行, 代码里写死就行, 实现RSA之前先解决public_key,hook cep.a():
WX20210819-162835@2x.png
python实现RSA:
# 公钥形式
# public_key = '''-----BEGIN PUBLIC KEY-----
# MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvEvISr3NNYWXI/6kkmoX
# qdtmRe7nN5qAs7Fs3ZmujiIH+Z4GaIO7xQOrVxM5FsH5Kdlx4E/AN7MTZexjOlSt
# 8jPBmuRSirUhHhbG6GdUmG5cOTRZIbP/FpJSFbSayf5XHsrKqKQWALy7akl/kYb5
# 8v39Q6vSEw6PRofYJT2rZMQR7FCDFwWkR4QzBLm1kgre9kxdrPWtrOy6IoyNfff7
# 8wnChQ8wRNk9WmIyEr1AqsOxyIPJO63t/3saRBX+CHIxcLWOe22dAbXAeeaSTOuN
# EnUPzWx3W7EFKJMliorkeZMfMMzKSaK06HgR74dyXA4NhUZJMwsgEDku2xcvgXvW
# nQIDAQAB
# -----END PUBLIC KEY-----'''
def pub_key(key):
start = '-----BEGIN PUBLIC KEY-----\n'
end = '-----END PUBLIC KEY-----'
result = ''
# 分割key,每64位长度换一行
divide = int(len(key) / 64)
divide = divide if (divide > 0) else divide + 1
line = divide if (len(key) % 64 == 0) else divide + 1
for i in range(line):
result += key[i * 64:(i + 1) * 64] + '\n'
result = start + result + end
return result
def rsa_encrypt(message):
"""校验RSA加密 使用公钥进行加密"""
cipher = Cipher_pkcs1_v1_5.new(RSA.importKey(public_key))
cipher_text = base64.b64encode(cipher.encrypt(message.encode())).decode()
return cipher_text
public_key = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvEvISr3NNYWXI/6kkmoXqdtmRe7nN5qAs7Fs3ZmujiIH+Z4GaIO7xQOrVxM5FsH5Kdlx4E/AN7MTZexjOlSt8jPBmuRSirUhHhbG6GdUmG5cOTRZIbP/FpJSFbSayf5XHsrKqKQWALy7akl/kYb58v39Q6vSEw6PRofYJT2rZMQR7FCDFwWkR4QzBLm1kgre9kxdrPWtrOy6IoyNfff78wnChQ8wRNk9WmIyEr1AqsOxyIPJO63t/3saRBX+CHIxcLWOe22dAbXAeeaSTOuNEnUPzWx3W7EFKJMliorkeZMfMMzKSaK06HgR74dyXA4NhUZJMwsgEDku2xcvgXvWnQIDAQAB"
public_key = pub_key(public_key)
param = get_param(message, public_key)
网友评论