Rizin
unix-like reverse engineering framework and cli tools
bin_mz.c
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: 2015-2019 nodepad <nod3pad@gmail.com>
2 // SPDX-License-Identifier: LGPL-3.0-only
3 
4 #include <rz_types.h>
5 #include <rz_bin.h>
6 #include <rz_lib.h>
7 #include "mz/mz.h"
8 
9 /* half-magic */
10 #define HM(x) (int)((int)(x[0] << 8) | (int)(x[1]))
11 
12 static Sdb *get_sdb(RzBinFile *bf) {
13  const struct rz_bin_mz_obj_t *bin;
14  if (bf && bf->o && bf->o->bin_obj) {
15  bin = (struct rz_bin_mz_obj_t *)bf->o->bin_obj;
16  if (bin && bin->kv) {
17  return bin->kv;
18  }
19  }
20  return NULL;
21 }
22 
24  ut8 h[2];
25  if (rz_buf_read_at(b, offset, h, sizeof(h)) != sizeof(h)) {
26  return false;
27  }
28  if (!memcmp(h, "PE", 2)) {
29  if (offset + 0x20 < rz_buf_size(b)) {
30  if (rz_buf_read_at(b, offset + 0x18, h, sizeof(h)) != 2) {
31  return false;
32  }
33  if (!memcmp(h, "\x0b\x01", 2)) {
34  return true;
35  }
36  }
37  } else {
38  if (!memcmp(h, "NE", 2) || !memcmp(h, "LE", 2) || !memcmp(h, "LX", 2) || !memcmp(h, "PL", 2)) {
39  return true;
40  }
41  }
42  return false;
43 }
44 
46  ut16 cs;
47  if (!rz_buf_read_le16_at(b, 0x16, &cs)) {
48  return false;
49  }
50 
51  ut16 ip;
52  if (!rz_buf_read_le16_at(b, 0x14, &ip)) {
53  return false;
54  }
55 
56  ut16 tmp;
57  if (!rz_buf_read_le16_at(b, 0x08, &tmp)) {
58  return false;
59  }
60 
61  ut32 pa = ((tmp + cs) << 4) + ip;
62 
63  /* A minimal MZ header is 0x1B bytes. Header length is measured in
64  * 16-byte paragraphs so the minimum header must occupy 2 paragraphs.
65  * This means that the entrypoint should be at least 0x20 unless someone
66  * cleverly fit a few instructions inside the header.
67  */
68  pa &= 0xffff;
70  if (pa >= 0x20 && pa + 1 < length) {
71  ut16 pe;
72  if (!rz_buf_read_le16_at(b, 0x3c, &pe)) {
73  return false;
74  }
75 
76  if (pe + 2 < length && length > 0x104) {
77  ut8 h[2];
78  if (rz_buf_read_at(b, pe, h, 2) == 2) {
79  if (!memcmp(h, "PE", 2)) {
80  return false;
81  }
82  }
83  }
84  return true;
85  }
86  return false;
87 }
88 
89 static bool check_buffer(RzBuffer *b) {
90  rz_return_val_if_fail(b, false);
91  ut64 b_size = rz_buf_size(b);
92  if (b_size <= 0x3d) {
93  return false;
94  }
95 
96  // Check for MZ magic.
97  ut8 h[2];
98  if (rz_buf_read_at(b, 0, h, 2) != 2) {
99  return false;
100  }
101  if (memcmp(h, "MZ", 2)) {
102  return false;
103  }
104 
105  // See if there is a new exe header.
106  ut16 new_exe_header_offset;
107  if (!rz_buf_read_le16_at(b, 0x3c, &new_exe_header_offset)) {
108  return false;
109  }
110 
111  if (b_size > new_exe_header_offset + 2) {
112  if (knownHeaderBuffer(b, new_exe_header_offset)) {
113  return false;
114  }
115  }
116 
117  // Raw plain MZ executable (watcom)
118  if (!checkEntrypointBuffer(b)) {
119  return false;
120  }
121  return true;
122 }
123 
124 static bool load(RzBinFile *bf, RzBinObject *obj, RzBuffer *buf, Sdb *sdb) {
125  struct rz_bin_mz_obj_t *mz_obj = rz_bin_mz_new_buf(buf);
126  if (mz_obj) {
127  sdb_ns_set(sdb, "info", mz_obj->kv);
128  obj->bin_obj = mz_obj;
129  return true;
130  }
131  return false;
132 }
133 
134 static void destroy(RzBinFile *bf) {
135  rz_bin_mz_free((struct rz_bin_mz_obj_t *)bf->o->bin_obj);
136 }
137 
139  RzBinAddr *mzaddr = NULL;
140  if (bf && bf->o && bf->o->bin_obj) {
141  switch (type) {
143  mzaddr = rz_bin_mz_get_main_vaddr(bf->o->bin_obj);
144  break;
145  default:
146  break;
147  }
148  }
149  return mzaddr;
150 }
151 
152 static RzList *entries(RzBinFile *bf) {
153  RzBinAddr *ptr = NULL;
154  RzList *res = NULL;
155  if (!(res = rz_list_newf(free))) {
156  return NULL;
157  }
158  ptr = rz_bin_mz_get_entrypoint(bf->o->bin_obj);
159  if (ptr) {
160  rz_list_append(res, ptr);
161  }
162  return res;
163 }
164 
165 static RzList *sections(RzBinFile *bf) {
166  return rz_bin_mz_get_segments(bf->o->bin_obj);
167 }
168 
169 static RzBinInfo *info(RzBinFile *bf) {
170  RzBinInfo *const ret = RZ_NEW0(RzBinInfo);
171  if (!ret) {
172  return NULL;
173  }
174  ret->file = strdup(bf->file);
175  ret->bclass = strdup("MZ");
176  ret->rclass = strdup("mz");
177  ret->os = strdup("DOS");
178  ret->arch = strdup("x86");
179  ret->machine = strdup("i386");
180  ret->type = strdup("EXEC (Executable file)");
181  ret->subsystem = strdup("DOS");
182  ret->bits = 16;
183  ret->dbg_info = 0;
184  ret->big_endian = false;
185  ret->has_crypto = false;
186  ret->has_canary = false;
187  ret->has_retguard = -1;
188  ret->has_nx = false;
189  ret->has_pi = false;
190  ret->has_va = true;
191  return ret;
192 }
193 
194 static void header(RzBinFile *bf) {
195  const struct rz_bin_mz_obj_t *mz = (struct rz_bin_mz_obj_t *)bf->o->bin_obj;
196  eprintf("[0000:0000] Signature %c%c\n",
197  mz->dos_header->signature & 0xFF,
198  mz->dos_header->signature >> 8);
199  eprintf("[0000:0002] BytesInLastBlock 0x%04x\n",
201  eprintf("[0000:0004] BlocksInFile 0x%04x\n",
203  eprintf("[0000:0006] NumRelocs 0x%04x\n",
204  mz->dos_header->num_relocs);
205  eprintf("[0000:0008] HeaderParagraphs 0x%04x\n",
207  eprintf("[0000:000a] MinExtraParagraphs 0x%04x\n",
209  eprintf("[0000:000c] MaxExtraParagraphs 0x%04x\n",
211  eprintf("[0000:000e] InitialSs 0x%04x\n",
212  mz->dos_header->ss);
213  eprintf("[0000:0010] InitialSp 0x%04x\n",
214  mz->dos_header->sp);
215  eprintf("[0000:0012] Checksum 0x%04x\n",
216  mz->dos_header->checksum);
217  eprintf("[0000:0014] InitialIp 0x%04x\n",
218  mz->dos_header->ip);
219  eprintf("[0000:0016] InitialCs 0x%04x\n",
220  mz->dos_header->cs);
221  eprintf("[0000:0018] RelocTableOffset 0x%04x\n",
223  eprintf("[0000:001a] OverlayNumber 0x%04x\n",
225 }
226 
227 static RzList *relocs(RzBinFile *bf) {
228  RzList *ret = NULL;
229  RzBinReloc *rel = NULL;
230  const struct rz_bin_mz_reloc_t *relocs = NULL;
231  int i;
232 
233  if (!bf || !bf->o || !bf->o->bin_obj) {
234  return NULL;
235  }
236  if (!(ret = rz_list_newf(free))) {
237  return NULL;
238  }
239  if (!(relocs = rz_bin_mz_get_relocs(bf->o->bin_obj))) {
240  return ret;
241  }
242  for (i = 0; !relocs[i].last; i++) {
243  if (!(rel = RZ_NEW0(RzBinReloc))) {
244  free((void *)relocs);
245  rz_list_free(ret);
246  return NULL;
247  }
248  rel->type = RZ_BIN_RELOC_16;
249  rel->vaddr = relocs[i].vaddr;
250  rel->paddr = relocs[i].paddr;
251  rz_list_append(ret, rel);
252  }
253  free((void *)relocs);
254  return ret;
255 }
256 
258  .name = "mz",
259  .desc = "MZ bin plugin",
260  .license = "MIT",
261  .get_sdb = &get_sdb,
262  .load_buffer = &load,
263  .destroy = &destroy,
264  .check_buffer = &check_buffer,
265  .binsym = &binsym,
266  .entries = &entries,
268  .sections = &sections,
269  .info = &info,
270  .header = &header,
271  .relocs = &relocs,
272  .minstrlen = 4,
273 };
274 
275 #ifndef RZ_PLUGIN_INCORE
278  .data = &rz_bin_plugin_mz,
280 };
281 #endif
lzma_index ** i
Definition: index.h:629
RZ_API RZ_OWN RzList * rz_bin_maps_of_file_sections(RZ_NONNULL RzBinFile *binfile)
Create a list of RzBinMap from RzBinSections queried from the given file.
Definition: bin.c:1040
static Sdb * get_sdb(RzBinFile *bf)
Definition: bin_mz.c:12
static bool knownHeaderBuffer(RzBuffer *b, ut16 offset)
Definition: bin_mz.c:23
static RzBinAddr * binsym(RzBinFile *bf, RzBinSpecialSymbol type)
Definition: bin_mz.c:138
static void header(RzBinFile *bf)
Definition: bin_mz.c:194
static void destroy(RzBinFile *bf)
Definition: bin_mz.c:134
RZ_API RzLibStruct rizin_plugin
Definition: bin_mz.c:276
static bool check_buffer(RzBuffer *b)
Definition: bin_mz.c:89
static RzBinInfo * info(RzBinFile *bf)
Definition: bin_mz.c:169
RzBinPlugin rz_bin_plugin_mz
Definition: bin_mz.c:257
static bool checkEntrypointBuffer(RzBuffer *b)
Definition: bin_mz.c:45
static RzList * entries(RzBinFile *bf)
Definition: bin_mz.c:152
static bool load(RzBinFile *bf, RzBinObject *obj, RzBuffer *buf, Sdb *sdb)
Definition: bin_mz.c:124
static RzList * sections(RzBinFile *bf)
Definition: bin_mz.c:165
static RzList * relocs(RzBinFile *bf)
Definition: bin_mz.c:227
#define RZ_API
#define NULL
Definition: cris-opc.c:27
static static sync static getppid static getegid const char static filename char static len const char char static bufsiz static mask static vfork const void static prot static getpgrp const char static swapflags static arg static fd static protocol static who struct sockaddr static addrlen static backlog struct timeval struct timezone static tz const struct iovec static count static mode const void const struct sockaddr static tolen const char static pathname void static offset struct stat static buf void long static basep static whence static length const void static len static semflg const void static shmflg const struct timespec struct timespec static rem const char static group const void length
Definition: sflib.h:133
uint16_t ut16
uint32_t ut32
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_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 RzListIter * rz_list_append(RZ_NONNULL RzList *list, void *data)
Appends at the end of the list a new element.
Definition: list.c:288
RZ_API void rz_list_free(RZ_NONNULL RzList *list)
Empties the list and frees the list pointer.
Definition: list.c:137
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")
#define ip
int type
Definition: mipsasm.c:17
RzList * rz_bin_mz_get_segments(const struct rz_bin_mz_obj_t *bin)
Definition: mz.c:62
RzBinAddr * rz_bin_mz_get_entrypoint(const struct rz_bin_mz_obj_t *bin)
Definition: mz.c:16
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
RzBinAddr * rz_bin_mz_get_main_vaddr(struct rz_bin_mz_obj_t *bin)
Definition: mz.c:330
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_ns_set(Sdb *s, const char *name, Sdb *r)
Definition: ns.c:156
#define eprintf(x, y...)
Definition: rlcc.c:7
#define rz_return_val_if_fail(expr, val)
Definition: rz_assert.h:108
@ RZ_BIN_RELOC_16
Definition: rz_bin.h:174
RzBinSpecialSymbol
Definition: rz_bin.h:136
@ RZ_BIN_SPECIAL_SYMBOL_MAIN
Definition: rz_bin.h:139
#define rz_buf_read_le16_at(b, addr, result)
Definition: rz_buf.h:270
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 ut64 rz_buf_size(RZ_NONNULL RzBuffer *b)
Return the size of the buffer.
Definition: buf.c:1225
@ RZ_LIB_TYPE_BIN
Definition: rz_lib.h:75
#define RZ_NEW0(x)
Definition: rz_types.h:284
#define RZ_VERSION
Definition: rz_version.h:8
#define b(i)
Definition: sha256.c:42
#define h(i)
Definition: sha256.c:48
ut16 min_extra_paragraphs
Definition: mz_specs.h:10
ut16 bytes_in_last_block
Definition: mz_specs.h:6
ut16 reloc_table_offset
Definition: mz_specs.h:17
ut16 max_extra_paragraphs
Definition: mz_specs.h:11
ut16 header_paragraphs
Definition: mz_specs.h:9
Definition: malloc.c:26
XX curplugin == o->plugin.
Definition: rz_bin.h:298
RzBinObject * o
Definition: rz_bin.h:305
char * file
Definition: rz_bin.h:299
int has_va
Definition: rz_bin.h:228
char * type
Definition: rz_bin.h:211
int has_crypto
Definition: rz_bin.h:233
int has_canary
Definition: rz_bin.h:230
char * os
Definition: rz_bin.h:219
char * subsystem
Definition: rz_bin.h:220
int has_pi
Definition: rz_bin.h:229
int has_nx
Definition: rz_bin.h:234
char * machine
Definition: rz_bin.h:216
char * bclass
Definition: rz_bin.h:212
char * file
Definition: rz_bin.h:210
ut64 dbg_info
Definition: rz_bin.h:240
int has_retguard
Definition: rz_bin.h:231
char * rclass
Definition: rz_bin.h:213
char * arch
Definition: rz_bin.h:214
int big_endian
Definition: rz_bin.h:235
Sdb * kv
Definition: mz.h:38
const MZ_image_dos_header * dos_header
Definition: mz.h:27
void * bin_obj
Definition: rz_bin.h:293
char * name
Definition: rz_bin.h:509
char * version
Definition: rz_bin.h:512
ut64 paddr
the paddr where the value should be patched into
Definition: rz_bin.h:717
RzBinRelocType type
Definition: rz_bin.h:712
ut64 vaddr
the vaddr where the value should be patched into
Definition: rz_bin.h:716
Definition: sdb.h:63
if(dbg->bits==RZ_SYS_BITS_64)
Definition: windows-arm64.h:4
ut64(WINAPI *w32_GetEnabledXStateFeatures)()