应该是今年在家的最后一天了,暑假结束了呜呜呜呜呜呜。–2022 8.3 23:06
GameMaster
0x00 Daily Shell Check
无壳32位 .NET 程序,拉进dnspy32
双击程序,用20块赢到2000万
0x01 Analyze
程序有亿点长,但其实关注关键位置就好了
首先比较在意的是 gamemessage 这个附件,这个大小估计就是加密的什么文件,而且在 BlackjackConsole.exe 用到了这个文件
注意存储到了 Program.memory
随后就是一排按键的不同效果,有趣的是当我们按 esc 的时候会有个特殊操作
在这个 verifyCode 又调用了 goldFunc,调用测试发现,按我们输入这些字符串再按 ESC 就是这个input
而在长长的 goldFunc 中有三个值得注意的 AchivePoint,对我们的 gamemessage 存储的东西进行了操作
(第三个没有,就不截图了)
然而我并不会动调取(呜呜呜有谁来教教我)
因为只是异或和AES解密,直接手动来好了
1 | from Crypto.Cipher import AES |
0x02 GameMessage
写出来的文件,拉进010,往下找MZ,把上面都删掉
再次拉进dnspy
1 | using System; |
发现3个环境变量不知(变量就是我们的存储的金额,打到正确的金额就是我们的flag),其他值都是已知的,然而这个check手逆有点麻,直接上Z3
0x03 GetFlag!
算法照抄即可,这一个个换行的数据强迫症患者表示很难受
1 | from z3 import * |
GetFlag!
EasyRe
0x00 Daily Shell Check
无壳64位
0x01 Analyze EasyRe
先把finger恢复符号表,然后看我们的主函数
MAIN
fork函数在主进程返回的是子进程的PID,在子进程返回的是0
- 所以在主进程我们会进入 if 分支
- 在子进程会进入 else 分支
1 | int __cdecl main(int argc, const char **argv, const char **envp) |
401F2F
而主进程与子进程通信与控制主要通过 ptrace 函数,可以看看这篇
函数原型
1 | long ptrace(enum _ptrace_request request,pid_t pid,void * addr ,void *data); |
ptrace最重要的就是第一个参数,借用该文中的图
光标在第一个参数上按M,搜索 ptrace,即可方便审计
于是阅读可知,也可以直接动调更清楚数据的走向,因为部分变量是结构体的原因其实F5的代码并不能直接确定
1 | __int64 __fastcall sub_401F2F(unsigned int Pid) |
那么目前,对该函数的认识有
4017E5 有一些有趣的数据
for 循环中 wait 函数等待子进程发送信号,主进程进行一些操作
0x02 RE3
找到 start 函数,对未定义的数据按C,再对start函数开头按p,恢复后找到main函数,熟悉的setjmp longjmp,梦回*CTF
那么我们可以获得的信息是
- 在 AdjustInput 我们的输入为 0101001 组成并存储到一个25x25的二维数组
- 再到 RecordData 处理,但是该函数没法成型,不过有两个 int 3
- 下面的longjmp setjmp 相当于一个循环,测试我们经过 RecordData 里的值
- savedregs + 25 * v13 + v11 - 0x28F 相当于lineData的地址
1 | __int64 __fastcall main(int argc, char **argv, char **a3) |
那么关键就是这个 RecordData 函数到底发生什么事情了
- 可以发现有个 int 3
- 同时下面的数据似曾相识,CAFEB055BF,这就是主进程进行比较的值
- 在函数末尾还有一处 int 3
那么此时一个大概的想法就出来了
- 主进程等待子进程运行
- 子进程除法int 3 等待主进程调试
- 主进程判断异常类型(这就是后面的值)
- 主进程进行 SMC 处理
0x03 SMC
那么我们该如何得到 SMC 后的文件呢,一种方法是直接逆SMC函数,另一种方法是动调获取
Analyze SMC
通过调试(由于主子进程的关系IDA会报些错,直接全部YES即可)和静态分析可知
sub_4017E5 函数里 fmemopen 的数据
- 第一个值是子进程地址 第二个值是要异或的值但还没处理
该原始值进行MD5后,再从第8个字节取倒叙后和主进程的值异或
(由于准备录视频解题就不贴动调过程了 XD)
那么我们只要取出这异或的值,再手动 patch RE3即可
于是在异或的值下个断点,再右键Edit breakpoint,打印出来即可
于是去子进程 Shift + F2 选择 python,run 一下得到我们的正确文件
1 | xorKey = {8723: 2533025110152939745, 8739: 5590097037203163468, 8755: 17414346542877855401, 8771: 17520503086133755340, 8787: 12492599841064285544, 8803: 12384833368350302160, 8819: 11956541642520230699, 8835: 12628929057681570616, 8851: 910654967627959011, 8867: 5684234031469876551, 8883: 6000358478182005051, 8899: 3341586462889168127, 8915: 11094889238442167020, 8931: 17237527861538956365, 8947: 17178915143649401084, 8963: 11176844209899222046, 8979: 18079493192679046363, 8995: 7090159446630928781, 9011: 863094436381699168, 9027: 6906972144372600884, 9043: 16780793948225765908, 9059: 7086655467811962655, 9075: 13977154540038163446, 9091: 7066662532691991888, 9107: 15157921356638311270, 9123: 12585839823593393444, 9139: 1360651393631625694, 9155: 2139328426318955142, 9171: 2478274715212481947, 9187: 12876028885252459748, 9203: 18132176846268847269, 9219: 17242441603067001509, 9235: 8492111998925944081, 9251: 14679986489201789069, 9267: 13188777131396593592, 9283: 5298970373130621883, 9299: 525902164359904478, 9315: 2117701741234018776, 9331: 9158760851580517972} |
(再把异常数值类型 patch 成 nop 即可)
Debugger SMC
这个思路出自 FallWind 师傅,只能说是曲线救国,太强了!
首先我们想 attach 我们修复后的子进程有几个困扰点
- 主进程在调试中我们没法直接调试
- 在 401F2F 函数的处理的第二个 int 3 是把函数 SMC 回去(也就是又回到加密状态)
- 在 401F2F 函数的 for 循环为3,前两个是处理 int 3 第三个是等待子进程结束
所以曲线救国的方法就是让主进程结束,子进程不结束
- patch EasyRe 的RE3资源文件,让在需要SMC的函数的结尾写个死循环
- patch RESMC函数 的异或值为0,让主进程不再加密回去
- patch 401F2F函数的 for 循环为2,这样主进程就不用等待子进程的结束值
这样执行完主程序两个异常处理就结束,然而我们的子进程还卡着,IDA直接attach上
(一会还要录视频今天有点晚了,就先不贴了)
0x04 GetFlag!
恢复后的函数,一眼丁真这是数织游戏(事后才知道
1 | // positive sp value has been detected, the output may be wrong! |
于是很明显我们RE3的主函数的对比数据不对,于是这时候就去init段还要个preinit段找
同样的手法是通过偏移来进行了混淆,手动计算即可,最后拿到真实数据
于是再去在线网站跑 https://handsomeone.github.io/Nonogram/
GetFlag!
Reference Article
About this Post
This post is written by P.Z, licensed under CC BY-NC 4.0.