Linux Hook技术(一)

本文借鉴了网上大多数文章,相当于一边学习一边整合。主要借鉴https://blog.csdn.net/yyttiao/article/details/7346287这一系列文章。感谢!

首先学习整个技术是在Linux下完成的,没有双系统的建议装个虚拟机,我使用的版本是Ubuntu18.04.2。以下所有的测试结果均在此环境下运行。贴个图:


电脑配置.png

注:建议安装一个VS code 使用起来非常方便。

Hook技术也被称作为“钩子技术”其作用简单的说就是别人本来是执行libA.so里面的函数的,结果现在被偷偷换成了执行你的libB.so里面的代码,是一种替换。(lib.so是Linux下的链接库)

为什么hook

1.恶意代码注入
2.调用常用库函数时打log
3.改变常用库函数的行为,个性化

在此之前听说过一些hook技术但是大多数都是在window下的,后来发现在Linux下也有只是实现起来比较复杂。
首先要认识的是ELF文件,在Linux中,ELF文件主要是应用在可执行文件,重定位文件,可执行文件动态连接库。

先认识ELF的Head

#define EI_NIDENT (16)
typedef struct
{
 
  unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */
 
  Elf32_Half e_type; /* Object file type */
 
  Elf32_Half e_machine; /* Architecture */
 
  Elf32_Word e_version; /* Object file version */
 
  Elf32_Addr e_entry; /* Entry point virtual address */
 
  Elf32_Off e_phoff; /* Program header table file offset */
 
  Elf32_Off e_shoff; /* Section header table file offset */
 
  Elf32_Word e_flags; /* Processor-specific flags */
 
  Elf32_Half e_ehsize; /* ELF header size in bytes */
 
  Elf32_Half e_phentsize; /* Program header table entry size */
 
  Elf32_Half e_phnum; /* Program header table entry count */
 
  Elf32_Half e_shentsize; /* Section header table entry size */
 
  Elf32_Half e_shnum; /* Section header table entry count */
 
  Elf32_Half e_shstrndx; /* Section header string table index */
 
} Elf32_Ehdr;

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

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

#define EI_MAG0 0 /* File identification byte 0 index */
 
#define ELFMAG0 0x7f /* Magic number byte 0 *
#define EI_MAG1 1 /* File identification byte 1 index */
 
#define ELFMAG1 'E' /* Magic number byte 1 */
 
#define EI_MAG2 2 /* File identification byte 2 index */
 
#define ELFMAG2 'L' /* Magic number byte 2 */
 
#define EI_MAG3 3 /* File identification byte 3 index */
 
#define ELFMAG3 'F' /* Magic number byte 3 */
 
/* Conglomeration of the identification bytes, for easy testing as a word.  */
 
#define ELFMAG "\177ELF"
 
#define SELFMAG 4

第四个字节表示ELF格式,1:32位2:64位

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

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

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

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

#define EV_CURRENT 1 /* Current version */

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

#define EI_OSABI 7 /* OS ABI identification */
 
#define ELFOSABI_NONE 0 /* UNIX System V ABI */
 
#define ELFOSABI_SYSV 0 /* Alias.  */
 
#define ELFOSABI_HPUX 1 /* HP-UX */
 
#define ELFOSABI_NETBSD 2 /* NetBSD.  */
 
#define ELFOSABI_LINUX 3 /* Linux.  */
 
#define ELFOSABI_SOLARIS 6 /* Sun Solaris.  */
 
#define ELFOSABI_AIX 7 /* IBM AIX.  */
 
#define ELFOSABI_IRIX 8 /* SGI Irix.  */
 
#define ELFOSABI_FREEBSD 9 /* FreeBSD.  */
 
#define ELFOSABI_TRU64 10 /* Compaq TRU64 UNIX.  */
 
#define ELFOSABI_MODESTO 11 /* Novell Modesto.  */
 
#define ELFOSABI_OPENBSD 12 /* OpenBSD.  */
 
#define ELFOSABI_ARM 97 /* ARM */
 
#define ELFOSABI_STANDALONE 255 
 
/*Standalone(embedded) application */

第八个字节表示ABI版本

#define EI_ABIVERSION 8 /* ABI version */

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

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

实例代码

#include <unistd.h>
#include <elf.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
 
int     g_File      = 0;
void    *g_pData    = NULL;
 
void * Map(char* szFileName)
{
    g_File = open(szFileName, O_RDWR);  
    if (g_File < 0)   
    {   
        g_File = 0;  
        return NULL;   
    }  
    struct stat status;  
    fstat(g_File, &status);  
 
    g_pData = mmap(0, status.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, g_File, 0);  
    if (MAP_FAILED != g_pData) {
        return g_pData;
    }  
  
    close(g_File);  
    g_pData = NULL;  
    g_File = 0;  
    return NULL;  
}
    
void displayEhdr(Elf32_Ehdr *ehdr)
{
    printf("Magic:");
    int i = 0;
    for(i = 0; i < EI_NIDENT;i++){
        printf(" %02x",ehdr->e_ident[i]);
    }
    printf("\n");
    printf("Version:            0x%x\n",ehdr->e_version);
    printf("Entry point address:        0x%x\n",ehdr->e_entry);
    printf("Start of program headers:   %d (bytes into file)\n",ehdr->e_phoff);
    printf("Start of section headers:   %d (bytes into file)\n",ehdr->e_shoff);
    printf("Flags:              %d\n",ehdr->e_flags);
    printf("Size of this header:        %d (bytes)\n",ehdr->e_ehsize);
    printf("Size of program headers:    %d (bytes)\n",ehdr->e_phentsize);
    printf("Number of program headers:  %d\n",ehdr->e_phnum);
    printf("Size of section headers:    %d (bytes)\n",ehdr->e_shentsize);
    printf("Number of section headers:  %d\n",ehdr->e_shnum);
    printf("Section header string table index:  %d\n",ehdr->e_shstrndx);
}
 
int main(int argc,char *argv[])
{
    if(argc != 2){
        printf("parameter error\n");
        exit(0);
    }
    Elf32_Ehdr *ehdr = (Elf32_Ehdr *)Map(argv[1]);
    if(ehdr == NULL){
        perror("Map Error\n");
        exit(0);
    }
    displayEhdr(ehdr);
}

gcc编译命令

gcc -o name file.c


demo.png
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,560评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,104评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,297评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,869评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,275评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,563评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,833评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,543评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,245评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,512评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,011评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,359评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,006评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,062评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,825评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,590评论 2 273
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,501评论 2 268

推荐阅读更多精彩内容