本文在 Linux内存替换(四)代码注入 的基础上,介绍了代码注入替换运行程序加载的动态链接库中指定函数的方法。 网上的一种思路是利用在被注入程序中申请空间存放待注入代码,然后通过修改GOT表函数地址指针实现函数替换;本文介绍的方法利用预先构造好的函数Shellcode直接覆盖动态链接库中指定函数代码实现函数替换。两种方法相比,前者具有更好的适用性,而且自动化程度更高,后者思路和实现都更加简单。
实现环境:
CentOS 6.6 (Final)
Linux version 2.6.32-504.el6.i686
gcc version 4.4.7 20120313
nasm version 2.07
一、被注入程序的编写
【动态链接库】
//fso.c
//gcc -c -Wall -Werror -fPIC fso.c
//gcc -shared -o libfso.so fso.o
#include <stdio.h>
void hello()
{
int i = 0;
int j = 0;
printf("Hello Myboy!\n");
for(i=0; i<10000000; i++)
{
j++;
}
}
以上代码中的for循环,仅仅是为了确保Shellcode在注入时具有足够的存储空间。
【被注入程序】
//main.c
//gcc -L /home/mycos/so -Wall -o main main.c -lfso
//export LD_LIBRARY_PATH=/home/mycos/so :$LD_LIBRARY_PATH
#include <stdio.h>
extern void hello(void);
int main()
{
int i = 0;
printf("This is Main!\n");
while(1)
{
if(i%10 == 0) printf("\n");
sleep(1);
hello();
i++;
}
return 0;
}
关于被注入程序的编写,详细信息或出现错误请参见 加载动态链接库so程序简单实例
二、Shellcode的编写
【hello.asm】
; 32-bit "Hello World!" in CentOS 6 i686
; nasm -felf32 hello.asm -o hello.o
; ld -s -o hello hello.o
global _start
_start:
jmp string
code:
pop ecx
mov eax, 0x4
mov ebx, 0x1
mov edx, 0xD
int 0x80
nop
nop
nop
nop
nop
nop
nop
nop
string:
call code
db 'Hello world!',0x0a
以上空指令nop,是为堆栈恢复和函数返回指令预留的存储空间,预留空指令空间必须比被注入程序动态库堆栈恢复和函数返回指令占用的空间大。
【提取Shellcode】
for i in $(objdump -d hello |grep "^ " |cut -f2); do echo -n '\x'$i; done; echo
执行以上命令得到如下Shellcode,共计49个字节,但是该Shellcode还不能直接使用,需要根据目标程序动态链接库实际情况进行修改。
\xe9\x1a\x00\x00\x00\x59\xb8\x04\x00\x00\x00\xbb\x01\x00\x00\x00\xba\x0d\x00\x00\x00\xcd\x80\x90\x90\x90\x90\x90\x90\x90\x90\xe8\xdf\xff\xff\xff\x48\x65\x6c\x6c\x6f\x20\x77\x6f