DyninstAPI

  插桩是进行二进制代码分析时常用的方法之一。通过插桩,我们能够得知代码在运行时的一些状况,包括堆栈、寄存器等。了解了这些情况,不仅能够分析软件的输入输出是否存在漏洞,也能对程序代码执行的整个流程进行监控。

  Dyninst是从1994nian就已经开始开发的一个项目,目的是在运行时动态地向程序中插入代码。但关于它的中文文章实在太少,官9方网站倒是有些英文的,只是有时候访问不了( http://www.dyninst.org)。

  动态插桩省却了代码的重写、重新链接编译、重新执行的过程。如果在执行过程中代码出现了难以理解的性能问题,通过插桩也可以帮助程序员更轻松地找到问题出现的原因。如果是大型的科学计算工程,往往进行以上的动作需要付出很大的代价。

  要达到任意代码的插桩需要解决三个问题:

  1) 在运行时插入指令代码

  2) 把代码插入静态二进制文件中并且把新的代码重新写入到磁盘文件

  3) 在二进制文件和进程中做静态和动态的分析

  在Dyninst中,进程在内存中被抽象成为一个address space。代码和数据被抽象成一个个函数和变量。函数中包含了可以插入指令的点,也包含了控制流图(CFG, Control Flow graph)的抽象。CFG中包含基本块 (Basic Block)、边、循环和指令。用户修改过的指令形成一个变体,如果在变体中包含了debug信息,DyninstAPI也能够提供关于变量、函数类型、局部变量、参数和源代码行是信息。函数和变量的集合在Dyninst的变体冲被当做映射 image。

  bpatch是BPatch中的一个静态指针,所有的BPatch只能使用这样一个指针。

#include <iostream>
#include "BPatch.h"
#include "BPatch_process.h"
#include "BPatch_addressSpace.h"
#include "BPatch_binaryEdit.h"
#include "BPatch_function.h"
#include "BPatch_point.h"
#include "BPatch_image.h"
#include <vector>
using namespace std;

Dyninst的库还是比较容易懂的,只不过二进制代码的抽象理解起来可能没有那么容易。下面示例在dyninst中创建一个进程并获取相关信息:

int main(int argc, const char** argv)
{
    const char path[] = "";    //此处是二进制文件的路径
    BPatch bpatch;
    BPatch_process *process = bpatch.processCreate(path,argv);
    cout<<process->getPid()<<endl;
    BPatch_addressSpace *app = process;
    vector<BPatch_function *> funcs;
    BPatch_image *image = app->getImage();
    image->findFunction("main",funcs);
    vector<BPatch_function*>::iterator it;
    for (it=funcs.begin();it!=funcs.end();it++)
    {
        cout<<*it<<endl;
    }
    return 0;
}

以上的例子完成了两个功能,1是获取了打开进程的pid,2是寻找到进程加载到内存中后main的地址。

在下一篇文章中将继续深入学习dyninstAPI的用法。




你可能感兴趣的:(二进制,Dyninst;,插桩;,动态修改;)