通过Frida-Labs 筑牢frida基础

admin 2025年1月15日11:12:17评论8 views字数 10600阅读35分20秒阅读模式

https://github.com/DERE-ad2001/Frida-Labs

免责声明

本公众号"好文推送"旨在分享网络安全领域的相关知识和工具,仅限于学习和研究之用。由于传播、利用本公众号"好文推送"所提供的信息而造成的任何直接或者间接的后果及损失,由使用者承担全部法律及连带责任,公众号"好文推送"及作者不为此承担任何责任。

有侵权烦请告知,我们会立即删除并致歉,谢谢。

准备工作

已经root的安卓设备一台,电脑手机安装完frida环境

adb 连接adb connect 172.20.10.2:40529(手机开启无线调试)

通过Frida-Labs 筑牢frida基础

启动frida

通过Frida-Labs 筑牢frida基础

安装软件

adb install ""

通过Frida-Labs 筑牢frida基础

Frida 0x1 简单hook

Frida setup, Hooking a method

jadx打开app。

通过Frida-Labs 筑牢frida基础

显然hook:check函数使得i*2+4==i2就行,其中i是随机数。

通过Frida-Labs 筑牢frida基础

所以hook后

1、i2=i*2+4

setTimeout(//该方法接受一个匿名方法并注册到js运行库中Java.perform(//是 Frida 中的一个函数,用于为脚本创建一个特殊上下文,以便与 Android 应用程序中的 Java 代码进行交互    function() {//一个匿名函数    let MainActivity = Java.use("com.ad2001.frida0x1.MainActivity");//要hook的类    MainActivity["check"].implementation = function (i, i2) {//覆盖调用栈中原函数的执行地址实现hook            i2 = i*2+4        console.log(`MainActivity.check is called: i=${i}, i2=${i2}`);        this["check"](i, i2);//调用原来的check函数    };  }  ))

直接是实现了任意密码

通过Frida-Labs 筑牢frida基础

2、i = (i2-4)/2 这里要考虑到除2就不是int了,故只能输入2的整数倍的值切要大于4

setTimeout(//该方法接受一个匿名方法并注册到js运行库中Java.perform(//是 Frida 中的一个函数,用于为脚本创建一个特殊上下文,以便与 Android 应用程序中的 Java 代码进行交互    function() {//一个匿名函数    let MainActivity = Java.use("com.ad2001.frida0x1.MainActivity");//要hook的类    MainActivity["check"].implementation = function (i, i2) {//覆盖调用栈中原函数的执行地址实现hook            i = (i2-4)/2        console.log(`MainActivity.check is called: i=${i}, i2=${i2}`);        this["check"](i, i2);//调用原来的check函数    };  }  ))
通过Frida-Labs 筑牢frida基础

3、直接输入一个密码0、4

setTimeout(Java.perform(    function() {    let MainActivity = Java.use("com.ad2001.frida0x1.MainActivity");    MainActivity["check"].implementation = function (i, i2) {        console.log(`MainActivity.check is called: i=${i}, i2=${i2}`);        this["check"](0, 4);    };  }  ))

hook get_random()函数

1、直接设置随机数为0,那么密码应该是4

通过Frida-Labs 筑牢frida基础

setTimeout(//该方法接受一个匿名方法并注册到js运行库中Java.perform(//是 Frida 中的一个函数,用于为脚本创建一个特殊上下文,以便与 Android 应用程序中的 Java 代码进行交互    function() {//一个匿名函数    let MainActivity = Java.use("com.ad2001.frida0x1.MainActivity");    MainActivity["get_random"].implementation = function () {        console.log(`MainActivity.get_random is called`);        let result = this["get_random"]();//获取原来的随机数        console.log(`MainActivity.get_random result=${result}`);        result = 0;        console.log(`MainActivity.get_random result=${result}`);        return result;    };        MainActivity["check"].implementation = function (i, i2) {          //i2 = i*2+4        console.log(`MainActivity.check is called: i=${i}, i2=${i2}`);        this["check"](i, i2);    };  }  ))

通过Frida-Labs 筑牢frida基础

2、直接打印密码

setTimeout(//该方法接受一个匿名方法并注册到js运行库中Java.perform(//是 Frida 中的一个函数,用于为脚本创建一个特殊上下文,以便与 Android 应用程序中的 Java 代码进行交互    function() {//一个匿名函数    let MainActivity = Java.use("com.ad2001.frida0x1.MainActivity");    MainActivity["get_random"].implementation = function () {        console.log(`MainActivity.get_random is called`);        let result = this["get_random"]();//获取原来的随机数        console.log(`MainActivity.get_random result=${result}`);        console.log("The value to bypass the check "+(result* 2 + 4));        return result;    };  }  ))
通过Frida-Labs 筑牢frida基础

Frida 0x2 主动调用静态函数

通过Frida-Labs 筑牢frida基础

显然这里get_flag是我们要的东西,先hook看看

setTimeout(Java.perform(    function() {    let MainActivity = Java.use("com.ad2001.frida0x2.MainActivity");    MainActivity["get_flag"].implementation = function (a) {        console.log(`MainActivity.get_flag is called: a=${a}`);        this["get_flag"](a);    };  }  ))

通过Frida-Labs 筑牢frida基础

显然没有调用,那我们主动调用,if条件要满足传入参数4919

setTimeout(Java.perform(    function() {    let MainActivity = Java.use("com.ad2001.frida0x2.MainActivity");    MainActivity["get_flag"] (4919);  }  ))

通过Frida-Labs 筑牢frida基础

这里直接脚本启动修改不了,显然是hook早了。需要启动后再hook,那只能在命令行hook了。

Frida 0x3 主动设置类静态值

通过Frida-Labs 筑牢frida基础

显然先要让chcker.code==512,看下check

通过Frida-Labs 筑牢frida基础

功能就是点击256下就可以,那么点击的时候会increase吗?hook一下看看

setTimeout(    Java.perform(        function() {            let Checker = Java.use("com.ad2001.frida0x3.Checker");            let AnonymousClass1 = Java.use("com.ad2001.frida0x3.MainActivity$1");            AnonymousClass1["onClick"].implementation = function (v) {                var code = Checker.code.value;                console.log(`AnonymousClass1.onClick is called: codoe=${code}`);                this["onClick"](v);            };      }))

通过Frida-Labs 筑牢frida基础

显然不会,那我们现在有两个思路,一调用increase 256次,二直接设置code==512

1、调用increase 256次

setTimeout(    Java.perform(        function() {            let Checker = Java.use("com.ad2001.frida0x3.Checker");            let AnonymousClass1 = Java.use("com.ad2001.frida0x3.MainActivity$1");            AnonymousClass1["onClick"].implementation = function (v) {                while(Checker.code.value != 512){                    Checker.increase();                }                var code = Checker.code.value;                console.log(`AnonymousClass1.onClick is called: codoe=${code}`);                this["onClick"](v);            };      }))
通过Frida-Labs 筑牢frida基础

也是可以的,直接在onclick的时候调用256次

通过Frida-Labs 筑牢frida基础

也是直接拿下了

2、直接设置code==512

setTimeout(    Java.perform(        function() {            let Checker = Java.use("com.ad2001.frida0x3.Checker");            let AnonymousClass1 = Java.use("com.ad2001.frida0x3.MainActivity$1");            AnonymousClass1["onClick"].implementation = function (v) {                Checker.code.value = 512                var code = Checker.code.value;                console.log(`AnonymousClass1.onClick is called: codoe=${code}`);                this["onClick"](v);            };      }      ))

通过Frida-Labs 筑牢frida基础

Ok也是可以直接拿下的。

Frida 0x4 主动调用动态函数1

打开发现mainActivity什么都没有,启动看看是在干什么。好的也只是打印了下hello hackers:)

通过Frida-Labs 筑牢frida基础

通过Frida-Labs 筑牢frida基础

可以看到有个check类,那么我们只要调用check类里的get_flag就行了,easy

Java.perform(        function() {            let Check = Java.use("com.ad2001.frida0x4.Check");            Check.get_flag(1337)      })
通过Frida-Labs 筑牢frida基础

啊报错了,怎么回事,那是因为get_flag不是static修饰的了,所以我们要这个对象。

1、生成一个对象

Java.perform(        function(){            let Check = Java.use("com.ad2001.frida0x4.Check");            var Check1 = Check.$new()            var str = Check1.get_flag(1337)            console.log('flag'+str)        }    )
通过Frida-Labs 筑牢frida基础

2、内存里寻找一个对象

通过Frida-Labs 筑牢frida基础

setTimeout(        Java.perform(            function() {                Java.choose("com.ad2001.frida0x4.Check",{                onMatch:function(instance){                    console.log("onMatch")                    var str = instance.get_flag(1337)                    console.log(str)                },                onComplete:function(){                    console.log("onComplete")                }                })        }    ))

通过Frida-Labs 筑牢frida基础

当然这是我在内存里生成了许多对象,直接内存里找不到。

通过Frida-Labs 筑牢frida基础

Frida 0x5  主动调用动态函数2

通过Frida-Labs 筑牢frida基础

显然这里也不是一个static方法。我们依然用4里的两种方法。

1生成一个对象

Java.perform(        function(){            let MainActivity= Java.use("com.ad2001.frida0x5.MainActivity");            var MainActivity2 = MainActivity.$new()            var str = MainActivity2.flag(1337)            console.log('flag'+str)        }    )

通过Frida-Labs 筑牢frida基础

显然失败了,由于 Android 的生命周期和线程规则,直接使用 Frida 创建 MainActivity 或任何 Android 组件的实例可能会很棘手。Android 组件(如 Activity 子类)依赖应用程序上下文才能正常运行。在 Frida 中,您可能缺少必要的上下文。Android UI 组件通常需要具有关联 Looper 的特定线程。如果您正在处理 UI 任务,请确保您在具有活动 Looper 的主线程上。活动是更大的 Android 应用程序生命周期的一部分。创建 MainActivity 的实例可能需要应用程序处于特定状态,并且通过 Frida 管理整个生命周期可能并不简单。总之,为 MainActivity 创建实例并不是一个好主意。

2、内存里寻找一个对象

setTimeout(        Java.perform(            function() {                Java.choose("com.ad2001.frida0x5.MainActivity",{                onMatch:function(instance){                    console.log("onMatch")                    var str = instance.flag(1337)                    console.log(str)                },                onComplete:function(){                    console.log("onComplete")                }                })        }    ))

通过Frida-Labs 筑牢frida基础

看app里也是成功拿下。

由此可见生成一个对象还是要内存里寻找一个对象取决于实际需求。

Frida 0x6 主动调用动态函数3

通过Frida-Labs 筑牢frida基础

可以看到此次传参使用的是一个对象,所以我们要使用类的处理方法,从前面所学到的,我们这里要构造一个checker对象并设置num1和num2,然后主动调用get_flag

Java.perform(        function(){            let Checker = Java.use("com.ad2001.frida0x6.Checker");            var A = Checker.$new()            A.num1.value = 1234            A.num2.value = 4321            Java.choose("com.ad2001.frida0x6.MainActivity",{                onMatch:function(instance){                    console.log("onMatch")                    var str = instance.get_flag(A)                },                onComplete:function(){                    console.log("onComplete")                }                })        }    )
通过Frida-Labs 筑牢frida基础

Ok 也是拿下了。

Frida 0x7 hook构造函数

通过Frida-Labs 筑牢frida基础

通过Frida-Labs 筑牢frida基础

这里我们也是看到程序里调用了flag函数,那么有两种hook方案,一是主动调用,二是hook让程序调用的条件满足。

1、主动调用

Java.perform(        function(){            let Checker = Java.use("com.ad2001.frida0x7.Checker");            var A = Checker.$new(513,513)            Java.choose("com.ad2001.frida0x7.MainActivity",{                onMatch:function(instance){                    console.log("onMatch")                    var str = instance.flag(A)                },                onComplete:function(){                    console.log("onComplete")                }                })        }    )

通过Frida-Labs 筑牢frida基础

Ok拿下

2、hook让程序调用的条件满足。这里显然我们可以hook flag函数或者hook checker的构造函数

2.1 hook flag函数

let MainActivity = Java.use("com.ad2001.frida0x7.MainActivity");MainActivity["flag"].implementation = function (A) {    console.log(`MainActivity.flag is called: A=${A}`);    this["flag"](A);};
通过Frida-Labs 筑牢frida基础

直接拿下

2.2 hook checker的构造函数

setTimeout(        Java.perform(            function() {                let Checker = Java.use("com.ad2001.frida0x7.Checker");                Checker["$init"].implementation = function (a, b) {                    console.log(`Checker.$init is called: a=${a}, b=${b}`);                    this["$init"](513, 513);                };        }    ))

通过Frida-Labs 筑牢frida基础

也是直接拿下

Frida 0x8 hook native层获取参数值

通过Frida-Labs 筑牢frida基础

这里就是提交了个ip然后比较,然后函数在frida0x8.so文件里,过if语句很简单,直接hook cmpstr函数返回值为1即可。但是这样其实不知道flag是多少。

setTimeout(        Java.perform(            function() {                let MainActivity = Java.use("com.ad2001.frida0x8.MainActivity");                MainActivity["cmpstr"].implementation = function (str) {                    console.log(`MainActivity.cmpstr is called: str=${str}`);                    let result = this["cmpstr"](str);                    console.log(`MainActivity.cmpstr result=${result}`);                    return 1;                };        }    ))

通过Frida-Labs 筑牢frida基础

那么现在我们要掏出神器ida了

通过Frida-Labs 筑牢frida基础

这里找到了反汇编一下

通过Frida-Labs 筑牢frida基础

Hook native层,那么我们要用这个方法

Interceptor.attach(targetAddress, {    onEnter: function (args) {        console.log('Entering ' + functionName);    // Modify or log arguments if needed    },    onLeave: function (retval) {        console.log('Leaving ' + functionName);    // Modify or log return value if needed    }});

这里我们需要知道目标函数的内存地址 targetAddress,获取so的动态地址可以使用以下方法

  • Using the frida API : Module.enumerateExports()枚举

  • Using the frida API : Module.getExportByName()通过name获取

  • Using the frida API : Module.findExportByName()通过name搜索

  • Calculate the offset and add() it to the Module.getBaseAddress() address 基地址+偏移量

  • Using the frida API : Module.enumerateImports()枚举

enumerateExports此 API 枚举指定模块的所有导出(符号)。导出的函数由我们的应用程序在 Java 空间中使用。它需要一个参数,即您要枚举其导出的模块(共享库或可执行文件)的名称。

Module.enumerateExports("libfrida0x8.so")

通过Frida-Labs 筑牢frida基础

通过Frida-Labs 筑牢frida基础

Module.getExportByName("libfrida0x8.so","Java_com_ad2001_frida0x8_MainActivity_cmpstr")

通过Frida-Labs 筑牢frida基础

Module.getBaseAddress("libfrida0x8.so")

通过Frida-Labs 筑牢frida基础

偏移量为0864 对应arm架构的0864偏移量。

通过Frida-Labs 筑牢frida基础

Module.enumerateImports("libfrida0x8.so")//导入

通过Frida-Labs 筑牢frida基础

我们要hook的是strcmp,所以打印下

通过Frida-Labs 筑牢frida基础

Module.enumerateImports("libfrida0x8.so")[4]["address"]

通过Frida-Labs 筑牢frida基础

现在知道地址我们就可以hook了,不同的架构具有不同的调用约定和不同的寄存器

通过Frida-Labs 筑牢frida基础

不建议使用js脚本,因为要在so加载之后才能有address。

var strcmp_adr = Module.enumerateImports("libfrida0x8.so")[4]["address"];Interceptor.attach(strcmp_adr, {    onEnter: function (args) {            //console.log('Entering ');        var arg0 = Memory.readUtf8String(args[0]);//从内存中读取字符串,参数需要是指针        var arg1 = Memory.readUtf8String(args[1]);        if (arg0.includes("Hello")) {//加if因为用到strcmp的函数太多了            console.log("Hookin the strcmp function");            console.log(arg1);        }                    },    onLeave: function (retval) {    }})

Frida 0x9 hook native层修改返回值

通过Frida-Labs 筑牢frida基础

看看链接库有什么

Module.enumerateExports("liba0x9.so")

通过Frida-Labs 筑牢frida基础

直接hook修改返回值试试

var check_flag = Module.enumerateExports("liba0x9.so")[0]["address"];Interceptor.attach(check_flag, {    onEnter: function () {        console.log('Entering ');            },    onLeave: function (retval) {        console.log(retval);        retval.replace(1337)//retval = 0x539 需要用replace去替换        console.log(retval);    }})

通过Frida-Labs 筑牢frida基础

反汇编看看so文件里面怎么写的,可以看到也是直接返回一个值。

通过Frida-Labs 筑牢frida基础

Frida 0xA 主动调用native方法

通过Frida-Labs 筑牢frida基础

通过Frida-Labs 筑牢frida基础

app内显示的为Hello hackers,根据上述代码可以看出来,在so文件中还有一个get_flag函数。

通过Frida-Labs 筑牢frida基础

那我们的想法肯定是要调用get_flag函数。但是这个函数并未被加载到java空间内,因此我们要用frida主动调用。

可以看到这个函数传入两个int参数,当a2+a1=3时可以解密flag

通过Frida-Labs 筑牢frida基础

使用基地址+偏移量的方式0x1DD60

var baseAddress = Module.getBaseAddress("libfrida0xa.so").add(0x1DD60);var native_adr = new NativePointer(baseAddress);//const native_function = new NativeFunction(native_adr, 'void', ['int', 'int']);native_function(1,2);

通过Frida-Labs 筑牢frida基础

Frida 0xB 动态patch

通过Frida-Labs 筑牢frida基础

直接看看getFlag

通过Frida-Labs 筑牢frida基础

接收一个参数直接返回,有问题,看下汇编代码

通过Frida-Labs 筑牢frida基础

这里将地址[ebp+var_10]的值赋值成deadbeef,并和539比较,显然不成立,走了另外的分支。

所以这里需要对这里patch。

通过Frida-Labs 筑牢frida基础

直接nop掉 arm中一个nop字节,刚好nop掉b.ne,由于代码就紧接着后面,直接nop两次也是可以的。

使用arm64Write

通过Frida-Labs 筑牢frida基础

var address = Module.getBaseAddress("libfrida0xb.so").add(0x15248);var writer = new Arm64Writer(address);//直接修改内存中的代码try {    writer.putNop();    writer.putNop();    writer.flush();    } finally {    writer.dispose();    }

失败,有读写保护

Memory.protect(address, size, protection);var address = Module.getBaseAddress("libfrida0xb.so").add(0x15248);Memory.protect(address, 0x100, "rwx");var writer = new Arm64Writer(address);//直接修改内存中的代码try {    writer.putNop();    writer.putNop();//nop一次或者两次都可以,只要执行之后的代码就行。    writer.flush();    } finally {    writer.dispose();    }

通过Frida-Labs 筑牢frida基础

也是成功拿下。

2、使用b代替b.ne

var address = Module.getBaseAddress("libfrida0xb.so").add(0x15248);Memory.protect(address, 0x100, "rwx");var writer = new Arm64Writer(address);//直接修改内存中的代码var target = Module.getBaseAddress("libfrida0xb.so").add(0x1524C);try {    writer.putBImm(target);//放入b指令,接收一个地址作为跳转地址    writer.flush();    } finally {    writer.dispose();    }

通过Frida-Labs 筑牢frida基础

原文始发于微信公众号(安全小圈):通过Frida-Labs 筑牢frida基础

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2025年1月15日11:12:17
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   通过Frida-Labs 筑牢frida基础http://cn-sec.com/archives/3629537.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息