N1CTF2020 oflo:花指令、自修改代码与 ptrace 反调试分析

拿到题目先查壳和文件类型 发现是个elf文件,没用壳。直接用IDA打开。 在ODA里面找到main函数,发现不能直接转换为伪代码。 直接看汇编指令。在0000000000400BB1处IDA解析的汇编有问题,依据loc_400BB1+1,将400BB1处第一个字节nop,继续往下看 ,看到一个奇怪的调用( call loc_400BBF), call 400BBF 执行时会将下一条指令地址 400BBC 压入栈中,随后 pop rax 将该返回地址取出,再通过 add rax, 1 将其修改为 400BBD,最终通过 retn 将执行流转移到 400BBD。 已知从400BBD开始,所以将400BBD开始的内容转换为code,400BBC直接nop. 这里直接跟进loc_400BD1, 这里看到三个函数sub_4008B9,loc_400BEF,loc_400CAC,通过跟进函数可以发现sub_4008B9,loc_400BEF这两个函数都没用问题,但是loc_400CAC处有和之前相似的花指令。 直接用之前的方法,把 400CB5-400CBA 和400CBD-400CCE 全部patch 为nop。 出现 jmp short loc_400CCF 继续跟进这个跳转。 这里可以看到 在 0x400D04 又发现一个非常经典的花指令,还是直接将第一个字节 patch 为 nop。 这样看起来就像一个正常的函数结尾了。 现在返回400B54(main的开头),先 p 一下重新建立函数,之后就可以正常 F5 反编译了 。 main函数的主要流程: 首先调用sub_4008B9;接着接收输入的19个字符;随后调用mprotect,修改sub_400B54 & 0xFFFFC000为首页地址区域的权限,将其改为 r | w | x ;紧跟着是改变400A69处的前10个字节;最终是调用sub_400A69检查flag是否正确。 程序开始 ↓ 调用 sub_4008B9 ↓ 接收用户输入 19 个字符 ↓ 调用 mprotect ↓ 将代码所在内存页权限修改为 R | W | X ↓ 使用输入的前 5 个字符 循环 XOR 修改 sub_400A69 的前 10 个字节 ↓ 恢复出运行时真正执行的代码 ↓ 调用 sub_400A69 ↓ 进行 Flag 校验 ↓ ┌───────────────┐ │ 校验是否正确 │ └───────┬───────┘ ↓ 正确 错误 ↓ ↓ 输出 Cong! 返回失败 由于题目是:N1CTF2020 - oflo,所以输入的前5个字符是n1ctf, ...

September 22, 2026 · 1 min