Dyninst 小结

0x00

Dyninst 学习暂时告一段落,学习的成果是为师兄做了一个二进制层面的静态插桩,之后也做了一些性能测试的工作。

0x01

主要以代码形式讲解和记录:

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
int main(int argc, char **argv)
{
//首先通过参数打开一个二进制文件
BPatch_addressSpace *app = bpatch->openBinary(argv[1]);
if (app == NULL)
{
exit(1);
}
//mgr 为patchAPI的主要操作对象
mgr = convert(app);
appImage = app->getImage();
Patcher patcher(mgr);

//获取modules和定义一个function的vector
vector<BPatch_module *> *modules = appImage->getModules();
vector<BPatch_function *> *functions;

//遍历所有modules,取出每一个modules的所有function
for (auto it = modules->begin(); it != modules->end(); ++it)
{
BPatch_module * module = *it;
functions = module->getProcedures();
}

//对每个function进行插桩
for (auto it = functions->begin(); it != functions->end(); ++it)
{
PatchFunction *func = convert(*it);
writeCanaryPoint(func);
}

//提交插桩结果,使插桩生效
patcher.commit();
cout << pts.size() << " inst points" << endl;

//重写二进制文件
string name = string(argv[1]);
finishInstrumenting(app, name.c_str());
cout << "Instrumentation Success!" << endl;
return 0;
}

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
void writeCanaryPoint(PatchFunction *func)
{
//取出function的所有basicblock
const PatchFunction::Blockset &blks = func->blocks();
char bytes[1024];

for (auto it = blks.begin(); it != blks.end(); it++)
{
PatchBlock *block = *it;
PatchBlock::Insns insns;
block->getInsns(insns);

char date[] = "\x90\x64\x33\x00\x25\xa0\x02\x00\x00";
char date_inst[] = "\x64\x33\x00\x25\xa0\x02\x00\x00";
// 64 48 33 04 25 28 00 00 00 xor %fs:0x28,%rax
//遍历basicblock的每一条指令,判断是否为 xor %fs:0x28,%rax
for (auto j = insns.begin(); j != insns.end(); j++)
{
// get instruction bytes
Address addr = (*j).first;
Instruction::Ptr iptr = (*j).second;
size_t nbytes = iptr->size();
assert(nbytes < 1024);
for (size_t i=0; i<nbytes; i++) {
bytes[i] = iptr->rawByte(i);
}

date[3] = bytes[nbytes - 6]; //raw byte about which register
date_inst[2] = bytes[nbytes - 6];

if (isCheckCanary(bytes, nbytes))
{
//如果找到对应的指令,则将该指令的地址添加到insert point
mgr->findPoint(
Location::InstructionInstance(func, block, addr),
Point::PreInsn,
back_inserter(pts));

//分两种情况选择重写不同的二进制代码
if (nbytes == 9)
{
if (!overwritePoint(pts.back(), date, 9))
{
cout << "write error" << endl;
exit(1);
}
} else if (nbytes == 8) {
if (!overwritePoint(pts.back(), date_inst, 8))
{
cout << "write error" << endl;
exit(1);
}
}

//生成snippet,将snippet插入insert point
snippet = MySnippet::create(new MySnippet(bytes[nbytes - 6]));
InstancePtr instptr = pts.back()->pushBack(snippet);
if (instptr == NULL)
{
cerr << "insert snipper error" << endl;
exit(1);
}
}
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
void finishInstrumenting(BPatch_addressSpace *app, const char *newName)
{
//首先类型转换
BPatch_binaryEdit *appBin = dynamic_cast<BPatch_binaryEdit *>(app);

if (!appBin)
{
fprintf(stderr, "appBin not defined!\n");
return;
}

// Write binary to file
if (!appBin->writeFile(newName))
{
fprintf(stderr, "writeFile failed\n");
}
}
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
bool overwritePoint(Point *pt, char *date, size_t size) 
{
//overwrite xor %fs:0x28,%rax
// xor %fs:0x2a0,%eax

PatchBlock *block = pt->block();
ParseAPI::Block *b = block->block();
//insert point addr
Offset off = pt->addr();
// printf("overwritePoint : %2X\n", off);

ParseAPI::SymtabCodeRegion *r =
dynamic_cast<ParseAPI::SymtabCodeRegion*>(b->region());

if (r == NULL)
{
cout << "SymtabCodeRegion is null" << endl;
return false;
}

//计算insert point和basicblock入口点的偏移
Offset region_off = (Offset)r->getPtrToInstruction(off) -
(Offset)r->symRegion()->getPtrToRawData();
bool success = false;
//重写该二进制部分
//region_off 偏移,date 写入的数据,size 大小
success = r->symRegion()->patchData(region_off, (void *)date, size);
if (!success)
{
cout << "patchData is error" << endl;
return false;
}
return true;
}

源文件地址
safeCanary.cpp