02 AndroidJava层逆向-关键代码快速定位

353 阅读2分钟

1 put方法定位

Java.perform(function () {

    // 该方法目的是打印堆栈
    function showStacks() {
        console.log(
            Java.use("android.util.Log").getStackTraceString(
                Java.use("java.lang.Throwable").$new()
            )
        )
    }

    // 获取HashMap对象
    let hashMap = Java.use("java.util.HashMap");

    // 对put方法进行hook
    hashMap.put.implementation = function (a, b) {

        // 过滤key
        if (a.equals('username')) {
            // 打印堆栈
            showStacks();
            console.log("hashMap.put:", a, b)
        }
        // console.log(a)
        // console.log(b)
        // console.log(">>>>>>>>>>>>>>>>>>")

        return this.put(a, b);
    }
})

效果图

image.png

2 打印堆栈方法

function showStacks() {
        console.log(
            Java.use("android.util.Log")
                .getStackTraceString(
                    Java.use("java.lang.Throwable").$new()
                )
        );
    }

3 hookArrayList的add、addAll、set方法等

var arrayList = Java.use("java.util.ArrayList");
arrayList.add.overload('java.lang.Object').implementation = function (a) {
   if(a.equals("username=18762345234")){
        showStacks();
        console.log("arrayList.add: ", a);
    }
    //console.log("arrayList.add: ", a);
    return this.add(a);
}
arrayList.add.overload('int', 'java.lang.Object').implementation = function (a, b) {
    console.log("arrayList.add: ", a, b);
    return this.add(a, b);
}

4 Android TextUtils.isEmpty(),查看用户的输入

var textUtils = Java.use("android.text.TextUtils");
    textUtils.isEmpty.implementation = function (a) {
        if(a == "2v+DC2gq7RuAC8PE5GZz5wH3/y9ZVcWhFwhDY9L19g9iEd075+Q7xwewvfIN0g0ec/NaaF43/S0="){
            showStacks();
            console.log("textUtils.isEmpty: ", a);
        }
        //console.log("textUtils.isEmpty: ", a);
        return this.isEmpty(a);
    }

5 android.util.Log 打印日志消息,一般没用


var log = Java.use("android.util.Log");
    log.w.overload('java.lang.String', 'java.lang.String').implementation = function (tag, message) {
        showStacks();
        console.log("log.w: ", tag, message);
        return this.w(tag, message);
    }

6 Collections的sort方法

var collections = Java.use("java.util.Collections");
    collections.sort.overload('java.util.List').implementation = function (a) {
        showStacks();
        var result = Java.cast(a, Java.use("java.util.ArrayList"));
        console.log("collections.sort List: ", result.toString());
        return this.sort(a);
    }
    collections.sort.overload('java.util.List', 'java.util.Comparator')
.implementation = function (a, b) {
        showStacks();
        var result = Java.cast(a, Java.use("java.util.ArrayList"));
        console.log("collections.sort List Comparator: ", result.toString());
        return this.sort(a, b);
    }

// 下述方法也可以使用此类操作
java.util.Arrays sort toString

7 JSONObject的put、getString方法等


 var jSONObject = Java.use("org.json.JSONObject");
    jSONObject.put.overload('java.lang.String', 'java.lang.Object')
.implementation = function (a, b) {
    showStacks();
    //var result = Java.cast(a, Java.use("java.util.ArrayList"));
    console.log("jSONObject.put: ", a, b);
    return this.put(a, b);
}
jSONObject.getString.implementation = function (a) {
    //showStacks();
    //var result = Java.cast(a, Java.use("java.util.ArrayList"));
    console.log("jSONObject.getString: ", a);
    var result = this.getString(a);
    console.log("jSONObject.getString result: ", result);
    return result;
}

8. Toast的show方法

var toast = Java.use("android.widget.Toast");
toast.show.implementation = function () {
    showStacks();
    console.log("toast.show: ");
    return this.show();
}

9 hookbase加密算法


 var base64 = Java.use("android.util.Base64");
base64.encodeToString.overload('[B', 'int').implementation = function (a, b) {
    showStacks();
    console.log("base64.encodeToString: ", JSON.stringify(a));
    var result = this.encodeToString(a, b);
    console.log("base64.encodeToString result: ", result)
    return result;
}

// 如下方法也可照例Hook
java.net.URLEncoder
java.util.Base64
okio.Base64
okio.ByteString

10. String的getBytes、isEmpty方法

var str = Java.use("java.lang.String");
str.getBytes.overload().implementation = function () {
    showStacks();
    var result = this.getBytes();
    var newStr = str.$new(result);
    console.log("str.getBytes result: ", newStr);
    return result;
}
str.getBytes.overload('java.lang.String').implementation = function (a) {
    showStacks();
    var result = this.getBytes(a);
    var newStr = str.$new(result, a);
    console.log("str.getBytes result: ", newStr);
    return result;
}

11 String构造函数的Hook

 var stringFactory = Java.use("java.lang.StringFactory");
stringFactory.newStringFromString.implementation = function (a) {
    showStacks();
    var retval = this.newStringFromString(a);
    console.log("stringFactory.newStringFromString: ", retval);
    return retval;
}
stringFactory.newStringFromChars.overload('[C').implementation = function (a) {
    showStacks();
    var retval = this.newStringFromChars(a);
    console.log("stringFactory.newStringFromChars: ", retval);
    return retval;
}

newStringFromBytes、newStringFromChars
newStringFromString、newStringFromStringBuffer、newStringFromStringBuilder

12. StringBuilder、StringBuffer的Hook

var sb = Java.use("java.lang.StringBuilder");
sb.toString.implementation = function () {
    var retval = this.toString();
    if (retval.indexOf("Encrypt") != -1) {
        showStacks();
    }
    console.log("StringBuilder.toString: ", retval);
    return retval;
}
var sb = Java.use("java.lang.StringBuffer");
sb.toString.implementation = function () {
    var retval = this.toString();
    if (retval.indexOf("username") != -1) {
        showStacks();
    }
    console.log("StringBuffer.toString: ", retval);
    return retval;
}

13. findViewById 找控件id(打印R$id的属性)

a) Java.enumerateLoadedClassesSync枚举所有已加载的类
    如果不知道类路径,可以用这个方法,然后过滤一下类名
b) frida -U -f com.dodonew.online -l HookDemo.js -o log.txt --no-pause
-f 代码让frida帮我们重新启动app,一开始就注入js
--no-pause 直接运行主线程,中途不暂停
c) R$id 内部类的访问
d) R$id.btn_login.value 类的属性的访问

var btn_login_id = Java.use("com.dodonew.online.R$id").btn_login.value;
console.log("btn_login_id", btn_login_id);
var appCompatActivity = Java.use("android.support.v7.app.AppCompatActivity");
appCompatActivity.findViewById.implementation = function (a) {
    if(a == btn_login_id){
        showStacks();
        console.log("appCompatActivity.findViewById: ", a);
    }
    return this.findViewById(a);
}

14. setOnClickListener

// hook这个函数,比对控件id,打印函数栈
var btn_login_id = Java.use("com.dodonew.online.R$id").btn_login.value;
console.log("btn_login_id", btn_login_id);

var view = Java.use("android.view.View");
view.setOnClickListener.implementation = function (a) {
if(this.getId() == btn_login_id){
    showStacks();
    console.log("view.id: " + this.getId());
    console.log("view.setOnClickListener is called");
}
return this.setOnClickListener(a);
}

15加密库相关的hook(自吐算法)

SSL相关的hook
socket相关的hook
SocketOutputStream
SocketInputStream
读写文件相关的 java.io.File
证书双向验证 Keystore.load 通常有证书和密码
安卓退出进程的方式

//快速定位协议头加密okhttp3的addHeader方法
var okhttp_Builder = Java.use('okhttp3.Request$Builder');
okhttp_Builder.addHeader.implementation = function (a, b) {
    showStacks();
    return this.addHeader(a, b);
}

16 在多线程中快速定位关键代码

//java.lang.Thread相关代码或者以下的线程池相关代码
var ThreadPoolExecutor = Java.use("java.util.concurrent.ThreadPoolExecutor");
ThreadPoolExecutor.execute.implementation = function (a) {
    showStacks();
    return this.execute(a);
}
ThreadPoolExecutor.submit.overload('java.lang.Runnable').implementation = function (a) {
    showStacks();
    return this.submit(a);
}
ThreadPoolExecutor.submit.overload('java.util.concurrent.Callable').implementation = function (a) {
    showStacks();
    return this.submit(a);
}
ThreadPoolExecutor.submit.overload('java.lang.Runnable', 'java.lang.Object').implementation = function (a, b) {
    showStacks();
    return this.submit(a, b);
}