1 /*
2  *	HT Editor
3  *	xex_analy.cc
4  *
5  *	Copyright (C) 2006 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_names.h"
27 #include "analy_register.h"
28 #include "analy_ppc.h"
29 #include "htctrl.h"
30 #include "htdebug.h"
31 #include "htiobox.h"
32 #include "htxex.h"
33 #include "strtools.h"
34 #include "xex_analy.h"
35 #include "xexstruct.h"
36 #include "snprintf.h"
37 
init(ht_xex_shared_data * XEX_shared,File * File)38 void	XEXAnalyser::init(ht_xex_shared_data *XEX_shared, File *File)
39 {
40 	xex_shared = XEX_shared;
41 	file = File;
42 
43 	validarea = new Area();
44 	validarea->init();
45 
46 	Analyser::init();
47 }
48 
49 /*
50  *
51  */
load(ObjectStream & f)52 void	XEXAnalyser::load(ObjectStream &f)
53 {
54 	GET_OBJECT(f, validarea);
55 	Analyser::load(f);
56 }
57 
58 /*
59  *
60  */
done()61 void	XEXAnalyser::done()
62 {
63 	validarea->done();
64 	delete validarea;
65 	Analyser::done();
66 }
67 
68 /*
69  *
70  */
beginAnalysis()71 void XEXAnalyser::beginAnalysis()
72 {
73 	char	buffer[1024];
74 
75 	Address *entry = createAddress32(xex_shared->entrypoint);
76 	pushAddress(entry, entry);
77 
78 	int lib_count=xex_shared->imports.lib_count;
79 	for (int i=0; i < lib_count; i++) {
80 		XexImportLib *lib = xex_shared->imports.libs + i;
81 		for (int j = 0; j < lib->func_count; j++) {
82 			XexImportFunc *func = lib->funcs + j;
83 			uint32 ord = func->ord;
84 			if (ord & 0xff000000) {
85 				int libidx = (ord & 0x00ff0000) >> 16;
86 				ord &= 0x7fff;
87 				if (libidx != i) {
88 					continue;
89 				}
90 				char s[200];
91 				ht_snprintf(s, sizeof s, "wrapper_import_%s_%d", lib->name, ord);
92 				Address *faddr = createAddress32(func->patch);
93 				addComment(faddr, 0, "");
94 				assignSymbol(faddr, s, label_func);
95 				delete faddr;
96 				faddr = createAddress32(func->patch+12);
97 				Address *faddr2 = createAddress32(func->ia);
98 				addXRef(faddr2, faddr, xrefijump);
99 				delete faddr;
100 				delete faddr2;
101 //				printf("xref 0x%08x -> 0x%08x\n", ia, imports[i].func[j].patch + 12);
102 
103 			} else {
104 				char s[200];
105 				ord &= 0x7fff;
106 				ht_snprintf(s, sizeof s, "import_%s_%d", lib->name, ord);
107 				Address *faddr = createAddress32(func->patch);
108 				addComment(faddr, 0, "");
109 				assignSymbol(faddr, s, label_func);
110 				data->setIntAddressType(faddr, dst_idword, 4);
111 				delete faddr;
112 //				printf("function_ptr 0x%08x name '%s'\n", imports[i].func[j].patch, s);
113 			}
114 
115 		}
116 	}
117 
118 #if 0
119 	int dimport_count=xex_shared->dimports.funcs->count();
120 	entropy = random_permutation(dimport_count);
121 	for (int i=0; i<dimport_count; i++) {
122 		// FIXME: delay imports need work (push addr)
123 		ht_pe_import_function *f=(ht_pe_import_function *)(*xex_shared->dimports.funcs)[entropy[i]];
124 		ht_pe_import_library *d=(ht_pe_import_library *)(*xex_shared->dimports.libs)[f->libidx];
125 		if (f->byname) {
126 			ht_snprintf(buffer, sizeof buffer, "; delay import function loader for %s, ordinal %04x", f->name.name, f->ordinal);
127 		} else {
128 			ht_snprintf(buffer, sizeof buffer, "; delay import function loader for ordinal %04x", f->ordinal);
129 		}
130 		char *label;
131 		label = import_func_name(d->name, f->byname ? f->name.name : NULL, f->ordinal);
132 		Address *faddr;
133 		if (pe32) {
134 			faddr = createAddress32(f->address);
135 		} else {
136 			faddr = createAddress64(f->address);
137 		}
138 		addComment(faddr, 0, "");
139 		addComment(faddr, 0, ";********************************************************");
140 		addComment(faddr, 0, buffer);
141 		addComment(faddr, 0, ";********************************************************");
142 		assignSymbol(faddr, label, label_func);
143 		free(label);
144 		delete faddr;
145 	}
146 	if (entropy) free(entropy);
147 #endif
148 
149 	addComment(entry, 0, "");
150 	addComment(entry, 0, ";****************************");
151 	addComment(entry, 0, ";  program entry point");
152 	addComment(entry, 0, ";****************************");
153 	assignSymbol(entry, "entrypoint", label_func);
154 
155 	setLocationTreeOptimizeThreshold(1000);
156 	setSymbolTreeOptimizeThreshold(1000);
157 	delete entry;
158 
159 	Analyser::beginAnalysis();
160 }
161 
162 /*
163  *
164  */
getObjectID() const165 ObjectID	XEXAnalyser::getObjectID() const
166 {
167 	return ATOM_XEX_ANALYSER;
168 }
169 
170 /*
171  *
172  */
bufPtr(Address * Addr,byte * buf,int size)173 uint XEXAnalyser::bufPtr(Address *Addr, byte *buf, int size)
174 {
175 	FileOfs ofs = addressToFileofs(Addr);
176 /*	if (ofs == INVALID_FILE_OFS) {
177 		int as=0;
178 	}*/
179 	assert(ofs != INVALID_FILE_OFS);
180 	file->seek(ofs);
181 	return file->read(buf, size);
182 }
183 
convertAddressToRVA(Address * addr,RVA * r)184 bool XEXAnalyser::convertAddressToRVA(Address *addr, RVA *r)
185 {
186 	ObjectID oid = addr->getObjectID();
187 	if (oid == ATOM_ADDRESS_FLAT_32) {
188 		*r = ((AddressFlat32*)addr)->addr - xex_shared->image_base;
189 		return true;
190 	}
191 	return false;
192 }
193 
194 /*
195  *
196  */
createAddress32(uint32 addr)197 Address *XEXAnalyser::createAddress32(uint32 addr)
198 {
199 	return new AddressFlat32(addr);
200 }
201 
202 
createAddress()203 Address *XEXAnalyser::createAddress()
204 {
205 	return new AddressFlat32();
206 }
207 
208 /*
209  *
210  */
addressToFileofs(Address * Addr)211 FileOfs XEXAnalyser::addressToFileofs(Address *Addr)
212 {
213 	if (validAddress(Addr, scinitialized)) {
214 		FileOfs ofs;
215 		RVA r;
216 		if (!convertAddressToRVA(Addr, &r)) return INVALID_FILE_OFS;
217 		if (!xex_rva_to_ofs(xex_shared, r, ofs)) return INVALID_FILE_OFS;
218 		return ofs;
219 	} else {
220 		return INVALID_FILE_OFS;
221 	}
222 }
223 
224 /*
225  *
226  */
getSegmentNameByAddress(Address * Addr)227 const char *XEXAnalyser::getSegmentNameByAddress(Address *Addr)
228 {
229 	return "";
230 }
231 
232 /*
233  *
234  */
getName(String & s)235 String &XEXAnalyser::getName(String &s)
236 {
237 	return file->getDesc(s);
238 }
239 
240 /*
241  *
242  */
getType()243 const char *XEXAnalyser::getType()
244 {
245 	return "XEX/Analyser";
246 }
247 
248 /*
249  *
250  */
initUnasm()251 void XEXAnalyser::initUnasm()
252 {
253 	analy_disasm = new AnalyPPCDisassembler();
254 	((AnalyPPCDisassembler*)analy_disasm)->init(this, ANALY_PPC_32);
255 }
256 
257 /*
258  *
259  */
nextValid(Address * Addr)260 Address *XEXAnalyser::nextValid(Address *Addr)
261 {
262 	return (Address *)validarea->findNext(Addr);
263 }
264 
265 /*
266  *
267  */
store(ObjectStream & st) const268 void XEXAnalyser::store(ObjectStream &st) const
269 {
270 	PUT_OBJECT(st, validarea);
271 	Analyser::store(st);
272 }
273 
274 
275 /*
276  *
277  */
fileofsToAddress(FileOfs fileofs)278 Address *XEXAnalyser::fileofsToAddress(FileOfs fileofs)
279 {
280 	RVA r;
281 	if (xex_ofs_to_rva(xex_shared, fileofs, r)) {
282 		return createAddress32(r + xex_shared->image_base);
283 	} else {
284 		return new InvalidAddress();
285 	}
286 }
287 
288 /*
289  *
290  */
validAddress(Address * Addr,tsectype action)291 bool XEXAnalyser::validAddress(Address *Addr, tsectype action)
292 {
293 //	e_section_headers *sections=&xex_shared->sections;
294 	int sec;
295 	RVA r;
296 	FileOfs ofs;
297 	if (!convertAddressToRVA(Addr, &r)) return false;
298 //	if (!pe_rva_to_section(sections, r, &sec)) return false;
299 	if (!xex_rva_to_ofs(xex_shared, r, ofs)) return false;
300 	uint32 flags = xex_get_rva_flags(xex_shared, r);
301 	switch (action) {
302 	case scvalid:
303 	case scinitialized:
304 	case scread:
305 		return true;
306 		return true;
307 	case scwrite:
308 	case screadwrite:
309 		return !(flags & 1);
310 	case sccode:
311 		return !(flags & 2);
312 	}
313 	return true;
314 }
315