函数劫持实验

知识

Linux 编译动态链接库(.so)

参考文章:

GCC 生成动态链接库 .so 文件 (-shared 和 -fPIC 选项)

gcc -shared -fpic

-fPIC 选项作用于编译阶段,告诉编译器产生与位置无关代码 (Position-Independent Code),这样一来,产生的代码中就没有绝对地址了,全部使用相对地址,所以代码可以被加载器加载到内存的任意位置,都可以正确的执行。这正是共享库所要求的,共享库被加载时,在内存的位置不是固定的。

如果想创建一个动态链接库,可以使用 GCC 的 -shared 选项。输入文件可以是源文件、汇编文件或者目标文件。

一般的编译链接命令行为:

gcc -fPIC -shared func.c -o libfunc.so

readelf <option(s)> elf-file(s)

参考:Linux中的readelf命令

关于ELF文件:

ELF文件类型:

a)可重定位文件:用户和其他目标文件一起创建可执行文件或者共享目标文件,例如lib*.a文件。

b)可执行文件:用于生成进程映像,载入内存执行,例如编译好的可执行文件a.out。

c)共享目标文件:用于和其他共享目标文件或者可重定位文件一起生成elf目标文件或者和执行文件一起创建进程映像,例如lib*.so文件。

ELF文件作用:

ELF文件参与程序的连接(建立一个程序)和程序的执行(运行一个程序),所以可以从不同的角度来看待elf格式的文件:

a)如果用于编译和链接(可重定位文件),则编译器和链接器将把elf文件看作是节头表描述的节的集合,程序头表可选。

b)如果用于加载执行(可执行文件),则加载器则将把elf文件看作是程序头表描述的段的集合,一个段可能包含多个节,节头表可选。

c)如果是共享文件,则两者都含有。

ELF文件总体组成:

elf文件头描述elf文件的总体信息。包括: 系统相关,类型相关,加载相关,链接相关。

-s –syms Display the symbol table

-W –wide Allow output width to exceed 80 characters

通过此命令可以查看动态库中包含的函数或者函数都调用了哪些库函数

###实验

参考

先编写一个c语言文件cp.c:

#!c
#include <stdio.h>
#include <string.h>
int main(int argc, char **argv){
char passwd[] = "password";
if (argc < 2) {
        printf("usage: %s <password>/n", argv[0]);
        return;
}
if (!strcmp(passwd, argv[1])) {
        printf("Correct Password!/n");
        return;
}
printf("Invalid Password!/n");
}

其中用到了strcmp()函数

我们尝试劫持strcmp()函数

先构造一个新的strcmp()函数:

hack.c

#include <stdio.h>
#include <string.h>
int strcmp(const char *s1, const char *s2){
    printf("hack function invoked. s1=<%s> s2=<%s>/n", s1, s2);
    return 0;
}

我们将hack.c编译成动态链接库

gcc -shared hack.c -o hack.so

再设置LD_PRELOAD

export LD_PRELOAD="./hack.so"

当我们再执行srtcmp()函数时,得到

hack function invoked. ……

此时函数劫持成功

实战