Skip to content

Cross-platform library for parsing and building PE\PE+ formats

License

Notifications You must be signed in to change notification settings

jnastarot/enma_pe

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ENMA PE

Build status Build Status License

--------------------------------------------------------------------------------
Name....: enma pe
Author..: JNA
e.mail..: jnastarot@gmail.com
--------------------------------------------------------------------------------

Supported directories

directory name reading building getting placement
export ✔️ ✔️ ✔️
import ✔️ ✔️ ✔️
import bound ✔️ ✔️ ✔️
import delay ✔️ ✖️ ✔️
resources ✔️ ✔️ ✔️
exceptions ✔️ ✔️ ✔️
security ✔️ ✖️ ✔️
relocations ✔️ ✔️ ✔️
debug ✔️ ✖️ ✔️
tls ✔️ ✔️ ✔️
load config ✔️ ✔️ ✔️
.NET meta data ✔️ ✖️ ✖️

Additional features

feature name description
build_pe_image build pe_image to packed binary version
load_virtual_pe_image load image in pe_image format from loaded in memory
get_runtime_type_information parsing runtime type information(MSVC only)
get_extended_exception_info parsing of extended variables for x64 exceptions
build_extended_exceptions_info building of extended variables for x64 exceptions
get_strings_from_image extracting ascii and wide strings
get_image_rich_header getting and building rich data
get_section_entropy calculating entropy of section
calculate_checksum calculating checksum of pe image

Usage examples

Image/Section IO

IO using file offset (raw)

pe_image_io image_io(image, enma_io_addressing_type::enma_io_address_raw);
pe_section_io section_io(section, enma_io_addressing_type::enma_io_address_raw);

IO using relative virtual offset (rva)

pe_image_io image_io(image, enma_io_addressing_type::enma_io_address_rva);
pe_image_io section_io(section, enma_io_addressing_type::enma_io_address_rva);

IO using virtual address (va)

pe_image_io image_io(image, enma_io_addressing_type::enma_io_address_va);
pe_image_io section_io(section, enma_io_addressing_type::enma_io_address_va);

IO with size changing policy (allow incrase size)

pe_image_io image_io(image, enma_io_mode::enma_io_mode_allow_expand, enma_io_addressing_type::enma_io_address_rva);
pe_image_io section_io(image, enma_io_mode::enma_io_mode_allow_expand, enma_io_addressing_type::enma_io_address_rva);

IO with size changing policy (disallow incrase size)

pe_image_io image_io(image, enma_io_mode::enma_io_mode_default, enma_io_addressing_type::enma_io_address_rva);
pe_image_io section_io(section, enma_io_mode::enma_io_mode_default, enma_io_addressing_type::enma_io_address_rva);

Image read data

using namespace enma;

int main() {

    pe_image image(L"C:\\Windows\\System32\\kernel32.dll");
    
    pe_image_io image_io(image, enma_io_addressing_type::enma_io_address_raw);

    image_dos_header header;
    image.get_dos_header(header); 

    uint32_t magic;

    if (image_io.set_image_offset(header.e_lfanew).read(magic) == enma_io_code::enma_io_success) {

        if (magic == IMAGE_NT_SIGNATURE) {

            //...
        }
    }
    
    return 0;
}

Image write data

using namespace enma;

int main() {

    pe_image image(L"C:\\Windows\\System32\\kernel32.dll");
    
    pe_image_io image_io(image, enma_io_addressing_type::enma_io_address_rva);

    std::vector<uint8_t> bytes_of_entry{0xCC};
            
    if (image_io.set_image_offset(image.get_entry_point()).write(bytes_of_entry) == enma_io_code::enma_io_success) {

        //...
    }
    
    return 0;
}

Imports

using namespace enma;

int main() {

    pe_image image(L"C:\\Windows\\System32\\kernel32.dll");
    
    pe_bound_import_directory bound_imports;
    pe_import_directory imports;

    get_bound_import_directory(image, bound_imports);

    if (get_import_directory(image, imports, bound_imports) == pe_directory_code::pe_directory_code_success) {

        for (auto& imp_library : imports.get_libraries()) {

            cout << imp_library.get_library_name();

            if (bound_imports.has_library(imp_library.get_library_name())) {
                cout << "  BOUNDED: " << bound_imports.get_library(imp_library.get_library_name())->get_timestamp();
            }

            cout << endl;

            for (auto& imp_function : imp_library.get_functions()) {

                cout << "RVA: " << hex << imp_function.get_iat_rva();
                cout << " ORD: " << imp_function.get_ordinal();
                cout << " HINT: " << hex << imp_function.get_hint();

                if (imp_function.is_import_by_name()) {
                    cout << " NAME: " << imp_function.get_func_name();
                }

                cout << endl;
            }
        }
    }
    
    return 0;
}

Exports

using namespace enma;

int main() {

    pe_image image(L"C:\\Windows\\System32\\kernel32.dll");
    
    pe_export_directory exports;
    if (get_export_directory(image, exports) == pe_directory_code::pe_directory_code_success) {

        for (auto& func : exports.get_functions()) {

            cout << "RVA: " << hex << func.get_rva();
            cout << " NAME ORD: " << hex << func.get_name_ordinal();
            cout << " ORD: " << hex << func.get_ordinal();

            if (func.has_name()) {
                cout << " NAME: " << hex << func.get_func_name();
            }

            if (func.is_forward()) {
                cout << " FWD: " << hex << func.get_forward_name();
            }

            cout << endl;
        }
    }
    
    return 0;
}

Preview information

using namespace enma;

bool get_image_icon(pe_resource_directory& resources) {
  
    hl::pe_image_preview_icon preview(resources);

    hl::pe_image_icon_group icon_group;
    uint16_t language_id;

    if (!preview.get_default_icon_group(icon_group, language_id)) {

        return false;
    }

    std::vector<uint8_t> icon_buf;
    
    if (!icon_group.get_icon(resources, language_id, icon_buf)) {

        return false;
    }

    //icon_buf <- raw icon
}

bool get_image_version_info(pe_resource_directory& resources) {

    hl::pe_image_preview_version_info preview(resources);

    hl::pe_image_version_info version;
    uint16_t language_id;

    if (!preview.get_default_version(version, language_id)) {

        return false;
    }

    for (auto& translate : version.get_string_table()) {

        for (auto& kv : translate.second) {

            wcout << kv.first << L" : " << kv.second << endl;
        }
    }
}

int main() {

    pe_image image(L"C:\\Windows\\System32\\kernel32.dll");
    
    pe_resource_directory resources;
    if (get_resources_directory(image, resources) == 	  pe_directory_code::pe_directory_code_success) {

        get_image_icon(resources);
        get_image_version_info(resources);
    }
    
    return 0;
}

Image manifests

bool get_internal_app_assembly(const pe_image& image, std::list<std::string>& assemblies) {

    pe_resource_directory resources;

    if (get_resources_directory(image, resources) !=
        pe_directory_code_success) {

        return false;
    }

    auto& res_list = resources.get_entry_list();

    for (auto& lv1_res_entry : res_list) {

        if (lv1_res_entry.get_id() == hl::kResourceManifest) {

            auto& lv2_res_entry = lv1_res_entry.get_resource_directory();

            for (auto& lv2_res_entry : lv2_res_entry.get_entry_list()) {

                lv2_res_entry.get_id(); // <- this is lang id

                auto& lv3_res_entry = lv2_res_entry.get_resource_directory();

                for (auto& lv3_res_entry : lv3_res_entry.get_entry_list()) {

                    if (lv3_res_entry.is_includes_data()) {

                        auto& data_res_entry = lv3_res_entry.get_data_entry();

                        std::string assembly_a;

                        lv3_res_entry.get_id(); // <- this is resource id in third tree root

                        assembly_a.resize(data_res_entry.get_data().size());

                        memcpy((void*)assembly_a.data(),
                            data_res_entry.get_data().data(), assembly_a.size());

                        if ((uint8_t)assembly_a[0] == 0xEF &&
                            (uint8_t)assembly_a[1] == 0xBB &&
                            (uint8_t)assembly_a[2] == 0xBF) {

                            assembly_a.erase(assembly_a.begin(), assembly_a.begin() + 3);
                        }

                        data_res_entry.get_codepage(); // <- code page of resource


                        assemblies.push_back(assembly_a); //push text of manifest
                    }
                }
            }
        }
    }

    return true;
}

References

https://github.com/dishather/richprint/
https://github.com/radare/radare2
https://github.com/cmu-sei/pharos
https://github.com/JusticeRage/Manalyze
https://kaimi.io/2012/09/portable-executable-library/