首页
课程
问答
CTF
社区
招聘
峰会
发现
排行榜
知识库
工具下载
看雪20年
看雪商城
证书查询
登录
注册
首页
社区
课程
招聘
发现
问答
CTF
排行榜
知识库
工具下载
峰会
看雪商城
证书查询
社区
CTF对抗
发新帖
0
0
[分享]KCTF 2026 - Rosetta Calibration
发表于: 2026-8-13 20:49
9
[分享]KCTF 2026 - Rosetta Calibration
mb_hfvhqurt
2026-8-13 20:49
9
## 题目概述 `kctf_rosetta.exe` 是一个 64 位 Windows 控制台程序(PE32+ / x86-64),纯静态链接,无加壳,`.text` 段仅约 0x556 字节。 - **已知合法键对**: - Name : `CAAA1C964B15D9B3` - Serial : `$/.;-):,(-#!%*-&?+@` - **目标**:求出 Name = `KCTF` 的 Serial。 - 程序提示语: - `Sixteen symbols. Sixteen meanings. One surviving record is the dictionary.`(16 个符号 ↔ 16 个含义,唯一的幸存记录就是“字典”) ## 解题环境 ubuntu + objdump + wine ## 一、基本信息收集 ```bash file kctf_rosetta.exe # PE32+ executable for MS Windows 6.00 (console), x86-64 sha256sum kctf_rosetta.exe # caaa1c964b15d9b3250be0dc64412e5f64c29e297a971c226e8dd705d6b87e67 (与 PUBLIC_INFO 一致) strings -a kctf_rosetta.exe # Serial : / Name : / [-] Calibration rejected. / [-] Invalid name format. # [-] The inscription cannot be translated. # [+] The symbols have found their meanings. / [+] Calibration accepted. # 导出: ExitProcess / GetStdHandle / ReadFile / WriteFile (KERNEL32.dll) ``` 程序逻辑非常直白:读入 Name → 读入 Serial → 一系列校验 → 输出成功/失败信息。 ## 二、逆向算法 用 `objdump -d kctf_rosetta.exe` 得到完整反汇编,逐段还原。 ### 1. 输入与格式校验 **Name 长度**(`0x14000123E`): ```asm lea -0x21(%rbx),%eax ; eax = len - 0x21 cmp $0xffffffe0,%eax jae 0x140001260 ; 合法则继续 ; 否则打印 "Invalid name format." ``` 利用无符号比较技巧:`len ∈ [1, 32]` 才合法。 **Name 字符范围**(`0x140001270` 循环): ```asm add $0xdf,%cl cmp $0x5e,%cl jae error ``` 等价于要求每个字符 `c ∈ [0x21, 0x7E]`(可打印 ASCII `!` ~ `~`)。 **Serial 长度**(`0x140001288`): ```asm cmp $0x13,%r12d jne 0x140001354 ; 必须恰好 19 字符 ``` **Serial 分隔符**(`0x140001292` 起): ```asm mov $0x4210,%ebp ; 二进制 0100 0010 0001 0000 -> bit4/bit9/bit14 bt %r14d,%ebp jb 0x1400012b0 ; 这三位必须是 '-' ``` 即 Serial 格式为 `XXXX-XXXX-XXXX-XXXX`,第 4、9、14 位为 `-`,其余 16 位是“符号”。 ### 2. 字典解码(Serial → 16 个 nibble) 函数 `0x140001540`: ```asm add $0xdf,%cl ; 相当于 c - 0x21 (对 '!'..'@') cmp $0x1f,%cl ja return -1 mov 0x140002000(%rax*4),%eax ; 查字典表 ``` `0x140002000` 处的 32 个 DWORD 就是“字典”(每个索引对应一个字符 `!`~`@`): ``` idx: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f val: 04 - 07 0c 01 09 - 03 0b 0e 06 0d - 08 0a - idx: 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f val: - - - - - - - - - - 0f 05 - - - 03 ``` 字符到 nibble 的唯一映射(注意函数 `0x140001520` 对 `'('` 额外 `^1`,即 `'('` 表值 3 → 实际 2,弥补表中缺失的 nibble 2): | nibble | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | |---|---|---|---|---|---|---|---|---|---|----|----|----|----|----|----| | 字符 | `?` | `%` | `(` | `@` | `!` | `;` | `+` | `#` | `.` | `&` | `/` | `)` | `$` | `,` | `*` | `:` | 校验中还有: - 解码值必须 `≤ 0xF`(合法 nibble); - 用位掩码 `edi` 检查 16 个 nibble **互不重复**,最终 `edi == 0xFFFF`; - 数量必须恰好 16 个。 即 Serial 的 16 个符号解码成 0~15 的一个**排列**。 ### 3. Name → 期望 nibble(核心函数 `0x1400013E0`) 参数:`rcx = name, edx = len, r8 = 输出 16 字节`。 ```c uint8_t T[16] = {0,1,2,...,15}; uint32_t sum = 0, r9 = 0; for (int i = 0; i < len; i++) { uint8_t c = name[i]; uint32_t nib = (c >> 4) ^ c; // 高半字节 ^ 低半字节 sum += nib; uint32_t j = (nib ^ r9) & 0xF; // r9 = 3*i uint32_t k = i & 0xF; swap(T[k], T[j]); // 交换 r9 += 3; } int p = sum & 0xF; for (int k = 0; k < 16; k++) out[k] = T[(p + k) & 0xF]; ``` 说明: - `r9` 每轮累加 3,等价于 `3*i`,注意它并不是死代码,它参与交换下标 `j` 的异或运算。 - 输出位置 8 在汇编里用 `T[(p & 0xF) ^ 8]`,因 `x ^ 8 == (x+8) & 0xF`,等价于 `T[(p+8)&0xF]`,只是编译器的优化写法。 - 输出第 15 位用 `T[(p-1) & 0xF]`,同样等价于 `(p+15)&0xF`。 ### 4. 最终比对 ```asm movdqa 0x40(%rsp),%xmm0 ; Serial 解码出的 16 个 nibble pcmpeqb 0x30(%rsp),%xmm0 ; Name 计算出的 16 个期望 nibble pmovmskb %xmm0,%eax xor $0xffff,%eax jne rejected ``` Serial 解码得到的排列必须与 Name 推导出的排列**逐字节相等**。 ## 三、编写 Keygen 并验证 按上述算法用 Python 实现,先用已知合法键对自检: ```python TABLE = [0x04,-1,0x07,0x0c,0x01,0x09,-1,0x03, 0x0b,0x0e,0x06,0x0d,-1,0x08,0x0a,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,0x0f,0x05,-1,-1,-1,0x00,0x03] INV = {4:'!', 1:'%', 7:'#',12:'$',9:'&',3:'@',11:')',14:'*', 6:'+',13:',',8:'.',10:'/',15:':',5:';',0:'?',2:'('} def name_nibbles(name): T = list(range(16)); s = 0; r9 = 0 for i, ch in enumerate(name): c = ord(ch) nib = (c >> 4) ^ c s += nib j = (nib ^ r9) & 0xF T[i & 0xF], T[j] = T[j], T[i & 0xF] r9 += 3 p = s & 0xF return [T[(p+k) & 0xF] for k in range(16)] def make_serial(name): n = name_nibbles(name) s = ''.join(INV[v] for v in n) return s[0:4]+'-'+s[4:8]+'-'+s[8:12]+'-'+s[12:16] ``` 自检结果:对合法 Name `CAAA1C964B15D9B3` 生成的 Serial 恰为 `$/.;-):,(-#!%*-&?+@`,与题面完全一致,算法正确。 ## 四、求解目标 ``` Name = KCTF 期望 nibbles = [9,10,3,12, 13,14,0,15, 4,7,11,1, 5,6,2,8] Serial = &/@$-,*?:-!#)%-;+(. ``` ## 五、真机验证(Wine) 安装 wine 后直接运行验证: ```bash $ printf 'KCTF\n&/@$-,*?:-!#)%%-;+(.\n' | wine kctf_rosetta.exe ... [+] The symbols have found their meanings. [+] Calibration accepted. Key correct! ``` 用错误的 Serial 测试则被拒绝: ```bash $ printf 'KCTF\nAAAAAAAAAAAAAAAAAAA\n' | wine kctf_rosetta.exe [-] The inscription cannot be translated. ``` ## 最终答案 ``` Name : KCTF Serial : &/@$-,*?:-!#)%-;+(. ```
传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!!
收藏
・
0
点赞
・
0
打赏
分享
分享到微信
分享到QQ
分享到微博
赞赏记录
参与人
雪币
留言
时间
查看更多
赞赏
×
1 雪花
5 雪花
10 雪花
20 雪花
50 雪花
80 雪花
100 雪花
150 雪花
200 雪花
支付方式:
微信支付
赞赏留言:
快捷留言
感谢分享~
精品文章~
原创内容~
精彩转帖~
助人为乐~
感谢分享~
最新回复
(
0
)
游客
登录
|
注册
方可回帖
回帖
表情
雪币赚取及消费
高级回复
返回
mb_hfvhqurt
1
发帖
0
回帖
0
RANK
关注
私信
他的文章
[分享]KCTF 2026 - Rosetta Calibration
9
关于我们
联系我们
企业服务
看雪公众号
专注于PC、移动、智能设备安全研究及逆向工程的开发者社区
看原图
赞赏
×
雪币:
+
留言:
快捷留言
为你点赞!
返回
顶部