@@ -67,6 +67,29 @@ def calculate_sh_offset(elf, vaddr):
67
67
if p_vaddr <= vaddr < (p_vaddr + p_filesz ):
68
68
return p_offset + (vaddr - p_vaddr )
69
69
raise Exception (f"Cannot find segment containing address { vaddr :#x} " )
70
+
71
+ @staticmethod
72
+ def create_reloc_section (elf ,name , is_rela , addr , size , entsize , sym_idx ):
73
+ if not addr or not size :
74
+ return None
75
+ if elf .elfclass == 32 :
76
+ entsize = entsize or (12 if is_rela else 8 )
77
+ else : # 64 bit
78
+ entsize = entsize or (24 if is_rela else 16 )
79
+ fake_rel_header = Container (
80
+ sh_name = 0 ,
81
+ sh_type = 'SHT_RELA' if is_rela else 'SHT_REL' ,
82
+ sh_flags = SH_FLAGS .SHF_ALLOC ,
83
+ sh_addr = addr ,
84
+ sh_offset = Modules .calculate_sh_offset (elf , addr ),
85
+ sh_size = size ,
86
+ sh_link = sym_idx ,
87
+ sh_info = 0 ,
88
+ sh_addralign = 8 if elf .elfclass == 64 else 4 ,
89
+ sh_entsize = entsize
90
+
91
+ )
92
+ return RelocationSection (fake_rel_header , name , elf )
70
93
71
94
def load_module (self , filename ):
72
95
logger .debug ("Loading module '%s'." % filename )
@@ -114,24 +137,23 @@ def load_module(self, filename):
114
137
self .emu .uc .mem_map (seg_addr , seg_size , prot )
115
138
self .emu .uc .mem_write (load_base + segment .header .p_vaddr , segment .data ())
116
139
117
- rel_section = None
118
- for section in elf .iter_sections ():
119
- if not isinstance (section , RelocationSection ):
120
- continue
121
- rel_section = section
122
- break
140
+ rel_sections = []
123
141
124
142
# Parse section header (Linking view).
125
143
dynsym = elf .get_section_by_name (".dynsym" )
126
144
dynstr = elf .get_section_by_name (".dynstr" )
127
145
128
- # Find rel section if not found.
129
- if rel_section is None or dynsym is None or dynstr is None :
146
+ # Find relocation table and symbol table by dynamic segment
147
+ if dynsym is None or dynstr is None :
130
148
rel_info = {
131
149
'rel' : {'addr' : None , 'size' : None , 'entsize' : None , 'count' : None },
132
150
'rela' : {'addr' : None , 'size' : None , 'entsize' : None , 'count' : None },
151
+ 'jmprel' : {'addr' : None , 'size' : None , 'entsize' : None },
152
+ 'android_rela' : {'addr' : None , 'size' : None , 'entsize' : None },
153
+ 'relr' : {'addr' : None , 'size' : None , 'entsize' : None },
154
+ 'pltrel' : None , # DT_PLTREL
155
+ 'textrel' : False , # DT_TEXTREL
133
156
'sym' : None ,
134
- 'type' : None
135
157
}
136
158
137
159
sym_info = {
@@ -174,35 +196,52 @@ def load_module(self, filename):
174
196
elif tag .entry .d_tag == 'DT_SYMENT' :
175
197
sym_info ['dynsym' ]['entsize' ] = tag .entry .d_val
176
198
177
- if rel_section is None :
178
- if rel_info ['rel' ]['addr' ] and rel_info ['rel' ]['size' ]:
179
- rel_info ['type' ] = 'REL'
180
- active_rel = rel_info ['rel' ]
181
- has_reloc_info = True
182
- elif rel_info ['rela' ]['addr' ] and rel_info ['rela' ]['size' ]:
183
- rel_info ['type' ] = 'RELA'
184
- active_rel = rel_info ['rela' ]
185
- has_reloc_info = True
186
- else :
187
- has_reloc_info = False
188
-
189
- if has_reloc_info and active_rel ['addr' ] and active_rel ['size' ] and active_rel ['entsize' ]:
190
- is_rela = rel_info ['type' ] == 'RELA'
191
- fake_rel_header = Container (
192
- sh_name = 0 , # we don't know the name
193
- sh_type = 'SHT_RELA' if is_rela else 'SHT_REL' ,
194
- sh_flags = SH_FLAGS .SHF_ALLOC ,
195
- sh_addr = active_rel ['addr' ],
196
- sh_offset = self .calculate_sh_offset (elf , active_rel ['addr' ]),
197
- sh_size = active_rel ['size' ],
198
- sh_link = rel_info ['sym' ], # link to dynsym
199
- sh_info = 0 ,
200
- sh_addralign = 8 if elf .elfclass == 64 else 4 ,
201
- sh_entsize = active_rel ['entsize' ]
202
- )
203
- rel_section = RelocationSection (fake_rel_header ,
204
- '.rela.dyn' if is_rela else '.rel.dyn' ,
205
- elf )
199
+ # other Relocation information
200
+ elif tag .entry .d_tag == 'DT_TEXTREL' :
201
+ rel_info ['textrel' ] = True
202
+ elif tag .entry .d_tag == 'DT_PLTREL' :
203
+ rel_info ['pltrel' ] = 'RELA' if tag .entry .d_val == 7 else 'REL'
204
+ elif tag .entry .d_tag == 'DT_JMPREL' :
205
+ rel_info ['jmprel' ]['addr' ] = tag .entry .d_val
206
+ elif tag .entry .d_tag == 'DT_PLTRELSZ' :
207
+ rel_info ['jmprel' ]['size' ] = tag .entry .d_val
208
+ elif tag .entry .d_tag == 'DT_ANDROID_RELA' :
209
+ rel_info ['android_rela' ]['addr' ] = tag .entry .d_val
210
+ elif tag .entry .d_tag == 'DT_ANDROID_RELASZ' :
211
+ rel_info ['android_rela' ]['size' ] = tag .entry .d_val
212
+ elif tag .entry .d_tag == 'DT_ANDROID_RELR' :
213
+ rel_info ['relr' ]['addr' ] = tag .entry .d_val
214
+ elif tag .entry .d_tag == 'DT_ANDROID_RELRSZ' :
215
+ rel_info ['relr' ]['size' ] = tag .entry .d_val
216
+
217
+ if rel_info ['rel' ]['addr' ] and rel_info ['rel' ]['size' ]:
218
+ rel_info ['type' ] = 'REL'
219
+ active_rel = rel_info ['rel' ]
220
+ has_reloc_info = True
221
+ elif rel_info ['rela' ]['addr' ] and rel_info ['rela' ]['size' ]:
222
+ rel_info ['type' ] = 'RELA'
223
+ active_rel = rel_info ['rela' ]
224
+ has_reloc_info = True
225
+ else :
226
+ has_reloc_info = False
227
+
228
+ if has_reloc_info and active_rel ['addr' ] and active_rel ['size' ] and active_rel ['entsize' ]:
229
+ is_rela = rel_info ['type' ] == 'RELA'
230
+ fake_rel_header = Container (
231
+ sh_name = 0 , # we don't know the name,but it's not important
232
+ sh_type = 'SHT_RELA' if is_rela else 'SHT_REL' ,
233
+ sh_flags = SH_FLAGS .SHF_ALLOC ,
234
+ sh_addr = active_rel ['addr' ],
235
+ sh_offset = self .calculate_sh_offset (elf , active_rel ['addr' ]),
236
+ sh_size = active_rel ['size' ],
237
+ sh_link = rel_info ['sym' ], # link to dynsym
238
+ sh_info = 0 ,
239
+ sh_addralign = 8 if elf .elfclass == 64 else 4 ,
240
+ sh_entsize = active_rel ['entsize' ]
241
+ )
242
+ rel_sections .append (RelocationSection (fake_rel_header ,
243
+ '.rela.dyn' if is_rela else '.rel.dyn' ,
244
+ elf ))
206
245
207
246
# create dynsym and dynstr if not found
208
247
if dynstr is None or dynsym is None :
@@ -241,17 +280,63 @@ def load_module(self, filename):
241
280
)
242
281
dynsym = SymbolTableSection (fake_sym_header , '.dynsym' , elf , dynstr )
243
282
283
+ # create all fake relocation section
284
+ if rel_info ['rel' ]['addr' ]:
285
+ rel = self .create_reloc_section (elf ,'.rel.dyn' , False ,
286
+ rel_info ['rel' ]['addr' ],
287
+ rel_info ['rel' ]['size' ],
288
+ rel_info ['rel' ]['entsize' ],
289
+ rel_info ['sym' ])
290
+ if rel :
291
+ rel_sections .append (rel )
292
+
293
+ if rel_info ['rela' ]['addr' ]:
294
+ rela = self .create_reloc_section (elf ,'.rela.dyn' , True ,
295
+ rel_info ['rela' ]['addr' ],
296
+ rel_info ['rela' ]['size' ],
297
+ rel_info ['rela' ]['entsize' ],
298
+ rel_info ['sym' ])
299
+ if rela :
300
+ rel_sections .append (rela )
301
+
302
+ if rel_info ['jmprel' ]['addr' ]:
303
+ is_rela = rel_info ['pltrel' ] == 'RELA'
304
+ jmprel = self .create_reloc_section (elf ,'.rela.plt' if is_rela else '.rel.plt' ,
305
+ is_rela ,
306
+ rel_info ['jmprel' ]['addr' ],
307
+ rel_info ['jmprel' ]['size' ],
308
+ rel_info ['jmprel' ]['entsize' ],
309
+ rel_info ['sym' ])
310
+ if jmprel :
311
+ rel_sections .append (jmprel )
312
+
313
+ if rel_info ['android_rela' ]['addr' ]:
314
+ android_rela = self .create_reloc_section (elf ,'.rela.android' , True ,
315
+ rel_info ['android_rela' ]['addr' ],
316
+ rel_info ['android_rela' ]['size' ],
317
+ rel_info ['android_rela' ]['entsize' ],
318
+ rel_info ['sym' ])
319
+ if android_rela :
320
+ rel_sections .append (android_rela )
321
+
244
322
# Find init array.
245
323
init_array_size = 0
246
324
init_array_offset = 0
247
325
init_array = []
326
+ init = None
248
327
for x in elf .iter_segments ():
249
328
if x .header .p_type == "PT_DYNAMIC" :
250
329
for tag in x .iter_tags ():
251
330
if tag .entry .d_tag == "DT_INIT_ARRAYSZ" :
252
331
init_array_size = tag .entry .d_val
253
332
elif tag .entry .d_tag == "DT_INIT_ARRAY" :
254
333
init_array_offset = tag .entry .d_val
334
+ elif tag .entry .d_tag == "DT_INIT" :
335
+ init = tag .entry .d_val
336
+
337
+ # DT_INIT should be called before DT_INIT_ARRAY if both are present
338
+ if init :
339
+ init = load_base + init
255
340
256
341
for _ in range (int (init_array_size / 4 )):
257
342
# covert va to file offset
@@ -267,23 +352,22 @@ def load_module(self, filename):
267
352
# print ("find init array for :%s %x" % (filename, fun_ptr))
268
353
else :
269
354
# search in reloc
270
- for rel in rel_section .iter_relocations ():
271
- rel_info_type = rel ['r_info_type' ]
272
- rel_addr = rel ['r_offset' ]
273
- if rel_info_type == arm .R_ARM_ABS32 and rel_addr == init_array_offset :
274
- sym = dynsym .get_symbol (rel ['r_info_sym' ])
275
- sym_value = sym ['st_value' ]
276
- init_array .append (load_base + sym_value )
277
- # print ("find init array for :%s %x" % (filename, sym_value))
278
- break
355
+ for rel_section in rel_sections :
356
+ for rel in rel_section .iter_relocations ():
357
+ rel_info_type = rel ['r_info_type' ]
358
+ rel_addr = rel ['r_offset' ]
359
+ if rel_info_type == arm .R_ARM_ABS32 and rel_addr == init_array_offset :
360
+ sym = dynsym .get_symbol (rel ['r_info_sym' ])
361
+ sym_value = sym ['st_value' ]
362
+ init_array .append (load_base + sym_value )
363
+ # print ("find init array for :%s %x" % (filename, sym_value))
364
+ break
365
+ break
279
366
init_array_offset += 4
280
367
281
368
# Resolve all symbols.
282
369
symbols_resolved = dict ()
283
370
284
- # for section in elf.iter_sections():
285
- # if not isinstance(section, SymbolTableSection):
286
- # continue
287
371
if dynsym :
288
372
itersymbols = dynsym .iter_symbols ()
289
373
next (itersymbols ) # Skip first symbol which is always NULL.
@@ -292,13 +376,23 @@ def load_module(self, filename):
292
376
if symbol_address is not None :
293
377
# TODO: Maybe we need to do something with uname symbols?
294
378
symbols_resolved [symbol .name ] = SymbolResolved (symbol_address , symbol )
379
+
380
+ # only for debug and call local function by symbol name directly, not by address.
381
+ for section in elf .iter_sections ():
382
+ if not isinstance (section , SymbolTableSection ):
383
+ continue
384
+ for symbol in itersymbols :
385
+ symbol_address = self ._elf_get_symval (elf , load_base , symbol )
386
+ if symbol_address is not None and symbol .name not in symbols_resolved :
387
+ symbols_resolved [symbol .name ] = SymbolResolved (symbol_address , symbol )
295
388
296
389
# Relocate.
297
- # for section in elf.iter_sections():
298
- # if not isinstance(section, RelocationSection):
299
- # continue
300
- if rel_section :
301
- for rel in rel_section .iter_relocations ():
390
+ processed_relocs = set () # Keep track of processed relocations to avoid double processing.
391
+
392
+ # process relocation in DT_DYNAMIC first
393
+ for section in rel_sections :
394
+ processed_relocs .add (section .header .sh_addr )
395
+ for rel in section .iter_relocations ():
302
396
sym = dynsym .get_symbol (rel ['r_info_sym' ])
303
397
sym_value = sym ['st_value' ]
304
398
@@ -341,6 +435,54 @@ def load_module(self, filename):
341
435
else :
342
436
logger .error ("Unhandled relocation type %i." % rel_info_type )
343
437
438
+ # then process relocation in Section Header(in fact, it's not necessary most of the time)
439
+ for section in elf .iter_sections ():
440
+ if isinstance (section , RelocationSection ):
441
+ if section .header .sh_addr in processed_relocs :
442
+ continue
443
+ for rel in section .iter_relocations ():
444
+ sym = dynsym .get_symbol (rel ['r_info_sym' ])
445
+ sym_value = sym ['st_value' ]
446
+
447
+ rel_addr = load_base + rel ['r_offset' ] # Location where relocation should happen
448
+ rel_info_type = rel ['r_info_type' ]
449
+
450
+ # https://static.docs.arm.com/ihi0044/e/IHI0044E_aaelf.pdf
451
+ # Relocation table for ARM
452
+ if rel_info_type == arm .R_ARM_ABS32 :
453
+ # Read value.
454
+ offset = int .from_bytes (self .emu .uc .mem_read (rel_addr , 4 ), byteorder = 'little' )
455
+ # Create the new value.
456
+ value = load_base + sym_value + offset
457
+ # Check thumb.
458
+ if sym ['st_info' ]['type' ] == 'STT_FUNC' :
459
+ value = value | 1
460
+ # Write the new value
461
+ self .emu .uc .mem_write (rel_addr , value .to_bytes (4 , byteorder = 'little' ))
462
+ elif rel_info_type == arm .R_ARM_GLOB_DAT or \
463
+ rel_info_type == arm .R_ARM_JUMP_SLOT :
464
+ # Resolve the symbol.
465
+ if sym .name in symbols_resolved :
466
+ value = symbols_resolved [sym .name ].address
467
+
468
+ # Write the new value
469
+ self .emu .uc .mem_write (rel_addr , value .to_bytes (4 , byteorder = 'little' ))
470
+ elif rel_info_type == arm .R_ARM_RELATIVE :
471
+ if sym_value == 0 :
472
+ # Load address at which it was linked originally.
473
+ value_orig_bytes = self .emu .uc .mem_read (rel_addr , 4 )
474
+ value_orig = int .from_bytes (value_orig_bytes , byteorder = 'little' )
475
+
476
+ # Create the new value
477
+ value = load_base + value_orig
478
+
479
+ # Write the new value
480
+ self .emu .uc .mem_write (rel_addr , value .to_bytes (4 , byteorder = 'little' ))
481
+ else :
482
+ raise NotImplementedError ()
483
+ else :
484
+ logger .error ("Unhandled relocation type %i." % rel_info_type )
485
+
344
486
# Store information about loaded module.
345
487
module = Module (filename , load_base , bound_high - bound_low , symbols_resolved , init_array )
346
488
self .modules .append (module )
0 commit comments