学习目标:能使用frida快速定位到关键代码 函数调用栈的打印 function showStacks ( ){ var Log = Java .use ("android.util.Log" ); var Throwable = Java .use ("java.util.Throwable" ); console .log (Log .getStackTraceString (Throwable .$new())) }
常用系统关键函数 java.util.HashMap put Java .perform (function ( ){ function showStack ( ){ var log = Java .use ("android.util.Log" ); var throwable = Java .use ("java.lang.Throwable" ); console .log (log.getStackTraceString (throwable.$new())); } var hashMap = Java .use ("java.util.HashMap" ); hashMap.put .implementation = function (a, b ){ if (a.equals ("username" )){ showStack (); console .log ("hashMap param: " ,a, b); } return this .put (a, b); } });
java.util.ArrayList add Java .perform (function ( ){ function showStack ( ){ var log = Java .use ("android.util.Log" ); var throwable = Java .use ("java.lang.Throwable" ); console .log (log.getStackTraceString (throwable.$new())); } var arrayList = Java .use ("java.util.ArrayList" ); arrayList.add .overload ('java.lang.Object' ).implementation = function (a ){ if (a.equals ("username=13905020820" )){ showStack (); console .log ("arrayList.param: " , a); } return this .add (a); } arrayList.add .overload ('int' , 'java.lang.Object' ).implementation = function (a, b ){ if (b.equals ("username=13905020820" )){ showStack (); console .log ("arrayList param: " , a, b); } return this .add (a, b); } });
addAll set java.lang.StringBuilder toString 这里打印堆栈也没有输出,调用的太多了
Java .perform (function ( ){ function showStack ( ){ var log = Java .use ("android.util.Log" ); var throwable = Java .use ("java.lang.throwable" ); console .log (log.getStackStringTrace (throwable.$new())); } var stringBuilder = Java .use ("java.lang.StringBuilder" ); stringBuilder.toString .implementation = function ( ){ showStack (); let result = this .toString (); console .log (result); return result; } });
append android.text.TextUtils isEmpty Java .perform (function ( ){ function showStack ( ){ var log = Java .use ("android.util.Log" ); var throwable = Java .use ("java.lang.Throwable" ); console .log (log.getStracTraceString (throwable.$new())); } var TextUtils = Java .use ("android.text.TextUtils" ); TextUtils .isEmpty .implementation = function (a ){ console .log (a); return this .isEmpty (a); } });
java.lang.String trim Log Java .perform (function ( ){ function showStack ( ){ var log = Java .use ("android.util.Log" ); var throwable = Java .use ("java.lang.Throwable" ); console .log (log.getStackTraceString (throwable.$new())); } var log = Java .use ("android.util.Log" ); log.w .overload ('java.lang.String' , 'java.lang.String' ).implementation = function (a, b ){ console .log (a, b); return this .w (a, b); } });
java.util.Collections sort Java .perform (function ( ){ function showStack ( ){ var log = Java .use ("android.util.Log" ); var throwable = Java .use ("java.lang.Throwable" ); console .log (log.getStackTraceString (throwable.$new())); } var collection = Java .use ("java.util.Collections" ); collection.sort .overload ('java.util.List' ).implementation = function (a ){ let result = Java .cast (a, Java .use ("java.util.ArrayList" )); console .log ("collection.sort: " , result.toString ()); return this .sort (a); } var collection = Java .use ("java.util.Collections" ); collection.sort .overload ('java.util.List' , 'java.util.Comparator' ).implementation = function (a, b ){ let result = Java .cast (a, Java .use ("java.util.ArrayList" )); console .log ("collection.sortComparator: " , result.toString (), b); return this .sort (a, b); } });
show Java .perform (function ( ){ function showStack ( ){ var log = Java .use ("android.util.Log" ); var throwable = Java .use ("java.lang.Throwable" ); console .log (log.getStackTraceString (throwable.$new())); } var toast = Java .use ("android.widget.Toast" ); toast.show .implementation = function ( ){ showStack (); return this .show (); } });
android.widget.EditText getText org.json.JSONObject put getString Java .perform (function ( ){ function showStack ( ){ var log = Java .use ("android.util.Log" ); var throwable = Java .use ("java.lang.Throwable" ); console .log (log.getStackTraceString (throwable.$new())); } var jSONObject = Java .use ("org.json.JSONObject" ); jSONObject.put .overload ('java.lang.String' , 'java.lang.Object' ).implementation = function (a, b ){ console .log ("put: " , a, b); return this .put (a, b); } jSONObject.getString .implementation = function (a ){ console .log ("getString: " , a); let result = this .getString (a); return result; } });
toJson java.util.Arrays sort、toString android.util.Base64 这里打印堆栈有时候没有输出结果,可能是因为调用太多了?
Java .perform (function ( ){ function showStack ( ){ var log = Java .use ("android.util.Log" ); var throwable = Java .use ("java.lang.Throwable" ); console .log (log.getStackTraceString (throwable.$new())); } var base64 = Java .use ("android.util.Base64" ); base64.encodeToString .overload ('[B' , 'int' ).implementation = function (a, b ) { showStack (); console .log ("base64.encodeToString: " , JSON .stringify (a)); var result = this .encodeToString (a, b); console .log ("base64.encodeToString result: " , result) return result; } });
java.util.Base64 okio.Base64 okio.ByteString java.lang.String getBytes 打印堆栈时也会没有信息输出,可能时因为调用的太多了
Java .perform (function ( ){ function showStack ( ){ var log = Java .use ("android.util.Log" ); var throwable = Java .use ("java.lang.Throwable" ); console .log (log.getStackStringTrace (throwable.$new())); } var str = Java .use ("java.lang.String" ); str.getBytes .overload ().implementation = function ( ){ showStack (); let result = this .getBytes (); let newStr = str.$new(result); console .log ("result: " , newStr); return result; } str.getBytes .overload ('java.lang.String' ).implementation = function (a ){ showStack (); let result = this .getBytes (a); let newStr = str.$new(result, a); console .log ("result: " , newStr); return result; } });
string的构造函数 直接hook$init()会崩溃
Java .perform (function ( ){ function showStack ( ){ var log = Java .use ("android.util.Log" ); var throwable = Java .use ("java.lang.Throwable" ); console .log (log.getStackStringTrace (throwable.$new())); } var str = Java .use ("java.lang.String" ); str.$init .overload ('[C' ).implementation = function (a ){ console .log ("stringConstructor is called" ); return this .$init(a); } str.$init .overload ('[B' ).implementation = function (a ){ console .log ("stringConstructor is called" ); return this .$init(a); } });
为什么呢?我们查看一下安卓源码http://aospxref.com
发现这个构造函数都是抛出一个错误,那么我们hook这个构造函数自然会导致app崩溃了
安卓系统在调用$init时,会将这个函数替换成调用StringFactory,以后会学到安卓源码,现在暂时看不懂
hook这个类
java.lang.StringFactory newStringFromChars Java .perform (function ( ){ function showStack ( ){ var log = Java .use ("android.util.Log" ); var throwable = Java .use ("java.lang.Throwable" ); console .log (log.getStackTraceString (throwable.$new())); } var stringFactory = Java .use ("java.lang.StringFactory" ); stringFactory.newStringFromChars .overload ('[C' ).implementation = function (a ){ let result = this .newStringFromChars (a); console .log (result); return result; } });
组件 findViewById 知识点 直接使用在android studio里面找的的这个findViewById类(androidx.appcompat.app.AppCompatActivity.findVIewById)是定位不到的
具体原因应该和安卓系统源码有关,目前没有能力理解
所以使用**Java.enumerateLoadedClassesSync()**枚举已加载的类,然后过滤下类名,就可以得到真实路径android.support.v7.app.AppCompatActivity
还有一个问题就是这个方法是在我们进入到登录页面之前就调用的,所以我们要使用spawn的方式启动app
frida -U -f com.dodonew.online -l locate.js --no-pause 高版本使用spawn的方式启动app时是默认没有停止的,若是要停止这样写,frida -U -f com.xiaojianbang.app -l Hook2.js --pause -f 表示让frida帮我们重新启动app,一开始就注入js --no-pause 直接运行主线程,中途不暂停 访问内部类要使用R$id 访问类的属性要使用R$id.btn_login.value
Java .perform (function ( ){ function showStack ( ){ var log = Java .use ("android.util.Log" ); var throwable = Java .use ("java.lang.Throwable" ); console .log (log.getStackTraceString (throwable.$new())); } var appCompatActivity = Java .use ("android.support.v7.app.AppCompatActivity" ); var btn_login = Java .use ("com.dodonew.online.R$id" ).btn_login .value ; appCompatActivity.findViewById .implementation = function (a ){ if (a == btn_login){ showStack (); console .log (a); } let result = this .findViewById (a); return result; } });
android.view.View setOnClickListener Java .perform (function ( ){ function showStack ( ){ var log = Java .use ("android.util.Log" ); var throwable = Java .use ("java.lang.Throwable" ); console .log (log.getStackTraceString (throwable.$new())); } var btn_login = Java .use ("com.dodonew.online.R$id" ).btn_login .value ; var view = Java .use ("android.view.View" ); view.setOnClickListener .implementation = function (a ){ if (this .getId () == btn_login){ showStack (); console .log ("view.id: " + this .getId ()); console .log ("view.setOnClickListener is called" ); } return this .setOnClickListener (a); } });