mcfx's blog

题解、Writeup、游记和碎碎念

部分交互题的通用 hack 方法

这篇文章原发布在 https://mcfxmcfx.blog.uoj.ac/blog/6519

背景

对于一部分交互性题目,他们的考点是调用某个函数的次数。对于某些题目,如果询问次数足够大,那么暴力算法(或者比正解简单的多的做法)也可以通过。

假设交互器不是 adaptive 的(即数据是预先确定的),那么我们可以考虑调用询问函数,然后再把询问次数改回去。这其实很容易做到,比如在程序中内嵌一个 qemu 之类的模拟器,把询问函数模拟执行一遍,并记录下他改动过的内存,事后再改回去。

实现

qemu 体量太大,比较难修改,并且修改完可能也压不进代码长度限制。所以需要找一个比较简单的 x86_64 模拟器。

我经过一番搜索,找到了 https://github.com/blbogdan/x64vcpu 这个项目,他的体量就比较小。去除 FPU 和 SSE 等一些用处不大的东西(这里其实埋了个坑,之后会讲到),再去掉 asm(为了满足 uoj 的要求),得到了 https://github.com/mcfx0/x64vcpu 这样一个东西。

接下来就可以去 hack 交互题了,比如 https://uoj.ac/submission/441760

不过对于其他一些题目,比如 https://uoj.ac/problem/165 ,他的交互次数非常多,暴力本身的运行时间就已经接近时限,这种情况下如果还是每次询问都模拟,显然会 TLE。所以可以在最开始模拟一次询问,获取他修改的内存位置,最后再把这些内存改回去,于是询问次数也被改了回去(比如 https://uoj.ac/submission/441773 )。

至于前面说到的坑,其实是 libc 的 memset 用到了 SSE,这导致询问函数中用到 memset,这份代码就失效了。(但是只要把 SSE 的实现加回来,就没有这个问题了)

可能的防范方法

12.07 更新:修了个 bug,改了改 api,可以见 github,也可以见 https://uoj.ac/submission/441827

日期: 2021-08-26

标签: 交互题