1 /* radare - LGPL - Copyright 2018 - JohnPeng47 */
2
3 #include <stdio.h>
4 #include "pemixed.h"
5
6 static bool check_il_only(ut32 flags);
7
r_bin_pemixed_init(struct r_bin_pemixed_obj_t * bin,struct PE_ (r_bin_pe_obj_t)* pe_bin)8 static int r_bin_pemixed_init(struct r_bin_pemixed_obj_t* bin, struct PE_(r_bin_pe_obj_t)* pe_bin) {
9 struct PE_(r_bin_pe_obj_t)* sub_bin_dos;
10 struct PE_(r_bin_pe_obj_t)* sub_bin_native;
11 struct PE_(r_bin_pe_obj_t)* sub_bin_net;
12
13 sub_bin_dos = r_bin_pemixed_init_dos (pe_bin);
14 if (sub_bin_dos) {
15 bin->sub_bin_dos = sub_bin_dos;
16 }
17
18 sub_bin_native = r_bin_pemixed_init_native (pe_bin);
19 if (sub_bin_native) {
20 bin->sub_bin_native = sub_bin_native;
21 }
22 sub_bin_net = pe_bin;
23 bin->sub_bin_net = sub_bin_net;
24 return true;
25 }
26
27 //carves out dos from original pe
28 //TODO: return mz file instead pe
PE_(r_bin_pe_obj_t)29 struct PE_(r_bin_pe_obj_t)* r_bin_pemixed_init_dos(struct PE_(r_bin_pe_obj_t)* pe_bin) {
30 ut8 * tmp_buf;
31
32 ut64 pe_hdr_off = pe_bin->dos_header->e_lfanew;
33
34 //idk if this is the most efficient way but could not find a function to read
35 //RBuffer into another RBuffer
36 if (!(tmp_buf = malloc (pe_hdr_off))) {
37 return NULL;
38 }
39
40 if ((r_buf_read_at (pe_bin->b, 0, tmp_buf, pe_hdr_off)) == -1) {
41 eprintf ("Error reading to buffer\n");
42 return NULL;
43 }
44
45 struct PE_(r_bin_pe_obj_t)* sub_bin_dos = R_NEW0 (struct PE_(r_bin_pe_obj_t));
46 if (!(sub_bin_dos->b = r_buf_new_with_bytes(tmp_buf, pe_hdr_off))) {
47 PE_(r_bin_pe_free) (sub_bin_dos);
48 return NULL;
49 }
50
51 sub_bin_dos->size = pe_hdr_off;
52 sub_bin_dos->dos_header = pe_bin->dos_header;
53
54 free (tmp_buf);
55 return sub_bin_dos;
56 }
57
PE_(r_bin_pe_obj_t)58 struct PE_(r_bin_pe_obj_t)* r_bin_pemixed_init_native(struct PE_(r_bin_pe_obj_t)* pe_bin) {
59 ut8* zero_out;
60
61 struct PE_(r_bin_pe_obj_t)* sub_bin_native = R_NEW0 (struct PE_(r_bin_pe_obj_t));
62 memcpy (sub_bin_native, pe_bin, sizeof(struct PE_(r_bin_pe_obj_t)));
63
64 //copy pe_bin->b and assign to sub_bin_native
65
66 // if (!(tmp_buf = malloc (b_size))) {
67 // eprintf("wtf malloc\n");
68 // };
69
70 // if (!(r_buf_read_at (pe_bin->b, 0, tmp_buf, b_size))) {
71 // free (sub_bin_native);
72 // return NULL;
73 // }
74
75 if (!(sub_bin_native->b = r_buf_new_with_buf(pe_bin->b))) {
76 free (sub_bin_native);
77 eprintf ("failed\n");
78 return NULL;
79 }
80
81 //calculate the dotnet data directory offset
82 int dotnet_offset = pe_bin->dos_header->e_lfanew;
83 dotnet_offset += sizeof (PE_(image_nt_headers));
84 dotnet_offset -= sizeof (PE_(image_data_directory)) * 2;
85
86 if (!(zero_out = (ut8*) calloc (2, 4 * sizeof (ut8)))) {
87 // can't call PE_(r_bin_pe_free) since this will free the underlying pe_bin
88 // object which we may need for later
89 // PE_(r_bin_pe_free) (sub_bin_native);
90 r_buf_free (sub_bin_native->b);
91 free (sub_bin_native);
92 return NULL;
93 }
94
95 if (r_buf_write_at (sub_bin_native->b, dotnet_offset, zero_out, sizeof (PE_(image_data_directory))) < -1) {
96 eprintf ("Zeroing out dotnet offset failed\n");
97 r_buf_free (sub_bin_native->b);
98 free (sub_bin_native);
99 free (zero_out);
100 return NULL;
101 }
102
103 free (zero_out);
104 return sub_bin_native;
105 }
106
107 //this method should just return the original pe file
108 // struct PE_(r_bin_pe_obj_t)* r_bin_pemixed_init_net(struct PE_(r_bin_pe_obj_t)* pe_bin) {
109 // return pe_bin;
110 // }
111
112 //not sure if this function is nessescary
PE_(r_bin_pe_obj_t)113 struct PE_(r_bin_pe_obj_t)* r_bin_pemixed_extract(struct r_bin_pemixed_obj_t* bin, int sub_bin) {
114 if (!bin) {
115 return NULL;
116 }
117
118 switch (sub_bin) {
119 case SUB_BIN_DOS:
120 return bin->sub_bin_dos;
121 case SUB_BIN_NATIVE:
122 return bin->sub_bin_native;
123 case SUB_BIN_NET:
124 return bin->sub_bin_net;
125 }
126 return NULL;
127 }
128
129 //if IL only bit is set; if true then it is pure .NET binary with no unmanaged code
check_il_only(ut32 flag)130 static bool check_il_only(ut32 flag) {
131 ut32 check_mask = 1;
132 return flag & check_mask;
133 }
134
r_bin_pemixed_free(struct r_bin_pemixed_obj_t * bin)135 void* r_bin_pemixed_free(struct r_bin_pemixed_obj_t* bin) {
136 if (!bin) {
137 return NULL;
138 }
139 //only one free is nessescary since they all point
140 //to the same original pe struct
141 //possible memleak here
142 PE_(r_bin_pe_free)(bin->sub_bin_net);
143 if (bin->sub_bin_dos) {
144 r_buf_free (bin->sub_bin_dos->b); //dos is the only one with its own buf
145 }
146 free (bin->sub_bin_dos);
147 free (bin->sub_bin_native);
148
149 // PE_(r_bin_pe_free)(bin->sub_bin_native);
150 // PE_(r_bin_pe_free)(bin->sub_bin_net);
151 r_buf_free (bin->b);
152 R_FREE(bin);
153 return NULL;
154 }
155
r_bin_pemixed_from_bytes_new(const ut8 * buf,ut64 size)156 struct r_bin_pemixed_obj_t * r_bin_pemixed_from_bytes_new(const ut8* buf, ut64 size) {
157 struct r_bin_pemixed_obj_t* bin = R_NEW0 (struct r_bin_pemixed_obj_t);
158 struct PE_(r_bin_pe_obj_t)* pe_bin;
159 if (!bin || !buf) {
160 return r_bin_pemixed_free (bin);
161 }
162 bin->b = r_buf_new_with_bytes (buf, size);
163 if (!bin->b) {
164 return r_bin_pemixed_free (bin);
165 }
166 bin->size = size;
167 pe_bin = PE_(r_bin_pe_new_buf) (bin->b, true);
168 if (!pe_bin) {
169 PE_(r_bin_pe_free)(pe_bin);
170 return r_bin_pemixed_free (bin);
171 }
172 if (!pe_bin->clr_hdr) {
173 PE_(r_bin_pe_free) (pe_bin);
174 return r_bin_pemixed_free (bin);
175 }
176 //check if binary only contains managed code
177 //check implemented here cuz we need to intialize
178 //the pe header to access the clr hdr
179 if (check_il_only(pe_bin->clr_hdr->Flags)) {
180 PE_(r_bin_pe_free) (pe_bin);
181 return r_bin_pemixed_free (bin);
182 }
183 if (!r_bin_pemixed_init (bin, pe_bin)) {
184 PE_(r_bin_pe_free) (pe_bin);
185 return r_bin_pemixed_free (bin);
186 }
187 return bin;
188 }
189
190