Frida 学习笔记

Frida

Hook 神器(Windows,MacOS,Linux,iOS,Android,Javscript)

Install

(Python2.7 or  python 3.6)

sudo pip2 install frida

下载服务段(选择相应的平台)

https://github.com/frida/frida/releases


adb push frida-server /data/tmp/frida-server
adb shell
chmod 777 /data/tmp/frida-server
./data/tmp/frida-server

adb forward tcp:27042 tcp:27042

Usage

这里只写Android平台上面的利用

Java.available 判断所hook的类是否可用

Example

#coding:utf-8

import frida, sys

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

jscode = """
Java.perform(function () {
    send("Is Java.available?");
    send(Java.available);
    if(Java.available)
        send("It is! :)");
    else
        send("It isn't! :(");
});
"""

process = frida.get_usb_device().attach('com.ctf.vezel')  #载入app
script = process.create_script(jscode) #载入脚本
script.on('message', on_message)
print('[*] Running ')
script.load()
sys.stdin.read()

"""

Java.enumerateLoadedClasses 列出所加载类

Example

#coding:utf-8

import frida, sys

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

jscode = """
Java.perform(function () {
Java.enumerateLoadedClasses({
    "onMatch": function(className){ 
    console.log(className) 
    },
     "onComplete":function(){}
      }
   )
});
"""

process = frida.get_usb_device().attach('com.ctf.vezel')  #载入app
script = process.create_script(jscode) #载入脚本
script.on('message', on_message)
print('[*] Running CTF')
script.load()
sys.stdin.read()

一些栗子

一开始入门就拿官方的例子来写poc

题目地址 Apk1

反编译之后

public class MainActivity
extends Activity
implements View.OnClickListener {
    Button P;
    Button S;
    int cnt = 0;
    int flag;
    private final Handler handler = new Handler();
    int m;
    int n;
    Button r;
    private final Runnable showMessageTask;
 
    static {
        System.loadLibrary("calc");
    }
 
    public MainActivity() {
        this.showMessageTask = new Runnable(){
 
            /*
             * Enabled aggressive block sorting
             */
            @Override
            public void run() {
                TextView textView = (TextView)MainActivity.this.findViewById(2131492946);
                if (MainActivity.this.n - MainActivity.this.m == 1) {
                    MainActivity mainActivity = MainActivity.this;
                    ++mainActivity.cnt;
                    textView.setText((CharSequence)("WIN! +" + String.valueOf(MainActivity.this.cnt)));
                } else if (MainActivity.this.m - MainActivity.this.n == 1) {
                    MainActivity.this.cnt = 0;
                    textView.setText((CharSequence)"LOSE +0");
                } else if (MainActivity.this.m == MainActivity.this.n) {
                    textView.setText((CharSequence)("DRAW +" + String.valueOf(MainActivity.this.cnt)));
                } else if (MainActivity.this.m < MainActivity.this.n) {
                    MainActivity.this.cnt = 0;
                    textView.setText((CharSequence)"LOSE +0");
                } else {
                    MainActivity mainActivity = MainActivity.this;
                    ++mainActivity.cnt;
                    textView.setText((CharSequence)("WIN! +" + String.valueOf(MainActivity.this.cnt)));
                }
                if (1000 == MainActivity.this.cnt) {
                    textView.setText((CharSequence)("SECCON{" + String.valueOf((MainActivity.this.cnt + MainActivity.this.calc()) * 107) + "}"));
                }
                MainActivity.this.flag = 0;
            }
        };
    }
 
    public native int calc();
 

我们可以看出只要cnt等于1000 那么就会成功输出flag. 所以我们只要hook住onclick事件然后修改变量使n-m=1和cnt=999即可满足条件

  if (MainActivity.this.n - MainActivity.this.m == 1) {
                    MainActivity mainActivity = MainActivity.this;
                    ++mainActivity.cnt;

poc

import frida, sys

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

jscode = """
Java.perform(function () {
    // Function to hook is defined here
    var MainActivity = Java.use('com.example.seccon2015.rock_paper_scissors.MainActivity');

    // Whenever button is clicked
    MainActivity.onClick.implementation = function (v) {
        // Show a message to know that the function got called
        send('onClick');

        // Call the original onClick handler
        this.onClick(v);

        // Set our values after running the original onClick handler
        this.m.value = 0;
        this.n.value = 1;
        this.cnt.value = 999;

        // Log to the console that it's done, and we should have the flag!
        console.log('Done:' + JSON.stringify(this.cnt));
    };
});
"""

process = frida.get_usb_device().attach('com.example.seccon2015.rock_paper_scissors')
script = process.create_script(jscode)
script.on('message', on_message)
print('[*] Running CTF')
script.load()
sys.stdin.read()

经过这一个例子,自己就随便拿了0ctf的Android逆向题目 Apk2 反编译之后

public class MainActivity
extends ActionBarActivity {
    Button bt;
    EditText et;
 
    private String getCrc() {
        long l;
        try {
            l = new ZipFile(this.getApplicationContext().getPackageCodePath()).getEntry("classes.dex").getCrc();
        }
        catch (Exception exception) {
            exception.printStackTrace();
            return "";
        }
        return String.valueOf(l);
    }
 
    private int getSig(String string2) {
        PackageManager packageManager = this.getPackageManager();
        try {
            int n = packageManager.getPackageInfo((String)string2, (int)64).signatures[0].toCharsString().hashCode();
            return n;
        }
        catch (Exception exception) {
            exception.printStackTrace();
            return 0;
        }
    }
 
    public void confirm(View object) {
        int n = this.getSig(this.getPackageName());
        object = this.getCrc();
        if (("0CTF{" + String.valueOf(n) + (String)object + "}").equals(this.et.getText().toString())) {
            Toast.makeText((Context)this, (CharSequence)"Yes!", (int)0).show();
            return;
        }
        Toast.makeText((Context)this, (CharSequence)"0ops!", (int)0).show();
    }

可以看出flag是由getSig和getCrc两个函数得到的 所以我们只要hook住两个函数然后获得其返回结果拼接成flag即可

#coding:utf-8

import frida, sys

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

jscode = """
Java.perform(function () {
    // Function to hook is defined here
    var MainActivity = Java.use('com.ctf.vezel.MainActivity'); 

    // Whenever button is clicked
   MainActivity.getSig.implementation = function (string2) {
        send('getSig');
       this.getSig(string2);
       var n = this.getSig(string2);
       console.log(n);
        
  };
    MainActivity.getCrc.implementation = function () {
        send('getCrc');
        this.getCrc();
        var n = this.getCrc();
        console.log(n);
        
    };
});
"""

process = frida.get_usb_device().attach('com.ctf.vezel')  #载入app
script = process.create_script(jscode) #载入脚本
script.on('message', on_message)
print('[*] Running CTF')
script.load()
sys.stdin.read()

得到返回

[*] Running CTF
[*] getSig
-183971537
[*] getCrc
1189242199

所以flag就是 0CTF{-1839715371189242199}

Frida这个Hook工具还是十分好用,而且编写poc还是十分简单的。只要能发现到关键的函数只需要几行代码就可以hook住关键函数。

最重要的就是这个工具通杀各个平台!

comments powered by Disqus