Rizin
unix-like reverse engineering framework and cli tools
bflt.c
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: 2021 Florian Märkl <info@florianmaerkl.de>
2 // SPDX-FileCopyrightText: 2016 Oscar Salvador <osalvador.vilardaga@gmail.com>
3 // SPDX-License-Identifier: LGPL-3.0-only
4 
14 #include <rz_util.h>
15 #include <rz_types.h>
16 
17 #include "bflt.h"
18 
19 #define MAX_SHARED_LIBS 1 // this may be 4 depending on kernel config
20 #define FLAT_DATA_ALIGN 0x20
21 
22 #define READ(x, i) \
23  rz_read_be32((x) + (i)); \
24  (i) += 4;
25 
26 static bool bflt_init_hdr(RzBfltObj *bin) {
27  ut8 bhdr[BFLT_HDR_SIZE] = { 0 };
28  st64 len = rz_buf_read_at(bin->b, 0, bhdr, BFLT_HDR_SIZE);
29  if (len != BFLT_HDR_SIZE) {
30  RZ_LOG_WARN("read bFLT hdr failed\n");
31  return false;
32  }
33 
34  if (strncmp((const char *)bhdr, "bFLT", 4)) {
35  RZ_LOG_WARN("wrong magic number in bFLT file\n");
36  return false;
37  }
38 
39  size_t i = 4;
40  bin->hdr.rev = READ(bhdr, i);
41  bin->hdr.entry = READ(bhdr, i);
42  bin->hdr.data_start = READ(bhdr, i);
43  bin->hdr.data_end = READ(bhdr, i);
44  bin->hdr.bss_end = READ(bhdr, i);
45  bin->hdr.stack_size = READ(bhdr, i);
46  bin->hdr.reloc_start = READ(bhdr, i);
47  bin->hdr.reloc_count = READ(bhdr, i);
48  bin->hdr.flags = READ(bhdr, i);
49  bin->hdr.build_date = READ(bhdr, i);
50 
51  if (bin->hdr.rev != FLAT_VERSION) {
52  RZ_LOG_WARN("only bFLT v4 is supported! This file has version %" PFMT32u "\n", bin->hdr.rev);
53  return false;
54  }
55  if (bin->hdr.flags & FLAT_FLAG_GZIP || bin->hdr.flags & FLAT_FLAG_GZDATA) {
56  RZ_LOG_WARN("this bFLT file is compressed. This is not (yet) supported.\n");
57  }
58  return true;
59 }
60 
62  // if bin->hdr.flags & FLAT_FLAG_GOTPIC, then all relocs
63  // are already in target order, otherwise they are always be
64  return (bin->hdr.flags & FLAT_FLAG_GOTPIC)
65  ? bin->big_endian
66  : true;
67 }
68 
70  bool big_endian = bflt_reloc_big_endian(bin);
71 
72  // got is a single table of 32bit values at the beginning of data
73  // to be rebased in-place, and terminated by -1
74  if (bin->hdr.flags & FLAT_FLAG_GOTPIC) {
75  for (ut64 offset = 0;; offset += 4) {
76  ut32 paddr = bin->hdr.data_start + offset;
77  if (paddr + 4 > bin->size || paddr + 4 < paddr) {
78  break;
79  }
80  ut32 value;
81  if (!rz_buf_read_ble32_at(bin->b, paddr, &value, big_endian)) {
82  break;
83  }
84  if (value == 0xffffffff) {
85  break;
86  }
87  RzBfltReloc *reloc = rz_vector_push(&bin->got_relocs, NULL);
88  if (!reloc) {
89  break;
90  }
91  reloc->reloc_paddr = paddr;
92  reloc->value_orig = value ? value + BFLT_HDR_SIZE : 0; // uClinux kernel leaves 0 relocs alone
93  }
94  }
95 
96  // addresses of other places to rebase are indirectly given in the reloc table
97  for (ut32 i = 0; i < bin->hdr.reloc_count; i++) {
98  ut32 table_paddr = bin->hdr.reloc_start + i * 4;
99  if (table_paddr + 4 > bin->size || table_paddr + 4 < bin->hdr.reloc_start) {
100  break;
101  }
102  ut32 reloc_paddr;
103  if (!rz_buf_read_be32_at(bin->b, table_paddr, &reloc_paddr)) {
104  break;
105  }
106  reloc_paddr += BFLT_HDR_SIZE;
107  if (reloc_paddr + 4 < reloc_paddr || reloc_paddr > bin->size) {
108  continue;
109  }
110  ut32 value;
111  if (!rz_buf_read_ble32_at(bin->b, reloc_paddr, &value, big_endian)) {
112  continue;
113  }
114  RzBfltReloc *reloc = rz_vector_push(&bin->got_relocs, NULL);
115  if (!reloc) {
116  break;
117  }
118  reloc->reloc_paddr = reloc_paddr;
119  reloc->value_orig = value + BFLT_HDR_SIZE;
120  }
121 }
122 
123 static void patch_relocs_in(RzBfltObj *bin, RzVector /*<RzBfltReloc>*/ *relocs) {
124  RzBfltReloc *reloc;
125  rz_vector_foreach(relocs, reloc) {
126  if (!reloc->value_orig) {
127  // 0 relocs are not patched (this is some workaround for null pointers in the uClinux kernel)
128  continue;
129  }
130  rz_buf_write_ble32_at(bin->buf_patched,
131  reloc->reloc_paddr,
133  bin->big_endian);
134  }
135 }
136 
139  if (!bin->buf_patched) {
140  return;
141  }
142  patch_relocs_in(bin, &bin->got_relocs);
143  patch_relocs_in(bin, &bin->relocs);
145 }
146 
147 static bool rz_bflt_init(RzBfltObj *obj, RzBuffer *buf, ut64 baddr, bool big_endian, bool patch_relocs) {
148  obj->b = rz_buf_ref(buf);
149  obj->size = rz_buf_size(buf);
150  obj->big_endian = big_endian;
151  rz_vector_init(&obj->relocs, sizeof(RzBfltReloc), NULL, NULL);
152  rz_vector_init(&obj->got_relocs, sizeof(RzBfltReloc), NULL, NULL);
153  obj->baddr = baddr == UT64_MAX ? 0 : baddr;
154  if (!bflt_init_hdr(obj)) {
155  return false;
156  }
157  bflt_load_relocs(obj);
158  if (patch_relocs) {
159  bflt_patch_relocs(obj);
160  }
161  return true;
162 }
163 
166  if (bin && rz_bflt_init(bin, buf, baddr, big_endian, patch_relocs)) {
167  return bin;
168  }
169  rz_bflt_free(bin);
170  return NULL;
171 }
172 
174  if (obj) {
175  rz_buf_free(obj->b);
176  rz_buf_free(obj->buf_patched);
177  rz_vector_fini(&obj->relocs);
178  rz_vector_fini(&obj->got_relocs);
179  RZ_FREE(obj);
180  }
181 }
182 
185  if (addr && bin) {
186  addr->paddr = bin->hdr.entry;
187  addr->vaddr = rz_bflt_get_text_base(bin) + bin->hdr.entry;
188  }
189  return addr;
190 }
191 
194  return bin->baddr;
195 }
196 
199  ut64 r = bin->baddr + bin->hdr.data_start + MAX_SHARED_LIBS * sizeof(ut32);
201 }
202 
205  return RZ_MAX(bin->hdr.data_end, bin->hdr.bss_end) - bin->hdr.data_start;
206 }
207 
209  if (paddr >= bin->hdr.data_start) {
210  return rz_bflt_get_data_base(bin) + paddr - bin->hdr.data_start;
211  }
212  return bin->baddr + paddr;
213 }
size_t len
Definition: 6502dis.c:15
lzma_index ** i
Definition: index.h:629
static bool rz_bflt_init(RzBfltObj *obj, RzBuffer *buf, ut64 baddr, bool big_endian, bool patch_relocs)
Definition: bflt.c:147
ut64 rz_bflt_get_data_base(RzBfltObj *bin)
Address to map data+bss segment to.
Definition: bflt.c:198
RzBinAddr * rz_bflt_get_entry(RzBfltObj *bin)
Definition: bflt.c:183
#define FLAT_DATA_ALIGN
Definition: bflt.c:20
static void patch_relocs_in(RzBfltObj *bin, RzVector *relocs)
Definition: bflt.c:123
static void bflt_patch_relocs(RzBfltObj *bin)
Definition: bflt.c:137
RzBfltObj * rz_bflt_new_buf(RzBuffer *buf, ut64 baddr, bool big_endian, bool patch_relocs)
Definition: bflt.c:164
#define MAX_SHARED_LIBS
Definition: bflt.c:19
void rz_bflt_free(RzBfltObj *obj)
Definition: bflt.c:173
static bool bflt_reloc_big_endian(RzBfltObj *bin)
Definition: bflt.c:61
ut64 rz_bflt_paddr_to_vaddr(RzBfltObj *bin, ut32 paddr)
Definition: bflt.c:208
static bool bflt_init_hdr(RzBfltObj *bin)
Definition: bflt.c:26
#define READ(x, i)
Definition: bflt.c:22
ut64 rz_bflt_get_data_vsize(RzBfltObj *bin)
Total size of data+bss.
Definition: bflt.c:204
static void bflt_load_relocs(RzBfltObj *bin)
Definition: bflt.c:69
ut64 rz_bflt_get_text_base(RzBfltObj *bin)
Address to map text segment to.
Definition: bflt.c:193
#define FLAT_FLAG_GOTPIC
Definition: bflt.h:16
#define FLAT_FLAG_GZDATA
Definition: bflt.h:18
#define BFLT_HDR_SIZE
Definition: bflt.h:53
#define FLAT_VERSION
Definition: bflt.h:14
#define FLAT_FLAG_GZIP
Definition: bflt.h:17
static ut64 baddr(RzBinFile *bf)
Definition: bin_any.c:58
RzList * relocs(RzBinFile *bf)
Definition: bin_ne.c:114
static int value
Definition: cmd_api.c:93
#define NULL
Definition: cris-opc.c:27
#define r
Definition: crypto_rc6.c:12
uint32_t ut32
voidpf uLong offset
Definition: ioapi.h:144
voidpf void * buf
Definition: ioapi.h:138
uint8_t ut8
Definition: lh5801.h:11
RZ_API void MACH0_() patch_relocs(RzBinFile *bf, struct MACH0_(obj_t) *obj)
Patching of external relocs in a sparse overlay buffer.
Definition: mach0_relocs.c:614
RZ_API void rz_buf_sparse_set_write_mode(RzBuffer *b, RzBufferSparseWriteMode mode)
Only for sparse RzBuffers.
Definition: buf_sparse.c:325
RZ_API RzBuffer * rz_buf_ref(RzBuffer *b)
Increment the reference count of the buffer.
Definition: buf.c:668
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_buf_read_be32_at(b, addr, result)
Definition: rz_buf.h:285
@ RZ_BUF_SPARSE_WRITE_MODE_SPARSE
all writes are performed in the sparse overlay
Definition: rz_buf.h:60
@ RZ_BUF_SPARSE_WRITE_MODE_THROUGH
all writes are performed in the underlying base buffer
Definition: rz_buf.h:61
RZ_API void rz_buf_free(RzBuffer *b)
Free all internal data hold by the buffer and the buffer.
Definition: buf.c:1253
RZ_API ut64 rz_buf_size(RZ_NONNULL RzBuffer *b)
Return the size of the buffer.
Definition: buf.c:1225
RZ_API RZ_OWN RzBuffer * rz_buf_new_sparse_overlay(RzBuffer *b, RzBufferSparseWriteMode write_mode)
Creates a sparse buffer from a already populated buffer.
Definition: buf.c:426
#define RZ_LOG_WARN(fmtstr,...)
Definition: rz_log.h:56
static ut64 rz_num_align_delta(ut64 v, ut64 alignment)
Padding to align v to the next alignment-boundary.
Definition: rz_num.h:116
#define RZ_NEW0(x)
Definition: rz_types.h:284
#define PFMT32u
Definition: rz_types.h:409
#define RZ_FREE(x)
Definition: rz_types.h:369
#define st64
Definition: rz_types_base.h:10
#define RZ_MAX(x, y)
#define UT64_MAX
Definition: rz_types_base.h:86
RZ_API void * rz_vector_push(RzVector *vec, void *x)
Definition: vector.c:197
#define rz_vector_foreach(vec, it)
Definition: rz_vector.h:169
RZ_API void rz_vector_fini(RzVector *vec)
Definition: vector.c:61
RZ_API void rz_vector_init(RzVector *vec, size_t elem_size, RzVectorFree free, void *free_user)
Definition: vector.c:33
Definition: malloc.c:26
bool big_endian
Definition: bflt.h:48
RzBuffer * b
Definition: bflt.h:45
size_t size
Definition: bflt.h:49
ut64 baddr
Definition: bflt.h:47
RzVector got_relocs
Definition: bflt.h:44
RzVector relocs
Definition: bflt.h:43
RzBuffer * buf_patched
overlay over the original file with relocs patched
Definition: bflt.h:46
ut32 reloc_paddr
where to patch, offset from the beginning of the file
Definition: bflt.h:37
ut32 value_orig
original value at that address
Definition: bflt.h:38
ut64(WINAPI *w32_GetEnabledXStateFeatures)()
static int addr
Definition: z80asm.c:58