1 /*
2 ** remap.c for elfsh
3 **
4 ** elfsh_reloc_pht/sht/symtab() are based on spacewalker's
5 ** original modremap.c
6 **
7 ** Started on Mon Mar 17 09:30:33 2003 mayhem
8 ** Last update Tue Jun 3 14:01:26 2003 mayhem
9 */
10 #include "libelfsh.h"
11
12
13 /* Remap the Program Header Table */
elfsh_reloc_pht(elfshobj_t * file,u_long diff)14 int elfsh_reloc_pht(elfshobj_t *file, u_long diff)
15 {
16 u_int i;
17 u_int count;
18 u_long base;
19
20 base = elfsh_get_object_baseaddr(file);
21 if (file == NULL || file->pht == NULL || file->hdr->e_phnum == 0)
22 ELFSH_SETERROR("[libelfsh:reloc_pht] Invalid NULL parameter\n", 0);
23 for (count = i = 0; i < file->hdr->e_phnum; i++)
24 {
25 if (file->pht[i].p_vaddr >= base)
26 {
27 file->pht[i].p_vaddr += diff;
28 count++;
29 }
30 if (file->pht[i].p_paddr >= base)
31 {
32 file->pht[i].p_paddr += diff;
33 count++;
34 }
35 }
36 return (count);
37 }
38
39 /* Remap the Section Header Table */
elfsh_reloc_sht(elfshobj_t * file,u_long diff)40 int elfsh_reloc_sht(elfshobj_t *file, u_long diff)
41 {
42 u_int i;
43 u_int count;
44 u_long base;
45
46 if (file == NULL || file->sht == NULL || file->hdr->e_shnum == 0)
47 ELFSH_SETERROR("[libelfsh:reloc_sht] Invalid NULL parameter\n", -1);
48 base = elfsh_get_object_baseaddr(file);
49 for (count = i = 0; i < file->hdr->e_shnum; i++)
50 if (file->sht[i].sh_addr > base)
51 {
52 file->sht[i].sh_addr += diff;
53 count++;
54 }
55 return (count);
56 }
57
58
59
60 /* Remap a section which type is SHT_SYMTAB or SHT_DYNSYM */
elfsh_reloc_symtab(elfshsect_t * s,u_long diff)61 int elfsh_reloc_symtab(elfshsect_t *s, u_long diff)
62 {
63 Elf32_Sym *symtab;
64 u_int i;
65 u_int vaddr;
66 u_int count;
67 u_long base;
68
69 if (s == NULL || s->shdr == NULL)
70 ELFSH_SETERROR("[libelfsh:reloc_symtab] Invalid NULL parameter\n", -1);
71 else if (s->shdr->sh_type != SHT_SYMTAB && s->shdr->sh_type != SHT_DYNSYM)
72 ELFSH_SETERROR("[libelfsh:reloc_symtab] Unexpected section type\n", -1);
73 symtab = s->data;
74 base = elfsh_get_object_baseaddr(s->parent);
75 for (count = i = 0; i < s->shdr->sh_size / sizeof(Elf32_Sym); i++)
76 {
77 vaddr = elfsh_get_symbol_value(symtab + i);
78 if (vaddr > base)
79 {
80 elfsh_set_symbol_value(symtab + i, vaddr + diff);
81 count++;
82 }
83 }
84
85 /* Synchronize the symtab hash table */
86 elfsh_sync_sorted_symtab(s);
87 return (count);
88 }
89
90
91 /* Remap a section using its extra relocation entries */
elfsh_reloc_raw(elfshsect_t * cur,u_long diff)92 int elfsh_reloc_raw(elfshsect_t *cur, u_long diff)
93 {
94 u_int index;
95 u_long addr;
96 elfshsect_t *target;
97 char *str;
98
99 if (cur == NULL || cur->shdr == NULL)
100 ELFSH_SETERROR("[libelfsh:reloc_raw] Invalid NULL parameter\n", -1);
101 if (cur->data == NULL || cur->rel == NULL)
102 return (0);
103
104 /* Read the actual section and find valid references */
105 for (index = 0; index < cur->srcref; index++)
106 switch (cur->rel[index].type)
107 {
108
109 /* Relocate by : section[idx_dst].vaddr + off_dst */
110 case ELFSH_RELOC_SECTBASE:
111 target = elfsh_get_section_by_index(cur->parent,
112 cur->rel[index].idx_dst,
113 NULL, NULL);
114 if (target == NULL)
115 ELFSH_SETERROR("[libelfsh:reloc_raw] Invalid IDX_DST\n", -1);
116 str = cur->data + cur->rel[index].off_src;
117 addr = target->shdr->sh_addr + cur->rel[index].off_dst + diff;
118 memcpy(str, &addr, sizeof(u_long));
119
120 /* Do not relocate */
121 case ELFSH_RELOC_FP:
122 default:
123 break;
124 }
125
126 return (cur->srcref);
127 }
128
129
130
131 /* Remap the .dynamic section */
elfsh_reloc_dynamic(elfshsect_t * sect,u_long diff)132 int elfsh_reloc_dynamic(elfshsect_t *sect, u_long diff)
133 {
134 elfshsect_t *parent;
135 Elf32_Dyn *dyn;
136 u_int index;
137 u_int count;
138 u_long val;
139 u_int nbr;
140
141 if (sect == NULL || sect->shdr == NULL)
142 ELFSH_SETERROR("[libelfsh:reloc_rel] Invalid NULL parameter\n", -1);
143 else if (sect->shdr->sh_type != SHT_DYNAMIC)
144 ELFSH_SETERROR("[libelfsh:reloc_rel] Unexpected section type\n", -1);
145
146 nbr = sect->shdr->sh_size / sizeof(Elf32_Dyn);
147 for (dyn = sect->data, count = index = 0; index < nbr; index++)
148 {
149 val = elfsh_get_dynentry_val(dyn + index);
150 parent = elfsh_get_parent_section(sect->parent, val, NULL);
151 if (val && parent != NULL && parent->shdr->sh_addr != NULL)
152 {
153 elfsh_set_dynentry_val(dyn + index, val + diff);
154 count++;
155 }
156 }
157 return (count);
158 }
159
160
161 /* Remap sections of type SHT_REL and SHT_RELA */
elfsh_reloc_rel(elfshsect_t * sect,u_long diff)162 int elfsh_reloc_rel(elfshsect_t *sect, u_long diff)
163 {
164 elfshsect_t *parent;
165 Elf32_Rel *rel;
166 u_int index;
167 u_int count;
168 u_int nbr;
169
170 if (sect == NULL || sect->shdr == NULL)
171 ELFSH_SETERROR("[libelfsh:reloc_rel] Invalid NULL parameter\n", -1);
172 else if (sect->shdr->sh_type != SHT_REL && sect->shdr->sh_type != SHT_RELA)
173 ELFSH_SETERROR("[libelfsh:reloc_rel] Unexpected section type\n", -1);
174
175 nbr = sect->shdr->sh_size / sizeof(Elf32_Rel);
176 for (rel = sect->data, count = index = 0; index < nbr; index++)
177 {
178 parent = elfsh_get_parent_section(sect->parent,
179 rel[index].r_offset,
180 NULL);
181 if (rel[index].r_offset && parent != NULL && parent->shdr->sh_addr != NULL)
182 {
183 rel[index].r_offset += diff;
184 count++;
185 }
186 }
187 return (count);
188 }
189
190
191
192 /* Remap section's whoose type is a data array (GOT, CTORS, DTORS ..) */
elfsh_reloc_array(elfshobj_t * file,u_long * array,u_int size,u_long diff)193 int elfsh_reloc_array(elfshobj_t *file, u_long *array, u_int size, u_long diff)
194 {
195 elfshsect_t *parent;
196 u_int index;
197 u_int count;
198
199 if (file == NULL || array == NULL)
200 ELFSH_SETERROR("[libelfsh:reloc_array] Invalid NULL paramater\n", -1);
201 for (count = index = 0; index < size; index++)
202 {
203 parent = elfsh_get_parent_section(file, array[index], NULL);
204 if (parent != NULL && parent->shdr->sh_addr != NULL && array[index] != NULL)
205 {
206 array[index] += diff;
207 count++;
208 }
209 }
210 return (count);
211 }
212
213
214 /* Remap Global Offset Table */
elfsh_reloc_got(elfshsect_t * sect,u_long diff)215 int elfsh_reloc_got(elfshsect_t *sect, u_long diff)
216 {
217 if (sect == NULL || sect->shdr == NULL)
218 ELFSH_SETERROR("[libelfsh:reloc_got] Invalid NULL parameter\n", -1);
219 else if (strcmp(sect->name, ELFSH_SECTION_NAME_GOT))
220 ELFSH_SETERROR("[libelfsh:reloc_got] Unexpected section name\n", -1);
221 return (elfsh_reloc_array(sect->parent, sect->data,
222 sect->shdr->sh_size / sizeof(u_long), diff));
223 }
224
225 /* Remap .ctors section */
elfsh_reloc_ctors(elfshsect_t * sect,u_long diff)226 int elfsh_reloc_ctors(elfshsect_t *sect, u_long diff)
227 {
228 if (sect == NULL || sect->shdr == NULL)
229 ELFSH_SETERROR("[libelfsh:reloc_ctors] Invalid NULL parameter\n", -1);
230 else if (strcmp(sect->name, ELFSH_SECTION_NAME_CTORS))
231 ELFSH_SETERROR("[libelfsh:reloc_ctors] Unexpected section name\n", -1);
232 return (elfsh_reloc_array(sect->parent, sect->data,
233 sect->shdr->sh_size / sizeof(u_long), diff));
234 }
235
236 /* Remap .dtors section */
elfsh_reloc_dtors(elfshsect_t * sect,u_long diff)237 int elfsh_reloc_dtors(elfshsect_t *sect, u_long diff)
238 {
239 if (sect == NULL || sect->shdr == NULL)
240 ELFSH_SETERROR("[libelfsh:reloc_dtors] Invalid NULL parameter\n", -1);
241 else if (strcmp(sect->name, ELFSH_SECTION_NAME_DTORS))
242 ELFSH_SETERROR("[libelfsh:reloc_dtors] Unexpected section name\n", -1);
243 return (elfsh_reloc_array(sect->parent, sect->data,
244 sect->shdr->sh_size / sizeof(u_long), diff));
245 }
246
247
248 /* Not used ATM since it triggers more false positives ;P */
elfsh_reloc_hash(elfshsect_t * sect,u_long diff)249 int elfsh_reloc_hash(elfshsect_t *sect, u_long diff)
250 {
251 if (sect == NULL || sect->shdr == NULL)
252 ELFSH_SETERROR("[libelfsh:reloc_hash] Invalid NULL parameter\n", -1);
253 else if (sect->shdr->sh_type != SHT_HASH)
254 ELFSH_SETERROR("[libelfsh:reloc_hash] Unexpected section type\n", -1);
255 return (elfsh_reloc_array(sect->parent, sect->data,
256 sect->shdr->sh_size / sizeof(u_long), diff));
257 }
258
259
260 /* Call the type dependant remapping routine for this section */
elfsh_relocate_section(elfshsect_t * sect,u_long diff)261 int elfsh_relocate_section(elfshsect_t *sect, u_long diff)
262 {
263 int ret;
264
265 ret = 0;
266 if (sect == NULL || sect->data == NULL)
267 ELFSH_SETERROR("[libelfsh:reloc_section] Invalid NULL paramater\n", -1);
268 if (sect->shdr->sh_addr != NULL)
269 elfsh_find_rel(sect);
270
271 if (sect->shdr->sh_type == SHT_SYMTAB)
272 ret = elfsh_reloc_symtab(sect, diff);
273 else if (sect->shdr->sh_type == SHT_DYNSYM)
274 ret = elfsh_reloc_symtab(sect, diff);
275 else if (sect->shdr->sh_type == SHT_RELA || sect->shdr->sh_type == SHT_REL)
276 ret = elfsh_reloc_rel(sect, diff);
277 else if (sect->shdr->sh_type == SHT_DYNAMIC)
278 ret = elfsh_reloc_dynamic(sect, diff);
279 else if (!strcmp(sect->name, ELFSH_SECTION_NAME_CTORS))
280 ret = elfsh_reloc_ctors(sect, diff);
281 else if (!strcmp(sect->name, ELFSH_SECTION_NAME_DTORS))
282 ret = elfsh_reloc_dtors(sect, diff);
283 else if (!strcmp(sect->name, ELFSH_SECTION_NAME_GOT))
284 ret = elfsh_reloc_got(sect, diff);
285 else if (sect->shdr->sh_addr != NULL)
286 ret = elfsh_reloc_raw(sect, diff);
287 if (ret < 0)
288 return (-1);
289 return (ret);
290 }
291
292
293
294 /*
295 ** XXX .::. TODO for ET_EXEC to ET_DYN :
296 ** - Insertion a new .rel section
297 ** - Change objtype and entryp in ELF header
298 ** - Relocate PHT and SHT
299 ** - Change reloc section size in .dynamic *
300 */
elfsh_remap(elfshobj_t * file,Elf32_Addr new_addr)301 int elfsh_remap(elfshobj_t *file, Elf32_Addr new_addr)
302 {
303 elfshsect_t *sect;
304 u_int diff;
305 u_int count;
306 int ret;
307
308 count = 0;
309 if (file == NULL)
310 ELFSH_SETERROR("[libelfsh:relocate] Invalid NULL parameter\n", -1);
311 else if (elfsh_read_obj(file) < 0)
312 return (-1);
313 diff = elfsh_get_object_baseaddr(file);
314 if (diff == (u_int) -1);
315 ELFSH_SETERROR("[libelfsh:relocate] Object base address is NULL\n", -1);
316 for (sect = file->sectlist; sect != NULL; sect = sect->next)
317 {
318 ret = elfsh_relocate_section(sect, -diff);
319 printf("Relocation number found for %-20s : %d \n", sect->name, ret);
320 if (ret < 0)
321 return (-1);
322 count += ret;
323 }
324 return (count);
325 }
326