环境安装,感觉python比较好用就下载python版的!
# 安装 frida库
pip install frida
# 安装frida-tools工具
pip install frida-tools
成功!
D:\CTF_Study\Reverse\Frida_Study>frida --version
16.1.11
先编写一个程序用来测试!
test.cpp,每输对一个字符i就会加一!
#include<iostream>
#include<stdlib.h>
#include<windows.h>
using namespace std;
typedef int status;
typedef int selemtype;
char flag[] = "flag{12321213}";
char w[] = "Wrong!";
char r[] = "Right!";
int main ()
{
char input[256] = {0};
gets(input);
for(int i = 0 ; flag[i] ; i ++ ){
if(flag[i]!=input[i]){
puts("Wrong!");
return 0;
}
}
puts("Right!");
}
编译一下:
D:\CTF_Study\Reverse\Frida_Study> g++ .\test.cpp -o test1.exe
接下来就是拖入ida查看地址看看我们需要的地址了!
int __fastcall main(int argc, const char **argv, const char **envp)
{
__int64 v4; // [rsp+20h] [rbp-60h] BYREF
char v5[260]; // [rsp+28h] [rbp-58h] BYREF
int i; // [rsp+12Ch] [rbp+ACh]
_main(argc, argv, envp);
v4 = 0i64;
memset(v5, 0, 0xF8ui64);
gets(&v4, v5);
for ( i = 0; flag[i]; ++i ) // ++i,序号增加的位置
{
if ( flag[i] != v5[i - 8] )
{
puts("Wrong!"); // 插桩结束的位置
Sleep(0x10u);
return 0;
}
}
puts("Right!");
return 0;
}
看汇编:
.text:000000014000159E lea rax, Buffer ; "Wrong!"
.text:00000001400015A5 mov rcx, rax ; Buffer
.text:00000001400015A8 call puts ; 程序结束的地址
...
.text:00000001400015C2 ; ---------------------------------------------------------------
.text:00000001400015C2
.text:00000001400015C2 loc_1400015C2: ; CODE XREF: main+6C↑j
.text:00000001400015C2 add [rbp+0C0h+var_14], 1 ; 序号增加的位置
.text:00000001400015C9
得到偏移地址:0x15A8程序结束;0x15C2序号增加!
知道后就可以开始编写js代码了
var number = 0 //定义插桩数
function main()
{
var base = Module.findBaseAddress("test1.exe")//在电脑进程种查找程序
if(base){ //成功找到
Interceptor.attach(base.add(0x15A8), { //监听结束地址
onEnter: function(args) {
send(number); //输出数据
}
});
Interceptor.attach(base.add(0x15C2), {//监听目标地址
onEnter: function(args) {
number+=1;
}
});
Interceptor.attach(base.add(0x15EA), {//监听成功地址
onEnter: function(args) {
send("成功!");
}
});
}
}
setImmediate(main);//设定插桩
下面就可以开始了!先双击启动程序test1.exe在来启动frida
D:\CTF_Study\Reverse\Frida_Study>frida -l .\hook.js -n test1.exe
成功启动:
尝试在test1.exe程序种输入不同的数据:
输入:aaaaaaa
结果:发现输出{‘type’: ‘send’, ‘payload’: 0}说明number为0
D:\CTF_Study\Reverse\Frida_Study>frida -l .\hook.js -n test1.exe
____
/ _ | Frida 16.1.11 - A world-class dynamic instrumentation toolkit
| (_| |
> _ | Commands:
/_/ |_| help -> Displays the help system
. . . . object? -> Display information about 'object'
. . . . exit/quit -> Exit
. . . .
. . . . More info at https://frida.re/docs/home/
. . . .
. . . . Connected to Local System (id=local)
[Local::test1.exe ]-> message: {'type': 'send', 'payload': 0} data: None
Process terminated
[Local::test1.exe ]->
Thank you for using Frida!
输入:flag{adasda}
结果:发现输出{‘type’: ‘send’, ‘payload’: 5}说明number为5,正好对了5个字符
D:\CTF_Study\Reverse\Frida_Study>frida -l .\hook.js -n test1.exe
____
/ _ | Frida 16.1.11 - A world-class dynamic instrumentation toolkit
| (_| |
> _ | Commands:
/_/ |_| help -> Displays the help system
. . . . object? -> Display information about 'object'
. . . . exit/quit -> Exit
. . . .
. . . . More info at https://frida.re/docs/home/
. . . .
. . . . Connected to Local System (id=local)
[Local::test1.exe ]-> message: {'type': 'send', 'payload': 5} data: None
Process terminated
[Local::test1.exe ]->
Thank you for using Frida!
输入:flag{12321213}
结果:发现输出{‘type’: ‘send’, ‘payload’: ‘成功!’}说明flag成功!
D:\CTF_Study\Reverse\Frida_Study>frida -l .\hook.js -n test1.exe
____
/ _ | Frida 16.1.11 - A world-class dynamic instrumentation toolkit
| (_| |
> _ | Commands:
/_/ |_| help -> Displays the help system
. . . . object? -> Display information about 'object'
. . . . exit/quit -> Exit
. . . .
. . . . More info at https://frida.re/docs/home/
. . . .
. . . . Connected to Local System (id=local)
[Local::test1.exe ]-> message: {'type': 'send', 'payload': '成功!'} data: None
Process terminated
[Local::test1.exe ]->
Thank you for using Frida!
经过上面的测试我们就已经明白了如何使用frida的运用了!
那么接下来就是写脚本来爆破程序的flag了!
又发现一个问题:使用之前的js脚本有一个问题,就是js将数据发过来python还没接收到程序就结束了QAQ
所以先修改一下js脚本,直接hook掉puts函数添加一个延时几毫秒的函数就可以了:
var number = 0
function main()
{
var base = Module.findBaseAddress("test1.exe")
if(base){
Interceptor.attach(base.add(0x15C2), {//序号加1的位置
onEnter: function(args) {
number+=1;
}
});
Interceptor.attach(base.add(0x15A8), {//程序报错的地址
onEnter: function(args) {
send(number);
}
});
Interceptor.attach(base.add(0x15DC), {//成功的位置
onEnter: function(args) {
send(number);
}
});
Interceptor.attach(base.add(0x2900), {//不让程序退出的太快!!直接hook掉puts函数
onEnter: function (args) {
// 延迟 10 秒钟
var delay = 0x10;
console.log("Program is ending, delaying for " + (delay / 1000) + " seconds...");
var start = new Date().getTime();
while (new Date().getTime() < start + delay);
console.log("Delay complete.");
}
});
}
}
setImmediate(main);
python脚本用来测试:
import subprocess
import frida
import time
def on_message(message, data):
print(message)
filename = "test1.exe"
jscode = open("hook.js", "rb").read().decode()
process = subprocess.Popen(filename, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)
session = frida.attach(filename)
script = session.create_script(jscode)
script.on('message', on_message)
script.load()
process.stdin.write("flag{12321213}")
output, error = process.communicate()
print(output)
输出:
PS D:\CTF_Study\Reverse\Frida_Study> & E:/python_env/python.exe d:/CTF_Study/Reverse/Frida_Study/exp.py
{'type': 'send', 'payload': 15}
Program is ending, delaying for 0.016 seconds...
Right!
成功解决程序退出过快的问题后就可以开始写爆破脚本了!
import subprocess
import frida
import time
flaglen = 14
flag = bytearray(b'!' * flaglen)
filename = "test1.exe"
jscode = open("hook.js", "rb").read().decode()
result = 0
def brute(F):
def on_message(message, data):
global result
if message['type'] == 'send':
result = message['payload']
else:
print(message)
process = subprocess.Popen(filename, stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
universal_newlines=True)
session = frida.attach(filename)
script = session.create_script(jscode)
script.on('message', on_message)
script.load()
process.stdin.write(F.decode())
output, error = process.communicate()
process.terminate()
return result
count = 0
new_number = brute(flag)
number = new_number
t = time.time()
st = t
while count < flaglen:
number = brute(flag)
if number > new_number:
print(f"本位耗时:{time.time()-t}s,正确字符为:{chr(flag[count])}")
t = time.time()
print(flag.decode())
new_number = number
count += 1
else:
flag[count] += 1
while(flag[count] > 127):
flag[count] = 33
count -= 1
flag[count] += 1
print("最终flag!",flag.decode())
print(f"总耗时{time.time()-st}")
var number = 0
function main()
{
var base = Module.findBaseAddress("test1.exe")
if(base){
Interceptor.attach(base.add(0x15C2), {//序号加1的位置
onEnter: function(args) {
number+=1;
}
});
Interceptor.attach(base.add(0x15A8), {//程序报错的地址
onEnter: function(args) {
send(number);
}
});
Interceptor.attach(base.add(0x15DC), {//成功的位置
onEnter: function(args) {
send(number);
}
});
Interceptor.attach(base.add(0x2900), {//不让程序退出的太快!!直接hook掉puts函数
onEnter: function (args) {
// 延迟 10 秒钟
var delay = 0x10;
// console.log("Program is ending, delaying for " + (delay / 1000) + " seconds...");
var start = new Date().getTime();
while (new Date().getTime() < start + delay);
// console.log("Delay complete.");
}
});
}
}
setImmediate(main);