# 超精准的宇宙射线模拟器

## 分析程序

反编译之后可以看出，程序初始化时将自己的代码段设置为了可写。

main 函数中，程序读入一个地址 addr 和一个整数 bit，然后把 addr 地址的第 bit 位翻转，然后程序退出。

我们只能翻转一个 bit，但只翻转一个 bit 不足以让我们获得任意命令执行的能力。所以这道题的关键在于，我们要利用翻转的第一个 bit 来创造出一个循环，使得我们可以翻转更多的 bit。可以翻转更多 bit 之后，我们就可以把 shellcode 写入代码段中，然后想办法跳转过去。

至于如何创造出循环，懒人做法是在代码段的地址范围内穷举所有地址，直到找到一个翻转后程序可以第二次读取我们输入（而不是崩溃或者正常退出）的位置。

我并没有去穷举，而是直接看汇编。

0x401295 处是一个 call 指令，调用了 `exit()` 函数退出程序，如果让它不要退出，就可以到达输出 `"Invalid input"` 的地方，然后跳转到输入的地方，形成循环。

这个 call 指令调用了 0x4010c0 这个函数，字节码是 `E8 26 FE FF FF`，如果翻转 `26` 的第 6 个 bit，就可以把字节码变成 `E8 66 FE FF FF`，即跳转到 0x401100，这里的逻辑是直接返回。

然后，我们利用这个循环来不断把 shellcode 覆盖 0x4010c0 也就是原来的 `exit()` 函数。

最后，我们把之前翻转那个 bit 改回去，程序跳转到 0x4010c0，我们的 shellcode 会被执行，就可以拿到 shell 了。

[最终的解题代码](src/solve_flip.py)
