首页 > 其他分享 >Angr Execution Pipeline

Angr Execution Pipeline

时间:2024-02-27 13:34:03浏览次数:25  
标签:function Pipeline Angr step will state angr unicorn Execution

Reference

Understanding the Execution Pipeline

If you’ve made it this far you know that at its core, angr is a highly flexible and intensely instrumentable emulator. In order to get the most mileage out of it, you’ll want to know what happens at every step of the way when you say simgr.run().

This is intended to be a more advanced document; you’ll need to understand the function and intent of SimulationManager, ExplorationTechnique, SimState, and SimEngine in order to understand what we’re talking about at times! You may want to have the angr source open to follow along with this.

At every step along the way, each function will take **kwargs and pass them along to the next function in the hierarchy, so you can pass parameters to any point in the hierarchy and they will trickle down to everything below.

Simulation Managers

So you’ve set your analysis in motion. Time to begin our journey.

run()

SimulationManager.run() takes several optional parameters, all of which control when to break out of the stepping loop. Notably, n, and until. n is used immediately - the run function loops, calling the step() function and passing on all its parameters until either n steps have happened or some other termination condition has occurred. If n is not provided, it defaults to 1, unless an until function is provided, in which case there will be no numerical cap on the loop. Additionally, the stash that is being used is taken into consideration, as if it becomes empty execution must terminate.

So, in summary, when you call run(), step() will be called in a loop until any of the following:

  1. The n number of steps have elapsed
  2. The until function returns true
  3. The exploration techniques complete() hooks (combined via the SimulationManager.completion_mode parameter/attribute - it is by default the any builtin function but can be changed to all for example) indicate that the analysis is complete
  4. The stash being executed becomes empty

An aside: explore()

SimulationManager.explore() is a very thin wrapper around run() which adds the Explorer exploration technique, since performing one-off explorations is a very common action. Its code in its entirety is below:

num_find += len(self._stashes[find_stash]) if find_stash in self._stashes else 0
tech = self.use_technique(Explorer(find, avoid, find_stash, avoid_stash, cfg, num_find))

try:
    self.run(stash=stash, n=n, **kwargs)
finally:
    self.remove_technique(tech)

return self

Exploration technique hooking

From here down, every function in the simulation manager can be instrumented by an exploration technique. The exact mechanism through which this works is that when you call SimulationManager.use_technique(), angr monkeypatches the simulation manager to replace any function implemented in the exploration technique’s body with a function which will first call the exploration technique’s function, and then on the second call will call the original function. This is somewhat messy to implement and certainly not thread safe by any means, but does produce a clean and powerful interface for exploration techniques to instrument stepping behavior, either before or after the original function is called, even choosing whether or not to call the original function whatsoever. Additionally, it allows multiple exploration techniques to hook the same function, as the monkeypatched function simply becomes the “original” function for the next-applied hook.

step()

There is a lot of complicated logic in step() to handle degenerate cases - mostly implementing the population of the deadended stash, the save_unsat option, and calling the filter() exploration technique hooks. Beyond this, though, most of the logic is looping through the stash specified by the stash argument and calling step_state() on each state, then applying the dict result of step_state() to the stash list. Finally, if the step_func parameter is provided, it is called with the simulation manager as a parameter before the step ends.

step_state()

The default step_state(), which can be overridden or instrumented by exploration techniques, is also simple - it calls successors(), which returns a SimSuccessors object, and then translates it into a dict mapping stash names to new states which should be added to that stash. It also implements error handling - if successors() throws an error, it will be caught and an ErrorRecord will be inserted into SimulationManager.errored.

successors()

We’ve almost made it out of SimulationManager. successors(), which can also be instrumented by exploration techniques, is supposed to take a state and step it forward, returning a SimSuccessors object categorizing its successors independently of any stash logic. If the successor_func parameter was provided, it is used and its return value is returned directly. If this parameter was not provided, we use the project.factory.successors method to tick the state forward and get our SimSuccessors.

The Engine

When we get to the actual successors generation, we need to figure out how to actually perform the execution. Hopefully, the angr documentation has been organized in a way such that by the time you reach this page, you know that a SimEngine is a device that knows how to take a state and produce its successors. There is only one “default engine” per project, but you can provide the engine parameter to specify which engine will be used to perform the step.

Keep in mind that this parameter can be provided way at the top, to .step(), .explore(), .run() or anything else that starts execution, and they will be filtered down to this level. Any additional parameters will continue being passed down, until they reach the part of the engine they are intended for. The engine will discard any parameters it doesn’t understand.

Generally, the main entry point of an engine is SimEngine.process(), which can return whatever result it likes, but for simulation managers, engines are required to use SuccessorsMixin, which provides a process() method, which creates a SimSuccessors object and then calls process_successors() so that other mixins can fill it out.

angr’s default engine, the UberEngine, contains several mixins which provide the process_successors() method:

  • SimEngineFailure - handles stepping states with degenerate jumpkinds
  • SimEngineSyscall - handles stepping states which have performed a syscall and need it executed
  • HooksMixin - handles stepping states which have reached a hooked address and need the hook executed
  • SimEngineUnicorn - executes machine code via the unicorn engine
  • SootMixin - executes java bytecode via the SOOT IR
  • HeavyVEXMixin - executes machine code via the VEX IR

Each of these mixins is implemented to fill out the SimSuccessors object if they can handle the current state, otherwise they call super() to pass the job on to the next class in the stack.

Engine mixins

SimEngineFailure handles error cases. It is only used when the previous jumpkind is one of Ijk_EmFail, Ijk_MapFail, Ijk_Sig*, Ijk_NoDecode (but only if the address is not hooked), or Ijk_Exit. In the first four cases, its action is to raise an exception. In the last case, its action is to simply produce no successors.

SimEngineSyscall services syscalls. It is used when the previous jumpkind is anything of the form Ijk_Sys*. It works by making a call into SimOS to retrieve the SimProcedure that should be run to respond to this syscall, and then running it! Pretty simple.

HooksMixin provides the hooking functionality in angr. It is used when a state is at an address that is hooked, and the previous jumpkind is not Ijk_NoHook. It simply looks up the associated SimProcedure and runs it on the state! It also takes the parameter procedure, which will cause the given procedure to be run for the current step even if the address is not hooked.

SimEngineUnicorn performs concrete execution with the Unicorn Engine. It is used when the state option o.UNICORN is enabled, and a myriad of other conditions designed for maximum efficiency (described below) are met.

SootMixin performs execution over the SOOT IR. Not very important unless you are analyzing java bytecode, in which case it is very important.

SimEngineVEX is the big fellow. It is used whenever any of the previous can’t be used. It attempts to lift bytes from the current address into an IRSB, and then executes that IRSB symbolically. There are a huge number of parameters that can control this process, so it is best to reference the API doc for angr.engines.vex.engine.SimEngineVEX.process() describing them.

The exact process by which SimEngineVEX digs into an IRSB is a little complicated, but essentially it runs all the block’s statements in order. This code is worth reading if you want to see the true inner core of angr’s symbolic execution.

When using Unicorn Engine

If you add the o.UNICORN state option, at every step SimEngineUnicorn will be invoked, and try to see if it is allowed to use Unicorn to execute concretely.

What you REALLY want to do is to add the predefined set o.unicorn (lowercase) of options to your state:

unicorn = { UNICORN, UNICORN_SYM_REGS_SUPPORT, INITIALIZE_ZERO_REGISTERS, UNICORN_HANDLE_TRANSMIT_SYSCALL }

These will enable some additional functionalities and defaults which will greatly enhance your experience. Additionally, there are a lot of options you can tune on the state.unicorn plugin.

A good way to understand how unicorn works is by examining the logging output logging.getLogger('angr.engines.unicorn_engine').setLevel('DEBUG'); logging.getLogger('angr.state_plugins.unicorn_engine').setLevel('DEBUG') from a sample run of unicorn.

INFO    | 2017-02-25 08:19:48,012 | angr.state_plugins.unicorn | started emulation at 0x4012f9 (1000000 steps)

Here, angr diverts to unicorn engine, beginning with the basic block at 0x4012f9. The maximum step count is set to 1000000, so if execution stays in Unicorn for 1000000 blocks, it’ll automatically pop out. This is to avoid hanging in an infinite loop. The block count is configurable via the state.unicorn.max_steps variable.

INFO    | 2017-02-25 08:19:48,014 | angr.state_plugins.unicorn | mmap [0x401000, 0x401fff], 5 (symbolic)
INFO    | 2017-02-25 08:19:48,016 | angr.state_plugins.unicorn | mmap [0x7fffffffffe0000, 0x7fffffffffeffff], 3 (symbolic)
INFO    | 2017-02-25 08:19:48,019 | angr.state_plugins.unicorn | mmap [0x6010000, 0x601ffff], 3
INFO    | 2017-02-25 08:19:48,022 | angr.state_plugins.unicorn | mmap [0x602000, 0x602fff], 3 (symbolic)
INFO    | 2017-02-25 08:19:48,023 | angr.state_plugins.unicorn | mmap [0x400000, 0x400fff], 5
INFO    | 2017-02-25 08:19:48,025 | angr.state_plugins.unicorn | mmap [0x7000000, 0x7000fff], 5

angr performs lazy mapping of data that is accessed by unicorn engine, as it is accessed. 0x401000 is the page of instructions that it is executing, 0x7fffffffffe0000 is the stack, and so on. Some of these pages are symbolic, meaning that they contain at least some data that, when accessed, will cause execution to abort out of Unicorn.

INFO    | 2017-02-25 08:19:48,037 | angr.state_plugins.unicorn | finished emulation at 0x7000080 after 3 steps: STOP_STOPPOINT

Execution stays in Unicorn for 3 basic blocks (a computational waste, considering the required setup), after which it reaches a simprocedure location and jumps out to execute the simproc in angr.

INFO    | 2017-02-25 08:19:48,076 | angr.state_plugins.unicorn | started emulation at 0x40175d (1000000 steps)
INFO    | 2017-02-25 08:19:48,077 | angr.state_plugins.unicorn | mmap [0x401000, 0x401fff], 5 (symbolic)
INFO    | 2017-02-25 08:19:48,079 | angr.state_plugins.unicorn | mmap [0x7fffffffffe0000, 0x7fffffffffeffff], 3 (symbolic)
INFO    | 2017-02-25 08:19:48,081 | angr.state_plugins.unicorn | mmap [0x6010000, 0x601ffff], 3

After the simprocedure, execution jumps back into Unicorn.

WARNING | 2017-02-25 08:19:48,082 | angr.state_plugins.unicorn | fetching empty page [0x0, 0xfff]
INFO    | 2017-02-25 08:19:48,103 | angr.state_plugins.unicorn | finished emulation at 0x401777 after 1 steps: STOP_EXECNONE

Execution bounces out of Unicorn almost right away because the binary accessed the zero-page.

INFO    | 2017-02-25 08:19:48,120 | angr.engines.unicorn_engine | not enough runs since last unicorn (100)
INFO    | 2017-02-25 08:19:48,125 | angr.engines.unicorn_engine | not enough runs since last unicorn (99)

To avoid thrashing in and out of Unicorn (which is expensive), we have cooldowns (attributes of the state.unicorn plugin) that wait for certain conditions to hold (i.e., no symbolic memory accesses for X blocks) before jumping back into unicorn when a unicorn run is aborted due to anything but a simprocedure or syscall. Here, the condition it’s waiting for is for 100 blocks to be executed before jumping back in.

标签:function,Pipeline,Angr,step,will,state,angr,unicorn,Execution
From: https://www.cnblogs.com/holylandofdora/p/18031941

相关文章

  • 实例详解在Go中构建流数据pipeline
    本文分享自华为云社区《Go并发范式流水线和优雅退出Pipeline与Cancellation》,作者:张俭。介绍Go的并发原语可以轻松构建流数据管道,从而高效利用I/O和多个CPU。本文展示了此类pipelines的示例,强调了操作失败时出现的细微之处,并介绍了干净地处理失败的技术。什么是pipeli......
  • CMU 15-445(Fall 2023) Project3 Query Execution个人笔记
    Task#1-AccessMethodExecutorsSeqScan算子实现逻辑使用exec_ctx属性获取对应的TableInfo调用MakeIterator方法,获取表的迭代器在Next方法中,每次利用迭代器获得一个满足条件的元组(检查元组是否被删除、元组是否满足filter)Insert算子实现逻辑在Next方法中调用child......
  • A trip through the Graphics Pipeline 2011: Index
    原文地址https://fgiesen.wordpress.com/2011/07/09/a-trip-through-the-graphics-pipeline-2011-index/Welcome.ThisistheindexpageforaseriesofblogpostsI’mcurrentlywritingabouttheD3D/OpenGLgraphicspipelinesasactuallyimplementedbyGPUs.Alot......
  • tensorflow distributed training in tfx pipeline run by kubeflow
    1.deployworker,parameterserveronkubernetescluster1.1buildcontainerimageofworker,parameterserver$gitclonehttps://github.com/tensorflow/ecosystem.git$cdecosystem/distribution_strategy$sudonerdctlbuild--no-cache-ttf_std_server:......
  • Debug : kfp.Client().upload_pipeline(): Failed to start a transaction to create
    [ERROR:Failedtostartatransactiontocreateanewpipelineandanewpipelineversion:dialtcp:lookupmysqlon10.96.0.10:53:nosuchhost","]>>>kfp.Client().upload_pipeline("/home/maye/pipeline_wafer_distribute.yaml",......
  • 全基因组测序流程 | WGS pipeline
     创建conda环境,安装必要软件condacreate-nwgscondaactivatewgscondainstallbioconda::bwa 下载最佳reffastagcloudstoragecpgs://BUCKET_NAME/OBJECT_NAMESAVE_TO_LOCATIONgs://gcp-public-data--broad-references/hg38/v0/Homo_sapiens_assembly38.fastaR......
  • PTES(Penetration Testing Execution Standard ,渗透测试执行标准)
    PTES是一种渗透测试标准,旨在提供一种通用语言描述的渗透测试执行范围和标准,始于2009年初,由一些创始成员围绕渗透测试行业讨论所得,参与者可以查看此列表。 其内容由7个主要部分组成,但该标准实际上并没有提供关于执行实际渗透测试的技术要求,但有一份相关的实践技术指南:http://ww......
  • 执行 set-ExecutionPolicy RemoteSigned 失败解决方法
    1、Window+r,输入powershell 2、输入命令行set-ExecutionPolicyRemoteSigned3、再输入命令行Set-ExecutionPolicy-ScopeCurrentUser4、验证一下是否成功了:输入get-ExecutionPolicy,系统回复Restricted,表示状态是禁止的;若是提示了RemoteSigned就代表成功。5、如......
  • 如何给极狐GitLab 配置 webhook,自动触发 Pipeline?
    本文根据工作中的痛点来举例介绍如何使用极狐GitLab,让你的日常工作更高效。还在只使用极狐GitLab存放代码?那你就OUT啦。赶紧看看这篇文章,让你的日常工作更高效。使用GitlabWebhook触发Pipeline,打通工作消息通知关于A/B同学的问题,我想可以使用Webhook触发Pipe......
  • Run a tfx pipeline using kubeflow pipeline
    1.whatiskubeflowpipelinefortfxpipeline?kubeflowpipelineisanochetratoroftfxpipeline,whichrunsonakubernetescluster.LocalDagRunerisanorchetratoroftfxpipeline,whichrunslocal.#runatfxpipelineusgingLocalGagRunnertfx.orc......