01 Frida开发和调试环境搭建
详见大佬博客r0ysue
02 Objection
不想写了,自己看r0的文章吧。
Objection
03 Frida上手和逆向三段
关于frida启动
frida -U com.kevin.android -l hook.js//直接附加
frida -UF -l hook.js//直接附加到当前应用中去
package com.example.myapplication;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import java.util.Locale;
public class MainActivity extends AppCompatActivity {
private String total="@@@###";
private Static String total2="@@@###";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
while(true){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
fun(50,80);
}
}
String fun(String x){
total +=x;
return x.toLowerCase();
}
int fun(int x,int y){
Log.d("Fup1p1 m =",String.valueOf(x+y));
Log.d("Fup1p1 tolowercase",fun("LOWERCASE"));
return x+y;
}
String secret(){
return total;
}
public static secret2(){
return total2;
}
}
js脚本指南
一.所有针对Java层的Hook脚本必须处于Java.perform()的包装内,表示将其中的函数注入到java运行时。
二.使用Java.use()API去获取指定类的handle,类似于java中调用类静态方法的方式去获取对应的函数。如果函数有多个重载,要加.overload()
三.setImmediate()表示注入后立即执行,setTimeout(xxx,1000)表示延迟1000ms。
函数的重载
错误代码
function main(){
Java.perform(function(){
Java.use("com.example.myapplication.MainActivity").fun.implementation=function(arg1,arg2){
var result=this.fun(114,514);
console.log("arg1 arg2 result" ,arg1,arg2,result)
return result;
}
})
}
setImmediate(main)
由于app中重载了fun函数,所以我们在hook调用fun时报错。
正确代码
function main(){
Java.perform(function(){
Java.use("com.example.myapplication.MainActivity").fun.overload("int","int").implementation=function(arg1,arg2){
var result=this.fun(arg1,arg2);
console.log("arg1 arg2 result" ,arg1,arg2,result)
console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new()));//打印调用栈
return result;
}
})
}
setImmediate(main)
动态要找到实例然后主动调用,静态直接调用
动态
Java.choose("com.example.myapplication.MainActivity",{
onMatch:function(instance){
console.log("found instance:" ,instance)
instance.secret();
console.log("found instance :",instance.secret())
},onComplete:function(){}
})
静态
var result =Java.use("com.example.myapplication.MainActivity").secret2()
console.log(result)
总结
一篇好文,链接
静态方法
直接Java.use就行了
非静态,有两种思路
直接获取内存中已存在的对象
因为运行过程中对象的成员的值可能已经发生了变化,所以如果重新创建一个对象,新对象的值还是初始值,在调用算法或者函数的时候,可能会产生影响。
Java.choose('xxx.xxx.xxx ', //这里写类名
{
//onMatch 匹配到对象时执行的函数
onMatch: function (instance)
{
instance.funcxxx();
},
//堆中搜索完成后执行的回调函数
onComplete: function ()
{
}
});
创建一个新对象
需要使用$new()
Java.use("com.xxx.xxx").$new()//无参构造函数
Java.use("com.xxx.xxx").$new(arg1....)//有参构造函数
frida构造数组,对象,Map和参数
打印数组
char arr[][] = new char[4][]; // 创建一个4行的二维数组
arr[0] = new char[] { '春', '眠', '不', '觉', '晓' }; // 为每一行赋值
arr[1] = new char[] { '处', '处', '闻', '啼', '鸟' };
arr[2] = new char[] { '夜', '来', '风', '雨', '声' };
arr[3] = new char[] { '花', '落', '知', '多', '少' };
Java.use("java.util.Arrays").toString.overload('[C').implementation=function(x){
var result=this.toString(x);
console.log("x,result",x,result);
return result;
}
我这里是可以正常输出x的,如果x输出时两个object,就用JSON.stringify(),将把一个 JavaScript 对象序列化为一个 JSON 字符串。
console.log("x,result",JSON.stringify(x),result);
或者使用gson打印,需要下载。然后放在frida-server同目录下。
Java.openClassFile("/data/local/tmp/xxx.dex").load();
const gson =Java.use("com.xxx.xxx.gson");
console.log("x,result",gson.$new().toJson(x),result);
自己构造一个数组
Java.use("java.util.Arrays").toString.overload('[C').implementation=function(x){
var chararray=Java.array("char",['1','2','3','4','5']);
var result=this.toString(chararray);
console.log("x,result",x,result);
return result;
}
或者
Java.use("java.util.Arrays").toString.overload('[C').implementation=function(x){
return Java.use("java.lang.String").$new(Java.array('char',['1','1','4','5','1']));
}
类型转换
写一个水类
public class Water { // 水 类
public static String flow(Water W) { // 水 的方法
// SomeSentence
Log.d("2Object", "water flow: I`m flowing");
return "water flow: I`m flowing";
}
public final String still(Water W) { // 水 的方法
// SomeSentence
Log.d("2Object", "water still: still water runs deep!");
return "water still: still water runs deep!";
}
}
写一个饮料类去继承水类
public class Juice extends Water { // 果汁 类 继承了水类
public String fillEnergy(){
Log.d("2Object", "Juice: i`m fillingEnergy!");
return "Juice: i`m fillingEnergy!";
}
public static void main() {
Water w1 = new Water();
flow(w1) ; //
Juice J = new Juice(); // 实例化果汁类对象
flow(J) ; // 调用水的方法 向上转型 J → W
Water w2 = new Juice();
((Juice) w2).fillEnergy();//需要类型转换
}
}
先调用一下水类
var Waterhandle=null;
Java.choose("com.r0ysue.a0526printout.Water",{
onMatch:function(instance){
console.log("found instance!",instance);
console.log("water instance call!",instance.still(instance));
Waterhandle=instance;
},onComplete:function(){
console.log("search complete!")
}
})
强制类型转换
实测发现,只能子类强制类型转换成父类,父类转子类的时候会报错,告诉你这不可能实现。。。
var Juicehandle=null;
Java.choose("com.r0ysue.a0526printout.Juice",{
onMatch:function(instance){
console.log("found instance",instance);
console.log("Juice method called",instance.fillEnergy());
Juicehandle=instance;
},onComplete:function(){"Search completed"}
})
var Waterhandle=Java.cast(Juicehandle,Java.use("com.r0ysue.a0526printout.Water"));//强制类型转换
console.log(Waterhandle.still(Waterhandle));
根据接口创建一个java的类
public class milk implements liquid {
public String flow(){
Log.d("3interface", "flowing : interface ");
return "nihao";
};
public static void main() {
milk m = new milk();
m.flow();
}
}
public interface liquid {
public String flow();
}
frida实现
var beer=Java.registerClass({
name:'com.r0ysue.a0526printout.beer',
implements:[Java.use('com.r0ysue.a0526printout.liquid')],
methods: {
flow:function(){
console.log("look i am beer!");
return "taste good!";
}
}
});
console.log("beer.flow:",beer.$new().flow())
打印Map
Map<String, String> mapr0ysue = new HashMap<>(); // 创建Map集合对象
mapr0ysue.put("ISBN 978-7-5677-8742-1", "Android项目开发实战入门"); // 向Map集合中添加元素
mapr0ysue.put("ISBN 978-7-5677-8741-4", "C语言项目开发实战入门");
mapr0ysue.put("ISBN 978-7-5677-9097-1", "PHP项目开发实战入门");
mapr0ysue.put("ISBN 978-7-5677-8740-7", "Java项目开发实战入门");
Log.d("5map", "key值toString"+mapr0ysue.toString());
Java.choose("java.util.HashMap",{
onMatch:function(instance){
if(instance.toString().indexOf("ISBN")!=-1){//遍历
console.log("found HashMap",instance);
console.log("HashMap toString",instance.toString());
}
},onComplete:function(){console.log("Search Completed!")
}
})
评论区