Rizin
unix-like reverse engineering framework and cli tools
mz.c File Reference
#include "mz.h"
#include <rz_list.h>

Go to the source code of this file.

Functions

static ut64 rz_bin_mz_va_to_la (const ut16 segment, const ut16 offset)
 
static ut64 rz_bin_mz_la_to_pa (const struct rz_bin_mz_obj_t *bin, ut64 la)
 
RzBinAddrrz_bin_mz_get_entrypoint (const struct rz_bin_mz_obj_t *bin)
 
static int cmp_sections (const void *a, const void *b)
 
static RzBinSectionrz_bin_mz_init_section (const struct rz_bin_mz_obj_t *bin, ut64 laddr)
 
RzListrz_bin_mz_get_segments (const struct rz_bin_mz_obj_t *bin)
 
struct rz_bin_mz_reloc_trz_bin_mz_get_relocs (const struct rz_bin_mz_obj_t *bin)
 
void * rz_bin_mz_free (struct rz_bin_mz_obj_t *bin)
 
static int rz_bin_mz_init_hdr (struct rz_bin_mz_obj_t *bin)
 
static bool rz_bin_mz_init (struct rz_bin_mz_obj_t *bin)
 
struct rz_bin_mz_obj_trz_bin_mz_new (const char *file)
 
struct rz_bin_mz_obj_trz_bin_mz_new_buf (RzBuffer *buf)
 
RzBinAddrrz_bin_mz_get_main_vaddr (struct rz_bin_mz_obj_t *bin)
 

Function Documentation

◆ cmp_sections()

static int cmp_sections ( const void *  a,
const void *  b 
)
static

Definition at line 41 of file mz.c.

41  {
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 }
#define b(i)
Definition: sha256.c:42
#define a(i)
Definition: sha256.c:41

References a, b, and rz_bin_section_t::vaddr.

Referenced by rz_bin_mz_get_segments().

◆ rz_bin_mz_free()

void* rz_bin_mz_free ( struct rz_bin_mz_obj_t bin)

Definition at line 188 of file mz.c.

188  {
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 }
#define NULL
Definition: cris-opc.c:27
RZ_API void Ht_() free(HtName_(Ht) *ht)
Definition: ht_inc.c:130
RZ_API void rz_buf_free(RzBuffer *b)
Free all internal data hold by the buffer and the buffer.
Definition: buf.c:1253
Definition: malloc.c:26

References free(), NULL, and rz_buf_free().

Referenced by destroy(), rz_bin_mz_new(), and rz_bin_mz_new_buf().

◆ rz_bin_mz_get_entrypoint()

RzBinAddr* rz_bin_mz_get_entrypoint ( const struct rz_bin_mz_obj_t bin)

Definition at line 16 of file mz.c.

16  {
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 }
static ut64 rz_bin_mz_la_to_pa(const struct rz_bin_mz_obj_t *bin, ut64 la)
Definition: mz.c:12
static ut64 rz_bin_mz_va_to_la(const ut16 segment, const ut16 offset)
Definition: mz.c:8
#define RZ_LOG_ERROR(fmtstr,...)
Definition: rz_log.h:58
#define RZ_NEW0(x)
Definition: rz_types.h:284
ut64 vaddr
Definition: rz_bin.h:186
ut64 paddr
Definition: rz_bin.h:187
ut64(WINAPI *w32_GetEnabledXStateFeatures)()

References MZ_image_dos_header::cs, MZ_image_dos_header::ip, NULL, rz_bin_addr_t::paddr, rz_bin_mz_la_to_pa(), rz_bin_mz_va_to_la(), RZ_LOG_ERROR, RZ_NEW0, ut64(), and rz_bin_addr_t::vaddr.

Referenced by entries(), and rz_bin_mz_get_main_vaddr().

◆ rz_bin_mz_get_main_vaddr()

RzBinAddr* rz_bin_mz_get_main_vaddr ( struct rz_bin_mz_obj_t bin)

Definition at line 330 of file mz.c.

330  {
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 }
uint16_t ut16
uint8_t ut8
Definition: lh5801.h:11
int n
Definition: mipsasm.c:19
RzBinAddr * rz_bin_mz_get_entrypoint(const struct rz_bin_mz_obj_t *bin)
Definition: mz.c:16
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
static ut16 rz_read_ble16(const void *src, bool big_endian)
Definition: rz_endian.h:493
#define ZERO_FILL(x)
Definition: rz_types.h:281
#define RZ_FREE(x)
Definition: rz_types.h:369
#define PFMT64x
Definition: rz_types.h:393
Definition: zipcmp.c:77

References b, free(), n, NULL, PFMT64x, rz_bin_mz_get_entrypoint(), rz_bin_mz_la_to_pa(), rz_bin_mz_va_to_la(), rz_buf_read_at(), RZ_FREE, RZ_LOG_ERROR, rz_read_ble16(), ut64(), and ZERO_FILL.

Referenced by binsym().

◆ rz_bin_mz_get_relocs()

struct rz_bin_mz_reloc_t* rz_bin_mz_get_relocs ( const struct rz_bin_mz_obj_t bin)

Definition at line 163 of file mz.c.

163  {
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 }
lzma_index ** i
Definition: index.h:629
RzList * relocs(RzBinFile *bf)
Definition: bin_ne.c:114
voidpf uLong offset
Definition: ioapi.h:144
void * calloc(size_t number, size_t size)
Definition: malloc.c:102
Definition: mz_specs.h:21
ut64 vaddr
Definition: mz.h:22

References calloc(), i, NULL, relocs(), rz_bin_mz_la_to_pa(), rz_bin_mz_va_to_la(), RZ_LOG_ERROR, and rz_bin_mz_reloc_t::vaddr.

Referenced by relocs().

◆ rz_bin_mz_get_segments()

RzList* rz_bin_mz_get_segments ( const struct rz_bin_mz_obj_t bin)

Definition at line 62 of file mz.c.

62  {
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 }
RZ_API void rz_bin_section_free(RzBinSection *bs)
Definition: bin.c:1116
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
static RzBinSection * rz_bin_mz_init_section(const struct rz_bin_mz_obj_t *bin, ut64 laddr)
Definition: mz.c:50
static int cmp_sections(const void *a, const void *b)
Definition: mz.c:41
#define rz_buf_read_le16_at(b, addr, result)
Definition: rz_buf.h:270
RZ_API ut64 rz_buf_size(RZ_NONNULL RzBuffer *b)
Return the size of the buffer.
Definition: buf.c:1225
void(* RzListFree)(void *ptr)
Definition: rz_list.h:11
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 c(i)
Definition: sha256.c:43
uint32_t size

References c, cmp_sections(), i, NULL, relocs(), rz_bin_mz_init_section(), rz_bin_mz_la_to_pa(), rz_bin_mz_va_to_la(), rz_bin_section_free(), rz_buf_read_le16_at, rz_buf_size(), rz_list_add_sorted(), rz_list_find(), rz_list_free(), rz_list_get_top(), rz_list_newf(), RZ_LOG_ERROR, rz_str_newf(), rz_str_rwx(), section::size, rz_bin_section_t::size, ut64(), rz_bin_section_t::vaddr, and rz_bin_section_t::vsize.

Referenced by sections().

◆ rz_bin_mz_init()

static bool rz_bin_mz_init ( struct rz_bin_mz_obj_t bin)
static

Definition at line 281 of file mz.c.

281  {
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 }
static int rz_bin_mz_init_hdr(struct rz_bin_mz_obj_t *bin)
Definition: mz.c:201
#define RZ_LOG_WARN(fmtstr,...)
Definition: rz_log.h:56
RZ_API Sdb * sdb_new0(void)
Definition: sdb.c:43

References NULL, rz_bin_mz_init_hdr(), RZ_LOG_WARN, and sdb_new0().

Referenced by rz_bin_mz_new(), and rz_bin_mz_new_buf().

◆ rz_bin_mz_init_hdr()

static int rz_bin_mz_init_hdr ( struct rz_bin_mz_obj_t bin)
static

Definition at line 201 of file mz.c.

201  {
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) +
224  mz->bytes_in_last_block;
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 }
void * malloc(size_t size)
Definition: malloc.c:123
RZ_API int sdb_num_set(Sdb *s, const char *key, ut64 v, ut32 cas)
Definition: num.c:25
RZ_API int sdb_set(Sdb *s, const char *key, const char *val, ut32 cas)
Definition: sdb.c:611

References MZ_image_dos_header::blocks_in_file, MZ_image_dos_header::bytes_in_last_block, MZ_image_dos_header::cs, MZ_image_dos_header::header_paragraphs, MZ_image_dos_header::ip, malloc(), MZ_image_dos_header::num_relocs, MZ_image_dos_header::overlay_number, MZ_image_dos_header::reloc_table_offset, rz_buf_read_at(), RZ_FREE, RZ_LOG_ERROR, RZ_NEW0, sdb_num_set(), sdb_set(), MZ_image_dos_header::sp, and MZ_image_dos_header::ss.

Referenced by rz_bin_mz_init().

◆ rz_bin_mz_init_section()

static RzBinSection* rz_bin_mz_init_section ( const struct rz_bin_mz_obj_t bin,
ut64  laddr 
)
static

Definition at line 50 of file mz.c.

51  {
53 
55  if (section) {
56  section->vaddr = laddr;
57  }
58 
59  return section;
60 }

References RZ_NEW0.

Referenced by rz_bin_mz_get_segments().

◆ rz_bin_mz_la_to_pa()

static ut64 rz_bin_mz_la_to_pa ( const struct rz_bin_mz_obj_t bin,
ut64  la 
)
static

Definition at line 12 of file mz.c.

12  {
13  return la + (bin->dos_header->header_paragraphs << 4);
14 }

Referenced by rz_bin_mz_get_entrypoint(), rz_bin_mz_get_main_vaddr(), rz_bin_mz_get_relocs(), and rz_bin_mz_get_segments().

◆ rz_bin_mz_new()

struct rz_bin_mz_obj_t* rz_bin_mz_new ( const char *  file)

Definition at line 293 of file mz.c.

293  {
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 }
voidpf void * buf
Definition: ioapi.h:138
static bool rz_bin_mz_init(struct rz_bin_mz_obj_t *bin)
Definition: mz.c:281
void * rz_bin_mz_free(struct rz_bin_mz_obj_t *bin)
Definition: mz.c:188
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 RZ_OWN char * rz_file_slurp(const char *str, RZ_NULLABLE size_t *usz)
Definition: file.c:454
Definition: gzappend.c:170
static int file
Definition: z80asm.c:58

References file, free(), NULL, rz_bin_mz_free(), rz_bin_mz_init(), rz_buf_new_with_bytes(), rz_buf_set_bytes(), rz_file_slurp(), and RZ_NEW0.

◆ rz_bin_mz_new_buf()

struct rz_bin_mz_obj_t* rz_bin_mz_new_buf ( RzBuffer buf)

Definition at line 317 of file mz.c.

317  {
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 }
RZ_API RZ_OWN RzBuffer * rz_buf_new_with_buf(RzBuffer *b)
Creates a new buffer from a source buffer.
Definition: buf.c:448

References NULL, rz_bin_mz_free(), rz_bin_mz_init(), rz_buf_new_with_buf(), rz_buf_size(), and RZ_NEW0.

Referenced by load().

◆ rz_bin_mz_va_to_la()

static ut64 rz_bin_mz_va_to_la ( const ut16  segment,
const ut16  offset 
)
static

Definition at line 8 of file mz.c.

8  {
9  return (segment << 4) + offset;
10 }

Referenced by rz_bin_mz_get_entrypoint(), rz_bin_mz_get_main_vaddr(), rz_bin_mz_get_relocs(), and rz_bin_mz_get_segments().