//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());
    }
}
Esempio n. 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;
}
//Rebuilds PE image headers
//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, image_dos_header& dos_header, bool strip_dos_header, bool change_size_of_headers, bool save_bound_import)
{
    dos_header = pe.get_dos_header();

    if(strip_dos_header)
    {
        //Strip stub overlay
        pe.strip_stub_overlay();
        //BaseOfCode NT Headers field now overlaps
        //e_lfanew field, so we're acrually setting
        //e_lfanew with this call
        pe.set_base_of_code(8 * sizeof(uint16_t));
    }
    else
    {
        //Set start of PE headers
        dos_header.e_lfanew = sizeof(image_dos_header)
            + pe_utils::align_up(static_cast<uint32_t>(pe.get_stub_overlay().size()), sizeof(uint32_t));
    }

    section_list& sections = pe.get_image_sections();

    //Calculate pointer to section data
    size_t ptr_to_section_data = (strip_dos_header ? 8 * sizeof(uint16_t) : sizeof(image_dos_header)) + pe.get_sizeof_nt_header()
        + pe_utils::align_up(pe.get_stub_overlay().size(), sizeof(uint32_t))
        - sizeof(image_data_directory) * (image_numberof_directory_entries - pe.get_number_of_rvas_and_sizes())
        + sections.size() * sizeof(image_section_header);

    if(save_bound_import && pe.has_bound_import())
    {
        //It will be aligned to DWORD, because we're aligning to DWORD everything above it
        pe.set_directory_rva(image_directory_entry_bound_import, static_cast<uint32_t>(ptr_to_section_data));
        ptr_to_section_data += pe.get_directory_size(image_directory_entry_bound_import);    
    }
    
    ptr_to_section_data = pe_utils::align_up(ptr_to_section_data, pe.get_file_alignment());

    //Set size of headers and size of optional header
    if(change_size_of_headers)
    {
        if(!pe.get_image_sections().empty())
        {
            if(static_cast<uint32_t>(ptr_to_section_data) > (*sections.begin()).get_virtual_address())
                throw pe_exception("Headers of PE file are too long. Try to strip STUB or don't build bound import", pe_exception::cannot_rebuild_image);
        }

        pe.set_size_of_headers(static_cast<uint32_t>(ptr_to_section_data));
    }

    //Set number of sections in PE header
    pe.update_number_of_sections();

    pe.update_image_size();

    pe.set_size_of_optional_header(static_cast<uint16_t>(pe.get_sizeof_opt_headers()
        - sizeof(image_data_directory) * (image_numberof_directory_entries - pe.get_number_of_rvas_and_sizes())));

    //Recalculate pointer to raw data according to section list
    for(section_list::iterator it = sections.begin(); it != sections.end(); ++it)
    {
        //Save section headers PointerToRawData
        if((*it).get_size_of_raw_data())
        {
            (*it).set_pointer_to_raw_data(static_cast<uint32_t>(ptr_to_section_data));
            ptr_to_section_data += (*it).get_aligned_raw_size(pe.get_file_alignment());
        }
    }
}