学习目标:能使用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);
}
});

android.widget.Toast

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;
}
});

com.google.gson.Gson

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);
}
});