Rizin
unix-like reverse engineering framework and cli tools
elf_imports.c
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: 2021 08A <08A@riseup.net>
2 // SPDX-FileCopyrightText: 2008-2020 nibble <nibble.ds@gmail.com>
3 // SPDX-FileCopyrightText: 2008-2020 pancake <pancake@nopcode.org>
4 // SPDX-FileCopyrightText: 2008-2020 alvaro_fe <alvaro.felipe91@gmail.com>
5 // SPDX-License-Identifier: LGPL-3.0-only
6 
7 #include "elf.h"
8 
9 #define MIPS_PLT_OFFSET 0x20
10 #define RISCV_PLT_ENTRY_SIZE 0x10
11 #define RISCV_PLT_OFFSET 0x20
12 #define SPARC_OFFSET_PLT_ENTRY_FROM_GOT_ADDR -0x6
13 #define X86_OFFSET_PLT_ENTRY_FROM_GOT_ADDR -0x6
14 #define X86_PLT_ENTRY_SIZE 0x10
15 
16 #define COMPUTE_PLTGOT_POSITION(rel, pltgot_addr, n_initial_unused_entries) \
17  ((rel->vaddr - pltgot_addr - n_initial_unused_entries * sizeof(Elf_(Addr))) / sizeof(Elf_(Addr)))
18 
20  Elf_(Addr) addr;
21 
22  if (rel->paddr == UT64_MAX) {
23  return UT64_MAX;
24  }
25 
26  ut64 paddr = rel->paddr;
27  if (!Elf_(rz_bin_elf_read_addr)(bin, &paddr, &addr) || !addr) {
28  return UT64_MAX;
29  }
30 
31  return addr;
32 }
33 
35  ut64 jmprel_addr;
36  ut64 got_addr;
37  ut64 dt_pltrelsz;
38 
39  if (!Elf_(rz_bin_elf_get_dt_info)(bin, DT_JMPREL, &jmprel_addr) || !Elf_(rz_bin_elf_get_dt_info)(bin, DT_MIPS_PLTGOT, &got_addr) || !Elf_(rz_bin_elf_get_dt_info)(bin, DT_PLTRELSZ, &dt_pltrelsz)) {
40  return UT64_MAX;
41  }
42 
43  ut64 pos = COMPUTE_PLTGOT_POSITION(rel, got_addr, 0x2);
44 
45  ut8 buf[1024];
46  ut64 plt_addr = jmprel_addr + dt_pltrelsz;
47  ut64 p_plt_addr = Elf_(rz_bin_elf_v2p)(bin, plt_addr);
48  int res = rz_buf_read_at(bin->b, p_plt_addr, buf, sizeof(buf));
49  if (res != sizeof(buf)) {
50  return UT64_MAX;
51  }
52 
53  const ut8 *base = rz_mem_mem_aligned(buf, sizeof(buf), (const ut8 *)"\x3c\x0f\x00", 3, 4);
54  plt_addr += base ? (int)(size_t)(base - buf) : MIPS_PLT_OFFSET + 8; // HARDCODED HACK
55  plt_addr += pos * 16;
56 
57  return plt_addr;
58 }
59 
61  ut64 got_addr;
62 
63  if (!Elf_(rz_bin_elf_get_dt_info)(bin, DT_PLTGOT, &got_addr)) {
64  return UT64_MAX;
65  }
66 
67  ut64 plt_addr = get_got_entry(bin, rel);
68  if (plt_addr == UT64_MAX) {
69  return UT64_MAX;
70  }
71 
72  ut64 pos = COMPUTE_PLTGOT_POSITION(rel, got_addr, 0x2);
73  return plt_addr + RISCV_PLT_OFFSET + pos * RISCV_PLT_ENTRY_SIZE;
74 }
75 
77  if (rel->type != RZ_SPARC_JMP_SLOT) {
78  RZ_LOG_WARN("Unknown sparc reloc type %d\n", rel->type);
79  return UT64_MAX;
80  }
81  ut64 tmp = get_got_entry(bin, rel);
82 
84 }
85 
87  ut64 plt_addr;
88 
89  if (!Elf_(rz_bin_elf_get_dt_info)(bin, DT_PLTGOT, &plt_addr)) {
90  return UT64_MAX;
91  }
92 
93  ut64 p_plt_addr = Elf_(rz_bin_elf_v2p)(bin, plt_addr);
94  if (p_plt_addr == UT64_MAX) {
95  return UT64_MAX;
96  }
97 
98  ut32 tmp;
99  if (!rz_buf_read_ble32_at(bin->b, p_plt_addr, &tmp, bin->big_endian)) {
100  return UT64_MAX;
101  }
102 
104  ut64 pos = COMPUTE_PLTGOT_POSITION(rel, plt_addr, 0x0);
105 
106  ut64 base = tmp;
107 
108  if (bin->big_endian) {
109  base -= (nrel * 16);
110  base += (pos * 16);
111  return base;
112  }
113 
114  base -= (nrel * 12) + 20;
115  base += (pos * 8);
116 
117  return base;
118 }
119 
121  ut64 got_addr;
122 
123  if (!Elf_(rz_bin_elf_get_dt_info)(bin, DT_PLTGOT, &got_addr)) {
124  return UT64_MAX;
125  }
126 
127  ut64 got_offset = Elf_(rz_bin_elf_v2p)(bin, got_addr);
128  if (got_offset == UT64_MAX) {
129  return UT64_MAX;
130  }
131 
132  // XXX HACK ALERT!!!! full relro?? try to fix it
133  // will there always be .plt.got, what would happen if is .got.plt?
136  return UT64_MAX;
137  }
138 
139  ut64 plt_addr = s->offset;
140  Elf_(Word) plt_sym_addr;
141 
142  while (plt_addr + 2 + 4 < s->offset + s->size) {
143  /*we try to locate the plt entry that correspond with the relocation
144  since got does not point back to .plt. In this case it has the following
145  form
146  ff253a152000 JMP QWORD [RIP + 0x20153A]
147  6690 NOP
148  ----
149  ff25ec9f0408 JMP DWORD [reloc.puts_236]
150  plt_addr + 2 to remove jmp opcode and get the imm reading 4
151  and if RIP (plt_addr + 6) + imm == rel->offset
152  return plt_addr, that will be our sym addr
153  perhaps this hack doesn't work on 32 bits
154  */
155  ut64 pos = plt_addr + 2;
156 
157  if (!Elf_(rz_bin_elf_read_word)(bin, &pos, &plt_sym_addr)) {
158  return UT64_MAX;
159  }
160 
161  ut64 tmp = Elf_(rz_bin_elf_v2p)(bin, plt_sym_addr);
162  if (tmp == UT64_MAX) {
163  tmp = plt_sym_addr;
164  }
165 
166  // relative address
167  if ((plt_addr + 6 + tmp) == rel->vaddr) {
168  return plt_addr;
169  }
170 
171  if (plt_sym_addr == rel->vaddr) {
172  return plt_addr;
173  }
174 
175  plt_addr += 8;
176  }
177 
178  return UT64_MAX;
179 }
180 
182  ut64 tmp = get_got_entry(bin, rel);
183  if (tmp == UT64_MAX) {
184  return get_import_addr_x86_manual(bin, rel);
185  }
186 
187  RzBinElfSection *pltsec_section = Elf_(rz_bin_elf_get_section_with_name)(bin, ".plt.sec");
188 
189  if (pltsec_section) {
190  ut64 got_addr;
191 
192  if (!Elf_(rz_bin_elf_get_dt_info)(bin, DT_PLTGOT, &got_addr)) {
193  return UT64_MAX;
194  }
195 
196  ut64 pos = COMPUTE_PLTGOT_POSITION(rel, got_addr, 0x3);
197  return pltsec_section->rva + pos * X86_PLT_ENTRY_SIZE;
198  }
199 
201 }
202 
204  ut64 got_addr;
205 
206  if (!Elf_(rz_bin_elf_get_dt_info)(bin, DT_PLTGOT, &got_addr)) {
207  return UT64_MAX;
208  }
209 
210  ut64 plt_addr = get_got_entry(bin, rel);
211  if (plt_addr == UT64_MAX) {
212  return UT64_MAX;
213  }
214 
215  ut64 pos = COMPUTE_PLTGOT_POSITION(rel, got_addr, 0x3);
216 
217  switch (rel->type) {
218  case RZ_ARM_JUMP_SLOT:
219  plt_addr += pos * 12 + 20;
220  if (Elf_(rz_bin_elf_is_thumb_addr)(plt_addr)) {
221  plt_addr--;
222  }
223  return plt_addr;
224  case RZ_AARCH64_RELATIVE:
225  RZ_LOG_WARN("Unsupported relocation type for imports %d\n", rel->type);
226  return UT64_MAX;
228  if (rel->addend > plt_addr) { // start
229  return (plt_addr + pos * 16 + 32) + rel->addend;
230  }
231  // same as fallback to JUMP_SLOT
232  return plt_addr + pos * 16 + 32;
234  return plt_addr + pos * 16 + 32;
235  default:
236  RZ_LOG_WARN("Unsupported relocation type for imports %d\n", rel->type);
237  return UT64_MAX;
238  }
239  return UT64_MAX;
240 }
241 
243  switch (bin->ehdr.e_machine) {
244  case EM_ARM:
245  case EM_AARCH64:
246  return get_import_addr_arm(bin, reloc);
247  case EM_MIPS: // MIPS32 BIG ENDIAN relocs
248  return get_import_addr_mips(bin, reloc);
249  case EM_RISCV:
250  return get_import_addr_riscv(bin, reloc);
251  case EM_SPARC:
252  case EM_SPARCV9:
253  case EM_SPARC32PLUS:
254  return get_import_addr_sparc(bin, reloc);
255  case EM_PPC:
256  case EM_PPC64:
257  return get_import_addr_ppc(bin, reloc);
258  case EM_386:
259  case EM_X86_64:
260  return get_import_addr_x86(bin, reloc);
261  default:
262  RZ_LOG_WARN("Unsupported relocs type %" PFMT64u " for arch %d\n",
263  (ut64)reloc->type, bin->ehdr.e_machine);
264  return UT64_MAX;
265  }
266 }
267 
268 static ut64 get_import_addr(ELFOBJ *bin, ut64 symbol) {
270  return UT64_MAX;
271  }
272 
273  RzBinElfReloc *reloc;
275  if (reloc->sym != symbol) {
276  continue;
277  }
278 
279  ut64 tmp = get_import_addr_aux(bin, reloc);
280  if (tmp != UT64_MAX) {
281  return tmp;
282  }
283  }
284 
285  return UT64_MAX;
286 }
287 
289  return get_import_addr(bin, symbol->ordinal);
290 }
291 
293  if (symbol->vaddr && symbol->vaddr != UT64_MAX) {
294  return;
295  }
296 
297  symbol->vaddr = get_import_offset(bin, symbol);
298  if (symbol->vaddr == UT64_MAX) {
299  return;
300  }
301  symbol->size = 16;
302  symbol->paddr = Elf_(rz_bin_elf_v2p)(bin, symbol->vaddr);
303 }
304 
306  RzBinElfSymbol *symbol;
307  rz_vector_foreach(symbols, symbol) {
309  }
310 }
311 
312 static bool filter_import(ELFOBJ *bin, Elf_(Sym) * symbol, bool is_dynamic) {
313  return symbol->st_shndx == SHT_NULL && (is_dynamic || Elf_(rz_bin_elf_is_relocatable)(bin));
314 }
315 
318 
319  RzBinElfSymbol *import;
321  if (import->ordinal == ordinal) {
322  return import;
323  }
324  }
325 
326  return NULL;
327 }
328 
331 
333  if (!result) {
334  return NULL;
335  }
336 
338 
339  return result;
340 }
341 
343  rz_return_val_if_fail(bin, false);
344  return bin->imports;
345 }
RzList * symbols(RzBinFile *bf)
Definition: bin_ne.c:102
#define NULL
Definition: cris-opc.c:27
uint32_t ut32
ut64 Elf_() rz_bin_elf_v2p(RZ_NONNULL ELFOBJ *bin, ut64 vaddr)
Convert a virtual address to the physical address.
Definition: elf.c:429
bool Elf_() rz_bin_elf_has_dt_dynamic(RZ_NONNULL ELFOBJ *bin)
Definition: elf_dynamic.c:130
#define rz_bin_elf_foreach_relocs(bin, reloc)
Definition: elf.h:38
#define rz_bin_elf_foreach_imports(bin, import)
Definition: elf.h:50
bool Elf_() rz_bin_elf_read_addr(RZ_NONNULL ELFOBJ *bin, RZ_NONNULL RZ_INOUT ut64 *offset, RZ_NONNULL RZ_OUT Elf_(Addr) *result)
Definition: elf_misc.c:82
#define ELFOBJ
Definition: elf.h:24
bool Elf_() rz_bin_elf_has_relocs(RZ_NONNULL ELFOBJ *bin)
Definition: elf_relocs.c:239
bool Elf_() rz_bin_elf_is_thumb_addr(ut64 addr)
Definition: elf_arm.c:24
bool Elf_() rz_bin_elf_read_word(RZ_NONNULL ELFOBJ *bin, RZ_NONNULL RZ_INOUT ut64 *offset, RZ_NONNULL RZ_OUT Elf_(Word) *result)
Definition: elf_misc.c:62
RZ_OWN RzVector *Elf_() rz_bin_elf_compute_symbols(ELFOBJ *bin, RzBinElfSymbolFilter filter)
Definition: elf_symbols.c:486
RZ_BORROW RzBinElfSection *Elf_() rz_bin_elf_get_section_with_name(RZ_NONNULL ELFOBJ *bin, RZ_NONNULL const char *name)
Definition: elf_sections.c:278
bool Elf_() rz_bin_elf_get_dt_info(RZ_NONNULL ELFOBJ *bin, ut64 key, RZ_OUT ut64 *info)
Definition: elf_dynamic.c:120
ut64 Elf_() rz_bin_elf_get_num_relocs_dynamic_plt(RZ_NONNULL ELFOBJ *bin)
Definition: elf_relocs.c:255
#define RZ_BIN_ELF_PART_RELRO
Definition: elf.h:21
bool Elf_() rz_bin_elf_is_relocatable(RZ_NONNULL ELFOBJ *bin)
Check if the elf binary is relocatable.
Definition: elf_info.c:1662
int Elf_() rz_bin_elf_has_relro(RZ_NONNULL ELFOBJ *bin)
Analyse if the elf binary has relro or partial relro.
Definition: elf_info.c:1733
#define X86_OFFSET_PLT_ENTRY_FROM_GOT_ADDR
Definition: elf_imports.c:13
static bool filter_import(ELFOBJ *bin, Elf_(Sym) *symbol, bool is_dynamic)
Definition: elf_imports.c:312
#define MIPS_PLT_OFFSET
Definition: elf_imports.c:9
RZ_BORROW RzBinElfSymbol *Elf_() rz_bin_elf_get_import(RZ_NONNULL ELFOBJ *bin, ut32 ordinal)
Definition: elf_imports.c:316
#define COMPUTE_PLTGOT_POSITION(rel, pltgot_addr, n_initial_unused_entries)
Definition: elf_imports.c:16
static void convert_elf_symbols_to_elf_imports(ELFOBJ *bin, RzVector *symbols)
Definition: elf_imports.c:305
static void convert_elf_symbol_to_elf_import(ELFOBJ *bin, RzBinElfSymbol *symbol)
Definition: elf_imports.c:292
static ut64 get_import_offset(ELFOBJ *bin, RzBinElfSymbol *symbol)
Definition: elf_imports.c:288
static ut64 get_import_addr_ppc(ELFOBJ *bin, RzBinElfReloc *rel)
Definition: elf_imports.c:86
#define RISCV_PLT_ENTRY_SIZE
Definition: elf_imports.c:10
#define X86_PLT_ENTRY_SIZE
Definition: elf_imports.c:14
bool Elf_() rz_bin_elf_has_imports(RZ_NONNULL ELFOBJ *bin)
Definition: elf_imports.c:342
#define RISCV_PLT_OFFSET
Definition: elf_imports.c:11
static ut64 get_import_addr(ELFOBJ *bin, ut64 symbol)
Definition: elf_imports.c:268
static ut64 get_import_addr_sparc(ELFOBJ *bin, RzBinElfReloc *rel)
Definition: elf_imports.c:76
static ut64 get_import_addr_x86(ELFOBJ *bin, RzBinElfReloc *rel)
Definition: elf_imports.c:181
static ut64 get_import_addr_x86_manual(ELFOBJ *bin, RzBinElfReloc *rel)
Definition: elf_imports.c:120
RZ_OWN RzVector *Elf_() rz_bin_elf_analyse_imports(RZ_NONNULL ELFOBJ *bin)
Definition: elf_imports.c:329
static ut64 get_import_addr_riscv(ELFOBJ *bin, RzBinElfReloc *rel)
Definition: elf_imports.c:60
static ut64 get_import_addr_mips(ELFOBJ *bin, RzBinElfReloc *rel)
Definition: elf_imports.c:34
static ut64 get_got_entry(ELFOBJ *bin, RzBinElfReloc *rel)
Definition: elf_imports.c:19
static ut64 get_import_addr_arm(ELFOBJ *bin, RzBinElfReloc *rel)
Definition: elf_imports.c:203
static ut64 get_import_addr_aux(ELFOBJ *bin, RzBinElfReloc *reloc)
Definition: elf_imports.c:242
#define SPARC_OFFSET_PLT_ENTRY_FROM_GOT_ADDR
Definition: elf_imports.c:12
#define Elf_(name)
Definition: elf_specs.h:32
#define EM_AARCH64
Definition: elf_specs.h:161
#define RZ_SPARC_JMP_SLOT
Definition: glibc_elf.h:1492
#define RZ_AARCH64_RELATIVE
Definition: glibc_elf.h:2785
#define RZ_ARM_JUMP_SLOT
Definition: glibc_elf.h:2824
#define RZ_AARCH64_JUMP_SLOT
Definition: glibc_elf.h:2784
#define RZ_AARCH64_IRELATIVE
Definition: glibc_elf.h:2790
#define DT_MIPS_PLTGOT
Definition: glibc_elf.h:1890
voidpf void * buf
Definition: ioapi.h:138
uint8_t ut8
Definition: lh5801.h:11
#define SHT_NULL
Definition: common.h:331
#define EM_RISCV
Definition: common.h:206
#define DT_PLTGOT
Definition: common.h:540
#define EM_X86_64
Definition: common.h:151
#define EM_MIPS
Definition: common.h:110
#define EM_SPARC
Definition: common.h:104
#define EM_PPC64
Definition: common.h:120
#define EM_386
Definition: common.h:105
#define DT_PLTRELSZ
Definition: common.h:539
#define EM_SPARC32PLUS
Definition: common.h:117
#define EM_PPC
Definition: common.h:119
#define EM_SPARCV9
Definition: common.h:132
#define DT_JMPREL
Definition: common.h:560
#define EM_ARM
Definition: common.h:129
static RzSocket * s
Definition: rtr.c:28
#define rz_return_val_if_fail(expr, val)
Definition: rz_assert.h:108
RZ_API st64 rz_buf_read_at(RZ_NONNULL RzBuffer *b, ut64 addr, RZ_NONNULL RZ_OUT ut8 *buf, ut64 len)
Read len bytes of the buffer at the specified address.
Definition: buf.c:1136
#define RZ_LOG_WARN(fmtstr,...)
Definition: rz_log.h:56
RZ_API const ut8 * rz_mem_mem_aligned(const ut8 *haystack, int hlen, const ut8 *needle, int nlen, int align)
Definition: mem.c:260
#define RZ_OWN
Definition: rz_types.h:62
#define RZ_NONNULL
Definition: rz_types.h:64
#define PFMT64u
Definition: rz_types.h:395
#define RZ_BORROW
Definition: rz_types.h:63
#define UT64_MAX
Definition: rz_types_base.h:86
#define rz_vector_foreach(vec, it)
Definition: rz_vector.h:169
static int
Definition: sfsocketcall.h:114
Definition: malloc.c:26
st64 addend
exact addend value taken from the ELF, meaning depends on type
Definition: elf.h:147
ut64 vaddr
source vaddr of the reloc, calculated from offset
Definition: elf.h:150
ut64 paddr
absolute paddr in the file, calculated from offset, or UT64_MAX if no such addr exists
Definition: elf.h:149
int pos
Definition: main.c:11
ut64(WINAPI *w32_GetEnabledXStateFeatures)()
static int addr
Definition: z80asm.c:58