编写Linux crash工具插件扩展crash命令(转载)

tech2025-11-17  1

当前时间,周五晚10点45分左右。

我的需求是用crash工具dump出Netfilter的某个hook点所有hook所属模块的名字。

我的方法如下,首先找到模块地址:

crash px nf_hooks[2][0] =>var crash list nf_hook_ops.list -s nf_hook_ops.owner -H $var |awk -F ‘=’ ‘/owner/{print $2}’ 1 2 如此会得到一个列表,比如:

0x1234 0x6678 0x8641 0x4570 …

显然,这些地址都是module结构体,我需要执行下面的命令得到其name字段:

crash module.name $addr_above 1 然而,我必须一个一个输入,或者使用文件redirect:

crash list nf_hook_ops.list -s nf_hook_ops.owner -H $var |awk -F ‘=’ ‘/owner/{print $2}’ >./aa crash module.name <./aa 1 2 这太麻烦了。

我想知道能不能在crash命令行编写脚本或者使用类似xargs,awk BEGIN,END之类的,比如使用下面这种:

crash list nf_hook_ops.list -s nf_hook_ops.owner -H $var |awk -F ‘=’ ‘/owner/{print $2}’ | xargs -i module.name {} 1 从而一次性获得所有结果,免除手工输入的麻烦。

我试了,crash命令没有办法被管道化。

经过询问,了解到crash有一个extend命令可以加载extension扩展插件,研究了一下,比较简单且有意义。

说白了就是基于crash的API写一个共享库,在crash命令行输入help extend将会显示这样的共享库如何来编码。我基于上述需求简单写了一个,可以用:

// nfhooks.c #include <crash/defs.h>

static int get_field(unsigned long addr, char *name, char field, void buf) { unsigned long off = MEMBER_OFFSET(name, field);

if (!readmem(addr + off, KVADDR, buf, MEMBER_SIZE(name, field), name, FAULT_ON_ERROR)) return 0; return 1;

}

void do_cmd(void) { unsigned long ops_addr, owner_addr; unsigned long list_addr, base, next; char name[64];

optind++; base = next = list_addr = htol(args[optind], FAULT_ON_ERROR, NULL); do { // 由于list就是nf_hook_ops的第一个字段,因此就不炫技了,强转即可。 //get_field(list_addr - MEMBER_OFFSET("nf_hook_ops", "list"), "list_head", "next", &ops_addr); ops_addr = list_addr = next; get_field(ops_addr, "nf_hook_ops", "owner", &owner_addr); get_field(owner_addr, "module", "name", &name[0]); if (list_addr != base) fprintf(fp, "--%s\n", name); } while(get_field(list_addr, "list_head", "next", &next) && next != base);

}

static struct command_table_entry command_table[] = { { “nfhooks”, do_cmd, NULL, 0}, { NULL }, };

void attribute((constructor)) nfhooks_init(void) { register_extension(command_table); }

void attribute((destructor)) nfhooks_fini(void) { }

编译命令如下:

gcc -fPIC -shared nfhooks.c -o nfhooks.so 1 将生成的so放在执行crash命令的目录下,在crash命令行加载之:

crash> extend nfhooks.so ./nfhooks.so: shared object loaded 1 2 随后就可以用了:

首先dump出INET IPv4的PREROUTING点的list地址

crash> px &nf_hooks[2][0] $1 = (struct list_head *) 0xffffffff81a71000 <nf_hooks+256> crash> nfhooks 0xffffffff81a71000 –bridge –nf_defrag_ipv4 –iptable_raw –nf_conntrack_ipv4 –iptable_mangle –iptable_nat crash>

是不是很有意思呢。

有了这个机制,就可以非常方便地使用readmem来进行Linux内核任意地址任意结构体字段的解析了,你就再也不用抱怨crash命令不够用了,不够用就自己写一个,而自己的写一个的成本非常低,无非就是readmem不断解析结构体,这一切的背后,只需要你对内核足够熟悉即可。

我之前写过一个手工解析/dev/mem或者vmcore的程序,但和crash插件扩展相比,太low太麻烦了,有了这个机制,以后再也不用干手工活儿了。

将上面的代码稍微扩展一下,就可以dump出所有协议族,所有hook点的所有模块名字了:

#include <crash/defs.h>

static int get_field(unsigned long addr, char *name, char field, void buf) { unsigned long off = MEMBER_OFFSET(name, field);

if (!readmem(addr + off, KVADDR, buf, MEMBER_SIZE(name, field), name, FAULT_ON_ERROR)) return 0; return 1;

}

#define FAMILY 12 #define TYPE 8

struct dummy_list { struct dummy_list *next, *prev; };

struct dummy_list *iter; void do_cmd(void) { unsigned long ops_addr, owner_addr; unsigned long list_addr, base, next; char name[64]; int i, j;

optind++; iter = (struct dummy_list *)htol(args[optind], FAULT_ON_ERROR, NULL); for (i = 0; i < FAMILY; i++) { for (j = 0; j < TYPE; j++) { fprintf(fp, "at PF: %d hooknum: %d \n", i, j); base = next = list_addr = (unsigned long)&iter[i*TYPE + j]; do { ops_addr = list_addr = next; get_field(ops_addr, "nf_hook_ops", "owner", &owner_addr); get_field(owner_addr, "module", "name", &name[0]); if (list_addr != base) fprintf(fp, " ----%s\n", name); } while(get_field(list_addr, "list_head", "next", &next) && next != base); } }

}

static struct command_table_entry command_table[] = { { “allnfhooks”, do_cmd, NULL, 0}, { NULL }, };

void attribute((constructor)) nfhooks_init(void) { register_extension(command_table); }

void attribute((destructor)) nfhooks_fini(void) { }

是不是很简单呢?我从来不记录复杂的东西,简单的才是真美。

当前时间,周五晚10点45分左右。已经不在996的管辖范围,请继续举报!

浙江温州皮鞋湿,下雨进水不会胖。

原文链接:https://blog.csdn.net/dog250/article/details/107997905?utm_medium=distribute.pc_feed.none-task-blog-personrec_tag-10.nonecase&depth_1-utm_source=distribute.pc_feed.none-task-blog-personrec_tag-10.nonecase&request_id=5f43950d0388ae0b5643c567

最新回复(0)