1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
use std::fs;
use crate::arch::test::*;
use crate::*;
#[test]
fn load_pie_elf() {
init();
let binary_blob = fs::read("test/test.aarch64").expect("Can't read binary");
let binary = ElfBinary::new(binary_blob.as_slice()).expect("Got proper ELF file");
assert!(binary.is_pie());
let mut loader = TestLoader::new(0x1000_0000);
binary.load(&mut loader).expect("Can't load?");
for action in loader.actions.iter() {
println!("{:?}", action);
}
// View allocate/load actions with readelf -l [binary]
// Program Headers:
// Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
// PHDR 0x000040 0x0000000000000040 0x0000000000000040 0x0001f8 0x0001f8 R 0x8
// INTERP 0x000238 0x0000000000000238 0x0000000000000238 0x00001b 0x00001b R 0x1
// [Requesting program interpreter: /lib/ld-linux-aarch64.so.1]
// LOAD 0x000000 0x0000000000000000 0x0000000000000000 0x0008cc 0x0008cc R E 0x10000
// LOAD 0x000d90 0x0000000000010d90 0x0000000000010d90 0x000280 0x000288 RW 0x10000
// DYNAMIC 0x000da0 0x0000000000010da0 0x0000000000010da0 0x0001f0 0x0001f0 RW 0x8
// NOTE 0x000254 0x0000000000000254 0x0000000000000254 0x000044 0x000044 R 0x4
// GNU_EH_FRAME 0x0007e4 0x00000000000007e4 0x00000000000007e4 0x00003c 0x00003c R 0x4
// GNU_STACK 0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RW 0x10
// GNU_RELRO 0x000d90 0x0000000000010d90 0x0000000000010d90 0x000270 0x000270 R 0x1
assert_eq!(
loader.actions[0],
LoaderAction::Allocate(VAddr::from(0x0u64), 0x8cc, Flags(1 | 4))
);
assert_eq!(
loader.actions[1],
LoaderAction::Allocate(VAddr::from(0x10d90u64), 0x288, Flags(0b110))
);
assert_eq!(
loader.actions[2],
LoaderAction::Load(VAddr::from(0x0u64), 0x8cc)
);
assert_eq!(
loader.actions[3],
LoaderAction::Load(VAddr::from(0x10d90u64), 0x280)
);
// View relocation actions with readelf -r [binary]
// Relocation section '.rela.dyn' at offset 0x480 contains 8 entries:
// Offset Info Type Symbol's Value Symbol's Name + Addend
// 0000000000010d90 0000000000000403 R_AARCH64_RELATIVE 750
// 0000000000010d98 0000000000000403 R_AARCH64_RELATIVE 700
// 0000000000010ff0 0000000000000403 R_AARCH64_RELATIVE 754
// 0000000000011008 0000000000000403 R_AARCH64_RELATIVE 11008
// 0000000000010fd8 0000000400000401 R_AARCH64_GLOB_DAT 0000000000000000 _ITM_deregisterTMCloneTable + 0
// 0000000000010fe0 0000000500000401 R_AARCH64_GLOB_DAT 0000000000000000 __cxa_finalize@GLIBC_2.17 + 0
// 0000000000010fe8 0000000600000401 R_AARCH64_GLOB_DAT 0000000000000000 __gmon_start__ + 0
// 0000000000010ff8 0000000800000401 R_AARCH64_GLOB_DAT 0000000000000000 _ITM_registerTMCloneTable + 0
//
// Relocation section '.rela.plt' at offset 0x540 contains 5 entries:
// Offset Info Type Symbol's Value Symbol's Name + Addend
// 0000000000010fa8 0000000300000402 R_AARCH64_JUMP_SLOT 0000000000000000 __libc_start_main@GLIBC_2.34 + 0
// 0000000000010fb0 0000000500000402 R_AARCH64_JUMP_SLOT 0000000000000000 __cxa_finalize@GLIBC_2.17 + 0
// 0000000000010fb8 0000000600000402 R_AARCH64_JUMP_SLOT 0000000000000000 __gmon_start__ + 0
// 0000000000010fc0 0000000700000402 R_AARCH64_JUMP_SLOT 0000000000000000 abort@GLIBC_2.17 + 0
// 0000000000010fc8 0000000900000402 R_AARCH64_JUMP_SLOT 0000000000000000 printf@GLIBC_2.17 + 0
assert_eq!(
loader.actions[4],
LoaderAction::Relocate(0x1000_0000 + 0x10d90, 0x1000_0750)
);
assert_eq!(
loader.actions[5],
LoaderAction::Relocate(0x1000_0000 + 0x10d98, 0x1000_0700)
);
assert_eq!(
loader.actions[6],
LoaderAction::Relocate(0x1000_0000 + 0x10ff0, 0x1000_0754)
);
assert_eq!(
loader.actions[7],
LoaderAction::Relocate(0x1000_0000 + 0x11008, 0x1001_1008)
);
// R_AARCH64_GLOB_DAT entries next, but we ignore them in the test loader:
/*assert_eq!(
loader.actions[8],
LoaderAction::Relocate(0x1000_0000 + 0x10fd8, 0x1000_0000)
);
assert_eq!(
loader.actions[9],
LoaderAction::Relocate(0x1000_0000 + 0x10fe0, 0x1000_0000)
);
assert_eq!(
loader.actions[10],
LoaderAction::Relocate(0x1000_0000 + 0x10fe8, 0x1000_0000)
);
assert_eq!(
loader.actions[11],
LoaderAction::Relocate(0x1000_0000 + 0x10ff8, 0x1000_0000)
);*/
assert_eq!(loader.actions.len(), 8);
}
#[test]
fn check_nopie() {
init();
let binary_blob = fs::read("test/test_nopie.aarch64").expect("Can't read binary");
let binary = ElfBinary::new(binary_blob.as_slice()).expect("Got proper ELF file");
assert!(!binary.is_pie());
}
#[test]
fn check_tls() {
init();
let binary_blob = fs::read("test/tls.aarch64").expect("Can't read binary");
let binary = ElfBinary::new(binary_blob.as_slice()).expect("Got proper ELF file");
let mut loader = TestLoader::new(0x1000_0000);
binary.load(&mut loader).expect("Can't load?");
/*
TLS produces entries of this form:
pheader = Program header:
type: Ok(Tls)
flags: R
offset: 0xdb4
virtual address: 0x200db4
physical address: 0x200db4
file size: 0x4
memory size: 0x8
align: 0x4
File size is 0x4 because we have one tdata entry; memory size
is 8 because we also have one bss entry that needs to be written with zeroes.
So to initialize TLS: we allocate zeroed memory of size `memory size`, then copy
file size starting at virtual address in the beginning.
*/
assert!(loader
.actions
.iter()
.find(|&&x| x == LoaderAction::Tls(VAddr::from(0x10d8cu64), 0x4, 0x8, 0x4))
.is_some());
}