[TBTL CTF 2024] re - Floopowder(Frida Hook 巧解算法问题)
本帖最后由 kn0sky 于 2024-5-17 14:41 编辑## analysis
> 题目加入附件,有兴趣可以拿去练练手
题目分析的时候先别陷入细节,先看整体逻辑:
```c
__int64 __fastcall main(int a1, char **a2, char **a3)
{
int i; //
int j; //
int line; //
int column; //
unsigned int v8; //
int v9; //
int v10; //
int v11; //
puts("Now don't forget to speak very, very clearly...");
for ( i = 0; i < 31; ++i ) // 32次输入
{
__isoc99_scanf("%s", &input); // 每次输入 31 字节
// 是矩阵
if ( strlen(&input) != 31 )
error_exit();
for ( j = 0; j < 31; ++j )
{
if ( input != '1' && input != '0' )// 数字必须是0和1中的一个
error_exit();
}
}
line = 0;
column = 0;
v8 = 0;
v9 = 1;
while ( line < 31 && column < 31 ) // 31*31矩阵
{
sub_11CA(line, column, v8++); // 需要知道校验顺序
if ( v9 == 1 )
{
v10 = line - 1;
v11 = column + 1;
}
else
{
v10 = line + 1;
v11 = column - 1;
}
if ( v10 < 0 || v10 == 31 || v11 < 0 || v11 == 31 )// 边界条件
{
if ( v9 == 1 )
{
line += column == 30; // line+0或者+1
column += column < 30; // column+1或者+0
}
else
{
column += line == 30;
line += line < 30;
}
v9 = 1 - v9;
}
else
{
line = v10;
column = v11;
}
}
puts("Welcome to Diagon Alley!");
return 0LL;
}
```
程序接收输入31次,每次接收31字符,是个正方形矩阵,接收完输入会进入到sub_11CA函数进行处理:
```c
_BOOL8 __fastcall sub_11CA(int line, int colunm, int idx)
{
_BOOL8 result; // rax
result = input == '1';
if ( (input == '1') != (((dword_4020 >> (31 - idx % 31 - 1)) & 1) != 0) )// 两边条件同时满足
error_exit();
return result;
}
```
这里进行校验,如果校验不通过,就退出程序
那么求解思路就是:
1. 分析校验的值
2. 分析校验的顺序
3. 还原矩阵的值
这里分析一下这个判断:
```c
(input == '1') != (((dword_4020 >> (31 - idx % 31 - 1)) & 1) != 0)
```
`(输入 == 1) != (一个值 & 1 !=0)`,简化一下:`(输入 == 1) != (一个值 == 1)`
也就是说,左边为1,右边算出来的值也需要为1
左边为0,右边算出来的值为0,第一步分析就完成了
接下来第二步,分析校验的顺序:矩阵这么多位,又不是一个一个按顺序校验,是按照某个算法逻辑进行的
常规思路是:去分析代码,手动分析校验顺序,然后写脚本还原矩阵;这里用一个取巧的思路:Hook 大法
这里我们看反汇编:
```c
.text:0000000000001266 cmp eax, ; 判断两个值是否相同
.text:0000000000001269 jz short loc_1275
.text:000000000000126B mov eax, 0 ; 不同就设置eax为0
.text:0000000000001270 call error_exit
.text:0000000000001275 ; ---------------------------------------------------------------------------
.text:0000000000001275
.text:0000000000001275 loc_1275: ; CODE XREF: sub_11CA+9F↑j
.text:0000000000001275 nop
.text:0000000000001276 leave
.text:0000000000001277 retn
.text:0000000000001277 ; } // starts at 11CA
.text:0000000000001277 sub_11CA endp
```
这里可以进行patch,把call给patch掉:
```c
.text:0000000000001266 cmp eax,
.text:0000000000001269 jz short loc_1275
.text:000000000000126B mov eax, 0
.text:0000000000001270 nop
.text:0000000000001271 nop
.text:0000000000001272 nop
.text:0000000000001273 nop
.text:0000000000001274 nop
.text:0000000000001275
.text:0000000000001275 loc_1275: ; CODE XREF: sub_11CA+9F↑j
.text:0000000000001275 nop
.text:0000000000001276 leave
.text:0000000000001277 retn
.text:0000000000001277 ; } // starts at 11CA
.text:0000000000001277 sub_11CA endp
.text:0000000000001277
```
这样一来,这个函数会被一直执行,每次执行的前两个参数,就是目标值所在的行和列,而这里的eax,也就是返回值,也会根据判断结果而变化:
* 如果输入是1,目标值是1,则返回1,
* 如果输入是0,目标值是1,则返回0,
* 如果输入是1,目标值是0,则返回0,
* 如果输入是0,目标值是0,则返回1,
输入是可控的,如果我们输入的是全1,则只有两种情况:
* 如果输入是1,目标值是1,则返回1,
* 如果输入是1,目标值是0,则返回0,
返回值就是答案,参数决定输入所在的位置
## exp:
写frida脚本进行Hook,拿到参数和返回值进行拼接字符串,变成python的数组赋值脚本:
```js
const module = Process.getModuleByName("FlooPowder2");
const baseAddr = module.base;
const targetFuncOffset = 0x11ca;
const targetFuncAddr = baseAddr.add(targetFuncOffset);
var inp = ""
Interceptor.attach(targetFuncAddr, {
onEnter: function(args) {
//console.log("line: " +args.toInt32() + " col: " + args.toInt32() + " idx: " + args.toInt32());
inp = "inp[" + args.toInt32() + "][" + args.toInt32() + "]"
},
onLeave: function(retval) {
console.log(inp +"="+ retval.toInt32());
}
});
```
```c
from __future__ import print_function
import frida
import sys
from pwn import *
path = "FlooPowder2"
io = process(path)
#device = frida.get_device_manager().enumerate_devices()
local = frida.get_local_device()
a = local.get_process(path)
print(a)
session = local.attach(path)
with open("hook.js", "r") as f:
code = f.read()
script = session.create_script(code)
script.load()
test_inp = """
1111111111111111111111111111111
1111111111111111111111111111111
1111111111111111111111111111111
1111111111111111111111111111111
1111111111111111111111111111111
1111111111111111111111111111111
1111111111111111111111111111111
1111111111111111111111111111111
1111111111111111111111111111111
1111111111111111111111111111111
1111111111111111111111111111111
1111111111111111111111111111111
1111111111111111111111111111111
1111111111111111111111111111111
1111111111111111111111111111111
1111111111111111111111111111111
1111111111111111111111111111111
1111111111111111111111111111111
1111111111111111111111111111111
1111111111111111111111111111111
1111111111111111111111111111111
1111111111111111111111111111111
1111111111111111111111111111111
1111111111111111111111111111111
1111111111111111111111111111111
1111111111111111111111111111111
1111111111111111111111111111111
1111111111111111111111111111111
1111111111111111111111111111111
1111111111111111111111111111111
1111111111111111111111111111111
"""
io.recvuntil(b"Now don't forget to speak very, very clearly...")
io.send(test_inp.encode())
io.interactive()
```
拿到超级长的输出,黏贴到python里,自己申请一个二维数组,开始赋值:
```c
from PIL import Image
import zlib
# 二维数组30*30
inp = [ for j in range(32)]
inp=0
inp=0
inp=0
inp=0
inp=1
inp=0
inp=0
inp=1
inp=1
inp=0
inp=0
inp=1
inp=0
inp=1
inp=0
inp=0
inp=1
inp=0
inp=0
inp=1
inp=0
inp=0
inp=1
inp=0
inp=1
inp=0
inp=1
inp=0
inp=0
inp=1
inp=0
inp=1
inp=1
inp=0
inp=1
inp=0
inp=0
inp=1
inp=0
inp=1
inp=1
inp=1
inp=0
inp=1
inp=0
inp=0
inp=0
inp=1
inp=0
inp=1
inp=1
inp=0
inp=1
inp=0
inp=0
inp=0
inp=1
inp=0
inp=1
inp=0
inp=1
inp=0
inp=1
inp=0
inp=0
inp=0
inp=0
inp=1
inp=1
inp=0
inp=1
inp=0
inp=0
inp=1
inp=0
inp=1
inp=0
inp=0
inp=0
inp=1
inp=0
inp=1
inp=0
inp=1
inp=0
inp=1
inp=0
inp=0
inp=1
inp=0
inp=0
inp=0
inp=0
inp=0
inp=1
inp=1
inp=0
inp=1
inp=1
inp=0
inp=1
inp=1
inp=0
inp=1
inp=0
inp=0
inp=0
inp=0
inp=1
inp=0
inp=1
inp=0
inp=1
inp=0
inp=0
inp=1
inp=1
inp=1
inp=0
inp=0
inp=0
inp=1
inp=1
inp=1
inp=0
inp=0
inp=1
inp=0
inp=0
inp=0
inp=0
inp=0
inp=0
inp=0
inp=0
inp=0
inp=0
inp=1
inp=0
inp=1
inp=1
inp=0
inp=1
inp=1
inp=0
inp=1
inp=0
inp=1
inp=1
inp=0
inp=0
inp=1
inp=0
inp=0
inp=0
inp=0
inp=0
inp=0
inp=0
inp=1
inp=0
inp=0
inp=1
inp=0
inp=0
inp=1
inp=0
inp=0
inp=1
inp=1
inp=0
inp=0
inp=1
inp=1
inp=1
inp=0
inp=1
inp=0
inp=1
inp=1
inp=1
inp=0
inp=1
inp=0
inp=1
inp=1
inp=1
inp=1
inp=1
inp=0
inp=0
inp=0
inp=1
inp=1
inp=0
inp=1
inp=0
inp=0
inp=0
inp=1
inp=0
inp=1
inp=0
inp=0
inp=1
inp=0
inp=1
inp=0
inp=1
inp=0
inp=0
inp=1
inp=0
inp=0
inp=1
inp=0
inp=1
inp=1
inp=1
inp=0
inp=1
inp=1
inp=0
inp=1
inp=1
inp=0
inp=1
inp=0
inp=1
inp=0
inp=0
inp=0
inp=1
inp=1
inp=0
inp=1
inp=0
inp=1
inp=0
inp=1
inp=0
inp=0
inp=1
inp=1
inp=0
inp=0
inp=0
inp=1
inp=1
inp=1
inp=0
inp=1
inp=0
inp=0
inp=1
inp=0
inp=0
inp=1
inp=0
inp=0
inp=1
inp=0
inp=1
inp=1
inp=0
inp=0
inp=1
inp=0
inp=1
inp=1
inp=0
inp=1
inp=0
inp=0
inp=0
inp=0
inp=0
inp=0
inp=0
inp=0
inp=1
inp=0
inp=0
inp=0
inp=0
inp=1
inp=0
inp=1
inp=1
inp=1
inp=1
inp=0
inp=0
inp=1
inp=0
inp=0
inp=1
inp=0
inp=0
inp=0
inp=0
inp=1
inp=0
inp=0
inp=1
inp=1
inp=1
inp=1
inp=0
inp=0
inp=1
inp=0
inp=1
inp=1
inp=1
inp=0
inp=1
inp=1
inp=0
inp=0
inp=0
inp=1
inp=0
inp=1
inp=0
inp=0
inp=1
inp=1
inp=0
inp=0
inp=0
inp=0
inp=0
inp=1
inp=0
inp=0
inp=1
inp=0
inp=1
inp=1
inp=1
inp=1
inp=1
inp=0
inp=1
inp=0
inp=1
inp=0
inp=1
inp=1
inp=0
inp=0
inp=1
inp=0
inp=1
inp=0
inp=0
inp=0
inp=1
inp=0
inp=1
inp=0
inp=0
inp=0
inp=0
inp=0
inp=1
inp=0
inp=0
inp=0
inp=1
inp=0
inp=1
inp=0
inp=1
inp=0
inp=1
inp=0
inp=0
inp=1
inp=0
inp=0
inp=1
inp=0
inp=1
inp=0
inp=1
inp=1
inp=1
inp=1
inp=0
inp=1
inp=1
inp=0
inp=1
inp=0
inp=0
inp=0
inp=0
inp=0
inp=0
inp=1
inp=0
inp=0
inp=1
inp=0
inp=0
inp=1
inp=0
inp=1
inp=0
inp=1
inp=0
inp=1
inp=1
inp=0
inp=1
inp=0
inp=0
inp=0
inp=1
inp=0
inp=1
inp=1
inp=0
inp=0
inp=1
inp=1
inp=0
inp=1
inp=0
inp=1
inp=0
inp=1
inp=0
inp=0
inp=1
inp=0
inp=1
inp=1
inp=0
inp=1
inp=0
inp=1
inp=1
inp=0
inp=1
inp=0
inp=1
inp=0
inp=1
inp=1
inp=0
inp=0
inp=0
inp=1
inp=0
inp=0
inp=1
inp=0
inp=1
inp=1
inp=0
inp=1
inp=0
inp=0
inp=1
inp=0
inp=1
inp=1
inp=1
inp=0
inp=1
inp=0
inp=0
inp=0
inp=1
inp=0
inp=1
inp=0
inp=1
inp=0
inp=0
inp=0
inp=1
inp=0
inp=1
inp=0
inp=1
inp=0
inp=1
inp=1
inp=1
inp=0
inp=1
inp=0
inp=0
inp=1
inp=0
inp=1
inp=1
inp=0
inp=1
inp=0
inp=1
inp=1
inp=0
inp=1
inp=1
inp=1
inp=1
inp=0
inp=1
inp=0
inp=1
inp=1
inp=1
inp=1
inp=0
inp=1
inp=0
inp=1
inp=1
inp=0
inp=1
inp=0
inp=0
inp=1
inp=0
inp=1
inp=0
inp=1
inp=0
inp=1
inp=0
inp=1
inp=1
inp=1
inp=1
inp=1
inp=0
inp=0
inp=1
inp=1
inp=0
inp=1
inp=1
inp=0
inp=0
inp=1
inp=0
inp=1
inp=0
inp=1
inp=0
inp=0
inp=1
inp=0
inp=0
inp=1
inp=0
inp=1
inp=1
inp=0
inp=0
inp=1
inp=0
inp=1
inp=1
inp=0
inp=1
inp=0
inp=0
inp=1
inp=1
inp=1
inp=0
inp=0
inp=1
inp=0
inp=0
inp=1
inp=0
inp=0
inp=1
inp=0
inp=1
inp=0
inp=1
inp=0
inp=0
inp=0
inp=0
inp=0
inp=1
inp=0
inp=0
inp=0
inp=0
inp=0
inp=1
inp=1
inp=0
inp=1
inp=0
inp=0
inp=1
inp=0
inp=1
inp=0
inp=0
inp=1
inp=1
inp=0
inp=1
inp=1
inp=1
inp=0
inp=0
inp=1
inp=0
inp=0
inp=0
inp=1
inp=1
inp=1
inp=0
inp=1
inp=0
inp=0
inp=0
inp=1
inp=0
inp=1
inp=1
inp=0
inp=0
inp=1
inp=0
inp=1
inp=0
inp=0
inp=0
inp=0
inp=1
inp=0
inp=1
inp=0
inp=1
inp=0
inp=0
inp=1
inp=0
inp=0
inp=0
inp=1
inp=1
inp=0
inp=0
inp=1
inp=0
inp=0
inp=0
inp=1
inp=1
inp=0
inp=1
inp=1
inp=0
inp=0
inp=0
inp=0
inp=0
inp=1
inp=0
inp=1
inp=0
inp=1
inp=1
inp=0
inp=0
inp=1
inp=1
inp=0
inp=0
inp=0
inp=1
inp=1
inp=1
inp=0
inp=1
inp=1
inp=1
inp=0
inp=1
inp=0
inp=0
inp=1
inp=0
inp=0
inp=1
inp=0
inp=0
inp=1
inp=0
inp=1
inp=0
inp=0
inp=0
inp=0
inp=0
inp=0
inp=1
inp=1
inp=0
inp=1
inp=0
inp=1
inp=0
inp=0
inp=0
inp=0
inp=1
inp=0
inp=0
inp=0
inp=1
inp=0
inp=1
inp=0
inp=0
inp=1
inp=1
inp=1
inp=0
inp=1
inp=0
inp=1
inp=0
inp=0
inp=0
inp=1
inp=1
inp=0
inp=1
inp=1
inp=0
inp=1
inp=1
inp=0
inp=0
inp=0
inp=0
inp=0
inp=1
inp=1
inp=1
inp=0
inp=0
inp=1
inp=1
inp=0
inp=1
inp=0
inp=1
inp=1
inp=0
inp=0
inp=0
inp=1
inp=0
inp=0
inp=0
inp=0
inp=0
inp=0
inp=0
inp=0
inp=0
inp=1
inp=1
inp=1
inp=1
inp=1
inp=1
inp=1
inp=1
inp=0
inp=0
inp=0
inp=0
inp=0
inp=0
inp=0
inp=1
inp=1
inp=1
inp=0
inp=1
inp=1
inp=1
inp=1
inp=1
inp=1
inp=1
inp=1
inp=0
inp=0
inp=0
inp=0
inp=1
inp=0
inp=0
inp=1
inp=0
inp=1
inp=0
inp=1
inp=1
inp=0
inp=1
inp=0
inp=1
inp=0
inp=0
inp=0
inp=1
inp=1
inp=0
inp=1
inp=0
inp=1
inp=0
inp=0
inp=1
inp=0
inp=0
inp=0
inp=1
inp=1
inp=0
inp=0
inp=1
inp=0
inp=1
inp=1
inp=1
inp=0
inp=1
inp=0
inp=1
inp=1
inp=1
inp=1
inp=0
inp=0
inp=0
inp=0
inp=0
inp=0
inp=0
inp=1
inp=0
inp=0
inp=1
inp=1
inp=1
inp=0
inp=1
inp=0
inp=0
inp=1
inp=1
inp=1
inp=1
inp=1
inp=0
inp=1
inp=0
inp=1
inp=1
inp=0
inp=0
inp=0
inp=0
inp=0
inp=1
inp=0
inp=1
inp=1
inp=0
inp=0
inp=0
inp=1
inp=0
inp=0
inp=0
inp=1
inp=1
inp=1
inp=1
inp=0
inp=0
inp=0
inp=0
inp=0
inp=0
inp=0
inp=0
inp=0
inp=1
inp=1
inp=1
inp=0
inp=0
inp=0
inp=0
inp=1
inp=1
inp=1
inp=1
inp=1
inp=0
inp=0
inp=0
inp=0
inp=0
inp=1
inp=0
inp=0
inp=0
inp=1
inp=0
inp=0
inp=1
inp=0
inp=0
inp=1
inp=1
inp=0
inp=0
inp=1
inp=1
inp=0
inp=1
inp=0
inp=0
inp=1
inp=1
inp=0
inp=0
inp=0
inp=0
inp=0
inp=0
inp=0
inp=0
inp=0
inp=0
inp=0
inp=0
for i in range(0,31):
for j in range(0,31):
a = inp
print(a, end='')
# print()
MAX = 31
pic = Image.new('RGB', (MAX, MAX))
str = "0000000000000000000000000000000011111110010001101001001111111001000001011011001111000100000100101110100111001100001010111010010111010110101011110001011101001011101000101100000010101110100100000101010011100001010000010011111110101010101010101111111000000000000001001101110000000000111110111110110001011101010100000100101010001001000111111110001010001101011111111010011000000100110011111000100100100110100000101010110101010111100101100000000110011101100110010001010000111000100100011101001010111000011111000101010001000001111011001001011110001110000000001101000101101000100011011011101110100010001110001110110100111101100001011000110110011000011010101000100100100111000110001111101000000000000101011000011100010100001111111011000111100110101000000100000100000110010101000100000010111010100010110110111111111001011101010000000100111011101100101110101111100100111011100100010000010110100111001010100010001111111011110001111100111110000000000000000000000000000000000"
i=0
for y in range(0,MAX):
for x in range(0,MAX):
if(str == '1'):
pic.putpixel(,(0,0,0))
else:pic.putpixel(,(255,255,255))
i = i+1
pic.show()
```
这里最终拿到的矩阵结果,打印出来张这个样:(1显示,0不显示)
```c
■■■■■■■■ ■■ ■■■■■■■■■
■ ■ ■■ ■■■■■■ ■ ■
■ ■■■ ■■■■■■ ■ ■ ■■■ ■
■ ■■■ ■ ■■ ■ ■ ■■■■ ■ ■■■ ■
■ ■■■ ■ ■ ■■ ■ ■ ■■■ ■
■ ■ ■ ■■■■ ■ ■ ■
■■■■■■■ ■ ■ ■ ■ ■ ■ ■ ■■■■■■■
■■■ ■■■
■■■■■ ■■■■■ ■■ ■ ■■■ ■ ■ ■
■■ ■ ■ ■■ ■■■■■■■■
■ ■ ■■ ■ ■■■■■■■■ ■■■
■■■■■■■■ ■■■■■ ■
■ ■ ■ ■■ ■ ■ ■ ■■■■■ ■■
■■■■■ ■■■■■ ■ ■
■■■ ■■ ■■■ ■■ ■ ■■■
■■■■■ ■ ■ ■ ■ ■■■■ ■■
■■ ■■■■ ■■■ ■■ ■
■ ■■ ■ ■ ■■ ■■ ■■■ ■■■ ■
■ ■■■ ■■■ ■■ ■■■■■ ■■
■ ■■ ■■ ■■■■ ■■ ■ ■ ■
■■■■■■ ■■ ■■■■■ ■
■ ■ ■■ ■■■ ■ ■
■■■■■■■ ■■ ■■■■■■ ■ ■
■ ■ ■■■ ■ ■ ■
■ ■■■ ■ ■ ■ ■■ ■■ ■■■■■■■■■
■ ■■■ ■ ■ ■■■■ ■■■ ■■
■ ■■■ ■ ■■■■■■■■■ ■■■■
■ ■ ■■ ■■■■■ ■ ■ ■
■■■■■■■ ■■■■ ■■■■■■■■■■
```
就是二维码呗,01字符串转二维码走起,扫码拿到flag:`TBTL{Wh47_D1d_H3_5aY_D34r?_D14g0nal1y...}`
## 参考资料
- 本人博客原文地址:https://www.kn0sky.com/?p=a0eb0445-bc09-45d3-9a97-25c190f3e9f8 分析的挺好的 感谢
页:
[1]