180204 逆向-Py多线程调用PinTools

1625-5 王子昂 总结《2018年2月4日》 【连续第492天总结】
A. Python多线程调用PinTools
B.

前言


本文初衷是为了拟补PinTools在爆破中效率较低的问题,而非PinTools针对多线程程序的相关描述
为了不引起期望获得后者的读者们的误会先行提出

思路


结果读取

之前参照Invicsfate一步一步修改来的爆破脚本原理是将待输入字符写入一个文件中,然后通过重定向来节省向管道写入的时间和麻烦
这样只需要读取回显即可

另一方面,inscount例程的输出方式都是写出文件,因此之前的脚本也只能再读取结果文件

对于这样的脚本,多线程修改的弊端在于输出方式。
输入方式可以通过每个线程使用独立的文件来重定向结局,
但结果最后都输出到同一个文件中,因此多线程并行的时候势必会彼此干扰

因此首先要找到一个可以使得多线程区分开的结果输出方式

刚开始想得是自定义命令行,与输入的方式类似,使每个线程的输出都放在独立的一个结果文件中。找了一下API只看到说在KNOB中,但是没有找到怎么使用

后来想了一下,既然是通过ostream输出到文件,当然也可以用cout来打印到屏幕中吧。因为每个线程都独立开了一个管道,所以是满足互不影响需求的

尝试了一下果然可以

参数传入

下一步是思考怎么进行线程间的通信。传递参数很简单,但是结果回收和统计就稍微有点意思了。
最理想的状况当然是送给子线程一个指针,然后子线程修改指针对应的值,达到引用传递的效果。然而python中并没有指针的说法

但Python中也并不是值传递,而是传对象引用的形式
在Python中,万物皆对象
无论是常数(1、2、3)还是字符串、列表、元组等等,它们都是对象
而对象就涉及到可变对象和不可变对象了
可变对象仅有列表和字典,其他都是不可变对象
可变对象意味着子元素可以修改,而对象不变。
eg:

list = [1, 2]
list[0] = 2

修改前后list指向的是同一个列表对象
而字符串、元组则不是

s = "123"
s[0] = "2"
->Error
s = "223"
s += "1"

它们不能修改元素的对象,虽然可以重新赋值或是通过一些内建方法来修改,但是这样修改完的字符串/元组实际上是一个新的对象,可以通过id()来验证

回到需求本身,如果传一个可变对象的引用过去,那么函数中是可以修改这个可变对象的,从而达到引用传递的效果

脚本写起来不是太复杂

代码


#coding=utf-8
import popen2
import string
import threading
import os
from time import time

CMD = r"E:\ctf\pin\pin.exe -t E:\ctf\pin\source\tools\Inscount0_win\obj-ia32\inscount0_win_stdout.dll -- F:\ctf\Whale\CrackMe\CrackMe.exe <"
choices = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!#$%&'()*+,-./:;<=>?@[\]^_`{|}~"

flag = ""
def writefile(data, file):
    fi = open(file,'w')
    fi.write(data)
    fi.close()


def execlCommand(command):
    fin,fout = popen2.popen2(command)
    for i in range(3):fin.readline()
    p = int(fin.readline())
    return p

def main(tmp, i):
    key = flag + i  # 测试字符串
    # print(">", key)
    writefile(key, str(ord(i)))
    result = execlCommand(CMD + str(ord(i)))
    print("%s : %d" % (i, result))
    tmp[result] = i

def test(command):
    fin,fout = popen2.popen2(command)
    (fin.readline())
    s = fin.readline()
    print(s)
    if("Failed" in s):
        return True
NUM_threads = 5
time1 = time()
while(1):
    tmp = {}
    for j in range(len(choices)//NUM_threads + 1):
        threads = []
        for i in range(NUM_threads):
            try:
                t = threading.Thread(target=main, args=(tmp, choices[j*NUM_threads+i]))
            except IndexError:
                break
            t.start()
            threads.append(t)
        for i in threads:
            i.join()

        p = sorted(tmp.keys(), reverse=True)[0]
        if(tmp.keys().count(p) != len(tmp)):break
    p = tmp[p]
    flag += p
    print(flag)
    if(test(CMD + str(ord(p)))):break

print("总用时:%ds"%(time()-time1))
for i in choices:
    os.remove('./' + str(ord(i)))

后记


然鹅。。。

效率过低的原因看来是PinTools本身吃光了CPU的资源,多线程并不能提高效率,甚至还会拉低一些。
单线程情况下平均每个字符需要2s左右,多线程(10个线程情况下)则需要20-30s。

于是多线程提高效率的方案就夭折了

下一步尝试Frida或者其他方法来Hook,还有Trace+BBL级别的使用尝试

C. 明日计划
PinTools-Trace\Bbl

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值