Rizin
unix-like reverse engineering framework and cli tools
mz.c
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: 2015-2018 nodepad <nod3pad@gmail.com>
2 // SPDX-FileCopyrightText: 2015-2018 pancake <pancake@nopcode.org>
3 // SPDX-License-Identifier: LGPL-3.0-only
4 
5 #include "mz.h"
6 #include <rz_list.h>
7 
8 static ut64 rz_bin_mz_va_to_la(const ut16 segment, const ut16 offset) {
9  return (segment << 4) + offset;
10 }
11 
12 static ut64 rz_bin_mz_la_to_pa(const struct rz_bin_mz_obj_t *bin, ut64 la) {
13  return la + (bin->dos_header->header_paragraphs << 4);
14 }
15 
17  const MZ_image_dos_header *mz;
18  ut64 la;
19  RzBinAddr *entrypoint;
20 
21  if (!bin || !bin->dos_header) {
22  return NULL;
23  }
24 
25  mz = bin->dos_header;
26  la = rz_bin_mz_va_to_la(mz->cs, mz->ip);
27  la &= 0xfffff;
28  if (la >= bin->load_module_size) {
29  RZ_LOG_ERROR("The entry point is outside the load module size\n");
30  return NULL;
31  }
32  entrypoint = RZ_NEW0(RzBinAddr);
33  if (entrypoint) {
34  entrypoint->vaddr = la;
35  entrypoint->paddr = rz_bin_mz_la_to_pa(bin, la);
36  }
37 
38  return entrypoint;
39 }
40 
41 static int cmp_sections(const void *a, const void *b) {
42  const RzBinSection *s_a, *s_b;
43 
44  s_a = a;
45  s_b = b;
46 
47  return s_a->vaddr - s_b->vaddr;
48 }
49 
51  ut64 laddr) {
53 
55  if (section) {
56  section->vaddr = laddr;
57  }
58 
59  return section;
60 }
61 
63  RzList *seg_list;
67  int i, num_relocs, section_number;
68  ut16 ss;
69 
70  if (!bin || !bin->dos_header) {
71  return NULL;
72  }
73 
75  if (!seg_list) {
76  return NULL;
77  }
78 
79  /* Add address of first segment to make sure that it is present
80  * even if there are no relocations or there isn't first segment in
81  * the relocations. */
83  if (!section) {
84  goto err_out;
85  }
87 
88  relocs = bin->relocation_entries;
89  num_relocs = bin->dos_header->num_relocs;
90  for (i = 0; i < num_relocs; i++) {
92  ut64 laddr, paddr, section_laddr;
93  ut16 curr_seg;
94 
95  laddr = rz_bin_mz_va_to_la(relocs[i].segment, relocs[i].offset);
96  if ((laddr + 2) >= bin->load_module_size) {
97  continue;
98  }
99 
100  paddr = rz_bin_mz_la_to_pa(bin, laddr);
101  if (rz_buf_size(bin->b) < paddr + 2) {
102  continue;
103  }
104 
105  if (!rz_buf_read_le16_at(bin->b, paddr, &curr_seg)) {
106  continue;
107  }
108 
109  section_laddr = rz_bin_mz_va_to_la(curr_seg, 0);
110  if (section_laddr > bin->load_module_size) {
111  continue;
112  }
113 
114  c.vaddr = section_laddr;
115  if (rz_list_find(seg_list, &c, cmp_sections)) {
116  continue;
117  }
118 
119  section = rz_bin_mz_init_section(bin, section_laddr);
120  if (!section) {
121  goto err_out;
122  }
124  }
125 
126  /* Add address of stack segment if it's inside the load module. */
127  ss = bin->dos_header->ss;
128  if (rz_bin_mz_va_to_la(ss, 0) < bin->load_module_size) {
130  if (!section) {
131  goto err_out;
132  }
134  }
135 
136  /* Fixup sizes and addresses, set name, permissions and set add flag */
137  section_number = 0;
138  rz_list_foreach (seg_list, iter, section) {
139  section->name = rz_str_newf("seg_%03d", section_number);
140  if (section_number) {
141  RzBinSection *p_section = iter->p->data;
142  p_section->size = section->vaddr - p_section->vaddr;
143  p_section->vsize = p_section->size;
144  }
145  section->vsize = section->size;
146  section->paddr = rz_bin_mz_la_to_pa(bin, section->vaddr);
147  section->perm = rz_str_rwx("rwx");
148  section_number++;
149  }
150  section = rz_list_get_top(seg_list);
151  section->size = bin->load_module_size - section->vaddr;
152  section->vsize = section->size;
153 
154  return seg_list;
155 
156 err_out:
157  RZ_LOG_ERROR("Failed to get segment list\n");
158  rz_list_free(seg_list);
159 
160  return NULL;
161 }
162 
164  int i, j;
165  const int num_relocs = bin->dos_header->num_relocs;
166  const MZ_image_relocation_entry *const rel_entry = bin->relocation_entries;
167 
168  struct rz_bin_mz_reloc_t *relocs = calloc(num_relocs + 1, sizeof(*relocs));
169  if (!relocs) {
170  RZ_LOG_ERROR("Cannot allocate struct rz_bin_mz_reloc_t\n");
171  return NULL;
172  }
173  for (i = 0, j = 0; i < num_relocs; i++) {
174  relocs[j].vaddr = rz_bin_mz_va_to_la(rel_entry[i].segment,
175  rel_entry[i].offset);
176  relocs[j].paddr = rz_bin_mz_la_to_pa(bin, relocs[j].vaddr);
177 
178  /* Add only relocations which resides inside dos executable */
179  if (relocs[j].vaddr < bin->load_module_size) {
180  j++;
181  }
182  }
183  relocs[j].last = 1;
184 
185  return relocs;
186 }
187 
189  if (!bin) {
190  return NULL;
191  }
192  free((void *)bin->dos_header);
193  free((void *)bin->dos_extended_header);
194  free((void *)bin->relocation_entries);
195  rz_buf_free(bin->b);
196  bin->b = NULL;
197  free(bin);
198  return NULL;
199 }
200 
202  int relocations_size, dos_file_size;
204  if (!(mz = RZ_NEW0(MZ_image_dos_header))) {
205  RZ_LOG_ERROR("Cannot allocate MZ_image_dos_header");
206  return false;
207  }
208  bin->dos_header = mz;
209  // TODO: read field by field to avoid endian and alignment issues
210  if (rz_buf_read_at(bin->b, 0, (ut8 *)mz, sizeof(*mz)) == -1) {
211  RZ_LOG_ERROR("Cannot read MZ_image_dos_header\n");
212  return false;
213  }
214  // dos_header is not endian safe here in this point
215  if (mz->blocks_in_file < 1) {
216  return false;
217  }
218  if (mz->bytes_in_last_block == 0) {
219  // last block is full
220  dos_file_size = mz->blocks_in_file << 9;
221  } else {
222  // last block is partially full
223  dos_file_size = ((mz->blocks_in_file - 1) << 9) +
225  }
226 
227  bin->dos_file_size = dos_file_size;
228  if (dos_file_size > bin->size) {
229  return false;
230  }
231  bin->load_module_size = dos_file_size - (mz->header_paragraphs << 4);
232  relocations_size = mz->num_relocs * sizeof(MZ_image_relocation_entry);
233  if ((mz->reloc_table_offset + relocations_size) > bin->size) {
234  return false;
235  }
236 
237  sdb_num_set(bin->kv, "mz.initial.cs", mz->cs, 0);
238  sdb_num_set(bin->kv, "mz.initial.ip", mz->ip, 0);
239  sdb_num_set(bin->kv, "mz.initial.ss", mz->ss, 0);
240  sdb_num_set(bin->kv, "mz.initial.sp", mz->sp, 0);
241  sdb_num_set(bin->kv, "mz.overlay_number", mz->overlay_number, 0);
242  sdb_num_set(bin->kv, "mz.dos_header.offset", 0, 0);
243  sdb_set(bin->kv, "mz.dos_header.format", "[2]zwwwwwwwwwwwww"
244  " signature bytes_in_last_block blocks_in_file num_relocs "
245  " header_paragraphs min_extra_paragraphs max_extra_paragraphs "
246  " ss sp checksum ip cs reloc_table_offset overlay_number ",
247  0);
248 
249  bin->dos_extended_header_size = mz->reloc_table_offset -
250  sizeof(MZ_image_dos_header);
251 
252  if (bin->dos_extended_header_size > 0) {
253  if (!(bin->dos_extended_header =
254  malloc(bin->dos_extended_header_size))) {
255  RZ_LOG_ERROR("Cannot allocate dos extended header");
256  return false;
257  }
258  if (rz_buf_read_at(bin->b, sizeof(MZ_image_dos_header),
259  (ut8 *)bin->dos_extended_header,
260  bin->dos_extended_header_size) == -1) {
261  RZ_LOG_ERROR("Cannot read dos extended header\n");
262  return false;
263  }
264  }
265 
266  if (relocations_size > 0) {
267  if (!(bin->relocation_entries = malloc(relocations_size))) {
268  RZ_LOG_ERROR("Cannot allocate dos relocation entries");
269  return false;
270  }
271  if (rz_buf_read_at(bin->b, bin->dos_header->reloc_table_offset,
272  (ut8 *)bin->relocation_entries, relocations_size) == -1) {
273  RZ_LOG_ERROR("Cannot read dos relocation entries\n");
274  RZ_FREE(bin->relocation_entries);
275  return false;
276  }
277  }
278  return true;
279 }
280 
281 static bool rz_bin_mz_init(struct rz_bin_mz_obj_t *bin) {
282  bin->dos_header = NULL;
283  bin->dos_extended_header = NULL;
284  bin->relocation_entries = NULL;
285  bin->kv = sdb_new0();
286  if (!rz_bin_mz_init_hdr(bin)) {
287  RZ_LOG_WARN("File is not MZ\n");
288  return false;
289  }
290  return true;
291 }
292 
293 struct rz_bin_mz_obj_t *rz_bin_mz_new(const char *file) {
294  struct rz_bin_mz_obj_t *bin = RZ_NEW0(struct rz_bin_mz_obj_t);
295  if (!bin) {
296  return NULL;
297  }
298  bin->file = file;
299  size_t binsz;
300  ut8 *buf = (ut8 *)rz_file_slurp(file, &binsz);
301  bin->size = binsz;
302  if (!buf) {
303  return rz_bin_mz_free(bin);
304  }
305  bin->b = rz_buf_new_with_bytes(NULL, 0);
306  if (!rz_buf_set_bytes(bin->b, buf, bin->size)) {
307  free((void *)buf);
308  return rz_bin_mz_free(bin);
309  }
310  free((void *)buf);
311  if (!rz_bin_mz_init(bin)) {
312  return rz_bin_mz_free(bin);
313  }
314  return bin;
315 }
316 
318  struct rz_bin_mz_obj_t *bin = RZ_NEW0(struct rz_bin_mz_obj_t);
319  if (!bin) {
320  return NULL;
321  }
323  if (!bin->b) {
324  return rz_bin_mz_free(bin);
325  }
326  bin->size = rz_buf_size(buf);
327  return rz_bin_mz_init(bin) ? bin : rz_bin_mz_free(bin);
328 }
329 
331  int n;
332  ut8 b[512];
333  if (!bin || !bin->b) {
334  return NULL;
335  }
337  if (!entry) {
338  return NULL;
339  }
340  ZERO_FILL(b);
341  if (rz_buf_read_at(bin->b, entry->paddr, b, sizeof(b)) < 0) {
342  RZ_LOG_ERROR("Cannot read entry at 0x%16" PFMT64x "\n", (ut64)entry->paddr);
343  free(entry);
344  return NULL;
345  }
346  // MSVC
347  if (b[0] == 0xb4 && b[1] == 0x30) {
348  // ff 36 XX XX push XXXX
349  // ff 36 XX XX push argv
350  // ff 36 XX XX push argc
351  // 9a XX XX XX XX lcall _main
352  // 50 push ax
353  for (n = 0; n < sizeof(b) - 18; n++) {
354  if (b[n] == 0xff && b[n + 4] == 0xff && b[n + 8] == 0xff && b[n + 12] == 0x9a && b[n + 17] == 0x50) {
355  const ut16 call_addr = rz_read_ble16(b + n + 13, 0);
356  const ut16 call_seg = rz_read_ble16(b + n + 15, 0);
357  entry->vaddr = rz_bin_mz_va_to_la(call_seg, call_addr);
358  entry->paddr = rz_bin_mz_la_to_pa(bin, entry->vaddr);
359  return entry;
360  }
361  }
362  }
363 
364  RZ_FREE(entry);
365  return NULL;
366 }
lzma_index ** i
Definition: index.h:629
RZ_API void rz_bin_section_free(RzBinSection *bs)
Definition: bin.c:1116
RzList * relocs(RzBinFile *bf)
Definition: bin_ne.c:114
#define NULL
Definition: cris-opc.c:27
uint16_t ut16
RZ_API void Ht_() free(HtName_(Ht) *ht)
Definition: ht_inc.c:130
voidpf uLong offset
Definition: ioapi.h:144
voidpf void * buf
Definition: ioapi.h:138
uint8_t ut8
Definition: lh5801.h:11
RZ_API RZ_BORROW RzListIter * rz_list_find(RZ_NONNULL const RzList *list, const void *p, RZ_NONNULL RzListComparator cmp)
Returns RzListIter element which matches via the RzListComparator.
Definition: list.c:620
RZ_API RZ_OWN RzList * rz_list_newf(RzListFree f)
Returns a new initialized RzList pointer and sets the free method.
Definition: list.c:248
RZ_API RZ_BORROW void * rz_list_get_top(RZ_NONNULL const RzList *list)
Returns the last element of the list.
Definition: list.c:457
RZ_API RZ_BORROW RzListIter * rz_list_add_sorted(RZ_NONNULL RzList *list, void *data, RZ_NONNULL RzListComparator cmp)
Adds an element to a sorted list via the RzListComparator.
Definition: list.c:518
RZ_API void rz_list_free(RZ_NONNULL RzList *list)
Empties the list and frees the list pointer.
Definition: list.c:137
void * malloc(size_t size)
Definition: malloc.c:123
void * calloc(size_t number, size_t size)
Definition: malloc.c:102
int n
Definition: mipsasm.c:19
RzList * rz_bin_mz_get_segments(const struct rz_bin_mz_obj_t *bin)
Definition: mz.c:62
static ut64 rz_bin_mz_la_to_pa(const struct rz_bin_mz_obj_t *bin, ut64 la)
Definition: mz.c:12
struct rz_bin_mz_obj_t * rz_bin_mz_new(const char *file)
Definition: mz.c:293
static bool rz_bin_mz_init(struct rz_bin_mz_obj_t *bin)
Definition: mz.c:281
static int rz_bin_mz_init_hdr(struct rz_bin_mz_obj_t *bin)
Definition: mz.c:201
RzBinAddr * rz_bin_mz_get_entrypoint(const struct rz_bin_mz_obj_t *bin)
Definition: mz.c:16
static RzBinSection * rz_bin_mz_init_section(const struct rz_bin_mz_obj_t *bin, ut64 laddr)
Definition: mz.c:50
struct rz_bin_mz_obj_t * rz_bin_mz_new_buf(RzBuffer *buf)
Definition: mz.c:317
void * rz_bin_mz_free(struct rz_bin_mz_obj_t *bin)
Definition: mz.c:188
static int cmp_sections(const void *a, const void *b)
Definition: mz.c:41
RzBinAddr * rz_bin_mz_get_main_vaddr(struct rz_bin_mz_obj_t *bin)
Definition: mz.c:330
static ut64 rz_bin_mz_va_to_la(const ut16 segment, const ut16 offset)
Definition: mz.c:8
struct rz_bin_mz_reloc_t * rz_bin_mz_get_relocs(const struct rz_bin_mz_obj_t *bin)
Definition: mz.c:163
RZ_API int sdb_num_set(Sdb *s, const char *key, ut64 v, ut32 cas)
Definition: num.c:25
#define rz_buf_read_le16_at(b, addr, result)
Definition: rz_buf.h:270
RZ_API RZ_OWN RzBuffer * rz_buf_new_with_buf(RzBuffer *b)
Creates a new buffer from a source buffer.
Definition: buf.c:448
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 void rz_buf_free(RzBuffer *b)
Free all internal data hold by the buffer and the buffer.
Definition: buf.c:1253
RZ_API bool rz_buf_set_bytes(RZ_NONNULL RzBuffer *b, RZ_NONNULL const ut8 *buf, ut64 len)
Replace the content of the buffer with the bytes array.
Definition: buf.c:905
RZ_API RZ_OWN RzBuffer * rz_buf_new_with_bytes(RZ_NULLABLE RZ_BORROW const ut8 *bytes, ut64 len)
Creates a new buffer with a bytes array.
Definition: buf.c:465
RZ_API ut64 rz_buf_size(RZ_NONNULL RzBuffer *b)
Return the size of the buffer.
Definition: buf.c:1225
static ut16 rz_read_ble16(const void *src, bool big_endian)
Definition: rz_endian.h:493
RZ_API RZ_OWN char * rz_file_slurp(const char *str, RZ_NULLABLE size_t *usz)
Definition: file.c:454
void(* RzListFree)(void *ptr)
Definition: rz_list.h:11
#define RZ_LOG_WARN(fmtstr,...)
Definition: rz_log.h:56
#define RZ_LOG_ERROR(fmtstr,...)
Definition: rz_log.h:58
RZ_API char * rz_str_newf(const char *fmt,...) RZ_PRINTF_CHECK(1
RZ_API int rz_str_rwx(const char *str)
Definition: str.c:318
#define ZERO_FILL(x)
Definition: rz_types.h:281
#define RZ_NEW0(x)
Definition: rz_types.h:284
#define RZ_FREE(x)
Definition: rz_types.h:369
#define PFMT64x
Definition: rz_types.h:393
RZ_API int sdb_set(Sdb *s, const char *key, const char *val, ut32 cas)
Definition: sdb.c:611
RZ_API Sdb * sdb_new0(void)
Definition: sdb.c:43
#define b(i)
Definition: sha256.c:42
#define c(i)
Definition: sha256.c:43
#define a(i)
Definition: sha256.c:41
ut16 bytes_in_last_block
Definition: mz_specs.h:6
ut16 reloc_table_offset
Definition: mz_specs.h:17
ut16 header_paragraphs
Definition: mz_specs.h:9
Definition: mz_specs.h:21
Definition: malloc.c:26
Definition: zipcmp.c:77
Definition: gzappend.c:170
ut64 vaddr
Definition: rz_bin.h:186
ut64 paddr
Definition: rz_bin.h:187
ut64 vaddr
Definition: mz.h:22
uint32_t size
ut64(WINAPI *w32_GetEnabledXStateFeatures)()
static int file
Definition: z80asm.c:58