邪恶八进制信息安全团队技术讨论组's Archiver

gary.wing 2007-6-18 19:19

[原创]获取FreeBSD系统sysent的地址

文章作者: GaRY <wofeiwo_at_gmail_dot_com>
文章来源: [url=http://www.phpweblog.net/GaRY/archive/2007/06/18/get_syent_address_on_freebsd.html]GaRY&#39;s Blog[/url]

FreeBSD的sysent表的地址在内核中可以直接使用,是个全局变量.可以直接hook.
但是如果是ring3下Patch on fly呢?和linux一样,都是读取/dev/kmem或者/dev/mem
开始走了点弯路,以为和linux一样需要到内核函数代码中去查找,于是做了如下分析( 可见不google自以为是的坏处:( )
[hr][b]FreeBSD# uname -a[/b]
FreeBSD FreeBSD.0x1057 6.0-RELEASE FreeBSD 6.0-RELEASE #0: Thu Nov 3 09:36:13 UTC 2005  [color=#66cc00]//系统是6.0的FREEBSD[/color] [email]root@x64.samsco.home[/email]:/usr/obj/usr/src/sys/GENERIC i386
[b]FreeBSD# gdb -q /boot/kernel/kernel[/b]
(no debugging symbols found)...[b](gdb) p &sysent[/b]
$1 = (<data variable, no debug info> *) 0xc08bdf60 [color=#66cc00]//sysent地址[/color]
[b](gdb) q[/b]
[b]FreeBSD# objdump -d /boot/kernel/kernel | grep 0xc08bdf60[/b] [color=#66cc00]//查找sysent地址在内核中出现的位置[/color]
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)
[b]FreeBSD# gdb -q /boot/kernel/kernel[/b]
(no debugging symbols found)...(gdb) disass 0xc063ec40 [color=#66cc00]//反汇编此地址[/color]
Dump of assembler code for function syscall_register: [color=#66cc00]//在函数体syscall_register内[/color]
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 [color=#66cc00]//找到[/color]
0xc063ec50 <syscall_register+140>:   mov  %edx,(%esi)
---Type <return> to continue, or q <return> to quit---q
Quit
[b](gdb) x/xw (syscall_register+134)[/b]
0xc063ec4a <syscall_register+134>:   0xdf60908b [color=#66cc00]//字节码是这样的阿[/color]
[b](gdb) q[/b]
[b]FreeBSD#[/b][hr]
于是速度动手,写了个第一版本获取sysent地址的代码:
[language=c]
#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);
}[/language]

结果也如人所愿:
[hr][b]FreeBSD# gcc -o getsysent getsysent.c -lkvm[/b]
[b]FreeBSD# ./getsysent[/b]
sysent at 0xc08bdf60[hr]
到这里突然发现一个问题,如果能直接从/dev/mem获取syscall_register符号的地址,那么也就能直接获取sysent
[language=c]
#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);
}
[/language]
结果:
[hr][b]FreeBSD# gcc -o getsysent2 getsysent2.c -lkvm[/b]
[b]FreeBSD# ./getsysent2 sysent[/b]
sysent at 0xc08bdf60
[b]FreeBSD# ./getsysent2 syscall[/b]
syscall at 0xc0807c90[hr]
也成功了,看来在FreeBSD里使用kvm库对mem等操作果然方便很多:)

页: [1]
© 1999-2008 EvilOctal Security Team