Hook入门小Demo

准备:
jadx_gui: apk反编译,获取apk包名、查看apk源码。

frida:hook框架: 用来植入js脚本,修改源程序实现拦截数据,获取想要的数据。

adb: 电脑操作真机或模拟器。

夜神模拟器: 用来测试。

frida-server: 用来实现通信,这里可以理解为服务端,用adb发送到手机修改权限并运行,注意要和本地python安装的frida版本一致,下载的版本也有区别,有些是不能使用的。

  • -pip install frida: 这里的frida是安装在本地的,可以理解为客户端
  • -pip install frida-tools: 一些工具

Demo:

import frida
import sys
import os


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

jscode = """
    function classExists(className) {
    var exists = false;
    try {
        var clz = Java.use(className);
        exists = true;
    } catch (err) {
    }
    return exists;
};

function checkLoadDex(className, dexfile) {
    if (!classExists(className)) {
        Java.openClassFile(dexfile).load();
    }
};

function toJSONString(obj) {
    try {
        checkLoadDex("com.alibaba.fastjson.JSON", "/data/local/tmp/fastjson.dex");
        var clz = Java.use("com.alibaba.fastjson.JSON");
        var toJSONStringMehtod = clz.toJSONString.overload("java.lang.Object");
        return toJSONStringMehtod.call(clz, obj);
    } catch (err) {
    }
    return "{}";
};

function fromJSONString(jsonStr, classObj) {
    try {
        checkLoadDex("com.alibaba.fastjson.JSON", "/data/local/tmp/fastjson.dex");
        var jsonObject = Java.use("com.alibaba.fastjson.JSONObject");
        var obj = jsonObject.parseObject(jsonStr, classObj.class);
        return obj;
    } catch (err) {
    }
    return null;

};

function newHashSet() {
    var HashSetClz = Java.use('java.util.HashSet');
    return HashSetClz.$new();
};

var Base64 = {
	_keyStr: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
	encode: function(e) {
		var t = "";
		var n, r, i, s, o, u, a;
		var f = 0;
		e = Base64._utf8_encode(e);
		while (f < e.length) {
			n = e.charCodeAt(f++);
			r = e.charCodeAt(f++);
			i = e.charCodeAt(f++);
			s = n >> 2;
			o = (n & 3) << 4 | r >> 4;
			u = (r & 15) << 2 | i >> 6;
			a = i & 63;
			if (isNaN(r)) {
				u = a = 64;
			} else if (isNaN(i)) {
				a = 64;
			}
			t = t + this._keyStr.charAt(s) + this._keyStr.charAt(o) + this._keyStr.charAt(u) + this._keyStr.charAt(a);
		}
		return t;
	},
	decode: function(e) {
		var t = "";
		var n, r, i;
		var s, o, u, a;
		var f = 0;
		e = e.replace(/[^A-Za-z0-9+/=]/g, "");
		while (f < e.length) {
			s = this._keyStr.indexOf(e.charAt(f++));
			o = this._keyStr.indexOf(e.charAt(f++));
			u = this._keyStr.indexOf(e.charAt(f++));
			a = this._keyStr.indexOf(e.charAt(f++));
			n = s << 2 | o >> 4;
			r = (o & 15) << 4 | u >> 2;
			i = (u & 3) << 6 | a;
			t = t + String.fromCharCode(n);
			if (u != 64) {
				t = t + String.fromCharCode(r);
			}
			if (a != 64) {
				t = t + String.fromCharCode(i);
			}
		}
		t = Base64._utf8_decode(t);
		return t;
	},
	_utf8_encode: function(e) {
		e = e.replace(/rn/g, "n");
		var t = "";
		for (var n = 0; n < e.length; n++) {
			var r = e.charCodeAt(n);
			if (r < 128) {
				t += String.fromCharCode(r);
			} else if (r > 127 && r < 2048) {
				t += String.fromCharCode(r >> 6 | 192);
				t += String.fromCharCode(r & 63 | 128);
			} else {
				t += String.fromCharCode(r >> 12 | 224);
				t += String.fromCharCode(r >> 6 & 63 | 128);
				t += String.fromCharCode(r & 63 | 128);
			}
		}
		return t;
	},
	_utf8_decode: function(e) {
		var t = "";
		var n = 0;
		var r =  0;
        var c1;
        var c2 = 0;
		while (n < e.length) {
			r = e.charCodeAt(n);
			if (r < 128) {
				t += String.fromCharCode(r);
				n++;
			} else if (r > 191 && r < 224) {
				c2 = e.charCodeAt(n + 1);
				t += String.fromCharCode((r & 31) << 6 | c2 & 63);
				n += 2;
			} else {
				c2 = e.charCodeAt(n + 1);
				c1 = e.charCodeAt(n + 2);
				t += String.fromCharCode((r & 15) << 12 | (c2 & 63) << 6 | c1 & 63);
				n += 3;
			}
		}
		return t;
	}
};

rpc.exports = {
    hooker: function (param1) {
        Java.perform(function () {
            console.log(param1);
            /* 参数
			传参:
				long   int64
			重写:
				普通参数
					int          int
					long         long
					byte         [B
					boolean      boolean
					float		 float
				容器类
					String       java.lang.String
					HashMap      java.util.HashMap
					ArrayList    java.util.ArrayList
					HashSet		 java.util.HashSet
					LinkedList   java.util.LinkedList
					eg:
						var hashMap_clz = Java.use('java.util.HashMap');
            			var map_clz = Java.use('java.util.Map');
						var hashMap = hashMap_clz.$new();
                    	var map = Java.cast(hashMap, map_clz);
                 自定义类
                 	com.tencent.mm.protocal.protobuf.cqt
                 	com.tencent.mm.an.q
             */

			// hook代码实现数据截取、篡改
			//普通方法hook
			var main = Java.use("com.example.pt_fun.MainActivity");
			main.add.implementation = function (a, b) {
				console.log("Hook start ...");
				send(a);
				send(b);
				send("Success");
				return this.add("2", "2");
			};
			//构造方法hook
			var money = Java.use("com.example.pt_fun.Money");
			money.$init.implementation = function (a, b) {
				console.log("Hook start ...");
				send(a);
				send(b);
				send("Success");
				return this.$init(2000, "美元");
			};
			//重载方法hook
			var money = Java.use("com.example.pt_fun.Money");
			money.getInfo.overload("int").implementation = function (a) {
				console.log("Hook start ...");
				send(a);
				send("Success");
				//return this.getInfo(88888);
				return "重载方法hook成功"
			};
			//对象参数
			var main = Java.use("com.example.pt_fun.MainActivity");
			var money = Java.use("com.example.pt_fun.Money");
			main.mobj.implementation = function (obj) {
				console.log("Hook start ...");
				//send(obj);
				send(obj.getInfo());
				//获取属性值(一)
				send(obj.type.value);
				//修改属性
				obj.type.value = "英镑";
				var m = money.$new(1000, "台币");
				send(m.getInfo());
				return this.mobj(m);
			};
			//修改属性(映射)
			var main = Java.use("com.example.pt_fun.MainActivity");
			var money = Java.use("com.example.pt_fun.Money");
			var clazz = Java.use("java.lang.Class");
			main.mobj.implementation = function (obj) {
				var countid = Java.cast(obj.getClass(), clazz).getDeclaredField("count");
				countid.setAccessible(true);
				var value = countid.get(obj);
				console.log(value);
				countid.setInt(obj, 11111);
				return this.mobj(obj);
			};
			// 注册类,即实现接口
			var ab_clz = Java.use('com.example.pt_fun.interface');
			var cust_ab_clz = Java.registerClass({
				name: 'com.example.pt_fun.interface.lllx1',
				implements: [ab_clz],
				methods: {
					add(a, b) {
						return a+b;
					}
				}
			});
			cust_ab_clz.$new().add(1, 2);
			//枚举所有的类和方法
			Java.enumerateLoadedClasses({
				onMatch: function (name, handle) {
					if (name.indexOf("com.tencent.mm") != -1) {
						console.log("name: ", name);
						var clazz = Java.use(name);
						console.log("clazz: ", clazz);
						var methods = clazz.class.getDeclaredMethods();
						for (var i = 0; i < methods.length; i++) {
							console.log("methods: ", methods[i]);
						}
						Thread.sleep(0.1);
					}
				},
				onComplete: function () {
					console.log("okok");
				}
			});
        });
    }
};

"""


# 端口转发
os.system("adb forward tcp:27042 tcp:27042")
# 连接并获取运行的apk包名,即进程
process = frida.get_remote_device().attach('com.example.pt_fun')
# 植入脚本,拦截数据
script = process.create_script(jscode)
script.on('message', on_message)
script.load()
# 控制台打印信息
sys.stdin.read()

测试apk:
点击下载
自己去首页找找包名叫PT_fun。

猜你喜欢

转载自blog.csdn.net/xiaoxin_OK/article/details/118253754