- hook是什么
hook框架是一种技术,用于在运行时拦截和修改应用程序的行为,通过hook,可以劫持应用程序的方法调用、修改参数、篡改返回值等,以达到对应用程序的修改、增强或调试的目的。
- 常见的hook框架有哪些
- Xposed Framework:Xposed 是一个功能强大的开源 Hook 框架,可以在不修改应用程序源代码的情况下,对应用程序进行各种修改。它允许你编写模块来拦截和修改应用程序的方法调用,修改应用程序的行为和逻辑。
- Frida:Frida 是一个跨平台的动态 Hook 框架,支持安卓和其他操作系统。它提供了一个强大的 JavaScript API,可以在运行时对应用程序进行 Hook,包括方法拦截、参数修改、调用注入等。Frida 可以用于安全研究、逆向工程和应用程序调试等方面。
下载安装Frida
- 电脑中安装模块
#我这里使用的是Python虚拟环境进行安装的
pip install frida==16.1.7
pip install frida-tools==12.3.0
- 手机端安装frida-server
#下载地址
https://github.com/frida/frida/releases
#查看手机架构,选择相对应的版本
adb shell getprop ro.product.cpu.abi
#选择相应版本下载后,在电脑上进行解压
- 把 frida-server-16.1.7-android-arm64 推送到手机上 /data/local/tmp
adb push ./frida-server-16.1.7-android-arm64 /data/local/tmp
- 进入手机shell,查看是否安装成功
- 赋予可执行权限
chmod +x frida-server-16.1.7-android-arm64
- 运行frida-server,敲回车就可以执行了,卡主,表示启动了,如果没启动会报错
启动frida
当手机启动了frida-server后,电脑要与手机端进行通信,通过某个端口进行通信。
- 方法一:
adb forward tcp:27042 tcp:27042
adb forward tcp:27043 tcp:27043
- 方法二:使用python代码,右键运行即可
import subprocess # python中执行系统命令的一个模块
subprocess.getoutput("adb forward tcp:27042 tcp:27042")
subprocess.getoutput("adb forward tcp:27043 tcp:27043")
使用Python代码,打印手机中的进程和前台运行的进程
import frida
#1 获取设备信息 必须手机端启动了frida-server并且做了端口转发
rdev = frida.get_remote_device()
# 2 枚举所有的进程
# processes = rdev.enumerate_processes()
# for process in processes:
# print(process)
# 3 打印出前台在运行的app
front_app = rdev.get_frontmost_application()
print(front_app)
hook方式
1、Python的hook方式
hook分为两种:spawn方案和attach方案
- spawn方案:Spawn 方式是在目标应用程序启动时直接注入 Frida 的 Agent 代码
- 需要在应用程序启动的早期阶段进行 Hook。
- 需要访问和修改应用程序的内部状态,例如应用程序的全局变量、静态变量等。
- 需要 Hook 应用程序的初始化过程,以实现对应用程序的自定义初始化逻辑。
- 需要在应用程序的上下文中执行代码,并与其他模块或库进行交互。
import frida
import sys
### 这个代码不需要动### ### ###
rdev = frida.get_remote_device()
session = rdev.attach("app名") # 写上要hook的app的名字
### 以后这个代码不需要动### ###
# 要改动的地方,js语法
scr = """
Java.perform(function () {
//找到类的包名和方法名
var SecurityUtil = Java.use("com.autohome.ahkit.utils.SecurityUtil");
//替换类中的方法,方法有几个参数,就要传几个参数
SecurityUtil.encodeMD5.implementation = function(str){
console.log("参数:",str); // 传入的参数打印了,
var res = this.encodeMD5(str); //调用原来的函数
console.log("返回值:",res); // 打印出正常执行这个方法,返回的结果
return str;
}
});
"""
####下面代码完全不需要动
script = session.create_script(scr)
def on_message(message, data):
print(message, data)
script.on("message", on_message)
script.load()
sys.stdin.read()
- attach方案:Attach 方式是在目标应用程序已经运行的过程中动态地连接并注入 Frida 的 Agent 代码
- 需要对已经运行的应用程序进行 Hook,即动态地连接到正在运行的进程。
- 需要在应用程序运行时拦截和修改特定的方法调用。
- 需要实时监视和修改应用程序的行为,例如参数修改、返回值篡改等。
- 需要对应用程序进行调试和分析,以查找潜在的问题和漏洞。
import frida
import sys
rdev = frida.get_remote_device()
pid = rdev.spawn(["运行APP的包名"])
session = rdev.attach(pid)
scr = """
Java.perform(function () {
// 包.类
var SecurityUtil = Java.use("com.autohome.ahkit.utils.SecurityUtil");
SecurityUtil.encodeMD5.implementation = function(str){
console.log("明文:",str);
var res = this.encodeMD5(str);
console.log("md5加密结果=",res);
return "305eb636-eb15-4e24-a29d-9fd60fbc91bf";
}
});
"""
script = session.create_script(scr)
def on_message(message, data):
print(message, data)
script.on("message", on_message)
script.load()
rdev.resume(pid)
sys.stdin.read()
2、js的hook方式
frida提供了js的api接口,可以使用js的脚本运行hook
- attach方式
// 名字叫:hook.js
Java.perform(function () {
// 包.类
var SecurityUtil = Java.use("com.autohome.ahkit.utils.SecurityUtil");
SecurityUtil.encodeMD5.implementation = function(str){
console.log("明文:",str);
var res = this.encodeMD5(str);
console.log("md5加密结果=",res);
return "123";
}
});
// attach 运行 命令 (应用已经在前台运行了,不需要指定应用名字和包名)
// frida -UF -l hook.js
- spawn
// hook.js
Java.perform(function () {
// 包.类
var SecurityUtil = Java.use("com.autohome.ahkit.utils.SecurityUtil");
SecurityUtil.encodeMD5.implementation = function(str){
console.log("明文:",str);
var res = this.encodeMD5(str);
console.log("md5加密结果=",res);
return "123";
}
});
// spawn 方案运行 命令,会重启应用,需要指定应用的包名,不能不写包名,不写包名,不知道启动哪个应用
// frida -U -f com.che168.autotradercloud -l hook.js
# 注意:输入q + 再点击回车则退出
Python常见的加密算法
1、MD5加密
import hashlib
m = hashlib.md5()
m.update('helloworld'.encode("utf8"))
print(m.hexdigest()) # md5加密后的16进制
2、sha1加密
import hashlib
sha1 = hashlib.sha1()
data = 'helloword'
sha1.update(data.encode('utf-8'))
sha1_data = sha1.hexdigest()
print(sha1_data) # sha1 加密后的16进制
3、DES加密
# pip3 install pycryptodomex -i https://pypi.douban.com/simple
# DES是一个分组加密算法,典型的DES以64位为分组对数据加密,加密和解密用的是同一个算法。它的密钥长度是56位(因为每个第8 位都用作奇偶校验),密钥可以是任意的56位的数,而且可以任意时候改变。
from Cryptodome.Cipher import DES
key = b'88888888'
data = "hello world"
count = 8 - (len(data) % 8)
plaintext = data + count * "="
des = DES.new(key, DES.MODE_ECB)
ciphertext = des.encrypt(plaintext.encode())
print(ciphertext)
plaintext = des.decrypt(ciphertext)
plaintext = plaintext[:(len(plaintext)-count)]
print(plaintext)
4、非对称加密算法RSA
# 安装模块
pip3 install rsa -i https://pypi.douban.com/simple
import rsa
# 返回 公钥加密、私钥解密
public_key, private_key = rsa.newkeys(1024)
print(public_key)
print(private_key)
# plaintext = b"hello world"
# ciphertext = rsa.encrypt(plaintext, public_key)
# print('公钥加密后:',ciphertext)
# plaintext = rsa.decrypt(ciphertext, private_key)
# print('私钥解密:',plaintext)
### 使用私钥签名
plaintext = b"hello world"
sign_message = rsa.sign(plaintext, private_key, "MD5")
print('私钥签名后:',sign_message)
## 验证私钥签名
plaintext = b"hello world"
# method = rsa.verify(b"hello world", sign_message, public_key)
method = rsa.verify(b"hello world1", sign_message, public_key) # 报错Verification failed
print(method)
5、base64编码
import base64
# 编码
res=base64.b64encode(b'hello world')
print(res)
# 解码
res=base64.b64decode('aGVsbG8gd29ybGQ=')
print(res)