ctf环境配置
前言
为了方便,将CTF的环境配置进行总结,方便日后快速恢复环境等
PWN环境
由于一般PWN题目涉及到各种Glibc版本,这里搭建多个虚拟机,下面给出主要版本下的虚拟机安装
ubuntu16.04
其安装脚本如下所示
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
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
set -x
# apt mirror
sudo tee /etc/apt/sources.list <<EOF
deb https://mirrors.ustc.edu.cn/ubuntu/ xenial main restricted universe multiverse
deb-src https://mirrors.ustc.edu.cn/ubuntu/ xenial main restricted universe multiverse
deb https://mirrors.ustc.edu.cn/ubuntu/ xenial-security main restricted universe multiverse
deb-src https://mirrors.ustc.edu.cn/ubuntu/ xenial-security main restricted universe multiverse
deb https://mirrors.ustc.edu.cn/ubuntu/ xenial-updates main restricted universe multiverse
deb-src https://mirrors.ustc.edu.cn/ubuntu/ xenial-updates main restricted universe multiverse
deb https://mirrors.ustc.edu.cn/ubuntu/ xenial-backports main restricted universe multiverse
deb-src https://mirrors.ustc.edu.cn/ubuntu/ xenial-backports main restricted universe multiverse
EOF
# necessary software
sudo add-apt-repository -y ppa:brightbox/ruby-ng \
&& sudo apt-get update \
&& sudo apt-get install -y libffi-dev libsqlite3-dev libbz2-dev liblzma-dev zlib1g-dev tk-dev libncursesw5-dev libgdbm-dev openssl libssl-dev libreadline-dev uuid-dev \
texinfo \
patchelf strace \
gcc gcc-multilib g++-multilib nasm \
git wget curl xsel \
qemu-system docker docker-compose
# docker
sudo tee /etc/docker/daemon.json <<EOF
{
"registry-mirrors":[
"https://docker.mirrors.ustc.edu.cn",
"https://registry.docker-cn.com"
]
}
EOF
sudo usermod -aG docker ${USER}
# python
wget https://www.python.org/ftp/python/3.8.10/Python-3.8.10.tar.xz \
&& tar -xvf Python-3.8.10.tar.xz -C ~ \
&& rm -rf Python-3.8.10.tar.xz \
&& (cd ~/Python-3.8.10 && mkdir build && cd build && ../configure --enable-shared --exec-prefix=/usr && make -j $(nproc) && sudo make -j $(nproc) install) \
&& sudo update-alternatives --install /usr/bin/python3 python3 /usr/local/bin/python3.8 150 \
&& wget https://bootstrap.pypa.io/get-pip.py \
&& python3 get-pip.py --user \
&& rm -rf get-pip.py \
# gdb
wget http://ftp.gnu.org/gnu/gdb/gdb-9.2.tar.xz \
&& tar -xvf gdb-9.2.tar.xz -C ~ \
&& rm -rf gdb-9.2.tar.xz \
&& (cd ~/gdb-9.2 && mkdir build && cd build && ../configure --with-python=/usr/bin/python3 && make -j $(nproc) && sudo make -j $(nproc) install) \
# neovim
wget -O ~/nvim.appimage https://ghproxy.com/https://github.com/neovim/neovim/releases/download/stable/nvim.appimage \
&& chmod +x ~/nvim.appimage \
&& sudo ln -sf ~/nvim.appimage /usr/bin/vi \
&& mkdir ~/.config/nvim \
&& cat > ~/.config/nvim/init.vim <<EOF
set clipboard+=unnamedplus
set nu
set tabstop=4
set shiftwidth=4
set softtabstop=4
set expandtab
EOF
# git
git config --global user.name "hawk" \
&& git config --global user.email 18801353760@163.com \
&& git config --global core.editor vi
# python
python3 -m pip install -U --force-reinstall pip -i https://pypi.tuna.tsinghua.edu.cn/simple \
&& python3 -m pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple
# pwntools
python3 -m pip install pwntools
# ropper
python3 -m pip install ropper
# pwndbg
git config --global url."https://ghproxy.com/https://github.com/".insteadOf "https://github.com/" \
&& git clone https://github.com/pwndbg/pwndbg.git ~/pwndbg \
&& (cd ~/pwndbg && ./setup.sh) \
&& git config --global --unset url."https://ghproxy.com/https://github.com/".insteadOf \
&& python3 -m pip install pwnlib psutil
# ruby
sudo apt-get update \
&& sudo apt-get install -y ruby2.6 ruby2.6-dev \
&& sudo gem install one_gadget seccomp-tools
ubuntu18.04
1 |
|
ubuntu20.04
1 |
|
ubuntu22.04
1 |
|
patchelf
CTF的PWN类型题目中,会有复杂的动态链接库和依赖关系,我们需要修改这些二进制的信息,使其可以在本地环境下正常运行,可以通过patchelf程序进行实现。
dynamic loader
如果没有正确的动态载入器,我们会导致程序执行错误或无法找到程序,因此可以通过如下命令修改指定的动态载入器地址
1
patchelf --set-interpreter [path] [execute]
runtime path
有时程序需要使用特殊的动态链接库,因此其指定了动态链接库的首要查找路径,即runtime path(rpath)。我们在本地可以通过修改rpath字段的值,从而让其在本地的对应路径下去寻找动态链接库,命令如下
1
patchelf --set-rpath [path] [execute]
LD_*环境变量
由于程序的动态链接和依赖关系十分的复杂,因此linux本身也提供了一些环境变量,方便进行程序动态链接和依赖的查找和调试
LD_DEBUG
实际上通过设置LD_DEBUG变量,可以方便的调试程序动态链接的各种过程,比如
1 | LD_DEBUG=libs [execute] |
终端会输出程序寻找动态库的全过程,然后接着是正常的执行过程。
LD_DEBUG中包含多个可选的值,如libs、symbols等,可以通过设置help值,然后屏幕会输出所有的可选项及其含义。
LD_LIBRARY_PATH
类似于前面的runtime path,但是优先级次一级。即程序运行前,在查找动态链接库时,会首先在指定的rpath路径下查找;然后在指定的LD_LIBRARY_PATH路径下查找;最后在系统的默认路径下进行查找
其命令执行形式如下所示
1
LD_LIBRARY_PATH=[path] [execute]
GDB调试器
再做PWN题目的时候,需要进行相关的调试,这就需要Linux中的GDB进行辅助。
常用命令
GDB及其插件中提供了大量的操作,方便进行调试程序,在GDB教程资源和pwndbg教程中有详细的信息,这里简单介绍几个
starti
,该命令将程序执行到真正的入口处,并停止等待后续DEBUG命令call [function]
,直接调用function
函数执行break [address] if [condition]
,即当条件condition
满足时,程序会在执行到address
时停止break *$rebase(address)
,即在装载基地址偏移address
设立断点dprintf *$rebase(address) "%d\n", $rax
,即当执行到*$rebase(address)
地址处,输出相关的格式信息find [/SIZE-CHAR] START-ADDRESS, END-ADDRESS, EXPR1
,即在指定范围内寻找指定值和类型的数据,其中,SIZE-CHAR可选b、h、w、g,分别表示8bit、16bit、32bit和64bitp *(struct s*)(address)
,即将address地址处的变量当作struct s结构体的指针,并打印出具体的结构体信息![command]
,即在gdb中打开shell,执行command指令
命令执行
除了手动一条一条命令的进行交互,也可以通过命令行,按照提前给定的指令依次执行,如下所示
1
gdb [file] -ex [command1] -ex [command2] ...
之后,gdb加载给定的目标程序,并按照参数顺序,依次在GDB中执行参数中传递的命令
pwntools库
这是专门用于CTF和漏洞利用的Python库
PWN模板
为了方便PWN,这里专门给出一个标准脚本,可以稍加修改即可用于任何不同的PWN题目
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
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119#!/usr/bin/python3
# -*- coding:utf-8 -*-
from pwn import *
import sys
import platform
'''
待修改数据
'''
context.log_level = 'debug'
context.arch = 'amd64' # 32位使用i386
context.os = 'linux'
execve_file = None
lib_file = None
'''
使用lambda函数包装pwntools的API,从而使与用户交互的都是str即可
'''
ENCODING = 'ISO-8859-1'
se = lambda senddata : r.send(senddata.encode(ENCODING))
sa = lambda recvdata, senddata, timeout=0x3f3f3f3f : r.sendafter(recvdata.encode(ENCODING), senddata.encode(ENCODING), timeout=timeout)
sl = lambda senddata : r.sendline(senddata.encode(ENCODING))
sla = lambda recvdata, senddata, timeout=0x3f3f3f3f : r.sendlineafter(recvdata.encode(ENCODING), senddata.encode(ENCODING), timeout=timeout)
re = lambda numb=0x3f3f3f3f, timeout=0x3f3f3f3f : (r.recv(numb, timeout=timeout).decode(ENCODING))
ru = lambda recvdata, timeout=0x3f3f3f3f : (r.recvuntil(recvdata.encode(ENCODING), timeout=timeout).decode(ENCODING))
uu32 = lambda data : u32((data.ljust(4, '\x00')).encode(ENCODING), signed="unsigned")
uu64 = lambda data : u64((data.ljust(8, '\x00')).encode(ENCODING), signed="unsigned")
iu32 = lambda data : u32((data.ljust(4, '\x00')).encode(ENCODING), signed="signed")
iu64 = lambda data : u64((data.ljust(8, '\x00')).encode(ENCODING), signed="signed")
up32 = lambda data : (p32(data, signed="unsigned").decode(ENCODING))
up64 = lambda data : (p64(data, signed="unsigned").decode(ENCODING))
ip32 = lambda data : (p32(data, signed="signed").decode(ENCODING))
ip64 = lambda data : (p64(data, signed="signed").decode(ENCODING))
'''
elf.plt[`symbol`] 获取elf文件中导入符号的plt地址
elf.got[`symbol`] 获取elf文件中导入符号的got地址
elf.sym['symbol'] 获取elf文件中本地符号的函数实际地址
'''
if execve_file != None:
elf = ELF(execve_file)
'''
lib.sym[`symbol`] 获取lib中符号地址
next(lib.search('string')) 获取lib中字符串地址
'''
if lib_file != None:
lib = ELF(lib_file)
'''
执行爆破攻击
只有当成功获取shell或者键盘Ctrl+C退出时,程序中止循环
否则程序一直进行循环
'''
def exp():
global r
if 'd' in sys.argv:
r = process(execve_file)
gdb.attach(r) # 断点必须在第一个输入之后
else:
r = remote(sys.argv[1], sys.argv[2])
'''
这里给出asm 汇编->机器代码的相关样例
'''
if context.arch == 'amd64':
shellcode = asm('''
mov rax, %d /*rbx = "/bin/sh"*/
push rax
mov rdi, rsp /*rdi -> "/bin/sh"*/
xor esi, esi /*esi -> NULL*/
xor edx, edx /*edx -> NULL*/
push 0x3b
pop rax /*rax = 0x3b*/
syscall /*execve("/bin/sh")*/
label1:
mov rax, [rsp + %d] /* 测试内存访问 */
cmp rax, 1
je label1 /* 测试近跳 */
'''%(uu64('/bin/sh'), 8)).decode(ENCODING)
elif context.arch == 'i386':
shellcode = asm('''
push %d /*"/bin"*/
push %d /*"/sh\x00"*/
mov ebx, esp /*ebx -> "/bin/sh"*/
xor ecx, ecx /*ecx -> NULL*/
xor edx, edx /*edx -> NULL*/
push 11
pop eax /*eax = 11*/
int 0x80 /*execve("/bin/sh")*/
label1:
mov eax, [esp + %d] /* 测试内存访问 */
cmp eax, 1
je label1 /* 测试近跳 */
'''%(uu32('/sh'), uu32('/bin'), 4)).decode(ENCODING)
while True:
try:
exp()
sl('cat flag')
data = ru('}', 1)
if '{' not in data:
r.close()
continue
else:
log.info(data)
break
except KeyboardInterrupt:
break
except:
continue
Kernel
kernel pwn中涉及非常琐碎的知识点,这里简单介绍一些
文件
内核文件
一般有如下几种内核文件格式
- vmlinux
从源码编译出来的,原始内核二进制文件 - bzImage
big zImage,也就是更大的zImage。而zImage是vmlinux经过压缩后的文件,使用extract-vmlinux脚本将zImage解压为vmlinux亦可使用vmlinux-to-elf,将bzImage转换为带符号的vmlinux1
./extract-vmlinux /path/to/bzImage > /path/to/vmlinux
1
vmlinux-to-elf /path/to/bzImage /path/to/vmlinux
镜像文件
即文件系统镜像——简单来说,该文件中保存着一个文件系统的dump。只要将该文件映射入内存,即建立了根文件系统所需要的结构信息
一般名称为rootfs.cpio
使用如下命令将其文件结构导出到当前目录中
1
cpio -D ${dir} -idv < /path/to/rootfs.cpio
如果想将${dir}的目录数据和结构作为内核的根目录,使用如下命令打包成文件系统镜像
1
(cd ${dir}; find . | cpio -o --format=newc > /path/to/rootfs.cpio)
结构体
在编写kernel pwn的exploit时,有时需要某个结构体的字段偏移。
往往有两种方式
- 根据源码手算结构体的偏移。这种方式虽然简单,但是十分容易出错
- 编写一个模块,其内容就是计算结构体偏移
对于第二种方式,(默认要计算的结构体在内核不同版本间无变化,否则要先编译对应版本的内核)这里给出编写驱动所需要的Makefile、编译脚本和驱动源代码,可以参照官方参考链接1和官方参考链接2
Makefile如下所示1
2
3
4
5
6
7obj-m += hawk.o
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
在Makefile同目录下执行如下命令
1
2make #编译驱动
make clean #清除编译
驱动源代码样例如下所示
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
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
static int vuln_open(struct inode *inode, struct file *filp);
static long vuln_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);
static struct file_operations vuln_fops = {
open : vuln_open,
unlocked_ioctl : vuln_unlocked_ioctl,
};
static struct miscdevice vuln_miscdev = {
.minor = 11,
.name = "vuln",
.fops = &vuln_fops,
.mode = 0666,
};
static int vuln_open(struct inode *inode, struct file *filp){
return 0;
}
typedef struct {
long long *addr;
long long val;
} Data;
static long vuln_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg){
Data data;
memset(&data, 0, sizeof(data));
switch (cmd){
case VULN_WRITE:
if(copy_from_user(&data, (Data *)arg, sizeof(data)) != 0)
return -ENOMEM;
*(data.addr) = data.val;
break;
case VULN_READ:
if(copy_from_user(&data, (Data *)arg, sizeof(data)) != 0)
return -ENOMEM;
if(copy_to_user((void*)data.val, data.addr, sizeof(data.val)) != 0)
return -ENOMEM;
break;
default:
return -ENOTTY;
}
return 0;
}
static int vuln_init(void){
return misc_register(&vuln_miscdev);
}
static void vuln_exit(void){
misc_deregister(&vuln_miscdev);
}
module_init(vuln_init);
module_exit(vuln_exit);
MODULE_LICENSE("GPL");
busybox
前面简单介绍过,Linux内核的启动过程,需要根文件系统映像。一般使用busybox
其中,通过make menuconfig
以静态链接方式编译,再通过make
和make install
命令,即可在${busybox}/_install目录中,构建一个基础的根文件系统。
再通过前面相关内容,即可通过cpio命令,生成根文件系统映像
创建挂载目录
执行下述命令,创建内核的伪文件系统的挂载点1
mkdir dev etc proc sys
/etc/inittab
根据init/init.c可知,/linuxrc会解析/etc/inittab文件,并完成相关的脚本执行。模板配置如下所示1
2
3::sysinit:/etc/init.d/rcS
::respawn:-/bin/sh
::restart:/sbin/init
/etc/init.d/rcS
根据上面的/etc/inittab脚本的内容,其会执行/etc/init.d/rcS脚本,初始化内核配置。模板配置如下所示1
2
3
4
5
6
mount -t proc none /proc
mount -t sysfs none /sys
echo /sbin/mdev > /proc/sys/kernel/hotplug
mdev -s
创建该文件后,还需要设置权限为可执行,即执行chmod +x /etc/init.d/rcS
即可
qemu
为了方便调试,一般通过qemu模拟运行内核,运行命令如下所示
1
2
3
4
5
6
7
8
9
10
11
12
13qemu-system-x86_64 \
-kernel ${linux}/arch/x86_64/boot/bzImage \
-initrd /path/to/rootfs.cpio \
-monitor /dev/null \
-serial mon:stdio \
-nographic \
-append "rdinit=/linuxrc console=ttyS0 oops=panic panic=1 nokaslr" \
-enable-kvm \
-smp cores=1,threads=1 \
-m 128M \
-cpu kvm64,+smep \
-no-reboot -no-shutdown \
-s -S
相关参数的含义通过man qemu-system
查看,如下所示
参数 | 含义 |
---|---|
-m | 虚拟机的内存大小,后缀为’M’或’G’ |
-kernel | 内核镜像 |
-initrd | 文件系统镜像 |
-monitor | 重定向Qemu控制台,可以查看虚拟机状态 |
-serial mon:dev_string | 当监视器以这种方式多路复用到 stdio 时,Ctrl+C 将不再终止 QEMU,而是传递给来宾 |
-append | kernel的参数,参考链接 root:根文件系统对应的设备,有默认值 init:制定内核执行的第一条命令,有默认值 console:console对应的设备,一般用ttyS0,从而重定向到串口 |
-enable-kvm | 开启KVM虚拟化 |
-nographic | 关闭Qemu GUI。可以使用-monitor重定向Qemu控制台;-serial重定向guest串口信息; -display重定向guest的GUI |
-smp | 设置虚拟机cpu属性 |
-cpu | 设置cpu模型信息 |
-no-reboot | 当内核崩溃后,静止重启 |
-no-shutdown | 当内核崩溃后,冻结在崩溃位置处 |
模板
qemu启动脚本
则本地调试脚本如下所示
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
set -x
apt_search()
{
for arg in "$@"
do
apt list --installed | grep "$arg";
if [ ! "$?" = "0" ]; then
return 1
fi
done
return 0
}
# 根文件系统路径
ROOT=$(pwd)/rootfs
# 文件系统映像路径
ROOTFS=$(pwd)/rootfs.cpio
# 内核镜像路径
KERNEL=$(pwd)/kernel
# exp源代码路径
EXP=$(pwd)/exp.c
# 安装所需要的依赖包
apt_search libkeyutils-dev musl-tools
if [ ! "$?" = "0" ]; then
sudo apt-get install -y libkeyutils-dev musl-tools
fi
# 静态编译exp
gcc -E -Werror -Wall -o $(pwd)/rootfs/exp.i ${EXP} \
&& musl-gcc -Os -Werror -Wall -static -o $(pwd)/rootfs/exp $(pwd)/rootfs/exp.i -lpthread \
&& strip -s $(pwd)/rootfs/exp \
&& rm -rf $(pwd)/rootfs/exp.i
# 生成文件系统映像
(cd ${ROOT}; find . | cpio -o --format=newc > ${ROOTFS})
# 启动qemu
qemu-system-x86_64 \
-m 128M \
-nographic \
-monitor /dev/null \
-serial mon:stdio \
-kernel ${KERNEL}/arch/x86_64/boot/bzImage \
-append 'console=ttyS0 loglevel=3 oops=panic panic=1 nokaslr' \
-initrd ${ROOTFS} \
-no-shutdown -no-reboot \
-s
gdb配置文件
1 | # .gdbinit |
exp
系统调用
参考arch/x86/entry/syscalls/syscall_64.tbl,使用如下命令cat arch/x86/entry/syscalls/syscall_64.tbl | awk '{print $3,$2,$1}' | awk '{if(NF==3){print $0}}' | awk '{if($2=="common" || $2=="64" || $2=="x32"){printf "|%-30s|%-6s|%s|\n",$1,$2,$3}}'
,生成64位下的系统调用号
系统调用名称 | abi | 系统调用号 |
---|---|---|
read | common | 0 |
write | common | 1 |
open | common | 2 |
close | common | 3 |
stat | common | 4 |
fstat | common | 5 |
lstat | common | 6 |
poll | common | 7 |
lseek | common | 8 |
mmap | common | 9 |
mprotect | common | 10 |
munmap | common | 11 |
brk | common | 12 |
rt_sigaction | 64 | 13 |
rt_sigprocmask | common | 14 |
rt_sigreturn | 64 | 15 |
ioctl | 64 | 16 |
pread64 | common | 17 |
pwrite64 | common | 18 |
readv | 64 | 19 |
writev | 64 | 20 |
access | common | 21 |
pipe | common | 22 |
select | common | 23 |
sched_yield | common | 24 |
mremap | common | 25 |
msync | common | 26 |
mincore | common | 27 |
madvise | common | 28 |
shmget | common | 29 |
shmat | common | 30 |
shmctl | common | 31 |
dup | common | 32 |
dup2 | common | 33 |
pause | common | 34 |
nanosleep | common | 35 |
getitimer | common | 36 |
alarm | common | 37 |
setitimer | common | 38 |
getpid | common | 39 |
sendfile | common | 40 |
socket | common | 41 |
connect | common | 42 |
accept | common | 43 |
sendto | common | 44 |
recvfrom | 64 | 45 |
sendmsg | 64 | 46 |
recvmsg | 64 | 47 |
shutdown | common | 48 |
bind | common | 49 |
listen | common | 50 |
getsockname | common | 51 |
getpeername | common | 52 |
socketpair | common | 53 |
setsockopt | 64 | 54 |
getsockopt | 64 | 55 |
clone | common | 56 |
fork | common | 57 |
vfork | common | 58 |
execve | 64 | 59 |
exit | common | 60 |
wait4 | common | 61 |
kill | common | 62 |
uname | common | 63 |
semget | common | 64 |
semop | common | 65 |
semctl | common | 66 |
shmdt | common | 67 |
msgget | common | 68 |
msgsnd | common | 69 |
msgrcv | common | 70 |
msgctl | common | 71 |
fcntl | common | 72 |
flock | common | 73 |
fsync | common | 74 |
fdatasync | common | 75 |
truncate | common | 76 |
ftruncate | common | 77 |
getdents | common | 78 |
getcwd | common | 79 |
chdir | common | 80 |
fchdir | common | 81 |
rename | common | 82 |
mkdir | common | 83 |
rmdir | common | 84 |
creat | common | 85 |
link | common | 86 |
unlink | common | 87 |
symlink | common | 88 |
readlink | common | 89 |
chmod | common | 90 |
fchmod | common | 91 |
chown | common | 92 |
fchown | common | 93 |
lchown | common | 94 |
umask | common | 95 |
gettimeofday | common | 96 |
getrlimit | common | 97 |
getrusage | common | 98 |
sysinfo | common | 99 |
times | common | 100 |
ptrace | 64 | 101 |
getuid | common | 102 |
syslog | common | 103 |
getgid | common | 104 |
setuid | common | 105 |
setgid | common | 106 |
geteuid | common | 107 |
getegid | common | 108 |
setpgid | common | 109 |
getppid | common | 110 |
getpgrp | common | 111 |
setsid | common | 112 |
setreuid | common | 113 |
setregid | common | 114 |
getgroups | common | 115 |
setgroups | common | 116 |
setresuid | common | 117 |
getresuid | common | 118 |
setresgid | common | 119 |
getresgid | common | 120 |
getpgid | common | 121 |
setfsuid | common | 122 |
setfsgid | common | 123 |
getsid | common | 124 |
capget | common | 125 |
capset | common | 126 |
rt_sigpending | 64 | 127 |
rt_sigtimedwait | 64 | 128 |
rt_sigqueueinfo | 64 | 129 |
rt_sigsuspend | common | 130 |
sigaltstack | 64 | 131 |
utime | common | 132 |
mknod | common | 133 |
uselib | 64 | 134 |
personality | common | 135 |
ustat | common | 136 |
statfs | common | 137 |
fstatfs | common | 138 |
sysfs | common | 139 |
getpriority | common | 140 |
setpriority | common | 141 |
sched_setparam | common | 142 |
sched_getparam | common | 143 |
sched_setscheduler | common | 144 |
sched_getscheduler | common | 145 |
sched_get_priority_max | common | 146 |
sched_get_priority_min | common | 147 |
sched_rr_get_interval | common | 148 |
mlock | common | 149 |
munlock | common | 150 |
mlockall | common | 151 |
munlockall | common | 152 |
vhangup | common | 153 |
modify_ldt | common | 154 |
pivot_root | common | 155 |
_sysctl | 64 | 156 |
prctl | common | 157 |
arch_prctl | common | 158 |
adjtimex | common | 159 |
setrlimit | common | 160 |
chroot | common | 161 |
sync | common | 162 |
acct | common | 163 |
settimeofday | common | 164 |
mount | common | 165 |
umount2 | common | 166 |
swapon | common | 167 |
swapoff | common | 168 |
reboot | common | 169 |
sethostname | common | 170 |
setdomainname | common | 171 |
iopl | common | 172 |
ioperm | common | 173 |
create_module | 64 | 174 |
init_module | common | 175 |
delete_module | common | 176 |
get_kernel_syms | 64 | 177 |
query_module | 64 | 178 |
quotactl | common | 179 |
nfsservctl | 64 | 180 |
getpmsg | common | 181 |
putpmsg | common | 182 |
afs_syscall | common | 183 |
tuxcall | common | 184 |
security | common | 185 |
gettid | common | 186 |
readahead | common | 187 |
setxattr | common | 188 |
lsetxattr | common | 189 |
fsetxattr | common | 190 |
getxattr | common | 191 |
lgetxattr | common | 192 |
fgetxattr | common | 193 |
listxattr | common | 194 |
llistxattr | common | 195 |
flistxattr | common | 196 |
removexattr | common | 197 |
lremovexattr | common | 198 |
fremovexattr | common | 199 |
tkill | common | 200 |
time | common | 201 |
futex | common | 202 |
sched_setaffinity | common | 203 |
sched_getaffinity | common | 204 |
set_thread_area | 64 | 205 |
io_setup | 64 | 206 |
io_destroy | common | 207 |
io_getevents | common | 208 |
io_submit | 64 | 209 |
io_cancel | common | 210 |
get_thread_area | 64 | 211 |
lookup_dcookie | common | 212 |
epoll_create | common | 213 |
epoll_ctl_old | 64 | 214 |
epoll_wait_old | 64 | 215 |
remap_file_pages | common | 216 |
getdents64 | common | 217 |
set_tid_address | common | 218 |
restart_syscall | common | 219 |
semtimedop | common | 220 |
fadvise64 | common | 221 |
timer_create | 64 | 222 |
timer_settime | common | 223 |
timer_gettime | common | 224 |
timer_getoverrun | common | 225 |
timer_delete | common | 226 |
clock_settime | common | 227 |
clock_gettime | common | 228 |
clock_getres | common | 229 |
clock_nanosleep | common | 230 |
exit_group | common | 231 |
epoll_wait | common | 232 |
epoll_ctl | common | 233 |
tgkill | common | 234 |
utimes | common | 235 |
vserver | 64 | 236 |
mbind | common | 237 |
set_mempolicy | common | 238 |
get_mempolicy | common | 239 |
mq_open | common | 240 |
mq_unlink | common | 241 |
mq_timedsend | common | 242 |
mq_timedreceive | common | 243 |
mq_notify | 64 | 244 |
mq_getsetattr | common | 245 |
kexec_load | 64 | 246 |
waitid | 64 | 247 |
add_key | common | 248 |
request_key | common | 249 |
keyctl | common | 250 |
ioprio_set | common | 251 |
ioprio_get | common | 252 |
inotify_init | common | 253 |
inotify_add_watch | common | 254 |
inotify_rm_watch | common | 255 |
migrate_pages | common | 256 |
openat | common | 257 |
mkdirat | common | 258 |
mknodat | common | 259 |
fchownat | common | 260 |
futimesat | common | 261 |
newfstatat | common | 262 |
unlinkat | common | 263 |
renameat | common | 264 |
linkat | common | 265 |
symlinkat | common | 266 |
readlinkat | common | 267 |
fchmodat | common | 268 |
faccessat | common | 269 |
pselect6 | common | 270 |
ppoll | common | 271 |
unshare | common | 272 |
set_robust_list | 64 | 273 |
get_robust_list | 64 | 274 |
splice | common | 275 |
tee | common | 276 |
sync_file_range | common | 277 |
vmsplice | 64 | 278 |
move_pages | 64 | 279 |
utimensat | common | 280 |
epoll_pwait | common | 281 |
signalfd | common | 282 |
timerfd_create | common | 283 |
eventfd | common | 284 |
fallocate | common | 285 |
timerfd_settime | common | 286 |
timerfd_gettime | common | 287 |
accept4 | common | 288 |
signalfd4 | common | 289 |
eventfd2 | common | 290 |
epoll_create1 | common | 291 |
dup3 | common | 292 |
pipe2 | common | 293 |
inotify_init1 | common | 294 |
preadv | 64 | 295 |
pwritev | 64 | 296 |
rt_tgsigqueueinfo | 64 | 297 |
perf_event_open | common | 298 |
recvmmsg | 64 | 299 |
fanotify_init | common | 300 |
fanotify_mark | common | 301 |
prlimit64 | common | 302 |
name_to_handle_at | common | 303 |
open_by_handle_at | common | 304 |
clock_adjtime | common | 305 |
syncfs | common | 306 |
sendmmsg | 64 | 307 |
setns | common | 308 |
getcpu | common | 309 |
process_vm_readv | 64 | 310 |
process_vm_writev | 64 | 311 |
kcmp | common | 312 |
finit_module | common | 313 |
sched_setattr | common | 314 |
sched_getattr | common | 315 |
renameat2 | common | 316 |
seccomp | common | 317 |
getrandom | common | 318 |
memfd_create | common | 319 |
kexec_file_load | common | 320 |
bpf | common | 321 |
execveat | 64 | 322 |
userfaultfd | common | 323 |
membarrier | common | 324 |
mlock2 | common | 325 |
copy_file_range | common | 326 |
preadv2 | 64 | 327 |
pwritev2 | 64 | 328 |
pkey_mprotect | common | 329 |
pkey_alloc | common | 330 |
pkey_free | common | 331 |
statx | common | 332 |
io_pgetevents | common | 333 |
rseq | common | 334 |
pidfd_send_signal | common | 424 |
io_uring_setup | common | 425 |
io_uring_enter | common | 426 |
io_uring_register | common | 427 |
open_tree | common | 428 |
move_mount | common | 429 |
fsopen | common | 430 |
fsconfig | common | 431 |
fsmount | common | 432 |
fspick | common | 433 |
pidfd_open | common | 434 |
clone3 | common | 435 |
close_range | common | 436 |
openat2 | common | 437 |
pidfd_getfd | common | 438 |
faccessat2 | common | 439 |
process_madvise | common | 440 |
epoll_pwait2 | common | 441 |
mount_setattr | common | 442 |
quotactl_fd | common | 443 |
landlock_create_ruleset | common | 444 |
landlock_add_rule | common | 445 |
landlock_restrict_self | common | 446 |
memfd_secret | common | 447 |
process_mrelease | common | 448 |
futex_waitv | common | 449 |
set_mempolicy_home_node | common | 450 |
rt_sigaction | x32 | 512 |
rt_sigreturn | x32 | 513 |
ioctl | x32 | 514 |
readv | x32 | 515 |
writev | x32 | 516 |
recvfrom | x32 | 517 |
sendmsg | x32 | 518 |
recvmsg | x32 | 519 |
execve | x32 | 520 |
ptrace | x32 | 521 |
rt_sigpending | x32 | 522 |
rt_sigtimedwait | x32 | 523 |
rt_sigqueueinfo | x32 | 524 |
sigaltstack | x32 | 525 |
timer_create | x32 | 526 |
mq_notify | x32 | 527 |
kexec_load | x32 | 528 |
waitid | x32 | 529 |
set_robust_list | x32 | 530 |
get_robust_list | x32 | 531 |
vmsplice | x32 | 532 |
move_pages | x32 | 533 |
preadv | x32 | 534 |
pwritev | x32 | 535 |
rt_tgsigqueueinfo | x32 | 536 |
recvmmsg | x32 | 537 |
sendmmsg | x32 | 538 |
process_vm_readv | x32 | 539 |
process_vm_writev | x32 | 540 |
setsockopt | x32 | 541 |
getsockopt | x32 | 542 |
io_setup | x32 | 543 |
io_submit | x32 | 544 |
execveat | x32 | 545 |
preadv2 | x32 | 546 |
pwritev2 | x32 | 547 |
BPF姿势
下面是一个BPF的模板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
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
/* ebpf用户态helper宏和函数
*
* 参数:
* 1. @cmd,表明bpf()执行的操作
* 2. @attr,表明此次执行的操作的参数
* 3. @size,即@attr union结构体的大小
*/
int bpf(int cmd, union bpf_attr *attr,
unsigned int size)
{
return syscall(SYS_bpf, cmd, attr, size);
}
/* bpf_create_map()创建一个新的map,并且返回该map对应的文件描述符
*
* 参数:
* 1. @map_type:即该map的类型,可以通过man bpf,搜索
* bpf_map_type \{关键词查看
* 2. @key_size: 即map的key元素的字节数
* 3. @value_size: 即map的value元素的字节数
* 4. @max_entries: 这个map所允许的最大映射数
*
* 返回值:
* @ret:返回相应的文件描述符
*/
int bpf_create_map(enum bpf_map_type map_type,
unsigned int key_size,
unsigned int value_size,
unsigned int max_entries)
{
union bpf_attr attr = {
.map_type = map_type,
.key_size = key_size,
.value_size = value_size,
.max_entries = max_entries
};
return bpf(BPF_MAP_CREATE, &attr, sizeof(attr));
}
/* bpf_lookup_elem()在fd对应的map中,查找key元素为@key的映射
* 的value值,并将映射的value值赋给@value
*
* 参数
* 1. @fd: 要查找的map对应的文件描述符
* 2. @key: 映射key元素的地址
* 3. @value:映射value元素的buf地址
*
* 返回值:
* @ret:成功找到元素,则返回@value元素的字节数
*/
int bpf_lookup_elem(int fd, const void *key, void *value)
{
union bpf_attr attr = {
.map_fd = fd,
.key = (__aligned_u64)key,
.value = (__aligned_u64)value,
};
return bpf(BPF_MAP_LOOKUP_ELEM, &attr, sizeof(attr));
}
/* bpf_update_elem()在fd对应的map中,创建/更新映射对
*
* 参数
* 1. @fd: 要查找的map对应的文件描述符
* 2. @key: 映射key元素的地址
* 3. @value:映射value元素的buf地址
* 4. @flags:用来设置此次操作的类型
* BPF_NOEXIST,表示仅仅在@key不存在时创建映射;
* BPF_EXIST,表示仅仅在@key存在是更新映射;
* BPF_ANY,表示如果存在,则更新,否则创建即可
*
* 返回值:
* @ret:成功更新或添加则返回0
*/
int bpf_update_elem(int fd, const void *key,
const void *value,
uint64_t flags)
{
union bpf_attr attr = {
.map_fd = fd,
.key = (__aligned_u64)key,
.value = (__aligned_u64)value,
.flags = flags,
};
return bpf(BPF_MAP_UPDATE_ELEM, &attr, sizeof(attr));
}
/* bpf_delete_elem()在fd对应的map中,查找key元素为@key的映射
* 并删除
*
* 参数
* 1. @fd: 要查找的map对应的文件描述符
* 2. @key: 映射key元素的地址
*
* 返回值
* @ret: 成功找到并删除返回0
*/
int bpf_delete_elem(int fd, const void *key)
{
union bpf_attr attr = {
.map_fd = fd,
.key = (__aligned_u64)key,
};
return bpf(BPF_MAP_DELETE_ELEM, &attr, sizeof(attr));
}
/* bpf_prog_load将ebpf程序载入内核中执行,并返回相关的文件描述符
*
* 参数:
* 1. @type:即bpf程序的类型,可以通过man bpf,搜索
* bpf_prog_type \{关键词查看
* 2. @insns: 即struct bpf_insn数组,一组指令组成一个
* bpf数组
* 3. @insn_cnt:即@insns数组的元素个数
*
* 返回值:
* @ret: ebpf程序关联的文件描述符
*/
int bpf_prog_load(enum bpf_prog_type type,
const struct bpf_insn *insns,
int insn_cnt)
{
int bpf_log_size = 0x1000, ret;
char *bpf_log;
assert((bpf_log = malloc(bpf_log_size)) != NULL);
union bpf_attr attr = {
.prog_type = type,
.insns = (__aligned_u64)insns,
.insn_cnt = insn_cnt,
.license = (__aligned_u64)"GPL",
.log_buf = (__aligned_u64)bpf_log,
.log_size = bpf_log_size,
.log_level = 2,
};
ret = bpf(BPF_PROG_LOAD, &attr, sizeof(attr));
printf("[bpf]\n%s\n", bpf_log);
fflush(stdout);
free(bpf_log);
assert(ret > 0);
return ret;
}
/* struct bpf_insn的wrapper宏,
* 参考自内核源代码中的kernel/samples/bpf/bpf_insn.h
* 其余相关的宏参考/usr/include/linux/bpf_common.h
*
* ebpf的指令集信息可参考
* https://docs.kernel.org/bpf/instruction-set.html
*
* R0: return value from function calls, and exit value for eBPF programs
* R1 - R5: arguments for function calls
* R6 - R9: callee saved registers that function calls will preserve
* R10: read-only frame pointer to access stack
*/
/* dst_reg OP= src_reg,
*
* OP包括如下候选
* BPF_ADD(+) BPF_SUB(-) BPF_MUL(*)
* BPF_DIV(/) BPF_OR(|) BPF_AND(&)
* BPF_LSH(<<) BPF_RSH(>>) BPF_NEG(~)
* BPF_MOD(%) BPF_XOR(^) BPF_MOV(=)
* ...,参考https://docs.kernel.org/bpf/instruction-set.html
*
* REG包括如下候选
* BPF_REG_0 BPF_REG_1 BPF_REG_2
* BPF_REG_3 BPF_REG_4 BPF_REG_5
* BPF_REG_6 BPF_REG_7 BPF_REG_8
* BPF_REG_9 BPF_REG_10
*/
/* dst_reg OP= imm32,
* OP包括如下候选
* BPF_ADD(+) BPF_SUB(-) BPF_MUL(*)
* BPF_DIV(/) BPF_OR(|) BPF_AND(&)
* BPF_LSH(<<) BPF_RSH(>>) BPF_NEG(~)
* BPF_MOD(%) BPF_XOR(^) BPF_MOV(=)
* ...,参考https://docs.kernel.org/bpf/instruction-set.html
*
* REG包括如下候选
* BPF_REG_0 BPF_REG_1 BPF_REG_2
* BPF_REG_3 BPF_REG_4 BPF_REG_5
* BPF_REG_6 BPF_REG_7 BPF_REG_8
* BPF_REG_9 BPF_REG_10
*/
/* *(dst_reg + off16) = imm32
* SIZE包括如下候选
* BPF_B(8-bit) BPF_H(16-bit)
* BPF_W(32-bit) BPF_DW(64-bit)
*
* REG包括如下候选
* BPF_REG_0 BPF_REG_1 BPF_REG_2
* BPF_REG_3 BPF_REG_4 BPF_REG_5
* BPF_REG_6 BPF_REG_7 BPF_REG_8
* BPF_REG_9 BPF_REG_10
*/
/* *(dst_reg + off16) = src_reg
* SIZE包括如下候选
* BPF_B(8-bit) BPF_H(16-bit)
* BPF_W(32-bit) BPF_DW(64-bit)
*
* REG包括如下候选
* BPF_REG_0 BPF_REG_1 BPF_REG_2
* BPF_REG_3 BPF_REG_4 BPF_REG_5
* BPF_REG_6 BPF_REG_7 BPF_REG_8
* BPF_REG_9 BPF_REG_10
*/
/* dst_reg = *(src_reg + off16)
* SIZE包括如下候选
* BPF_B(8-bit) BPF_H(16-bit)
* BPF_W(32-bit) BPF_DW(64-bit)
*
* REG包括如下候选
* BPF_REG_0 BPF_REG_1 BPF_REG_2
* BPF_REG_3 BPF_REG_4 BPF_REG_5
* BPF_REG_6 BPF_REG_7 BPF_REG_8
* BPF_REG_9 BPF_REG_10
*/
/* dst_reg = *(imm64)
* SIZE包括如下候选
* BPF_B(8-bit) BPF_H(16-bit)
* BPF_W(32-bit) BPF_DW(64-bit)
*
* REG包括如下候选
* BPF_REG_0 BPF_REG_1 BPF_REG_2
* BPF_REG_3 BPF_REG_4 BPF_REG_5
* BPF_REG_6 BPF_REG_7 BPF_REG_8
* BPF_REG_9 BPF_REG_10
*/
/* if (dst_reg OP src_reg) goto pc + off16
* OP包括如下候选
* BPF_JEQ(==) BPF_JGT(unsigned <)
* BPF_JGE(unsigned >=) BPF_JNE(!=)
* BPF_JLT(unsigned <) BPF_JLE(unsigned <=)
* BPF_CALL BPF_EXIT
* ...,参考https://docs.kernel.org/bpf/instruction-set.html
*
* REG包括如下候选
* BPF_REG_0 BPF_REG_1 BPF_REG_2
* BPF_REG_3 BPF_REG_4 BPF_REG_5
* BPF_REG_6 BPF_REG_7 BPF_REG_8
* BPF_REG_9 BPF_REG_10
*/
/* if (dst_reg OP imm32) goto pc + off16
* OP包括如下候选
* BPF_JEQ(==) BPF_JGT(unsigned <)
* BPF_JGE(unsigned >=) BPF_JNE(!=)
* BPF_JLT(unsigned <) BPF_JLE(unsigned <=)
* BPF_CALL(参考man bpf-helpers,调用)
* BPF_EXIT
* ...,参考https://docs.kernel.org/bpf/instruction-set.html
*
* REG包括如下候选
* BPF_REG_0 BPF_REG_1 BPF_REG_2
* BPF_REG_3 BPF_REG_4 BPF_REG_5
* BPF_REG_6 BPF_REG_7 BPF_REG_8
* BPF_REG_9 BPF_REG_10
*/
/* if (!(dst_reg OP src_reg)) exit
* OP包括如下候选
* BPF_JEQ(==) BPF_JGT(unsigned <)
* BPF_JGE(unsigned >=) BPF_JNE(!=)
* BPF_JLT(unsigned <) BPF_JLE(unsigned <=)
* BPF_CALL(参考man bpf-helpers,调用)
* BPF_EXIT
* ...,参考https://docs.kernel.org/bpf/instruction-set.html
*
* REG包括如下候选
* BPF_REG_0 BPF_REG_1 BPF_REG_2
* BPF_REG_3 BPF_REG_4 BPF_REG_5
* BPF_REG_6 BPF_REG_7 BPF_REG_8
* BPF_REG_9 BPF_REG_10
*/
/* if (!(dst_reg OP imm32)) exit
* OP包括如下候选
* BPF_JEQ(==) BPF_JGT(unsigned <)
* BPF_JGE(unsigned >=) BPF_JNE(!=)
* BPF_JLT(unsigned <) BPF_JLE(unsigned <=)
* BPF_CALL(参考man bpf-helpers,调用)
* BPF_EXIT
* ...,参考https://docs.kernel.org/bpf/instruction-set.html
*
* REG包括如下候选
* BPF_REG_0 BPF_REG_1 BPF_REG_2
* BPF_REG_3 BPF_REG_4 BPF_REG_5
* BPF_REG_6 BPF_REG_7 BPF_REG_8
* BPF_REG_9 BPF_REG_10
*/
/* bpf_prog_load()将bpf程序装载入内核中,然后trigger_bpf()
* 会将对应的bpf程序关联到对应事件的hook点,并产生相关事件,来
* 触发执行对应的bpf程序
*
* 参数:
* 1. @progfd:即bpf_prog_load()返回的关联bpf程序的文件描述符
*/
void trigger_bpf(int progfd)
{
int sockets[2];
char buf[0x80] = {0};
// 将bpf程序关联到该socket的PACKET FILTER事件
assert(socketpair(AF_UNIX, SOCK_DGRAM, 0, sockets) == 0);
assert(setsockopt(sockets[0], SOL_SOCKET, SO_ATTACH_BPF, &progfd, sizeof(progfd)) == 0);
// 向socket中写数据,从而触发PACKET FILTER事件,执行关联的bpf程序
assert(write(sockets[1], buf, sizeof(buf)) == sizeof(buf));
}
int main(void) {
int progfd;
struct bpf_insn insns[] = {
BPF_ALU64_IMM32(BPF_MOV, BPF_REG_0, 0x1737), /* r0 = 0x1737 */
BPF_ASSERT_IMM32(BPF_JEQ, BPF_REG_0, 0x1737), /* assert(r0 = 0x1737) */
BPF_ALU64_REG(BPF_MOV, BPF_REG_2, BPF_REG_0), /* r2 = r0 */
BPF_ASSERT_IMM32(BPF_JEQ, BPF_REG_2, 0x1737), /* assert(r2 = 0x1737) */
BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_2, -0x8), /* *(uint64_t*)(r10 - 0x8) = r2 */
BPF_LDX_MEM(BPF_B, BPF_REG_9, BPF_REG_10, -0x8), /* r9 = *(uint8_t*)(r10 - 0x8) */
BPF_ASSERT_IMM32(BPF_JEQ, BPF_REG_9, 0x37), /* assert(r9 = 0x37) */
BPF_EXIT_INSN(), /* exit */
};
progfd = bpf_prog_load(BPF_PROG_TYPE_SOCKET_FILTER, insns);
/* 创建一个socket,并发送数据包,从而触发bpf */
trigger_bpf(progfd);
return 0;
}
模板姿势
1 |
|
IDA
IDA是世界上顶级的交互式反汇编工具,往往使用IDA静态分析程序,从而理清程序中的代码组织结构,并统计相关资源信息
IDAPython
这是IDA的一个插件,允许IDA执行相关的python脚本信息。其中,该插件提供了大量的IDA接口,从而可以方便的获取程序的相关信息,我们将其整理成如下模板
1
2
3
4
5
6
7import ida_bytes
'''
获取虚拟地址处的1字节的值
返回的是整形
'''
val = ida_bytes.get_byte(address)