亚欧色一区w666天堂,色情一区二区三区免费看,少妇特黄A片一区二区三区,亚洲人成网站999久久久综合,国产av熟女一区二区三区

  • 發布文章
  • 消息中心
點贊
收藏
評論
分享
原創

ebpf調研(6)

2023-04-26 03:11:06
15
0

在 eBPF 中使用 uprobe 捕獲 bash 的 readline 函數調用


eBPF (Extended Berkeley Packet Filter) 是 Linux 內核上的一個強大的網絡和性能分析工具,它允許開發者在內核運行時動態加載、更新和運行用戶定義的代碼。

本文主要介紹如何使用 uprobe 捕獲 bash 的 readline 函數調用。

什么是uprobe

uprobe是一種用戶空間探針,uprobe探針允許在用戶空間程序中動態插樁,插樁位置包括:函數入口、特定偏移處,以及函數返回處。當我們定義uprobe時,內核會在附加的指令上創建快速斷點指令(x86機器上為int3指令),當程序執行到該指令時,內核將觸發事件,程序陷入到內核態,并以回調函數的方式調用探針函數,執行完探針函數再返回到用戶態繼續執行后序的指令。

uprobe基于文件,當一個二進制文件中的一個函數被跟蹤時,所有使用到這個文件的進程都會被插樁,包括那些尚未啟動的進程,這樣就可以在全系統范圍內跟蹤系統調用。

uprobe適用于在用戶態去解析一些內核態探針無法解析的流量,例如http2流量(報文header被編碼,內核無法解碼),https流量(加密流量,內核無法解密)。

使用 uprobe 捕獲 bash 的 readline 函數調用

uprobe 是一種用于捕獲用戶空間函數調用的 eBPF 的探針,我們可以通過它來捕獲用戶空間程序調用的系統函數。

例如,我們可以使用 uprobe 來捕獲 bash 的 readline 函數調用,從而獲取用戶在 bash 中輸入的命令行。示例代碼如下:

#cat read.bpf.c

#include <vmlinux.h>
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h>

#define TASK_COMM_LEN 16
#define MAX_LINE_SIZE 80

SEC("uretprobe//bin/bash:readline")
int BPF_KRETPROBE(printret, const void *ret)
{
 char str[MAX_LINE_SIZE];
 char comm[TASK_COMM_LEN];
 u32 pid;

 if (!ret)
  return 0;

 bpf_get_current_comm(&comm, sizeof(comm));

 pid = bpf_get_current_pid_tgid() >> 32;
 bpf_probe_read_user_str(str, sizeof(str), ret);

 bpf_printk("PID %d (%s) read: %s ", pid, comm, str);

 return 0;
};

char LICENSE[] SEC("license") = "GPL";

這段代碼的作用是在 bash 的 readline 函數返回時執行指定的 BPF_KRETPROBE 函數,即 printret 函數。

在 printret 函數中,我們首先獲取了調用 readline 函數的進程的進程名稱和進程 ID,然后通過 bpf_probe_read_user_str 函數讀取了用戶輸入的命令行字符串,最后通過 bpf_printk 函數打印出進程 ID、進程名稱和輸入的命令行字符串。

除此之外,我們還需要通過 SEC 宏來定義 uprobe 探針,并使用 BPF_KRETPROBE 宏來定義探針函數。

在 SEC 宏中,我們需要指定 uprobe 的類型、要捕獲的二進制文件的路徑和要捕獲的函數名稱。例如,上面的代碼中的 SEC 宏的定義如下:

SEC("uprobe//bin/bash:readline")

這表示我們要捕獲的是 /bin/bash 二進制文件中的 readline 函數。

接下來,我們需要使用 BPF_KRETPROBE 宏來定義探針函數,例如:

BPF_KRETPROBE(printret, const void *ret)

這里的 printret 是探針函數的名稱,const void *ret 是探針函數的參數,它代表被捕獲的函數的返回值。

然后,我們使用了 bpf_get_current_comm 函數獲取當前任務的名稱,并將其存儲在 comm 數組中。

 bpf_get_current_comm(&comm, sizeof(comm));

使用 bpf_get_current_pid_tgid 函數獲取當前進程的 PID,并將其存儲在 pid 變量中。

 pid = bpf_get_current_pid_tgid() >> 32;

使用 bpf_probe_read_user_str 函數從用戶空間讀取 readline 函數的返回值,并將其存儲在 str 數組中。

 bpf_probe_read_user_str(str, sizeof(str), ret);

最后使用 bpf_printk 函數輸出 PID、任務名稱和用戶輸入的字符串。

 bpf_printk("PID %d (%s) read: %s ", pid, comm, str);

eunomia-bpf 是一個結合 Wasm 的開源 eBPF 動態加載運行時和開發工具鏈,它的目的是簡化 eBPF 程序的開發、構建、分發、運行。可以參考 //github.com/eunomia-bpf/eunomia-bpf 下載和安裝 ecc 編譯工具鏈和 ecli 運行時。我們使用 eunomia-bpf 編譯運行這個例子。

如何編譯呢? 在wsl2(ubuntu-22.04)下面

還是推薦用官網的 docker靠譜

//eunomia.dev/ecc/docker-usage.html

$ docker run -it -v /path/to/repo/:/src ghcr.io/eunomia-bpf/ecc-`uname -m`:latest # use absolute path

當然必須有格式要求:

xx.bpf.c # 必須的

xxx.h  # 可選的

xx.bpf.c 和 xxx.h 必須放在  /path/to/repo/ 目錄下 ,運行完畢之后會有一個 package.json文件產生。

要運行 package.json 文件,必須下載 ecli 二進制工具,

$ wget //aka.pw/bpf-ecli -O ecli && chmod +x ecli

又報錯了,缺少這個!

完了,wsl2 好像還不支持vmlinux BTF , 哎,太難了,搞一個環境。

還是搞一個ecli的docker環境來運行吧,參考官網

//eunomia.dev/ecli-dockerfile-usage.html

這個ecli的鏡像需要自己制作, ecli可執行文件 sources.list Dockerfile這三個文件缺一不可,other文件可忽略。docker容器中wget無法連接外部網絡,因此需要在docker構建時將ecli放入鏡像中。使用鏡像時只要掛載的本機目錄中有package.json文件即可。需要注意的是bpf 運行時需要有Linux內核相關支持,docker 中的內核共享的宿主機的內核,因此使用docker運行bpf程序時需要使用以下命令為容器賦予權限和相關內核支持。

 

編譯運行上述代碼, 運行這段程序后,可以通過查看 /sys/kernel/debug/tracing/trace_pipe 文件來查看 eBPF 程序的輸出:

$ sudo cat /sys/kernel/debug/tracing/trace_pipe

可以看到,我們成功的捕獲了 bash 的 readline 函數調用,并獲取了用戶在 bash 中輸入的命令行。

總結

在上述代碼中,我們使用了 SEC 宏來定義了一個 uprobe 探針,它指定了要捕獲的用戶空間程序 (bin/bash) 和要捕獲的函數 (readline)。此外,我們還使用了 BPF_KRETPROBE 宏來定義了一個用于處理 readline 函數返回值的回調函數 (printret)。該函數可以獲取到 readline 函數的返回值,并將其打印到內核日志中。通過這樣的方式,我們就可以使用 eBPF 來捕獲 bash 的 readline 函數調用,并獲取用戶在 bash 中輸入的命令行。

更多的例子和詳細的開發指南,請參考 eunomia-bpf 的官方文檔:

//github.com/eunomia-bpf/eunomia-bpf

完整的教程和源代碼已經全部開源,可以在

//github.com/eunomia-bpf/bpf-developer-tutorial

本來想基于eunomia-bpf 想寫個新的,發現環境把我勸退了,看看原版的

//mp.weixin.qq.com/s/cvnp2oCJTvpaDe9fhFFjhg

 

 

0條評論
0 / 1000
Top123
32文章數
3粉絲數
Top123
32 文章 | 3 粉絲
Top123
32文章數
3粉絲數
Top123
32 文章 | 3 粉絲
原創

ebpf調研(6)

2023-04-26 03:11:06
15
0

在 eBPF 中使用 uprobe 捕獲 bash 的 readline 函數調用


eBPF (Extended Berkeley Packet Filter) 是 Linux 內核上的一個強大的網絡和性能分析工具,它允許開發者在內核運行時動態加載、更新和運行用戶定義的代碼。

本文主要介紹如何使用 uprobe 捕獲 bash 的 readline 函數調用。

什么是uprobe

uprobe是一種用戶空間探針,uprobe探針允許在用戶空間程序中動態插樁,插樁位置包括:函數入口、特定偏移處,以及函數返回處。當我們定義uprobe時,內核會在附加的指令上創建快速斷點指令(x86機器上為int3指令),當程序執行到該指令時,內核將觸發事件,程序陷入到內核態,并以回調函數的方式調用探針函數,執行完探針函數再返回到用戶態繼續執行后序的指令。

uprobe基于文件,當一個二進制文件中的一個函數被跟蹤時,所有使用到這個文件的進程都會被插樁,包括那些尚未啟動的進程,這樣就可以在全系統范圍內跟蹤系統調用。

uprobe適用于在用戶態去解析一些內核態探針無法解析的流量,例如http2流量(報文header被編碼,內核無法解碼),https流量(加密流量,內核無法解密)。

使用 uprobe 捕獲 bash 的 readline 函數調用

uprobe 是一種用于捕獲用戶空間函數調用的 eBPF 的探針,我們可以通過它來捕獲用戶空間程序調用的系統函數。

例如,我們可以使用 uprobe 來捕獲 bash 的 readline 函數調用,從而獲取用戶在 bash 中輸入的命令行。示例代碼如下:

#cat read.bpf.c

#include <vmlinux.h>
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h>

#define TASK_COMM_LEN 16
#define MAX_LINE_SIZE 80

SEC("uretprobe//bin/bash:readline")
int BPF_KRETPROBE(printret, const void *ret)
{
 char str[MAX_LINE_SIZE];
 char comm[TASK_COMM_LEN];
 u32 pid;

 if (!ret)
  return 0;

 bpf_get_current_comm(&comm, sizeof(comm));

 pid = bpf_get_current_pid_tgid() >> 32;
 bpf_probe_read_user_str(str, sizeof(str), ret);

 bpf_printk("PID %d (%s) read: %s ", pid, comm, str);

 return 0;
};

char LICENSE[] SEC("license") = "GPL";

這段代碼的作用是在 bash 的 readline 函數返回時執行指定的 BPF_KRETPROBE 函數,即 printret 函數。

在 printret 函數中,我們首先獲取了調用 readline 函數的進程的進程名稱和進程 ID,然后通過 bpf_probe_read_user_str 函數讀取了用戶輸入的命令行字符串,最后通過 bpf_printk 函數打印出進程 ID、進程名稱和輸入的命令行字符串。

除此之外,我們還需要通過 SEC 宏來定義 uprobe 探針,并使用 BPF_KRETPROBE 宏來定義探針函數。

在 SEC 宏中,我們需要指定 uprobe 的類型、要捕獲的二進制文件的路徑和要捕獲的函數名稱。例如,上面的代碼中的 SEC 宏的定義如下:

SEC("uprobe//bin/bash:readline")

這表示我們要捕獲的是 /bin/bash 二進制文件中的 readline 函數。

接下來,我們需要使用 BPF_KRETPROBE 宏來定義探針函數,例如:

BPF_KRETPROBE(printret, const void *ret)

這里的 printret 是探針函數的名稱,const void *ret 是探針函數的參數,它代表被捕獲的函數的返回值。

然后,我們使用了 bpf_get_current_comm 函數獲取當前任務的名稱,并將其存儲在 comm 數組中。

 bpf_get_current_comm(&comm, sizeof(comm));

使用 bpf_get_current_pid_tgid 函數獲取當前進程的 PID,并將其存儲在 pid 變量中。

 pid = bpf_get_current_pid_tgid() >> 32;

使用 bpf_probe_read_user_str 函數從用戶空間讀取 readline 函數的返回值,并將其存儲在 str 數組中。

 bpf_probe_read_user_str(str, sizeof(str), ret);

最后使用 bpf_printk 函數輸出 PID、任務名稱和用戶輸入的字符串。

 bpf_printk("PID %d (%s) read: %s ", pid, comm, str);

eunomia-bpf 是一個結合 Wasm 的開源 eBPF 動態加載運行時和開發工具鏈,它的目的是簡化 eBPF 程序的開發、構建、分發、運行。可以參考 //github.com/eunomia-bpf/eunomia-bpf 下載和安裝 ecc 編譯工具鏈和 ecli 運行時。我們使用 eunomia-bpf 編譯運行這個例子。

如何編譯呢? 在wsl2(ubuntu-22.04)下面

還是推薦用官網的 docker靠譜

//eunomia.dev/ecc/docker-usage.html

$ docker run -it -v /path/to/repo/:/src ghcr.io/eunomia-bpf/ecc-`uname -m`:latest # use absolute path

當然必須有格式要求:

xx.bpf.c # 必須的

xxx.h  # 可選的

xx.bpf.c 和 xxx.h 必須放在  /path/to/repo/ 目錄下 ,運行完畢之后會有一個 package.json文件產生。

要運行 package.json 文件,必須下載 ecli 二進制工具,

$ wget //aka.pw/bpf-ecli -O ecli && chmod +x ecli

又報錯了,缺少這個!

完了,wsl2 好像還不支持vmlinux BTF , 哎,太難了,搞一個環境。

還是搞一個ecli的docker環境來運行吧,參考官網

//eunomia.dev/ecli-dockerfile-usage.html

這個ecli的鏡像需要自己制作, ecli可執行文件 sources.list Dockerfile這三個文件缺一不可,other文件可忽略。docker容器中wget無法連接外部網絡,因此需要在docker構建時將ecli放入鏡像中。使用鏡像時只要掛載的本機目錄中有package.json文件即可。需要注意的是bpf 運行時需要有Linux內核相關支持,docker 中的內核共享的宿主機的內核,因此使用docker運行bpf程序時需要使用以下命令為容器賦予權限和相關內核支持。

 

編譯運行上述代碼, 運行這段程序后,可以通過查看 /sys/kernel/debug/tracing/trace_pipe 文件來查看 eBPF 程序的輸出:

$ sudo cat /sys/kernel/debug/tracing/trace_pipe

可以看到,我們成功的捕獲了 bash 的 readline 函數調用,并獲取了用戶在 bash 中輸入的命令行。

總結

在上述代碼中,我們使用了 SEC 宏來定義了一個 uprobe 探針,它指定了要捕獲的用戶空間程序 (bin/bash) 和要捕獲的函數 (readline)。此外,我們還使用了 BPF_KRETPROBE 宏來定義了一個用于處理 readline 函數返回值的回調函數 (printret)。該函數可以獲取到 readline 函數的返回值,并將其打印到內核日志中。通過這樣的方式,我們就可以使用 eBPF 來捕獲 bash 的 readline 函數調用,并獲取用戶在 bash 中輸入的命令行。

更多的例子和詳細的開發指南,請參考 eunomia-bpf 的官方文檔:

//github.com/eunomia-bpf/eunomia-bpf

完整的教程和源代碼已經全部開源,可以在

//github.com/eunomia-bpf/bpf-developer-tutorial

本來想基于eunomia-bpf 想寫個新的,發現環境把我勸退了,看看原版的

//mp.weixin.qq.com/s/cvnp2oCJTvpaDe9fhFFjhg

 

 

文章來自個人專欄
文章 | 訂閱
0條評論
0 / 1000
請輸入你的評論
0
0