Chinaunix首页 | 论坛 | 博客
  • 博客访问: 134904
  • 博文数量: 12
  • 博客积分: 550
  • 博客等级: 中士
  • 技术积分: 151
  • 用 户 组: 普通用户
  • 注册时间: 2010-09-14 12:19
文章分类

全部博文(12)

文章存档

2014年(2)

2012年(1)

2010年(9)

我的朋友

分类: LINUX

2014-08-15 16:38:30

1、背景
    在Ip_tables.c 中有一个函数static int get_info(struct net *net, void __user *user, int *len, int compat),现在想仔细的调试这个函数的内部细节,所以需要编写一个函数跟它一模一样的,来替换它,一遍我们可以随意打印和更改程序流程。这个函数并没有被导出。

2、准备模块的框架
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include

static __init int init_function_replace_sample(void)
{
printk(KERN_EMERG"init_function_replace_sample is called \n");

return 0;
}
module_init(init_function_replace_sample);


static __exit void cleanup_function_replace_sample(void)
{
printk(KERN_EMERG"cleanup_function_replace_sample is called \n");

}
module_exit(cleanup_function_replace_sample);
MODULE_LICENSE("GPL");

这个模块就可以直接编译运行了。

3、编辑一个new函数
    new函数准备来替换掉get_info(old函数),他们的函数签名除了名字不同,其他的都一样。
static int my_get_info(struct net *net, void __user *user, int *len, int compat)
{
return 0;
}


先让它什么都不干,等会家处理逻辑。

4、实现替换框架
static void hook(void)
{
u_char *buf;
long p;

buf = (u_char *)get_info;
p = (long)my_get_info - (long)get_info - (long)5;

//printk(KERN_EMERG"%d\n",p);

lock_kernel();
CLEAR_CR0
memcpy(tmp, buf, 5);   

buf[0] = 0xe9;
memcpy(buf + 1, &p, 4);

SET_CR0
unlock_kernel();
     
}
 
static  void unhook(void)
{
u_char *buf;
return;
lock_kernel();
CLEAR_CR0

buf = (u_char *)get_info;
memcpy(buf, tmp, 5);

SET_CR0
unlock_kernel();
}
红字部分是每调试一个函数必须要更改的地方,加了着重标记的就是需要替换的地方。my_get_info 是new函数,get_info 是old函数。

并且在init_function_replace_sample中添加hook,cleanup_function_replace_sample中添加unhook。如下所示
static __init int init_function_replace_sample(void)
{
printk(KERN_EMERG"init_function_replace_sample is called \n");
hook();
return 0;
}
module_init(init_function_replace_sample);


static __exit void cleanup_function_replace_sample(void)
{
printk(KERN_EMERG"cleanup_function_replace_sample is called \n");
unhook();
}
module_exit(cleanup_function_replace_sample);

5、编译
    在make以后会出现错误,提示get_info找不到,当然找不到。在sourceinsight中找到get_info的原型如下
static int get_info(struct net *net, void __user *user, int *len, int compat);
    错误信息
/root/kprobe/test_iptables/test_iptables.c:113: 错误:‘get_info’未声明(在此函数内第一次使用)
/root/kprobe/test_iptables/test_iptables.c:113: 错误:(即使在一个函数内多次出现,每个未声明的标识符在其
/root/kprobe/test_iptables/test_iptables.c:113: 错误:所在的函数内也只报告一次。)

处理方法:先在模块的源文件里面加上extern,让编译先通过再说。
extern int get_info(struct net *net, void __user *user, int *len, int compat);

再次make会出现
WARNING: "get_info" [/root/kprobe/test_iptables/tt.ko] undefined!
这时模块其实就已经生成了。

6、解决符号链接问题
执行
cat /proc/kallsyms | grep get_info
会出现
c067347f t acpi_battery_get_info
c06b6450 t uart_get_info
c07cb720 T tcp_get_info
c09f75cc r __ksymtab_tcp_get_info
c09fc9fc r __kcrctab_tcp_get_info
c0a12fde r __kstrtab_tcp_get_info
f7f0a000 t my_get_info  [tt]
f7e36220 t get_info     [ip_tables]
f7e44020 t list_version_get_info        [dm_mod]
红字部分就是我们想要替换的那个函数。有个问题,我第一次执行这个命令的时候,没有iptable的get_info函数显示。我执行一次iptanles -L以后,再次执行cat /proc/kallsyms | grep get_info才会有上面的结果。

编辑一个文件叫addr.dat,内容是
SECTIONS
{
per_cpu__current_kprobe = 0xc0b202c0;
kallsyms_lookup_name = 0xc04942b0;
get_info   = 0xf7e36220;
}
其中红字是我们需要的get_info的地址,其余两行则是我在调试中会用的,所以这里也都差出来先。

最后执行
ld -r -o ttt.ko tt.ko -R addrs.dat
将原来那个不完整的模块tt.ko,链接陈一个完整的ttt.ko。
这个ttt.ko就是我们可以调试的模块了。

7、开始调试

8、调试模块
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include

#define IPT_TABLE_MAXNAMELEN 32
#define AF_INET 2
#define NF_INET_NUMHOOKS 5
#define CLEAR_CR0    asm ("pushl %eax\n\t"             \
"movl %cr0, %eax\n\t"        \
"andl $0xfffeffff, %eax\n\t"     \
"movl %eax, %cr0\n\t"        \
"popl %eax");
 
#define SET_CR0        asm ("pushl %eax\n\t"             \
"movl %cr0, %eax\n\t"         \
"orl $0x00010000, %eax\n\t"     \
"movl %eax, %cr0\n\t"        \
"popl %eax");
 static  u_char tmp[5];

extern int get_info(struct net *net, void __user *user, int *len, int compat);
struct ipt_getinfo
{
char name[IPT_TABLE_MAXNAMELEN];
unsigned int valid_hooks;
unsigned int hook_entry[NF_INET_NUMHOOKS];
unsigned int underflow[NF_INET_NUMHOOKS];
unsigned int num_entries;
unsigned int size;
};

struct kprobe kp;

static int my_get_info(struct net *net, void __user *user, int *len, int compat)
{

char name[IPT_TABLE_MAXNAMELEN];
struct xt_table *t;
int ret;

printk(KERN_EMERG "my_get_info is called \n");

if (*len != sizeof(struct ipt_getinfo)) {
printk(KERN_EMERG "length %u != %zu\n", *len,
 sizeof(struct ipt_getinfo));
return -EINVAL;
}

printk(KERN_EMERG "msglen=%d \n",*len);
return 0;

if (copy_from_user(name, user, sizeof(name)) != 0)
return -EFAULT;

name[IPT_TABLE_MAXNAMELEN-1] = '\0';
printk(KERN_EMERG "name=%s \n",name);

t = try_then_request_module(xt_find_table_lock(net, AF_INET, name),"iptable_%s", name);
if (t && !IS_ERR(t)) {
struct ipt_getinfo info;
const struct xt_table_info *private = t->private;

info.valid_hooks = t->valid_hooks;
memcpy(info.hook_entry, private->hook_entry,
       sizeof(info.hook_entry));
memcpy(info.underflow, private->underflow,
       sizeof(info.underflow));
info.num_entries = private->number;
info.size = private->size;
strcpy(info.name, name);

if (copy_to_user(user, &info, *len) != 0)
ret = -EFAULT;
else
ret = 0;

xt_table_unlock(t);
module_put(t->me);
} else
ret = t ? PTR_ERR(t) : -ENOENT;
return ret;
}

/*
//恢复函数
unhook();
//调用原函数
ret = gate_info(net,*user, len, compat );
//恢复hook
hook();
*/


static void hook(void)
{
u_char *buf;
long p;

buf = (u_char *)get_info;
p = (long)my_get_info - (long)get_info - (long)5;

//printk(KERN_EMERG"%d\n",p);

lock_kernel();
CLEAR_CR0
memcpy(tmp, buf, 5);   

buf[0] = 0xe9;
memcpy(buf + 1, &p, 4);

SET_CR0
unlock_kernel();
     
}
 
static  void unhook(void)
{
u_char *buf;
return;
lock_kernel();
CLEAR_CR0

buf = (u_char *)gate_info;
memcpy(buf, tmp, 5);

SET_CR0
unlock_kernel();
}



static __init int init_function_replace_sample(void)
{
printk(KERN_EMERG"init_function_replace_sample is called \n");
hook();
return 0;
}
module_init(init_function_replace_sample);


static __exit void cleanup_function_replace_sample(void)
{
printk(KERN_EMERG"cleanup_function_replace_sample is called \n");
unhook();
}
module_exit(cleanup_function_replace_sample);
MODULE_LICENSE("GPL");






阅读(2367) | 评论(0) | 转发(0) |
0

上一篇:通过oops判断模块故障--武汉地铁项目

下一篇:没有了

给主人留下些什么吧!~~