Rizin
unix-like reverse engineering framework and cli tools
coff.c
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: 2008-2019 pancake <pancake@nopcode.org>
2 // SPDX-FileCopyrightText: 2008-2019 inisider <inisider@gmail.com>
3 // SPDX-License-Identifier: LGPL-3.0-only
4 
5 #include <rz_util.h>
6 
7 #include "coff.h"
8 
11  switch (arch) {
18  case COFF_FILE_TI_COFF:
30  return true;
31  default:
32  return false;
33  }
34 }
35 
37  ut32 r = 0;
38  if (flags & COFF_SCN_MEM_READ) {
39  r |= RZ_PERM_R;
40  }
41  if (flags & COFF_SCN_MEM_WRITE) {
42  r |= RZ_PERM_W;
43  }
45  r |= RZ_PERM_X;
46  }
47  return r;
48 }
49 
50 RZ_API char *rz_coff_symbol_name(struct rz_bin_coff_obj *obj, void *ptr) {
51  char n[256] = { 0 };
52  int len = 0, offset = 0;
53  union {
54  char name[8];
55  struct {
56  ut32 zero;
57  ut32 offset;
58  };
59  } *p = ptr;
60  if (!ptr) {
61  return strdup("");
62  }
63  if (p->zero) {
64  return rz_str_ndup(p->name, 8);
65  }
66  offset = obj->hdr.f_symptr + obj->hdr.f_nsyms * sizeof(struct coff_symbol) + p->offset;
67  if (offset > obj->size) {
68  return strdup("");
69  }
70  len = rz_buf_read_at(obj->b, offset, (ut8 *)n, sizeof(n));
71  if (len < 1) {
72  return strdup("");
73  }
74  /* ensure null terminated string */
75  n[sizeof(n) - 1] = 0;
76  return strdup(n);
77 }
78 
79 static int rz_coff_rebase_sym(struct rz_bin_coff_obj *obj, RzBinAddr *addr, struct coff_symbol *sym) {
80  if (sym->n_scnum < 1 || sym->n_scnum > obj->hdr.f_nscns) {
81  return 0;
82  }
83  addr->paddr = obj->scn_hdrs[sym->n_scnum - 1].s_scnptr + sym->n_value;
84  return 1;
85 }
86 
87 /* Try to get a valid entrypoint using the methods outlined in
88  * http://ftp.gnu.org/old-gnu/Manuals/ld-2.9.1/html_mono/ld.html#SEC24 */
91  int i;
92  if (!addr) {
93  return NULL;
94  }
95  /* Simplest case, the header provides the entrypoint address */
96  if (obj->hdr.f_opthdr) {
97  addr->paddr = obj->opt_hdr.entry;
98  return addr;
99  }
100  /* No help from the header eh? Use the address of the symbols '_start'
101  * or 'main' if present */
102  if (obj->symbols) {
103  for (i = 0; i < obj->hdr.f_nsyms; i++) {
104  if ((!strcmp(obj->symbols[i].n_name, "_start") ||
105  !strcmp(obj->symbols[i].n_name, "start")) &&
106  rz_coff_rebase_sym(obj, addr, &obj->symbols[i])) {
107  return addr;
108  }
109  }
110  for (i = 0; i < obj->hdr.f_nsyms; i++) {
111  if ((!strcmp(obj->symbols[i].n_name, "_main") ||
112  !strcmp(obj->symbols[i].n_name, "main")) &&
113  rz_coff_rebase_sym(obj, addr, &obj->symbols[i])) {
114  return addr;
115  }
116  }
117  }
118 #if 0
119  /* Still clueless ? Let's just use the address of .text */
120  if (obj->scn_hdrs) {
121  for (i = 0; i < obj->hdr.f_nscns; i++) {
122  // avoid doing string matching and use x bit from the section
123  if (obj->scn_hdrs[i].s_flags & COFF_SCN_MEM_EXECUTE) {
124  addr->paddr = obj->scn_hdrs[i].s_scnptr;
125  return addr;
126  }
127  }
128  }
129 #else
130  free(addr);
131  return NULL;
132 #endif
133  return addr;
134 }
135 
136 static bool rz_bin_coff_init_hdr(struct rz_bin_coff_obj *obj) {
137  ut16 magic;
138  if (!rz_buf_read_le16_at(obj->b, 0, &magic)) {
139  return false;
140  }
141 
142  switch (magic) {
145  obj->endian = COFF_IS_BIG_ENDIAN;
146  break;
147  default:
149  }
150  int ret = 0;
151  ret = rz_buf_fread_at(obj->b, 0, (ut8 *)&obj->hdr, obj->endian ? "2S3I2S" : "2s3i2s", 1);
152  if (ret != sizeof(struct coff_hdr)) {
153  return false;
154  }
155  if (obj->hdr.f_magic == COFF_FILE_TI_COFF) {
156  ret = rz_buf_fread(obj->b, (ut8 *)&obj->target_id, obj->endian ? "S" : "s", 1);
157  if (ret != sizeof(ut16)) {
158  return false;
159  }
160  }
161  return true;
162 }
163 
164 static bool rz_bin_coff_init_opt_hdr(struct rz_bin_coff_obj *obj) {
165  int ret;
166  if (!obj->hdr.f_opthdr) {
167  return false;
168  }
169  ret = rz_buf_fread_at(obj->b, sizeof(struct coff_hdr),
170  (ut8 *)&obj->opt_hdr, obj->endian ? "2S6I" : "2s6i", 1);
171  if (ret != sizeof(struct coff_opt_hdr)) {
172  return false;
173  }
174  return true;
175 }
176 
177 static bool rz_bin_coff_init_scn_hdr(struct rz_bin_coff_obj *obj) {
178  int ret, size;
179  ut64 offset = sizeof(struct coff_hdr) + (obj->hdr.f_opthdr ? sizeof(struct coff_opt_hdr) : 0);
180  if (obj->hdr.f_magic == COFF_FILE_TI_COFF) {
181  offset += 2;
182  }
183  size = obj->hdr.f_nscns * sizeof(struct coff_scn_hdr);
184  if (offset > obj->size || offset + size > obj->size || size < 0) {
185  return false;
186  }
187  obj->scn_hdrs = calloc(1, size + sizeof(struct coff_scn_hdr));
188  if (!obj->scn_hdrs) {
189  return false;
190  }
191  ret = rz_buf_fread_at(obj->b, offset, (ut8 *)obj->scn_hdrs, obj->endian ? "8c6I2S1I" : "8c6i2s1i", obj->hdr.f_nscns);
192  if (ret != size) {
193  RZ_FREE(obj->scn_hdrs);
194  return false;
195  }
196  return true;
197 }
198 
199 static bool rz_bin_coff_init_symtable(struct rz_bin_coff_obj *obj) {
200  int ret, size;
201  ut64 offset = obj->hdr.f_symptr;
202  if (obj->hdr.f_nsyms >= 0xffff || !obj->hdr.f_nsyms) { // too much symbols, probably not allocatable
203  return false;
204  }
205  size = obj->hdr.f_nsyms * sizeof(struct coff_symbol);
206  if (size < 0 ||
207  size > obj->size ||
208  offset > obj->size ||
209  offset + size > obj->size) {
210  return false;
211  }
212  obj->symbols = calloc(1, size + sizeof(struct coff_symbol));
213  if (!obj->symbols) {
214  return false;
215  }
216  ret = rz_buf_fread_at(obj->b, offset, (ut8 *)obj->symbols, obj->endian ? "8c1I2S2c" : "8c1i2s2c", obj->hdr.f_nsyms);
217  if (ret != size) {
218  RZ_FREE(obj->symbols);
219  return false;
220  }
221  return true;
222 }
223 
224 static bool rz_bin_coff_init_scn_va(struct rz_bin_coff_obj *obj) {
225  obj->scn_va = RZ_NEWS(ut64, obj->hdr.f_nscns);
226  if (!obj->scn_va) {
227  return false;
228  }
229  int i;
230  ut64 va = 0;
231  for (i = 0; i < obj->hdr.f_nscns; i++) {
232  obj->scn_va[i] = va;
233  va += obj->scn_hdrs[i].s_size ? obj->scn_hdrs[i].s_size : 16;
234  va = RZ_ROUND(va, 16ULL);
235  }
236  return true;
237 }
238 
239 static int rz_bin_coff_init(struct rz_bin_coff_obj *obj, RzBuffer *buf, bool verbose) {
240  obj->b = rz_buf_ref(buf);
241  obj->size = rz_buf_size(buf);
242  obj->verbose = verbose;
243  obj->sym_ht = ht_up_new0();
244  obj->imp_ht = ht_up_new0();
245  obj->imp_index = ht_uu_new0();
246  if (!rz_bin_coff_init_hdr(obj)) {
247  RZ_LOG_ERROR("failed to init hdr\n");
248  return false;
249  }
251  if (!rz_bin_coff_init_scn_hdr(obj)) {
252  RZ_LOG_ERROR("failed to init section header\n");
253  return false;
254  }
255  if (!rz_bin_coff_init_scn_va(obj)) {
256  RZ_LOG_ERROR("failed to init section VA table\n");
257  return false;
258  }
259  if (!rz_bin_coff_init_symtable(obj)) {
260  RZ_LOG_ERROR("failed to init symtable\n");
261  return false;
262  }
263  return true;
264 }
265 
267  ht_up_free(obj->sym_ht);
268  ht_up_free(obj->imp_ht);
269  ht_uu_free(obj->imp_index);
270  free(obj->scn_va);
271  free(obj->scn_hdrs);
272  free(obj->symbols);
273  rz_buf_free(obj->buf_patched);
274  rz_buf_free(obj->b);
275  free(obj);
276 }
277 
279  struct rz_bin_coff_obj *bin = RZ_NEW0(struct rz_bin_coff_obj);
281  return bin;
282 }
size_t len
Definition: 6502dis.c:15
lzma_index ** i
Definition: index.h:629
RZ_API struct rz_bin_coff_obj * rz_bin_coff_new_buf(RzBuffer *buf, bool verbose)
Definition: coff.c:278
static bool rz_bin_coff_init_scn_hdr(struct rz_bin_coff_obj *obj)
Definition: coff.c:177
static bool rz_bin_coff_init_symtable(struct rz_bin_coff_obj *obj)
Definition: coff.c:199
static int rz_bin_coff_init(struct rz_bin_coff_obj *obj, RzBuffer *buf, bool verbose)
Definition: coff.c:239
static bool rz_bin_coff_init_hdr(struct rz_bin_coff_obj *obj)
Definition: coff.c:136
RZ_API void rz_bin_coff_free(struct rz_bin_coff_obj *obj)
Definition: coff.c:266
RZ_API ut64 rz_coff_perms_from_section_flags(ut32 flags)
Definition: coff.c:36
RZ_API RzBinAddr * rz_coff_get_entry(struct rz_bin_coff_obj *obj)
Definition: coff.c:89
static int rz_coff_rebase_sym(struct rz_bin_coff_obj *obj, RzBinAddr *addr, struct coff_symbol *sym)
Definition: coff.c:79
RZ_API bool rz_coff_supported_arch(const ut8 *buf)
Definition: coff.c:9
RZ_API char * rz_coff_symbol_name(struct rz_bin_coff_obj *obj, void *ptr)
Definition: coff.c:50
static bool rz_bin_coff_init_opt_hdr(struct rz_bin_coff_obj *obj)
Definition: coff.c:164
static bool rz_bin_coff_init_scn_va(struct rz_bin_coff_obj *obj)
Definition: coff.c:224
#define COFF_IS_LITTLE_ENDIAN
Definition: coff.h:15
#define COFF_IS_BIG_ENDIAN
Definition: coff.h:14
#define COFF_FILE_MACHINE_SH3DSP
Definition: coff_specs.h:27
#define COFF_FILE_MACHINE_SH4
Definition: coff_specs.h:28
#define COFF_FILE_MACHINE_AMD29KBE
Definition: coff_specs.h:21
#define COFF_FILE_MACHINE_ARM64
Definition: coff_specs.h:13
#define COFF_FILE_MACHINE_AMD64
Definition: coff_specs.h:10
#define COFF_SCN_MEM_EXECUTE
Definition: coff_specs.h:81
#define COFF_FILE_MACHINE_ARM
Definition: coff_specs.h:11
#define COFF_FILE_TI_COFF
Definition: coff_specs.h:34
#define COFF_FILE_MACHINE_MIPSFPU
Definition: coff_specs.h:19
#define COFF_FILE_MACHINE_SH3
Definition: coff_specs.h:26
#define COFF_SCN_MEM_READ
Definition: coff_specs.h:82
#define COFF_FILE_MACHINE_MIPS16
Definition: coff_specs.h:18
#define COFF_FILE_MACHINE_MIPSFPU16
Definition: coff_specs.h:20
#define COFF_FILE_MACHINE_I386
Definition: coff_specs.h:15
#define COFF_FILE_MACHINE_SH5
Definition: coff_specs.h:29
#define COFF_FILE_MACHINE_AMD29KLE
Definition: coff_specs.h:22
#define COFF_FILE_MACHINE_THUMB
Definition: coff_specs.h:30
#define COFF_FILE_MACHINE_R4000
Definition: coff_specs.h:25
#define COFF_SCN_MEM_WRITE
Definition: coff_specs.h:83
#define COFF_FILE_MACHINE_H8300
Definition: coff_specs.h:32
#define COFF_FILE_MACHINE_ARMNT
Definition: coff_specs.h:12
#define RZ_API
#define NULL
Definition: cris-opc.c:27
#define r
Definition: crypto_rc6.c:12
cs_arch arch
Definition: cstool.c:13
uint16_t ut16
uint32_t ut32
RZ_API void Ht_() free(HtName_(Ht) *ht)
Definition: ht_inc.c:130
voidpf void uLong size
Definition: ioapi.h:138
voidpf uLong offset
Definition: ioapi.h:144
voidpf void * buf
Definition: ioapi.h:138
uint8_t ut8
Definition: lh5801.h:11
void * p
Definition: libc.cpp:67
void * calloc(size_t number, size_t size)
Definition: malloc.c:102
return strdup("=SP r13\n" "=LR r14\n" "=PC r15\n" "=A0 r0\n" "=A1 r1\n" "=A2 r2\n" "=A3 r3\n" "=ZF zf\n" "=SF nf\n" "=OF vf\n" "=CF cf\n" "=SN or0\n" "gpr lr .32 56 0\n" "gpr pc .32 60 0\n" "gpr cpsr .32 64 0 ____tfiae_________________qvczn\n" "gpr or0 .32 68 0\n" "gpr tf .1 64.5 0 thumb\n" "gpr ef .1 64.9 0 endian\n" "gpr jf .1 64.24 0 java\n" "gpr qf .1 64.27 0 sticky_overflow\n" "gpr vf .1 64.28 0 overflow\n" "gpr cf .1 64.29 0 carry\n" "gpr zf .1 64.30 0 zero\n" "gpr nf .1 64.31 0 negative\n" "gpr itc .4 64.10 0 if_then_count\n" "gpr gef .4 64.16 0 great_or_equal\n" "gpr r0 .32 0 0\n" "gpr r1 .32 4 0\n" "gpr r2 .32 8 0\n" "gpr r3 .32 12 0\n" "gpr r4 .32 16 0\n" "gpr r5 .32 20 0\n" "gpr r6 .32 24 0\n" "gpr r7 .32 28 0\n" "gpr r8 .32 32 0\n" "gpr r9 .32 36 0\n" "gpr r10 .32 40 0\n" "gpr r11 .32 44 0\n" "gpr r12 .32 48 0\n" "gpr r13 .32 52 0\n" "gpr r14 .32 56 0\n" "gpr r15 .32 60 0\n" "gpr r16 .32 64 0\n" "gpr r17 .32 68 0\n")
int n
Definition: mipsasm.c:19
#define rz_buf_read_le16_at(b, addr, result)
Definition: rz_buf.h:270
RZ_API st64 rz_buf_fread(RZ_NONNULL RzBuffer *b, RZ_NONNULL ut8 *buf, RZ_NONNULL const char *fmt, int n)
...
Definition: buf.c:978
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
RZ_API st64 rz_buf_fread_at(RZ_NONNULL RzBuffer *b, ut64 addr, RZ_NONNULL ut8 *buf, RZ_NONNULL const char *fmt, int n)
...
Definition: buf.c:1001
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
static ut16 rz_read_le16(const void *src)
Definition: rz_endian.h:206
#define RZ_LOG_ERROR(fmtstr,...)
Definition: rz_log.h:58
RZ_API char * rz_str_ndup(RZ_NULLABLE const char *ptr, int len)
Create new copy of string ptr limited to size len.
Definition: str.c:1006
#define RZ_NEWS(x, y)
Definition: rz_types.h:283
#define RZ_PERM_R
Definition: rz_types.h:93
#define RZ_NEW0(x)
Definition: rz_types.h:284
#define RZ_PERM_W
Definition: rz_types.h:94
#define RZ_PERM_X
Definition: rz_types.h:95
#define RZ_FREE(x)
Definition: rz_types.h:369
#define RZ_ROUND(x, y)
static struct sockaddr static addrlen static backlog const void static flags void flags
Definition: sfsocketcall.h:123
Definition: malloc.c:26
Definition: z80asm.h:102
RzBuffer * buf_patched
overlay over the original file with relocs patched
Definition: coff.h:38
ut8 endian
Definition: coff.h:29
ut64 * scn_va
Definition: coff.h:35
HtUP * sym_ht
Definition: coff.h:32
ut16 target_id
Definition: coff.h:25
HtUP * imp_ht
Definition: coff.h:33
struct coff_symbol * symbols
Definition: coff.h:23
size_t size
Definition: coff.h:28
struct coff_hdr hdr
Definition: coff.h:20
struct coff_scn_hdr * scn_hdrs
Definition: coff.h:22
HtUU * imp_index
locally-generated indices for imports, in particular for deterministically assigning reloc targets
Definition: coff.h:34
bool verbose
Definition: coff.h:31
struct coff_opt_hdr opt_hdr
Definition: coff.h:21
RzBuffer * b
Definition: coff.h:27
if(dbg->bits==RZ_SYS_BITS_64)
Definition: windows-arm64.h:4
ut64(WINAPI *w32_GetEnabledXStateFeatures)()
static int verbose
Definition: z80asm.c:73
static int addr
Definition: z80asm.c:58