对哔咔漫画的逆向以及接口sign的C++实现(一)

前言

今天有些闲….所以找了一个玩具来玩(❁ᴗ͈ˬᴗ͈)◞
咱对于逆向这方面的经验几乎是0呢…
对于哔咔app也是一边摸索一边来的,途中遇到了一些蛮傻的问题(当然原因在窝自己)
奈月ちゃん的提示下,发现了问题所在….

代码的反编译

窝直接拉到了jadx里,然后导出成了gradle工程
咱还是蛮喜欢vscode的~~ヽ(✿゚▽゚)ノ
所以全程基本都在vscode里看代码~

导出完成之后,在AndroidManifest.xml里找到入口,省去不必要的麻烦

对ok.http3的封装

之后定位到了RestClient.java,作者封装了一个okhttp3的类,用来实现sign的生成。

主要逻辑在第81行

1
2
3
4
5
6
7
8
9
10
11
12
Response proceed = chain.proceed(request.newBuilder()
.header("api-key", "C69BAF41DA5ABD1FFEDC6D2FEA56B")
.header("accept", "application/vnd.picacomic.com.v1+json")
.header("app-channel", RestClient.this.f816tx + "")
.header("time", str)
.header("nonce", replace)
.header("signature", c)
.header("app-version", RestClient.version)
.header("app-uuid", RestClient.f812tu)
.header("image-quality", RestClient.this.f815tw)
.header("app-platform", "android")
.header("app-build-version", RestClient.f813tv).method(request.method(), request.body()).build());

其中,RestClient.this.f816tx RestClient.version
RestClient.f812tuRestClient.this.f815tw这四个变量是固定的,可以直接搜索资源文件来找到。

通过对RestClient.javabuilder进行整理,可以得出bika的http请求头格式。

1
2
3
4
5
6
7
8
9
10
11
12
13
api-key: C69BAF41DA5ABD1FFEDC6D2FEA56B
accept: application/vnd.picacomic.com.v1+json
app-channel: 1
time: `str`
nonce: 52931cf1335c4b689b615e1d7dec24e9
signature: `c`
app-version: 2.2.1.3.3.4
app-uuid: defaultUuid
image-quality: original
app-platform: android
app-build-version: 45
User-Agent: okhttp/3.8.1
Content-Type: application/json;charset=UTF-8

小问题就出现在这里(°ー°〃) 在写完sign的generator之后的测试环节,不管怎么post,服务端都会给窝一个error
Cannot read property 'toLowerCase' of undefined
窝以为是太久没写json,忘记了格式还是怎么样…一直拼命的在修改post数据
后来奈月ちゃん跟窝说:会不会是没加Content-Type的原因….
结果加完之后立刻解决了问题~~~

1
2
3
4
5
6
7
8
app-channel: 分流服务器id 1;2;3
time: ((System.currentTimeMillis() / 1000) + Long.parseLong(Server-Time) - (System.currentTimeMillis() / 1000);
即用时间戳/1000 加上之前测定的与服务器时间的差值
image-quality:
original,low,medium,high
nonce: 随机32位字符串(UUID去掉- ,可能是作者懒得写一个生成器?///•A•///)
c:
new String[]{"https://picaapi.picacomic.com/", replace2, str, replace, request.method(), "C69BAF41DA5ABD1FFEDC6D2FEA56B", RestClient.version, RestClient.f813tv}

其中,最重要的就是c,也就是signature的生成逻辑,继续跟进到MyApplication.java

这里将传进来的array拼成了一个string变量str,窝上来直接主观的认为这个变量是signature的逻辑之一,
结果后来才发现,原来只是作者用来log的一个临时变量( ´•︵•` )

在该函数内,最后的返回是
return this.f552hl.mo10943C(stringConFromNative, getStringSigFromNative());
那么,首先要确定getStringConFromNative(strArr)getStringSigFromNative()的逻辑
窝比较喜欢从参数比较少的那一个先入手
在类的开始,进行了这两个函数的声明

1
2
3
public native String getStringComFromNative();
public native String getStringConFromNative(String[] strArr);
public native String getStringSigFromNative();

而后,是对jni的声明

1
2
3
static {
System.loadLibrary("JniTest");
}

那么就直接上手,反编译JniTest.so,来看看这两个函数的实现吧

在liunx上装idapro费了窝好大的力气….最后实在没力气,就用crossover跑了个虚拟机(笑)
还蛮好用的

getStringSigFromNative()的反编译

其实还蛮明显的,将~*}$#,$-").=$)",,#/-.'%(;$[,|@/&(#"~%*!-?*"-:*!!*,$"%.&'*|%/*,*放到dest里,然后按位置替换
不过用反编译的代码其实不是太舒适
还是要看一下汇编

非常直观呢~~~
窝把这部分的mov指令都copy到了编辑器里,然后文本处理了一下,把每个mov都变成了一个pair<char,char>

然后按位置给替换一下就可以了,不过这里有两个小问题
窝在debug的时候,发现有数组越界的问题,之后发现dest有一个0x8的偏移量,
所以在进行替换的时候,应该将位置减去0x8

另外一个呢,是需要注意,其中有一些dword,在处理的时候要按照入栈的顺序来,所以在处理时,窝直接倒序迭代,模拟入栈顺序。

之后就可以得到getStringSigFromNative的值
~d}$Q7$eIni=V)9\RK/P.RM4;9[7|@/CA}b~OW!3?EV`:<>M7pddUBL5n|0/*Cn

getStringConFromNative(String[] strArr)的反编译

结构还是蛮简单的,但是上面的指针就不太友好啦~,因为指针*a1是jni传来的jvm地址,所以在静态分析的时候是没办法知道调用的是什么函数的。

是吗?

(o゚ω゚o)偶然在查资料的时候,发现了一个宝藏repo

jnianalyzer

A simple tool to help finding JNI calls in a x86/ARM disassembly listing.

这是一个用来寻找JNI函数偏移的小程序
简直是太棒啦~~~

直接将jni的文件dump过去

将偏移量转为16进制,然后批量替换一下下~

现在就好看多啦~( *︾▽︾)

很直观的看到,getStringConFromNative函数就是拼接…
不过拼接的逻辑和GenKey10有关系,不过这里窝直接默认他为true,错了的话再回来改一下,
无非就是两种结果_( ‘-‘ )⌒)

对GenerateSignature的分析

接下来就跟进到mo10943C

可以看到,这里将str2,也就是getStringSigFromNative的值,转化为了一个Byte[]
然后传入到了mo10944a(String str, byte[] bArr)
mo10944a就特别的明显啦~
是一个HMAC-HASH256的哈希函数
getStringSigFromNative作为key
加密转化为小写的getStringConFromNative
之后结果在通过m1388a函数后返回。

m1388a的逻辑特别简单,窝直接改成了c++。

最后进行一下测试

完美( ´・ω・)ノ(._.`)
不过这里有一些注意事项

nonce需要进行变化,不然会告诉你 Too many requests,应该是防止Intruder的
(然鹅并没有什么用)
time直接使用服务端的time就可以啦~~ 如果差比较多会直接bad request

下一步的玩具

C++的哔咔漫画的接口库,以及对漫画类型的交叉搜索

多谢乃看完~~ 辛苦啦,以后再见。

Link

picacomic-cpp

文章作者: 米澤 由香里
文章链接: https://0w0.live/2022/05/01/对哔咔漫画的逆向以及接口sign的C-实现(一)/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 私は米沢ユカリニャー