免责声明:内容仅供学习参考,请合法利用知识,禁止进行违法犯罪活动!
内容参考于:图灵Python学院
本人写的内容纯属胡编乱造,全都是合成造假,仅仅只是为了娱乐,请不要盲目相信。
工具下载:
链接:https://pan.baidu.com/s/1rEEJnt85npn7N38Ai0_F2Q?pwd=6tw3
提取码:6tw3
复制这段内容后打开百度网盘手机App,操作更方便哦
上一个内容:12.安卓逆向-frida基础-hook
上一个内容里搭建了Frida环境,并简单的使用Frida hook的脚本hook了一个app的网络,接下来就开始写,怎么才能写一个hook脚本,上一个内容里的脚本是都是什么意思
frida脚本的关键字
Java.use():它用于获取 Java类的对象,以便于在 JavaScript 中对其进行操作。例如,Java.use('java.util.ArrayList') 会返回 ArrayList 类的代理对象,然后就可以使用Frida访问ArrayList 对象
Java.perform():它用于在 Frida 的 JavaScript 环境中执行代码块。这个代码块中可以包含对 Java 类的修改、Hook 方法的实现等操作。
implementation属性:用于指定要 Hook 的方法的新实现。通过设置 implementation 属性,可以在方法执行前后添加自定义的逻辑。例如, targetMethod.implementation = function(){ ... } 可以将 targetMethod 替换为自定义的实现。
this 和参数:在自定义的方法实现中,可以使用 this 关键字表示原始方法的调用和属性访问。此外,可以使用传入的参数对方法的输入进行修改或记录
调用原始方法:在自定义的方法实现中,通过调用原始方法,可以确保原始方法的行为仍然被执行。例如, this.targetMethod.apply(this, arguments) 可以调用原始的 targetMethod 方法。
frida和java的数据类型对应
有一个app(没法给)
然后对这个app进行反编译,反编译工具jadx-gui
然后打开jadx-gui把app拖到它的界面里,如下图
然后就可以看到它的源码了
然后可以看到它里面有静态方法(static方法)和非静态方法,如下图红框
它们都属于Utils类
然后接下来就使用Frida来HOOK这个app里的函数,首先是Utils类里的函数,调用它的静态方法,如下图
说明:
代码:
function demo(){ var utils = Java.use("com.luoge.com.Utils") utils.getCalc.implementation = function(i, i2){ console.log("参数1--》"+i);// 查看参数 console.log("参数2--》"+i2);// 查看参数 res = this.getCalc(i, i2); // 调用原本的getCalc方法 return res } }
上方是hook getCalc方法的脚本,执行脚本要在java.perform里写
function demo(){ var utils = Java.use("com.luoge.com.Utils") utils.getCalc.implementation = function(i, i2){ console.log("参数1--》"+i) console.log("参数2--》"+i2) var res = this.getCalc(i, i2) console.log("返回值--》"+res) return res } } function main(){ Java.perform(function (){ // 调用java代码也就是getCalc方法 demo() }) } setImmediate(main)// 调用入口函数
然后测试代码,开启f14(也就是手机上的FridaServer)开启之后测试Firda脚本,如下图,下图中使用的是frida -UF -l ./lizi1.js,-UF它找当前在前台运行的app,前台运行效果是可以看到app的界面,然后下图可以看到getCalc方法的入参和返回值
这里补充一下执行了 frida -UF -l ./lizi1.js 指令怎么退出,如下图红框输入exit然后按回车(Enter键)就退出了
然后源码中调用getCalc的位置,如下图红框,它也确实传的2000和2000
然后下图红框它是4000,接下来我们通过脚本修改getCalc方法它的返回值试试
脚本代码,返回值改成了8889999,在不退出的情况下,修改脚本代码之后不需要重新执行frida -UF -l ./lizi1.js指令,它会自动根据最新的脚本代码执行
然后再次点击普通方法按钮,可以看到下图红框内容变了,之前很火的羊了个羊那些用脚本通过的就是这样的一样原理,羊了个羊它第一关很简单第二关很难,它就是在第一关通过之后在请求完第二关的时候把返回值改成第一关的数据,这样不管第几关玩的都是第一关,然后有的东西玩多少分钟看多久短视频它会返现,可以通过修改返回值的方式强制玩1秒钟返现
然后再写一个修改它入参的例子,修改下图红框setFlag方法的参数的值,它也是一个静态方法
脚本代码
function demo1(){ var utils = Java.use("com.luoge.com.Utils") utils.setFlag.implementation = function(str){ console.log("参数1--》"+str) var res = this.setFlag("52am") console.log("返回值--》"+res) return res } } function main(){ Java.perform(function (){ // 调用java代码也就是getCalc方法 demo1() }) } setImmediate(main)// 调用入口函数
效果图:强制改入参
它源码中调用的setFlag函数的入参
调用非静态方法,getFlag方法
脚本代码
function demo1(){ var utils = Java.use("com.luoge.com.Utils") utils.setFlag.implementation = function(str){ console.log("setFlag参数1--》"+str) var res = this.setFlag("52am") console.log("setFlag返回值--》"+res) return res } utils.getFlag.implementation = function(){ var res = this.getFlag() console.log("getFlag返回值--》"+res) return "52" } } function main(){ Java.perform(function (){ // 调用java代码也就是getCalc方法 demo1() }) } setImmediate(main)// 调用入口函数
效果图:
hook重载方法
重载方法是方法名一样但是参数不一样,如下图getOver就是重载方法
脚本如下
运行它会报错说getOver是一个重载函数需要指定,记住下图白框里的东西
代码
function demo2(){// hook重载方法 var utils = Java.use("com.luoge.com.Utils") utils.getOver.overload().implementation = function(){ var res = this.getOver() console.log("demo2返回值-》"+res+"\n") return res } utils.getOver.overload('int').implementation = function(i){ console.log("overload('int')入参-》"+i+"\n") var res = this.getOver(i) console.log("overload('int')返回值-》"+res+"\n") return res } utils.getOver.overload('com.luoge.com.Money').implementation = function(a){ console.log("overload('com.luoge.com.Money')入参-》"+a+"\n") var res = this.getOver(a) console.log("overload('com.luoge.com.Money')返回值-》"+res+"\n") return res } } function main(){ Java.perform(function (){ // 调用java代码也就是getCalc方法 demo2() }) } setImmediate(main)// 调用入口函数
修改之后的脚本和hook源码中的方法对应关系,如下图
效果图:
一次性hook全部重置方法
function demo2(){// hook重载方法 var utils = Java.use("com.luoge.com.Utils") var o = utils.getOver.overloads// 获取全部的重载方法,给到o // o.length这里的意思是获取 getOver方法有多少个重载方法 // for是一个运行会多次执行{}之间的代码,执行多少次取决于 i < o.length 这个条件 for(var i = 0; i < o.length;i++){ // utils.getOver.overloads[i],i是一个数字,所以 // utils.getOver.overloads[i]可以写成utils.getOver.overloads[0] // utils.getOver.overloads[1]、utils.getOver.overloads[2]。。。。 // 下方的意思就会把所有重载方法全部拦截 utils.getOver.overloads[i].implementation = function (){ // arguments 里面是入参,arguments.length是获取当前getOver函数的入参个数 for(var j = 0; j < arguments.length; j++){ // arguments[j]里的j是一个数字,arguments[j]可以写成 // arguments[0],arguments[1],arguments[2]。。。 // arguments[0]这意思是取出第一个入参的值 console.log("参数序号:"+j+" 参数的值:"+arguments[j]) } // 调用原本的方法,原本的方法会根据 arguments不同从而调用不同的getOver方法 return this.getOver.apply(this, arguments); } } } function main(){ Java.perform(function (){ // 调用java代码也就是getCalc方法 demo2() }) } setImmediate(main)// 调用入口函数
效果图:
第二种hook全部重载方法的写法forEach
function demo2(){// hook重载方法 var utils = Java.use("com.luoge.com.Utils") var methods = utils['getOver'].overloads; console.log(methods); console.log(methods.length); methods.forEach(function(method){ method.implementation = function(){ for(var j = 0; j < arguments.length; j++){ // arguments[j]里的j是一个数字,arguments[j]可以写成 // arguments[0],arguments[1],arguments[2]。。。 // arguments[0]这意思是取出第一个入参的值 console.log("参数序号:"+j+" 参数的值:"+arguments[j]+"\n") } return this.getOver.apply(this, arguments); } }) } function main(){ Java.perform(function (){ // 调用java代码也就是getCalc方法 demo2() }) } setImmediate(main)// 调用入口函数
源码中调用的getOver方法
手动给它们传参,脚本代码如下图红框
function demo3(){ var utils = Java.use("com.luoge.com.Utils") utils.getOver.overload('com.luoge.com.Money').implementation = function(a){ var m = Java.use("com.luoge.com.Money") var money = m.$new() var res = utils.getOver.overload('com.luoge.com.Money').call(this, money) console.log("demo3返回值1"+res+"\n") res = utils.getOver(113331) console.log("demo3返回值2"+res+"\n") res = utils.getOver() console.log("demo3返回值3"+res+"\n") return res } } function main(){ Java.perform(function (){ // 调用java代码也就是getCalc方法 // demo() // demo1() // demo2() demo3() }) } setImmediate(main)// 调用入口函数
效果图: