1 /*
2  *	HT Editor
3  *	pe_analy.cc
4  *
5  *	Copyright (C) 1999-2002 Sebastian Biallas (sb@biallas.net)
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 <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 
25 #include "analy.h"
26 #include "analy_alpha.h"
27 #include "analy_il.h"
28 #include "analy_names.h"
29 #include "analy_register.h"
30 #include "analy_ppc.h"
31 #include "analy_x86.h"
32 #include "analy_arm.h"
33 #include "htctrl.h"
34 #include "htdebug.h"
35 #include "htiobox.h"
36 #include "htpe.h"
37 #include "strtools.h"
38 #include "ilopc.h"
39 #include "pe_analy.h"
40 #include "pestruct.h"
41 #include "snprintf.h"
42 #include "x86asm.h"
43 
init(ht_pe_shared_data * Pe_shared,File * File)44 void	PEAnalyser::init(ht_pe_shared_data *Pe_shared, File *File)
45 {
46 	pe_shared = Pe_shared;
47 	file = File;
48 
49 	validarea = new Area();
50 	validarea->init();
51 
52 	fixupque_git = Pe_shared->fixupque.begin();
53 
54 	Analyser::init();
55 }
56 
57 
58 static char *string_func(uint32 ofs, void *context);
59 static char *token_func(uint32 token, void *context);
60 
61 /*
62  *
63  */
load(ObjectStream & f)64 void	PEAnalyser::load(ObjectStream &f)
65 {
66 	GET_OBJECT(f, validarea);
67 	Analyser::load(f);
68 }
69 
70 /*
71  *
72  */
done()73 void	PEAnalyser::done()
74 {
75 	validarea->done();
76 	delete validarea;
77 	Analyser::done();
78 }
79 
80 /*
81  *
82  */
reinit(ht_pe_shared_data * Pe_shared,File * f)83 void	PEAnalyser::reinit(ht_pe_shared_data *Pe_shared, File *f)
84 {
85 	pe_shared = Pe_shared;
86 	file = f;
87 	if (disasm->getObjectID() == ATOM_DISASM_IL) {
88 		((ILDisassembler *)disasm)->initialize(string_func, token_func, pe_shared);
89 	}
90 }
91 
92 /*
93  *
94  */
beginAnalysis()95 void PEAnalyser::beginAnalysis()
96 {
97 	char	buffer[1024];
98 
99 	setLocationTreeOptimizeThreshold(100);
100 	setSymbolTreeOptimizeThreshold(100);
101 
102 	bool pe32 = (pe_shared->opt_magic == COFF_OPTMAGIC_PE32);
103 
104 	/*
105 	 *	entrypoint
106 	 */
107 	Address *entry;
108 	if (pe32) {
109 		entry = createAddress32(pe_shared->pe32.header.entrypoint_address+pe_shared->pe32.header_nt.image_base);
110 	} else {
111 		entry = createAddress64(pe_shared->pe64.header.entrypoint_address+pe_shared->pe64.header_nt.image_base);
112 	}
113 	pushAddress(entry, entry);
114 
115 	/*
116 	 * give all sections a descriptive comment:
117 	 */
118 
119 	/*struct PE_SECTION_HEADER {
120 		byte name[PE_SIZEOF_SHORT_NAME] __attribute__ ((packed));
121 		uint32 data_vsize __attribute__ ((packed));
122 		uint32 data_address __attribute__ ((packed));
123 		uint32 data_size __attribute__	((packed));
124 		uint32 data_offset __attribute__ ((packed));
125 		uint32 relocation_offset __attribute__ ((packed));
126 		uint32 linenumber_offset __attribute__ ((packed));
127 		uint16 relocation_count __attribute__ ((packed));
128 		uint16 linenumber_count __attribute__ ((packed));
129 		uint32 characteristics __attribute__ ((packed));
130 	};*/
131 	COFF_SECTION_HEADER *s=pe_shared->sections.sections;
132 	char blub[100];
133 	for (uint i=0; i<pe_shared->sections.section_count; i++) {
134 		Address *secaddr;
135 		if (pe32) {
136 			secaddr = createAddress32(s->data_address + pe_shared->pe32.header_nt.image_base);
137 		} else {
138 			secaddr = createAddress64(s->data_address + pe_shared->pe64.header_nt.image_base);
139 		}
140 		ht_snprintf(blub, sizeof blub, ";  section %d <%s>", i+1, getSegmentNameByAddress(secaddr));
141 		addComment(secaddr, 0, "");
142 		addComment(secaddr, 0, ";******************************************************************");
143 		addComment(secaddr, 0, blub);
144 		ht_snprintf(blub, sizeof blub, ";  virtual address  %08x  virtual size   %08x", s->data_address, s->data_vsize);
145 		addComment(secaddr, 0, blub);
146 		ht_snprintf(blub, sizeof blub, ";  file offset      %08x  file size      %08x", s->data_offset, s->data_size);
147 		addComment(secaddr, 0, blub);
148 		addComment(secaddr, 0, ";******************************************************************");
149 
150 		// mark end of sections
151 		ht_snprintf(blub, sizeof blub, ";  end of section <%s>", getSegmentNameByAddress(secaddr));
152 		Address *secend_addr = secaddr->clone();
153 		secend_addr->add(MAX(s->data_size, s->data_vsize));
154 		newLocation(secend_addr)->flags |= AF_FUNCTION_END;
155 		addComment(secend_addr, 0, "");
156 		addComment(secend_addr, 0, ";******************************************************************");
157 		addComment(secend_addr, 0, blub);
158 		addComment(secend_addr, 0, ";******************************************************************");
159 
160 		validarea->add(secaddr, secend_addr);
161 		Address *seciniaddr = secaddr->clone();
162 		seciniaddr->add(MIN(s->data_size, s->data_vsize));
163 		if (validAddress(secaddr, scinitialized) && validAddress(seciniaddr, scinitialized)) {
164 			initialized->add(secaddr, seciniaddr);
165 		}
166 		s++;
167 		delete secaddr;
168 		delete secend_addr;
169 		delete seciniaddr;
170 	}
171 
172 	// exports
173 
174 	int export_count=pe_shared->exports.funcs->count();
175 	int *entropy = random_permutation(export_count);
176 	for (int i=0; i<export_count; i++) {
177 		ht_pe_export_function *f=(ht_pe_export_function *)(*pe_shared->exports.funcs)[entropy[i]];
178 		Address *faddr;
179 		if (pe32) {
180 			faddr = createAddress32(f->address + pe_shared->pe32.header_nt.image_base);
181 		} else {
182 			faddr = createAddress64(f->address + pe_shared->pe64.header_nt.image_base);
183 		}
184 		if (validAddress(faddr, scvalid)) {
185 			char *label;
186 			if (f->byname) {
187 				ht_snprintf(buffer, sizeof buffer, "; exported function %s, ordinal %04x", f->name, f->ordinal);
188 			} else {
189 				ht_snprintf(buffer, sizeof buffer, "; unnamed exported function, ordinal %04x", f->ordinal);
190 			}
191 			label = export_func_name((f->byname) ? f->name : NULL, f->ordinal);
192 			addComment(faddr, 0, "");
193 			addComment(faddr, 0, ";********************************************************");
194 			addComment(faddr, 0, buffer);
195 			addComment(faddr, 0, ";********************************************************");
196 			pushAddress(faddr, faddr);
197 			assignSymbol(faddr, label, label_func);
198 			free(label);
199 		}
200 		delete faddr;
201 	}
202 	if (entropy) free(entropy);
203 
204 	int import_count=pe_shared->imports.funcs->count();
205 	entropy = random_permutation(import_count);
206 	for (int i=0; i<import_count; i++) {
207 		ht_pe_import_function *f = (ht_pe_import_function *)(*pe_shared->imports.funcs)[entropy[i]];
208 		ht_pe_import_library *d = (ht_pe_import_library *)(*pe_shared->imports.libs)[f->libidx];
209 		char *label;
210 		label = import_func_name(d->name, (f->byname) ? f->name.name : NULL, f->ordinal);
211 		Address *faddr;
212 		if (pe32) {
213 			faddr = createAddress32(f->address + pe_shared->pe32.header_nt.image_base);
214 		} else {
215 			faddr = createAddress64(f->address + pe_shared->pe64.header_nt.image_base);
216 		}
217 		addComment(faddr, 0, "");
218 		if (!assignSymbol(faddr, label, label_func)) {
219 			// multiple import of a function (duplicate labelname)
220 			// -> mangle name a bit more
221 			addComment(faddr, 0, "; duplicate import");
222 			ht_snprintf(buffer, sizeof buffer, "%s_%x", label, f->address);
223 			assignSymbol(faddr, buffer, label_func);
224 		}
225 		if (pe32) {
226 			data->setIntAddressType(faddr, dst_idword, 4);
227 		} else {
228 			data->setIntAddressType(faddr, dst_iqword, 8);
229 		}
230 		free(label);
231 		delete faddr;
232 	}
233 	if (entropy) free(entropy);
234 
235 	int dimport_count=pe_shared->dimports.funcs->count();
236 	entropy = random_permutation(dimport_count);
237 	for (int i=0; i<dimport_count; i++) {
238 		// FIXME: delay imports need work (push addr)
239 		ht_pe_import_function *f=(ht_pe_import_function *)(*pe_shared->dimports.funcs)[entropy[i]];
240 		ht_pe_import_library *d=(ht_pe_import_library *)(*pe_shared->dimports.libs)[f->libidx];
241 		if (f->byname) {
242 			ht_snprintf(buffer, sizeof buffer, "; delay import function loader for %s, ordinal %04x", f->name.name, f->ordinal);
243 		} else {
244 			ht_snprintf(buffer, sizeof buffer, "; delay import function loader for ordinal %04x", f->ordinal);
245 		}
246 		char *label;
247 		label = import_func_name(d->name, f->byname ? f->name.name : NULL, f->ordinal);
248 		Address *faddr;
249 		if (pe32) {
250 			faddr = createAddress32(f->address);
251 		} else {
252 			faddr = createAddress64(f->address);
253 		}
254 		addComment(faddr, 0, "");
255 		addComment(faddr, 0, ";********************************************************");
256 		addComment(faddr, 0, buffer);
257 		addComment(faddr, 0, ";********************************************************");
258 		assignSymbol(faddr, label, label_func);
259 		free(label);
260 		delete faddr;
261 	}
262 	if (entropy) free(entropy);
263 
264 	addComment(entry, 0, "");
265 	addComment(entry, 0, ";****************************");
266 	if (pe_shared->coffheader.characteristics & COFF_DLL) {
267 		addComment(entry, 0, ";  dll entry point");
268 	} else {
269 		addComment(entry, 0, ";  program entry point");
270 	}
271 	addComment(entry, 0, ";****************************");
272 	assignSymbol(entry, "entrypoint", label_func);
273 
274 	setLocationTreeOptimizeThreshold(1000);
275 	setSymbolTreeOptimizeThreshold(1000);
276 	delete entry;
277 
278 	Analyser::beginAnalysis();
279 }
280 
281 /*
282  *
283  */
getObjectID() const284 ObjectID	PEAnalyser::getObjectID() const
285 {
286 	return ATOM_PE_ANALYSER;
287 }
288 
289 /*
290  *
291  */
bufPtr(Address * Addr,byte * buf,int size)292 uint PEAnalyser::bufPtr(Address *Addr, byte *buf, int size)
293 {
294 	FileOfs ofs = addressToFileofs(Addr);
295 /*	if (ofs == INVALID_FILE_OFS) {
296 		int as=0;
297 	}*/
298 	assert(ofs != INVALID_FILE_OFS);
299 	file->seek(ofs);
300 	return file->read(buf, size);
301 }
302 
convertAddressToRVA(Address * addr,RVA * r)303 bool PEAnalyser::convertAddressToRVA(Address *addr, RVA *r)
304 {
305 	ObjectID oid = addr->getObjectID();
306 	if (oid == ATOM_ADDRESS_FLAT_32) {
307 		*r = ((AddressFlat32*)addr)->addr - pe_shared->pe32.header_nt.image_base;
308 		return true;
309 	} else if (oid == ATOM_ADDRESS_X86_FLAT_32) {
310 		*r = ((AddressX86Flat32*)addr)->addr - pe_shared->pe32.header_nt.image_base;
311 		return true;
312 	} else if (oid == ATOM_ADDRESS_FLAT_64) {
313 		uint64 q = ((AddressFlat64*)addr)->addr - pe_shared->pe64.header_nt.image_base;
314 		if (q >> 32) return false;
315 		*r = q;
316 		return true;
317 	}
318 	return false;
319 }
320 
321 /*
322  *
323  */
createAddress32(uint32 addr)324 Address *PEAnalyser::createAddress32(uint32 addr)
325 {
326 	switch (pe_shared->coffheader.machine) {
327 		case COFF_MACHINE_I386:
328 		case COFF_MACHINE_I486:
329 		case COFF_MACHINE_I586:
330 			return new AddressX86Flat32(addr);
331 	}
332 	// fallback to standard-addrs
333 	return new AddressFlat32(addr);
334 }
335 
336 /*
337  *
338  */
createAddress64(uint64 addr)339 Address *PEAnalyser::createAddress64(uint64 addr)
340 {
341 	return new AddressFlat64(addr);
342 }
343 
createAddress()344 Address *PEAnalyser::createAddress()
345 {
346 	switch (pe_shared->coffheader.machine) {
347 		case COFF_MACHINE_I386:
348 		case COFF_MACHINE_I486:
349 		case COFF_MACHINE_I586:
350 			if (pe_shared->opt_magic == COFF_OPTMAGIC_PE64) {
351 				return new AddressFlat64();
352 			} else {
353 				return new AddressX86Flat32();
354 			}
355 	}
356 	if (pe_shared->opt_magic == COFF_OPTMAGIC_PE64) {
357 		return new AddressFlat64();
358 	}
359 	return new AddressFlat32();
360 }
361 
362 /*
363  *
364  */
createAssembler()365 Assembler *PEAnalyser::createAssembler()
366 {
367 	Assembler *a = NULL;
368 	switch (pe_shared->coffheader.machine) {
369 	case COFF_MACHINE_I386:
370 	case COFF_MACHINE_I486:
371 	case COFF_MACHINE_I586:
372 		a = new x86asm(X86_OPSIZE32, X86_ADDRSIZE32);
373 		a->init();
374 		return a;
375 	case COFF_MACHINE_AMD64:
376 		a = new x86_64asm();
377 		a->init();
378 		return a;
379 	}
380 	return a;
381 }
382 
383 /*
384  *
385  */
addressToFileofs(Address * Addr)386 FileOfs PEAnalyser::addressToFileofs(Address *Addr)
387 {
388 /*     char tbuf[1024];
389 	Addr->stringify(tbuf, 1024, 0);
390 	printf("ADDR=%s", tbuf);*/
391 	if (validAddress(Addr, scinitialized)) {
392 //     	printf(" v1\n");
393 		FileOfs ofs;
394 		RVA r;
395 		if (!convertAddressToRVA(Addr, &r)) return INVALID_FILE_OFS;
396 		if (!pe_rva_to_ofs(&pe_shared->sections, r, &ofs)) return INVALID_FILE_OFS;
397 		return ofs;
398 	} else {
399 //     	printf(" IV1\n");
400 		return INVALID_FILE_OFS;
401 	}
402 }
403 
404 // This function checks if a fixup is present on a byte at the given Addr plus offset,
405 // it also stores the last entry found, to speedup the next check.
406 
isAddressFixedUp(Address * Addr,int offset)407 bool 	PEAnalyser::isAddressFixedUp(Address *Addr, int offset)
408 {
409 	RVA r, rng_start, rng_end;
410 	std::deque<fixup_listentry>::iterator fixupque_lit;
411 	unsigned char listmovdir = 0;								// 1 down 2 up
412 
413 	if (!convertAddressToRVA(Addr, &r)) return false;
414 	r += offset;
415 
416 	if (fixupque_git == pe_shared->fixupque.end() ) return false;		// exit on empty list
417 	fixupque_lit = fixupque_git;
418 
419 	while (fixupque_lit != pe_shared->fixupque.end() ) {
420 
421 		rng_start = fixupque_lit->addr;
422 		rng_end = rng_start + fixupque_lit->size;
423 
424 		if (r >= rng_start && r < rng_end) {
425 			fixupque_git = fixupque_lit;
426 			return true;
427 		}
428 
429 		if (r < rng_start && listmovdir != 2 ) {
430 			fixupque_git = fixupque_lit;
431 			if (fixupque_lit == pe_shared->fixupque.begin()) return false;
432 			fixupque_lit--;
433 			listmovdir = 1;
434 
435 		} else if (r > rng_start && listmovdir != 1){
436 			fixupque_git = fixupque_lit;
437 			fixupque_lit++;
438 			listmovdir = 2;
439 
440 		} else {
441 			return false;
442 		}
443 	}
444 
445 	return false;
446 }
447 
448 
449 /*
450  *
451  */
getSegmentNameByAddress(Address * Addr)452 const char *PEAnalyser::getSegmentNameByAddress(Address *Addr)
453 {
454 	static char sectionname[9];
455 	pe_section_headers *sections=&pe_shared->sections;
456 	int i;
457 	RVA r;
458 //	Addr-=pe_shared->pe32.header_nt.image_base;
459 	if (!convertAddressToRVA(Addr, &r)) return NULL;
460 	pe_rva_to_section(sections, r, &i);
461 	COFF_SECTION_HEADER *s=sections->sections+i;
462 	if (!pe_rva_is_valid(sections, r)) return NULL;
463 	memcpy(sectionname, s->name, 8);
464 	sectionname[8] = 0;
465 	return sectionname;
466 }
467 
468 /*
469  *
470  */
getName(String & s)471 String &PEAnalyser::getName(String &s)
472 {
473 	return file->getDesc(s);
474 }
475 
476 /*
477  *
478  */
getType()479 const char *PEAnalyser::getType()
480 {
481 	return "PE/Analyser";
482 }
483 
484 /*
485  *
486  */
initCodeAnalyser()487 void PEAnalyser::initCodeAnalyser()
488 {
489 	Analyser::initCodeAnalyser();
490 }
491 
string_func(uint32 ofs,void * context)492 static char *string_func(uint32 ofs, void *context)
493 {
494 	char str[1024];
495 	static char str2[1024];
496 	ht_pe_shared_data *pe = (ht_pe_shared_data*)context;
497 	if (ofs < pe->il->string_pool_size) {
498 		uint32 length;
499 		uint32 o = ILunpackDword(length, (byte*)&pe->il->string_pool[ofs], 10);
500 		wide_char_to_multi_byte(str, (byte*)&pe->il->string_pool[ofs+o], length/2+1);
501 		escape_special_str(str2, sizeof str2, str, "\"");
502 		return str2;
503 	} else {
504 		return NULL;
505 	}
506 }
507 
token_func(uint32 token,void * context)508 static char *token_func(uint32 token, void *context)
509 {
510 	static char tokenstr[1024];
511 //	ht_pe_shared_data *pe = (ht_pe_shared_data*)context;
512 	switch (token & IL_META_TOKEN_MASK) {
513 	case IL_META_TOKEN_TYPE_REF:
514 	case IL_META_TOKEN_TYPE_DEF: {
515 		sprintf(tokenstr, "typedef");
516 		break;
517 	}
518 	case IL_META_TOKEN_FIELD_DEF: {
519 		sprintf(tokenstr, "fielddef");
520 		break;
521 	}
522 	case IL_META_TOKEN_METHOD_DEF: {
523 		sprintf(tokenstr, "methoddef");
524 		break;
525 	}
526 	case IL_META_TOKEN_MEMBER_REF: {
527 		sprintf(tokenstr, "memberref");
528 		break;
529 	}
530 	case IL_META_TOKEN_TYPE_SPEC: {
531 		sprintf(tokenstr, "typespec");
532 		break;
533 	}
534 	default:
535 		return NULL;
536 	}
537 	return tokenstr;
538 }
539 
540 /*
541  *
542  */
initUnasm()543 void PEAnalyser::initUnasm()
544 {
545 	bool pe64 = false;
546 	if (pe_shared->opt_magic == COFF_OPTMAGIC_PE64) {
547 		pe64 = true;
548 	}
549 	DPRINTF("pe_analy: ");
550 	if (pe_shared->il) {
551 		analy_disasm = new AnalyILDisassembler();
552 		((AnalyILDisassembler *)analy_disasm)->init(this, string_func, token_func, pe_shared);
553 	} else {
554 		switch (pe_shared->coffheader.machine) {
555 		case COFF_MACHINE_I386:	// Intel 386
556 		case COFF_MACHINE_I486:	// Intel 486
557 		case COFF_MACHINE_I586:	// Intel 586
558 			if (pe64) {
559 				errorbox("x86 cant be used in PE64 format.");
560 			} else {
561 				DPRINTF("initing analy_x86_disassembler\n");
562 				analy_disasm = new AnalyX86Disassembler();
563 				((AnalyX86Disassembler *)analy_disasm)->init(this, 0);
564 			}
565 			break;
566 		case COFF_MACHINE_AMD64:
567 			if (!pe64) {
568 				errorbox("x86_64 cant be used in PE32 format.");
569 			} else {
570 				analy_disasm = new AnalyX86Disassembler();
571 				((AnalyX86Disassembler *)analy_disasm)->init(this, ANALYX86DISASSEMBLER_FLAGS_AMD64);
572 			}
573 			break;
574 		case COFF_MACHINE_R3000:	// MIPS little-endian, 0x160 big-endian
575 			DPRINTF("no apropriate disassembler for MIPS\n");
576 			warnbox("No disassembler for MIPS!");
577 			break;
578 		case COFF_MACHINE_R4000:	// MIPS little-endian
579 			DPRINTF("no apropriate disassembler for MIPS\n");
580 			warnbox("No disassembler for MIPS!");
581 			break;
582 		case COFF_MACHINE_R10000:	// MIPS little-endian
583 			DPRINTF("no apropriate disassembler for MIPS\n");
584 			warnbox("No disassembler for MIPS!");
585 			break;
586 		case COFF_MACHINE_ALPHA:	// Alpha_AXP
587 			DPRINTF("initing alpha_axp_disassembler\n");
588 			analy_disasm = new AnalyAlphaDisassembler();
589 			((AnalyAlphaDisassembler *)analy_disasm)->init(this);
590 			break;
591 		case COFF_MACHINE_POWERPC_LE:	// IBM PowerPC Little-Endian
592 			DPRINTF("no apropriate disassembler for POWER PC\n");
593 			warnbox("No disassembler for little endian POWER PC!");
594 			break;
595 		case COFF_MACHINE_POWERPC_BE:
596 		case COFF_MACHINE_POWERPC64_BE:
597 			analy_disasm = new AnalyPPCDisassembler();
598 			((AnalyPPCDisassembler*)analy_disasm)->init(this, pe64 ? ANALY_PPC_64 : ANALY_PPC_32);
599 			break;
600 		case COFF_MACHINE_ARM: // ARM
601 		case COFF_MACHINE_THUMB: // Thumb
602 			DPRINTF("initing arm_disassembler\n");
603 			analy_disasm = new AnalyArmDisassembler();
604 			((AnalyArmDisassembler *)analy_disasm)->init(this);
605                         break;
606 		case COFF_MACHINE_UNKNOWN:
607 		default:
608 			DPRINTF("no apropriate disassembler for machine %04x\n", pe_shared->coffheader.machine);
609 			warnbox("No disassembler for unknown machine type %04x!", pe_shared->coffheader.machine);
610 		}
611 	}
612 }
613 
614 /*
615  *
616  */
log(const char * msg)617 void PEAnalyser::log(const char *msg)
618 {
619 	/*
620 	 *	log() creates to much traffic so dont log
621 	 *   perhaps we reactivate this later
622 	 *
623 	 */
624 /*	LOG(msg);*/
625 }
626 
627 /*
628  *
629  */
nextValid(Address * Addr)630 Address *PEAnalyser::nextValid(Address *Addr)
631 {
632 	return (Address *)validarea->findNext(Addr);
633 }
634 
635 /*
636  *
637  */
store(ObjectStream & st) const638 void PEAnalyser::store(ObjectStream &st) const
639 {
640 	PUT_OBJECT(st, validarea);
641 	Analyser::store(st);
642 }
643 
644 /*
645  *
646  */
queryConfig(int mode)647 int	PEAnalyser::queryConfig(int mode)
648 {
649 	switch (mode) {
650 	case Q_DO_ANALYSIS:
651 	case Q_ENGAGE_CODE_ANALYSER:
652 	case Q_ENGAGE_DATA_ANALYSER:
653 		return true;
654 	default:
655 		return 0;
656 	}
657 }
658 
659 /*
660  *
661  */
fileofsToAddress(FileOfs fileofs)662 Address *PEAnalyser::fileofsToAddress(FileOfs fileofs)
663 {
664 	RVA r;
665 	if (pe_ofs_to_rva(&pe_shared->sections, fileofs, &r)) {
666 		if (pe_shared->opt_magic == COFF_OPTMAGIC_PE32) {
667 			return createAddress32(r + pe_shared->pe32.header_nt.image_base);
668 		} else {
669 			return createAddress64(r + pe_shared->pe64.header_nt.image_base);
670 		}
671 	} else {
672 		return new InvalidAddress();
673 	}
674 }
675 
676 /*
677  *
678  */
validAddress(Address * Addr,tsectype action)679 bool PEAnalyser::validAddress(Address *Addr, tsectype action)
680 {
681 	pe_section_headers *sections=&pe_shared->sections;
682 	int sec;
683 	RVA r;
684 	if (!convertAddressToRVA(Addr, &r)) return false;
685 	if (!pe_rva_to_section(sections, r, &sec)) return false;
686 	COFF_SECTION_HEADER *s=sections->sections+sec;
687 	switch (action) {
688 	case scvalid:
689 		return true;
690 	case scread:
691 		return s->characteristics & COFF_SCN_MEM_READ;
692 	case scwrite:
693 		return s->characteristics & COFF_SCN_MEM_WRITE;
694 	case screadwrite:
695 		return s->characteristics & COFF_SCN_MEM_WRITE;
696 	case sccode:
697 		// FIXME: EXECUTE vs. CNT_CODE ?
698 		if (!pe_rva_is_physical(sections, r)) return false;
699 		return (s->characteristics & (COFF_SCN_MEM_EXECUTE | COFF_SCN_CNT_CODE));
700 	case scinitialized:
701 		if (!pe_rva_is_physical(sections, r)) return false;
702 		return true;
703 		// !(s->characteristics & COFF_SCN_CNT_UNINITIALIZED_DATA);
704 	}
705 	return false;
706 }
707 
708 
709