【angr源码分析】8. Angr的插件机制

Angr的插件机制

参考:Angr源码分析——SimState类

个人理解:以SimState为例理解Plugin。PluginHub类是一个插件管理器,里面管理若干插件(SimState的插件都是SimStatePlugin的子类实例化的对象)。当需要使用某个插件(比如解析器Solver,Solver是一个插件,memroy和regs都是)的时候,调用PluginHub提供的方法获得对应的插件来使用。为了方便,angr设置了一个新的类——PluginPreset。PluginPreset本身就包含很多插件,也是一个插件的集合。(如果说Hub是一个储藏室,preset就是储藏室里的柜子,plugin就是物品。物品可以放在柜子中,也可以直接放在储藏室里。plugin可以直接添加到Hub中,也可以添加到preset中,再将preset添加到Hub中。)angr设置了默认的preset,里面包含了我们会用到的插件。Hub将默认的preset添加进来,里面的插件可以直接使用。我们也可以编写自己的插件,添加到Hub中。

一个Hub中可以有多个添加的插件,也可以有多个preset。直接添加的插件已经是激活的,可以直接使用;而多个preset中,只能有一个处于激活状态。未激活的preset中的插件不能使用。

Hub的state包括 _active_plugin, _active_preset, provided_by_preset这三个变量。(意思可能是,保存一个Hub的状态,就是保存这三个变量,可以先保存,后面再恢复(调用getstate和setstate))

PluginHub类

Plugin Hub的官方说明:

A plugin hub is an object which contains many plugins, as well as the notion of a “preset”, or a backer that can provide default implementations of plugins which cater to a certain circumstance.

Plugin Hub是包括了很多插件的对象,也包含 “预设(preset)” 的概念,可以针对默认的情况,提供默认的插件实现。

Objects in angr like the SimState, the Analyses hub, the SimEngine selector, etc all use this model to unify their mechanisms for automatically collecting and selecting components to use. If you’re familiar with design patterns this is a configurable Strategy Pattern.

Angr中的对象,比如SimState,Analyses hub,SimEngine selector等,都使用了这个模型来统一自动收集和自动选择原件的机制,如果您熟悉设计模式,这是一个可配置的策略模式 。

Each PluginHub subclass should have a corresponding Plugin subclass, and perhaps a PluginPreset subclass if it wants its presets to be able to specify anything more interesting than a list of defaults.

每个PluginHub子类都应当有一个对应的Plugin子类,而且可能一个PluginPreset子类能指定更多东西。

PluginHub像是一个插槽,在SimState上加载了一个插槽,要扩展SimState的功能,只需要开发插件即可。

代码描述如下:

_init_(self):

设置了三个实例变量:

  1. _active_plugins:保存Hub中直接添加的插件
  2. _active_preset:保存当前状态下,被激活的preset
  3. provided_by_preset:(未知**)

还有一个变量:_presets,保存Hub中的所有preset

1
2
3
4
5
6
_presets = None
def __init__(self):
super(PluginHub, self).__init__()
self._active_plugins = {}
self._active_preset = None
self._provided_by_preset = []

def register_plugin(self, name, plugin):

将一个插件注册到Hub中。注册的插件会被默认激活(加入_active_plugins字典中)。如果已经存在该名字的插件,就覆盖。

1
2
3
4
5
6
def register_plugin(self, name, plugin):
if self.has_plugin(name):
self.release_plugin(name)
self._active_plugins[name] = plugin
setattr(self, name, plugin)
return plugin

def register_preset(cls, name, preset):

和register_plugin类似,将一个preset注册到Hub中(只是单纯地添加进来,没有直接激活。)

1
2
3
4
5
6
7
8
9
def register_preset(cls, name, preset):
"""
Register a preset instance with the class of the hub it corresponds to. This allows individual plugin objects to
automatically register themselves with a preset by using a classmethod of their own with only the name of the
preset to register with.
"""
if cls._presets is None:
cls._presets = {}
cls._presets[name] = preset

def get_plugin(self, name):

从已有的插件中,根据name寻找该插件。寻找插件时,会先从_active_plugins中寻找,再从preset中寻找。

1
2
3
4
5
6
7
8
9
10
11
12
13
def get_plugin(self, name): 

if name in self._active_plugins:
return self._active_plugins[name]
elif self.has_plugin_preset: #如果有这个插件
plugin_cls = self._active_preset.request_plugin(name)
plugin = self._init_plugin(plugin_cls)

# Remember that this plugin was provided by preset.
self._provided_by_preset.append(id(plugin))

self.register_plugin(name, plugin)
return plugin

def use_plugin_preset(self, preset):

将一个preset设置为激活状态

1
2
3
4
def use_plugin_preset(self, preset):
... ... 检查preset是否是一个正确的插件,确定当前没有已经激活的preset
preset.activate(self)
self._active_preset = preset

def register_default():

如果说register_plugin是把一个插件加入到active_plugins中,那么register_default就是把这个插件插入到一个preset中。给出插件名,插件,和preset名。

1
2
3
4
5
def register_default(cls, name, plugin_cls, preset='default'):
if cls._presets is None or preset not in cls._presets:
l.error("Preset %s does not exist yet...", preset)
return
cls._presets[preset].add_default_plugin(name, plugin_cls)

PluginPreset类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class PluginPreset(object):
"""
A plugin preset object contains a mapping from name to a plugin class. (plugin preset对象包括一个从名字到插件类的映射)
A preset can be active on a hub, which will cause it to handle requests for plugins which are not already present on the hub.
(一个preset可以在hub上活跃,这将导致它处理在集线器上不存在的插件的请求(??))

Unlike Plugins and PluginHubs, instances of PluginPresets are defined on the module level for individual presets.(和Plugin和PluginHub不同,在模块级别上为单个预置定义了PluginPresets实例)
You should register the preset instance with a hub to allow plugins to easily add themselves to the preset without an explicit reference to the preset itself.(你应该将 preset 实例注册到一个hub中,以便插件可以轻松地将自己添加到 preset 中,而无需显式地引用预置本身)
"""
#属性:
_default_plugins :默认的插件列表
#方法:
activate: 在激活这个preset时,进行一些操作
deactivate: 相反的操作
add_default_plugin: 在preset中增加一个插件
list_default_plugins(): 返回preset中可用的插件
request_plugin(self, name): 查找名为name的插件是否存在于preset中,如果没有就返回错误;否则返回插件类。
copy(self): 获得PluginPreset的一个拷贝

preset中包含多个插件。一般,这个preset由angr自己定义。

Angr一次性将可能需要的所有插件放入preset中,然后将这个preset放入Hub中激活。当需要使用该插件时,提供插件的名字即可。angr会自动地在preset中以及active_plugin中寻找这个插件。

sim_state.py中,下面两行代码在import 时就会执行:

1
2
default_state_plugin_preset = PluginPreset()
SimState.register_preset('default', default_state_plugin_preset)