aboutsummaryrefslogtreecommitdiff
path: root/drivers/pe_bliss/resource_message_list_reader.cpp
blob: ff9a5dd8610c6004ed0a59b870a1eb3eeac227b6 (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
#include "resource_message_list_reader.h"
#include "pe_resource_viewer.h"

namespace pe_bliss
{
using namespace pe_win;

resource_message_list_reader::resource_message_list_reader(const pe_resource_viewer& res)
	:res_(res)
{}

//Helper function of parsing message list table
const resource_message_list resource_message_list_reader::parse_message_list(const std::string& resource_data)
{
	resource_message_list ret;

	//Check resource data length
	if(resource_data.length() < sizeof(message_resource_data))
		throw pe_exception("Incorrect resource message table", pe_exception::resource_incorrect_message_table);

	const message_resource_data* message_data = reinterpret_cast<const message_resource_data*>(resource_data.data());

	//Check resource data length more carefully and some possible overflows
	if(message_data->NumberOfBlocks >= pe_utils::max_dword / sizeof(message_resource_block)
		|| !pe_utils::is_sum_safe(message_data->NumberOfBlocks * sizeof(message_resource_block), sizeof(message_resource_data))
		|| resource_data.length() < message_data->NumberOfBlocks * sizeof(message_resource_block) + sizeof(message_resource_data))
		throw pe_exception("Incorrect resource message table", pe_exception::resource_incorrect_message_table);

	//Iterate over all message resource blocks
	for(unsigned long i = 0; i != message_data->NumberOfBlocks; ++i)
	{
		//Get block
		const message_resource_block* block =
			reinterpret_cast<const message_resource_block*>(resource_data.data() + sizeof(message_resource_data) - sizeof(message_resource_block) + sizeof(message_resource_block) * i);

		//Check resource data length and IDs
		if(resource_data.length() < block->OffsetToEntries || block->LowId > block->HighId)
			throw pe_exception("Incorrect resource message table", pe_exception::resource_incorrect_message_table);

		unsigned long current_pos = 0;
		static const unsigned long size_of_entry_headers = 4;
		//List all message resource entries in block
		for(uint32_t curr_id = block->LowId; curr_id <= block->HighId; curr_id++)
		{
			//Check resource data length and some possible overflows
			if(!pe_utils::is_sum_safe(block->OffsetToEntries, current_pos)
				|| !pe_utils::is_sum_safe(block->OffsetToEntries + current_pos, size_of_entry_headers)
				|| resource_data.length() < block->OffsetToEntries + current_pos + size_of_entry_headers)
				throw pe_exception("Incorrect resource message table", pe_exception::resource_incorrect_message_table);

			//Get entry
			const message_resource_entry* entry = reinterpret_cast<const message_resource_entry*>(resource_data.data() + block->OffsetToEntries + current_pos);

			//Check resource data length and entry length and some possible overflows
			if(entry->Length < size_of_entry_headers
				|| !pe_utils::is_sum_safe(block->OffsetToEntries + current_pos, entry->Length)
				|| resource_data.length() < block->OffsetToEntries + current_pos + entry->Length
				|| entry->Length < size_of_entry_headers)
				throw pe_exception("Incorrect resource message table", pe_exception::resource_incorrect_message_table);

			if(entry->Flags & message_resource_unicode)
			{
				//If string is UNICODE
				//Check its length
				if(entry->Length % 2)
					throw pe_exception("Incorrect resource message table", pe_exception::resource_incorrect_message_table);

				//Add ID and string to message table
#ifdef PE_BLISS_WINDOWS
				ret.insert(std::make_pair(curr_id, message_table_item(
					std::wstring(reinterpret_cast<const wchar_t*>(resource_data.data() + block->OffsetToEntries + current_pos + size_of_entry_headers),
					(entry->Length - size_of_entry_headers) / 2)
					)));
#else
				ret.insert(std::make_pair(curr_id, message_table_item(
					pe_utils::from_ucs2(u16string(reinterpret_cast<const unicode16_t*>(resource_data.data() + block->OffsetToEntries + current_pos + size_of_entry_headers),
					(entry->Length - size_of_entry_headers) / 2))
					)));
#endif
			}
			else
			{
				//If string is ANSI
				//Add ID and string to message table
				ret.insert(std::make_pair(curr_id, message_table_item(
					std::string(resource_data.data() + block->OffsetToEntries + current_pos + size_of_entry_headers,
					entry->Length - size_of_entry_headers)
					)));
			}

			//Go to next entry
			current_pos += entry->Length;
		}
	}

	return ret;
}

//Returns message table data by ID and index in language directory (instead of language)
const resource_message_list resource_message_list_reader::get_message_table_by_id(uint32_t id, uint32_t index) const
{
	return parse_message_list(res_.get_resource_data_by_id(pe_resource_viewer::resource_message_table, id, index).get_data());
}

//Returns message table data by ID and language
const resource_message_list resource_message_list_reader::get_message_table_by_id_lang(uint32_t language, uint32_t id) const
{
	return parse_message_list(res_.get_resource_data_by_id(language, pe_resource_viewer::resource_message_table, id).get_data());
}
}