typedef struct elf64_shdr {
Elf64_Word sh_name; /* Section name, index in string tbl */
Elf64_Word sh_type; /* Type of section */
Elf64_Xword sh_flags; /* Miscellaneous section attributes */
Elf64_Addr sh_addr; /* Section virtual addr at execution */
Elf64_Off sh_offset; /* Section file offset */
Elf64_Xword sh_size; /* Size of section in bytes */
Elf64_Word sh_link; /* Index of another section */
Elf64_Word sh_info; /* Additional section information */
Elf64_Xword sh_addralign; /* Section alignment */
Elf64_Xword sh_entsize; /* Entry size if section holds table */
} Elf64_Shdr;
(gdb) p/d (Elf64_Shdr *)0 + 1
$13 = 64
/* sh_type */
#define SHT_NULL 0
#define SHT_PROGBITS 1
#define SHT_SYMTAB 2
#define SHT_STRTAB 3
#define SHT_RELA 4
#define SHT_HASH 5
#define SHT_DYNAMIC 6
#define SHT_NOTE 7
#define SHT_NOBITS 8
#define SHT_REL 9
#define SHT_SHLIB 10
#define SHT_DYNSYM 11
#define SHT_NUM 12
#define SHT_LOPROC 0x70000000
#define SHT_HIPROC 0x7fffffff
#define SHT_LOUSER 0x80000000
#define SHT_HIUSER 0xffffffff
/* sh_flags */
#define SHF_WRITE 0x1
#define SHF_ALLOC 0x2
#define SHF_EXECINSTR 0x4
#define SHF_RELA_LIVEPATCH 0x00100000
#define SHF_RO_AFTER_INIT 0x00200000
#define SHF_MASKPROC 0xf0000000
// 根据ELF file header:
// section headers 位于文件的 offset:37336 ~ 39256(37336+64*30 0x9958)
// 共 1920(0x780) bytes
Start of section headers: 37336 (bytes into file)
Size of section headers: 64 (bytes)
Number of section headers: 30
Section header string table index: 29
// 37336 == 0x91d8
// 37336 + 64 == 37400
$ hd /bin/echo -s 37400 -n 64
00009218 0b 00 00 00 01 00 00 00 02 00 00 00 00 00 00 00 |................|
00009228 18 03 00 00 00 00 00 00 18 03 00 00 00 00 00 00 |................|
00009238 1c 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00009248 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00009258
Elf64_Word sh_name = 0x0000000b -> %s , 0x90b4+0xb : .interp
// $ hd /bin/echo -s $(((16#90b4)+11)) -n 8
// 000090bf 2e 69 6e 74 65 72 70 00 |.interp.|
Elf64_Word sh_type = 0x00000001 -> SHT_PROGBITS
Elf64_Xword sh_flags = 0x0000000000000002 -> SHF_ALLOC
Elf64_Addr sh_addr = 0x0000000000000318
Elf64_Off sh_offset = 0x0000000000000318
Elf64_Xword sh_size = 0x000000000000001c
Elf64_Word sh_link = 0x00000000
Elf64_Word sh_info = 0x00000000
Elf64_Xword sh_addralign = 0x0000000000000001
Elf64_Xword sh_entsize = 0x0000000000000000
...
$ hd /bin/echo -s 39192 -n 64
00009918 01 00 00 00 03 00 00 00 00 00 00 00 00 00 00 00 |................|
00009928 00 00 00 00 00 00 00 00 b4 90 00 00 00 00 00 00 |................|
00009938 1d 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00009948 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00009958
Elf64_Word sh_name = 0x00000001 -> %s , 0x90b4+1 : .shstrtab
// $ hd /bin/echo -s $(((16#90b4)+1)) -n 10
// 000090b5 2e 73 68 73 74 72 74 61 62 00 |.shstrtab.|
Elf64_Word sh_type = 0x00000003 -> SHT_STRTAB
Elf64_Xword sh_flags = 0x0000000000000000
Elf64_Addr sh_addr = 0x0000000000000000
Elf64_Off sh_offset = 0x00000000000090b4
Elf64_Xword sh_size = 0x000000000000011d
Elf64_Word sh_link = 0x00000000
Elf64_Word sh_info = 0x00000000
Elf64_Xword sh_addralign = 0x0000000000000001
Elf64_Xword sh_entsize = 0x0000000000000000
$ hd /bin/echo -s 0x90b4 -n 285
000090b4 00 2e 73 68 73 74 72 74 61 62 00 2e 69 6e 74 65 |..shstrtab..inte|
000090c4 72 70 00 2e 6e 6f 74 65 2e 67 6e 75 2e 70 72 6f |rp..note.gnu.pro|
000090d4 70 65 72 74 79 00 2e 6e 6f 74 65 2e 67 6e 75 2e |perty..note.gnu.|
000090e4 62 75 69 6c 64 2d 69 64 00 2e 6e 6f 74 65 2e 41 |build-id..note.A|
000090f4 42 49 2d 74 61 67 00 2e 67 6e 75 2e 68 61 73 68 |BI-tag..gnu.hash|
00009104 00 2e 64 79 6e 73 79 6d 00 2e 64 79 6e 73 74 72 |..dynsym..dynstr|
00009114 00 2e 67 6e 75 2e 76 65 72 73 69 6f 6e 00 2e 67 |..gnu.version..g|
00009124 6e 75 2e 76 65 72 73 69 6f 6e 5f 72 00 2e 72 65 |nu.version_r..re|
00009134 6c 61 2e 64 79 6e 00 2e 72 65 6c 61 2e 70 6c 74 |la.dyn..rela.plt|
00009144 00 2e 69 6e 69 74 00 2e 70 6c 74 2e 67 6f 74 00 |..init..plt.got.|
00009154 2e 70 6c 74 2e 73 65 63 00 2e 74 65 78 74 00 2e |.plt.sec..text..|
00009164 66 69 6e 69 00 2e 72 6f 64 61 74 61 00 2e 65 68 |fini..rodata..eh|
00009174 5f 66 72 61 6d 65 5f 68 64 72 00 2e 65 68 5f 66 |_frame_hdr..eh_f|
00009184 72 61 6d 65 00 2e 69 6e 69 74 5f 61 72 72 61 79 |rame..init_array|
00009194 00 2e 66 69 6e 69 5f 61 72 72 61 79 00 2e 64 61 |..fini_array..da|
000091a4 74 61 2e 72 65 6c 2e 72 6f 00 2e 64 79 6e 61 6d |ta.rel.ro..dynam|
000091b4 69 63 00 2e 64 61 74 61 00 2e 62 73 73 00 2e 67 |ic..data..bss..g|
000091c4 6e 75 5f 64 65 62 75 67 6c 69 6e 6b 00 |nu_debuglink.|
hd /bin/echo -s $((16#90b4)+1) -n 10
$ readelf -S -W /bin/echo
There are 30 section headers, starting at offset 0x91d8:
Section Headers:
[Nr] Name Type Address Off Size ES Flg Lk Inf Al
[ 0] NULL 0000000000000000 000000 000000 00 0 0 0
[ 1] .interp PROGBITS 0000000000000318 000318 00001c 00 A 0 0 1
[ 2] .note.gnu.property NOTE 0000000000000338 000338 000020 00 A 0 0 8
[ 3] .note.gnu.build-id NOTE 0000000000000358 000358 000024 00 A 0 0 4
[ 4] .note.ABI-tag NOTE 000000000000037c 00037c 000020 00 A 0 0 4
[ 5] .gnu.hash GNU_HASH 00000000000003a0 0003a0 000068 00 A 6 0 8
[ 6] .dynsym DYNSYM 0000000000000408 000408 0005b8 18 A 7 1 8
[ 7] .dynstr STRTAB 00000000000009c0 0009c0 000301 00 A 0 0 1
[ 8] .gnu.version VERSYM 0000000000000cc2 000cc2 00007a 02 A 6 0 2
[ 9] .gnu.version_r VERNEED 0000000000000d40 000d40 000060 00 A 7 1 8
[10] .rela.dyn RELA 0000000000000da0 000da0 000258 18 A 6 0 8
[11] .rela.plt RELA 0000000000000ff8 000ff8 0003d8 18 AI 6 25 8
[12] .init PROGBITS 0000000000002000 002000 00001b 00 AX 0 0 4
[13] .plt PROGBITS 0000000000002020 002020 0002a0 10 AX 0 0 16
[14] .plt.got PROGBITS 00000000000022c0 0022c0 000010 10 AX 0 0 16
[15] .plt.sec PROGBITS 00000000000022d0 0022d0 000290 10 AX 0 0 16
[16] .text PROGBITS 0000000000002560 002560 003712 00 AX 0 0 16
[17] .fini PROGBITS 0000000000005c74 005c74 00000d 00 AX 0 0 4
[18] .rodata PROGBITS 0000000000006000 006000 00128c 00 A 0 0 32
[19] .eh_frame_hdr PROGBITS 000000000000728c 00728c 00028c 00 A 0 0 4
[20] .eh_frame PROGBITS 0000000000007518 007518 000be0 00 A 0 0 8
[21] .init_array INIT_ARRAY 0000000000009c10 008c10 000008 08 WA 0 0 8
[22] .fini_array FINI_ARRAY 0000000000009c18 008c18 000008 08 WA 0 0 8
[23] .data.rel.ro PROGBITS 0000000000009c20 008c20 000058 00 WA 0 0 32
[24] .dynamic DYNAMIC 0000000000009c78 008c78 0001f0 10 WA 7 0 8
[25] .got PROGBITS 0000000000009e68 008e68 000188 08 WA 0 0 8
[26] .data PROGBITS 000000000000a000 009000 000080 00 WA 0 0 32
[27] .bss NOBITS 000000000000a080 009080 000198 00 WA 0 0 32
[28] .gnu_debuglink PROGBITS 0000000000000000 009080 000034 00 0 0 4
[29] .shstrtab STRTAB 0000000000000000 0090b4 00011d 00 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
L (link order), O (extra OS processing required), G (group), T (TLS),
C (compressed), x (unknown), o (OS specific), E (exclude),
l (large), p (processor specific)
根据上面的知识,要插入一个section:
Number of section headers + 1
section header table 的长度 + 64
shstrtab 的长度 + x
#define EI_NIDENT 16
typedef struct elf64_hdr {
unsigned char e_ident[EI_NIDENT]; // off: 0, size: 16
Elf64_Half e_type; // off: 16, size: 2
Elf64_Half e_machine; // off: 18, size: 2
Elf64_Word e_version; // off: 20, size: 4
Elf64_Addr e_entry; // off: 24, size: 8 Entry point virtual address
Elf64_Off e_phoff; // off: 32, size: 8 Program header table file offset
Elf64_Off e_shoff; // off: 40, size: 8 Section header table file offset
Elf64_Word e_flags; // off: 48, size: 4
Elf64_Half e_ehsize; // off: 52, size: 2
Elf64_Half e_phentsize; // off: 54, size: 2
Elf64_Half e_phnum; // off: 56, size: 2
Elf64_Half e_shentsize; // off: 58, size: 2
Elf64_Half e_shnum; // off: 60, size: 2
Elf64_Half e_shstrndx;
} Elf64_Ehdr;
typedef struct elf64_shdr {
Elf64_Word sh_name; /* 4 Section name, index in string tbl */
Elf64_Word sh_type; /* 4 Type of section */
Elf64_Xword sh_flags; /* 8 Miscellaneous section attributes */
Elf64_Addr sh_addr; /* 8 Section virtual addr at execution */
Elf64_Off sh_offset; /* 8 Section file offset */
Elf64_Xword sh_size; /* 8 Size of section in bytes */
Elf64_Word sh_link; /* 4 Index of another section */
Elf64_Word sh_info; /* 4 Additional section information */
Elf64_Xword sh_addralign; /* 8 Section alignment */
Elf64_Xword sh_entsize; /* 8 Entry size if section holds table */
} Elf64_Shdr;
定位 number of section headers
$ readelf -h /bin/ls|grep "Number of section"
Number of section headers: 30
$ hd /bin/ls -s 60 -n 2
0000003c 1e 00 |..|
0000003e
定位 section headers table
#!/bin/bash
# print_shdrs.sh
if [[ $1 ]]; then
target=$1
else
target="/bin/ls"
fi
echo "target:" $target
# 1. Number of section headers, offset: 60, size: 2
num=$[0x$(hd $target -s 60 -n 2 |awk '{print $3$2}')]
echo -n "Number of section headers:" $num
printf ' (0x%x)\\n' $num
# 2. Start of section headers, offset: 40, size: 8
off=$[0x$(hd $target -s 40 -n 8|awk '{print $9$8$7$6$5$4$3$2}')]
echo -n "Start of section headers:" $off
printf ' (0x%x)\\n\\n' $off
# 3. Section headers
echo "********************** Section headers *************************************"
echo -n "Section headers start:" $off
printf ' (0x%x)\\n' $off
echo -n "Section headers end:" $[$off + 64 * $num]
printf ' (0x%x)\\n' $[$off + 64 * $num]
for i in $(seq 1 $num)
do
echo "[$[$i - 1]]"
hd $target -s $[$off + 64*($i-1)] -n 64
echo "******************************************************************************"
done