首页
课程
问答
CTF
社区
招聘
峰会
发现
排行榜
知识库
工具下载
看雪20年
看雪商城
证书查询
登录
注册
首页
社区
课程
招聘
发现
问答
CTF
排行榜
知识库
工具下载
峰会
看雪商城
证书查询
社区
CTF对抗
发新帖
0
1
[原创][RCTF2019]crack
发表于: 2026-6-17 20:33
2064
[原创][RCTF2019]crack
lingyi223
2026-6-17 20:33
2064
##### **[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了
冰与火的战歌:Windows内核攻防实战高级班!从零到实战,融合AI与Windows内核攻防全技术栈,打造具备自动化能力的内核开发高手。
收藏
・
0
点赞
・
1
打赏
分享
分享到微信
分享到QQ
分享到微博
赞赏记录
参与人
雪币
留言
时间
wx_晨梦
谢谢你的细致分析,受益匪浅!
2026-7-16 08:32
查看更多
赞赏
×
1 雪花
5 雪花
10 雪花
20 雪花
50 雪花
80 雪花
100 雪花
150 雪花
200 雪花
支付方式:
微信支付
赞赏留言:
快捷留言
感谢分享~
精品文章~
原创内容~
精彩转帖~
助人为乐~
感谢分享~
最新回复
(
0
)
游客
登录
|
注册
方可回帖
回帖
表情
雪币赚取及消费
高级回复
返回
lingyi223
6
发帖
35
回帖
40
RANK
关注
私信
他的文章
[原创]乐校园跑协议分析
27027
[原创][RCTF2019]crack
2064
[原创]简单分析onCreate
14811
[原创]frida 反调
43786
关于我们
联系我们
企业服务
看雪公众号
专注于PC、移动、智能设备安全研究及逆向工程的开发者社区
看原图
赞赏
×
雪币:
+
留言:
快捷留言
为你点赞!
返回
顶部