Android逆向:frida学习(2)

在Android逆向:frida学习(1)中已经介绍了frida的安装与基本使用方法,并且以一道2015年的SECCON CTF例题展示了如何使用它的hook功能。下面还是以一道CTF题目来对frida的使用进行进一步说明


题目分析

首先看一下Mainifest文件,发现有两个activity
Android逆向:frida学习(2)_第1张图片
在LaucherActivity中,关键代码如下:

	public void verifyClick(View arg16) {
        String v6 = this.findViewById(0x7F0B005D).getText().toString();
        try {
            InputStream v5 = new URL("http://broken.license.server.com/query?license=" + v6).openConnection().getInputStream();
            StringBuilder v9 = new StringBuilder();
            byte[] v1 = new byte[0];
            while(v5.read(v1) > 0) {
                v9.append(v1);
            }

            String v8 = v9.toString();
            if(v8.equals("LICENSEKEYOK")) {
                String v0 = new String(MainActivity.xor(this.getMac().getBytes(), v8.getBytes()));
                SharedPreferences$Editor v4 = this.getApplicationContext().getSharedPreferences("preferences", 0).edit();
                v4.putString("KEY", v0);
                v4.commit();
                new Builder(((Context)this)).setTitle("Activation successful").setMessage("Activation successful").setIcon(0x1080027).show();
                return;
            }

            new Builder(((Context)this)).setTitle("Invalid license!").setMessage("Invalid license!").setIcon(0x1080027).show();
        }
        catch(Exception v3) {
            new Builder(((Context)this)).setTitle("Error occured").setMessage("Server unreachable").setNeutralButton("OK", null).setIcon(0x1080027).show();
        }
    }

该函数会向一个不存在的url发送我们填写的数据,只有收到’LICENSEKEYOK'才能继续
函数先利用该字符串与Mac地址进行亦或得到KEY,并且在启动MainActivity的时候会把KEY和MAC地址传过去

	public void showPremium(View arg4) {
        Intent v0 = new Intent(((Context)this), MainActivity.class);
        v0.putExtra("MAC", this.getMac());
        v0.putExtra("KEY", this.getKey());
        this.startActivity(v0);
    }

根据MainActivity中的onCreate(),大体可以判断获得flag需要把MAC地址和KEY当做参数传给stringFromJNI()

	protected void onCreate(Bundle arg6) {
        String v0 = this.getIntent().getStringExtra("KEY");
        String v1 = this.getIntent().getStringExtra("MAC");
        if(v0 == "" || v1 == "") {
            v0 = "";
            v1 = "";
        }

        super.onCreate(arg6);
        this.setContentView(0x7F04001B);
        this.findViewById(0x7F0B0060).setText(this.stringFromJNI(v0, v1));
    }

当然了,向之前的rps那题一样,本题也可以去逆向so文件,不过本文还是讲使用frida的hook来解题

解题思路

通过上面的分析,我们的解题思路如下:

  1. 调用程序中的getMac()获得Mac地址
  2. 把Mac地址和’LICENSEKEYOK'当做参数传给xor()计算出KEY
  3. 把getkey()给hook了,让它返回值为刚才计算的KEY
  4. 调用showPremium(),这样就能获得flag
  5. 把上面1-4步hook verifyClick()

解题流程

按照Android逆向:frida学习(1)中的操作配置好frida-server,然后运行下面的脚本

import frida, sys

def on_message(message, data):
    if message['type'] == 'send':
        print("[*] {0}".format(message['payload']))
    else:
        print(message)

jscode = """
Java.perform(function () {
	var LauncherActivity = Java.use('de.fraunhofer.sit.premiumapp.LauncherActivity');
	var MainActivity = Java.use('de.fraunhofer.sit.premiumapp.MainActivity');

	var mac = "";
    var mac_bytes = [];
    var key = "";
    LauncherActivity.verifyClick.implementation = function(v){
        send("Hook LauncherActivity.verifyClick.");
        mac = this.getMac();
        send("mac is: " + mac.toString());
        for (var i = 0; i < mac.length; ++i) {
            var code = mac.charCodeAt(i);
            mac_bytes = mac_bytes.concat([code]);
        }
        var resp = "LICENSEKEYOK";
        var resp_bytes = [];
        for (var i = 0; i < resp.length; ++i) {
            var code = resp.charCodeAt(i);
            resp_bytes = resp_bytes.concat([code]);
        }
        var key_bytes = MainActivity.xor(mac_bytes, resp_bytes);
        for (var i = 0; i < key_bytes.length; ++i) {
            key += (String.fromCharCode(key_bytes[i]));
        }
        send("key is: " + key.toString());
    }
    LauncherActivity.getKey.implementation = function () {
        return key;
    }
});
"""

process = frida.get_usb_device().attach('de.fraunhofer.sit.premiumapp')
script = process.create_script(jscode)
script.on('message', on_message)
print('[*] Running CTF')
script.load()
sys.stdin.read()

charCodeAt() 方法可返回指定位置的字符的 Unicode 编码。这个返回值是 0 - 65535 之间的整数。类似python中的ord()
fromCharCode() 可接受一个指定的 Unicode 值,然后返回一个字符串。类似python中的chr()
concat() 方法用于连接两个或多个数组。该方法不会改变现有的数组,而仅仅会返回被连接数组的一个副本。

收到KEY
Android逆向:frida学习(2)_第2张图片

点击PREMIUM CONTENT获得flag
Android逆向:frida学习(2)_第3张图片

你可能感兴趣的:(Andriod逆向学习,CTF知识学习)