一步一步走进Linux HOOK API

最近我查阅很多参考资料.发现对于讲述Linux HOOK API的资料是很少,让我们这些新人难以去走进Linux HOOK大门.在这里我将全面的讲述Linux HOOK API的全部实现过程,这个过程中我也遇到很多坎坷,所以在这么写下这份教程.让大家都来进入HOOK的神秘世界.

不要认为HOOK API是windows的专利(PS.其实我以前就是这么认为的.哈哈....),其实在Linux中也有HOOK API这样的技术,只是实现起来相对比较麻烦,首先今天主要带大家认识的是ELF文件,在Linux中,ELF文件主要是应用在可执行文件,重定位文件,可执行文件动态连接库。首先来看一下ELF Head的定义:

PS.我们这里主要针对的是32位平台.有关64位平台相关定义请参阅/usr/include/elf.h

  1. #define EI_NIDENT (16)   
  2.   
  3.   
  4. typedef struct  
  5.   
  6. {  
  7.   
  8.   unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */  
  9.   
  10.   Elf32_Half e_type; /* Object file type */  
  11.   
  12.   Elf32_Half e_machine; /* Architecture */  
  13.   
  14.   Elf32_Word e_version; /* Object file version */  
  15.   
  16.   Elf32_Addr e_entry; /* Entry point virtual address */  
  17.   
  18.   Elf32_Off e_phoff; /* Program header table file offset */  
  19.   
  20.   Elf32_Off e_shoff; /* Section header table file offset */  
  21.   
  22.   Elf32_Word e_flags; /* Processor-specific flags */  
  23.   
  24.   Elf32_Half e_ehsize; /* ELF header size in bytes */  
  25.   
  26.   Elf32_Half e_phentsize; /* Program header table entry size */  
  27.   
  28.   Elf32_Half e_phnum; /* Program header table entry count */  
  29.   
  30.   Elf32_Half e_shentsize; /* Section header table entry size */  
  31.   
  32.   Elf32_Half e_shnum; /* Section header table entry count */  
  33.   
  34.   Elf32_Half e_shstrndx; /* Section header string table index */  
  35.   
  36. } Elf32_Ehdr;  

e_ident: 这个成员,ELF文件的第一个成员,该成员是个数字,根据上面的宏可以看出,这个程序是个16字节的数据.该成员的前4个字节依次是 0x7F,0x45,0x4c,0x46,也 就是"\177ELF"。这是ELF文件的标志,任何一个ELF文件这四个字节都完全相同。

为了让我们更方便的使用ELF数据在elf.h中对上述数据进行了宏定义.如下:

  1. #define EI_MAG0 0 /* File identification byte 0 index */   
  2.   
  3. #define ELFMAG0 0x7f /* Magic number byte 0 *   
  4.   
  5. #define EI_MAG1 1 /* File identification byte 1 index */   
  6.   
  7. #define ELFMAG1 'E' /* Magic number byte 1 */   
  8.   
  9. #define EI_MAG2 2 /* File identification byte 2 index */   
  10.   
  11. #define ELFMAG2 'L' /* Magic number byte 2 */   
  12.   
  13. #define EI_MAG3 3 /* File identification byte 3 index */   
  14.   
  15. #define ELFMAG3 'F' /* Magic number byte 3 */   
  16.   
  17. /* Conglomeration of the identification bytes, for easy testing as a word.  */  
  18.   
  19. #define ELFMAG "\177ELF"   
  20.   
  21. #define SELFMAG 4  

第四个字节表示ELF格式,1:322:64

  1. #define EI_CLASS 4 /* File class byte index */   
  2.   
  3. #define ELFCLASSNONE 0 /* Invalid class */   
  4.   
  5. #define ELFCLASS32 1 /* 32-bit objects */   
  6.   
  7. #define ELFCLASS64 2 /* 64-bit objects */   
  8.   
  9. #define ELFCLASSNUM 3  

第五个字节表示数据编码格式,1:小端模式 2:大端模式

  1. #define EI_DATA 5 /* Data encoding byte index */   
  2.   
  3. #define ELFDATANONE 0 /* Invalid data encoding */   
  4.   
  5. #define ELFDATA2LSB 1 /* 2's complement, little endian */   
  6.   
  7. #define ELFDATA2MSB 2 /* 2's complement, big endian */   
  8.   
  9. #define ELFDATANUM 3  

第六个字节表示文件版本,该值目前必须为1

  1. #define EV_CURRENT 1 /* Current version */  

第七个字节表示操作系统标识:

  1. #define EI_OSABI 7 /* OS ABI identification */   
  2.   
  3. #define ELFOSABI_NONE 0 /* UNIX System V ABI */   
  4.   
  5. #define ELFOSABI_SYSV 0 /* Alias.  */   
  6.   
  7. #define ELFOSABI_HPUX 1 /* HP-UX */   
  8.   
  9. #define ELFOSABI_NETBSD 2 /* NetBSD.  */   
  10.   
  11. #define ELFOSABI_LINUX 3 /* Linux.  */   
  12.   
  13. #define ELFOSABI_SOLARIS 6 /* Sun Solaris.  */   
  14.   
  15. #define ELFOSABI_AIX 7 /* IBM AIX.  */   
  16.   
  17. #define ELFOSABI_IRIX 8 /* SGI Irix.  */   
  18.   
  19. #define ELFOSABI_FREEBSD 9 /* FreeBSD.  */   
  20.   
  21. #define ELFOSABI_TRU64 10 /* Compaq TRU64 UNIX.  */   
  22.   
  23. #define ELFOSABI_MODESTO 11 /* Novell Modesto.  */   
  24.   
  25. #define ELFOSABI_OPENBSD 12 /* OpenBSD.  */   
  26.   
  27. #define ELFOSABI_ARM 97 /* ARM */   
  28.   
  29. #define ELFOSABI_STANDALONE 255    
  30.   
  31. /*Standalone(embedded) application */  

第八个字节表示ABI版本

  1. #define EI_ABIVERSION 8 /* ABI version */  

第九个字节表示e_ident中从哪开始之后未使用.

  1. #define EI_PAD 9 /* Byte index of padding bytes */  

e_type:          这个成员是ELF文件的类型:

                         1:表示此文件是重定位文件.

                         2:表示可执行文件.

                         3:表示此文件是一个动态连接库。


e_machine:       这个成员表示机器版本.具体定义参与elf.h (篇幅问题,太长了)

e_version:          这个成员表示ELF文件版本,为 1

e_entry:              这个成员表示可执行文件的入口虚拟地址。此字段指出了该文件中第一条可执 行机器指令在进程被正确加载后的内存地址!ELF可执行文件只能被加载到固定位 置.

e_phoff:             这个成员表示程序头(Program Headers)在ELF文件中的偏移量。如果程序头 不存在此值为0

e_shoff:             这个成员表示节头(Section Headers:)在ELF文件中的偏移量。如果节头不存 在此值为0

e_flags:             这个成员表示处理器标志.

e_ehsize:          这个成员描述了“ELF自身占用的字节数。

e_phentsize:    该成员表示程序头中的每一个结构占用的字节数。程序头也叫程序头表,可以 被看做一个在文件中连续存储的结构数组,数组中每一项是一个结构,此字段 给出了这个结构占用的字节大小。

e_phoff:             指出程序头在ELF文件中的起始偏移。

e_phnum:        此字段给出了程序头中保存了多少个结构。如果程序头中有3个结构则程序头 在文件中占用了3×e_phentsize个字节的大小。

e_shentsize:   节头中每个结构占用的字节大小。节头与程序头类似也是一个结构数组,关于 这两个结构的定义将分别在讲述程序头和节头的时候给出。

e_shnum:        节头中保存了多少个结构。

e_shstrndx:     这是一个整数索引值。节头可以看作是一个结构数组,用这个索引值做为此数 组的下标,它在节头中指定的一个结构进一步给出了一个字符串表的信息,而这 个字符串表保存着节头中描述的每一个节的名称,包括字符串表自己也是其中的一 个节。

示例代码:

  1. #include <unistd.h>   
  2. #include <elf.h>   
  3. #include <fcntl.h>   
  4. #include <stdio.h>   
  5. #include <string.h>   
  6. #include <stdlib.h>   
  7. #include <sys/mman.h>   
  8. #include <sys/types.h>   
  9. #include <sys/stat.h>   
  10.   
  11. int     g_File      = 0;  
  12. void    *g_pData    = NULL;  
  13.   
  14. void * Map(char* szFileName)  
  15. {  
  16.     g_File = open(szFileName, O_RDWR);    
  17.     if (g_File < 0)     
  18.     {     
  19.         g_File = 0;    
  20.         return NULL;     
  21.     }    
  22.     struct stat status;    
  23.     fstat(g_File, &status);    
  24.   
  25.     g_pData = mmap(0, status.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, g_File, 0);    
  26.     if (MAP_FAILED != g_pData) {  
  27.         return g_pData;  
  28.     }    
  29.     
  30.     close(g_File);    
  31.     g_pData = NULL;    
  32.     g_File = 0;    
  33.     return NULL;    
  34. }  
  35.       
  36. void displayEhdr(Elf32_Ehdr *ehdr)  
  37. {  
  38.     printf("Magic:");  
  39.     int i = 0;  
  40.     for(i = 0; i < EI_NIDENT;i++){  
  41.         printf(" %02x",ehdr->e_ident[i]);  
  42.     }  
  43.     printf("\n");  
  44.     printf("Version:            0x%x\n",ehdr->e_version);  
  45.     printf("Entry point address:        0x%x\n",ehdr->e_entry);  
  46.     printf("Start of program headers:   %d (bytes into file)\n",ehdr->e_phoff);  
  47.     printf("Start of section headers:   %d (bytes into file)\n",ehdr->e_shoff);  
  48.     printf("Flags:              %d\n",ehdr->e_flags);  
  49.     printf("Size of this header:        %d (bytes)\n",ehdr->e_ehsize);  
  50.     printf("Size of program headers:    %d (bytes)\n",ehdr->e_phentsize);  
  51.     printf("Number of program headers:  %d\n",ehdr->e_phnum);  
  52.     printf("Size of section headers:    %d (bytes)\n",ehdr->e_shentsize);  
  53.     printf("Number of section headers:  %d\n",ehdr->e_shnum);  
  54.     printf("Section header string table index:  %d\n",ehdr->e_shstrndx);  
  55. }  
  56.   
  57. int main(int argc,char *argv[])  
  58. {  
  59.     if(argc != 2){  
  60.         printf("parameter error\n");  
  61.         exit(0);  
  62.     }  
  63.     Elf32_Ehdr *ehdr = (Elf32_Ehdr *)Map(argv[1]);  
  64.     if(ehdr == NULL){  
  65.         perror("Map Error\n");  
  66.         exit(0);  
  67.     }  
  68.     displayEhdr(ehdr);  
  69. }  

相关推荐