nesting
通过函数分析 ,有一个VM的指令解析器,也看不懂,VM的题看起来特别费劲
在sub_16BC里面找cmp的flag比对指令,0x1E21和0x1EC9。最终发现输入正确的字符和错误的字符,0x1E21处的指令执行次数不一样,可以通过输入fo,fl,fi,其中fl是正确的字符,发现正确的字符在0x1E21处执行的次数更多,因此可以使用这个方法来进行逐字节爆破,但是需要一款工具来统计执行次数,看了别人的WP好像是通过直接patch的方式,让返回值返回执行次数,但没详细写,也看不懂,所以自己找了下,发现一款动态插桩工具可以实现指令执行次数统计,叫pin
安装教程
https://www.intel.com/content/www/us/en/developer/articles/tool/pin-a-dynamic-binary-instrumentation-tool.html
下载完之后解压,然后进入source/tools/ManualExamples,
make obj-intel64/inscount0.so TARGET=intel64
,这是计数器的so,
此时在 obj-intel64 下编译生成了 inscount0.so,这个 so 即为一种 pintool,功能为记录程序执行的指令的条数;
判断 pintool 的功能可以阅读 pintool 源代码或者使用下条指令
$ pin -t your_pintool -h -- your_application
类似的,要编译 32 位的 pintool 可以使用
make obj-ia32/inscount0.so
编译 ManualExamples 中的所有 pintool 可以使用
make all TAEGET=intel64 make all TAEGET=ia32
编译完的使用格式是
../../../pin -t obj-intel64/inscount00.so -o inscount0.log -- you_binary
实战
原example是统计的所有指令的执行次数,但是,这个程序的执行次数是变化的,可能来自库函数的指令差异,我们只想统计指定行的执行次数,需要对inscount.cc进行更改,具体如下:
差异如下:
VOID docount() { icount++; }
已更改为:
VOID docount(void *ip)
{
if ((long long int)ip == 0x0000555555555E21)
icount++;
}
和:INS_InsertCall(ins, IPOINT_BEFORE, (AFUNPTR)docount, IARG_END);
已更改为:
INS_InsertCall(ins, IPOINT_BEFORE, (AFUNPTR)docount, IARG_INST_PTR, IARG_END);
这里的IARG_INST_PTR的解释,表示传入eip
这还有一个小坑,我使用的ubuntu开了ALSR,所以基址一直在变,追踪不到,需要关闭ALSR
点击查看代码
sudo su
echo 0 > /proc/sys/kernel/randomize_va_space
然后就可以编写脚本爆破了,附上我的脚本
from pwn import *
import subprocess
def run(msg):
cmd = [
"../../../pin",
"-t", "obj-intel64/inscount00.so",
"-o", "inscount0.log",
"--",
"/home/xiaowei/Desktop/CTF/nesting"
]
# 启动进程,并设置 stdin, stdout, stderr 为 PIPE,以便与进程交互
p = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
# 发送数据到进程
p.stdin.write(msg.encode())
p.stdin.flush()
# # 从进程接收数据
output = p.stdout.readline()
# print(output)
# 结束进程
p.terminate()
return int(read("inscount0.log").split(" ")[1])
def read(fname):
with open(fname) as f:
return f.read()
# print(run("fl"))
charset = string.printable
l = []
flag = ""
counter = 0
while(True):
max_chr = 0
first_iteration = True # 初始化标志为 True
for chr in charset:
tmp = run(flag + chr)
if first_iteration: # 只在第一次迭代时执行
max_value = tmp
first_iteration = False # 设置标志为 False
if tmp > max_value:
max_chr = chr
max_value = tmp
break
print(max_chr)
flag += str(max_chr)
print(flag)
大概半小时左右就能出来了
参考文章
标签:inscount0,..,max,intel64,chr,详解,so,nesting,2023 From: https://www.cnblogs.com/immune53/p/17769444.htmlhttps://eternal.red/2017/dont_panic-writeup/
https://firmianay.gitbooks.io/ctf-all-in-one/content/doc/5.6_llvm.htmlhttps://firmianay.gitbooks.io/ctf-all-in-one/content/doc/5.6_llvm.html