方式一:通过objdump -t
直接从目标文件中获取函数size
#objdump -t file_unread.o | grep hook
0000000000000030 l F .text 000000000000012f hook_vfs_read
0000000000000030 l F .text 000000000000012f hook_vfs_read
各个字段说明
vfs_read+0xe6/0x2c0
表示什么意思呢?
其中vfs_read
是函数名,+0xe6/0x2c0
是函数在代码中的偏移量。具体来说,+0xe6
表示函数内部代码的偏移量,/
后面的 0x2c0
表示函数的总大小(以字节为单位)。
hook_vfs_read+0xe4/0x130 [fi_file]
为动态打印进程调用栈信息。
方式二:通过objdump -D
反汇编后计算函数size
用objdump
对目标文件进行反汇编,从汇编代码中计算hook_vfs_read
的函数size
0000000000000030 <hook_vfs_read>:
30: e8 00 00 00 00 callq 35 <hook_vfs_read+0x5>
35: 41 57 push %r15
37: 41 56 push %r14
39: 31 c0 xor %eax,%eax
......
14f: eb c3 jmp 114 <hook_vfs_read+0xe4>
151: 48 c7 c7 00 00 00 00 mov $0x0,%rdi
158: e8 00 00 00 00 callq 15d <hook_vfs_read+0x12d>
15d: eb a3 jmp 102 <hook_vfs_read+0xd2>
15f: 90 nop
hook_vfs_read_size = 0x15f - 0x30 = 0x12f + 1
,从计算的结果来看,加上偏移与调用栈打印的函数size
是一致的。
-t, --syms Display the contents of the symbol table(s)
-D, --disassemble-all Display assembler contents of all sections
方式三:通过内核函数动态获取函数size
/**
* sprint_symbol - Look up a kernel symbol and return it in a text buffer
* @buffer: buffer to be stored
* @address: address to lookup
*
* This function looks up a kernel symbol with @address and stores its name,
* offset, size and module name to @buffer if possible. If no symbol was found,
* just saves its @address as is.
*
* This function returns the number of bytes stored in @buffer.
*/
int sprint_symbol(char *buffer, unsigned long address)
{
return __sprint_symbol(buffer, address, 0, 1);
}
EXPORT_SYMBOL_GPL(sprint_symbol);
路径1:
获取到的字符串信息示例为hook_vfs_read+0x0/0x130 [fi_file]
,这种方式需要从数组str
中解析出函数大小0x130
解析字符串中的函数size
,还是要骚操作获取,在内核中没有看到直接获取函数size
的函数。
#include
static int __init my_init(void)
{
const char *str = "hook_vfs_read+0x0/0x130 [fi_file]";
const char *prefix = "/0x";
const char *suffix = " [";
char *start, *end;
unsigned long value;
// 查找前缀字符串
start = strstr(str, prefix);
if (!start) {
printk(KERN_ERR "Failed to find prefix string\n");
return -EINVAL;
}
start += strlen(prefix);
// 查找后缀字符串
end = strstr(start, suffix);
if (!end) {
printk(KERN_ERR "Failed to find suffix string\n");
return -EINVAL;
}
// 截取字符串
*end = '\0';
value = simple_strtoul(start, NULL, 16);
printk(KERN_INFO "Value: 0x%lx\n", value);
return 0;
}
路径二:
内核代码v4.18.20
中sprint_symbol
最终调用kallsyms_lookup
返回函数size
,因此也可以直接调用该函数获取函数size
。
/*
* Lookup an address
* - modname is set to NULL if it's in the kernel.
* - We guarantee that the returned name is valid until we reschedule even if.
* It resides in a module.
* - We also guarantee that modname will be valid until rescheduled.
*/
const char *kallsyms_lookup(unsigned long addr,
unsigned long *symbolsize,
unsigned long *offset,
char **modname, char *namebuf)
{
const char *ret;
namebuf[KSYM_NAME_LEN - 1] = 0;
namebuf[0] = 0;
if (is_ksym_addr(addr)) {
unsigned long pos;
pos = get_symbol_pos(addr, symbolsize, offset);
/* Grab name */
kallsyms_expand_symbol(get_symbol_offset(pos),
namebuf, KSYM_NAME_LEN);
if (modname)
*modname = NULL;
return namebuf;
}
/* See if it's in a module or a BPF JITed image. */
ret = module_address_lookup(addr, symbolsize, offset,
modname, namebuf);
if (!ret)
ret = bpf_address_lookup(addr, symbolsize,
offset, modname, namebuf);
if (!ret)
ret = ftrace_mod_address_lookup(addr, symbolsize,
offset, modname, namebuf);
return ret;
}