frida插桩爆破

参考资料

[原创]基于 Frida 对单字节加密验证程序侧信道爆破-CTF对抗-看雪-安全社区|安全招聘|kanxue.com

应用场景

面对一些单次较短字节的比较验证场景,例如vm等

原理

通过frida插桩获取到比较正确的计数器进行反馈实现爆破

简单代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include<iostream>
#include<stdlib.h>
using namespace std;
typedef int status;
typedef int selemtype;
#include<windows.h>
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!");
Sleep(0x10);
return 0;
}
}
puts("Right!");
}

ida打开找到比较正确的计数器加一的地方

image-20250320195110568

image-20250320195145188

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
var number = 0
function main()
{
var base = Module.findBaseAddress("frida.exe")

if(base){
Interceptor.attach(base.add(0x15CB), {
onEnter: function(args) {
console.log(number)
send(number);
}
});
Interceptor.attach(base.add(0x15EC), {

onEnter: function(args) {
number+=1;
}

});
}
}
setImmediate(main);

运行exe

1
frida -l hook.js -n frida.exe

image-20250322202326602

插进去了 输入一下字符串 可以看到正确的位数

按照这个回显就可以使用python加载js脚本多次启动exe插桩获取正确的位数作为依据进行爆破

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
var number = 0
function main()
{
var base = Module.findBaseAddress("ezVM.exe")
if(base){
Interceptor.attach(base.add(0x1044), {
//opcode
onEnter: function(args) {
number+=1
}

});
Interceptor.attach(base.add(0x113f), {
onEnter: function(args) {
send(number)
var a = 0;
for(var i = 0 ; i < 9999 ; i ++ ){
a+=1;
}
var f = new NativeFunction(base.add(0x21D8),'void',['int']);
//exit(0)
f(0)
}
});
}
}
setImmediate(main);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
import subprocess
import frida
import sys
import win32api
import win32con

number = 0
flaglen = 43
filename = "ezVM.exe"
#flag{O1SC_VM_1s_h4rd_to_r3v3rs3_#a78abffaa#}
flag = bytearray(b'flag{O1SC_VM_1s_h4rd_!!!!!!!!!!!!!!!!!!!!!!}')
jscode = open("fridahook.js", "rb").read().decode()
new_number = 0

result = 0


def brute(F):
def on_message(message, data):
global result
if message['type'] == 'send':
result = message['payload']
# print(result)
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())
print(F.decode())
output, error = process.communicate()
print(output,error)

print(f"number:{result}")
process.terminate()
return result


import time

count = 21

new_number = brute(flag) #进行第一次的验证 获取到初始当前flag的正确位数
number = new_number
t = time.time()
st = t

while count < flaglen:
number = brute(flag)
print(flag.decode())
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: #超出ascll的限制
flag[count] += 1
while (flag[count] > 127):
flag[count] = 33 #倒序检验
count -= 1
flag[count] += 1
print(flag.decode())
print(f"总耗时{time.time() - st}")