GaRY's Blog

Beginning is always beautiful

Get Sysent Address On FreeBSD

FreeBSD的sysent表的地址在内核中可以直接使用,是个全局变量.可以直接hook.
但是如果是ring3下Patch on fly呢?和linux一样,都是读取/dev/kmem或者/dev/mem
开始走了点弯路,以为和linux一样需要到内核函数代码中去查找,于是做了如下分析( 可见不google自以为是的坏处:( )

FreeBSD# uname -a
FreeBSD FreeBSD.0x1057 6.0-RELEASE FreeBSD 6.0-RELEASE #0: Thu Nov  3 09:36:13 UTC 2005    //系统是6.0的FREEBSD root@x64.samsco.home:/usr/obj/usr/src/sys/GENERIC  i386
FreeBSD# gdb -q /boot/kernel/kernel
(no debugging symbols found)...(gdb) p &sysent
$1 = (<data variable, no debug info> *) 0xc08bdf60 //sysent地址
(gdb) q
FreeBSD# objdump -d /boot/kernel/kernel | grep 0xc08bdf60 //查找sysent地址在内核中出现的位置
c063ec4a:       8b 90 60 df 8b c0       mov    0xc08bdf60(%eax),%edx
c063ec6e:       89 90 60 df 8b c0       mov    %edx,0xc08bdf60(%eax)
c063ecac:       89 90 60 df 8b c0       mov    %edx,0xc08bdf60(%eax)
FreeBSD# gdb -q /boot/kernel/kernel
(no debugging symbols found)...(gdb) disass 0xc063ec40 //反汇编此地址
Dump of assembler code for function syscall_register: //在函数体syscall_register内
0xc063ebc4 <syscall_register+0>:        push   %ebp
0xc063ebc5 <syscall_register+1>:        mov    %esp,%ebp
0xc063ebc7 <syscall_register+3>:        push   %edi
0xc063ebc8 <syscall_register+4>:        push   %esi
.....
.....
0xc063ec36 <syscall_register+114>:      cmpl   $0xc063ebb4,0xc08bdf64(%eax)
0xc063ec40 <syscall_register+124>:      jne    0xc063ec8b <syscall_register+199>
0xc063ec42 <syscall_register+126>:      mov    (%ebx),%eax
0xc063ec44 <syscall_register+128>:      lea    (%eax,%eax,2),%eax
0xc063ec47 <syscall_register+131>:      shl    $0x2,%eax
0xc063ec4a <syscall_register+134>:      mov    0xc08bdf60(%eax),%edx  //找到
0xc063ec50 <syscall_register+140>:      mov    %edx,(%esi)
---Type <return> to continue, or q <return> to quit---q
Quit
(gdb) x/xw (syscall_register+134)
0xc063ec4a <syscall_register+134>:      0xdf60908b //字节码是这样的阿
(gdb) q
FreeBSD#

于是速度动手,写了个第一版本获取sysent地址的代码:

#include <fcntl.h>
#
include <kvm.h>
#
include <limits.h>
#
include <nlist.h>
#
include <stdio.h>
#
include <sys/types.h>

#define SIZE    0x100 // 搜索0x100个字节

int
main(int argc
, char *argv[])
{
    char errbuf[_POSIX2_LINE_MAX]
, *p;
    kvm_t 
*kd;
    struct nlist nl[] 
= { {NULL}, {NULL}, };
    unsigned char syscall_register_code[SIZE]; 
// 保存原始函数字节码
    unsigned sct;

    kd 
= kvm_openfiles(NULL, NULL, NULL, O_RDWR, errbuf);// 打开/dev/mem
    if (kd == NULL) {
        
fprintf(stderr, "ERROR: %s\n", errbuf);
        
exit(-1);
    }

    nl[
0].n_name = "syscall_register";

    
if (kvm_nlist(kd, nl) < 0) { // 查找syscall_register
        fprintf(stderr, "ERROR: %s\n", kvm_geterr(kd));
        
exit(-1);
    }

    
if (!nl[0].n_value) {
        
fprintf(stderr, "ERROR: Symbol %s not found\n", nl[0].n_name);
        
exit(-1);
    }

    
if (kvm_read(kd, nl[0].n_value, syscall_register_code, SIZE) < 0) { // 保存字节码
        fprintf(stderr, "ERROR: %s\n", kvm_geterr(kd));
        
exit(-1);
    }

    p 
= (char *) memmem(syscall_register_code, SIZE, "\x8b\x90", 2); // 查找 mov    0xc08bdf60(%eax),%edx
    sct = *(unsigned*)(p+2);

    
printf ("sysent at 0x%x\n", sct);

    
if (kvm_close(kd) < 0) {
        
fprintf(stderr, "ERROR: %s\n", kvm_geterr(kd));
        
exit(-1);
    }

    
exit(0);
}

结果也如人所愿:

FreeBSD# gcc -o getsysent getsysent.c -lkvm
FreeBSD# ./getsysent
sysent at 0xc08bdf60

到这里突然发现一个问题,如果能直接从/dev/mem获取syscall_register符号的地址,那么也就能直接获取sysent

#include <fcntl.h>
#
include <kvm.h>
#
include <limits.h>
#
include <nlist.h>
#
include <stdio.h>
#
include <sys/types.h>

int
main(int argc
, char *argv[])
{
    char errbuf[_POSIX2_LINE_MAX];
    kvm_t 
*kd;
    struct nlist nl[] 
= { {NULL}, {NULL}, };

    if(argc != 2) return 0;

    kd 
= kvm_openfiles(NULL, NULL, NULL, O_RDWR, errbuf);// 打开/dev/mem
    if (kd == NULL) {
        
fprintf(stderr, "ERROR: %s\n", errbuf);
        
exit(-1);
    }

    nl[
0].n_name = argv[1];

    
if (kvm_nlist(kd, nl) < 0) {
        fprintf(stderr, "ERROR: %s\n", kvm_geterr(kd));
        
exit(-1);
    }

    
if (!nl[0].n_value) {
        
fprintf(stderr, "ERROR: Symbol %s not found\n", nl[0].n_name);
        
exit(-1);
    }

    
printf ("%s at 0x%x\n", nl[0].n_name, nl[0].n_value);

    
if (kvm_close(kd) < 0) {
        
fprintf(stderr, "ERROR: %s\n", kvm_geterr(kd));
        
exit(-1);
    }

    
exit(0);
}

结果:

FreeBSD# gcc -o getsysent2 getsysent2.c -lkvm
FreeBSD# ./getsysent2 sysent
sysent at 0xc08bdf60
FreeBSD# ./getsysent2 syscall
syscall at 0xc0807c90


也成功了,看来在FreeBSD里使用kvm库对mem等操作果然方便很多:)


posted on 2007-06-18 19:09 wofeiwo 阅读(756) 评论(0)  编辑 收藏 引用 网摘 所属分类: SystemPrograming

导航

<2024年3月>
252627282912
3456789
10111213141516
17181920212223
24252627282930
31123456

统计

留言簿(10)

随笔分类(90)

随笔档案(61)

搜索

最新随笔

最新评论