需要完整算法加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

更多推荐