前言
今天有些闲….所以找了一个玩具来玩(❁ᴗ͈ˬᴗ͈)◞
咱对于逆向这方面的经验几乎是0呢…
对于哔咔app也是一边摸索一边来的,途中遇到了一些蛮傻的问题(当然原因在窝自己)
在奈月ちゃん的提示下,发现了问题所在….
代码的反编译
窝直接拉到了jadx里,然后导出成了gradle工程
咱还是蛮喜欢vscode的~~ヽ(✿゚▽゚)ノ
所以全程基本都在vscode里看代码~
导出完成之后,在AndroidManifest.xml
里找到入口,省去不必要的麻烦
对ok.http3的封装
之后定位到了RestClient.java
,作者封装了一个okhttp3的类,用来实现sign的生成。
主要逻辑在第81行
1 | Response proceed = chain.proceed(request.newBuilder() |
其中,RestClient.this.f816tx
、RestClient.version
、RestClient.f812tu
、RestClient.this.f815tw
这四个变量是固定的,可以直接搜索资源文件来找到。
通过对RestClient.java
的builder
进行整理,可以得出bika的http请求头格式。
1 | api-key: C69BAF41DA5ABD1FFEDC6D2FEA56B |
小问题就出现在这里(°ー°〃) 在写完sign的generator之后的测试环节,不管怎么post,服务端都会给窝一个error
Cannot read property 'toLowerCase' of undefined
窝以为是太久没写json,忘记了格式还是怎么样…一直拼命的在修改post数据
后来奈月ちゃん跟窝说:会不会是没加Content-Type的原因….
结果加完之后立刻解决了问题~~~
1 | app-channel: 分流服务器id 1;2;3 |
其中,最重要的就是c
,也就是signature
的生成逻辑,继续跟进到MyApplication.java
这里将传进来的array拼成了一个string变量
str
,窝上来直接主观的认为这个变量是signature的逻辑之一,
结果后来才发现,原来只是作者用来log的一个临时变量( ´•︵•` )
在该函数内,最后的返回是return this.f552hl.mo10943C(stringConFromNative, getStringSigFromNative());
那么,首先要确定getStringConFromNative(strArr)
和getStringSigFromNative()
的逻辑
窝比较喜欢从参数比较少的那一个先入手
在类的开始,进行了这两个函数的声明
1 | public native String getStringComFromNative(); |
而后,是对jni的声明
1 | static { |
那么就直接上手,反编译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
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++的哔咔漫画的接口库,以及对漫画类型的交叉搜索
多谢乃看完~~ 辛苦啦,以后再见。