脱壳
010打开

UPX改了特征码,版本5.1.0
直接拖到ida分析不出来
这里我们选择动态调试脱壳,先找OEP,f9运行到入口

触发TLS回调函数断点,停在了ret上
64位UPX壳中不会用一个明显的跨段jmp指令跳向OEP,而是把OEP的地址压入堆栈,然后执行一条ret指令,这样CPU就会把堆栈顶部的OEP地址当作返回地址弹出来,并跳转过去
我们直接f8过去

此时进入了系统DLL地址,不用管,执行到用户代码

标准的UPX壳保存环境的方式,步过4次

此时当前的栈顶已经被修改了,内存中转到RSP,在栈顶位置下硬件断点,然后一直f9到触发硬件断点


此时正在恢复保存的寄存器状态,最后的jmp即是尾部跳转,直接f4过去,然后步过一下

可以看到已经解密完成,0x4014E0就是OEP
打开Scylla插件搜索IAT

找到两个IAT大小,因为这个exe只有几十kb,528字节的输入表正好,选择否,然后获取输入表

dump之后修复得到最终脱壳后的程序

运行报错,但不影响ida分析
第一层EXE
通过ida逆向

可以看到这里是获取了用户的输入并和Str2进行比较,Str 为 NGeQwv8eCRpINEcO


标准的windows可执行文件
如果正确就会通过sub_401660函数进行base64解码并向缓存路径内写入一个随机名称的exe,直接执行原文件输入密码就能得到

第二层EXE
运行发现需要输入key

继续通过ida逆向这个文件,通过main函数找到处理逻辑(sub_401550函数)

分析可知,这里的逻辑也是接收用户输入的key,然后通过nullsub_3函数判断key是否正确
中间的do-while步骤是优化后的strlen函数实现,输入长度不超过240
现在我们的思路就是分析nullsub_3函数,不过nullsub在ida中代表为只有一个ret的空函数,说明针对反编译器做了修改,我们需要看看到底是不是真的空函数

跟进后发现是一个奇怪的hello节,应该就是题目提示了
这里我们选择通过x64dbg进行动态调试,首先加载后找到主逻辑函数地址
查找Enter the key关键字引用

ida中找到地址


输出Faild和Success中间的call就是,直接跳转然后下断点0x401623

然后一直f9运行到等待用户输入,返回窗口随便输入一串key:12345678

跟进


这里可以看到明显是有内容的,分析逻辑如下:
1 | 1、逐字节读取刚刚输入的key |
基本可以判断是AES或者SM4
运行到404F86(调用404CB0函数之前)拿到三个参数

1 | Key: C2 30 12 AB 39 10 18 33 F8 ED 4E 46 8D A1 5D 8D 8C FB F0 72 68 99 DC 7C 84 6E 7E CF 32 BB DA F8 |
然而AES和SM4解密都失败了,说明题目对标准加密流程进行了魔改
跟进404CB0函数内部:

这里往栈上压入了一个参数E(十进制14),而加密轮数14的分组密码只有AES,我们上一步解密失败了,最大的可能就是魔改了标准的S盒
往下看,压栈后调用了404B60函数,直接跟进

这里就是AES的核心算法,先把内存地址 4071E0 装载到了 r14 寄存器里,然后把明文字节当做索引 rdx,去 r14 也就是 4071E0 这个地址里查表替换,这就是 AES 加密中最核心的字节替换操作,那么4071E0地址就是魔改S盒的地址

然而进去后发现就是标准的S盒
接下来就该排查行移位ShiftRows和列混淆MixColumns步骤有没有问题

这里调用了2个函数,分别跟进看一下
404070:

0, 5, 10, 15、13, 4, 9, 14、8, 13, 2, 7
正确对应行移位后的矩阵排列
404190:

0x1B 是 AES 有限域乘法的标准多项式常数,2 和 3 也是标准的乘法矩阵
到这里我们总结一下:
1 | 1、标准S盒 |
还剩最后一个密钥扩展算法,这里我们想要重新分析算法就比较复杂了,但是最终是要生成好放进内存,直接在密钥生成器之后在内存中获取即可
重新运行跟进到404B60内部:

在字节替换操作之前,调用了一个404940函数,多半就是轮密钥的生成逻辑,运行到此处步过一次,而生成的轮密钥随后就被存放在了rbx寄存器指向的地址,内存窗口中找到

正好240字节
1 | C2 30 12 AB 39 10 18 33 F8 ED 4E 46 8D A1 5D 8D 8C FB F0 72 68 99 DC 7C 84 6E 7E CF 32 BB DA F8 B4 67 53 88 8D 77 4B BB 75 9A 05 FD F8 3B 58 70 CD 19 9A 23 A5 80 46 5F 21 EE 38 90 13 55 E2 68 58 FF 16 F5 D5 88 5D 4E A0 12 58 B3 58 29 00 C3 A7 BC F9 0D 02 3C BF 52 23 D2 87 C2 30 87 65 AA 5C B2 BA F1 89 3A E7 BF 29 28 BF 0C 71 01 BF CF 04 C0 F1 87 06 FC 4E D5 25 2E C9 17 15 A9 AC BD 9A 23 C0 A8 13 19 27 17 3A 31 98 1B 4B 30 27 D4 B7 C4 3D CF B1 38 73 1A 94 16 BA 0D 81 BF 16 B0 8B 64 27 A4 98 7D 00 B3 A2 4C 98 A8 E9 7C BF 7C A9 D4 35 DF 18 EC 46 C5 8C FA FC C8 0D 45 EA 78 E4 E3 9B 73 7C 9E 9B C0 DE D2 03 68 37 AE BC 14 33 30 50 25 2B DC 16 E0 A7 26 EA 28 AA 63 00 50 2E 80 C8 DF 52 1E 53 1F 8C CC 50 77 BB 62 EC 63 |
编写自定义轮密钥的解密脚本:
1 | # 自定义的轮密钥 |
FLAG

得到flag:dart{c3d4f5cc-8aab-46ce-a188-2fc453f3b288}