动态库生成和使用

先看代码:

pop.c

extern int stack[512];
extern int top;
int pop()
{
        if(top<=0)
                return;
        top--;
        return stack[top];
}

push.c

extern int stack[512];
extern int top;
void push(int v)
{
        if(top>=512)
                return;
        stack[top]=v;
        top++;
}

main.c

#include <stdio.h>
int stack[512];
int top=0;
void main(int n,void * a[])
{
        push(1);
        push(2);
        int d=pop();
        printf("%d\n",d);
}

正常编译

正常编译时使用gcc -c -g pop.c push.c main.c,然后使用objdump -ds 查看反汇编:

objdump -dS pop.o

int pop()
{
   0:55                   push   %ebp
   1:89 e5                mov    %esp,%ebp
if(top<=0)
   3:a1 00 00 00 00       mov    0x0,%eax
   8:85 c0                test   %eax,%eax
   a:7f 02                jg     e <pop+0xe>
   c:eb 19                jmp    27 <pop+0x27>
return;
top--;
   e:a1 00 00 00 00       mov    0x0,%eax
  13:83 e8 01             sub    $0x1,%eax
  16:a3 00 00 00 00       mov    %eax,0x0
return stack[top];
  1b:a1 00 00 00 00       mov    0x0,%eax
  20:8b 04 85 00 00 00 00 mov    0x0(,%eax,4),%eax
}
  27:5d                   pop    %ebp
  28:c3                   ret 


可以看出top的访问地址都是0。

使用gcc pop.o push.o main.o -o main,然后使用 objdump -dS main查看反汇编

extern int top;
int pop()
{
 8048428:	55                   	push   %ebp
 8048429:	89 e5                	mov    %esp,%ebp
	if(top<=0)
 804842b:	a1 28 a0 04 08       	mov    0x804a028,%eax
 8048430:	85 c0                	test   %eax,%eax
 8048432:	7f 02                	jg     8048436 <pop+0xe>
 8048434:	eb 19                	jmp    804844f <pop+0x27>
		return;
	top--;
 8048436:	a1 28 a0 04 08       	mov    0x804a028,%eax
 804843b:	83 e8 01             	sub    $0x1,%eax
 804843e:	a3 28 a0 04 08       	mov    %eax,0x804a028
	return stack[top];
 8048443:	a1 28 a0 04 08       	mov    0x804a028,%eax
 8048448:	8b 04 85 40 a0 04 08 	mov    0x804a040(,%eax,4),%eax
}

可以看到top的地址已经被硬编码为0x804a028。

位置无关编译

在编译动态链接库时,一般需要添加fPIC编译选项,例如:

gcc -g -fPIC -c pop.c push.c,使用objdump -dS pop.o查看反汇编

extern int stack[512];
extern int top;
int pop()
{
   0:	55                   	push   %ebp
   1:	89 e5                	mov    %esp,%ebp
   3:	e8 fc ff ff ff       	call   4 <pop+0x4>
   8:	81 c1 02 00 00 00    	add    $0x2,%ecx
	if(top<=0)
   e:	8b 81 00 00 00 00    	mov    0x0(%ecx),%eax
  14:	8b 00                	mov    (%eax),%eax
  16:	85 c0                	test   %eax,%eax
  18:	7f 02                	jg     1c <pop+0x1c>
  1a:	eb 24                	jmp    40 <pop+0x40>
		return;
	top--;
  1c:	8b 81 00 00 00 00    	mov    0x0(%ecx),%eax
  22:	8b 00                	mov    (%eax),%eax
  24:	8d 50 ff             	lea    -0x1(%eax),%edx
  27:	8b 81 00 00 00 00    	mov    0x0(%ecx),%eax
  2d:	89 10                	mov    %edx,(%eax)
	return stack[top];
  2f:	8b 81 00 00 00 00    	mov    0x0(%ecx),%eax
  35:	8b 10                	mov    (%eax),%edx
  37:	8b 81 00 00 00 00    	mov    0x0(%ecx),%eax
  3d:	8b 04 90             	mov    (%eax,%edx,4),%eax
}
上面访问top需要经过2步骤:

eax = ecx[0]

eax = exa[0]

和一般编译方式不同,它使用的间接地址访问top数据。


将这些对象文件链接成为动态库

gcc -shared -o libstack.so push.o pop.o,然后察看libstack.so的反汇编

000004b8 <pop>:
extern int stack[512];
extern int top;
int pop()
{
 4b8:	55                   	push   %ebp
 4b9:	89 e5                	mov    %esp,%ebp
 4bb:	e8 3a 00 00 00       	call   4fa <__i686.get_pc_thunk.cx>
 4c0:	81 c1 34 1b 00 00    	add    $0x1b34,%ecx
	if(top<=0)
 4c6:	8b 81 f4 ff ff ff    	mov    -0xc(%ecx),%eax
 4cc:	8b 00                	mov    (%eax),%eax
 4ce:	85 c0                	test   %eax,%eax
 4d0:	7f 02                	jg     4d4 <pop+0x1c>
 4d2:	eb 24                	jmp    4f8 <pop+0x40>
		return;
	top--;
 4d4:	8b 81 f4 ff ff ff    	mov    -0xc(%ecx),%eax
 4da:	8b 00                	mov    (%eax),%eax
 4dc:	8d 50 ff             	lea    -0x1(%eax),%edx
 4df:	8b 81 f4 ff ff ff    	mov    -0xc(%ecx),%eax
 4e5:	89 10                	mov    %edx,(%eax)
	return stack[top];
 4e7:	8b 81 f4 ff ff ff    	mov    -0xc(%ecx),%eax
 4ed:	8b 10                	mov    (%eax),%edx
 4ef:	8b 81 fc ff ff ff    	mov    -0x4(%ecx),%eax
 4f5:	8b 04 90             	mov    (%eax,%edx,4),%eax
}

比较pop.o可以看出:

top的地址存储位置由原来的ecx[0]改变为ecx[-12]

另外也能看出stack的地址存储位置由原来的ecx[0]改变为ecx[-4]


编译可执行文件并执行

htm@htm:~/test/testlink$ gcc main.o -lstack -o main -L.
htm@htm:~/test/testlink$ ./main 
./main: error while loading shared libraries: libstack.so: cannot open shared object file: No such file or directory
编译时指定了libstack.so的查找路径,但执行时却找不到这个文件。

ldd命令能够模拟程序执行,查找需要的动态链接文件。

htm@htm:~/test/testlink$ ldd main
	linux-gate.so.1 =>  (0xb77d5000)
	libstack.so => not found
	libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb7614000)
	/lib/ld-linux.so.2 (0xb77d6000)
对于找不到动态库可以修改LD_LIBRARY_PATH环境变量或者/etc/ld.so.conf文件,也可以将路径直接写入可执行文件中:

htm@htm:~/test/testlink$ gcc -lstack -L. main.c -o main -Wl,-rpath,/home/htm/test/testlink/
htm@htm:~/test/testlink$ ldd main
	linux-gate.so.1 =>  (0xb77d6000)
	libstack.so => /home/htm/test/testlink/libstack.so (0xb77d1000)
	libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb7612000)
	/lib/ld-linux.so.2 (0xb77d7000)


注意-L只能告诉编译器在哪里找到库文件,但是运行时库文件在哪里需要环境变量或者配置文件或者查找执行文件中的rpath

使用Wl,rpath后,利用readelf可以查看到main文件中多了一些信息

htm@htm:~/test/testlink$ readelf -d main

Dynamic section at offset 0xf18 contains 22 entries:
  Tag        Type                         Name/Value
 0x00000001 (NEEDED)                     Shared library: [libstack.so]
 0x00000001 (NEEDED)                     Shared library: [libc.so.6]
 <span style="color:#ff0000;">0x0000000f (RPATH)                      Library rpath: [/home/htm/test/testlink/]</span>
 0x0000000c (INIT)                       0x804840c
 0x0000000d (FINI)                       0x804864c
 0x6ffffef5 (GNU_HASH)                   0x80481ac
 0x00000005 (STRTAB)                     0x80482e0
 0x00000006 (SYMTAB)                     0x80481f0
 0x0000000a (STRSZ)                      188 (bytes)
 0x0000000b (SYMENT)                     16 (bytes)
 0x00000015 (DEBUG)                      0x0
 0x00000003 (PLTGOT)                     0x8049ff4
 0x00000002 (PLTRELSZ)                   40 (bytes)
 0x00000014 (PLTREL)                     REL
 0x00000017 (JMPREL)                     0x80483e4
 0x00000011 (REL)                        0x80483dc
 0x00000012 (RELSZ)                      8 (bytes)
 0x00000013 (RELENT)                     8 (bytes)
 0x6ffffffe (VERNEED)                    0x80483bc
 0x6fffffff (VERNEEDNUM)                 1
 0x6ffffff0 (VERSYM)                     0x804839c
 0x00000000 (NULL)                       0x0
使用这种技术,可以为指定程序添加后门。

动态链接库运行过程

程序运行时,遇到动态库提供的接口或者变量,程序会跳转到动态连接器/lib/ld-linux.so.2,在其中完成动态链接的过程,并调用或者访问变量。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值