android逆向奇技淫巧九:frida常见java层的加密/hash算法自吐
逆向分析X东时,遇到了狠角色,通过fidderl抓包如下:登陆的包和返回包的body全都不是明文!这是我分析了这么多app以来头一次遇到这种情况!
以前抓包分析,遇到最多的情况就是某些字段加密,x东时我遇到第一个数据包的body都加密的app;以前可以根据字段名称在java层或so层查找加密的方法,这次body的字段都加密了,字段名称都不知道,怎么找?
有同学就会说了:既然加密了,先解密呗! 没错,思路是这样的,但是加密算法是啥呀? 密钥又是啥了? 这些都不知道,怎么解密?
可能又有同学会说:那就静态分析呗,肯定能找到加密的方法和密钥!理论上是这样的,但x东怎么说也是大厂,技术实例杠杠滴,(1)代码都做过了很严重的混淆,静态分析有那么容易?如果静态分析很容易了,还要动态调试干嘛了? (2)参考之前tls1.3的分析,这里双方对称加密的密钥有可能是动态协商出来的,并不是在客户端内置写死的,静态分析没任何用!这里又要用到frida了!
先说说加解密算法:常见的加解密/hash算法,都是顶级数学家发明的!哪怕就是顶尖的码农,他也是码农,要想设计安全的加密算法是不现实的,所以互联网公司的码农知道各种加密算法的适用场景已经很不错了,绝对不会有设计加密算法的实力!具体到工程实现,肯定是调用现有的API来加解密,突破口就在这里了!但是在x东这里逆向,我也不知道登陆时用了那种加密算法,只能广撒网了:把所有已知的加密算法都hook,看看到底是哪些被调用了,以及传入的参数都是啥!下面是frida的js代码:
Java.perform(function() { //Base64 var base64=Java.use('android.util.Base64'); var string=Java.use('java.lang.String'); /*base64.encode.overload('[B', 'int', 'int', 'int').implementation = function(){ send("=================base64 encode===================="); send(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new())); send(arguments[0]); send(arguments[1]); send(arguments[2]); send(arguments[3]); var data=this.encode(arguments[0],arguments[1],arguments[2],arguments[3]) send("base64:"+string.$new(data)); return data; }*/ /*base64.decode.overload('[B', 'int', 'int', 'int').implementation = function(){ send("=================base64 decode===================="); send(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new())); send(arguments[0]); send(arguments[1]); send(arguments[2]); send(arguments[3]); var data=this.decode(arguments[0],arguments[1],arguments[2],arguments[3]) send("base64:"+string.$new(data)); return data; }*/ // MD SHA var messageDigest=Java.use('java.security.MessageDigest'); // update for(var i = 0; i < messageDigest.update.overloads.length; i++){ messageDigest.update.overloads[i].implementation = function(){ var name=this.getAlgorithm() send("================="+name+"===================="); send(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new())); if(arguments.length == 1){ send(arguments[0]); this.update(arguments[0]); }else if(arguments.length == 3){ send(arguments[0]); send(arguments[1]); send(arguments[2]); this.update(arguments[0],arguments[1],arguments[2]); } } } // digest for(var i = 0; i < messageDigest.digest.overloads.length; i++){ messageDigest.digest.overloads[i].implementation = function(){ var name=this.getAlgorithm() send("================="+name+"===================="); send(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new())); if(arguments.length == 0){ var data=this.digest(); send(data); return data; }else if(arguments.length == 1){ send(arguments[0]); var data=this.digest(arguments[0]); send(data); return data; }else if(arguments.length == 3){ send(arguments[0]); send(arguments[1]); send(arguments[2]); var data=this.digest(arguments[0],arguments[1],arguments[2]); send(data); return data; } } } //MAC var mac=Java.use('javax.crypto.Mac'); for(var i = 0; i < mac.doFinal.overloads.length; i++){ mac.doFinal.overloads[i].implementation = function(){ var name=this.getAlgorithm() send("================="+name+"===================="); send(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new())); if(arguments.length == 0){ var data=this.doFinal(); send(data); return data; }else if(arguments.length == 1){ send(arguments[0]); var data=this.doFinal(arguments[0]); send(data); return data; }else if(arguments.length == 2){ send(arguments[0]); send(arguments[1]); var data=this.doFinal(arguments[0],arguments[1]); send(data); return data; } } } // DES DESede AES PBE RSA var cipher=Java.use('javax.crypto.Cipher'); for(var i = 0; i < cipher.doFinal.overloads.length; i++){ cipher.doFinal.overloads[i].implementation = function(){ var name=this.getAlgorithm() send("================="+name+"===================="); send(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new())); if(arguments.length == 0){ var data=this.doFinal(); send(data); return data; }else if(arguments.length == 1){ send(arguments[0]); var data=this.doFinal(arguments[0]); send(data); return data; }else if(arguments.length == 2){ send(arguments[0]); send(arguments[1]); var data=this.doFinal(arguments[0],arguments[1]); send(data); return data; }else if(arguments.length == 3){ send(arguments[0]); send(arguments[1]); send(arguments[2]); var data=this.doFinal(arguments[0],arguments[1],arguments[2]); send(data); return data; }else if(arguments.length == 5){ send(arguments[0]); send(arguments[1]); send(arguments[2]); send(arguments[3]); send(arguments[4]); var data=this.doFinal(arguments[0],arguments[1],arguments[2],arguments[3],arguments[4]); send(data); return data; }else{ send(arguments[0]); send(arguments[1]); send(arguments[2]); send(arguments[3]); var data=this.doFinal(arguments[0],arguments[1],arguments[2],arguments[3]); send(data); return data; } } } //KEY var secretKey=Java.use('javax.crypto.spec.SecretKeySpec'); for(var i = 0; i < secretKey.$init.overloads.length; i++){ secretKey.$init.overloads[i].implementation = function(){ var name=this.getAlgorithm() send("=================KEY===================="); //send(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new())); if(arguments.length == 2){ send(arguments[0]); send(arguments[1]); this.$init(arguments[0],arguments[1]); }else if(arguments.length == 4){ send(arguments[0]); send(arguments[1]); send(arguments[2]); send(arguments[3]); this.$init(arguments[0],arguments[1],arguments[2],arguments[3]); } } } //IV //DES KEY //DESede KEY //PBE KEY salt });
如上所示:其实就是把java层所有涉及编码、加解密、hash的函数都hook,看看传参、函数的调用栈等!用这个脚本去hook x东登陆时的加密算法调用,打印的日志如下:
(1)我输入的密码是123456,这里明显在用md5转化:jd.wjlogin_sdk.util.MD5.encrypt32 这个方法可以重点研究下(比如用objection hook一下,看看参数都是啥)!
[*] =================MD5==================== [*] java.lang.Throwable at java.security.MessageDigest.digest(Native Method) at jd.wjlogin_sdk.util.MD5.encrypt32(Proguard:36) at com.jd.lib.login.unit.a.b.f(AccountFragment.java:605) at com.jd.lib.login.unit.a.b.onClick(AccountFragment.java:8346) at android.view.View.performClick(View.java:5637) at android.view.View$PerformClick.run(View.java:22429) at android.os.Handler.handleCallback(Handler.java:751) at android.os.Handler.dispatchMessage(Handler.java:95) at android.os.Looper.loop(Looper.java:154) at android.app.ActivityThread.main(ActivityThread.java:6153) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:892) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:782) [*] [49, 50, 51, 52, 53, 54]
(2)这里还用SHA1,不知道在干嘛,所以com.jd.sec.utils.LoadDoor.getToken、jd.wjlogin_sdk.common.a.b.j值得好好研究!
[*] =================SHA1==================== [*] java.lang.Throwable at java.security.MessageDigest.digest(Native Method) at com.jd.sec.utils.LoadDoor.getToken(Native Method) at com.jd.sec.utils.LoadDoor.a(LoadDoor.java:69) at com.jd.sec.logo.TokenManager.getToken(TokenManager.java:13) at com.jingdong.common.login.LoginUserBase.getDeviceJson(LoginUserBase.java:288) at com.jingdong.common.utils.gf.getDeviceFinger(UserUtil.java:220) at jd.wjlogin_sdk.common.a.b.j(Proguard:1000) at jd.wjlogin_sdk.common.a.a.b(Proguard:25) at jd.wjlogin_sdk.c.d.a(Proguard:708) at jd.wjlogin_sdk.common.inland.WJLoginInland.getCaptchaSid(Proguard:2848) at com.jd.lib.login.unit.a.n.a(AccountPresenter.java:108) at com.jd.lib.login.unit.a.b.onClick(AccountFragment.java:8346) at android.view.View.performClick(View.java:5637) at android.view.View$PerformClick.run(View.java:22429) at android.os.Handler.handleCallback(Handler.java:751) at android.os.Handler.dispatchMessage(Handler.java:95) at android.os.Looper.loop(Looper.java:154) at android.app.ActivityThread.main(ActivityThread.java:6153) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:892) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:782) [*] [101, 105, 100, 65, 48, 56, 52, 48, 56, 49, 50, 51, 51, 97, 115, 57, 80, 68, 121, 115, 57, 56, 112, 79, 83, 66, 79, 79, 118, 83, 76, 65, 107, 47, 117, 102, 118, 122, 119, 56, 114, 110, 71, 75, 121, 99, 86, 102, 47, 55, 55, 109, 85, 87, 88, 114, 98, 54, 112, 111, 78, 80, 66, 81, 121, 113, 119, 102, 72, 68, 82, 52, 113, 73, 53, 68, 84, 100, 111, 57, 109, 82, 56, 75, 85, 120, 73, 83, 87, 56, 98, 73, 105, 111, 79, 48, 107, 76, 83, 106, 103, 70, 72, 70, 102, 86, 110, 73, 106, 100, 101, 113, 111, 106, 77, 122, 50, 48, 50, 49, 54, 53, 49, 49, 52, 54, 51, 54, 57, 57, 50, 52, 56, 50, 97, 38, 48, 33, 91, 42, 55, 81, 49, 86]
(3)这里用上key了,还用HMAC的散列:目的是为了防止加密数据被删改!
[*] =================KEY==================== [*] [51, 52, 54, 54, 57, 99, 54, 54, 97, 101, 56, 51, 52, 53, 55, 97, 57, 97, 56, 101, 55, 98, 52, 100, 48, 52, 49, 55, 102, 48, 50, 102] [*] HmacSHA256 [*] =================HmacSHA256==================== [*] java.lang.Throwable at javax.crypto.Mac.doFinal(Native Method) at com.jingdong.sdk.jdhttpdns.core.SignatureHelper.HMACSHA256(SignatureHelper.java:90) at com.jingdong.sdk.jdhttpdns.core.SignatureHelper.signature(SignatureHelper.java:62) at com.jingdong.sdk.jdhttpdns.core.ParamHelper.getDnsQueryStr(ParamHelper.java:54) at com.jingdong.sdk.jdhttpdns.core.Request.getUrl(Request.java:137) at com.jingdong.sdk.jdhttpdns.core.NetworkHandler.performRequest(NetworkHandler.java:75) at com.jingdong.sdk.jdhttpdns.core.NetworkHandler.requests(NetworkHandler.java:46) at com.jingdong.sdk.jdhttpdns.core.WorkRunnable.run(WorkRunnable.java:39) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:428) at java.util.concurrent.FutureTask.run(FutureTask.java:237) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607) at java.lang.Thread.run(Thread.java:761) [*] [106, 100, 109, 111, 98, 105, 108, 101, 38, 119, 108, 109, 111, 110, 105, 116, 111, 114, 46, 109, 46, 106, 100, 46, 99, 111, 109, 38, 119, 105, 102, 105, 38, 97, 110, 100, 114, 111, 105, 100, 38, 49, 54, 50, 50, 56, 54, 52, 55, 57, 55, 51, 51, 54, 38, 98, 56, 51, 101, 99, 54, 97, 54, 55, 53, 97, 100, 98, 97, 54, 97, 38, 57, 46, 53, 46, 52, 95, 56, 56, 49, 51, 54]
(4)这里貌似找到了关键函数:jd.wjlogin_sdk.common.inland.WJLoginInland.JDLoginWithPasswordNew
[*] =================SHA1==================== [*] java.lang.Throwable at java.security.MessageDigest.digest(Native Method) at java.security.MessageDigest.digest(MessageDigest.java:426) at java.security.MessageDigest.digest(Native Method) at com.jd.sec.utils.LoadDoor.getToken(Native Method) at com.jd.sec.utils.LoadDoor.a(LoadDoor.java:69) at com.jd.sec.logo.TokenManager.getToken(TokenManager.java:13) at com.jingdong.common.login.LoginUserBase.getDeviceJson(LoginUserBase.java:288) at com.jingdong.common.utils.gf.getDeviceFinger(UserUtil.java:220) at jd.wjlogin_sdk.common.a.b.j(Proguard:1000) at jd.wjlogin_sdk.common.a.a.b(Proguard:25) at jd.wjlogin_sdk.c.d.a(Proguard:708) at jd.wjlogin_sdk.common.inland.WJLoginInland.JDLoginWithPasswordNew(Proguard:131) at com.jd.lib.login.unit.a.n.a(AccountPresenter.java:145) at com.jd.lib.login.unit.a.e.onSuccess(AccountFragment.java:570) at com.jd.verify.common.a.run(Proguard:13) at android.os.Handler.handleCallback(Handler.java:751) at android.os.Handler.dispatchMessage(Handler.java:95) at android.os.Looper.loop(Looper.java:154) at android.app.ActivityThread.main(ActivityThread.java:6153) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:892) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:782) [*] [-126, -106, -116, 66, 57, -90, -31, -58, 80, 65, 44, -84, -60, 94, -102, -24, -102, -40, -86, -37] [*] [-126, -106, -116, 66, 57, -90, -31, -58, 80, 65, 44, -84, -60, 94, -102, -24, -102, -40, -86, -37]
用objection hook上面列举的几个关键函数:
com.jingdong.app.mall on (samsung: 7.1.2) [usb] # android hooking watch class_method jd.wjlogin_sdk.common.inland.WJLoginInland.JDLoginWithPasswordNew --dump-args --dump-backtrac e --dump-return (agent) Attempting to watch class jd.wjlogin_sdk.common.inland.WJLoginInland and method JDLoginWithPasswordNew. (agent) Hooking jd.wjlogin_sdk.common.inland.WJLoginInland.JDLoginWithPasswordNew(java.lang.String, java.lang.String, java.lang.String, java.lang.String, jd.wjlogin_sdk.common.listener.OnLoginCallback) (agent) Registering job 463404. Type: watch-method for: jd.wjlogin_sdk.common.inland.WJLoginInland.JDLoginWithPasswordNew com.jingdong.app.mall on (samsung: 7.1.2) [usb] # android hooking watch class_method com.jd.sec.utils.LoadDoor.getToken --dump-args --dump-backtrace --dump-return (agent) Attempting to watch class com.jd.sec.utils.LoadDoor and method getToken. (agent) Hooking com.jd.sec.utils.LoadDoor.getToken(java.lang.Object) (agent) Registering job 063371. Type: watch-method for: com.jd.sec.utils.LoadDoor.getToken com.jingdong.app.mall on (samsung: 7.1.2) [usb] # android hooking watch class_method jd.wjlogin_sdk.common.a.b.j --dump-args --dump-backtrace --dump-return (agent) Attempting to watch class jd.wjlogin_sdk.common.a.b and method j. (agent) Hooking jd.wjlogin_sdk.common.a.b.j() (agent) Registering job 063544. Type: watch-method for: jd.wjlogin_sdk.common.a.b.j com.jingdong.app.mall on (samsung: 7.1.2) [usb] # android hooking watch class_method jd.wjlogin_sdk.util.MD5.encrypt32 --dump-args --dump-backtrace --dump-return (agent) Attempting to watch class jd.wjlogin_sdk.util.MD5 and method encrypt32. (agent) Hooking jd.wjlogin_sdk.util.MD5.encrypt32(java.lang.String) (agent) Registering job 184672. Type: watch-method for: jd.wjlogin_sdk.util.MD5.encrypt32 com.jingdong.app.mall on (samsung: 7.1.2) [usb] # (agent) [184672] Called jd.wjlogin_sdk.util.MD5.encrypt32(java.lang.String)
打印的日志如下:
com.jingdong.app.mall on (samsung: 7.1.2) [usb] # (agent) [184672] Called jd.wjlogin_sdk.util.MD5.encrypt32(java.lang.String) (agent) [184672] Backtrace: jd.wjlogin_sdk.util.MD5.encrypt32(Native Method) com.jd.lib.login.unit.a.b.f(AccountFragment.java:605) com.jd.lib.login.unit.a.b.onClick(AccountFragment.java:8346) android.view.View.performClick(View.java:5637) android.view.View$PerformClick.run(View.java:22429) android.os.Handler.handleCallback(Handler.java:751) android.os.Handler.dispatchMessage(Handler.java:95) android.os.Looper.loop(Looper.java:154) android.app.ActivityThread.main(ActivityThread.java:6153) java.lang.reflect.Method.invoke(Native Method) com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:892) com.android.internal.os.ZygoteInit.main(ZygoteInit.java:782) (agent) [184672] Arguments jd.wjlogin_sdk.util.MD5.encrypt32(123456) (agent) [184672] Return Value: e10adc3949ba59abbe56e057f20f883e (agent) [063544] Called jd.wjlogin_sdk.common.a.b.j() (agent) [063544] Backtrace: jd.wjlogin_sdk.common.a.b.j(Native Method) jd.wjlogin_sdk.common.a.a.b(Proguard:25) jd.wjlogin_sdk.c.d.a(Proguard:708) jd.wjlogin_sdk.common.inland.WJLoginInland.getCaptchaSid(Proguard:2848) com.jd.lib.login.unit.a.n.a(AccountPresenter.java:108) com.jd.lib.login.unit.a.b.onClick(AccountFragment.java:8346) android.view.View.performClick(View.java:5637) android.view.View$PerformClick.run(View.java:22429) android.os.Handler.handleCallback(Handler.java:751) android.os.Handler.dispatchMessage(Handler.java:95) android.os.Looper.loop(Looper.java:154) android.app.ActivityThread.main(ActivityThread.java:6153) java.lang.reflect.Method.invoke(Native Method) com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:892) com.android.internal.os.ZygoteInit.main(ZygoteInit.java:782) (agent) [063371] Called com.jd.sec.utils.LoadDoor.getToken(java.lang.Object) (agent) [063371] Backtrace: com.jd.sec.utils.LoadDoor.getToken(Native Method) com.jd.sec.utils.LoadDoor.a(LoadDoor.java:69) com.jd.sec.logo.TokenManager.getToken(TokenManager.java:13) com.jingdong.common.login.LoginUserBase.getDeviceJson(LoginUserBase.java:288) com.jingdong.common.utils.gf.getDeviceFinger(UserUtil.java:220) jd.wjlogin_sdk.common.a.b.j(Proguard:1000) jd.wjlogin_sdk.common.a.b.j(Native Method) jd.wjlogin_sdk.common.a.a.b(Proguard:25) jd.wjlogin_sdk.c.d.a(Proguard:708) jd.wjlogin_sdk.common.inland.WJLoginInland.getCaptchaSid(Proguard:2848) com.jd.lib.login.unit.a.n.a(AccountPresenter.java:108) com.jd.lib.login.unit.a.b.onClick(AccountFragment.java:8346) android.view.View.performClick(View.java:5637) android.view.View$PerformClick.run(View.java:22429) android.os.Handler.handleCallback(Handler.java:751) android.os.Handler.dispatchMessage(Handler.java:95) android.os.Looper.loop(Looper.java:154) android.app.ActivityThread.main(ActivityThread.java:6153) java.lang.reflect.Method.invoke(Native Method) com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:892) com.android.internal.os.ZygoteInit.main(ZygoteInit.java:782) (agent) [063371] Arguments com.jd.sec.utils.LoadDoor.getToken(com.jingdong.app.mall.JDApp@56edf59) (agent) [063371] Return Value: 3506QJLNHI545OL22KN764E0KL3F01D16OO229923124CPP3467LLLK6DCQ1VCF12D (agent) [063544] Return Value: {"eid":"eidA084081233as9PDys98pOSBOOvSLAk\/ufvzw8rnGKycVf\/77mUWXrb6poNPBQyqwfHDR4qI5DTdo9mR8KUxISW8bIioO0kLSjgFHFfVnIjdeqojMz","token":"3506QJLNHI545OL22KN764E0KL3F01D16OO229923124CPP3467LLLK6DCQ1VCF12D","unionwsws":"{\"devicefinger\":\"eidA084081233as9PDys98pOSBOOvSLAk\\\/ufvzw8rnGKycVf\\\/77mUWXrb6poNPBQyqwfHDR4qI5DTdo9mR8KUxISW8bIioO0kLSjgFHFfVnIjdeqojMz\",\"jmafinger\":\"ebMdecnT8fvsTrLtkO9NXqp6tTZhAGGjpEOgxuDg8ULxB5gIhoqNZX266wOt+0Ed8NrcDmKTQHBkAyH+Fe5745Q==\"}"} (agent) [184672] Called jd.wjlogin_sdk.util.MD5.encrypt32(java.lang.String) (agent) [184672] Backtrace: jd.wjlogin_sdk.util.MD5.encrypt32(Native Method) com.jd.lib.login.unit.a.b.f(AccountFragment.java:605) com.jd.lib.login.unit.a.b.m(AccountFragment.java:61) com.jd.lib.login.unit.a.e.onSuccess(AccountFragment.java:570) com.jd.verify.common.a.run(Proguard:13) android.os.Handler.handleCallback(Handler.java:751) android.os.Handler.dispatchMessage(Handler.java:95) android.os.Looper.loop(Looper.java:154) android.app.ActivityThread.main(ActivityThread.java:6153) java.lang.reflect.Method.invoke(Native Method) com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:892) com.android.internal.os.ZygoteInit.main(ZygoteInit.java:782) (agent) [184672] Arguments jd.wjlogin_sdk.util.MD5.encrypt32(123456) (agent) [184672] Return Value: e10adc3949ba59abbe56e057f20f883e (agent) [463404] Called jd.wjlogin_sdk.common.inland.WJLoginInland.JDLoginWithPasswordNew(java.lang.String, java.lang.String, java.lang.String, java.lang.String, jd.wjlogin_sdk.common.listener.OnLoginCallback) (agent) [463404] Backtrace: jd.wjlogin_sdk.common.inland.WJLoginInland.JDLoginWithPasswordNew(Native Method) com.jd.lib.login.unit.a.n.a(AccountPresenter.java:145) com.jd.lib.login.unit.a.e.onSuccess(AccountFragment.java:570) com.jd.verify.common.a.run(Proguard:13) android.os.Handler.handleCallback(Handler.java:751) android.os.Handler.dispatchMessage(Handler.java:95) android.os.Looper.loop(Looper.java:154) android.app.ActivityThread.main(ActivityThread.java:6153) java.lang.reflect.Method.invoke(Native Method) com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:892) com.android.internal.os.ZygoteInit.main(ZygoteInit.java:782) (agent) [463404] Arguments jd.wjlogin_sdk.common.inland.WJLoginInland.JDLoginWithPasswordNew(18888888888, eacadc3949ba59abbe56e057f20f883e, WIQAxQABAAAAAAAAAAAAMO2PcCPs73q8Ab1lswJ94Kvv3e2lwE8c-mu8Wy6Qom21i0WRSiUZKlC6c_vEU5rA4gAAAAA, LEZAEgABAAABedp0U0IAgBxTXfHLWqEFODZP8KIupy_HB945JxIcQJOj4W_nMHNp6cnfdFjX7JJoShRJYjY74L5B863OOSDWrNFxBpBd0FUKyWbSY1qzEPG18CQ6oaY8vBbyWpoR-uW2XP3vR_eDGFMzs_5iEetZlsrpMrPq2ctmHTF5vvXJkwb41MWRzItC, com.jd.lib.login.unit.a.q@91765f8) (agent) [063544] Called jd.wjlogin_sdk.common.a.b.j() (agent) [063544] Backtrace: jd.wjlogin_sdk.common.a.b.j(Native Method) jd.wjlogin_sdk.common.a.a.b(Proguard:25) jd.wjlogin_sdk.c.d.a(Proguard:708) jd.wjlogin_sdk.common.inland.WJLoginInland.JDLoginWithPasswordNew(Proguard:131) jd.wjlogin_sdk.common.inland.WJLoginInland.JDLoginWithPasswordNew(Native Method) com.jd.lib.login.unit.a.n.a(AccountPresenter.java:145) com.jd.lib.login.unit.a.e.onSuccess(AccountFragment.java:570) com.jd.verify.common.a.run(Proguard:13) android.os.Handler.handleCallback(Handler.java:751) android.os.Handler.dispatchMessage(Handler.java:95) android.os.Looper.loop(Looper.java:154) android.app.ActivityThread.main(ActivityThread.java:6153) java.lang.reflect.Method.invoke(Native Method) com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:892) com.android.internal.os.ZygoteInit.main(ZygoteInit.java:782) (agent) [063371] Called com.jd.sec.utils.LoadDoor.getToken(java.lang.Object) (agent) [063371] Backtrace: com.jd.sec.utils.LoadDoor.getToken(Native Method) com.jd.sec.utils.LoadDoor.a(LoadDoor.java:69) com.jd.sec.logo.TokenManager.getToken(TokenManager.java:13) com.jingdong.common.login.LoginUserBase.getDeviceJson(LoginUserBase.java:288) com.jingdong.common.utils.gf.getDeviceFinger(UserUtil.java:220) jd.wjlogin_sdk.common.a.b.j(Proguard:1000) jd.wjlogin_sdk.common.a.b.j(Native Method) jd.wjlogin_sdk.common.a.a.b(Proguard:25) jd.wjlogin_sdk.c.d.a(Proguard:708) jd.wjlogin_sdk.common.inland.WJLoginInland.JDLoginWithPasswordNew(Proguard:131) jd.wjlogin_sdk.common.inland.WJLoginInland.JDLoginWithPasswordNew(Native Method) com.jd.lib.login.unit.a.n.a(AccountPresenter.java:145) com.jd.lib.login.unit.a.e.onSuccess(AccountFragment.java:570) com.jd.verify.common.a.run(Proguard:13) android.os.Handler.handleCallback(Handler.java:751) android.os.Handler.dispatchMessage(Handler.java:95) android.os.Looper.loop(Looper.java:154) android.app.ActivityThread.main(ActivityThread.java:6153) java.lang.reflect.Method.invoke(Native Method) com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:892) com.android.internal.os.ZygoteInit.main(ZygoteInit.java:782) (agent) [063371] Arguments com.jd.sec.utils.LoadDoor.getToken(com.jingdong.app.mall.JDApp@56edf59) (agent) [063371] Return Value: 8906OHHHMJ829PRC4LO7F05DKL1C87463OO9656DF403EPPE287LLLK797Q1V3417B (agent) [063544] Return Value: {"eid":"eidA084081233as9PDys98pOSBOOvSLAk\/ufvzw8rnGKycVf\/77mUWXrb6poNPBQyqwfHDR4qI5DTdo9mR8KUxISW8bIioO0kLSjgFHFfVnIjdeqojMz","token":"8906OHHHMJ829PRC4LO7F05DKL1C87463OO9656DF403EPPE287LLLK797Q1V3417B","unionwsws":"{\"devicefinger\":\"eidA084081233as9PDys98pOSBOOvSLAk\\\/ufvzw8rnGKycVf\\\/77mUWXrb6poNPBQyqwfHDR4qI5DTdo9mR8KUxISW8bIioO0kLSjgFHFfVnIjdeqojMz\",\"jmafinger\":\"ebMdecnT8fvsTrLtkO9NXqp6tTZhAGGjpEOgxuDg8ULxB5gIhoqNZX266wOt+0Ed8NrcDmKTQHBkAyH+Fe5745Q==\"}"} (agent) [463404] Return Value: (none)
我输入的电话号码18888888888和密码123456一览无遗!jd.wjlogin_sdk.common.inland.WJLoginInland.JDLoginWithPasswordNew这个就是登陆函数实锤了!这里话说回来,这么明显的函数,为啥不混淆了?
===================================分割线=================================
Java层因为加密函数名称没法混淆,所以很容易找到并hook,so层的加密算法怎么识别了?有一个简单的常量特征识别法:一般来说,这些加密算法都会使用一些固定的常量用来异或(注意不是用来做if判断),比如:
- MD5的常量
Context->a = 0x67452301; Context->b = 0xefcdab89; Context->c = 0x98badcfe; Context->d = 0x10325476;
- sha256的常量
#define K_00_19 0x5a827999UL #define K_20_39 0x6ed9eba1UL #define K_40_59 0x8f1bbcdcUL #define K_60_79 0xca62c1d6UL
- AES的常量(太多了,这里只放一部分,详细的常量建议参考链接2)
static const uint32_t TE0[256] = { 0xc66363a5UL, 0xf87c7c84UL, 0xee777799UL, 0xf67b7b8dUL, 0xfff2f20dUL, 0xd66b6bbdUL, 0xde6f6fb1UL, 0x91c5c554UL, 0x60303050UL, 0x02010103UL, 0xce6767a9UL, 0x562b2b7dUL, 0xe7fefe19UL, 0xb5d7d762UL, 0x4dababe6UL, 0xec76769aUL, 0x8fcaca45UL, 0x1f82829dUL, 0x89c9c940UL, 0xfa7d7d87UL, 0xeffafa15UL, 0xb25959ebUL, 0x8e4747c9UL, 0xfbf0f00bUL, 0x41adadecUL, 0xb3d4d467UL, 0x5fa2a2fdUL, 0x45afafeaUL, 0x239c9cbfUL, 0x53a4a4f7UL, 0xe4727296UL, 0x9bc0c05bUL, 0x75b7b7c2UL, 0xe1fdfd1cUL, 0x3d9393aeUL, 0x4c26266aUL, 0x6c36365aUL, 0x7e3f3f41UL, 0xf5f7f702UL, 0x83cccc4fUL, 0x6834345cUL, 0x51a5a5f4UL, 0xd1e5e534UL, 0xf9f1f108UL, 0xe2717193UL, 0xabd8d873UL, 0x62313153UL, 0x2a15153fUL, 0x0804040cUL, 0x95c7c752UL, 0x46232365UL, 0x9dc3c35eUL, 0x30181828UL, 0x379696a1UL, 0x0a05050fUL, 0x2f9a9ab5UL, 0x0e070709UL, 0x24121236UL, 0x1b80809bUL, 0xdfe2e23dUL, 0xcdebeb26UL, 0x4e272769UL, 0x7fb2b2cdUL, 0xea75759fUL, 0x1209091bUL, 0x1d83839eUL, 0x582c2c74UL, 0x341a1a2eUL, 0x361b1b2dUL, 0xdc6e6eb2UL, 0xb45a5aeeUL, 0x5ba0a0fbUL, 0xa45252f6UL, 0x763b3b4dUL, 0xb7d6d661UL, 0x7db3b3ceUL, 0x5229297bUL, 0xdde3e33eUL, 0x5e2f2f71UL, 0x13848497UL, 0xa65353f5UL, 0xb9d1d168UL, 0x00000000UL, 0xc1eded2cUL, 0x40202060UL, 0xe3fcfc1fUL, 0x79b1b1c8UL, 0xb65b5bedUL, 0xd46a6abeUL, 0x8dcbcb46UL, 0x67bebed9UL, 0x7239394bUL, 0x944a4adeUL, 0x984c4cd4UL, 0xb05858e8UL, 0x85cfcf4aUL, 0xbbd0d06bUL, 0xc5efef2aUL, 0x4faaaae5UL, 0xedfbfb16UL, 0x864343c5UL, 0x9a4d4dd7UL, 0x66333355UL, 0x11858594UL, 0x8a4545cfUL, 0xe9f9f910UL, 0x04020206UL, 0xfe7f7f81UL, 0xa05050f0UL, 0x783c3c44UL, 0x259f9fbaUL, 0x4ba8a8e3UL, 0xa25151f3UL, 0x5da3a3feUL, 0x804040c0UL, 0x058f8f8aUL, 0x3f9292adUL, 0x219d9dbcUL, 0x70383848UL, 0xf1f5f504UL, 0x63bcbcdfUL, 0x77b6b6c1UL, 0xafdada75UL, 0x42212163UL, 0x20101030UL, 0xe5ffff1aUL, 0xfdf3f30eUL, 0xbfd2d26dUL, 0x81cdcd4cUL, 0x180c0c14UL, 0x26131335UL, 0xc3ecec2fUL, 0xbe5f5fe1UL, 0x359797a2UL, 0x884444ccUL, 0x2e171739UL, 0x93c4c457UL, 0x55a7a7f2UL, 0xfc7e7e82UL, 0x7a3d3d47UL, 0xc86464acUL, 0xba5d5de7UL, 0x3219192bUL, 0xe6737395UL, 0xc06060a0UL, 0x19818198UL, 0x9e4f4fd1UL, 0xa3dcdc7fUL, 0x44222266UL, 0x542a2a7eUL, 0x3b9090abUL, 0x0b888883UL, 0x8c4646caUL, 0xc7eeee29UL, 0x6bb8b8d3UL, 0x2814143cUL, 0xa7dede79UL, 0xbc5e5ee2UL, 0x160b0b1dUL, 0xaddbdb76UL, 0xdbe0e03bUL, 0x64323256UL, 0x743a3a4eUL, 0x140a0a1eUL, 0x924949dbUL, 0x0c06060aUL, 0x4824246cUL, 0xb85c5ce4UL, 0x9fc2c25dUL, 0xbdd3d36eUL, 0x43acacefUL, 0xc46262a6UL, 0x399191a8UL, 0x319595a4UL, 0xd3e4e437UL, 0xf279798bUL, 0xd5e7e732UL, 0x8bc8c843UL, 0x6e373759UL, 0xda6d6db7UL, 0x018d8d8cUL, 0xb1d5d564UL, 0x9c4e4ed2UL, 0x49a9a9e0UL, 0xd86c6cb4UL, 0xac5656faUL, 0xf3f4f407UL, 0xcfeaea25UL, 0xca6565afUL, 0xf47a7a8eUL, 0x47aeaee9UL, 0x10080818UL, 0x6fbabad5UL, 0xf0787888UL, 0x4a25256fUL, 0x5c2e2e72UL, 0x381c1c24UL, 0x57a6a6f1UL, 0x73b4b4c7UL, 0x97c6c651UL, 0xcbe8e823UL, 0xa1dddd7cUL, 0xe874749cUL, 0x3e1f1f21UL, 0x964b4bddUL, 0x61bdbddcUL, 0x0d8b8b86UL, 0x0f8a8a85UL, 0xe0707090UL, 0x7c3e3e42UL, 0x71b5b5c4UL, 0xcc6666aaUL, 0x904848d8UL, 0x06030305UL, 0xf7f6f601UL, 0x1c0e0e12UL, 0xc26161a3UL, 0x6a35355fUL, 0xae5757f9UL, 0x69b9b9d0UL, 0x17868691UL, 0x99c1c158UL, 0x3a1d1d27UL, 0x279e9eb9UL, 0xd9e1e138UL, 0xebf8f813UL, 0x2b9898b3UL, 0x22111133UL, 0xd26969bbUL, 0xa9d9d970UL, 0x078e8e89UL, 0x339494a7UL, 0x2d9b9bb6UL, 0x3c1e1e22UL, 0x15878792UL, 0xc9e9e920UL, 0x87cece49UL, 0xaa5555ffUL, 0x50282878UL, 0xa5dfdf7aUL, 0x038c8c8fUL, 0x59a1a1f8UL, 0x09898980UL, 0x1a0d0d17UL, 0x65bfbfdaUL, 0xd7e6e631UL, 0x844242c6UL, 0xd06868b8UL, 0x824141c3UL, 0x299999b0UL, 0x5a2d2d77UL, 0x1e0f0f11UL, 0x7bb0b0cbUL, 0xa85454fcUL, 0x6dbbbbd6UL, 0x2c16163aUL, };
- base64的字符集
ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/
其他自定义的加密算法可能没有固定的套路,只能hook可疑函数,打印函数的参数和返回值来判断,参数或返回值一般有这三种:
- 指针/地址:这个是一段字符串的buf或类的对象;建议用hexdump查看内容;
- 数值:一般是字符串的长度
- 有些函数可能没有返回值,就要重点观察参数了;因为函数一旦执行,结果肯定要保存的,否则就失去了函数调用的意义;没有返回值就只能把结果保存在参数了!
最后就是找一些标准的加密算法so库,hook其导出函数了,从导出的符号名称大致判断是哪种加密算法!
参考:
1、https://opensource.apple.com/source/ 这里有很多加密算法的c实现
2、https://github.com/WaterJuice/WjCryptLib/tree/master/lib 同上