歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> 一步一步走進Linux HOOK API

一步一步走進Linux HOOK API

日期:2017/3/1 10:25:25   编辑:Linux編程

最近我查閱很多參考資料.發現對於講述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. typedef struct
  3. {
  4. unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */
  5. Elf32_Half e_type; /* Object file type */
  6. Elf32_Half e_machine; /* Architecture */
  7. Elf32_Word e_version; /* Object file version */
  8. Elf32_Addr e_entry; /* Entry point virtual address */
  9. Elf32_Off e_phoff; /* Program header table file offset */
  10. Elf32_Off e_shoff; /* Section header table file offset */
  11. Elf32_Word e_flags; /* Processor-specific flags */
  12. Elf32_Half e_ehsize; /* ELF header size in bytes */
  13. Elf32_Half e_phentsize; /* Program header table entry size */
  14. Elf32_Half e_phnum; /* Program header table entry count */
  15. Elf32_Half e_shentsize; /* Section header table entry size */
  16. Elf32_Half e_shnum; /* Section header table entry count */
  17. Elf32_Half e_shstrndx; /* Section header string table index */
  18. } 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. #define ELFMAG0 0x7f /* Magic number byte 0 *
  3. #define EI_MAG1 1 /* File identification byte 1 index */
  4. #define ELFMAG1 'E' /* Magic number byte 1 */
  5. #define EI_MAG2 2 /* File identification byte 2 index */
  6. #define ELFMAG2 'L' /* Magic number byte 2 */
  7. #define EI_MAG3 3 /* File identification byte 3 index */
  8. #define ELFMAG3 'F' /* Magic number byte 3 */
  9. /* Conglomeration of the identification bytes, for easy testing as a word. */
  10. #define ELFMAG "\177ELF"
  11. #define SELFMAG 4

第四個字節表示ELF格式,1:32位2:64位

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

第五個字節表示數據編碼格式,1:小端模式 2:大端模式

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

第六個字節表示文件版本,該值目前必須為1

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

第七個字節表示操作系統標識:

  1. #define EI_OSABI 7 /* OS ABI identification */
  2. #define ELFOSABI_NONE 0 /* UNIX System V ABI */
  3. #define ELFOSABI_SYSV 0 /* Alias. */
  4. #define ELFOSABI_HPUX 1 /* HP-UX */
  5. #define ELFOSABI_NETBSD 2 /* NetBSD. */
  6. #define ELFOSABI_LINUX 3 /* Linux. */
  7. #define ELFOSABI_SOLARIS 6 /* Sun Solaris. */
  8. #define ELFOSABI_AIX 7 /* IBM AIX. */
  9. #define ELFOSABI_IRIX 8 /* SGI Irix. */
  10. #define ELFOSABI_FREEBSD 9 /* FreeBSD. */
  11. #define ELFOSABI_TRU64 10 /* Compaq TRU64 UNIX. */
  12. #define ELFOSABI_MODESTO 11 /* Novell Modesto. */
  13. #define ELFOSABI_OPENBSD 12 /* OpenBSD. */
  14. #define ELFOSABI_ARM 97 /* ARM */
  15. #define ELFOSABI_STANDALONE 255
  16. /*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. int g_File = 0;
  11. void *g_pData = NULL;
  12. void * Map(char* szFileName)
  13. {
  14. g_File = open(szFileName, O_RDWR);
  15. if (g_File < 0)
  16. {
  17. g_File = 0;
  18. return NULL;
  19. }
  20. struct stat status;
  21. fstat(g_File, &status);
  22. g_pData = mmap(0, status.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, g_File, 0);
  23. if (MAP_FAILED != g_pData) {
  24. return g_pData;
  25. }
  26. close(g_File);
  27. g_pData = NULL;
  28. g_File = 0;
  29. return NULL;
  30. }
  31. void displayEhdr(Elf32_Ehdr *ehdr)
  32. {
  33. printf("Magic:");
  34. int i = 0;
  35. for(i = 0; i < EI_NIDENT;i++){
  36. printf(" %02x",ehdr->e_ident[i]);
  37. }
  38. printf("\n");
  39. printf("Version: 0x%x\n",ehdr->e_version);
  40. printf("Entry point address: 0x%x\n",ehdr->e_entry);
  41. printf("Start of program headers: %d (bytes into file)\n",ehdr->e_phoff);
  42. printf("Start of section headers: %d (bytes into file)\n",ehdr->e_shoff);
  43. printf("Flags: %d\n",ehdr->e_flags);
  44. printf("Size of this header: %d (bytes)\n",ehdr->e_ehsize);
  45. printf("Size of program headers: %d (bytes)\n",ehdr->e_phentsize);
  46. printf("Number of program headers: %d\n",ehdr->e_phnum);
  47. printf("Size of section headers: %d (bytes)\n",ehdr->e_shentsize);
  48. printf("Number of section headers: %d\n",ehdr->e_shnum);
  49. printf("Section header string table index: %d\n",ehdr->e_shstrndx);
  50. }
  51. int main(int argc,char *argv[])
  52. {
  53. if(argc != 2){
  54. printf("parameter error\n");
  55. exit(0);
  56. }
  57. Elf32_Ehdr *ehdr = (Elf32_Ehdr *)Map(argv[1]);
  58. if(ehdr == NULL){
  59. perror("Map Error\n");
  60. exit(0);
  61. }
  62. displayEhdr(ehdr);
  63. }
Copyright © Linux教程網 All Rights Reserved