(本文记录了自己学习Dyninst的一点简单的学习笔记,希望能对您有所帮助,也欢迎留言讨论。本文会随着我的学习过程不断更新。)
1. 介绍
Instrumentation是一种直接修改程序二进制文件的方法。其可以用于程序的调试,优化,分析[5],安全[4]等等。对这个词一般的翻译是“插桩”,但这更多适用于软件测试领域。Instrumentation一般可以分为两类,动态和静态。动态修改是在目标进程运行时插入代码(dynamic binary instrumentation)。常见的工具有Pin, Valgrind, DynamoRio。静态修改则是直接向二进制文件插入代码(static binary instrumentation or binary rewriting)。静态instrumentation的工具少一些,我知道的有PEBIL(似乎不是很成熟)。此外,或许可以用BAP,LLVM等工具先将二进制代码反编译成一种中间表示,然后对中间表示进行修改,最后再编译回二进制,或许也是一种可能的静态instrumentation途径。
Dyninst是一种可以动态或静态的修改程序的二进制代码的工具。由于其易用性,使得许多研究工作都使用Dyninst(见http://www.dyninst.org/related/view_papers)。Dyninst的开发大概可以追溯到1994年,而且现在依然active。
3. Dyninst实现原理
Dynamic Instrumentation的工具有不少。比较著名的有Intel的Pin和Valgrind。这两个工具都是使用JIT来实现Instrumentation。下图是Pin的架构[3]:
与之相对,Dyninst则使用Code Patching。这也使得Dyninst可以用同一个接口支持静态和动态的instrumentation。【Dyninst和Pin各自优缺点是什么?】
Dyninst实现的大致原理如下。首先,对于一个二进制image,找到用户指定的插入点。然后把插入点的一条或几条指令替换成一个跳转指令。这个跳转指令指向一个Base Trampoline(Trampoline的翻译是蹦床),这个Base Trampoline包含有被替换的指令以及跳转到Mini Trampoline的指令。Mini Tranpoline会保存/恢复当前的状态,并且执行相应的插入代码(Snippet)。原理图[2]如下:
为什么需要两层Trampoline?我觉得可能是为了重用Mini-Trampoline。比如上图中,同一个Mini-Trampoline可以被用于Pre和Post。
最早解释Dyninst实现原理的文章[1]发表于1994年。这篇发表于2000年的文章[2]的介绍可能更清晰。感兴趣的读者可以一阅。
4. Dyninst API
Dyninst提供了大量的API,可以从其主页上的手册下载。
5. 相关工作
此外,Dyninst还衍生出许多其他的工具,可以更加方便的进行instrumentation。这些工具的API同样可以在Dyninst主页上下载。下面是一个简单且不完全的介绍:
DynC:方便插入代码的构造。
6. 引用
[1] Dynamic program instrumentation for scalable performance tools[2] An API for Runtime Code Patching
[3] http://download-software.intel.com/sites/default/files/article/256675/pldi2007-pintutorial.pdf
[4] Detecting Code Reuse Attacks with a Model of Conformant Program Execution
[5] Extracting Compiler Provenance from Program Binaries