summaryrefslogtreecommitdiff
path: root/sysmap/src/mapper/pe.h
blob: 9841cb29949799fdced2bf5728a3e52ea5c91e66 (plain) (blame)
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
#pragma once

#include <linuxpe>

namespace pe {
	struct export_data_t {
		uintptr_t func_rva;
		std::string f_mod;
		std::string f_func;
	};

	struct image_t {
		uintptr_t base;
		std::unordered_map<std::string, export_data_t> exports;
		std::vector<win::section_header_t> sections;

		image_t() : base{ 0 } { }
		image_t(uintptr_t b) : base{ b } {
			auto image = reinterpret_cast<win::image_x64_t*>(b);

			auto nt = image->get_nt_headers();

			for (auto &sec : nt->sections()) {
				sections.emplace_back(sec);
			}

			auto export_dir = b + nt->optional_header.data_directories.export_directory.rva;
			auto export_size = nt->optional_header.data_directories.export_directory.size;

			auto exp = reinterpret_cast<win::export_directory_t*>(export_dir);

			if (exp->num_functions == 0) return;

			auto names = reinterpret_cast<uint32_t*>(b + exp->rva_names);
			auto funcs = reinterpret_cast<uint32_t*>(b + exp->rva_functions);
			auto ords = reinterpret_cast<uint16_t*>(b + exp->rva_name_ordinals);

			if (!names || !funcs || !ords) return;

			for (size_t i{}; i < exp->num_names; i++) {
				std::string name = reinterpret_cast<const char*>(b + names[i]);

				export_data_t ret;

				ret.func_rva = funcs[ords[i]];

				uintptr_t proc_addr = b + funcs[ords[i]];
				if (proc_addr > export_dir && proc_addr < export_dir + export_size) {
					std::string forwarded_name = reinterpret_cast<char*>(proc_addr);

					size_t delim = forwarded_name.find('.');
					if (delim == std::string::npos) continue;

					ret.f_mod = forwarded_name.substr(0, delim + 1);
					ret.f_mod.append("dll");

					std::transform(ret.f_mod.begin(), ret.f_mod.end(), ret.f_mod.begin(), ::tolower);

					ret.f_func = forwarded_name.substr(delim + 1);
				}


				exports[name] = ret;
			}
		}
	};

	struct import_data_t {
		std::string name;
		uintptr_t rva;
	};

	struct raw_image_t {
		win::nt_headers_x64_t* nt;

		std::unordered_map<std::string, std::vector<import_data_t>> imports;
		std::unordered_map<uintptr_t, std::vector<win::reloc_entry_t>> relocs;
		std::vector<win::section_header_t> sections;

		raw_image_t(std::vector<u8>& buffer) {
			auto image = reinterpret_cast<win::image_x64_t*>(buffer.data());

			nt = image->get_nt_headers();

			for (auto& sec : nt->sections()) {
				sections.emplace_back(sec);
			}

			auto import_rva = nt->optional_header.data_directories.import_directory.rva;

			auto desc = image->rva_to_ptr<win::import_directory_t>(import_rva);

			for (uint32_t i = 0; i < desc->rva_name; i = desc->rva_name, ++desc) {
				std::string mod = image->rva_to_ptr<char>(desc->rva_name);

				auto thunk = image->rva_to_ptr<win::image_thunk_data_x64_t>(desc->rva_original_first_thunk);

				for (uint32_t index = 0; thunk->address; index += sizeof(u64), ++thunk) {
					auto named_import = image->rva_to_ptr<win::image_named_import_t>(thunk->address);

					if (!thunk->is_ordinal) {
						std::transform(mod.begin(), mod.end(), mod.begin(), ::tolower);

						imports[mod].emplace_back(import_data_t{ reinterpret_cast<const char*>(named_import->name), desc->rva_first_thunk + index });
					}
				}
			}

			auto reloc_dir = image->rva_to_ptr<win::reloc_directory_t>(nt->optional_header.data_directories.basereloc_directory.rva);

			for (auto* block = &reloc_dir->first_block; block->base_rva; block = block->next()) {
				for (auto& entry : *block) {
					relocs[block->base_rva].emplace_back(entry);
				}
			}
		}
	};
};