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