通过实例理解 .gnu.hash section

Assume the file is libc.so.6, the system is of 64 bit. The file is in /lib/x86_64-linux-gnu/. This document is helpful to understand the gnu hash section through an example. The symbol to be checked is “printf”.

Let’s go!

$ objdump -s /lib/x86_64-linux-gnu/libc.so.6|grep .gnu.hash -A 5
Contents of section .gnu.hash: (5 lines after the section start)
02b8 f3030000 0a000000 00010000 0e000000 …
02c8 00301044 a0200201 8803e690 c5458c00 .0.D. …E…
02d8 c4000800 05840060 c080000d 8a0c0004 …`…
02e8 10008840 32082a40 88543c2c 200e3248 …@2.*@.T<, .2H
02f8 2684c08c 04080002 020ea1ac 1a0466c0 &…f.

nbuckets: 03f3, hash buckets, 4 bytes
symndx: 000a, Index of 1st dynsym, 4 bytes
bloom: 0100, Bloom filter words, 4 bytes
shift2: 000e, Bloom filter hash shift2, 4 bytes

start of bloom filter: 02b8 + 0010 = 02c8
start of bucket: 02c8 + 8 * 0100 = 0ac8 , each bloom 8 bytes
start of hash value: 0ac8 + 4 * 03f3 = 1a94 , each bucket 4 bytes

hash of “printf”: new_hash = 0x156b2bb8

 "printf"=70 72 69 6e 74 66
 h = 0x1505  // 5381
 t = 0x21    //33
 h = h * t + 70  //h * 33 = h >> 5 +h
 h = h * t + 72
 h = h * t + 69
 h = h * t + 6e 
 h = h * t + 74
 h = h * t + 66
 h = h & 0xffffffff

Hash function
The GNU hash function user the DJB hash (blogs.oracle.com/solaris/post/gnu-hash-elf-sections)

 uint32_t dl_new_hash (const char *s)
 {
     uint32 h = 5381;
     for (unsigned char c = *s; c != '\0'; c = *++s)
        h = h * 33 + c;  //or ((h = h >> 5) +h) +c
     return h; // h in uint32 means h = h & 0xffffffff
 }

class64 = 0x40, 64
hashbit1 = new_hash & (class64 - 1) = 56
hashbit2 = (new_hash >> shift2) & (class64 - 1) = 44
if a value is power of 2, & (value - 1) equals % value
bits 56 and 44 of maskword N are set to 1
N =((new_hash /class64) % maskwords), maskwords = bloom

bloom word: (new_hash / 64) % bloom = 0xae
bloom word address: 02c8 + 8 * ae = 0x0838 , one bloom word 8 bytes

find the address 0838:
$ objdump -s /lib/x86_64-linux-gnu/libc.so.6|grep " 0838 "
0838 d0884a41 c0703429 10ec4303 92003103 …JA.p4)…C…1.

the bloom word value at 0838 is 0x293470c0 414a88d0
(0x293470c0 414a88d0 >> 56) & 1 = 0x29 & 1 =1
(0x293470c0 414a88d0 >> 44) & 1 = 0x293447 & 1 =1
“printf” pass the check

determine bucket:
bucket_id = new_hash % nbuckets = 0x127
address of the bucket: 0ac8 + 4 * 0x127 = 0x0f64 , one bucket 4 bytes

find the address 0f64
$ objdump -s /lib/x86_64-linux-gnu/libc.so.6|grep " 0f58 " -A 2
0f58 55020000 00000000 58020000 5a020000 U…X…Z…
0f68 5f020000 62020000 63020000 66020000 _…b…c…f…
0f78 67020000 6a020000 6c020000 70020000 g…j…l…p…

bucket value at 0f64 is: 025a
hash value of the bucket at:
1a94 + 4*(025a -symndx) = 0x23d4

find the address 23d4
$ objdump -s /lib/x86_64-linux-gnu/libc.so.6|grep " 23c8 " -A 2
23c8 ade8dbbb 142dcb13 bb86f85f e6952000 …-…_… .
23d8 b82b6b15 0a05f1d5 deb6427f 856177fd .+k…B…aw.
23e8 ec296fa8 1ae585e7 29ce248f e7d045cc .)o…).$…E.

the new_hash 156b2bb8 at 23d8
it’s the second hash value of the bucket, so the dynsym index is: 025a + 1=0x025b

find the start of dynsym section:
$ objdump -s /lib/x86_64-linux-gnu/libc.so.6|grep .dynsym -A 2
Contents of section .dynsym:
03d80 00000000 00000000 00000000 00000000 …
03d90 00000000 00000000 00000000 03000d00 …

the 0x025b dynsym at: 0x03d80+0x18*0x25b = 0x07608, one sym item 24 bytes
docs.oracle.com/cd/E19120-01/open.solaris/819-0690/chapter6-79797/index.html

type struct {
	Elf64_Word    st_name;//4 bytes
	unsigned char st_info;//1 byte
	unsigned char st_others;//1 byte
	Elf64_Half    st_shndx;// 2 bytes
	Elf64_Addr    st_value;// 8 bytes
    Elf64_Xword   stsize;  // 8 bytes 
 } Elf6s_Sym

find the dynsym at 0x07608:
$ objdump -s /lib/x86_64-linux-gnu/libc.so.6|grep " 07600 " -A 2
07600 12000000 00000000 c2040000 12000d00 …
07610 10580500 00000000 a1000000 00000000 .X…
07620 533c0000 12000d00 70e70f00 00000000 S<…p…

st_name = 00000402
st_info =12,
ELF64_ST_BIND (info) = info >> 4 =1, STB_GLOBAL, Global symbols.
ELF64_ST_TYPE (info) = info & 0xf =2, STT_FUNC, a function or executable
st_other = 00, STV_DEFAULT, visibility specified by the symbol’s binding type
st_shndx =000d, relevant section header table index,
st_value = 00000000 00055810, virtual address
st_size = 00000000 000000a1, object size in bytes

the dynsym_name at 0x7608 points to 04c2 of section dynstr

find the start of dynstr section:

$ objdump -s /lib/x86_64-linux-gnu/libc.so.6|grep .dynstr -A 2
Contents of section .dynstr:
10ff8 00786472 5f755f6c 6f6e6700 5f5f7763 .xdr_u_long.__wc
11008 746f6d62 5f63686b 00676574 6d6e7465 tomb_chk.getmnte

the symbol start at: 10ff8 + 04c2 =0x114ba
find the symbol at 0x114ba
$ objdump -s /lib/x86_64-linux-gnu/libc.so.6|grep " 114b8 " -A 2
114b8 4f5f7072 696e7466 00726567 69737465 O_printf.registe
114c8 725f7072 696e7466 5f66756e 6374696f r_printf_functio
114d8 6e00706f 7369785f 6f70656e 70740069 n.posix_openpt.i

the symbol at 0x114ba is: 70 72 69 6e 74 66, that is “printf”

look at the address specified by st_value = 55810
$ objdump -S /lib/x86_64-linux-gnu/libc.so.6|grep "55810 " -A 2
0000000000055810 <_IO_printf@@GLIBC_2.2.5>:
55810: 48 81 ec d8 00 00 00 sub $0xd8,%rsp
55817: 84 c0 test %al,%al

It’s the start code of _IO_printf@@GLIBC_2.2.5

End

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值