1.FRIDA 初级

1.1.Frida远程过程调用(rpc)

有时候分析一个应用的算法时找到了算法的实现方法但方法的逻辑特别复杂或被混淆了怎么办?
这时候我们可以选择一个简单而粗暴的方式,直接刚,啊呸,直接调。
frida支持在js代码中使用rpc.exports关键字对js函数进行导出,导出方法可在python代码中通过script.exports.导出符号()进行调用。配合之前说过的frida的方法主动调用,可以很好的完成对应用中的算法或核心方法进行主动单独调用。

function Hook10(){Java.perform(function(){console.log("Frida Test Hook10");// 主动调用类静态方法var clszz = Java.use("cn.gemini.k.fridatest.FridaHook1");console.log("func3_verify_static  ret:"+clszz.func3_verify_static(">>>pwd<<<"));});
}rpc.exports = {exporthook10: Hook10 //将方法导出为exporthook10符号,这里要注意导出名千万不能有大写字母或下划线
};

python代码

# -*- coding: UTF-8 -*-
import frida
import sys# 目标包名
appPacknName = "cn.gemini.k.fridatest"
scriptFile = "hook_script.js"# 输出日志的回调方法
def on_message(message, data):if message['type'] == 'send':print("[*] {0}".format(message['payload']))else:print(message)device = frida.get_usb_device()
# spawn模式,找到目标包名并重启,在启动前注入脚本
pid = device.spawn([appPacknName])
session = device.attach(pid)
# 注意这里需要将device.attach(pid)这句代码写在前面,这样执行才符合预期(启动时程序白屏,等待下面这行代码来恢复执行)
# 其实在https://www.jianshu.com/p/b833fba1bffe这篇文章中有提到
device.resume(pid)# 方式一: 通过js文件创建hook代码
with open(scriptFile, encoding='UTF-8') as f:script = session.create_script(f.read())
# 方式二: 直接将hook代码写在python文件中
# script = session.create_script(js_code)script.on("message", on_message)
script.load()  # 把js代码注入到目标应用中
# 避免结束
# sys.stdin.read()# frida RPC测试
script.exports.exporthook10()  # exportmain为js文件中的导出符号

1.2.Frida手动加载dex

破解应用时如果想在应用中执行我们自己写的Java类代码通过frida怎么实现?
可以将自定义的Java类编译成一个dex文件,懒得单独编译也可以直接去apk文件中获取,需要注意的是有些apk可能存在多个dex文件,这里需要找一下一定要是含有我们Java类的那个dex。
dex文件准备好后使用adb工具push到设备的"/data/local/tmp/“目录下方便我们的frida代码加载,之后通过Java.openClassFile(”/data/local/tmp/my.dex").load()对目标dex进行加载。这样就可以通过Java.use调用我们直接写的方法了。

function hook() {Java.perform(function () {Java.openClassFile("/data/local/tmp/my.dex").load();var cls = Java.use("xx.xxxxxx.x.xxxxxxxxxxxx"); // 自定义的Java类console.log(cls);var obj = cls.$new();   // 实例化自定义的Java类console.log(obj);});
}

1.3.Frida Hook动态加载的dex

如果需要hook的类所在dex是应用在运行过程中动态加载的怎么hook?
首先怎么判断是否为动态加载:内存中确实存在该类,但apk中的dex却找不到该类,那么可能就是动态加载的。
这种情况下通过frida的一般hook流程是hook不上这个类的,因为frida使用的默认classloader与加载该类的classloader是不一样,此时就需要通过frida的enumerateClassLoaders方法来枚举当前进程的classloader,再通过loader.findClass方法在每个枚举到的classloader中寻找是否存在我们想要的类,找到后再通过Java.classFactory.loader=loader来切换一下当前frida使用的classloader,切换完成后就可以通过Java.use进行类的查找了。

// hook动态加载的dex
function Hook11(){Java.perform(function(){console.log("Frida Test Hook11");// 遍历当前所有的classloaderJava.enumerateClassLoaders({onMatch:function(loader){try {// 这里需要注意的是如果遍历到的loader中没有找到目标类则会报错,所以需要添加try catchif(loader.loadClass("xxx.xxx.xxx")){Java.classFactory.loader = loader;var Dynamic = Java.use("xxx.xxx.xxx");console.log(Dynamic);Dynamic.HHH.implementation = function(){return "hook 11";}}} catch (error) {}},onComplete:function(){}})});
}

1.4.Frida栈回溯

一般在定位应用的某个功能点时用的较多,常见用法是对一些系统API进行hook,比如系统加解密API、接受用户输入的系统API等,当程序执行到被hook的方法时再通过对当时的堆栈进行打印并分析上下栈信息即可得知该功能的代码实现所在位置。

function PrintJavaStacks1(){var thread = Java.use("java.lang.Thread");var tOBJ = thread.$new();var stack = tOBJ.currentThread().getStackTrace();var at = ""for(var i = 0; i < stack.length; i++){at += stack[i].toString()+"\n";}console.log(at);
}

1.5.Frida Hook时机

有些场景下的hook要求我们在APP应用启动前就要进行hook,比如分析被加过固的应用又或是需要hook的方法是一个静态方法,在程序启动时就被初始化,这种情况该如何控制frida的hook时机呢?
前面说过frida支持两种注入模式,一种是直接对已启动的目标应用进行附加注入。另一种是以挂起的方式重启目标应用,应用启动时会先进入等待模式,观察设备发现应用是处于白屏状态的,实际上是在等待我们唤醒主线程来继续完成启动。
对于需要在APP应用启动前就hook的场景我们就需要选择第二种注入模式。
以挂起的方式启动应用可以使用"frida -U -f com.xxx.xxx -l hook.js “来实现,之后需要我们通过手动输入%resume的方式来让主线程开始运行。
该命令没有加”–no-pause"参数,如果加上该参数程序启动时就不会进入等待而是直接启动。加与不加的区别就是启动时不等待与等待。
参数"-f"表示,需要重启这个应用并且attach上去,与之对应的是"-n"或"-p"参数,分别是通过指定进程名或进程id来attach到正在运行的应用。
参数"-l"表示本次需要加载的js注入代码。
如果是在python代码中要以挂起的方式启动则可以使用spawn()方法,唤醒的方法是resume(),需要指定pid。

1.6.Frida程序与App数据交互

主要涉及到两个方法send()/recv();
send:向Frida应用程序发送JSON可序列化消息
recv:接收来自Frida应用程序发送的一条消息
wait:直到消息已经被recv接收,并且recv的回调方法已经执行完毕并返回
js注入程序通过send方法将应用的数据发送给PC端的frida应用程序,然后frida应用程序对接收到的数据进行各种处理修改后再发送给js注入程序,这样就可以完成python对app数据动态修改的效果了。可能有些小伙伴会问,为什么要传到PC端去处理,之后又回传给js代码而不直接通过js代码处理呢?
主要是考虑到手机性能的问题,如果需要处理的数据比较复杂,那么使用PC去跑则效果更好。
python客户端处理代码

def my_message_handler(message, payload):print(message)print(payload)if message["type"] == "send":print(message["payload"])data = message["payload"].split(":")[1].strip()print('message:', message)print("burning data:"+data)data = str(base64.b64decode(data), "utf-8")# 解码user, pw = data.split(":") # 提取用户名和密码data  =  str(base64.b64encode(("admin" + ":" + pw).encode("utf-8")), "utf-8") # 组成新的组合并编码,这是使用admin登陆print("encoded data:", data)script.post({"my_data": data})  # 将JSON对象发送回去print("Modified data sent")

注入的js代码

Java.perform(function () {var tv_class = Java.use("android.widget.TextView");tv_class.setText.overload("java.lang.CharSequence").implementation = function (x) {var string_to_send = x.toString();var string_to_recv;console.log("send"+string_to_send);send(string_to_send); // 将数据发送给PC端recv(function (received_json_object) {string_to_recv = received_json_object.my_dataconsole.log("string_to_recv: " + string_to_recv);}).wait(); //收到数据之后,再执行下去var string = Java.use("java.lang.String");string_to_recv = string.$new(string_to_recv);//将收到的数据转化为String类型return this.setText(string_to_recv);}
});

1.7.Frida类型转换、参数构造

1.7.1.类型转换
我们在hook某个方法分析其参数值时,如果参数不是string类型,那么打印出来的很可能就是[object Object],这种情况我们就需要对参数做一些转换处理才能打印出来真实的值。

  • 打印HashMap或Map类型的参数x

frida给我们提供了类型强转方法:Java.cast()

var map = Java.use("java.util.HashMap");
var args_x = Java.cast(x,map);  //将参数x转换为HashMap类型
console.log(args_x.toString()); //调用HashMap的toString方法
  • 打印char[]类型的参数x
var arr = Java.use("java.util.Arrays");
console.log("参数对应数组:" + arr.toString(x));
  • 打印byte[]类型的参数x
var arr = Java.use("java.util,Arrays")
var JavaString = Java.use("java.lang.String")
console.log("参数对应数组:" + arr.toString(x)); //调用Arrays类的toString方法将byte[]类型参数x转为string类型
console.log("参数对应字符串:" + JavaString.$new(x));//将byte[]类型参数x做为String类构造参数

1.7.2.参数构造

frida获取应用context
我们在主动调用app的某个方法时经常会遇到参数是一个context对象,此时我们就可以通过下面的方式获取context对象。

var currentApplication= Java.use("android.app.ActivityThread").currentApplication();
var context = currentApplication.getApplicationContext();

frida构造任意类型的数组
frida还给我们提供了构造任意类型数组的方法java.array()
用法格式:Java.array(‘type’,[value1,value2,…])
使用构造char[]类型:

var charArray = Java.array('char',['你','好']);

使用构造Object[]类型:

var objectclass = Java.use("java.lang.Object");
var objectArray = Java.array('char',[objectclass.class]);

1.8.打印non-ascii
应用场景一般是apk被混淆了,混淆后的方法名都是一些乱码或不显示的非ASCII字符,这时候因为我们没法确定方法名所以就没法指定需要hook的方法,这时候可以通过先编码打印出来,再用编码后的字符串去hook即可解决方法名乱码的问题。
https://api-caller.com/2019/03/30/frida-note/#non-ascii
示例方法:

int ֏(int x) {return x + 100;
}

js代码:

Java.perform(function x() {var cls = Java.use("com.example.hooktest.MainActivity");var methods = cls.class.getDeclaredMethods();   // getDeclaredMethods方法会获取该类的所有方法,包括私有的,公有的,保护的for (var i in methods) {    // 遍历获取到的所有方法console.log(methods[i].toString()); // 打印原始方法名console.log(encodeURIComponent(methods[i].toString().replace(/^.*?\.([^\s\.\(\)]+)\(.*?$/, "$1")));    // 过滤处理并编码}// %D6%8F == ֏cls[decodeURIComponent("%D6%8F")].implementation = function (x) {console.log("original call: fun(" + x + ")");var result = this[decodeURIComponent("%D6%8F")](900);return result;}}
)

1.9.收集的一些工具方法
string转byte[]

function stringToBytes(str) {  var ch, st, re = []; for (var i = 0; i < str.length; i++ ) { ch = str.charCodeAt(i);  st = [];                 do {  st.push( ch & 0xFF );  ch = ch >> 8;          }    while ( ch );  re = re.concat( st.reverse() ); }  return re;
}

frida读写std::string

function readStdString(str){const isTiny = (str.readU8()&1) === 0;if (isTiny)return str.add(1).readUtf8String();return str.add(2*Provess.pointerSize).readPointer().readUtf8String();
}function writeStdString(str, content){const isTiny = (str.readU8()&1) === 0;if (isTiny)str.add(1).writeUtf8String(content);elsestr.add(2*Process.pointerSize).readPointer().writeUtf8String(content);
}

Frida 基础操作2相关推荐

  1. Frida基础操作命令

    Frida相关的基础操作,包含adb.frida.objection的基本命令. 1.ADB常用命令 # 查看当前连接设备 adb devices# 多个设备时指定设备 adb -s 设备号 其他指令 ...

  2. 提交表单自动刷新_Web自动化测试:元素的基础操作和浏览器基础操作

    上一节,我们了解了如何定位元素,其实也有涉及对于元素的操作,这一节我们就详细的介绍一下对于元素的操作和对于浏览器的一些操作 一.对于元素的基础操作: clear():清除输入框内的文本 send_ke ...

  3. 【opencv】(1) 基础操作:图像视频读取、图像截取、颜色通道

    主要内容有:图像及视频的读取和保存.图像显示.转换灰度图.图像截取.颜色通道提取和组合 那我们开始吧. 1. 图像操作 首先我们导入opencv库,彩色图像一般都是由RGB(红绿蓝)三颜色通道构成,灰 ...

  4. JavaのFile类基础操作之问题

    在上一章节,介绍了File类的基础操作,比如文件的创建,文件的删除等等.这一章节,将介绍在File类基础操作中遇到的问题. 1.路径分割符问题 在实际的软件开发与运行过程中,往往都会在Windows环 ...

  5. 计算机应用基础统考操作,全国统考计算机应用基础操作题

    全国统考计算机应用基础操作题 (16页) 本资源提供全文预览,点击全文预览即可全文预览,如果喜欢文档就下载吧,查找使用更方便哦! 19.9 积分 .1.打开考生文件夹下的文件Word6.doc,完成 ...

  6. Docker 之 Docker基础操作

    第1章 Docker基础操作 1.1 常用的命令 0) 安装Docker 环境 yum -y install docker 1)   指定 IP,DNS 网络位启动Docker容器 a)  docke ...

  7. cameraraw面板大小调整_Camera Raw基础操作面板介绍

    大家好,我是摄影师:爱撒谎的猫. 今天我想和大家分享的内容是:Camera Raw基础操作面板介绍. 我们每次将RAW格式的图片文件拖入Photoshop中时,最先出现的都是Camera Raw的基础 ...

  8. MATLAB基础操作--命令窗口

    MATLAB基础操作–命令窗口 常用的赋值运算符-'='对变量进行赋值 x=9-5 x = 4 x-8=9 x-8=9 ↑ 错误: '=' 运算符的使用不正确.要为变量赋值,请使用 '='.要比较值是 ...

  9. 项目实战12.1—企业级监控工具应用实战-zabbix安装与基础操作

    无监控,不运维.好了,废话不多说,下面都是干货. 警告:流量党勿入,图片太多!!! 项目实战系列,总架构图 http://www.cnblogs.com/along21/p/8000812.html ...

最新文章

  1. Canvas 的基本原理
  2. 基于AFNetworking3.0网络封装
  3. js prototype
  4. 怎样用python搭建简单的系统_如何用Python搭建一个简单的推荐系统?
  5. Chrome的vimium插件的使用笔记
  6. 机器学习中的交叉验证
  7. 第五章---引入复制后的数据库架构
  8. 三星linux打印机驱动官网下载,三星SL-C515驱动
  9. 查询记录时rs.previous()的使用
  10. 移动端动画使用transform提升性能
  11. K3销售订单携带批号至销售出库单
  12. 调试和运行matlab代码(源程序)的技巧和教程
  13. cesium使用obj格式的3D模型
  14. Google的C++编程规范总结
  15. win10以太网dns服务器未响应,Win10系统dns服务器未响应如何修复?
  16. 抖音怎么知道自己上热门 手机视频md5值修改
  17. 智能设备系统的测试分析——语音识别系统和面部识别系统
  18. 资讯汇总230128
  19. StrictMode总结
  20. 張潮《幽夢影》:「讀史宜夏」

热门文章

  1. Fanout交换器-搭建环境
  2. Zuul使用正则表达式指定路由规则
  3. ebs java并发_EBS中Java并发程序笔记(1)
  4. python之路day9_亮仔的Python之路Day9——Python知识体系重组
  5. php自定义中文分词方法,php实现的中文分词类完整实例
  6. 简易 IM 双向通信电脑端 GUI 应用——基于 Netty、JavaFX、多线程技术等
  7. 大归因+小归因,先崛网络帮你还原SEM的真实价值
  8. openlayers 2 高亮显示元素以及通过属性查询高亮某一元素
  9. 电脑文件系统的管理总结
  10. 运用Edraw为WPF应用程序嵌入Office文档的方法总结