前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >使用 BPF 改变运行中的程序的函数参数

使用 BPF 改变运行中的程序的函数参数

原创
作者头像
ritchiechen
发布2021-02-23 09:20:11
4.2K0
发布2021-02-23 09:20:11
举报
文章被收录于专栏:Serverless+

本文探索使用 BPF 改变运行中的程序的函数参数,挖掘 BPF 的黑魔法。

实验环境

  • Ubuntu 20.04.2 LTS
  • BCC

测试程序

这是我们的示例程序,打印第一个命令行参数:

代码语言:txt
复制
package main

import (
	"fmt"
	"os"
	"time"
)

//go:noinline
func greet(s string) {
	fmt.Println(s)
}

func main() {
	for {
		greet(os.Args[1])
		time.Sleep(time.Second)
	}
}

注意到我们使用 //go:noinline 修饰了 main.greet 函数,防止被编译器内联,方便进行测试验证。

这是我们的 BPF 程序,尝试修改函数参数为字符串 You are hacked!:

代码语言:txt
复制
#include <uapi/linux/ptrace.h>

int hack(struct pt_regs *ctx) {
    char text[] = "You are hacked!";
    // read string address
    u64 addr = 0;
    u64* sp = (u64*)ctx->sp;
    bpf_probe_read(&addr, sizeof(addr), sp + 1);
    // overwrite string content
    bpf_probe_write_user((u64*)addr, text, sizeof(text));
    return 0;
}

使用 bpf_probe_write_user 修改用户内存空间的内容,此操作存在风险,因此每当带有此函数的 BPF 程序被加载时,从 dmesg 中都可以看到如下日志:

代码语言:txt
复制
tracer[609901] is installing a program with bpf_probe_write_user helper that may corrupt user memory!

实验结果

在第一个终端先启动示例程序,每隔一秒打印字符串 hello world!:

代码语言:txt
复制
$ ./tracee 'hello world!'
hello world!
hello world!
...

在第二个终端再启动 BPF 程序:

代码语言:txt
复制
$ sudo ./tracer /path/to/tracee 'main.greet'

此时再看看示例程序的输出:

代码语言:txt
复制
$ ./tracee 'hello world!'
hello world!
hello world!
...
You are hack
You are hack
You are hack
...

修改成功!

结论

本文探索使用 BPF 修改执行中的 Go 程序的函数参数, 由于 Golang 的 ABI 是使用栈来传递函数参数,通过读取栈上的指针地址,使用 bpf_probe_write_user 修改对应地址的内存内容来达成修改函数参数的目的。你可以在这里找到本文的全部代码。

参考

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 实验环境
  • 测试程序
  • 实验结果
  • 结论
  • 参考
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档