起点读书QDSign QDInfo signature算法分析
需要完整算法加QQ:848416881
会持续更新
源代码下载链接:https://github.com/lavender1203/QDreaderApp
Apktool 反编译加 回编译后 启动app死在splash界面进不去登录界面。
动态调试下:
1.Manifest.xml 文件加入<application android:debuggable=“true” …>
编译出来有5个dex,mutidex被禁止。。。。sdk24之后建议打包成一个dex
invoke-static {p0}, La/b;->c(Landroid/content/Context;)V #加载load-jni库 —然后dead。。。。。
加载了一个so文件然后AndroidStudio+smali调试死掉,找到libload-jni.so文件,IDA来干它
1.adb shell am start -D com.qidian.QDReader/.ui.activity.SplashActivity
2.启动调试服务,进行端口转发
./data/local/tmp/android_server
adb forward tcp:23946 tcp:23946
3.附加so或进程,在执行函数打断点。
4.使用jdb连接apk的java层(需要关闭Android selinux)
HWFRD:/ # getenforce
Enforcing
HWFRD:/ # setenforce 0
HWFRD:/ # getenforce
Permissive
adb forward tcp:8000 jdwp:pid
jdb -connect com.sun.jdi.SocketAttach:hostname=127.0.0.1,port=8000
F1085218+11CC= F10863E4
6000 – 6E64数据丢失
adb shell dumpsys activity activities 查看当前活动activity
-签名验证(已破解)—
com.qidian.QDReader.ui.activity;->QDLoginActivity->loginByPassWord()->
this.mPresenter.a(str1, str2); #str1= nickname str2 = password
登录所需参数:
首次登录:
auth_request+username+passwd 获取 id_token
以后登录:
Request + id_token
Filtter抓包:
参考文章地址:https://bbs.125.la/thread-14053235-1-1.html
账号=xf71320 密码=1212aaq
POST https://ptlogin.qidian.com/sdk/staticlogin HTTP/1.1
referer: http://android.qidian.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 619
Host: ptlogin.qidian.com
Connection: Keep-Alive
Accept-Encoding: gzip
User-Agent: okhttp/3.9.1
password=1212aaq&devicename=Honor%208&loginType=23&source=1000031&signature=JAtW2i9cmk06eSFBn6G4%2BusAXP8s%2FVUwg0vj7bSPrWqmQxtEUjU0%2B6Pab5hc%20d2MC&appid=12&referer=http%3A%2F%2Fandroid.qidian.com&auto=1&ticket=0&devicetype=Huawei_FRD-AL00&qimei=43757bd7111bb806&code=%40VMH&format=json&osversion=Android7.0_7.8.5_380&username=xf71320&imei=862679037204730&sdkversion=121&autotime=30&version=380&returnurl=http%3A%2F%2Fwww.qidian.com&areaid=30&sessionkey=sig8e31c8ac7e094b07940328a27d6b4af6&sig=t02EMF-zI53IY3TSY8cAhFDg4qgXt2fIwtFn2BNeklrPD7pUYRDtojQy8_0g9_F2u2eIZUgR16hx1HTkXgnr8f6u3ckZCzw4lvt-xt0LOZ3ntseY2kzXpNmlA**
Response:
HTTP/1.1 200 OK
Server: nginx
Date: Sun, 24 Mar 2019 08:27:09 GMT
Content-Type: text/html
Content-Length: 479
Connection: keep-alive
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
P3p: CP=CAO PSA OUR
{“code”:0,“data”:{“appId”:12,“areaId”:30,“ywGuid”:0,“ticket”:"",“autoLoginSessionKey”:"",“autoLoginKeepTime”:0,“ywKey”:"",“nextAction”:11,“contextId”:“sigea0ad4936ab84cdb91b03e4243c49b53”,“imgSrc”:“https://ssl.captcha.qq.com/TCaptcha.js”,“deviceType”:"",“challenge”:"",“deviceDisplaytype”:"",“inputUserId”:"",“loginType”:1,“autoLoginFlag”:1,“isRiskAccount”:false,“ywOpenId”:"",“sessionKey”:“sigea0ad4936ab84cdb91b03e4243c49b53”,“autoLoginExpiredTime”:1553416029},“message”:""}
以上为登录抓到的数据,我们发现账号和密码都没有加密 但是有一个signature 这个是变化的 加密的 找到了加密参数我们就开始分析APP
调试app获取这些参数:
Jeb分析signature怎么计算出来的?
ywlogin下搜索signature c/d.f()函数
加密方式 由两部分组成:Java层和so层
Java层好办直接copy, so层函数需要写成python或java代码
public class d {
private static final char[] a;
static {
d.a = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".toCharArray();
}
public static String a(byte[] arg9) {
int v4 = arg9.length;
StringBuilder v5 = new StringBuilder(arg9.length * 3 / 2);
int v6 = v4 - 3;
int v2 = 0;
int v0;
for(v0 = 0; v0 <= v6; v0 = v3) {
int v3 = (arg9[v0] & 255) << 16 | (arg9[v0 + 1] & 255) << 8 | arg9[v0 + 2] & 255;
v5.append(d.a[v3 >> 18 & 63]);
v5.append(d.a[v3 >> 12 & 63]);
v5.append(d.a[v3 >> 6 & 63]);
v5.append(d.a[v3 & 63]);
v3 = v0 + 3;
v0 = v2 + 1;
if(v2 >= 14) {
v5.append(" ");
v0 = 0;
}
v2 = v0;
}
if(v0 == -2 + v4) {
v0 = (arg9[v0 + 1] & 255) << 8 | (arg9[v0] & 255) << 16;
v5.append(d.a[v0 >> 18 & 63]);
v5.append(d.a[v0 >> 12 & 63]);
v5.append(d.a[v0 >> 6 & 63]);
v5.append("=");
}
else if(v0 == -1 + v4) {
v0 = (arg9[v0] & 255) << 16;
v5.append(d.a[v0 >> 18 & 63]);
v5.append(d.a[v0 >> 12 & 63]);
v5.append("==");
}
return v5.toString();
}
}
c函数在so层,libd-lib.so
由于so层函数是和硬件相关的,所以要用python将其重写
从java层传进来的参数arg1,变成了R0=EDF23A10,R1=E23FB300这是个地址,(g)去查看下,发现arg1存放的地方就在R1寄存器这块内存,那么R0是干嘛的呢?然后继续调用了
sub_83C(v1, (int)v3)这个函数,实际上调用sub_96C((char *)a2, &v6)
int __fastcall sub_83C(int a1, int a2)
{
int v2; // r4
int v3; // ST10_4
int v4; // r5
int result; // r0
int v6; // [sp+10h] [bp-14h]
int v7; // [sp+14h] [bp-10h]
v2 = a1;
v3 = sub_96C((char )a2, &v6);
v4 = ((int (__fastcall **)(int, int))((_DWORD )v2 + 704))(v2, v6);
((void (__fastcall **)(int, int, _DWORD, int, int))((_DWORD *)v2 + 832))(v2, v4, 0, v6, v3);
result = _stack_chk_guard - v7;
if ( _stack_chk_guard == v7 )
result = v4;
return result;
}
int __fastcall Java_a_d_c(int a1)
{
int v1; // r5
int v2; // r4
void *v3; // r6
v1 = a1;
v2 = 0;
if ( a1 )
{
v3 = (void )((int (**)(void))(*(_DWORD *)a1 + 676))();
v2 = sub_83C(v1, (int)v3);
if ( v3 )
free(v3);
}
return v2;
}
void DES_ede3_cbc_encrypt(const unsigned char *input,unsigned char *output,
long length,
DES_key_schedule *ks1,DES_key_schedule *ks2,
DES_key_schedule *ks3,DES_cblock *ivec,int enc);
Key1=sewxf03h
Key2=hz3ew9qc
Key3=CXMHiDMK
Ivec =0
Frida hook: key 和ivec
adb push /data/local/tmp frida-server
root# chmod 777 /data/local/tmp/frida-server
Root#data/local/tmp/frida-server
adb forward tcp:27042 tcp:27042
Com/yuewen/Ywlogin/d/b/a 验证码
QDSign:
signParams( context, postParams, timestamp, userToken, deviceID, v5, arg9, arg10)
postParams: r=ODYyNjc5MDM3MjA0NzMwfDAuMHwwLjB8Ny44LjV8MTA4MHwxNzk0fDEwMDAwMzF8Ny4wfDF8RlJELUFMMDB8ZjQ2OTE0Yzc0MmYxOTM1OTQ4NzZhODMxMTFjZmI4ZjRmYzBlNWJlZnwwMjowMDowMDowMDowMDowMHxudWxsfDAwMDAwMDAwMDAwMDAwMDB8NC4xLjE4LWdmNjQwMmQwNy4wRlJELUFMMDBOUkQ5ME0gdGVzdC1rZXlzfDQzNzU3YmQ3MTExYmI4MDZ8MXw0Mzc1N2JkNzExMWJiODA2
第一步:
Md5(postParams) = a8d97ea8ae07d8a99e253787a2be6b40
更多推荐


所有评论(0)