在angr文档里发现writing exploration technique的部分是空的。然后,恰好看到一篇博客讲了如何控制符号执行的资源消耗,看到里头的代码是基于自定义exploration technique来实现的。
如果对于如何控制符号执行的内存消耗感兴趣可以看这篇博客:
https://degrigis.github.io/posts/explosion_detector/
先来看看他的例子,这个代码的思路是利用psutil获取进程占用的内存信息。如果占用的内存超出了设定的最大内存值,则将active的状态移为out_of_memory的状态去。
import angr
class MemLimiter(angr.exploration_techniques.ExplorationTechnique):
def __init__(self, max_mem, drop_errored):
super(MemLimiter, self).__init__()
self.max_mem = max_mem # 设定最大内存
self.drop_errored = drop_errored
self.process = psutil.Process(os.getpid())
def step(self, simgr, stash='active', **kwargs):
#如果内存占用超过90%或者内存超出了设定的最大值,则将active状态移到out_of_memory状态
if psutil.virtual_memory().percent > 90 or (self.max_mem - 1) < self.memory_usage_psutil:
simgr.move(from_stash='active', to_stash='out_of_memory')
simgr.move(from_stash='deferred', to_stash='out_of_memory')
# 丢弃deadended,avoid,found状态,暂时没明白为什么要丢弃,是因为超出内存大小,所以不需要这些不是很重要的状态了?
simgr.drop(stash='deadended')
simgr.drop(stash='avoid')
simgr.drop(stash='found')
if self.drop_errored:
del simgr.errored[:]
return simgr.step(stash=stash)
#将内存使用情况设为这个类的属性
@property
def memory_usage_psutil(self):
# return the memory usage in MB
mem = self.process.memory_info().vms / float(2 ** 30)
return mem
这个例子给了一个很好的例子,来告诉我们如何写exploration_technique…
首先创建一个类,继承angr里的类:angr.exploration_techniques.ExplorationTechnique,其次,这个类里有两个方法需要自己完善,一个是__init__,另一个是step。
init中可以使用super来直接使用父类的init方法。
step中的参数有以下几个:
- simgr(模拟执行的管理器)
- stash=‘active’:stash是保存状态的列表,这里是只处理active状态
- **kwargs:允许不定长度的键值对来作为参数传递给一个函数。
class className(angr.exploration_techniques.ExplorationTechnique):
def __init__(self):
super(className, self).__init__()
def step(self,simgr,stash='active',**kwargs):
return simgr.step(stash=stash)
这个例子简单介绍了如何写exploration_technique,但是没说如何使用你定义好的exploration_technique。贴心的作者又贴出了一个检测状态爆炸的代码,这段代码也介绍了如何使用自定义的exploration_technique。
先来看explosion_detector这个类。init方法内,还是一样,需要继承父类的init方法。这里省略了大部分的代码。因为和本次博客主题没啥关系。
class ExplosionDetector(ExplorationTechnique):
def __init__(self, stashes=('active', 'deferred', 'errored', 'cut'), threshold=100):
super(ExplosionDetector, self).__init__()
...
def step(self, simgr, stash='active', **kwargs):
simgr = simgr.step(stash=stash, **kwargs)
...
return simgr
然后是使用自定义的exploration_technique的代码,主要是14行和15行,使用simgr对象里的use_technique方法,参数为刚才写的exploration_technique的类。
from threading import Event, Timer
'''
project: an angr Project object
state: state that will be used to start dse
'''
def dse_it(project, state):
sm = project.factory.simgr(state)
dfs = angr.exploration_techniques.DFS()
sm.use_technique(dfs)
ed = ExplosionDetector(threshold=1000)
sm.use_technique(ed)
# Callback for timeout that sets the boolean inside the
# ExplosionDetector
def timeout():
l.warning("Timeout during DSE has been reached.")
ed.timed_out.set()
ed.timed_out_bool = True
# The actual timer
timer = Timer(300, timeout)
timer.start()
while len(sm.active) > 0 and not ed.timed_out_bool:
new_state = sm.active[0]
state_addr = new_state.solver.eval(new_state.regs.pc)
sm.step()
# Cancel the timer
timer.cancel()
# Check ExplosionDetector and do something if we timed out.
if ed.timed_out_bool:
l.fatal("DSE timed out")
总结一下,构造exploration_technique的模板为
class className(angr.exploration_techniques.ExplorationTechnique):
def __init__(self):
super(className, self).__init__()
def step(self,simgr,stash='active',**kwargs):
return simgr.step(stash=stash)
使用exploration_technique的代码为:
cn = className() # className为你定义的exploration_technique那个类的名字
simgr.use_technique(cn) # simgr为simulation_manager,相信看到这个博客的都知道是啥东西吧
参考资料:
- https://degrigis.github.io/posts/explosion_detector/