<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>CTF on 我的CTF自留地</title>
    <link>https://yaoyaowq.com/categories/ctf/</link>
    <description>Recent content in CTF on 我的CTF自留地</description>
    <generator>Hugo</generator>
    <language>en</language>
    <lastBuildDate>Tue, 22 Sep 2026 00:00:00 +0000</lastBuildDate>
    <atom:link href="https://yaoyaowq.com/categories/ctf/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>N1CTF2020 oflo：花指令、自修改代码与 ptrace 反调试分析</title>
      <link>https://yaoyaowq.com/posts/n1ctf2020_oflo/</link>
      <pubDate>Tue, 22 Sep 2026 00:00:00 +0000</pubDate>
      <guid>https://yaoyaowq.com/posts/n1ctf2020_oflo/</guid>
      <description>&lt;p&gt;拿到题目先查壳和文件类型&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;1790074685084&#34; loading=&#34;lazy&#34; src=&#34;https://yaoyaowq.com/posts/n1ctf2020_oflo/1790074685084.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;发现是个elf文件，没用壳。直接用IDA打开。&lt;/p&gt;
&lt;p&gt;在ODA里面找到main函数，发现不能直接转换为伪代码。&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;1790074925023&#34; loading=&#34;lazy&#34; src=&#34;https://yaoyaowq.com/posts/n1ctf2020_oflo/1790074925023.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;直接看汇编指令。在0000000000400BB1处IDA解析的汇编有问题，依据loc_400BB1+1，将400BB1处第一个字节nop，继续往下看 ，看到一个奇怪的调用( call    loc_400BBF)，&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;1790075227617&#34; loading=&#34;lazy&#34; src=&#34;https://yaoyaowq.com/posts/n1ctf2020_oflo/1790075227617.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;call 400BBF&lt;/code&gt; 执行时会将下一条指令地址 &lt;code&gt;400BBC&lt;/code&gt; 压入栈中，随后 &lt;code&gt;pop rax&lt;/code&gt; 将该返回地址取出，再通过 &lt;code&gt;add rax, 1&lt;/code&gt; 将其修改为 &lt;code&gt;400BBD&lt;/code&gt;，最终通过 &lt;code&gt;retn&lt;/code&gt; 将执行流转移到 &lt;code&gt;400BBD&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;1790075692509&#34; loading=&#34;lazy&#34; src=&#34;https://yaoyaowq.com/posts/n1ctf2020_oflo/1790075692509.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;已知从400BBD开始，所以将400BBD开始的内容转换为code，400BBC直接nop.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;1790075789466&#34; loading=&#34;lazy&#34; src=&#34;https://yaoyaowq.com/posts/n1ctf2020_oflo/1790075789466.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;这里直接跟进loc_400BD1，&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;1790075831228&#34; loading=&#34;lazy&#34; src=&#34;https://yaoyaowq.com/posts/n1ctf2020_oflo/1790075831228.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;这里看到三个函数sub_4008B9，loc_400BEF，loc_400CAC，通过跟进函数可以发现sub_4008B9，loc_400BEF这两个函数都没用问题，但是loc_400CAC处有和之前相似的花指令。&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;1790076086373&#34; loading=&#34;lazy&#34; src=&#34;https://yaoyaowq.com/posts/n1ctf2020_oflo/1790076086373.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;直接用之前的方法，把&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;400CB5-400CBA 和400CBD-400CCE
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;全部patch 为nop。&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;1790076315193&#34; loading=&#34;lazy&#34; src=&#34;https://yaoyaowq.com/posts/n1ctf2020_oflo/1790076315193.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;出现&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;jmp     short loc_400CCF
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;继续跟进这个跳转。&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;1790076450282&#34; loading=&#34;lazy&#34; src=&#34;https://yaoyaowq.com/posts/n1ctf2020_oflo/1790076450282.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;这里可以看到 在 &lt;code&gt;0x400D04&lt;/code&gt; 又发现一个非常经典的花指令，还是直接将第一个字节 patch 为 nop。&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;1790076652013&#34; loading=&#34;lazy&#34; src=&#34;https://yaoyaowq.com/posts/n1ctf2020_oflo/1790076652013.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;这样看起来就像一个正常的函数结尾了。&lt;/p&gt;
&lt;p&gt;现在返回400B54(main的开头)，先 &lt;code&gt;p&lt;/code&gt; 一下重新建立函数，之后就可以正常 &lt;code&gt;F5&lt;/code&gt; 反编译了 。&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;1790077079570&#34; loading=&#34;lazy&#34; src=&#34;https://yaoyaowq.com/posts/n1ctf2020_oflo/1790077079570.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;main函数的主要流程:&lt;/p&gt;
&lt;p&gt;首先调用sub_4008B9;接着接收输入的19个字符;随后调用mprotect，修改sub_400B54 &amp;amp; 0xFFFFC000为首页地址区域的权限，将其改为 r | w | x ;紧跟着是改变400A69处的前10个字节;最终是调用sub_400A69检查flag是否正确。&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;程序开始
   ↓
调用 sub_4008B9
   ↓
接收用户输入 19 个字符
   ↓
调用 mprotect
   ↓
将代码所在内存页权限修改为
R | W | X
   ↓
使用输入的前 5 个字符
循环 XOR 修改 sub_400A69
的前 10 个字节
   ↓
恢复出运行时真正执行的代码
   ↓
调用 sub_400A69
   ↓
进行 Flag 校验
   ↓
┌───────────────┐
│   校验是否正确 │
└───────┬───────┘
        ↓
   正确        错误
    ↓            ↓
输出 Cong!     返回失败
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;由于题目是:N1CTF2020 - oflo,所以输入的前5个字符是n1ctf，&lt;/p&gt;</description>
    </item>
  </channel>
</rss>
