Factory SimManger State

Last updated on May 29, 2023 am

facntory SimManger State

一般使用angr时,都会以以下几句开头

1
2
3
4
import angr
proj = angr.Project('examples/fauxware/fauxware', auto_load_libs=False)
state = proj.factory.entry_state()
simgr = proj.factory.simgr(state)

现在就来看看factory都究竟是个啥

首先factory是一个类,但是它更像是一个工具类,帮助我们完成一些事情,我们就可以简单调用里面的方法。比如我们想要初始化一个入口函数的state,那么我们就可以调用factory里面的entry_state(),就不用自己再去关心那细节。

现在就来看看里面还有哪些方法

State

blank_state(self, **kwargs)

调用此方法,会返回一个几乎没有初始化的state对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def blank_state(self,**kwargs)
"""
Returns a mostly-uninitialized state object. All parameters are optional.

:param addr: State 开始的地址
:param initial_prefix: 如果提供,所有的符号寄存器都会有一个以此为前缀字符串的符号值
:param fs: A dictionary of file names with associated preset SimFile objects.
:param concrete_fs: bool describing whether the host filesystem should be consulted when opening files.
:param chroot: A path to use as a fake root directory, Behaves similarly to a real chroot. Used only when concrete_fs is set to True.
:param kwargs: Any additional keyword args will be passed to the SimState constructor.
:return: 返回一个空 state
:rtype: 返回类型 SimState
"""
return self.project.simos.state_blank

entry_state(self, **kwargs)

调用此方法,返回一个起始地址的state

full_init_state(self, **kwargs)

Very much like :meth:entry_state(), except that instead of starting execution at the program entry point, execution begins at a special SimProcedure that plays the role of the dynamic loader, calling each of the initializer functions that should be called before execution reaches the entry point. It can take any of the arguments that can be provided to entry_state, except for addr.

意思是,这个方法拥有以上的所有参数除了addr,因为这个方法是先于符号执行的,它的作用是初始化,调用哪些所有的初始化函数

call_state(self, addr, *args, **kwargs)

很显然是一个创建call到某个函数的state,它的参数

Returns a state object initialized to the start of a given function, as if it were called with given parameters.

:param addr: The address the state should start at instead of the entry point.

:param args: Any additional positional arguments will be used as arguments to the function call.

返回一个以给定函数起初地址的state,换句话说提供addr,它将以此创建一个state,而不再是entry point。它也可以通过args来传递所call的函数参数

Simulation Manager

simgr simulation_manager( self, thing: Optional[Union[List[SimState], SimState]] = None,**kwargs)

Constructs a new simulation manager.

:param thing: What to put in the new SimulationManager’s active stash (either a SimState or a list of SimStates).

:param kwargs: Any additional keyword arguments will be passed to the SimulationManager constructor

:returns: The new SimulationManager

:rtype: angr.sim_manager.SimulationManager

这个方法也很常用,但是它不再是创建和返回state对象,而是利用state对象创建一个simulation manager对象并返回。它的参数就是接受一个state列表或者单独一个state,并把他们放进stash的active里面。如果什么参数也不传,那么它就默认以entry_point为state创建。

那么这个simulation manager对象是个啥呢?

SimulationManager

angr在[文档](angr.sim_manager - angr documentation)里面这样评论The Simulation Manager is the future future.

SimulationManager 也是angr里面的一个类。这个类的功能就是帮助我们根据state的stash来管理state,可以往下step,可以过滤filter,也可以融合merge。可以通过属性值来直接获取stash,比如.active,也可以用一些前缀比如mp_,那么就可以mp_active,同理one_.

这是它的一些成员

:param project: A Project instance.

:type project: angr.project.Project

:param stashes: 一个字典用于存储stash

:param active_states: Active states to seed the “active” stash with.

:param hierarchy: 一个StateHierarchy对象,用于追踪state之间关系

:param resilience: 收集error的集合

:param save_unsat: 如果为True,则保留unsat的state,而不是直接丢掉

:param auto_drop: 存放直接丢弃的stash的名字

:param completion_mode: 描述exploretion techniques的函数

:param techniques: 需要预先设定exploretion tech的列表

……

当然里面也有很多的方法,最重要的是step ,explore,use_technique三个方法

看看它的构造函数,通过初始化函数就能这些成员有一个更直观的了解

__init__

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
def __init__(
self,
project,
active_states=None,
stashes=None,
hierarchy=None,
resilience=None,
save_unsat=False,
auto_drop=None,
errored=None,
completion_mode=any,
techniques=None,
suggestions=True,
**kwargs,
):
super().__init__()

self._project = project
self.completion_mode = completion_mode
self._errored = []
self._lock = PicklableLock()
# 这里就可以放入自己的stash
if stashes is None:
stashes = self._create_integral_stashes()
self._stashes: DefaultDict[str, List["SimState"]] = stashes
self._hierarchy = StateHierarchy() if hierarchy is None else hierarchy
self._save_unsat = save_unsat
self._auto_drop = {
SimulationManager.DROP,
}
self._techniques = []

if resilience is None:
self._resilience = (AngrError, SimError, claripy.ClaripyError)
elif resilience is True:
self._resilience = (
AngrError,
SimError,
claripy.ClaripyError,
KeyError,
IndexError,
TypeError,
ValueError,
ArithmeticError,
MemoryError,
)
elif resilience is False:
self._resilience = ()
else:
self._resilience = tuple(resilience)

if suggestions:
self.use_technique(Suggestions())

# 8<----------------- Compatibility layer -----------------

if auto_drop is None and not kwargs.pop("save_unconstrained", True):
self._auto_drop |= {"unconstrained"}

if kwargs.pop("veritesting", False):
self.use_technique(Veritesting(**kwargs.get("veritesting_options", {})))
kwargs.pop("veritesting_options", {})

threads = kwargs.pop("threads", None)
if threads is not None:
self.use_technique(Threading(threads))

if kwargs:
raise TypeError("Unexpected keyword arguments: " + " ".join(kwargs))
# ------------------ Compatibility layer ---------------->8

if auto_drop:
self._auto_drop |= set(auto_drop)

if errored is not None:
self._errored.extend(errored)

if active_states:
self._store_states("active", active_states)

if techniques:
for t in techniques:
self.use_technique(t)

step

看看它的参数即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def step(
self,
stash="active",
target_stash=None,
n=None,
selector_func=None,
step_func=None,
error_list=None,
successor_func=None,
until=None,
filter_func=None,
**run_args,
):

stash : 需要step的stash名字,默认是active

target_stash : 将结果放入哪个stash

n : 如果until是NULL的话,那么会一直执行n步

selector_fun : 接收一个以state为参数、返回类型为布尔的函数,如果返回为True,那么执行该 state,否则保持原样

step_fun : 接收一个以SimulationManager为参数并返回SimulantionManager的函数,每一次调用step()时,都会调用该函数,但该函数里面不应该有step()

error_list : 一个list来存储ErroredState

successor_fun : 接收一个以state为参数并返回它后继的函数

until: 接收一个以SimulationManger为参数并返回布尔值的函数,一直执行到返回为True

filter_func : 接收一个以state为参数并返回该state要移去哪个stash名字的函数

现在的angr中nuntil已经移植到run()中,用法相同

use_technique

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
"""
Use an exploration technique with this SimulationManager.

Techniques can be found in :mod:`angr.exploration_techniques`.

:param tech: 一个ExplorationTechnique对象,用以控制该SimluationManger行为
:type tech: ExplorationTechnique (note:ExplorationTechnique也是angr的一个比较重要的类)
:return: The technique that was added, for convenience
"""
if not isinstance(tech, ExplorationTechnique):
raise SimulationManagerError

# XXX: as promised
tech.project = self._project
tech.setup(self)

HookSet.install_hooks(self, **tech._get_hooks())
self._techniques.append(tech)
return tech

总结

State是一个模拟状态,里面包含很多值,各种寄存器,内存以及几乎所有可以变得值,它是大多数函数的参数。

我们想要得到一个state,可以调用factory里的关于state的方法。还可以使用得到的state的对象以及factory.simgr方法得到一个SimManger对象。factory相当于一个工具箱,封装angr内部许多常用方法,方便我们调用,就不需要自己手动操作了。

当我们拥有一个state的时候,就可以把它丢给SimManger了,我们可以到一个SimManger的对象,这一步相当于把这个state拉伸进内存,得到更多有效信息,就可以开始正式执行了,而且我们还可以设定各种执行方式,是只走一步还是一直走到尽头?中间状态要怎么处理?以什么方式走?等等


Factory SimManger State
http://example.com/2023/05/24/Factory SimManger State/
Author
yring
Posted on
May 24, 2023
Licensed under