-
-
[原创][RCTF2019]crack
-
发表于: 1小时前 46
-
[RCTF2019]crack
水
直接弹窗字符串定位不说了
sub_94E558(this, 1);
v2 = *(this + 52);
if ( *(v2 - 4) > 1 )
sub_9413E0(this + 52, *(v2 - 12));
v22 = 3 * *(this + 58);
v21 = *(this + 56);
*(this + 53) = *(this + 52);
memset(v21, 0, v22);
len = *(*(this + 52) - 12); // len
_04DE2020 = *(this + 54); // 04DE2020
cows = 0;
v6 = 0;
rows = 0;
v27 = 0x100758E540FLL;
len_1 = len; // 输入长度
base = _04DE2020;
len_4 = 0;
if ( len <= 0 )
return MessageBoxA(nullptr, "Try Again!", "tip", MB_OK);
do
{
len_3 = *(this + 58); // 512
if ( rows >= len_3 )
break;
if ( rows < 0 || (v9 = *(this + 52), rows > *(v9 - 12)) )
sub_941560(0x80070057);
n_0_ = *(v9 + 2 * rows); // input
if ( n_0_ != '0' && n_0_ != '1' )
return MessageBoxA(nullptr, "Input no accept!", "tip", MB_OK);
if ( n_0_ == '1' )
len_4 = ++cows;
v11 = *(base + 4 * (cows + rows * len_3));
v12 = v27 < v11;
LODWORD(v27) = v27 - v11;
cows = len_4;
_04DE2020 = base;
HIDWORD(v27) -= v12;
if ( rows > len_4 )
{
*(v6 + *(this + 56)) = *(base + 4 * (rows + len_4 * len_3));
*(v6 + *(this + 56) + 1) = *(base + 4 * (rows + len_4 * *(this + 58)) + 1);
*(v6 + *(this + 56) + 2) = *(base + 4 * (rows + len_4 * *(this + 58)) + 2);
cows = len_4;
v6 += 3;
}
++rows;
}
while ( rows < len_1 );
if ( v27 > 0 )
return MessageBoxA(nullptr, "Try Again!", "tip", MB_OK);
根据这一行,并且对cows,和rows的限制可以知道base是一个512*512的二维矩阵,并且每一元素占4字节,只有当输入为1的时候cows才会增加,rows无条件增加,每次取出一个数,然后v27减去他,最后只有v27<=0的时候输入合法
v11 = *(base + 4 * (cows + rows * len_3));
所以现在让ai写一个脚本获取base数组
import idaapi
import idc
import os
# 设置起始地址和数量
start_address = 0x042F4020
count = 512 * 512
# 读取数据
data = []
for i in range(count):
value = idaapi.get_wide_dword(start_address + i * 4)
data.append(str(value))
# 保存到桌面
desktop = os.path.expanduser("~/Desktop")
output_path = os.path.join(desktop, "extracted_data.txt")
# 或者直接保存在当前目录(更简单)
# output_path = "extracted_data.txt"
with open(output_path, "w") as f:
f.write(" ".join(data))
print(f"已读取 {len(data)} 个int值,保存到 {output_path}")
数组获取到了,然后根据输入的0或者1代表两种操作,0是往下走,1是往右下走,所以可以写个动态规划求解
if __name__ == '__main__':
result = []
found = False
end_x, end_y = -1, -1
TARGET = 0x100758E540F
N = 512
with open("./extracted_data.txt", "r") as f:
all_nums = [int(x) for x in f.read().split()]
all_len = len(all_nums)
if len(all_nums) != N * N:
print("非法输入")
exit(0)
matrix = [all_nums[i * N:(i + 1) * N] for i in range(N)]
dp = [[0] * (N + 1) for j in range(N + 1)]
choose = [[0] * (N + 1) for j in range(N + 1)]
dp[0][0] = matrix[0][0]
for i in range(1, N):
dp[i][0] = dp[i - 1][0] + matrix[i][0]
for i in range(1, N):
dp[0][i] = dp[0][i - 1] + matrix[0][i]
for i in range(1, N):
for j in range(i + 1):
current_val = matrix[i][j]
left_up = dp[i - 1][j - 1] + current_val
up = dp[i - 1][j] + current_val
if left_up > up:
choose[i][j] = 1
dp[i][j] = left_up
else:
choose[i][j] = 0
dp[i][j] = up
if dp[i][j] >= TARGET:
end_x, end_y = i, j
found = True
break
if found:
break
while end_x >= 0:
value = choose[end_x][end_y]
result.append(str(value))
if value == 1:
end_x -= 1
end_y -= 1
else:
end_x -= 1
input_str = "".join(reversed(result))
print(input_str)
00000000010101000000000111100111111110100111100101001000101010010011101100111101011111111111111111001110111011011000000101110111001111100100011000000000000110001111110100000000001101110111010101011111000101110000011000111001110000000000000000000000011001000010000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000011100011111110000100111000000000000000000000000000000010000000000000001000001100000000000000101000000000100000010000000000000000010000000000000000000000
然后运行到这里
v13(this, &v27, v23);
跟进去发现是一个vmp,n128_3很明显是一个pc指针
LODWORD(n128) 一会高字节,一会低字节很奇怪,看一下汇编,猜测可能是两个虚拟寄存器
HIDWORD(n128)
debug103:03CF44BA mov dword ptr [ebp+var_274], ecx
debug103:03CF428E mov dword ptr [ebp+var_274+4], eax
if ( n128 < 128 ) 有对寄存器的约束,所以大胆猜测开了128个int的虚拟寄存器,而且是从n128开始的
int __stdcall sub_3CF4020(_DWORD *a1, int a2, int a3)
{
while ( 1 )
{
result = n128_3 + a3;
if ( !*(n128_3 + a3) )
return result;
v21 += (*(n128_3 + a3) - 48) << (n128_3 % 6);
result = n128_3 / 6;
if ( n128_3 % 6 != 5 )
goto LABEL_70;
switch ( v21 )
{
case 0:
v21 = 0;
for ( i = 0; i < 24; ++i )
v21 += (*(++n128_3 + a3) - 48) << i;
LODWORD(n128) = v21;
goto LABEL_69;
case 1:
v21 = 0;
for ( j = 0; j < 24; ++j )
v21 += (*(++n128_3 + a3) - 48) << j;
HIDWORD(n128) = v21;
goto LABEL_69;
case 2:
LODWORD(n128) = *(v29 + 2 * v22++);
LABEL_69:
v21 = 0;
LABEL_70:
++n128_3;
break;
case 3:
HIDWORD(n128) = n128;
goto LABEL_69;
case 4:
n128_2 = n128_1;
goto LABEL_69;
case 5:
if ( n128 < 128 )
*(&n128 + n128) = HIDWORD(n128);
goto LABEL_69;
case 6:
if ( SHIDWORD(n128) < 128 )
LODWORD(n128) = *(&n128 + HIDWORD(n128));
goto LABEL_69;
case 7:
if ( n128_1 < 128 )
*(&n128 + n128_1) = n128_2;
goto LABEL_69;
case 8:
if ( n128_2 < 128 )
n128_1 = *(&n128 + n128_2);
goto LABEL_69;
case 9:
LODWORD(n128) = *(n128 + 4 * HIDWORD(n128));
goto LABEL_69;
case 10:
*(n128 + 4 * HIDWORD(n128)) = v9;
goto LABEL_69;
case 11:
LODWORD(n128) = HIDWORD(n128) + n128;
goto LABEL_69;
case 12:
LODWORD(n128) = n128 - HIDWORD(n128);
goto LABEL_69;
case 13:
LODWORD(n128) = HIDWORD(n128) * n128;
goto LABEL_69;
case 14:
LODWORD(n128) = n128 / SHIDWORD(n128);
goto LABEL_69;
case 15:
LODWORD(n128) = HIDWORD(n128) & n128;
goto LABEL_69;
case 16:
LODWORD(n128) = HIDWORD(n128) | n128;
goto LABEL_69;
case 17:
LODWORD(n128) = HIDWORD(n128) ^ n128;
goto LABEL_69;
case 18:
LODWORD(n128) = n128 << SBYTE4(n128);
goto LABEL_69;
case 19:
LODWORD(n128) = n128 >> SBYTE4(n128);
goto LABEL_69;
case 20:
LODWORD(n128) = n128 > SHIDWORD(n128);
goto LABEL_69;
case 21:
LODWORD(n128) = n128 < SHIDWORD(n128);
goto LABEL_69;
case 22:
LODWORD(n128) = n128 == HIDWORD(n128);
goto LABEL_69;
case 23:
LODWORD(n128) = n128 != HIDWORD(n128);
goto LABEL_69;
case 24:
LODWORD(n128) = n128_3;
goto LABEL_69;
case 25:
n128_3 = n128;
v21 = 0;
break;
case 26:
if ( n128 )
goto LABEL_69;
n128_3 = HIDWORD(n128);
v21 = 0;
break;
default:
return result;
}
}
}
而且在堆栈窗口也有opcode,直接拿下来
001DF138 006D2764 sub_6D25E0+184 → cmp dword ptr [esp+28h+v27], ebx
001DF13C 001DF984 Stack[0000569C] → 008156C4 .rdata → 006DA342 sub_6DA342 → mov eax, offset off_7ECED8; "CDialogEx"
001DF140 001DF160 Stack[0000569C] → FFFFFFFF
001DF144 00814970 .rdata → "0000000101011001000000000000001100000100000101101000000000110000"
001DF148 00000111
001DF14C 00815638 .rdata → 006DA7EF sub_6DA7EF → mov eax, offset off_7ED0A4
001DF150 00000001
001DF154 00000090
001DF158 03BE1020 → 009C8171 → FFFFFFFF
然后写出解释器,附件提供
00 mov reg[0],0x26a
03 mov reg[1],reg[0]
02 mov reg[0],input[0]
01 mov reg[1],0x30
0c sub reg[0],reg[1]
03 mov reg[1],reg[0]
00 mov reg[0],0x3
05 mov reg[3],reg[1]
00 mov reg[0],0x0
03 mov reg[1],reg[0]
00 mov reg[0],0x2
05 mov reg[2],reg[1]
00 mov reg[0],0x7
03 mov reg[1],reg[0]
06 mov reg[0],reg[7]
03 mov reg[1],reg[0]
07 mov reg[0],reg[3]
12 shl reg[0],reg[1]
03 mov reg[1],reg[0]
00 mov reg[0],0x3
05 mov reg[3],reg[1]
00 mov reg[0],0x1
03 mov reg[1],reg[0]
00 mov reg[0],0x2
05 mov reg[2],reg[1]
00 mov reg[0],0x6
03 mov reg[1],reg[0]
06 mov reg[0],reg[6]
07 mov reg[1],reg[3]
0b add reg[0],reg[1]
03 mov reg[1],reg[0]
00 mov reg[0],0x6
05 mov reg[6],reg[1]
01 mov reg[1],0x7
06 mov reg[0],reg[7]
01 mov reg[1],0x1
0b add reg[0],reg[1]
03 mov reg[1],reg[0]
00 mov reg[0],0x7
05 mov reg[7],reg[1]
00 mov reg[0],0x0
19 jmp reg[0] 0x0
00 mov reg[0],0x26a
03 mov reg[1],reg[0]
02 mov reg[0],input[1]
01 mov reg[1],0x30
0c sub reg[0],reg[1]
03 mov reg[1],reg[0]
00 mov reg[0],0x3
05 mov reg[3],reg[1]
00 mov reg[0],0x0
03 mov reg[1],reg[0]
00 mov reg[0],0x2
05 mov reg[2],reg[1]
00 mov reg[0],0x7
03 mov reg[1],reg[0]
06 mov reg[0],reg[7]
03 mov reg[1],reg[0]
07 mov reg[0],reg[3]
12 shl reg[0],reg[1]
03 mov reg[1],reg[0]
00 mov reg[0],0x3
05 mov reg[3],reg[1]
00 mov reg[0],0x1
03 mov reg[1],reg[0]
00 mov reg[0],0x2
05 mov reg[2],reg[1]
00 mov reg[0],0x6
03 mov reg[1],reg[0]
06 mov reg[0],reg[6]
07 mov reg[1],reg[3]
0b add reg[0],reg[1]
03 mov reg[1],reg[0]
00 mov reg[0],0x6
05 mov reg[6],reg[1]
01 mov reg[1],0x7
06 mov reg[0],reg[7]
01 mov reg[1],0x1
0b add reg[0],reg[1]
03 mov reg[1],reg[0]
00 mov reg[0],0x7
05 mov reg[7],reg[1]
00 mov reg[0],0x0
19 jmp reg[0] 0x0
00 mov reg[0],0x26a
03 mov reg[1],reg[0]
02 mov reg[0],input[2]
01 mov reg[1],0x30
0c sub reg[0],reg[1]
03 mov reg[1],reg[0]
00 mov reg[0],0x3
05 mov reg[3],reg[1]
00 mov reg[0],0x0
03 mov reg[1],reg[0]
00 mov reg[0],0x2
05 mov reg[2],reg[1]
00 mov reg[0],0x7
03 mov reg[1],reg[0]
06 mov reg[0],reg[7]
03 mov reg[1],reg[0]
07 mov reg[0],reg[3]
12 shl reg[0],reg[1]
03 mov reg[1],reg[0]
00 mov reg[0],0x3
05 mov reg[3],reg[1]
00 mov reg[0],0x1
03 mov reg[1],reg[0]
00 mov reg[0],0x2
05 mov reg[2],reg[1]
00 mov reg[0],0x6
03 mov reg[1],reg[0]
06 mov reg[0],reg[6]
07 mov reg[1],reg[3]
0b add reg[0],reg[1]
03 mov reg[1],reg[0]
00 mov reg[0],0x6
05 mov reg[6],reg[1]
01 mov reg[1],0x7
06 mov reg[0],reg[7]
01 mov reg[1],0x1
0b add reg[0],reg[1]
03 mov reg[1],reg[0]
00 mov reg[0],0x7
05 mov reg[7],reg[1]
00 mov reg[0],0x0
19 jmp reg[0] 0x0
00 mov reg[0],0x26a
03 mov reg[1],reg[0]
02 mov reg[0],input[3]
1a jmp.jz 0x26a
01 mov reg[1],0x6
06 mov reg[0],reg[6]
01 mov reg[1],0x7
0d mul reg[0],reg[1]
01 mov reg[1],0xf423f
16 cmp reg[0],reg[1] reg[0]:0x126 reg[1]:0xf423f
还原一下算法
inp = "666"
result = 0
for i in range(len(inp)):
result += (ord(inp[i]) - 0x30) << i
print(hex(result*7))
然后用z3求解一下
from z3 import *
def solve_for_N(N):
solver = Solver()
digits = [BitVec(f'd_{i}', 32) for i in range(N)]
for d in digits:
solver.add(And(d >= 0, d <= 9))
if N > 0:
solver.add(digits[N - 1] != 0)
total = BitVecVal(0, 32)
for i in range(N):
total += digits[i] << i
solver.add(total * 7 == 0xf423f)
if solver.check() == sat:
m = solver.model()
return ''.join([str(m[d].as_long()) for d in digits])
return None
N = 1
while True:
result = solve_for_N(N)
if result:
print(f"N={N}: {result}")
break
N += 1
结果拼接一下就拿到flag了
赞赏
他的文章
- [原创][RCTF2019]crack 47
- [原创]简单分析onCreate 1350
- [原创]frida 反调 39833
- [讨论]一个使用luajava的flag题目, 1155
赞赏
雪币:
留言: