强网杯初赛的这道 re 挺有意思的,做了快 20h 出了。
ptrace 父子进程调试,父进程追踪子进程 int 3 指令的位置,替换成相应的操作,因为开始的赋值操作导致数据结构不好看,可以考虑 dump + nop 初始化的方式。每次 int 3 触发之后,会执行一个结构体中的函数,结构体如下定义。经过遍历结构体,去重得到一共只会执行以下几个函数。分析父进程的操作根据还原的伪代码逻辑也可以看出:第一步,断 fork,dump 结构体内容,保存为 .h 文件第一步可以验证前面两个猜想,一个是找 func 函数,去重,用一个 set 做就行,另一个是当 func return 3 的时候,输出 rchild,观察函数。第一步不给代码了,第二步运行一下:运行可以发现,输出地址均为 plt 表中的地址。后续我还做了一张 dot 表,可以直观地感受节点之间的控制关系。用输出的结果转为 dot 图。最后得到下面的图是的最开始拿到这张图,我也没招了,总不能真一个个看吧,随后我写了一个分析 vm 指令流的脚本,并用广搜去解析它们之前基本块的关系。在 case 2 的处理中,我输出了下一步的块,虽然可能会有点错误,但是不影响指令分析。把这些块解引用之后,可以输出结构体,然后编写 idapy 脚本去取指令分块重构,以 int 3 为间隔,每次扫描该块的 RIP 字段,取出该地址往下的所有指令,直到遇到 int 3 停止,这里根据 func 去处理函数:jumptable 来源于上一个脚本向标准错误流打印的数据(方便重定向)。运行脚本之后得到原指令流,事实上可以根据广搜结果将明显访问不到的块去掉。如图右边这一块,但是事实上只有 80 个块你也不可能拉条儿去硬找,基本都是用 search。汇编好的选手可以直接秒了,像我这种汇编不好的选手只能求助 AI 了,通过求助 AI 大致摸清楚了前面的执行流程。而比较关键的是对于两个 256 字节的数组进行的初始化,仅仅简单对一个 32 字节硬编码数组做了一个异或运算。这下看懂了,这就是 AES 的 SBOX 数组,随后的循环明显是轮密钥加,之后我写了 dump 脚本去 dump 轮密钥,并用程序去进行了验证。dump 的轮密钥和 AES 的key对应上了,而且 key 可以用随机数种子去验证,分段发给 AI 汇编代码,AI 后面可以分析出又使用了 srand(rand()) 。动调也可以验证,因为发现整个块里面就调用了两次 srand,第二次 srand 前驱调用了一个 rand() 函数。如果实在不放心,可以在 0x400b79 地址被引用的代码下硬件断点去观察也就是这里的 0x606b58。这样刚好可以在 case 3 call srand 之前断住。这里的 rchild=0x400870 就是 srand 的地址,本次continue过去就会执行srand,那么这里关心的值当然就是上一个块 rand 的返回值,直接找 regs 结构体的 RAX 。这里找到了它的返回值 1343350356,刚好是可以对应上的(可以自己 srand(0x10000),然后输出第 17 个 rand 值验证)。后面的异或操作都是问 AI 的,最后比较的 target 就是祝贺找到正确的 flag 那句话。通过输入 24 个 a,观察 AI 拿的加密数组,基本可以确定异或之前的值就是输入进行 AES 之后的值,这里我直接用 /proc/pid/mem 去 dump 指定区域的内存。通过dump结果比对发现就是普普通通的 AES ECB/Nopadding。那么流程就清晰了:提取目标比对的字节,异或硬编码数组和随机数数组之后输出,最后 AES 解密即可。最后的 AES 解密得到 flag。也分享一下我的 AI 聊天记录866K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6U0K9r3q4@1k6%4m8@1i4K6u0W2j5$3!0E0i4K6u0r3M7$3S2S2M7X3g2Q4x3V1j5$3z5r3j5@1k6X3t1J5x3q4)9J5k6o6R3#2x3X3y4Q4x3X3b7^5x3o6l9J5i4K6u0V1j5e0y4W2k6g2)9J5k6o6y4X3j5e0V1^5x3h3j5^5z5o6V1J5y4b7`.`.在群友的帮助下,我大概知道正确的恢复流程了,应该给 case 4 建立 rchild 的 call,再建立lchild的jmp,而 case 2 直接 ret 就行,但是即使恢复正确的流程 ida 也是无法正确恢复指令流,所以差别不大。这题属于签到的水平,只不过就是静态链接的题目,对于静态链接的题目,lumina 直接秒了,我搭建了一个私人服务器,里面放了一些常用的库代码。关于 lumina:729K9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8U0S2Q4x3X3f1I4y4e0y4Q4x3X3f1%4x3g2)9J5k6e0t1@1y4#2)9K6b7e0R3H3x3o6m8Q4x3V1k6D9N6h3#2A6L8X3q4Q4x3V1k6A6L8X3k6G2i4K6u0W2K9s2c8E0L8l9`.`.恢复符号之后约等于裸奔,然后全选,复制,粘贴,发给 AI,秒了。。。2faK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6U0K9r3q4@1k6%4m8@1i4K6u0W2j5$3!0E0i4K6u0r3M7$3S2S2M7X3g2Q4x3V1j5$3z5r3j5#2z5h3y4X3k6q4)9J5k6r3t1$3x3e0m8Q4x3X3b7^5x3o6l9J5i4K6u0V1z5h3k6X3k6W2)9J5k6o6b7H3y4K6f1@1z5o6R3@1x3r3j5@1y4H3`.`.总共就问了两句话,用时 1 分钟。CTF 真好玩,上周末单休,这周的强网杯直接把周末干碎了,从 11 点到 6 点(第二天凌晨),已经是一个活人微死的状态了,tradre 这题 80 解,我 CN 的逆向水平真好。struct data
---
来源: 看雪论坛
原文链接: https://bbs.kanxue.com/thread-288872.htm
[原创]强网杯S9初赛逆向 writeup
161 浏览
4 回复
求一下 群
神奇的人鱼
求一下 群
看52
求一下 群
看52
看着挺复杂的,没点逆向功底还真搞不定。一时来兴趣分析了下,重点还是控制流混淆的还原,也有动态反调试,但是可以用pin直接hook父进程打印出真实控制流指令,中间调试时直接patch alarm(60)的情况,把60秒改成0xFFFFFFFF,就不会在调试时被中断退出,而子进程虽然被ptrace,无法直接调试或hook,但可以跟踪父进程。于是,边ida逆向父进程函数,边寻找插点位置,其实重点就3处,:KNOB<ADDRINT> KnobPInst(KNOB_MODE_WRITEONCE, "pintool", "pinst", "0x40238D", "parent instruction address to read rax");
KNOB<ADDRINT> KnobPCall(KNOB_MODE_WRITEONCE, "pintool", "pcall", "0x4021B2", "parent call instruction address");
KNOB<ADDRINT> KnobPSrc(KNOB_MODE_WRITEONCE, "pintool", "psrc", "0x40203D", "parent instruction address to read rdx");就是记录跳转前后的地址而已,至于中间什么栈模拟操作的虚拟机指令,完全不用逆,不用管,这就大大地提升解题速度。
然后用pin执行,获得还原指令:"$PIN_ROOT/pin" -t ./obj-intel64/child_ins_trace.so -- ../tradre > ../trace.txt对比下控制流还原前后的情况:
基于pin hook的代码完全是让AI写的,我没写一行代码,但是要基于自己手工逆向分析后,告诉AI具体怎么做才行,也折腾了几个小时,还原出指令后,后面的就是分析汇编,详细见楼主的分析,主要就是AES+xor随机值+xor固定数组的算法,不再赘述。
完整的pin代码和还原出来的指令见附件。
最后于 2025-12-20 21:10
被riusksk编辑
,原因:
KNOB<ADDRINT> KnobPCall(KNOB_MODE_WRITEONCE, "pintool", "pcall", "0x4021B2", "parent call instruction address");
KNOB<ADDRINT> KnobPSrc(KNOB_MODE_WRITEONCE, "pintool", "psrc", "0x40203D", "parent instruction address to read rdx");就是记录跳转前后的地址而已,至于中间什么栈模拟操作的虚拟机指令,完全不用逆,不用管,这就大大地提升解题速度。
然后用pin执行,获得还原指令:"$PIN_ROOT/pin" -t ./obj-intel64/child_ins_trace.so -- ../tradre > ../trace.txt对比下控制流还原前后的情况:
基于pin hook的代码完全是让AI写的,我没写一行代码,但是要基于自己手工逆向分析后,告诉AI具体怎么做才行,也折腾了几个小时,还原出指令后,后面的就是分析汇编,详细见楼主的分析,主要就是AES+xor随机值+xor固定数组的算法,不再赘述。
完整的pin代码和还原出来的指令见附件。
最后于 2025-12-20 21:10
被riusksk编辑
,原因:
顺道问下楼主,ABabyChal这道Reverse题分析过没:93aK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6U0N6r3k6Q4x3X3g2T1N6h3N6C8N6g2)9J5k6h3y4G2L8g2)9J5c8X3y4Z5j5h3I4D9k6h3&6Y4k6i4y4Q4x3V1k6V1k6i4c8S2K9h3I4Q4x3V1k6A6k6q4)9J5c8U0t1&6z5e0k6Q4x3X3g2Z5N6r3#2D9i4@1g2r3i4@1u0o6i4K6S2o6i4@1f1%4i4K6V1@1i4@1p5^5i4@1f1#2i4@1q4q4i4K6V1^5i4@1f1$3i4K6V1$3i4@1t1&6j5i4u0C8i4K6g2X3k6r3W2K6j5i4y4E0i4@1f1@1i4@1t1^5i4K6S2q4j5i4u0C8i4K6g2X3k6r3g2U0L8$3#2H3L8r3W2D9k6i4u0Q4c8e0g2Q4z5f1c8Q4z5o6N6Q4c8e0k6Q4z5e0N6Q4b7e0m8Q4c8e0k6Q4b7U0y4Q4z5e0g2Q4c8e0g2Q4z5p5k6Q4z5p5c8Q4c8e0N6Q4b7V1y4Q4z5e0k6Q4c8e0S2Q4b7f1k6Q4z5e0q4Q4c8f1k6Q4b7V1y4Q4z5p5y4Q4c8e0g2Q4z5p5k6Q4b7f1k6Q4c8e0S2Q4z5o6y4Q4b7V1c8Q4c8e0k6Q4z5e0S2Q4b7f1k6S2j5X3y4Q4c8e0g2Q4b7V1y4Q4z5e0g2Q4c8e0k6Q4z5e0y4Q4z5p5g2Q4c8e0S2Q4b7e0u0Q4b7f1u0Q4c8e0c8Q4b7V1k6Q4b7f1g2Q4c8e0k6Q4z5e0c8Q4b7U0W2Q4c8e0c8Q4b7V1q4Q4z5o6j5`.
最后于 2025-12-31 15:38
被riusksk编辑
,原因:
最后于 2025-12-31 15:38
被riusksk编辑
,原因: