1 /*
2  *	HT Editor
3  *	htpe.cc
4  *
5  *	Copyright (C) 1999-2002 Stefan Weyergraf
6  *
7  *	This program is free software; you can redistribute it and/or modify
8  *	it under the terms of the GNU General Public License version 2 as
9  *	published by the Free Software Foundation.
10  *
11  *	This program is distributed in the hope that it will be useful,
12  *	but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *	GNU General Public License for more details.
15  *
16  *	You should have received a copy of the GNU General Public License
17  *	along with this program; if not, write to the Free Software
18  *	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19  */
20 
21 #include "log.h"
22 #include "endianess.h"
23 #include "htnewexe.h"
24 #include "htpe.h"
25 #include "htpehead.h"
26 #include "htpeexp.h"
27 #include "htpeil.h"
28 #include "htpeimp.h"
29 #include "htpedimp.h"
30 #include "htpeimg.h"
31 #include "htperes.h"
32 #include "htpereloc.h"
33 #include "stream.h"
34 #include "tools.h"
35 
36 #include <stdlib.h>
37 #include <string.h>
38 
39 static format_viewer_if *htpe_ifs[] = {
40 	&htpeheader_if,
41 	&htpeexports_if,
42 	&htpeimports_if,
43 	&htpereloc_if,
44 	&htpedelayimports_if,
45 	&htperesources_if,
46 	&htpeil_if,
47 	&htpeimage_if,
48 	0
49 };
50 
htpe_init(Bounds * b,File * file,ht_format_group * format_group)51 static ht_view *htpe_init(Bounds *b, File *file, ht_format_group *format_group)
52 {
53 	byte pemagic[4];
54 	FileOfs h = get_newexe_header_ofs(file);
55 	file->seek(h);
56 	;
57 	if (file->read(pemagic, 4) != 4
58 	 || pemagic[0] != PE_MAGIC0 || pemagic[1] != PE_MAGIC1
59 	 || pemagic[2] != PE_MAGIC2 || pemagic[3] != PE_MAGIC3) return 0;
60 
61 	ht_pe *g = new ht_pe();
62 	g->init(b, file, htpe_ifs, format_group, h);
63 	return g;
64 }
65 
66 format_viewer_if htpe_if = {
67 	htpe_init,
68 	0
69 };
70 
71 /*
72  *	CLASS ht_pe
73  */
init(Bounds * b,File * file,format_viewer_if ** ifs,ht_format_group * format_group,FileOfs header_ofs)74 void ht_pe::init(Bounds *b, File *file, format_viewer_if **ifs, ht_format_group *format_group, FileOfs header_ofs)
75 {
76 	ht_format_group::init(b, VO_BROWSABLE | VO_SELECTABLE | VO_RESIZE, DESC_PE, file, false, true, 0, format_group);
77 	VIEW_DEBUG_NAME("ht_pe");
78 
79 	String fn;
80 	LOG("%y: PE: found header at 0x%08qx", &file->getFilename(fn), header_ofs);
81 	ht_pe_shared_data *pe_shared = new ht_pe_shared_data;
82 
83 	shared_data = pe_shared;
84 	pe_shared->header_ofs = header_ofs;
85 
86 	pe_shared->exports.funcs = new Array(true);
87 	pe_shared->dimports.funcs = new Array(true);
88 	pe_shared->dimports.libs = new Array(true);
89 	pe_shared->imports.funcs = new Array(true);
90 	pe_shared->imports.libs = new Array(true);
91 
92 	pe_shared->il = NULL;
93 	pe_shared->v_image = NULL;
94 	pe_shared->v_dimports = NULL;
95 	pe_shared->v_imports = NULL;
96 	pe_shared->v_exports = NULL;
97 	pe_shared->v_resources = NULL;
98 	pe_shared->v_header = NULL;
99 
100 	/* read header */
101 	file->seek(header_ofs+4);
102 	file->readx(&pe_shared->coffheader, sizeof pe_shared->coffheader);
103 	createHostStruct(&pe_shared->coffheader, COFF_HEADER_struct, little_endian);
104 	file->readx(&pe_shared->opt_magic, sizeof pe_shared->opt_magic);
105 	pe_shared->opt_magic = createHostInt(&pe_shared->opt_magic, sizeof pe_shared->opt_magic, little_endian);
106 	file->seek(header_ofs+4+sizeof pe_shared->coffheader);
107 	switch (pe_shared->opt_magic) {
108 	case COFF_OPTMAGIC_PE32:
109 		file->readx(&pe_shared->pe32.header, sizeof pe_shared->pe32.header);
110 		createHostStruct(&pe_shared->pe32.header, COFF_OPTIONAL_HEADER32_struct, little_endian);
111 		file->readx(&pe_shared->pe32.header_nt, sizeof pe_shared->pe32.header_nt);
112 		createHostStruct(&pe_shared->pe32.header_nt, PE_OPTIONAL_HEADER32_NT_struct, little_endian);
113 		for (uint i=0; i<PE_NUMBEROF_DIRECTORY_ENTRIES; i++) {
114 			createHostStruct(&pe_shared->pe32.header_nt.directory[i], PE_DATA_DIRECTORY_struct, little_endian);
115 		}
116 		break;
117 	case COFF_OPTMAGIC_PE64:
118 		file->readx(&pe_shared->pe64.header, sizeof pe_shared->pe64.header);
119 		createHostStruct(&pe_shared->pe64.header, COFF_OPTIONAL_HEADER64_struct, little_endian);
120 		file->readx(&pe_shared->pe64.header_nt, sizeof pe_shared->pe64.header_nt);
121 		createHostStruct(&pe_shared->pe64.header_nt, PE_OPTIONAL_HEADER64_NT_struct, little_endian);
122 		for (uint i=0; i<PE_NUMBEROF_DIRECTORY_ENTRIES; i++) {
123 			createHostStruct(&pe_shared->pe64.header_nt.directory[i], PE_DATA_DIRECTORY_struct, little_endian);
124 		}
125 		break;
126 	}
127 
128 	/* read section headers */
129 	int os=pe_shared->coffheader.optional_header_size;
130 	pe_shared->sections.section_count=pe_shared->coffheader.section_count;
131 
132 	file->seek(header_ofs+os+sizeof(COFF_HEADER)+4/*magic*/);
133 	pe_shared->sections.sections = ht_malloc(pe_shared->sections.section_count * sizeof *pe_shared->sections.sections);
134 	file->readx(pe_shared->sections.sections, pe_shared->sections.section_count*sizeof *pe_shared->sections.sections);
135 
136 	for (uint i=0; i<pe_shared->sections.section_count; i++) {
137 		createHostStruct(&pe_shared->sections.sections[i], COFF_SECTION_HEADER_struct, little_endian);
138 		/*
139 		 *	To make those uninitialized/initialized flags
140 		 *	correct we guess a little
141 		 *
142 		if (pe_shared->sections.sections[i].data_size &&
143 			pe_shared->sections.sections[i].data_offset) {
144 
145 			pe_shared->sections.sections[i].characteristics |= ;
146 			pe_shared->sections.sections[i].characteristics ~= ;
147 		} else {
148 			pe_shared->sections.sections[i].characteristics |= ;
149 			pe_shared->sections.sections[i].characteristics ~= ;
150 		}*/
151 	}
152 
153 	shared_data = pe_shared;
154 
155 	ht_format_group::init_ifs(ifs);
156 }
157 
done()158 void ht_pe::done()
159 {
160 	ht_format_group::done();
161 
162 	ht_pe_shared_data *pe_shared = (ht_pe_shared_data*)shared_data;
163 
164 	delete pe_shared->exports.funcs;
165 	delete pe_shared->dimports.funcs;
166 	delete pe_shared->dimports.libs;
167 	delete pe_shared->imports.funcs;
168 	delete pe_shared->imports.libs;
169 
170 	free(pe_shared->sections.sections);
171 	delete pe_shared;
172 }
173 
loc_enum_start()174 void ht_pe::loc_enum_start()
175 {
176 /*
177 	ht_pe_shared_data *sh=(ht_pe_shared_data*)shared_data;
178 	if (sh->opt_magic==COFF_OPTMAGIC_PE32) {
179 		loc_enum=1;
180 	} else {
181 		loc_enum=0;
182 	}
183 */
184 }
185 
loc_enum_next(ht_format_loc * loc)186 bool ht_pe::loc_enum_next(ht_format_loc *loc)
187 {
188 #if 0
189 	ht_pe_shared_data *sh=(ht_pe_shared_data*)shared_data;
190 	if (loc_enum) {
191 		loc->name="pe";
192 		loc->start=sh->header_ofs;
193 		// calc pe size
194 		uint l=sizeof (COFF_HEADER) + sh->coffheader.optional_header_size;
195 		// go through directories
196 		for (uint i=0; i<16; i++) {
197 			FileOfs o;
198 			if (pe_rva_to_ofs(&sh->sections, sh->pe32.header_nt.directory[i].address, &o)) {
199 				uint k=o+sh->pe32.header_nt.directory[i].size-sh->header_ofs;
200 				l=MAX(k, l);
201 			}
202 		}
203 		// go through sections
204 		for (uint i=0; i<sh->sections.section_count; i++) {
205 			uint k=sh->sections.sections[i].data_offset+sh->sections.sections[i].data_size-sh->header_ofs;
206 			l=MAX(k, l);
207 		}
208 		loc->length=l;
209 
210 		loc_enum=0;
211 		return true;
212 	}
213 	return false;
214 #endif
215 	return false;
216 }
217 
218 /*
219  *	rva conversion routines
220  */
221 
pe_rva_to_ofs(pe_section_headers * section_headers,RVA rva,FileOfs * ofs)222 bool pe_rva_to_ofs(pe_section_headers *section_headers, RVA rva, FileOfs *ofs)
223 {
224 	COFF_SECTION_HEADER *s=section_headers->sections;
225 	for (uint i=0; i<section_headers->section_count; i++) {
226 		if ((rva>=s->data_address) &&
227 		(rva<s->data_address+s->data_size)) {
228 			*ofs=rva-s->data_address+s->data_offset;
229 			return true;
230 		}
231 		s++;
232 	}
233 	return false;
234 }
235 
pe_rva_to_section(pe_section_headers * section_headers,RVA rva,int * section)236 bool pe_rva_to_section(pe_section_headers *section_headers, RVA rva, int *section)
237 {
238 	COFF_SECTION_HEADER *s=section_headers->sections;
239 	for (uint i=0; i<section_headers->section_count; i++) {
240 		if ((rva>=s->data_address) &&
241 		(rva<s->data_address+MAX(s->data_size, s->data_vsize))) {
242 			*section=i;
243 			return true;
244 		}
245 		s++;
246 	}
247 	return false;
248 }
249 
pe_rva_is_valid(pe_section_headers * section_headers,RVA rva)250 bool pe_rva_is_valid(pe_section_headers *section_headers, RVA rva)
251 {
252 	COFF_SECTION_HEADER *s=section_headers->sections;
253 	for (uint i=0; i<section_headers->section_count; i++) {
254 		if ((rva>=s->data_address) &&
255 		(rva<s->data_address+MAX(s->data_size, s->data_vsize))) {
256 			return true;
257 		}
258 		s++;
259 	}
260 	return false;
261 }
262 
pe_rva_is_physical(pe_section_headers * section_headers,RVA rva)263 bool pe_rva_is_physical(pe_section_headers *section_headers, RVA rva)
264 {
265 	COFF_SECTION_HEADER *s=section_headers->sections;
266 	for (uint i=0; i<section_headers->section_count; i++) {
267 		if ((rva>=s->data_address) &&
268 		(rva<s->data_address+s->data_size)) {
269 			return true;
270 		}
271 		s++;
272 	}
273 	return false;
274 }
275 
276 /*
277  *	ofs conversion routines
278  */
279 
pe_ofs_to_rva(pe_section_headers * section_headers,FileOfs ofs,RVA * rva)280 bool pe_ofs_to_rva(pe_section_headers *section_headers, FileOfs ofs, RVA *rva)
281 {
282 	COFF_SECTION_HEADER *s=section_headers->sections;
283 	for (uint i=0; i<section_headers->section_count; i++) {
284 		if ((ofs>=s->data_offset) &&
285 		(ofs<s->data_offset+s->data_size)) {
286 			*rva=ofs-s->data_offset+s->data_address;
287 			return true;
288 		}
289 		s++;
290 	}
291 	return false;
292 }
293 
pe_ofs_to_section(pe_section_headers * section_headers,FileOfs ofs,int * section)294 bool pe_ofs_to_section(pe_section_headers *section_headers, FileOfs ofs, int *section)
295 {
296 	COFF_SECTION_HEADER *s=section_headers->sections;
297 	for (uint i=0; i<section_headers->section_count; i++) {
298 		if ((ofs>=s->data_offset) &&
299 		(ofs<s->data_offset+s->data_size)) {
300 			*section=i;
301 			return true;
302 		}
303 		s++;
304 	}
305 	return false;
306 }
307 
pe_ofs_to_rva_and_section(pe_section_headers * section_headers,FileOfs ofs,RVA * rva,int * section)308 bool pe_ofs_to_rva_and_section(pe_section_headers *section_headers, FileOfs ofs, RVA *rva, int *section)
309 {
310 	bool r = pe_ofs_to_rva(section_headers, ofs, rva);
311 	if (r) {
312 		r = pe_ofs_to_section(section_headers, ofs, section);
313 	}
314 	return r;
315 }
316 
pe_ofs_is_valid(pe_section_headers * section_headers,FileOfs ofs)317 bool pe_ofs_is_valid(pe_section_headers *section_headers, FileOfs ofs)
318 {
319 	RVA rva;
320 	return pe_ofs_to_rva(section_headers, ofs, &rva);
321 }
322 
323 /*
324  *
325  */
326 
pe_section_name_to_section(pe_section_headers * section_headers,const char * name,int * section)327 bool pe_section_name_to_section(pe_section_headers *section_headers, const char *name, int *section)
328 {
329 	COFF_SECTION_HEADER *s = section_headers->sections;
330 	int slen = strlen(name);
331 	slen = MIN(slen, COFF_SIZEOF_SHORT_NAME);
332 	for (uint i=0; i < section_headers->section_count; i++) {
333 		if (ht_strncmp(name, (char*)&s->name, slen) == 0) {
334 			*section = i;
335 			return true;
336 		}
337 		s++;
338 	}
339 	return false;
340 }
341