summaryrefslogtreecommitdiff
path: root/drivers/pe_bliss/pe_imports.cpp
blob: 704d5fca9971ebafc02d13158cf4fe0fafb2475f (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
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
#include <string.h>
#include "pe_imports.h"
#include "pe_properties_generic.h"

namespace pe_bliss
{
using namespace pe_win;

//IMPORTS
//Default constructor
//If set_to_pe_headers = true, IMAGE_DIRECTORY_ENTRY_IMPORT entry will be reset
//to new value after import rebuilding
//If auto_zero_directory_entry_iat = true, IMAGE_DIRECTORY_ENTRY_IAT will be set to zero
//IMAGE_DIRECTORY_ENTRY_IAT is used by loader to temporarily make section, where IMAGE_DIRECTORY_ENTRY_IAT RVA points, writeable
//to be able to modify IAT thunks
import_rebuilder_settings::import_rebuilder_settings(bool set_to_pe_headers, bool auto_zero_directory_entry_iat)
	:offset_from_section_start_(0),
	build_original_iat_(true),
	save_iat_and_original_iat_rvas_(true),
	fill_missing_original_iats_(false),
	set_to_pe_headers_(set_to_pe_headers),
	zero_directory_entry_iat_(auto_zero_directory_entry_iat),
	rewrite_iat_and_original_iat_contents_(false),
	auto_strip_last_section_(true)
{}

//Returns offset from section start where import directory data will be placed
uint32_t import_rebuilder_settings::get_offset_from_section_start() const
{
	return offset_from_section_start_;
}

//Returns true if Original import address table (IAT) will be rebuilt
bool import_rebuilder_settings::build_original_iat() const
{
	return build_original_iat_;
}

//Returns true if Original import address and import address tables will not be rebuilt,
//works only if import descriptor IAT (and orig.IAT, if present) RVAs are not zero
bool import_rebuilder_settings::save_iat_and_original_iat_rvas() const
{
	return save_iat_and_original_iat_rvas_;
}

//Returns true if Original import address and import address tables contents will be rewritten
//works only if import descriptor IAT (and orig.IAT, if present) RVAs are not zero
//and save_iat_and_original_iat_rvas is true
bool import_rebuilder_settings::rewrite_iat_and_original_iat_contents() const
{
	return rewrite_iat_and_original_iat_contents_;
}

//Returns true if original missing IATs will be rebuilt
//(only if IATs are saved)
bool import_rebuilder_settings::fill_missing_original_iats() const
{
	return fill_missing_original_iats_;
}

//Returns true if PE headers should be updated automatically after rebuilding of imports
bool import_rebuilder_settings::auto_set_to_pe_headers() const
{
	return set_to_pe_headers_;
}

//Returns true if IMAGE_DIRECTORY_ENTRY_IAT must be zeroed, works only if auto_set_to_pe_headers = true
bool import_rebuilder_settings::zero_directory_entry_iat() const
{
	return zero_directory_entry_iat_;	
}

//Returns true if the last section should be stripped automatically, if imports are inside it
bool import_rebuilder_settings::auto_strip_last_section_enabled() const
{
	return auto_strip_last_section_;
}

//Sets offset from section start where import directory data will be placed
void import_rebuilder_settings::set_offset_from_section_start(uint32_t offset)
{
	offset_from_section_start_ = offset;
}

//Sets if Original import address table (IAT) will be rebuilt
void import_rebuilder_settings::build_original_iat(bool enable)
{
	build_original_iat_ = enable;
}

//Sets if Original import address and import address tables will not be rebuilt,
//works only if import descriptor IAT (and orig.IAT, if present) RVAs are not zero
void import_rebuilder_settings::save_iat_and_original_iat_rvas(bool enable, bool enable_rewrite_iat_and_original_iat_contents)
{
	save_iat_and_original_iat_rvas_ = enable;
	if(save_iat_and_original_iat_rvas_)
		rewrite_iat_and_original_iat_contents_ = enable_rewrite_iat_and_original_iat_contents;
	else
		rewrite_iat_and_original_iat_contents_ = false;
}

//Sets if original missing IATs will be rebuilt
//(only if IATs are saved)
void import_rebuilder_settings::fill_missing_original_iats(bool enable)
{
	fill_missing_original_iats_ = enable;
}

//Sets if PE headers should be updated automatically after rebuilding of imports
void import_rebuilder_settings::auto_set_to_pe_headers(bool enable)
{
	set_to_pe_headers_ = enable;
}

//Sets if IMAGE_DIRECTORY_ENTRY_IAT must be zeroed, works only if auto_set_to_pe_headers = true
void import_rebuilder_settings::zero_directory_entry_iat(bool enable)
{
	zero_directory_entry_iat_ = enable;
}

//Sets if the last section should be stripped automatically, if imports are inside it, default true
void import_rebuilder_settings::enable_auto_strip_last_section(bool enable)
{
	auto_strip_last_section_ = enable;
}

//Default constructor
imported_function::imported_function()
	:hint_(0), ordinal_(0), iat_va_(0)
{}

//Returns name of function
const std::string& imported_function::get_name() const
{
	return name_;
}

//Returns true if imported function has name (and hint)
bool imported_function::has_name() const
{
	return !name_.empty();
}

//Returns hint
uint16_t imported_function::get_hint() const
{
	return hint_;
}

//Returns ordinal of function
uint16_t imported_function::get_ordinal() const
{
	return ordinal_;
}

//Returns IAT entry VA (usable if image has both IAT and original IAT and is bound)
uint64_t imported_function::get_iat_va() const
{
	return iat_va_;
}

//Sets name of function
void imported_function::set_name(const std::string& name)
{
	name_ = name;
}

//Sets hint
void imported_function::set_hint(uint16_t hint)
{
	hint_ = hint;
}

//Sets ordinal
void imported_function::set_ordinal(uint16_t ordinal)
{
	ordinal_ = ordinal;
}

//Sets IAT entry VA (usable if image has both IAT and original IAT and is bound)
void imported_function::set_iat_va(uint64_t va)
{
	iat_va_ = va;
}

//Default constructor
import_library::import_library()
	:rva_to_iat_(0), rva_to_original_iat_(0), timestamp_(0)
{}

//Returns name of library
const std::string& import_library::get_name() const
{
	return name_;
}

//Returns RVA to Import Address Table (IAT)
uint32_t import_library::get_rva_to_iat() const
{
	return rva_to_iat_;
}

//Returns RVA to Original Import Address Table (Original IAT)
uint32_t import_library::get_rva_to_original_iat() const
{
	return rva_to_original_iat_;
}

//Returns timestamp
uint32_t import_library::get_timestamp() const
{
	return timestamp_;
}

//Sets name of library
void import_library::set_name(const std::string& name)
{
	name_ = name;
}

//Sets RVA to Import Address Table (IAT)
void import_library::set_rva_to_iat(uint32_t rva_to_iat)
{
	rva_to_iat_ = rva_to_iat;
}

//Sets RVA to Original Import Address Table (Original IAT)
void import_library::set_rva_to_original_iat(uint32_t rva_to_original_iat)
{
	rva_to_original_iat_ = rva_to_original_iat;
}

//Sets timestamp
void import_library::set_timestamp(uint32_t timestamp)
{
	timestamp_ = timestamp;
}

//Returns imported functions list
const import_library::imported_list& import_library::get_imported_functions() const
{
	return imports_;
}

//Adds imported function
void import_library::add_import(const imported_function& func)
{
	imports_.push_back(func);
}

//Clears imported functions list
void import_library::clear_imports()
{
	imports_.clear();
}

const imported_functions_list get_imported_functions(const pe_base& pe)
{
	return (pe.get_pe_type() == pe_type_32 ?
		get_imported_functions_base<pe_types_class_32>(pe)
		: get_imported_functions_base<pe_types_class_64>(pe));
}

const image_directory rebuild_imports(pe_base& pe, const imported_functions_list& imports, section& import_section, const import_rebuilder_settings& import_settings)
{
	return (pe.get_pe_type() == pe_type_32 ?
		rebuild_imports_base<pe_types_class_32>(pe, imports, import_section, import_settings)
		: rebuild_imports_base<pe_types_class_64>(pe, imports, import_section, import_settings));
}

//Returns imported functions list with related libraries info
template<typename PEClassType>
const imported_functions_list get_imported_functions_base(const pe_base& pe)
{
	imported_functions_list ret;

	//If image has no imports, return empty array
	if(!pe.has_imports())
		return ret;

	unsigned long current_descriptor_pos = pe.get_directory_rva(image_directory_entry_import);
	//Get first IMAGE_IMPORT_DESCRIPTOR
	image_import_descriptor import_descriptor = pe.section_data_from_rva<image_import_descriptor>(current_descriptor_pos, section_data_virtual, true);

	//Iterate them until we reach zero-element
	//We don't need to check correctness of this, because exception will be thrown
	//inside of loop if we go outsize of section
	while(import_descriptor.Name)
	{
		//Get imported library information
		import_library lib;

		unsigned long max_name_length;
		//Get byte count that we have for library name
		if((max_name_length = pe.section_data_length_from_rva(import_descriptor.Name, import_descriptor.Name, section_data_virtual, true)) < 2)
			throw pe_exception("Incorrect import directory", pe_exception::incorrect_import_directory);

		//Get DLL name pointer
		const char* dll_name = pe.section_data_from_rva(import_descriptor.Name, section_data_virtual, true);

		//Check for null-termination
		if(!pe_utils::is_null_terminated(dll_name, max_name_length))
			throw pe_exception("Incorrect import directory", pe_exception::incorrect_import_directory);

		//Set library name
		lib.set_name(dll_name);
		//Set library timestamp
		lib.set_timestamp(import_descriptor.TimeDateStamp);
		//Set library RVA to IAT and original IAT
		lib.set_rva_to_iat(import_descriptor.FirstThunk);
		lib.set_rva_to_original_iat(import_descriptor.OriginalFirstThunk);

		//Get RVA to IAT (it must be filled by loader when loading PE)
		uint32_t current_thunk_rva = import_descriptor.FirstThunk;
		typename PEClassType::BaseSize import_address_table = pe.section_data_from_rva<typename PEClassType::BaseSize>(current_thunk_rva, section_data_virtual, true);

		//Get RVA to original IAT (lookup table), which must handle imported functions names
		//Some linkers leave this pointer zero-filled
		//Such image is valid, but it is not possible to restore imported functions names
		//afted image was loaded, because IAT becomes the only one table
		//containing both function names and function RVAs after loading
		uint32_t current_original_thunk_rva = import_descriptor.OriginalFirstThunk;
		typename PEClassType::BaseSize import_lookup_table = current_original_thunk_rva == 0 ? import_address_table : pe.section_data_from_rva<typename PEClassType::BaseSize>(current_original_thunk_rva, section_data_virtual, true);
		if(current_original_thunk_rva == 0)
			current_original_thunk_rva = current_thunk_rva;

		//List all imported functions for current DLL
		if(import_lookup_table != 0 && import_address_table != 0)
		{
			while(true)
			{
				//Imported function description
				imported_function func;

				//Get VA from IAT
				typename PEClassType::BaseSize address = pe.section_data_from_rva<typename PEClassType::BaseSize>(current_thunk_rva, section_data_virtual, true);
				//Move pointer
				current_thunk_rva += sizeof(typename PEClassType::BaseSize);

				//Jump to next DLL if we finished with this one
				if(!address)
					break;

				func.set_iat_va(address);

				//Get VA from original IAT
				typename PEClassType::BaseSize lookup = pe.section_data_from_rva<typename PEClassType::BaseSize>(current_original_thunk_rva, section_data_virtual, true);
				//Move pointer
				current_original_thunk_rva += sizeof(typename PEClassType::BaseSize);

				//Check if function is imported by ordinal
				if((lookup & PEClassType::ImportSnapFlag) != 0)
				{
					//Set function ordinal
					func.set_ordinal(static_cast<uint16_t>(lookup & 0xffff));
				}
				else
				{
					//Get byte count that we have for function name
					if(lookup > static_cast<uint32_t>(-1) - sizeof(uint16_t))
						throw pe_exception("Incorrect import directory", pe_exception::incorrect_import_directory);

					//Get maximum available length of function name
					if((max_name_length = pe.section_data_length_from_rva(static_cast<uint32_t>(lookup + sizeof(uint16_t)), static_cast<uint32_t>(lookup + sizeof(uint16_t)), section_data_virtual, true)) < 2)
						throw pe_exception("Incorrect import directory", pe_exception::incorrect_import_directory);

					//Get imported function name
					const char* func_name = pe.section_data_from_rva(static_cast<uint32_t>(lookup + sizeof(uint16_t)), section_data_virtual, true);

					//Check for null-termination
					if(!pe_utils::is_null_terminated(func_name, max_name_length))
						throw pe_exception("Incorrect import directory", pe_exception::incorrect_import_directory);

					//HINT in import table is ORDINAL in export table
					uint16_t hint = pe.section_data_from_rva<uint16_t>(static_cast<uint32_t>(lookup), section_data_virtual, true);

					//Save hint and name
					func.set_name(func_name);
					func.set_hint(hint);
				}

				//Add function to list
				lib.add_import(func);
			}
		}

		//Check possible overflow
		if(!pe_utils::is_sum_safe(current_descriptor_pos, sizeof(image_import_descriptor)))
			throw pe_exception("Incorrect import directory", pe_exception::incorrect_import_directory);

		//Go to next library
		current_descriptor_pos += sizeof(image_import_descriptor);
		import_descriptor = pe.section_data_from_rva<image_import_descriptor>(current_descriptor_pos, section_data_virtual, true);

		//Save import information
		ret.push_back(lib);
	}

	//Return resulting list
	return ret;
}


//Simple import directory rebuilder
//You can get all image imports with get_imported_functions() function
//You can use returned value to, for example, add new imported library with some functions
//to the end of list of imported libraries
//To keep PE file working, rebuild its imports with save_iat_and_original_iat_rvas = true (default)
//Don't add new imported functions to existing imported library entries, because this can cause
//rewriting of some used memory (or other IAT/orig.IAT fields) by system loader
//The safest way is just adding import libraries with functions to the end of imported_functions_list array
template<typename PEClassType>
const image_directory rebuild_imports_base(pe_base& pe, const imported_functions_list& imports, section& import_section, const import_rebuilder_settings& import_settings)
{
	//Check that import_section is attached to this PE image
	if(!pe.section_attached(import_section))
		throw pe_exception("Import section must be attached to PE file", pe_exception::section_is_not_attached);

	uint32_t needed_size = 0; //Calculate needed size for import structures and strings
	uint32_t needed_size_for_strings = 0; //Calculate needed size for import strings (library and function names and hints)
	uint32_t size_of_iat = 0; //Size of IAT structures

	needed_size += static_cast<uint32_t>((1 /* ending null descriptor */ + imports.size()) * sizeof(image_import_descriptor));
	
	//Enumerate imported functions
	for(imported_functions_list::const_iterator it = imports.begin(); it != imports.end(); ++it)
	{
		needed_size_for_strings += static_cast<uint32_t>((*it).get_name().length() + 1 /* nullbyte */);

		const import_library::imported_list& funcs = (*it).get_imported_functions();

		//IMAGE_THUNK_DATA
		size_of_iat += static_cast<uint32_t>(sizeof(typename PEClassType::BaseSize) * (1 /*ending null */ + funcs.size()));

		//Enumerate all imported functions in library
		for(import_library::imported_list::const_iterator f = funcs.begin(); f != funcs.end(); ++f)
		{
			if((*f).has_name())
				needed_size_for_strings += static_cast<uint32_t>((*f).get_name().length() + 1 /* nullbyte */ + sizeof(uint16_t) /* hint */);
		}
	}

	if(import_settings.build_original_iat() || import_settings.fill_missing_original_iats())
		needed_size += size_of_iat * 2; //We'll have two similar-sized IATs if we're building original IAT
	else
		needed_size += size_of_iat;

	needed_size += sizeof(typename PEClassType::BaseSize); //Maximum align for IAT and original IAT
	
	//Total needed size for import structures and strings
	needed_size += needed_size_for_strings;

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

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

	//This will be done only if image_section is the last section of image or for section with unaligned raw length of data
	if(raw_data.length() < needed_size + import_settings.get_offset_from_section_start())
		raw_data.resize(needed_size + import_settings.get_offset_from_section_start()); //Expand section raw data
	
	uint32_t current_string_pointer = import_settings.get_offset_from_section_start();/* we will paste structures after strings */
	
	//Position for IAT
	uint32_t current_pos_for_iat = pe_utils::align_up(static_cast<uint32_t>(needed_size_for_strings + import_settings.get_offset_from_section_start() + (1 + imports.size()) * sizeof(image_import_descriptor)), sizeof(typename PEClassType::BaseSize));
	//Position for original IAT
	uint32_t current_pos_for_original_iat = current_pos_for_iat + size_of_iat;
	//Position for import descriptors
	uint32_t current_pos_for_descriptors = needed_size_for_strings + import_settings.get_offset_from_section_start();

	//Build imports
	for(imported_functions_list::const_iterator it = imports.begin(); it != imports.end(); ++it)
	{
		//Create import descriptor
		image_import_descriptor descr;
		memset(&descr, 0, sizeof(descr));
		descr.TimeDateStamp = (*it).get_timestamp(); //Restore timestamp
		descr.Name = pe.rva_from_section_offset(import_section, current_string_pointer); //Library name RVA

		//If we should save IAT for current import descriptor
		bool save_iats_for_this_descriptor = import_settings.save_iat_and_original_iat_rvas() && (*it).get_rva_to_iat() != 0;
		//If we should write original IAT
		bool write_original_iat = (!save_iats_for_this_descriptor && import_settings.build_original_iat()) || import_settings.fill_missing_original_iats();

		//If we should rewrite saved original IAT for current import descriptor (without changing its position)
		bool rewrite_saved_original_iat = save_iats_for_this_descriptor && import_settings.rewrite_iat_and_original_iat_contents() && import_settings.build_original_iat();
		//If we should rewrite saved IAT for current import descriptor (without changing its position)
		bool rewrite_saved_iat = save_iats_for_this_descriptor && import_settings.rewrite_iat_and_original_iat_contents() && (*it).get_rva_to_iat() != 0;

		//Helper values if we're rewriting existing IAT or orig.IAT
		uint32_t original_first_thunk = 0;
		uint32_t first_thunk = 0;

		if(save_iats_for_this_descriptor)
		{
			//If there's no original IAT and we're asked to rebuild missing original IATs
			if(!(*it).get_rva_to_original_iat() && import_settings.fill_missing_original_iats())
				descr.OriginalFirstThunk = import_settings.build_original_iat() ? pe.rva_from_section_offset(import_section, current_pos_for_original_iat) : 0;
			else
				descr.OriginalFirstThunk = import_settings.build_original_iat() ? (*it).get_rva_to_original_iat() : 0;
			
			descr.FirstThunk = (*it).get_rva_to_iat();

			original_first_thunk = descr.OriginalFirstThunk;
			first_thunk = descr.FirstThunk;

			if(rewrite_saved_original_iat)
			{
				if((*it).get_rva_to_original_iat())
					write_original_iat = true;
				else
					rewrite_saved_original_iat = false;
			}

			if(rewrite_saved_iat)
				save_iats_for_this_descriptor = false;
		}
		else
		{
			//We are creating new IAT and original IAT (if needed)
			descr.OriginalFirstThunk = import_settings.build_original_iat() ? pe.rva_from_section_offset(import_section, current_pos_for_original_iat) : 0;
			descr.FirstThunk = pe.rva_from_section_offset(import_section, current_pos_for_iat);
		}
		
		//Save import descriptor
		memcpy(&raw_data[current_pos_for_descriptors], &descr, sizeof(descr));
		current_pos_for_descriptors += sizeof(descr);

		//Save library name
		memcpy(&raw_data[current_string_pointer], (*it).get_name().c_str(), (*it).get_name().length() + 1 /* nullbyte */);
		current_string_pointer += static_cast<uint32_t>((*it).get_name().length() + 1 /* nullbyte */);
		
		//List all imported functions
		const import_library::imported_list& funcs = (*it).get_imported_functions();
		for(import_library::imported_list::const_iterator f = funcs.begin(); f != funcs.end(); ++f)
		{
			if((*f).has_name()) //If function is imported by name
			{
				//Get RVA of IMAGE_IMPORT_BY_NAME
				typename PEClassType::BaseSize rva_of_named_import = pe.rva_from_section_offset(import_section, current_string_pointer);

				if(!save_iats_for_this_descriptor)
				{
					if(write_original_iat)
					{
						//We're creating original IATs - so we can write to IAT saved VA (because IMAGE_IMPORT_BY_NAME will be read
						//by PE loader from original IAT)
						typename PEClassType::BaseSize iat_value = static_cast<typename PEClassType::BaseSize>((*f).get_iat_va());

						if(rewrite_saved_iat)
						{
							if(pe.section_data_length_from_rva(first_thunk, first_thunk, section_data_raw, true) <= sizeof(iat_value))
								throw pe_exception("Insufficient space inside initial IAT", pe_exception::insufficient_space);

							memcpy(pe.section_data_from_rva(first_thunk, true), &iat_value, sizeof(iat_value));

							first_thunk += sizeof(iat_value);
						}
						else
						{
							memcpy(&raw_data[current_pos_for_iat], &iat_value, sizeof(iat_value));
							current_pos_for_iat += sizeof(rva_of_named_import);
						}
					}
					else
					{
						//Else - write to IAT RVA of IMAGE_IMPORT_BY_NAME
						if(rewrite_saved_iat)
						{
							if(pe.section_data_length_from_rva(first_thunk, first_thunk, section_data_raw, true) <= sizeof(rva_of_named_import))
								throw pe_exception("Insufficient space inside initial IAT", pe_exception::insufficient_space);

							memcpy(pe.section_data_from_rva(first_thunk, true), &rva_of_named_import, sizeof(rva_of_named_import));

							first_thunk += sizeof(rva_of_named_import);
						}
						else
						{
							memcpy(&raw_data[current_pos_for_iat], &rva_of_named_import, sizeof(rva_of_named_import));
							current_pos_for_iat += sizeof(rva_of_named_import);
						}
					}
				}

				if(write_original_iat)
				{
					if(rewrite_saved_original_iat)
					{
						if(pe.section_data_length_from_rva(original_first_thunk, original_first_thunk, section_data_raw, true) <= sizeof(rva_of_named_import))
							throw pe_exception("Insufficient space inside initial original IAT", pe_exception::insufficient_space);

						memcpy(pe.section_data_from_rva(original_first_thunk, true), &rva_of_named_import, sizeof(rva_of_named_import));

						original_first_thunk += sizeof(rva_of_named_import);
					}
					else
					{
						//We're creating original IATs
						memcpy(&raw_data[current_pos_for_original_iat], &rva_of_named_import, sizeof(rva_of_named_import));
						current_pos_for_original_iat += sizeof(rva_of_named_import);
					}
				}

				//Write IMAGE_IMPORT_BY_NAME (WORD hint + string function name)
				uint16_t hint = (*f).get_hint();
				memcpy(&raw_data[current_string_pointer], &hint, sizeof(hint));
				memcpy(&raw_data[current_string_pointer + sizeof(uint16_t)], (*f).get_name().c_str(), (*f).get_name().length() + 1 /* nullbyte */);
				current_string_pointer += static_cast<uint32_t>((*f).get_name().length() + 1 /* nullbyte */ + sizeof(uint16_t) /* hint */);
			}
			else //Function is imported by ordinal
			{
				uint16_t ordinal = (*f).get_ordinal();
				typename PEClassType::BaseSize thunk_value = ordinal;
				thunk_value |= PEClassType::ImportSnapFlag; //Imported by ordinal

				if(!save_iats_for_this_descriptor)
				{
					if(write_original_iat)
					{
						//We're creating original IATs - so we can wtire to IAT saved VA (because ordinal will be read
						//by PE loader from original IAT)
						typename PEClassType::BaseSize iat_value = static_cast<typename PEClassType::BaseSize>((*f).get_iat_va());
						if(rewrite_saved_iat)
						{
							if(pe.section_data_length_from_rva(first_thunk, first_thunk, section_data_raw, true) <= sizeof(iat_value))
								throw pe_exception("Insufficient space inside initial IAT", pe_exception::insufficient_space);

							memcpy(pe.section_data_from_rva(first_thunk, true), &iat_value, sizeof(iat_value));

							first_thunk += sizeof(iat_value);
						}
						else
						{
							memcpy(&raw_data[current_pos_for_iat], &iat_value, sizeof(iat_value));
							current_pos_for_iat += sizeof(thunk_value);
						}
					}
					else
					{
						//Else - write ordinal to IAT
						if(rewrite_saved_iat)
						{
							if(pe.section_data_length_from_rva(first_thunk, first_thunk, section_data_raw, true) <= sizeof(thunk_value))
								throw pe_exception("Insufficient space inside initial IAT", pe_exception::insufficient_space);

							memcpy(pe.section_data_from_rva(first_thunk, true), &thunk_value, sizeof(thunk_value));

							first_thunk += sizeof(thunk_value);
						}
						else
						{
							memcpy(&raw_data[current_pos_for_iat], &thunk_value, sizeof(thunk_value));
						}
					}
				}

				//We're writing ordinal to original IAT slot
				if(write_original_iat)
				{
					if(rewrite_saved_original_iat)
					{
						if(pe.section_data_length_from_rva(original_first_thunk, original_first_thunk, section_data_raw, true) <= sizeof(thunk_value))
							throw pe_exception("Insufficient space inside initial original IAT", pe_exception::insufficient_space);

						memcpy(pe.section_data_from_rva(original_first_thunk, true), &thunk_value, sizeof(thunk_value));

						original_first_thunk += sizeof(thunk_value);
					}
					else
					{
						memcpy(&raw_data[current_pos_for_original_iat], &thunk_value, sizeof(thunk_value));
						current_pos_for_original_iat += sizeof(thunk_value);
					}
				}
			}
		}

		if(!save_iats_for_this_descriptor)
		{
			//Ending null thunks
			typename PEClassType::BaseSize thunk_value = 0;

			if(rewrite_saved_iat)
			{
				if(pe.section_data_length_from_rva(first_thunk, first_thunk, section_data_raw, true) <= sizeof(thunk_value))
					throw pe_exception("Insufficient space inside initial IAT", pe_exception::insufficient_space);

				memcpy(pe.section_data_from_rva(first_thunk, true), &thunk_value, sizeof(thunk_value));

				first_thunk += sizeof(thunk_value);
			}
			else
			{
				memcpy(&raw_data[current_pos_for_iat], &thunk_value, sizeof(thunk_value));
				current_pos_for_iat += sizeof(thunk_value);
			}
		}

		if(write_original_iat)
		{
			//Ending null thunks
			typename PEClassType::BaseSize thunk_value = 0;

			if(rewrite_saved_original_iat)
			{
				if(pe.section_data_length_from_rva(original_first_thunk, original_first_thunk, section_data_raw, true) <= sizeof(thunk_value))
					throw pe_exception("Insufficient space inside initial original IAT", pe_exception::insufficient_space);

				memcpy(pe.section_data_from_rva(original_first_thunk, true), &thunk_value, sizeof(thunk_value));

				original_first_thunk += sizeof(thunk_value);
			}
			else
			{
				memcpy(&raw_data[current_pos_for_original_iat], &thunk_value, sizeof(thunk_value));
				current_pos_for_original_iat += sizeof(thunk_value);
			}
		}
	}

	{
		//Null ending descriptor
		image_import_descriptor descr;
		memset(&descr, 0, sizeof(descr));
		memcpy(&raw_data[current_pos_for_descriptors], &descr, sizeof(descr));
	}

	//Strip data a little, if we saved some place
	//We're allocating more space than needed, if present original IAT and IAT are saved
	raw_data.resize(current_pos_for_original_iat);

	//Adjust section raw and virtual sizes
	pe.recalculate_section_sizes(import_section, import_settings.auto_strip_last_section_enabled());

	//Return information about rebuilt import directory
	image_directory ret(pe.rva_from_section_offset(import_section, import_settings.get_offset_from_section_start() + needed_size_for_strings), needed_size - needed_size_for_strings);

	//If auto-rewrite of PE headers is required
	if(import_settings.auto_set_to_pe_headers())
	{
		pe.set_directory_rva(image_directory_entry_import, ret.get_rva());
		pe.set_directory_size(image_directory_entry_import, ret.get_size());

		//If we are requested to zero IMAGE_DIRECTORY_ENTRY_IAT also
		if(import_settings.zero_directory_entry_iat())
		{
			pe.set_directory_rva(image_directory_entry_iat, 0);
			pe.set_directory_size(image_directory_entry_iat, 0);
		}
	}

	return ret;
}
}