/*************************************************************************/ /* 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 "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(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(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(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(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(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()); } }