当前位置: 首页 > 科技观察

Frida,Android原生开发App的框架,常用关键代码定位

时间:2023-03-11 21:37:58 科技观察

大家好,我是码农周吧!本教程仅供学习讨论,任何人不得利用技术进行非法操作,阅读教程即表示同意!前言有时您可能会对APP进行字符串加密等操作。这样的话,你的变量名等东西就会一头雾水,看代码可能就不知道怎么下手了。没关系,系统级的东西,Toast等功能是不能混淆的,总算可以根据蛛丝马迹找到破解点了。Frida常用命令frida-UconnectUSBdevice-Fattachtothefrontapp-linjectjs-ooutputtofile-frestart--no-pause立即执行,不暂停打印堆栈异常,他的结果是从下往上看的!代码functionprintStacks(){console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new()));}常用的hooks执行结果函数代码hook了HashMap的put方法hashMap,这个方法很常用,大家都懂,但是一定要屏蔽好,否则app很容易崩溃!varhashMap=Java.use("java.util.HashMap");hashMap.put.implementation=function(a,b){//a=="username"anda.equals("username")一般都可以//如果不行就改if(a=="username"){console.log("hashMap.put:",a,b);打印堆栈();}returnthis.put(a,b);}hookArrayList的add方法Array好像很常用;vararrayList=Java.use("java.util.ArrayList");arrayList.add.overload('java.lang.Object').implementation=function(a){if(a=="username=18903916120"){console.log("arrayList.add:",a);打印堆栈();}//console.log("arrayList.add:",a);返回this.add(a);}arrayList.add.overload('int','java.lang.Object').implementation=function(a,b){console.log("arrayList.add:",a,b);returnthis.add(a,b);}hookTextUtils的isEmpty方法这个方法通常是Android判断输入框是否为空的必备方法!vartextUtils=Java.use("android.text.TextUtils");textUtils.isEmpty.implementation=function(a){if(a=="TURJNk1EQTZNREE2TURBNk1EQTZNREE9"){console.log("textUtils.isEmpty:",a);打印堆栈();}//console.log("textUtils.isEmpty:",a);returnthis.isEmpty(a);}hookString的trim方法好像挺多的,去除首尾空格,防止脏数据;varstr=Java.use("java.lang.String");str.trim.implementation=function(){console.log("str.trim:",this);打印堆栈();返回这个.trim();}hook日志的w方法varlog=Java.use("android.util.Log");log.w.overload('java.lang.String','java.lang.String').implementation=function(tag,message){console.log("log.w:",tag,message);打印堆栈();返回this.w(tag,message);}钩EditText的getText方法应该比较多,不过这个一般在加密的上层,可以考虑使用vareditText=Java.use("android.widget.EditText");editText.getText.overload().implementation=function(){varresult=this.getText();结果=Java.cast(结果,Java.use("java.lang.CharSequence"));console.log("editText.getText:",result.toString());打印堆栈();returnresult;}hookCollections的排序方法排序方法,频率还组合;varcollections=Java.use("java.util.Collections");collections.sort.overload('java.util.List').implementation=function(a){varresult=Java.cast(a,Java.use("java.util.ArrayList"));console.log("collections.sortList:",result.toString());打印堆栈();returnthis.sort(a);}collections.sort.overload('java.util.List','java.util.Comparator').implementation=function(a,b){varresult=Java.cast(a,Java.use("java.util.ArrayList"));console.log("collections.sort列表比较器:",result.toString());打印堆栈();returnthis.sort(a,b);}//.overload('java.lang.String','double')//.overload('java.lang.String','int')//.overload('java.lang.String','long')//.overload('java.lang.String','boolean')hookjSONObject的put方法一般在转json的时候使用,可以考虑;varjSONObject=Java.use("org.json.JSONObject");jSONObject.put.overload('java.lang.String','java.lang.Object').implementation=function(a,b){//varresult=Java.cast(a,Java.use("java.util.ArrayList"));console.log("jSONObject.put:",a,b);打印堆栈();returnthis.put(a,b);}jSONObject.getString.implementation=function(a){//varresult=Java.cast(a,Java.use("java.util.ArrayList"));console.log("jSONObject.getString:",a);varresult=this.getString(a);console.log("jSONObject.getString结果:",result);打印堆栈();returnresult;}hookToast的show方法有很多,基本上每个app都有,但是hook的位置在加密的低层,因为处理完一定要弹出窗口;但是可以考虑不直接输入账号密码提交,这样位置大概在加密的上层,可以往下走;vartoast=Java.use("android.widget.Toast");toast.show.implementation=function(){console.log("toast.show:");printStacks();returnthis.show();}hookBase64的encodeToString方法有很多base64,除了消息摘要算法,最后的形式都是base64格式,非常有必要varbase64=Java.use("android.util.Base64");base64.encodeToString.overload('[B','int').implementation=function(a,b){console.log("base64.encodeToString:",JSON.stringify(a));varresult=this.encodeToString(a,b);console.log("base64.encodeToString结果:",result)printStacks();returnresult;}hookString的getBytes方法varstr=Java.use("java.lang.String");str.getBytes.overload().implementation=function(){varresult=this.getBytes();varnewStr=str.$new(结果);console.log("str.getBytes结果:",newStr);打印堆栈();返回结果;}str.getBytes.overload('java.lang.String').implementation=function(a){varresult=this.getBytes(a);varnewStr=str.$new(result,a);console.log("str.getBytes结果:",newStr);打印堆栈();returnresult;}findViewById找到控件方法这种方式hook代码,需要frida帮助我们启动app。所以这次启动的命令是;frida-U-fcom.dodonew.online-lg_关键代码快速定位。js-o1.txt--no-pause因为很多控件可能一开始就绑定了,所以从一开始就开始hooking。如何找到控件id控件id可以通过\tools\bin下的uiautomatorviewer.bat查看;检查登录按钮id,所以登录按钮的id是btn_login;代码//查找idvarbtn_login_id=Java.use("com.dodonew.online.R$id").btn_login.value;console.log("btn_login_id:",btn_login_id);varview=Java.use("android.view.View");view.setOnClickListener.implementation=function(a){if(this.getId()==btn_login_id){console.log("view.id:"+this.getId());console.log("调用了view.setOnClickListener");打印堆栈();}returnthis.setOnClickListener(a);}简单使用在度度牛app中,最后使用DES算法,base64结果显示加密后的内容。所以尝试挂钩base64;codeJava.perform(function(){//打印堆栈functionprintStacks(){console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new()));}//base64varbase64=Java.use("android.util.Base64");base64.encodeToString.overload('[B','int').implementation=function(a,b){console.log("base64.encodeToString:",JSON.stringify(a));varresult=this.encodeToString(a,b);console.log("base64.encodeToString结果:",result)printStacks();returnresult;}})hookresult所以说,如果你看结果是base或者md5或者hex之类的,就用这些常用的hook代码试试,扔栈。您可以很好地分析代码。总结虽然写了重点代码定位,但其实只是常用的代码。上面使用了逆向app中总结的钩子代码。当然,现实中肯定不止这些。根据需求,经验越多,轮子越多。人生无路可走,加油!