DDCTF pintools

利用pintools解决逐字节校验的逆向题

首先,什么是pintools?大概就是一种指令级插桩工具https://huirongis.me/archives/page/2/,这位巨巨的博客介绍也算是十分详细的了,先总结下pintools在ctf中的应用。
目前萌新如我,用pintool也只会用用他的指令计数也就是inscount模块,在逆向中进行逐字节校验时,第一位输入正确和第一位输入错误,必然导致了不同的流程,也就是会有大量的指令数偏差,指令数偏差也需要自己稍微尝试下才能确定一个大概的范围,就拿ddctf那题来说,之前的wp中我是采用直接找check点来找出flag的,赛时也想了pin,但是环境没装好,也没去细看,就算了,这里用pin试看看。
image_1d9es1e5vgqj18k21e6ebt7lkq9.png-228.2kB
原本的pintools是将指令计数结果写入一个文件中的,我们这里直接修改下,让他在每次运行结束直接给出指令数回显,然后make all重新编译即可。
然后我们就可以分析下脚本编写了,首先尝试使用subprocess进行模拟shell运行pin和目标软件

import subprocess
import os
import logging
import json


# js = json.dumps(ssst, sort_keys=True, indent=4, separators=(',', ':'))# format json output

class Shell(object):
    def runCmd(self, cmd, input):
        res = subprocess.Popen(cmd, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
        res.stdin.write(input)
        sout, serr = res.communicate()
        return sout

returnStr = shell.runCmd(cmd, flag1)
count=returnStr.split("Count ")[1]

并且使用split从回显中分离出指令数,然后就是逐两位爆破了,这个就是需要稍微跟一下程序了,dd那题是每两位转hex,然后校验,也就是说我们爆破时也需要两位两位爆破

import subprocess
import os
import logging
import json


# js = json.dumps(ssst, sort_keys=True, indent=4, separators=(',', ':'))# format json output

class Shell(object):
    def runCmd(self, cmd, input):
        res = subprocess.Popen(cmd, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
        res.stdin.write(input)
        sout, serr = res.communicate()
        return sout


filename = "/root/Desktop/elfreverse/obfuscating_macros.out"
cmd1 = "/root/Desktop/elfreverse/obfuscating_macros.out"
cmd = "/root/Desktop/pin/pin -t " + \
      "/root/Desktop/inscount0.so " + " -- " + filename
shell = Shell()
list1=['0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F']
flag=""
count_old=0
count_new=0
count=0
s=""
for i in range(28):
    for ch1 in list1:
        for ch2 in list1:
            s+=ch1
            s+=ch2
            print(s)
            returnStr = shell.runCmd(cmd, s)
            count=returnStr.split("Count ")[1]
            a=int(count)
            cha=a - int(count_old)
            if(cha >5000 and s!="00" and s!="01"):
               print( "current char ", s,"current count",count)
               flag+=s
            else:
                s=flag
            count_old=count

这里我定的时候就是定一下指令差为5000,就能跑出结果了,不仅仅是这道题,任何诸位校验的题目(比如rc4这种)都可以用pin暴力解,但是,一般真正做题时,盲目pin肯定不行,需要调试判断校验方式以后再弄才行,看了夜影师傅关于pin的博客,发现多线程爆破速度甚至不如单线程,就没想去加多线程,这个模板也可以存着,以后拿来改改就用,考研复习期间可能很少看这些,下一个目标就是抽空看会unicorn,感觉会是十分有趣的工具呢!