diff --git a/efiXloader/efi_loader.cc b/efiXloader/efi_loader.cc index 1725e192..fb6e26d7 100644 --- a/efiXloader/efi_loader.cc +++ b/efiXloader/efi_loader.cc @@ -118,7 +118,8 @@ void idaapi load_file(linput_t *li, ushort neflag, const char *fileformatname) { msg("[efiXloader] machine type: %04x\n", uefiParser.machine_type); efiloader::PeManager peManager(uefiParser.machine_type); - add_til("uefi.til", ADDTIL_DEFAULT); + // add_til("uefi.til", ADDTIL_DEFAULT); + // we currently only handle 64-bit binaries with the EFI loader add_til("uefi64.til", ADDTIL_DEFAULT); msg("processing UEFI binaries:\n"); diff --git a/efiXloader/efi_loader.h b/efiXloader/efi_loader.h index 01caf3f3..854a8e9e 100644 --- a/efiXloader/efi_loader.h +++ b/efiXloader/efi_loader.h @@ -87,7 +87,7 @@ class driver_chooser_t : public chooser_t { void build_list(bool ok, std::vector files) { size_t n = 0; for (auto file : files) { - drivers_names.push_back(qstring(file->qname)); + drivers_names.push_back(qstring(file->module_name)); n++; } ok = true; diff --git a/efiXloader/uefitool.cc b/efiXloader/uefitool.cc index 63884280..25d4b593 100644 --- a/efiXloader/uefitool.cc +++ b/efiXloader/uefitool.cc @@ -20,7 +20,7 @@ #include "uefitool.h" void efiloader::File::print() { - msg("[UEFITOOL PARSER] file ( %s ) \n", qname.c_str()); + msg("[UEFITOOL PARSER] file ( %s ) \n", module_name.c_str()); for (int i = 0; i < 0x10; i++) { msg("%02X ", ubytes[i]); } @@ -34,7 +34,7 @@ void efiloader::Uefitool::show_messages() { } void efiloader::Uefitool::get_unique_name(qstring &name) { - // If the given name is already in use, create a new one + // if the given name is already in use, create a new one qstring new_name = name; std::string suf; int index = 0; @@ -50,8 +50,16 @@ void efiloader::Uefitool::get_image_guid(qstring &image_guid, UString guid; UModelIndex guid_index; switch (model.subtype(model.parent(index))) { - case EFI_SECTION_COMPRESSION: case EFI_SECTION_GUID_DEFINED: + if (model.type(model.parent(index)) == Types::File) { + guid_index = model.parent(index); + } else { + guid_index = model.parent(model.parent(index)); + } + if (model.subtype(guid_index) == EFI_SECTION_COMPRESSION) + guid_index = model.parent(guid_index); + break; + case EFI_SECTION_COMPRESSION: guid_index = model.parent(model.parent(index)); break; default: @@ -74,7 +82,7 @@ efiloader::Uefitool::parse_depex_section_body(const UModelIndex &index, UByteArray body = model.body(index); - // Check data to be present + // check data to be present if (body.size() < 2) { // 2 is a minimal sane value, i.e TRUE + END return res; } @@ -82,7 +90,7 @@ efiloader::Uefitool::parse_depex_section_body(const UModelIndex &index, const EFI_GUID *guid; const UINT8 *current = (const UINT8 *)body.constData(); - // Special cases of first opcode + // special cases of first opcode switch (*current) { case EFI_DEP_BEFORE: if (body.size() != 2 * EFI_DEP_OPCODE_SIZE + sizeof(EFI_GUID)) { @@ -115,7 +123,7 @@ efiloader::Uefitool::parse_depex_section_body(const UModelIndex &index, break; } - // Parse the rest of depex + // parse the rest of depex while (current - (const UINT8 *)body.constData() < body.size()) { switch (*current) { case EFI_DEP_BEFORE: { @@ -128,7 +136,7 @@ efiloader::Uefitool::parse_depex_section_body(const UModelIndex &index, return res; } case EFI_DEP_PUSH: - // Check that the rest of depex has correct size + // check that the rest of depex has correct size if ((UINT32)body.size() - (UINT32)(current - (const UINT8 *)body.constData()) <= EFI_DEP_OPCODE_SIZE + sizeof(EFI_GUID)) { @@ -137,7 +145,7 @@ efiloader::Uefitool::parse_depex_section_body(const UModelIndex &index, } guid = (const EFI_GUID *)(current + EFI_DEP_OPCODE_SIZE); parsed += UString("\nPUSH ") + guidToUString(readUnaligned(guid)); - // Add protocol GUID to result vector + // add protocol GUID to result vector res.push_back( reinterpret_cast(guidToUString(readUnaligned(guid)).data)); current += EFI_DEP_OPCODE_SIZE + sizeof(EFI_GUID); @@ -165,7 +173,7 @@ efiloader::Uefitool::parse_depex_section_body(const UModelIndex &index, case EFI_DEP_END: parsed += UString("\nEND"); current += EFI_DEP_OPCODE_SIZE; - // Check that END is the last opcode + // check that END is the last opcode if (current - (const UINT8 *)body.constData() < body.size()) { parsed.clear(); } @@ -181,7 +189,7 @@ efiloader::Uefitool::parse_depex_section_body(const UModelIndex &index, std::vector efiloader::Uefitool::parse_apriori_raw_section(const UModelIndex &index) { - // Adopted from FfsParser::parseDepexSectionBody + // adopted from FfsParser::parseDepexSectionBody std::vector res; if (!index.isValid()) @@ -189,7 +197,7 @@ efiloader::Uefitool::parse_apriori_raw_section(const UModelIndex &index) { UByteArray body = model.body(index); - // Sanity check + // sanity check if (body.size() % sizeof(EFI_GUID)) { return res; } @@ -217,7 +225,7 @@ void efiloader::Uefitool::set_machine_type(UByteArray pe_body) { } if (*(uint32_t *)(data + _pe_header_off) == 0x4550) { machine_type = *(uint16_t *)(data + _pe_header_off + 4); - machine_type_detected = true; + machine_type_initialised = true; } } @@ -238,10 +246,15 @@ void efiloader::Uefitool::handle_raw_section(const UModelIndex &index) { } } -void efiloader::Uefitool::dump(const UModelIndex &index, uint8_t el_type, +inline void get_module_name(qstring &module_name, efiloader::File *file) { + utf16_utf8(&module_name, + reinterpret_cast(file->uname.data())); +} + +void efiloader::Uefitool::dump(const UModelIndex &index, int i, efiloader::File *file) { - qstring module_name(""); - qstring guid(""); + qstring name; + qstring guid; switch (model.subtype(index)) { case EFI_SECTION_RAW: @@ -250,34 +263,19 @@ void efiloader::Uefitool::dump(const UModelIndex &index, uint8_t el_type, case EFI_SECTION_TE: file->is_te = true; file->ubytes = model.body(index); + file->module_kind = get_kind(index); break; case EFI_SECTION_PE32: file->is_pe = true; file->ubytes = model.body(index); - if (!machine_type_detected) { + file->module_kind = get_kind(index); + if (!machine_type_initialised) { set_machine_type(model.body(index)); } break; case EFI_SECTION_USER_INTERFACE: file->has_ui = true; - if (file->is_pe || file->is_te) { - file->uname = model.body(index); - utf16_utf8(&module_name, - reinterpret_cast(file->uname.data())); - if (module_name.size()) { - // save image to the images_guids - get_image_guid(guid, index); - if (images_guids[guid.c_str()] - .is_null()) { // check if GUID already exists - get_unique_name(module_name); - images_guids[guid.c_str()] = {{"name", module_name.c_str()}, - {"kind", get_kind(index)}}; - file->qname.swap(module_name); - file->write(); - files.push_back(file); - } - } - } + file->uname = model.body(index); break; case EFI_SECTION_COMPRESSION: case EFI_SECTION_GUID_DEFINED: @@ -285,7 +283,6 @@ void efiloader::Uefitool::dump(const UModelIndex &index, uint8_t el_type, dump(index.child(i, 0), i, file); } break; - // Get DEPEX information case EFI_SECTION_DXE_DEPEX: get_deps(index, "EFI_SECTION_DXE_DEPEX"); break; @@ -298,35 +295,43 @@ void efiloader::Uefitool::dump(const UModelIndex &index, uint8_t el_type, case EFI_SECTION_VERSION: break; default: - // if there is no UI section, then the image name is GUID - if ((file->is_pe || file->is_te) && !file->has_ui) { - get_image_guid(module_name, index); - file->qname.swap(module_name); - file->write(); - files.push_back(file); - if (module_name.size()) { - // save image to the images_guids - images_guids[module_name.c_str()] = {{"name", module_name.c_str()}, - {"kind", get_kind(index)}}; - } - } break; } - return dump(index); + // update file + if (file->is_pe || file->is_te) { + get_image_guid(guid, index); + if (file->has_ui) { + // get module name from UI section + get_module_name(name, file); + } else { + // use module GUID as module name + name = guid; + } + file->module_name.swap(name); + file->module_guid.swap(guid); + } + + dump(index); } void efiloader::Uefitool::dump(const UModelIndex &index) { USTATUS err; - msg("[UEFITOOL PARSER] file (%s, %s)\n", - itemTypeToUString(model.type(index)).data, - itemSubtypeToUString(model.type(index), model.subtype(index)).data); - msg("[UEFITOOL PARSER] number of items: %#x\n", model.rowCount(index)); + if (is_file_index(index)) { efiloader::File *file = new File; for (int i = 0; i < model.rowCount(index); i++) { dump(index.child(i, 0), i, file); } + + // append file + if (file->is_ok()) { + all_modules[file->module_guid.c_str()] = { + {"name", file->module_name.c_str()}, + {"kind", file->module_kind.c_str()}}; + file->write(); + files.push_back(file); + } } else { for (int i = 0; i < model.rowCount(index); i++) { dump(index.child(i, 0)); @@ -363,7 +368,6 @@ void efiloader::Uefitool::get_apriori(UModelIndex index, std::string key) { void efiloader::Uefitool::dump_jsons() { // dump JSON with DEPEX and GUIDs information for each image - std::filesystem::path out; out /= get_path(PATH_TYPE_IDB); out.replace_extension(".deps.json"); @@ -372,5 +376,5 @@ void efiloader::Uefitool::dump_jsons() { out.replace_extension("").replace_extension(".images.json"); std::ofstream out_guids(out); - out_guids << std::setw(2) << images_guids << std::endl; + out_guids << std::setw(2) << all_modules << std::endl; } diff --git a/efiXloader/uefitool.h b/efiXloader/uefitool.h index 825a895e..d30eaf3b 100644 --- a/efiXloader/uefitool.h +++ b/efiXloader/uefitool.h @@ -67,7 +67,7 @@ class File { public: File() {} void set_data(char *data_in, uint32_t size_in) { - qname.qclear(); + module_name.qclear(); bytes.resize(size_in); memcpy(&bytes[0], data_in, size_in); } @@ -79,8 +79,9 @@ class File { #else mkdir(images_path.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); #endif - if (!qname.empty()) { - qstring image_path = images_path + qstring("/") + qstring(qname.c_str()); + if (!module_name.empty()) { + qstring image_path = + images_path + qstring("/") + qstring(module_name.c_str()); std::ofstream file; file.open(image_path.c_str(), std::ios::out | std::ios::binary); file.write(ubytes.constData(), ubytes.size()); @@ -89,6 +90,10 @@ class File { } } void print(); + bool is_ok() { + return !module_name.empty() && !module_guid.empty() && !module_kind.empty(); + } + UByteArray ubytes; UByteArray uname; bytevec_t bytes; @@ -96,8 +101,10 @@ class File { uint32_t size = 0; std::string name_utf8; std::string name_utf16; - qstring qname; qstring dump_name; + qstring module_guid; + qstring module_kind; + qstring module_name; bool is_pe = false; bool is_te = false; bool has_ui = false; @@ -120,7 +127,7 @@ class Uefitool { bool messages_occurs() { return !messages.empty(); } void dump(); void dump(const UModelIndex &index); - void dump(const UModelIndex &index, uint8_t el_type, File *pe_file); + void dump(const UModelIndex &index, int i, File *pe_file); void handle_raw_section(const UModelIndex &index); bool is_pe_index(const UModelIndex &index) { return model.rowCount(index) == 4; @@ -136,24 +143,23 @@ class Uefitool { void get_deps(UModelIndex index, std::string key); void get_apriori(UModelIndex index, std::string key); void dump_jsons(); + void set_machine_type(UByteArray pe_body); - // DEPEX information for each image json all_deps; + json all_modules; + std::vector files; + std::set unique_names; - json images_guids; TreeModel model; const char *buffer; uint32_t buffer_size; std::vector> messages; - std::set unique_names; - std::vector files; USTATUS err; - void set_machine_type(UByteArray pe_body); uint16_t machine_type = 0xffff; - bool machine_type_detected = false; + bool machine_type_initialised = false; private: - std::string get_kind(const UModelIndex &index) { + qstring get_kind(const UModelIndex &index) { return fileTypeToUString(model.subtype(index.parent())).toLocal8Bit(); } };