第一种是借助于kprobe机制,通过kprobe机制中会调用kallsyms_lookup_name函数并设置到kprobe结构体中返回的原理找到我们需要的函数地址
内核中调用逻辑简化代码如下:
如上逻辑可以看到其实就是调用的kallsyms_lookup_name函数来获取地址存到我们的addr中
第二种方式是借助于内核调试器提供的能力间接调用kallsyms_lookup_name函数获取地址
在内核中有这样一个函数并且这个函数是导出的
int
register_kprobe(
struct
kprobe *p)
{
int
ret;
struct
kprobe *old_p;
struct
module *probed_mod;
kprobe_opcode_t *addr;
addr = kprobe_addr(p);
if
(IS_ERR(addr))
return
PTR_ERR(addr);
p->addr = addr;
。。。。。。
}
static
kprobe_opcode_t *kprobe_addr(
struct
kprobe *p)
{
return
_kprobe_addr(p->addr, p->symbol_name, p->offset);
}
static
kprobe_opcode_t *_kprobe_addr(kprobe_opcode_t *addr,
const
char
*symbol_name, unsigned
int
offset)
{
if
((symbol_name && addr) || (!symbol_name && !addr))
goto
invalid;
if
(symbol_name) {
addr = kprobe_lookup_name(symbol_name, offset);
if
(!addr)
return
ERR_PTR(-ENOENT);
}
。。。。。
}
kprobe_opcode_t * __weak kprobe_lookup_name(
const
char
*name,
unsigned
int
__unused)
{
return
((kprobe_opcode_t *)(kallsyms_lookup_name(name)));
}
int
register_kprobe(
struct
kprobe *p)
{
int
ret;
struct
kprobe *old_p;
struct
module *probed_mod;
kprobe_opcode_t *addr;
addr = kprobe_addr(p);
if
(IS_ERR(addr))
return
PTR_ERR(addr);
p->addr = addr;
。。。。。。
}
static
kprobe_opcode_t *kprobe_addr(
struct
kprobe *p)
{
return
_kprobe_addr(p->addr, p->symbol_name, p->offset);
}
static
kprobe_opcode_t *_kprobe_addr(kprobe_opcode_t *addr,
const
char
*symbol_name, unsigned
int
offset)
{
if
((symbol_name && addr) || (!symbol_name && !addr))
goto
invalid;
if
(symbol_name) {
addr = kprobe_lookup_name(symbol_name, offset);
if
(!addr)
return
ERR_PTR(-ENOENT);
}
。。。。。
}
kprobe_opcode_t * __weak kprobe_lookup_name(
const
char
*name,
unsigned
int
__unused)
{
return
((kprobe_opcode_t *)(kallsyms_lookup_name(name)));
}
extern
int
kdbgetsymval(
const
char
*, kdb_symtab_t *);
int
kdbgetsymval(
const
char
*symname, kdb_symtab_t *symtab)
{
if
(KDB_DEBUG(AR))
kdb_printf(
"kdbgetsymval: symname=%s, symtab=%px\n"
, symname,
symtab);
memset
(symtab, 0,
sizeof
(*symtab));
symtab->sym_start = kallsyms_lookup_name(symname);
if
(symtab->sym_start) {
if
(KDB_DEBUG(AR))
kdb_printf(
"kdbgetsymval: returns 1, "
"symtab->sym_start=0x%lx\n"
,
symtab->sym_start);
return
1;
}
if
(KDB_DEBUG(AR))
kdb_printf(
"kdbgetsymval: returns 0\n"
);
return
0;
}
EXPORT_SYMBOL(kdbgetsymval);
extern
int
kdbgetsymval(
const
char
*, kdb_symtab_t *);
int
kdbgetsymval(
const
char
*symname, kdb_symtab_t *symtab)
{
if
(KDB_DEBUG(AR))
kdb_printf(
"kdbgetsymval: symname=%s, symtab=%px\n"
, symname,
symtab);
memset
(symtab, 0,
sizeof
(*symtab));
symtab->sym_start = kallsyms_lookup_name(symname);
if
(symtab->sym_start) {
if
(KDB_DEBUG(AR))
kdb_printf(
"kdbgetsymval: returns 1, "
"symtab->sym_start=0x%lx\n"
,
symtab->sym_start);
return
1;
}
if
(KDB_DEBUG(AR))
kdb_printf(
"kdbgetsymval: returns 0\n"
);
return
0;
}
EXPORT_SYMBOL(kdbgetsymval);
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kallsyms.h>
#include <linux/kprobes.h>
#include <linux/cdev.h>
MODULE_LICENSE(
"GPL"
);
MODULE_AUTHOR(
"ch"
);
typedef
struct
__ksymtab {
unsigned
long
value;
const
char
*mod_name;
unsigned
long
mod_start;
unsigned
long
mod_end;
const
char
*sec_name;
unsigned
long
sec_start;
unsigned
long
sec_end;
const
char
*sym_name;
unsigned
long
sym_start;
unsigned
long
sym_end;
} kdb_symtab_t;
extern
int
kdbgetsymval(
const
char
*, kdb_symtab_t *);
struct
char_device_struct {
struct
char_device_struct *next;
unsigned
int
major;
unsigned
int
baseminor;
int
minorct;
char
name[64];
struct
cdev *cdev;
};
int
noop_pre(
struct
kprobe* p,
struct
pt_regs* regs) {
return
0;}
static
struct
kprobe kp = {
.symbol_name =
"kallsyms_lookup_name"
,
};
unsigned
long
(*kallsyms_lookup_name_func)(
const
char
* name) = NULL;
static
int
__init m_init(
void
) {
kp.pre_handler = noop_pre;
int
ret = register_kprobe(&kp);
if
(ret != 0) {
printk(
"find failed\n"
);
return
ret;
}
kallsyms_lookup_name_func = (
void
*)kp.addr;
printk(
"lookup func addr is %p\n"
, kp.addr);
unregister_kprobe(&kp);
unsigned
long
chrdevs_addr = kallsyms_lookup_name_func(
"chrdevs"
);
printk(
"chardevs addr is 0x%p\n"
, chrdevs_addr);
kdb_symtab_t val;
kdbgetsymval(
"chrdevs"
, &val);
printk(
"second method get chrdevs addr is 0x%p\n"
, val.sym_start);
return
0;
}
static
void
__exit m_exit(
void
) {
}
module_init(m_init);
module_exit(m_exit);
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课