Rizin
unix-like reverse engineering framework and cli tools
pemixed.c
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: 2018 JohnPeng47 <johnpeng47@gmail.com>
2 // SPDX-License-Identifier: LGPL-3.0-only
3 
4 #include <stdio.h>
5 #include "pemixed.h"
6 
7 static bool check_il_only(ut32 flags);
8 
9 static int rz_bin_pemixed_init(struct rz_bin_pemixed_obj_t *bin, RzBinPEObj *pe_bin) {
10  RzBinPEObj *sub_bin_dos;
11  RzBinPEObj *sub_bin_native;
12  RzBinPEObj *sub_bin_net;
13 
14  sub_bin_dos = rz_bin_pemixed_init_dos(pe_bin);
15  if (sub_bin_dos) {
16  bin->sub_bin_dos = sub_bin_dos;
17  }
18 
19  sub_bin_native = rz_bin_pemixed_init_native(pe_bin);
20  if (sub_bin_native) {
21  bin->sub_bin_native = sub_bin_native;
22  }
23  sub_bin_net = pe_bin;
24  bin->sub_bin_net = sub_bin_net;
25  return true;
26 }
27 
28 // carves out dos from original pe
29 // TODO: return mz file instead pe
31  ut8 *tmp_buf;
32 
33  ut64 pe_hdr_off = pe_bin->dos_header->e_lfanew;
34 
35  // idk if this is the most efficient way but could not find a function to read
36  // RzBuffer into another RzBuffer
37  if (!(tmp_buf = malloc(pe_hdr_off))) {
38  return NULL;
39  }
40 
41  if ((rz_buf_read_at(pe_bin->b, 0, tmp_buf, pe_hdr_off)) == -1) {
42  RZ_LOG_ERROR("Cannot read buffer\n");
43  return NULL;
44  }
45 
46  RzBinPEObj *sub_bin_dos = RZ_NEW0(RzBinPEObj);
47  if (!(sub_bin_dos->b = rz_buf_new_with_bytes(tmp_buf, pe_hdr_off))) {
49  (sub_bin_dos);
50  return NULL;
51  }
52 
53  sub_bin_dos->size = pe_hdr_off;
54  sub_bin_dos->dos_header = pe_bin->dos_header;
55 
56  free(tmp_buf);
57  return sub_bin_dos;
58 }
59 
61  ut8 *zero_out;
62 
63  RzBinPEObj *sub_bin_native = RZ_NEW0(RzBinPEObj);
64  memcpy(sub_bin_native, pe_bin, sizeof(RzBinPEObj));
65 
66  // copy pe_bin->b and assign to sub_bin_native
67 
68  // if (!(tmp_buf = malloc (b_size))) {
69  // RZ_LOG_ERROR("bad malloc\n");
70  // };
71 
72  // if (!(rz_buf_read_at (pe_bin->b, 0, tmp_buf, b_size))) {
73  // free (sub_bin_native);
74  // return NULL;
75  // }
76 
77  if (!(sub_bin_native->b = rz_buf_new_with_buf(pe_bin->b))) {
78  free(sub_bin_native);
79  RZ_LOG_ERROR("failed to create new buffer\n");
80  return NULL;
81  }
82 
83  // calculate the dotnet data directory offset
84  int dotnet_offset = pe_bin->dos_header->e_lfanew;
85  dotnet_offset += sizeof(PE_(image_nt_headers));
86  dotnet_offset -= sizeof(PE_(image_data_directory)) * 2;
87 
88  if (!(zero_out = (ut8 *)calloc(2, 4 * sizeof(ut8)))) {
89  // can't call PE_(rz_bin_pe_free) since this will free the underlying pe_bin
90  // object which we may need for later
91  // PE_(rz_bin_pe_free) (sub_bin_native);
92  rz_buf_free(sub_bin_native->b);
93  free(sub_bin_native);
94  return NULL;
95  }
96 
97  if (rz_buf_write_at(sub_bin_native->b, dotnet_offset, zero_out, sizeof(PE_(image_data_directory))) < -1) {
98  RZ_LOG_ERROR("Zeroing out dotnet offset failed\n");
99  rz_buf_free(sub_bin_native->b);
100  free(sub_bin_native);
101  free(zero_out);
102  return NULL;
103  }
104 
105  free(zero_out);
106  return sub_bin_native;
107 }
108 
109 // this method should just return the original pe file
110 // RzBinPEObj* rz_bin_pemixed_init_net(RzBinPEObj* pe_bin) {
111 // return pe_bin;
112 // }
113 
114 // not sure if this function is nessescary
116  if (!bin) {
117  return NULL;
118  }
119 
120  switch (sub_bin) {
121  case SUB_BIN_DOS:
122  return bin->sub_bin_dos;
123  case SUB_BIN_NATIVE:
124  return bin->sub_bin_native;
125  case SUB_BIN_NET:
126  return bin->sub_bin_net;
127  }
128  return NULL;
129 }
130 
131 // if IL only bit is set; if true then it is pure .NET binary with no unmanaged code
132 static bool check_il_only(ut32 flag) {
133  ut32 check_mask = 1;
134  return flag & check_mask;
135 }
136 
138  if (!bin) {
139  return NULL;
140  }
141  // only one free is nessescary since they all point
142  // to the same original pe struct
143  // possible memleak here
145  (bin->sub_bin_net);
146  if (bin->sub_bin_dos) {
147  rz_buf_free(bin->sub_bin_dos->b); // dos is the only one with its own buf
148  }
149  free(bin->sub_bin_dos);
150  free(bin->sub_bin_native);
151 
152  // PE_(rz_bin_pe_free)(bin->sub_bin_native);
153  // PE_(rz_bin_pe_free)(bin->sub_bin_net);
154  rz_buf_free(bin->b);
155  RZ_FREE(bin);
156  return NULL;
157 }
158 
161  RzBinPEObj *pe_bin;
162  if (!bin || !buf) {
163  return rz_bin_pemixed_free(bin);
164  }
166  if (!bin->b) {
167  return rz_bin_pemixed_free(bin);
168  }
169  bin->size = size;
170  pe_bin = PE_(rz_bin_pe_new_buf)(bin->b, true);
171  if (!pe_bin) {
173  (pe_bin);
174  return rz_bin_pemixed_free(bin);
175  }
176  if (!pe_bin->clr || !pe_bin->clr->header) {
178  (pe_bin);
179  return rz_bin_pemixed_free(bin);
180  }
181  // check if binary only contains managed code
182  // check implemented here cuz we need to intialize
183  // the pe header to access the clr hdr
184  if (check_il_only(pe_bin->clr->header->Flags)) {
186  (pe_bin);
187  return rz_bin_pemixed_free(bin);
188  }
189  if (!rz_bin_pemixed_init(bin, pe_bin)) {
191  (pe_bin);
192  return rz_bin_pemixed_free(bin);
193  }
194  return bin;
195 }
#define NULL
Definition: cris-opc.c:27
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 void * buf
Definition: ioapi.h:138
uint8_t ut8
Definition: lh5801.h:11
memcpy(mem, inblock.get(), min(CONTAINING_RECORD(inblock.get(), MEMBLOCK, data) ->size, size))
void * malloc(size_t size)
Definition: malloc.c:123
void * calloc(size_t number, size_t size)
Definition: malloc.c:102
void *PE_() rz_bin_pe_free(RzBinPEObj *bin)
Definition: pe.c:88
RzBinPEObj *PE_() rz_bin_pe_new_buf(RzBuffer *buf, bool verbose)
Definition: pe.c:116
#define RzBinPEObj
Definition: pe.h:126
#define PE_(name)
Definition: pe_specs.h:23
struct rz_bin_pemixed_obj_t * rz_bin_pemixed_from_bytes_new(const ut8 *buf, ut64 size)
Definition: pemixed.c:159
RzBinPEObj * rz_bin_pemixed_extract(struct rz_bin_pemixed_obj_t *bin, int sub_bin)
Definition: pemixed.c:115
static bool check_il_only(ut32 flags)
Definition: pemixed.c:132
RzBinPEObj * rz_bin_pemixed_init_dos(RzBinPEObj *pe_bin)
Definition: pemixed.c:30
void * rz_bin_pemixed_free(struct rz_bin_pemixed_obj_t *bin)
Definition: pemixed.c:137
static int rz_bin_pemixed_init(struct rz_bin_pemixed_obj_t *bin, RzBinPEObj *pe_bin)
Definition: pemixed.c:9
RzBinPEObj * rz_bin_pemixed_init_native(RzBinPEObj *pe_bin)
Definition: pemixed.c:60
#define SUB_BIN_NATIVE
Definition: pemixed.h:8
#define SUB_BIN_DOS
Definition: pemixed.h:7
#define SUB_BIN_NET
Definition: pemixed.h:9
RZ_API st64 rz_buf_write_at(RZ_NONNULL RzBuffer *b, ut64 addr, RZ_NONNULL const ut8 *buf, ut64 len)
Write len bytes of the buffer at the specified address.
Definition: buf.c:1197
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 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
#define RZ_LOG_ERROR(fmtstr,...)
Definition: rz_log.h:58
#define RZ_NEW0(x)
Definition: rz_types.h:284
#define RZ_FREE(x)
Definition: rz_types.h:369
static struct sockaddr static addrlen static backlog const void static flags void flags
Definition: sfsocketcall.h:123
Definition: malloc.c:26
ut64(WINAPI *w32_GetEnabledXStateFeatures)()