Frida's CTF idea of actively calling Java classes/methods to blast

Use Frida to call classes in java code, and then blast. It is a method of active invocation. Active calls can be used for blasting, simulating part of the execution of the program. The knowledge point that needs to be noted is that the static type data in the java code needs to reset the value of this type every time during the blasting process. Because the static type is uniform in all instances, modifying one instance will modify all instances, and the 变量.属性.value = ...value needs to be reset using the wording method.

var bvar = b.$new(IntClass.$new(2));
for (...) {
    bvar._static_val.value = ...;
}

background knowledge

The static value in the java class needs to be modified during the blasting

In the Java class, if an attribute is true static, it does not mean that the value cannot be changed, but that the attribute is unique in the program. No matter how many instances, as long as the value of static in one instance is changed, other instances correspond to The value will also be changed.

During the blasting process, if you need to keep creating a new class instance during the blasting process, remember to check if there are any variables of static type. Such as the following example

public class b {
    public static ArrayList<Integer> a = new ArrayList<>();
    static String b = "abcdefghijklmnopqrstuvwxyz";
    static Integer d = 0;
    Integer[] c = {8, 25, 17, 23, 7, 22, 1, 16, 6, 9, 21, 0, 15, 5, 10, 18, 2, 24, 4, 11, 3, 14, 19, 12, 20, 13};


    public b(Integer num) {
        for (int intValue = num.intValue(); intValue < this.c.length; intValue++) {
            a.add(this.c[intValue]);
        }
        for (int i = 0; i < num.intValue(); i++) {
            a.add(this.c[i]);
        }
    }
...

Every time a class b is new, for example b bVar = new b(2), if you want to call this class continuously and use the methods in it, you should pay attention to whether staticthe variables in it will change. If it will change, then during the blasting process, you need to modify the value of the static variable after the instance is new.

Frida calls static methods and dynamic methods in java

If you call a static method, you can call it directly, for example, the java code is as follows

public class Verifier {
    private Verifier() {
    }

    public static boolean verifyPassword(Context context, String input) {
        ...
    }

Then if you call verifyPassword, you can call it directly in frida

var verify = Java.use("org.teamsik.ahe17.qualification.Verifier");
verify.verifyPassword(a, b);

If it is a dynamic method, there are two ways to call a dynamic method

The first is to use the method of existing instances in memory, which needs to be used java.choose(...). This is to find objects in memory

//从内存中(堆)直接搜索已存在的对象
Java.choose('xxx.xxx.xxx', //这里写类名 
{ //onMatch 匹配到对象执行的回调函数
    onMatch: function (instance) {
    },
    //堆中搜索完成后执行的回调函数
    onComplete: function () {
    }
});

The second is that we new a new instance, and then call the method in the instance

//获取类的引用
var cls = Java.use('这里写类名');

//调用构造函数 创建新对象  这里注意参数
var obj = cls.$new();

Easy-QAHE17

The first is to look at a question that I love to crack. The core code is as follows.

public void verifyPasswordClick(View view) {
        String password = this.txPassword.getText().toString();
        if (!Verifier.verifyPassword(this, password)) {
            Toast.makeText(this, (int) org.teamsik.ahe17.qualification.easy.R.string.dialog_failure, 1).show();
        } else {
            showSuccessDialog();
        }
    }

public class Verifier {
    private Verifier() {
    }

    public static boolean verifyPassword(Context context, String input) {
        if (input.length() != 4) {
            return false;
        }
        byte[] v = encodePassword(input);
        byte[] p = "09042ec2c2c08c4cbece042681caf1d13984f24a".getBytes();
        if (v.length == p.length) {
            for (int i = 0; i < v.length; i++) {
                if (v[i] != p[i]) {
                    return false;
                }
            }
            return true;
        }
        return false;
    }
...
...
...

The input length is 4, and it is known that the input is a number after analysis. So the range is 1000-9999. So it can be blasted, but blasting requires encodePassworda method. Of course, it is also possible to write one yourself, but it is very troublesome. Here you can directly call encodePasswordthe function from frida.

Note that encodePassword is a static method here, so it can be called directly

function main() {
    Java.perform(function x() {
        console.log("In Java perform")
        var verify = Java.use("org.teamsik.ahe17.qualification.Verifier")
        var stringClass = Java.use("java.lang.String")
        var p = stringClass.$new("09042ec2c2c08c4cbece042681caf1d13984f24a")
        
        for (var i = 999; i < 10000; i++){
            var v = stringClass.$new(String(i))
            var vSign = verify.encodePassword(v)
            if (parseInt(p) == parseInt(stringClass.$new(vSign))) {
                console.log("yes: " + v)
                break
            }
            console.log("not :" + v)
        }
    })
}
setImmediate(main)

result

not :9078
not :9079
not :9080
not :9081
not :9082
yes: 9083

It should be noted that parseIntthe memory in the parsing memory needs to be called for comparison, because the string type is the string type of java, which is a piece of memory for js code.

EasyJava

This question is a pure java question, the logic is very clear, each input character is checked individually, encrypted and compared. So you can easily think of the idea of ​​blasting

public static Boolean b(String str) {
    if (str.startsWith("flag{") && str.endsWith("}")) {
        String substring = str.substring(5, str.length() - 1);
        b bVar = new b(2);
        a aVar = new a(3);
        StringBuilder sb = new StringBuilder();
        int i = 0;
        for (int i2 = 0; i2 < substring.length(); i2++) {
            sb.append(a(substring.charAt(i2) + "", bVar, aVar));
            Integer valueOf = Integer.valueOf(bVar.b().intValue() / 25);
            if (valueOf.intValue() > i && valueOf.intValue() >= 1) {
                i++;
            }
        }
        return Boolean.valueOf(sb.toString().equals("wigwrkaugala"));
    }
    return false;
}

So it can be blasted with a single character, but it should be noted that there are variables with static attributes in both classes, and the following is class com.a.easyjava.bbcom.a.easyjava.a

public class b {
    public static ArrayList<Integer> a = new ArrayList<>();
    static String b = "abcdefghijklmnopqrstuvwxyz";
    static Integer d = 0;
    Integer[] c = {8, 25, 17, 23, 7, 22, 1, 16, 6, 9, 21, 0, 15, 5, 10, 18, 2, 24, 4, 11, 3, 14, 19, 12, 20, 13};

    public b(Integer num) {
        for (int intValue = num.intValue(); intValue < this.c.length; intValue++) {
            a.add(this.c[intValue]);
        }
        for (int i = 0; i < num.intValue(); i++) {
            a.add(this.c[i]);
        }
    }

    public static void a() {
        int intValue = a.get(0).intValue();
        a.remove(0);
        a.add(Integer.valueOf(intValue));
        b += "" + b.charAt(0);
        b = b.substring(1, 27);
        Integer num = d;
        d = Integer.valueOf(d.intValue() + 1);
    }

    public Integer a(String str) {
        int i = 0;
        if (b.contains(str.toLowerCase())) {
            Integer valueOf = Integer.valueOf(b.indexOf(str));
            for (int i2 = 0; i2 < a.size() - 1; i2++) {
                if (a.get(i2) == valueOf) {
                    i = Integer.valueOf(i2);
                }
            }
        } else {
            i = str.contains(" ") ? -10 : -1;
        }
        a();
        return i;
    }

    public Integer b() {
        return d;
    }
}

While the a, b, and d variables in class b are all static types, these three variables will be changed by the following methods. So if you want to blast, you need to re-modify the attribute values ​​​​in the instance. If we do not re-modify the value of the attribute, we can see what is wrong by observing the b variable in the b class.

This script is to blast the first character with all possibilities after encryption. The scope of blasting can be narrowed down by analyzing category b a-z, and then imitate the encryption process, encrypt a character and see the result. Every cycle in the middle will re-apply for an instance of the bclass aand want to avoid modification of variables in the class by applying for a new instance.

function main() {
    Java.perform(function x() {
        console.log('[+] script load');
        
        var b = Java.use("com.a.easyjava.b");
        var a = Java.use("com.a.easyjava.a");
        var StringClass = Java.use("java.lang.String");
        var IntClass = Java.use("java.lang.Integer");
        var MainActivity = Java.use("com.a.easyjava.MainActivity");

        try { // try catch 用来查看报错的,可以去掉
            for (var i = 97; i < 123; i++) {
                var bvar = b.$new(IntClass.$new(2));
                var avar = a.$new(IntClass.$new(3));

                var s = String.fromCharCode(i);
                var c = MainActivity.a(s, bvar, avar);
                console.log(`enc(${s}) => ${c}, b.a => ${b._b.value}`);
            }
        } catch (e) {
            console.log(e);
        }
        console.log('[+] script end');
    })
}
setImmediate(main)

The result is as follows

# python3 loader.py
[+] script load
enc(a) => a, b.b => bcdefghijklmnopqrstuvwxyza
enc(b) => a, b.b => cdefghijklmnopqrstuvwxyzab
enc(c) => a, b.b => defghijklmnopqrstuvwxyzabc
enc(d) => a, b.b => efghijklmnopqrstuvwxyzabcd
enc(e) => a, b.b => fghijklmnopqrstuvwxyzabcde
enc(f) => a, b.b => ghijklmnopqrstuvwxyzabcdef
enc(g) => a, b.b => hijklmnopqrstuvwxyzabcdefg
enc(h) => a, b.b => ijklmnopqrstuvwxyzabcdefgh
enc(i) => a, b.b => jklmnopqrstuvwxyzabcdefghi
enc(j) => a, b.b => klmnopqrstuvwxyzabcdefghij
enc(k) => a, b.b => lmnopqrstuvwxyzabcdefghijk
enc(l) => a, b.b => mnopqrstuvwxyzabcdefghijkl
enc(m) => a, b.b => nopqrstuvwxyzabcdefghijklm
enc(n) => a, b.b => opqrstuvwxyzabcdefghijklmn
enc(o) => a, b.b => pqrstuvwxyzabcdefghijklmno
enc(p) => a, b.b => qrstuvwxyzabcdefghijklmnop
enc(q) => a, b.b => rstuvwxyzabcdefghijklmnopq
enc(r) => a, b.b => stuvwxyzabcdefghijklmnopqr
enc(s) => a, b.b => tuvwxyzabcdefghijklmnopqrs
enc(t) => a, b.b => uvwxyzabcdefghijklmnopqrst
enc(u) => a, b.b => vwxyzabcdefghijklmnopqrstu
enc(v) => a, b.b => wxyzabcdefghijklmnopqrstuv
enc(w) => a, b.b => xyzabcdefghijklmnopqrstuvw
enc(x) => a, b.b => yzabcdefghijklmnopqrstuvwx
enc(y) => a, b.b => zabcdefghijklmnopqrstuvwxy
enc(z) => a, b.b => abcdefghijklmnopqrstuvwxyz
[+] script end

It can be seen that in fact, although a new instance is created every time, the static variable in the instance changes, which causes the previous blasting to affect the next blasting, and it can also be seen that the encryption results are all a. So if you want to blast, you have to find a way to keep the value in the new instance unchanged every time you blast.

You need to use bvar._b.value = StringClass.$new("abcdefghijklmnopqrstuvwxyz");this syntax to reset the value of a variable of static type.

It should be noted that the names of some variables seen in jadx/jeb may be overloaded, and an underscore needs to be added, such as b -> _b. You can print it through the console to see if it is unknown, or you can directly use jadx to right-click to copy the frida segment, and check whether this variable frida needs to be underlined

The idea of ​​the problem-solving script is very simple, a single character is blasted, an instance of the class is regenerated each time, and the value in the class is set to the initial state (by calling the class $initmethod).

exp

function main() {
    Java.perform(function x() {
        console.log('[+] script load');

        var b = Java.use("com.a.easyjava.b");
        var a = Java.use("com.a.easyjava.a");
        var IntClass = Java.use("java.lang.Integer");
        var StringClass = Java.use("java.lang.String");
        var ArrayList = Java.use("java.util.ArrayList");
        var MainActivity = Java.use("com.a.easyjava.MainActivity");

        var flag = new Array();
        var cipher = "wigwrkaugala";

        var bvar = b.$new(IntClass.$new(2));
        var avar = a.$new(IntClass.$new(3));

        for (var _ = 0; _ < cipher.length; _++) {
            for (var i = 97; i < 123; i++) { // 97 - 123是字母a-z
                // reset static value
                bvar._b.value = StringClass.$new("abcdefghijklmnopqrstuvwxyz");
                bvar.d.value = IntClass.$new(0);
                bvar._a.value = ArrayList.$new();
                bvar["$init"](IntClass.$new(2));

                avar.b.value = StringClass.$new("abcdefghijklmnopqrstuvwxyz");
                avar.d.value = IntClass.$new(0);
                avar._a.value = ArrayList.$new();
                avar["$init"](IntClass.$new(3));

                var s = String.fromCharCode(i);
                flag.push(s);

                for (var e = 0; e < flag.length; e++) {
                    var c = MainActivity.a(flag[e].toString(), bvar, avar);
                    if (c != cipher[e]) {
                        break;
                    }
                }
                if (c == cipher[flag.length - 1]) {
                    console.log(flag);
                    break
                }
                flag.length -= 1;
            }
        }
        console.log('flag{' + flag.join('') + '}');
        console.log('[+] script end');
    })
}
setImmediate(main);

result

root@kali ~/frida-script-dev# python3 loader.py
[+] script load
v
v,e
v,e,n
v,e,n,i
v,e,n,i,v
v,e,n,i,v,i
v,e,n,i,v,i,a
v,e,n,i,v,i,a,i
v,e,n,i,v,i,a,i,v
v,e,n,i,v,i,a,i,v,i
v,e,n,i,v,i,a,i,v,i,c
v,e,n,i,v,i,a,i,v,i,c,i
flag{veniviaivici}
[+] script end

reference

Frida Android hook | Sakura's blog (eternalsakura13.com)

52pojie2020 Spring Festival Red Envelope-Third Question (Upgraded Version) Violent Cracking

Frida actively calls the app method - Programmer Sought (manongjc.com)

Java static difference_Difference between Java static and dynamic_

Offensive and defensive world novice exercises_MOBILE (Mobile) - Cainiao - Legend - Blog Garden (cnblogs.com)

Call for original manuscripts

Call for original technical articles, welcome to post

Submission email: [email protected]

Article type: hacker geek technology, information security hotspots, security research and analysis, etc.

If you pass the review and publish it, you can get a remuneration ranging from 200-800 yuan.

For more details, click me to view!

e41b867968536b0554502f945321b26f.gif

Shooting range practice, click "Read the original text "

Guess you like

Origin blog.csdn.net/qq_38154820/article/details/131672102