void rebase_image_base(pe_base& pe, const relocation_table_list& tables, uint64_t new_base)
{
    //Get current image base value
    typename PEClassType::BaseSize image_base;
    pe.get_image_base(image_base);

    //ImageBase difference
    typename PEClassType::BaseSize base_rel = static_cast<typename PEClassType::BaseSize>(static_cast<int64_t>(new_base) - image_base);

    //We need to fix addresses from relocation tables
    //Enumerate relocation tables
    for(relocation_table_list::const_iterator it = tables.begin(); it != tables.end(); ++it)
    {
        const relocation_table::relocation_list& relocs = (*it).get_relocations();

        uint32_t base_rva = (*it).get_rva();

        //Enumerate relocations
        for(relocation_table::relocation_list::const_iterator rel = relocs.begin(); rel != relocs.end(); ++rel)
        {
            //Skip ABSOLUTE entries
            if((*rel).get_type() == pe_win::image_rel_based_absolute)
                continue;

            //Recalculate value by RVA and rewrite it
            uint32_t current_rva = base_rva + (*rel).get_rva();
            typename PEClassType::BaseSize value = pe.section_data_from_rva<typename PEClassType::BaseSize>(current_rva, section_data_raw, true);
            value += base_rel;
            memcpy(pe.section_data_from_rva(current_rva, true), &value, sizeof(value));
        }
    }

    //Finally, save new image base
    pe.set_image_base_64(new_base);
}
Example #2
0
const bound_import_module_list get_bound_import_module_list(const pe_base& pe)
{
    //Returned bound import modules list
    bound_import_module_list ret;

    //If image has no bound imports
    if(!pe.has_bound_import())
        return ret;

    uint32_t bound_import_data_len =
        pe.section_data_length_from_rva(pe.get_directory_rva(image_directory_entry_bound_import), pe.get_directory_rva(image_directory_entry_bound_import), section_data_raw, true);

    if(bound_import_data_len < pe.get_directory_size(image_directory_entry_bound_import))
        throw pe_exception("Incorrect bound import directory", pe_exception::incorrect_bound_import_directory);

    const char* bound_import_data = pe.section_data_from_rva(pe.get_directory_rva(image_directory_entry_bound_import), section_data_raw, true);

    //Check read in "read_pe" function raw bound import data size
    if(bound_import_data_len < sizeof(image_bound_import_descriptor))
        throw pe_exception("Incorrect bound import directory", pe_exception::incorrect_bound_import_directory);

    //current bound_import_data_ in-string position
    unsigned long current_pos = 0;
    //first bound import descriptor
    //so, we're working with raw data here, no section helpers available
    const image_bound_import_descriptor* descriptor = reinterpret_cast<const image_bound_import_descriptor*>(&bound_import_data[current_pos]);

    //Enumerate until zero
    while(descriptor->OffsetModuleName)
    {
        //Check module name offset
        if(descriptor->OffsetModuleName >= bound_import_data_len)
            throw pe_exception("Incorrect bound import directory", pe_exception::incorrect_bound_import_directory);

        //Check module name for null-termination
        if(!pe_utils::is_null_terminated(&bound_import_data[descriptor->OffsetModuleName], bound_import_data_len - descriptor->OffsetModuleName))
            throw pe_exception("Incorrect bound import directory", pe_exception::incorrect_bound_import_directory);

        //Create bound import descriptor structure
        bound_import elem(&bound_import_data[descriptor->OffsetModuleName], descriptor->TimeDateStamp);

        //Check DWORDs
        if(descriptor->NumberOfModuleForwarderRefs >= pe_utils::max_dword / sizeof(image_bound_forwarder_ref)
                || !pe_utils::is_sum_safe(current_pos, 2 /* this descriptor and the next one */ * sizeof(image_bound_import_descriptor) + descriptor->NumberOfModuleForwarderRefs * sizeof(image_bound_forwarder_ref)))
            throw pe_exception("Incorrect bound import directory", pe_exception::incorrect_bound_import_directory);

        //Move after current descriptor
        current_pos += sizeof(image_bound_import_descriptor);

        //Enumerate referenced bound import descriptors
        for(unsigned long i = 0; i != descriptor->NumberOfModuleForwarderRefs; ++i)
        {
            //They're just after parent descriptor
            //Check size of structure
            if(current_pos + sizeof(image_bound_forwarder_ref) > bound_import_data_len)
                throw pe_exception("Incorrect bound import directory", pe_exception::incorrect_bound_import_directory);

            //Get IMAGE_BOUND_FORWARDER_REF pointer
            const image_bound_forwarder_ref* ref_descriptor = reinterpret_cast<const image_bound_forwarder_ref*>(&bound_import_data[current_pos]);

            //Check referenced module name
            if(ref_descriptor->OffsetModuleName >= bound_import_data_len)
                throw pe_exception("Incorrect bound import directory", pe_exception::incorrect_bound_import_directory);

            //And its null-termination
            if(!pe_utils::is_null_terminated(&bound_import_data[ref_descriptor->OffsetModuleName], bound_import_data_len - ref_descriptor->OffsetModuleName))
                throw pe_exception("Incorrect bound import directory", pe_exception::incorrect_bound_import_directory);

            //Add referenced module to current bound import structure
            elem.add_module_ref(bound_import_ref(&bound_import_data[ref_descriptor->OffsetModuleName], ref_descriptor->TimeDateStamp));

            //Move after referenced bound import descriptor
            current_pos += sizeof(image_bound_forwarder_ref);
        }

        //Check structure size
        if(current_pos + sizeof(image_bound_import_descriptor) > bound_import_data_len)
            throw pe_exception("Incorrect bound import directory", pe_exception::incorrect_bound_import_directory);

        //Move to next bound import descriptor
        descriptor = reinterpret_cast<const image_bound_import_descriptor*>(&bound_import_data[current_pos]);

        //Save created descriptor structure and references
        ret.push_back(elem);
    }

    //Return result
    return ret;
}
Example #3
0
//Returns array of exported functions and information about export (if info != 0)
const exported_functions_list get_exported_functions(const pe_base& pe, export_info* info)
{
	//Returned exported functions info array
	std::vector<exported_function> ret;

	if(pe.has_exports())
	{
		//Check the length in bytes of the section containing export directory
		if(pe.section_data_length_from_rva(pe.get_directory_rva(image_directory_entry_export),
			pe.get_directory_rva(image_directory_entry_export), section_data_virtual, true)
			< sizeof(image_export_directory))
			throw pe_exception("Incorrect export directory", pe_exception::incorrect_export_directory);

		image_export_directory exports = pe.section_data_from_rva<image_export_directory>(pe.get_directory_rva(image_directory_entry_export), section_data_virtual, true);

		unsigned long max_name_length;

		if(info)
		{
			//Save some export info data
			info->set_characteristics(exports.Characteristics);
			info->set_major_version(exports.MajorVersion);
			info->set_minor_version(exports.MinorVersion);

			//Get byte count that we have for dll name
			if((max_name_length = pe.section_data_length_from_rva(exports.Name, exports.Name, section_data_virtual, true)) < 2)
				throw pe_exception("Incorrect export directory", pe_exception::incorrect_export_directory);

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

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

			//Save the rest of export information data
			info->set_name(dll_name);
			info->set_number_of_functions(exports.NumberOfFunctions);
			info->set_number_of_names(exports.NumberOfNames);
			info->set_ordinal_base(exports.Base);
			info->set_rva_of_functions(exports.AddressOfFunctions);
			info->set_rva_of_names(exports.AddressOfNames);
			info->set_rva_of_name_ordinals(exports.AddressOfNameOrdinals);
			info->set_timestamp(exports.TimeDateStamp);
		}

		if(!exports.NumberOfFunctions)
			return ret;

		//Check IMAGE_EXPORT_DIRECTORY fields
		if(exports.NumberOfNames > exports.NumberOfFunctions)
			throw pe_exception("Incorrect export directory", pe_exception::incorrect_export_directory);

		//Check some export directory fields
		if((!exports.AddressOfNameOrdinals && exports.AddressOfNames) ||
			(exports.AddressOfNameOrdinals && !exports.AddressOfNames) ||
			!exports.AddressOfFunctions
			|| exports.NumberOfFunctions >= pe_utils::max_dword / sizeof(uint32_t)
			|| exports.NumberOfNames > pe_utils::max_dword / sizeof(uint32_t)
			|| !pe_utils::is_sum_safe(exports.AddressOfFunctions, exports.NumberOfFunctions * sizeof(uint32_t))
			|| !pe_utils::is_sum_safe(exports.AddressOfNames, exports.NumberOfNames * sizeof(uint32_t))
			|| !pe_utils::is_sum_safe(exports.AddressOfNameOrdinals, exports.NumberOfFunctions * sizeof(uint32_t))
			|| !pe_utils::is_sum_safe(pe.get_directory_rva(image_directory_entry_export), pe.get_directory_size(image_directory_entry_export)))
			throw pe_exception("Incorrect export directory", pe_exception::incorrect_export_directory);

		//Check if it is enough bytes to hold AddressOfFunctions table
		if(pe.section_data_length_from_rva(exports.AddressOfFunctions, exports.AddressOfFunctions, section_data_virtual, true)
			< exports.NumberOfFunctions * sizeof(uint32_t))
			throw pe_exception("Incorrect export directory", pe_exception::incorrect_export_directory);

		if(exports.AddressOfNames)
		{
			//Check if it is enough bytes to hold name and ordinal tables
			if(pe.section_data_length_from_rva(exports.AddressOfNameOrdinals, exports.AddressOfNameOrdinals, section_data_virtual, true)
				< exports.NumberOfNames * sizeof(uint16_t))
				throw pe_exception("Incorrect export directory", pe_exception::incorrect_export_directory);

			if(pe.section_data_length_from_rva(exports.AddressOfNames, exports.AddressOfNames, section_data_virtual, true)
				< exports.NumberOfNames * sizeof(uint32_t))
				throw pe_exception("Incorrect export directory", pe_exception::incorrect_export_directory);
		}
		
		for(uint32_t ordinal = 0; ordinal < exports.NumberOfFunctions; ordinal++)
		{
			//Get function address
			//Sum and multiplication are safe (checked above)
			uint32_t rva = pe.section_data_from_rva<uint32_t>(exports.AddressOfFunctions + ordinal * sizeof(uint32_t), section_data_virtual, true);

			//If we have a skip
			if(!rva)
				continue;

			exported_function func;
			func.set_rva(rva);

			if(!pe_utils::is_sum_safe(exports.Base, ordinal) || exports.Base + ordinal > pe_utils::max_word)
				throw pe_exception("Incorrect export directory", pe_exception::incorrect_export_directory);

			func.set_ordinal(static_cast<uint16_t>(ordinal + exports.Base));

			//Scan for function name ordinal
			for(uint32_t i = 0; i < exports.NumberOfNames; i++)
			{
				uint16_t ordinal2 = pe.section_data_from_rva<uint16_t>(exports.AddressOfNameOrdinals + i * sizeof(uint16_t), section_data_virtual, true);

				//If function has name (and name ordinal)
				if(ordinal == ordinal2)
				{
					//Get function name
					//Sum and multiplication are safe (checked above)
					uint32_t function_name_rva = pe.section_data_from_rva<uint32_t>(exports.AddressOfNames + i * sizeof(uint32_t), section_data_virtual, true);

					//Get byte count that we have for function name
					if((max_name_length = pe.section_data_length_from_rva(function_name_rva, function_name_rva, section_data_virtual, true)) < 2)
						throw pe_exception("Incorrect export directory", pe_exception::incorrect_export_directory);

					//Get function name pointer
					const char* func_name = pe.section_data_from_rva(function_name_rva, section_data_virtual, true);

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

					//Save function info
					func.set_name(func_name);
					func.set_name_ordinal(ordinal2);

					//If the function is just a redirect, save its name
					if(rva >= pe.get_directory_rva(image_directory_entry_export) + sizeof(image_directory_entry_export) &&
						rva < pe.get_directory_rva(image_directory_entry_export) + pe.get_directory_size(image_directory_entry_export))
					{
						if((max_name_length = pe.section_data_length_from_rva(rva, rva, section_data_virtual, true)) < 2)
							throw pe_exception("Incorrect export directory", pe_exception::incorrect_export_directory);

						//Get forwarded function name pointer
						const char* forwarded_func_name = pe.section_data_from_rva(rva, section_data_virtual, true);

						//Check for null-termination
						if(!pe_utils::is_null_terminated(forwarded_func_name, max_name_length))
							throw pe_exception("Incorrect export directory", pe_exception::incorrect_export_directory);

						//Set the name of forwarded function
						func.set_forwarded_name(forwarded_func_name);
					}

					break;
				}
			}

			//Add function info to output array
			ret.push_back(func);
		}
	}

	return ret;
}
//Rebuild PE image and write it to "out" ostream
//If strip_dos_header is true, DOS headers partially will be used for PE headers
//If change_size_of_headers == true, SizeOfHeaders will be recalculated automatically
//If save_bound_import == true, existing bound import directory will be saved correctly (because some compilers and bind.exe put it to PE headers)
void rebuild_pe(pe_base& pe, std::ostream& out, bool strip_dos_header, bool change_size_of_headers, bool save_bound_import)
{
    if(out.bad())
        throw pe_exception("Stream is bad", pe_exception::stream_is_bad);

    if(save_bound_import && pe.has_bound_import())
    {
        if(pe.section_data_length_from_rva(pe.get_directory_rva(image_directory_entry_bound_import), pe.get_directory_rva(image_directory_entry_bound_import), section_data_raw, true)
            < pe.get_directory_size(image_directory_entry_bound_import))
            throw pe_exception("Incorrect bound import directory", pe_exception::incorrect_bound_import_directory);
    }

    //Change ostream state
    out.exceptions(std::ios::goodbit);
    out.clear();
    
    uint32_t original_bound_import_rva = pe.has_bound_import() ? pe.get_directory_rva(image_directory_entry_bound_import) : 0;
    if(original_bound_import_rva && original_bound_import_rva > pe.get_size_of_headers())
    {
        //No need to do anything with bound import directory
        //if it is placed inside of any section, not headers
        original_bound_import_rva = 0;
        save_bound_import = false;
    }

    {
        image_dos_header dos_header;

        //Rebuild PE image headers
        rebuild_pe(pe, dos_header, strip_dos_header, change_size_of_headers, save_bound_import);

        //Write DOS header
        out.write(reinterpret_cast<const char*>(&dos_header), strip_dos_header ? 8 * sizeof(uint16_t) : sizeof(image_dos_header));
    }

    //If we have stub overlay, write it too
    {
        const std::string& stub = pe.get_stub_overlay();
        if(stub.size())
        {
            out.write(stub.data(), stub.size());
            size_t aligned_size = pe_utils::align_up(stub.size(), sizeof(uint32_t));
            //Align PE header, which is right after rich overlay
            while(aligned_size > stub.size())
            {
                out.put('\0');
                --aligned_size;
            }
        }
    }
    
    //Write NT headers
    out.write(static_cast<const pe_base&>(pe).get_nt_headers_ptr(), pe.get_sizeof_nt_header()
        - sizeof(image_data_directory) * (image_numberof_directory_entries - pe.get_number_of_rvas_and_sizes()));

    //Write section headers
    const section_list& sections = pe.get_image_sections();
    for(section_list::const_iterator it = sections.begin(); it != sections.end(); ++it)
    {
        out.write(reinterpret_cast<const char*>(&(*it).get_raw_header()), sizeof(image_section_header));
    }

    //Write bound import data if requested
    if(save_bound_import && pe.has_bound_import())
    {
        out.write(pe.section_data_from_rva(original_bound_import_rva, section_data_raw, true),
            pe.get_directory_size(image_directory_entry_bound_import));
    }

    //Write section data finally
    for(section_list::const_iterator it = sections.begin(); it != sections.end(); ++it)
    {
        const section& s = *it;

        std::streamoff wpos = out.tellp();

        //Fill unused overlay data between sections with null bytes
        for(unsigned int i = 0; i < s.get_pointer_to_raw_data() - wpos; i++)
            out.put(0);

        //Write raw section data
        out.write(s.get_raw_data().data(), s.get_size_of_raw_data());
    }
}
//Processes resource directory
const resource_directory process_resource_directory(const pe_base& pe, uint32_t res_rva, uint32_t offset_to_directory, std::set<uint32_t>& processed)
{
    resource_directory ret;
    
    //Check for resource loops
    if(!processed.insert(offset_to_directory).second)
        throw pe_exception("Incorrect resource directory", pe_exception::incorrect_resource_directory);

    if(!pe_utils::is_sum_safe(res_rva, offset_to_directory))
        throw pe_exception("Incorrect resource directory", pe_exception::incorrect_resource_directory);

    //Get root IMAGE_RESOURCE_DIRECTORY
    image_resource_directory directory = pe.section_data_from_rva<image_resource_directory>(res_rva + offset_to_directory, section_data_virtual, true);

    ret = resource_directory(directory);

    //Check DWORDs for possible overflows
    if(!pe_utils::is_sum_safe(directory.NumberOfIdEntries, directory.NumberOfNamedEntries)
        || directory.NumberOfIdEntries + directory.NumberOfNamedEntries >= pe_utils::max_dword / sizeof(image_resource_directory_entry) + sizeof(image_resource_directory))
        throw pe_exception("Incorrect resource directory", pe_exception::incorrect_resource_directory);

    if(!pe_utils::is_sum_safe(offset_to_directory, sizeof(image_resource_directory) + (directory.NumberOfIdEntries + directory.NumberOfNamedEntries) * sizeof(image_resource_directory_entry))
        || !pe_utils::is_sum_safe(res_rva, offset_to_directory + sizeof(image_resource_directory) + (directory.NumberOfIdEntries + directory.NumberOfNamedEntries) * sizeof(image_resource_directory_entry)))
        throw pe_exception("Incorrect resource directory", pe_exception::incorrect_resource_directory);

    for(uint32_t i = 0; i != static_cast<uint32_t>(directory.NumberOfIdEntries) + directory.NumberOfNamedEntries; ++i)
    {
        //Read directory entries one by one
        image_resource_directory_entry dir_entry = pe.section_data_from_rva<image_resource_directory_entry>(
            res_rva + sizeof(image_resource_directory) + i * sizeof(image_resource_directory_entry) + offset_to_directory, section_data_virtual, true);

        //Create directory entry structure
        resource_directory_entry entry;

        //If directory is named
        const auto& nameEntry = dir_entry.NameItem.NameEntry;
        if(nameEntry.NameIsString)
        {
            if(!pe_utils::is_sum_safe(res_rva + sizeof(uint16_t) /* safe */, nameEntry.NameOffset))
                throw pe_exception("Incorrect resource directory", pe_exception::incorrect_resource_directory);

            //get directory name length
            uint16_t directory_name_length = pe.section_data_from_rva<uint16_t>(res_rva + nameEntry.NameOffset, section_data_virtual, true);

            //Check name length
            if(pe.section_data_length_from_rva(res_rva + nameEntry.NameOffset + sizeof(uint16_t), res_rva + nameEntry.NameOffset + sizeof(uint16_t), section_data_virtual, true)
                < directory_name_length)
                throw pe_exception("Incorrect resource directory", pe_exception::incorrect_resource_directory);

#ifdef PE_BLISS_WINDOWS
            //Set entry UNICODE name
            entry.set_name(std::wstring(
                reinterpret_cast<const wchar_t*>(pe.section_data_from_rva(res_rva + dir_entry.NameEntry.NameOffset + sizeof(uint16_t), section_data_virtual, true)),
                directory_name_length));
#else
            //Set entry UNICODE name
            entry.set_name(pe_utils::from_ucs2(u16string(
                reinterpret_cast<const unicode16_t*>(pe.section_data_from_rva(res_rva + nameEntry.NameOffset + sizeof(uint16_t), section_data_virtual, true)),
                directory_name_length)));
#endif
        }
        else
        {
            //Else - set directory ID
            entry.set_id(dir_entry.NameItem.Id);
        }

        //If directory entry has another resource directory
        const auto& dirEntry = dir_entry.DirItem.DirEntry;
        if(dirEntry.DataIsDirectory)
        {
            entry.add_resource_directory(process_resource_directory(pe, res_rva, dirEntry.OffsetToDirectory, processed));
        }
        else
        {
            //If directory entry has data
            image_resource_data_entry data_entry = pe.section_data_from_rva<image_resource_data_entry>(
                res_rva + dir_entry.DirItem.OffsetToData, section_data_virtual, true);

            //Check byte count that stated by data entry
            if(pe.section_data_length_from_rva(data_entry.OffsetToData, data_entry.OffsetToData, section_data_virtual, true) < data_entry.Size)
                throw pe_exception("Incorrect resource directory", pe_exception::incorrect_resource_directory);

            //Add data entry to directory entry
            entry.add_data_entry(resource_data_entry(
                std::string(pe.section_data_from_rva(data_entry.OffsetToData, section_data_virtual, true), data_entry.Size),
                data_entry.CodePage));
        }

        //Save directory entry
        ret.add_resource_directory_entry(entry);
    }

    //Return resource directory
    return ret;
}