summaryrefslogtreecommitdiff
path: root/tools/pe_bliss/pe_load_config.cpp
blob: c05895fecdc432d9a0f9f3068afe98d4ef534f83 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
/*************************************************************************/
/* Copyright (c) 2015 dx, http://kaimi.ru                                */
/*                                                                       */
/* Permission is hereby granted, free of charge, to any person           */
/* obtaining a copy of this software and associated documentation        */
/* files (the "Software"), to deal in the Software without               */
/* restriction, including without limitation the rights to use,          */
/* copy, modify, merge, publish, distribute, sublicense, and/or          */
/* sell copies of the Software, and to permit persons to whom the        */
/* Software is furnished to do so, subject to the following conditions:  */
/* The above copyright notice and this permission notice shall be        */
/* included in all copies or substantial portions of the Software.       */
/*                                                                       */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
/*************************************************************************/
#include <algorithm>
#include <string.h>
#include "pe_load_config.h"
#include "pe_properties_generic.h"

namespace pe_bliss
{
using namespace pe_win;

//IMAGE CONFIG
//Default constructor
image_config_info::image_config_info()
	:time_stamp_(0),
	major_version_(0), minor_version_(0),
	global_flags_clear_(0), global_flags_set_(0),
	critical_section_default_timeout_(0),
	decommit_free_block_threshold_(0), decommit_total_free_threshold_(0),
	lock_prefix_table_va_(0),
	max_allocation_size_(0),
	virtual_memory_threshold_(0),
	process_affinity_mask_(0),
	process_heap_flags_(0),
	service_pack_version_(0),
	edit_list_va_(0),
	security_cookie_va_(0),
	se_handler_table_va_(0),
	se_handler_count_(0)
{}

//Constructors from PE structures
template<typename ConfigStructure>
image_config_info::image_config_info(const ConfigStructure& info)
	:time_stamp_(info.TimeDateStamp),
	major_version_(info.MajorVersion), minor_version_(info.MinorVersion),
	global_flags_clear_(info.GlobalFlagsClear), global_flags_set_(info.GlobalFlagsSet),
	critical_section_default_timeout_(info.CriticalSectionDefaultTimeout),
	decommit_free_block_threshold_(info.DeCommitFreeBlockThreshold), decommit_total_free_threshold_(info.DeCommitTotalFreeThreshold),
	lock_prefix_table_va_(info.LockPrefixTable),
	max_allocation_size_(info.MaximumAllocationSize),
	virtual_memory_threshold_(info.VirtualMemoryThreshold),
	process_affinity_mask_(info.ProcessAffinityMask),
	process_heap_flags_(info.ProcessHeapFlags),
	service_pack_version_(info.CSDVersion),
	edit_list_va_(info.EditList),
	security_cookie_va_(info.SecurityCookie),
	se_handler_table_va_(info.SEHandlerTable),
	se_handler_count_(info.SEHandlerCount)
{}

//Instantiate template constructor with needed structures
template image_config_info::image_config_info(const image_load_config_directory32& info);
template image_config_info::image_config_info(const image_load_config_directory64& info);

//Returns the date and time stamp value
uint32_t image_config_info::get_time_stamp() const
{
	return time_stamp_;
}

//Returns major version number
uint16_t image_config_info::get_major_version() const
{
	return major_version_;
}

//Returns minor version number
uint16_t image_config_info::get_minor_version() const
{
	return minor_version_;
}

//Returns clear global flags
uint32_t image_config_info::get_global_flags_clear() const
{
	return global_flags_clear_;
}

//Returns set global flags
uint32_t image_config_info::get_global_flags_set() const
{
	return global_flags_set_;
}

//Returns critical section default timeout
uint32_t image_config_info::get_critical_section_default_timeout() const
{
	return critical_section_default_timeout_;
}

//Get the size of the minimum block that
//must be freed before it is freed (de-committed), in bytes
uint64_t image_config_info::get_decommit_free_block_threshold() const
{
	return decommit_free_block_threshold_;
}

//Returns the size of the minimum total memory
//that must be freed in the process heap before it is freed (de-committed), in bytes
uint64_t image_config_info::get_decommit_total_free_threshold() const
{
	return decommit_total_free_threshold_;
}

//Returns VA of a list of addresses where the LOCK prefix is used
uint64_t image_config_info::get_lock_prefix_table_va() const
{
	return lock_prefix_table_va_;
}

//Returns the maximum allocation size, in bytes
uint64_t image_config_info::get_max_allocation_size() const
{
	return max_allocation_size_;
}

//Returns the maximum block size that can be allocated from heap segments, in bytes
uint64_t image_config_info::get_virtual_memory_threshold() const
{
	return virtual_memory_threshold_;
}

//Returns process affinity mask
uint64_t image_config_info::get_process_affinity_mask() const
{
	return process_affinity_mask_;
}

//Returns process heap flags
uint32_t image_config_info::get_process_heap_flags() const
{
	return process_heap_flags_;
}

//Returns service pack version (CSDVersion)
uint16_t image_config_info::get_service_pack_version() const
{
	return service_pack_version_;
}

//Returns VA of edit list (reserved by system)
uint64_t image_config_info::get_edit_list_va() const
{
	return edit_list_va_;
}

//Returns a pointer to a cookie that is used by Visual C++ or GS implementation
uint64_t image_config_info::get_security_cookie_va() const
{
	return security_cookie_va_;
}

//Returns VA of the sorted table of RVAs of each valid, unique handler in the image
uint64_t image_config_info::get_se_handler_table_va() const
{
	return se_handler_table_va_;
}

//Returns the count of unique handlers in the table
uint64_t image_config_info::get_se_handler_count() const
{
	return se_handler_count_;
}

//Returns SE Handler RVA list
const image_config_info::se_handler_list& image_config_info::get_se_handler_rvas() const
{
	return se_handlers_;
}

//Returns Lock Prefix RVA list
const image_config_info::lock_prefix_rva_list& image_config_info::get_lock_prefix_rvas() const
{
	return lock_prefixes_;
}

//Adds SE Handler RVA to list
void image_config_info::add_se_handler_rva(uint32_t rva)
{
	se_handlers_.push_back(rva);
}

//Clears SE Handler list
void image_config_info::clear_se_handler_list()
{
	se_handlers_.clear();
}

//Adds Lock Prefix RVA to list
void image_config_info::add_lock_prefix_rva(uint32_t rva)
{
	lock_prefixes_.push_back(rva);
}

//Clears Lock Prefix list
void image_config_info::clear_lock_prefix_list()
{
	lock_prefixes_.clear();
}

//Sets the date and time stamp value
void image_config_info::set_time_stamp(uint32_t time_stamp)
{
	time_stamp_ = time_stamp;
}

//Sets major version number
void image_config_info::set_major_version(uint16_t major_version)
{
	major_version_ = major_version;
}

//Sets minor version number
void image_config_info::set_minor_version(uint16_t minor_version)
{
	minor_version_ = minor_version;
}

//Sets clear global flags
void image_config_info::set_global_flags_clear(uint32_t global_flags_clear)
{
	global_flags_clear_ = global_flags_clear;
}

//Sets set global flags
void image_config_info::set_global_flags_set(uint32_t global_flags_set)
{
	global_flags_set_ = global_flags_set;
}

//Sets critical section default timeout
void image_config_info::set_critical_section_default_timeout(uint32_t critical_section_default_timeout)
{
	critical_section_default_timeout_ = critical_section_default_timeout;
}

//Sets the size of the minimum block that
//must be freed before it is freed (de-committed), in bytes
void image_config_info::set_decommit_free_block_threshold(uint64_t decommit_free_block_threshold)
{
	decommit_free_block_threshold_ = decommit_free_block_threshold;
}

//Sets the size of the minimum total memory
//that must be freed in the process heap before it is freed (de-committed), in bytes
void image_config_info::set_decommit_total_free_threshold(uint64_t decommit_total_free_threshold)
{
	decommit_total_free_threshold_ = decommit_total_free_threshold;
}

//Sets VA of a list of addresses where the LOCK prefix is used
//If you rebuild this list, VA will be re-assigned automatically
void image_config_info::set_lock_prefix_table_va(uint64_t lock_prefix_table_va)
{
	lock_prefix_table_va_ = lock_prefix_table_va;
}

//Sets the maximum allocation size, in bytes
void image_config_info::set_max_allocation_size(uint64_t max_allocation_size)
{
	max_allocation_size_ = max_allocation_size;
}

//Sets the maximum block size that can be allocated from heap segments, in bytes
void image_config_info::set_virtual_memory_threshold(uint64_t virtual_memory_threshold)
{
	virtual_memory_threshold_ = virtual_memory_threshold;
}

//Sets process affinity mask
void image_config_info::set_process_affinity_mask(uint64_t process_affinity_mask)
{
	process_affinity_mask_ = process_affinity_mask;
}

//Sets process heap flags
void image_config_info::set_process_heap_flags(uint32_t process_heap_flags)
{
	process_heap_flags_ = process_heap_flags;
}

//Sets service pack version (CSDVersion)
void image_config_info::set_service_pack_version(uint16_t service_pack_version)
{
	service_pack_version_ = service_pack_version;
}

//Sets VA of edit list (reserved by system)
void image_config_info::set_edit_list_va(uint64_t edit_list_va)
{
	edit_list_va_ = edit_list_va;
}

//Sets a pointer to a cookie that is used by Visual C++ or GS implementation
void image_config_info::set_security_cookie_va(uint64_t security_cookie_va)
{
	security_cookie_va_ = security_cookie_va;
}

//Sets VA of the sorted table of RVAs of each valid, unique handler in the image
//If you rebuild this list, VA will be re-assigned automatically
void image_config_info::set_se_handler_table_va(uint64_t se_handler_table_va)
{
	se_handler_table_va_ = se_handler_table_va;
}

//Returns SE Handler RVA list
image_config_info::se_handler_list& image_config_info::get_se_handler_rvas()
{
	return se_handlers_;
}

//Returns Lock Prefix RVA list
image_config_info::lock_prefix_rva_list& image_config_info::get_lock_prefix_rvas()
{
	return lock_prefixes_;
}

//Returns image config info
//If image does not have config info, throws an exception
const image_config_info get_image_config(const pe_base& pe)
{
	return pe.get_pe_type() == pe_type_32
		? get_image_config_base<pe_types_class_32>(pe)
		: get_image_config_base<pe_types_class_64>(pe);
}

//Image config rebuilder
const image_directory rebuild_image_config(pe_base& pe, const image_config_info& info, section& image_config_section, uint32_t offset_from_section_start, bool write_se_handlers, bool write_lock_prefixes, bool save_to_pe_header, bool auto_strip_last_section)
{
	return pe.get_pe_type() == pe_type_32
		? rebuild_image_config_base<pe_types_class_32>(pe, info, image_config_section, offset_from_section_start, write_se_handlers, write_lock_prefixes, save_to_pe_header, auto_strip_last_section)
		: rebuild_image_config_base<pe_types_class_64>(pe, info, image_config_section, offset_from_section_start, write_se_handlers, write_lock_prefixes, save_to_pe_header, auto_strip_last_section);
}


//Returns image config info
//If image does not have config info, throws an exception
template<typename PEClassType>
const image_config_info get_image_config_base(const pe_base& pe)
{
	//Check if image has config directory
	if(!pe.has_config())
		throw pe_exception("Image does not have load config directory", pe_exception::directory_does_not_exist);

	//Get load config structure
	typename PEClassType::ConfigStruct config_info = pe.section_data_from_rva<typename PEClassType::ConfigStruct>(pe.get_directory_rva(image_directory_entry_load_config), section_data_virtual);

	//Check size of config directory
	if(config_info.Size != sizeof(config_info))
		throw pe_exception("Incorrect (or old) load config directory", pe_exception::incorrect_config_directory);

	//Fill return structure
	image_config_info ret(config_info);

	//Check possible overflow
	if(config_info.SEHandlerCount >= pe_utils::max_dword / sizeof(uint32_t)
		|| config_info.SEHandlerTable >= static_cast<typename PEClassType::BaseSize>(-1) - config_info.SEHandlerCount * sizeof(uint32_t))
		throw pe_exception("Incorrect load config directory", pe_exception::incorrect_config_directory);

	//Read sorted SE handler RVA list (if any)
	for(typename PEClassType::BaseSize i = 0; i != config_info.SEHandlerCount; ++i)
		ret.add_se_handler_rva(pe.section_data_from_va<uint32_t>(static_cast<typename PEClassType::BaseSize>(config_info.SEHandlerTable + i * sizeof(uint32_t))));

	if(config_info.LockPrefixTable)
	{
		//Read Lock Prefix VA list (if any)
		unsigned long current = 0;
		while(true)
		{
			typename PEClassType::BaseSize lock_prefix_va = pe.section_data_from_va<typename PEClassType::BaseSize>(static_cast<typename PEClassType::BaseSize>(config_info.LockPrefixTable + current * sizeof(typename PEClassType::BaseSize)));
			if(!lock_prefix_va)
				break;

			ret.add_lock_prefix_rva(pe.va_to_rva(lock_prefix_va));

			++current;
		}
	}

	return ret;
}

//Image config directory rebuilder
//auto_strip_last_section - if true and TLS are placed in the last section, it will be automatically stripped
//If write_se_handlers = true, SE Handlers list will be written just after image config directory structure
//If write_lock_prefixes = true, Lock Prefixes address list will be written just after image config directory structure
template<typename PEClassType>
const image_directory rebuild_image_config_base(pe_base& pe, const image_config_info& info, section& image_config_section, uint32_t offset_from_section_start, bool write_se_handlers, bool write_lock_prefixes, bool save_to_pe_header, bool auto_strip_last_section)
{
	//Check that image_config_section is attached to this PE image
	if(!pe.section_attached(image_config_section))
		throw pe_exception("Image Config section must be attached to PE file", pe_exception::section_is_not_attached);
	
	uint32_t alignment = pe_utils::align_up(offset_from_section_start, sizeof(typename PEClassType::BaseSize)) - offset_from_section_start;

	uint32_t needed_size = sizeof(typename PEClassType::ConfigStruct); //Calculate needed size for Image Config table
	
	uint32_t image_config_data_pos = offset_from_section_start + alignment;

	uint32_t current_pos_of_se_handlers = 0;
	uint32_t current_pos_of_lock_prefixes = 0;
	
	if(write_se_handlers)
	{
		current_pos_of_se_handlers = needed_size + image_config_data_pos;
		needed_size += static_cast<uint32_t>(info.get_se_handler_rvas().size()) * sizeof(uint32_t); //RVAs of SE Handlers
	}
	
	if(write_lock_prefixes)
	{
		current_pos_of_lock_prefixes = needed_size + image_config_data_pos;
		needed_size += static_cast<uint32_t>((info.get_lock_prefix_rvas().size() + 1) * sizeof(typename PEClassType::BaseSize)); //VAs of Lock Prefixes (and ending null element)
	}

	//Check if image_config_section is last one. If it's not, check if there's enough place for Image Config data
	if(&image_config_section != &*(pe.get_image_sections().end() - 1) && 
		(image_config_section.empty() || pe_utils::align_up(image_config_section.get_size_of_raw_data(), pe.get_file_alignment()) < needed_size + image_config_data_pos))
		throw pe_exception("Insufficient space for TLS directory", pe_exception::insufficient_space);

	std::string& raw_data = image_config_section.get_raw_data();

	//This will be done only if image_config_section is the last section of image or for section with unaligned raw length of data
	if(raw_data.length() < needed_size + image_config_data_pos)
		raw_data.resize(needed_size + image_config_data_pos); //Expand section raw data

	//Create and fill Image Config structure
	typename PEClassType::ConfigStruct image_config_section_struct = {0};
	image_config_section_struct.Size = sizeof(image_config_section_struct);
	image_config_section_struct.TimeDateStamp = info.get_time_stamp();
	image_config_section_struct.MajorVersion = info.get_major_version();
	image_config_section_struct.MinorVersion = info.get_minor_version();
	image_config_section_struct.GlobalFlagsClear = info.get_global_flags_clear();
	image_config_section_struct.GlobalFlagsSet = info.get_global_flags_set();
	image_config_section_struct.CriticalSectionDefaultTimeout = info.get_critical_section_default_timeout();
	image_config_section_struct.DeCommitFreeBlockThreshold = static_cast<typename PEClassType::BaseSize>(info.get_decommit_free_block_threshold());
	image_config_section_struct.DeCommitTotalFreeThreshold = static_cast<typename PEClassType::BaseSize>(info.get_decommit_total_free_threshold());
	image_config_section_struct.MaximumAllocationSize = static_cast<typename PEClassType::BaseSize>(info.get_max_allocation_size());
	image_config_section_struct.VirtualMemoryThreshold = static_cast<typename PEClassType::BaseSize>(info.get_virtual_memory_threshold());
	image_config_section_struct.ProcessHeapFlags = info.get_process_heap_flags();
	image_config_section_struct.ProcessAffinityMask = static_cast<typename PEClassType::BaseSize>(info.get_process_affinity_mask());
	image_config_section_struct.CSDVersion = info.get_service_pack_version();
	image_config_section_struct.EditList = static_cast<typename PEClassType::BaseSize>(info.get_edit_list_va());
	image_config_section_struct.SecurityCookie = static_cast<typename PEClassType::BaseSize>(info.get_security_cookie_va());
	image_config_section_struct.SEHandlerCount = static_cast<typename PEClassType::BaseSize>(info.get_se_handler_rvas().size());
	

	if(write_se_handlers)
	{
		if(info.get_se_handler_rvas().empty())
		{
			write_se_handlers = false;
			image_config_section_struct.SEHandlerTable = 0;
		}
		else
		{
			typename PEClassType::BaseSize va;
			pe.rva_to_va(pe.rva_from_section_offset(image_config_section, current_pos_of_se_handlers), va);
			image_config_section_struct.SEHandlerTable = va;
		}
	}
	else
	{
		image_config_section_struct.SEHandlerTable = static_cast<typename PEClassType::BaseSize>(info.get_se_handler_table_va());
	}

	if(write_lock_prefixes)
	{
		if(info.get_lock_prefix_rvas().empty())
		{
			write_lock_prefixes = false;
			image_config_section_struct.LockPrefixTable = 0;
		}
		else
		{
			typename PEClassType::BaseSize va;
			pe.rva_to_va(pe.rva_from_section_offset(image_config_section, current_pos_of_lock_prefixes), va);
			image_config_section_struct.LockPrefixTable = va;
		}
	}
	else
	{
		image_config_section_struct.LockPrefixTable = static_cast<typename PEClassType::BaseSize>(info.get_lock_prefix_table_va());
	}

	//Write image config section
	memcpy(&raw_data[image_config_data_pos], &image_config_section_struct, sizeof(image_config_section_struct));

	if(write_se_handlers)
	{
		//Sort SE Handlers list
		image_config_info::se_handler_list sorted_list = info.get_se_handler_rvas();
		std::sort(sorted_list.begin(), sorted_list.end());

		//Write SE Handlers table
		for(image_config_info::se_handler_list::const_iterator it = sorted_list.begin(); it != sorted_list.end(); ++it)
		{
			uint32_t se_handler_rva = *it;
			memcpy(&raw_data[current_pos_of_se_handlers], &se_handler_rva, sizeof(se_handler_rva));
			current_pos_of_se_handlers += sizeof(se_handler_rva);
		}
	}

	if(write_lock_prefixes)
	{
		//Write Lock Prefixes VA list
		for(image_config_info::lock_prefix_rva_list::const_iterator it = info.get_lock_prefix_rvas().begin(); it != info.get_lock_prefix_rvas().end(); ++it)
		{
			typename PEClassType::BaseSize lock_prefix_va;
			pe.rva_to_va(*it, lock_prefix_va);
			memcpy(&raw_data[current_pos_of_lock_prefixes], &lock_prefix_va, sizeof(lock_prefix_va));
			current_pos_of_lock_prefixes += sizeof(lock_prefix_va);
		}

		{
			//Ending null VA
			typename PEClassType::BaseSize lock_prefix_va = 0;
			memcpy(&raw_data[current_pos_of_lock_prefixes], &lock_prefix_va, sizeof(lock_prefix_va));
		}
	}

	//Adjust section raw and virtual sizes
	pe.recalculate_section_sizes(image_config_section, auto_strip_last_section);

	image_directory ret(pe.rva_from_section_offset(image_config_section, image_config_data_pos), sizeof(typename PEClassType::ConfigStruct));

	//If auto-rewrite of PE headers is required
	if(save_to_pe_header)
	{
		pe.set_directory_rva(image_directory_entry_load_config, ret.get_rva());
		pe.set_directory_size(image_directory_entry_load_config, ret.get_size());
	}

	return ret;
}

}