1 /*
2  *	HT Editor
3  *	htpedimp.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 "formats.h"
22 #include "htanaly.h"
23 #include "htctrl.h"
24 #include "endianess.h"
25 #include "htiobox.h"
26 #include "htnewexe.h"
27 #include "htpal.h"
28 #include "htpe.h"
29 #include "htpeimp.h"
30 #include "htpedimp.h"
31 #include "httag.h"
32 #include "strtools.h"
33 #include "log.h"
34 #include "pe_analy.h"
35 #include "snprintf.h"
36 #include "stream.h"
37 
38 #include <stdlib.h>
39 
htpedelayimports_init(Bounds * b,File * file,ht_format_group * group)40 static ht_view *htpedelayimports_init(Bounds *b, File *file, ht_format_group *group)
41 {
42 	ht_pe_shared_data *pe_shared=(ht_pe_shared_data *)group->get_shared_data();
43 	String fn;
44 
45 	if (pe_shared->opt_magic!=COFF_OPTMAGIC_PE32) return NULL;
46 
47 	RVA sec_rva = pe_shared->pe32.header_nt.directory[PE_DIRECTORY_ENTRY_DELAY_IMPORT].address;
48 	uint sec_size = pe_shared->pe32.header_nt.directory[PE_DIRECTORY_ENTRY_DELAY_IMPORT].size;
49 	if (!sec_rva || !sec_size) return NULL;
50 
51 	int h0=new_timer();
52 	start_timer(h0);
53 
54 	uint dll_count=0;
55 	uint function_count=0;
56 
57 	ht_group *g;
58 	Bounds c;
59 	ht_statictext *head;
60 
61 	c=*b;
62 	g=new ht_group();
63 	g->init(&c, VO_RESIZE, DESC_PE_DIMPORTS"-g");
64 
65 	c.y++;
66 	c.h--;
67 	ht_pe_dimport_viewer *v=new ht_pe_dimport_viewer();
68 	v->init(&c, DESC_PE_DIMPORTS, group);
69 
70 	PE_DELAY_IMPORT_DESCRIPTOR dimport;
71 	uint dll_index;
72 	char iline[256];
73 
74 	c.y--;
75 	c.h=1;
76 /* get delay import directory offset */
77 	/* 1. get import directory rva */
78 	FileOfs iofs;
79 	RVA irva=pe_shared->pe32.header_nt.directory[PE_DIRECTORY_ENTRY_DELAY_IMPORT].address;
80 //	uint isize=pe_shared->pe32.header_nt.directory[PE_DIRECTORY_ENTRY_DELAY_IMPORT].size;
81 	/* 2. transform it into an offset */
82 	if (!pe_rva_to_ofs(&pe_shared->sections, irva, &iofs)) goto pe_read_error;
83 	LOG("%y: PE: reading delay-import directory at offset 0x%08qx, rva 0x%08x, size 0x%08x...", &file->getFilename(fn), iofs, irva, pe_shared->pe32.header_nt.directory[PE_DIRECTORY_ENTRY_DELAY_IMPORT].size);
84 
85 /*** read delay import directory ***/
86 	dll_index=0;
87 
88 	while (1) {
89 		file->seek(iofs);
90 		file->read(&dimport, sizeof dimport);
91 		createHostStruct(&dimport, PE_DELAY_IMPORT_DESCRIPTOR_struct, little_endian);
92 		if (!dimport.name) break;
93 		uint32 base = dimport.attributes & 1 ? 0 : pe_shared->pe32.header_nt.image_base;
94 
95 		FileOfs dllname_ofs;
96 		if (!pe_rva_to_ofs(&pe_shared->sections, dimport.name-base, &dllname_ofs)) goto pe_read_error;
97 		file->seek(dllname_ofs);
98 		char *dllname = file->fgetstrz();
99 		ht_pe_import_library *lib=new ht_pe_import_library(dllname);
100 		pe_shared->dimports.libs->insert(lib);
101 		dll_count++;
102 
103 		FileOfs ntofs, atofs;
104 		uint nva, ava;
105 		if (!pe_rva_to_ofs(&pe_shared->sections, dimport.delay_int-base, &ntofs)) goto pe_read_error;
106 		if (!pe_rva_to_ofs(&pe_shared->sections, dimport.delay_iat-base, &atofs)) goto pe_read_error;
107 		while (1) {
108 			ht_pe_import_function *func;
109 			file->seek(ntofs);
110 			file->read(&nva, 4);
111 			nva = createHostInt(&nva, 4, little_endian);
112 			if (!nva) break;
113 			function_count++;
114 			file->seek(atofs);
115 			file->read(&ava, 4);
116 			ava = createHostInt(&ava, 4, little_endian);
117 			if (nva & 0x80000000) {
118 /* import by ordinal */
119 				func=new ht_pe_import_function(dll_index, ava, nva&0xffff);
120 			} else {
121 				FileOfs nofs;
122 /* import by name */
123 				if (!pe_rva_to_ofs(&pe_shared->sections, nva-base, &nofs)) goto pe_read_error;
124 				uint16 hint=0;
125 				file->seek(nofs);
126 				file->read(&hint, 2);
127 				hint = createHostInt(&hint, 2, little_endian);
128 				char *name = file->fgetstrz();
129 				func=new ht_pe_import_function(dll_index, ava, name, hint);
130 				free(name);
131 			}
132 			pe_shared->dimports.funcs->insert(func);
133 			ntofs+=4;
134 			atofs+=4;
135 		}
136 
137 		free(dllname);
138 		iofs+=sizeof dimport;
139 		dll_index++;
140 	}
141 
142 	stop_timer(h0);
143 //	LOG("%y: PE: %d ticks (%d msec) to read delay-imports", file->get_name(), get_timer_tick(h0), get_timer_msec(h0));
144 	delete_timer(h0);
145 
146 	ht_snprintf(iline, sizeof iline, "* PE delay-import directory at offset %08x (%d delay-imports from %d libraries)", iofs, function_count, dll_count);
147 
148 	head=new ht_statictext();
149 	head->init(&c, iline, align_left);
150 
151 	g->insert(head);
152 	g->insert(v);
153 //
154 	for (uint i=0; i < pe_shared->dimports.funcs->count(); i++) {
155 
156 		ht_pe_import_function *func = (ht_pe_import_function*)(*pe_shared->dimports.funcs)[i];
157 		assert(func);
158 		ht_pe_import_library *lib = (ht_pe_import_library*)(*pe_shared->dimports.libs)[func->libidx];
159 		assert(lib);
160 		char addr[32], name[256];
161 		ht_snprintf(addr, sizeof addr, "%08x", func->address);
162 		if (func->byname) {
163 			ht_snprintf(name, sizeof name, "%s", func->name.name);
164 		} else {
165 			ht_snprintf(name, sizeof name, "%04x (by ordinal)", func->ordinal);
166 		}
167 		v->insert_str(i, lib->name, addr, name);
168 	}
169 //
170 	v->update();
171 
172 	g->setpalette(palkey_generic_window_default);
173 
174 	pe_shared->v_dimports=v;
175 
176 	return g;
177 pe_read_error:
178 	delete_timer(h0);
179 	errorbox("%y: PE delay-import directory seems to be corrupted.", &file->getFilename(fn));
180 	v->done();
181 	delete v;
182 	g->done();
183 	delete g;
184 	return NULL;
185 }
186 
187 format_viewer_if htpedelayimports_if = {
188 	htpedelayimports_init,
189 	NULL
190 };
191 
192 /*
193  *	CLASS ht_pe_dimport_viewer
194  */
195 
select_entry(void * entry)196 bool ht_pe_dimport_viewer::select_entry(void *entry)
197 {
198 	ht_text_listbox_item *i = (ht_text_listbox_item *)entry;
199 
200 	ht_pe_shared_data *pe_shared=(ht_pe_shared_data *)format_group->get_shared_data();
201 
202 	ht_pe_import_function *e = (ht_pe_import_function*)(*pe_shared->dimports.funcs)[i->id];
203 	if (!e) return true;
204 	if (pe_shared->v_image) {
205 		ht_aviewer *av = (ht_aviewer*)pe_shared->v_image;
206 		PEAnalyser *a = (PEAnalyser*)av->analy;
207 		Address *addr;
208 		if (pe_shared->opt_magic == COFF_OPTMAGIC_PE32) {
209 			addr = a->createAddress32(e->address/*+pe_shared->pe32.header_nt.image_base*/);
210 		} else {
211 			addr = a->createAddress64(e->address/*+pe_shared->pe64.header_nt.image_base*/);
212 		}
213 		if (av->gotoAddress(addr, NULL)) {
214 			app->focus(av);
215 			vstate_save();
216 		} else {
217 			global_analyser_address_string_format = ADDRESS_STRING_FORMAT_COMPACT | ADDRESS_STRING_FORMAT_ADD_0X;
218 			errorbox("can't follow: %s %y is not valid!", "delay-import address", addr);
219 		}
220 		delete addr;
221 	} else errorbox("can't follow: no image viewer");
222 	return true;
223 }
224 
225