1.打开libsmsdk.so,找到JNI_函数,导入jni.h文件,找到RegisterNatives函数。
if( v11 == -2109534065) { v20 = v9-> functions-> RegisterNatives( &v9->functions, v34, ( constJNINativeMethod *)off_7283C, 6 ) ; v5 = -1802225456; v10 = 86439211; v11 = -(~(v20 >> 31) | 0x3253F2B3) – 581453431; }
2. off_7283C即为JNI动态注册的函数。
. data.rel.ro: 0007283C off_7283C DCD aZ1 ; DATA XREF: JNI_+ 2F0↑o . data.rel.ro: 0007283C ; JNI_+ 2F6↑o … . data.rel.ro: 0007283C ; “z1” . data.rel.ro: 00072840DCD aLandroidConten ; “(Landroid/content/Context;)Ljava/lang/S”… . data.rel.ro: 00072844DCD sub_3F094+ 1 . data.rel.ro: 00072848DCD aX2 ; “x2” . data.rel.ro: 0007284C DCD aLjavaLangStrin_2 ; “(Ljava/lang/String;Ljava/lang/String;)L”… . data.rel.ro: 00072850DCD sub_3F098+ 1 . data.rel.ro: 00072854DCD aX4 ; “x4” . data.rel.ro: 00072858DCD aLjavaLangStrin_2 ; “(Ljava/lang/String;Ljava/lang/String;)L”… . data.rel.ro: 0007285C DCD sub_3F0A0+ 1 . data.rel.ro: 00072860DCD aX6 ; “x6” . data.rel.ro: 00072864DCD aLjavaLangStrin_2 ; “(Ljava/lang/String;Ljava/lang/String;)L”… . data.rel.ro: 00072868DCD sub_3F524+ 1 . data.rel.ro: 0007286C DCD aZ3 ; “z3” . data.rel.ro: 00072870DCD aLjavaLangStrin_3 ; “(Ljava/lang/String;)I” . data.rel.ro: 00072874DCD sub_3F634+ 1 . data.rel.ro: 00072878DCD aY2_0 ; “y2” . data.rel.ro: 0007287C DCD aZljavaLangStri ; “(ZLjava/lang/String;ZLjava/lang/String;”… . data.rel.ro: 00072880DCD sub_3F7AC+ 1
3. aX2,aX4,aX6,aZ3,aY2_0 的传参和返回值都是jstring类型。初步判断这些是加解密函数。
4. 要分析的协议
{ “data”: { “pri”: “……”, “fingerprint”: “……”, “tn”: “…..”, “sessionId”: “……”, “fpEncode”: xx }, “encrypt”: 1, “organization”: “……”, “channel”: “……” }
5. 使用 Frida hook java.net.SocketOutputStream.socketWrite函数,并打印调用栈
atjava.net.SocketOutputStream.write(SocketOutputStream.java:153) atcom.android.okhttp.okio.Okio$1.write(Okio.java:76) atcom.android.okhttp.okio.AsyncTimeout$1.write(AsyncTimeout.java:155) atcom.android.okhttp.okio.RealBufferedSink.emitCompleteSegments(RealBufferedSink.java:176) atcom.android.okhttp.okio.RealBufferedSink.write(RealBufferedSink.java:46) atcom.android.okhttp.internal.http.Http1xStream$FixedLengthSink.write(Http1xStream.java:288) atcom.android.okhttp.okio.RealBufferedSink.emitCompleteSegments(RealBufferedSink.java:176) atcom.android.okhttp.okio.RealBufferedSink$1.write(RealBufferedSink.java:198) atjava.io.OutputStream.write(OutputStream.java:75) atcom.ishumei.O000O0000O0oO.O000O00000OoO.a(Unknown Source:245) atcom.ishumei.O000O0000O0oO.O000O00000OoO.a(Unknown Source:119) atcom.ishumei.O0000O000000oO.O000O0000OoO$O0000O000000oO$1.run(Unknown Source:94) atandroid.os.Handler.handleCallback(Handler.java:790) atandroid.os.Handler.dispatchMessage(Handler.java:99) atandroid.os.Looper.loop(Looper.java:164) atandroid.os.HandlerThread.run(HandlerThread.java:65)
6. 根据调用栈找到对应函数
publicstaticStringa( booleanz, Stringstr, booleanz2, Stringstr2) { try{ returnnewSMSDK.y2(z, str, z2, str2); } catch(Throwable th) { thrownewIOException(th); } }
7. 打开IDA定位到y2 函数
8. 进入sub_19188 函数
整个函数用了混淆,但影响不大,抓住关键点就行。
9. 从返回值开始入手,返回值是jstring类型的指针
根据v340,查找引用定位到此处
好家伙,s即为加密结果的字符串指针。继续查找s引用
继续查找v190的引用
10. 分别在上图的sub_6188处打上断点。IDA动态调试确认一下。发现在,v29 = sub_6188(v403, v28, 0)断下
执行前R0的值为
执行后R0的值为
可以确定此函数为加密算法了。
11. 跟进此函数,查找a1的引用,定位到此处
sub_3549C函数传入指针s,计算的结果在指针v54中,然后再传入sub_504c。
12. 继续跟进sub_504C,查找a2的引用
定位到此处
根据传参猜测为魔改AES加密。跟进sub_386B0函数确认一下,猜测此函数为扩展密钥函数,看看是否调用了sbox数组,进入子函数
可以确定次函数为AES加密算法了。
13. IDA动态调试抠出算法代码,测试运行,传入参数
结果:
进行base64位加密
与原结果进行比较
大功告成!
看雪ID:Mr.YX
声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!