From c5eb06fb3fd43b978a3f2e5c51afb63055e91cfb Mon Sep 17 00:00:00 2001 From: yeggor Date: Wed, 14 Aug 2024 17:32:26 +0100 Subject: [PATCH 01/69] initial compatibility with idasdk90 --- efiXloader/CMakeLists.txt | 11 ++++++++--- efiXloader/efiLoader.cpp | 2 ++ 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/efiXloader/CMakeLists.txt b/efiXloader/CMakeLists.txt index 4a192912..4a4777ec 100644 --- a/efiXloader/CMakeLists.txt +++ b/efiXloader/CMakeLists.txt @@ -8,10 +8,15 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON) if(APPLE) # to build Mach-O universal binaries with 2 architectures - set(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} "-fPIC -arch x86_64 -arch arm64") - set(CMAKE_C_FLAGS ${CMAKE_C_FLAGS} "-fPIC -arch x86_64 -arch arm64") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC -arch x86_64 -arch arm64") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC -arch x86_64 -arch arm64") else() - set(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} "-fPIC") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC") +endif() + +if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") + set(CMAKE_CXX_FLAGS + "${CMAKE_CXX_FLAGS} -Wno-nullability-completeness -Wno-varargs") endif() list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/../cmake) diff --git a/efiXloader/efiLoader.cpp b/efiXloader/efiLoader.cpp index 68f0d001..b68966ce 100644 --- a/efiXloader/efiLoader.cpp +++ b/efiXloader/efiLoader.cpp @@ -123,10 +123,12 @@ void idaapi load_file(linput_t *li, ushort neflag, const char *fileformatname) { } else { msg("[efiXloader] loaded IDA types\n"); } +#if IDA_SDK_VERSION < 900 tid_t struct_err = import_type(idati, -1, "EFI_GUID"); if (struct_err == BADNODE) { loader_failure("failed to import \"EFI_GUID\""); } +#endif msg("processing UEFI binaries:\n"); if (uefiParser.files.size()) { for (int i = 0; i < uefiParser.files.size(); i++) { From 07bd015fe101564241a6b73ba49de69e5b2358cb Mon Sep 17 00:00:00 2001 From: yeggor Date: Wed, 14 Aug 2024 17:33:33 +0100 Subject: [PATCH 02/69] initial compatibility with idasdk90 for efixplorer --- efiXplorer/CMakeLists.txt | 9 +++++-- efiXplorer/efiAnalyzer.h | 5 +++- efiXplorer/efiHexRays.cpp | 4 +++ efiXplorer/efiHexRays.h | 4 +++ efiXplorer/efiUtils.cpp | 52 ++++++++++++++++++--------------------- efiXplorer/efiUtils.h | 5 ++-- 6 files changed, 45 insertions(+), 34 deletions(-) diff --git a/efiXplorer/CMakeLists.txt b/efiXplorer/CMakeLists.txt index 88a33806..3f61d6c6 100644 --- a/efiXplorer/CMakeLists.txt +++ b/efiXplorer/CMakeLists.txt @@ -8,9 +8,14 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON) if(APPLE) # to build Mach-O universal binaries with 2 architectures - set(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} "-fPIC -arch x86_64 -arch arm64") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC -arch x86_64 -arch arm64") else() - set(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} "-fPIC") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC") +endif() + +if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") + set(CMAKE_CXX_FLAGS + "${CMAKE_CXX_FLAGS} -Wno-nullability-completeness -Wno-varargs") endif() if(BATCH) diff --git a/efiXplorer/efiAnalyzer.h b/efiXplorer/efiAnalyzer.h index 3f31d522..ea3f8506 100644 --- a/efiXplorer/efiAnalyzer.h +++ b/efiXplorer/efiAnalyzer.h @@ -234,6 +234,7 @@ class EfiAnalyzer { class EfiAnalyzerX86 : public EfiAnalyzer { public: EfiAnalyzerX86() : EfiAnalyzer() { +#if IDA_SDK_VERSION < 900 // import necessary types const til_t *idati = get_idati(); import_type(idati, -1, "EFI_GUID"); @@ -245,7 +246,7 @@ class EfiAnalyzerX86 : public EfiAnalyzer { import_type(idati, -1, "EFI_PEI_SERVICES"); import_type(idati, -1, "EFI_PEI_READ_ONLY_VARIABLE2_PPI"); import_type(idati, -1, "EFI_SMM_VARIABLE_PROTOCOL"); - +#endif #ifdef HEX_RAYS for (auto idx = 0; idx < get_entry_qty(); idx++) { uval_t ord = get_entry_ordinal(idx); @@ -289,12 +290,14 @@ class EfiAnalyzerArm : public EfiAnalyzer { // uefi.til, uefi64.til files in {idadir}/til/arm/ add_til("uefi64.til", ADDTIL_DEFAULT); +#if IDA_SDK_VERSION < 900 const til_t *idati = get_idati(); import_type(idati, -1, "EFI_GUID"); import_type(idati, -1, "EFI_HANDLE"); import_type(idati, -1, "EFI_SYSTEM_TABLE"); import_type(idati, -1, "EFI_BOOT_SERVICES"); import_type(idati, -1, "EFI_RUNTIME_SERVICES"); +#endif } void fixOffsets(); void initialAnalysis(); diff --git a/efiXplorer/efiHexRays.cpp b/efiXplorer/efiHexRays.cpp index 82afaaf6..f5668a39 100644 --- a/efiXplorer/efiHexRays.cpp +++ b/efiXplorer/efiHexRays.cpp @@ -63,9 +63,11 @@ bool setHexRaysVariableInfoAndHandleInterfaces(ea_t funcEa, lvar_t &ll, tinfo_t // Set lvar name if (ll.is_stk_var()) { // Rename local variable on stack +#if IDA_SDK_VERSION < 900 sval_t stkoff = ll.get_stkoff(); struc_t *frame = get_frame(funcEa); set_member_name(frame, stkoff, name.c_str()); +#endif // TODO: add support for idasdk90 } else { // Modufy user lvar info lsi.name = static_cast(name.c_str()); modify_user_lvar_info(funcEa, MLI_NAME, lsi); @@ -106,9 +108,11 @@ bool setHexRaysVariableInfo(ea_t funcEa, lvar_t &ll, tinfo_t tif, std::string na // Set lvar name if (ll.is_stk_var()) { // Rename local variable on stack +#if IDA_SDK_VERSION < 900 sval_t stkoff = ll.get_stkoff(); struc_t *frame = get_frame(funcEa); set_member_name(frame, stkoff, name.c_str()); +#endif // TODO: add support for idasdk90 } else { // Modufy user lvar info lsi.name = static_cast(name.c_str()); modify_user_lvar_info(funcEa, MLI_NAME, lsi); diff --git a/efiXplorer/efiHexRays.h b/efiXplorer/efiHexRays.h index 191dc6f8..39a04640 100644 --- a/efiXplorer/efiHexRays.h +++ b/efiXplorer/efiHexRays.h @@ -71,8 +71,10 @@ class ServiceDescriptor { // Ensure we can look up the type that this instance describes bool InitType(const char *name) { +#if IDA_SDK_VERSION < 900 // Import type import_type(get_idati(), -1, name); +#endif // Get type by name if (!mType.get_named_type(get_idati(), name, BTF_STRUCT)) @@ -516,7 +518,9 @@ class GUIDRetyper : public GUIDRelatedVisitorBase { // Need to get the type for the interface variable here tinfo_t tif; +#if IDA_SDK_VERSION < 900 import_type(get_idati(), -1, interfaceTypeName.c_str()); +#endif if (!tif.get_named_type(get_idati(), interfaceTypeName.c_str())) { // Get the referent for the interface argument. cexpr_t *outArgReferent = GetReferent(mOutArg, "ptr", true); diff --git a/efiXplorer/efiUtils.cpp b/efiXplorer/efiUtils.cpp index 8449b28e..fd9e6798 100644 --- a/efiXplorer/efiUtils.cpp +++ b/efiXplorer/efiUtils.cpp @@ -55,24 +55,6 @@ extern size_t variable_ppi_table_size; static const char plugin_name[] = "efiXplorer"; -//-------------------------------------------------------------------------- -// Create EFI_GUID structure -void createGuidStructure(ea_t ea) { - static const char struct_name[] = "_EFI_GUID"; - struc_t *sptr = get_struc(get_struc_id(struct_name)); - if (sptr == nullptr) { - sptr = get_struc(add_struc(-1, struct_name)); - if (sptr == nullptr) - return; - add_struc_member(sptr, "data1", -1, dword_flag(), NULL, 4); - add_struc_member(sptr, "data2", -1, word_flag(), NULL, 2); - add_struc_member(sptr, "data3", -1, word_flag(), NULL, 2); - add_struc_member(sptr, "data4", -1, byte_flag(), NULL, 8); - } - asize_t size = get_struc_size(sptr); - create_struct(ea, size, sptr->id); -} - //-------------------------------------------------------------------------- // Set EFI_GUID type void setGuidType(ea_t ea) { @@ -114,7 +96,7 @@ std::string getFileFormatName() { // Get input file type (64-bit, 32-bit image or UEFI firmware) uint8_t getInputFileType() { processor_t &ph = PH; - auto filetype = (filetype_t)inf.filetype; + auto filetype = inf_get_filetype(); auto bits = inf_is_64bit() ? 64 : inf_is_32bit_exactly() ? 32 : 16; // check if input file is UEFI firmware image @@ -333,8 +315,8 @@ std::vector getXrefsToArray(ea_t addr) { bool opStroff(ea_t addr, std::string type) { insn_t insn; decode_insn(&insn, addr); - tid_t struc_id = get_struc_id(type.c_str()); - return op_stroff(insn, 0, &struc_id, 1, 0); + tid_t tid = get_named_type_tid(type.c_str()); + return op_stroff(insn, 0, &tid, 1, 0); } //-------------------------------------------------------------------------- @@ -511,6 +493,7 @@ bool setRetToPeiSvc(ea_t start_ea) { //-------------------------------------------------------------------------- // Add EFI_PEI_SERVICES_4 structure bool addStrucForShiftedPtr() { +#if IDA_SDK_VERSION < 900 auto sid = add_struc(BADADDR, "EFI_PEI_SERVICES_4"); if (sid == BADADDR) { return false; @@ -541,6 +524,10 @@ bool addStrucForShiftedPtr() { set_member_tinfo(new_struct, member, 0, ptr2Tinfo, 0); return true; +#endif + + // use parse_decls() instead + return false; } //-------------------------------------------------------------------------- @@ -648,7 +635,11 @@ std::vector searchProtocol(std::string protocol) { std::copy(guid_bytes.begin(), guid_bytes.end(), bytes); ea_t start = 0; while (true) { +#if IDA_SDK_VERSION < 900 ea_t addr = bin_search2(start, BADADDR, bytes, nullptr, 16, BIN_SEARCH_FORWARD); +#else + ea_t addr = bin_search3(start, BADADDR, bytes, nullptr, 16, BIN_SEARCH_FORWARD); +#endif if (addr == BADADDR) { break; } @@ -830,23 +821,24 @@ std::string typeToName(std::string type) { } xreflist_t xrefsToStackVar(ea_t funcEa, qstring varName) { + xreflist_t xrefs_list; + +#if IDA_SDK_VERSION < 900 struc_t *frame = get_frame(funcEa); func_t *func = get_func(funcEa); member_t member; // Get member by name - bool found = false; for (int i = 0; i < frame->memqty; i++) { member = frame->members[i]; qstring name; get_member_name(&name, frame->members[i].id); if (name == varName) { - found = true; - break; + build_stkvar_xrefs(&xrefs_list, func, &member); + return xrefs_list; } } - xreflist_t xrefs_list; // Get xrefs - if (found) { - build_stkvar_xrefs(&xrefs_list, func, &member); - } +#endif + + // TODO: rewrite for idasdk90 return xrefs_list; } @@ -944,7 +936,11 @@ std::vector findData(ea_t start_ea, ea_t end_ea, uchar *data, size_t len) ea_t start = start_ea; int counter = 0; while (true) { +#if IDA_SDK_VERSION < 900 auto ea = bin_search2(start, end_ea, data, nullptr, len, BIN_SEARCH_FORWARD); +#else + auto ea = bin_search3(start, end_ea, data, nullptr, len, BIN_SEARCH_FORWARD); +#endif if (ea == BADADDR) { break; } diff --git a/efiXplorer/efiUtils.h b/efiXplorer/efiUtils.h index b7543456..8cc66858 100644 --- a/efiXplorer/efiUtils.h +++ b/efiXplorer/efiUtils.h @@ -44,7 +44,9 @@ #include #include #include +#if IDA_SDK_VERSION < 900 #include +#endif #include #ifdef HEX_RAYS @@ -191,9 +193,6 @@ std::vector getXrefsToArray(ea_t addr); // Wrapper for op_stroff function bool opStroff(ea_t addr, std::string type); -// Create EFI_GUID structure -void createGuidStructure(ea_t ea); - // Get boot service description comment std::string getBsComment(uint32_t offset, uint8_t arch); From 817e863130ec74b56c3a106a46b26efcbd2c3b4a Mon Sep 17 00:00:00 2001 From: yeggor Date: Thu, 15 Aug 2024 04:21:30 +0100 Subject: [PATCH 03/69] fix op_stroff wrapper + minor fixes in build script and cmake files --- build.py | 11 +---------- efiXloader/CMakeLists.txt | 2 +- efiXplorer/CMakeLists.txt | 8 +------- efiXplorer/efiHexRays.cpp | 18 +++++++++--------- efiXplorer/efiHexRays.h | 18 +++++++++--------- efiXplorer/efiUtils.cpp | 24 +++++++++++++++++------- 6 files changed, 38 insertions(+), 43 deletions(-) diff --git a/build.py b/build.py index 41fc2ff2..b6ca7207 100755 --- a/build.py +++ b/build.py @@ -12,13 +12,6 @@ def cli(): @click.command() -@click.option( - "--batch", - "batch", - type=bool, - default=False, - help="set to True if the plugin will be used in batch mode", -) @click.option( "--hexrays_sdk", "hexrays_sdk", @@ -27,7 +20,7 @@ def cli(): help="path to hexrays_sdk directory", ) @click.argument("idasdk") -def build_plugin(idasdk: str, hexrays_sdk: str, batch: bool): +def build_plugin(idasdk: str, hexrays_sdk: str): """Build efiXplorer plugin""" os.chdir("efiXplorer") @@ -38,8 +31,6 @@ def build_plugin(idasdk: str, hexrays_sdk: str, batch: bool): os.chdir("build") command = ["cmake", "..", f"-DIdaSdk_ROOT_DIR={idasdk}"] - if batch: - command.append("-DBATCH=1") if hexrays_sdk: print("[INFO] HexRays analysis will be enabled") command.append(f"-DHexRaysSdk_ROOT_DIR={hexrays_sdk}") diff --git a/efiXloader/CMakeLists.txt b/efiXloader/CMakeLists.txt index 4a4777ec..1859f415 100644 --- a/efiXloader/CMakeLists.txt +++ b/efiXloader/CMakeLists.txt @@ -14,7 +14,7 @@ else() set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC") endif() -if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") +if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-nullability-completeness -Wno-varargs") endif() diff --git a/efiXplorer/CMakeLists.txt b/efiXplorer/CMakeLists.txt index 3f61d6c6..fecf7088 100644 --- a/efiXplorer/CMakeLists.txt +++ b/efiXplorer/CMakeLists.txt @@ -13,17 +13,11 @@ else() set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC") endif() -if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") +if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-nullability-completeness -Wno-varargs") endif() -if(BATCH) - add_definitions(-DBATCH=1) - set(BATCH 1) - message(STATUS "efiXplorer plugin version for idat/idat64 binaries") -endif() - list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/../cmake) find_package(IdaSdk REQUIRED) diff --git a/efiXplorer/efiHexRays.cpp b/efiXplorer/efiHexRays.cpp index f5668a39..de6fb8a3 100644 --- a/efiXplorer/efiHexRays.cpp +++ b/efiXplorer/efiHexRays.cpp @@ -54,27 +54,27 @@ bool offsetOf(tinfo_t tif, const char *name, unsigned int *offset) { } // Utility function to set a Hex-Rays variable type and set types for the interfaces -bool setHexRaysVariableInfoAndHandleInterfaces(ea_t funcEa, lvar_t &ll, tinfo_t tif, +bool setHexRaysVariableInfoAndHandleInterfaces(ea_t func_addr, lvar_t &ll, tinfo_t tif, std::string name) { lvar_saved_info_t lsi; lsi.ll = ll; lsi.type = tif; - modify_user_lvar_info(funcEa, MLI_TYPE, lsi); + modify_user_lvar_info(func_addr, MLI_TYPE, lsi); // Set lvar name if (ll.is_stk_var()) { // Rename local variable on stack #if IDA_SDK_VERSION < 900 sval_t stkoff = ll.get_stkoff(); - struc_t *frame = get_frame(funcEa); + struc_t *frame = get_frame(func_addr); set_member_name(frame, stkoff, name.c_str()); #endif // TODO: add support for idasdk90 } else { // Modufy user lvar info lsi.name = static_cast(name.c_str()); - modify_user_lvar_info(funcEa, MLI_NAME, lsi); + modify_user_lvar_info(func_addr, MLI_NAME, lsi); } // Get xrefs to local variable - xreflist_t xrefs = xrefsToStackVar(funcEa, static_cast(name.c_str())); + xreflist_t xrefs = xrefsToStackVar(func_addr, static_cast(name.c_str())); qstring typeName; ptr_type_data_t pi; tif.get_ptr_details(&pi); @@ -100,22 +100,22 @@ bool setLvarName(qstring name, lvar_t lvar, ea_t func_addr) { } // Utility function to set a Hex-Rays variable type and name -bool setHexRaysVariableInfo(ea_t funcEa, lvar_t &ll, tinfo_t tif, std::string name) { +bool setHexRaysVariableInfo(ea_t func_addr, lvar_t &ll, tinfo_t tif, std::string name) { lvar_saved_info_t lsi; lsi.ll = ll; lsi.type = tif; - modify_user_lvar_info(funcEa, MLI_TYPE, lsi); + modify_user_lvar_info(func_addr, MLI_TYPE, lsi); // Set lvar name if (ll.is_stk_var()) { // Rename local variable on stack #if IDA_SDK_VERSION < 900 sval_t stkoff = ll.get_stkoff(); - struc_t *frame = get_frame(funcEa); + struc_t *frame = get_frame(func_addr); set_member_name(frame, stkoff, name.c_str()); #endif // TODO: add support for idasdk90 } else { // Modufy user lvar info lsi.name = static_cast(name.c_str()); - modify_user_lvar_info(funcEa, MLI_NAME, lsi); + modify_user_lvar_info(func_addr, MLI_NAME, lsi); } return true; diff --git a/efiXplorer/efiHexRays.h b/efiXplorer/efiHexRays.h index 39a04640..bc77e6db 100644 --- a/efiXplorer/efiHexRays.h +++ b/efiXplorer/efiHexRays.h @@ -77,7 +77,7 @@ class ServiceDescriptor { #endif // Get type by name - if (!mType.get_named_type(get_idati(), name, BTF_STRUCT)) + if (!mType.get_named_type(get_idati(), name)) return false; // Save ordinal and name @@ -107,7 +107,7 @@ class ServiceDescriptor { public: // Constructor does nothing - ServiceDescriptor() : mOrdinal(0), bInitialized(false){}; + ServiceDescriptor() : mOrdinal(0), bInitialized(false) {}; // Accessor for ordinal uint32 GetOrdinal() { return mOrdinal; }; @@ -203,7 +203,7 @@ class GUIDRelatedVisitorBase : public ctree_visitor_t { public: // We need access to a ServiceDescriptorMap from above. GUIDRelatedVisitorBase(ServiceDescriptorMap &m) - : ctree_visitor_t(CV_FAST), mDebug(true), mServices(m){}; + : ctree_visitor_t(CV_FAST), mDebug(true), mServices(m) {}; // We need the function ea when setting Hex-Rays variable types. void SetFuncEa(ea_t ea) { mFuncEa = ea; }; @@ -483,7 +483,7 @@ class GUIDRelatedVisitorBase : public ctree_visitor_t { // we know about, and setting the types of the output variables accordingly. class GUIDRetyper : public GUIDRelatedVisitorBase { public: - GUIDRetyper(ServiceDescriptorMap &m) : GUIDRelatedVisitorBase(m), mNumApplied(0){}; + GUIDRetyper(ServiceDescriptorMap &m) : GUIDRelatedVisitorBase(m), mNumApplied(0) {}; // This is the callback function that Hex-Rays invokes for every expression // in the CTREE. @@ -666,7 +666,7 @@ class VariablesInfoExtractor : public ctree_visitor_t { class PrototypesFixer : public ctree_visitor_t { public: - PrototypesFixer() : ctree_visitor_t(CV_FAST){}; + PrototypesFixer() : ctree_visitor_t(CV_FAST) {}; std::vector child_functions; // This is the callback function that Hex-Rays invokes for every expression @@ -768,7 +768,7 @@ class PrototypesFixer : public ctree_visitor_t { class VariablesDetector : public ctree_visitor_t { public: - VariablesDetector() : ctree_visitor_t(CV_FAST){}; + VariablesDetector() : ctree_visitor_t(CV_FAST) {}; std::vector child_functions; @@ -896,7 +896,7 @@ class VariablesDetector : public ctree_visitor_t { class ServicesDetector : public ctree_visitor_t { // detect all services (Boot services, Runtime services, etc) public: - ServicesDetector() : ctree_visitor_t(CV_FAST){}; + ServicesDetector() : ctree_visitor_t(CV_FAST) {}; std::vector services; @@ -965,7 +965,7 @@ class ServicesDetector : public ctree_visitor_t { class PeiServicesDetector : public ctree_visitor_t { // detect and mark all PEI services public: - PeiServicesDetector() : ctree_visitor_t(CV_FAST){}; + PeiServicesDetector() : ctree_visitor_t(CV_FAST) {}; bool make_shifted_ptr(tinfo_t outer, tinfo_t inner, int32 offset, tinfo_t *shifted_tif) { @@ -1059,7 +1059,7 @@ class PeiServicesDetectorArm : public ctree_visitor_t { // detect and mark all PEI services for ARM firmware // tested on Ampere firmware that contains small PEI stack public: - PeiServicesDetectorArm() : ctree_visitor_t(CV_FAST){}; + PeiServicesDetectorArm() : ctree_visitor_t(CV_FAST) {}; std::vector services; diff --git a/efiXplorer/efiUtils.cpp b/efiXplorer/efiUtils.cpp index fd9e6798..26c006da 100644 --- a/efiXplorer/efiUtils.cpp +++ b/efiXplorer/efiUtils.cpp @@ -313,9 +313,20 @@ std::vector getXrefsToArray(ea_t addr) { //-------------------------------------------------------------------------- // Wrapper for op_stroff function bool opStroff(ea_t addr, std::string type) { + tinfo_t tinfo; + if (!tinfo.get_named_type(get_idati(), type.c_str())) { + return false; + } + + // use force_tid() instead of get_tid() + // to import type if it's not imported + tid_t tid = tinfo.force_tid(); + if (tid == BADADDR) { + return false; + } + insn_t insn; decode_insn(&insn, addr); - tid_t tid = get_named_type_tid(type.c_str()); return op_stroff(insn, 0, &tid, 1, 0); } @@ -858,22 +869,21 @@ void opstroffForAddress(ea_t ea, qstring typeName) { plugin_name, u64_addr(ea), typeName.c_str()); // check for EfiSmmBase2Protocol->GetSmstLocation - if (typeName == qstring("EFI_SMM_BASE2_PROTOCOL") && - insn.ops[0].type == o_displ && insn.ops[0].addr == 8) { + if (typeName == "EFI_SMM_BASE2_PROTOCOL" && insn.ops[0].type == o_displ && + insn.ops[0].addr == 8) { if (!addrInVec(g_get_smst_location_calls, ea)) { g_get_smst_location_calls.push_back(ea); } } - if (typeName == qstring("EFI_SMM_VARIABLE_PROTOCOL") && - insn.ops[0].type == o_phrase) { + if (typeName == "EFI_SMM_VARIABLE_PROTOCOL" && insn.ops[0].type == o_phrase) { if (!addrInVec(g_smm_get_variable_calls, ea)) { g_smm_get_variable_calls.push_back(ea); } } - if (typeName == qstring("EFI_SMM_VARIABLE_PROTOCOL") && - insn.ops[0].type == o_displ && insn.ops[0].addr == 0x10) { + if (typeName == "EFI_SMM_VARIABLE_PROTOCOL" && insn.ops[0].type == o_displ && + insn.ops[0].addr == 0x10) { if (!addrInVec(g_smm_set_variable_calls, ea)) { g_smm_set_variable_calls.push_back(ea); } From f3cf8cba1e9bb86649019138c6f62631bdfe5261 Mon Sep 17 00:00:00 2001 From: yeggor Date: Thu, 15 Aug 2024 04:47:21 +0100 Subject: [PATCH 04/69] add stub for import_type (when using idasdk90) --- efiXplorer/efiAnalyzer.h | 4 ---- efiXplorer/efiHexRays.h | 4 ---- efiXplorer/efiUtils.cpp | 13 ++++++++++++- efiXplorer/efiUtils.h | 4 ++++ efiXplorer/efiXplorer.cpp | 3 ++- 5 files changed, 18 insertions(+), 10 deletions(-) diff --git a/efiXplorer/efiAnalyzer.h b/efiXplorer/efiAnalyzer.h index ea3f8506..4286e5a4 100644 --- a/efiXplorer/efiAnalyzer.h +++ b/efiXplorer/efiAnalyzer.h @@ -234,7 +234,6 @@ class EfiAnalyzer { class EfiAnalyzerX86 : public EfiAnalyzer { public: EfiAnalyzerX86() : EfiAnalyzer() { -#if IDA_SDK_VERSION < 900 // import necessary types const til_t *idati = get_idati(); import_type(idati, -1, "EFI_GUID"); @@ -246,7 +245,6 @@ class EfiAnalyzerX86 : public EfiAnalyzer { import_type(idati, -1, "EFI_PEI_SERVICES"); import_type(idati, -1, "EFI_PEI_READ_ONLY_VARIABLE2_PPI"); import_type(idati, -1, "EFI_SMM_VARIABLE_PROTOCOL"); -#endif #ifdef HEX_RAYS for (auto idx = 0; idx < get_entry_qty(); idx++) { uval_t ord = get_entry_ordinal(idx); @@ -290,14 +288,12 @@ class EfiAnalyzerArm : public EfiAnalyzer { // uefi.til, uefi64.til files in {idadir}/til/arm/ add_til("uefi64.til", ADDTIL_DEFAULT); -#if IDA_SDK_VERSION < 900 const til_t *idati = get_idati(); import_type(idati, -1, "EFI_GUID"); import_type(idati, -1, "EFI_HANDLE"); import_type(idati, -1, "EFI_SYSTEM_TABLE"); import_type(idati, -1, "EFI_BOOT_SERVICES"); import_type(idati, -1, "EFI_RUNTIME_SERVICES"); -#endif } void fixOffsets(); void initialAnalysis(); diff --git a/efiXplorer/efiHexRays.h b/efiXplorer/efiHexRays.h index bc77e6db..9c54e288 100644 --- a/efiXplorer/efiHexRays.h +++ b/efiXplorer/efiHexRays.h @@ -71,10 +71,8 @@ class ServiceDescriptor { // Ensure we can look up the type that this instance describes bool InitType(const char *name) { -#if IDA_SDK_VERSION < 900 // Import type import_type(get_idati(), -1, name); -#endif // Get type by name if (!mType.get_named_type(get_idati(), name)) @@ -518,9 +516,7 @@ class GUIDRetyper : public GUIDRelatedVisitorBase { // Need to get the type for the interface variable here tinfo_t tif; -#if IDA_SDK_VERSION < 900 import_type(get_idati(), -1, interfaceTypeName.c_str()); -#endif if (!tif.get_named_type(get_idati(), interfaceTypeName.c_str())) { // Get the referent for the interface argument. cexpr_t *outArgReferent = GetReferent(mOutArg, "ptr", true); diff --git a/efiXplorer/efiUtils.cpp b/efiXplorer/efiUtils.cpp index 26c006da..d7d8ff79 100644 --- a/efiXplorer/efiUtils.cpp +++ b/efiXplorer/efiUtils.cpp @@ -537,7 +537,7 @@ bool addStrucForShiftedPtr() { return true; #endif - // use parse_decls() instead + // TODO: in idasdk90+ use parse_decls() instead return false; } @@ -1079,3 +1079,14 @@ uint16_t get_machine_type() { ea_t pe_offset = get_dword(0x3c); return get_word(pe_offset + 4); } + +#if IDA_SDK_VERSION >= 900 +tid_t import_type(const til_t *til, int _idx, const char *name) { + tinfo_t tinfo; + if (!tinfo.get_named_type(til, name)) { + return BADADDR; + } + + return tinfo.force_tid(); +} +#endif diff --git a/efiXplorer/efiUtils.h b/efiXplorer/efiUtils.h index 8cc66858..4f1c643f 100644 --- a/efiXplorer/efiUtils.h +++ b/efiXplorer/efiUtils.h @@ -308,3 +308,7 @@ std::string lookupRuntimeServiceName(uint64_t offset); uint64_t u64_addr(ea_t addr); uint32_t u32_addr(ea_t addr); uint16_t get_machine_type(); + +#if IDA_SDK_VERSION >= 900 +tid_t import_type(const til_t *til, int _idx, const char *name); +#endif diff --git a/efiXplorer/efiXplorer.cpp b/efiXplorer/efiXplorer.cpp index 65590af8..ed9ff8fd 100644 --- a/efiXplorer/efiXplorer.cpp +++ b/efiXplorer/efiXplorer.cpp @@ -83,7 +83,8 @@ bool idaapi run(size_t arg) { g_args.disable_vuln_hunt = 1; } - msg("[%s] plugin run with argument %lu (sdk version: %d)\n", plugin_name, arg, IDA_SDK_VERSION); + msg("[%s] plugin run with argument %lu (sdk version: %d)\n", plugin_name, arg, + IDA_SDK_VERSION); msg("[%s] disable_ui = %d, disable_vuln_hunt = %d\n", plugin_name, g_args.disable_ui, g_args.disable_vuln_hunt); From f1e6972ce24c677f59150dadecb97367b4a026fc Mon Sep 17 00:00:00 2001 From: yeggor Date: Thu, 15 Aug 2024 05:02:35 +0100 Subject: [PATCH 05/69] remove redundant functionality from loader --- efiXloader/efiLoader.cpp | 15 ++------------- efiXloader/pe_ida.h | 2 +- efiXloader/uefitool.h | 2 +- 3 files changed, 4 insertions(+), 15 deletions(-) diff --git a/efiXloader/efiLoader.cpp b/efiXloader/efiLoader.cpp index b68966ce..8073a10e 100644 --- a/efiXloader/efiLoader.cpp +++ b/efiXloader/efiLoader.cpp @@ -114,21 +114,10 @@ void idaapi load_file(linput_t *li, ushort neflag, const char *fileformatname) { uefiParser.dump_jsons(); msg("[efiXloader] machine type: %04x\n", uefiParser.machine_type); efiloader::PeManager peManager(uefiParser.machine_type); + add_til("uefi.til", ADDTIL_DEFAULT); add_til("uefi64.til", ADDTIL_DEFAULT); - qstring err; - const til_t *idati = get_idati(); - if (!idati) { - loader_failure("failed to load IDA types"); - } else { - msg("[efiXloader] loaded IDA types\n"); - } -#if IDA_SDK_VERSION < 900 - tid_t struct_err = import_type(idati, -1, "EFI_GUID"); - if (struct_err == BADNODE) { - loader_failure("failed to import \"EFI_GUID\""); - } -#endif + msg("processing UEFI binaries:\n"); if (uefiParser.files.size()) { for (int i = 0; i < uefiParser.files.size(); i++) { diff --git a/efiXloader/pe_ida.h b/efiXloader/pe_ida.h index 266b14b0..71d58917 100644 --- a/efiXloader/pe_ida.h +++ b/efiXloader/pe_ida.h @@ -46,7 +46,7 @@ struct petab_t { uint32 rva; // relative virtual address uint32 size; // size -}; // PE va/size array element +}; // PE va/size array element template struct peheader_tpl { int32 signature; // 00 Current value is "PE/0/0". diff --git a/efiXloader/uefitool.h b/efiXloader/uefitool.h index 3e69b618..647f88ee 100644 --- a/efiXloader/uefitool.h +++ b/efiXloader/uefitool.h @@ -112,7 +112,7 @@ class Uefitool { } messages = ffs.getMessages(); } - ~Uefitool(){}; + ~Uefitool() {}; void show_messages(); bool messages_occurs() { return !messages.empty(); }; void dump(); From 0e1de975699613fecaf04a28bd1939950876f31d Mon Sep 17 00:00:00 2001 From: yeggor Date: Thu, 22 Aug 2024 06:18:16 +0100 Subject: [PATCH 06/69] fix support for pei images analysis (parse decls for EFI_PEI_SERVICES_4 and EFI_PEI_SIDT): - this will work only for 32-bit modules --- efiXplorer/efiGlobal.h | 2 ++ efiXplorer/efiHexRays.h | 9 ++++----- efiXplorer/efiUtils.cpp | 24 +++++++++++++++++++++--- 3 files changed, 27 insertions(+), 8 deletions(-) diff --git a/efiXplorer/efiGlobal.h b/efiXplorer/efiGlobal.h index bbe62f27..7eef356f 100644 --- a/efiXplorer/efiGlobal.h +++ b/efiXplorer/efiGlobal.h @@ -19,6 +19,8 @@ * */ +#pragma once + #include "efiDeps.h" enum module_types { DXE_SMM = 0, PEI = 1 }; diff --git a/efiXplorer/efiHexRays.h b/efiXplorer/efiHexRays.h index 9c54e288..3eeb9bd2 100644 --- a/efiXplorer/efiHexRays.h +++ b/efiXplorer/efiHexRays.h @@ -984,8 +984,8 @@ class PeiServicesDetector : public ctree_visitor_t { // This is the callback function that Hex-Rays invokes for every expression // in the CTREE. int visit_expr(cexpr_t *e) { - ea_t pointer_offset = BADADDR; - ea_t service_offset = BADADDR; + auto pointer_offset = BADADDR; + auto service_offset = BADADDR; bool call = false; var_ref_t var_ref; if (e->op == cot_ptr && e->x->op == cot_cast && e->x->x->op == cot_add && @@ -993,8 +993,8 @@ class PeiServicesDetector : public ctree_visitor_t { e->x->x->x->x->x->op == cot_cast && e->x->x->x->x->x->x->op == cot_sub && e->x->x->x->x->x->x->x->op == cot_var && e->x->x->x->x->x->x->y->op == cot_num && e->x->x->y->op == cot_num) { - // (*ADJ(v2)->PeiServices)->GetHobList((const EFI_PEI_SERVICES - // **)ADJ(v2)->PeiServices, HobList); + // (*ADJ(v2)->PeiServices)->GetHobList( + // (const EFI_PEI_SERVICES**)ADJ(v2)->PeiServices, HobList); service_offset = e->x->x->y->numval(); pointer_offset = e->x->x->x->x->x->x->y->numval(); var_ref = e->x->x->x->x->x->x->x->v; @@ -1017,7 +1017,6 @@ class PeiServicesDetector : public ctree_visitor_t { } if (pointer_offset != 4) { - // handle only 4 for now return 0; } diff --git a/efiXplorer/efiUtils.cpp b/efiXplorer/efiUtils.cpp index d7d8ff79..b7eb469d 100644 --- a/efiXplorer/efiUtils.cpp +++ b/efiXplorer/efiUtils.cpp @@ -501,6 +501,24 @@ bool setRetToPeiSvc(ea_t start_ea) { return true; } +int parseEfiPeiServices4() { + return parse_decls(nullptr, + "struct EFI_PEI_SERVICES_4 {\n" + " EFI_PEI_SERVICES **PeiServices;\n" + " UINT32 BaseAddress;\n" + "};", + msg, HTI_DCL); +} + +int parseEfiPeiSidt() { + return parse_decls(nullptr, + "struct EFI_PEI_SIDT {\n" + " UINT16 Limit;\n" + " int *__shifted(EFI_PEI_SERVICES_4, 4) BaseAddress;\n" + "};", + msg, HTI_DCL | HTI_PAK1); +} + //-------------------------------------------------------------------------- // Add EFI_PEI_SERVICES_4 structure bool addStrucForShiftedPtr() { @@ -518,7 +536,7 @@ bool addStrucForShiftedPtr() { add_struc_member(new_struct, nullptr, 0, dword_flag(), nullptr, 4); add_struc_member(new_struct, nullptr, 4, dword_flag(), nullptr, 4); set_member_name(new_struct, 0, "PeiServices"); - set_member_name(new_struct, 4, "PeiServices4"); + set_member_name(new_struct, 4, "BaseAddress"); tinfo_t tinfo; if (!tinfo.get_named_type(get_idati(), "EFI_PEI_SERVICES")) { @@ -537,8 +555,8 @@ bool addStrucForShiftedPtr() { return true; #endif - // TODO: in idasdk90+ use parse_decls() instead - return false; + // return true if there are no errors from parse_decls() + return !parseEfiPeiServices4() && !parseEfiPeiSidt(); } //-------------------------------------------------------------------------- From 6f0c4a867403f86ca0f288720b3a3cc8385bd954 Mon Sep 17 00:00:00 2001 From: yeggor Date: Wed, 11 Sep 2024 08:01:11 +0200 Subject: [PATCH 07/69] format efixloader, change main source name --- efiXloader/.clang-format | 2 +- efiXloader/CMakeLists.txt | 2 +- efiXloader/efiLoader.cpp | 168 ----- efiXloader/efiLoader.h | 98 --- efiXloader/efi_loader.cpp | 168 +++++ efiXloader/efi_loader.h | 98 +++ efiXloader/ida_core.h | 95 ++- efiXloader/pe.cpp | 1217 ++++++++++++++++++------------------- efiXloader/pe.h | 260 ++++---- efiXloader/pe_ida.h | 938 ++++++++++++++-------------- efiXloader/pe_manager.cpp | 20 +- efiXloader/pe_manager.h | 48 +- efiXloader/uefitool.cpp | 565 +++++++++-------- efiXloader/uefitool.h | 158 ++--- efiXloader/utils.cpp | 104 ++-- efiXloader/utils.h | 16 +- 16 files changed, 1975 insertions(+), 1982 deletions(-) delete mode 100644 efiXloader/efiLoader.cpp delete mode 100644 efiXloader/efiLoader.h create mode 100644 efiXloader/efi_loader.cpp create mode 100644 efiXloader/efi_loader.h diff --git a/efiXloader/.clang-format b/efiXloader/.clang-format index 6bde2289..92cfffbb 100644 --- a/efiXloader/.clang-format +++ b/efiXloader/.clang-format @@ -2,4 +2,4 @@ Language: Cpp BasedOnStyle: LLVM ColumnLimit: 90 -IndentWidth: 4 +IndentWidth: 2 diff --git a/efiXloader/CMakeLists.txt b/efiXloader/CMakeLists.txt index 1859f415..17b3a634 100644 --- a/efiXloader/CMakeLists.txt +++ b/efiXloader/CMakeLists.txt @@ -59,7 +59,7 @@ file( # efiLoader sources file(GLOB efiloader_src "*.h" "*.c" "*.cpp") -add_ida_loader(efiXloader NOEA32 ${PROJECT_SOURCE_DIR}/efiLoader.cpp) +add_ida_loader(efiXloader NOEA32 ${PROJECT_SOURCE_DIR}/efi_loader.cpp) set_ida_target_properties(efiXloader PROPERTIES CXX_STANDARD 17) ida_target_include_directories(efiXloader PRIVATE ${IdaSdk_INCLUDE_DIRS}) diff --git a/efiXloader/efiLoader.cpp b/efiXloader/efiLoader.cpp deleted file mode 100644 index 8073a10e..00000000 --- a/efiXloader/efiLoader.cpp +++ /dev/null @@ -1,168 +0,0 @@ -/* - * efiXloader - * Copyright (C) 2020-2023 Binarly - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * efiLoader.cpp - */ - -#include "efiLoader.h" -#include "uefitool.h" -#include "utils.h" - -#define USE_UEFITOOL_PARSER - -bool first_uefi_image = true; - -//------------------------ -// IDA wrappers -//------------------------ - -void idaapi load_binary(const char *fname) { - load_info_t *ld = NULL; - linput_t *li = NULL; - ushort nflags = NEF_SEGS | NEF_RSCS | NEF_NAME | NEF_IMPS | NEF_LALL | NEF_FLAT; - if (first_uefi_image) { - nflags |= NEF_FIRST; - } - first_uefi_image = false; - // linput - li = open_linput(fname, false); - if (li == NULL) { - error("failed to process input source: %s", fname); - } - // get loaders - ld = build_loaders_list(li, fname); - msg("[efiXloader] using %s to load %s\n", ld->dllname.c_str(), fname); - // load EFI binary into database - if ((load_nonbinary_file(fname, li, ".", nflags, ld))) { - msg("[efiXloader] successfully loaded %s\n", fname); - } else { - loader_failure("[efiXloader] 'load_nonbinary_file' failed"); - } - close_linput(li); - free_loaders_list(ld); - return; -} - -void idaapi wait(void) { - while (!auto_is_ok()) { - auto_wait(); - } -} - -//------------------------ -// IDA analyzing -//------------------------ - -void inline idaapi reanalyze_all(void) { - plan_range(inf_get_min_ea(), inf_get_max_ea()); - auto_wait(); - auto_make_proc(inf_get_min_ea()); -} - -void efi_til_init(const char *til_name) { - qstring err; - til_t *res; - res = load_til(til_name, &err); - if (!res) { - loader_failure("failed to load %s", til_name); - } else { - msg("[efiXloader] lib %s is ready\n", til_name); - } -} - -//------------------------ -// IDA loader -//------------------------ - -static int idaapi accept_file(qstring *fileformatname, qstring *processor, linput_t *li, - const char *filename) { - efiloader::Utils utils; - bytevec_t data; - data.resize(qlsize(li)); - qlseek(li, 0); - qlread(li, data.begin(), qlsize(li)); - *fileformatname = "UEFI firmware image"; - return utils.find_vol_test(data) != std::string::npos; -} - -void idaapi load_file(linput_t *li, ushort neflag, const char *fileformatname) { - bool ok = true; - bool is_pe; - Ui ui; - bytevec_t data; - data.resize(qlsize(li)); - qlread(li, data.begin(), qlsize(li)); - efiloader::Uefitool uefiParser(data); - if (uefiParser.messages_occurs()) { - uefiParser.show_messages(); - } - uefiParser.dump(); - uefiParser.dump_jsons(); - msg("[efiXloader] machine type: %04x\n", uefiParser.machine_type); - efiloader::PeManager peManager(uefiParser.machine_type); - - add_til("uefi.til", ADDTIL_DEFAULT); - add_til("uefi64.til", ADDTIL_DEFAULT); - - msg("processing UEFI binaries:\n"); - if (uefiParser.files.size()) { - for (int i = 0; i < uefiParser.files.size(); i++) { - if (uefiParser.files[i]->is_te) { - continue; - } - auto inf = open_linput(uefiParser.files[i]->dump_name.c_str(), false); - if (!inf) { - msg("Unable to open file %s\n", uefiParser.files[i]->dump_name.c_str()); - continue; - } - peManager.process(inf, uefiParser.files[i]->dump_name.c_str(), i); - } - } else { - msg("[efiXloader] Can not parse input firmware\n"); - } - - plugin_t *findpat = find_plugin("patfind", true); - if (findpat) { - msg("Running the Find functions plugin\n"); - run_plugin(findpat, 0); - } -} - -static int idaapi move_segm(ea_t from, ea_t to, asize_t, const char *) { return 1; } - -//---------------------------------------------------------------------- -// -// LOADER DESCRIPTION BLOCK -// -//---------------------------------------------------------------------- -loader_t LDSC = { - IDP_INTERFACE_VERSION, - // loader flags - 0, - // check input file format. if recognized, then return 1 - // and fill 'fileformatname'. - // otherwise return 0 - accept_file, - // load file into the database. - load_file, - // create output file from the database. - // this function may be absent. - NULL, - // take care of a moved segment (fix up relocations, for example) - NULL, - NULL, -}; diff --git a/efiXloader/efiLoader.h b/efiXloader/efiLoader.h deleted file mode 100644 index 0de27690..00000000 --- a/efiXloader/efiLoader.h +++ /dev/null @@ -1,98 +0,0 @@ -/* - * efiXloader - * Copyright (C) 2020-2023 Binarly - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * efiLoader.h - */ - -#ifndef EFILOADER_EFILOADER_H -#define EFILOADER_EFILOADER_H - -#include "ida_core.h" -#include "pe.h" -#include "pe_manager.h" -#include "uefitool.h" - -extern loader_t LDSC; - -//----------------------- -// definitions -//----------------------- - -void idaapi load_binary(const char *fname); -void idaapi close_and_save_db(const char *fname); -void idaapi reanalyze_all(void); -void idaapi wait(void); -void idaapi idb_to_asm(const char *fname); -void idaapi clean_db(void); - -void idaapi efi_til_init(); - -// UI - -class Ui { - public: - Ui() { ; } - int ask_for_single_image(); -}; - -class driver_chooser_t : public chooser_t { - protected: - static const int widths_drivers[]; - static const char *const drivers_headers[]; - - public: - /* remember the addresses in this qvector */ - qvector drivers_names; - - /* this object must be allocated using `new` */ - driver_chooser_t(const char *title, bool ok, std::vector drivers); - - /* function that is used to decide whether a new chooser should be opened or - * we can use the existing one. The contents of the window are completely - * determined by its title */ - virtual const void *get_obj_id(size_t *len) const { - *len = strlen(title); - return title; - } - - /* function that returns number of lines in the list */ - virtual size_t idaapi get_count() const { return drivers_names.size(); } - - /* function that generates the list line */ - virtual void idaapi get_row(qstrvec_t *cols, int *icon_, chooser_item_attrs_t *attrs, - size_t n) const; - - /* function that is called when the user hits Enter */ - virtual cbret_t idaapi enter(size_t n) { - if (n < drivers_names.size()) { - // jumpto(list[n]); - } - return cbret_t(); - } - - protected: - void build_list(bool ok, std::vector files) { - size_t n = 0; - for (auto file : files) { - drivers_names.push_back(qstring(file->qname)); - n++; - } - ok = true; - }; -}; - -#endif // EFILOADER_EFILOADER_H diff --git a/efiXloader/efi_loader.cpp b/efiXloader/efi_loader.cpp new file mode 100644 index 00000000..3abb3bf4 --- /dev/null +++ b/efiXloader/efi_loader.cpp @@ -0,0 +1,168 @@ +/* + * efiXloader + * Copyright (C) 2020-2024 Binarly + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * efiLoader.cpp + */ + +#include "efi_loader.h" +#include "uefitool.h" +#include "utils.h" + +#define USE_UEFITOOL_PARSER + +bool first_uefi_image = true; + +//------------------------ +// IDA wrappers +//------------------------ + +void idaapi load_binary(const char *fname) { + load_info_t *ld = NULL; + linput_t *li = NULL; + ushort nflags = NEF_SEGS | NEF_RSCS | NEF_NAME | NEF_IMPS | NEF_LALL | NEF_FLAT; + if (first_uefi_image) { + nflags |= NEF_FIRST; + } + first_uefi_image = false; + // linput + li = open_linput(fname, false); + if (li == NULL) { + error("failed to process input source: %s", fname); + } + // get loaders + ld = build_loaders_list(li, fname); + msg("[efiXloader] using %s to load %s\n", ld->dllname.c_str(), fname); + // load EFI binary into database + if ((load_nonbinary_file(fname, li, ".", nflags, ld))) { + msg("[efiXloader] successfully loaded %s\n", fname); + } else { + loader_failure("[efiXloader] 'load_nonbinary_file' failed"); + } + close_linput(li); + free_loaders_list(ld); + return; +} + +void idaapi wait(void) { + while (!auto_is_ok()) { + auto_wait(); + } +} + +//------------------------ +// IDA analyzing +//------------------------ + +void inline idaapi reanalyze_all(void) { + plan_range(inf_get_min_ea(), inf_get_max_ea()); + auto_wait(); + auto_make_proc(inf_get_min_ea()); +} + +void efi_til_init(const char *til_name) { + qstring err; + til_t *res; + res = load_til(til_name, &err); + if (!res) { + loader_failure("failed to load %s", til_name); + } else { + msg("[efiXloader] lib %s is ready\n", til_name); + } +} + +//------------------------ +// IDA loader +//------------------------ + +static int idaapi accept_file(qstring *fileformatname, qstring *processor, linput_t *li, + const char *filename) { + efiloader::Utils utils; + bytevec_t data; + data.resize(qlsize(li)); + qlseek(li, 0); + qlread(li, data.begin(), qlsize(li)); + *fileformatname = "UEFI firmware image"; + return utils.find_vol_test(data) != std::string::npos; +} + +void idaapi load_file(linput_t *li, ushort neflag, const char *fileformatname) { + bool ok = true; + bool is_pe; + Ui ui; + bytevec_t data; + data.resize(qlsize(li)); + qlread(li, data.begin(), qlsize(li)); + efiloader::Uefitool uefiParser(data); + if (uefiParser.messages_occurs()) { + uefiParser.show_messages(); + } + uefiParser.dump(); + uefiParser.dump_jsons(); + msg("[efiXloader] machine type: %04x\n", uefiParser.machine_type); + efiloader::PeManager peManager(uefiParser.machine_type); + + add_til("uefi.til", ADDTIL_DEFAULT); + add_til("uefi64.til", ADDTIL_DEFAULT); + + msg("processing UEFI binaries:\n"); + if (uefiParser.files.size()) { + for (int i = 0; i < uefiParser.files.size(); i++) { + if (uefiParser.files[i]->is_te) { + continue; + } + auto inf = open_linput(uefiParser.files[i]->dump_name.c_str(), false); + if (!inf) { + msg("Unable to open file %s\n", uefiParser.files[i]->dump_name.c_str()); + continue; + } + peManager.process(inf, uefiParser.files[i]->dump_name.c_str(), i); + } + } else { + msg("[efiXloader] Can not parse input firmware\n"); + } + + plugin_t *findpat = find_plugin("patfind", true); + if (findpat) { + msg("Running the Find functions plugin\n"); + run_plugin(findpat, 0); + } +} + +static int idaapi move_segm(ea_t from, ea_t to, asize_t, const char *) { return 1; } + +//---------------------------------------------------------------------- +// +// LOADER DESCRIPTION BLOCK +// +//---------------------------------------------------------------------- +loader_t LDSC = { + IDP_INTERFACE_VERSION, + // loader flags + 0, + // check input file format. if recognized, then return 1 + // and fill 'fileformatname'. + // otherwise return 0 + accept_file, + // load file into the database. + load_file, + // create output file from the database. + // this function may be absent. + NULL, + // take care of a moved segment (fix up relocations, for example) + NULL, + NULL, +}; diff --git a/efiXloader/efi_loader.h b/efiXloader/efi_loader.h new file mode 100644 index 00000000..a202f91d --- /dev/null +++ b/efiXloader/efi_loader.h @@ -0,0 +1,98 @@ +/* + * efiXloader + * Copyright (C) 2020-2024 Binarly + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * efiLoader.h + */ + +#ifndef EFILOADER_EFILOADER_H +#define EFILOADER_EFILOADER_H + +#include "ida_core.h" +#include "pe.h" +#include "pe_manager.h" +#include "uefitool.h" + +extern loader_t LDSC; + +//----------------------- +// definitions +//----------------------- + +void idaapi load_binary(const char *fname); +void idaapi close_and_save_db(const char *fname); +void idaapi reanalyze_all(void); +void idaapi wait(void); +void idaapi idb_to_asm(const char *fname); +void idaapi clean_db(void); + +void idaapi efi_til_init(); + +// UI + +class Ui { +public: + Ui() { ; } + int ask_for_single_image(); +}; + +class driver_chooser_t : public chooser_t { +protected: + static const int widths_drivers[]; + static const char *const drivers_headers[]; + +public: + /* remember the addresses in this qvector */ + qvector drivers_names; + + /* this object must be allocated using `new` */ + driver_chooser_t(const char *title, bool ok, std::vector drivers); + + /* function that is used to decide whether a new chooser should be opened or + * we can use the existing one. The contents of the window are completely + * determined by its title */ + virtual const void *get_obj_id(size_t *len) const { + *len = strlen(title); + return title; + } + + /* function that returns number of lines in the list */ + virtual size_t idaapi get_count() const { return drivers_names.size(); } + + /* function that generates the list line */ + virtual void idaapi get_row(qstrvec_t *cols, int *icon_, chooser_item_attrs_t *attrs, + size_t n) const; + + /* function that is called when the user hits Enter */ + virtual cbret_t idaapi enter(size_t n) { + if (n < drivers_names.size()) { + // jumpto(list[n]); + } + return cbret_t(); + } + +protected: + void build_list(bool ok, std::vector files) { + size_t n = 0; + for (auto file : files) { + drivers_names.push_back(qstring(file->qname)); + n++; + } + ok = true; + }; +}; + +#endif // EFILOADER_EFILOADER_H diff --git a/efiXloader/ida_core.h b/efiXloader/ida_core.h index 41dd492e..4dbd21ba 100644 --- a/efiXloader/ida_core.h +++ b/efiXloader/ida_core.h @@ -1,6 +1,6 @@ /* * efiXloader - * Copyright (C) 2020-2023 Binarly + * Copyright (C) 2020-2024 Binarly * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -61,32 +61,32 @@ template bool _validate_array_count(linput_t *li, T *p_cnt, size_t elsize, int64 current_offset = -1, int64 max_offset = -1) { - if (current_offset == -1) - current_offset = qltell(li); - if (max_offset == -1) - max_offset = qlsize(li); - int64 rest = max_offset - current_offset; - T cnt = *p_cnt; - if (current_offset >= 0 && rest >= 0) { + if (current_offset == -1) + current_offset = qltell(li); + if (max_offset == -1) + max_offset = qlsize(li); + int64 rest = max_offset - current_offset; + T cnt = *p_cnt; + if (current_offset >= 0 && rest >= 0) { #ifndef __X86__ - typedef size_t biggest_t; + typedef size_t biggest_t; #else - typedef ea_t biggest_t; + typedef ea_t biggest_t; #endif - if (is_mul_ok(elsize, cnt)) { - biggest_t needed = elsize * cnt; + if (is_mul_ok(elsize, cnt)) { + biggest_t needed = elsize * cnt; #ifdef __X86__ - if (needed == size_t(needed)) + if (needed == size_t(needed)) #endif - if (rest >= needed) - return true; // all ok - } - cnt = rest / elsize; - } else { - cnt = 0; + if (rest >= needed) + return true; // all ok } - *p_cnt = cnt; - return false; + cnt = rest / elsize; + } else { + cnt = 0; + } + *p_cnt = cnt; + return false; } //-------------------------------------------------------------------------- @@ -95,21 +95,21 @@ bool _validate_array_count(linput_t *li, T *p_cnt, size_t elsize, template void validate_array_count(linput_t *li, T *p_cnt, size_t elsize, const char *counter_name, int64 curoff = -1, int64 maxoff = -1) { - T old = *p_cnt; - if (!_validate_array_count(li, p_cnt, elsize, curoff, maxoff)) { - static const char *const format = - "AUTOHIDE SESSION\n" - "HIDECANCEL\n" - "%s %" FMT_64 "u is incorrect, maximum possible value is %" FMT_64 "u%s"; + T old = *p_cnt; + if (!_validate_array_count(li, p_cnt, elsize, curoff, maxoff)) { + static const char *const format = + "AUTOHIDE SESSION\n" + "HIDECANCEL\n" + "%s %" FMT_64 "u is incorrect, maximum possible value is %" FMT_64 "u%s"; #ifndef __KERNEL__ - if (ask_yn(ASKBTN_YES, format, counter_name, uint64(old), uint64(*p_cnt), - ". Do you want to continue with the new value?") != ASKBTN_YES) { - loader_failure(NULL); - } + if (ask_yn(ASKBTN_YES, format, counter_name, uint64(old), uint64(*p_cnt), + ". Do you want to continue with the new value?") != ASKBTN_YES) { + loader_failure(NULL); + } #else - warning(format, counter_name, uint64(old), uint64(*p_cnt), ""); + warning(format, counter_name, uint64(old), uint64(*p_cnt), ""); #endif - } + } } //-------------------------------------------------------------------------- @@ -119,36 +119,35 @@ template void validate_array_count_or_die(linput_t *li, T cnt, size_t elsize, const char *counter_name, int64 curoff = -1, int64 maxoff = -1) { - if (!_validate_array_count(li, &cnt, elsize, curoff, maxoff)) { - static const char *const format = - "%s is incorrect, maximum possible value is %u%s"; + if (!_validate_array_count(li, &cnt, elsize, curoff, maxoff)) { + static const char *const format = "%s is incorrect, maximum possible value is %u%s"; #ifndef __KERNEL__ - loader_failure(format, counter_name, uint(cnt), ""); + loader_failure(format, counter_name, uint(cnt), ""); #else - error(format, counter_name, uint(cnt), ""); + error(format, counter_name, uint(cnt), ""); #endif - } + } } //---------------------------------- inline uchar readchar(linput_t *li) { - uchar x; - lread(li, &x, sizeof(x)); - return x; + uchar x; + lread(li, &x, sizeof(x)); + return x; } //---------------------------------- inline uint16 readshort(linput_t *li) { - uint16 x; - lread(li, &x, sizeof(x)); - return x; + uint16 x; + lread(li, &x, sizeof(x)); + return x; } //---------------------------------- inline uint32 readlong(linput_t *li) { - uint32 x; - lread(li, &x, sizeof(x)); - return x; + uint32 x; + lread(li, &x, sizeof(x)); + return x; } inline uint32 mf_readlong(linput_t *li) { return swap32(readlong(li)); } diff --git a/efiXloader/pe.cpp b/efiXloader/pe.cpp index b7a29537..637c11b8 100644 --- a/efiXloader/pe.cpp +++ b/efiXloader/pe.cpp @@ -1,6 +1,6 @@ /* * efiXloader - * Copyright (C) 2020-2023 Binarly + * Copyright (C) 2020-2024 Binarly * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -55,11 +55,11 @@ std::map DIRECTORIES = { // qoff64_t efiloader::PE::head_start() { - qoff64_t off = 0; - qlseek(li, 0x3c); - off = readshort(li); - reset(); - return off; + qoff64_t off = 0; + qlseek(li, 0x3c); + off = readshort(li); + reset(); + return off; } // @@ -67,132 +67,132 @@ qoff64_t efiloader::PE::head_start() { // bool efiloader::PE::good() { - uint16_t mz = 0; - qlread(li, &mz, sizeof(uint16_t)); - if (mz != MZ_SIGN) { - return false; - } - _pe_header_off = head_start(); - if (is_p32_plus()) { - _bits = 64; - } else if (!is_p32()) { - loader_failure("[efiXloader] failed to guess PE bitness"); - } else { - _bits = 32; - } - return is_pe(); + uint16_t mz = 0; + qlread(li, &mz, sizeof(uint16_t)); + if (mz != MZ_SIGN) { + return false; + } + _pe_header_off = head_start(); + if (is_p32_plus()) { + _bits = 64; + } else if (!is_p32()) { + loader_failure("[efiXloader] failed to guess PE bitness"); + } else { + _bits = 32; + } + return is_pe(); } bool efiloader::PE::is_p32() { - uint16_t magic = 0; - qlseek(li, _pe_header_off + sizeof(uint32_t)); - qlread(li, &magic, sizeof(uint16_t)); - reset(); - return magic == I386; + uint16_t magic = 0; + qlseek(li, _pe_header_off + sizeof(uint32_t)); + qlread(li, &magic, sizeof(uint16_t)); + reset(); + return magic == I386; } bool efiloader::PE::is_p32_plus() { - uint16_t magic = 0; - qlseek(li, _pe_header_off + sizeof(uint32_t)); - qlread(li, &magic, sizeof(uint16_t)); - reset(); - return (magic == AMD64 || magic == AARCH64); + uint16_t magic = 0; + qlseek(li, _pe_header_off + sizeof(uint32_t)); + qlread(li, &magic, sizeof(uint16_t)); + reset(); + return (magic == AMD64 || magic == AARCH64); } bool efiloader::PE::is_pe() { - uint16_t pe_sign = 0; - qlseek(li, _pe_header_off); - pe_sign = readshort(li); - reset(); - return pe_sign == PE_SIGN; + uint16_t pe_sign = 0; + qlseek(li, _pe_header_off); + pe_sign = readshort(li); + reset(); + return pe_sign == PE_SIGN; } uint16_t efiloader::PE::arch() { - qlseek(li, head_off + sizeof(uint32_t)); - qlread(li, &pe, sizeof(peheader_t)); - return pe.machine; + qlseek(li, head_off + sizeof(uint32_t)); + qlread(li, &pe, sizeof(peheader_t)); + return pe.machine; } bool efiloader::PE::process() { - preprocess(); - *pe_base = image_base + image_size; - return true; + preprocess(); + *pe_base = image_base + image_size; + return true; } const char *efiloader::PE::_machine_name() { - switch (pe64.machine) { - case PECPU_80386: - return "80386"; - case PECPU_80486: - return "80486"; - case PECPU_80586: - return "80586"; - case PECPU_SH3: - return "SH3"; - case PECPU_SH3DSP: - return "SH3DSP"; - case PECPU_SH3E: - return "SH3E"; - case PECPU_SH4: - return "SH4"; - case PECPU_SH5: - return "SH5"; - case PECPU_ARM: - return "ARM"; - case PECPU_ARMI: - return "ARMI"; - case PECPU_ARMV7: - return "ARMv7"; - case PECPU_EPOC: - return "ARM EPOC"; - case PECPU_PPC: - return "PPC"; - case PECPU_PPCFP: - return "PPC FP"; - case PECPU_PPCBE: - return "PPC BE"; - case PECPU_IA64: - return "IA64"; - case PECPU_R3000: - return "MIPS R3000"; - case PECPU_R4000: - return "MIPS R4000"; - case PECPU_R6000: - return "MIPS R6000"; - case PECPU_R10000: - return "MIPS R10000"; - case PECPU_MIPS16: - return "MIPS16"; - case PECPU_WCEMIPSV2: - return "MIPS WCEv2"; - case PECPU_ALPHA: - return "ALPHA"; - case PECPU_ALPHA64: - return "ALPHA 64"; - case PECPU_AMD64: - return "AMD64"; - case PECPU_ARM64: - return "ARM64"; - case PECPU_M68K: - return "M68K"; - case PECPU_MIPSFPU: - return "MIPS FPU"; - case PECPU_MIPSFPU16: - return "MIPS16 FPU"; - case PECPU_EBC: - return "EFI Bytecode"; - case PECPU_AM33: - return "AM33"; - case PECPU_M32R: - return "M32R"; - case PECPU_CEF: - return "CEF"; - case PECPU_CEE: - return "CEE"; - case PECPU_TRICORE: - return "TRICORE"; - } - return NULL; + switch (pe64.machine) { + case PECPU_80386: + return "80386"; + case PECPU_80486: + return "80486"; + case PECPU_80586: + return "80586"; + case PECPU_SH3: + return "SH3"; + case PECPU_SH3DSP: + return "SH3DSP"; + case PECPU_SH3E: + return "SH3E"; + case PECPU_SH4: + return "SH4"; + case PECPU_SH5: + return "SH5"; + case PECPU_ARM: + return "ARM"; + case PECPU_ARMI: + return "ARMI"; + case PECPU_ARMV7: + return "ARMv7"; + case PECPU_EPOC: + return "ARM EPOC"; + case PECPU_PPC: + return "PPC"; + case PECPU_PPCFP: + return "PPC FP"; + case PECPU_PPCBE: + return "PPC BE"; + case PECPU_IA64: + return "IA64"; + case PECPU_R3000: + return "MIPS R3000"; + case PECPU_R4000: + return "MIPS R4000"; + case PECPU_R6000: + return "MIPS R6000"; + case PECPU_R10000: + return "MIPS R10000"; + case PECPU_MIPS16: + return "MIPS16"; + case PECPU_WCEMIPSV2: + return "MIPS WCEv2"; + case PECPU_ALPHA: + return "ALPHA"; + case PECPU_ALPHA64: + return "ALPHA 64"; + case PECPU_AMD64: + return "AMD64"; + case PECPU_ARM64: + return "ARM64"; + case PECPU_M68K: + return "M68K"; + case PECPU_MIPSFPU: + return "MIPS FPU"; + case PECPU_MIPSFPU16: + return "MIPS16 FPU"; + case PECPU_EBC: + return "EFI Bytecode"; + case PECPU_AM33: + return "AM33"; + case PECPU_M32R: + return "M32R"; + case PECPU_CEF: + return "CEF"; + case PECPU_CEE: + return "CEE"; + case PECPU_TRICORE: + return "TRICORE"; + } + return NULL; } // @@ -200,12 +200,12 @@ const char *efiloader::PE::_machine_name() { // void efiloader::PE::make_entry(ea_t ea) { - char func_name[MAXNAMESIZE] = {0}; - ea_t new_ea = image_base + ea; - qsnprintf(func_name, sizeof(func_name), "%s_entry_%08X", _image_name.c_str(), - calc_file_crc32(li)); - add_entry(new_ea, new_ea, func_name, true); - memset(func_name, 0, sizeof(func_name)); + char func_name[MAXNAMESIZE] = {0}; + ea_t new_ea = image_base + ea; + qsnprintf(func_name, sizeof(func_name), "%s_entry_%08X", _image_name.c_str(), + calc_file_crc32(li)); + add_entry(new_ea, new_ea, func_name, true); + memset(func_name, 0, sizeof(func_name)); } // @@ -214,35 +214,35 @@ void efiloader::PE::make_entry(ea_t ea) { inline size_t efiloader::PE::make_named_word(ea_t ea, const char *name, const char *extra, size_t count) { - if (extra) { - add_extra_cmt(ea, true, "%s", extra); - } - create_word(ea, 2 * count); - set_cmt(ea, name, 0); - op_hex(ea, 0); - return 2 * count; + if (extra) { + add_extra_cmt(ea, true, "%s", extra); + } + create_word(ea, 2 * count); + set_cmt(ea, name, 0); + op_hex(ea, 0); + return 2 * count; } inline size_t efiloader::PE::make_named_dword(ea_t ea, const char *name, const char *extra, size_t count) { - if (extra) { - add_extra_cmt(ea, true, "%s", extra); - } - create_word(ea, 4 * count); - set_cmt(ea, name, 0); - op_hex(ea, 0); - return 4 * count; + if (extra) { + add_extra_cmt(ea, true, "%s", extra); + } + create_word(ea, 4 * count); + set_cmt(ea, name, 0); + op_hex(ea, 0); + return 4 * count; } inline size_t efiloader::PE::make_named_qword(ea_t ea, const char *name, const char *extra, size_t count) { - if (extra) { - add_extra_cmt(ea, true, "%s", extra); - } - create_word(ea, 8 * count); - set_cmt(ea, name, 0); - op_hex(ea, 0); - return 8 * count; + if (extra) { + add_extra_cmt(ea, true, "%s", extra); + } + create_word(ea, 8 * count); + set_cmt(ea, name, 0); + op_hex(ea, 0); + return 8 * count; } // @@ -251,164 +251,164 @@ inline size_t efiloader::PE::make_named_qword(ea_t ea, const char *name, segment_t *efiloader::PE::make_head_segment(ea_t start, ea_t end, const char *section_name) { - segment_t *seg = new segment_t; - seg->bitness = 2; - seg->perm = SEG_DATA; - seg->sel = allocate_selector(0x0); - seg->start_ea = start; - seg->end_ea = end; - add_segm_ex(seg, section_name, "DATA", ADDSEG_NOAA | ADDSEG_NOSREG); - return seg; + segment_t *seg = new segment_t; + seg->bitness = 2; + seg->perm = SEG_DATA; + seg->sel = allocate_selector(0x0); + seg->start_ea = start; + seg->end_ea = end; + add_segm_ex(seg, section_name, "DATA", ADDSEG_NOAA | ADDSEG_NOSREG); + return seg; } segment_t *efiloader::PE::make_generic_segment(ea_t seg_ea, ea_t seg_ea_end, const char *section_name, uint32_t flags) { - segment_t *generic_segm = new segment_t; - generic_segm->sel = allocate_selector(0x0); - generic_segm->start_ea = seg_ea; - generic_segm->end_ea = seg_ea_end; - generic_segm->bitness = 2; - generic_segm->perm = SEGPERM_READ; - if (flags & PEST_EXEC) - generic_segm->perm |= SEGPERM_EXEC; - if (flags & PEST_WRITE) - generic_segm->perm |= SEGPERM_WRITE; - - qstring name(section_name); - - if (name.find('.') == qstring::npos) { - name += qstring(".unkn"); - } - - if (flags & PEST_EXEC) { - generic_segm->type = SEG_CODE; - add_segm_ex(generic_segm, name.c_str(), "CODE", ADDSEG_NOAA); - } else { - generic_segm->type = SEG_DATA; - add_segm_ex(generic_segm, name.c_str(), "DATA", ADDSEG_NOAA); - } - - if (name == ".text") { - code_segm_name.insert(name); - } else if (name == ".data") { - data_segm_name.insert(name); - data_segment_sel = get_segm_by_name(data_segm_name.c_str())->sel; - } - - secs_names.push_back(name); - return generic_segm; + segment_t *generic_segm = new segment_t; + generic_segm->sel = allocate_selector(0x0); + generic_segm->start_ea = seg_ea; + generic_segm->end_ea = seg_ea_end; + generic_segm->bitness = 2; + generic_segm->perm = SEGPERM_READ; + if (flags & PEST_EXEC) + generic_segm->perm |= SEGPERM_EXEC; + if (flags & PEST_WRITE) + generic_segm->perm |= SEGPERM_WRITE; + + qstring name(section_name); + + if (name.find('.') == qstring::npos) { + name += qstring(".unkn"); + } + + if (flags & PEST_EXEC) { + generic_segm->type = SEG_CODE; + add_segm_ex(generic_segm, name.c_str(), "CODE", ADDSEG_NOAA); + } else { + generic_segm->type = SEG_DATA; + add_segm_ex(generic_segm, name.c_str(), "DATA", ADDSEG_NOAA); + } + + if (name == ".text") { + code_segm_name.insert(name); + } else if (name == ".data") { + data_segm_name.insert(name); + data_segment_sel = get_segm_by_name(data_segm_name.c_str())->sel; + } + + secs_names.push_back(name); + return generic_segm; } int efiloader::PE::preprocess_sections() { - qlseek(li, _pe_header_off); - qlread(li, &pe, sizeof(peheader_t)); - - // x86 - number_of_sections = pe.nobjs; - int section_headers_offset = pe.first_section_pos(_pe_header_off); - headers_size = pe.allhdrsize; - - if (pe.machine == PECPU_AMD64 || pe.machine == PECPU_ARM64) { // AMD64/AARCH64 - qlseek(li, _pe_header_off); - qlread(li, &pe64, sizeof(peheader64_t)); - number_of_sections = pe64.nobjs; - section_headers_offset = pe64.first_section_pos(_pe_header_off); - headers_size = pe64.allhdrsize; - } + qlseek(li, _pe_header_off); + qlread(li, &pe, sizeof(peheader_t)); - if (!headers_size) { - return -1; - } + // x86 + number_of_sections = pe.nobjs; + int section_headers_offset = pe.first_section_pos(_pe_header_off); + headers_size = pe.allhdrsize; - _sec_headers.resize(number_of_sections); - qlseek(li, section_headers_offset); - for (int i = 0; i < number_of_sections; i++) { - qlread(li, &_sec_headers[i], sizeof(pesection_t)); - } - - return 0; + if (pe.machine == PECPU_AMD64 || pe.machine == PECPU_ARM64) { // AMD64/AARCH64 + qlseek(li, _pe_header_off); + qlread(li, &pe64, sizeof(peheader64_t)); + number_of_sections = pe64.nobjs; + section_headers_offset = pe64.first_section_pos(_pe_header_off); + headers_size = pe64.allhdrsize; + } + + if (!headers_size) { + return -1; + } + + _sec_headers.resize(number_of_sections); + qlseek(li, section_headers_offset); + for (int i = 0; i < number_of_sections; i++) { + qlread(li, &_sec_headers[i], sizeof(pesection_t)); + } + + return 0; } ea_t efiloader::PE::process_section_entry(ea_t next_ea) { - create_strlit(next_ea, 8, STRTYPE_C); - set_cmt(next_ea, "Name", 0); - op_hex(next_ea, 0); - size_t segm_name_len = get_max_strlit_length(next_ea, STRTYPE_C); - - if (segm_name_len) { - get_strlit_contents(&segm_names.push_back(), next_ea, segm_name_len, STRTYPE_C); - } else { - // if the segm_name_len is 0, it will trigger a crash on segm_names.pop_back() - // later. - segm_names.push_back("UNKNOWN"); - } - - next_ea += 8; - create_dword(next_ea, 4); - set_cmt(next_ea, "Virtual size", 0); - op_hex(next_ea, 0); - segm_sizes.push_back(get_dword(next_ea)); - next_ea += 4; - create_dword(next_ea, 4); - set_cmt(next_ea, "Virtual address", 0); - op_hex(next_ea, 0); - segm_entries.push_back(get_dword(next_ea)); - next_ea += 4; - create_dword(next_ea, 4); - set_cmt(next_ea, "Size of raw data", 0); - op_hex(next_ea, 0); - segm_raw_sizes.push_back(get_dword(next_ea)); - next_ea += 4; - create_dword(next_ea, 4); - set_cmt(next_ea, "Pointer to raw data", 0); - op_hex(next_ea, 0); - next_ea += 4; - create_dword(next_ea, 4); - set_cmt(next_ea, "Pointer to relocations", 0); - op_hex(next_ea, 0); - next_ea += 4; - create_dword(next_ea, 4); - set_cmt(next_ea, "Pointer to line numbers", 0); - op_hex(next_ea, 0); - next_ea += 4; - create_word(next_ea, 2); - set_cmt(next_ea, "Number of relocations", 0); - op_hex(next_ea, 0); - next_ea += 2; - create_word(next_ea, 2); - set_cmt(next_ea, "Number of linenumbers", 0); - op_hex(next_ea, 0); - next_ea += 2; - create_dword(next_ea, 4); - set_cmt(next_ea, "Characteristics", 0); - op_hex(next_ea, 0); - uint32_t section_characteristics = get_dword(next_ea); - next_ea += 4; - - qstring section_name = qstring(_image_name.c_str()); - section_name += qstring("_") + qstring(segm_names[0].c_str()); - - ea_t seg_ea = image_base + segm_entries[0]; - ea_t seg_ea_end = seg_ea + segm_raw_sizes[0]; - msg("[efiXloader]\tprocessing: %s\n", segm_names[0].c_str()); - - segments.push_back(make_generic_segment(seg_ea, seg_ea_end, section_name.c_str(), - section_characteristics)); - segm_names.pop_back(); - segm_sizes.pop_back(); - segm_raw_sizes.pop_back(); - segm_entries.pop_back(); - return next_ea; + create_strlit(next_ea, 8, STRTYPE_C); + set_cmt(next_ea, "Name", 0); + op_hex(next_ea, 0); + size_t segm_name_len = get_max_strlit_length(next_ea, STRTYPE_C); + + if (segm_name_len) { + get_strlit_contents(&segm_names.push_back(), next_ea, segm_name_len, STRTYPE_C); + } else { + // if the segm_name_len is 0, it will trigger a crash on segm_names.pop_back() + // later. + segm_names.push_back("UNKNOWN"); + } + + next_ea += 8; + create_dword(next_ea, 4); + set_cmt(next_ea, "Virtual size", 0); + op_hex(next_ea, 0); + segm_sizes.push_back(get_dword(next_ea)); + next_ea += 4; + create_dword(next_ea, 4); + set_cmt(next_ea, "Virtual address", 0); + op_hex(next_ea, 0); + segm_entries.push_back(get_dword(next_ea)); + next_ea += 4; + create_dword(next_ea, 4); + set_cmt(next_ea, "Size of raw data", 0); + op_hex(next_ea, 0); + segm_raw_sizes.push_back(get_dword(next_ea)); + next_ea += 4; + create_dword(next_ea, 4); + set_cmt(next_ea, "Pointer to raw data", 0); + op_hex(next_ea, 0); + next_ea += 4; + create_dword(next_ea, 4); + set_cmt(next_ea, "Pointer to relocations", 0); + op_hex(next_ea, 0); + next_ea += 4; + create_dword(next_ea, 4); + set_cmt(next_ea, "Pointer to line numbers", 0); + op_hex(next_ea, 0); + next_ea += 4; + create_word(next_ea, 2); + set_cmt(next_ea, "Number of relocations", 0); + op_hex(next_ea, 0); + next_ea += 2; + create_word(next_ea, 2); + set_cmt(next_ea, "Number of linenumbers", 0); + op_hex(next_ea, 0); + next_ea += 2; + create_dword(next_ea, 4); + set_cmt(next_ea, "Characteristics", 0); + op_hex(next_ea, 0); + uint32_t section_characteristics = get_dword(next_ea); + next_ea += 4; + + qstring section_name = qstring(_image_name.c_str()); + section_name += qstring("_") + qstring(segm_names[0].c_str()); + + ea_t seg_ea = image_base + segm_entries[0]; + ea_t seg_ea_end = seg_ea + segm_raw_sizes[0]; + msg("[efiXloader]\tprocessing: %s\n", segm_names[0].c_str()); + + segments.push_back(make_generic_segment(seg_ea, seg_ea_end, section_name.c_str(), + section_characteristics)); + segm_names.pop_back(); + segm_sizes.pop_back(); + segm_raw_sizes.pop_back(); + segm_entries.pop_back(); + return next_ea; } void efiloader::PE::setup_ds_selector() { - for (; !secs_names.empty(); secs_names.pop_back()) { - msg("[efiXloader]\tsetting DS ( 0x%016llX ) for %s segment\n", - static_cast(data_segment_sel), - secs_names[secs_names.size() - 1].c_str()); - segment_t *seg = get_segm_by_name(secs_names[secs_names.size() - 1].c_str()); - set_default_sreg_value(seg, str2reg("DS"), data_segment_sel); - } + for (; !secs_names.empty(); secs_names.pop_back()) { + msg("[efiXloader]\tsetting DS ( 0x%016llX ) for %s segment\n", + static_cast(data_segment_sel), + secs_names[secs_names.size() - 1].c_str()); + segment_t *seg = get_segm_by_name(secs_names[secs_names.size() - 1].c_str()); + set_default_sreg_value(seg, str2reg("DS"), data_segment_sel); + } } // @@ -416,332 +416,331 @@ void efiloader::PE::setup_ds_selector() { // void efiloader::PE::preprocess() { - char seg_name[MAXNAMESIZE] = {0}; - char seg_header_name[MAXNAMESIZE] = {0}; - char image_base_name[MAXNAMESIZE] = {0}; - char section_name[MAXNAMESIZE] = {0}; - ea_t next_ea = 0; - ea_t ea = align_up(*pe_base, PAGE_SIZE); - image_base = ea; - ea_t start = ea; - ea_t end = ea + qlsize(li); - qsnprintf(seg_name, sizeof(seg_name), "%s_%08X", _image_name.c_str(), - calc_file_crc32(li)); - qsnprintf(seg_header_name, sizeof(seg_header_name), "%s_HEADER", _image_name.c_str()); - qsnprintf(image_base_name, sizeof(image_base_name), "%s_IMAGE_BASE", - _image_name.c_str()); - - if (preprocess_sections() == -1) { - msg("[efiXloader]\tcannot load %s\n", _image_name.c_str()); - image_base = 0; - image_size = 0; - return; - } - push_to_idb(start, end); - segments.push_back( - make_head_segment(image_base, image_base + headers_size, seg_header_name)); - secs_names.push_back(qstring(seg_header_name)); - create_word(ea, 2); - set_cmt(ea, "PE magic number", 0); - op_hex(ea, 0); - create_word(ea + 2, 2); - set_cmt(ea + 2, "Bytes on last page of file", 0); - op_hex(ea + 2, 0); - create_word(ea + 4, 2); - set_cmt(ea + 4, "Pages in file", 0); - op_hex(ea + 4, 0); - create_word(ea + 6, 2); - set_cmt(ea + 6, "Relocations", 0); - op_hex(ea + 6, 0); - create_word(ea + 8, 2); - set_cmt(ea + 8, "Size of header in paragraphs", 0); - op_hex(ea + 8, 0); - create_word(ea + 10, 2); - set_cmt(ea + 10, "Minimum extra paragraphs needed", 0); - op_hex(ea + 10, 0); - create_word(ea + 10, 2); - set_cmt(ea + 12, "Maximum extra paragraphs needed", 0); - op_hex(ea + 12, 0); - create_word(ea + 14, 2); - set_cmt(ea + 14, "Initial (relative) SS value", 0); - op_hex(ea + 12, 0); - create_word(ea + 16, 2); - set_cmt(ea + 16, "Initial SP value", 0); - op_hex(ea + 16, 0); - create_word(ea + 18, 2); - set_cmt(ea + 18, "Checksum", 0); - op_hex(ea + 18, 0); - create_word(ea + 20, 2); - set_cmt(ea + 20, "Initial IP value", 0); - op_hex(ea + 20, 0); - create_word(ea + 22, 2); - set_cmt(ea + 22, "Initial (relative) CS value", 0); - op_hex(ea + 22, 0); - create_word(ea + 24, 2); - set_cmt(ea + 24, "File address of relocation table", 0); - op_hex(ea + 24, 0); - op_offset(ea + 24, 0, REF_OFF64, BADADDR, image_base); - create_word(ea + 26, 2); - set_cmt(ea + 26, "Overlay number", 0); - op_hex(ea + 26, 0); - create_word(ea + 28, 8); - set_cmt(ea + 28, "Reserved words", 0); - op_hex(ea + 28, 0); - create_word(ea + 36, 2); - set_cmt(ea + 36, "OEM identifier (for e_oeminfo)", 0); - op_hex(ea + 36, 0); - create_word(ea + 38, 2); - set_cmt(ea + 38, "OEM information; e_oemid specific", 0); - op_hex(ea + 38, 0); - create_word(ea + 40, 2); - set_cmt(ea + 40, "Reserved words", 0); - op_hex(ea + 38, 0); - ea_t old_ea = ea; - ea = ea + 0x3c; - create_dword(ea, 4); - if (is_loaded(ea) && get_dword(ea)) { - msg("[efiXloader] making relative offset: 0x%016llX\n", - static_cast(ea)); - op_plain_offset(ea, 0, *pe_base); - } - set_cmt(ea, "File address of new exe header", 0); - uint32_t nt_headers_off = get_dword(ea); - create_byte(old_ea + 0x40, nt_headers_off - 0x40); - set_cmt(old_ea + 0x40, "DOS Stub code", 0); - ea_t nt_headers_ea = old_ea + nt_headers_off; - add_extra_cmt(nt_headers_ea, 1, "IMAGE_NT_HEADERS"); - switch (get_word(old_ea)) { - case 0x20B: - del_items(nt_headers_ea, 3, 0x108); - break; - default: - del_items(nt_headers_ea, 3, 0xf8); - break; - } - create_dword(nt_headers_ea, 4); - set_cmt(nt_headers_ea, "Signature", 0); - op_hex(nt_headers_ea, 0); - ea_t image_file_header_ea = nt_headers_ea + 4; - add_extra_cmt(image_file_header_ea, 1, "IMAGE_FILE_HEADER"); - create_word(image_file_header_ea, 2); - set_cmt(image_file_header_ea, "Machine", 0); - op_hex(image_file_header_ea, 0); - image_file_header_ea += 2; - create_word(image_file_header_ea, 2); - set_cmt(image_file_header_ea, "Number of sections", 0); - number_of_sections = get_word(image_file_header_ea); - op_hex(image_file_header_ea, 0); - ea_t timestamp_ea = image_file_header_ea + 2; - create_dword(timestamp_ea, 4); - set_cmt(timestamp_ea, "Time stamp", 0); - ea_t pointer_to_symbol_table = timestamp_ea + 4; - create_dword(pointer_to_symbol_table, 4); - set_cmt(pointer_to_symbol_table, "Pointer to symbol table", 0); - op_hex(pointer_to_symbol_table, 0); - next_ea = pointer_to_symbol_table + 4; - create_dword(next_ea, 4); - set_cmt(next_ea, "Number of symbols", 0); - op_hex(next_ea, 0); - next_ea += 4; - uint16_t size_of_optional_header = get_word(next_ea); - create_word(next_ea, 2); - set_cmt(next_ea, "Size of optional header", 0); - op_hex(next_ea, 0); - next_ea += 2; - create_word(next_ea, 2); - set_cmt(next_ea, "Characteristics", 0); - op_hex(next_ea, 0); - next_ea += 2; - add_extra_cmt(next_ea, 1, "IMAGE_OPTIONAL_HEADER"); - ea_t image_optional_header = next_ea; - create_word(next_ea, 2); - set_cmt(next_ea, "Magic number", 0); - op_hex(next_ea, 0); - next_ea += 2; - create_byte(next_ea, 1); - set_cmt(next_ea, "Major linker version", 0); - op_hex(next_ea, 0); - next_ea += 1; - create_byte(next_ea, 1); - set_cmt(next_ea, "Minor linker version", 0); - op_hex(next_ea, 0); - next_ea += 1; - create_dword(next_ea, 4); - set_cmt(next_ea, "Size of code", 0); - op_hex(next_ea, 0); - next_ea += 4; - create_dword(next_ea, 4); - set_cmt(next_ea, "Size of initialized data", 0); - op_hex(next_ea, 0); - next_ea += 4; - create_dword(next_ea, 4); - set_cmt(next_ea, "Size of uninitialized data", 0); - op_hex(next_ea, 0); - next_ea += 4; - create_dword(next_ea, 4); - set_cmt(next_ea, "Address of entry point", 0); - make_entry(get_dword(next_ea)); - refinfo_t ri; - ri.init(REF_OFF64, image_base); - if (is_loaded(next_ea) && get_dword(next_ea)) { - op_offset_ex(next_ea, 0, &ri); - } - next_ea += 4; - create_dword(next_ea, 4); - if (is_loaded(next_ea) && get_dword(next_ea)) { - op_offset_ex(next_ea, 0, &ri); - } - set_cmt(next_ea, "Base of code", 0); - next_ea += 4; - uint64_t default_image_base = get_qword(next_ea); - create_qword(next_ea, 8); - set_cmt(next_ea, "Image base", 0); - op_hex(next_ea, 0); - op_plain_offset(next_ea, 0, *pe_base); - next_ea += 8; - create_dword(next_ea, 4); - set_cmt(next_ea, "Section alignment", 0); - op_hex(next_ea, 0); - next_ea += 4; - create_dword(next_ea, 4); - set_cmt(next_ea, "File alignment", 0); - op_hex(next_ea, 0); - next_ea += 4; - create_word(next_ea, 2); - set_cmt(next_ea, "Major operating system version", 0); - op_hex(next_ea, 0); - next_ea += 2; - create_word(next_ea, 2); - set_cmt(next_ea, "Minor operating system version", 0); - op_hex(next_ea, 0); - next_ea += 2; - create_word(next_ea, 2); - set_cmt(next_ea, "Major image version", 0); - op_hex(next_ea, 0); - next_ea += 2; - create_word(next_ea, 2); - set_cmt(next_ea, "Minor image version", 0); - op_hex(next_ea, 0); - next_ea += 2; - create_word(next_ea, 2); - set_cmt(next_ea, "Major subsystem version", 0); - op_hex(next_ea, 0); - next_ea += 2; - create_word(next_ea, 2); - set_cmt(next_ea, "Minor subsystem version", 0); - op_hex(next_ea, 0); - next_ea += 2; - create_dword(next_ea, 4); - set_cmt(next_ea, "Win32 Version value", 0); - op_hex(next_ea, 0); - next_ea += 4; - create_dword(next_ea, 4); - set_cmt(next_ea, "Size of image", 0); - op_hex(next_ea, 0); - image_size = get_dword(next_ea); - next_ea += 4; - create_dword(next_ea, 4); - set_cmt(next_ea, "Size of headers", 0); - op_hex(next_ea, 0); - next_ea += 4; - create_dword(next_ea, 4); - set_cmt(next_ea, "Checksum", 0); - op_hex(next_ea, 0); - next_ea += 4; - create_word(next_ea, 2); - set_cmt(next_ea, "Subsystem", 0); - op_hex(next_ea, 0); - next_ea += 2; - create_word(next_ea, 2); - set_cmt(next_ea, "Dll characteristics", 0); - op_hex(next_ea, 0); - next_ea += 2; - create_qword(next_ea, 8); - set_cmt(next_ea, "Size of stack reserve", 0); - op_hex(next_ea, 0); - next_ea += 8; - create_qword(next_ea, 8); - set_cmt(next_ea, "Size of stack commit", 0); - op_hex(next_ea, 0); - next_ea += 8; - create_qword(next_ea, 8); - set_cmt(next_ea, "Size of heap reserve", 0); - op_hex(next_ea, 0); - next_ea += 8; - create_qword(next_ea, 8); - set_cmt(next_ea, "Size of heap commit", 0); - op_hex(next_ea, 0); - next_ea += 8; - create_dword(next_ea, 4); - set_cmt(next_ea, "Loader flag", 0); - op_hex(next_ea, 0); - next_ea += 4; - create_dword(next_ea, 4); - set_cmt(next_ea, "Number of data directories", 0); - op_hex(next_ea, 0); - while (!is_loaded(next_ea)) { - continue; - } - number_of_dirs = get_dword(next_ea); - uint32_t va = 0; - uint32_t size = 0; - next_ea += 4; - for (int i = 0; i < number_of_dirs; i++) { - if (is_reloc_dir(i)) { - uint32_t relocs_rva = get_dword(next_ea); - uint32_t relocs_size = get_dword(next_ea + 4); - if (relocs_rva && relocs_size) { - ea_t relocs_va = image_base + relocs_rva; - ea_t relocs_va_end = relocs_va + relocs_size; - ea_t delta = image_base - default_image_base; - ea_t block_addr = get_dword(relocs_va); - ea_t block_size = get_dword(relocs_va + 4); - while (block_size && relocs_va < relocs_va_end) { - ea_t block_base = image_base + block_addr; - int block_reloc_count = (block_size - 8) / 2; - - ea_t block_ptr = relocs_va + 8; - while (block_reloc_count--) { - uint16_t reloc_value = get_word(block_ptr); - uint16_t type = reloc_value & PER_TYPE; - uint16_t offset = reloc_value & PER_OFF; - if (type == PER_DIR64) - add_qword(block_base + offset, delta); - else if (type == PER_HIGHLOW) - add_dword(block_base + offset, (uint32_t)delta); - else if (type == PER_HIGH) - add_word(block_base + offset, (uint16_t)(delta >> 16)); - else if (type == PER_LOW) - add_word(block_base + offset, (uint16_t)delta); - block_ptr += 2; - } - relocs_va += block_size; - - block_addr = get_dword(relocs_va); - block_size = get_dword(relocs_va + 4); - } - } - } - if (is_reloc_dir(i) || is_debug_dir(i)) { - add_extra_cmt(next_ea, true, "%s", DIRECTORIES[i]); - create_dword(next_ea, 4); - create_dword(next_ea + 4, 4); - op_hex(next_ea, 0); - op_hex(next_ea + 4, 0); - set_cmt(next_ea, "Virtual address", 0); - set_cmt(next_ea + 4, "Size", 0); - } else { - create_qword(next_ea, 8); - set_cmt(next_ea, DIRECTORIES[i], 0); + char seg_name[MAXNAMESIZE] = {0}; + char seg_header_name[MAXNAMESIZE] = {0}; + char image_base_name[MAXNAMESIZE] = {0}; + char section_name[MAXNAMESIZE] = {0}; + ea_t next_ea = 0; + ea_t ea = align_up(*pe_base, PAGE_SIZE); + image_base = ea; + ea_t start = ea; + ea_t end = ea + qlsize(li); + qsnprintf(seg_name, sizeof(seg_name), "%s_%08X", _image_name.c_str(), + calc_file_crc32(li)); + qsnprintf(seg_header_name, sizeof(seg_header_name), "%s_HEADER", _image_name.c_str()); + qsnprintf(image_base_name, sizeof(image_base_name), "%s_IMAGE_BASE", + _image_name.c_str()); + + if (preprocess_sections() == -1) { + msg("[efiXloader]\tcannot load %s\n", _image_name.c_str()); + image_base = 0; + image_size = 0; + return; + } + push_to_idb(start, end); + segments.push_back( + make_head_segment(image_base, image_base + headers_size, seg_header_name)); + secs_names.push_back(qstring(seg_header_name)); + create_word(ea, 2); + set_cmt(ea, "PE magic number", 0); + op_hex(ea, 0); + create_word(ea + 2, 2); + set_cmt(ea + 2, "Bytes on last page of file", 0); + op_hex(ea + 2, 0); + create_word(ea + 4, 2); + set_cmt(ea + 4, "Pages in file", 0); + op_hex(ea + 4, 0); + create_word(ea + 6, 2); + set_cmt(ea + 6, "Relocations", 0); + op_hex(ea + 6, 0); + create_word(ea + 8, 2); + set_cmt(ea + 8, "Size of header in paragraphs", 0); + op_hex(ea + 8, 0); + create_word(ea + 10, 2); + set_cmt(ea + 10, "Minimum extra paragraphs needed", 0); + op_hex(ea + 10, 0); + create_word(ea + 10, 2); + set_cmt(ea + 12, "Maximum extra paragraphs needed", 0); + op_hex(ea + 12, 0); + create_word(ea + 14, 2); + set_cmt(ea + 14, "Initial (relative) SS value", 0); + op_hex(ea + 12, 0); + create_word(ea + 16, 2); + set_cmt(ea + 16, "Initial SP value", 0); + op_hex(ea + 16, 0); + create_word(ea + 18, 2); + set_cmt(ea + 18, "Checksum", 0); + op_hex(ea + 18, 0); + create_word(ea + 20, 2); + set_cmt(ea + 20, "Initial IP value", 0); + op_hex(ea + 20, 0); + create_word(ea + 22, 2); + set_cmt(ea + 22, "Initial (relative) CS value", 0); + op_hex(ea + 22, 0); + create_word(ea + 24, 2); + set_cmt(ea + 24, "File address of relocation table", 0); + op_hex(ea + 24, 0); + op_offset(ea + 24, 0, REF_OFF64, BADADDR, image_base); + create_word(ea + 26, 2); + set_cmt(ea + 26, "Overlay number", 0); + op_hex(ea + 26, 0); + create_word(ea + 28, 8); + set_cmt(ea + 28, "Reserved words", 0); + op_hex(ea + 28, 0); + create_word(ea + 36, 2); + set_cmt(ea + 36, "OEM identifier (for e_oeminfo)", 0); + op_hex(ea + 36, 0); + create_word(ea + 38, 2); + set_cmt(ea + 38, "OEM information; e_oemid specific", 0); + op_hex(ea + 38, 0); + create_word(ea + 40, 2); + set_cmt(ea + 40, "Reserved words", 0); + op_hex(ea + 38, 0); + ea_t old_ea = ea; + ea = ea + 0x3c; + create_dword(ea, 4); + if (is_loaded(ea) && get_dword(ea)) { + msg("[efiXloader] making relative offset: 0x%016llX\n", static_cast(ea)); + op_plain_offset(ea, 0, *pe_base); + } + set_cmt(ea, "File address of new exe header", 0); + uint32_t nt_headers_off = get_dword(ea); + create_byte(old_ea + 0x40, nt_headers_off - 0x40); + set_cmt(old_ea + 0x40, "DOS Stub code", 0); + ea_t nt_headers_ea = old_ea + nt_headers_off; + add_extra_cmt(nt_headers_ea, 1, "IMAGE_NT_HEADERS"); + switch (get_word(old_ea)) { + case 0x20B: + del_items(nt_headers_ea, 3, 0x108); + break; + default: + del_items(nt_headers_ea, 3, 0xf8); + break; + } + create_dword(nt_headers_ea, 4); + set_cmt(nt_headers_ea, "Signature", 0); + op_hex(nt_headers_ea, 0); + ea_t image_file_header_ea = nt_headers_ea + 4; + add_extra_cmt(image_file_header_ea, 1, "IMAGE_FILE_HEADER"); + create_word(image_file_header_ea, 2); + set_cmt(image_file_header_ea, "Machine", 0); + op_hex(image_file_header_ea, 0); + image_file_header_ea += 2; + create_word(image_file_header_ea, 2); + set_cmt(image_file_header_ea, "Number of sections", 0); + number_of_sections = get_word(image_file_header_ea); + op_hex(image_file_header_ea, 0); + ea_t timestamp_ea = image_file_header_ea + 2; + create_dword(timestamp_ea, 4); + set_cmt(timestamp_ea, "Time stamp", 0); + ea_t pointer_to_symbol_table = timestamp_ea + 4; + create_dword(pointer_to_symbol_table, 4); + set_cmt(pointer_to_symbol_table, "Pointer to symbol table", 0); + op_hex(pointer_to_symbol_table, 0); + next_ea = pointer_to_symbol_table + 4; + create_dword(next_ea, 4); + set_cmt(next_ea, "Number of symbols", 0); + op_hex(next_ea, 0); + next_ea += 4; + uint16_t size_of_optional_header = get_word(next_ea); + create_word(next_ea, 2); + set_cmt(next_ea, "Size of optional header", 0); + op_hex(next_ea, 0); + next_ea += 2; + create_word(next_ea, 2); + set_cmt(next_ea, "Characteristics", 0); + op_hex(next_ea, 0); + next_ea += 2; + add_extra_cmt(next_ea, 1, "IMAGE_OPTIONAL_HEADER"); + ea_t image_optional_header = next_ea; + create_word(next_ea, 2); + set_cmt(next_ea, "Magic number", 0); + op_hex(next_ea, 0); + next_ea += 2; + create_byte(next_ea, 1); + set_cmt(next_ea, "Major linker version", 0); + op_hex(next_ea, 0); + next_ea += 1; + create_byte(next_ea, 1); + set_cmt(next_ea, "Minor linker version", 0); + op_hex(next_ea, 0); + next_ea += 1; + create_dword(next_ea, 4); + set_cmt(next_ea, "Size of code", 0); + op_hex(next_ea, 0); + next_ea += 4; + create_dword(next_ea, 4); + set_cmt(next_ea, "Size of initialized data", 0); + op_hex(next_ea, 0); + next_ea += 4; + create_dword(next_ea, 4); + set_cmt(next_ea, "Size of uninitialized data", 0); + op_hex(next_ea, 0); + next_ea += 4; + create_dword(next_ea, 4); + set_cmt(next_ea, "Address of entry point", 0); + make_entry(get_dword(next_ea)); + refinfo_t ri; + ri.init(REF_OFF64, image_base); + if (is_loaded(next_ea) && get_dword(next_ea)) { + op_offset_ex(next_ea, 0, &ri); + } + next_ea += 4; + create_dword(next_ea, 4); + if (is_loaded(next_ea) && get_dword(next_ea)) { + op_offset_ex(next_ea, 0, &ri); + } + set_cmt(next_ea, "Base of code", 0); + next_ea += 4; + uint64_t default_image_base = get_qword(next_ea); + create_qword(next_ea, 8); + set_cmt(next_ea, "Image base", 0); + op_hex(next_ea, 0); + op_plain_offset(next_ea, 0, *pe_base); + next_ea += 8; + create_dword(next_ea, 4); + set_cmt(next_ea, "Section alignment", 0); + op_hex(next_ea, 0); + next_ea += 4; + create_dword(next_ea, 4); + set_cmt(next_ea, "File alignment", 0); + op_hex(next_ea, 0); + next_ea += 4; + create_word(next_ea, 2); + set_cmt(next_ea, "Major operating system version", 0); + op_hex(next_ea, 0); + next_ea += 2; + create_word(next_ea, 2); + set_cmt(next_ea, "Minor operating system version", 0); + op_hex(next_ea, 0); + next_ea += 2; + create_word(next_ea, 2); + set_cmt(next_ea, "Major image version", 0); + op_hex(next_ea, 0); + next_ea += 2; + create_word(next_ea, 2); + set_cmt(next_ea, "Minor image version", 0); + op_hex(next_ea, 0); + next_ea += 2; + create_word(next_ea, 2); + set_cmt(next_ea, "Major subsystem version", 0); + op_hex(next_ea, 0); + next_ea += 2; + create_word(next_ea, 2); + set_cmt(next_ea, "Minor subsystem version", 0); + op_hex(next_ea, 0); + next_ea += 2; + create_dword(next_ea, 4); + set_cmt(next_ea, "Win32 Version value", 0); + op_hex(next_ea, 0); + next_ea += 4; + create_dword(next_ea, 4); + set_cmt(next_ea, "Size of image", 0); + op_hex(next_ea, 0); + image_size = get_dword(next_ea); + next_ea += 4; + create_dword(next_ea, 4); + set_cmt(next_ea, "Size of headers", 0); + op_hex(next_ea, 0); + next_ea += 4; + create_dword(next_ea, 4); + set_cmt(next_ea, "Checksum", 0); + op_hex(next_ea, 0); + next_ea += 4; + create_word(next_ea, 2); + set_cmt(next_ea, "Subsystem", 0); + op_hex(next_ea, 0); + next_ea += 2; + create_word(next_ea, 2); + set_cmt(next_ea, "Dll characteristics", 0); + op_hex(next_ea, 0); + next_ea += 2; + create_qword(next_ea, 8); + set_cmt(next_ea, "Size of stack reserve", 0); + op_hex(next_ea, 0); + next_ea += 8; + create_qword(next_ea, 8); + set_cmt(next_ea, "Size of stack commit", 0); + op_hex(next_ea, 0); + next_ea += 8; + create_qword(next_ea, 8); + set_cmt(next_ea, "Size of heap reserve", 0); + op_hex(next_ea, 0); + next_ea += 8; + create_qword(next_ea, 8); + set_cmt(next_ea, "Size of heap commit", 0); + op_hex(next_ea, 0); + next_ea += 8; + create_dword(next_ea, 4); + set_cmt(next_ea, "Loader flag", 0); + op_hex(next_ea, 0); + next_ea += 4; + create_dword(next_ea, 4); + set_cmt(next_ea, "Number of data directories", 0); + op_hex(next_ea, 0); + while (!is_loaded(next_ea)) { + continue; + } + number_of_dirs = get_dword(next_ea); + uint32_t va = 0; + uint32_t size = 0; + next_ea += 4; + for (int i = 0; i < number_of_dirs; i++) { + if (is_reloc_dir(i)) { + uint32_t relocs_rva = get_dword(next_ea); + uint32_t relocs_size = get_dword(next_ea + 4); + if (relocs_rva && relocs_size) { + ea_t relocs_va = image_base + relocs_rva; + ea_t relocs_va_end = relocs_va + relocs_size; + ea_t delta = image_base - default_image_base; + ea_t block_addr = get_dword(relocs_va); + ea_t block_size = get_dword(relocs_va + 4); + while (block_size && relocs_va < relocs_va_end) { + ea_t block_base = image_base + block_addr; + int block_reloc_count = (block_size - 8) / 2; + + ea_t block_ptr = relocs_va + 8; + while (block_reloc_count--) { + uint16_t reloc_value = get_word(block_ptr); + uint16_t type = reloc_value & PER_TYPE; + uint16_t offset = reloc_value & PER_OFF; + if (type == PER_DIR64) + add_qword(block_base + offset, delta); + else if (type == PER_HIGHLOW) + add_dword(block_base + offset, (uint32_t)delta); + else if (type == PER_HIGH) + add_word(block_base + offset, (uint16_t)(delta >> 16)); + else if (type == PER_LOW) + add_word(block_base + offset, (uint16_t)delta); + block_ptr += 2; + } + relocs_va += block_size; + + block_addr = get_dword(relocs_va); + block_size = get_dword(relocs_va + 4); } - next_ea += 8; + } } - del_items(next_ea, DELIT_EXPAND | DELIT_DELNAMES, 0x28 * number_of_sections); - for (int i = 0; i < number_of_sections; i++) { - next_ea = process_section_entry(next_ea); - memset(seg_name, 0, sizeof(seg_name)); - memset(seg_header_name, 0, sizeof(seg_name)); - memset(image_base_name, 0, sizeof(seg_name)); - memset(section_name, 0, sizeof(seg_name)); + if (is_reloc_dir(i) || is_debug_dir(i)) { + add_extra_cmt(next_ea, true, "%s", DIRECTORIES[i]); + create_dword(next_ea, 4); + create_dword(next_ea + 4, 4); + op_hex(next_ea, 0); + op_hex(next_ea + 4, 0); + set_cmt(next_ea, "Virtual address", 0); + set_cmt(next_ea + 4, "Size", 0); + } else { + create_qword(next_ea, 8); + set_cmt(next_ea, DIRECTORIES[i], 0); } + next_ea += 8; + } + del_items(next_ea, DELIT_EXPAND | DELIT_DELNAMES, 0x28 * number_of_sections); + for (int i = 0; i < number_of_sections; i++) { + next_ea = process_section_entry(next_ea); + memset(seg_name, 0, sizeof(seg_name)); + memset(seg_header_name, 0, sizeof(seg_name)); + memset(image_base_name, 0, sizeof(seg_name)); + memset(section_name, 0, sizeof(seg_name)); + } } diff --git a/efiXloader/pe.h b/efiXloader/pe.h index 885ec487..6b4d70ab 100644 --- a/efiXloader/pe.h +++ b/efiXloader/pe.h @@ -1,6 +1,6 @@ /* * efiXloader - * Copyright (C) 2020-2023 Binarly + * Copyright (C) 2020-2024 Binarly * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -43,139 +43,139 @@ namespace efiloader { class PE { - public: - PE(linput_t *i_li, std::basic_string fname, ea_t *base, ushort *sel_base, - int ord, uint16_t mt) { - _image_name = fname.substr(fname.find_last_of("/\\") + 1); - msg("[efiXloader] image name is %s\n", _image_name.c_str()); - pe_base = base; - pe_sel_base = sel_base; - li = i_li; - utils = new Utils; - _sec_off = 0; - _sec_ea = 0; - _sel = 0; - _ord = ord; - inf_set_64bit(); - if (mt == PECPU_ARM64) { - set_processor_type("arm", SETPROC_LOADER); - } else { - set_processor_type("metapc", SETPROC_LOADER); - } - cm_t cm = inf_get_cc_cm() & ~CM_MASK; - inf_set_cc_cm(cm | CM_N64); - if (default_compiler() == COMP_UNK) { - set_compiler_id(COMP_MS); - } - reset(); - }; - ~PE() { - close_linput(li); - delete utils; +public: + PE(linput_t *i_li, std::basic_string fname, ea_t *base, ushort *sel_base, int ord, + uint16_t mt) { + _image_name = fname.substr(fname.find_last_of("/\\") + 1); + msg("[efiXloader] image name is %s\n", _image_name.c_str()); + pe_base = base; + pe_sel_base = sel_base; + li = i_li; + utils = new Utils; + _sec_off = 0; + _sec_ea = 0; + _sel = 0; + _ord = ord; + inf_set_64bit(); + if (mt == PECPU_ARM64) { + set_processor_type("arm", SETPROC_LOADER); + } else { + set_processor_type("metapc", SETPROC_LOADER); } - uint32_t number_of_sections; - uint32_t number_of_dirs; - char *name; - bool is_reloc_dir(uint32_t i) { return i == 5; }; - bool is_debug_dir(uint32_t i) { return i == 6; }; - void set_64_bit_segm_and_rabase(ea_t ea) { - segment_t *tmp_seg = getseg(ea); - set_segm_addressing(tmp_seg, 2); - set_segm_base(tmp_seg, *pe_base); + cm_t cm = inf_get_cc_cm() & ~CM_MASK; + inf_set_cc_cm(cm | CM_N64); + if (default_compiler() == COMP_UNK) { + set_compiler_id(COMP_MS); } - void set_64_bit(ea_t ea) { - segment_t *tmp_seg = getseg(ea); - set_segm_addressing(tmp_seg, 2); - }; - bool is_p32(); - bool is_p32_plus(); - bool is_pe(); - bool good(); - bool process(); - uint16_t arch(); - // data processing - inline size_t make_named_byte(ea_t ea, const char *name, const char *extra = NULL, - size_t count = 1); - inline size_t make_named_word(ea_t ea, const char *name, const char *extra = NULL, - size_t count = 1); - inline size_t make_named_dword(ea_t ea, const char *name, const char *extra = NULL, - size_t count = 1); - inline size_t make_named_qword(ea_t ea, const char *name, const char *extra = NULL, - size_t count = 1); - inline ea_t skip(ea_t ea, qoff64_t off) { return ea + off; }; - // ida db processing - void push_to_idb(ea_t start, ea_t end) { - // Map header - file2base(li, 0x0, start, start + headers_size, FILEREG_PATCHABLE); - // Map sections - for (int i = 0; i < number_of_sections; i++) { - file2base(li, _sec_headers[i].s_scnptr, start + _sec_headers[i].s_vaddr, - start + _sec_headers[i].s_vaddr + _sec_headers[i].s_psize, - FILEREG_PATCHABLE); - } - }; + reset(); + }; + ~PE() { + close_linput(li); + delete utils; + } + uint32_t number_of_sections; + uint32_t number_of_dirs; + char *name; + bool is_reloc_dir(uint32_t i) { return i == 5; }; + bool is_debug_dir(uint32_t i) { return i == 6; }; + void set_64_bit_segm_and_rabase(ea_t ea) { + segment_t *tmp_seg = getseg(ea); + set_segm_addressing(tmp_seg, 2); + set_segm_base(tmp_seg, *pe_base); + } + void set_64_bit(ea_t ea) { + segment_t *tmp_seg = getseg(ea); + set_segm_addressing(tmp_seg, 2); + }; + bool is_p32(); + bool is_p32_plus(); + bool is_pe(); + bool good(); + bool process(); + uint16_t arch(); + // data processing + inline size_t make_named_byte(ea_t ea, const char *name, const char *extra = NULL, + size_t count = 1); + inline size_t make_named_word(ea_t ea, const char *name, const char *extra = NULL, + size_t count = 1); + inline size_t make_named_dword(ea_t ea, const char *name, const char *extra = NULL, + size_t count = 1); + inline size_t make_named_qword(ea_t ea, const char *name, const char *extra = NULL, + size_t count = 1); + inline ea_t skip(ea_t ea, qoff64_t off) { return ea + off; }; + // ida db processing + void push_to_idb(ea_t start, ea_t end) { + // Map header + file2base(li, 0x0, start, start + headers_size, FILEREG_PATCHABLE); + // Map sections + for (int i = 0; i < number_of_sections; i++) { + file2base(li, _sec_headers[i].s_scnptr, start + _sec_headers[i].s_vaddr, + start + _sec_headers[i].s_vaddr + _sec_headers[i].s_psize, + FILEREG_PATCHABLE); + } + }; - private: - qvector segments_ea; - std::basic_string _full_path; - std::basic_string _image_name; - efiloader::Utils *utils; - linput_t *li; - qoff64_t head_start(); - qoff64_t head_off; - qoff64_t _pe_header_off; - uint16_t headers_size; - peheader_t pe; - peheader64_t pe64; - uint16_t _sec_num; - uint16_t _bits; - qvector selectors; - qvector data_selectors; - qvector ds_seg_names; - qvector cs_seg_names; - void reset() { qlseek(li, 0); }; - const char *_machine_name(); - // - // PE image preprocessing - // - void preprocess(); - // - // sections processing - // - qvector _sec_headers; - ea_t *pe_base; - ushort *pe_sel_base; - ushort _sel; - ea_t _sec_off; - ea_t _sec_ea; - // pe ord - uval_t _ord; - ea_t image_base; - uint32_t image_size; - qvector segm_sizes; - qvector segm_raw_sizes; - qvector segm_entries; +private: + qvector segments_ea; + std::basic_string _full_path; + std::basic_string _image_name; + efiloader::Utils *utils; + linput_t *li; + qoff64_t head_start(); + qoff64_t head_off; + qoff64_t _pe_header_off; + uint16_t headers_size; + peheader_t pe; + peheader64_t pe64; + uint16_t _sec_num; + uint16_t _bits; + qvector selectors; + qvector data_selectors; + qvector ds_seg_names; + qvector cs_seg_names; + void reset() { qlseek(li, 0); }; + const char *_machine_name(); + // + // PE image preprocessing + // + void preprocess(); + // + // sections processing + // + qvector _sec_headers; + ea_t *pe_base; + ushort *pe_sel_base; + ushort _sel; + ea_t _sec_off; + ea_t _sec_ea; + // pe ord + uval_t _ord; + ea_t image_base; + uint32_t image_size; + qvector segm_sizes; + qvector segm_raw_sizes; + qvector segm_entries; - int preprocess_sections(); - // - // functions processing - // - void make_entry(ea_t ea); - void make_code(ea_t ea); - // - // segments processing - // - qstring code_segm_name; - qstring data_segm_name; - sel_t data_segment_sel; - qvector segments; - qvector segm_names; - qvector secs_names; - ea_t process_section_entry(ea_t ea); - segment_t *make_generic_segment(ea_t seg_ea, ea_t seg_ea_end, - const char *section_name, uint32_t flags); - segment_t *make_head_segment(ea_t start, ea_t end, const char *name); - void setup_ds_selector(); + int preprocess_sections(); + // + // functions processing + // + void make_entry(ea_t ea); + void make_code(ea_t ea); + // + // segments processing + // + qstring code_segm_name; + qstring data_segm_name; + sel_t data_segment_sel; + qvector segments; + qvector segm_names; + qvector secs_names; + ea_t process_section_entry(ea_t ea); + segment_t *make_generic_segment(ea_t seg_ea, ea_t seg_ea_end, const char *section_name, + uint32_t flags); + segment_t *make_head_segment(ea_t start, ea_t end, const char *name); + void setup_ds_selector(); }; } // namespace efiloader diff --git a/efiXloader/pe_ida.h b/efiXloader/pe_ida.h index 71d58917..a650b481 100644 --- a/efiXloader/pe_ida.h +++ b/efiXloader/pe_ida.h @@ -1,6 +1,6 @@ /* * efiXloader - * Copyright (C) 2020-2023 Binarly + * Copyright (C) 2020-2024 Binarly * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -44,19 +44,19 @@ // //----------------------------------------------------------------------- struct petab_t { - uint32 rva; // relative virtual address - uint32 size; // size + uint32 rva; // relative virtual address + uint32 size; // size }; // PE va/size array element template struct peheader_tpl { - int32 signature; // 00 Current value is "PE/0/0". + int32 signature; // 00 Current value is "PE/0/0". #define PEEXE_ID 0x4550 // 'PE' followed by two zeroes #define BPEEXE_ID 0x455042 // Borland's extenson for DPMI'host #define PLEXE_ID \ - 0x4C50 // 'PL', PharLap TNT DOS-Extender Lite file that uses real mode APIs + 0x4C50 // 'PL', PharLap TNT DOS-Extender Lite file that uses real mode APIs #define TEEXE_ID 0x5A56 // 'VZ', EFI Terse Executable - uint16 machine; // 04 This field specifies the type of CPU + uint16 machine; // 04 This field specifies the type of CPU // compatibility required by this image to run. // The values are: #define PECPU_UNKNOWN 0x0000 // unknown @@ -105,44 +105,44 @@ template struct peheader_tpl { #define PECPU_CEE 0xC0EE // ? #define PECPU_TRICORE 0x0520 // TRICORE (Infineon) - bool is_64bit_cpu(void) const { - return machine == PECPU_AMD64 || machine == PECPU_IA64 || machine == PECPU_ARM64; - } - bool is_pc(void) const { - return machine == PECPU_80386 || machine == PECPU_80486 || - machine == PECPU_80586 || machine == PECPU_AMD64; - } - bool is_mips(void) const { - return machine == PECPU_R3000 || machine == PECPU_R6000 || - machine == PECPU_R4000 || machine == PECPU_R10000 || - machine == PECPU_WCEMIPSV2 || machine == PECPU_MIPS16 || - machine == PECPU_MIPSFPU || machine == PECPU_MIPSFPU16; - } - - bool is_arm(void) const { - return machine == PECPU_ARM || machine == PECPU_ARMI || machine == PECPU_ARMV7; - } - - bool has_code16_bit(void) const { return is_arm() || is_mips(); } - - uint16 nobjs; // 06 This field specifies the number of entries - // in the Object Table. - qtime32_t datetime; // 08 Used to store the time and date the file was - // created or modified by the linker. - uint32 symtof; // 0C Symbol Table Offset - uint32 nsyms; // 10 Number of Symbols in Symbol Table - uint16 hdrsize; // 14 This is the number of remaining bytes in the NT - // header that follow the FLAGS field. - uint16 flags; // 16 Flag bits for the image. 0000h Program image. + bool is_64bit_cpu(void) const { + return machine == PECPU_AMD64 || machine == PECPU_IA64 || machine == PECPU_ARM64; + } + bool is_pc(void) const { + return machine == PECPU_80386 || machine == PECPU_80486 || machine == PECPU_80586 || + machine == PECPU_AMD64; + } + bool is_mips(void) const { + return machine == PECPU_R3000 || machine == PECPU_R6000 || machine == PECPU_R4000 || + machine == PECPU_R10000 || machine == PECPU_WCEMIPSV2 || + machine == PECPU_MIPS16 || machine == PECPU_MIPSFPU || + machine == PECPU_MIPSFPU16; + } + + bool is_arm(void) const { + return machine == PECPU_ARM || machine == PECPU_ARMI || machine == PECPU_ARMV7; + } + + bool has_code16_bit(void) const { return is_arm() || is_mips(); } + + uint16 nobjs; // 06 This field specifies the number of entries + // in the Object Table. + qtime32_t datetime; // 08 Used to store the time and date the file was + // created or modified by the linker. + uint32 symtof; // 0C Symbol Table Offset + uint32 nsyms; // 10 Number of Symbols in Symbol Table + uint16 hdrsize; // 14 This is the number of remaining bytes in the NT + // header that follow the FLAGS field. + uint16 flags; // 16 Flag bits for the image. 0000h Program image. #define PEF_BRVHI 0x8000 // Big endian: MSB precedes LSB in memory #define PEF_UP 0x4000 // File should be run only on a UP machine #define PEF_DLL 0x2000 // Dynamic Link Library (DLL) #define PEF_SYS 0x1000 // System file #define PEF_NSWAP \ - 0x0800 // If the image is on network media, fully load it and copy it to the - // swap file. + 0x0800 // If the image is on network media, fully load it and copy it to the + // swap file. #define PEF_SWAP \ - 0x0400 // If image is on removable media, + 0x0400 // If image is on removable media, // copy and run from swap file #define PEF_NODEB 0x0200 // Debugging info stripped #define PEF_32BIT 0x0100 // 32-bit word machine @@ -155,47 +155,47 @@ template struct peheader_tpl { #define PEF_EXEC 0x0002 // Image is executable #define PEF_NOFIX 0x0001 // Relocation info stripped - int32 first_section_pos(int32 peoff) const { - return peoff + offsetof(peheader_tpl, magic) + hdrsize; - } + int32 first_section_pos(int32 peoff) const { + return peoff + offsetof(peheader_tpl, magic) + hdrsize; + } - // COFF fields: + // COFF fields: - uint16 magic; // 18 Magic + uint16 magic; // 18 Magic #define MAGIC_ROM 0x107 // ROM image #define MAGIC_P32 0x10B // Normal PE file #define MAGIC_P32_PLUS 0x20B // 64-bit image - bool is_pe_plus(void) const { return magic == MAGIC_P32_PLUS; } - uchar vstamp_major; // 1A Major Linker Version - uchar vstamp_minor; // 1B Minor Linker Version - uint32 tsize; // 1C TEXT size (padded) - uint32 dsize; // 20 DATA size (padded) - uint32 bsize; // 24 BSS size (padded) - uint32 entry; // 28 Entry point - uint32 text_start; // 2C Base of text - union { - struct { - uint32 data_start; // 30 Base of data - - // Win32/NT extensions: - - uint32 imagebase32; // 34 Virtual base of the image. - }; - uint64 imagebase64; + bool is_pe_plus(void) const { return magic == MAGIC_P32_PLUS; } + uchar vstamp_major; // 1A Major Linker Version + uchar vstamp_minor; // 1B Minor Linker Version + uint32 tsize; // 1C TEXT size (padded) + uint32 dsize; // 20 DATA size (padded) + uint32 bsize; // 24 BSS size (padded) + uint32 entry; // 28 Entry point + uint32 text_start; // 2C Base of text + union { + struct { + uint32 data_start; // 30 Base of data + + // Win32/NT extensions: + + uint32 imagebase32; // 34 Virtual base of the image. }; - uint64 imagebase() const { - if (is_pe_plus()) - return imagebase64; - else - return imagebase32; - } - // This will be the virtual address of the first - // byte of the file (Dos Header). This must be - // a multiple of 64K. - uint32 objalign; // 38 The alignment of the objects. This must be a power - // of 2 between 512 and 256M inclusive. The default - // is 64K. - uint32 filealign; // 3C Alignment factor used to align image pages. + uint64 imagebase64; + }; + uint64 imagebase() const { + if (is_pe_plus()) + return imagebase64; + else + return imagebase32; + } + // This will be the virtual address of the first + // byte of the file (Dos Header). This must be + // a multiple of 64K. + uint32 objalign; // 38 The alignment of the objects. This must be a power + // of 2 between 512 and 256M inclusive. The default + // is 64K. + uint32 filealign; // 3C Alignment factor used to align image pages. // The alignment factor (in bytes) used to align the // base of the image pages and to determine the // granularity of per-object trailing zero pad. @@ -206,37 +206,37 @@ template struct peheader_tpl { // should be a power of 2 between 512 and 64K inclusive. // Get the file position aligned: #define FILEALIGN 512 // IDA5.1: it seems that for standard object alignment (if 4096) - // the Windows kernel does not use filealign - // (just checks that it is in the valid range) but uses 512 - uint32 get_align_mask(void) const { - return ((objalign == 4096 || filealign == 0) ? FILEALIGN : filealign) - 1; - } - uint32 align_up_in_file(uint32 pos) const { - if (is_efi()) // apparently EFI images are not aligned - return pos; - uint32 mask = get_align_mask(); - return (pos + mask) & ~mask; - } - uint32 align_down_in_file(uint32 pos) const { - return is_efi() ? pos : (pos & ~get_align_mask()); - } - uint16 osmajor; // 40 OS version number required to run this image. - uint16 osminor; // 42 OS version number required to run this image. - uint16 imagemajor; // 44 User major version number. - uint16 imageminor; // 46 User minor version number. - uint16 subsysmajor; // 48 Subsystem major version number. - uint16 subsysminor; // 4A Subsystem minor version number. - - uint32 subsystem_version(void) const { return (subsysmajor << 16) | subsysminor; } - - uint32 reserved; // 4C - uint32 imagesize; // 50 The virtual size (in bytes) of the image. - // This includes all headers. The total image size - // must be a multiple of Object Align. - uint32 allhdrsize; // 54 Total header size. The combined size of the Dos - // Header, PE Header and Object Table. - uint32 checksum; // 58 Checksum for entire file. Set to 0 by the linker. - uint16 subsys; // 5C NT Subsystem required to run this image. + // the Windows kernel does not use filealign + // (just checks that it is in the valid range) but uses 512 + uint32 get_align_mask(void) const { + return ((objalign == 4096 || filealign == 0) ? FILEALIGN : filealign) - 1; + } + uint32 align_up_in_file(uint32 pos) const { + if (is_efi()) // apparently EFI images are not aligned + return pos; + uint32 mask = get_align_mask(); + return (pos + mask) & ~mask; + } + uint32 align_down_in_file(uint32 pos) const { + return is_efi() ? pos : (pos & ~get_align_mask()); + } + uint16 osmajor; // 40 OS version number required to run this image. + uint16 osminor; // 42 OS version number required to run this image. + uint16 imagemajor; // 44 User major version number. + uint16 imageminor; // 46 User minor version number. + uint16 subsysmajor; // 48 Subsystem major version number. + uint16 subsysminor; // 4A Subsystem minor version number. + + uint32 subsystem_version(void) const { return (subsysmajor << 16) | subsysminor; } + + uint32 reserved; // 4C + uint32 imagesize; // 50 The virtual size (in bytes) of the image. + // This includes all headers. The total image size + // must be a multiple of Object Align. + uint32 allhdrsize; // 54 Total header size. The combined size of the Dos + // Header, PE Header and Object Table. + uint32 checksum; // 58 Checksum for entire file. Set to 0 by the linker. + uint16 subsys; // 5C NT Subsystem required to run this image. #define PES_UNKNOWN 0x0000 // Unknown #define PES_NATIVE 0x0001 // Native #define PES_WINGUI 0x0002 // Windows GUI @@ -252,75 +252,75 @@ template struct peheader_tpl { #define PES_XBOX 0x000E // Xbox system #define PES_BOOTAPP 0x0010 // Windows Boot Application - bool is_efi(void) const { - return subsys == PES_EFI_APP || subsys == PES_EFI_BDV || subsys == PES_EFI_RDV || - subsys == PES_EFI_ROM; - } - bool is_console_app(void) const { - return subsys == PES_WINCHAR || subsys == PES_OS2CHAR || subsys == PES_POSIX; - } - bool is_userland(void) const { - return subsys == PES_WINGUI || subsys == PES_WINCHAR || subsys == PES_OS2CHAR || - subsys == PES_POSIX || subsys == PES_WINCE; - } - uint16 dllflags; // 5E Indicates special loader requirements. + bool is_efi(void) const { + return subsys == PES_EFI_APP || subsys == PES_EFI_BDV || subsys == PES_EFI_RDV || + subsys == PES_EFI_ROM; + } + bool is_console_app(void) const { + return subsys == PES_WINCHAR || subsys == PES_OS2CHAR || subsys == PES_POSIX; + } + bool is_userland(void) const { + return subsys == PES_WINGUI || subsys == PES_WINCHAR || subsys == PES_OS2CHAR || + subsys == PES_POSIX || subsys == PES_WINCE; + } + uint16 dllflags; // 5E Indicates special loader requirements. #define PEL_PINIT 0x0001 // Per-Process Library Initialization. #define PEL_PTERM 0x0002 // Per-Process Library Termination. #define PEL_TINIT 0x0004 // Per-Thread Library Initialization. #define PEL_TTERM 0x0008 // Per-Thread Library Termination. #define PEL_HIGH_ENT \ - 0x0020 // Image can handle a high entropy 64-bit virtual address space. + 0x0020 // Image can handle a high entropy 64-bit virtual address space. #define PEL_DYNAMIC_BASE 0x0040 // The DLL can be relocated at load time. #define PEL_FORCE_INTEGRITY 0x0080 // Code integrity checks are forced. #define PEF_NX 0x0100 // The image is compatible with data execution prevention (DEP). #define PEF_NO_ISOLATION \ - 0x0200 // The image is isolation aware, but should not be isolated. + 0x0200 // The image is isolation aware, but should not be isolated. #define PEF_NO_SEH \ - 0x0400 // The image does not use structured exception handling (SEH). No - // handlers can be called in this image. + 0x0400 // The image does not use structured exception handling (SEH). No + // handlers can be called in this image. #define PEL_NO_BIND 0x0800 // Do not bind image #define PEL_APPCONTAINER 0x1000 // Image should execute in an AppContainer #define PEL_WDM_DRV 0x2000 // Driver is a WDM Driver #define PEL_GUARDCF 0x4000 // Image supports Control Flow Guard checking #define PEL_TSRVAWA 0x8000 // Image is Terminal Server aware - pointer_t stackres; // 60 Stack size needed for image. The memory is - // reserved, but only the STACK COMMIT SIZE is - // committed. The next page of the stack is a - // 'guarded page'. When the application hits the - // guarded page, the guarded page becomes valid, - // and the next page becomes the guarded page. - // This continues until the RESERVE SIZE is reached. - pointer_t stackcom; // 64 Stack commit size. - pointer_t heapres; // 68 Size of local heap to reserve. - pointer_t heapcom; // 6C Amount to commit in local heap. - uint32 loaderflags; // 70 ? - uint32 nrvas; // 74 Indicates the size of the VA/SIZE array - // that follows. - petab_t expdir; // 0 78 Export Directory - petab_t impdir; // 1 80 Import Directory - petab_t resdir; // 2 88 Resource Directory - petab_t excdir; // 3 90 Exception Directory - petab_t secdir; // 4 98 Security Directory - // The Certificate Table entry points to a table of - // attribute certificates. These certificates are not - // loaded into memory as part of the image. As such, - // the first field of this entry, which is normally - // an RVA, is a File Pointer instead - petab_t reltab; // 5 A0 Relocation Table - petab_t debdir; // 6 A8 Debug Directory - petab_t desstr; // 7 B0 Description String - petab_t cputab; // 8 B8 Machine Value - petab_t tlsdir; // 9 C0 TLS Directory - petab_t loddir; // 10 Load Configuration Directory - petab_t bimtab; // 11 Bound Import Table address and size. - petab_t iat; // 12 Import Address Table address and size. - petab_t didtab; // 13 Address and size of the Delay Import Descriptor. - petab_t comhdr; // 14 COM+ Runtime Header address and size - petab_t x00tab; // 15 Reserved - - bool is_te() const { return signature == TEEXE_ID; } - inline bool has_debdir() const; + pointer_t stackres; // 60 Stack size needed for image. The memory is + // reserved, but only the STACK COMMIT SIZE is + // committed. The next page of the stack is a + // 'guarded page'. When the application hits the + // guarded page, the guarded page becomes valid, + // and the next page becomes the guarded page. + // This continues until the RESERVE SIZE is reached. + pointer_t stackcom; // 64 Stack commit size. + pointer_t heapres; // 68 Size of local heap to reserve. + pointer_t heapcom; // 6C Amount to commit in local heap. + uint32 loaderflags; // 70 ? + uint32 nrvas; // 74 Indicates the size of the VA/SIZE array + // that follows. + petab_t expdir; // 0 78 Export Directory + petab_t impdir; // 1 80 Import Directory + petab_t resdir; // 2 88 Resource Directory + petab_t excdir; // 3 90 Exception Directory + petab_t secdir; // 4 98 Security Directory + // The Certificate Table entry points to a table of + // attribute certificates. These certificates are not + // loaded into memory as part of the image. As such, + // the first field of this entry, which is normally + // an RVA, is a File Pointer instead + petab_t reltab; // 5 A0 Relocation Table + petab_t debdir; // 6 A8 Debug Directory + petab_t desstr; // 7 B0 Description String + petab_t cputab; // 8 B8 Machine Value + petab_t tlsdir; // 9 C0 TLS Directory + petab_t loddir; // 10 Load Configuration Directory + petab_t bimtab; // 11 Bound Import Table address and size. + petab_t iat; // 12 Import Address Table address and size. + petab_t didtab; // 13 Address and size of the Delay Import Descriptor. + petab_t comhdr; // 14 COM+ Runtime Header address and size + petab_t x00tab; // 15 Reserved + + bool is_te() const { return signature == TEEXE_ID; } + inline bool has_debdir() const; }; typedef peheader_tpl peheader_t; @@ -331,27 +331,27 @@ const size_t total_rvatab_count = total_rvatab_size / sizeof(petab_t); //----------------------------------------------------------------------- struct diheader_t { - uint16 signature; // 00 Current value is "DI" + uint16 signature; // 00 Current value is "DI" #define DBG_ID 0x4944 - uint16 flags2; // 02 ?? pedump mentions about this - // I've never seen something other than 0 - uint16 machine; // 04 This field specifies the type of CPU - // compatibility required by this image to run. - uint16 flags; // 06 Flag bits for the image. - qtime32_t datetime; // 08 Used to store the time and date the file was - // created or modified by the linker. - uint32 checksum; // 12 Checksum - uint32 imagebase; // 16 Virtual base of the image. - // This will be the virtual address of the first - // byte of the file (Dos Header). This must be - // a multiple of 64K. - uint32 imagesize; // 20 The virtual size (in bytes) of the image. - // This includes all headers. The total image size - // must be a multiple of Object Align. - uint32 n_secs; // 24 Number of sections - uint32 exp_name_size; // 28 Exported Names Size - uint32 dbg_dir_size; // 32 Debug Directory Size - uint32 reserved[3]; // 36 Reserved fields + uint16 flags2; // 02 ?? pedump mentions about this + // I've never seen something other than 0 + uint16 machine; // 04 This field specifies the type of CPU + // compatibility required by this image to run. + uint16 flags; // 06 Flag bits for the image. + qtime32_t datetime; // 08 Used to store the time and date the file was + // created or modified by the linker. + uint32 checksum; // 12 Checksum + uint32 imagebase; // 16 Virtual base of the image. + // This will be the virtual address of the first + // byte of the file (Dos Header). This must be + // a multiple of 64K. + uint32 imagesize; // 20 The virtual size (in bytes) of the image. + // This includes all headers. The total image size + // must be a multiple of Object Align. + uint32 n_secs; // 24 Number of sections + uint32 exp_name_size; // 28 Exported Names Size + uint32 dbg_dir_size; // 32 Debug Directory Size + uint32 reserved[3]; // 36 Reserved fields }; //------------------------------------------------------------------------- @@ -359,23 +359,23 @@ struct diheader_t { // S E C T I O N S // struct pesection_t { - char s_name[8]; /* section name */ - uint32 s_vsize; /* virtual size */ - uint32 s_vaddr; /* virtual address */ - uint32 s_psize; /* physical size */ - int32 s_scnptr; /* file ptr to raw data for section */ - int32 s_relptr; /* file ptr to relocation */ - int32 s_lnnoptr; /* file ptr to line numbers */ - uint16 s_nreloc; /* number of relocation entries */ - uint16 s_nlnno; /* number of line number entries */ - int32 s_flags; /* flags */ + char s_name[8]; /* section name */ + uint32 s_vsize; /* virtual size */ + uint32 s_vaddr; /* virtual address */ + uint32 s_psize; /* physical size */ + int32 s_scnptr; /* file ptr to raw data for section */ + int32 s_relptr; /* file ptr to relocation */ + int32 s_lnnoptr; /* file ptr to line numbers */ + uint16 s_nreloc; /* number of relocation entries */ + uint16 s_nlnno; /* number of line number entries */ + int32 s_flags; /* flags */ #define PEST_REG 0x00000000 // obsolete: regular: allocated, relocated, loaded #define PEST_DUMMY 0x00000001 // obsolete: dummy: not allocated, relocated, not loaded #define PEST_NOLOAD 0x00000002 // obsolete: noload: allocated, relocated, not loaded #define PEST_GROUP 0x00000004 // obsolete: grouped: formed of input sections #define PEST_PAD 0x00000008 // obsolete: padding: not allocated, not relocated, loaded #define PEST_COPY \ - 0x00000010 // obsolete: copy: for decision function used + 0x00000010 // obsolete: copy: for decision function used // by field update; not // allocated, not relocated, // loaded; reloc & lineno @@ -394,16 +394,16 @@ struct pesection_t { #define PEST_OVRFLO 0x00008000L // obsolete: RLD and line number overflow sec hdr #define PEST_F0000 0x000F0000L // Unknown #define PEST_ALIGN 0x00F00000L // Alignment 2^(x-1): - uint32 get_sect_alignment(void) const { - int align = ((s_flags >> 20) & 15); - return align == 0 ? 0 : (1 << (align - 1)); - } + uint32 get_sect_alignment(void) const { + int align = ((s_flags >> 20) & 15); + return align == 0 ? 0 : (1 << (align - 1)); + } - asize_t get_vsize(const peheader_t &pe) const { - return align_up(s_vsize ? s_vsize : s_psize, pe.objalign ? pe.objalign : 1); - } + asize_t get_vsize(const peheader_t &pe) const { + return align_up(s_vsize ? s_vsize : s_psize, pe.objalign ? pe.objalign : 1); + } - asize_t get_psize(const peheader_t &pe) const { return qmin(s_psize, get_vsize(pe)); } + asize_t get_psize(const peheader_t &pe) const { return qmin(s_psize, get_vsize(pe)); } #define PEST_1000000 0x01000000L // Unknown #define PEST_DISCARD 0x02000000L // Discardable @@ -420,28 +420,28 @@ struct pesection_t { // E X P O R T S // struct peexpdir_t { - uint32 flags; // Currently set to zero. - qtime32_t datetime; // Time/Date the export data was created. - uint16 major; // A user settable major/minor version number. - uint16 minor; - uint32 dllname; // Relative Virtual Address of the Dll asciiz Name. - // This is the address relative to the Image Base. - uint32 ordbase; // First valid exported ordinal. This field specifies - // the starting ordinal number for the export - // address table for this image. Normally set to 1. - uint32 naddrs; // Indicates number of entries in the Export Address - // Table. - uint32 nnames; // This indicates the number of entries in the Name - // Ptr Table (and parallel Ordinal Table). - uint32 adrtab; // Relative Virtual Address of the Export Address - // Table. This address is relative to the Image Base. - uint32 namtab; // Relative Virtual Address of the Export Name Table - // Pointers. This address is relative to the - // beginning of the Image Base. This table is an - // array of RVA's with # NAMES entries. - uint32 ordtab; // Relative Virtual Address of Export Ordinals - // Table Entry. This address is relative to the - // beginning of the Image Base. + uint32 flags; // Currently set to zero. + qtime32_t datetime; // Time/Date the export data was created. + uint16 major; // A user settable major/minor version number. + uint16 minor; + uint32 dllname; // Relative Virtual Address of the Dll asciiz Name. + // This is the address relative to the Image Base. + uint32 ordbase; // First valid exported ordinal. This field specifies + // the starting ordinal number for the export + // address table for this image. Normally set to 1. + uint32 naddrs; // Indicates number of entries in the Export Address + // Table. + uint32 nnames; // This indicates the number of entries in the Name + // Ptr Table (and parallel Ordinal Table). + uint32 adrtab; // Relative Virtual Address of the Export Address + // Table. This address is relative to the Image Base. + uint32 namtab; // Relative Virtual Address of the Export Name Table + // Pointers. This address is relative to the + // beginning of the Image Base. This table is an + // array of RVA's with # NAMES entries. + uint32 ordtab; // Relative Virtual Address of Export Ordinals + // Table Entry. This address is relative to the + // beginning of the Image Base. }; //------------------------------------------------------------------------- @@ -449,65 +449,65 @@ struct peexpdir_t { // I M P O R T S // struct peimpdir_t { - uint32 table1; // aka OriginalFirstThunk - qtime32_t datetime; // Time/Date the import data was pre-snapped or - // zero if not pre-snapped. - uint32 fchain; // Forwarder chain - uint32 dllname; // Relative Virtual Address of the Dll asciiz Name. - // This is the address relative to the Image Base. - uint32 looktab; // aka FirstThunk - // This field contains the address of the start of - // the import lookup table for this image. The address - // is relative to the beginning of the Image Base. + uint32 table1; // aka OriginalFirstThunk + qtime32_t datetime; // Time/Date the import data was pre-snapped or + // zero if not pre-snapped. + uint32 fchain; // Forwarder chain + uint32 dllname; // Relative Virtual Address of the Dll asciiz Name. + // This is the address relative to the Image Base. + uint32 looktab; // aka FirstThunk + // This field contains the address of the start of + // the import lookup table for this image. The address + // is relative to the beginning of the Image Base. #define hibit(type) ((type(-1) >> 1) ^ type(-1)) #define IMP_BY_ORD32 hibit(uint32) // Import by ordinal, otherwise by name #define IMP_BY_ORD64 hibit(uint64) // Import by ordinal, otherwise by name - peimpdir_t(void) { memset(this, 0, sizeof(peimpdir_t)); } + peimpdir_t(void) { memset(this, 0, sizeof(peimpdir_t)); } }; struct dimpdir_t // delayed load import table { - uint32 attrs; // Attributes. + uint32 attrs; // Attributes. #define DIMP_NOBASE 0x0001 // pe.imagebase was not added to addresses - uint32 dllname; // Relative virtual address of the name of the DLL - // to be loaded. The name resides in the read-only - // data section of the image. - uint32 handle; // Relative virtual address of the module handle - // (in the data section of the image) of the DLL to - // be delay-loaded. Used for storage by the routine - // supplied to manage delay-loading. - uint32 diat; // Relative virtual address of the delay-load import - // address table. See below for further details. - uint32 dint; // Relative virtual address of the delay-load name - // table, which contains the names of the imports - // that may need to be loaded. Matches the layout of - // the Import Name Table, Section 6.4.3. Hint/Name Table. - uint32 dbiat; // Bound Delay Import Table. Relative virtual address - // of the bound delay-load address table, if it exists. - uint32 duiat; // Unload Delay Import Table. Relative virtual address - // of the unload delay-load address table, if it exists. - // This is an exact copy of the Delay Import Address - // Table. In the event that the caller unloads the DLL, - // this table should be copied back over the Delay IAT - // such that subsequent calls to the DLL continue to - // use the thunking mechanism correctly. - qtime32_t datetime; // Time stamp of DLL to which this image has been bound. + uint32 dllname; // Relative virtual address of the name of the DLL + // to be loaded. The name resides in the read-only + // data section of the image. + uint32 handle; // Relative virtual address of the module handle + // (in the data section of the image) of the DLL to + // be delay-loaded. Used for storage by the routine + // supplied to manage delay-loading. + uint32 diat; // Relative virtual address of the delay-load import + // address table. See below for further details. + uint32 dint; // Relative virtual address of the delay-load name + // table, which contains the names of the imports + // that may need to be loaded. Matches the layout of + // the Import Name Table, Section 6.4.3. Hint/Name Table. + uint32 dbiat; // Bound Delay Import Table. Relative virtual address + // of the bound delay-load address table, if it exists. + uint32 duiat; // Unload Delay Import Table. Relative virtual address + // of the unload delay-load address table, if it exists. + // This is an exact copy of the Delay Import Address + // Table. In the event that the caller unloads the DLL, + // this table should be copied back over the Delay IAT + // such that subsequent calls to the DLL continue to + // use the thunking mechanism correctly. + qtime32_t datetime; // Time stamp of DLL to which this image has been bound. }; // Bound Import Table format: struct BOUND_IMPORT_DESCRIPTOR { - qtime32_t TimeDateStamp; - uint16 OffsetModuleName; - uint16 NumberOfModuleForwarderRefs; - // Array of zero or more IMAGE_BOUND_FORWARDER_REF follows + qtime32_t TimeDateStamp; + uint16 OffsetModuleName; + uint16 NumberOfModuleForwarderRefs; + // Array of zero or more IMAGE_BOUND_FORWARDER_REF follows }; struct BOUND_FORWARDER_REF { - qtime32_t TimeDateStamp; - uint16 OffsetModuleName; - uint16 Reserved; + qtime32_t TimeDateStamp; + uint16 OffsetModuleName; + uint16 Reserved; }; //------------------------------------------------------------------------- @@ -516,21 +516,21 @@ struct BOUND_FORWARDER_REF { // struct image_tls_directory64 { - uint64 StartAddressOfRawData; - uint64 EndAddressOfRawData; - uint64 AddressOfIndex; // PDWORD - uint64 AddressOfCallBacks; // PIMAGE_TLS_CALLBACK *; - uint32 SizeOfZeroFill; - uint32 Characteristics; + uint64 StartAddressOfRawData; + uint64 EndAddressOfRawData; + uint64 AddressOfIndex; // PDWORD + uint64 AddressOfCallBacks; // PIMAGE_TLS_CALLBACK *; + uint32 SizeOfZeroFill; + uint32 Characteristics; }; struct image_tls_directory32 { - uint32 StartAddressOfRawData; - uint32 EndAddressOfRawData; - uint32 AddressOfIndex; // PDWORD - uint32 AddressOfCallBacks; // PIMAGE_TLS_CALLBACK * - uint32 SizeOfZeroFill; - uint32 Characteristics; + uint32 StartAddressOfRawData; + uint32 EndAddressOfRawData; + uint32 AddressOfIndex; // PDWORD + uint32 AddressOfCallBacks; // PIMAGE_TLS_CALLBACK * + uint32 SizeOfZeroFill; + uint32 Characteristics; }; //------------------------------------------------------------------------- @@ -540,51 +540,51 @@ struct image_tls_directory32 { // ARM, PowerPC, SH3 and SH4 WindowsCE platforms struct function_entry_ce { - uint32 FuncStart; // Virtual address of the corresponding function. - uint32 PrologLen : 8; // Number of instructions in the function's prolog. - uint32 FuncLen : 22; // Number of instructions in the function. - uint32 ThirtyTwoBit : 1; // Set if the function is comprised of 32-bit - // instructions, cleared for a 16-bit function. - uint32 ExceptionFlag : 1; // Set if an exception handler exists for the - // function. + uint32 FuncStart; // Virtual address of the corresponding function. + uint32 PrologLen : 8; // Number of instructions in the function's prolog. + uint32 FuncLen : 22; // Number of instructions in the function. + uint32 ThirtyTwoBit : 1; // Set if the function is comprised of 32-bit + // instructions, cleared for a 16-bit function. + uint32 ExceptionFlag : 1; // Set if an exception handler exists for the + // function. }; // ARMv7 struct function_entry_armv7 { - uint32 BeginAddress; // The RVA of the corresponding function - uint32 UnwindInfo; // The RVA of the unwind information, including function - // length. - // If the low 2 bits are non-zero, then this word represents a - // compacted inline form of the unwind information, - // including function length. + uint32 BeginAddress; // The RVA of the corresponding function + uint32 UnwindInfo; // The RVA of the unwind information, including function + // length. + // If the low 2 bits are non-zero, then this word represents a + // compacted inline form of the unwind information, + // including function length. }; // for MIPS and 32-bit Alpha struct function_entry_alpha { - uint32 BeginAddress; // Virtual address of the corresponding function. - uint32 EndAddress; // Virtual address of the end of the function. - uint32 ExceptionHandler; // Pointer to the exception handler to be executed. - uint32 HandlerData; // Pointer to additional information to be passed to the - // handler. - uint32 PrologEndAddress; // Virtual address of the end of the function's - // prolog. + uint32 BeginAddress; // Virtual address of the corresponding function. + uint32 EndAddress; // Virtual address of the end of the function. + uint32 ExceptionHandler; // Pointer to the exception handler to be executed. + uint32 HandlerData; // Pointer to additional information to be passed to the + // handler. + uint32 PrologEndAddress; // Virtual address of the end of the function's + // prolog. }; // x64 typedef enum _UNWIND_OP_CODES { - UWOP_PUSH_NONVOL = 0, // info == register number - UWOP_ALLOC_LARGE = 1, // alloc size/8 in next 1(info=0) or 2(info=1) slots - UWOP_ALLOC_SMALL = 2, // info == size of allocation / 8 - 1 - UWOP_SET_FPREG = 3, // FP = RSP + UNWIND_INFO.FPRegOffset*16 - UWOP_SAVE_NONVOL = 4, // info == register number, offset/8 in next slot - UWOP_SAVE_NONVOL_FAR = 5, // info == register number, offset/8 in next 2 slots - UWOP_SAVE_XMM = 6, // Version 1: info == XMM reg number, offset/8 in next slot - UWOP_EPILOG = 6, // Version 2; code offset is epilog size; - UWOP_SAVE_XMM_FAR = 7, // version 1:info == XMM reg number, offset/8 in next 2 slots - UWOP_SPARE_CODE = 7, // unused ("previously 64-bit UWOP_SAVE_XMM_FAR"); skip 2 slots - UWOP_SAVE_XMM128 = 8, // info == XMM reg number, offset/16 in next slot - UWOP_SAVE_XMM128_FAR = 9, // info == XMM reg number, offset/16 in next 2 slots - UWOP_PUSH_MACHFRAME = 10, // info == 0: no error-code, 1: with error code + UWOP_PUSH_NONVOL = 0, // info == register number + UWOP_ALLOC_LARGE = 1, // alloc size/8 in next 1(info=0) or 2(info=1) slots + UWOP_ALLOC_SMALL = 2, // info == size of allocation / 8 - 1 + UWOP_SET_FPREG = 3, // FP = RSP + UNWIND_INFO.FPRegOffset*16 + UWOP_SAVE_NONVOL = 4, // info == register number, offset/8 in next slot + UWOP_SAVE_NONVOL_FAR = 5, // info == register number, offset/8 in next 2 slots + UWOP_SAVE_XMM = 6, // Version 1: info == XMM reg number, offset/8 in next slot + UWOP_EPILOG = 6, // Version 2; code offset is epilog size; + UWOP_SAVE_XMM_FAR = 7, // version 1:info == XMM reg number, offset/8 in next 2 slots + UWOP_SPARE_CODE = 7, // unused ("previously 64-bit UWOP_SAVE_XMM_FAR"); skip 2 slots + UWOP_SAVE_XMM128 = 8, // info == XMM reg number, offset/16 in next slot + UWOP_SAVE_XMM128_FAR = 9, // info == XMM reg number, offset/16 in next 2 slots + UWOP_PUSH_MACHFRAME = 10, // info == 0: no error-code, 1: with error code } UNWIND_CODE_OPS; // Define unwind information flags. @@ -600,11 +600,11 @@ typedef enum _UNWIND_OP_CODES { // F I X U P S // struct pefixup_t { - uint32 page; // The image base plus the page rva is added to each offset - // to create the virtual address of where the fixup needs to - // be applied. - uint32 size; // Number of bytes in the fixup block. This includes the - // PAGE RVA and SIZE fields. + uint32 page; // The image base plus the page rva is added to each offset + // to create the virtual address of where the fixup needs to + // be applied. + uint32 size; // Number of bytes in the fixup block. This includes the + // PAGE RVA and SIZE fields. }; #define PER_OFF 0x0FFF @@ -665,11 +665,11 @@ struct pefixup_t { // DBG file debug entry format // struct debug_entry_t { - uint32 flags; // usually zero - qtime32_t datetime; - uint16 major; - uint16 minor; - int32 type; + uint32 flags; // usually zero + qtime32_t datetime; + uint16 major; + uint16 minor; + int32 type; #define DBG_COFF 1 #define DBG_CV 2 #define DBG_FPO 3 @@ -685,14 +685,14 @@ struct debug_entry_t { #define DBG_POGO 13 #define DBG_ILTCG 14 #define DBG_MPX 15 - uint32 size; - uint32 rva; // virtual address - uint32 seek; // ptr to data in the file + uint32 size; + uint32 rva; // virtual address + uint32 seek; // ptr to data in the file }; // now we can define has_debdir() because we have debug_entry_t defined template <> inline bool peheader_t::has_debdir() const { - return debdir.size >= sizeof(debug_entry_t) && debdir.rva != 0; + return debdir.size >= sizeof(debug_entry_t) && debdir.rva != 0; } //------------------------------------------------------------------------- @@ -700,14 +700,14 @@ template <> inline bool peheader_t::has_debdir() const { // DBG file COFF debug information header // struct coff_debug_t { - uint32 NumberOfSymbols; - uint32 LvaToFirstSymbol; - uint32 NumberOfLinenumbers; - uint32 LvaToFirstLinenumber; - uint32 RvaToFirstByteOfCode; - uint32 RvaToLastByteOfCode; - uint32 RvaToFirstByteOfData; - uint32 RvaToLastByteOfData; + uint32 NumberOfSymbols; + uint32 LvaToFirstSymbol; + uint32 NumberOfLinenumbers; + uint32 LvaToFirstLinenumber; + uint32 RvaToFirstByteOfCode; + uint32 RvaToLastByteOfCode; + uint32 RvaToFirstByteOfData; + uint32 RvaToLastByteOfData; }; //------------------------------------------------------------------------- @@ -715,12 +715,12 @@ struct coff_debug_t { // DBG file FPO debug information // struct fpo_t { - uint32 address; - uint32 size; - uint32 locals; - uint16 params; - uchar prolog; - uchar regs; + uint32 address; + uint32 size; + uint32 locals; + uint16 params; + uchar prolog; + uchar regs; #define FPO_REGS 0x07 // register number #define FPO_SEH 0x08 // #define FPO_BP 0x10 // has BP frame? @@ -734,55 +734,55 @@ struct fpo_t { // DBG file OMAP debug information struct omap_t { - uint32 a1; - uint32 a2; + uint32 a1; + uint32 a2; }; // misc entry format struct misc_debug_t { - uint32 type; // type of misc data, see defines + uint32 type; // type of misc data, see defines #define MISC_EXENAME 1 - uint32 length; // total length of record, rounded to four - // byte multiple. - uchar unicode; // TRUE if data is unicode string - uchar reserved[3]; // padding - uchar data[1]; // Actual data + uint32 length; // total length of record, rounded to four + // byte multiple. + uchar unicode; // TRUE if data is unicode string + uchar reserved[3]; // padding + uchar data[1]; // Actual data }; //---------------------------------------------------------------------- // Resource information struct rsc_dir_t { - uint32 Characteristics; - uint32 TimeDateStamp; - uint16 MajorVersion; - uint16 MinorVersion; - uint16 NumberOfNamedEntries; - uint16 NumberOfIdEntries; + uint32 Characteristics; + uint32 TimeDateStamp; + uint16 MajorVersion; + uint16 MinorVersion; + uint16 NumberOfNamedEntries; + uint16 NumberOfIdEntries; }; struct rsc_dir_entry_t { - union { - struct { - uint32 NameOffset : 31; - uint32 NameIsString : 1; - }; - uint32 Name; - uint16 Id; + union { + struct { + uint32 NameOffset : 31; + uint32 NameIsString : 1; }; - union { - uint32 OffsetToData; - struct { - uint32 OffsetToDirectory : 31; - uint32 DataIsDirectory : 1; - }; + uint32 Name; + uint16 Id; + }; + union { + uint32 OffsetToData; + struct { + uint32 OffsetToDirectory : 31; + uint32 DataIsDirectory : 1; }; + }; }; struct rsc_data_entry_t { - uint32 OffsetToData; - uint32 Size; - uint32 CodePage; - uint32 Reserved; + uint32 OffsetToData; + uint32 Size; + uint32 CodePage; + uint32 Reserved; }; // Resource types @@ -894,13 +894,13 @@ struct rsc_data_entry_t { // altval(segnum) -> s->start_ea #define PE_ALT_DBG_FPOS nodeidx_t(-1) // altval() -> translated fpos of debuginfo #define PE_ALT_IMAGEBASE \ - nodeidx_t(-2) // altval() -> loading address (usually pe.imagebase) + nodeidx_t(-2) // altval() -> loading address (usually pe.imagebase) #define PE_ALT_PEHDR_OFF nodeidx_t(-3) // altval() -> offset of PE header #define PE_ALT_NEFLAGS nodeidx_t(-4) // altval() -> neflags #define PE_ALT_TDS_LOADED \ - nodeidx_t(-5) // altval() -> tds already loaded(1) or invalid(-1) + nodeidx_t(-5) // altval() -> tds already loaded(1) or invalid(-1) #define PE_ALT_PSXDLL \ - nodeidx_t(-6) // altval() -> if POSIX(x86) imports from PSXDLL netnode + nodeidx_t(-6) // altval() -> if POSIX(x86) imports from PSXDLL netnode #define PE_ALT_OVRVA nodeidx_t(-7) // altval() -> overlay rva (if present) #define PE_ALT_OVRSZ nodeidx_t(-8) // altval() -> overlay size (if present) #define PE_SUPSTR_PDBNM nodeidx_t(-9) // supstr() -> pdb file name @@ -915,119 +915,119 @@ struct rsc_data_entry_t { #define UTDS_TAG 't' struct load_config_t { - uint32 Size; - uint32 TimeDateStamp; - uint16 MajorVersion; - uint16 MinorVersion; - uint32 GlobalFlagsClear; - uint32 GlobalFlagsSet; - uint32 CriticalSectionDefaultTimeout; - uint32 DeCommitFreeBlockThreshold; - uint32 DeCommitTotalFreeThreshold; - uint32 LockPrefixTable; // VA - uint32 MaximumAllocationSize; - uint32 VirtualMemoryThreshold; - uint32 ProcessHeapFlags; - uint32 ProcessAffinityMask; - uint16 CSDVersion; - uint16 Reserved1; - uint32 EditList; // VA - uint32 SecurityCookie; // VA - // Version 2 - uint32 SEHandlerTable; // VA - uint32 SEHandlerCount; - // Version 3 - uint32 GuardCFCheckFunctionPointer; // VA - uint32 GuardCFDispatchFunctionPointer; // VA - uint32 GuardCFFunctionTable; // VA - uint32 GuardCFFunctionCount; - uint32 GuardFlags; + uint32 Size; + uint32 TimeDateStamp; + uint16 MajorVersion; + uint16 MinorVersion; + uint32 GlobalFlagsClear; + uint32 GlobalFlagsSet; + uint32 CriticalSectionDefaultTimeout; + uint32 DeCommitFreeBlockThreshold; + uint32 DeCommitTotalFreeThreshold; + uint32 LockPrefixTable; // VA + uint32 MaximumAllocationSize; + uint32 VirtualMemoryThreshold; + uint32 ProcessHeapFlags; + uint32 ProcessAffinityMask; + uint16 CSDVersion; + uint16 Reserved1; + uint32 EditList; // VA + uint32 SecurityCookie; // VA + // Version 2 + uint32 SEHandlerTable; // VA + uint32 SEHandlerCount; + // Version 3 + uint32 GuardCFCheckFunctionPointer; // VA + uint32 GuardCFDispatchFunctionPointer; // VA + uint32 GuardCFFunctionTable; // VA + uint32 GuardCFFunctionCount; + uint32 GuardFlags; }; struct load_config64_t { - uint32 Size; - uint32 TimeDateStamp; - uint16 MajorVersion; - uint16 MinorVersion; - uint32 GlobalFlagsClear; - uint32 GlobalFlagsSet; - uint32 CriticalSectionDefaultTimeout; - uint64 DeCommitFreeBlockThreshold; - uint64 DeCommitTotalFreeThreshold; - uint64 LockPrefixTable; // VA - uint64 MaximumAllocationSize; - uint64 VirtualMemoryThreshold; - uint64 ProcessAffinityMask; - uint32 ProcessHeapFlags; - uint16 CSDVersion; - uint16 Reserved1; - uint64 EditList; // VA - uint64 SecurityCookie; // VA - // Version 2 - uint64 SEHandlerTable; // VA - uint64 SEHandlerCount; - // Version 3 - uint64 GuardCFCheckFunctionPointer; // VA - uint64 GuardCFDispatchFunctionPointer; // VA - uint64 GuardCFFunctionTable; // VA - uint64 GuardCFFunctionCount; - uint32 GuardFlags; + uint32 Size; + uint32 TimeDateStamp; + uint16 MajorVersion; + uint16 MinorVersion; + uint32 GlobalFlagsClear; + uint32 GlobalFlagsSet; + uint32 CriticalSectionDefaultTimeout; + uint64 DeCommitFreeBlockThreshold; + uint64 DeCommitTotalFreeThreshold; + uint64 LockPrefixTable; // VA + uint64 MaximumAllocationSize; + uint64 VirtualMemoryThreshold; + uint64 ProcessAffinityMask; + uint32 ProcessHeapFlags; + uint16 CSDVersion; + uint16 Reserved1; + uint64 EditList; // VA + uint64 SecurityCookie; // VA + // Version 2 + uint64 SEHandlerTable; // VA + uint64 SEHandlerCount; + // Version 3 + uint64 GuardCFCheckFunctionPointer; // VA + uint64 GuardCFDispatchFunctionPointer; // VA + uint64 GuardCFFunctionTable; // VA + uint64 GuardCFFunctionCount; + uint32 GuardFlags; }; #ifndef IMAGE_GUARD_CF_INSTRUMENTED #define IMAGE_GUARD_CF_INSTRUMENTED \ - 0x000000100 // Module performs control flow integrity checks using - // system-supplied support + 0x000000100 // Module performs control flow integrity checks using + // system-supplied support #define IMAGE_GUARD_CFW_INSTRUMENTED \ - 0x000000200 // Module performs control flow and write integrity checks + 0x000000200 // Module performs control flow and write integrity checks #define IMAGE_GUARD_CF_FUNCTION_TABLE_PRESENT \ - 0x000000400 // Module contains valid control flow target metadata + 0x000000400 // Module contains valid control flow target metadata #define IMAGE_GUARD_SECURITY_COOKIE_UNUSED \ - 0x000000800 // Module does not make use of the /GS security cookie + 0x000000800 // Module does not make use of the /GS security cookie #define IMAGE_GUARD_PROTECT_DELAYLOAD_IAT \ - 0x00001000 // Module supports read only delay load IAT + 0x00001000 // Module supports read only delay load IAT #define IMAGE_GUARD_DELAYLOAD_IAT_IN_ITS_OWN_SECTION \ - 0x00002000 // Delayload import table in its own .didat section (with nothing - // else in it) that can be freely reprotected + 0x00002000 // Delayload import table in its own .didat section (with nothing + // else in it) that can be freely reprotected #define IMAGE_GUARD_CF_FUNCTION_TABLE_SIZE_MASK \ - 0xF0000000 // Stride of Guard CF function table encoded in these bits - // (additional count of bytes per element) + 0xF0000000 // Stride of Guard CF function table encoded in these bits + // (additional count of bytes per element) #define IMAGE_GUARD_CF_FUNCTION_TABLE_SIZE_SHIFT \ - 28 // Shift to right-justify Guard CF function table stride + 28 // Shift to right-justify Guard CF function table stride #endif //---------------------------------------------------------------------- // MS Windows CLSID, GUID struct clsid_t { - uint32 id1; - uint16 id2; - uint16 id3; - uchar id4[8]; - bool operator==(const struct clsid_t &r) const { - return memcmp(this, &r, sizeof(r)) == 0; - } + uint32 id1; + uint16 id2; + uint16 id3; + uchar id4[8]; + bool operator==(const struct clsid_t &r) const { + return memcmp(this, &r, sizeof(r)) == 0; + } }; //---------------------------------------------------------------------- // RSDS debug information struct rsds_t { - uint32 magic; + uint32 magic; #define RSDS_MAGIC MC4('R', 'S', 'D', 'S') #define UTDS_MAGIC MC4('u', 'T', 'D', 'S') - clsid_t guid; - uint32 age; - // char name[]; // followed by a zero-terminated UTF8 file name + clsid_t guid; + uint32 age; + // char name[]; // followed by a zero-terminated UTF8 file name }; //---------------------------------------------------------------------- // NB10 debug information struct cv_info_pdb20_t { - uint32 magic; // 'NB10' + uint32 magic; // 'NB10' #define NB10_MAGIC MC4('N', 'B', '1', '0') - uint32 offset; - uint32 signature; - uint32 age; - // char pdb_file_name[]; + uint32 offset; + uint32 signature; + uint32 age; + // char pdb_file_name[]; }; //---------------------------------------------------------------------- @@ -1036,37 +1036,37 @@ struct cv_info_pdb20_t { // by the 'mtoc' utility. see // https://opensource.apple.com/source/cctools/cctools-921/efitools/mtoc.c.auto.html struct mtoc_info_t { - uint32 magic; // 'MTOC' + uint32 magic; // 'MTOC' #define MTOC_MAGIC MC4('M', 'T', 'O', 'C') - uchar uuid[16]; // UUID of original Mach-O file - // char debug_filename[]; + uchar uuid[16]; // UUID of original Mach-O file + // char debug_filename[]; }; // TE (Terse Executable) struct teheader_t { - uint16 signature; // 00 - uint16 machine; // 02 same as in PE + uint16 signature; // 00 + uint16 machine; // 02 same as in PE - bool is_64bit_cpu(void) const { - return machine == PECPU_AMD64 || machine == PECPU_IA64 || machine == PECPU_ARM64; - } + bool is_64bit_cpu(void) const { + return machine == PECPU_AMD64 || machine == PECPU_IA64 || machine == PECPU_ARM64; + } - uint8 nobjs; // 04 number of sections - uint8 subsys; // 05 target subsystem - uint16 strippedsize; // 06 number of bytes removed from the base of the - // original image + uint8 nobjs; // 04 number of sections + uint8 subsys; // 05 target subsystem + uint16 strippedsize; // 06 number of bytes removed from the base of the + // original image - int32 first_section_pos(int32 peoff) const { return peoff + sizeof(teheader_t); } + int32 first_section_pos(int32 peoff) const { return peoff + sizeof(teheader_t); } - // value which should be added to the sections' file offsets and RVAs - int32 te_adjust() const { return sizeof(teheader_t) - strippedsize; } + // value which should be added to the sections' file offsets and RVAs + int32 te_adjust() const { return sizeof(teheader_t) - strippedsize; } - uint32 entry; // 08 Entry point - uint32 text_start; // 0C Base of code - uint64 imagebase64; // 10 Virtual base of the image. - uint64 imagebase() const { return imagebase64; } - petab_t reltab; // 18 Relocation Table - petab_t debdir; // 20 Debug Directory + uint32 entry; // 08 Entry point + uint32 text_start; // 0C Base of code + uint64 imagebase64; // 10 Virtual base of the image. + uint64 imagebase() const { return imagebase64; } + petab_t reltab; // 18 Relocation Table + petab_t debdir; // 20 Debug Directory }; const char *get_pe_machine_name(uint16 machine); diff --git a/efiXloader/pe_manager.cpp b/efiXloader/pe_manager.cpp index a84e5c69..19bd9053 100644 --- a/efiXloader/pe_manager.cpp +++ b/efiXloader/pe_manager.cpp @@ -1,6 +1,6 @@ /* * efiXloader - * Copyright (C) 2020-2023 Binarly + * Copyright (C) 2020-2024 Binarly * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -21,13 +21,13 @@ #include "pe_manager.h" void efiloader::PeManager::process(linput_t *li, std::basic_string fname, int ord) { - efiloader::PE pe(li, fname, &pe_base, &pe_sel_base, ord, machine_type); - if (pe.good() && pe.is_p32_plus()) { - msg("[efiXloader] PE detected\n"); - pe.process(); - } else if (pe.is_p32()) { - msg("[efiXloader] this loader is not ready for PE32\n"); - } else { - warning("[efiXloader] not PE\n"); - } + efiloader::PE pe(li, fname, &pe_base, &pe_sel_base, ord, machine_type); + if (pe.good() && pe.is_p32_plus()) { + msg("[efiXloader] PE detected\n"); + pe.process(); + } else if (pe.is_p32()) { + msg("[efiXloader] this loader is not ready for PE32\n"); + } else { + warning("[efiXloader] not PE\n"); + } } diff --git a/efiXloader/pe_manager.h b/efiXloader/pe_manager.h index e4d61901..304d1313 100644 --- a/efiXloader/pe_manager.h +++ b/efiXloader/pe_manager.h @@ -1,6 +1,6 @@ /* * efiXloader - * Copyright (C) 2020-2023 Binarly + * Copyright (C) 2020-2024 Binarly * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -26,30 +26,30 @@ namespace efiloader { class PeManager { - public: - PeManager(uint16_t mt) { - inf_set_64bit(); - set_imagebase(0x0); - if (mt == PECPU_ARM64) { - set_processor_type("arm", SETPROC_LOADER); - } else { - set_processor_type("metapc", SETPROC_LOADER); - } - pe_base = 0; - pe_sel_base = 0; - machine_type = mt; - }; - void process(linput_t *li, std::basic_string fname, int ord); - uint16_t machine_type; +public: + PeManager(uint16_t mt) { + inf_set_64bit(); + set_imagebase(0x0); + if (mt == PECPU_ARM64) { + set_processor_type("arm", SETPROC_LOADER); + } else { + set_processor_type("metapc", SETPROC_LOADER); + } + pe_base = 0; + pe_sel_base = 0; + machine_type = mt; + }; + void process(linput_t *li, std::basic_string fname, int ord); + uint16_t machine_type; - private: - void to_base(linput_t *); - efiloader::PE *pe; - qvector pe_files; - ushort pe_sel_base; - ea_t pe_base; - // head processing - void pe_head_to_base(linput_t *li); +private: + void to_base(linput_t *); + efiloader::PE *pe; + qvector pe_files; + ushort pe_sel_base; + ea_t pe_base; + // head processing + void pe_head_to_base(linput_t *li); }; } // namespace efiloader diff --git a/efiXloader/uefitool.cpp b/efiXloader/uefitool.cpp index 5c8a8244..f7b9b5f3 100644 --- a/efiXloader/uefitool.cpp +++ b/efiXloader/uefitool.cpp @@ -1,6 +1,6 @@ /* * efiXloader - * Copyright (C) 2020-2023 Binarly + * Copyright (C) 2020-2024 Binarly * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -24,350 +24,345 @@ #include void efiloader::File::print() { - msg("[UEFITOOL PARSER] file ( %s ) \n", qname.c_str()); - for (int i = 0; i < 0x10; i++) { - msg("%02X ", ubytes[i]); - }; - msg("\n"); + msg("[UEFITOOL PARSER] file ( %s ) \n", qname.c_str()); + for (int i = 0; i < 0x10; i++) { + msg("%02X ", ubytes[i]); + }; + msg("\n"); } void efiloader::Uefitool::show_messages() { - for (size_t i = 0; i < messages.size(); i++) { - msg("[UEFITOOL PARSER] %s\n", messages[i].first.toLocal8Bit()); - } + for (size_t i = 0; i < messages.size(); i++) { + msg("[UEFITOOL PARSER] %s\n", messages[i].first.toLocal8Bit()); + } } void efiloader::Uefitool::get_unique_name(qstring &name) { - // If the given name is already in use, create a new one - qstring new_name = name; - std::string suf; - int index = 0; - while (!(unique_names.insert(new_name).second)) { - suf = "_" + std::to_string(++index); - new_name = name + static_cast(suf.c_str()); - } - name = new_name; + // If the given name is already in use, create a new one + qstring new_name = name; + std::string suf; + int index = 0; + while (!(unique_names.insert(new_name).second)) { + suf = "_" + std::to_string(++index); + new_name = name + static_cast(suf.c_str()); + } + name = new_name; } void efiloader::Uefitool::get_image_guid(qstring &image_guid, UModelIndex index) { - UString guid; - UModelIndex guid_index; - switch (model.subtype(model.parent(index))) { - case EFI_SECTION_COMPRESSION: - case EFI_SECTION_GUID_DEFINED: - guid_index = model.parent(model.parent(index)); - break; - default: - guid_index = model.parent(index); - } - // get parent header and read GUID - guid = guidToUString( - readUnaligned((const EFI_GUID *)(model.header(guid_index).constData()))); - image_guid = reinterpret_cast(guid.data); + UString guid; + UModelIndex guid_index; + switch (model.subtype(model.parent(index))) { + case EFI_SECTION_COMPRESSION: + case EFI_SECTION_GUID_DEFINED: + guid_index = model.parent(model.parent(index)); + break; + default: + guid_index = model.parent(index); + } + // get parent header and read GUID + guid = guidToUString( + readUnaligned((const EFI_GUID *)(model.header(guid_index).constData()))); + image_guid = reinterpret_cast(guid.data); } std::vector efiloader::Uefitool::parseDepexSectionBody(const UModelIndex &index, UString &parsed) { - // Adopted from FfsParser::parseDepexSectionBody - std::vector res; + // Adopted from FfsParser::parseDepexSectionBody + std::vector res; - if (!index.isValid()) - return res; + if (!index.isValid()) + return res; - UByteArray body = model.body(index); + UByteArray body = model.body(index); - // Check data to be present - if (body.size() < 2) { // 2 is a minimal sane value, i.e TRUE + END - return res; - } + // Check data to be present + if (body.size() < 2) { // 2 is a minimal sane value, i.e TRUE + END + return res; + } - const EFI_GUID *guid; - const UINT8 *current = (const UINT8 *)body.constData(); + const EFI_GUID *guid; + const UINT8 *current = (const UINT8 *)body.constData(); - // Special cases of first opcode - switch (*current) { - case EFI_DEP_BEFORE: - if (body.size() != 2 * EFI_DEP_OPCODE_SIZE + sizeof(EFI_GUID)) { - return res; - } - guid = (const EFI_GUID *)(current + EFI_DEP_OPCODE_SIZE); - parsed += UString("\nBEFORE ") + guidToUString(readUnaligned(guid)); - current += EFI_DEP_OPCODE_SIZE + sizeof(EFI_GUID); - if (*current != EFI_DEP_END) { - return res; - } - return res; - case EFI_DEP_AFTER: - if (body.size() != 2 * EFI_DEP_OPCODE_SIZE + sizeof(EFI_GUID)) { - return res; - } - guid = (const EFI_GUID *)(current + EFI_DEP_OPCODE_SIZE); - parsed += UString("\nAFTER ") + guidToUString(readUnaligned(guid)); - current += EFI_DEP_OPCODE_SIZE + sizeof(EFI_GUID); - if (*current != EFI_DEP_END) { - return res; - } - return res; - case EFI_DEP_SOR: - if (body.size() <= 2 * EFI_DEP_OPCODE_SIZE) { - return res; - } - parsed += UString("\nSOR"); - current += EFI_DEP_OPCODE_SIZE; - break; + // Special cases of first opcode + switch (*current) { + case EFI_DEP_BEFORE: + if (body.size() != 2 * EFI_DEP_OPCODE_SIZE + sizeof(EFI_GUID)) { + return res; + } + guid = (const EFI_GUID *)(current + EFI_DEP_OPCODE_SIZE); + parsed += UString("\nBEFORE ") + guidToUString(readUnaligned(guid)); + current += EFI_DEP_OPCODE_SIZE + sizeof(EFI_GUID); + if (*current != EFI_DEP_END) { + return res; + } + return res; + case EFI_DEP_AFTER: + if (body.size() != 2 * EFI_DEP_OPCODE_SIZE + sizeof(EFI_GUID)) { + return res; + } + guid = (const EFI_GUID *)(current + EFI_DEP_OPCODE_SIZE); + parsed += UString("\nAFTER ") + guidToUString(readUnaligned(guid)); + current += EFI_DEP_OPCODE_SIZE + sizeof(EFI_GUID); + if (*current != EFI_DEP_END) { + return res; + } + return res; + case EFI_DEP_SOR: + if (body.size() <= 2 * EFI_DEP_OPCODE_SIZE) { + return res; } + parsed += UString("\nSOR"); + current += EFI_DEP_OPCODE_SIZE; + break; + } - // Parse the rest of depex - while (current - (const UINT8 *)body.constData() < body.size()) { - switch (*current) { - case EFI_DEP_BEFORE: { - return res; - } - case EFI_DEP_AFTER: { - return res; - } - case EFI_DEP_SOR: { - return res; - } - case EFI_DEP_PUSH: - // 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)) { - parsed.clear(); - return res; - } - guid = (const EFI_GUID *)(current + EFI_DEP_OPCODE_SIZE); - parsed += UString("\nPUSH ") + guidToUString(readUnaligned(guid)); - // Add protocol GUID to result vector - res.push_back( - reinterpret_cast(guidToUString(readUnaligned(guid)).data)); - current += EFI_DEP_OPCODE_SIZE + sizeof(EFI_GUID); - break; - case EFI_DEP_AND: - parsed += UString("\nAND"); - current += EFI_DEP_OPCODE_SIZE; - break; - case EFI_DEP_OR: - parsed += UString("\nOR"); - current += EFI_DEP_OPCODE_SIZE; - break; - case EFI_DEP_NOT: - parsed += UString("\nNOT"); - current += EFI_DEP_OPCODE_SIZE; - break; - case EFI_DEP_TRUE: - parsed += UString("\nTRUE"); - current += EFI_DEP_OPCODE_SIZE; - break; - case EFI_DEP_FALSE: - parsed += UString("\nFALSE"); - current += EFI_DEP_OPCODE_SIZE; - break; - case EFI_DEP_END: - parsed += UString("\nEND"); - current += EFI_DEP_OPCODE_SIZE; - // Check that END is the last opcode - if (current - (const UINT8 *)body.constData() < body.size()) { - parsed.clear(); - } - break; - default: - return res; - break; - } + // Parse the rest of depex + while (current - (const UINT8 *)body.constData() < body.size()) { + switch (*current) { + case EFI_DEP_BEFORE: { + return res; + } + case EFI_DEP_AFTER: { + return res; + } + case EFI_DEP_SOR: { + return res; } + case EFI_DEP_PUSH: + // 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)) { + parsed.clear(); + return res; + } + guid = (const EFI_GUID *)(current + EFI_DEP_OPCODE_SIZE); + parsed += UString("\nPUSH ") + guidToUString(readUnaligned(guid)); + // Add protocol GUID to result vector + res.push_back(reinterpret_cast(guidToUString(readUnaligned(guid)).data)); + current += EFI_DEP_OPCODE_SIZE + sizeof(EFI_GUID); + break; + case EFI_DEP_AND: + parsed += UString("\nAND"); + current += EFI_DEP_OPCODE_SIZE; + break; + case EFI_DEP_OR: + parsed += UString("\nOR"); + current += EFI_DEP_OPCODE_SIZE; + break; + case EFI_DEP_NOT: + parsed += UString("\nNOT"); + current += EFI_DEP_OPCODE_SIZE; + break; + case EFI_DEP_TRUE: + parsed += UString("\nTRUE"); + current += EFI_DEP_OPCODE_SIZE; + break; + case EFI_DEP_FALSE: + parsed += UString("\nFALSE"); + current += EFI_DEP_OPCODE_SIZE; + break; + case EFI_DEP_END: + parsed += UString("\nEND"); + current += EFI_DEP_OPCODE_SIZE; + // Check that END is the last opcode + if (current - (const UINT8 *)body.constData() < body.size()) { + parsed.clear(); + } + break; + default: + return res; + break; + } + } - return res; + return res; } std::vector efiloader::Uefitool::parseAprioriRawSection(const UModelIndex &index) { - // Adopted from FfsParser::parseDepexSectionBody - std::vector res; + // Adopted from FfsParser::parseDepexSectionBody + std::vector res; - if (!index.isValid()) - return res; + if (!index.isValid()) + return res; - UByteArray body = model.body(index); + UByteArray body = model.body(index); - // Sanity check - if (body.size() % sizeof(EFI_GUID)) { - return res; - } + // Sanity check + if (body.size() % sizeof(EFI_GUID)) { + return res; + } - UINT32 count = (UINT32)(body.size() / sizeof(EFI_GUID)); - if (count > 0) { - for (UINT32 i = 0; i < count; i++) { - const EFI_GUID *guid = (const EFI_GUID *)body.constData() + i; - res.push_back( - reinterpret_cast(guidToUString(readUnaligned(guid)).data)); - } + UINT32 count = (UINT32)(body.size() / sizeof(EFI_GUID)); + if (count > 0) { + for (UINT32 i = 0; i < count; i++) { + const EFI_GUID *guid = (const EFI_GUID *)body.constData() + i; + res.push_back(reinterpret_cast(guidToUString(readUnaligned(guid)).data)); } + } - return res; + return res; } void efiloader::Uefitool::set_machine_type(UByteArray pe_body) { - const char *data = pe_body.constData(); - if (pe_body.size() < 64) { - return; - } - uint32_t _pe_header_off = *(uint32_t *)(data + 0x3c); - if (pe_body.size() < _pe_header_off + 6) { - return; - } - if (*(uint32_t *)(data + _pe_header_off) == 0x4550) { - machine_type = *(uint16_t *)(data + _pe_header_off + 4); - machine_type_detected = true; - } + const char *data = pe_body.constData(); + if (pe_body.size() < 64) { + return; + } + uint32_t _pe_header_off = *(uint32_t *)(data + 0x3c); + if (pe_body.size() < _pe_header_off + 6) { + return; + } + if (*(uint32_t *)(data + _pe_header_off) == 0x4550) { + machine_type = *(uint16_t *)(data + _pe_header_off + 4); + machine_type_detected = true; + } } void efiloader::Uefitool::handle_raw_section(const UModelIndex &index) { - UModelIndex parent_file = model.findParentOfType(index, Types::File); - if (!parent_file.isValid()) { - return; - } - UByteArray parent_file_guid(model.header(parent_file).constData(), sizeof(EFI_GUID)); - if (parent_file_guid == EFI_PEI_APRIORI_FILE_GUID) { - msg("[efiXloader] PEI Apriori file found\n"); - get_apriori(index, "PEI_APRIORI_FILE"); - } - if (parent_file_guid == EFI_DXE_APRIORI_FILE_GUID) { - msg("[efiXloader] DXE Apriori file found\n"); - get_apriori(index, "DXE_APRIORI_FILE"); - } + UModelIndex parent_file = model.findParentOfType(index, Types::File); + if (!parent_file.isValid()) { + return; + } + UByteArray parent_file_guid(model.header(parent_file).constData(), sizeof(EFI_GUID)); + if (parent_file_guid == EFI_PEI_APRIORI_FILE_GUID) { + msg("[efiXloader] PEI Apriori file found\n"); + get_apriori(index, "PEI_APRIORI_FILE"); + } + if (parent_file_guid == EFI_DXE_APRIORI_FILE_GUID) { + msg("[efiXloader] DXE Apriori file found\n"); + get_apriori(index, "DXE_APRIORI_FILE"); + } } void efiloader::Uefitool::dump(const UModelIndex &index, uint8_t el_type, efiloader::File *file) { - qstring module_name(""); - qstring guid(""); + qstring module_name(""); + qstring guid(""); - switch (model.subtype(index)) { - case EFI_SECTION_RAW: - handle_raw_section(index); - break; - case EFI_SECTION_TE: - file->is_te = true; - file->ubytes = model.body(index); - break; - case EFI_SECTION_PE32: - file->is_pe = true; - file->ubytes = model.body(index); - if (!machine_type_detected) { - 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()] = module_name.c_str(); - file->qname.swap(module_name); - file->write(); - files.push_back(file); - } - } - } - break; - case EFI_SECTION_COMPRESSION: - case EFI_SECTION_GUID_DEFINED: - for (int i = 0; i < model.rowCount(index); i++) { - dump(index.child(i, 0), i, file); - } - break; - // Get DEPEX information - case EFI_SECTION_DXE_DEPEX: - get_deps(index, "EFI_SECTION_DXE_DEPEX"); - break; - case EFI_SECTION_MM_DEPEX: - get_deps(index, "EFI_SECTION_MM_DEPEX"); - break; - case EFI_SECTION_PEI_DEPEX: - get_deps(index, "EFI_SECTION_PEI_DEPEX"); - break; - 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()] = module_name.c_str(); - } + switch (model.subtype(index)) { + case EFI_SECTION_RAW: + handle_raw_section(index); + break; + case EFI_SECTION_TE: + file->is_te = true; + file->ubytes = model.body(index); + break; + case EFI_SECTION_PE32: + file->is_pe = true; + file->ubytes = model.body(index); + if (!machine_type_detected) { + 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()] = module_name.c_str(); + file->qname.swap(module_name); + file->write(); + files.push_back(file); } - break; + } + } + break; + case EFI_SECTION_COMPRESSION: + case EFI_SECTION_GUID_DEFINED: + for (int i = 0; i < model.rowCount(index); i++) { + dump(index.child(i, 0), i, file); } + break; + // Get DEPEX information + case EFI_SECTION_DXE_DEPEX: + get_deps(index, "EFI_SECTION_DXE_DEPEX"); + break; + case EFI_SECTION_MM_DEPEX: + get_deps(index, "EFI_SECTION_MM_DEPEX"); + break; + case EFI_SECTION_PEI_DEPEX: + get_deps(index, "EFI_SECTION_PEI_DEPEX"); + break; + 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()] = module_name.c_str(); + } + } + break; + } - return dump(index); + return 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); - } - } else { - for (int i = 0; i < model.rowCount(index); i++) { - dump(index.child(i, 0)); - } + 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); + } + } else { + for (int i = 0; i < model.rowCount(index); i++) { + dump(index.child(i, 0)); } + } } void efiloader::Uefitool::dump() { return dump(model.index(0, 0)); } void efiloader::Uefitool::get_deps(UModelIndex index, std::string key) { - UString parsed; - std::vector deps; - qstring image_guid(""); + UString parsed; + std::vector deps; + qstring image_guid(""); - get_image_guid(image_guid, index); - deps = parseDepexSectionBody(index, parsed); - if (deps.size()) { - msg("[efiXloader] dependency section for image with GUID %s: %s\n", - image_guid.c_str(), parsed.data); - all_deps[key][image_guid.c_str()] = deps; - } + get_image_guid(image_guid, index); + deps = parseDepexSectionBody(index, parsed); + if (deps.size()) { + msg("[efiXloader] dependency section for image with GUID %s: %s\n", + image_guid.c_str(), parsed.data); + all_deps[key][image_guid.c_str()] = deps; + } } void efiloader::Uefitool::get_apriori(UModelIndex index, std::string key) { - if (all_deps.contains(key)) { - return; - } - std::vector deps = parseAprioriRawSection(index); - if (deps.empty()) { - return; - } - all_deps[key] = deps; + if (all_deps.contains(key)) { + return; + } + std::vector deps = parseAprioriRawSection(index); + if (deps.empty()) { + return; + } + all_deps[key] = deps; } void efiloader::Uefitool::dump_jsons() { - // Dump deps - std::filesystem::path out; - out /= get_path(PATH_TYPE_IDB); - out.replace_extension(".deps.json"); - std::ofstream out_deps(out); - out_deps << std::setw(4) << all_deps << std::endl; - // Dump images - out.replace_extension("").replace_extension(".images.json"); - std::ofstream out_guids(out); - out_guids << std::setw(4) << images_guids << std::endl; + // Dump deps + std::filesystem::path out; + out /= get_path(PATH_TYPE_IDB); + out.replace_extension(".deps.json"); + std::ofstream out_deps(out); + out_deps << std::setw(4) << all_deps << std::endl; + // Dump images + out.replace_extension("").replace_extension(".images.json"); + std::ofstream out_guids(out); + out_guids << std::setw(4) << images_guids << std::endl; } diff --git a/efiXloader/uefitool.h b/efiXloader/uefitool.h index 647f88ee..241f5ed1 100644 --- a/efiXloader/uefitool.h +++ b/efiXloader/uefitool.h @@ -1,6 +1,6 @@ /* * efiXloader - * Copyright (C) 2020-2023 Binarly + * Copyright (C) 2020-2024 Binarly * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -53,96 +53,96 @@ using namespace nlohmann; enum FILE_SECTION_TYPE { - PE_DEPENDENCY_SECTION = 0, - PE_TE_IMAGE_SECTION = 1, - UI_SECTION = 2, - VERSION_SECTION = 3 + PE_DEPENDENCY_SECTION = 0, + PE_TE_IMAGE_SECTION = 1, + UI_SECTION = 2, + VERSION_SECTION = 3 }; namespace efiloader { class File { - public: - File() {} - void set_data(char *data_in, uint32_t size_in) { - qname.qclear(); - bytes.resize(size_in); - memcpy(&bytes[0], data_in, size_in); - }; - void write() { - qstring idb_path(get_path(PATH_TYPE_IDB)); - qstring images_path = idb_path + qstring(".efiloader"); +public: + File() {} + void set_data(char *data_in, uint32_t size_in) { + qname.qclear(); + bytes.resize(size_in); + memcpy(&bytes[0], data_in, size_in); + }; + void write() { + qstring idb_path(get_path(PATH_TYPE_IDB)); + qstring images_path = idb_path + qstring(".efiloader"); #ifdef WIN32 - _mkdir(images_path.c_str()); + _mkdir(images_path.c_str()); #else - mkdir(images_path.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); + 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()); - std::ofstream file; - file.open(image_path.c_str(), std::ios::out | std::ios::binary); - file.write(ubytes.constData(), ubytes.size()); - file.close(); - dump_name.swap(image_path); - } + if (!qname.empty()) { + qstring image_path = images_path + qstring("/") + qstring(qname.c_str()); + std::ofstream file; + file.open(image_path.c_str(), std::ios::out | std::ios::binary); + file.write(ubytes.constData(), ubytes.size()); + file.close(); + dump_name.swap(image_path); } - void print(); - UByteArray ubytes; - UByteArray uname; - bytevec_t bytes; - char *data = NULL; - uint32_t size = 0; - std::string name_utf8; - std::string name_utf16; - qstring qname; - qstring dump_name; - bool is_pe = false; - bool is_te = false; - bool has_ui = false; + } + void print(); + UByteArray ubytes; + UByteArray uname; + bytevec_t bytes; + char *data = NULL; + uint32_t size = 0; + std::string name_utf8; + std::string name_utf16; + qstring qname; + qstring dump_name; + bool is_pe = false; + bool is_te = false; + bool has_ui = false; }; class Uefitool { - public: - Uefitool(bytevec_t &data) { - buffer = (const char *)&data[0]; - buffer_size = data.size(); - UByteArray ubuffer(buffer, buffer_size); - FfsParser ffs(&model); - if (ffs.parse(ubuffer)) { - loader_failure("failed to parse data via UEFITool"); - } - messages = ffs.getMessages(); +public: + Uefitool(bytevec_t &data) { + buffer = (const char *)&data[0]; + buffer_size = data.size(); + UByteArray ubuffer(buffer, buffer_size); + FfsParser ffs(&model); + if (ffs.parse(ubuffer)) { + loader_failure("failed to parse data via UEFITool"); } - ~Uefitool() {}; - void show_messages(); - 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 handle_raw_section(const UModelIndex &index); - bool is_pe_index(const UModelIndex &index) { return model.rowCount(index) == 4; }; - bool is_file_index(const UModelIndex &index) { - return model.type(index) == Types::File; - }; - void get_unique_name(qstring &image_name); - void get_image_guid(qstring &image_guid, UModelIndex index); - std::vector parseDepexSectionBody(const UModelIndex &index, - UString &parsed); - std::vector parseAprioriRawSection(const UModelIndex &index); - void get_deps(UModelIndex index, std::string key); - void get_apriori(UModelIndex index, std::string key); - void dump_jsons(); // dump JSON with DEPEX and GUIDs information for each image - json all_deps; // DEPEX information for each image - json images_guids; // matching the modules to the parent's 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; + messages = ffs.getMessages(); + } + ~Uefitool() {}; + void show_messages(); + 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 handle_raw_section(const UModelIndex &index); + bool is_pe_index(const UModelIndex &index) { return model.rowCount(index) == 4; }; + bool is_file_index(const UModelIndex &index) { + return model.type(index) == Types::File; + }; + void get_unique_name(qstring &image_name); + void get_image_guid(qstring &image_guid, UModelIndex index); + std::vector parseDepexSectionBody(const UModelIndex &index, + UString &parsed); + std::vector parseAprioriRawSection(const UModelIndex &index); + void get_deps(UModelIndex index, std::string key); + void get_apriori(UModelIndex index, std::string key); + void dump_jsons(); // dump JSON with DEPEX and GUIDs information for each image + json all_deps; // DEPEX information for each image + json images_guids; // matching the modules to the parent's 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; }; } // namespace efiloader diff --git a/efiXloader/utils.cpp b/efiXloader/utils.cpp index 123abcb3..08aef36c 100644 --- a/efiXloader/utils.cpp +++ b/efiXloader/utils.cpp @@ -1,6 +1,6 @@ /* * efiXloader - * Copyright (C) 2020-2023 Binarly + * Copyright (C) 2020-2024 Binarly * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -21,71 +21,71 @@ #include "utils.h" void efiloader::Utils::show_hex(void *buffer, size_t length, const char *prefix) { - uint8_t *buf = (uint8_t *)buffer; - msg("[efiXloader] %s = ", prefix); - for (int i = 0; i < length; i++) { - msg("%02x", buf[i]); - } - msg("\n"); + uint8_t *buf = (uint8_t *)buffer; + msg("[efiXloader] %s = ", prefix); + for (int i = 0; i < length; i++) { + msg("%02x", buf[i]); + } + msg("\n"); } bool efiloader::Utils::find_vol(bytevec_t &frm, std::string &sig, qoff64_t &vol_off) { - auto found = std::search(frm.begin(), frm.end(), sig.begin(), sig.end()); - if (found != frm.end()) { - vol_off = std::distance(frm.begin(), found); - return true; - } else { - return false; - } + auto found = std::search(frm.begin(), frm.end(), sig.begin(), sig.end()); + if (found != frm.end()) { + vol_off = std::distance(frm.begin(), found); + return true; + } else { + return false; + } } qoff64_t efiloader::Utils::find_vol_new(linput_t *li, char *sig) { - qoff64_t sig_off; - char buf[5] = {0}; - while (qltell(li) != qlsize(li)) { - qlread(li, &buf, 4); - if (strneq(buf, sig, 4)) { + qoff64_t sig_off; + char buf[5] = {0}; + while (qltell(li) != qlsize(li)) { + qlread(li, &buf, 4); + if (strneq(buf, sig, 4)) { #ifdef DEBUG - msg("[efiloader:PARSER] found FV sign %s: %#x\n", buf, qltell(li) - 4); + msg("[efiloader:PARSER] found FV sign %s: %#x\n", buf, qltell(li) - 4); #endif - return qltell(li) - 4 - 0x28; - } + return qltell(li) - 4 - 0x28; } - return -1; + } + return -1; } qoff64_t efiloader::Utils::find_vol_test(bytevec_t &data) { - std::string tmp(data.begin(), data.end()); - std::size_t res = tmp.find("_FVH"); - if (res != std::string::npos) { - return res - 0x28; - } - return res; + std::string tmp(data.begin(), data.end()); + std::size_t res = tmp.find("_FVH"); + if (res != std::string::npos) { + return res - 0x28; + } + return res; } void efiloader::Utils::skip(memory_deserializer_t *ser, size_t size, size_t count) { - switch (size) { - case 1: - for (int i = 0; i < count; i++) { - ser->unpack_db(); - } - break; - case 2: - for (int i = 0; i < count; i++) { - ser->unpack_dw(); - } - break; - case 4: - for (int i = 0; i < count; i++) { - ser->unpack_dd(); - } - break; - case 8: - for (int i = 0; i < count; i++) { - ser->unpack_dq(); - } - break; - default: - break; + switch (size) { + case 1: + for (int i = 0; i < count; i++) { + ser->unpack_db(); + } + break; + case 2: + for (int i = 0; i < count; i++) { + ser->unpack_dw(); + } + break; + case 4: + for (int i = 0; i < count; i++) { + ser->unpack_dd(); + } + break; + case 8: + for (int i = 0; i < count; i++) { + ser->unpack_dq(); } + break; + default: + break; + } } diff --git a/efiXloader/utils.h b/efiXloader/utils.h index 4032564f..bb7fbeb3 100644 --- a/efiXloader/utils.h +++ b/efiXloader/utils.h @@ -1,6 +1,6 @@ /* * efiXloader - * Copyright (C) 2020-2023 Binarly + * Copyright (C) 2020-2024 Binarly * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -30,13 +30,13 @@ namespace efiloader { class Utils { - public: - Utils() { ; }; - void show_hex(void *buffer, size_t length, const char *prefix); - bool find_vol(bytevec_t &frm, std::string &sig, qoff64_t &vol_off); - qoff64_t find_vol_new(linput_t *li, char *sig); - qoff64_t find_vol_test(bytevec_t &data); - void skip(memory_deserializer_t *ser, size_t size, size_t count); +public: + Utils() { ; }; + void show_hex(void *buffer, size_t length, const char *prefix); + bool find_vol(bytevec_t &frm, std::string &sig, qoff64_t &vol_off); + qoff64_t find_vol_new(linput_t *li, char *sig); + qoff64_t find_vol_test(bytevec_t &data); + void skip(memory_deserializer_t *ser, size_t size, size_t count); }; } // namespace efiloader From 5fefc5077e915ea4a170f87b51550c0845e413ce Mon Sep 17 00:00:00 2001 From: yeggor Date: Wed, 11 Sep 2024 08:02:46 +0200 Subject: [PATCH 08/69] unify tables usage, remove tables and use efi_defs instead, change indent --- efiXplorer/.clang-format | 2 +- efiXplorer/CMakeLists.txt | 11 +- efiXplorer/efiAnalyzer.h | 544 +- efiXplorer/efiAnalyzerArm.cpp | 792 ++- efiXplorer/efiAnalyzerX86.cpp | 4952 ++++++++--------- efiXplorer/efiDeps.cpp | 662 ++- efiXplorer/efiDeps.h | 62 +- efiXplorer/efiGlobal.cpp | 4 +- efiXplorer/efiGlobal.h | 16 +- efiXplorer/efiHexRays.cpp | 580 +- efiXplorer/efiHexRays.h | 1943 ++++--- efiXplorer/efiSmmUtils.cpp | 1000 ++-- efiXplorer/efiSmmUtils.h | 2 +- efiXplorer/efiUi.cpp | 469 +- efiXplorer/efiUi.h | 426 +- efiXplorer/efiUtils.cpp | 1451 +++-- efiXplorer/efiUtils.h | 161 +- efiXplorer/efiXplorer.cpp | 145 +- efiXplorer/efiXplorer.h | 4 +- .../{tables/efi_services.h => efi_defs.cpp} | 276 +- efiXplorer/efi_defs.h | 326 ++ efiXplorer/tables/efi_pei_tables.h | 237 - efiXplorer/tables/efi_system_tables.h | 597 -- 23 files changed, 6855 insertions(+), 7807 deletions(-) rename efiXplorer/{tables/efi_services.h => efi_defs.cpp} (56%) create mode 100644 efiXplorer/efi_defs.h delete mode 100644 efiXplorer/tables/efi_pei_tables.h delete mode 100644 efiXplorer/tables/efi_system_tables.h diff --git a/efiXplorer/.clang-format b/efiXplorer/.clang-format index 6bde2289..92cfffbb 100644 --- a/efiXplorer/.clang-format +++ b/efiXplorer/.clang-format @@ -2,4 +2,4 @@ Language: Cpp BasedOnStyle: LLVM ColumnLimit: 90 -IndentWidth: 4 +IndentWidth: 2 diff --git a/efiXplorer/CMakeLists.txt b/efiXplorer/CMakeLists.txt index fecf7088..69a94b96 100644 --- a/efiXplorer/CMakeLists.txt +++ b/efiXplorer/CMakeLists.txt @@ -27,21 +27,24 @@ include_directories(${PROJECT_SOURCE_DIR}/3rd/nlohmann_json) # efiXplorer sources set(efiXplorer_src + "efi_defs.h" + "efi_defs.cpp" + "efiAnalyzer.h" "efiAnalyzerArm.cpp" "efiAnalyzerX86.cpp" - "efiAnalyzer.h" "efiDeps.cpp" "efiDeps.h" - "efiGlobal.h" "efiGlobal.cpp" + "efiGlobal.h" "efiSmmUtils.cpp" "efiSmmUtils.h" "efiUi.cpp" "efiUi.h" "efiUtils.cpp" "efiUtils.h" - "efiXplorer.cpp" - "efiXplorer.h") + "efixplorer.cpp" + "efixplorer.h" +) if(HexRaysSdk_ROOT_DIR) add_definitions(-DHEX_RAYS=1) diff --git a/efiXplorer/efiAnalyzer.h b/efiXplorer/efiAnalyzer.h index 4286e5a4..16928fbe 100644 --- a/efiXplorer/efiAnalyzer.h +++ b/efiXplorer/efiAnalyzer.h @@ -1,6 +1,6 @@ /* * efiXplorer - * Copyright (C) 2020-2023 Binarly + * Copyright (C) 2020-2024 Binarly * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -23,314 +23,314 @@ #include "efiSmmUtils.h" #include "efiUtils.h" +#include "efi_defs.h" #ifdef HEX_RAYS #include "efiHexRays.h" #endif -namespace EfiAnalysis { +namespace efi_analysis { class EfiAnalyzer { - public: - EfiAnalyzer(); - ~EfiAnalyzer(); +public: + EfiAnalyzer(); + ~EfiAnalyzer(); - std::vector allGuids; - std::vector allProtocols; - std::vector allPPIs; - std::vector allServices; - std::vector smiHandlers; - uint8_t arch; + std::vector allGuids; + std::vector allProtocols; + std::vector allPPIs; + std::vector allServices; + std::vector smiHandlers; + uint8_t arch; - void getSegments(); - void setStrings(); + void getSegments(); + void setStrings(); - void printInterfaces(); - void markInterfaces(); - void markDataGuids(); + void printInterfaces(); + void markInterfaces(); + void markDataGuids(); - bool efiSmmCpuProtocolResolver(); - void findSwSmiHandlers(); - bool findGetVariableOveflow(std::vector allServices); - bool findPPIGetVariableStackOveflow(); - bool findSmmGetVariableOveflow(); - bool findSmmCallout(); - bool analyzeNvramVariables(); - bool AnalyzeVariableService(ea_t ea, std::string service_str); - bool AddProtocol(std::string serviceName, ea_t guidAddress, ea_t xrefAddress, - ea_t callAddress); - void dumpInfo(); + bool efiSmmCpuProtocolResolver(); + void findSwSmiHandlers(); + bool findGetVariableOveflow(std::vector allServices); + bool findPPIGetVariableStackOveflow(); + bool findSmmGetVariableOveflow(); + bool findSmmCallout(); + bool analyzeNvramVariables(); + bool AnalyzeVariableService(ea_t ea, std::string service_str); + bool AddProtocol(std::string serviceName, ea_t guidAddress, ea_t xrefAddress, + ea_t callAddress); + void dumpInfo(); - uint8_t fileType = 0; - json dbProtocols; - ea_t base; - ea_t startAddress = 0; - ea_t endAddress = 0; - std::vector funcs; - std::filesystem::path guidsJsonPath; - std::map dbProtocolsMap; // a map to look up a GUID name by value - json bootServices; - json peiServices; - json peiServicesAll; - json ppiCallsAll; - json runtimeServicesAll; - json smmServices; - json smmServicesAll; - std::vector nvramVariables; - std::vector markedInterfaces; + uint8_t fileType = 0; + json dbProtocols; + ea_t base; + ea_t startAddress = 0; + ea_t endAddress = 0; + std::vector funcs; + std::filesystem::path guidsJsonPath; + std::map dbProtocolsMap; // a map to look up a GUID name by value + json bootServices; + json peiServices; + json peiServicesAll; + json ppiCallsAll; + json runtimeServicesAll; + json smmServices; + json smmServicesAll; + std::vector nvramVariables; + std::vector markedInterfaces; - // Format-dependent interface-related settings (protocols for DXE, PPIs for PEI) - std::string if_name; - std::string if_pl; - std::string if_key; - std::vector *if_tbl; + // Format-dependent interface-related settings (protocols for DXE, PPIs for PEI) + std::string if_name; + std::string if_pl; + std::string if_key; + std::vector *if_tbl; - // EFI_SMM_SW_DISPATCH2_PROTOCOL_GUID - EfiGuid sw_guid2 = { - 0x18a3c6dc, 0x5eea, 0x48c8, {0xa1, 0xc1, 0xb5, 0x33, 0x89, 0xf9, 0x89, 0x99}}; - // EFI_SMM_SW_DISPATCH_PROTOCOL_GUID - EfiGuid sw_guid = { - 0xe541b773, 0xdd11, 0x420c, {0xb0, 0x26, 0xdf, 0x99, 0x36, 0x53, 0xf8, 0xbf}}; - // EFI_SMM_SX_DISPATCH2_PROTOCOL_GUID - EfiGuid sx_guid2 = { - 0x456d2859, 0xa84b, 0x4e47, {0xa2, 0xee, 0x32, 0x76, 0xd8, 0x86, 0x99, 0x7d}}; - // EFI_SMM_SX_DISPATCH_PROTOCOL_GUID - EfiGuid sx_guid = { - 0x14FC52BE, 0x01DC, 0x426C, {0x91, 0xAE, 0xA2, 0x3C, 0x3E, 0x22, 0x0A, 0xE8}}; - // EFI_SMM_IO_TRAP_DISPATCH2_PROTOCOL_GUID - EfiGuid io_trap_guid2 = { - 0x58DC368D, 0x7BFA, 0x4E77, {0xAB, 0xBC, 0x0E, 0x29, 0x41, 0x8D, 0xF9, 0x30}}; - // EFI_SMM_IO_TRAP_DISPATCH_PROTOCOL_GUID - EfiGuid io_trap_guid = { - 0xDB7F536B, 0xEDE4, 0x4714, {0xA5, 0xC8, 0xE3, 0x46, 0xEB, 0xAA, 0x20, 0x1D}}; - // EFI_SMM_GPI_DISPATCH2_PROTOCOL_GUID - EfiGuid gpi_guid2 = { - 0x25566B03, 0xB577, 0x4CBF, {0x95, 0x8C, 0xED, 0x66, 0x3E, 0xA2, 0x43, 0x80}}; - // EFI_SMM_GPI_DISPATCH_PROTOCOL_GUID - EfiGuid gpi_guid = { - 0xE0744B81, 0x9513, 0x49CD, {0x8C, 0xEA, 0xE9, 0x24, 0x5E, 0x70, 0x39, 0xDA}}; - // EFI_SMM_USB_DISPATCH2_PROTOCOL_GUID - EfiGuid usb_guid2 = { - 0xEE9B8D90, 0xC5A6, 0x40A2, {0xBD, 0xE2, 0x52, 0x55, 0x8D, 0x33, 0xCC, 0xA1}}; - // EFI_SMM_USB_DISPATCH_PROTOCOL_GUID - EfiGuid usb_guid = { - 0xA05B6FFD, 0x87AF, 0x4E42, {0x95, 0xC9, 0x62, 0x28, 0xB6, 0x3C, 0xF3, 0xF3}}; - // EFI_SMM_STANDBY_BUTTON_DISPATCH2_PROTOCOL_GUID - EfiGuid standby_button_guid2 = { - 0x7300C4A1, 0x43F2, 0x4017, {0xA5, 0x1B, 0xC8, 0x1A, 0x7F, 0x40, 0x58, 0x5B}}; - // EFI_SMM_STANDBY_BUTTON_DISPATCH_PROTOCOL_GUID - EfiGuid standby_button_guid = { - 0x78965B98, 0xB0BF, 0x449E, {0x8B, 0x22, 0xD2, 0x91, 0x4E, 0x49, 0x8A, 0x98}}; - // EFI_SMM_PERIODIC_TIMER_DISPATCH2_PROTOCOL_GUID - EfiGuid periodic_timer_guid2 = { - 0x4CEC368E, 0x8E8E, 0x4D71, {0x8B, 0xE1, 0x95, 0x8C, 0x45, 0xFC, 0x8A, 0x53}}; - // EFI_SMM_PERIODIC_TIMER_DISPATCH_PROTOCOL_GUID - EfiGuid periodic_timer_guid = { - 0x9CCA03FC, 0x4C9E, 0x4A19, {0x9B, 0x06, 0xED, 0x7B, 0x47, 0x9B, 0xDE, 0x55}}; - // EFI_SMM_POWER_BUTTON_DISPATCH2_PROTOCOL_GUID - EfiGuid power_button_guid2 = { - 0x1B1183FA, 0x1823, 0x46A7, {0x88, 0x72, 0x9C, 0x57, 0x87, 0x55, 0x40, 0x9D}}; - // EFI_SMM_POWER_BUTTON_DISPATCH_PROTOCOL_GUID - EfiGuid power_button_guid = { - 0xB709EFA0, 0x47A6, 0x4B41, {0xB9, 0x31, 0x12, 0xEC, 0xE7, 0xA8, 0xEE, 0x56}}; - // EFI_SMM_ICHN_DISPATCH_PROTOCOL_GUID - EfiGuid ichn_guid = { - 0xC50B323E, 0x9075, 0x4F2A, {0xAC, 0x8E, 0xD2, 0x59, 0x6A, 0x10, 0x85, 0xCC}}; - // EFI_SMM_ICHN_DISPATCH2_PROTOCOL_GUID - EfiGuid ichn_guid2 = { - 0xADF3A128, 0x416D, 0x4060, {0x8D, 0xDF, 0x30, 0xA1, 0xD7, 0xAA, 0xB6, 0x99}}; - // PCH_TCO_SMI_DISPATCH_PROTOCOL_GUID - EfiGuid tco_guid = { - 0x9E71D609, 0x6D24, 0x47FD, {0xB5, 0x72, 0x61, 0x40, 0xF8, 0xD9, 0xC2, 0xA4}}; - // PCH_PCIE_SMI_DISPATCH_PROTOCOL_GUID - EfiGuid pcie_guid = { - 0x3E7D2B56, 0x3F47, 0x42AA, {0x8F, 0x6B, 0x22, 0xF5, 0x19, 0x81, 0x8D, 0xAB}}; - // PCH_ACPI_SMI_DISPATCH_PROTOCOL_GUID - EfiGuid acpi_guid = { - 0xD52BB262, 0xF022, 0x49EC, {0x86, 0xD2, 0x7A, 0x29, 0x3A, 0x7A, 0x5, 0x4B}}; - // PCH_GPIO_UNLOCK_SMI_DISPATCH_PROTOCOL_GUID - EfiGuid gpio_unlock_guid = { - 0x83339EF7, 0x9392, 0x4716, {0x8D, 0x3A, 0xD1, 0xFC, 0x67, 0xCD, 0x55, 0xDB}}; - // PCH_SMI_DISPATCH_PROTOCOL_GUID - EfiGuid pch_guid = { - 0xE6A81BBF, 0x873D, 0x47FD, {0xB6, 0xBE, 0x61, 0xB3, 0xE5, 0x72, 0x9, 0x93}}; - // PCH_ESPI_SMI_DISPATCH_PROTOCOL_GUID - EfiGuid espi_guid = { - 0xB3C14FF3, 0xBAE8, 0x456C, {0x86, 0x31, 0x27, 0xFE, 0x0C, 0xEB, 0x34, 0x0C}}; - // EFI_ACPI_EN_DISPATCH_PROTOCOL_GUID - EfiGuid acpi_en_guid = { - 0xBD88EC68, 0xEBE4, 0x4F7B, {0x93, 0x5A, 0x4F, 0x66, 0x66, 0x42, 0xE7, 0x5F}}; - // EFI_ACPI_DIS_DISPATCH_PROTOCOL_GUID - EfiGuid acpi_dis_guid = { - 0x9C939BA6, 0x1FCC, 0x46F6, {0xB4, 0xE1, 0x10, 0x2D, 0xBE, 0x18, 0x65, 0x67}}; - // FCH_SMM_GPI_DISPATCH2_PROTOCOL_GUID - EfiGuid fch_gpi_guid2 = { - 0x7051ab6d, 0x9ec2, 0x42eb, {0xa2, 0x13, 0xde, 0x48, 0x81, 0xf1, 0xf7, 0x87}}; - // FCH_SMM_IO_TRAP_DISPATCH2_PROTOCOL_GUID - EfiGuid fch_io_trap_guid2 = { - 0x91288fc4, 0xe64b, 0x4ef9, {0xa4, 0x63, 0x66, 0x88, 0x0, 0x71, 0x7f, 0xca}}; - // FCH_SMM_PERIODICAL_DISPATCH2_PROTOCOL_GUID - EfiGuid fch_periodical_guid2 = { - 0x736102f1, 0x9584, 0x44e7, {0x82, 0x8a, 0x43, 0x4b, 0x1e, 0x67, 0x5c, 0xc4}}; - // FCH_SMM_PWR_BTN_DISPATCH2_PROTOCOL_GUID - EfiGuid fch_pwr_btn_guid2 = { - 0xa365240e, 0x56b0, 0x426d, {0x83, 0xa, 0x30, 0x66, 0xc6, 0x81, 0xbe, 0x9a}}; - // FCH_SMM_SW_DISPATCH2_PROTOCOL_GUID - EfiGuid fch_sw_guid2 = { - 0x881b4ab6, 0x17b0, 0x4bdf, {0x88, 0xe2, 0xd4, 0x29, 0xda, 0x42, 0x5f, 0xfd}}; - // FCH_SMM_SX_DISPATCH2_PROTOCOL_GUID - EfiGuid fch_sx_guid2 = { - 0x87e2a6cf, 0x91fb, 0x4581, {0x90, 0xa9, 0x6f, 0x50, 0x5d, 0xdc, 0x1c, 0xb2}}; - // FCH_SMM_USB_DISPATCH_PROTOCOL_GUID - EfiGuid fch_usb_guid = { - 0x59053b0d, 0xeeb8, 0x4379, {0xb1, 0xc8, 0x14, 0x5f, 0x1b, 0xb, 0xe4, 0xb9}}; - // FCH_SMM_USB_DISPATCH2_PROTOCOL_GUID - EfiGuid fch_usb_guid2 = { - 0xfbbb2ea9, 0xce0e, 0x4689, {0xb3, 0xf0, 0xc6, 0xb8, 0xf0, 0x76, 0xbd, 0x20}}; - // FCH_SMM_MISC_DISPATCH_PROTOCOL_GUID - EfiGuid fch_misc_guid = { - 0x13bd659b, 0xb4c6, 0x47da, {0x9b, 0x22, 0x11, 0x50, 0xd4, 0xf3, 0xb, 0xda}}; - // FCH_SMM_APU_RAS_DISPATCH_PROTOCOL_GUID - EfiGuid fch_apu_ras_guid = { - 0xf871ee59, 0x29d2, 0x4b15, {0x9e, 0x67, 0xaf, 0x32, 0xcd, 0xc1, 0x41, 0x73}}; + // EFI_SMM_SW_DISPATCH2_PROTOCOL_GUID + EfiGuid sw_guid2 = { + 0x18a3c6dc, 0x5eea, 0x48c8, {0xa1, 0xc1, 0xb5, 0x33, 0x89, 0xf9, 0x89, 0x99}}; + // EFI_SMM_SW_DISPATCH_PROTOCOL_GUID + EfiGuid sw_guid = { + 0xe541b773, 0xdd11, 0x420c, {0xb0, 0x26, 0xdf, 0x99, 0x36, 0x53, 0xf8, 0xbf}}; + // EFI_SMM_SX_DISPATCH2_PROTOCOL_GUID + EfiGuid sx_guid2 = { + 0x456d2859, 0xa84b, 0x4e47, {0xa2, 0xee, 0x32, 0x76, 0xd8, 0x86, 0x99, 0x7d}}; + // EFI_SMM_SX_DISPATCH_PROTOCOL_GUID + EfiGuid sx_guid = { + 0x14FC52BE, 0x01DC, 0x426C, {0x91, 0xAE, 0xA2, 0x3C, 0x3E, 0x22, 0x0A, 0xE8}}; + // EFI_SMM_IO_TRAP_DISPATCH2_PROTOCOL_GUID + EfiGuid io_trap_guid2 = { + 0x58DC368D, 0x7BFA, 0x4E77, {0xAB, 0xBC, 0x0E, 0x29, 0x41, 0x8D, 0xF9, 0x30}}; + // EFI_SMM_IO_TRAP_DISPATCH_PROTOCOL_GUID + EfiGuid io_trap_guid = { + 0xDB7F536B, 0xEDE4, 0x4714, {0xA5, 0xC8, 0xE3, 0x46, 0xEB, 0xAA, 0x20, 0x1D}}; + // EFI_SMM_GPI_DISPATCH2_PROTOCOL_GUID + EfiGuid gpi_guid2 = { + 0x25566B03, 0xB577, 0x4CBF, {0x95, 0x8C, 0xED, 0x66, 0x3E, 0xA2, 0x43, 0x80}}; + // EFI_SMM_GPI_DISPATCH_PROTOCOL_GUID + EfiGuid gpi_guid = { + 0xE0744B81, 0x9513, 0x49CD, {0x8C, 0xEA, 0xE9, 0x24, 0x5E, 0x70, 0x39, 0xDA}}; + // EFI_SMM_USB_DISPATCH2_PROTOCOL_GUID + EfiGuid usb_guid2 = { + 0xEE9B8D90, 0xC5A6, 0x40A2, {0xBD, 0xE2, 0x52, 0x55, 0x8D, 0x33, 0xCC, 0xA1}}; + // EFI_SMM_USB_DISPATCH_PROTOCOL_GUID + EfiGuid usb_guid = { + 0xA05B6FFD, 0x87AF, 0x4E42, {0x95, 0xC9, 0x62, 0x28, 0xB6, 0x3C, 0xF3, 0xF3}}; + // EFI_SMM_STANDBY_BUTTON_DISPATCH2_PROTOCOL_GUID + EfiGuid standby_button_guid2 = { + 0x7300C4A1, 0x43F2, 0x4017, {0xA5, 0x1B, 0xC8, 0x1A, 0x7F, 0x40, 0x58, 0x5B}}; + // EFI_SMM_STANDBY_BUTTON_DISPATCH_PROTOCOL_GUID + EfiGuid standby_button_guid = { + 0x78965B98, 0xB0BF, 0x449E, {0x8B, 0x22, 0xD2, 0x91, 0x4E, 0x49, 0x8A, 0x98}}; + // EFI_SMM_PERIODIC_TIMER_DISPATCH2_PROTOCOL_GUID + EfiGuid periodic_timer_guid2 = { + 0x4CEC368E, 0x8E8E, 0x4D71, {0x8B, 0xE1, 0x95, 0x8C, 0x45, 0xFC, 0x8A, 0x53}}; + // EFI_SMM_PERIODIC_TIMER_DISPATCH_PROTOCOL_GUID + EfiGuid periodic_timer_guid = { + 0x9CCA03FC, 0x4C9E, 0x4A19, {0x9B, 0x06, 0xED, 0x7B, 0x47, 0x9B, 0xDE, 0x55}}; + // EFI_SMM_POWER_BUTTON_DISPATCH2_PROTOCOL_GUID + EfiGuid power_button_guid2 = { + 0x1B1183FA, 0x1823, 0x46A7, {0x88, 0x72, 0x9C, 0x57, 0x87, 0x55, 0x40, 0x9D}}; + // EFI_SMM_POWER_BUTTON_DISPATCH_PROTOCOL_GUID + EfiGuid power_button_guid = { + 0xB709EFA0, 0x47A6, 0x4B41, {0xB9, 0x31, 0x12, 0xEC, 0xE7, 0xA8, 0xEE, 0x56}}; + // EFI_SMM_ICHN_DISPATCH_PROTOCOL_GUID + EfiGuid ichn_guid = { + 0xC50B323E, 0x9075, 0x4F2A, {0xAC, 0x8E, 0xD2, 0x59, 0x6A, 0x10, 0x85, 0xCC}}; + // EFI_SMM_ICHN_DISPATCH2_PROTOCOL_GUID + EfiGuid ichn_guid2 = { + 0xADF3A128, 0x416D, 0x4060, {0x8D, 0xDF, 0x30, 0xA1, 0xD7, 0xAA, 0xB6, 0x99}}; + // PCH_TCO_SMI_DISPATCH_PROTOCOL_GUID + EfiGuid tco_guid = { + 0x9E71D609, 0x6D24, 0x47FD, {0xB5, 0x72, 0x61, 0x40, 0xF8, 0xD9, 0xC2, 0xA4}}; + // PCH_PCIE_SMI_DISPATCH_PROTOCOL_GUID + EfiGuid pcie_guid = { + 0x3E7D2B56, 0x3F47, 0x42AA, {0x8F, 0x6B, 0x22, 0xF5, 0x19, 0x81, 0x8D, 0xAB}}; + // PCH_ACPI_SMI_DISPATCH_PROTOCOL_GUID + EfiGuid acpi_guid = { + 0xD52BB262, 0xF022, 0x49EC, {0x86, 0xD2, 0x7A, 0x29, 0x3A, 0x7A, 0x5, 0x4B}}; + // PCH_GPIO_UNLOCK_SMI_DISPATCH_PROTOCOL_GUID + EfiGuid gpio_unlock_guid = { + 0x83339EF7, 0x9392, 0x4716, {0x8D, 0x3A, 0xD1, 0xFC, 0x67, 0xCD, 0x55, 0xDB}}; + // PCH_SMI_DISPATCH_PROTOCOL_GUID + EfiGuid pch_guid = { + 0xE6A81BBF, 0x873D, 0x47FD, {0xB6, 0xBE, 0x61, 0xB3, 0xE5, 0x72, 0x9, 0x93}}; + // PCH_ESPI_SMI_DISPATCH_PROTOCOL_GUID + EfiGuid espi_guid = { + 0xB3C14FF3, 0xBAE8, 0x456C, {0x86, 0x31, 0x27, 0xFE, 0x0C, 0xEB, 0x34, 0x0C}}; + // EFI_ACPI_EN_DISPATCH_PROTOCOL_GUID + EfiGuid acpi_en_guid = { + 0xBD88EC68, 0xEBE4, 0x4F7B, {0x93, 0x5A, 0x4F, 0x66, 0x66, 0x42, 0xE7, 0x5F}}; + // EFI_ACPI_DIS_DISPATCH_PROTOCOL_GUID + EfiGuid acpi_dis_guid = { + 0x9C939BA6, 0x1FCC, 0x46F6, {0xB4, 0xE1, 0x10, 0x2D, 0xBE, 0x18, 0x65, 0x67}}; + // FCH_SMM_GPI_DISPATCH2_PROTOCOL_GUID + EfiGuid fch_gpi_guid2 = { + 0x7051ab6d, 0x9ec2, 0x42eb, {0xa2, 0x13, 0xde, 0x48, 0x81, 0xf1, 0xf7, 0x87}}; + // FCH_SMM_IO_TRAP_DISPATCH2_PROTOCOL_GUID + EfiGuid fch_io_trap_guid2 = { + 0x91288fc4, 0xe64b, 0x4ef9, {0xa4, 0x63, 0x66, 0x88, 0x0, 0x71, 0x7f, 0xca}}; + // FCH_SMM_PERIODICAL_DISPATCH2_PROTOCOL_GUID + EfiGuid fch_periodical_guid2 = { + 0x736102f1, 0x9584, 0x44e7, {0x82, 0x8a, 0x43, 0x4b, 0x1e, 0x67, 0x5c, 0xc4}}; + // FCH_SMM_PWR_BTN_DISPATCH2_PROTOCOL_GUID + EfiGuid fch_pwr_btn_guid2 = { + 0xa365240e, 0x56b0, 0x426d, {0x83, 0xa, 0x30, 0x66, 0xc6, 0x81, 0xbe, 0x9a}}; + // FCH_SMM_SW_DISPATCH2_PROTOCOL_GUID + EfiGuid fch_sw_guid2 = { + 0x881b4ab6, 0x17b0, 0x4bdf, {0x88, 0xe2, 0xd4, 0x29, 0xda, 0x42, 0x5f, 0xfd}}; + // FCH_SMM_SX_DISPATCH2_PROTOCOL_GUID + EfiGuid fch_sx_guid2 = { + 0x87e2a6cf, 0x91fb, 0x4581, {0x90, 0xa9, 0x6f, 0x50, 0x5d, 0xdc, 0x1c, 0xb2}}; + // FCH_SMM_USB_DISPATCH_PROTOCOL_GUID + EfiGuid fch_usb_guid = { + 0x59053b0d, 0xeeb8, 0x4379, {0xb1, 0xc8, 0x14, 0x5f, 0x1b, 0xb, 0xe4, 0xb9}}; + // FCH_SMM_USB_DISPATCH2_PROTOCOL_GUID + EfiGuid fch_usb_guid2 = { + 0xfbbb2ea9, 0xce0e, 0x4689, {0xb3, 0xf0, 0xc6, 0xb8, 0xf0, 0x76, 0xbd, 0x20}}; + // FCH_SMM_MISC_DISPATCH_PROTOCOL_GUID + EfiGuid fch_misc_guid = { + 0x13bd659b, 0xb4c6, 0x47da, {0x9b, 0x22, 0x11, 0x50, 0xd4, 0xf3, 0xb, 0xda}}; + // FCH_SMM_APU_RAS_DISPATCH_PROTOCOL_GUID + EfiGuid fch_apu_ras_guid = { + 0xf871ee59, 0x29d2, 0x4b15, {0x9e, 0x67, 0xaf, 0x32, 0xcd, 0xc1, 0x41, 0x73}}; - std::vector ppiFlags = { - 0x1, 0x10, 0x11, 0x20, 0x21, 0x30, - 0x31, 0x40, 0x41, 0x50, 0x51, 0x60, - 0x61, 0x70, 0x71, 0x80000000, 0x80000001, 0x80000010, - 0x80000011, 0x80000020, 0x80000021, 0x80000030, 0x80000031, 0x80000040, - 0x80000041, 0x80000050, 0x80000051, 0x80000060, 0x80000061, 0x80000070, - 0x80000071, - }; + std::vector ppiFlags = { + 0x1, 0x10, 0x11, 0x20, 0x21, 0x30, 0x31, + 0x40, 0x41, 0x50, 0x51, 0x60, 0x61, 0x70, + 0x71, 0x80000000, 0x80000001, 0x80000010, 0x80000011, 0x80000020, 0x80000021, + 0x80000030, 0x80000031, 0x80000040, 0x80000041, 0x80000050, 0x80000051, 0x80000060, + 0x80000061, 0x80000070, 0x80000071, + }; - // Set boot services that work with protocols - std::vector protBsNames = {"InstallProtocolInterface", - "ReinstallProtocolInterface", - "UninstallProtocolInterface", - "HandleProtocol", - "RegisterProtocolNotify", - "OpenProtocol", - "CloseProtocol", - "OpenProtocolInformation", - "ProtocolsPerHandle", - "LocateHandleBuffer", - "LocateProtocol", - "InstallMultipleProtocolInterfaces", - "UninstallMultipleProtocolInterfaces"}; + // Set boot services that work with protocols + std::vector protBsNames = {"InstallProtocolInterface", + "ReinstallProtocolInterface", + "UninstallProtocolInterface", + "HandleProtocol", + "RegisterProtocolNotify", + "OpenProtocol", + "CloseProtocol", + "OpenProtocolInformation", + "ProtocolsPerHandle", + "LocateHandleBuffer", + "LocateProtocol", + "InstallMultipleProtocolInterfaces", + "UninstallMultipleProtocolInterfaces"}; - // Set smm services that work with protocols - std::vector protSmmNames = {"SmmInstallProtocolInterface", - "SmmUninstallProtocolInterface", - "SmmHandleProtocol", - "SmmRegisterProtocolNotify", - "SmmLocateHandle", - "SmmLocateProtocol"}; + // Set smm services that work with protocols + std::vector protSmmNames = {"SmmInstallProtocolInterface", + "SmmUninstallProtocolInterface", + "SmmHandleProtocol", + "SmmRegisterProtocolNotify", + "SmmLocateHandle", + "SmmLocateProtocol"}; - // Set of PEI services that work with PPI - std::vector ppiPEINames = {"InstallPpi", "ReInstallPpi", "LocatePpi", - "NotifyPpi"}; + // Set of PEI services that work with PPI + std::vector ppiPEINames = {"InstallPpi", "ReInstallPpi", "LocatePpi", + "NotifyPpi"}; }; class EfiAnalyzerX86 : public EfiAnalyzer { - public: - EfiAnalyzerX86() : EfiAnalyzer() { - // import necessary types - const til_t *idati = get_idati(); - import_type(idati, -1, "EFI_GUID"); - import_type(idati, -1, "EFI_HANDLE"); - import_type(idati, -1, "EFI_SYSTEM_TABLE"); - import_type(idati, -1, "EFI_BOOT_SERVICES"); - import_type(idati, -1, "EFI_RUNTIME_SERVICES"); - import_type(idati, -1, "_EFI_SMM_SYSTEM_TABLE2"); - import_type(idati, -1, "EFI_PEI_SERVICES"); - import_type(idati, -1, "EFI_PEI_READ_ONLY_VARIABLE2_PPI"); - import_type(idati, -1, "EFI_SMM_VARIABLE_PROTOCOL"); +public: + EfiAnalyzerX86() : EfiAnalyzer() { + // import necessary types + const til_t *idati = get_idati(); + import_type(idati, -1, "EFI_GUID"); + import_type(idati, -1, "EFI_HANDLE"); + import_type(idati, -1, "EFI_SYSTEM_TABLE"); + import_type(idati, -1, "EFI_BOOT_SERVICES"); + import_type(idati, -1, "EFI_RUNTIME_SERVICES"); + import_type(idati, -1, "_EFI_SMM_SYSTEM_TABLE2"); + import_type(idati, -1, "EFI_PEI_SERVICES"); + import_type(idati, -1, "EFI_PEI_READ_ONLY_VARIABLE2_PPI"); + import_type(idati, -1, "EFI_SMM_VARIABLE_PROTOCOL"); #ifdef HEX_RAYS - for (auto idx = 0; idx < get_entry_qty(); idx++) { - uval_t ord = get_entry_ordinal(idx); - ea_t ep = get_entry(ord); - TrackEntryParams(get_func(ep), 0); - } -#endif + for (auto idx = 0; idx < get_entry_qty(); idx++) { + uval_t ord = get_entry_ordinal(idx); + ea_t ep = get_entry(ord); + TrackEntryParams(get_func(ep), 0); } - bool findImageHandleX64(); - bool findSystemTableX64(); - bool findBootServicesTables(); - bool findRuntimeServicesTables(); - bool findSmstX64(); - bool findSmstPostProcX64(); - void findOtherBsTablesX64(); +#endif + } + bool findImageHandleX64(); + bool findSystemTableX64(); + bool findBootServicesTables(); + bool findRuntimeServicesTables(); + bool findSmstX64(); + bool findSmstPostProcX64(); + void findOtherBsTablesX64(); - void getProtBootServicesX64(); - void getProtBootServicesX86(); - void getAllBootServices(); - void getAllRuntimeServices(); - void getAllSmmServicesX64(); + void getProtBootServicesX64(); + void getProtBootServicesX86(); + void getAllBootServices(); + void getAllRuntimeServices(); + void getAllSmmServicesX64(); - void getBsProtNamesX64(); - void getBsProtNamesX86(); - void getSmmProtNamesX64(); + void getBsProtNamesX64(); + void getBsProtNamesX86(); + void getSmmProtNamesX64(); - void getAllPeiServicesX86(); - void getPpiNamesX86(); - void getAllVariablePPICallsX86(); + void getAllPeiServicesX86(); + void getPpiNamesX86(); + void getAllVariablePPICallsX86(); - void markLocalGuidsX64(); + void markLocalGuidsX64(); - private: - bool InstallMultipleProtocolInterfacesHandler(); +private: + bool InstallMultipleProtocolInterfacesHandler(); }; class EfiAnalyzerArm : public EfiAnalyzer { - public: - EfiAnalyzerArm() : EfiAnalyzer() { - // in order to make it work, it is necessary to copy - // uefi.til, uefi64.til files in {idadir}/til/arm/ - add_til("uefi64.til", ADDTIL_DEFAULT); +public: + EfiAnalyzerArm() : EfiAnalyzer() { + // in order to make it work, it is necessary to copy + // uefi.til, uefi64.til files in {idadir}/til/arm/ + add_til("uefi64.til", ADDTIL_DEFAULT); - const til_t *idati = get_idati(); - import_type(idati, -1, "EFI_GUID"); - import_type(idati, -1, "EFI_HANDLE"); - import_type(idati, -1, "EFI_SYSTEM_TABLE"); - import_type(idati, -1, "EFI_BOOT_SERVICES"); - import_type(idati, -1, "EFI_RUNTIME_SERVICES"); - } - void fixOffsets(); - void initialAnalysis(); - void findBootServicesTables(); - void initialGlobalVarsDetection(); - void servicesDetection(); - void protocolsDetection(); - void findPeiServicesFunction(); + const til_t *idati = get_idati(); + import_type(idati, -1, "EFI_GUID"); + import_type(idati, -1, "EFI_HANDLE"); + import_type(idati, -1, "EFI_SYSTEM_TABLE"); + import_type(idati, -1, "EFI_BOOT_SERVICES"); + import_type(idati, -1, "EFI_RUNTIME_SERVICES"); + } + void fixOffsets(); + void initialAnalysis(); + void findBootServicesTables(); + void initialGlobalVarsDetection(); + void servicesDetection(); + void protocolsDetection(); + void findPeiServicesFunction(); - private: - bool getProtocol(ea_t address, uint32_t p_reg, std::string service_name); - struct service_info_64bit { - char service_name[64]; - uint32_t offset; - uint32_t reg; - uint16_t arg_index; - }; +private: + bool getProtocol(ea_t address, uint32_t p_reg, std::string service_name); + struct service_info_64bit { + char name[64]; + uint32_t offset; + uint32_t reg; + uint16_t arg_index; + }; - struct service_info_64bit bs_table_aarch64[13] = { - {"InstallProtocolInterface", 0x80, REG_X1, 1}, - {"ReinstallProtocolInterface", 0x88, REG_X1, 1}, - {"UninstallProtocolInterface", 0x90, REG_X1, 1}, - {"HandleProtocol", 0x98, REG_X1, 1}, - {"RegisterProtocolNotify", 0xA8, REG_X0, 0}, - {"OpenProtocol", 0x118, REG_X1, 1}, - {"CloseProtocol", 0x120, REG_X1, 1}, - {"ProtocolsPerHandle", 0x128, REG_X1, 1}, - {"OpenProtocolInformation", 0x130, REG_X1, 1}, - {"LocateHandleBuffer", 0x138, REG_X1, 1}, - {"LocateProtocol", 0x140, REG_X0, 1}, - {"InstallMultipleProtocolInterfaces", 0x148, REG_X1, 1}, - {"UninstallMultipleProtocolInterfaces", 0x150, REG_X1, 1}}; + struct service_info_64bit bs_table_aarch64[13] = { + {"InstallProtocolInterface", 0x80, REG_X1, 1}, + {"ReinstallProtocolInterface", 0x88, REG_X1, 1}, + {"UninstallProtocolInterface", 0x90, REG_X1, 1}, + {"HandleProtocol", 0x98, REG_X1, 1}, + {"RegisterProtocolNotify", 0xA8, REG_X0, 0}, + {"OpenProtocol", 0x118, REG_X1, 1}, + {"CloseProtocol", 0x120, REG_X1, 1}, + {"ProtocolsPerHandle", 0x128, REG_X1, 1}, + {"OpenProtocolInformation", 0x130, REG_X1, 1}, + {"LocateHandleBuffer", 0x138, REG_X1, 1}, + {"LocateProtocol", 0x140, REG_X0, 1}, + {"InstallMultipleProtocolInterfaces", 0x148, REG_X1, 1}, + {"UninstallMultipleProtocolInterfaces", 0x150, REG_X1, 1}}; }; bool efiAnalyzerMainX64(); bool efiAnalyzerMainX86(); bool efiAnalyzerMainArm(); -}; // namespace EfiAnalysis +}; // namespace efi_analysis -void showAllChoosers(EfiAnalysis::EfiAnalyzer analyzer); +void showAllChoosers(efi_analysis::EfiAnalyzer analyzer); diff --git a/efiXplorer/efiAnalyzerArm.cpp b/efiXplorer/efiAnalyzerArm.cpp index c73b4eef..352c5bd8 100644 --- a/efiXplorer/efiAnalyzerArm.cpp +++ b/efiXplorer/efiAnalyzerArm.cpp @@ -1,6 +1,6 @@ /* * efiXplorer - * Copyright (C) 2020-2023 Binarly + * Copyright (C) 2020-2024 Binarly * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -23,489 +23,487 @@ #include "efiAnalyzer.h" #include "efiGlobal.h" #include "efiUi.h" +#include "efiUtils.h" -using namespace EfiAnalysis; +using namespace efi_analysis; std::vector gImageHandleListArm; std::vector gStListArm; std::vector gBsListArm; std::vector gRtListArm; -void EfiAnalysis::EfiAnalyzerArm::fixOffsets() { - insn_t insn; - for (auto func_addr : funcs) { - func_t *f = get_func(func_addr); - if (f == nullptr) { - continue; - } - ea_t ea = f->start_ea; - while (ea < f->end_ea) { - ea = next_head(ea, BADADDR); - decode_insn(&insn, ea); - if (insn.itype == ARM_str) { - continue; - } - if (insn.ops[0].type == o_displ) { - op_num(ea, 0); - } - if (insn.ops[1].type == o_displ) { - op_num(ea, 1); - } - } +void efi_analysis::EfiAnalyzerArm::fixOffsets() { + insn_t insn; + for (auto func_addr : funcs) { + func_t *f = get_func(func_addr); + if (f == nullptr) { + continue; } + ea_t ea = f->start_ea; + while (ea < f->end_ea) { + ea = next_head(ea, BADADDR); + decode_insn(&insn, ea); + if (insn.itype == ARM_str) { + continue; + } + if (insn.ops[0].type == o_displ) { + op_num(ea, 0); + } + if (insn.ops[1].type == o_displ) { + op_num(ea, 1); + } + } + } } -void EfiAnalysis::EfiAnalyzerArm::initialAnalysis() { - fixOffsets(); - for (auto idx = 0; idx < get_entry_qty(); idx++) { - uval_t ord = get_entry_ordinal(idx); - ea_t ep = get_entry(ord); - set_name(ep, "_ModuleEntryPoint", SN_FORCE); +void efi_analysis::EfiAnalyzerArm::initialAnalysis() { + fixOffsets(); + for (auto idx = 0; idx < get_entry_qty(); idx++) { + uval_t ord = get_entry_ordinal(idx); + ea_t ep = get_entry(ord); + set_name(ep, "_ModuleEntryPoint", SN_FORCE); #ifdef HEX_RAYS - TrackEntryParams(get_func(ep), 0); + TrackEntryParams(get_func(ep), 0); #endif /* HEX_RAYS */ - } - if (fileType == FTYPE_PEI) { - // setEntryArgToPeiSvc(); - } + } + if (fileType == FTYPE_PEI) { + // setEntryArgToPeiSvc(); + } } ea_t getTable(ea_t code_addr, uint64_t offset) { - ea_t table = BADADDR; - insn_t insn; - decode_insn(&insn, code_addr); - if (insn.itype != ARM_ldr || insn.ops[0].type != o_reg || - insn.ops[1].type != o_displ || insn.ops[1].addr != offset || - insn.ops[1].reg == REG_XSP) { - return table; - } - uint8_t table_reg = insn.ops[0].reg; - uint8_t st_reg = insn.ops[1].reg; - - // handle following code patterns - // ADR REG1, gBS - // LDR REG2, [REG3,#0x60] <- we are here - // STR REG2, [REG4] - ea_t ea = code_addr; - uint8_t adr_reg = 0xff; - while (true) { - ea = next_head(ea, BADADDR); - decode_insn(&insn, ea); - if (insn.itype == ARM_str && insn.ops[0].type == o_reg && - insn.ops[1].type == o_displ && insn.ops[1].addr == 0x0) { - adr_reg = insn.ops[1].reg; - } - if (is_basic_block_end(insn, false)) { - break; - } + ea_t table = BADADDR; + insn_t insn; + decode_insn(&insn, code_addr); + if (insn.itype != ARM_ldr || insn.ops[0].type != o_reg || insn.ops[1].type != o_displ || + insn.ops[1].addr != offset || insn.ops[1].reg == REG_XSP) { + return table; + } + uint8_t table_reg = insn.ops[0].reg; + uint8_t st_reg = insn.ops[1].reg; + + // handle following code patterns + // ADR REG1, gBS + // LDR REG2, [REG3,#0x60] <- we are here + // STR REG2, [REG4] + ea_t ea = code_addr; + uint8_t adr_reg = 0xff; + while (true) { + ea = next_head(ea, BADADDR); + decode_insn(&insn, ea); + if (insn.itype == ARM_str && insn.ops[0].type == o_reg && + insn.ops[1].type == o_displ && insn.ops[1].addr == 0x0) { + adr_reg = insn.ops[1].reg; } - if (adr_reg != 0xff) { - ea = code_addr; - while (true) { - ea = prev_head(ea, 0); - decode_insn(&insn, ea); - if (insn.itype == ARM_adr && insn.ops[0].type == o_reg && - insn.ops[0].reg == adr_reg && insn.ops[1].type == o_imm) { - return insn.ops[1].value; // gBS/gRT - } - if (is_basic_block_end(insn, false)) { - break; - } - } + if (is_basic_block_end(insn, false)) { + break; } - + } + if (adr_reg != 0xff) { ea = code_addr; while (true) { - ea = next_head(ea, BADADDR); - decode_insn(&insn, ea); - ea_t base = BADADDR; - uint8_t reg = 0xff; - if (insn.itype == ARM_adrp && insn.ops[0].type == o_reg && - insn.ops[1].type == o_imm) { - // Example: - // LDR X8, [X1,#0x58] - // ADRP X9, #gRT@PAGE <- we are here - // ... - // STR X8, [X9,#gRT@PAGEOFF] - - base = insn.ops[1].value; - reg = insn.ops[0].reg; - ea_t current_addr = ea; - while (true) { - current_addr = next_head(current_addr, BADADDR); - decode_insn(&insn, current_addr); - if (insn.itype == ARM_str && insn.ops[0].type == o_reg && - insn.ops[0].reg == table_reg && insn.ops[1].type == o_displ && - insn.ops[1].reg == reg) { - return base + insn.ops[1].addr; - } - if (is_basic_block_end(insn, false)) { - break; - } - } + ea = prev_head(ea, 0); + decode_insn(&insn, ea); + if (insn.itype == ARM_adr && insn.ops[0].type == o_reg && + insn.ops[0].reg == adr_reg && insn.ops[1].type == o_imm) { + return insn.ops[1].value; // gBS/gRT + } + if (is_basic_block_end(insn, false)) { + break; + } + } + } + + ea = code_addr; + while (true) { + ea = next_head(ea, BADADDR); + decode_insn(&insn, ea); + ea_t base = BADADDR; + uint8_t reg = 0xff; + if (insn.itype == ARM_adrp && insn.ops[0].type == o_reg && + insn.ops[1].type == o_imm) { + // Example: + // LDR X8, [X1,#0x58] + // ADRP X9, #gRT@PAGE <- we are here + // ... + // STR X8, [X9,#gRT@PAGEOFF] + + base = insn.ops[1].value; + reg = insn.ops[0].reg; + ea_t current_addr = ea; + while (true) { + current_addr = next_head(current_addr, BADADDR); + decode_insn(&insn, current_addr); + if (insn.itype == ARM_str && insn.ops[0].type == o_reg && + insn.ops[0].reg == table_reg && insn.ops[1].type == o_displ && + insn.ops[1].reg == reg) { + return base + insn.ops[1].addr; } if (is_basic_block_end(insn, false)) { - break; + break; } + } } - return table; + if (is_basic_block_end(insn, false)) { + break; + } + } + return table; } json getService(ea_t addr, uint8_t table_id) { - json s; - insn_t insn; - decode_insn(&insn, addr); - if (insn.itype == ARM_ldr && insn.ops[0].type == o_reg && - insn.ops[1].type == o_displ) { - ea_t ea = addr; - uint8_t blr_reg = 0xff; - uint8_t table_reg = insn.ops[0].reg; - uint64_t service_offset = BADADDR; - while (true) { - ea = next_head(ea, BADADDR); - decode_insn(&insn, ea); - if (insn.itype == ARM_ldr && insn.ops[0].type == o_reg && - insn.ops[1].type == o_displ && insn.ops[1].reg == table_reg) { - service_offset = insn.ops[1].addr; - blr_reg = insn.ops[0].reg; - } - if (blr_reg != 0xff && service_offset != BADADDR && insn.itype == ARM_blr && - insn.ops[0].type == o_reg && insn.ops[0].reg == blr_reg) { - s["address"] = ea; - if (table_id == 1) { - s["service_name"] = lookupBootServiceName(service_offset); - s["table_name"] = "EFI_BOOT_SERVICES"; - } else if (table_id == 2) { - s["service_name"] = lookupRuntimeServiceName(service_offset); - s["table_name"] = "EFI_RUNTIME_SERVICES"; - } else { - s["table_name"] = "OTHER"; - } - return s; - } - if (is_basic_block_end(insn, false)) { - break; - } + json s; + insn_t insn; + decode_insn(&insn, addr); + if (insn.itype == ARM_ldr && insn.ops[0].type == o_reg && insn.ops[1].type == o_displ) { + ea_t ea = addr; + uint8_t blr_reg = 0xff; + uint8_t table_reg = insn.ops[0].reg; + uint64_t service_offset = BADADDR; + while (true) { + ea = next_head(ea, BADADDR); + decode_insn(&insn, ea); + if (insn.itype == ARM_ldr && insn.ops[0].type == o_reg && + insn.ops[1].type == o_displ && insn.ops[1].reg == table_reg) { + service_offset = insn.ops[1].addr; + blr_reg = insn.ops[0].reg; + } + if (blr_reg != 0xff && service_offset != BADADDR && insn.itype == ARM_blr && + insn.ops[0].type == o_reg && insn.ops[0].reg == blr_reg) { + s["address"] = ea; + if (table_id == 1) { + s["service_name"] = lookupBootServiceName(service_offset); + s["table_name"] = "EFI_BOOT_SERVICES"; + } else if (table_id == 2) { + s["service_name"] = lookupRuntimeServiceName(service_offset); + s["table_name"] = "EFI_RUNTIME_SERVICES"; + } else { + s["table_name"] = "OTHER"; } + return s; + } + if (is_basic_block_end(insn, false)) { + break; + } } - - // handle following code patterns - // ADR REG1, gBS - // ... - // LDR REG2, [REG1] - // ... - // LDR REG3, [REG2,#0x28] - if (insn.itype == ARM_adr && insn.ops[0].type == o_reg && insn.ops[1].type == o_imm) { - uint8_t reg1 = insn.ops[0].reg; - uint8_t reg2 = 0xff; - ea_t ea = addr; - while (true) { - ea = next_head(ea, BADADDR); - decode_insn(&insn, ea); - if (insn.itype == ARM_ldr && insn.ops[0].type == o_reg && - insn.ops[1].type == o_displ && insn.ops[1].reg == reg1 && - insn.ops[1].addr == 0) { - reg2 = insn.ops[0].reg; - } - if (reg2 != 0xff && insn.itype == ARM_ldr && insn.ops[0].type == o_reg && - insn.ops[1].type == o_displ && insn.ops[1].reg == reg2) { - s["address"] = ea; - if (table_id == 1) { - s["service_name"] = lookupBootServiceName(insn.ops[1].addr); - s["table_name"] = "EFI_BOOT_SERVICES"; - } else if (table_id == 2) { - s["service_name"] = lookupRuntimeServiceName(insn.ops[1].addr); - s["table_name"] = "EFI_RUNTIME_SERVICES"; - } else { - s["table_name"] = "OTHER"; - } - return s; - } + } + + // handle following code patterns + // ADR REG1, gBS + // ... + // LDR REG2, [REG1] + // ... + // LDR REG3, [REG2,#0x28] + if (insn.itype == ARM_adr && insn.ops[0].type == o_reg && insn.ops[1].type == o_imm) { + uint8_t reg1 = insn.ops[0].reg; + uint8_t reg2 = 0xff; + ea_t ea = addr; + while (true) { + ea = next_head(ea, BADADDR); + decode_insn(&insn, ea); + if (insn.itype == ARM_ldr && insn.ops[0].type == o_reg && + insn.ops[1].type == o_displ && insn.ops[1].reg == reg1 && + insn.ops[1].addr == 0) { + reg2 = insn.ops[0].reg; + } + if (reg2 != 0xff && insn.itype == ARM_ldr && insn.ops[0].type == o_reg && + insn.ops[1].type == o_displ && insn.ops[1].reg == reg2) { + s["address"] = ea; + if (table_id == 1) { + s["service_name"] = lookupBootServiceName(insn.ops[1].addr); + s["table_name"] = "EFI_BOOT_SERVICES"; + } else if (table_id == 2) { + s["service_name"] = lookupRuntimeServiceName(insn.ops[1].addr); + s["table_name"] = "EFI_RUNTIME_SERVICES"; + } else { + s["table_name"] = "OTHER"; } + return s; + } } + } - return s; + return s; } -void EfiAnalysis::EfiAnalyzerArm::initialGlobalVarsDetection() { +void efi_analysis::EfiAnalyzerArm::initialGlobalVarsDetection() { #ifdef HEX_RAYS - // analyze entry point with Hex-Rays - for (auto func_addr : funcs) { - json res = DetectVars(get_func(func_addr)); - if (res.contains("gImageHandleList")) { - for (auto addr : res["gImageHandleList"]) { - if (!addrInVec(gImageHandleListArm, addr)) { - gImageHandleListArm.push_back(addr); - } - } + // analyze entry point with Hex-Rays + for (auto func_addr : funcs) { + json res = DetectVars(get_func(func_addr)); + if (res.contains("gImageHandleList")) { + for (auto addr : res["gImageHandleList"]) { + if (!addrInVec(gImageHandleListArm, addr)) { + gImageHandleListArm.push_back(addr); } - if (res.contains("gStList")) { - for (auto addr : res["gStList"]) { - if (!addrInVec(gStListArm, addr)) { - gStListArm.push_back(addr); - } - } + } + } + if (res.contains("gStList")) { + for (auto addr : res["gStList"]) { + if (!addrInVec(gStListArm, addr)) { + gStListArm.push_back(addr); } - if (res.contains("gBsList")) { - for (auto addr : res["gBsList"]) { - if (!addrInVec(gBsListArm, addr)) { - gBsListArm.push_back(addr); - } - } + } + } + if (res.contains("gBsList")) { + for (auto addr : res["gBsList"]) { + if (!addrInVec(gBsListArm, addr)) { + gBsListArm.push_back(addr); } - if (res.contains("gRtList")) { - for (auto addr : res["gRtList"]) { - if (!addrInVec(gRtListArm, addr)) { - gRtListArm.push_back(addr); - } - } + } + } + if (res.contains("gRtList")) { + for (auto addr : res["gRtList"]) { + if (!addrInVec(gRtListArm, addr)) { + gRtListArm.push_back(addr); } + } } + } #endif /* HEX_RAYS */ - // analysis of all functions and search for additional table initializations - for (auto func_addr : funcs) { - func_t *f = get_func(func_addr); - if (f == nullptr) { - continue; + // analysis of all functions and search for additional table initializations + for (auto func_addr : funcs) { + func_t *f = get_func(func_addr); + if (f == nullptr) { + continue; + } + auto ea = f->start_ea; + while (ea < f->end_ea) { + ea = next_head(ea, BADADDR); + ea_t bs = getTable(ea, 0x60); + if (bs != BADADDR) { + msg("[efiXplorer] gBS = 0x%016llX\n", u64_addr(ea)); + setPtrTypeAndName(bs, "gBS", "EFI_BOOT_SERVICES"); + if (!addrInVec(gBsListArm, bs)) { + gBsListArm.push_back(bs); } - auto ea = f->start_ea; - while (ea < f->end_ea) { - ea = next_head(ea, BADADDR); - ea_t bs = getTable(ea, 0x60); - if (bs != BADADDR) { - msg("[efiXplorer] gBS = 0x%016llX\n", u64_addr(ea)); - setPtrTypeAndName(bs, "gBS", "EFI_BOOT_SERVICES"); - if (!addrInVec(gBsListArm, bs)) { - gBsListArm.push_back(bs); - } - continue; - } - ea_t rt = getTable(ea, 0x58); - if (rt != BADADDR) { - msg("[efiXplorer] gRT = 0x%016llX\n", u64_addr(ea)); - setPtrTypeAndName(rt, "gRT", "EFI_RUNTIME_SERVICES"); - if (!addrInVec(gRtListArm, rt)) { - gRtListArm.push_back(rt); - } - continue; - } + continue; + } + ea_t rt = getTable(ea, 0x58); + if (rt != BADADDR) { + msg("[efiXplorer] gRT = 0x%016llX\n", u64_addr(ea)); + setPtrTypeAndName(rt, "gRT", "EFI_RUNTIME_SERVICES"); + if (!addrInVec(gRtListArm, rt)) { + gRtListArm.push_back(rt); } + continue; + } } + } } -void EfiAnalysis::EfiAnalyzerArm::servicesDetection() { +void efi_analysis::EfiAnalyzerArm::servicesDetection() { #ifdef HEX_RAYS - for (auto func_addr : funcs) { - std::vector services = DetectServices(get_func(func_addr)); - for (auto service : services) { - allServices.push_back(service); - } + for (auto func_addr : funcs) { + std::vector services = DetectServices(get_func(func_addr)); + for (auto service : services) { + allServices.push_back(service); } + } #endif /* HEX_RAYS */ - // analyze xrefs to gBS, gRT - for (auto bs : gBsListArm) { - auto xrefs = getXrefs(bs); - for (auto ea : xrefs) { - auto s = getService(ea, 1); - if (!s.contains("address")) { - continue; - } - std::string name = s["service_name"]; - if (name == "Unknown") { - continue; - } - if (!jsonInVec(allServices, s)) { - msg("[efiXplorer] gBS xref address: 0x%016llX, found new service\n", - u64_addr(ea)); - allServices.push_back(s); - } - } + // analyze xrefs to gBS, gRT + for (auto bs : gBsListArm) { + auto xrefs = getXrefs(bs); + for (auto ea : xrefs) { + auto s = getService(ea, 1); + if (!s.contains("address")) { + continue; + } + std::string name = s["service_name"]; + if (name == "Unknown") { + continue; + } + if (!jsonInVec(allServices, s)) { + msg("[efiXplorer] gBS xref address: 0x%016llX, found new service\n", + u64_addr(ea)); + allServices.push_back(s); + } } - for (auto rt : gRtListArm) { - auto xrefs = getXrefs(rt); - for (auto ea : xrefs) { - auto s = getService(ea, 2); - if (!s.contains("address")) { - continue; - } - std::string name = s["service_name"]; - if (name == "Unknown") { - continue; - } - if (!jsonInVec(allServices, s)) { - msg("[efiXplorer] gRT xref address: 0x%016llX, found new service\n", - u64_addr(ea)); - allServices.push_back(s); - } - } + } + for (auto rt : gRtListArm) { + auto xrefs = getXrefs(rt); + for (auto ea : xrefs) { + auto s = getService(ea, 2); + if (!s.contains("address")) { + continue; + } + std::string name = s["service_name"]; + if (name == "Unknown") { + continue; + } + if (!jsonInVec(allServices, s)) { + msg("[efiXplorer] gRT xref address: 0x%016llX, found new service\n", + u64_addr(ea)); + allServices.push_back(s); + } } + } } -bool EfiAnalysis::EfiAnalyzerArm::getProtocol(ea_t address, uint32_t p_reg, - std::string service_name) { - ea_t ea = address; - insn_t insn; - ea_t offset = BADADDR; - ea_t guid_addr = BADADDR; - ea_t code_addr = BADADDR; - while (true) { - ea = prev_head(ea, 0); - decode_insn(&insn, ea); - if (insn.itype == ARM_adrl && insn.ops[0].type == o_reg && - insn.ops[0].reg == p_reg && insn.ops[1].type == o_imm) { - guid_addr = insn.ops[1].value; - code_addr = ea; - break; - } - if (insn.itype == ARM_add && insn.ops[0].type == o_reg && - insn.ops[0].reg == p_reg && insn.ops[1].type == o_reg && - insn.ops[1].reg == p_reg && insn.ops[2].type == o_imm) { - offset = insn.ops[2].value; - } - if (insn.itype == ARM_adrp && insn.ops[0].type == o_reg && - insn.ops[0].reg == p_reg && insn.ops[1].type == o_imm) { - guid_addr = insn.ops[1].value + offset; - code_addr = ea; - break; - } - if (is_basic_block_end(insn, false)) { - break; - } +bool efi_analysis::EfiAnalyzerArm::getProtocol(ea_t address, uint32_t p_reg, + std::string service_name) { + ea_t ea = address; + insn_t insn; + ea_t offset = BADADDR; + ea_t guid_addr = BADADDR; + ea_t code_addr = BADADDR; + while (true) { + ea = prev_head(ea, 0); + decode_insn(&insn, ea); + if (insn.itype == ARM_adrl && insn.ops[0].type == o_reg && insn.ops[0].reg == p_reg && + insn.ops[1].type == o_imm) { + guid_addr = insn.ops[1].value; + code_addr = ea; + break; + } + if (insn.itype == ARM_add && insn.ops[0].type == o_reg && insn.ops[0].reg == p_reg && + insn.ops[1].type == o_reg && insn.ops[1].reg == p_reg && + insn.ops[2].type == o_imm) { + offset = insn.ops[2].value; + } + if (insn.itype == ARM_adrp && insn.ops[0].type == o_reg && insn.ops[0].reg == p_reg && + insn.ops[1].type == o_imm) { + guid_addr = insn.ops[1].value + offset; + code_addr = ea; + break; } - if (guid_addr == BADADDR || code_addr == BADADDR) { - return false; + if (is_basic_block_end(insn, false)) { + break; } - msg("[efiXplorer] address: 0x%016llX, found new protocol\n", u64_addr(code_addr)); - return AddProtocol(service_name, guid_addr, code_addr, address); + } + if (guid_addr == BADADDR || code_addr == BADADDR) { + return false; + } + msg("[efiXplorer] address: 0x%016llX, found new protocol\n", u64_addr(code_addr)); + return AddProtocol(service_name, guid_addr, code_addr, address); } -void EfiAnalysis::EfiAnalyzerArm::protocolsDetection() { - for (auto s : allServices) { - std::string service_name = s["service_name"]; - for (auto i = 0; i < 13; i++) { - std::string current_name = - static_cast(bs_table_aarch64[i].service_name); - if (current_name != service_name) { - continue; - } - getProtocol(s["address"], bs_table_aarch64[i].reg, service_name); - break; - } +void efi_analysis::EfiAnalyzerArm::protocolsDetection() { + for (auto s : allServices) { + std::string service_name = s["service_name"]; + for (auto i = 0; i < 13; i++) { + std::string current_name = static_cast(bs_table_aarch64[i].name); + if (current_name != service_name) { + continue; + } + getProtocol(s["address"], bs_table_aarch64[i].reg, service_name); + break; } + } } -void EfiAnalysis::EfiAnalyzerArm::findPeiServicesFunction() { - insn_t insn; - for (auto start_ea : funcs) { - decode_insn(&insn, start_ea); - if (!(insn.itype == ARM_mrs && insn.ops[0].type == o_reg && - insn.ops[0].reg == REG_X0 && insn.ops[1].type == o_imm && - insn.ops[1].value == 0x3 && insn.ops[2].type == o_idpspec3 && - insn.ops[2].reg == REG_C13 && insn.ops[3].type == o_idpspec3 && - insn.ops[3].reg == REG_C0 && insn.ops[4].type == o_imm && - insn.ops[4].value == 0x2)) { - continue; - } - auto end_ea = next_head(start_ea, BADADDR); - if (end_ea == BADADDR) { - continue; - } - decode_insn(&insn, end_ea); - if (insn.itype == ARM_ret) { - msg("[efiXplorer] found GetPeiServices() function: 0x%016llX\n", - u64_addr(start_ea)); - set_name(start_ea, "GetPeiServices", SN_FORCE); - setRetToPeiSvc(start_ea); - } +void efi_analysis::EfiAnalyzerArm::findPeiServicesFunction() { + insn_t insn; + for (auto start_ea : funcs) { + decode_insn(&insn, start_ea); + if (!(insn.itype == ARM_mrs && insn.ops[0].type == o_reg && + insn.ops[0].reg == REG_X0 && insn.ops[1].type == o_imm && + insn.ops[1].value == 0x3 && insn.ops[2].type == o_idpspec3 && + insn.ops[2].reg == REG_C13 && insn.ops[3].type == o_idpspec3 && + insn.ops[3].reg == REG_C0 && insn.ops[4].type == o_imm && + insn.ops[4].value == 0x2)) { + continue; + } + auto end_ea = next_head(start_ea, BADADDR); + if (end_ea == BADADDR) { + continue; } + decode_insn(&insn, end_ea); + if (insn.itype == ARM_ret) { + msg("[efiXplorer] found GetPeiServices() function: 0x%016llX\n", + u64_addr(start_ea)); + set_name(start_ea, "GetPeiServices", SN_FORCE); + setRetToPeiSvc(start_ea); + } + } } //-------------------------------------------------------------------------- // Show all non-empty choosers windows -void showAllChoosers(EfiAnalysis::EfiAnalyzerArm analyzer) { - qstring title; - - // open window with all services - if (analyzer.allServices.size()) { - title = "efiXplorer: services"; - services_show(analyzer.allServices, title); - } - - // open window with data guids - if (analyzer.allGuids.size()) { - qstring title = "efiXplorer: GUIDs"; - guids_show(analyzer.allGuids, title); - } - - // open window with protocols - if (analyzer.allProtocols.size()) { - title = "efiXplorer: protocols"; - protocols_show(analyzer.allProtocols, title); - } +void showAllChoosers(efi_analysis::EfiAnalyzerArm analyzer) { + qstring title; + + // open window with all services + if (analyzer.allServices.size()) { + title = "efiXplorer: services"; + services_show(analyzer.allServices, title); + } + + // open window with data guids + if (analyzer.allGuids.size()) { + qstring title = "efiXplorer: GUIDs"; + guids_show(analyzer.allGuids, title); + } + + // open window with protocols + if (analyzer.allProtocols.size()) { + title = "efiXplorer: protocols"; + protocols_show(analyzer.allProtocols, title); + } } //-------------------------------------------------------------------------- // Main function for AARCH64 modules -bool EfiAnalysis::efiAnalyzerMainArm() { +bool efi_analysis::efiAnalyzerMainArm() { - show_wait_box("HIDECANCEL\nAnalyzing module(s) with efiXplorer..."); + show_wait_box("HIDECANCEL\nAnalyzing module(s) with efiXplorer..."); - EfiAnalysis::EfiAnalyzerArm analyzer; + efi_analysis::EfiAnalyzerArm analyzer; - while (!auto_is_ok()) { - auto_wait(); - }; + while (!auto_is_ok()) { + auto_wait(); + }; - // find .text and .data segments - analyzer.getSegments(); + // find .text and .data segments + analyzer.getSegments(); - // mark GUIDs - analyzer.markDataGuids(); + // mark GUIDs + analyzer.markDataGuids(); - if (g_args.disable_ui) { - analyzer.fileType = g_args.module_type == PEI - ? analyzer.fileType = FTYPE_PEI - : analyzer.fileType = FTYPE_DXE_AND_THE_LIKE; - } else { - analyzer.fileType = getFileType(&analyzer.allGuids); - } + if (g_args.disable_ui) { + analyzer.fileType = g_args.module_type == PEI + ? analyzer.fileType = FTYPE_PEI + : analyzer.fileType = FTYPE_DXE_AND_THE_LIKE; + } else { + analyzer.fileType = getFileType(&analyzer.allGuids); + } - if (analyzer.fileType == FTYPE_PEI) { - msg("[efiXplorer] input file is PEI module\n"); - } + if (analyzer.fileType == FTYPE_PEI) { + msg("[efiXplorer] input file is PEI module\n"); + } - // set the correct name for the entry point and automatically fix the prototype - analyzer.initialAnalysis(); + // set the correct name for the entry point and automatically fix the prototype + analyzer.initialAnalysis(); - if (analyzer.fileType == FTYPE_DXE_AND_THE_LIKE) { - analyzer.initialGlobalVarsDetection(); + if (analyzer.fileType == FTYPE_DXE_AND_THE_LIKE) { + analyzer.initialGlobalVarsDetection(); - // detect services - analyzer.servicesDetection(); + // detect services + analyzer.servicesDetection(); - // detect protocols - analyzer.protocolsDetection(); - } else if (analyzer.fileType == FTYPE_PEI) { - analyzer.findPeiServicesFunction(); - } + // detect protocols + analyzer.protocolsDetection(); + } else if (analyzer.fileType == FTYPE_PEI) { + analyzer.findPeiServicesFunction(); + } #ifdef HEX_RAYS - for (auto addr : analyzer.funcs) { - std::vector services = DetectPeiServicesArm(get_func(addr)); - for (auto service : services) { - analyzer.allServices.push_back(service); - } + for (auto addr : analyzer.funcs) { + std::vector services = DetectPeiServicesArm(get_func(addr)); + for (auto service : services) { + analyzer.allServices.push_back(service); } - applyAllTypesForInterfacesBootServices(analyzer.allProtocols); + } + applyAllTypesForInterfacesBootServices(analyzer.allProtocols); #endif /* HEX_RAYS */ - showAllChoosers(analyzer); + showAllChoosers(analyzer); - analyzer.dumpInfo(); + analyzer.dumpInfo(); - hide_wait_box(); + hide_wait_box(); - return true; + return true; } diff --git a/efiXplorer/efiAnalyzerX86.cpp b/efiXplorer/efiAnalyzerX86.cpp index b37f34d5..4db1b6aa 100644 --- a/efiXplorer/efiAnalyzerX86.cpp +++ b/efiXplorer/efiAnalyzerX86.cpp @@ -1,6 +1,6 @@ /* * efiXplorer - * Copyright (C) 2020-2023 Binarly + * Copyright (C) 2020-2024 Binarly * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -23,16 +23,14 @@ #include "efiAnalyzer.h" #include "efiGlobal.h" #include "efiUi.h" -#include "tables/efi_pei_tables.h" -#include "tables/efi_services.h" +#include "efiUtils.h" #ifdef HEX_RAYS #include "efiHexRays.h" #endif -using namespace EfiAnalysis; +using namespace efi_analysis; -static const char plugin_name[] = "efiXplorer"; extern std::vector g_get_smst_location_calls; extern std::vector g_smm_get_variable_calls; extern std::vector g_smm_set_variable_calls; @@ -63,889 +61,853 @@ std::vector peiGetVariableOverflow; std::vector getVariableOverflow; std::vector smmGetVariableOverflow; -EfiAnalysis::EfiAnalyzer::EfiAnalyzer() { - // 32-bit, 64-bit, ARM or UEFI (in loader instance) - arch = getInputFileType(); - - // get guids.json path - guidsJsonPath /= getGuidsJsonFile(); - - // get base address - base = get_imagebase(); - - func_t *start_func = nullptr; - func_t *end_func = nullptr; - - // get start address for scan - start_func = getn_func(0); - if (start_func) { - startAddress = start_func->start_ea; - } - - // get end address for scan - end_func = getn_func(get_func_qty() - 1); - if (end_func) { - endAddress = end_func->end_ea; - } - - // save all funcs - for (auto i = 0; i < get_func_qty(); i++) { - auto func = getn_func(i); - funcs.push_back(func->start_ea); - } - - std::vector addrs; - for (auto service : protBsNames) { - bootServices[service] = addrs; - } - - for (auto service : protSmmNames) { - smmServices[service] = addrs; - } - - try { - // load protocols from guids.json file - std::ifstream in(guidsJsonPath); - in >> dbProtocols; - } catch (std::exception &e) { - dbProtocols.clear(); - std::string msg_text = "guids.json file is invalid, check its contents"; - msg("[%s] %s\n", plugin_name, msg_text.c_str()); - warning("%s: %s\n", plugin_name, msg_text.c_str()); - } - - // get reverse dictionary - for (auto g = dbProtocols.begin(); g != dbProtocols.end(); ++g) { - dbProtocolsMap[static_cast(g.value())] = static_cast(g.key()); - } +efi_analysis::EfiAnalyzer::EfiAnalyzer() { + // 32-bit, 64-bit, ARM or UEFI (in loader instance) + arch = getInputFileType(); + + // get guids.json path + guidsJsonPath /= getGuidsJsonFile(); + + // get base address + base = get_imagebase(); + + func_t *start_func = nullptr; + func_t *end_func = nullptr; + + // get start address for scan + start_func = getn_func(0); + if (start_func) { + startAddress = start_func->start_ea; + } + + // get end address for scan + end_func = getn_func(get_func_qty() - 1); + if (end_func) { + endAddress = end_func->end_ea; + } + + // save all funcs + for (auto i = 0; i < get_func_qty(); i++) { + auto func = getn_func(i); + funcs.push_back(func->start_ea); + } + + std::vector addrs; + for (auto service : protBsNames) { + bootServices[service] = addrs; + } + + for (auto service : protSmmNames) { + smmServices[service] = addrs; + } + + try { + // load protocols from guids.json file + std::ifstream in(guidsJsonPath); + in >> dbProtocols; + } catch (std::exception &e) { + dbProtocols.clear(); + std::string msg_text = "guids.json file is invalid, check its contents"; + msg("[%s] %s\n", g_plugin_name, msg_text.c_str()); + warning("%s: %s\n", g_plugin_name, msg_text.c_str()); + } + + // get reverse dictionary + for (auto g = dbProtocols.begin(); g != dbProtocols.end(); ++g) { + dbProtocolsMap[static_cast(g.value())] = static_cast(g.key()); + } } -EfiAnalysis::EfiAnalyzer::~EfiAnalyzer() { - funcs.clear(); +efi_analysis::EfiAnalyzer::~EfiAnalyzer() { + funcs.clear(); - gStList.clear(); - gPeiSvcList.clear(); - gBsList.clear(); - gRtList.clear(); - gSmstList.clear(); - gImageHandleList.clear(); - gRtServicesList.clear(); - stackGuids.clear(); - dataGuids.clear(); + gStList.clear(); + gPeiSvcList.clear(); + gBsList.clear(); + gRtList.clear(); + gSmstList.clear(); + gImageHandleList.clear(); + gRtServicesList.clear(); + stackGuids.clear(); + dataGuids.clear(); - textSegments.clear(); - dataSegments.clear(); + textSegments.clear(); + dataSegments.clear(); - calloutAddrs.clear(); - excFunctions.clear(); - readSaveStateCalls.clear(); - smiHandlers.clear(); - childSmiHandlers.clear(); + calloutAddrs.clear(); + excFunctions.clear(); + readSaveStateCalls.clear(); + smiHandlers.clear(); + childSmiHandlers.clear(); - peiGetVariableOverflow.clear(); - getVariableOverflow.clear(); - smmGetVariableOverflow.clear(); + peiGetVariableOverflow.clear(); + getVariableOverflow.clear(); + smmGetVariableOverflow.clear(); - g_get_smst_location_calls.clear(); - g_smm_get_variable_calls.clear(); - g_smm_set_variable_calls.clear(); + g_get_smst_location_calls.clear(); + g_smm_get_variable_calls.clear(); + g_smm_set_variable_calls.clear(); #ifdef HEX_RAYS - clear_cached_cfuncs(); + clear_cached_cfuncs(); #endif } -void EfiAnalysis::EfiAnalyzer::setStrings() { +void efi_analysis::EfiAnalyzer::setStrings() { - if (fileType == FTYPE_DXE_AND_THE_LIKE) { - if_name = " Protocol name "; - if_pl = "protocols"; - if_key = "prot_name"; - if_tbl = &allProtocols; + if (fileType == FTYPE_DXE_AND_THE_LIKE) { + if_name = " Protocol name "; + if_pl = "protocols"; + if_key = "prot_name"; + if_tbl = &allProtocols; - } else if (fileType == FTYPE_PEI) { - if_name = " PPI name "; - if_pl = "PPIs"; - if_key = "ppi_name"; - if_tbl = &allPPIs; - } + } else if (fileType == FTYPE_PEI) { + if_name = " PPI name "; + if_pl = "PPIs"; + if_key = "ppi_name"; + if_tbl = &allPPIs; + } } //-------------------------------------------------------------------------- // Get all .text and .data segments -void EfiAnalysis::EfiAnalyzer::getSegments() { - for (segment_t *s = get_first_seg(); s != NULL; s = get_next_seg(s->start_ea)) { - qstring seg_name; - get_segm_name(&seg_name, s); - - std::vector codeSegNames{ - ".text", ".code"}; // for compatibility with ida-efitools2 - for (auto name : codeSegNames) { - auto index = seg_name.find(name.c_str()); - if (index != std::string::npos) { - // fix permissions and class for code segment - // in order for decompilation to work properly - s->perm = (SEGPERM_READ | SEGPERM_WRITE | SEGPERM_EXEC); - set_segm_class(s, "DATA"); - textSegments.push_back(s); - continue; - } - } - - auto index = seg_name.find(".data"); - if (index != std::string::npos) { - dataSegments.push_back(s); - continue; - } - } - - // print all .text and .code segments addresses - for (auto seg : textSegments) { - segment_t *s = seg; - msg("[%s] code segment: 0x%016llX\n", plugin_name, u64_addr(s->start_ea)); - } - - // print all .data segments addresses - for (auto seg : dataSegments) { - segment_t *s = seg; - msg("[%s] data segment: 0x%016llX\n", plugin_name, u64_addr(s->start_ea)); - } +void efi_analysis::EfiAnalyzer::getSegments() { + for (segment_t *s = get_first_seg(); s != NULL; s = get_next_seg(s->start_ea)) { + qstring seg_name; + get_segm_name(&seg_name, s); + + std::vector codeSegNames{ + ".text", ".code"}; // for compatibility with ida-efitools2 + for (auto name : codeSegNames) { + auto index = seg_name.find(name.c_str()); + if (index != std::string::npos) { + // fix permissions and class for code segment + // in order for decompilation to work properly + s->perm = (SEGPERM_READ | SEGPERM_WRITE | SEGPERM_EXEC); + set_segm_class(s, "DATA"); + textSegments.push_back(s); + continue; + } + } + + auto index = seg_name.find(".data"); + if (index != std::string::npos) { + dataSegments.push_back(s); + continue; + } + } + + // print all .text and .code segments addresses + for (auto seg : textSegments) { + segment_t *s = seg; + msg("[%s] code segment: 0x%016llX\n", g_plugin_name, u64_addr(s->start_ea)); + } + + // print all .data segments addresses + for (auto seg : dataSegments) { + segment_t *s = seg; + msg("[%s] data segment: 0x%016llX\n", g_plugin_name, u64_addr(s->start_ea)); + } } //-------------------------------------------------------------------------- // Find gImageHandle address for X64 modules -bool EfiAnalysis::EfiAnalyzerX86::findImageHandleX64() { - msg("[%s] gImageHandle finding\n", plugin_name); - insn_t insn; - for (int idx = 0; idx < get_entry_qty(); idx++) { - - // get address of entry point - uval_t ord = get_entry_ordinal(idx); - ea_t ea = get_entry(ord); - - // EFI_IMAGE_HANDLE finding, first 8 instructions checking - for (auto i = 0; i < 8; i++) { - decode_insn(&insn, ea); - if (insn.itype == NN_mov && insn.ops[1].type == o_reg && - insn.ops[1].reg == REG_RCX && insn.ops[0].type == o_mem) { - msg("[%s] found ImageHandle at 0x%016llX, address = 0x%016llX\n", - plugin_name, u64_addr(ea), u64_addr(insn.ops[0].addr)); - set_cmt(ea, "EFI_IMAGE_HANDLE gImageHandle", true); - - // set type and name - setTypeAndName(insn.ops[0].addr, "gImageHandle", "EFI_IMAGE_HANDLE"); - gImageHandleList.push_back(insn.ops[0].addr); - break; - } - ea = next_head(ea, endAddress); - } - } - return true; +bool efi_analysis::EfiAnalyzerX86::findImageHandleX64() { + msg("[%s] gImageHandle finding\n", g_plugin_name); + insn_t insn; + for (int idx = 0; idx < get_entry_qty(); idx++) { + + // get address of entry point + uval_t ord = get_entry_ordinal(idx); + ea_t ea = get_entry(ord); + + // EFI_IMAGE_HANDLE finding, first 8 instructions checking + for (auto i = 0; i < 8; i++) { + decode_insn(&insn, ea); + if (insn.itype == NN_mov && insn.ops[1].type == o_reg && + insn.ops[1].reg == REG_RCX && insn.ops[0].type == o_mem) { + msg("[%s] found ImageHandle at 0x%016llX, address = 0x%016llX\n", g_plugin_name, + u64_addr(ea), u64_addr(insn.ops[0].addr)); + set_cmt(ea, "EFI_IMAGE_HANDLE gImageHandle", true); + + // set type and name + setTypeAndName(insn.ops[0].addr, "gImageHandle", "EFI_IMAGE_HANDLE"); + gImageHandleList.push_back(insn.ops[0].addr); + break; + } + ea = next_head(ea, endAddress); + } + } + return true; } //-------------------------------------------------------------------------- // Find gST address for X64 modules -bool EfiAnalysis::EfiAnalyzerX86::findSystemTableX64() { - msg("[%s] gEfiSystemTable finding\n", plugin_name); - insn_t insn; - for (int idx = 0; idx < get_entry_qty(); idx++) { - - // get address of entry point - uval_t ord = get_entry_ordinal(idx); - ea_t ea = get_entry(ord); - - // EFI_SYSTEM_TABLE finding, first 16 instructions checking - for (int i = 0; i < 16; i++) { - decode_insn(&insn, ea); - if (insn.itype == NN_mov && insn.ops[1].type == o_reg && - insn.ops[1].reg == REG_RDX && insn.ops[0].type == o_mem) { - set_cmt(ea, "EFI_SYSTEM_TABLE *gST", true); - setPtrTypeAndName(insn.ops[0].addr, "gST", "EFI_SYSTEM_TABLE"); - gStList.push_back(insn.ops[0].addr); - return true; - } - ea = next_head(ea, BADADDR); - } - } - return false; +bool efi_analysis::EfiAnalyzerX86::findSystemTableX64() { + msg("[%s] gEfiSystemTable finding\n", g_plugin_name); + insn_t insn; + for (int idx = 0; idx < get_entry_qty(); idx++) { + + // get address of entry point + uval_t ord = get_entry_ordinal(idx); + ea_t ea = get_entry(ord); + + // EFI_SYSTEM_TABLE finding, first 16 instructions checking + for (int i = 0; i < 16; i++) { + decode_insn(&insn, ea); + if (insn.itype == NN_mov && insn.ops[1].type == o_reg && + insn.ops[1].reg == REG_RDX && insn.ops[0].type == o_mem) { + set_cmt(ea, "EFI_SYSTEM_TABLE *gST", true); + setPtrTypeAndName(insn.ops[0].addr, "gST", "EFI_SYSTEM_TABLE"); + gStList.push_back(insn.ops[0].addr); + return true; + } + ea = next_head(ea, BADADDR); + } + } + return false; } //-------------------------------------------------------------------------- // Find and mark gSmst global variable address for X64 module -bool EfiAnalysis::EfiAnalyzerX86::findSmstX64() { - msg("[%s] gSmst finding\n", plugin_name); - std::vector gSmstListSmmBase = findSmstSmmBase(gBsList); - std::vector gSmstListSwDispatch = findSmstSwDispatch(gBsList); - gSmstList.insert(gSmstList.end(), gSmstListSwDispatch.begin(), - gSmstListSwDispatch.end()); - gSmstList.insert(gSmstList.end(), gSmstListSmmBase.begin(), gSmstListSmmBase.end()); - - // Deduplicate - auto last = std::unique(gSmstList.begin(), gSmstList.end()); - gSmstList.erase(last, gSmstList.end()); - - for (auto smst : gSmstList) { - msg("[%s] 0x%016llX: gSmst\n", plugin_name, u64_addr(smst)); - } - return gSmstList.size(); +bool efi_analysis::EfiAnalyzerX86::findSmstX64() { + msg("[%s] gSmst finding\n", g_plugin_name); + std::vector gSmstListSmmBase = findSmstSmmBase(gBsList); + std::vector gSmstListSwDispatch = findSmstSwDispatch(gBsList); + gSmstList.insert(gSmstList.end(), gSmstListSwDispatch.begin(), + gSmstListSwDispatch.end()); + gSmstList.insert(gSmstList.end(), gSmstListSmmBase.begin(), gSmstListSmmBase.end()); + + // Deduplicate + auto last = std::unique(gSmstList.begin(), gSmstList.end()); + gSmstList.erase(last, gSmstList.end()); + + for (auto smst : gSmstList) { + msg("[%s] 0x%016llX: gSmst\n", g_plugin_name, u64_addr(smst)); + } + return gSmstList.size(); } //-------------------------------------------------------------------------- // Find and mark gSmst global and local variable address for X64 module // after Hex-Rays based analysis -bool EfiAnalysis::EfiAnalyzerX86::findSmstPostProcX64() { - for (auto ea : g_get_smst_location_calls) { - msg("[%s] EfiSmmBase2Protocol->GetSmstLocation call: 0x%016llX\n", plugin_name, - u64_addr(ea)); - insn_t insn; - auto addr = ea; - ea_t smst_addr = BADADDR; - json smst_stack; - while (true) { - addr = prev_head(addr, 0); - decode_insn(&insn, addr); - - if (insn.itype == NN_lea && insn.ops[0].type == o_reg && - insn.ops[0].reg == REG_RDX) { - switch (insn.ops[1].type) { - case o_displ: - if (insn.ops[1].reg == REG_RSP || insn.ops[1].reg == REG_RBP) { - smst_addr = insn.ops[1].addr; - smst_stack["addr"] = smst_addr; - smst_stack["reg"] = insn.ops[1].reg; - smst_stack["start"] = next_head(ea, BADADDR); - // get bounds - func_t *f = get_func(addr); - if (f == nullptr) { - smst_stack["end"] = BADADDR; - } else { - smst_stack["end"] = f->end_ea; - } - set_cmt(addr, "_EFI_SMM_SYSTEM_TABLE2 *gSmst;", true); - } - break; - case o_mem: - smst_addr = insn.ops[1].addr; - set_cmt(addr, "_EFI_SMM_SYSTEM_TABLE2 *gSmst;", true); - break; - } - } - - // Exit loop if end of previous basic block found - if (is_basic_block_end(insn, false)) { - break; - } +bool efi_analysis::EfiAnalyzerX86::findSmstPostProcX64() { + for (auto ea : g_get_smst_location_calls) { + msg("[%s] EfiSmmBase2Protocol->GetSmstLocation call: 0x%016llX\n", g_plugin_name, + u64_addr(ea)); + insn_t insn; + auto addr = ea; + ea_t smst_addr = BADADDR; + json smst_stack; + while (true) { + addr = prev_head(addr, 0); + decode_insn(&insn, addr); + + if (insn.itype == NN_lea && insn.ops[0].type == o_reg && + insn.ops[0].reg == REG_RDX) { + switch (insn.ops[1].type) { + case o_displ: + if (insn.ops[1].reg == REG_RSP || insn.ops[1].reg == REG_RBP) { + smst_addr = insn.ops[1].addr; + smst_stack["addr"] = smst_addr; + smst_stack["reg"] = insn.ops[1].reg; + smst_stack["start"] = next_head(ea, BADADDR); + // get bounds + func_t *f = get_func(addr); + if (f == nullptr) { + smst_stack["end"] = BADADDR; + } else { + smst_stack["end"] = f->end_ea; + } + set_cmt(addr, "_EFI_SMM_SYSTEM_TABLE2 *gSmst;", true); + } + break; + case o_mem: + smst_addr = insn.ops[1].addr; + set_cmt(addr, "_EFI_SMM_SYSTEM_TABLE2 *gSmst;", true); + break; } + } - if (smst_stack.is_null() && smst_addr != BADADDR) { - msg("[%s] gSmst: 0x%016llX\n", plugin_name, u64_addr(smst_addr)); - if (!addrInVec(gSmstList, smst_addr)) { - setPtrTypeAndName(smst_addr, "gSmst", "_EFI_SMM_SYSTEM_TABLE2"); - gSmstList.push_back(smst_addr); - } + // Exit loop if end of previous basic block found + if (is_basic_block_end(insn, false)) { + break; + } + } + + if (smst_stack.is_null() && smst_addr != BADADDR) { + msg("[%s] gSmst: 0x%016llX\n", g_plugin_name, u64_addr(smst_addr)); + if (!addrInVec(gSmstList, smst_addr)) { + setPtrTypeAndName(smst_addr, "gSmst", "_EFI_SMM_SYSTEM_TABLE2"); + gSmstList.push_back(smst_addr); + } + } + + if (!smst_stack.is_null()) { + auto reg = smst_stack["reg"] == REG_RSP ? "RSP" : "RBP"; + msg("[%s] Smst: 0x%016llX, reg = %s\n", g_plugin_name, u64_addr(smst_addr), reg); + + // try to extract ChildSwSmiHandler + auto counter = 0; + ea_t ea = static_cast(smst_stack["start"]); + uint16_t smst_reg = BAD_REG; + uint64_t rcx_last = BADADDR; + while (ea < static_cast(smst_stack["end"])) { + + counter += 1; + if (counter > 500) { + break; // just in case } - if (!smst_stack.is_null()) { - auto reg = smst_stack["reg"] == REG_RSP ? "RSP" : "RBP"; - msg("[%s] Smst: 0x%016llX, reg = %s\n", plugin_name, u64_addr(smst_addr), - reg); - - // try to extract ChildSwSmiHandler - auto counter = 0; - ea_t ea = static_cast(smst_stack["start"]); - uint16_t smst_reg = BAD_REG; - uint64_t rcx_last = BADADDR; - while (ea < static_cast(smst_stack["end"])) { - - counter += 1; - if (counter > 500) { - break; // just in case - } + ea = next_head(ea, BADADDR); + decode_insn(&insn, ea); - ea = next_head(ea, BADADDR); - decode_insn(&insn, ea); - - if (insn.itype == NN_mov && insn.ops[0].type == o_reg && - insn.ops[1].type == o_displ && - smst_stack["addr"] == insn.ops[1].addr) { - switch (insn.ops[1].reg) { - case REG_RSP: - if (smst_stack["reg"] == REG_RSP) { - smst_reg = insn.ops[0].reg; - } - break; - case REG_RBP: - if (smst_stack["reg"] == REG_RBP) { - smst_reg = insn.ops[0].reg; - } - default: - break; - } - } + if (insn.itype == NN_mov && insn.ops[0].type == o_reg && + insn.ops[1].type == o_displ && smst_stack["addr"] == insn.ops[1].addr) { + switch (insn.ops[1].reg) { + case REG_RSP: + if (smst_stack["reg"] == REG_RSP) { + smst_reg = insn.ops[0].reg; + } + break; + case REG_RBP: + if (smst_stack["reg"] == REG_RBP) { + smst_reg = insn.ops[0].reg; + } + default: + break; + } + } - // Save potencial ChildSwSmiHandler address - if (insn.itype == NN_lea && insn.ops[0].type == o_reg && - insn.ops[0].reg == REG_RCX && insn.ops[1].type == o_mem) { - rcx_last = insn.ops[1].addr; - } + // Save potencial ChildSwSmiHandler address + if (insn.itype == NN_lea && insn.ops[0].type == o_reg && + insn.ops[0].reg == REG_RCX && insn.ops[1].type == o_mem) { + rcx_last = insn.ops[1].addr; + } - if (rcx_last == BADADDR || smst_reg == BAD_REG) { - continue; - } + if (rcx_last == BADADDR || smst_reg == BAD_REG) { + continue; + } - if (insn.itype == NN_callni && insn.ops[0].type == o_displ && - insn.ops[0].reg == smst_reg && - insn.ops[0].addr == SmiHandlerRegisterOffset64) { - opStroff(ea, "_EFI_SMM_SYSTEM_TABLE2"); - // save child SW SMI handler - func_t *handler_func = get_func(rcx_last); - if (handler_func != nullptr) { - childSmiHandlers.push_back(handler_func); - set_name(rcx_last, "ChildSwSmiHandler", SN_FORCE); - break; - } - } - } + if (insn.itype == NN_callni && insn.ops[0].type == o_displ && + insn.ops[0].reg == smst_reg && + insn.ops[0].addr == SmiHandlerRegisterOffset64) { + opStroff(ea, "_EFI_SMM_SYSTEM_TABLE2"); + // save child SW SMI handler + func_t *handler_func = get_func(rcx_last); + if (handler_func != nullptr) { + childSmiHandlers.push_back(handler_func); + set_name(rcx_last, "ChildSwSmiHandler", SN_FORCE); + break; + } } + } } + } - return true; + return true; } //-------------------------------------------------------------------------- // Find gBS addresses for 32-bit/64-bit modules -bool EfiAnalysis::EfiAnalyzerX86::findBootServicesTables() { +bool efi_analysis::EfiAnalyzerX86::findBootServicesTables() { + + // init architecture-specific constants + auto BS_OFFSET = BS_OFFSET_64BIT; + uint16_t REG_SP = static_cast(REG_RSP); + + if (arch == X86) { + BS_OFFSET = BS_OFFSET_32BIT; + REG_SP = static_cast(REG_ESP); + } + + insn_t insn; + for (auto seg : textSegments) { + segment_t *s = seg; + msg("[%s] gEfiBootServices finding from 0x%016llX to 0x%016llX\n", g_plugin_name, + u64_addr(s->start_ea), u64_addr(s->end_ea)); + ea_t ea = s->start_ea; + uint16_t bsRegister = 0; + uint16_t stRegister = 0; + ea_t var_addr = BADADDR; // current global variable address + while (ea <= s->end_ea) { + ea = next_head(ea, endAddress); + decode_insn(&insn, ea); + if (insn.itype == NN_mov && insn.ops[1].type == o_displ && + insn.ops[1].phrase != REG_SP) { + if (insn.ops[0].type == o_reg && insn.ops[1].addr == BS_OFFSET) { + auto bsFound = false; + auto stFound = false; + ea_t baseInsnAddr = BADADDR; + bsRegister = insn.ops[0].reg; + stRegister = insn.ops[1].phrase; + + // found BS_OFFSET, need to check 10 instructions below + for (auto i = 0; i < 10; i++) { + ea = next_head(ea, endAddress); + decode_insn(&insn, ea); + if (insn.itype == NN_mov && insn.ops[0].type == o_reg && + insn.ops[1].type == o_imm) { + var_addr = insn.ops[1].value; + auto phrase_reg = insn.ops[0].phrase; + auto next_ea = next_head(ea, BADADDR); + insn_t next_insn; + decode_insn(&next_insn, next_ea); + if (next_insn.itype == NN_mov && next_insn.ops[0].type == o_phrase && + next_insn.ops[0].phrase == phrase_reg && + next_insn.ops[1].type == o_reg && next_insn.ops[1].reg == bsRegister) { + baseInsnAddr = ea; + if (!addrInVec(gBsList, var_addr)) { + set_cmt(ea, "EFI_BOOT_SERVICES *gBS", true); + setPtrTypeAndName(var_addr, "gBS", "EFI_BOOT_SERVICES"); + gBsList.push_back(var_addr); + } + bsFound = true; + } + } - // init architecture-specific constants - auto BS_OFFSET = BS_OFFSET_64BIT; - uint16_t REG_SP = static_cast(REG_RSP); + if (insn.itype == NN_mov && insn.ops[1].type == o_reg && + insn.ops[0].type == o_mem) { + if (insn.ops[1].reg == bsRegister && !bsFound) { + baseInsnAddr = ea; + var_addr = insn.ops[0].addr; + if (!addrInVec(gBsList, var_addr)) { + set_cmt(ea, "EFI_BOOT_SERVICES *gBS", true); + setPtrTypeAndName(var_addr, "gBS", "EFI_BOOT_SERVICES"); + gBsList.push_back(var_addr); + } + bsFound = true; + } + + // here you can also find gST + if (insn.ops[1].reg == stRegister && !stFound && stRegister != bsRegister) { + var_addr = insn.ops[0].addr; + if (!addrInTables(gStList, gBsList, gRtList, var_addr)) { + set_cmt(ea, "EFI_SYSTEM_TABLE *gST", true); + setPtrTypeAndName(var_addr, "gST", "EFI_SYSTEM_TABLE"); + gStList.push_back(var_addr); + } + stFound = true; + } + } - if (arch == X86) { - BS_OFFSET = BS_OFFSET_32BIT; - REG_SP = static_cast(REG_ESP); - } + if (bsFound && stFound) { + break; + } - insn_t insn; - for (auto seg : textSegments) { - segment_t *s = seg; - msg("[%s] gEfiBootServices finding from 0x%016llX to 0x%016llX\n", plugin_name, - u64_addr(s->start_ea), u64_addr(s->end_ea)); - ea_t ea = s->start_ea; - uint16_t bsRegister = 0; - uint16_t stRegister = 0; - ea_t var_addr = BADADDR; // current global variable address - while (ea <= s->end_ea) { - ea = next_head(ea, endAddress); - decode_insn(&insn, ea); - if (insn.itype == NN_mov && insn.ops[1].type == o_displ && - insn.ops[1].phrase != REG_SP) { - if (insn.ops[0].type == o_reg && insn.ops[1].addr == BS_OFFSET) { - auto bsFound = false; - auto stFound = false; - ea_t baseInsnAddr = BADADDR; - bsRegister = insn.ops[0].reg; - stRegister = insn.ops[1].phrase; - - // found BS_OFFSET, need to check 10 instructions below - for (auto i = 0; i < 10; i++) { - ea = next_head(ea, endAddress); - decode_insn(&insn, ea); - if (insn.itype == NN_mov && insn.ops[0].type == o_reg && - insn.ops[1].type == o_imm) { - var_addr = insn.ops[1].value; - auto phrase_reg = insn.ops[0].phrase; - auto next_ea = next_head(ea, BADADDR); - insn_t next_insn; - decode_insn(&next_insn, next_ea); - if (next_insn.itype == NN_mov && - next_insn.ops[0].type == o_phrase && - next_insn.ops[0].phrase == phrase_reg && - next_insn.ops[1].type == o_reg && - next_insn.ops[1].reg == bsRegister) { - baseInsnAddr = ea; - if (!addrInVec(gBsList, var_addr)) { - set_cmt(ea, "EFI_BOOT_SERVICES *gBS", true); - setPtrTypeAndName(var_addr, "gBS", - "EFI_BOOT_SERVICES"); - gBsList.push_back(var_addr); - } - bsFound = true; - } - } - - if (insn.itype == NN_mov && insn.ops[1].type == o_reg && - insn.ops[0].type == o_mem) { - if (insn.ops[1].reg == bsRegister && !bsFound) { - baseInsnAddr = ea; - var_addr = insn.ops[0].addr; - if (!addrInVec(gBsList, var_addr)) { - set_cmt(ea, "EFI_BOOT_SERVICES *gBS", true); - setPtrTypeAndName(var_addr, "gBS", - "EFI_BOOT_SERVICES"); - gBsList.push_back(var_addr); - } - bsFound = true; - } - - // here you can also find gST - if (insn.ops[1].reg == stRegister && !stFound && - stRegister != bsRegister) { - var_addr = insn.ops[0].addr; - if (!addrInTables(gStList, gBsList, gRtList, var_addr)) { - set_cmt(ea, "EFI_SYSTEM_TABLE *gST", true); - setPtrTypeAndName(var_addr, "gST", - "EFI_SYSTEM_TABLE"); - gStList.push_back(var_addr); - } - stFound = true; - } - } - - if (bsFound && stFound) { - break; - } - - if (bsFound && !stFound) { - // check 8 instructions above baseInsnAddr - auto addr = baseInsnAddr; - for (auto i = 0; i < 8; i++) { - addr = prev_head(addr, startAddress); - decode_insn(&insn, addr); - if (insn.itype == NN_mov && insn.ops[1].type == o_reg && - insn.ops[1].reg == stRegister && - insn.ops[0].type == o_mem) { - var_addr = insn.ops[0].addr; - if (!addrInTables(gStList, gBsList, gRtList, - var_addr)) { - set_cmt(addr, "EFI_SYSTEM_TABLE *gST", true); - setPtrTypeAndName(var_addr, "gST", - "EFI_SYSTEM_TABLE"); - gStList.push_back(var_addr); - } - stFound = true; - break; - } - } - } - } + if (bsFound && !stFound) { + // check 8 instructions above baseInsnAddr + auto addr = baseInsnAddr; + for (auto i = 0; i < 8; i++) { + addr = prev_head(addr, startAddress); + decode_insn(&insn, addr); + if (insn.itype == NN_mov && insn.ops[1].type == o_reg && + insn.ops[1].reg == stRegister && insn.ops[0].type == o_mem) { + var_addr = insn.ops[0].addr; + if (!addrInTables(gStList, gBsList, gRtList, var_addr)) { + set_cmt(addr, "EFI_SYSTEM_TABLE *gST", true); + setPtrTypeAndName(var_addr, "gST", "EFI_SYSTEM_TABLE"); + gStList.push_back(var_addr); + } + stFound = true; + break; } + } } + } } + } } - return (gBsList.size() != 0); + } + return (gBsList.size() != 0); } //-------------------------------------------------------------------------- // Find gRT addresses for X86/X64 modules -bool EfiAnalysis::EfiAnalyzerX86::findRuntimeServicesTables() { +bool efi_analysis::EfiAnalyzerX86::findRuntimeServicesTables() { + + // init architecture-specific constants + auto RT_OFFSET = RT_OFFSET_64BIT; + uint16_t REG_SP = static_cast(REG_RSP); + + if (arch == X86) { + RT_OFFSET = RT_OFFSET_32BIT; + REG_SP = static_cast(REG_ESP); + } + + insn_t insn; + for (auto seg : textSegments) { + segment_t *s = seg; + msg("[%s] gEfiRuntimeServices finding from 0x%016llX to 0x%016llX\n", g_plugin_name, + u64_addr(s->start_ea), u64_addr(s->end_ea)); + ea_t ea = s->start_ea; + uint16_t rtRegister = 0; + uint16_t stRegister = 0; + ea_t var_addr = BADADDR; // current global variable address + while (ea <= s->end_ea) { + ea = next_head(ea, endAddress); + decode_insn(&insn, ea); + if (insn.itype == NN_mov && insn.ops[1].type == o_displ && + insn.ops[1].phrase != REG_SP) { + if (insn.ops[0].type == o_reg && insn.ops[1].addr == RT_OFFSET) { + rtRegister = insn.ops[0].reg; + stRegister = insn.ops[1].phrase; + auto rtFound = false; + auto stFound = false; + ea_t baseInsnAddr; + + // found RT_OFFSET, need to check 10 instructions below + for (auto i = 0; i < 10; i++) { + ea = next_head(ea, endAddress); + decode_insn(&insn, ea); + if (insn.itype == NN_mov && insn.ops[0].type == o_reg && + insn.ops[1].type == o_imm) { + var_addr = insn.ops[1].value; + auto phrase_reg = insn.ops[0].phrase; + auto next_ea = next_head(ea, BADADDR); + insn_t next_insn; + decode_insn(&next_insn, next_ea); + if (next_insn.itype == NN_mov && next_insn.ops[0].type == o_phrase && + next_insn.ops[0].phrase == phrase_reg && + next_insn.ops[1].type == o_reg && next_insn.ops[1].reg == rtRegister) { + baseInsnAddr = ea; + if (!addrInVec(gRtList, var_addr)) { + set_cmt(ea, "EFI_RUNTIME_SERVICES *gRT", true); + setPtrTypeAndName(var_addr, "gRT", "EFI_RUNTIME_SERVICES"); + gRtList.push_back(var_addr); + } + rtFound = true; + } + } - // init architecture-specific constants - auto RT_OFFSET = RT_OFFSET_64BIT; - uint16_t REG_SP = static_cast(REG_RSP); + if (insn.itype == NN_mov && insn.ops[1].type == o_reg && + insn.ops[0].type == o_mem) { + if (insn.ops[1].reg == rtRegister && !rtFound) { + baseInsnAddr = ea; + var_addr = insn.ops[0].addr; + if (!addrInVec(gRtList, var_addr)) { + set_cmt(ea, "EFI_RUNTIME_SERVICES *gRT", true); + setPtrTypeAndName(var_addr, "gRT", "EFI_RUNTIME_SERVICES"); + gRtList.push_back(var_addr); + } + rtFound = true; + } + + // here you can also find gST + if (insn.ops[1].reg == stRegister && !stFound && stRegister != rtRegister) { + var_addr = insn.ops[0].addr; + if (!addrInTables(gStList, gBsList, gRtList, var_addr)) { + set_cmt(ea, "EFI_SYSTEM_TABLE *gST", true); + setPtrTypeAndName(insn.ops[0].addr, "gST", "EFI_SYSTEM_TABLE"); + gStList.push_back(insn.ops[0].addr); + } + stFound = true; + } + } - if (arch == X86) { - RT_OFFSET = RT_OFFSET_32BIT; - REG_SP = static_cast(REG_ESP); - } + if (rtFound && stFound) { + break; + } - insn_t insn; - for (auto seg : textSegments) { - segment_t *s = seg; - msg("[%s] gEfiRuntimeServices finding from 0x%016llX to 0x%016llX\n", plugin_name, - u64_addr(s->start_ea), u64_addr(s->end_ea)); - ea_t ea = s->start_ea; - uint16_t rtRegister = 0; - uint16_t stRegister = 0; - ea_t var_addr = BADADDR; // current global variable address - while (ea <= s->end_ea) { - ea = next_head(ea, endAddress); - decode_insn(&insn, ea); - if (insn.itype == NN_mov && insn.ops[1].type == o_displ && - insn.ops[1].phrase != REG_SP) { - if (insn.ops[0].type == o_reg && insn.ops[1].addr == RT_OFFSET) { - rtRegister = insn.ops[0].reg; - stRegister = insn.ops[1].phrase; - auto rtFound = false; - auto stFound = false; - ea_t baseInsnAddr; - - // found RT_OFFSET, need to check 10 instructions below - for (auto i = 0; i < 10; i++) { - ea = next_head(ea, endAddress); - decode_insn(&insn, ea); - if (insn.itype == NN_mov && insn.ops[0].type == o_reg && - insn.ops[1].type == o_imm) { - var_addr = insn.ops[1].value; - auto phrase_reg = insn.ops[0].phrase; - auto next_ea = next_head(ea, BADADDR); - insn_t next_insn; - decode_insn(&next_insn, next_ea); - if (next_insn.itype == NN_mov && - next_insn.ops[0].type == o_phrase && - next_insn.ops[0].phrase == phrase_reg && - next_insn.ops[1].type == o_reg && - next_insn.ops[1].reg == rtRegister) { - baseInsnAddr = ea; - if (!addrInVec(gRtList, var_addr)) { - set_cmt(ea, "EFI_RUNTIME_SERVICES *gRT", true); - setPtrTypeAndName(var_addr, "gRT", - "EFI_RUNTIME_SERVICES"); - gRtList.push_back(var_addr); - } - rtFound = true; - } - } - - if (insn.itype == NN_mov && insn.ops[1].type == o_reg && - insn.ops[0].type == o_mem) { - if (insn.ops[1].reg == rtRegister && !rtFound) { - baseInsnAddr = ea; - var_addr = insn.ops[0].addr; - if (!addrInVec(gRtList, var_addr)) { - set_cmt(ea, "EFI_RUNTIME_SERVICES *gRT", true); - setPtrTypeAndName(var_addr, "gRT", - "EFI_RUNTIME_SERVICES"); - gRtList.push_back(var_addr); - } - rtFound = true; - } - - // here you can also find gST - if (insn.ops[1].reg == stRegister && !stFound && - stRegister != rtRegister) { - var_addr = insn.ops[0].addr; - if (!addrInTables(gStList, gBsList, gRtList, var_addr)) { - set_cmt(ea, "EFI_SYSTEM_TABLE *gST", true); - setPtrTypeAndName(insn.ops[0].addr, "gST", - "EFI_SYSTEM_TABLE"); - gStList.push_back(insn.ops[0].addr); - } - stFound = true; - } - } - - if (rtFound && stFound) { - break; - } - - if (rtFound && !stFound) { - // check 8 instructions above baseInsnAddr - auto addr = baseInsnAddr; - for (auto i = 0; i < 8; i++) { - addr = prev_head(addr, startAddress); - decode_insn(&insn, addr); - if (insn.itype == NN_mov && insn.ops[1].type == o_reg && - insn.ops[1].reg == stRegister && - insn.ops[0].type == o_mem) { - if (!addrInTables(gStList, gBsList, gRtList, - var_addr)) { - set_cmt(addr, "EFI_SYSTEM_TABLE *gST", true); - setPtrTypeAndName(var_addr, "gST", - "EFI_SYSTEM_TABLE"); - gStList.push_back(var_addr); - } - stFound = true; - break; - } - } - } - } + if (rtFound && !stFound) { + // check 8 instructions above baseInsnAddr + auto addr = baseInsnAddr; + for (auto i = 0; i < 8; i++) { + addr = prev_head(addr, startAddress); + decode_insn(&insn, addr); + if (insn.itype == NN_mov && insn.ops[1].type == o_reg && + insn.ops[1].reg == stRegister && insn.ops[0].type == o_mem) { + if (!addrInTables(gStList, gBsList, gRtList, var_addr)) { + set_cmt(addr, "EFI_SYSTEM_TABLE *gST", true); + setPtrTypeAndName(var_addr, "gST", "EFI_SYSTEM_TABLE"); + gStList.push_back(var_addr); + } + stFound = true; + break; } + } } + } } + } } - return (gRtList.size() != 0); + } + return (gRtList.size() != 0); } //-------------------------------------------------------------------------- // Get all boot services by xrefs for X86/X64 modules -void EfiAnalysis::EfiAnalyzerX86::getAllBootServices() { - msg("[%s] BootServices finding (xrefs)\n", plugin_name); - - if (!gBsList.size()) { - return; - } +void efi_analysis::EfiAnalyzerX86::getAllBootServices() { + msg("[%s] BootServices finding (xrefs)\n", g_plugin_name); - insn_t insn; - for (auto bs : gBsList) { + if (!gBsList.size()) { + return; + } - msg("[%s] BootServices finding by xrefs to gBS (0x%016llX)\n", plugin_name, - u64_addr(bs)); + insn_t insn; + for (auto bs : gBsList) { - auto xrefs = getXrefs(bs); - for (auto ea : xrefs) { - bool found = false; - decode_insn(&insn, ea); + msg("[%s] BootServices finding by xrefs to gBS (0x%016llX)\n", g_plugin_name, + u64_addr(bs)); - if (!(insn.itype == NN_mov && - (insn.ops[1].addr == bs || insn.ops[1].value == bs))) { - continue; - } + auto xrefs = getXrefs(bs); + for (auto ea : xrefs) { + bool found = false; + decode_insn(&insn, ea); - auto bs_reg = insn.ops[0].reg; + if (!(insn.itype == NN_mov && + (insn.ops[1].addr == bs || insn.ops[1].value == bs))) { + continue; + } - // 16 instructions below - auto addr = ea; - ea_t service_offset = BADADDR; - for (auto i = 0; i < 16; i++) { - addr = next_head(addr, BADADDR); - decode_insn(&insn, addr); + auto bs_reg = insn.ops[0].reg; - if (insn.itype == NN_mov && insn.ops[1].type == o_displ && - insn.ops[1].reg == bs_reg && insn.ops[1].addr) { - service_offset = insn.ops[1].addr; - } + // 16 instructions below + auto addr = ea; + ea_t service_offset = BADADDR; + for (auto i = 0; i < 16; i++) { + addr = next_head(addr, BADADDR); + decode_insn(&insn, addr); - if (insn.itype == NN_callni && insn.ops[0].reg == bs_reg) { - - if (insn.ops[0].addr) { - service_offset = insn.ops[0].addr; - } - - for (int j = 0; j < bootServicesTableAllLength; j++) { - - // architecture-specific variables - auto offset = bootServicesTableAll[j].offset64; - if (arch == X86) { - offset = bootServicesTableAll[j].offset32; - } - - if (service_offset == u32_addr(offset)) { - - // additional check for gBS->RegisterProtocolNotify - // (can be confused with - // gSmst->SmmInstallProtocolInterface) - if (u32_addr(offset) == RegisterProtocolNotifyOffset64) { - if (!bootServiceProtCheck(addr)) { - break; - } - } - - std::string cmt = getBsComment(u32_addr(offset), arch); - set_cmt(addr, cmt.c_str(), true); - opStroff(addr, "EFI_BOOT_SERVICES"); - - msg("[%s] 0x%016llX : %s\n", plugin_name, u64_addr(addr), - static_cast( - bootServicesTableAll[j].service_name)); - bootServices[static_cast( - bootServicesTableAll[j].service_name)] - .push_back(addr); - - // add item to allBootServices - json bsItem; - bsItem["address"] = addr; - bsItem["service_name"] = static_cast( - bootServicesTableAll[j].service_name); - bsItem["table_name"] = - static_cast("EFI_BOOT_SERVICES"); - bsItem["offset"] = offset; - - // add code addresses for arguments - eavec_t args; - get_arg_addrs(&args, addr); - bsItem["args"] = args; - - if (!jsonInVec(allServices, bsItem)) { - allServices.push_back(bsItem); - } - - found = true; - break; - } - } - } - if (found) { - break; - } - } + if (insn.itype == NN_mov && insn.ops[1].type == o_displ && + insn.ops[1].reg == bs_reg && insn.ops[1].addr) { + service_offset = insn.ops[1].addr; } - } -} -//-------------------------------------------------------------------------- -// Get all runtime services for X86/X64 modules by xrefs -void EfiAnalysis::EfiAnalyzerX86::getAllRuntimeServices() { - msg("[%s] RuntimeServices finding (xrefs)\n", plugin_name); + if (insn.itype == NN_callni && insn.ops[0].reg == bs_reg) { - if (!gRtList.size()) { - return; - } + if (insn.ops[0].addr) { + service_offset = insn.ops[0].addr; + } - insn_t insn; - for (auto rt : gRtList) { - auto xrefs = getXrefs(rt); + for (int j = 0; j < bootServicesTableAllCount; j++) { - msg("[%s] RuntimeServices finding by xrefs to gRT (0x%016llX)\n", plugin_name, - u64_addr(rt)); + // architecture-specific variables + auto offset = bootServicesTableAll[j].offset64; + if (arch == X86) { + offset = bootServicesTableAll[j].offset32; + } - for (auto ea : xrefs) { - decode_insn(&insn, ea); + if (service_offset == u32_addr(offset)) { - if (!(insn.itype == NN_mov && - (insn.ops[1].addr == rt || insn.ops[1].value == rt))) { - continue; - } + // additional check for gBS->RegisterProtocolNotify + // (can be confused with + // gSmst->SmmInstallProtocolInterface) + if (u32_addr(offset) == RegisterProtocolNotifyOffset64) { + if (!bootServiceProtCheck(addr)) { + break; + } + } - auto rt_reg = insn.ops[0].reg; + opStroff(addr, "EFI_BOOT_SERVICES"); - // 16 instructions below - ea_t addr = ea; - ea_t service_offset = BADADDR; - for (int i = 0; i < 16; i++) { - addr = next_head(addr, BADADDR); - decode_insn(&insn, addr); + msg("[%s] 0x%016llX : %s\n", g_plugin_name, u64_addr(addr), + static_cast(bootServicesTableAll[j].name)); + bootServices[static_cast(bootServicesTableAll[j].name)] + .push_back(addr); - if (insn.itype == NN_mov && insn.ops[1].type == o_displ && - insn.ops[1].reg == rt_reg && insn.ops[1].addr) { - service_offset = insn.ops[1].addr; - } + // add item to allBootServices + json bsItem; + bsItem["address"] = addr; + bsItem["service_name"] = + static_cast(bootServicesTableAll[j].name); + bsItem["table_name"] = static_cast("EFI_BOOT_SERVICES"); + bsItem["offset"] = offset; - if (insn.itype == NN_callni && insn.ops[0].reg == rt_reg) { - - if (insn.ops[0].addr) { - service_offset = insn.ops[0].addr; - } - - for (int j = 0; j < runtimeServicesTableAllLength; j++) { - - // architecture-specific variables - auto offset = runtimeServicesTableAll[j].offset64; - if (arch == X86) { - offset = runtimeServicesTableAll[j].offset32; - } - if (service_offset == u32_addr(offset)) { - std::string cmt = getRtComment(u32_addr(offset), arch); - set_cmt(addr, cmt.c_str(), true); - opStroff(addr, "EFI_RUNTIME_SERVICES"); - msg("[%s] 0x%016llX : %s\n", plugin_name, u64_addr(addr), - static_cast( - runtimeServicesTableAll[j].service_name)); - runtimeServicesAll[static_cast( - runtimeServicesTableAll[j] - .service_name)] - .push_back(addr); - - // add item to allRuntimeServices - json rtItem; - rtItem["address"] = addr; - rtItem["service_name"] = static_cast( - runtimeServicesTableAll[j].service_name); - rtItem["table_name"] = - static_cast("EFI_RUNTIME_SERVICES"); - rtItem["offset"] = offset; - - // add code addresses for arguments - eavec_t args; - get_arg_addrs(&args, addr); - rtItem["args"] = args; - - if (!jsonInVec(allServices, rtItem)) { - allServices.push_back(rtItem); - } - gRtServicesList.push_back(addr); - break; - } - } - } + // add code addresses for arguments + eavec_t args; + get_arg_addrs(&args, addr); + bsItem["args"] = args; + + if (!jsonInVec(allServices, bsItem)) { + allServices.push_back(bsItem); + } + + found = true; + break; } + } + } + if (found) { + break; } + } } + } } //-------------------------------------------------------------------------- -// Get all smm services for X64 modules -void EfiAnalysis::EfiAnalyzerX86::getAllSmmServicesX64() { - msg("[%s] SmmServices finding (xrefs)\n", plugin_name); +// Get all runtime services for X86/X64 modules by xrefs +void efi_analysis::EfiAnalyzerX86::getAllRuntimeServices() { + msg("[%s] RuntimeServices finding (xrefs)\n", g_plugin_name); - if (!gSmstList.size()) { - return; - } + if (!gRtList.size()) { + return; + } - insn_t insn; - for (auto smms : gSmstList) { - auto xrefs = getXrefs(smms); + insn_t insn; + for (auto rt : gRtList) { + auto xrefs = getXrefs(rt); - msg("[%s] SmmServices finding by xref to gSmst (0x%016llX)\n", plugin_name, - u64_addr(smms)); + msg("[%s] RuntimeServices finding by xrefs to gRT (0x%016llX)\n", g_plugin_name, + u64_addr(rt)); - for (auto ea : xrefs) { - decode_insn(&insn, ea); + for (auto ea : xrefs) { + decode_insn(&insn, ea); - if (!(insn.itype == NN_mov && insn.ops[1].type == o_mem && - insn.ops[1].addr == smms)) { - continue; - } + if (!(insn.itype == NN_mov && + (insn.ops[1].addr == rt || insn.ops[1].value == rt))) { + continue; + } - auto smst_reg = insn.ops[0].reg; + auto rt_reg = insn.ops[0].reg; - // 10 instructions below - auto addr = ea; - for (auto i = 0; i < 10; i++) { - addr = next_head(addr, BADADDR); - decode_insn(&insn, addr); - // Add NN_jmpni insn type to handle such cases - // jmp qword ptr [r9+0D0h] - if ((insn.itype == NN_callni || insn.itype == NN_jmpni) && - insn.ops[0].reg == smst_reg) { - for (int j = 0; j < smmServicesTableAllLength; j++) { - if (insn.ops[0].addr == - u32_addr(smmServicesTableAll[j].offset64)) { - - if (u32_addr(smmServicesTableAll[j].offset64) == - SmiHandlerRegisterOffset64) { - // set name for Handler argument - auto smiHandlerAddr = markChildSwSmiHandler(addr); - // save SMI handler - func_t *childSmiHandler = get_func(smiHandlerAddr); - if (childSmiHandler != nullptr) { - childSmiHandlers.push_back(childSmiHandler); - } - } - - std::string cmt = - "gSmst->" + static_cast( - smmServicesTableAll[j].service_name); - set_cmt(addr, cmt.c_str(), true); - opStroff(addr, "_EFI_SMM_SYSTEM_TABLE2"); - msg("[%s] 0x%016llX : %s\n", plugin_name, u64_addr(addr), - static_cast(smmServicesTableAll[j].service_name)); - - // add address to smmServices[...] - if (find(protSmmNames.begin(), protSmmNames.end(), - smmServicesTableAll[j].service_name) != - protSmmNames.end()) { - smmServices[smmServicesTableAll[j].service_name] - .push_back(addr); - } - smmServicesAll[static_cast( - smmServicesTableAll[j].service_name)] - .push_back(addr); - - // add item to allSmmServices - json smmsItem; - smmsItem["address"] = addr; - smmsItem["service_name"] = static_cast( - smmServicesTableAll[j].service_name); - smmsItem["table_name"] = - static_cast("_EFI_SMM_SYSTEM_TABLE2"); - smmsItem["offset"] = smmServicesTableAll[j].offset64; - - // add code addresses for arguments - eavec_t args; - get_arg_addrs(&args, addr); - smmsItem["args"] = args; - - if (!jsonInVec(allServices, smmsItem)) { - allServices.push_back(smmsItem); - } - break; - } - } + // 16 instructions below + ea_t addr = ea; + ea_t service_offset = BADADDR; + for (int i = 0; i < 16; i++) { + addr = next_head(addr, BADADDR); + decode_insn(&insn, addr); + + if (insn.itype == NN_mov && insn.ops[1].type == o_displ && + insn.ops[1].reg == rt_reg && insn.ops[1].addr) { + service_offset = insn.ops[1].addr; + } + + if (insn.itype == NN_callni && insn.ops[0].reg == rt_reg) { + + if (insn.ops[0].addr) { + service_offset = insn.ops[0].addr; + } + + for (int j = 0; j < runtimeServicesTableAllCount; j++) { + + // architecture-specific variables + auto offset = runtimeServicesTableAll[j].offset64; + if (arch == X86) { + offset = runtimeServicesTableAll[j].offset32; + } + if (service_offset == u32_addr(offset)) { + opStroff(addr, "EFI_RUNTIME_SERVICES"); + msg("[%s] 0x%016llX : %s\n", g_plugin_name, u64_addr(addr), + static_cast(runtimeServicesTableAll[j].name)); + runtimeServicesAll[static_cast( + runtimeServicesTableAll[j].name)] + .push_back(addr); + + // add item to allRuntimeServices + json rtItem; + rtItem["address"] = addr; + rtItem["service_name"] = + static_cast(runtimeServicesTableAll[j].name); + rtItem["table_name"] = static_cast("EFI_RUNTIME_SERVICES"); + rtItem["offset"] = offset; + + // add code addresses for arguments + eavec_t args; + get_arg_addrs(&args, addr); + rtItem["args"] = args; + + if (!jsonInVec(allServices, rtItem)) { + allServices.push_back(rtItem); + } + gRtServicesList.push_back(addr); + break; + } + } + } + } + } + } +} + +//-------------------------------------------------------------------------- +// Get all smm services for X64 modules +void efi_analysis::EfiAnalyzerX86::getAllSmmServicesX64() { + msg("[%s] SmmServices finding (xrefs)\n", g_plugin_name); + + if (!gSmstList.size()) { + return; + } + + insn_t insn; + for (auto smms : gSmstList) { + auto xrefs = getXrefs(smms); + + msg("[%s] SmmServices finding by xref to gSmst (0x%016llX)\n", g_plugin_name, + u64_addr(smms)); + + for (auto ea : xrefs) { + decode_insn(&insn, ea); + + if (!(insn.itype == NN_mov && insn.ops[1].type == o_mem && + insn.ops[1].addr == smms)) { + continue; + } + + auto smst_reg = insn.ops[0].reg; + + // 10 instructions below + auto addr = ea; + for (auto i = 0; i < 10; i++) { + addr = next_head(addr, BADADDR); + decode_insn(&insn, addr); + // Add NN_jmpni insn type to handle such cases + // jmp qword ptr [r9+0D0h] + if ((insn.itype == NN_callni || insn.itype == NN_jmpni) && + insn.ops[0].reg == smst_reg) { + for (int j = 0; j < smmServicesTableAllCount; j++) { + if (insn.ops[0].addr == u32_addr(smmServicesTableAll[j].offset64)) { + + if (u32_addr(smmServicesTableAll[j].offset64) == + SmiHandlerRegisterOffset64) { + // set name for Handler argument + auto smiHandlerAddr = markChildSwSmiHandler(addr); + // save SMI handler + func_t *childSmiHandler = get_func(smiHandlerAddr); + if (childSmiHandler != nullptr) { + childSmiHandlers.push_back(childSmiHandler); } - } + } + + std::string cmt = + "gSmst->" + static_cast(smmServicesTableAll[j].name); + set_cmt(addr, cmt.c_str(), true); + opStroff(addr, "_EFI_SMM_SYSTEM_TABLE2"); + msg("[%s] 0x%016llX : %s\n", g_plugin_name, u64_addr(addr), + static_cast(smmServicesTableAll[j].name)); + + // add address to smmServices[...] + if (find(protSmmNames.begin(), protSmmNames.end(), + smmServicesTableAll[j].name) != protSmmNames.end()) { + smmServices[smmServicesTableAll[j].name].push_back(addr); + } + smmServicesAll[static_cast(smmServicesTableAll[j].name)] + .push_back(addr); + + // add item to allSmmServices + json smmsItem; + smmsItem["address"] = addr; + smmsItem["service_name"] = + static_cast(smmServicesTableAll[j].name); + smmsItem["table_name"] = static_cast("_EFI_SMM_SYSTEM_TABLE2"); + smmsItem["offset"] = smmServicesTableAll[j].offset64; + + // add code addresses for arguments + eavec_t args; + get_arg_addrs(&args, addr); + smmsItem["args"] = args; + + if (!jsonInVec(allServices, smmsItem)) { + allServices.push_back(smmsItem); + } + break; + } + } } + } } + } } //-------------------------------------------------------------------------- @@ -953,1955 +915,1915 @@ void EfiAnalysis::EfiAnalyzerX86::getAllSmmServicesX64() { // Currently should cover all PeiServices except EFI_PEI_COPY_MEM, // EFI_PEI_SET_MEM, EFI_PEI_RESET2_SYSTEM, and "Future Installed Services" // (EFI_PEI_FFS_FIND_BY_NAME, etc.) -void EfiAnalysis::EfiAnalyzerX86::getAllPeiServicesX86() { - msg("[%s] PeiServices finding from 0x%016llX to 0x%016llX (all)\n", plugin_name, - u64_addr(startAddress), u64_addr(endAddress)); - ea_t ea = startAddress; - insn_t insn; - auto found = false; - while (ea <= endAddress) { - ea = next_head(ea, BADADDR); - decode_insn(&insn, ea); - if (insn.itype == NN_callni && - (insn.ops[0].reg == REG_EAX || insn.ops[0].reg == REG_ECX || - insn.ops[0].reg == REG_EDX)) { - for (int j = 0; j < pei_services_table_size; j++) { - if (insn.ops[0].addr == u32_addr(pei_services_table[j].offset)) { - bool found_src_reg = false; - ea_t address = ea; - insn_t aboveInst; - uint16_t src_reg = 0xffff; - - // 15 instructions above - for (auto j = 0; j < 15; j++) { - address = prev_head(address, startAddress); - decode_insn(&aboveInst, address); - if (aboveInst.itype == NN_mov && aboveInst.ops[0].type == o_reg && - aboveInst.ops[0].reg == insn.ops[0].reg && - aboveInst.ops[1].type == o_phrase) { - found_src_reg = true; - src_reg = aboveInst.ops[1].reg; - } - } - - bool found_push = false; - - // 15 instructions above - address = ea; - for (auto j = 0; j < 15; j++) { - address = prev_head(address, startAddress); - decode_insn(&aboveInst, address); - if (aboveInst.itype == NN_push) { - if (aboveInst.ops[0].type == o_reg && - aboveInst.ops[0].reg == src_reg) { - found_push = true; - } - break; - } - } - - if (found_src_reg && found_push) { - eavec_t args; - get_arg_addrs(&args, ea); - if (!args.size()) { - // looks like a FP - break; - } - std::string cmt = - getPeiSvcComment(u32_addr(pei_services_table[j].offset)); - set_cmt(ea, cmt.c_str(), true); - opStroff(ea, "EFI_PEI_SERVICES"); - msg("[%s] 0x%016llX : %s\n", plugin_name, u64_addr(ea), - static_cast(pei_services_table[j].name)); - peiServicesAll[static_cast( - pei_services_table[j].name)] - .push_back(ea); - json psItem; - psItem["address"] = ea; - psItem["service_name"] = - static_cast(pei_services_table[j].name); - psItem["table_name"] = - static_cast("EFI_PEI_SERVICES"); - psItem["offset"] = pei_services_table[j].offset; - - // add code addresses for arguments - psItem["args"] = args; - - if (!jsonInVec(allServices, psItem)) { - allServices.push_back(psItem); - } - } - break; - } +void efi_analysis::EfiAnalyzerX86::getAllPeiServicesX86() { + msg("[%s] PeiServices finding from 0x%016llX to 0x%016llX (all)\n", g_plugin_name, + u64_addr(startAddress), u64_addr(endAddress)); + ea_t ea = startAddress; + insn_t insn; + auto found = false; + while (ea <= endAddress) { + ea = next_head(ea, BADADDR); + decode_insn(&insn, ea); + if (insn.itype == NN_callni && + (insn.ops[0].reg == REG_EAX || insn.ops[0].reg == REG_ECX || + insn.ops[0].reg == REG_EDX)) { + for (int j = 0; j < peiServicesTable32Count; j++) { + if (insn.ops[0].addr == u32_addr(peiServicesTable32[j].offset)) { + bool found_src_reg = false; + ea_t address = ea; + insn_t aboveInst; + uint16_t src_reg = 0xffff; + + // 15 instructions above + for (auto j = 0; j < 15; j++) { + address = prev_head(address, startAddress); + decode_insn(&aboveInst, address); + if (aboveInst.itype == NN_mov && aboveInst.ops[0].type == o_reg && + aboveInst.ops[0].reg == insn.ops[0].reg && + aboveInst.ops[1].type == o_phrase) { + found_src_reg = true; + src_reg = aboveInst.ops[1].reg; } + } + + bool found_push = false; + + // 15 instructions above + address = ea; + for (auto j = 0; j < 15; j++) { + address = prev_head(address, startAddress); + decode_insn(&aboveInst, address); + if (aboveInst.itype == NN_push) { + if (aboveInst.ops[0].type == o_reg && aboveInst.ops[0].reg == src_reg) { + found_push = true; + } + break; + } + } + + if (found_src_reg && found_push) { + eavec_t args; + get_arg_addrs(&args, ea); + if (!args.size()) { + // looks like a FP + break; + } + opStroff(ea, "EFI_PEI_SERVICES"); + msg("[%s] 0x%016llX : %s\n", g_plugin_name, u64_addr(ea), + static_cast(peiServicesTable32[j].name)); + peiServicesAll[static_cast(peiServicesTable32[j].name)] + .push_back(ea); + json psItem; + psItem["address"] = ea; + psItem["service_name"] = static_cast(peiServicesTable32[j].name); + psItem["table_name"] = static_cast("EFI_PEI_SERVICES"); + psItem["offset"] = peiServicesTable32[j].offset; + + // add code addresses for arguments + psItem["args"] = args; + + if (!jsonInVec(allServices, psItem)) { + allServices.push_back(psItem); + } + } + break; } + } } + } } //-------------------------------------------------------------------------- // Get all EFI_PEI_READ_ONLY_VARIABLE2_PPI (GetVariable, NextVariableName) -void EfiAnalysis::EfiAnalyzerX86::getAllVariablePPICallsX86() { - msg("[%s] Variable PPI calls finding from 0x%016llX to 0x%016llX (all)\n", - plugin_name, u64_addr(startAddress), u64_addr(endAddress)); - ea_t ea = startAddress; - insn_t insn; - auto found = false; - while (ea <= endAddress) { - ea = next_head(ea, BADADDR); - decode_insn(&insn, ea); - if (insn.itype == NN_callni && insn.ops[0].type == o_phrase) { - for (int j = 0; j < variable_ppi_table_size; j++) { - if (insn.ops[0].addr == u32_addr(variable_ppi_table[j].offset)) { - uint16_t ppi_reg = insn.ops[0].reg; - insn_t aboveInst; - ea_t address = ea; - bool found_push = false; - - for (auto j = 0; j < 15; j++) { - address = prev_head(address, startAddress); - decode_insn(&aboveInst, address); - if (aboveInst.itype == NN_push) { - if (aboveInst.ops[0].type == o_reg && - aboveInst.ops[0].reg == ppi_reg) { - found_push = true; - } - break; - } - } - - if (found_push) { - std::string cmt = getPPICallComment( - u32_addr(variable_ppi_table[j].offset), - static_cast(variable_ppi_name)); - set_cmt(ea, cmt.c_str(), true); - opStroff(ea, "EFI_PEI_READ_ONLY_VARIABLE2_PPI"); - msg("[%s] 0x%016llX : %s\n", plugin_name, u64_addr(ea), - static_cast(variable_ppi_table[j].name)); - std::string ppi_call = - static_cast(variable_ppi_name) + "." + - static_cast(variable_ppi_table[j].name); - ppiCallsAll[ppi_call].push_back(ea); - - // Injecting PPI call as service - json ppiItem; - ppiItem["address"] = ea; - ppiItem["service_name"] = ppi_call; - ppiItem["table_name"] = - static_cast("EFI_PEI_READ_ONLY_VARIABLE2_PPI"); - ppiItem["offset"] = variable_ppi_table[j].offset; - - // add code addresses for arguments - eavec_t args; - get_arg_addrs(&args, ea); - ppiItem["args"] = args; - - if (!jsonInVec(allServices, ppiItem)) { - allServices.push_back(ppiItem); - } - } - break; - } - } +void efi_analysis::EfiAnalyzerX86::getAllVariablePPICallsX86() { + msg("[%s] Variable PPI calls finding from 0x%016llX to 0x%016llX (all)\n", + g_plugin_name, u64_addr(startAddress), u64_addr(endAddress)); + ea_t ea = startAddress; + insn_t insn; + auto found = false; + while (ea <= endAddress) { + ea = next_head(ea, BADADDR); + decode_insn(&insn, ea); + if (insn.itype == NN_callni && insn.ops[0].type == o_phrase) { + for (int j = 0; j < variablePpiTableAllCount; j++) { + if (insn.ops[0].addr == u32_addr(variablePpiTableAll[j].offset32)) { + uint16_t ppi_reg = insn.ops[0].reg; + insn_t aboveInst; + ea_t address = ea; + bool found_push = false; + + for (auto j = 0; j < 15; j++) { + address = prev_head(address, startAddress); + decode_insn(&aboveInst, address); + if (aboveInst.itype == NN_push) { + if (aboveInst.ops[0].type == o_reg && aboveInst.ops[0].reg == ppi_reg) { + found_push = true; + } + break; + } + } + + if (found_push) { + opStroff(ea, "EFI_PEI_READ_ONLY_VARIABLE2_PPI"); + msg("[%s] 0x%016llX : %s\n", g_plugin_name, u64_addr(ea), + static_cast(variablePpiTableAll[j].name)); + std::string ppi_call = + "VariablePPI." + static_cast(variablePpiTableAll[j].name); + ppiCallsAll[ppi_call].push_back(ea); + + // Injecting PPI call as service + json ppiItem; + ppiItem["address"] = ea; + ppiItem["service_name"] = ppi_call; + ppiItem["table_name"] = + static_cast("EFI_PEI_READ_ONLY_VARIABLE2_PPI"); + ppiItem["offset"] = variablePpiTableAll[j].offset32; + + // add code addresses for arguments + eavec_t args; + get_arg_addrs(&args, ea); + ppiItem["args"] = args; + + if (!jsonInVec(allServices, ppiItem)) { + allServices.push_back(ppiItem); + } + } + break; } + } } + } } //-------------------------------------------------------------------------- // Get PPI names for X86 PEI modules -void EfiAnalysis::EfiAnalyzerX86::getPpiNamesX86() { - msg("[%s] PPI finding (PEI services)\n", plugin_name); - ea_t start = startAddress; - segment_t *seg_info = get_segm_by_name(".text"); - if (seg_info != nullptr) { - start = seg_info->start_ea; - } - for (int i = 0; i < pei_services_table_size; i++) { - if (pei_services_table[i].ppi_guid_push_number == PUSH_NONE || - !peiServicesAll.contains(pei_services_table[i].name)) { - continue; - } - - std::vector addrs = peiServicesAll[pei_services_table[i].name]; - - // for each PEI service - for (auto ea : addrs) { - ea_t address = ea; - - insn_t insn; - ea_t guidCodeAddress = 0; - ea_t guidDataAddress = 0; - auto found = false; - - uint16_t pushCounter = 0; - msg("[%s] looking for PPIs in the 0x%016llX area (push number: %d)\n", - plugin_name, u64_addr(address), - pei_services_table[i].ppi_guid_push_number); +void efi_analysis::EfiAnalyzerX86::getPpiNamesX86() { + msg("[%s] PPI finding (PEI services)\n", g_plugin_name); + ea_t start = startAddress; + segment_t *seg_info = get_segm_by_name(".text"); + if (seg_info != nullptr) { + start = seg_info->start_ea; + } + for (int i = 0; i < peiServicesTable32Count; i++) { + if (peiServicesTable32[i].push_number == PUSH_NONE || + !peiServicesAll.contains(peiServicesTableAll[i].name)) { + continue; + } + + std::vector addrs = peiServicesAll[peiServicesTable32[i].name]; + + // for each PEI service + for (auto ea : addrs) { + ea_t address = ea; - // Check current basic block - while (true) { - address = prev_head(address, startAddress); - decode_insn(&insn, address); + insn_t insn; + ea_t guidCodeAddress = 0; + ea_t guidDataAddress = 0; + auto found = false; - if (insn.itype == NN_push) { - pushCounter += 1; - } + uint16_t pushCounter = 0; + msg("[%s] looking for PPIs in the 0x%016llX area (push number: %d)\n", + g_plugin_name, u64_addr(address), peiServicesTable32[i].push_number); - if (pushCounter == pei_services_table[i].ppi_guid_push_number && - insn.ops[0].type == o_imm && - (insn.ops[0].value & 0xffffffff) >= start && - insn.ops[0].value != BADADDR) { // found "push gGuid" insn - guidCodeAddress = address; - guidDataAddress = insn.ops[0].value & 0xffffffff; - found = true; - break; - } + // Check current basic block + while (true) { + address = prev_head(address, startAddress); + decode_insn(&insn, address); - // Exit loop if end of previous basic block found - if (is_basic_block_end(insn, false)) { - break; - } - } + if (insn.itype == NN_push) { + pushCounter += 1; + } - msg("[%s] GUID address: 0x%016llX\n", plugin_name, u64_addr(guidDataAddress)); + if (pushCounter == peiServicesTable32[i].push_number && + insn.ops[0].type == o_imm && (insn.ops[0].value & 0xffffffff) >= start && + insn.ops[0].value != BADADDR) { // found "push gGuid" insn + guidCodeAddress = address; + guidDataAddress = insn.ops[0].value & 0xffffffff; + found = true; + break; + } - if (found) { - msg("[%s] found PPI GUID parameter at 0x%016llX\n", plugin_name, - u64_addr(guidCodeAddress)); - auto guid = getGuidByAddr(guidDataAddress); - if (!checkGuid(guid)) { - msg("[%s] Incorrect GUID at 0x%016llX\n", plugin_name, - u64_addr(guidCodeAddress)); - continue; - } + // Exit loop if end of previous basic block found + if (is_basic_block_end(insn, false)) { + break; + } + } + + msg("[%s] GUID address: 0x%016llX\n", g_plugin_name, u64_addr(guidDataAddress)); + + if (found) { + msg("[%s] found PPI GUID parameter at 0x%016llX\n", g_plugin_name, + u64_addr(guidCodeAddress)); + auto guid = getGuidByAddr(guidDataAddress); + if (!checkGuid(guid)) { + msg("[%s] Incorrect GUID at 0x%016llX\n", g_plugin_name, + u64_addr(guidCodeAddress)); + continue; + } - // get PPI item - json ppiItem; - ppiItem["address"] = guidDataAddress; - ppiItem["xref"] = guidCodeAddress; - ppiItem["service"] = pei_services_table[i].name; - ppiItem["guid"] = getGuidFromValue(guid); - ppiItem["module"] = "Current"; - - // find GUID name - auto it = dbProtocolsMap.find(guid); - if (it != dbProtocolsMap.end()) { - std::string name = it->second; - ppiItem["ppi_name"] = name; - - // check if item already exists - if (!jsonInVec(allPPIs, ppiItem)) { - allPPIs.push_back(ppiItem); - } - continue; - } + // get PPI item + json ppiItem; + ppiItem["address"] = guidDataAddress; + ppiItem["xref"] = guidCodeAddress; + ppiItem["service"] = peiServicesTableAll[i].name; + ppiItem["guid"] = getGuidFromValue(guid); + ppiItem["module"] = "Current"; + + // find GUID name + auto it = dbProtocolsMap.find(guid); + if (it != dbProtocolsMap.end()) { + std::string name = it->second; + ppiItem["ppi_name"] = name; + + // check if item already exists + if (!jsonInVec(allPPIs, ppiItem)) { + allPPIs.push_back(ppiItem); + } + continue; + } - // proprietary PPI - if (ppiItem["ppi_name"].is_null()) { - ppiItem["ppi_name"] = "ProprietaryPpi"; + // proprietary PPI + if (ppiItem["ppi_name"].is_null()) { + ppiItem["ppi_name"] = "ProprietaryPpi"; - // check if item already exists - if (!jsonInVec(allPPIs, ppiItem)) { - allPPIs.push_back(ppiItem); - } - continue; - } - } + // check if item already exists + if (!jsonInVec(allPPIs, ppiItem)) { + allPPIs.push_back(ppiItem); + } + continue; } + } } + } } //-------------------------------------------------------------------------- // Get boot services by protocols for X64 modules -void EfiAnalysis::EfiAnalyzerX86::getProtBootServicesX64() { - insn_t insn; - for (auto s : textSegments) { - msg("[%s] BootServices finding from 0x%016llX to 0x%016llX (protocols)\n", - plugin_name, u64_addr(s->start_ea), u64_addr(s->end_ea)); - ea_t ea = s->start_ea; - uint16_t bsRegister = 0; - while (ea <= s->end_ea) { - ea = next_head(ea, endAddress); - decode_insn(&insn, ea); - if (insn.itype != NN_callni || insn.ops[0].reg != REG_RAX) { - continue; - } - for (auto i = 0; i < bootServicesTable64Length; i++) { - if (insn.ops[0].addr != u32_addr(bootServicesTable64[i].offset)) { - continue; - } +void efi_analysis::EfiAnalyzerX86::getProtBootServicesX64() { + insn_t insn; + for (auto s : textSegments) { + msg("[%s] BootServices finding from 0x%016llX to 0x%016llX (protocols)\n", + g_plugin_name, u64_addr(s->start_ea), u64_addr(s->end_ea)); + ea_t ea = s->start_ea; + uint16_t bsRegister = 0; + while (ea <= s->end_ea) { + ea = next_head(ea, endAddress); + decode_insn(&insn, ea); + if (insn.itype != NN_callni || insn.ops[0].reg != REG_RAX) { + continue; + } + for (auto i = 0; i < bootServicesTable64Count; i++) { + if (insn.ops[0].addr != u32_addr(bootServicesTable64[i].offset)) { + continue; + } - // additional check for gBS->RegisterProtocolNotify - // (can be confused with gSmst->SmmInstallProtocolInterface) - if (u32_addr(bootServicesTable64[i].offset) == - RegisterProtocolNotifyOffset64) { - if (!bootServiceProtCheck(ea)) { - break; - } - } + // additional check for gBS->RegisterProtocolNotify + // (can be confused with gSmst->SmmInstallProtocolInterface) + if (u32_addr(bootServicesTable64[i].offset) == RegisterProtocolNotifyOffset64) { + if (!bootServiceProtCheck(ea)) { + break; + } + } - // check that address does not belong to the protocol interface - // (gBS != gInterface) - auto bs_addr = findUnknownBsVarX64(ea); - if (addrInVec(gRtList, bs_addr) || !bootServiceProtCheckXrefs(bs_addr)) { - break; - } + // check that address does not belong to the protocol interface + // (gBS != gInterface) + auto bs_addr = findUnknownBsVarX64(ea); + if (addrInVec(gRtList, bs_addr) || !bootServiceProtCheckXrefs(bs_addr)) { + break; + } - std::string cmt = - getBsComment(u32_addr(bootServicesTable64[i].offset), X64); - set_cmt(ea, cmt.c_str(), true); - opStroff(ea, "EFI_BOOT_SERVICES"); - msg("[%s] 0x%016llX : %s\n", plugin_name, u64_addr(ea), - static_cast(bootServicesTable64[i].service_name)); - bootServices[static_cast( - bootServicesTable64[i].service_name)] - .push_back(ea); - - // add item to allBootServices - json bsItem; - bsItem["address"] = ea; - bsItem["service_name"] = - static_cast(bootServicesTable64[i].service_name); - bsItem["table_name"] = static_cast("EFI_BOOT_SERVICES"); - bsItem["offset"] = bootServicesTable64[i].offset; - - // add code addresses for arguments - eavec_t args; - get_arg_addrs(&args, ea); - bsItem["args"] = args; - - if (!jsonInVec(allServices, bsItem)) { - allServices.push_back(bsItem); - } - break; - } + opStroff(ea, "EFI_BOOT_SERVICES"); + msg("[%s] 0x%016llX : %s\n", g_plugin_name, u64_addr(ea), + static_cast(bootServicesTable64[i].name)); + bootServices[static_cast(bootServicesTable64[i].name)].push_back(ea); + + // add item to allBootServices + json bsItem; + bsItem["address"] = ea; + bsItem["service_name"] = static_cast(bootServicesTable64[i].name); + bsItem["table_name"] = static_cast("EFI_BOOT_SERVICES"); + bsItem["offset"] = bootServicesTable64[i].offset; + + // add code addresses for arguments + eavec_t args; + get_arg_addrs(&args, ea); + bsItem["args"] = args; + + if (!jsonInVec(allServices, bsItem)) { + allServices.push_back(bsItem); } + break; + } } + } } //-------------------------------------------------------------------------- // Get boot services by protocols for X86 modules -void EfiAnalysis::EfiAnalyzerX86::getProtBootServicesX86() { - msg("[%s] BootServices finding from 0x%016llX to 0x%016llX (protocols)\n", - plugin_name, u64_addr(startAddress), u64_addr(endAddress)); - ea_t ea = startAddress; - insn_t insn; - uint16_t bsRegister = 0; - while (ea <= endAddress) { - ea = next_head(ea, endAddress); - decode_insn(&insn, ea); - if (insn.itype == NN_callni && insn.ops[0].reg == REG_EAX) { - for (auto i = 0; i < bootServicesTable32Length; i++) { - if (insn.ops[0].addr == u32_addr(bootServicesTable32[i].offset)) { - std::string cmt = - getBsComment(u32_addr(bootServicesTable32[i].offset), X86); - set_cmt(ea, cmt.c_str(), true); - opStroff(ea, "EFI_BOOT_SERVICES"); - msg("[%s] 0x%016llX : %s\n", plugin_name, u64_addr(ea), - static_cast(bootServicesTable32[i].service_name)); - bootServices[static_cast( - bootServicesTable32[i].service_name)] - .push_back(ea); - - // add item to allBootServices - json bsItem; - bsItem["address"] = ea; - bsItem["service_name"] = - static_cast(bootServicesTable32[i].service_name); - bsItem["table_name"] = static_cast("EFI_BOOT_SERVICES"); - bsItem["offset"] = bootServicesTable32[i].offset; - - // add code addresses for arguments - eavec_t args; - get_arg_addrs(&args, ea); - bsItem["args"] = args; - - if (!jsonInVec(allServices, bsItem)) { - allServices.push_back(bsItem); - } - break; - } - } +void efi_analysis::EfiAnalyzerX86::getProtBootServicesX86() { + msg("[%s] BootServices finding from 0x%016llX to 0x%016llX (protocols)\n", + g_plugin_name, u64_addr(startAddress), u64_addr(endAddress)); + ea_t ea = startAddress; + insn_t insn; + uint16_t bsRegister = 0; + while (ea <= endAddress) { + ea = next_head(ea, endAddress); + decode_insn(&insn, ea); + if (insn.itype == NN_callni && insn.ops[0].reg == REG_EAX) { + for (auto i = 0; i < bootServicesTable32Count; i++) { + if (insn.ops[0].addr == u32_addr(bootServicesTable32[i].offset)) { + opStroff(ea, "EFI_BOOT_SERVICES"); + msg("[%s] 0x%016llX : %s\n", g_plugin_name, u64_addr(ea), + static_cast(bootServicesTable32[i].name)); + bootServices[static_cast(bootServicesTable32[i].name)].push_back( + ea); + + // add item to allBootServices + json bsItem; + bsItem["address"] = ea; + bsItem["service_name"] = static_cast(bootServicesTable32[i].name); + bsItem["table_name"] = static_cast("EFI_BOOT_SERVICES"); + bsItem["offset"] = bootServicesTable32[i].offset; + + // add code addresses for arguments + eavec_t args; + get_arg_addrs(&args, ea); + bsItem["args"] = args; + + if (!jsonInVec(allServices, bsItem)) { + allServices.push_back(bsItem); + } + break; } + } } + } } //-------------------------------------------------------------------------- // find other addresses of global gBS vars for X64 modules -void EfiAnalysis::EfiAnalyzerX86::findOtherBsTablesX64() { - msg("[%s] Finding of other addresses of global gBS variables\n", plugin_name); - for (auto s : allServices) { - std::string table_name = s["table_name"]; - if (table_name.compare(static_cast("EFI_BOOT_SERVICES"))) { - continue; - } - auto offset = u32_addr(s["offset"]); - if (offset < 0xf0) { - continue; - } - ea_t addr = static_cast(s["address"]); - msg("[%s] current service: 0x%016llX\n", plugin_name, u64_addr(addr)); - ea_t addr_bs = findUnknownBsVarX64(addr); - if (!addr_bs || addrInVec(gBsList, addr_bs) || addrInVec(gRtList, addr_bs)) { - continue; - } - msg("[%s] found BootServices table at 0x%016llX, address = 0x%016llX\n", - plugin_name, u64_addr(addr), u64_addr(addr_bs)); - setPtrTypeAndName(addr_bs, "gBS", "EFI_BOOT_SERVICES"); - gBsList.push_back(addr_bs); - } +void efi_analysis::EfiAnalyzerX86::findOtherBsTablesX64() { + msg("[%s] Finding of other addresses of global gBS variables\n", g_plugin_name); + for (auto s : allServices) { + std::string table_name = s["table_name"]; + if (table_name.compare(static_cast("EFI_BOOT_SERVICES"))) { + continue; + } + auto offset = u32_addr(s["offset"]); + if (offset < 0xf0) { + continue; + } + ea_t addr = static_cast(s["address"]); + msg("[%s] current service: 0x%016llX\n", g_plugin_name, u64_addr(addr)); + ea_t addr_bs = findUnknownBsVarX64(addr); + if (!addr_bs || addrInVec(gBsList, addr_bs) || addrInVec(gRtList, addr_bs)) { + continue; + } + msg("[%s] found BootServices table at 0x%016llX, address = 0x%016llX\n", + g_plugin_name, u64_addr(addr), u64_addr(addr_bs)); + setPtrTypeAndName(addr_bs, "gBS", "EFI_BOOT_SERVICES"); + gBsList.push_back(addr_bs); + } } -bool EfiAnalysis::EfiAnalyzer::AddProtocol(std::string serviceName, ea_t guidAddress, - ea_t xrefAddress, ea_t callAddress) { - - if (arch != UEFI && guidAddress >= startAddress && guidAddress <= endAddress) { - msg("[%s] wrong service call detection: 0x%016llX\n", plugin_name, - u64_addr(callAddress)); - return false; // filter FP - } - - json protocol; - auto guid = getGuidByAddr(guidAddress); - protocol["address"] = guidAddress; - protocol["xref"] = xrefAddress; - protocol["service"] = serviceName; - protocol["guid"] = getGuidFromValue(guid); - protocol["ea"] = callAddress; - - qstring moduleName("Current"); - if (getInputFileType() == UEFI) { - moduleName = getModuleNameLoader(callAddress); - } - protocol["module"] = static_cast(moduleName.c_str()); - - // find GUID name - auto it = dbProtocolsMap.find(guid); - if (it != dbProtocolsMap.end()) { - std::string name = it->second; - protocol["prot_name"] = name; - } else { - protocol["prot_name"] = "UNKNOWN_PROTOCOL_GUID"; - setTypeAndName(guidAddress, "UNKNOWN_PROTOCOL_GUID", "EFI_GUID"); - } - if (!jsonInVec(allProtocols, protocol)) { - allProtocols.push_back(protocol); - } - return true; +bool efi_analysis::EfiAnalyzer::AddProtocol(std::string serviceName, ea_t guidAddress, + ea_t xrefAddress, ea_t callAddress) { + + if (arch != UEFI && guidAddress >= startAddress && guidAddress <= endAddress) { + msg("[%s] wrong service call detection: 0x%016llX\n", g_plugin_name, + u64_addr(callAddress)); + return false; // filter FP + } + + json protocol; + auto guid = getGuidByAddr(guidAddress); + protocol["address"] = guidAddress; + protocol["xref"] = xrefAddress; + protocol["service"] = serviceName; + protocol["guid"] = getGuidFromValue(guid); + protocol["ea"] = callAddress; + + qstring moduleName("Current"); + if (getInputFileType() == UEFI) { + moduleName = getModuleNameLoader(callAddress); + } + protocol["module"] = static_cast(moduleName.c_str()); + + // find GUID name + auto it = dbProtocolsMap.find(guid); + if (it != dbProtocolsMap.end()) { + std::string name = it->second; + protocol["prot_name"] = name; + } else { + protocol["prot_name"] = "UNKNOWN_PROTOCOL_GUID"; + setTypeAndName(guidAddress, "UNKNOWN_PROTOCOL_GUID", "EFI_GUID"); + } + if (!jsonInVec(allProtocols, protocol)) { + allProtocols.push_back(protocol); + } + return true; } //-------------------------------------------------------------------------- // Extract protocols from InstallMultipleProtocolInterfaces service call -bool EfiAnalysis::EfiAnalyzerX86::InstallMultipleProtocolInterfacesHandler() { - std::vector addrs = bootServices["InstallMultipleProtocolInterfaces"]; - std::map stack_params; - insn_t insn; - - for (auto ea : addrs) { - ea_t address = ea; - bool found = false; - bool check_stack = true; - ea_t handle_arg = BADADDR; - stack_params.clear(); - - // Check current basic block - while (true) { - address = prev_head(address, startAddress); - decode_insn(&insn, address); - - if (!check_stack && found) { - break; // installed only one protocol - } - - // Exit loop if end of previous basic block found - if (is_basic_block_end(insn, false)) { - break; - } - - // Get handle stack/data parameter - if (handle_arg == BADADDR && insn.itype == NN_lea && - insn.ops[0].reg == REG_RCX) { - switch (insn.ops[1].type) { - case o_displ: - if (insn.ops[1].reg == REG_RSP || insn.ops[1].reg == REG_RBP) { - handle_arg = insn.ops[1].addr; - } - break; - case o_mem: - handle_arg = insn.ops[1].addr; - break; - } - } - - // Exit from loop if found last argument (NULL) - if (insn.itype == NN_xor && insn.ops[0].reg == REG_R9 && - insn.ops[1].reg == REG_R9) { - check_stack = false; - } - - if (insn.itype == NN_and && insn.ops[0].type == o_displ && - (insn.ops[0].reg == REG_RSP || insn.ops[0].reg == REG_RBP) && - insn.ops[0].addr != handle_arg && insn.ops[1].type == o_imm && - insn.ops[1].value == 0) { - check_stack = false; - break; - } - - if (insn.itype == NN_lea && insn.ops[0].type == o_reg && - insn.ops[1].type == o_mem) { - - switch (insn.ops[0].reg) { - case REG_RDX: - case REG_R9: - AddProtocol("InstallMultipleProtocolInterfaces", insn.ops[1].addr, - address, ea); - found = true; - break; - case REG_RAX: - stack_params.insert(std::make_pair(address, insn.ops[1].addr)); - break; - } - } +bool efi_analysis::EfiAnalyzerX86::InstallMultipleProtocolInterfacesHandler() { + std::vector addrs = bootServices["InstallMultipleProtocolInterfaces"]; + std::map stack_params; + insn_t insn; + + for (auto ea : addrs) { + ea_t address = ea; + bool found = false; + bool check_stack = true; + ea_t handle_arg = BADADDR; + stack_params.clear(); + + // Check current basic block + while (true) { + address = prev_head(address, startAddress); + decode_insn(&insn, address); + + if (!check_stack && found) { + break; // installed only one protocol + } + + // Exit loop if end of previous basic block found + if (is_basic_block_end(insn, false)) { + break; + } + + // Get handle stack/data parameter + if (handle_arg == BADADDR && insn.itype == NN_lea && insn.ops[0].reg == REG_RCX) { + switch (insn.ops[1].type) { + case o_displ: + if (insn.ops[1].reg == REG_RSP || insn.ops[1].reg == REG_RBP) { + handle_arg = insn.ops[1].addr; + } + break; + case o_mem: + handle_arg = insn.ops[1].addr; + break; } - - // Enumerate all stack params - auto index = 0; - for (auto const ¶m : stack_params) { - if (index++ % 2) { - AddProtocol("InstallMultipleProtocolInterfaces", param.second, - param.first, ea); - } + } + + // Exit from loop if found last argument (NULL) + if (insn.itype == NN_xor && insn.ops[0].reg == REG_R9 && + insn.ops[1].reg == REG_R9) { + check_stack = false; + } + + if (insn.itype == NN_and && insn.ops[0].type == o_displ && + (insn.ops[0].reg == REG_RSP || insn.ops[0].reg == REG_RBP) && + insn.ops[0].addr != handle_arg && insn.ops[1].type == o_imm && + insn.ops[1].value == 0) { + check_stack = false; + break; + } + + if (insn.itype == NN_lea && insn.ops[0].type == o_reg && + insn.ops[1].type == o_mem) { + + switch (insn.ops[0].reg) { + case REG_RDX: + case REG_R9: + AddProtocol("InstallMultipleProtocolInterfaces", insn.ops[1].addr, address, ea); + found = true; + break; + case REG_RAX: + stack_params.insert(std::make_pair(address, insn.ops[1].addr)); + break; } + } } - return true; + // Enumerate all stack params + auto index = 0; + for (auto const ¶m : stack_params) { + if (index++ % 2) { + AddProtocol("InstallMultipleProtocolInterfaces", param.second, param.first, ea); + } + } + } + + return true; } //-------------------------------------------------------------------------- // Get boot services protocols names for X64 modules -void EfiAnalysis::EfiAnalyzerX86::getBsProtNamesX64() { - if (!textSegments.size()) { - return; - } - segment_t *s = textSegments.at(0); - ea_t start = s->start_ea; - msg("[%s] protocols finding (boot services, start address = 0x%016llX)\n", - plugin_name, u64_addr(start)); +void efi_analysis::EfiAnalyzerX86::getBsProtNamesX64() { + if (!textSegments.size()) { + return; + } + segment_t *s = textSegments.at(0); + ea_t start = s->start_ea; + msg("[%s] protocols finding (boot services, start address = 0x%016llX)\n", + g_plugin_name, u64_addr(start)); - InstallMultipleProtocolInterfacesHandler(); - for (int i = 0; i < bootServicesTable64Length; i++) { - - if (bootServicesTable64[i].offset == InstallMultipleProtocolInterfacesOffset64) { - // Handle InstallMultipleProtocolInterfaces separately - continue; - } + InstallMultipleProtocolInterfacesHandler(); + for (int i = 0; i < bootServicesTable64Count; i++) { - std::vector addrs = bootServices[bootServicesTable64[i].service_name]; - for (auto ea : addrs) { - ea_t address = ea; - msg("[%s] looking for protocols in the 0x%016llX area\n", plugin_name, - u64_addr(address)); - insn_t insn; - ea_t guidCodeAddress = 0; - ea_t guidDataAddress = 0; - auto found = false; - - // check current basic block - while (true) { - address = prev_head(address, startAddress); - decode_insn(&insn, address); - - // exit from loop if end of previous basic block found - if (is_basic_block_end(insn, false)) { - break; - } + if (bootServicesTable64[i].offset == InstallMultipleProtocolInterfacesOffset64) { + // Handle InstallMultipleProtocolInterfaces separately + continue; + } - if (insn.itype == NN_lea && insn.ops[0].type == o_reg && - insn.ops[0].reg == bootServicesTable64[i].reg && - insn.ops[1].type == o_mem) { - guidCodeAddress = address; - guidDataAddress = insn.ops[1].addr; - if (insn.ops[1].addr > start && insn.ops[1].addr != BADADDR) { - found = true; - break; - } - } + std::vector addrs = bootServices[bootServicesTable64[i].name]; + for (auto ea : addrs) { + ea_t address = ea; + msg("[%s] looking for protocols in the 0x%016llX area\n", g_plugin_name, + u64_addr(address)); + insn_t insn; + ea_t guidCodeAddress = 0; + ea_t guidDataAddress = 0; + auto found = false; + + // check current basic block + while (true) { + address = prev_head(address, startAddress); + decode_insn(&insn, address); + + // exit from loop if end of previous basic block found + if (is_basic_block_end(insn, false)) { + break; + } - if (insn.itype == NN_mov && insn.ops[0].type == o_reg && - insn.ops[0].reg == bootServicesTable64[i].reg && - insn.ops[1].type == o_imm) { - guidCodeAddress = address; - guidDataAddress = insn.ops[1].value; - if (insn.ops[1].value > start && insn.ops[1].value != BADADDR) { - found = true; - break; - } - } - } + if (insn.itype == NN_lea && insn.ops[0].type == o_reg && + insn.ops[0].reg == bootServicesTable64[i].reg && insn.ops[1].type == o_mem) { + guidCodeAddress = address; + guidDataAddress = insn.ops[1].addr; + if (insn.ops[1].addr > start && insn.ops[1].addr != BADADDR) { + found = true; + break; + } + } - if (found) { - msg("[%s] getBsProtNamesX64: found protocol GUID parameter at " - "0x%016llX\n", - plugin_name, u64_addr(guidCodeAddress)); - auto guid = getGuidByAddr(guidDataAddress); - if (!checkGuid(guid)) { - msg("[%s] Incorrect GUID at 0x%016llX\n", plugin_name, - u64_addr(guidCodeAddress)); - continue; - } + if (insn.itype == NN_mov && insn.ops[0].type == o_reg && + insn.ops[0].reg == bootServicesTable64[i].reg && insn.ops[1].type == o_imm) { + guidCodeAddress = address; + guidDataAddress = insn.ops[1].value; + if (insn.ops[1].value > start && insn.ops[1].value != BADADDR) { + found = true; + break; + } + } + } - AddProtocol(bootServicesTable64[i].service_name, guidDataAddress, - guidCodeAddress, ea); - } + if (found) { + msg("[%s] getBsProtNamesX64: found protocol GUID parameter at " + "0x%016llX\n", + g_plugin_name, u64_addr(guidCodeAddress)); + auto guid = getGuidByAddr(guidDataAddress); + if (!checkGuid(guid)) { + msg("[%s] Incorrect GUID at 0x%016llX\n", g_plugin_name, + u64_addr(guidCodeAddress)); + continue; } + + AddProtocol(bootServicesTable64[i].name, guidDataAddress, guidCodeAddress, ea); + } } + } } //-------------------------------------------------------------------------- // Get boot services protocols names for X86 modules -void EfiAnalysis::EfiAnalyzerX86::getBsProtNamesX86() { - msg("[%s] protocols finding (boot services)\n", plugin_name); - ea_t start = startAddress; - segment_t *seg_info = get_segm_by_name(".text"); - if (seg_info != nullptr) { - start = seg_info->start_ea; - } - for (int i = 0; i < bootServicesTable32Length; i++) { - std::vector addrs = bootServices[bootServicesTable32[i].service_name]; - - // for each boot service - for (auto ea : addrs) { - ea_t address = ea; - msg("[%s] looking for protocols in the 0x%016llX area\n", plugin_name, - u64_addr(address)); - insn_t insn; - ea_t guidCodeAddress = 0; - ea_t guidDataAddress = 0; - auto found = false; - uint16_t pushNumber = bootServicesTable32[i].push_number; - - // if service is not currently being processed - if (pushNumber == PUSH_NONE) { - break; - } - - // check current basic block - uint16_t pushCounter = 0; - while (true) { - address = prev_head(address, startAddress); - decode_insn(&insn, address); - - // exit from loop if end of previous basic block found - if (is_basic_block_end(insn, false)) { - break; - } - - if (insn.itype == NN_push) { - pushCounter += 1; - if (pushCounter > pushNumber) { - break; - } - if (pushCounter == pushNumber) { - guidCodeAddress = address; - guidDataAddress = insn.ops[0].value; - if (insn.ops[0].value > start && insn.ops[0].value != BADADDR) { - found = true; - break; - } - } - } - } +void efi_analysis::EfiAnalyzerX86::getBsProtNamesX86() { + msg("[%s] protocols finding (boot services)\n", g_plugin_name); + ea_t start = startAddress; + segment_t *seg_info = get_segm_by_name(".text"); + if (seg_info != nullptr) { + start = seg_info->start_ea; + } + for (int i = 0; i < bootServicesTable32Count; i++) { + std::vector addrs = bootServices[bootServicesTable32[i].name]; + + // for each boot service + for (auto ea : addrs) { + ea_t address = ea; + msg("[%s] looking for protocols in the 0x%016llX area\n", g_plugin_name, + u64_addr(address)); + insn_t insn; + ea_t guidCodeAddress = 0; + ea_t guidDataAddress = 0; + auto found = false; + uint16_t pushNumber = bootServicesTable32[i].push_number; + + // if service is not currently being processed + if (pushNumber == PUSH_NONE) { + break; + } + + // check current basic block + uint16_t pushCounter = 0; + while (true) { + address = prev_head(address, startAddress); + decode_insn(&insn, address); + + // exit from loop if end of previous basic block found + if (is_basic_block_end(insn, false)) { + break; + } - if (found) { - msg("[%s] getBsProtNamesX86: found protocol GUID parameter at " - "0x%016llX\n", - plugin_name, u64_addr(guidCodeAddress)); - auto guid = getGuidByAddr(guidDataAddress); - if (!checkGuid(guid)) { - msg("[%s] Incorrect GUID at 0x%016llX\n", plugin_name, - u64_addr(guidCodeAddress)); - continue; - } + if (insn.itype == NN_push) { + pushCounter += 1; + if (pushCounter > pushNumber) { + break; + } + if (pushCounter == pushNumber) { + guidCodeAddress = address; + guidDataAddress = insn.ops[0].value; + if (insn.ops[0].value > start && insn.ops[0].value != BADADDR) { + found = true; + break; + } + } + } + } - AddProtocol(bootServicesTable32[i].service_name, guidDataAddress, - guidCodeAddress, ea); - } + if (found) { + msg("[%s] getBsProtNamesX86: found protocol GUID parameter at " + "0x%016llX\n", + g_plugin_name, u64_addr(guidCodeAddress)); + auto guid = getGuidByAddr(guidDataAddress); + if (!checkGuid(guid)) { + msg("[%s] Incorrect GUID at 0x%016llX\n", g_plugin_name, + u64_addr(guidCodeAddress)); + continue; } + + AddProtocol(bootServicesTable32[i].name, guidDataAddress, guidCodeAddress, ea); + } } + } } //-------------------------------------------------------------------------- // Get smm services protocols names for X64 modules -void EfiAnalysis::EfiAnalyzerX86::getSmmProtNamesX64() { - if (!textSegments.size()) { - return; - } - segment_t *s = textSegments.at(0); - ea_t start = s->start_ea; - msg("[%s] protocols finding (smm services, start address = 0x%016llX)\n", plugin_name, - u64_addr(start)); - for (int i = 0; i < smmServicesProt64Length; i++) { - auto addrs = smmServices[smmServicesProt64[i].service_name]; - - // for each SMM service - for (auto ea : addrs) { - ea_t address = ea; - msg("[%s] looking for protocols in the 0x%016llX area\n", plugin_name, - u64_addr(address)); - insn_t insn; - ea_t guidCodeAddress = 0; - ea_t guidDataAddress = 0; - auto found = false; - - // check current basic block - while (true) { - address = prev_head(address, startAddress); - decode_insn(&insn, address); - - // exit from loop if end of previous basic block found - if (is_basic_block_end(insn, false)) { - break; - } - - if (insn.itype == NN_lea && insn.ops[0].type == o_reg && - insn.ops[0].reg == smmServicesProt64[i].reg) { - guidCodeAddress = address; - guidDataAddress = insn.ops[1].addr; - if (insn.ops[1].addr > start && insn.ops[1].addr != BADADDR) { - found = true; - break; - } - } - } +void efi_analysis::EfiAnalyzerX86::getSmmProtNamesX64() { + if (!textSegments.size()) { + return; + } + segment_t *s = textSegments.at(0); + ea_t start = s->start_ea; + msg("[%s] protocols finding (smm services, start address = 0x%016llX)\n", g_plugin_name, + u64_addr(start)); + for (int i = 0; i < smmServicesProt64Count; i++) { + auto addrs = smmServices[smmServicesProt64[i].name]; + + // for each SMM service + for (auto ea : addrs) { + ea_t address = ea; + msg("[%s] looking for protocols in the 0x%016llX area\n", g_plugin_name, + u64_addr(address)); + insn_t insn; + ea_t guidCodeAddress = 0; + ea_t guidDataAddress = 0; + auto found = false; + + // check current basic block + while (true) { + address = prev_head(address, startAddress); + decode_insn(&insn, address); + + // exit from loop if end of previous basic block found + if (is_basic_block_end(insn, false)) { + break; + } - if (found) { - msg("[%s] getSmmProtNamesX64: found protocol GUID parameter at " - "0x%016llX\n", - plugin_name, u64_addr(guidCodeAddress)); - auto guid = getGuidByAddr(guidDataAddress); - if (!checkGuid(guid)) { - msg("[%s] Incorrect GUID at 0x%016llX\n", plugin_name, - u64_addr(guidCodeAddress)); - continue; - } + if (insn.itype == NN_lea && insn.ops[0].type == o_reg && + insn.ops[0].reg == smmServicesProt64[i].reg) { + guidCodeAddress = address; + guidDataAddress = insn.ops[1].addr; + if (insn.ops[1].addr > start && insn.ops[1].addr != BADADDR) { + found = true; + break; + } + } + } - AddProtocol(smmServicesProt64[i].service_name, guidDataAddress, - guidCodeAddress, ea); - } + if (found) { + msg("[%s] getSmmProtNamesX64: found protocol GUID parameter at " + "0x%016llX\n", + g_plugin_name, u64_addr(guidCodeAddress)); + auto guid = getGuidByAddr(guidDataAddress); + if (!checkGuid(guid)) { + msg("[%s] Incorrect GUID at 0x%016llX\n", g_plugin_name, + u64_addr(guidCodeAddress)); + continue; } + + AddProtocol(smmServicesProt64[i].name, guidDataAddress, guidCodeAddress, ea); + } } + } } //-------------------------------------------------------------------------- // Mark protocols -void EfiAnalysis::EfiAnalyzer::markInterfaces() { - msg("[%s] %s marking\n", plugin_name, if_pl.c_str()); - for (auto ifItemIt = if_tbl->begin(); ifItemIt != if_tbl->end(); ++ifItemIt) { - json ifItem = *ifItemIt; - ea_t address = static_cast(ifItem["address"]); - - // check if guid on this address already marked - bool marked = false; - for (auto markedAddress = markedInterfaces.begin(); - markedAddress != markedInterfaces.end(); ++markedAddress) { - if (*markedAddress == address) { - marked = true; - break; - } - } - - if (!marked) { - std::string svcName = static_cast(ifItem[if_key]); - set_name(address, svcName.c_str(), SN_FORCE); - setGuidType(address); - std::string comment = "EFI_GUID " + svcName; - markedInterfaces.push_back(address); - msg("[%s] address: 0x%016llX, comment: %s\n", plugin_name, u64_addr(address), - comment.c_str()); - } - } +void efi_analysis::EfiAnalyzer::markInterfaces() { + msg("[%s] %s marking\n", g_plugin_name, if_pl.c_str()); + for (auto ifItemIt = if_tbl->begin(); ifItemIt != if_tbl->end(); ++ifItemIt) { + json ifItem = *ifItemIt; + ea_t address = static_cast(ifItem["address"]); + + // check if guid on this address already marked + bool marked = false; + for (auto markedAddress = markedInterfaces.begin(); + markedAddress != markedInterfaces.end(); ++markedAddress) { + if (*markedAddress == address) { + marked = true; + break; + } + } + + if (!marked) { + std::string svcName = static_cast(ifItem[if_key]); + set_name(address, svcName.c_str(), SN_FORCE); + setGuidType(address); + std::string comment = "EFI_GUID " + svcName; + markedInterfaces.push_back(address); + msg("[%s] address: 0x%016llX, comment: %s\n", g_plugin_name, u64_addr(address), + comment.c_str()); + } + } } //-------------------------------------------------------------------------- // Mark GUIDs found in the .text and .data segment -void EfiAnalysis::EfiAnalyzer::markDataGuids() { - ea_t ptrSize = inf_is_64bit() ? 8 : 4; - auto guids_segments = textSegments; - // find GUIDs in .text and .data segments - // TODO: scan only the areas between the beginning of the .text segment and the first - // function address (?) - guids_segments.insert(guids_segments.end(), dataSegments.begin(), dataSegments.end()); - for (auto s : guids_segments) { - msg("[%s] marking GUIDs from 0x%016llX to 0x%016llX\n", plugin_name, - u64_addr(s->start_ea), u64_addr(s->end_ea)); - ea_t ea = s->start_ea; - while (ea != BADADDR && ea <= s->end_ea - 15) { - if (get_wide_dword(ea) == 0x00000000 || get_wide_dword(ea) == 0xffffffff) { - ea += 1; - continue; - } - auto guid = getGuidByAddr(ea); - - // find GUID name - auto it = dbProtocolsMap.find(guid); - if (it != dbProtocolsMap.end()) { - std::string guidName = it->second; - set_name(ea, guidName.c_str(), SN_FORCE); - setGuidType(ea); - - // rename PPI - if (guidName.length() > 9 && - guidName.rfind("_PPI_GUID") == guidName.length() - 9) { - auto xrefs = getXrefs(ea); - for (auto addr : xrefs) { - std::string ppiName = - "g" + typeToName(guidName.substr(0, guidName.length() - 5)); - ea_t ppiEa = addr - ptrSize; - // check flags - if (ptrSize == 8 && get_wide_dword(ppiEa + 4)) { - // 4 high bytes must be 0 - continue; - } - uint64_t flags = static_cast(get_wide_dword(ppiEa)); - if (!qwordInVec(ppiFlags, flags)) { - continue; - } - msg("[%s] address: 0x%016llX, PPI: %s\n", plugin_name, - u64_addr(ppiEa), ppiName.c_str()); - set_name(ppiEa, ppiName.c_str(), SN_FORCE); - } - } +void efi_analysis::EfiAnalyzer::markDataGuids() { + ea_t ptrSize = inf_is_64bit() ? 8 : 4; + auto guids_segments = textSegments; + // find GUIDs in .text and .data segments + // TODO: scan only the areas between the beginning of the .text segment and the first + // function address (?) + guids_segments.insert(guids_segments.end(), dataSegments.begin(), dataSegments.end()); + for (auto s : guids_segments) { + msg("[%s] marking GUIDs from 0x%016llX to 0x%016llX\n", g_plugin_name, + u64_addr(s->start_ea), u64_addr(s->end_ea)); + ea_t ea = s->start_ea; + while (ea != BADADDR && ea <= s->end_ea - 15) { + if (get_wide_dword(ea) == 0x00000000 || get_wide_dword(ea) == 0xffffffff) { + ea += 1; + continue; + } + auto guid = getGuidByAddr(ea); + + // find GUID name + auto it = dbProtocolsMap.find(guid); + if (it != dbProtocolsMap.end()) { + std::string guidName = it->second; + set_name(ea, guidName.c_str(), SN_FORCE); + setGuidType(ea); + + // rename PPI + if (guidName.length() > 9 && + guidName.rfind("_PPI_GUID") == guidName.length() - 9) { + auto xrefs = getXrefs(ea); + for (auto addr : xrefs) { + std::string ppiName = + "g" + typeToName(guidName.substr(0, guidName.length() - 5)); + ea_t ppiEa = addr - ptrSize; + // check flags + if (ptrSize == 8 && get_wide_dword(ppiEa + 4)) { + // 4 high bytes must be 0 + continue; + } + uint64_t flags = static_cast(get_wide_dword(ppiEa)); + if (!qwordInVec(ppiFlags, flags)) { + continue; + } + msg("[%s] address: 0x%016llX, PPI: %s\n", g_plugin_name, u64_addr(ppiEa), + ppiName.c_str()); + set_name(ppiEa, ppiName.c_str(), SN_FORCE); + } + } - std::string comment = "EFI_GUID " + guidName; - msg("[%s] address: 0x%016llX, comment: %s\n", plugin_name, u64_addr(ea), - comment.c_str()); + std::string comment = "EFI_GUID " + guidName; + msg("[%s] address: 0x%016llX, comment: %s\n", g_plugin_name, u64_addr(ea), + comment.c_str()); - json guid_item; - guid_item["address"] = ea; - guid_item["name"] = guidName; - guid_item["guid"] = getGuidFromValue(guid); - allGuids.push_back(guid_item); - dataGuids.push_back(guid_item); - } - ea += 1; - } + json guid_item; + guid_item["address"] = ea; + guid_item["name"] = guidName; + guid_item["guid"] = getGuidFromValue(guid); + allGuids.push_back(guid_item); + dataGuids.push_back(guid_item); + } + ea += 1; } + } } //-------------------------------------------------------------------------- // Mark GUIDs found in local variables for X64 modules -void EfiAnalysis::EfiAnalyzerX86::markLocalGuidsX64() { - for (auto seg : textSegments) { - segment_t *s = seg; - ea_t ea = s->start_ea; - insn_t insn; - insn_t insn_next; - msg("[%s] local GUIDs finding from 0x%016llX to 0x%016llX\n", plugin_name, - u64_addr(s->start_ea), u64_addr(s->end_ea)); - while (ea <= s->end_ea) { +void efi_analysis::EfiAnalyzerX86::markLocalGuidsX64() { + for (auto seg : textSegments) { + segment_t *s = seg; + ea_t ea = s->start_ea; + insn_t insn; + insn_t insn_next; + msg("[%s] local GUIDs finding from 0x%016llX to 0x%016llX\n", g_plugin_name, + u64_addr(s->start_ea), u64_addr(s->end_ea)); + while (ea <= s->end_ea) { + ea = next_head(ea, BADADDR); + decode_insn(&insn, ea); + + // check if insn like mov dword ptr [...], data1 + if (!(insn.itype == NN_mov && insn.ops[0].type == o_displ && + insn.ops[1].type == o_imm)) { + continue; + } + + // get guid->Data1 value + uint32_t data1 = u32_addr(insn.ops[1].value); + if (data1 == 0x00000000 || data1 == 0xffffffff) { + ea = next_head(ea, BADADDR); + continue; + } + + // check 4 insns + bool exit = false; + for (auto i = 0; i < 4; i++) { + auto ea_next = next_head(ea, BADADDR); + decode_insn(&insn_next, ea_next); + // check if insn like mov dword ptr [...], data2 + if (insn_next.itype == NN_mov && insn_next.ops[0].type == o_displ && + insn_next.ops[1].type == o_imm) { + + // get guid->Data2 value + uint16_t data2 = static_cast(insn_next.ops[1].value); + if (data2 == 0x0000 || data2 == 0xffff) { ea = next_head(ea, BADADDR); - decode_insn(&insn, ea); - - // check if insn like mov dword ptr [...], data1 - if (!(insn.itype == NN_mov && insn.ops[0].type == o_displ && - insn.ops[1].type == o_imm)) { - continue; - } - - // get guid->Data1 value - uint32_t data1 = u32_addr(insn.ops[1].value); - if (data1 == 0x00000000 || data1 == 0xffffffff) { - ea = next_head(ea, BADADDR); - continue; - } - - // check 4 insns - bool exit = false; - for (auto i = 0; i < 4; i++) { - auto ea_next = next_head(ea, BADADDR); - decode_insn(&insn_next, ea_next); - // check if insn like mov dword ptr [...], data2 - if (insn_next.itype == NN_mov && insn_next.ops[0].type == o_displ && - insn_next.ops[1].type == o_imm) { - - // get guid->Data2 value - uint16_t data2 = static_cast(insn_next.ops[1].value); - if (data2 == 0x0000 || data2 == 0xffff) { - ea = next_head(ea, BADADDR); - continue; - } - - // found guid->Data1 and guid->Data2 values, try to get - // guid name - for (auto dbItem = dbProtocols.begin(); dbItem != dbProtocols.end(); - ++dbItem) { - auto guid = dbItem.value(); - if (data1 == static_cast(guid[0]) && - data2 == static_cast(guid[1])) { - - // mark local GUID - std::string comment = "EFI_GUID " + dbItem.key(); - msg("[%s] address: 0x%016llX, comment: %s\n", plugin_name, - u64_addr(ea), comment.c_str()); - set_cmt(ea, comment.c_str(), true); - - json guid_item; - guid_item["address"] = ea; - guid_item["name"] = dbItem.key(); - guid_item["guid"] = getGuidFromValue(guid); - allGuids.push_back(guid_item); - stackGuids.push_back(guid_item); - exit = true; - break; - } - } - } - if (exit) { - break; - } - } + continue; + } + + // found guid->Data1 and guid->Data2 values, try to get + // guid name + for (auto dbItem = dbProtocols.begin(); dbItem != dbProtocols.end(); ++dbItem) { + auto guid = dbItem.value(); + if (data1 == static_cast(guid[0]) && + data2 == static_cast(guid[1])) { + + // mark local GUID + std::string comment = "EFI_GUID " + dbItem.key(); + msg("[%s] address: 0x%016llX, comment: %s\n", g_plugin_name, u64_addr(ea), + comment.c_str()); + set_cmt(ea, comment.c_str(), true); + + json guid_item; + guid_item["address"] = ea; + guid_item["name"] = dbItem.key(); + guid_item["guid"] = getGuidFromValue(guid); + allGuids.push_back(guid_item); + stackGuids.push_back(guid_item); + exit = true; + break; + } + } + } + if (exit) { + break; } + } } + } } //-------------------------------------------------------------------------- // Search for callouts recursively void findCalloutRec(func_t *func) { - insn_t insn; - for (ea_t ea = func->start_ea; ea < func->end_ea; ea = next_head(ea, BADADDR)) { - decode_insn(&insn, ea); - if (insn.itype == NN_call) { - ea_t nextFuncAddr = insn.ops[0].addr; - func_t *nextFunc = get_func(nextFuncAddr); - if (nextFunc) { - auto it = std::find(excFunctions.begin(), excFunctions.end(), nextFunc); - if (it == excFunctions.end()) { - excFunctions.push_back(nextFunc); - findCalloutRec(nextFunc); - } - } + insn_t insn; + for (ea_t ea = func->start_ea; ea < func->end_ea; ea = next_head(ea, BADADDR)) { + decode_insn(&insn, ea); + if (insn.itype == NN_call) { + ea_t nextFuncAddr = insn.ops[0].addr; + func_t *nextFunc = get_func(nextFuncAddr); + if (nextFunc) { + auto it = std::find(excFunctions.begin(), excFunctions.end(), nextFunc); + if (it == excFunctions.end()) { + excFunctions.push_back(nextFunc); + findCalloutRec(nextFunc); } + } + } - if (insn.itype == NN_mov && insn.ops[0].type == o_reg && - insn.ops[1].type == o_mem) { - // search for callouts with gBS - if (addrInVec(gBsList, insn.ops[1].addr)) { - msg("[%s] SMM callout found: 0x%016llX\n", plugin_name, u64_addr(ea)); - // filter FP - auto reg = insn.ops[0].reg; - auto addr = ea; - insn_t next_insn; - auto fp = false; - while (true) { - addr = next_head(addr, BADADDR); - decode_insn(&next_insn, addr); - if ((next_insn.itype == NN_jmpni || next_insn.itype == NN_callni) && - next_insn.ops[0].type == o_displ && next_insn.ops[0].reg == reg && - next_insn.ops[0].addr == FreePoolOffset64) { - fp = true; - break; - } - if (is_basic_block_end(next_insn, false)) { - break; - } - } - if (!fp) { - msg("[%s] SMM callout found (gBS): 0x%016llX\n", plugin_name, - u64_addr(ea)); - calloutAddrs.push_back(ea); - continue; - } - } - - // search for callouts with gRT - if (addrInVec(gRtList, insn.ops[1].addr)) { - msg("[%s] SMM callout found (gRT): 0x%016llX\n", plugin_name, - u64_addr(ea)); - calloutAddrs.push_back(ea); - continue; - } - - // search for usage of interfaces installed with gBS->LocateProtocol() - auto g_addr = insn.ops[1].addr; - insn_t insn_xref; - bool interface_callout_found = false; - // check all xrefs for found global variable - for (auto xref : getXrefs(g_addr)) { - // chcek if it looks like interface - decode_insn(&insn_xref, xref); - if (insn_xref.itype != NN_lea || insn_xref.ops[0].type != o_reg || - insn_xref.ops[0].reg != REG_R8) { - continue; - } + if (insn.itype == NN_mov && insn.ops[0].type == o_reg && insn.ops[1].type == o_mem) { + // search for callouts with gBS + if (addrInVec(gBsList, insn.ops[1].addr)) { + msg("[%s] SMM callout found: 0x%016llX\n", g_plugin_name, u64_addr(ea)); + // filter FP + auto reg = insn.ops[0].reg; + auto addr = ea; + insn_t next_insn; + auto fp = false; + while (true) { + addr = next_head(addr, BADADDR); + decode_insn(&next_insn, addr); + if ((next_insn.itype == NN_jmpni || next_insn.itype == NN_callni) && + next_insn.ops[0].type == o_displ && next_insn.ops[0].reg == reg && + next_insn.ops[0].addr == FreePoolOffset64) { + fp = true; + break; + } + if (is_basic_block_end(next_insn, false)) { + break; + } + } + if (!fp) { + msg("[%s] SMM callout found (gBS): 0x%016llX\n", g_plugin_name, u64_addr(ea)); + calloutAddrs.push_back(ea); + continue; + } + } + + // search for callouts with gRT + if (addrInVec(gRtList, insn.ops[1].addr)) { + msg("[%s] SMM callout found (gRT): 0x%016llX\n", g_plugin_name, u64_addr(ea)); + calloutAddrs.push_back(ea); + continue; + } + + // search for usage of interfaces installed with gBS->LocateProtocol() + auto g_addr = insn.ops[1].addr; + insn_t insn_xref; + bool interface_callout_found = false; + // check all xrefs for found global variable + for (auto xref : getXrefs(g_addr)) { + // chcek if it looks like interface + decode_insn(&insn_xref, xref); + if (insn_xref.itype != NN_lea || insn_xref.ops[0].type != o_reg || + insn_xref.ops[0].reg != REG_R8) { + continue; + } - // check rest of basic block to find gBS->LocateProtocol() - insn_t next_insn; - auto current_addr = xref; - while (true) { - current_addr = next_head(current_addr, BADADDR); - decode_insn(&next_insn, current_addr); - - if (next_insn.itype == NN_callni && - next_insn.ops[0].type == o_displ && - next_insn.ops[0].reg == REG_RAX) { - if (next_insn.ops[0].addr == LocateProtocolOffset64 || - next_insn.ops[0].addr == AllocatePoolOffset64) { - // found callout - msg("[%s] SMM callout found (usage of memory controlled by " - "the attacker inside SMI handler): 0x%016llX\n", - plugin_name, u64_addr(ea)); - calloutAddrs.push_back(ea); - interface_callout_found = true; - } // else: FP - break; - } - - if (is_basic_block_end(next_insn, false)) { - break; - } - } - if (interface_callout_found) { - break; - } - } + // check rest of basic block to find gBS->LocateProtocol() + insn_t next_insn; + auto current_addr = xref; + while (true) { + current_addr = next_head(current_addr, BADADDR); + decode_insn(&next_insn, current_addr); + + if (next_insn.itype == NN_callni && next_insn.ops[0].type == o_displ && + next_insn.ops[0].reg == REG_RAX) { + if (next_insn.ops[0].addr == LocateProtocolOffset64 || + next_insn.ops[0].addr == AllocatePoolOffset64) { + // found callout + msg("[%s] SMM callout found (usage of memory controlled by " + "the attacker inside SMI handler): 0x%016llX\n", + g_plugin_name, u64_addr(ea)); + calloutAddrs.push_back(ea); + interface_callout_found = true; + } // else: FP + break; + } + + if (is_basic_block_end(next_insn, false)) { + break; + } + } + if (interface_callout_found) { + break; } + } } + } } //-------------------------------------------------------------------------- // Find SmiHandler function inside SMM drivers -void EfiAnalysis::EfiAnalyzer::findSwSmiHandlers() { - std::map types = { - {&sw_guid2, "Sw"}, - {&sw_guid, "Sw"}, - {&sx_guid2, "Sx"}, - {&sx_guid, "Sx"}, - {&io_trap_guid2, "IoTrap"}, - {&io_trap_guid, "IoTrap"}, - {&gpi_guid2, "Gpi"}, - {&gpi_guid, "Gpi"}, - {&usb_guid2, "Usb"}, - {&usb_guid, "Usb"}, - {&standby_button_guid2, "StandbyButton"}, - {&standby_button_guid, "StandbyButton"}, - {&periodic_timer_guid2, "PeriodicTimer"}, - {&periodic_timer_guid, "PeriodicTimer"}, - {&power_button_guid2, "PowerButton"}, - {&power_button_guid, "PowerButton"}, - {&ichn_guid, "Ichn"}, - {&ichn_guid2, "Ichn"}, - {&tco_guid, "Tco"}, - {&pcie_guid, "Pcie"}, - {&acpi_guid, "Acpi"}, - {&gpio_unlock_guid, "GpioUnlock"}, - {&pch_guid, "Pch"}, - {&espi_guid, "Espi"}, - {&acpi_en_guid, "AcpiEn"}, - {&acpi_dis_guid, "AcpiDis"}, - {&fch_gpi_guid2, "Gpi"}, - {&fch_io_trap_guid2, "IoTrap"}, - {&fch_periodical_guid2, "PeriodicTimer"}, - {&fch_pwr_btn_guid2, "PowerButton"}, - {&fch_sw_guid2, "Sw"}, - {&fch_sx_guid2, "Sx"}, - {&fch_usb_guid2, "Usb"}, - {&fch_usb_guid, "Usb"}, - {&fch_misc_guid, "Misc"}, - {&fch_apu_ras_guid, "ApuRas"}, - }; - for (auto &[guid, prefix] : types) { - auto res = findSmiHandlersSmmDispatch(*guid, prefix); - smiHandlers.insert(smiHandlers.end(), res.begin(), res.end()); - } +void efi_analysis::EfiAnalyzer::findSwSmiHandlers() { + std::map types = { + {&sw_guid2, "Sw"}, + {&sw_guid, "Sw"}, + {&sx_guid2, "Sx"}, + {&sx_guid, "Sx"}, + {&io_trap_guid2, "IoTrap"}, + {&io_trap_guid, "IoTrap"}, + {&gpi_guid2, "Gpi"}, + {&gpi_guid, "Gpi"}, + {&usb_guid2, "Usb"}, + {&usb_guid, "Usb"}, + {&standby_button_guid2, "StandbyButton"}, + {&standby_button_guid, "StandbyButton"}, + {&periodic_timer_guid2, "PeriodicTimer"}, + {&periodic_timer_guid, "PeriodicTimer"}, + {&power_button_guid2, "PowerButton"}, + {&power_button_guid, "PowerButton"}, + {&ichn_guid, "Ichn"}, + {&ichn_guid2, "Ichn"}, + {&tco_guid, "Tco"}, + {&pcie_guid, "Pcie"}, + {&acpi_guid, "Acpi"}, + {&gpio_unlock_guid, "GpioUnlock"}, + {&pch_guid, "Pch"}, + {&espi_guid, "Espi"}, + {&acpi_en_guid, "AcpiEn"}, + {&acpi_dis_guid, "AcpiDis"}, + {&fch_gpi_guid2, "Gpi"}, + {&fch_io_trap_guid2, "IoTrap"}, + {&fch_periodical_guid2, "PeriodicTimer"}, + {&fch_pwr_btn_guid2, "PowerButton"}, + {&fch_sw_guid2, "Sw"}, + {&fch_sx_guid2, "Sx"}, + {&fch_usb_guid2, "Usb"}, + {&fch_usb_guid, "Usb"}, + {&fch_misc_guid, "Misc"}, + {&fch_apu_ras_guid, "ApuRas"}, + }; + for (auto &[guid, prefix] : types) { + auto res = findSmiHandlersSmmDispatch(*guid, prefix); + smiHandlers.insert(smiHandlers.end(), res.begin(), res.end()); + } } //-------------------------------------------------------------------------- // Find callouts inside SwSmiHandler function: // * find SwSmiHandler function // * find gBS->service_name and gRT->service_name inside SmiHandler function -bool EfiAnalysis::EfiAnalyzer::findSmmCallout() { - msg("[%s] Looking for SMM callout\n", plugin_name); - if (!gBsList.size() && !gRtList.size()) { - return false; - } - if (!smiHandlers.size() && !childSmiHandlers.size()) { - msg("[%s] can't find a SwSmiHandler functions\n", plugin_name); - return false; - } - for (auto func : smiHandlers) { - findCalloutRec(func); - } - for (auto func : childSmiHandlers) { - findCalloutRec(func); - } - return true; +bool efi_analysis::EfiAnalyzer::findSmmCallout() { + msg("[%s] Looking for SMM callout\n", g_plugin_name); + if (!gBsList.size() && !gRtList.size()) { + return false; + } + if (!smiHandlers.size() && !childSmiHandlers.size()) { + msg("[%s] can't find a SwSmiHandler functions\n", g_plugin_name); + return false; + } + for (auto func : smiHandlers) { + findCalloutRec(func); + } + for (auto func : childSmiHandlers) { + findCalloutRec(func); + } + return true; } -bool EfiAnalysis::EfiAnalyzer::findPPIGetVariableStackOveflow() { - msg("[%s] Looking for PPI GetVariable buffer overflow, " - "allServices.size() = %lu\n", - plugin_name, allServices.size()); - std::vector getVariableServicesCalls; - std::string getVariableStr("VariablePPI.GetVariable"); - for (auto j_service : allServices) { - json service = j_service; - std::string service_name = static_cast(service["service_name"]); - std::string table_name = static_cast(service["table_name"]); - ea_t addr = static_cast(service["address"]); - if (service_name.compare(getVariableStr) == 0) { - getVariableServicesCalls.push_back(addr); +bool efi_analysis::EfiAnalyzer::findPPIGetVariableStackOveflow() { + msg("[%s] Looking for PPI GetVariable buffer overflow, " + "allServices.size() = %lu\n", + g_plugin_name, allServices.size()); + std::vector getVariableServicesCalls; + std::string getVariableStr("VariablePPI.GetVariable"); + for (auto j_service : allServices) { + json service = j_service; + std::string service_name = static_cast(service["service_name"]); + std::string table_name = static_cast(service["table_name"]); + ea_t addr = static_cast(service["address"]); + if (service_name.compare(getVariableStr) == 0) { + getVariableServicesCalls.push_back(addr); + } + } + msg("[%s] Finished iterating over allServices, " + "getVariableServicesCalls.size() = " + "%lu\n", + g_plugin_name, getVariableServicesCalls.size()); + sort(getVariableServicesCalls.begin(), getVariableServicesCalls.end()); + if (getVariableServicesCalls.size() < 2) { + msg("[%s] less than 2 VariablePPI.GetVariable calls found\n", g_plugin_name); + return false; + } + ea_t prev_addr = getVariableServicesCalls.at(0); + for (auto i = 1; i < getVariableServicesCalls.size(); ++i) { + ea_t curr_addr = getVariableServicesCalls.at(i); + msg("[%s] VariablePPI.GetVariable_1: 0x%016llX, " + "VariablePPI.GetVariable_2: " + "0x%016llX\n", + g_plugin_name, u64_addr(prev_addr), u64_addr(curr_addr)); + + // check code from GetVariable_1 to GetVariable_2 + ea_t ea = next_head(prev_addr, BADADDR); + bool ok = true; + insn_t insn; + while (ea < curr_addr) { + decode_insn(&insn, ea); + if (insn.itype == NN_callni || insn.itype == NN_call || insn.itype == NN_retn || + insn.itype == NN_jmp || insn.itype == NN_jmpni) { + ok = false; + break; + } + ea = next_head(ea, BADADDR); + } + if (ok) { + bool same_datasize = false; + uint16_t pushNumber = 5; + uint16_t pushCounter = 0; + uint16_t arg5_reg = 0xffff; + ea_t curr_datasize_addr = 0xffff; + bool datasize_addr_found = false; + ea_t address = curr_addr; + for (auto j = 0; j < 15; j++) { + address = prev_head(address, startAddress); + decode_insn(&insn, address); + if (insn.itype == NN_push) { + pushCounter += 1; + if (pushCounter == pushNumber) { + if (insn.ops[0].type == o_reg) { + arg5_reg = insn.ops[0].reg; + } else { + // if it's not push , just let the pattern + // trigger - for manual review + same_datasize = true; + } + break; + } } - } - msg("[%s] Finished iterating over allServices, " - "getVariableServicesCalls.size() = " - "%lu\n", - plugin_name, getVariableServicesCalls.size()); - sort(getVariableServicesCalls.begin(), getVariableServicesCalls.end()); - if (getVariableServicesCalls.size() < 2) { - msg("[%s] less than 2 VariablePPI.GetVariable calls found\n", plugin_name); - return false; - } - ea_t prev_addr = getVariableServicesCalls.at(0); - for (auto i = 1; i < getVariableServicesCalls.size(); ++i) { - ea_t curr_addr = getVariableServicesCalls.at(i); - msg("[%s] VariablePPI.GetVariable_1: 0x%016llX, " - "VariablePPI.GetVariable_2: " - "0x%016llX\n", - plugin_name, u64_addr(prev_addr), u64_addr(curr_addr)); - - // check code from GetVariable_1 to GetVariable_2 - ea_t ea = next_head(prev_addr, BADADDR); - bool ok = true; - insn_t insn; - while (ea < curr_addr) { - decode_insn(&insn, ea); - if (insn.itype == NN_callni || insn.itype == NN_call || - insn.itype == NN_retn || insn.itype == NN_jmp || insn.itype == NN_jmpni) { - ok = false; - break; - } - ea = next_head(ea, BADADDR); + } + + if (same_datasize) { + peiGetVariableOverflow.push_back(curr_addr); + msg("[%s] overflow can occur here: 0x%016llX\n", g_plugin_name, + u64_addr(curr_addr)); + continue; + } + + for (auto j = 0; j < 15; j++) { + address = prev_head(address, startAddress); + decode_insn(&insn, address); + if (insn.itype == NN_lea && insn.ops[0].type == o_reg && + insn.ops[0].reg == arg5_reg && insn.ops[1].type == o_displ) { + curr_datasize_addr = insn.ops[1].addr; + datasize_addr_found = true; + break; } - if (ok) { - bool same_datasize = false; - uint16_t pushNumber = 5; - uint16_t pushCounter = 0; - uint16_t arg5_reg = 0xffff; - ea_t curr_datasize_addr = 0xffff; - bool datasize_addr_found = false; - ea_t address = curr_addr; - for (auto j = 0; j < 15; j++) { - address = prev_head(address, startAddress); - decode_insn(&insn, address); - if (insn.itype == NN_push) { - pushCounter += 1; - if (pushCounter == pushNumber) { - if (insn.ops[0].type == o_reg) { - arg5_reg = insn.ops[0].reg; - } else { - // if it's not push , just let the pattern - // trigger - for manual review - same_datasize = true; - } - break; - } - } - } - - if (same_datasize) { - peiGetVariableOverflow.push_back(curr_addr); - msg("[%s] overflow can occur here: 0x%016llX\n", plugin_name, - u64_addr(curr_addr)); - continue; - } - - for (auto j = 0; j < 15; j++) { - address = prev_head(address, startAddress); - decode_insn(&insn, address); - if (insn.itype == NN_lea && insn.ops[0].type == o_reg && - insn.ops[0].reg == arg5_reg && insn.ops[1].type == o_displ) { - curr_datasize_addr = insn.ops[1].addr; - datasize_addr_found = true; - break; - } - } - - msg("[%s] curr_datasize_addr = 0x%016llX, datasize_addr_found = " - "%d\n", - plugin_name, u64_addr(curr_datasize_addr), datasize_addr_found); - - if (!datasize_addr_found) { - // if datasize wasn't found, just let the pattern - // trigger - for manual review - peiGetVariableOverflow.push_back(curr_addr); - msg("[%s] overflow can occur here: 0x%016llX\n", plugin_name, - u64_addr(curr_addr)); - continue; - } - - pushCounter = 0; - arg5_reg = 0xffff; - ea_t prev_datasize_addr = 0xffff; - datasize_addr_found = false; - address = prev_addr; - for (auto j = 0; j < 15; j++) { - address = prev_head(address, startAddress); - decode_insn(&insn, address); - if (insn.itype == NN_push) { - pushCounter += 1; - if (pushCounter == pushNumber) { - if (insn.ops[0].type == o_reg) { - arg5_reg = insn.ops[0].reg; - } else { - // if it's not push , just let the pattern - // trigger - for manual review - same_datasize = true; - } - break; - } - } - } - - if (same_datasize) { - peiGetVariableOverflow.push_back(curr_addr); - msg("[%s] overflow can occur here: 0x%016llX\n", plugin_name, - u64_addr(curr_addr)); - continue; - } - - for (auto j = 0; j < 15; j++) { - address = prev_head(address, startAddress); - decode_insn(&insn, address); - if (insn.itype == NN_lea && insn.ops[0].type == o_reg && - insn.ops[0].reg == arg5_reg && insn.ops[1].type == o_displ) { - prev_datasize_addr = insn.ops[1].addr; - datasize_addr_found = true; - break; - } - } - - msg("[%s] prev_datasize_addr = 0x%016llX, datasize_addr_found = " - "%d, " - "(prev_datasize_addr == curr_datasize_addr) = %d\n", - plugin_name, u64_addr(prev_datasize_addr), datasize_addr_found, - (prev_datasize_addr == curr_datasize_addr)); - - if (!datasize_addr_found) { - peiGetVariableOverflow.push_back(curr_addr); - msg("[%s] overflow can occur here: 0x%016llX\n", plugin_name, - u64_addr(curr_addr)); - } else if (prev_datasize_addr == curr_datasize_addr) { - peiGetVariableOverflow.push_back(curr_addr); - msg("[%s] overflow can occur here: 0x%016llX " - "(prev_datasize_addr == " - "curr_datasize_addr)\n", - plugin_name, u64_addr(curr_addr)); - } + } + + msg("[%s] curr_datasize_addr = 0x%016llX, datasize_addr_found = " + "%d\n", + g_plugin_name, u64_addr(curr_datasize_addr), datasize_addr_found); + + if (!datasize_addr_found) { + // if datasize wasn't found, just let the pattern + // trigger - for manual review + peiGetVariableOverflow.push_back(curr_addr); + msg("[%s] overflow can occur here: 0x%016llX\n", g_plugin_name, + u64_addr(curr_addr)); + continue; + } + + pushCounter = 0; + arg5_reg = 0xffff; + ea_t prev_datasize_addr = 0xffff; + datasize_addr_found = false; + address = prev_addr; + for (auto j = 0; j < 15; j++) { + address = prev_head(address, startAddress); + decode_insn(&insn, address); + if (insn.itype == NN_push) { + pushCounter += 1; + if (pushCounter == pushNumber) { + if (insn.ops[0].type == o_reg) { + arg5_reg = insn.ops[0].reg; + } else { + // if it's not push , just let the pattern + // trigger - for manual review + same_datasize = true; + } + break; + } } - prev_addr = curr_addr; - } - return (peiGetVariableOverflow.size() > 0); + } + + if (same_datasize) { + peiGetVariableOverflow.push_back(curr_addr); + msg("[%s] overflow can occur here: 0x%016llX\n", g_plugin_name, + u64_addr(curr_addr)); + continue; + } + + for (auto j = 0; j < 15; j++) { + address = prev_head(address, startAddress); + decode_insn(&insn, address); + if (insn.itype == NN_lea && insn.ops[0].type == o_reg && + insn.ops[0].reg == arg5_reg && insn.ops[1].type == o_displ) { + prev_datasize_addr = insn.ops[1].addr; + datasize_addr_found = true; + break; + } + } + + msg("[%s] prev_datasize_addr = 0x%016llX, datasize_addr_found = " + "%d, " + "(prev_datasize_addr == curr_datasize_addr) = %d\n", + g_plugin_name, u64_addr(prev_datasize_addr), datasize_addr_found, + (prev_datasize_addr == curr_datasize_addr)); + + if (!datasize_addr_found) { + peiGetVariableOverflow.push_back(curr_addr); + msg("[%s] overflow can occur here: 0x%016llX\n", g_plugin_name, + u64_addr(curr_addr)); + } else if (prev_datasize_addr == curr_datasize_addr) { + peiGetVariableOverflow.push_back(curr_addr); + msg("[%s] overflow can occur here: 0x%016llX " + "(prev_datasize_addr == " + "curr_datasize_addr)\n", + g_plugin_name, u64_addr(curr_addr)); + } + } + prev_addr = curr_addr; + } + return (peiGetVariableOverflow.size() > 0); } //-------------------------------------------------------------------------- // Find potential stack/heap overflow with double GetVariable calls -bool EfiAnalysis::EfiAnalyzer::findGetVariableOveflow(std::vector allServices) { - msg("[%s] Looking for GetVariable stack/heap overflow\n", plugin_name); - std::vector getVariableServicesCalls; - std::string getVariableStr("GetVariable"); - for (auto j_service : allServices) { - json service = j_service; - std::string service_name = static_cast(service["service_name"]); - ea_t addr = static_cast(service["address"]); - if (service_name.compare(getVariableStr) == 0) { - getVariableServicesCalls.push_back(addr); +bool efi_analysis::EfiAnalyzer::findGetVariableOveflow(std::vector allServices) { + msg("[%s] Looking for GetVariable stack/heap overflow\n", g_plugin_name); + std::vector getVariableServicesCalls; + std::string getVariableStr("GetVariable"); + for (auto j_service : allServices) { + json service = j_service; + std::string service_name = static_cast(service["service_name"]); + ea_t addr = static_cast(service["address"]); + if (service_name.compare(getVariableStr) == 0) { + getVariableServicesCalls.push_back(addr); + } + } + sort(getVariableServicesCalls.begin(), getVariableServicesCalls.end()); + if (getVariableServicesCalls.size() < 2) { + msg("[%s] less than 2 GetVariable calls found\n", g_plugin_name); + return false; + } + ea_t prev_addr = getVariableServicesCalls.at(0); + ea_t ea; + insn_t insn; + for (auto i = 1; i < getVariableServicesCalls.size(); ++i) { + ea_t curr_addr = getVariableServicesCalls.at(i); + msg("[%s] GetVariable_1: 0x%016llX, GetVariable_2: 0x%016llX\n", g_plugin_name, + u64_addr(prev_addr), u64_addr(curr_addr)); + + // get dataSizeStackAddr + int dataSizeStackAddr = 0; + uint16 dataSizeOpReg = 0xFF; + ea = prev_head(curr_addr, 0); + for (auto i = 0; i < 10; ++i) { + decode_insn(&insn, ea); + if (insn.itype == NN_lea && insn.ops[0].type == o_reg && + insn.ops[0].reg == REG_R9) { + dataSizeStackAddr = insn.ops[1].addr; + dataSizeOpReg = insn.ops[1].phrase; + break; + } + ea = prev_head(ea, 0); + } + + // check code from GetVariable_1 to GetVariable_2 + ea = next_head(prev_addr, BADADDR); + bool ok = true; + size_t dataSizeUseCounter = 0; + while (ea < curr_addr) { + decode_insn(&insn, ea); + if (((dataSizeStackAddr == insn.ops[0].addr) && + (dataSizeOpReg == insn.ops[0].phrase)) || + ((dataSizeStackAddr == insn.ops[1].addr) && + (dataSizeOpReg == insn.ops[1].phrase))) { + dataSizeUseCounter++; + } + if ((insn.itype == NN_callni && insn.ops[0].addr == 0x48) || + insn.itype == NN_retn || insn.itype == NN_jmp || insn.itype == NN_jmpni || + dataSizeUseCounter > 1) { + ok = false; + break; + } + ea = next_head(ea, BADADDR); + } + if (ok) { + + // check for wrong GetVariable detection + bool wrong_detection = false; + ea = prev_head(curr_addr, 0); + for (auto i = 0; i < 8; ++i) { + decode_insn(&insn, ea); + if (insn.itype == NN_mov && insn.ops[0].type == o_reg && + insn.ops[1].type == o_mem) { + ea_t mem_addr = insn.ops[1].addr; + if (addrInVec(gBsList, mem_addr)) { + wrong_detection = true; + break; + } } - } - sort(getVariableServicesCalls.begin(), getVariableServicesCalls.end()); - if (getVariableServicesCalls.size() < 2) { - msg("[%s] less than 2 GetVariable calls found\n", plugin_name); - return false; - } - ea_t prev_addr = getVariableServicesCalls.at(0); - ea_t ea; - insn_t insn; - for (auto i = 1; i < getVariableServicesCalls.size(); ++i) { - ea_t curr_addr = getVariableServicesCalls.at(i); - msg("[%s] GetVariable_1: 0x%016llX, GetVariable_2: 0x%016llX\n", plugin_name, - u64_addr(prev_addr), u64_addr(curr_addr)); - - // get dataSizeStackAddr - int dataSizeStackAddr = 0; - uint16 dataSizeOpReg = 0xFF; - ea = prev_head(curr_addr, 0); - for (auto i = 0; i < 10; ++i) { - decode_insn(&insn, ea); - if (insn.itype == NN_lea && insn.ops[0].type == o_reg && - insn.ops[0].reg == REG_R9) { - dataSizeStackAddr = insn.ops[1].addr; - dataSizeOpReg = insn.ops[1].phrase; - break; - } - ea = prev_head(ea, 0); + ea = prev_head(ea, 0); + } + + // check DataSize initialization + bool init_ok = false; + decode_insn(&insn, prev_head(curr_addr, 0)); + if (!wrong_detection && + !(insn.itype == NN_mov && insn.ops[0].type == o_displ && + (insn.ops[0].phrase == REG_RSP || insn.ops[0].phrase == REG_RBP) && + (insn.ops[0].addr == dataSizeStackAddr))) { + init_ok = true; + } + + // check that the DataSize argument variable is the same for two + // calls + if (init_ok) { + ea = prev_head(prev_addr, 0); + // for (auto i = 0; i < 10; ++i) { + func_t *func_start = get_func(ea); + if (func_start == nullptr) { + return (getVariableOverflow.size() > 0); } - - // check code from GetVariable_1 to GetVariable_2 - ea = next_head(prev_addr, BADADDR); - bool ok = true; - size_t dataSizeUseCounter = 0; - while (ea < curr_addr) { - decode_insn(&insn, ea); - if (((dataSizeStackAddr == insn.ops[0].addr) && - (dataSizeOpReg == insn.ops[0].phrase)) || - ((dataSizeStackAddr == insn.ops[1].addr) && - (dataSizeOpReg == insn.ops[1].phrase))) { - dataSizeUseCounter++; - } - if ((insn.itype == NN_callni && insn.ops[0].addr == 0x48) || - insn.itype == NN_retn || insn.itype == NN_jmp || insn.itype == NN_jmpni || - dataSizeUseCounter > 1) { - ok = false; - break; - } - ea = next_head(ea, BADADDR); + uint16 stack_base_reg = 0xFF; + decode_insn(&insn, func_start->start_ea); + if (insn.itype == NN_mov && insn.ops[1].is_reg(REG_RSP) && + insn.ops[0].type == o_reg) { + stack_base_reg = insn.ops[0].reg; } - if (ok) { - - // check for wrong GetVariable detection - bool wrong_detection = false; - ea = prev_head(curr_addr, 0); - for (auto i = 0; i < 8; ++i) { - decode_insn(&insn, ea); - if (insn.itype == NN_mov && insn.ops[0].type == o_reg && - insn.ops[1].type == o_mem) { - ea_t mem_addr = insn.ops[1].addr; - if (addrInVec(gBsList, mem_addr)) { - wrong_detection = true; - break; - } - } - ea = prev_head(ea, 0); - } - - // check DataSize initialization - bool init_ok = false; - decode_insn(&insn, prev_head(curr_addr, 0)); - if (!wrong_detection && - !(insn.itype == NN_mov && insn.ops[0].type == o_displ && - (insn.ops[0].phrase == REG_RSP || insn.ops[0].phrase == REG_RBP) && - (insn.ops[0].addr == dataSizeStackAddr))) { - init_ok = true; - } - - // check that the DataSize argument variable is the same for two - // calls - if (init_ok) { - ea = prev_head(prev_addr, 0); - // for (auto i = 0; i < 10; ++i) { - func_t *func_start = get_func(ea); - if (func_start == nullptr) { - return (getVariableOverflow.size() > 0); - } - uint16 stack_base_reg = 0xFF; - decode_insn(&insn, func_start->start_ea); - if (insn.itype == NN_mov && insn.ops[1].is_reg(REG_RSP) && - insn.ops[0].type == o_reg) { - stack_base_reg = insn.ops[0].reg; - } - while (ea >= func_start->start_ea) { - decode_insn(&insn, ea); - if (insn.itype == NN_call) - break; - if (insn.itype == NN_lea && insn.ops[0].type == o_reg && - insn.ops[0].reg == REG_R9) { - - ea_t stack_addr = insn.ops[1].addr; - sval_t sval = get_spd(func_start, ea) * -1; - - if ((insn.ops[1].phrase == stack_base_reg && - (sval + stack_addr) == dataSizeStackAddr) || - (dataSizeStackAddr == insn.ops[1].addr)) { - getVariableOverflow.push_back(curr_addr); - msg("[%s] \toverflow can occur here: 0x%016llX\n", - plugin_name, u64_addr(curr_addr)); - break; - } - } - ea = prev_head(ea, 0); - } - } + while (ea >= func_start->start_ea) { + decode_insn(&insn, ea); + if (insn.itype == NN_call) + break; + if (insn.itype == NN_lea && insn.ops[0].type == o_reg && + insn.ops[0].reg == REG_R9) { + + ea_t stack_addr = insn.ops[1].addr; + sval_t sval = get_spd(func_start, ea) * -1; + + if ((insn.ops[1].phrase == stack_base_reg && + (sval + stack_addr) == dataSizeStackAddr) || + (dataSizeStackAddr == insn.ops[1].addr)) { + getVariableOverflow.push_back(curr_addr); + msg("[%s] \toverflow can occur here: 0x%016llX\n", g_plugin_name, + u64_addr(curr_addr)); + break; + } + } + ea = prev_head(ea, 0); } - prev_addr = curr_addr; + } } - return (getVariableOverflow.size() > 0); + prev_addr = curr_addr; + } + return (getVariableOverflow.size() > 0); } //-------------------------------------------------------------------------- // Find potential stack/heap overflow with double SmmGetVariable calls -bool EfiAnalysis::EfiAnalyzer::findSmmGetVariableOveflow() { - msg("[%s] Looking for SmmGetVariable stack/heap overflow\n", plugin_name); - std::vector smmGetVariableCalls = - findSmmGetVariableCalls(dataSegments, &allServices); - sort(smmGetVariableCalls.begin(), smmGetVariableCalls.end()); - if (smmGetVariableCalls.size() < 2) { - msg("[%s] less than 2 GetVariable calls found\n", plugin_name); - return false; - } - ea_t prev_addr = smmGetVariableCalls.at(0); - ea_t ea; - insn_t insn; - for (auto i = 1; i < smmGetVariableCalls.size(); ++i) { - ea_t curr_addr = smmGetVariableCalls.at(i); - msg("[%s] SmmGetVariable_1: 0x%016llX, SmmGetVariable_2: 0x%016llX\n", - plugin_name, u64_addr(prev_addr), u64_addr(curr_addr)); - - // get dataSizeStackAddr - uint32_t dataSizeStackAddr = 0xffffffff; - ea = prev_head(curr_addr, 0); +bool efi_analysis::EfiAnalyzer::findSmmGetVariableOveflow() { + msg("[%s] Looking for SmmGetVariable stack/heap overflow\n", g_plugin_name); + std::vector smmGetVariableCalls = + findSmmGetVariableCalls(dataSegments, &allServices); + sort(smmGetVariableCalls.begin(), smmGetVariableCalls.end()); + if (smmGetVariableCalls.size() < 2) { + msg("[%s] less than 2 GetVariable calls found\n", g_plugin_name); + return false; + } + ea_t prev_addr = smmGetVariableCalls.at(0); + ea_t ea; + insn_t insn; + for (auto i = 1; i < smmGetVariableCalls.size(); ++i) { + ea_t curr_addr = smmGetVariableCalls.at(i); + msg("[%s] SmmGetVariable_1: 0x%016llX, SmmGetVariable_2: 0x%016llX\n", g_plugin_name, + u64_addr(prev_addr), u64_addr(curr_addr)); + + // get dataSizeStackAddr + uint32_t dataSizeStackAddr = 0xffffffff; + ea = prev_head(curr_addr, 0); + for (auto i = 0; i < 10; ++i) { + decode_insn(&insn, ea); + if (insn.itype == NN_lea && insn.ops[0].type == o_reg && + insn.ops[0].reg == REG_R9) { + dataSizeStackAddr = insn.ops[1].addr; + break; + } + ea = prev_head(ea, 0); + } + + // check code from SmmGetVariable_1 to SmmGetVariable_2 + ea = next_head(prev_addr, BADADDR); + bool ok = true; + size_t dataSizeUseCounter = 0; + while (ea < curr_addr) { + decode_insn(&insn, ea); + if (insn.itype == NN_callni || insn.itype == NN_retn || insn.itype == NN_jmpni || + insn.itype == NN_jmp) { + ok = false; + break; + } + ea = next_head(ea, BADADDR); + } + + if (ok) { + + // check DataSize initialization + bool init_ok = false; + decode_insn(&insn, prev_head(curr_addr, 0)); + if (!(insn.itype == NN_mov && insn.ops[0].type == o_displ && + (insn.ops[0].phrase == REG_RSP || insn.ops[0].phrase == REG_RBP))) { + init_ok = true; + } + + // check that the DataSize argument variable is the same for two + // calls + if (init_ok) { + ea = prev_head(prev_addr, 0); for (auto i = 0; i < 10; ++i) { - decode_insn(&insn, ea); - if (insn.itype == NN_lea && insn.ops[0].type == o_reg && - insn.ops[0].reg == REG_R9) { - dataSizeStackAddr = insn.ops[1].addr; - break; - } - ea = prev_head(ea, 0); - } - - // check code from SmmGetVariable_1 to SmmGetVariable_2 - ea = next_head(prev_addr, BADADDR); - bool ok = true; - size_t dataSizeUseCounter = 0; - while (ea < curr_addr) { - decode_insn(&insn, ea); - if (insn.itype == NN_callni || insn.itype == NN_retn || - insn.itype == NN_jmpni || insn.itype == NN_jmp) { - ok = false; - break; - } - ea = next_head(ea, BADADDR); + decode_insn(&insn, ea); + if (insn.itype == NN_lea && insn.ops[0].type == o_reg && + insn.ops[0].reg == REG_R9) { + if (dataSizeStackAddr == insn.ops[1].addr) { + smmGetVariableOverflow.push_back(curr_addr); + msg("[%s] \toverflow can occur here: 0x%016llX\n", g_plugin_name, + u64_addr(curr_addr)); + break; + } + msg("[%s] \tDataSize argument variable is not the " + "same: 0x%016llX\n", + g_plugin_name, u64_addr(curr_addr)); + } + ea = prev_head(ea, 0); } - - if (ok) { - - // check DataSize initialization - bool init_ok = false; - decode_insn(&insn, prev_head(curr_addr, 0)); - if (!(insn.itype == NN_mov && insn.ops[0].type == o_displ && - (insn.ops[0].phrase == REG_RSP || insn.ops[0].phrase == REG_RBP))) { - init_ok = true; - } - - // check that the DataSize argument variable is the same for two - // calls - if (init_ok) { - ea = prev_head(prev_addr, 0); - for (auto i = 0; i < 10; ++i) { - decode_insn(&insn, ea); - if (insn.itype == NN_lea && insn.ops[0].type == o_reg && - insn.ops[0].reg == REG_R9) { - if (dataSizeStackAddr == insn.ops[1].addr) { - smmGetVariableOverflow.push_back(curr_addr); - msg("[%s] \toverflow can occur here: 0x%016llX\n", - plugin_name, u64_addr(curr_addr)); - break; - } - msg("[%s] \tDataSize argument variable is not the " - "same: 0x%016llX\n", - plugin_name, u64_addr(curr_addr)); - } - ea = prev_head(ea, 0); - } - } - } - prev_addr = curr_addr; + } } - return (smmGetVariableOverflow.size() > 0); + prev_addr = curr_addr; + } + return (smmGetVariableOverflow.size() > 0); } -bool EfiAnalysis::EfiAnalyzer::AnalyzeVariableService(ea_t ea, std::string service_str) { - msg("[%s] %s call: 0x%016llX\n", plugin_name, service_str.c_str(), u64_addr(ea)); - json item; - item["addr"] = ea; - insn_t insn; - bool name_found = false; - bool guid_found = false; - func_t *f = get_func(ea); - if (f == nullptr) { - return false; - } - eavec_t args; - get_arg_addrs(&args, ea); - if (args.size() < 3) { - return false; - } - - auto addr = args[0]; // Get VariableName - decode_insn(&insn, addr); - if (insn.itype == NN_lea && insn.ops[0].type == o_reg && insn.ops[0].reg == REG_RCX && - insn.ops[1].type == o_mem) { - msg("[%s] VariableName address: 0x%016llX\n", plugin_name, - u64_addr(insn.ops[1].addr)); - std::string var_name = getWideString(insn.ops[1].addr); - - // retype CHAR16 to const CHAR16 to improve pseudocode quality - setConstChar16Type(insn.ops[1].addr); - - msg("[%s] VariableName: %s\n", plugin_name, var_name.c_str()); - item["VariableName"] = var_name; - name_found = true; - } - - addr = args[1]; // Get VendorGuid - decode_insn(&insn, addr); - // If GUID is global variable - if (insn.itype == NN_lea && insn.ops[0].type == o_reg && insn.ops[0].reg == REG_RDX && - insn.ops[1].type == o_mem) { - msg("[%s] VendorGuid address (global): 0x%016llX\n", plugin_name, - u64_addr(insn.ops[1].addr)); - EfiGuid guid = getGlobalGuid(insn.ops[1].addr); - msg("[%s] GUID: %s\n", plugin_name, guid.to_string().c_str()); - item["VendorGuid"] = guid.to_string(); - guid_found = true; - } - // If GUID is local variable - if (!guid_found && insn.itype == NN_lea && insn.ops[0].type == o_reg && - insn.ops[0].reg == REG_RDX && insn.ops[1].type == o_displ) { - switch (insn.ops[1].reg) { - case REG_RBP: { - msg("[%s] VendorGuid address (regarding to RBP): 0x%016llX\n", plugin_name, - u64_addr(insn.ops[1].addr)); - EfiGuid guid = getStackGuid(f, insn.ops[1].addr); - msg("[%s] GUID: %s\n", plugin_name, guid.to_string().c_str()); - item["VendorGuid"] = guid.to_string(); - guid_found = true; - } - case REG_RSP: { - msg("[%s] VendorGuid address (regarding to RSP): 0x%016llX\n", plugin_name, - u64_addr(insn.ops[1].addr)); - EfiGuid guid = getStackGuid(f, insn.ops[1].addr); - msg("[%s] GUID: %s\n", plugin_name, guid.to_string().c_str()); - item["VendorGuid"] = guid.to_string(); - guid_found = true; - } - } - } - - std::map attributes_defs = { - {0x00000001, "NON_VOLATILE"}, - {0x00000002, "BOOTSERVICE_ACCESS"}, - {0x00000004, "RUNTIME_ACCESS"}, - {0x00000008, "HARDWARE_ERROR_RECORD"}, - {0x00000010, "AUTHENTICATED_WRITE_ACCESS"}}; - - addr = args[2]; // Get Attributes - decode_insn(&insn, addr); - if (insn.itype == NN_xor && insn.ops[0].type == o_reg && insn.ops[1].type == o_reg && - insn.ops[0].reg == insn.ops[1].reg && insn.ops[0].reg == REG_R8) { - item["Attributes"] = 0; - std::string attributes_hr = "No attributes"; - item["AttributesHumanReadable"] = attributes_hr; - msg("[%s] Attributes: %d (%s)\n", plugin_name, 0, attributes_hr.c_str()); - } else { +bool efi_analysis::EfiAnalyzer::AnalyzeVariableService(ea_t ea, std::string service_str) { + msg("[%s] %s call: 0x%016llX\n", g_plugin_name, service_str.c_str(), u64_addr(ea)); + json item; + item["addr"] = ea; + insn_t insn; + bool name_found = false; + bool guid_found = false; + func_t *f = get_func(ea); + if (f == nullptr) { + return false; + } + eavec_t args; + get_arg_addrs(&args, ea); + if (args.size() < 3) { + return false; + } + + auto addr = args[0]; // Get VariableName + decode_insn(&insn, addr); + if (insn.itype == NN_lea && insn.ops[0].type == o_reg && insn.ops[0].reg == REG_RCX && + insn.ops[1].type == o_mem) { + msg("[%s] VariableName address: 0x%016llX\n", g_plugin_name, + u64_addr(insn.ops[1].addr)); + std::string var_name = getWideString(insn.ops[1].addr); + + // retype CHAR16 to const CHAR16 to improve pseudocode quality + setConstChar16Type(insn.ops[1].addr); + + msg("[%s] VariableName: %s\n", g_plugin_name, var_name.c_str()); + item["VariableName"] = var_name; + name_found = true; + } + + addr = args[1]; // Get VendorGuid + decode_insn(&insn, addr); + // If GUID is global variable + if (insn.itype == NN_lea && insn.ops[0].type == o_reg && insn.ops[0].reg == REG_RDX && + insn.ops[1].type == o_mem) { + msg("[%s] VendorGuid address (global): 0x%016llX\n", g_plugin_name, + u64_addr(insn.ops[1].addr)); + EfiGuid guid = getGlobalGuid(insn.ops[1].addr); + msg("[%s] GUID: %s\n", g_plugin_name, guid.to_string().c_str()); + item["VendorGuid"] = guid.to_string(); + guid_found = true; + } + // If GUID is local variable + if (!guid_found && insn.itype == NN_lea && insn.ops[0].type == o_reg && + insn.ops[0].reg == REG_RDX && insn.ops[1].type == o_displ) { + switch (insn.ops[1].reg) { + case REG_RBP: { + msg("[%s] VendorGuid address (regarding to RBP): 0x%016llX\n", g_plugin_name, + u64_addr(insn.ops[1].addr)); + EfiGuid guid = getStackGuid(f, insn.ops[1].addr); + msg("[%s] GUID: %s\n", g_plugin_name, guid.to_string().c_str()); + item["VendorGuid"] = guid.to_string(); + guid_found = true; + } + case REG_RSP: { + msg("[%s] VendorGuid address (regarding to RSP): 0x%016llX\n", g_plugin_name, + u64_addr(insn.ops[1].addr)); + EfiGuid guid = getStackGuid(f, insn.ops[1].addr); + msg("[%s] GUID: %s\n", g_plugin_name, guid.to_string().c_str()); + item["VendorGuid"] = guid.to_string(); + guid_found = true; + } + } + } + + std::map attributes_defs = { + {0x00000001, "NON_VOLATILE"}, + {0x00000002, "BOOTSERVICE_ACCESS"}, + {0x00000004, "RUNTIME_ACCESS"}, + {0x00000008, "HARDWARE_ERROR_RECORD"}, + {0x00000010, "AUTHENTICATED_WRITE_ACCESS"}}; + + addr = args[2]; // Get Attributes + decode_insn(&insn, addr); + if (insn.itype == NN_xor && insn.ops[0].type == o_reg && insn.ops[1].type == o_reg && + insn.ops[0].reg == insn.ops[1].reg && insn.ops[0].reg == REG_R8) { + item["Attributes"] = 0; + std::string attributes_hr = "No attributes"; + item["AttributesHumanReadable"] = attributes_hr; + msg("[%s] Attributes: %d (%s)\n", g_plugin_name, 0, attributes_hr.c_str()); + } else { #ifdef HEX_RAYS - // Extract attributes with Hex-Rays SDK - auto res = VariablesInfoExtractAll(f, ea); - item["Attributes"] = res; - std::string attributes_hr = std::string(); - if (res == 0xff) { - attributes_hr = "Unknown attributes"; - } else { - for (auto &[attr, attr_def] : attributes_defs) { - if (res & attr & 0x0f) { - attributes_hr += attr_def + " | "; - } - } - if (attributes_hr.size() >= 3) { // remove the last operation OR - attributes_hr = attributes_hr.substr(0, attributes_hr.size() - 3); - } + // Extract attributes with Hex-Rays SDK + auto res = VariablesInfoExtractAll(f, ea); + item["Attributes"] = res; + std::string attributes_hr = std::string(); + if (res == 0xff) { + attributes_hr = "Unknown attributes"; + } else { + for (auto &[attr, attr_def] : attributes_defs) { + if (res & attr & 0x0f) { + attributes_hr += attr_def + " | "; } - item["AttributesHumanReadable"] = attributes_hr; - msg("[%s] Attributes: %d (%s)\n", plugin_name, res, attributes_hr.c_str()); + } + if (attributes_hr.size() >= 3) { // remove the last operation OR + attributes_hr = attributes_hr.substr(0, attributes_hr.size() - 3); + } + } + item["AttributesHumanReadable"] = attributes_hr; + msg("[%s] Attributes: %d (%s)\n", g_plugin_name, res, attributes_hr.c_str()); #else - // If Hex-Rays analysis is not used, this feature does not work - item["Attributes"] = 0xff; - item["AttributesHumanReadable"] = "Unknown attributes"; + // If Hex-Rays analysis is not used, this feature does not work + item["Attributes"] = 0xff; + item["AttributesHumanReadable"] = "Unknown attributes"; #endif - } + } - if (name_found && guid_found) { // if only name or only GUID found, it will - // now saved (check the logs) - item["service"] = service_str; - nvramVariables.push_back(item); - } + if (name_found && guid_found) { // if only name or only GUID found, it will + // now saved (check the logs) + item["service"] = service_str; + nvramVariables.push_back(item); + } - return true; + return true; } -bool EfiAnalysis::EfiAnalyzer::analyzeNvramVariables() { - msg("[%s] Get NVRAM variables information\n", plugin_name); - std::vector nvram_services = {"GetVariable", "SetVariable"}; - for (auto service_str : nvram_services) { - std::vector var_services; - for (auto j_service : allServices) { - json service = j_service; - std::string service_name = static_cast(service["service_name"]); - ea_t addr = static_cast(service["address"]); - if (!service_name.compare(service_str)) { - var_services.push_back(addr); - } - } - sort(var_services.begin(), var_services.end()); - for (auto ea : var_services) { - AnalyzeVariableService(ea, service_str); - } +bool efi_analysis::EfiAnalyzer::analyzeNvramVariables() { + msg("[%s] Get NVRAM variables information\n", g_plugin_name); + std::vector nvram_services = {"GetVariable", "SetVariable"}; + for (auto service_str : nvram_services) { + std::vector var_services; + for (auto j_service : allServices) { + json service = j_service; + std::string service_name = static_cast(service["service_name"]); + ea_t addr = static_cast(service["address"]); + if (!service_name.compare(service_str)) { + var_services.push_back(addr); + } + } + sort(var_services.begin(), var_services.end()); + for (auto ea : var_services) { + AnalyzeVariableService(ea, service_str); + } - for (auto ea : g_smm_get_variable_calls) { - AnalyzeVariableService(ea, "EFI_SMM_VARIABLE_PROTOCOL::SmmGetVariable"); - } + for (auto ea : g_smm_get_variable_calls) { + AnalyzeVariableService(ea, "EFI_SMM_VARIABLE_PROTOCOL::SmmGetVariable"); + } - for (auto ea : g_smm_set_variable_calls) { - AnalyzeVariableService(ea, "EFI_SMM_VARIABLE_PROTOCOL::SmmSetVariable"); - } + for (auto ea : g_smm_set_variable_calls) { + AnalyzeVariableService(ea, "EFI_SMM_VARIABLE_PROTOCOL::SmmSetVariable"); } - return true; + } + return true; } //-------------------------------------------------------------------------- // Resolve EFI_SMM_CPU_PROTOCOL -bool EfiAnalysis::EfiAnalyzer::efiSmmCpuProtocolResolver() { - readSaveStateCalls = resolveEfiSmmCpuProtocol(stackGuids, dataGuids, &allServices); - return true; +bool efi_analysis::EfiAnalyzer::efiSmmCpuProtocolResolver() { + readSaveStateCalls = resolveEfiSmmCpuProtocol(stackGuids, dataGuids, &allServices); + return true; } //-------------------------------------------------------------------------- // Dump all info to JSON file -void EfiAnalysis::EfiAnalyzer::dumpInfo() { - json info; - if (gStList.size()) { - info["gStList"] = gStList; - } - if (gBsList.size()) { - info["gBsList"] = gBsList; - } - if (gRtList.size()) { - info["gRtList"] = gRtList; - } - if (gSmstList.size()) { - info["gSmstList"] = gSmstList; - } - if (gImageHandleList.size()) { - info["gImageHandleList"] = gImageHandleList; - } - if (allPPIs.size()) { - info["allPPIs"] = allPPIs; - } - if (allProtocols.size()) { - info["allProtocols"] = allProtocols; - } - if (allServices.size()) { - info["allServices"] = allServices; - } - if (allGuids.size()) { - info["allGuids"] = allGuids; - } - if (nvramVariables.size()) { - info["nvramVariables"] = nvramVariables; - } - if (readSaveStateCalls.size()) { - info["readSaveStateCalls"] = readSaveStateCalls; - } - if (calloutAddrs.size()) { - info["vulns"]["smm_callout"] = calloutAddrs; - } - if (peiGetVariableOverflow.size()) { - info["vulns"]["pei_get_variable_buffer_overflow"] = peiGetVariableOverflow; - } - if (getVariableOverflow.size()) { - info["vulns"]["get_variable_buffer_overflow"] = getVariableOverflow; - } - if (smmGetVariableOverflow.size()) { - info["vulns"]["smm_get_variable_buffer_overflow"] = smmGetVariableOverflow; - } - - std::vector smiHandlersAddrs; - if (smiHandlers.size() > 0) { - for (auto f : smiHandlers) { - func_t *func = f; - smiHandlersAddrs.push_back(func->start_ea); - } - info["smiHandlersAddrs"] = smiHandlersAddrs; - } - - std::string idbPath; - idbPath = get_path(PATH_TYPE_IDB); - std::filesystem::path logFile; - logFile /= idbPath; - logFile.replace_extension(".json"); - std::ofstream out(logFile); - out << std::setw(4) << info << std::endl; - msg("[%s] the log is saved in a JSON file\n", plugin_name); +void efi_analysis::EfiAnalyzer::dumpInfo() { + json info; + if (gStList.size()) { + info["gStList"] = gStList; + } + if (gBsList.size()) { + info["gBsList"] = gBsList; + } + if (gRtList.size()) { + info["gRtList"] = gRtList; + } + if (gSmstList.size()) { + info["gSmstList"] = gSmstList; + } + if (gImageHandleList.size()) { + info["gImageHandleList"] = gImageHandleList; + } + if (allPPIs.size()) { + info["allPPIs"] = allPPIs; + } + if (allProtocols.size()) { + info["allProtocols"] = allProtocols; + } + if (allServices.size()) { + info["allServices"] = allServices; + } + if (allGuids.size()) { + info["allGuids"] = allGuids; + } + if (nvramVariables.size()) { + info["nvramVariables"] = nvramVariables; + } + if (readSaveStateCalls.size()) { + info["readSaveStateCalls"] = readSaveStateCalls; + } + if (calloutAddrs.size()) { + info["vulns"]["smm_callout"] = calloutAddrs; + } + if (peiGetVariableOverflow.size()) { + info["vulns"]["pei_get_variable_buffer_overflow"] = peiGetVariableOverflow; + } + if (getVariableOverflow.size()) { + info["vulns"]["get_variable_buffer_overflow"] = getVariableOverflow; + } + if (smmGetVariableOverflow.size()) { + info["vulns"]["smm_get_variable_buffer_overflow"] = smmGetVariableOverflow; + } + + std::vector smiHandlersAddrs; + if (smiHandlers.size() > 0) { + for (auto f : smiHandlers) { + func_t *func = f; + smiHandlersAddrs.push_back(func->start_ea); + } + info["smiHandlersAddrs"] = smiHandlersAddrs; + } + + std::string idbPath; + idbPath = get_path(PATH_TYPE_IDB); + std::filesystem::path logFile; + logFile /= idbPath; + logFile.replace_extension(".json"); + std::ofstream out(logFile); + out << std::setw(4) << info << std::endl; + msg("[%s] the log is saved in a JSON file\n", g_plugin_name); } //-------------------------------------------------------------------------- // Show all non-empty choosers windows -void showAllChoosers(EfiAnalysis::EfiAnalyzerX86 analyzer) { - qstring title; - - // open window with all services - if (analyzer.allServices.size()) { - title = "efiXplorer: services"; - services_show(analyzer.allServices, title); - } - - // open window with protocols - if (analyzer.fileType == FTYPE_PEI) { - if (analyzer.allPPIs.size()) { - title = "efiXplorer: PPIs"; - ppis_show(analyzer.allPPIs, title); - } - - } else { // FTYPE_DXE_AND_THE_LIKE - if (analyzer.allProtocols.size()) { - title = "efiXplorer: protocols"; - protocols_show(analyzer.allProtocols, title); - } - } - - // open window with data guids - if (analyzer.allGuids.size()) { - qstring title = "efiXplorer: GUIDs"; - guids_show(analyzer.allGuids, title); - } - - // open window with NVRAM variables - if (analyzer.nvramVariables.size()) { - qstring title = "efiXplorer: NVRAM"; - nvram_show(analyzer.nvramVariables, title); - } - - // open window with vulnerabilities - if (calloutAddrs.size() || peiGetVariableOverflow.size() || - getVariableOverflow.size() || smmGetVariableOverflow.size()) { - std::vector vulns; - std::map> vulns_map = { - {"SmmCallout", calloutAddrs}, - {"PeiGetVariableOverflow", peiGetVariableOverflow}, - {"DxeGetVariableOverflow", getVariableOverflow}, - {"SmmGetVariableOverflow", smmGetVariableOverflow}}; - for (const auto &[type, addrs] : vulns_map) { - for (auto addr : addrs) { - json item; - item["type"] = type; - item["address"] = addr; - vulns.push_back(item); - } - } - qstring title = "efiXplorer: vulns"; - vulns_show(vulns, title); - } +void showAllChoosers(efi_analysis::EfiAnalyzerX86 analyzer) { + qstring title; + + // open window with all services + if (analyzer.allServices.size()) { + title = "efiXplorer: services"; + services_show(analyzer.allServices, title); + } + + // open window with protocols + if (analyzer.fileType == FTYPE_PEI) { + if (analyzer.allPPIs.size()) { + title = "efiXplorer: PPIs"; + ppis_show(analyzer.allPPIs, title); + } + + } else { // FTYPE_DXE_AND_THE_LIKE + if (analyzer.allProtocols.size()) { + title = "efiXplorer: protocols"; + protocols_show(analyzer.allProtocols, title); + } + } + + // open window with data guids + if (analyzer.allGuids.size()) { + qstring title = "efiXplorer: GUIDs"; + guids_show(analyzer.allGuids, title); + } + + // open window with NVRAM variables + if (analyzer.nvramVariables.size()) { + qstring title = "efiXplorer: NVRAM"; + nvram_show(analyzer.nvramVariables, title); + } + + // open window with vulnerabilities + if (calloutAddrs.size() || peiGetVariableOverflow.size() || + getVariableOverflow.size() || smmGetVariableOverflow.size()) { + std::vector vulns; + std::map> vulns_map = { + {"SmmCallout", calloutAddrs}, + {"PeiGetVariableOverflow", peiGetVariableOverflow}, + {"DxeGetVariableOverflow", getVariableOverflow}, + {"SmmGetVariableOverflow", smmGetVariableOverflow}}; + for (const auto &[type, addrs] : vulns_map) { + for (auto addr : addrs) { + json item; + item["type"] = type; + item["address"] = addr; + vulns.push_back(item); + } + } + qstring title = "efiXplorer: vulns"; + vulns_show(vulns, title); + } } //-------------------------------------------------------------------------- // Main function for X64 modules -bool EfiAnalysis::efiAnalyzerMainX64() { - show_wait_box("HIDECANCEL\nAnalyzing module(s) with efiXplorer..."); - - EfiAnalysis::EfiAnalyzerX86 analyzer; - - while (!auto_is_ok()) { - auto_wait(); - }; - - // find .text and .data segments - analyzer.getSegments(); - - // analyze all - auto res = ASKBTN_NO; - if (analyzer.arch == UEFI) { - res = ask_yn(1, "Want to further analyze all drivers with auto_mark_range?"); - } - if (res == ASKBTN_YES && textSegments.size() && dataSegments.size()) { - segment_t *start_seg = textSegments.at(0); - segment_t *end_seg = dataSegments.at(dataSegments.size() - 1); - ea_t start_ea = start_seg->start_ea; - ea_t end_ea = end_seg->end_ea; - auto_mark_range(start_ea, end_ea, AU_USED); - plan_and_wait(start_ea, end_ea, 1); - } - - // mark GUIDs - analyzer.markDataGuids(); - analyzer.markLocalGuidsX64(); - - if (g_args.disable_ui) { - analyzer.fileType = g_args.module_type == PEI - ? analyzer.fileType = FTYPE_PEI - : analyzer.fileType = FTYPE_DXE_AND_THE_LIKE; - } else { - analyzer.fileType = getFileType(&analyzer.allGuids); - } - - analyzer.setStrings(); - - // find global vars for gImageHandle, gST, gBS, gRT, gSmst - if (analyzer.fileType == FTYPE_DXE_AND_THE_LIKE) { - analyzer.findImageHandleX64(); - analyzer.findSystemTableX64(); - analyzer.findBootServicesTables(); - analyzer.findRuntimeServicesTables(); - - analyzer.findSmstX64(); - - // find Boot services and Runtime services - analyzer.getProtBootServicesX64(); - analyzer.findOtherBsTablesX64(); - analyzer.getAllBootServices(); - analyzer.getAllRuntimeServices(); - - analyzer.getBsProtNamesX64(); +bool efi_analysis::efiAnalyzerMainX64() { + show_wait_box("HIDECANCEL\nAnalyzing module(s) with efiXplorer..."); + + efi_analysis::EfiAnalyzerX86 analyzer; + + while (!auto_is_ok()) { + auto_wait(); + }; + + // find .text and .data segments + analyzer.getSegments(); + + // analyze all + auto res = ASKBTN_NO; + if (analyzer.arch == UEFI) { + res = ask_yn(1, "Want to further analyze all drivers with auto_mark_range?"); + } + if (res == ASKBTN_YES && textSegments.size() && dataSegments.size()) { + segment_t *start_seg = textSegments.at(0); + segment_t *end_seg = dataSegments.at(dataSegments.size() - 1); + ea_t start_ea = start_seg->start_ea; + ea_t end_ea = end_seg->end_ea; + auto_mark_range(start_ea, end_ea, AU_USED); + plan_and_wait(start_ea, end_ea, 1); + } + + // mark GUIDs + analyzer.markDataGuids(); + analyzer.markLocalGuidsX64(); + + if (g_args.disable_ui) { + analyzer.fileType = g_args.module_type == PEI + ? analyzer.fileType = FTYPE_PEI + : analyzer.fileType = FTYPE_DXE_AND_THE_LIKE; + } else { + analyzer.fileType = getFileType(&analyzer.allGuids); + } + + analyzer.setStrings(); + + // find global vars for gImageHandle, gST, gBS, gRT, gSmst + if (analyzer.fileType == FTYPE_DXE_AND_THE_LIKE) { + analyzer.findImageHandleX64(); + analyzer.findSystemTableX64(); + analyzer.findBootServicesTables(); + analyzer.findRuntimeServicesTables(); + + analyzer.findSmstX64(); + + // find Boot services and Runtime services + analyzer.getProtBootServicesX64(); + analyzer.findOtherBsTablesX64(); + analyzer.getAllBootServices(); + analyzer.getAllRuntimeServices(); + + analyzer.getBsProtNamesX64(); #ifdef HEX_RAYS - applyAllTypesForInterfacesBootServices(analyzer.allProtocols); - analyzer.findSmstPostProcX64(); + applyAllTypesForInterfacesBootServices(analyzer.allProtocols); + analyzer.findSmstPostProcX64(); #endif - // find SMM services - analyzer.getAllSmmServicesX64(); - analyzer.getSmmProtNamesX64(); + // find SMM services + analyzer.getAllSmmServicesX64(); + analyzer.getSmmProtNamesX64(); - // mark protocols - analyzer.markInterfaces(); + // mark protocols + analyzer.markInterfaces(); - // search for copies of global variables - markCopiesForGlobalVars(gSmstList, "gSmst"); - markCopiesForGlobalVars(gBsList, "gBS"); - markCopiesForGlobalVars(gRtList, "gRT"); + // search for copies of global variables + markCopiesForGlobalVars(gSmstList, "gSmst"); + markCopiesForGlobalVars(gBsList, "gBS"); + markCopiesForGlobalVars(gRtList, "gRT"); - // search for vulnerabilities - if (!g_args.disable_vuln_hunt) { + // search for vulnerabilities + if (!g_args.disable_vuln_hunt) { - // find potential SMM callouts - analyzer.findSwSmiHandlers(); - analyzer.findSmmCallout(); + // find potential SMM callouts + analyzer.findSwSmiHandlers(); + analyzer.findSmmCallout(); - // find potential OOB RW with GetVariable function - analyzer.findGetVariableOveflow(analyzer.allServices); + // find potential OOB RW with GetVariable function + analyzer.findGetVariableOveflow(analyzer.allServices); - // find potential OOB RW with SmmGetVariable function - analyzer.findSmmGetVariableOveflow(); - analyzer.efiSmmCpuProtocolResolver(); - } + // find potential OOB RW with SmmGetVariable function + analyzer.findSmmGetVariableOveflow(); + analyzer.efiSmmCpuProtocolResolver(); + } #ifdef HEX_RAYS - applyAllTypesForInterfacesSmmServices(analyzer.allProtocols); + applyAllTypesForInterfacesSmmServices(analyzer.allProtocols); #endif - analyzer.analyzeNvramVariables(); + analyzer.analyzeNvramVariables(); - } else { - msg("[%s] Parsing of 64-bit PEI files is not supported yet\n", plugin_name); - } + } else { + msg("[%s] Parsing of 64-bit PEI files is not supported yet\n", g_plugin_name); + } - // dump info to JSON file - analyzer.dumpInfo(); + // dump info to JSON file + analyzer.dumpInfo(); - // show all choosers windows - if (!g_args.disable_ui) { - showAllChoosers(analyzer); - } + // show all choosers windows + if (!g_args.disable_ui) { + showAllChoosers(analyzer); + } - if (analyzer.arch == UEFI) { - // Init public EdiDependencies members - g_deps.getProtocolsChooser(analyzer.allProtocols); - g_deps.getProtocolsByGuids(analyzer.allProtocols); + if (analyzer.arch == UEFI) { + // Init public EdiDependencies members + g_deps.getProtocolsChooser(analyzer.allProtocols); + g_deps.getProtocolsByGuids(analyzer.allProtocols); - // Save all protocols information to build dependencies - attachActionProtocolsDeps(); - attachActionModulesSeq(); - } + // Save all protocols information to build dependencies + attachActionProtocolsDeps(); + attachActionModulesSeq(); + } - hide_wait_box(); + hide_wait_box(); - return true; + return true; } //-------------------------------------------------------------------------- // Main function for X86 modules -bool EfiAnalysis::efiAnalyzerMainX86() { +bool efi_analysis::efiAnalyzerMainX86() { - show_wait_box("HIDECANCEL\nAnalyzing module(s) with efiXplorer..."); + show_wait_box("HIDECANCEL\nAnalyzing module(s) with efiXplorer..."); - EfiAnalysis::EfiAnalyzerX86 analyzer; + efi_analysis::EfiAnalyzerX86 analyzer; - while (!auto_is_ok()) { - auto_wait(); - }; + while (!auto_is_ok()) { + auto_wait(); + }; - // find .text and .data segments - analyzer.getSegments(); + // find .text and .data segments + analyzer.getSegments(); - // mark GUIDs - analyzer.markDataGuids(); + // mark GUIDs + analyzer.markDataGuids(); - if (g_args.disable_ui) { - analyzer.fileType = g_args.module_type == PEI - ? analyzer.fileType = FTYPE_PEI - : analyzer.fileType = FTYPE_DXE_AND_THE_LIKE; - } else { - analyzer.fileType = getFileType(&analyzer.allGuids); - } + if (g_args.disable_ui) { + analyzer.fileType = g_args.module_type == PEI + ? analyzer.fileType = FTYPE_PEI + : analyzer.fileType = FTYPE_DXE_AND_THE_LIKE; + } else { + analyzer.fileType = getFileType(&analyzer.allGuids); + } - analyzer.setStrings(); + analyzer.setStrings(); - if (analyzer.fileType == FTYPE_DXE_AND_THE_LIKE) { + if (analyzer.fileType == FTYPE_DXE_AND_THE_LIKE) { - // find global vars for gST, gBS, gRT - analyzer.findBootServicesTables(); - analyzer.findRuntimeServicesTables(); + // find global vars for gST, gBS, gRT + analyzer.findBootServicesTables(); + analyzer.findRuntimeServicesTables(); - // find boot services and runtime services - analyzer.getAllRuntimeServices(); - analyzer.getProtBootServicesX86(); - analyzer.getAllBootServices(); + // find boot services and runtime services + analyzer.getAllRuntimeServices(); + analyzer.getProtBootServicesX86(); + analyzer.getAllBootServices(); - // print and mark protocols - analyzer.getBsProtNamesX86(); - analyzer.markInterfaces(); + // print and mark protocols + analyzer.getBsProtNamesX86(); + analyzer.markInterfaces(); #ifdef HEX_RAYS - applyAllTypesForInterfacesBootServices(analyzer.allProtocols); - applyAllTypesForInterfacesSmmServices(analyzer.allProtocols); + applyAllTypesForInterfacesBootServices(analyzer.allProtocols); + applyAllTypesForInterfacesSmmServices(analyzer.allProtocols); #endif - } else if (analyzer.fileType == FTYPE_PEI) { - setEntryArgToPeiSvc(); - addStrucForShiftedPtr(); + } else if (analyzer.fileType == FTYPE_PEI) { + setEntryArgToPeiSvc(); + addStrucForShiftedPtr(); #ifdef HEX_RAYS - for (auto addr : analyzer.funcs) { - DetectPeiServices(get_func(addr)); - } + for (auto addr : analyzer.funcs) { + DetectPeiServices(get_func(addr)); + } #endif - analyzer.getAllPeiServicesX86(); - analyzer.getPpiNamesX86(); - analyzer.getAllVariablePPICallsX86(); - analyzer.markInterfaces(); - - // search for vulnerabilities - if (!g_args.disable_vuln_hunt) { - analyzer.findPPIGetVariableStackOveflow(); - } + analyzer.getAllPeiServicesX86(); + analyzer.getPpiNamesX86(); + analyzer.getAllVariablePPICallsX86(); + analyzer.markInterfaces(); + + // search for vulnerabilities + if (!g_args.disable_vuln_hunt) { + analyzer.findPPIGetVariableStackOveflow(); } + } - // dump info to JSON file - analyzer.dumpInfo(); + // dump info to JSON file + analyzer.dumpInfo(); - // show all choosers windows - if (!g_args.disable_ui) { - showAllChoosers(analyzer); - } + // show all choosers windows + if (!g_args.disable_ui) { + showAllChoosers(analyzer); + } - hide_wait_box(); + hide_wait_box(); - return true; + return true; } diff --git a/efiXplorer/efiDeps.cpp b/efiXplorer/efiDeps.cpp index 90895a00..bf1290d2 100644 --- a/efiXplorer/efiDeps.cpp +++ b/efiXplorer/efiDeps.cpp @@ -1,6 +1,6 @@ /* * efiXplorer - * Copyright (C) 2020-2023 Binarly + * Copyright (C) 2020-2024 Binarly * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -22,408 +22,400 @@ #include "efiDeps.h" EfiDependencies::EfiDependencies() { - // Read DEPEX (for protocols) from - // .deps.json file if this file exists - loadDepsFromUefiTool(); - // Get images names from IDB - getImages(); - // Read images with GUIDs from - // .images.json file if this file exists - loadImagesWithGuids(); + // Read DEPEX (for protocols) from + // .deps.json file if this file exists + loadDepsFromUefiTool(); + // Get images names from IDB + getImages(); + // Read images with GUIDs from + // .images.json file if this file exists + loadImagesWithGuids(); }; EfiDependencies::~EfiDependencies() { - imagesInfo.clear(); - imagesGuids.clear(); - imagesFromIdb.clear(); - uefitoolDeps.clear(); - modulesSequence.clear(); - protocolsChooser.clear(); - protocolsByGuids.clear(); - additionalInstallers.clear(); - protocolsWithoutInstallers.clear(); + imagesInfo.clear(); + imagesGuids.clear(); + imagesFromIdb.clear(); + uefitoolDeps.clear(); + modulesSequence.clear(); + protocolsChooser.clear(); + protocolsByGuids.clear(); + additionalInstallers.clear(); + protocolsWithoutInstallers.clear(); }; json EfiDependencies::getDeps(std::string guid) { - json res; - std::vector installers({"InstallProtocolInterface", - "InstallMultipleProtocolInterfaces", - "SmmInstallProtocolInterface"}); - for (auto &it : protocolsChooser.items()) { - auto p = it.value(); - if (p["guid"] != guid) { - continue; - } - p["ea"] = getHex(u64_addr(p["ea"])); - p["xref"] = getHex(u64_addr(p["xref"])); - p["address"] = getHex(u64_addr(p["address"])); - if (find(installers.begin(), installers.end(), p["service"]) != - installers.end()) { - res["installed"].push_back(p); - } else { - res["used"].push_back(p); - } + json res; + std::vector installers({"InstallProtocolInterface", "InstallMultipleProtocolInterfaces", + "SmmInstallProtocolInterface"}); + for (auto &it : protocolsChooser.items()) { + auto p = it.value(); + if (p["guid"] != guid) { + continue; + } + p["ea"] = getHex(u64_addr(p["ea"])); + p["xref"] = getHex(u64_addr(p["xref"])); + p["address"] = getHex(u64_addr(p["address"])); + if (find(installers.begin(), installers.end(), p["service"]) != installers.end()) { + res["installed"].push_back(p); + } else { + res["used"].push_back(p); } + } - return res; + return res; } void EfiDependencies::getProtocolsByGuids(std::vector protocols) { - for (auto p : protocols) { - // check if entry for GUID already exist - std::string guid = p["guid"]; - auto deps = protocolsByGuids[guid]; - if (deps.is_null()) { - protocolsByGuids[guid] = getDeps(guid); - } + for (auto p : protocols) { + // check if entry for GUID already exist + std::string guid = p["guid"]; + auto deps = protocolsByGuids[guid]; + if (deps.is_null()) { + protocolsByGuids[guid] = getDeps(guid); } + } } void EfiDependencies::getProtocolsChooser(std::vector protocols) { - auto i = 0; - for (auto p : protocols) { - protocolsChooser[i] = p; - ++i; - } + auto i = 0; + for (auto p : protocols) { + protocolsChooser[i] = p; + ++i; + } } bool EfiDependencies::loadDepsFromUefiTool() { - std::filesystem::path deps_json; - deps_json /= get_path(PATH_TYPE_IDB); - deps_json.replace_extension(".deps.json"); - if (!std::filesystem::exists(deps_json)) { - return false; - } - std::ifstream file(deps_json); - file >> uefitoolDeps; - return true; + std::filesystem::path deps_json; + deps_json /= get_path(PATH_TYPE_IDB); + deps_json.replace_extension(".deps.json"); + if (!std::filesystem::exists(deps_json)) { + return false; + } + std::ifstream file(deps_json); + file >> uefitoolDeps; + return true; } bool EfiDependencies::loadImagesWithGuids() { - std::filesystem::path images_json; - images_json /= get_path(PATH_TYPE_IDB); - images_json.replace_extension(".images.json"); - if (!std::filesystem::exists(images_json)) { - return false; - } - std::ifstream file(images_json); - file >> imagesGuids; - return true; + std::filesystem::path images_json; + images_json /= get_path(PATH_TYPE_IDB); + images_json.replace_extension(".images.json"); + if (!std::filesystem::exists(images_json)) { + return false; + } + std::ifstream file(images_json); + file >> imagesGuids; + return true; } bool EfiDependencies::installerFound(std::string protocol) { - auto deps_prot = protocolsByGuids[protocol]; - if (deps_prot.is_null()) { - return false; - } - auto installers = deps_prot["installed"]; - if (installers.is_null()) { - return false; - } - return true; + auto deps_prot = protocolsByGuids[protocol]; + if (deps_prot.is_null()) { + return false; + } + auto installers = deps_prot["installed"]; + if (installers.is_null()) { + return false; + } + return true; } void EfiDependencies::getProtocolsWithoutInstallers() { - // Check DXE_DEPEX and MM_DEPEX - std::vector sections{"EFI_SECTION_DXE_DEPEX", "EFI_SECTION_MM_DEPEX"}; - for (auto section : sections) { - auto images = uefitoolDeps[section]; - for (auto &element : images.items()) { - auto protocols = element.value(); - for (auto p : protocols) { - std::string ps = static_cast(p); - if (!installerFound(ps)) { - protocolsWithoutInstallers.insert(ps); - } - } + // Check DXE_DEPEX and MM_DEPEX + std::vector sections{"EFI_SECTION_DXE_DEPEX", "EFI_SECTION_MM_DEPEX"}; + for (auto section : sections) { + auto images = uefitoolDeps[section]; + for (auto &element : images.items()) { + auto protocols = element.value(); + for (auto p : protocols) { + std::string ps = static_cast(p); + if (!installerFound(ps)) { + protocolsWithoutInstallers.insert(ps); } + } } + } } void EfiDependencies::getInstallersModules() { - // search for this protocols in binary - for (auto &protocol : protocolsWithoutInstallers) { - auto addrs = searchProtocol(protocol); - bool installerFound = false; - for (auto addr : addrs) { - auto xrefs = getXrefs(addr); - if (!xrefs.size()) { - continue; - } - if (xrefs.size() == 1) { - func_t *func = get_func(xrefs.at(0)); - if (func == nullptr) { - xrefs = getXrefsToArray(xrefs.at(0)); - } - } - for (auto ea : xrefs) { - if (checkInstallProtocol(ea)) { - auto module = getModuleNameLoader(ea); - additionalInstallers[protocol] = - static_cast(module.c_str()); - installerFound = true; - break; - } - } - if (installerFound) { - break; - } + // search for this protocols in binary + for (auto &protocol : protocolsWithoutInstallers) { + auto addrs = searchProtocol(protocol); + bool installerFound = false; + for (auto addr : addrs) { + auto xrefs = getXrefs(addr); + if (!xrefs.size()) { + continue; + } + if (xrefs.size() == 1) { + func_t *func = get_func(xrefs.at(0)); + if (func == nullptr) { + xrefs = getXrefsToArray(xrefs.at(0)); } - if (!installerFound) { - untrackedProtocols.insert(protocol); + } + for (auto ea : xrefs) { + if (checkInstallProtocol(ea)) { + auto module = getModuleNameLoader(ea); + additionalInstallers[protocol] = static_cast(module.c_str()); + installerFound = true; + break; } + } + if (installerFound) { + break; + } + } + if (!installerFound) { + untrackedProtocols.insert(protocol); } + } } void EfiDependencies::getAdditionalInstallers() { - getProtocolsWithoutInstallers(); - getInstallersModules(); - std::string installers = additionalInstallers.dump(2); - msg("Additional installers: %s\n", installers.c_str()); - msg("Untracked protocols:\n"); - for (auto &protocol : untrackedProtocols) { - msg("%s\n", protocol.c_str()); - } + getProtocolsWithoutInstallers(); + getInstallersModules(); + std::string installers = additionalInstallers.dump(2); + msg("Additional installers: %s\n", installers.c_str()); + msg("Untracked protocols:\n"); + for (auto &protocol : untrackedProtocols) { + msg("%s\n", protocol.c_str()); + } } void EfiDependencies::getImages() { - for (segment_t *s = get_first_seg(); s != nullptr; s = get_next_seg(s->start_ea)) { - qstring seg_name; - get_segm_name(&seg_name, s); - - std::vector codeSegNames{"_.text", "_.code"}; - for (auto name : codeSegNames) { - auto index = seg_name.find(name.c_str()); - if (index != std::string::npos) { - std::string image_name = - static_cast(seg_name.c_str()).substr(0, index); - if (!image_name.rfind("_", 0)) { - image_name = image_name.erase(0, 1); - } - imagesFromIdb.push_back(image_name); - } + for (segment_t *s = get_first_seg(); s != nullptr; s = get_next_seg(s->start_ea)) { + qstring seg_name; + get_segm_name(&seg_name, s); + + std::vector codeSegNames{"_.text", "_.code"}; + for (auto name : codeSegNames) { + auto index = seg_name.find(name.c_str()); + if (index != std::string::npos) { + std::string image_name = + static_cast(seg_name.c_str()).substr(0, index); + if (!image_name.rfind("_", 0)) { + image_name = image_name.erase(0, 1); } + imagesFromIdb.push_back(image_name); + } } + } } json EfiDependencies::getImageInfo(std::string image) { - json info; - std::vector installedProtocols; - json depsProtocols; - std::vector installers({"InstallProtocolInterface", - "InstallMultipleProtocolInterfaces", - "SmmInstallProtocolInterface"}); - - // Get installed protocols - for (auto &p : additionalInstallers.items()) { // check additional installers - std::string adInstImage = p.value(); - std::string adInstProtocol = p.key(); - if (adInstImage == image) { - installedProtocols.push_back(adInstProtocol); - break; - } + json info; + std::vector installedProtocols; + json depsProtocols; + std::vector installers({"InstallProtocolInterface", "InstallMultipleProtocolInterfaces", + "SmmInstallProtocolInterface"}); + + // Get installed protocols + for (auto &p : additionalInstallers.items()) { // check additional installers + std::string adInstImage = p.value(); + std::string adInstProtocol = p.key(); + if (adInstImage == image) { + installedProtocols.push_back(adInstProtocol); + break; } + } - for (auto &element : protocolsChooser.items()) { // check efiXplorer report - json p = element.value(); - std::string image_name = p["module"]; - if (!image_name.rfind("_", 0)) { - image_name = image_name.erase(0, 1); - } - if (image_name != image) { - continue; - } - if (find(installers.begin(), installers.end(), p["service"]) != - installers.end()) { - installedProtocols.push_back(p["guid"]); - } + for (auto &element : protocolsChooser.items()) { // check efiXplorer report + json p = element.value(); + std::string image_name = p["module"]; + if (!image_name.rfind("_", 0)) { + image_name = image_name.erase(0, 1); } - - // Get deps - bool found = false; - std::vector sections{"EFI_SECTION_DXE_DEPEX", "EFI_SECTION_MM_DEPEX"}; - for (auto section : sections) { - json deps_images = uefitoolDeps[section]; - for (auto &element : deps_images.items()) { - std::string dimage_guid = element.key(); - if (imagesGuids[dimage_guid].is_null()) { - // Can not get name for image - continue; - } - std::string dimage_name = imagesGuids[dimage_guid]; - if (dimage_name == image) { - depsProtocols = element.value(); - found = true; - break; - } - } - if (found) { - break; - } + if (image_name != image) { + continue; + } + if (find(installers.begin(), installers.end(), p["service"]) != installers.end()) { + installedProtocols.push_back(p["guid"]); + } + } + + // Get deps + bool found = false; + std::vector sections{"EFI_SECTION_DXE_DEPEX", "EFI_SECTION_MM_DEPEX"}; + for (auto section : sections) { + json deps_images = uefitoolDeps[section]; + for (auto &element : deps_images.items()) { + std::string dimage_guid = element.key(); + if (imagesGuids[dimage_guid].is_null()) { + // Can not get name for image + continue; + } + std::string dimage_name = imagesGuids[dimage_guid]; + if (dimage_name == image) { + depsProtocols = element.value(); + found = true; + break; + } + } + if (found) { + break; } + } - info["installed_protocols"] = installedProtocols; - info["deps_protocols"] = depsProtocols; + info["installed_protocols"] = installedProtocols; + info["deps_protocols"] = depsProtocols; - return info; + return info; } bool EfiDependencies::getImagesInfo() { - if (imagesInfo.size()) { - return true; - } - for (auto image : imagesFromIdb) { - imagesInfo[image] = getImageInfo(image); - } + if (imagesInfo.size()) { return true; + } + for (auto image : imagesFromIdb) { + imagesInfo[image] = getImageInfo(image); + } + return true; } std::string EfiDependencies::getInstaller(std::string protocol) { - std::string res; - for (auto &e : imagesInfo.items()) { - std::string image = e.key(); - std::vector installers = imagesInfo[image]["installed_protocols"]; - if (find(installers.begin(), installers.end(), protocol) != installers.end()) { - return image; - } + std::string res; + for (auto &e : imagesInfo.items()) { + std::string image = e.key(); + std::vector installers = imagesInfo[image]["installed_protocols"]; + if (find(installers.begin(), installers.end(), protocol) != installers.end()) { + return image; } - return res; + } + return res; } bool EfiDependencies::buildModulesSequence() { - if (modulesSequence.size()) { - return true; + if (modulesSequence.size()) { + return true; + } + + std::set modulesSeq; + std::set installed_protocols; + + getProtocolsWithoutInstallers(); // hard to find installers for all protocols in + // statiс + getImagesInfo(); + + size_t index = 0; + while (modulesSeq.size() != imagesInfo.size()) { + bool changed = false; + for (auto &e : imagesInfo.items()) { + std::string image = e.key(); // current module + + // check if the image is already loaded + if (modulesSeq.find(image) != modulesSeq.end()) { + continue; + } + + std::vector installers = imagesInfo[image]["installed_protocols"]; + + // if there are no dependencies + if (imagesInfo[image]["deps_protocols"].is_null()) { + for (auto protocol : installers) { + installed_protocols.insert(protocol); + } + modulesSeq.insert(image); + json info; + info["module"] = image; + modulesSequence[index++] = info; + changed = true; + continue; + } + + std::vector deps = imagesInfo[image]["deps_protocols"]; + std::vector unresolved_deps; + bool load = true; + for (auto protocol : deps) { + if (installed_protocols.find(protocol) != installed_protocols.end()) { + continue; + } + if (protocolsWithoutInstallers.find(protocol) != + protocolsWithoutInstallers.end()) { + unresolved_deps.push_back(protocol); + continue; + } + load = false; + break; + } + + if (load) { + for (auto protocol : installers) { + installed_protocols.insert(protocol); + } + modulesSeq.insert(image); + json info; + info["image"] = image; + info["deps"] = deps; + if (unresolved_deps.size()) { + info["unresolved_deps"] = unresolved_deps; + } + modulesSequence[index++] = info; + changed = true; + } } - std::set modulesSeq; - std::set installed_protocols; - - getProtocolsWithoutInstallers(); // hard to find installers for all protocols in - // statiс - getImagesInfo(); - - size_t index = 0; - while (modulesSeq.size() != imagesInfo.size()) { - bool changed = false; - for (auto &e : imagesInfo.items()) { - std::string image = e.key(); // current module - - // check if the image is already loaded - if (modulesSeq.find(image) != modulesSeq.end()) { - continue; - } - - std::vector installers = - imagesInfo[image]["installed_protocols"]; - - // if there are no dependencies - if (imagesInfo[image]["deps_protocols"].is_null()) { - for (auto protocol : installers) { - installed_protocols.insert(protocol); - } - modulesSeq.insert(image); - json info; - info["module"] = image; - modulesSequence[index++] = info; - changed = true; - continue; - } - - std::vector deps = imagesInfo[image]["deps_protocols"]; - std::vector unresolved_deps; - bool load = true; - for (auto protocol : deps) { - if (installed_protocols.find(protocol) != installed_protocols.end()) { - continue; - } - if (protocolsWithoutInstallers.find(protocol) != - protocolsWithoutInstallers.end()) { - unresolved_deps.push_back(protocol); - continue; - } - load = false; - break; - } - - if (load) { - for (auto protocol : installers) { - installed_protocols.insert(protocol); - } - modulesSeq.insert(image); - json info; - info["image"] = image; - info["deps"] = deps; - if (unresolved_deps.size()) { - info["unresolved_deps"] = unresolved_deps; - } - modulesSequence[index++] = info; - changed = true; - } + if (!changed) { // we are in a loop, we need to load a module that installs the + // most popular protocol + std::map protocols_usage; // get the most popular protocol + for (auto &e : imagesInfo.items()) { + std::string image = e.key(); + + // check if the image is already loaded + if (modulesSeq.find(image) != modulesSeq.end()) { + continue; } - if (!changed) { // we are in a loop, we need to load a module that installs the - // most popular protocol - std::map - protocols_usage; // get the most popular protocol - for (auto &e : imagesInfo.items()) { - std::string image = e.key(); - - // check if the image is already loaded - if (modulesSeq.find(image) != modulesSeq.end()) { - continue; - } - - if (imagesInfo[image]["deps_protocols"].is_null()) { - continue; - } - - std::vector deps_protocols = - imagesInfo[image]["deps_protocols"]; - for (auto protocol : deps_protocols) { - if (installed_protocols.find(protocol) != installed_protocols.end()) { - continue; - } - if (protocolsWithoutInstallers.find(protocol) != - protocolsWithoutInstallers.end()) { - continue; - } - if (protocols_usage.find(protocol) == protocols_usage.end()) { - protocols_usage[protocol] = 1; - } else { - protocols_usage[protocol] += 1; - } - } - } - std::string mprotocol; - size_t mnum = 0; - for (auto const &[prot, counter] : protocols_usage) { - if (counter > mnum) { - mnum = static_cast(counter); - mprotocol = static_cast(prot); - } - } - if (!mnum) { - break; // the most popular protocol was not found - } - // find installer module for mprotocol - std::string installer_image = getInstaller(mprotocol); - if (!installer_image.size()) { - msg("Can not find installer for protocol %s\n", mprotocol.c_str()); - break; // something went wrong, extra mitigation for an infinite loop - } - // load installer_image - std::vector current_installers = - imagesInfo[installer_image]["installed_protocols"]; - for (auto protocol : current_installers) { - installed_protocols.insert(protocol); - } - modulesSeq.insert(installer_image); - json info; - info["image"] = installer_image; - info["deps"] = imagesInfo[installer_image]["deps_protocols"]; - modulesSequence[index++] = info; + if (imagesInfo[image]["deps_protocols"].is_null()) { + continue; } + + std::vector deps_protocols = imagesInfo[image]["deps_protocols"]; + for (auto protocol : deps_protocols) { + if (installed_protocols.find(protocol) != installed_protocols.end()) { + continue; + } + if (protocolsWithoutInstallers.find(protocol) != + protocolsWithoutInstallers.end()) { + continue; + } + if (protocols_usage.find(protocol) == protocols_usage.end()) { + protocols_usage[protocol] = 1; + } else { + protocols_usage[protocol] += 1; + } + } + } + std::string mprotocol; + size_t mnum = 0; + for (auto const &[prot, counter] : protocols_usage) { + if (counter > mnum) { + mnum = static_cast(counter); + mprotocol = static_cast(prot); + } + } + if (!mnum) { + break; // the most popular protocol was not found + } + // find installer module for mprotocol + std::string installer_image = getInstaller(mprotocol); + if (!installer_image.size()) { + msg("Can not find installer for protocol %s\n", mprotocol.c_str()); + break; // something went wrong, extra mitigation for an infinite loop + } + // load installer_image + std::vector current_installers = + imagesInfo[installer_image]["installed_protocols"]; + for (auto protocol : current_installers) { + installed_protocols.insert(protocol); + } + modulesSeq.insert(installer_image); + json info; + info["image"] = installer_image; + info["deps"] = imagesInfo[installer_image]["deps_protocols"]; + modulesSequence[index++] = info; } + } - return true; + return true; } diff --git a/efiXplorer/efiDeps.h b/efiXplorer/efiDeps.h index d841a212..4d79881c 100644 --- a/efiXplorer/efiDeps.h +++ b/efiXplorer/efiDeps.h @@ -1,6 +1,6 @@ /* * efiXplorer - * Copyright (C) 2020-2023 Binarly + * Copyright (C) 2020-2024 Binarly * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -24,35 +24,35 @@ #include "efiUtils.h" class EfiDependencies { - public: - EfiDependencies(); - ~EfiDependencies(); - json protocolsByGuids; // protocols sorted by GUIDs - json protocolsChooser; // numbered json with protocols - json uefitoolDeps; - json imagesGuids; - json additionalInstallers; // getAdditionalInstallers result - json imagesInfo; // getImagesInfo result - json modulesSequence; // buildModulesSequence result - std::vector imagesFromIdb; - std::set untrackedProtocols; - // Input: protocols from report - void getProtocolsByGuids(std::vector protocols); - void getProtocolsChooser(std::vector protocols); - json getDeps(std::string protocol); // get dependencies for specific protocol - void getAdditionalInstallers(); // get installers by protocol GUIDs by searching in - // the firmware and analyzing xrefs - bool buildModulesSequence(); - bool getImagesInfo(); +public: + EfiDependencies(); + ~EfiDependencies(); + json protocolsByGuids; // protocols sorted by GUIDs + json protocolsChooser; // numbered json with protocols + json uefitoolDeps; + json imagesGuids; + json additionalInstallers; // getAdditionalInstallers result + json imagesInfo; // getImagesInfo result + json modulesSequence; // buildModulesSequence result + std::vector imagesFromIdb; + std::set untrackedProtocols; + // Input: protocols from report + void getProtocolsByGuids(std::vector protocols); + void getProtocolsChooser(std::vector protocols); + json getDeps(std::string protocol); // get dependencies for specific protocol + void getAdditionalInstallers(); // get installers by protocol GUIDs by searching in + // the firmware and analyzing xrefs + bool buildModulesSequence(); + bool getImagesInfo(); - private: - void getImages(); - std::set protocolsWithoutInstallers; - void getProtocolsWithoutInstallers(); - void getInstallersModules(); - bool loadDepsFromUefiTool(); - bool loadImagesWithGuids(); - bool installerFound(std::string protocol); - json getImageInfo(std::string image); - std::string getInstaller(std::string protocol); +private: + void getImages(); + std::set protocolsWithoutInstallers; + void getProtocolsWithoutInstallers(); + void getInstallersModules(); + bool loadDepsFromUefiTool(); + bool loadImagesWithGuids(); + bool installerFound(std::string protocol); + json getImageInfo(std::string image); + std::string getInstaller(std::string protocol); }; diff --git a/efiXplorer/efiGlobal.cpp b/efiXplorer/efiGlobal.cpp index fdcdf5aa..1089359c 100644 --- a/efiXplorer/efiGlobal.cpp +++ b/efiXplorer/efiGlobal.cpp @@ -1,6 +1,6 @@ /* * efiXplorer - * Copyright (C) 2020-2023 Binarly + * Copyright (C) 2020-2024 Binarly * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,6 +19,6 @@ * */ -#include "efiGlobal.h" +#include "efiDeps.h" EfiDependencies g_deps; diff --git a/efiXplorer/efiGlobal.h b/efiXplorer/efiGlobal.h index 7eef356f..788a3e2f 100644 --- a/efiXplorer/efiGlobal.h +++ b/efiXplorer/efiGlobal.h @@ -1,6 +1,6 @@ /* * efiXplorer - * Copyright (C) 2020-2023 Binarly + * Copyright (C) 2020-2024 Binarly * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -23,13 +23,11 @@ #include "efiDeps.h" -enum module_types { DXE_SMM = 0, PEI = 1 }; +typedef struct args { + int module_type; + int disable_ui; + int disable_vuln_hunt; +} args_t; -struct args { - int module_type; - int disable_ui; - int disable_vuln_hunt; -}; - -extern struct args g_args; +extern args_t g_args; extern EfiDependencies g_deps; diff --git a/efiXplorer/efiHexRays.cpp b/efiXplorer/efiHexRays.cpp index de6fb8a3..4d4444d5 100644 --- a/efiXplorer/efiHexRays.cpp +++ b/efiXplorer/efiHexRays.cpp @@ -1,6 +1,6 @@ /* * efiXplorer - * Copyright (C) 2020-2023 Binarly, Rolf Rolles + * Copyright (C) 2020-2024 Binarly, Rolf Rolles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -24,101 +24,101 @@ // Given a tinfo_t specifying a user-defined type (UDT), look up the specified // field by its name, and retrieve its offset. bool offsetOf(tinfo_t tif, const char *name, unsigned int *offset) { - // Get the udt details - udt_type_data_t udt; - if (!tif.get_udt_details(&udt)) { - qstring str; - tif.get_type_name(&str); - return false; - } + // Get the udt details + udt_type_data_t udt; + if (!tif.get_udt_details(&udt)) { + qstring str; + tif.get_type_name(&str); + return false; + } - // Find the udt member + // Find the udt member #if IDA_SDK_VERSION < 840 - udt_member_t udm; - udm.name = name; - int fIdx = tif.find_udt_member(&udm, STRMEM_NAME); + udt_member_t udm; + udm.name = name; + int fIdx = tif.find_udt_member(&udm, STRMEM_NAME); #else - udm_t udm; - udm.name = name; - int fIdx = tif.find_udm(&udm, STRMEM_NAME); + udm_t udm; + udm.name = name; + int fIdx = tif.find_udm(&udm, STRMEM_NAME); #endif - if (fIdx < 0) { - qstring tstr; - tif.get_type_name(&tstr); - return false; - } + if (fIdx < 0) { + qstring tstr; + tif.get_type_name(&tstr); + return false; + } - // Get the offset of the field - *offset = static_cast(udt.at(fIdx).offset >> 3ULL); - return true; + // Get the offset of the field + *offset = static_cast(udt.at(fIdx).offset >> 3ULL); + return true; } // Utility function to set a Hex-Rays variable type and set types for the interfaces bool setHexRaysVariableInfoAndHandleInterfaces(ea_t func_addr, lvar_t &ll, tinfo_t tif, std::string name) { - lvar_saved_info_t lsi; - lsi.ll = ll; - lsi.type = tif; - modify_user_lvar_info(func_addr, MLI_TYPE, lsi); + lvar_saved_info_t lsi; + lsi.ll = ll; + lsi.type = tif; + modify_user_lvar_info(func_addr, MLI_TYPE, lsi); - // Set lvar name - if (ll.is_stk_var()) { // Rename local variable on stack + // Set lvar name + if (ll.is_stk_var()) { // Rename local variable on stack #if IDA_SDK_VERSION < 900 - sval_t stkoff = ll.get_stkoff(); - struc_t *frame = get_frame(func_addr); - set_member_name(frame, stkoff, name.c_str()); -#endif // TODO: add support for idasdk90 - } else { // Modufy user lvar info - lsi.name = static_cast(name.c_str()); - modify_user_lvar_info(func_addr, MLI_NAME, lsi); - } - - // Get xrefs to local variable - xreflist_t xrefs = xrefsToStackVar(func_addr, static_cast(name.c_str())); - qstring typeName; - ptr_type_data_t pi; - tif.get_ptr_details(&pi); - pi.obj_type.get_type_name(&typeName); - // Handling all interface functions (to rename function arguments) - opstroffForInterface(xrefs, typeName); - - return true; + sval_t stkoff = ll.get_stkoff(); + struc_t *frame = get_frame(func_addr); + set_member_name(frame, stkoff, name.c_str()); +#endif // TODO: add support for idasdk90 + } else { // Modufy user lvar info + lsi.name = static_cast(name.c_str()); + modify_user_lvar_info(func_addr, MLI_NAME, lsi); + } + + // Get xrefs to local variable + xreflist_t xrefs = xrefsToStackVar(func_addr, static_cast(name.c_str())); + qstring typeName; + ptr_type_data_t pi; + tif.get_ptr_details(&pi); + pi.obj_type.get_type_name(&typeName); + // Handling all interface functions (to rename function arguments) + opstroffForInterface(xrefs, typeName); + + return true; } // Utility function to set a Hex-Rays variable name bool setLvarName(qstring name, lvar_t lvar, ea_t func_addr) { - lvar_saved_info_t lsi; - lvar_uservec_t lvuv; + lvar_saved_info_t lsi; + lvar_uservec_t lvuv; - lsi.ll = lvar; - lsi.name = name; - if (!lvuv.lvvec.add_unique(lsi)) { - return false; - } - save_user_lvar_settings(func_addr, lvuv); - return true; + lsi.ll = lvar; + lsi.name = name; + if (!lvuv.lvvec.add_unique(lsi)) { + return false; + } + save_user_lvar_settings(func_addr, lvuv); + return true; } // Utility function to set a Hex-Rays variable type and name bool setHexRaysVariableInfo(ea_t func_addr, lvar_t &ll, tinfo_t tif, std::string name) { - lvar_saved_info_t lsi; - lsi.ll = ll; - lsi.type = tif; - modify_user_lvar_info(func_addr, MLI_TYPE, lsi); + lvar_saved_info_t lsi; + lsi.ll = ll; + lsi.type = tif; + modify_user_lvar_info(func_addr, MLI_TYPE, lsi); - // Set lvar name - if (ll.is_stk_var()) { // Rename local variable on stack + // Set lvar name + if (ll.is_stk_var()) { // Rename local variable on stack #if IDA_SDK_VERSION < 900 - sval_t stkoff = ll.get_stkoff(); - struc_t *frame = get_frame(func_addr); - set_member_name(frame, stkoff, name.c_str()); -#endif // TODO: add support for idasdk90 - } else { // Modufy user lvar info - lsi.name = static_cast(name.c_str()); - modify_user_lvar_info(func_addr, MLI_NAME, lsi); - } - - return true; + sval_t stkoff = ll.get_stkoff(); + struc_t *frame = get_frame(func_addr); + set_member_name(frame, stkoff, name.c_str()); +#endif // TODO: add support for idasdk90 + } else { // Modufy user lvar info + lsi.name = static_cast(name.c_str()); + modify_user_lvar_info(func_addr, MLI_NAME, lsi); + } + + return true; } // I added this bit of logic when I noticed that sometimes Hex-Rays will @@ -130,298 +130,298 @@ bool setHexRaysVariableInfo(ea_t func_addr, lvar_t &ll, tinfo_t tif, std::string // caller to specify the maximum depth "depth" of the pointers. E.g. at // depth 1, "int *[10]" is acceptable. At depth 2, "int **[10]" is acceptable. bool isPODArray(tinfo_t tif, unsigned int ptrDepth = 0) { - // If it's not an array, we're done - if (!tif.is_array()) - return false; + // If it's not an array, we're done + if (!tif.is_array()) + return false; - qstring tstr; + qstring tstr; - // If it is an array, we should be able to get its array details. - array_type_data_t atd; - if (!tif.get_array_details(&atd)) { - tif.get_type_name(&tstr); - return false; - } + // If it is an array, we should be able to get its array details. + array_type_data_t atd; + if (!tif.get_array_details(&atd)) { + tif.get_type_name(&tstr); + return false; + } - // Get the element type from the array - tinfo_t et = atd.elem_type; + // Get the element type from the array + tinfo_t et = atd.elem_type; - // Start off with depth + 1, so the loop will execute at least once - int iDepth = ptrDepth + 1; + // Start off with depth + 1, so the loop will execute at least once + int iDepth = ptrDepth + 1; - // Loop over the user-specified depth - while (iDepth > 0) { + // Loop over the user-specified depth + while (iDepth > 0) { - // Use typeid last checks. I should clean this up; I'm sure I can get rid - // of one of them. - bool b1 = is_typeid_last(et.get_realtype()); - bool b2 = et.is_decl_last(); + // Use typeid last checks. I should clean this up; I'm sure I can get rid + // of one of them. + bool b1 = is_typeid_last(et.get_realtype()); + bool b2 = et.is_decl_last(); - // Debug printing - et.get_type_name(&tstr); + // Debug printing + et.get_type_name(&tstr); - // If it was an integer type, return true - if (b1 || b2) - return true; + // If it was an integer type, return true + if (b1 || b2) + return true; - // Otherwise, this is where the "pointer depth" comes in. - // If we haven't exhausted the pointer depth, - if (--iDepth > 0) { - // Remove one layer of indirection from the element type - if (et.is_ptr()) - et = remove_pointer(et); + // Otherwise, this is where the "pointer depth" comes in. + // If we haven't exhausted the pointer depth, + if (--iDepth > 0) { + // Remove one layer of indirection from the element type + if (et.is_ptr()) + et = remove_pointer(et); - // Unless it's not a pointer, then return false. - else - return false; - } + // Unless it's not a pointer, then return false. + else + return false; } + } - // If the array wasn't pointers of POD types up to the specified depth, we - // failed. Return false. - return false; + // If the array wasn't pointers of POD types up to the specified depth, we + // failed. Return false. + return false; } // Utility function to get a printable qstring from a cexpr_t const char *Expr2String(cexpr_t *e, qstring *out) { - e->print1(out, NULL); - tag_remove(out); - return out->c_str(); + e->print1(out, NULL); + tag_remove(out); + return out->c_str(); } bool applyAllTypesForInterfacesBootServices(std::vector protocols) { - if (!init_hexrays_plugin()) { - return false; - } - - // Descriptors for EFI_BOOT_SERVICES functions - struct TargetFunctionPointer BootServicesFunctions[5]{ - {"InstallProtocolInterface", 0x80, 4, 1, 3}, - {"HandleProtocol", 0x98, 3, 1, 2}, - {"OpenProtocol", 0x118, 6, 1, 2}, - {"LocateProtocol", 0x140, 3, 0, 2}, - {"InstallMultipleProtocolInterfaces", 0x148, 4, 1, 2}}; + if (!init_hexrays_plugin()) { + return false; + } - // Initialize - ServiceDescriptor sdBs; - sdBs.Initialize("EFI_BOOT_SERVICES", BootServicesFunctions, 5); + // Descriptors for EFI_BOOT_SERVICES functions + struct TargetFunctionPointer BootServicesFunctions[5]{ + {"InstallProtocolInterface", 0x80, 4, 1, 3}, + {"HandleProtocol", 0x98, 3, 1, 2}, + {"OpenProtocol", 0x118, 6, 1, 2}, + {"LocateProtocol", 0x140, 3, 0, 2}, + {"InstallMultipleProtocolInterfaces", 0x148, 4, 1, 2}}; - ServiceDescriptorMap mBs; - mBs.Register(sdBs); + // Initialize + ServiceDescriptor sdBs; + sdBs.Initialize("EFI_BOOT_SERVICES", BootServicesFunctions, 5); - GUIDRetyper retyperBs(mBs); - retyperBs.SetProtocols(protocols); + ServiceDescriptorMap mBs; + mBs.Register(sdBs); - // Handle all protocols - for (auto protocol : protocols) { - auto code_addr = protocol["ea"]; - auto service = protocol["service"]; + GUIDRetyper retyperBs(mBs); + retyperBs.SetProtocols(protocols); - func_t *f = get_func(code_addr); - if (f == nullptr) { - continue; - } + // Handle all protocols + for (auto protocol : protocols) { + auto code_addr = protocol["ea"]; + auto service = protocol["service"]; - retyperBs.SetCodeEa(code_addr); - retyperBs.SetFuncEa(f->start_ea); + func_t *f = get_func(code_addr); + if (f == nullptr) { + continue; + } - hexrays_failure_t hf; - cfuncptr_t cfunc = decompile(f, &hf, DECOMP_NO_WAIT); + retyperBs.SetCodeEa(code_addr); + retyperBs.SetFuncEa(f->start_ea); - // Сheck that the function is decompiled - if (cfunc == nullptr) { - continue; - } + hexrays_failure_t hf; + cfuncptr_t cfunc = decompile(f, &hf, DECOMP_NO_WAIT); - retyperBs.apply_to(&cfunc->body, nullptr); + // Сheck that the function is decompiled + if (cfunc == nullptr) { + continue; } - return true; + retyperBs.apply_to(&cfunc->body, nullptr); + } + + return true; } bool applyAllTypesForInterfacesSmmServices(std::vector protocols) { - if (!init_hexrays_plugin()) { - return false; - } - - // Descriptors for _EFI_SMM_SYSTEM_TABLE2 functions - struct TargetFunctionPointer SmmServicesFunctions[2]{ - {"SmmHandleProtocol", 0xb8, 3, 1, 2}, - {"SmmLocateProtocol", 0xd0, 3, 0, 2}, - }; - - // Initialize - ServiceDescriptor sdSmm; - sdSmm.Initialize("_EFI_SMM_SYSTEM_TABLE2", SmmServicesFunctions, 2); - - ServiceDescriptorMap mSmm; - mSmm.Register(sdSmm); - - GUIDRetyper retyperSmm(mSmm); - retyperSmm.SetProtocols(protocols); + if (!init_hexrays_plugin()) { + return false; + } - // Handle all protocols - for (auto protocol : protocols) { - auto code_addr = protocol["ea"]; - auto service = protocol["service"]; + // Descriptors for _EFI_SMM_SYSTEM_TABLE2 functions + struct TargetFunctionPointer SmmServicesFunctions[2]{ + {"SmmHandleProtocol", 0xb8, 3, 1, 2}, + {"SmmLocateProtocol", 0xd0, 3, 0, 2}, + }; - func_t *f = get_func(code_addr); - if (f == nullptr) { - continue; - } + // Initialize + ServiceDescriptor sdSmm; + sdSmm.Initialize("_EFI_SMM_SYSTEM_TABLE2", SmmServicesFunctions, 2); - retyperSmm.SetCodeEa(code_addr); - retyperSmm.SetFuncEa(f->start_ea); + ServiceDescriptorMap mSmm; + mSmm.Register(sdSmm); - hexrays_failure_t hf; - cfuncptr_t cfunc = decompile(f, &hf, DECOMP_NO_WAIT); + GUIDRetyper retyperSmm(mSmm); + retyperSmm.SetProtocols(protocols); - // Сheck that the function is decompiled - if (cfunc == nullptr) { - continue; - } + // Handle all protocols + for (auto protocol : protocols) { + auto code_addr = protocol["ea"]; + auto service = protocol["service"]; - retyperSmm.apply_to(&cfunc->body, nullptr); + func_t *f = get_func(code_addr); + if (f == nullptr) { + continue; } - return true; -} - -uint8_t VariablesInfoExtractAll(func_t *f, ea_t code_addr) { - if (!init_hexrays_plugin()) { - return 0xff; - } + retyperSmm.SetCodeEa(code_addr); + retyperSmm.SetFuncEa(f->start_ea); - // check func - if (f == nullptr) { - return 0xff; - } - VariablesInfoExtractor extractor(code_addr); hexrays_failure_t hf; cfuncptr_t cfunc = decompile(f, &hf, DECOMP_NO_WAIT); + // Сheck that the function is decompiled if (cfunc == nullptr) { - return 0xff; + continue; } - extractor.apply_to(&cfunc->body, nullptr); - auto res = extractor.mAttributes; - return res; + + retyperSmm.apply_to(&cfunc->body, nullptr); + } + + return true; } -bool TrackEntryParams(func_t *f, uint8_t depth) { - if (!init_hexrays_plugin()) { - return false; - } +uint8_t VariablesInfoExtractAll(func_t *f, ea_t code_addr) { + if (!init_hexrays_plugin()) { + return 0xff; + } + + // check func + if (f == nullptr) { + return 0xff; + } + VariablesInfoExtractor extractor(code_addr); + hexrays_failure_t hf; + cfuncptr_t cfunc = decompile(f, &hf, DECOMP_NO_WAIT); + // Сheck that the function is decompiled + if (cfunc == nullptr) { + return 0xff; + } + extractor.apply_to(&cfunc->body, nullptr); + auto res = extractor.mAttributes; + return res; +} - if (depth == 2) { - return true; - } - // check func - if (f == nullptr) { - return false; - } - hexrays_failure_t hf; - cfuncptr_t cfunc = decompile(f, &hf, DECOMP_NO_WAIT); - if (cfunc == nullptr) { - return false; - } - PrototypesFixer *pf = new PrototypesFixer(); - pf->apply_to(&cfunc->body, nullptr); - for (auto addr : pf->child_functions) { - TrackEntryParams(get_func(addr), ++depth); - } - delete pf; +bool TrackEntryParams(func_t *f, uint8_t depth) { + if (!init_hexrays_plugin()) { + return false; + } + if (depth == 2) { return true; + } + // check func + if (f == nullptr) { + return false; + } + hexrays_failure_t hf; + cfuncptr_t cfunc = decompile(f, &hf, DECOMP_NO_WAIT); + if (cfunc == nullptr) { + return false; + } + PrototypesFixer *pf = new PrototypesFixer(); + pf->apply_to(&cfunc->body, nullptr); + for (auto addr : pf->child_functions) { + TrackEntryParams(get_func(addr), ++depth); + } + delete pf; + + return true; } json DetectVars(func_t *f) { - json res; + json res; - if (!init_hexrays_plugin()) { - return res; - } + if (!init_hexrays_plugin()) { + return res; + } - // check func - if (f == nullptr) { - return res; - } - VariablesDetector vars_detector; - hexrays_failure_t hf; - cfuncptr_t cfunc = decompile(f, &hf, DECOMP_NO_WAIT); - if (cfunc == nullptr) { - return res; - } + // check func + if (f == nullptr) { + return res; + } + VariablesDetector vars_detector; + hexrays_failure_t hf; + cfuncptr_t cfunc = decompile(f, &hf, DECOMP_NO_WAIT); + if (cfunc == nullptr) { + return res; + } - vars_detector.SetFuncEa(f->start_ea); - vars_detector.apply_to(&cfunc->body, nullptr); + vars_detector.SetFuncEa(f->start_ea); + vars_detector.apply_to(&cfunc->body, nullptr); - res["gImageHandleList"] = vars_detector.gImageHandleList; - res["gStList"] = vars_detector.gStList; - res["gBsList"] = vars_detector.gBsList; - res["gRtList"] = vars_detector.gRtList; + res["gImageHandleList"] = vars_detector.gImageHandleList; + res["gStList"] = vars_detector.gStList; + res["gBsList"] = vars_detector.gBsList; + res["gRtList"] = vars_detector.gRtList; - return res; + return res; } std::vector DetectServices(func_t *f) { - // check func - std::vector res; + // check func + std::vector res; - if (!init_hexrays_plugin()) { - return res; - } + if (!init_hexrays_plugin()) { + return res; + } - if (f == nullptr) { - return res; - } - ServicesDetector services_detector; - hexrays_failure_t hf; - cfuncptr_t cfunc = decompile(f, &hf, DECOMP_NO_WAIT); - if (cfunc == nullptr) { - return res; - } - services_detector.apply_to(&cfunc->body, nullptr); - return services_detector.services; + if (f == nullptr) { + return res; + } + ServicesDetector services_detector; + hexrays_failure_t hf; + cfuncptr_t cfunc = decompile(f, &hf, DECOMP_NO_WAIT); + if (cfunc == nullptr) { + return res; + } + services_detector.apply_to(&cfunc->body, nullptr); + return services_detector.services; } bool DetectPeiServices(func_t *f) { - if (!init_hexrays_plugin()) { - return false; - } + if (!init_hexrays_plugin()) { + return false; + } - if (f == nullptr) { - return false; - } + if (f == nullptr) { + return false; + } - PeiServicesDetector pei_services_detector; - hexrays_failure_t hf; - cfuncptr_t cfunc = decompile(f, &hf, DECOMP_NO_WAIT); - if (cfunc == nullptr) { - return false; - } - pei_services_detector.apply_to(&cfunc->body, nullptr); + PeiServicesDetector pei_services_detector; + hexrays_failure_t hf; + cfuncptr_t cfunc = decompile(f, &hf, DECOMP_NO_WAIT); + if (cfunc == nullptr) { + return false; + } + pei_services_detector.apply_to(&cfunc->body, nullptr); - return true; + return true; } std::vector DetectPeiServicesArm(func_t *f) { - std::vector res; + std::vector res; - if (!init_hexrays_plugin()) { - return res; - } + if (!init_hexrays_plugin()) { + return res; + } - if (f == nullptr) { - return res; - } + if (f == nullptr) { + return res; + } - PeiServicesDetectorArm pei_services_detector_arm; - hexrays_failure_t hf; - cfuncptr_t cfunc = decompile(f, &hf, DECOMP_NO_WAIT); - if (cfunc == nullptr) { - return res; - } - pei_services_detector_arm.apply_to(&cfunc->body, nullptr); - return pei_services_detector_arm.services; + PeiServicesDetectorArm pei_services_detector_arm; + hexrays_failure_t hf; + cfuncptr_t cfunc = decompile(f, &hf, DECOMP_NO_WAIT); + if (cfunc == nullptr) { + return res; + } + pei_services_detector_arm.apply_to(&cfunc->body, nullptr); + return pei_services_detector_arm.services; } diff --git a/efiXplorer/efiHexRays.h b/efiXplorer/efiHexRays.h index 3eeb9bd2..ff6e176d 100644 --- a/efiXplorer/efiHexRays.h +++ b/efiXplorer/efiHexRays.h @@ -1,6 +1,6 @@ /* * efiXplorer - * Copyright (C) 2020-2023 Binarly, Rolf Rolles + * Copyright (C) 2020-2024 Binarly, Rolf Rolles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -43,102 +43,102 @@ const char *Expr2String(cexpr_t *e, qstring *out); // plugin is looking for calls to specific UEFI functions. This structure // describes basic information about those functions: struct TargetFunctionPointer { - const char *name; // Name of function pointer in structure - int offset; // Offset of function pointer (filled in later) - unsigned int nArgs; // Number of expected arguments - unsigned int nGUIDArg; // Which argument has the EFI_GUID * - unsigned int nOutArg; // Which argument retrieves the output + const char *name; // Name of function pointer in structure + int offset; // Offset of function pointer (filled in later) + unsigned int nArgs; // Number of expected arguments + unsigned int nGUIDArg; // Which argument has the EFI_GUID * + unsigned int nOutArg; // Which argument retrieves the output }; // This class holds all function pointer descriptors for one structure, as well // as providing a utility to look up function pointers by offset. class ServiceDescriptor { - // Instance data - protected: - // The type of the containing structure (e.g. EFI_BOOT_SERVICES) - tinfo_t mType; - - // The name of the type (e.g. "EFI_BOOT_SERVICES") - qstring mName; - - // The ordinal of the type (e.g. 4) - uint32 mOrdinal; - - // A vector of the structures above, copied, and with the offsets filled in - std::vector mTargets; - - bool bInitialized; - - // Ensure we can look up the type that this instance describes - bool InitType(const char *name) { - // Import type - import_type(get_idati(), -1, name); - - // Get type by name - if (!mType.get_named_type(get_idati(), name)) - return false; - - // Save ordinal and name - mOrdinal = mType.get_ordinal(); - mName = name; - return true; + // Instance data +protected: + // The type of the containing structure (e.g. EFI_BOOT_SERVICES) + tinfo_t mType; + + // The name of the type (e.g. "EFI_BOOT_SERVICES") + qstring mName; + + // The ordinal of the type (e.g. 4) + uint32 mOrdinal; + + // A vector of the structures above, copied, and with the offsets filled in + std::vector mTargets; + + bool bInitialized; + + // Ensure we can look up the type that this instance describes + bool InitType(const char *name) { + // Import type + import_type(get_idati(), -1, name); + + // Get type by name + if (!mType.get_named_type(get_idati(), name)) + return false; + + // Save ordinal and name + mOrdinal = mType.get_ordinal(); + mName = name; + return true; + } + + // Look up the offsets for all function pointer targets; save the results + // in the vector. Return false if offset lookup fails. + bool InitTargets(TargetFunctionPointer *targets, size_t num) { + // Iterate through all targets + for (int i = 0; i < num; ++i) { + + // Copy the target structure into our local vector + TargetFunctionPointer &tgt = mTargets.emplace_back(); + tgt = targets[i]; + + // Retrieve the offsets of each named function pointer + unsigned int offset; + if (!offsetOf(mType, targets[i].name, &offset)) { + return false; + } } - - // Look up the offsets for all function pointer targets; save the results - // in the vector. Return false if offset lookup fails. - bool InitTargets(TargetFunctionPointer *targets, size_t num) { - // Iterate through all targets - for (int i = 0; i < num; ++i) { - - // Copy the target structure into our local vector - TargetFunctionPointer &tgt = mTargets.emplace_back(); - tgt = targets[i]; - - // Retrieve the offsets of each named function pointer - unsigned int offset; - if (!offsetOf(mType, targets[i].name, &offset)) { - return false; - } - } + return true; + } + +public: + // Constructor does nothing + ServiceDescriptor() : mOrdinal(0), bInitialized(false) {}; + + // Accessor for ordinal + uint32 GetOrdinal() { return mOrdinal; }; + + // Accessor for name + const char *GetName() { return mName.c_str(); }; + + // Needs to be called before the object can be used + bool Initialize(const char *name, TargetFunctionPointer *targets, size_t num) { + if (bInitialized) + return true; + bInitialized = InitType(name) && InitTargets(targets, num); + return bInitialized; + } + + // After initialization, look up a target by offset + bool LookupOffset(unsigned int offset, TargetFunctionPointer **tgt) { + // Iterating through a vector generally is inefficient compared to a map, + // but there are at most 3 function pointers so far, so it outweighs the + // overhead of the associative containers. + for (auto &it : mTargets) { + // Match by offset + if (it.offset == offset) { + *tgt = ⁢ return true; + } } - - public: - // Constructor does nothing - ServiceDescriptor() : mOrdinal(0), bInitialized(false) {}; - - // Accessor for ordinal - uint32 GetOrdinal() { return mOrdinal; }; - - // Accessor for name - const char *GetName() { return mName.c_str(); }; - - // Needs to be called before the object can be used - bool Initialize(const char *name, TargetFunctionPointer *targets, size_t num) { - if (bInitialized) - return true; - bInitialized = InitType(name) && InitTargets(targets, num); - return bInitialized; - } - - // After initialization, look up a target by offset - bool LookupOffset(unsigned int offset, TargetFunctionPointer **tgt) { - // Iterating through a vector generally is inefficient compared to a map, - // but there are at most 3 function pointers so far, so it outweighs the - // overhead of the associative containers. - for (auto &it : mTargets) { - // Match by offset - if (it.offset == offset) { - *tgt = ⁢ - return true; - } - } - // If we don't find it, it's not necessarily "bad" from the point of view - // of the plugin's logic. After all, we're looking at every access to the - // selected structures, and so, quite rightly, we'll want to ignore the - // function pointers that we're not tracking. - return false; - } + // If we don't find it, it's not necessarily "bad" from the point of view + // of the plugin's logic. After all, we're looking at every access to the + // selected structures, and so, quite rightly, we'll want to ignore the + // function pointers that we're not tracking. + return false; + } }; // This class manages multiple instances of the class above. Each such @@ -148,1002 +148,999 @@ class ServiceDescriptor { // class looks up the ServiceDescriptor in a map by ordinal, and then looks up // the offset if that succeeded. class ServiceDescriptorMap { - protected: - // Our map for looking up ServiceDescriptor structures. I should probably - // change the value type to a pointer. - std::map mServices; - - public: - // Add a new ServiceDescriptor to the map. I should change the argument - // type to match whatever I change the value type of the map to. - bool Register(ServiceDescriptor sd) { - - // Get the ordinal from the ServiceDescriptor - uint32 ord = sd.GetOrdinal(); - - // Are we already tracking this structure? - if (mServices.find(ord) != mServices.end()) { - return false; - } - // If not, register it. Get rid of std::move - mServices[ord] = std::move(sd); - return true; +protected: + // Our map for looking up ServiceDescriptor structures. I should probably + // change the value type to a pointer. + std::map mServices; + +public: + // Add a new ServiceDescriptor to the map. I should change the argument + // type to match whatever I change the value type of the map to. + bool Register(ServiceDescriptor sd) { + + // Get the ordinal from the ServiceDescriptor + uint32 ord = sd.GetOrdinal(); + + // Are we already tracking this structure? + if (mServices.find(ord) != mServices.end()) { + return false; } - - // This function could be protected, but whatever. Given an ordinal, get - // the tracked ServiceDescriptor, if applicable. - bool LookupOrdinal(uint32 ord, ServiceDescriptor **sd) { - auto it = mServices.find(ord); - if (it == mServices.end()) { - return false; - } - *sd = &it->second; - return true; - } - - // This is the high-level function that clients call. Given a structure - // ordinal and offset of a function pointer, see if it's something we're - // tracking. If so, get pointers to the tracked objects and return true. - bool LookupOffset(uint32 ord, unsigned int offset, ServiceDescriptor **sd, - TargetFunctionPointer **tgt) { - if (!LookupOrdinal(ord, sd)) - return false; - if (!(*sd)->LookupOffset(offset, tgt)) - return false; - return true; + // If not, register it. Get rid of std::move + mServices[ord] = std::move(sd); + return true; + } + + // This function could be protected, but whatever. Given an ordinal, get + // the tracked ServiceDescriptor, if applicable. + bool LookupOrdinal(uint32 ord, ServiceDescriptor **sd) { + auto it = mServices.find(ord); + if (it == mServices.end()) { + return false; } + *sd = &it->second; + return true; + } + + // This is the high-level function that clients call. Given a structure + // ordinal and offset of a function pointer, see if it's something we're + // tracking. If so, get pointers to the tracked objects and return true. + bool LookupOffset(uint32 ord, unsigned int offset, ServiceDescriptor **sd, + TargetFunctionPointer **tgt) { + if (!LookupOrdinal(ord, sd)) + return false; + if (!(*sd)->LookupOffset(offset, tgt)) + return false; + return true; + } }; // Base class for two visitors that require similar functionality. Here we // collect all of the common data and functionality that will be used by both // of those visitors. This allows the derivatives to be very succinct. class GUIDRelatedVisitorBase : public ctree_visitor_t { - public: - // We need access to a ServiceDescriptorMap from above. - GUIDRelatedVisitorBase(ServiceDescriptorMap &m) - : ctree_visitor_t(CV_FAST), mDebug(true), mServices(m) {}; - - // We need the function ea when setting Hex-Rays variable types. - void SetFuncEa(ea_t ea) { mFuncEa = ea; }; - void SetCodeEa(ea_t ea) { mCodeEa = ea; }; - void SetProtocols(std::vector protocols) { mProtocols = protocols; }; - - protected: - // - // Persistent variables - // - - // Function address - ea_t mFuncEa; - ea_t mCodeEa; - - // Protocols - std::vector mProtocols; - - // Print debug messages? - bool mDebug = false; - - // Used for looking up calls to function pointers in structures - ServiceDescriptorMap &mServices; - - // - // State variables, cleared on every iteration. I debated with myself - // whether this was a nasty design decision. I think it's fine. These - // variables are only valid to access after the client has called - // ValidateCallAndGUID, and it returned true. If you called that and it - // returned false, these will be in an inconsistent state. Don't touch them - // if that's the case. - // - - // Address of the indirect function call - ea_t mEa; - - // The pointer type that's being accessed (that of the structure) - tinfo_t mTif; - - // The structure type, with the pointer indirection removed - tinfo_t mTifNoPtr; - - // The ServiceDescriptor for the containing structure - ServiceDescriptor *mpService; - - // The ordinal of the structure type - uint32 mOrdinal; - - // The offset of the function pointer in the structure - unsigned int mOffset; - - // Details about the target of the indirect call (e.g. name) - TargetFunctionPointer *mpTarget; - - // The list of arguments for the indirect call - carglist_t *mArgs; - - // The argument that specifies the GUID for the indirect call - cexpr_t *mGUIDArg; - - // The argument that gets the output for the indirect call - cexpr_t *mOutArg; - - // The GUID argument will be &x; this is x - cexpr_t *mGUIDArgRefTo; - - // The address of the GUID being passed to the indirect call - ea_t mGUIDEa; - - // This function clears all the state variables above. Technically, it - // doesn't need to exist, since the flow of logic in the functions below - // always write to them before reading to them. But, it seems like good - // programming practice not to have stale values, anyway. - void Clear() { - mEa = BADADDR; - mTif.clear(); - mTifNoPtr.clear(); - mpService = nullptr; - mOrdinal = 0; - mOffset = -1; - mpTarget = nullptr; - mArgs = nullptr; - mGUIDArg = nullptr; - mOutArg = nullptr; - mGUIDArgRefTo = nullptr; - mGUIDEa = BADADDR; - }; - - // Debug print, if the instance debug variable says to - void DebugPrint(const char *fmt, ...) { - va_list va; - va_start(va, fmt); - if (mDebug) - vmsg(fmt, va); - }; - - // This is the first function called every time the visitor visits an - // expression. This function determines if the expression is a call to a - // function pointer contained in a structure. - bool GetICallOrdAndOffset(cexpr_t *e) { - // Set instance variable for call address - mEa = e->ea; - - if (mEa != mCodeEa) { - return false; - } - - // If it's not a call, we're done. - if (e->op != cot_call) - return false; - - // Set instance variable with call arguments - mArgs = e->a; - - // If it's a direct call, we're done. - cexpr_t *callDest = e->x; - if (callDest->op == cot_obj) - return false; - - // Eat any casts on the type of what's being called - while (callDest->op == cot_cast) - callDest = callDest->x; - - // If the destination is not a member of a structure, we're done. - if (callDest->op != cot_memptr) - return false; - - // Set instance variable with type of structure containing pointer - mTif = callDest->x->type; +public: + // We need access to a ServiceDescriptorMap from above. + GUIDRelatedVisitorBase(ServiceDescriptorMap &m) + : ctree_visitor_t(CV_FAST), mDebug(true), mServices(m) {}; + + // We need the function ea when setting Hex-Rays variable types. + void SetFuncEa(ea_t ea) { mFuncEa = ea; }; + void SetCodeEa(ea_t ea) { mCodeEa = ea; }; + void SetProtocols(std::vector protocols) { mProtocols = protocols; }; + +protected: + // + // Persistent variables + // + + // Function address + ea_t mFuncEa; + ea_t mCodeEa; + + // Protocols + std::vector mProtocols; + + // Print debug messages? + bool mDebug = false; + + // Used for looking up calls to function pointers in structures + ServiceDescriptorMap &mServices; + + // + // State variables, cleared on every iteration. I debated with myself + // whether this was a nasty design decision. I think it's fine. These + // variables are only valid to access after the client has called + // ValidateCallAndGUID, and it returned true. If you called that and it + // returned false, these will be in an inconsistent state. Don't touch them + // if that's the case. + // + + // Address of the indirect function call + ea_t mEa; + + // The pointer type that's being accessed (that of the structure) + tinfo_t mTif; + + // The structure type, with the pointer indirection removed + tinfo_t mTifNoPtr; + + // The ServiceDescriptor for the containing structure + ServiceDescriptor *mpService; + + // The ordinal of the structure type + uint32 mOrdinal; + + // The offset of the function pointer in the structure + unsigned int mOffset; + + // Details about the target of the indirect call (e.g. name) + TargetFunctionPointer *mpTarget; + + // The list of arguments for the indirect call + carglist_t *mArgs; + + // The argument that specifies the GUID for the indirect call + cexpr_t *mGUIDArg; + + // The argument that gets the output for the indirect call + cexpr_t *mOutArg; + + // The GUID argument will be &x; this is x + cexpr_t *mGUIDArgRefTo; + + // The address of the GUID being passed to the indirect call + ea_t mGUIDEa; + + // This function clears all the state variables above. Technically, it + // doesn't need to exist, since the flow of logic in the functions below + // always write to them before reading to them. But, it seems like good + // programming practice not to have stale values, anyway. + void Clear() { + mEa = BADADDR; + mTif.clear(); + mTifNoPtr.clear(); + mpService = nullptr; + mOrdinal = 0; + mOffset = -1; + mpTarget = nullptr; + mArgs = nullptr; + mGUIDArg = nullptr; + mOutArg = nullptr; + mGUIDArgRefTo = nullptr; + mGUIDEa = BADADDR; + }; + + // Debug print, if the instance debug variable says to + void DebugPrint(const char *fmt, ...) { + va_list va; + va_start(va, fmt); + if (mDebug) + vmsg(fmt, va); + }; + + // This is the first function called every time the visitor visits an + // expression. This function determines if the expression is a call to a + // function pointer contained in a structure. + bool GetICallOrdAndOffset(cexpr_t *e) { + // Set instance variable for call address + mEa = e->ea; + + if (mEa != mCodeEa) { + return false; + } - // Ensure that the structure is being accessed via pointer, and not as a - // reference (i.e., through a structure held on the stack as a local - // variable). - if (!mTif.is_ptr()) { - return false; - } + // If it's not a call, we're done. + if (e->op != cot_call) + return false; - // Remove pointer from containing structure type, set instance variable - mTifNoPtr = remove_pointer(mTif); + // Set instance variable with call arguments + mArgs = e->a; - // Get the ordinal of the structure - mOrdinal = mTifNoPtr.get_ordinal(); + // If it's a direct call, we're done. + cexpr_t *callDest = e->x; + if (callDest->op == cot_obj) + return false; - // If we can't get a type for the structure, that's bad - if (mOrdinal == 0) - return false; + // Eat any casts on the type of what's being called + while (callDest->op == cot_cast) + callDest = callDest->x; - // Get the offset of the function pointer in the structure - mOffset = callDest->m; + // If the destination is not a member of a structure, we're done. + if (callDest->op != cot_memptr) + return false; - // Okay: now we know we're dealing with an indirect call to a function - // pointer contained in a structure, where the structure is being - // accessed by a pointer. - return true; - }; - - // This is the second function called as part of indirect call validation. - // Now we want to know: is it a call to something that we're tracking? - bool ValidateICallDestination() { - - // Look up the structure ordinal and function offset; get the associated - // ServiceDescriptor and TargetFunctionPointer (instance variables). - if (!mServices.LookupOffset(mOrdinal, mOffset, &mpService, &mpTarget)) - return false; - - // Great, it was something that we were tracking. Now, sanity-check the - // number of arguments on the function call. (Hex-Rays might have gotten - // this wrong. The user can fix it via "set call type".) - size_t mArgsSize = mArgs->size(); - size_t nArgs = mpTarget->nArgs; - if (mArgsSize != nArgs) { - return false; - } + // Set instance variable with type of structure containing pointer + mTif = callDest->x->type; - // The TargetFunctionPointer tells us which argument takes an EFI_GUID *, - // and which one retrieves the output. Get those arguments, and save them - // as instance variables. - mGUIDArg = &mArgs->at(mpTarget->nGUIDArg); - mOutArg = &mArgs->at(mpTarget->nOutArg); - - // Great; now we know that the expression is an indirect call to - // something that we're tracking, and that Hex-Rays decompiled the call - // the way we expected it to. - return true; - }; - - // This is a helper function used to get the thing being referred to. What - // does that mean? - // - // * For GUID arguments, we'll usually have &globvar. Return globvar. - // * For output arguments, we'll usually have &globvar or &locvar. Due to - // Hex-Rays internal heuristics, we might end up with "locarray", which - // does not actually have a "&" when passed as a call argument. There's - // a bit of extra logic to check for that case. - cexpr_t *GetReferent(cexpr_t *e, const char *desc, bool bAcceptVar) { - - // Eat casts - cexpr_t *x = e; - while (x->op == cot_cast) - x = x->x; - - qstring estr; - // If we're accepting local variables, and this is a variable (note: not - // a *reference* to a variable) - if (bAcceptVar && x->op == cot_var) { - // Get the variable details - var_ref_t varRef = x->v; - lvar_t destVar = varRef.mba->vars[varRef.idx]; - - // Ensure that it's an array of POD types, or pointers to them - bool bisPODArray = isPODArray(destVar.tif, 1); - - // If it is a POD array, good, we'll take it. - return bisPODArray ? x : nullptr; - } + // Ensure that the structure is being accessed via pointer, and not as a + // reference (i.e., through a structure held on the stack as a local + // variable). + if (!mTif.is_ptr()) { + return false; + } - // For everything else, we really want it to be a reference: either to a - // global or local variable. If it's not a reference, we can't get the - // referent, so fail. - if (x->op != cot_ref) { - return nullptr; - } + // Remove pointer from containing structure type, set instance variable + mTifNoPtr = remove_pointer(mTif); + + // Get the ordinal of the structure + mOrdinal = mTifNoPtr.get_ordinal(); + + // If we can't get a type for the structure, that's bad + if (mOrdinal == 0) + return false; + + // Get the offset of the function pointer in the structure + mOffset = callDest->m; + + // Okay: now we know we're dealing with an indirect call to a function + // pointer contained in a structure, where the structure is being + // accessed by a pointer. + return true; + }; + + // This is the second function called as part of indirect call validation. + // Now we want to know: is it a call to something that we're tracking? + bool ValidateICallDestination() { + + // Look up the structure ordinal and function offset; get the associated + // ServiceDescriptor and TargetFunctionPointer (instance variables). + if (!mServices.LookupOffset(mOrdinal, mOffset, &mpService, &mpTarget)) + return false; + + // Great, it was something that we were tracking. Now, sanity-check the + // number of arguments on the function call. (Hex-Rays might have gotten + // this wrong. The user can fix it via "set call type".) + size_t mArgsSize = mArgs->size(); + size_t nArgs = mpTarget->nArgs; + if (mArgsSize != nArgs) { + return false; + } - // If we get here, we know it's a reference. Return the referent. - return x->x; - }; - - // The third function in the validation logic. We already know the - // expression is an indirect call to something that we're tracking, and - // that Hex-Rays' decompilation matches on the number of arguments. Now, - // we validate that the GUID argument does in fact point to a global - // variable. - bool ValidateGUIDArgument() { - // Does the GUID argument point to a local variable? - mGUIDArgRefTo = GetReferent(mGUIDArg, "GUID", false); - if (!mGUIDArgRefTo) - return false; - - // If we get here, we know it was a reference to *something*. Ensure that - // something is a global variable. - if (mGUIDArgRefTo->op != cot_obj) { - return false; - } + // The TargetFunctionPointer tells us which argument takes an EFI_GUID *, + // and which one retrieves the output. Get those arguments, and save them + // as instance variables. + mGUIDArg = &mArgs->at(mpTarget->nGUIDArg); + mOutArg = &mArgs->at(mpTarget->nOutArg); + + // Great; now we know that the expression is an indirect call to + // something that we're tracking, and that Hex-Rays decompiled the call + // the way we expected it to. + return true; + }; + + // This is a helper function used to get the thing being referred to. What + // does that mean? + // + // * For GUID arguments, we'll usually have &globvar. Return globvar. + // * For output arguments, we'll usually have &globvar or &locvar. Due to + // Hex-Rays internal heuristics, we might end up with "locarray", which + // does not actually have a "&" when passed as a call argument. There's + // a bit of extra logic to check for that case. + cexpr_t *GetReferent(cexpr_t *e, const char *desc, bool bAcceptVar) { + + // Eat casts + cexpr_t *x = e; + while (x->op == cot_cast) + x = x->x; + + qstring estr; + // If we're accepting local variables, and this is a variable (note: not + // a *reference* to a variable) + if (bAcceptVar && x->op == cot_var) { + // Get the variable details + var_ref_t varRef = x->v; + lvar_t destVar = varRef.mba->vars[varRef.idx]; + + // Ensure that it's an array of POD types, or pointers to them + bool bisPODArray = isPODArray(destVar.tif, 1); + + // If it is a POD array, good, we'll take it. + return bisPODArray ? x : nullptr; + } - // Save the address of the global variable to which the GUID argument is - // pointing. - mGUIDEa = mGUIDArgRefTo->obj_ea; + // For everything else, we really want it to be a reference: either to a + // global or local variable. If it's not a reference, we can't get the + // referent, so fail. + if (x->op != cot_ref) { + return nullptr; + } - // Great; now we know we're dealing with an indirect call to something - // we're tracking; that Hex-Rays decompiled the call with the proper - // number of arguments; and that the GUID argument did in fact point to - // a global variable, whose address we now have in an instance variable. - return true; - }; - - // Finally, this function combines all three checks above into one single - // function. If you call this and it returns true, feel free to access the - // instance variables, as they are guaranteed to be valid. If it returns - // false, they aren't, so don't touch them. - bool ValidateCallAndGUID(cexpr_t *e) { - // Reset all instance variables. Not strictly necessary; call it - // "defensive programming". - Clear(); - - // Validate according to the logic above. - if (!GetICallOrdAndOffset(e) || !ValidateICallDestination() || - !ValidateGUIDArgument()) - return false; - - // Good, all checks passed - return true; + // If we get here, we know it's a reference. Return the referent. + return x->x; + }; + + // The third function in the validation logic. We already know the + // expression is an indirect call to something that we're tracking, and + // that Hex-Rays' decompilation matches on the number of arguments. Now, + // we validate that the GUID argument does in fact point to a global + // variable. + bool ValidateGUIDArgument() { + // Does the GUID argument point to a local variable? + mGUIDArgRefTo = GetReferent(mGUIDArg, "GUID", false); + if (!mGUIDArgRefTo) + return false; + + // If we get here, we know it was a reference to *something*. Ensure that + // something is a global variable. + if (mGUIDArgRefTo->op != cot_obj) { + return false; } + + // Save the address of the global variable to which the GUID argument is + // pointing. + mGUIDEa = mGUIDArgRefTo->obj_ea; + + // Great; now we know we're dealing with an indirect call to something + // we're tracking; that Hex-Rays decompiled the call with the proper + // number of arguments; and that the GUID argument did in fact point to + // a global variable, whose address we now have in an instance variable. + return true; + }; + + // Finally, this function combines all three checks above into one single + // function. If you call this and it returns true, feel free to access the + // instance variables, as they are guaranteed to be valid. If it returns + // false, they aren't, so don't touch them. + bool ValidateCallAndGUID(cexpr_t *e) { + // Reset all instance variables. Not strictly necessary; call it + // "defensive programming". + Clear(); + + // Validate according to the logic above. + if (!GetICallOrdAndOffset(e) || !ValidateICallDestination() || + !ValidateGUIDArgument()) + return false; + + // Good, all checks passed + return true; + } }; // Now that we've implemented all that validation logic, this class is pretty // simple. This one is responsible for ensuring that the GUID is something that // we know about, and setting the types of the output variables accordingly. class GUIDRetyper : public GUIDRelatedVisitorBase { - public: - GUIDRetyper(ServiceDescriptorMap &m) : GUIDRelatedVisitorBase(m), mNumApplied(0) {}; - - // This is the callback function that Hex-Rays invokes for every expression - // in the CTREE. - int visit_expr(cexpr_t *e) { - // Perform the checks from GUIDRelatedVisitorBase. If they fail, we're - // not equipped to deal with this expression, so bail out. - if (!ValidateCallAndGUID(e)) - return 0; - - mGUIDArgRefTo = GetReferent(mGUIDArg, "GUID", false); - if (mGUIDArgRefTo == nullptr) - return 0; - ea_t guidAddr = mGUIDArgRefTo->obj_ea; - - // Get interface type name - std::string GUIDName; - for (auto g : mProtocols) { - if (guidAddr == g["address"]) { - GUIDName = g["prot_name"]; - break; - } - } - if (GUIDName.empty()) { - return 0; - } - - std::string interfaceTypeName = GUIDName.substr(0, GUIDName.find("_GUID")); - if (!interfaceTypeName.find("FCH_")) { - // convert FCH_SMM_* dispatcher type to EFI_SMM_* dispatcher type - interfaceTypeName.replace(0, 4, "EFI_"); - } - - // Need to get the type for the interface variable here - tinfo_t tif; - import_type(get_idati(), -1, interfaceTypeName.c_str()); - if (!tif.get_named_type(get_idati(), interfaceTypeName.c_str())) { - // Get the referent for the interface argument. - cexpr_t *outArgReferent = GetReferent(mOutArg, "ptr", true); - if (outArgReferent == nullptr) - return 0; - ApplyName(outArgReferent, interfaceTypeName); - return 0; - } +public: + GUIDRetyper(ServiceDescriptorMap &m) : GUIDRelatedVisitorBase(m), mNumApplied(0) {}; + + // This is the callback function that Hex-Rays invokes for every expression + // in the CTREE. + int visit_expr(cexpr_t *e) { + // Perform the checks from GUIDRelatedVisitorBase. If they fail, we're + // not equipped to deal with this expression, so bail out. + if (!ValidateCallAndGUID(e)) + return 0; + + mGUIDArgRefTo = GetReferent(mGUIDArg, "GUID", false); + if (mGUIDArgRefTo == nullptr) + return 0; + ea_t guidAddr = mGUIDArgRefTo->obj_ea; + + // Get interface type name + std::string GUIDName; + for (auto g : mProtocols) { + if (guidAddr == g["address"]) { + GUIDName = g["prot_name"]; + break; + } + } + if (GUIDName.empty()) { + return 0; + } - qstring tStr; - if (!tif.get_type_name(&tStr)) { - return 0; - } + std::string interfaceTypeName = GUIDName.substr(0, GUIDName.find("_GUID")); + if (!interfaceTypeName.find("FCH_")) { + // convert FCH_SMM_* dispatcher type to EFI_SMM_* dispatcher type + interfaceTypeName.replace(0, 4, "EFI_"); + } - tinfo_t tifGuidPtr; - if (!tifGuidPtr.create_ptr(tif)) { - return 0; - } + // Need to get the type for the interface variable here + tinfo_t tif; + import_type(get_idati(), -1, interfaceTypeName.c_str()); + if (!tif.get_named_type(get_idati(), interfaceTypeName.c_str())) { + // Get the referent for the interface argument. + cexpr_t *outArgReferent = GetReferent(mOutArg, "ptr", true); + if (outArgReferent == nullptr) + return 0; + ApplyName(outArgReferent, interfaceTypeName); + return 0; + } - // Get the referent for the interface argument. - cexpr_t *outArgReferent = GetReferent(mOutArg, "ptr", true); - if (outArgReferent == nullptr) - return 0; + qstring tStr; + if (!tif.get_type_name(&tStr)) { + return 0; + } - // Apply the type to the output referent. - ApplyType(outArgReferent, tifGuidPtr, tStr); - return 1; + tinfo_t tifGuidPtr; + if (!tifGuidPtr.create_ptr(tif)) { + return 0; } - protected: - unsigned int mNumApplied; - - // Given an expression (either a local or global variable) and a type to - // apply, apply the type. This is just a bit of IDA/Hex-Rays type system - // skullduggery. - void ApplyType(cexpr_t *outArg, tinfo_t ptrTif, qstring tStr) { - ea_t dest_ea = outArg->obj_ea; - - // For global variables - if (outArg->op == cot_obj) { - // Just apply the type information to the address - apply_tinfo(dest_ea, ptrTif, TINFO_DEFINITE); - ++mNumApplied; - - // Rename global variable - auto name = "g" + typeToName(static_cast(tStr.c_str())); - set_name(dest_ea, name.c_str(), SN_FORCE); - - // Get xrefs to global variable - auto xrefs = getXrefs(dest_ea); - qstring typeName; - ptr_type_data_t pi; - ptrTif.get_ptr_details(&pi); - pi.obj_type.get_type_name(&typeName); - // Handling all interface functions (to rename function arguments) - opstroffForGlobalInterface(xrefs, typeName); - } + // Get the referent for the interface argument. + cexpr_t *outArgReferent = GetReferent(mOutArg, "ptr", true); + if (outArgReferent == nullptr) + return 0; + + // Apply the type to the output referent. + ApplyType(outArgReferent, tifGuidPtr, tStr); + return 1; + } + +protected: + unsigned int mNumApplied; + + // Given an expression (either a local or global variable) and a type to + // apply, apply the type. This is just a bit of IDA/Hex-Rays type system + // skullduggery. + void ApplyType(cexpr_t *outArg, tinfo_t ptrTif, qstring tStr) { + ea_t dest_ea = outArg->obj_ea; + + // For global variables + if (outArg->op == cot_obj) { + // Just apply the type information to the address + apply_tinfo(dest_ea, ptrTif, TINFO_DEFINITE); + ++mNumApplied; + + // Rename global variable + auto name = "g" + typeToName(static_cast(tStr.c_str())); + set_name(dest_ea, name.c_str(), SN_FORCE); + + // Get xrefs to global variable + auto xrefs = getXrefs(dest_ea); + qstring typeName; + ptr_type_data_t pi; + ptrTif.get_ptr_details(&pi); + pi.obj_type.get_type_name(&typeName); + // Handling all interface functions (to rename function arguments) + opstroffForGlobalInterface(xrefs, typeName); + } - // For local variables - else if (outArg->op == cot_var) { - var_ref_t varRef = outArg->v; - lvar_t &destVar = varRef.mba->vars[varRef.idx]; - // Set the Hex-Rays variable type - auto name = typeToName(static_cast(tStr.c_str())); - setLvarName(static_cast(name.c_str()), destVar, mFuncEa); - if (setHexRaysVariableInfoAndHandleInterfaces(mFuncEa, destVar, ptrTif, - name)) { - ++mNumApplied; - } - } + // For local variables + else if (outArg->op == cot_var) { + var_ref_t varRef = outArg->v; + lvar_t &destVar = varRef.mba->vars[varRef.idx]; + // Set the Hex-Rays variable type + auto name = typeToName(static_cast(tStr.c_str())); + setLvarName(static_cast(name.c_str()), destVar, mFuncEa); + if (setHexRaysVariableInfoAndHandleInterfaces(mFuncEa, destVar, ptrTif, name)) { + ++mNumApplied; + } } + } - void ApplyName(cexpr_t *outArg, std::string type_name) { - ea_t dest_ea = outArg->obj_ea; + void ApplyName(cexpr_t *outArg, std::string type_name) { + ea_t dest_ea = outArg->obj_ea; - // For global variables - if (outArg->op == cot_obj) { - // Rename global variable - auto name = "g" + typeToName(type_name); - set_name(dest_ea, name.c_str(), SN_FORCE); - } + // For global variables + if (outArg->op == cot_obj) { + // Rename global variable + auto name = "g" + typeToName(type_name); + set_name(dest_ea, name.c_str(), SN_FORCE); + } - // For local variables - else if (outArg->op == cot_var) { - var_ref_t varRef = outArg->v; - lvar_t &destVar = varRef.mba->vars[varRef.idx]; - // Set the Hex-Rays variable type - auto name = typeToName(type_name); - setLvarName(static_cast(name.c_str()), destVar, mFuncEa); - } + // For local variables + else if (outArg->op == cot_var) { + var_ref_t varRef = outArg->v; + lvar_t &destVar = varRef.mba->vars[varRef.idx]; + // Set the Hex-Rays variable type + auto name = typeToName(type_name); + setLvarName(static_cast(name.c_str()), destVar, mFuncEa); } + } }; class VariablesInfoExtractor : public ctree_visitor_t { - public: - VariablesInfoExtractor(ea_t code_addr) : ctree_visitor_t(CV_FAST) { - mCodeAddr = code_addr; - }; +public: + VariablesInfoExtractor(ea_t code_addr) : ctree_visitor_t(CV_FAST) { + mCodeAddr = code_addr; + }; + + uint8_t mAttributes = 0xff; + + // This is the callback function that Hex-Rays invokes for every expression + // in the CTREE. + int visit_expr(cexpr_t *e) { + if (mCodeAddr == BADADDR) { + return 0; + } - uint8_t mAttributes = 0xff; + if (e->ea != mCodeAddr) { + return 0; + } - // This is the callback function that Hex-Rays invokes for every expression - // in the CTREE. - int visit_expr(cexpr_t *e) { - if (mCodeAddr == BADADDR) { - return 0; - } + if (e->op != cot_call) + return 0; - if (e->ea != mCodeAddr) { - return 0; - } + carglist_t *args = e->a; + if (args == nullptr) { + return 0; + } - if (e->op != cot_call) - return 0; + size_t args_size = args->size(); + if (args_size < 3) { + return 0; + } - carglist_t *args = e->a; - if (args == nullptr) { - return 0; - } + cexpr_t *attributes_arg = &args->at(2); + if (attributes_arg->op == cot_num) { + if (mDebug) { + msg("[I] Service call: %016llX, Attributes: %02X\n", u64_addr(mCodeAddr), + static_cast(attributes_arg->numval())); + } + attributes_arg->numval(); + mAttributes = static_cast(attributes_arg->numval()); + } - size_t args_size = args->size(); - if (args_size < 3) { - return 0; - } + return 0; + } - cexpr_t *attributes_arg = &args->at(2); - if (attributes_arg->op == cot_num) { - if (mDebug) { - msg("[I] Service call: %016llX, Attributes: %02X\n", u64_addr(mCodeAddr), - static_cast(attributes_arg->numval())); - } - attributes_arg->numval(); - mAttributes = static_cast(attributes_arg->numval()); - } +protected: + ea_t mCodeAddr = BADADDR; + bool mDebug = false; +}; - return 0; +class PrototypesFixer : public ctree_visitor_t { +public: + PrototypesFixer() : ctree_visitor_t(CV_FAST) {}; + std::vector child_functions; + + // This is the callback function that Hex-Rays invokes for every expression + // in the CTREE. + int visit_expr(cexpr_t *e) { + if (e->op != cot_call) + return 0; + + // get child function address + if (e->x->op != cot_obj) { + return 0; + } + if (mDebug) { + msg("[I] Child function address: %016llX\n", u64_addr(e->x->obj_ea)); } - protected: - ea_t mCodeAddr = BADADDR; - bool mDebug = false; -}; + carglist_t *args = e->a; + if (args == nullptr) { + return 0; + } -class PrototypesFixer : public ctree_visitor_t { - public: - PrototypesFixer() : ctree_visitor_t(CV_FAST) {}; - std::vector child_functions; - - // This is the callback function that Hex-Rays invokes for every expression - // in the CTREE. - int visit_expr(cexpr_t *e) { - if (e->op != cot_call) - return 0; + // get child function prototype + ea_t func_addr = e->x->obj_ea; + hexrays_failure_t hf; + func_t *f = get_func(func_addr); + if (f == nullptr) { + return 0; + } - // get child function address - if (e->x->op != cot_obj) { - return 0; + cfuncptr_t cf = decompile(f, &hf, DECOMP_NO_WAIT); + if (cf == nullptr) { + return 0; + } + + msg("[I] Call address: 0x%016llX\n", u64_addr(e->ea)); + for (auto i = 0; i < args->size(); i++) { + cexpr_t *arg = &args->at(i); + if (arg->op == cot_cast || arg->op == cot_var) { + // extract argument type + tinfo_t arg_type; + tinfo_t arg_type_no_ptr; + if (arg->op == cot_var) { + arg_type = arg->type; } - if (mDebug) { - msg("[I] Child function address: %016llX\n", u64_addr(e->x->obj_ea)); + if (arg->op == cot_cast) { + arg_type = arg->x->type; } - carglist_t *args = e->a; - if (args == nullptr) { - return 0; + // print type + if (arg_type.is_ptr()) { + arg_type_no_ptr = remove_pointer(arg_type); } - // get child function prototype - ea_t func_addr = e->x->obj_ea; - hexrays_failure_t hf; - func_t *f = get_func(func_addr); - if (f == nullptr) { - return 0; + qstring type_name; + bool is_ptr = false; + if (!arg_type.get_type_name(&type_name)) { + if (!arg_type_no_ptr.get_type_name(&type_name)) { + // msg("[E] Can not get type name: 0x%016llX\n", u64_addr(e->ea)); + continue; + } + is_ptr = true; } - cfuncptr_t cf = decompile(f, &hf, DECOMP_NO_WAIT); - if (cf == nullptr) { - return 0; + if (is_ptr) { + msg("[I] Arg #%d, type = %s *\n", i, type_name.c_str()); + } else { + msg("[I] Arg #%d, type = %s\n", i, type_name.c_str()); } - msg("[I] Call address: 0x%016llX\n", u64_addr(e->ea)); - for (auto i = 0; i < args->size(); i++) { - cexpr_t *arg = &args->at(i); - if (arg->op == cot_cast || arg->op == cot_var) { - // extract argument type - tinfo_t arg_type; - tinfo_t arg_type_no_ptr; - if (arg->op == cot_var) { - arg_type = arg->type; - } - if (arg->op == cot_cast) { - arg_type = arg->x->type; - } - - // print type - if (arg_type.is_ptr()) { - arg_type_no_ptr = remove_pointer(arg_type); - } - - qstring type_name; - bool is_ptr = false; - if (!arg_type.get_type_name(&type_name)) { - if (!arg_type_no_ptr.get_type_name(&type_name)) { - // msg("[E] Can not get type name: 0x%016llX\n", u64_addr(e->ea)); - continue; - } - is_ptr = true; - } - - if (is_ptr) { - msg("[I] Arg #%d, type = %s *\n", i, type_name.c_str()); - } else { - msg("[I] Arg #%d, type = %s\n", i, type_name.c_str()); - } - - if (type_name == qstring("EFI_HANDLE") || - type_name == qstring("EFI_SYSTEM_TABLE")) { - if (!addrInVec(child_functions, func_addr)) { - child_functions.push_back(func_addr); - } - // set argument type and name - if (cf->argidx.size() <= i) { - return 0; - } - auto argid = cf->argidx[i]; - lvar_t &arg_var = cf->mba->vars[argid]; // get lvar for argument - if (type_name == qstring("EFI_HANDLE")) { - setHexRaysVariableInfo(func_addr, arg_var, arg_type, - "ImageHandle"); - } - if (type_name == qstring("EFI_SYSTEM_TABLE")) { - setHexRaysVariableInfo(func_addr, arg_var, arg_type, - "SystemTable"); - } - } - } + if (type_name == qstring("EFI_HANDLE") || + type_name == qstring("EFI_SYSTEM_TABLE")) { + if (!addrInVec(child_functions, func_addr)) { + child_functions.push_back(func_addr); + } + // set argument type and name + if (cf->argidx.size() <= i) { + return 0; + } + auto argid = cf->argidx[i]; + lvar_t &arg_var = cf->mba->vars[argid]; // get lvar for argument + if (type_name == qstring("EFI_HANDLE")) { + setHexRaysVariableInfo(func_addr, arg_var, arg_type, "ImageHandle"); + } + if (type_name == qstring("EFI_SYSTEM_TABLE")) { + setHexRaysVariableInfo(func_addr, arg_var, arg_type, "SystemTable"); + } } - - return 0; + } } - protected: - bool mDebug = true; + return 0; + } + +protected: + bool mDebug = true; }; class VariablesDetector : public ctree_visitor_t { - public: - VariablesDetector() : ctree_visitor_t(CV_FAST) {}; - - std::vector child_functions; - - std::vector gImageHandleList; - std::vector gStList; - std::vector gBsList; - std::vector gRtList; - - void SetFuncEa(ea_t ea) { mFuncEa = ea; }; - - // This is the callback function that Hex-Rays invokes for every expression - // in the CTREE. - int visit_expr(cexpr_t *e) { - if (e->op == cot_asg) { - // saving a child function for recursive analysis - if (!addrInVec(child_functions, e->ea)) { - child_functions.push_back(e->x->obj_ea); - } - } +public: + VariablesDetector() : ctree_visitor_t(CV_FAST) {}; + + std::vector child_functions; + + std::vector gImageHandleList; + std::vector gStList; + std::vector gBsList; + std::vector gRtList; + + void SetFuncEa(ea_t ea) { mFuncEa = ea; }; + + // This is the callback function that Hex-Rays invokes for every expression + // in the CTREE. + int visit_expr(cexpr_t *e) { + if (e->op == cot_asg) { + // saving a child function for recursive analysis + if (!addrInVec(child_functions, e->ea)) { + child_functions.push_back(e->x->obj_ea); + } + } - bool global_var = false; - bool local_var = false; - if (e->op != cot_asg) { - return 0; - } + bool global_var = false; + bool local_var = false; + if (e->op != cot_asg) { + return 0; + } - switch (e->x->op) { - case cot_obj: - // asg operation for global variable - global_var = true; - break; - case cot_var: - // asg operation for local variable - local_var = true; - break; - default: - return 0; - } + switch (e->x->op) { + case cot_obj: + // asg operation for global variable + global_var = true; + break; + case cot_var: + // asg operation for local variable + local_var = true; + break; + default: + return 0; + } - if (e->y->op != cot_cast && e->y->op != cot_var) { - return 0; - } + if (e->y->op != cot_cast && e->y->op != cot_var) { + return 0; + } - // extract variable type - tinfo_t var_type; - tinfo_t var_type_no_ptr; - if (e->y->op == cot_var) { - var_type = e->y->type; - } - if (e->y->op == cot_cast) { - var_type = e->y->x->type; - } + // extract variable type + tinfo_t var_type; + tinfo_t var_type_no_ptr; + if (e->y->op == cot_var) { + var_type = e->y->type; + } + if (e->y->op == cot_cast) { + var_type = e->y->x->type; + } - if (var_type.is_ptr()) { - var_type_no_ptr = remove_pointer(var_type); - } + if (var_type.is_ptr()) { + var_type_no_ptr = remove_pointer(var_type); + } - qstring type_name; - bool is_ptr = false; - if (!var_type.get_type_name(&type_name)) { - if (!var_type_no_ptr.get_type_name(&type_name)) { - // msg("[E] can not get type name: 0x%016llX\n", u64_addr(e->ea)); - return 0; - } - is_ptr = true; - } + qstring type_name; + bool is_ptr = false; + if (!var_type.get_type_name(&type_name)) { + if (!var_type_no_ptr.get_type_name(&type_name)) { + // msg("[E] can not get type name: 0x%016llX\n", u64_addr(e->ea)); + return 0; + } + is_ptr = true; + } - if (mDebug) { - msg("[I] code address: 0x%016llX, type name: %s\n", u64_addr(e->ea), - type_name.c_str()); - } + if (mDebug) { + msg("[I] code address: 0x%016llX, type name: %s\n", u64_addr(e->ea), + type_name.c_str()); + } - if (global_var) { - // extract variable data - ea_t g_addr = e->x->obj_ea; - std::string type_name_str = static_cast(type_name.c_str()); - if (type_name == qstring("EFI_HANDLE")) { - setTypeAndName(g_addr, "gImageHandle", type_name_str); - if (!addrInVec(gImageHandleList, g_addr)) { - gImageHandleList.push_back(g_addr); - } - } - if (type_name == qstring("EFI_SYSTEM_TABLE")) { - setPtrTypeAndName(g_addr, "gST", type_name_str); - if (!addrInVec(gStList, g_addr)) { - gStList.push_back(g_addr); - } - } - if (type_name == qstring("EFI_BOOT_SERVICES")) { - setPtrTypeAndName(g_addr, "gBS", type_name_str); - if (!addrInVec(gBsList, g_addr)) { - gBsList.push_back(g_addr); - } - } - if (type_name == qstring("EFI_RUNTIME_SERVICES")) { - setPtrTypeAndName(g_addr, "gRT", type_name_str); - if (!addrInVec(gRtList, g_addr)) { - gRtList.push_back(g_addr); - } - } + if (global_var) { + // extract variable data + ea_t g_addr = e->x->obj_ea; + std::string type_name_str = static_cast(type_name.c_str()); + if (type_name == qstring("EFI_HANDLE")) { + setTypeAndName(g_addr, "gImageHandle", type_name_str); + if (!addrInVec(gImageHandleList, g_addr)) { + gImageHandleList.push_back(g_addr); } - - if (local_var) { - var_ref_t var_ref; - if (e->y->op == cot_var) { - var_ref = e->y->v; - } - if (e->y->op == cot_cast) { - var_ref = e->y->x->v; - } - lvar_t &dest_var = var_ref.mba->vars[var_ref.idx]; - // Set the Hex-Rays variable type - auto name = typeToName(static_cast(type_name.c_str())); - // setHexRaysVariableInfo(mFuncEa, dest_var, var_type, name); + } + if (type_name == qstring("EFI_SYSTEM_TABLE")) { + setPtrTypeAndName(g_addr, "gST", type_name_str); + if (!addrInVec(gStList, g_addr)) { + gStList.push_back(g_addr); } + } + if (type_name == qstring("EFI_BOOT_SERVICES")) { + setPtrTypeAndName(g_addr, "gBS", type_name_str); + if (!addrInVec(gBsList, g_addr)) { + gBsList.push_back(g_addr); + } + } + if (type_name == qstring("EFI_RUNTIME_SERVICES")) { + setPtrTypeAndName(g_addr, "gRT", type_name_str); + if (!addrInVec(gRtList, g_addr)) { + gRtList.push_back(g_addr); + } + } + } - return 0; + if (local_var) { + var_ref_t var_ref; + if (e->y->op == cot_var) { + var_ref = e->y->v; + } + if (e->y->op == cot_cast) { + var_ref = e->y->x->v; + } + lvar_t &dest_var = var_ref.mba->vars[var_ref.idx]; + // Set the Hex-Rays variable type + auto name = typeToName(static_cast(type_name.c_str())); + // setHexRaysVariableInfo(mFuncEa, dest_var, var_type, name); } - protected: - bool mDebug = true; - ea_t mFuncEa = BADADDR; + return 0; + } + +protected: + bool mDebug = true; + ea_t mFuncEa = BADADDR; }; class ServicesDetector : public ctree_visitor_t { - // detect all services (Boot services, Runtime services, etc) - public: - ServicesDetector() : ctree_visitor_t(CV_FAST) {}; - - std::vector services; + // detect all services (Boot services, Runtime services, etc) +public: + ServicesDetector() : ctree_visitor_t(CV_FAST) {}; - // This is the callback function that Hex-Rays invokes for every expression - // in the CTREE. - int visit_expr(cexpr_t *e) { - if (e->op != cot_call) { - return 0; - } - - if (e->x->op != cot_cast) { - return 0; - } + std::vector services; - // extract function type - auto e_func = e->x->x; - tinfo_t func_type; - tinfo_t func_type_no_ptr; - func_type = e_func->type; + // This is the callback function that Hex-Rays invokes for every expression + // in the CTREE. + int visit_expr(cexpr_t *e) { + if (e->op != cot_call) { + return 0; + } - if (func_type.is_ptr()) { - func_type_no_ptr = remove_pointer(func_type); - } + if (e->x->op != cot_cast) { + return 0; + } - qstring type_name; - bool is_ptr = false; - if (!func_type.get_type_name(&type_name)) { - if (!func_type_no_ptr.get_type_name(&type_name)) { - // msg("[E] can not get type name: 0x%016llX\n", u64_addr(e->ea)); - return 0; - } - is_ptr = 0; - } + // extract function type + auto e_func = e->x->x; + tinfo_t func_type; + tinfo_t func_type_no_ptr; + func_type = e_func->type; - auto service_name = typeToName(static_cast(type_name.c_str())); - if (service_name.rfind("Efi", 0) == 0) { - service_name = service_name.substr(3); - if (service_name == "RaiseTpl") { - service_name = "RaiseTPL"; - } - if (service_name == "RestoreTpl") { - service_name = "RestoreTPL"; - } - } - msg("[efiXplorer] address: 0x%016llX, service type: %s, service name: %s\n", - u64_addr(e->ea), type_name.c_str(), service_name.c_str()); - - // append service - // add item to allBootServices - json s; - s["address"] = e->ea; - s["service_name"] = service_name; - s["table_name"] = getTable(service_name); - - if (!jsonInVec(services, s)) { - services.push_back(s); - } + if (func_type.is_ptr()) { + func_type_no_ptr = remove_pointer(func_type); + } + qstring type_name; + bool is_ptr = false; + if (!func_type.get_type_name(&type_name)) { + if (!func_type_no_ptr.get_type_name(&type_name)) { + // msg("[E] can not get type name: 0x%016llX\n", u64_addr(e->ea)); return 0; + } + is_ptr = 0; + } + + auto service_name = typeToName(static_cast(type_name.c_str())); + if (service_name.rfind("Efi", 0) == 0) { + service_name = service_name.substr(3); + if (service_name == "RaiseTpl") { + service_name = "RaiseTPL"; + } + if (service_name == "RestoreTpl") { + service_name = "RestoreTPL"; + } } + msg("[efiXplorer] address: 0x%016llX, service type: %s, service name: %s\n", + u64_addr(e->ea), type_name.c_str(), service_name.c_str()); + + // append service + // add item to allBootServices + json s; + s["address"] = e->ea; + s["service_name"] = service_name; + s["table_name"] = getTable(service_name); + + if (!jsonInVec(services, s)) { + services.push_back(s); + } + + return 0; + } - protected: - bool mDebug = true; +protected: + bool mDebug = true; }; class PeiServicesDetector : public ctree_visitor_t { - // detect and mark all PEI services - public: - PeiServicesDetector() : ctree_visitor_t(CV_FAST) {}; - - bool make_shifted_ptr(tinfo_t outer, tinfo_t inner, int32 offset, - tinfo_t *shifted_tif) { - ptr_type_data_t pi; - pi.taptr_bits = TAPTR_SHIFTED; - pi.delta = offset; - pi.parent = outer; - pi.obj_type = inner; - shifted_tif->create_ptr(pi); - return shifted_tif->is_correct(); + // detect and mark all PEI services +public: + PeiServicesDetector() : ctree_visitor_t(CV_FAST) {}; + + bool make_shifted_ptr(tinfo_t outer, tinfo_t inner, int32 offset, + tinfo_t *shifted_tif) { + ptr_type_data_t pi; + pi.taptr_bits = TAPTR_SHIFTED; + pi.delta = offset; + pi.parent = outer; + pi.obj_type = inner; + shifted_tif->create_ptr(pi); + return shifted_tif->is_correct(); + } + + bool set_var_type(ea_t func_ea, lvar_t lvar, tinfo_t tif) { + lvar_saved_info_t lsi; + lsi.ll = lvar; + lsi.type = tif; + return modify_user_lvar_info(func_ea, MLI_TYPE, lsi); + } + + // This is the callback function that Hex-Rays invokes for every expression + // in the CTREE. + int visit_expr(cexpr_t *e) { + auto pointer_offset = BADADDR; + auto service_offset = BADADDR; + bool call = false; + var_ref_t var_ref; + if (e->op == cot_ptr && e->x->op == cot_cast && e->x->x->op == cot_add && + e->x->x->x->op == cot_ptr && e->x->x->x->x->op == cot_ptr && + e->x->x->x->x->x->op == cot_cast && e->x->x->x->x->x->x->op == cot_sub && + e->x->x->x->x->x->x->x->op == cot_var && e->x->x->x->x->x->x->y->op == cot_num && + e->x->x->y->op == cot_num) { + // (*ADJ(v2)->PeiServices)->GetHobList( + // (const EFI_PEI_SERVICES**)ADJ(v2)->PeiServices, HobList); + service_offset = e->x->x->y->numval(); + pointer_offset = e->x->x->x->x->x->x->y->numval(); + var_ref = e->x->x->x->x->x->x->x->v; + call = true; + } else if (e->op == cot_asg && e->x->op == cot_var && e->y->op == cot_ptr && + e->y->x->op == cot_cast && e->y->x->x->op == cot_sub && + e->y->x->x->x->op == cot_var && e->y->x->x->y->op == cot_num) { + // __sidt(v6); + // PeiServices = ADJ(v7)->PeiServices; + pointer_offset = e->y->x->x->y->numval(); + var_ref = e->y->x->x->x->v; + } else { + return 0; } - bool set_var_type(ea_t func_ea, lvar_t lvar, tinfo_t tif) { - lvar_saved_info_t lsi; - lsi.ll = lvar; - lsi.type = tif; - return modify_user_lvar_info(func_ea, MLI_TYPE, lsi); + msg("[efiXplorer] address: 0x%08llX, PEI service detected\n", u64_addr(e->ea)); + msg("[efiXplorer] delta: %llx\n", u64_addr(pointer_offset)); + if (service_offset != BADADDR) { + msg("[efiXplorer] service offset: %llx\n", u64_addr(service_offset)); } - // This is the callback function that Hex-Rays invokes for every expression - // in the CTREE. - int visit_expr(cexpr_t *e) { - auto pointer_offset = BADADDR; - auto service_offset = BADADDR; - bool call = false; - var_ref_t var_ref; - if (e->op == cot_ptr && e->x->op == cot_cast && e->x->x->op == cot_add && - e->x->x->x->op == cot_ptr && e->x->x->x->x->op == cot_ptr && - e->x->x->x->x->x->op == cot_cast && e->x->x->x->x->x->x->op == cot_sub && - e->x->x->x->x->x->x->x->op == cot_var && - e->x->x->x->x->x->x->y->op == cot_num && e->x->x->y->op == cot_num) { - // (*ADJ(v2)->PeiServices)->GetHobList( - // (const EFI_PEI_SERVICES**)ADJ(v2)->PeiServices, HobList); - service_offset = e->x->x->y->numval(); - pointer_offset = e->x->x->x->x->x->x->y->numval(); - var_ref = e->x->x->x->x->x->x->x->v; - call = true; - } else if (e->op == cot_asg && e->x->op == cot_var && e->y->op == cot_ptr && - e->y->x->op == cot_cast && e->y->x->x->op == cot_sub && - e->y->x->x->x->op == cot_var && e->y->x->x->y->op == cot_num) { - // __sidt(v6); - // PeiServices = ADJ(v7)->PeiServices; - pointer_offset = e->y->x->x->y->numval(); - var_ref = e->y->x->x->x->v; - } else { - return 0; - } - - msg("[efiXplorer] address: 0x%08llX, PEI service detected\n", u64_addr(e->ea)); - msg("[efiXplorer] delta: %llx\n", u64_addr(pointer_offset)); - if (service_offset != BADADDR) { - msg("[efiXplorer] service offset: %llx\n", u64_addr(service_offset)); - } - - if (pointer_offset != 4) { - return 0; - } - - tinfo_t outer; - if (!outer.get_named_type(get_idati(), "EFI_PEI_SERVICES_4", BTF_STRUCT)) { - return 0; - } + if (pointer_offset != 4) { + return 0; + } - tinfo_t shifted_tif; - if (!make_shifted_ptr(outer, outer, pointer_offset, &shifted_tif)) { - return 0; - } + tinfo_t outer; + if (!outer.get_named_type(get_idati(), "EFI_PEI_SERVICES_4", BTF_STRUCT)) { + return 0; + } - lvar_t &dest_var = var_ref.mba->vars[var_ref.idx]; - func_t *func = get_func(e->ea); - if (func == nullptr) { - return 0; - } - if (set_var_type(func->start_ea, dest_var, shifted_tif)) { - msg("[efiXplorer] shifted pointer applied (0x%08llX)\n", u64_addr(e->ea)); - } + tinfo_t shifted_tif; + if (!make_shifted_ptr(outer, outer, pointer_offset, &shifted_tif)) { + return 0; + } - if (call) { - opStroff(e->ea, "EFI_PEI_SERVICES"); - } + lvar_t &dest_var = var_ref.mba->vars[var_ref.idx]; + func_t *func = get_func(e->ea); + if (func == nullptr) { + return 0; + } + if (set_var_type(func->start_ea, dest_var, shifted_tif)) { + msg("[efiXplorer] shifted pointer applied (0x%08llX)\n", u64_addr(e->ea)); + } - return 0; + if (call) { + opStroff(e->ea, "EFI_PEI_SERVICES"); } - protected: - bool mDebug = true; + return 0; + } + +protected: + bool mDebug = true; }; class PeiServicesDetectorArm : public ctree_visitor_t { - // detect and mark all PEI services for ARM firmware - // tested on Ampere firmware that contains small PEI stack - public: - PeiServicesDetectorArm() : ctree_visitor_t(CV_FAST) {}; - - std::vector services; - - // This is the callback function that Hex-Rays invokes for every expression - // in the CTREE. - int visit_expr(cexpr_t *e) { - if (!(e->op == cot_call && e->x->op == cot_memptr && e->x->x->op == cot_ptr && - e->x->x->x->op == cot_var)) { - return 0; - } - ea_t offset = e->x->m; - - // check if service from EFI_PEI_SERVICES - tinfo_t table_type = e->x->x->type; - tinfo_t table_type_no_ptr; - qstring table_type_name; - if (table_type.is_ptr()) { - table_type_no_ptr = remove_pointer(table_type); - table_type_no_ptr.get_type_name(&table_type_name); - } else { - table_type.get_type_name(&table_type_name); - } - - // get service name from function type - std::string service_name; - if (table_type_name != "EFI_PEI_SERVICES") { - qstring func_type_name; - tinfo_t service_type = e->x->type; - service_type.get_type_name(&func_type_name); - std::string func_type = static_cast(func_type_name.c_str()); - std::string prefix = "EFI_PEI_"; - if (func_type.substr(0, prefix.length()) == prefix) { - func_type.erase(0, prefix.length()); - } - service_name = typeToName(func_type); - } else { - auto s = mPeiServices.find(offset); - if (s == mPeiServices.end()) { - return 0; - } - service_name = s->second; - } - if (mDebug) { - msg("[efiXplorer] 0x%08llX: %s service detected (offset: %d): %s\n", - u64_addr(e->ea), table_type_name.c_str(), u32_addr(offset), - service_name.c_str()); - } + // detect and mark all PEI services for ARM firmware + // tested on Ampere firmware that contains small PEI stack +public: + PeiServicesDetectorArm() : ctree_visitor_t(CV_FAST) {}; + + std::vector services; + + // This is the callback function that Hex-Rays invokes for every expression + // in the CTREE. + int visit_expr(cexpr_t *e) { + if (!(e->op == cot_call && e->x->op == cot_memptr && e->x->x->op == cot_ptr && + e->x->x->x->op == cot_var)) { + return 0; + } + ea_t offset = e->x->m; + + // check if service from EFI_PEI_SERVICES + tinfo_t table_type = e->x->x->type; + tinfo_t table_type_no_ptr; + qstring table_type_name; + if (table_type.is_ptr()) { + table_type_no_ptr = remove_pointer(table_type); + table_type_no_ptr.get_type_name(&table_type_name); + } else { + table_type.get_type_name(&table_type_name); + } - json s; - s["address"] = e->ea; - s["service_name"] = service_name; - s["table_name"] = table_type_name.c_str(); + // get service name from function type + std::string service_name; + if (table_type_name != "EFI_PEI_SERVICES") { + qstring func_type_name; + tinfo_t service_type = e->x->type; + service_type.get_type_name(&func_type_name); + std::string func_type = static_cast(func_type_name.c_str()); + std::string prefix = "EFI_PEI_"; + if (func_type.substr(0, prefix.length()) == prefix) { + func_type.erase(0, prefix.length()); + } + service_name = typeToName(func_type); + } else { + auto s = mPeiServices.find(offset); + if (s == mPeiServices.end()) { + return 0; + } + service_name = s->second; + } + if (mDebug) { + msg("[efiXplorer] 0x%08llX: %s service detected (offset: %d): %s\n", + u64_addr(e->ea), table_type_name.c_str(), u32_addr(offset), + service_name.c_str()); + } - if (!jsonInVec(services, s)) { - services.push_back(s); - } + json s; + s["address"] = e->ea; + s["service_name"] = service_name; + s["table_name"] = table_type_name.c_str(); - return 0; + if (!jsonInVec(services, s)) { + services.push_back(s); } - protected: - bool mDebug = true; - std::map mPeiServices = { - {0x18, "InstallPpi"}, - {0x20, "ReInstallPpi"}, - {0x28, "LocatePpi"}, - {0x30, "NotifyPpi"}, - {0x38, "GetBootMode"}, - {0x40, "SetBootMode"}, - {0x48, "GetHobList"}, - {0x50, "CreateHob"}, - {0x58, "FfsFindNextVolume"}, - {0x60, "FfsFindNextFile"}, - {0x68, "FfsFindSectionData"}, - {0x70, "InstallPeiMemory"}, - {0x78, "AllocatePages"}, - {0x80, "AllocatePool"}, - {0x88, "CopyMem"}, - {0x90, "SetMem"}, - {0x98, "ReportStatusCode"}, - {0xA0, "ResetSystem"}, - {0xA8, "CpuIo"}, - {0xB0, "PciCfg"}, - {0xB8, "FfsFindFileByName"}, - {0xC0, "FfsGetFileInfo"}, - {0xC8, "FfsGetVolumeInfo"}, - {0xD0, "RegisterForShadow"}, - {0xD8, "FindSectionData4"}, - {0xE0, "FfsGetFileInfo3"}, - {0xE8, "ResetSystem3"}, - }; + return 0; + } + +protected: + bool mDebug = true; + std::map mPeiServices = { + {0x18, "InstallPpi"}, + {0x20, "ReInstallPpi"}, + {0x28, "LocatePpi"}, + {0x30, "NotifyPpi"}, + {0x38, "GetBootMode"}, + {0x40, "SetBootMode"}, + {0x48, "GetHobList"}, + {0x50, "CreateHob"}, + {0x58, "FfsFindNextVolume"}, + {0x60, "FfsFindNextFile"}, + {0x68, "FfsFindSectionData"}, + {0x70, "InstallPeiMemory"}, + {0x78, "AllocatePages"}, + {0x80, "AllocatePool"}, + {0x88, "CopyMem"}, + {0x90, "SetMem"}, + {0x98, "ReportStatusCode"}, + {0xA0, "ResetSystem"}, + {0xA8, "CpuIo"}, + {0xB0, "PciCfg"}, + {0xB8, "FfsFindFileByName"}, + {0xC0, "FfsGetFileInfo"}, + {0xC8, "FfsGetVolumeInfo"}, + {0xD0, "RegisterForShadow"}, + {0xD8, "FindSectionData4"}, + {0xE0, "FfsGetFileInfo3"}, + {0xE8, "ResetSystem3"}, + }; }; diff --git a/efiXplorer/efiSmmUtils.cpp b/efiXplorer/efiSmmUtils.cpp index e2532764..f673f066 100644 --- a/efiXplorer/efiSmmUtils.cpp +++ b/efiXplorer/efiSmmUtils.cpp @@ -1,6 +1,6 @@ /* * efiXplorer - * Copyright (C) 2020-2023 Binarly + * Copyright (C) 2020-2024 Binarly * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,287 +20,286 @@ */ #include "efiSmmUtils.h" - -static const char plugin_name[] = "efiXplorer"; +#include "efiGlobal.h" //-------------------------------------------------------------------------- // Find and mark gSmst global variable via EFI_SMM_SW_DISPATCH(2)_PROTOCOL_GUID std::vector findSmstSwDispatch(std::vector gBsList) { - std::vector smst_addrs; - EfiGuid guid2 = {0x18a3c6dc, - 0x5eea, - 0x48c8, - {0xa1, 0xc1, 0xb5, 0x33, 0x89, 0xf9, 0x89, - 0x99}}; // EFI_SMM_SW_DISPATCH2_PROTOCOL_GUID - EfiGuid guid = {0xe541b773, - 0xdd11, - 0x420c, - {0xb0, 0x26, 0xdf, 0x99, 0x36, 0x53, 0xf8, - 0xbf}}; // EFI_SMM_SW_DISPATCH_PROTOCOL_GUID - std::vector data_addrs = findData(0, BADADDR, guid.uchar_data().data(), 16); - std::vector data2_addrs = findData(0, BADADDR, guid2.uchar_data().data(), 16); - data_addrs.insert(data_addrs.end(), data2_addrs.begin(), data2_addrs.end()); - for (auto data_addr : data_addrs) { - msg("[%s] EFI_SMM_SW_DISPATCH(2)_PROTOCOL_GUID: 0x%016llX\n", plugin_name, - u64_addr(data_addr)); - std::vector xrefs = getXrefs(data_addr); - insn_t insn; - for (auto xref : xrefs) { - uint16_t smst_reg = 0xffff; // Smst register - ea_t cur_addr = xref; - while (true) { - cur_addr = next_head(cur_addr, BADADDR); - decode_insn(&insn, cur_addr); - // check for SmmLocateProtocol function call - if (insn.itype == NN_callni && insn.ops[0].type == o_displ && - insn.ops[0].addr == 0xd0) { - smst_reg = insn.ops[0].reg; - break; - } - if (is_basic_block_end(insn, false)) { - break; - } - } + std::vector smst_addrs; + EfiGuid guid2 = {0x18a3c6dc, + 0x5eea, + 0x48c8, + {0xa1, 0xc1, 0xb5, 0x33, 0x89, 0xf9, 0x89, + 0x99}}; // EFI_SMM_SW_DISPATCH2_PROTOCOL_GUID + EfiGuid guid = {0xe541b773, + 0xdd11, + 0x420c, + {0xb0, 0x26, 0xdf, 0x99, 0x36, 0x53, 0xf8, + 0xbf}}; // EFI_SMM_SW_DISPATCH_PROTOCOL_GUID + std::vector data_addrs = findData(0, BADADDR, guid.uchar_data().data(), 16); + std::vector data2_addrs = findData(0, BADADDR, guid2.uchar_data().data(), 16); + data_addrs.insert(data_addrs.end(), data2_addrs.begin(), data2_addrs.end()); + for (auto data_addr : data_addrs) { + msg("[%s] EFI_SMM_SW_DISPATCH(2)_PROTOCOL_GUID: 0x%016llX\n", g_plugin_name, + u64_addr(data_addr)); + std::vector xrefs = getXrefs(data_addr); + insn_t insn; + for (auto xref : xrefs) { + uint16_t smst_reg = 0xffff; // Smst register + ea_t cur_addr = xref; + while (true) { + cur_addr = next_head(cur_addr, BADADDR); + decode_insn(&insn, cur_addr); + // check for SmmLocateProtocol function call + if (insn.itype == NN_callni && insn.ops[0].type == o_displ && + insn.ops[0].addr == 0xd0) { + smst_reg = insn.ops[0].reg; + break; + } + if (is_basic_block_end(insn, false)) { + break; + } + } - if (smst_reg == 0xffff) { - continue; // smst_reg not found - } + if (smst_reg == 0xffff) { + continue; // smst_reg not found + } - ea_t res_addr = BADADDR; - cur_addr = xref; - while (true) { - cur_addr = prev_head(cur_addr, 0); - decode_insn(&insn, cur_addr); - if (insn.itype == NN_mov && insn.ops[0].type == o_reg && - insn.ops[0].reg == smst_reg && insn.ops[1].type == o_mem) { - msg("[%s] found gSmst at 0x%016llX, address = 0x%016llX\n", - plugin_name, u64_addr(cur_addr), u64_addr(insn.ops[1].addr)); - res_addr = insn.ops[1].addr; - if (addrInVec(gBsList, res_addr)) { - continue; - } - set_cmt(cur_addr, "_EFI_SMM_SYSTEM_TABLE2 *gSmst;", true); - setPtrTypeAndName(res_addr, "gSmst", "_EFI_SMM_SYSTEM_TABLE2"); - smst_addrs.push_back(res_addr); - break; - } - if (is_basic_block_end(insn, false)) { - break; - } - } + ea_t res_addr = BADADDR; + cur_addr = xref; + while (true) { + cur_addr = prev_head(cur_addr, 0); + decode_insn(&insn, cur_addr); + if (insn.itype == NN_mov && insn.ops[0].type == o_reg && + insn.ops[0].reg == smst_reg && insn.ops[1].type == o_mem) { + msg("[%s] found gSmst at 0x%016llX, address = 0x%016llX\n", g_plugin_name, + u64_addr(cur_addr), u64_addr(insn.ops[1].addr)); + res_addr = insn.ops[1].addr; + if (addrInVec(gBsList, res_addr)) { + continue; + } + set_cmt(cur_addr, "_EFI_SMM_SYSTEM_TABLE2 *gSmst;", true); + setPtrTypeAndName(res_addr, "gSmst", "_EFI_SMM_SYSTEM_TABLE2"); + smst_addrs.push_back(res_addr); + break; } + if (is_basic_block_end(insn, false)) { + break; + } + } } + } - return smst_addrs; + return smst_addrs; } //-------------------------------------------------------------------------- // Find and mark gSmst global variable via EFI_SMM_BASE2_PROTOCOL_GUID std::vector findSmstSmmBase(std::vector gBsList) { - std::vector smst_addrs; - EfiGuid guid = { - 0xf4ccbfb7, - 0xf6e0, - 0x47fd, - {0x9d, 0xd4, 0x10, 0xa8, 0xf1, 0x50, 0xc1, 0x91}}; // EFI_SMM_BASE2_PROTOCOL_GUID - std::vector data_addrs = findData(0, BADADDR, guid.uchar_data().data(), 16); - for (auto data_addr : data_addrs) { - msg("[%s] EFI_SMM_BASE2_PROTOCOL_GUID: 0x%016llX\n", plugin_name, - u64_addr(data_addr)); - std::vector data_xrefs = getXrefs(data_addr); - insn_t insn; - for (auto xref : data_xrefs) { - ea_t res_addr = BADADDR; - ea_t cur_addr = xref; - bool in_smram = false; - // Check 16 instructions below - for (auto i = 0; i < 16; i++) { - cur_addr = next_head(cur_addr, BADADDR); - decode_insn(&insn, cur_addr); - if (insn.itype == NN_lea && insn.ops[0].type == o_reg && - insn.ops[0].reg == REG_RDX && insn.ops[1].type == o_mem) { - res_addr = insn.ops[1].addr; - msg("[%s] found gSmst/gInSmram at 0x%016llX, address = 0x%016llX\n", - plugin_name, u64_addr(cur_addr), u64_addr(res_addr)); - } - if (res_addr != BADADDR && insn.itype == NN_callni && - insn.ops[0].type == o_phrase && !insn.ops[0].addr) { - // gEfiSmmBase2Protocol->InSmm(gEfiSmmBase2Protocol, &gInSmram) - in_smram = true; - } - } - if (!in_smram) { - // we found gSmst - if (addrInVec(gBsList, res_addr)) { - continue; - } - set_cmt(cur_addr, "_EFI_SMM_SYSTEM_TABLE2 *gSmst;", true); - setPtrTypeAndName(res_addr, "gSmst", "_EFI_SMM_SYSTEM_TABLE2"); - smst_addrs.push_back(res_addr); - } else { - // we found gInSmram - setTypeAndName(res_addr, "gInSmram", "BOOLEAN"); - } + std::vector smst_addrs; + EfiGuid guid = { + 0xf4ccbfb7, + 0xf6e0, + 0x47fd, + {0x9d, 0xd4, 0x10, 0xa8, 0xf1, 0x50, 0xc1, 0x91}}; // EFI_SMM_BASE2_PROTOCOL_GUID + std::vector data_addrs = findData(0, BADADDR, guid.uchar_data().data(), 16); + for (auto data_addr : data_addrs) { + msg("[%s] EFI_SMM_BASE2_PROTOCOL_GUID: 0x%016llX\n", g_plugin_name, + u64_addr(data_addr)); + std::vector data_xrefs = getXrefs(data_addr); + insn_t insn; + for (auto xref : data_xrefs) { + ea_t res_addr = BADADDR; + ea_t cur_addr = xref; + bool in_smram = false; + // Check 16 instructions below + for (auto i = 0; i < 16; i++) { + cur_addr = next_head(cur_addr, BADADDR); + decode_insn(&insn, cur_addr); + if (insn.itype == NN_lea && insn.ops[0].type == o_reg && + insn.ops[0].reg == REG_RDX && insn.ops[1].type == o_mem) { + res_addr = insn.ops[1].addr; + msg("[%s] found gSmst/gInSmram at 0x%016llX, address = 0x%016llX\n", + g_plugin_name, u64_addr(cur_addr), u64_addr(res_addr)); + } + if (res_addr != BADADDR && insn.itype == NN_callni && + insn.ops[0].type == o_phrase && !insn.ops[0].addr) { + // gEfiSmmBase2Protocol->InSmm(gEfiSmmBase2Protocol, &gInSmram) + in_smram = true; } + } + if (!in_smram) { + // we found gSmst + if (addrInVec(gBsList, res_addr)) { + continue; + } + set_cmt(cur_addr, "_EFI_SMM_SYSTEM_TABLE2 *gSmst;", true); + setPtrTypeAndName(res_addr, "gSmst", "_EFI_SMM_SYSTEM_TABLE2"); + smst_addrs.push_back(res_addr); + } else { + // we found gInSmram + setTypeAndName(res_addr, "gInSmram", "BOOLEAN"); + } } + } - return smst_addrs; + return smst_addrs; } //-------------------------------------------------------------------------- // Find SmiHandler in reg_smi_func function (prefix: Sw, TrapIo, Sx, Gpi, Usb, // StandbyButton, PeriodicTimer, PowerButton) std::vector findSmiHandlers(ea_t address, std::string prefix) { - msg("[%s] Analyze xref to gEfiSmm%sDispatch(2)Protocol: 0x%016llX\n", plugin_name, - prefix.c_str(), u64_addr(address)); + msg("[%s] Analyze xref to gEfiSmm%sDispatch(2)Protocol: 0x%016llX\n", g_plugin_name, + prefix.c_str(), u64_addr(address)); - std::vector smiHandlers; - insn_t insn; + std::vector smiHandlers; + insn_t insn; - // Find Dispatch interface address (via gSmst->SmmLocateProtocol call) + // Find Dispatch interface address (via gSmst->SmmLocateProtocol call) - // Check instruction - decode_insn(&insn, address); - if (!(insn.ops[0].type == o_reg && insn.ops[0].reg == REG_RCX)) { - msg("[%s] %sSmiHandler: wrong xref to dispatch(2) protocol\n", plugin_name, - prefix.c_str()); - return smiHandlers; + // Check instruction + decode_insn(&insn, address); + if (!(insn.ops[0].type == o_reg && insn.ops[0].reg == REG_RCX)) { + msg("[%s] %sSmiHandler: wrong xref to dispatch(2) protocol\n", g_plugin_name, + prefix.c_str()); + return smiHandlers; + } + + // Analyze current basic block + auto ea = address; + + // Search for SmmLocateProtocol + bool found = false; + uint64_t dispatch_interface = BADADDR; + while (!is_basic_block_end(insn, false)) { + ea = next_head(ea, BADADDR); + decode_insn(&insn, ea); + if (insn.itype == NN_callni && insn.ops[0].type == o_displ && + insn.ops[0].addr == 0xd0) { + found = true; + msg("[%s] %sSmiHandler: found = true\n", g_plugin_name, prefix.c_str()); + break; } + // Interface in stack + if (insn.itype == NN_lea && insn.ops[0].type == o_reg && insn.ops[0].reg == REG_R8 && + insn.ops[1].type == o_displ && + (insn.ops[1].reg == REG_RBP || insn.ops[1].reg == REG_RSP)) { + if (dispatch_interface == BADADDR) { + dispatch_interface = insn.ops[1].addr; + } + } + // Interface in data + if (insn.itype == NN_lea && insn.ops[0].type == o_reg && insn.ops[0].reg == REG_R8 && + insn.ops[1].type == o_mem) { + if (dispatch_interface == BADADDR) { + dispatch_interface = insn.ops[1].addr; + } + } + } - // Analyze current basic block - auto ea = address; + if (!found) { + return smiHandlers; + } - // Search for SmmLocateProtocol - bool found = false; - uint64_t dispatch_interface = BADADDR; + if (dispatch_interface == BADADDR) { + ea = address; while (!is_basic_block_end(insn, false)) { - ea = next_head(ea, BADADDR); - decode_insn(&insn, ea); - if (insn.itype == NN_callni && insn.ops[0].type == o_displ && - insn.ops[0].addr == 0xd0) { - found = true; - msg("[%s] %sSmiHandler: found = true\n", plugin_name, prefix.c_str()); - break; - } - // Interface in stack - if (insn.itype == NN_lea && insn.ops[0].type == o_reg && - insn.ops[0].reg == REG_R8 && insn.ops[1].type == o_displ && - (insn.ops[1].reg == REG_RBP || insn.ops[1].reg == REG_RSP)) { - if (dispatch_interface == BADADDR) { - dispatch_interface = insn.ops[1].addr; - } - } - // Interface in data - if (insn.itype == NN_lea && insn.ops[0].type == o_reg && - insn.ops[0].reg == REG_R8 && insn.ops[1].type == o_mem) { - if (dispatch_interface == BADADDR) { - dispatch_interface = insn.ops[1].addr; - } - } + ea = prev_head(ea, 0); + decode_insn(&insn, ea); + // Interface in stack + if (insn.itype == NN_lea && insn.ops[0].type == o_reg && + insn.ops[0].reg == REG_R8 && insn.ops[1].type == o_displ && + (insn.ops[1].reg == REG_RBP || insn.ops[1].reg == REG_RSP)) { + dispatch_interface = insn.ops[1].addr; + break; + } + // Interface in data + if (insn.itype == NN_lea && insn.ops[0].type == o_reg && + insn.ops[0].reg == REG_R8 && insn.ops[1].type == o_mem) { + dispatch_interface = insn.ops[1].addr; + break; + } } + } - if (!found) { - return smiHandlers; + if (dispatch_interface == BADADDR) { + return smiHandlers; + } + + msg("[%s] Found EfiSmm%sDispatch(2)Protocol interface: 0x%016llX\n", g_plugin_name, + prefix.c_str(), dispatch_interface); + + // TODO: handle xrefs for globals + // (fw71.bin.out/SmmHddSecurity-316b1230-0500-4592-8c09-eaba0fb6b07f.smm) + + // Track interface stack variable + ea = address; + uint16_t reg = BAD_REG; + uint64_t dispatch_func = BADADDR; + for (auto i = 0; i < 100; i++) { + ea = next_head(ea, BADADDR); + decode_insn(&insn, ea); + // get Interface base register + if (insn.itype == NN_mov && insn.ops[0].type == o_reg && + (insn.ops[1].type == o_displ || insn.ops[1].type == o_mem)) { + if (insn.ops[1].addr == dispatch_interface) { + reg = insn.ops[0].reg; + } else { + reg = BAD_REG; // resetting + } + continue; } - if (dispatch_interface == BADADDR) { - ea = address; - while (!is_basic_block_end(insn, false)) { - ea = prev_head(ea, 0); - decode_insn(&insn, ea); - // Interface in stack - if (insn.itype == NN_lea && insn.ops[0].type == o_reg && - insn.ops[0].reg == REG_R8 && insn.ops[1].type == o_displ && - (insn.ops[1].reg == REG_RBP || insn.ops[1].reg == REG_RSP)) { - dispatch_interface = insn.ops[1].addr; - break; - } - // Interface in data - if (insn.itype == NN_lea && insn.ops[0].type == o_reg && - insn.ops[0].reg == REG_R8 && insn.ops[1].type == o_mem) { - dispatch_interface = insn.ops[1].addr; - break; - } - } + // resetting (register overwrite or call) + if (reg != BAD_REG && insn.ops[0].type == o_reg && insn.ops[0].reg == reg) { + reg = BAD_REG; + continue; } - if (dispatch_interface == BADADDR) { - return smiHandlers; + // resetting (call) + if (insn.itype == NN_call) { + reg = BAD_REG; + continue; } - msg("[%s] Found EfiSmm%sDispatch(2)Protocol interface: 0x%016llX\n", plugin_name, - prefix.c_str(), dispatch_interface); - - // TODO: handle xrefs for globals - // (fw71.bin.out/SmmHddSecurity-316b1230-0500-4592-8c09-eaba0fb6b07f.smm) - - // Track interface stack variable - ea = address; - uint16_t reg = BAD_REG; - uint64_t dispatch_func = BADADDR; - for (auto i = 0; i < 100; i++) { - ea = next_head(ea, BADADDR); - decode_insn(&insn, ea); - // get Interface base register - if (insn.itype == NN_mov && insn.ops[0].type == o_reg && - (insn.ops[1].type == o_displ || insn.ops[1].type == o_mem)) { - if (insn.ops[1].addr == dispatch_interface) { - reg = insn.ops[0].reg; - } else { - reg = BAD_REG; // resetting - } - continue; - } - - // resetting (register overwrite or call) - if (reg != BAD_REG && insn.ops[0].type == o_reg && insn.ops[0].reg == reg) { - reg = BAD_REG; - continue; - } - - // resetting (call) - if (insn.itype == NN_call) { - reg = BAD_REG; - continue; - } - - // get DispatchFunction address - if (insn.itype == NN_lea && insn.ops[0].type == o_reg && - insn.ops[0].reg == REG_RDX && insn.ops[1].type == o_mem) { - dispatch_func = insn.ops[1].addr; - continue; - } - if (insn.itype == NN_callni && insn.ops[0].type == o_phrase && - insn.ops[0].reg == reg) { - msg("[%s] Found EfiSmm%sDispatch2Protocol->Register call (0x%016llX)\n", - plugin_name, prefix.c_str(), u64_addr(ea)); - msg("[%s] %sSmiHandler: 0x%016llX\n", plugin_name, prefix.c_str(), - dispatch_func); - auto handler_func = get_func(dispatch_func); - if (handler_func == nullptr) { - add_func(dispatch_func); // create function - handler_func = get_func(dispatch_func); // retry - } - if (handler_func != nullptr) { - smiHandlers.push_back(handler_func); // add in result - } - reg = BAD_REG; // resetting - - // op_stroff + set_name - std::string name = prefix + "SmiHandler"; - set_name(dispatch_func, name.c_str(), SN_FORCE); - std::string prefix_upper; - std::transform(prefix.begin(), prefix.end(), prefix_upper.begin(), ::toupper); - std::string type = "EFI_SMM_" + prefix_upper + "_DISPATCH2_PROTOCOL"; - opStroff(ea, type); - } + // get DispatchFunction address + if (insn.itype == NN_lea && insn.ops[0].type == o_reg && insn.ops[0].reg == REG_RDX && + insn.ops[1].type == o_mem) { + dispatch_func = insn.ops[1].addr; + continue; + } + if (insn.itype == NN_callni && insn.ops[0].type == o_phrase && + insn.ops[0].reg == reg) { + msg("[%s] Found EfiSmm%sDispatch2Protocol->Register call (0x%016llX)\n", + g_plugin_name, prefix.c_str(), u64_addr(ea)); + msg("[%s] %sSmiHandler: 0x%016llX\n", g_plugin_name, prefix.c_str(), + dispatch_func); + auto handler_func = get_func(dispatch_func); + if (handler_func == nullptr) { + add_func(dispatch_func); // create function + handler_func = get_func(dispatch_func); // retry + } + if (handler_func != nullptr) { + smiHandlers.push_back(handler_func); // add in result + } + reg = BAD_REG; // resetting + + // op_stroff + set_name + std::string name = prefix + "SmiHandler"; + set_name(dispatch_func, name.c_str(), SN_FORCE); + std::string prefix_upper; + std::transform(prefix.begin(), prefix.end(), prefix_upper.begin(), ::toupper); + std::string type = "EFI_SMM_" + prefix_upper + "_DISPATCH2_PROTOCOL"; + opStroff(ea, type); + } - if (insn.itype == NN_retn || insn.itype == NN_int3) { - break; - } + if (insn.itype == NN_retn || insn.itype == NN_int3) { + break; } + } - return smiHandlers; + return smiHandlers; } //-------------------------------------------------------------------------- @@ -314,20 +313,20 @@ std::vector findSmiHandlers(ea_t address, std::string prefix) { // lea rdx, // call qword ptr [...] std::vector findSmiHandlersSmmDispatch(EfiGuid guid, std::string prefix) { - std::vector smiHandlers; - std::vector data_addrs = findData(0, BADADDR, guid.uchar_data().data(), 16); - msg("[%s] %sSmiHandler function finding\n", plugin_name, prefix.c_str()); - for (auto data_addr : data_addrs) { - std::vector xrefs = getXrefs(data_addr); - - for (auto xref : xrefs) { - msg("[%s] findSmiHandlers: 0x%016llX\n", plugin_name, u64_addr(xref)); - auto res = findSmiHandlers(xref, prefix); - smiHandlers.insert(smiHandlers.end(), res.begin(), res.end()); - } + std::vector smiHandlers; + std::vector data_addrs = findData(0, BADADDR, guid.uchar_data().data(), 16); + msg("[%s] %sSmiHandler function finding\n", g_plugin_name, prefix.c_str()); + for (auto data_addr : data_addrs) { + std::vector xrefs = getXrefs(data_addr); + + for (auto xref : xrefs) { + msg("[%s] findSmiHandlers: 0x%016llX\n", g_plugin_name, u64_addr(xref)); + auto res = findSmiHandlers(xref, prefix); + smiHandlers.insert(smiHandlers.end(), res.begin(), res.end()); } + } - return smiHandlers; + return smiHandlers; } //-------------------------------------------------------------------------- @@ -335,293 +334,286 @@ std::vector findSmiHandlersSmmDispatch(EfiGuid guid, std::string prefi // EFI_SMM_SW_DISPATCH(2)_PROTOCOL_GUID is a local variable std::vector findSmiHandlersSmmDispatchStack(std::vector stackGuids, std::string prefix) { - // TODO: make it generic - std::vector smiHandlers; - - for (auto guid : stackGuids) { - std::string name = static_cast(guid["name"]); + // TODO: make it generic + std::vector smiHandlers; - if (name != "EFI_SMM_SW_DISPATCH2_PROTOCOL_GUID" && - name != "EFI_SMM_SW_DISPATCH_PROTOCOL_GUID") { - continue; - } + for (auto guid : stackGuids) { + std::string name = static_cast(guid["name"]); - ea_t address = static_cast(guid["address"]); - msg("[%s] found EFI_SMM_SW_DISPATCH(2)_PROTOCOL_GUID on stack: " - "0x%016llX\n", - plugin_name, u64_addr(address)); - auto res = findSmiHandlers(address, prefix); - smiHandlers.insert(smiHandlers.end(), res.begin(), res.end()); + if (name != "EFI_SMM_SW_DISPATCH2_PROTOCOL_GUID" && + name != "EFI_SMM_SW_DISPATCH_PROTOCOL_GUID") { + continue; } - return smiHandlers; + ea_t address = static_cast(guid["address"]); + msg("[%s] found EFI_SMM_SW_DISPATCH(2)_PROTOCOL_GUID on stack: " + "0x%016llX\n", + g_plugin_name, u64_addr(address)); + auto res = findSmiHandlers(address, prefix); + smiHandlers.insert(smiHandlers.end(), res.begin(), res.end()); + } + + return smiHandlers; } //-------------------------------------------------------------------------- // Find gSmmVar->SmmGetVariable calls via EFI_SMM_VARIABLE_PROTOCOL_GUID std::vector findSmmGetVariableCalls(std::vector dataSegments, std::vector *allServices) { - msg("[%s] gSmmVar->SmmGetVariable calls finding via " - "EFI_SMM_VARIABLE_PROTOCOL_GUID\n", - plugin_name); - std::vector smmGetVariableCalls; - EfiGuid guid = {0xed32d533, - 0x99e6, - 0x4209, - {0x9c, 0xc0, 0x2d, 0x72, 0xcd, 0xd9, 0x98, - 0xa7}}; // EFI_SMM_VARIABLE_PROTOCOL_GUID - - // Find all EFI_GUID EFI_SMM_VARIABLE_PROTOCOL_GUID addresses - std::vector data_addrs = findData(0, BADADDR, guid.uchar_data().data(), 16); - std::vector gSmmVarAddrs; // Find all gSmmVar variables - for (auto data_addr : data_addrs) { - std::vector xrefs = getXrefs(data_addr); - - for (auto xref : xrefs) { - segment_t *seg = getseg(static_cast(xref)); - qstring seg_name; - get_segm_name(&seg_name, seg); - msg("[%s] EFI_SMM_VARIABLE_PROTOCOL_GUID xref address: 0x%016llX, " - "segment: %s\n", - plugin_name, u64_addr(xref), seg_name.c_str()); - - size_t index = seg_name.find(".text"); - if (index == std::string::npos) { - continue; - } - - insn_t insn; - ea_t ea = xref; - for (auto i = 0; i < 8; i++) { - // Find `lea r8, ` instruction - ea = prev_head(ea, 0); - decode_insn(&insn, ea); - if (insn.itype == NN_lea && insn.ops[0].type == o_reg && - insn.ops[0].reg == REG_R8 && insn.ops[1].type == o_mem) { - msg("[%s] gSmmVar address: 0x%016llX\n", plugin_name, - u64_addr(insn.ops[1].addr)); - set_cmt(ea, "EFI_SMM_VARIABLE_PROTOCOL *gSmmVar", true); - setPtrTypeAndName(insn.ops[1].addr, "gSmmVar", - "EFI_SMM_VARIABLE_PROTOCOL"); - gSmmVarAddrs.push_back(insn.ops[1].addr); - break; - } - } + msg("[%s] gSmmVar->SmmGetVariable calls finding via " + "EFI_SMM_VARIABLE_PROTOCOL_GUID\n", + g_plugin_name); + std::vector smmGetVariableCalls; + EfiGuid guid = { + 0xed32d533, + 0x99e6, + 0x4209, + {0x9c, 0xc0, 0x2d, 0x72, 0xcd, 0xd9, 0x98, 0xa7}}; // EFI_SMM_VARIABLE_PROTOCOL_GUID + + // Find all EFI_GUID EFI_SMM_VARIABLE_PROTOCOL_GUID addresses + std::vector data_addrs = findData(0, BADADDR, guid.uchar_data().data(), 16); + std::vector gSmmVarAddrs; // Find all gSmmVar variables + for (auto data_addr : data_addrs) { + std::vector xrefs = getXrefs(data_addr); + + for (auto xref : xrefs) { + segment_t *seg = getseg(static_cast(xref)); + qstring seg_name; + get_segm_name(&seg_name, seg); + msg("[%s] EFI_SMM_VARIABLE_PROTOCOL_GUID xref address: 0x%016llX, " + "segment: %s\n", + g_plugin_name, u64_addr(xref), seg_name.c_str()); + + size_t index = seg_name.find(".text"); + if (index == std::string::npos) { + continue; + } + + insn_t insn; + ea_t ea = xref; + for (auto i = 0; i < 8; i++) { + // Find `lea r8, ` instruction + ea = prev_head(ea, 0); + decode_insn(&insn, ea); + if (insn.itype == NN_lea && insn.ops[0].type == o_reg && + insn.ops[0].reg == REG_R8 && insn.ops[1].type == o_mem) { + msg("[%s] gSmmVar address: 0x%016llX\n", g_plugin_name, + u64_addr(insn.ops[1].addr)); + set_cmt(ea, "EFI_SMM_VARIABLE_PROTOCOL *gSmmVar", true); + setPtrTypeAndName(insn.ops[1].addr, "gSmmVar", "EFI_SMM_VARIABLE_PROTOCOL"); + gSmmVarAddrs.push_back(insn.ops[1].addr); + break; } + } } + } - if (!gSmmVarAddrs.size()) { - msg("[%s] can't find gSmmVar addresses\n", plugin_name); - return smmGetVariableCalls; - } - - for (auto smmVarAddr : gSmmVarAddrs) { - std::vector smmVarXrefs = getXrefs(static_cast(smmVarAddr)); - for (auto smmVarXref : smmVarXrefs) { - segment_t *seg = getseg(static_cast(smmVarXref)); - qstring seg_name; - get_segm_name(&seg_name, seg); - msg("[%s] gSmmVar xref address: 0x%016llX, segment: %s\n", plugin_name, - u64_addr(smmVarXref), seg_name.c_str()); - - size_t index = seg_name.find(".text"); - if (index == std::string::npos) { - continue; + if (!gSmmVarAddrs.size()) { + msg("[%s] can't find gSmmVar addresses\n", g_plugin_name); + return smmGetVariableCalls; + } + + for (auto smmVarAddr : gSmmVarAddrs) { + std::vector smmVarXrefs = getXrefs(static_cast(smmVarAddr)); + for (auto smmVarXref : smmVarXrefs) { + segment_t *seg = getseg(static_cast(smmVarXref)); + qstring seg_name; + get_segm_name(&seg_name, seg); + msg("[%s] gSmmVar xref address: 0x%016llX, segment: %s\n", g_plugin_name, + u64_addr(smmVarXref), seg_name.c_str()); + + size_t index = seg_name.find(".text"); + if (index == std::string::npos) { + continue; + } + + uint16 gSmmVarReg = 0xffff; + insn_t insn; + ea_t ea = static_cast(smmVarXref); + decode_insn(&insn, ea); + + if (insn.itype == NN_mov && insn.ops[0].type == o_reg && + insn.ops[1].type == o_mem) { + gSmmVarReg = insn.ops[0].reg; + for (auto i = 0; i < 16; i++) { + ea = next_head(ea, BADADDR); + decode_insn(&insn, ea); + + if (insn.itype == NN_callni && gSmmVarReg == insn.ops[0].reg && + insn.ops[0].addr == 0) { + msg("[%s] gSmmVar->SmmGetVariable found: 0x%016llX\n", g_plugin_name, + u64_addr(ea)); + + if (find(smmGetVariableCalls.begin(), smmGetVariableCalls.end(), ea) == + smmGetVariableCalls.end()) { + smmGetVariableCalls.push_back(ea); } - uint16 gSmmVarReg = 0xffff; - insn_t insn; - ea_t ea = static_cast(smmVarXref); - decode_insn(&insn, ea); - - if (insn.itype == NN_mov && insn.ops[0].type == o_reg && - insn.ops[1].type == o_mem) { - gSmmVarReg = insn.ops[0].reg; - for (auto i = 0; i < 16; i++) { - ea = next_head(ea, BADADDR); - decode_insn(&insn, ea); - - if (insn.itype == NN_callni && gSmmVarReg == insn.ops[0].reg && - insn.ops[0].addr == 0) { - msg("[%s] gSmmVar->SmmGetVariable found: 0x%016llX\n", - plugin_name, u64_addr(ea)); - - if (find(smmGetVariableCalls.begin(), smmGetVariableCalls.end(), - ea) == smmGetVariableCalls.end()) { - smmGetVariableCalls.push_back(ea); - } - - // Temporarily add a "virtual" smm service call - // for easier annotations and UI - - std::string cmt = getSmmVarComment(); - set_cmt(ea, cmt.c_str(), true); - opStroff(ea, "EFI_SMM_VARIABLE_PROTOCOL"); - msg("[%s] 0x%016llX : %s\n", plugin_name, u64_addr(ea), - "SmmGetVariable"); - std::string smm_call = "gSmmVar->SmmGetVariable"; - json smm_item; - smm_item["address"] = ea; - smm_item["service_name"] = smm_call; - smm_item["table_name"] = - static_cast("EFI_SMM_VARIABLE_PROTOCOL"); - smm_item["offset"] = 0; - - if (find(allServices->begin(), allServices->end(), smm_item) == - allServices->end()) { - allServices->push_back(smm_item); - } - - break; - } - } + // Temporarily add a "virtual" smm service call + // for easier annotations and UI + + opStroff(ea, "EFI_SMM_VARIABLE_PROTOCOL"); + msg("[%s] 0x%016llX : %s\n", g_plugin_name, u64_addr(ea), "SmmGetVariable"); + std::string smm_call = "gSmmVar->SmmGetVariable"; + json smm_item; + smm_item["address"] = ea; + smm_item["service_name"] = smm_call; + smm_item["table_name"] = + static_cast("EFI_SMM_VARIABLE_PROTOCOL"); + smm_item["offset"] = 0; + + if (find(allServices->begin(), allServices->end(), smm_item) == + allServices->end()) { + allServices->push_back(smm_item); } + + break; + } } + } } - return smmGetVariableCalls; + } + return smmGetVariableCalls; } std::vector resolveEfiSmmCpuProtocol(std::vector stackGuids, std::vector dataGuids, std::vector *allServices) { - std::vector readSaveStateCalls; - msg("[%s] Looking for EFI_SMM_CPU_PROTOCOL\n", plugin_name); - std::vector codeAddrs; - std::vector gSmmCpuAddrs; - for (auto guid : stackGuids) { - std::string name = static_cast(guid["name"]); - if (name != "EFI_SMM_CPU_PROTOCOL_GUID") - continue; - ea_t address = static_cast(guid["address"]); - msg("[%s] found EFI_SMM_CPU_PROTOCOL on stack: 0x%016llX\n", plugin_name, - u64_addr(address)); - codeAddrs.push_back(address); + std::vector readSaveStateCalls; + msg("[%s] Looking for EFI_SMM_CPU_PROTOCOL\n", g_plugin_name); + std::vector codeAddrs; + std::vector gSmmCpuAddrs; + for (auto guid : stackGuids) { + std::string name = static_cast(guid["name"]); + if (name != "EFI_SMM_CPU_PROTOCOL_GUID") + continue; + ea_t address = static_cast(guid["address"]); + msg("[%s] found EFI_SMM_CPU_PROTOCOL on stack: 0x%016llX\n", g_plugin_name, + u64_addr(address)); + codeAddrs.push_back(address); + } + + for (auto guid : dataGuids) { + std::string name = static_cast(guid["name"]); + if (name != "EFI_SMM_CPU_PROTOCOL_GUID") + continue; + + ea_t address = static_cast(guid["address"]); + msg("[%s] found EFI_SMM_CPU_PROTOCOL: 0x%016llX\n", g_plugin_name, u64_addr(address)); + std::vector guidXrefs = getXrefs(address); + + for (auto guidXref : guidXrefs) { + segment_t *seg = getseg(static_cast(guidXref)); + qstring seg_name; + get_segm_name(&seg_name, seg); + size_t index = seg_name.find(".text"); + if (index == std::string::npos) { + continue; + } + codeAddrs.push_back(static_cast(guidXref)); } + } - for (auto guid : dataGuids) { - std::string name = static_cast(guid["name"]); - if (name != "EFI_SMM_CPU_PROTOCOL_GUID") - continue; - - ea_t address = static_cast(guid["address"]); - msg("[%s] found EFI_SMM_CPU_PROTOCOL: 0x%016llX\n", plugin_name, - u64_addr(address)); - std::vector guidXrefs = getXrefs(address); - - for (auto guidXref : guidXrefs) { - segment_t *seg = getseg(static_cast(guidXref)); - qstring seg_name; - get_segm_name(&seg_name, seg); - size_t index = seg_name.find(".text"); - if (index == std::string::npos) { - continue; - } - codeAddrs.push_back(static_cast(guidXref)); - } + for (auto addr : codeAddrs) { + msg("[%s] current address: 0x%016llX\n", g_plugin_name, u64_addr(addr)); + insn_t insn; + ea_t ea = prev_head(addr, 0); + + for (auto i = 0; i < 8; i++) { + // Find 'lea r8, ' instruction + decode_insn(&insn, ea); + if (insn.itype == NN_lea && insn.ops[0].type == o_reg && + insn.ops[0].reg == REG_R8 && insn.ops[1].type == o_mem) { + msg("[%s] gSmmCpu address: 0x%016llX\n", g_plugin_name, + u64_addr(insn.ops[1].addr)); + set_cmt(ea, "EFI_SMM_CPU_PROTOCOL *gSmmCpu", true); + setPtrTypeAndName(insn.ops[1].addr, "gSmmCpu", "EFI_SMM_CPU_PROTOCOL"); + gSmmCpuAddrs.push_back(insn.ops[1].addr); + break; + } + ea = prev_head(ea, 0); } + } - for (auto addr : codeAddrs) { - msg("[%s] current address: 0x%016llX\n", plugin_name, u64_addr(addr)); - insn_t insn; - ea_t ea = prev_head(addr, 0); - - for (auto i = 0; i < 8; i++) { - // Find 'lea r8, ' instruction - decode_insn(&insn, ea); - if (insn.itype == NN_lea && insn.ops[0].type == o_reg && - insn.ops[0].reg == REG_R8 && insn.ops[1].type == o_mem) { - msg("[%s] gSmmCpu address: 0x%016llX\n", plugin_name, - u64_addr(insn.ops[1].addr)); - set_cmt(ea, "EFI_SMM_CPU_PROTOCOL *gSmmCpu", true); - setPtrTypeAndName(insn.ops[1].addr, "gSmmCpu", "EFI_SMM_CPU_PROTOCOL"); - gSmmCpuAddrs.push_back(insn.ops[1].addr); - break; + if (!gSmmCpuAddrs.size()) { + msg("[%s] can't find gSmmCpu addresses\n", g_plugin_name); + return readSaveStateCalls; + } + + for (auto smmCpu : gSmmCpuAddrs) { + std::vector smmCpuXrefs = getXrefs(static_cast(smmCpu)); + + for (auto smmCpuXref : smmCpuXrefs) { + segment_t *seg = getseg(static_cast(smmCpuXref)); + qstring seg_name; + get_segm_name(&seg_name, seg); + size_t index = seg_name.find(".text"); + + if (index == std::string::npos) { + continue; + } + + uint16_t gSmmCpuReg = 0xffff; + insn_t insn; + ea_t ea = static_cast(smmCpuXref); + decode_insn(&insn, ea); + + if (insn.itype == NN_mov && insn.ops[0].type == o_reg && + insn.ops[1].type == o_mem) { + gSmmCpuReg = insn.ops[0].reg; + + for (auto i = 0; i < 16; i++) { + ea = next_head(ea, BADADDR); + decode_insn(&insn, ea); + + if (insn.itype == NN_callni && gSmmCpuReg == insn.ops[0].reg && + insn.ops[0].addr == 0) { + if (find(readSaveStateCalls.begin(), readSaveStateCalls.end(), ea) == + readSaveStateCalls.end()) { + readSaveStateCalls.push_back(ea); } - ea = prev_head(ea, 0); - } - } - if (!gSmmCpuAddrs.size()) { - msg("[%s] can't find gSmmCpu addresses\n", plugin_name); - return readSaveStateCalls; - } - - for (auto smmCpu : gSmmCpuAddrs) { - std::vector smmCpuXrefs = getXrefs(static_cast(smmCpu)); - - for (auto smmCpuXref : smmCpuXrefs) { - segment_t *seg = getseg(static_cast(smmCpuXref)); - qstring seg_name; - get_segm_name(&seg_name, seg); - size_t index = seg_name.find(".text"); - - if (index == std::string::npos) { - continue; + opStroff(ea, "EFI_SMM_CPU_PROTOCOL"); + msg("[%s] 0x%016llX : %s\n", g_plugin_name, u64_addr(ea), + "gSmmCpu->ReadSaveState"); + std::string smm_call = "gSmmCpu->ReadSaveState"; + json smm_item; + smm_item["address"] = ea; + smm_item["service_name"] = smm_call; + smm_item["table_name"] = static_cast("EFI_SMM_CPU_PROTOCOL"); + smm_item["offset"] = 0; + + if (find(allServices->begin(), allServices->end(), smm_item) == + allServices->end()) { + allServices->push_back(smm_item); } - uint16_t gSmmCpuReg = 0xffff; - insn_t insn; - ea_t ea = static_cast(smmCpuXref); - decode_insn(&insn, ea); - - if (insn.itype == NN_mov && insn.ops[0].type == o_reg && - insn.ops[1].type == o_mem) { - gSmmCpuReg = insn.ops[0].reg; - - for (auto i = 0; i < 16; i++) { - ea = next_head(ea, BADADDR); - decode_insn(&insn, ea); - - if (insn.itype == NN_callni && gSmmCpuReg == insn.ops[0].reg && - insn.ops[0].addr == 0) { - if (find(readSaveStateCalls.begin(), readSaveStateCalls.end(), - ea) == readSaveStateCalls.end()) { - readSaveStateCalls.push_back(ea); - } - - opStroff(ea, "EFI_SMM_CPU_PROTOCOL"); - msg("[%s] 0x%016llX : %s\n", plugin_name, u64_addr(ea), - "gSmmCpu->ReadSaveState"); - std::string smm_call = "gSmmCpu->ReadSaveState"; - json smm_item; - smm_item["address"] = ea; - smm_item["service_name"] = smm_call; - smm_item["table_name"] = - static_cast("EFI_SMM_CPU_PROTOCOL"); - smm_item["offset"] = 0; - - if (find(allServices->begin(), allServices->end(), smm_item) == - allServices->end()) { - allServices->push_back(smm_item); - } - - break; - } - } - } + break; + } } + } } - return readSaveStateCalls; + } + return readSaveStateCalls; } ea_t markChildSwSmiHandler(ea_t ea) { - insn_t insn; - auto addr = prev_head(ea, 0); + insn_t insn; + auto addr = prev_head(ea, 0); + decode_insn(&insn, addr); + while (!is_basic_block_end(insn, false)) { + // for next iteration decode_insn(&insn, addr); - while (!is_basic_block_end(insn, false)) { - // for next iteration - decode_insn(&insn, addr); - addr = prev_head(addr, 0); - - // check current instruction - if (insn.itype == NN_lea && insn.ops[0].type == o_reg && - insn.ops[0].reg == REG_RCX) { - if (insn.ops[1].type != o_mem) { - continue; - } - set_name(insn.ops[1].addr, "ChildSwSmiHandler", SN_FORCE); - return insn.ops[1].addr; - } + addr = prev_head(addr, 0); + + // check current instruction + if (insn.itype == NN_lea && insn.ops[0].type == o_reg && insn.ops[0].reg == REG_RCX) { + if (insn.ops[1].type != o_mem) { + continue; + } + set_name(insn.ops[1].addr, "ChildSwSmiHandler", SN_FORCE); + return insn.ops[1].addr; } - return BADADDR; + } + return BADADDR; } diff --git a/efiXplorer/efiSmmUtils.h b/efiXplorer/efiSmmUtils.h index 3dd3d9e6..57aeff95 100644 --- a/efiXplorer/efiSmmUtils.h +++ b/efiXplorer/efiSmmUtils.h @@ -1,6 +1,6 @@ /* * efiXplorer - * Copyright (C) 2020-2023 Binarly + * Copyright (C) 2020-2024 Binarly * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/efiXplorer/efiUi.cpp b/efiXplorer/efiUi.cpp index 742a152e..729605a4 100644 --- a/efiXplorer/efiUi.cpp +++ b/efiXplorer/efiUi.cpp @@ -1,6 +1,6 @@ /* * efiXplorer - * Copyright (C) 2020-2023 Binarly + * Copyright (C) 2020-2024 Binarly * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -23,8 +23,6 @@ #include "efiDeps.h" #include "efiGlobal.h" -static const char plugin_name[] = "efiXplorer"; - // vulns column widths const int vulns_chooser_t::widths_vulns[] = { 16, // Address @@ -104,63 +102,63 @@ const char *const nvram_chooser_t::header_nvram[] = { inline nvram_chooser_t::nvram_chooser_t(const char *title_, bool ok, std::vector nvram) : chooser_t(0, qnumber(widths_nvram), widths_nvram, header_nvram, title_), list() { - CASSERT(qnumber(widths_nvram) == qnumber(header_nvram)); - build_list(ok, nvram); + CASSERT(qnumber(widths_nvram) == qnumber(header_nvram)); + build_list(ok, nvram); } void idaapi nvram_chooser_t::get_row(qstrvec_t *cols_, int *, chooser_item_attrs_t *, size_t n) const { - ea_t ea = list[n]; - qstrvec_t &cols = *cols_; - json item = chooser_nvram[n]; - std::string name = static_cast(item["VariableName"]); - std::string guid = static_cast(item["VendorGuid"]); - std::string service = static_cast(item["service"]); - std::string attributes = static_cast(item["AttributesHumanReadable"]); - cols[0].sprnt("%016llX", u64_addr(ea)); - cols[1].sprnt("%s", name.c_str()); - cols[2].sprnt("%s", guid.c_str()); - cols[3].sprnt("%s", service.c_str()); - cols[4].sprnt("%s", attributes.c_str()); - CASSERT(qnumber(header_nvram) == 5); + ea_t ea = list[n]; + qstrvec_t &cols = *cols_; + json item = chooser_nvram[n]; + std::string name = static_cast(item["VariableName"]); + std::string guid = static_cast(item["VendorGuid"]); + std::string service = static_cast(item["service"]); + std::string attributes = static_cast(item["AttributesHumanReadable"]); + cols[0].sprnt("%016llX", u64_addr(ea)); + cols[1].sprnt("%s", name.c_str()); + cols[2].sprnt("%s", guid.c_str()); + cols[3].sprnt("%s", service.c_str()); + cols[4].sprnt("%s", attributes.c_str()); + CASSERT(qnumber(header_nvram) == 5); } inline vulns_chooser_t::vulns_chooser_t(const char *title_, bool ok, std::vector vulns) : chooser_t(0, qnumber(widths_vulns), widths_vulns, header_vulns, title_), list() { - CASSERT(qnumber(widths_vulns) == qnumber(header_vulns)); - build_list(ok, vulns); + CASSERT(qnumber(widths_vulns) == qnumber(header_vulns)); + build_list(ok, vulns); } void idaapi vulns_chooser_t::get_row(qstrvec_t *cols_, int *, chooser_item_attrs_t *, size_t n) const { - ea_t ea = list[n]; - qstrvec_t &cols = *cols_; - json item = chooser_vulns[n]; - std::string type = static_cast(item["type"]); - cols[0].sprnt("%016llX", u64_addr(ea)); - cols[1].sprnt("%s", type.c_str()); - CASSERT(qnumber(header_vulns) == 2); + ea_t ea = list[n]; + qstrvec_t &cols = *cols_; + json item = chooser_vulns[n]; + std::string type = static_cast(item["type"]); + cols[0].sprnt("%016llX", u64_addr(ea)); + cols[1].sprnt("%s", type.c_str()); + CASSERT(qnumber(header_vulns) == 2); } inline guids_chooser_t::guids_chooser_t(const char *title_, bool ok, std::vector guids) : chooser_t(0, qnumber(widths_guids), widths_guids, header_guids, title_), list() { - CASSERT(qnumber(widths_guids) == qnumber(header_guids)); - build_list(ok, guids); + CASSERT(qnumber(widths_guids) == qnumber(header_guids)); + build_list(ok, guids); } void idaapi guids_chooser_t::get_row(qstrvec_t *cols_, int *, chooser_item_attrs_t *, size_t n) const { - ea_t ea = list[n]; - qstrvec_t &cols = *cols_; - json item = chooser_guids[n]; - std::string guid = static_cast(item["guid"]); - std::string name = static_cast(item["name"]); - cols[0].sprnt("%016llX", u64_addr(ea)); - cols[1].sprnt("%s", guid.c_str()); - cols[2].sprnt("%s", name.c_str()); - CASSERT(qnumber(header_guids) == 3); + ea_t ea = list[n]; + qstrvec_t &cols = *cols_; + json item = chooser_guids[n]; + std::string guid = static_cast(item["guid"]); + std::string name = static_cast(item["name"]); + cols[0].sprnt("%016llX", u64_addr(ea)); + cols[1].sprnt("%s", guid.c_str()); + cols[2].sprnt("%s", name.c_str()); + CASSERT(qnumber(header_guids) == 3); } inline protocols_chooser_t::protocols_chooser_t(const char *title_, bool ok, @@ -168,130 +166,129 @@ inline protocols_chooser_t::protocols_chooser_t(const char *title_, bool ok, std::string name_key_) : chooser_t(0, qnumber(widths_protocols), widths_protocols, header_protocols, title_), list() { - CASSERT(qnumber(widths_protocols) == qnumber(header_protocols)); - name_key = name_key_; - build_list(ok, protocols); + CASSERT(qnumber(widths_protocols) == qnumber(header_protocols)); + name_key = name_key_; + build_list(ok, protocols); } void idaapi protocols_chooser_t::get_row(qstrvec_t *cols_, int *, chooser_item_attrs_t *, size_t n) const { - ea_t ea = list[n]; - qstrvec_t &cols = *cols_; - json item = chooser_protocols[n]; - std::string name = static_cast(item[name_key]); - std::string service = static_cast(item["service"]); - std::string protGuid = static_cast(item["guid"]); - std::string moduleName = static_cast(item["module"]); - cols[0].sprnt("%016llX", u64_addr(ea)); - cols[1].sprnt("%s", protGuid.c_str()); - cols[2].sprnt("%s", name.c_str()); - cols[3].sprnt("%s", service.c_str()); - cols[4].sprnt("%s", moduleName.c_str()); - CASSERT(qnumber(header_protocols) == 5); + ea_t ea = list[n]; + qstrvec_t &cols = *cols_; + json item = chooser_protocols[n]; + std::string name = static_cast(item[name_key]); + std::string service = static_cast(item["service"]); + std::string protGuid = static_cast(item["guid"]); + std::string moduleName = static_cast(item["module"]); + cols[0].sprnt("%016llX", u64_addr(ea)); + cols[1].sprnt("%s", protGuid.c_str()); + cols[2].sprnt("%s", name.c_str()); + cols[3].sprnt("%s", service.c_str()); + cols[4].sprnt("%s", moduleName.c_str()); + CASSERT(qnumber(header_protocols) == 5); } inline s_chooser_t::s_chooser_t(const char *title_, bool ok, std::vector services) : chooser_t(0, qnumber(widths_s), widths_s, header_s, title_), list() { - CASSERT(qnumber(widths_s) == qnumber(header_s)); - build_list(ok, services); + CASSERT(qnumber(widths_s) == qnumber(header_s)); + build_list(ok, services); } void idaapi s_chooser_t::get_row(qstrvec_t *cols_, int *, chooser_item_attrs_t *, size_t n) const { - ea_t ea = list[n]; - qstrvec_t &cols = *cols_; - json item = chooser_s[n]; - std::string service_name = static_cast(item["service_name"]); - std::string table_name = static_cast(item["table_name"]); - cols[0].sprnt("%016llX", u64_addr(ea)); - cols[1].sprnt("%s", service_name.c_str()); - cols[2].sprnt("%s", table_name.c_str()); - CASSERT(qnumber(header_s) == 3); + ea_t ea = list[n]; + qstrvec_t &cols = *cols_; + json item = chooser_s[n]; + std::string service_name = static_cast(item["service_name"]); + std::string table_name = static_cast(item["table_name"]); + cols[0].sprnt("%016llX", u64_addr(ea)); + cols[1].sprnt("%s", service_name.c_str()); + cols[2].sprnt("%s", table_name.c_str()); + CASSERT(qnumber(header_s) == 3); } bool nvram_show(std::vector nvram, qstring title) { - bool ok; - // open the window - nvram_chooser_t *ch = new nvram_chooser_t(title.c_str(), ok, nvram); - // default cursor position is 0 (first row) - ch->choose(); - return true; + bool ok; + // open the window + nvram_chooser_t *ch = new nvram_chooser_t(title.c_str(), ok, nvram); + // default cursor position is 0 (first row) + ch->choose(); + return true; } bool vulns_show(std::vector vulns, qstring title) { - bool ok; - // open the window - vulns_chooser_t *ch = new vulns_chooser_t(title.c_str(), ok, vulns); - // default cursor position is 0 (first row) - ch->choose(); - return true; + bool ok; + // open the window + vulns_chooser_t *ch = new vulns_chooser_t(title.c_str(), ok, vulns); + // default cursor position is 0 (first row) + ch->choose(); + return true; } bool guids_show(std::vector guids, qstring title) { - bool ok; - // open the window - guids_chooser_t *ch = new guids_chooser_t(title.c_str(), ok, guids); - // default cursor position is 0 (first row) - ch->choose(); - return true; + bool ok; + // open the window + guids_chooser_t *ch = new guids_chooser_t(title.c_str(), ok, guids); + // default cursor position is 0 (first row) + ch->choose(); + return true; } bool protocols_show(std::vector protocols, qstring title) { - bool ok; - // open the window - protocols_chooser_t *ch = - new protocols_chooser_t(title.c_str(), ok, protocols, "prot_name"); - // default cursor position is 0 (first row) - ch->choose(); - return true; + bool ok; + // open the window + protocols_chooser_t *ch = + new protocols_chooser_t(title.c_str(), ok, protocols, "prot_name"); + // default cursor position is 0 (first row) + ch->choose(); + return true; } bool ppis_show(std::vector ppis, qstring title) { - bool ok; - // open the window - protocols_chooser_t *ch = - new protocols_chooser_t(title.c_str(), ok, ppis, "ppi_name"); - // default cursor position is 0 (first row) - ch->choose(); - return true; + bool ok; + // open the window + protocols_chooser_t *ch = new protocols_chooser_t(title.c_str(), ok, ppis, "ppi_name"); + // default cursor position is 0 (first row) + ch->choose(); + return true; } bool services_show(std::vector services, qstring title) { - bool ok; - // open the window - s_chooser_t *ch = new s_chooser_t(title.c_str(), ok, services); - // default cursor position is 0 (first row) - ch->choose(); - return true; + bool ok; + // open the window + s_chooser_t *ch = new s_chooser_t(title.c_str(), ok, services); + // default cursor position is 0 (first row) + ch->choose(); + return true; } //------------------------------------------------------------------------- // Action handler for protocols dependencies struct protocols_deps_handler_t : public action_handler_t { - virtual int idaapi activate(action_activation_ctx_t *ctx) { - auto n = ctx->chooser_selection.at(0); - json info = g_deps.protocolsChooser[n]; + virtual int idaapi activate(action_activation_ctx_t *ctx) { + auto n = ctx->chooser_selection.at(0); + json info = g_deps.protocolsChooser[n]; - if (info.is_null()) { - return -1; // protocol not found - } + if (info.is_null()) { + return -1; // protocol not found + } - // get dependencies for protocol - std::string guid = info["guid"]; - json d = g_deps.protocolsByGuids[guid]; + // get dependencies for protocol + std::string guid = info["guid"]; + json d = g_deps.protocolsByGuids[guid]; - // print dependencies for current - // protocol in output window - std::string s = d.dump(2); - msg("[%s] dependencies for protocol with GUID %s: %s\n", plugin_name, - guid.c_str(), s.c_str()); + // print dependencies for current + // protocol in output window + std::string s = d.dump(2); + msg("[%s] dependencies for protocol with GUID %s: %s\n", g_plugin_name, guid.c_str(), + s.c_str()); - return 0; - } + return 0; + } - virtual action_state_t idaapi update(action_update_ctx_t *ctx) { - return AST_ENABLE_ALWAYS; - } + virtual action_state_t idaapi update(action_update_ctx_t *ctx) { + return AST_ENABLE_ALWAYS; + } }; static protocols_deps_handler_t protocols_deps_ah; @@ -299,30 +296,30 @@ action_desc_t protocols_deps = ACTION_DESC_LITERAL( "efiXplorer:protocolsDeps", "Show dependencies", &protocols_deps_ah, NULL, NULL, -1); void attachActionProtocolsDeps() { - // Attach action in protocols chooser - TWidget *widget = find_widget("efiXplorer: protocols"); - if (widget == nullptr) { - msg("[%s] can not find efiXplorer: protocols chooser", plugin_name); - return; - } - register_action(protocols_deps); - attach_action_to_popup(widget, nullptr, protocols_deps.name); + // Attach action in protocols chooser + TWidget *widget = find_widget("efiXplorer: protocols"); + if (widget == nullptr) { + msg("[%s] can not find efiXplorer: protocols chooser", g_plugin_name); + return; + } + register_action(protocols_deps); + attach_action_to_popup(widget, nullptr, protocols_deps.name); } //------------------------------------------------------------------------- // Action handler for showing the sequence of modules execution struct modules_seq_handler_t : public action_handler_t { - virtual int idaapi activate(action_activation_ctx_t *ctx) { - g_deps.buildModulesSequence(); - std::string s = g_deps.modulesSequence.dump(2); - msg("[%s] sequence of modules execution: %s\n", plugin_name, s.c_str()); + virtual int idaapi activate(action_activation_ctx_t *ctx) { + g_deps.buildModulesSequence(); + std::string s = g_deps.modulesSequence.dump(2); + msg("[%s] sequence of modules execution: %s\n", g_plugin_name, s.c_str()); - return 0; - } + return 0; + } - virtual action_state_t idaapi update(action_update_ctx_t *ctx) { - return AST_ENABLE_ALWAYS; - } + virtual action_state_t idaapi update(action_update_ctx_t *ctx) { + return AST_ENABLE_ALWAYS; + } }; static modules_seq_handler_t modules_seq_ah; @@ -331,112 +328,112 @@ action_desc_t modules_seq = &modules_seq_ah, NULL, NULL, -1); void attachActionModulesSeq() { - // Attach action in protocols chooser - TWidget *widget = find_widget("efiXplorer: protocols"); - if (widget == nullptr) { - msg("[%s] can not find efiXplorer: protocols chooser", plugin_name); - return; - } - register_action(modules_seq); - attach_action_to_popup(widget, nullptr, modules_seq.name); + // Attach action in protocols chooser + TWidget *widget = find_widget("efiXplorer: protocols"); + if (widget == nullptr) { + msg("[%s] can not find efiXplorer: protocols chooser", g_plugin_name); + return; + } + register_action(modules_seq); + attach_action_to_popup(widget, nullptr, modules_seq.name); } //------------------------------------------------------------------------- // Action handler (load efiXplorer analysis report) struct action_handler_loadreport_t : public action_handler_t { - virtual int idaapi activate(action_activation_ctx_t *ctx) { - std::filesystem::path reportPath; - char *file = ask_file(false, "*.json", "Load efiXplorer analysis report"); - if (file == nullptr) { - msg("[%s] report file not specified\n", plugin_name); - return -1; - } - reportPath /= file; - msg("[%s] loading report from %s file\n", plugin_name, reportPath.c_str()); - - json reportData; - try { - std::ifstream in(reportPath); - in >> reportData; - } catch (std::exception &e) { - msg("[%s] report file is invalid, check its contents\n", plugin_name); - return -1; - } + virtual int idaapi activate(action_activation_ctx_t *ctx) { + std::filesystem::path reportPath; + char *file = ask_file(false, "*.json", "Load efiXplorer analysis report"); + if (file == nullptr) { + msg("[%s] report file not specified\n", g_plugin_name); + return -1; + } + reportPath /= file; + msg("[%s] loading report from %s file\n", g_plugin_name, reportPath.c_str()); + + json reportData; + try { + std::ifstream in(reportPath); + in >> reportData; + } catch (std::exception &e) { + msg("[%s] report file is invalid, check its contents\n", g_plugin_name); + return -1; + } - // Initialize vuln types list - std::vector vulnTypes{ - "smm_callout", "pei_get_variable_buffer_overflow", - "get_variable_buffer_overflow", "smm_get_variable_buffer_overflow"}; - - // Show all choosers with data from report - qstring title; - - try { - auto protocols = reportData["allProtocols"]; - if (!protocols.is_null()) { // show protocols - title = "efiXplorer: protocols"; - protocols_show(protocols, title); - } - auto ppis = reportData["allPPIs"]; - if (!ppis.is_null()) { // show PPIs - title = "efiXplorer: PPIs"; - protocols_show(ppis, title); - } - auto services = reportData["allServices"]; - if (!services.is_null()) { // show services - title = "efiXplorer: services"; - services_show(services, title); - } - auto guids = reportData["allGuids"]; - if (!guids.is_null()) { // show GUIDs - title = "efiXplorer: GUIDs"; - guids_show(guids, title); - } - auto nvram = reportData["nvramVariables"]; - if (!nvram.is_null()) { // show NVRAM - title = "efiXplorer: NVRAM"; - nvram_show(nvram, title); - } - auto vulns = reportData["vulns"]; - if (!vulns.is_null()) { // show vulns - std::vector vulnsRes; - for (auto vulnType : vulnTypes) { - // For each vuln type add list of vulns in `vulnsRes` - auto vulnAddrs = vulns[vulnType]; - if (vulnAddrs.is_null()) { - continue; - } - for (auto addr : vulnAddrs) { - json item; - item["type"] = vulnType; - item["address"] = addr; - vulnsRes.push_back(item); - } - } - if (vulnsRes.size()) { - title = "efiXplorer: vulns"; - vulns_show(vulnsRes, title); - } - } - - // Init public EdiDependencies members - g_deps.getProtocolsChooser(protocols); - g_deps.getProtocolsByGuids(protocols); - - // Save all protocols information to build dependencies - attachActionProtocolsDeps(); - attachActionModulesSeq(); - } catch (std::exception &e) { - msg("[%s] report file is invalid, check its contents\n", plugin_name); - return -1; + // Initialize vuln types list + std::vector vulnTypes{"smm_callout", "pei_get_variable_buffer_overflow", + "get_variable_buffer_overflow", + "smm_get_variable_buffer_overflow"}; + + // Show all choosers with data from report + qstring title; + + try { + auto protocols = reportData["allProtocols"]; + if (!protocols.is_null()) { // show protocols + title = "efiXplorer: protocols"; + protocols_show(protocols, title); + } + auto ppis = reportData["allPPIs"]; + if (!ppis.is_null()) { // show PPIs + title = "efiXplorer: PPIs"; + protocols_show(ppis, title); + } + auto services = reportData["allServices"]; + if (!services.is_null()) { // show services + title = "efiXplorer: services"; + services_show(services, title); + } + auto guids = reportData["allGuids"]; + if (!guids.is_null()) { // show GUIDs + title = "efiXplorer: GUIDs"; + guids_show(guids, title); + } + auto nvram = reportData["nvramVariables"]; + if (!nvram.is_null()) { // show NVRAM + title = "efiXplorer: NVRAM"; + nvram_show(nvram, title); + } + auto vulns = reportData["vulns"]; + if (!vulns.is_null()) { // show vulns + std::vector vulnsRes; + for (auto vulnType : vulnTypes) { + // For each vuln type add list of vulns in `vulnsRes` + auto vulnAddrs = vulns[vulnType]; + if (vulnAddrs.is_null()) { + continue; + } + for (auto addr : vulnAddrs) { + json item; + item["type"] = vulnType; + item["address"] = addr; + vulnsRes.push_back(item); + } } - - return 0; + if (vulnsRes.size()) { + title = "efiXplorer: vulns"; + vulns_show(vulnsRes, title); + } + } + + // Init public EdiDependencies members + g_deps.getProtocolsChooser(protocols); + g_deps.getProtocolsByGuids(protocols); + + // Save all protocols information to build dependencies + attachActionProtocolsDeps(); + attachActionModulesSeq(); + } catch (std::exception &e) { + msg("[%s] report file is invalid, check its contents\n", g_plugin_name); + return -1; } - virtual action_state_t idaapi update(action_update_ctx_t *ctx) { - return AST_ENABLE_ALWAYS; - } + return 0; + } + + virtual action_state_t idaapi update(action_update_ctx_t *ctx) { + return AST_ENABLE_ALWAYS; + } }; static action_handler_loadreport_t load_report_handler; diff --git a/efiXplorer/efiUi.h b/efiXplorer/efiUi.h index 65a3d81d..193133f3 100644 --- a/efiXplorer/efiUi.h +++ b/efiXplorer/efiUi.h @@ -1,6 +1,6 @@ /* * efiXplorer - * Copyright (C) 2020-2023 Binarly + * Copyright (C) 2020-2024 Binarly * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -26,243 +26,243 @@ //------------------------------------------------------------------------- // Vulns chooser class vulns_chooser_t : public chooser_t { - protected: - static const int widths_vulns[]; - static const char *const header_vulns[]; - - public: - eavec_t list; - json chooser_vulns; - - // this object must be allocated using `new` - vulns_chooser_t(const char *title, bool ok, std::vector vulns); - - // function that is used to decide whether a new chooser should be opened or - // we can use the existing one. The contents of the window are completely - // determined by its title - virtual const void *get_obj_id(size_t *len) const { - *len = strlen(title); - return title; +protected: + static const int widths_vulns[]; + static const char *const header_vulns[]; + +public: + eavec_t list; + json chooser_vulns; + + // this object must be allocated using `new` + vulns_chooser_t(const char *title, bool ok, std::vector vulns); + + // function that is used to decide whether a new chooser should be opened or + // we can use the existing one. The contents of the window are completely + // determined by its title + virtual const void *get_obj_id(size_t *len) const { + *len = strlen(title); + return title; + } + + // function that returns number of lines in the list + virtual size_t idaapi get_count() const { return list.size(); } + + // function that generates the list line + virtual void idaapi get_row(qstrvec_t *cols, int *icon_, chooser_item_attrs_t *attrs, + size_t n) const; + + // function that is called when the user hits `Enter` + virtual cbret_t idaapi enter(size_t n) { + if (n < list.size()) + jumpto(list[n]); + return cbret_t(); + } + +protected: + void build_list(bool ok, std::vector vulns) { + size_t n = 0; + for (auto vuln : vulns) { + list.push_back(vuln["address"]); + chooser_vulns[n] = vuln; + n++; } - - // function that returns number of lines in the list - virtual size_t idaapi get_count() const { return list.size(); } - - // function that generates the list line - virtual void idaapi get_row(qstrvec_t *cols, int *icon_, chooser_item_attrs_t *attrs, - size_t n) const; - - // function that is called when the user hits `Enter` - virtual cbret_t idaapi enter(size_t n) { - if (n < list.size()) - jumpto(list[n]); - return cbret_t(); - } - - protected: - void build_list(bool ok, std::vector vulns) { - size_t n = 0; - for (auto vuln : vulns) { - list.push_back(vuln["address"]); - chooser_vulns[n] = vuln; - n++; - } - ok = true; - }; + ok = true; + }; }; //------------------------------------------------------------------------- // GUIDs chooser class guids_chooser_t : public chooser_t { - protected: - static const int widths_guids[]; - static const char *const header_guids[]; - - public: - eavec_t list; - json chooser_guids; - - // this object must be allocated using `new` - guids_chooser_t(const char *title, bool ok, std::vector guids); - - // function that is used to decide whether a new chooser should be opened or - // we can use the existing one. The contents of the window are completely - // determined by its title - virtual const void *get_obj_id(size_t *len) const { - *len = strlen(title); - return title; +protected: + static const int widths_guids[]; + static const char *const header_guids[]; + +public: + eavec_t list; + json chooser_guids; + + // this object must be allocated using `new` + guids_chooser_t(const char *title, bool ok, std::vector guids); + + // function that is used to decide whether a new chooser should be opened or + // we can use the existing one. The contents of the window are completely + // determined by its title + virtual const void *get_obj_id(size_t *len) const { + *len = strlen(title); + return title; + } + + // function that returns number of lines in the list + virtual size_t idaapi get_count() const { return list.size(); } + + // function that generates the list line + virtual void idaapi get_row(qstrvec_t *cols, int *icon_, chooser_item_attrs_t *attrs, + size_t n) const; + + // function that is called when the user hits `Enter` + virtual cbret_t idaapi enter(size_t n) { + if (n < list.size()) + jumpto(list[n]); + return cbret_t(); + } + +protected: + void build_list(bool ok, std::vector guids) { + size_t n = 0; + for (auto guid : guids) { + list.push_back(guid["address"]); + chooser_guids[n] = guid; + n++; } - - // function that returns number of lines in the list - virtual size_t idaapi get_count() const { return list.size(); } - - // function that generates the list line - virtual void idaapi get_row(qstrvec_t *cols, int *icon_, chooser_item_attrs_t *attrs, - size_t n) const; - - // function that is called when the user hits `Enter` - virtual cbret_t idaapi enter(size_t n) { - if (n < list.size()) - jumpto(list[n]); - return cbret_t(); - } - - protected: - void build_list(bool ok, std::vector guids) { - size_t n = 0; - for (auto guid : guids) { - list.push_back(guid["address"]); - chooser_guids[n] = guid; - n++; - } - ok = true; - }; + ok = true; + }; }; //------------------------------------------------------------------------- // Protocols chooser class protocols_chooser_t : public chooser_t { - protected: - static const int widths_protocols[]; - static const char *const header_protocols[]; - - public: - eavec_t list; - json chooser_protocols; - std::string name_key; - - // this object must be allocated using `new` - protocols_chooser_t(const char *title, bool ok, std::vector interfaces, - std::string name_key); - - // function that is used to decide whether a new chooser should be opened or - // we can use the existing one. The contents of the window are completely - // determined by its title - virtual const void *get_obj_id(size_t *len) const { - *len = strlen(title); - return title; +protected: + static const int widths_protocols[]; + static const char *const header_protocols[]; + +public: + eavec_t list; + json chooser_protocols; + std::string name_key; + + // this object must be allocated using `new` + protocols_chooser_t(const char *title, bool ok, std::vector interfaces, + std::string name_key); + + // function that is used to decide whether a new chooser should be opened or + // we can use the existing one. The contents of the window are completely + // determined by its title + virtual const void *get_obj_id(size_t *len) const { + *len = strlen(title); + return title; + } + + // function that returns number of lines in the list + virtual size_t idaapi get_count() const { return list.size(); } + + // function that generates the list line + virtual void idaapi get_row(qstrvec_t *cols, int *icon_, chooser_item_attrs_t *attrs, + size_t n) const; + + // function that is called when the user hits `Enter` + virtual cbret_t idaapi enter(size_t n) { + if (n < list.size()) + jumpto(list[n]); + return cbret_t(); + } + +protected: + void build_list(bool ok, std::vector protocols) { + size_t n = 0; + for (auto protocol : protocols) { + list.push_back(protocol["xref"]); + chooser_protocols[n] = protocol; + n++; } - - // function that returns number of lines in the list - virtual size_t idaapi get_count() const { return list.size(); } - - // function that generates the list line - virtual void idaapi get_row(qstrvec_t *cols, int *icon_, chooser_item_attrs_t *attrs, - size_t n) const; - - // function that is called when the user hits `Enter` - virtual cbret_t idaapi enter(size_t n) { - if (n < list.size()) - jumpto(list[n]); - return cbret_t(); - } - - protected: - void build_list(bool ok, std::vector protocols) { - size_t n = 0; - for (auto protocol : protocols) { - list.push_back(protocol["xref"]); - chooser_protocols[n] = protocol; - n++; - } - ok = true; - }; + ok = true; + }; }; //------------------------------------------------------------------------- // Service chooser (address : service_name) class s_chooser_t : public chooser_t { - protected: - static const int widths_s[]; - static const char *const header_s[]; - - public: - eavec_t list; - json chooser_s; - - // this object must be allocated using `new` - s_chooser_t(const char *title, bool ok, std::vector services); - - // function that is used to decide whether a new chooser should be opened or - // we can use the existing one. The contents of the window are completely - // determined by its title - virtual const void *get_obj_id(size_t *len) const { - *len = strlen(title); - return title; - } - - // function that returns number of lines in the list - virtual size_t idaapi get_count() const { return list.size(); } - - // function that generates the list line - virtual void idaapi get_row(qstrvec_t *cols, int *icon_, chooser_item_attrs_t *attrs, - size_t n) const; - - // function that is called when the user hits `Enter` - virtual cbret_t idaapi enter(size_t n) { - if (n < list.size()) - jumpto(list[n]); - return cbret_t(); +protected: + static const int widths_s[]; + static const char *const header_s[]; + +public: + eavec_t list; + json chooser_s; + + // this object must be allocated using `new` + s_chooser_t(const char *title, bool ok, std::vector services); + + // function that is used to decide whether a new chooser should be opened or + // we can use the existing one. The contents of the window are completely + // determined by its title + virtual const void *get_obj_id(size_t *len) const { + *len = strlen(title); + return title; + } + + // function that returns number of lines in the list + virtual size_t idaapi get_count() const { return list.size(); } + + // function that generates the list line + virtual void idaapi get_row(qstrvec_t *cols, int *icon_, chooser_item_attrs_t *attrs, + size_t n) const; + + // function that is called when the user hits `Enter` + virtual cbret_t idaapi enter(size_t n) { + if (n < list.size()) + jumpto(list[n]); + return cbret_t(); + } + +protected: + void build_list(bool ok, std::vector services) { + size_t n = 0; + for (auto j_service : services) { + list.push_back(j_service["address"]); + chooser_s[n] = j_service; + n++; } - - protected: - void build_list(bool ok, std::vector services) { - size_t n = 0; - for (auto j_service : services) { - list.push_back(j_service["address"]); - chooser_s[n] = j_service; - n++; - } - ok = true; - }; + ok = true; + }; }; //------------------------------------------------------------------------- // NVRAM chooser class nvram_chooser_t : public chooser_t { - protected: - static const int widths_nvram[]; - static const char *const header_nvram[]; - - public: - eavec_t list; - json chooser_nvram; - - // this object must be allocated using `new` - nvram_chooser_t(const char *title, bool ok, std::vector nvrams); - - // function that is used to decide whether a new chooser should be opened or - // we can use the existing one. The contents of the window are completely - // determined by its title - virtual const void *get_obj_id(size_t *len) const { - *len = strlen(title); - return title; - } - - // function that returns number of lines in the list - virtual size_t idaapi get_count() const { return list.size(); } - - // function that generates the list line - virtual void idaapi get_row(qstrvec_t *cols, int *icon_, chooser_item_attrs_t *attrs, - size_t n) const; - - // function that is called when the user hits `Enter` - virtual cbret_t idaapi enter(size_t n) { - if (n < list.size()) - jumpto(list[n]); - return cbret_t(); +protected: + static const int widths_nvram[]; + static const char *const header_nvram[]; + +public: + eavec_t list; + json chooser_nvram; + + // this object must be allocated using `new` + nvram_chooser_t(const char *title, bool ok, std::vector nvrams); + + // function that is used to decide whether a new chooser should be opened or + // we can use the existing one. The contents of the window are completely + // determined by its title + virtual const void *get_obj_id(size_t *len) const { + *len = strlen(title); + return title; + } + + // function that returns number of lines in the list + virtual size_t idaapi get_count() const { return list.size(); } + + // function that generates the list line + virtual void idaapi get_row(qstrvec_t *cols, int *icon_, chooser_item_attrs_t *attrs, + size_t n) const; + + // function that is called when the user hits `Enter` + virtual cbret_t idaapi enter(size_t n) { + if (n < list.size()) + jumpto(list[n]); + return cbret_t(); + } + +protected: + void build_list(bool ok, std::vector nvrams) { + size_t n = 0; + for (auto nvram : nvrams) { + list.push_back(nvram["addr"]); + chooser_nvram[n] = nvram; + n++; } - - protected: - void build_list(bool ok, std::vector nvrams) { - size_t n = 0; - for (auto nvram : nvrams) { - list.push_back(nvram["addr"]); - chooser_nvram[n] = nvram; - n++; - } - ok = true; - }; + ok = true; + }; }; extern action_desc_t action_load_report; diff --git a/efiXplorer/efiUtils.cpp b/efiXplorer/efiUtils.cpp index b7eb469d..165c0edf 100644 --- a/efiXplorer/efiUtils.cpp +++ b/efiXplorer/efiUtils.cpp @@ -1,6 +1,6 @@ /* * efiXplorer - * Copyright (C) 2020-2023 Binarly + * Copyright (C) 2020-2024 Binarly * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -21,1072 +21,959 @@ #include "efiUtils.h" #include "efiGlobal.h" -#include "tables/efi_system_tables.h" - -struct pei_services_entry { - char name[256]; - uint32_t offset; - char description[1024]; - uint32_t nr_args; - char prototype[512]; - uint32_t count; - uint16_t ppi_guid_push_number; - uint16_t guid_offset; -}; +#include "efi_defs.h" // can be used after Hex-Rays based analysis std::vector g_get_smst_location_calls; std::vector g_smm_get_variable_calls; std::vector g_smm_set_variable_calls; -extern struct pei_services_entry pei_services_table[]; -extern size_t pei_services_table_size; - -struct variable_ppi_entry { - char name[256]; - uint32_t offset; - char description[1024]; - uint32_t nr_args; - char prototype[512]; -}; - -extern struct variable_ppi_entry variable_ppi_table[]; -extern size_t variable_ppi_table_size; - -static const char plugin_name[] = "efiXplorer"; - //-------------------------------------------------------------------------- // Set EFI_GUID type void setGuidType(ea_t ea) { - tinfo_t tinfo; - if (tinfo.get_named_type(get_idati(), "EFI_GUID")) { - apply_tinfo(ea, tinfo, TINFO_DEFINITE); - } + tinfo_t tinfo; + if (tinfo.get_named_type(get_idati(), "EFI_GUID")) { + apply_tinfo(ea, tinfo, TINFO_DEFINITE); + } } //-------------------------------------------------------------------------- // Set type and name void setTypeAndName(ea_t ea, std::string name, std::string type) { - set_name(ea, name.c_str(), SN_FORCE); - tinfo_t tinfo; - if (tinfo.get_named_type(get_idati(), type.c_str())) { - apply_tinfo(ea, tinfo, TINFO_DEFINITE); - } + set_name(ea, name.c_str(), SN_FORCE); + tinfo_t tinfo; + if (tinfo.get_named_type(get_idati(), type.c_str())) { + apply_tinfo(ea, tinfo, TINFO_DEFINITE); + } } //-------------------------------------------------------------------------- // Set const CHAR16 type void setConstChar16Type(ea_t ea) { - tinfo_t tinfo; - if (tinfo.get_named_type(get_idati(), "CHAR16")) { - tinfo.set_const(); - apply_tinfo(ea, tinfo, TINFO_DEFINITE); - } + tinfo_t tinfo; + if (tinfo.get_named_type(get_idati(), "CHAR16")) { + tinfo.set_const(); + apply_tinfo(ea, tinfo, TINFO_DEFINITE); + } } //-------------------------------------------------------------------------- // Get file format name (fileformatname) std::string getFileFormatName() { - char file_format[256] = {0}; - get_file_type_name(file_format, 256); - return static_cast(file_format); + char file_format[256] = {0}; + get_file_type_name(file_format, 256); + return static_cast(file_format); } //-------------------------------------------------------------------------- // Get input file type (64-bit, 32-bit image or UEFI firmware) uint8_t getInputFileType() { - processor_t &ph = PH; - auto filetype = inf_get_filetype(); - auto bits = inf_is_64bit() ? 64 : inf_is_32bit_exactly() ? 32 : 16; + processor_t &ph = PH; + auto filetype = inf_get_filetype(); + auto bits = inf_is_64bit() ? 64 : inf_is_32bit_exactly() ? 32 : 16; - // check if input file is UEFI firmware image - if (getFileFormatName().find("UEFI") != std::string::npos) { - return UEFI; - } + // check if input file is UEFI firmware image + if (getFileFormatName().find("UEFI") != std::string::npos) { + return UEFI; + } - if (filetype == f_PE || filetype == f_ELF) { - if (ph.id == PLFM_386) { - if (bits == 64) // x86 64-bit executable - return X64; - if (bits == 32) // x86 32-bit executable - return X86; - } - if (ph.id == PLFM_ARM) { - if (bits == 64) // ARM 64-bit executable - return ARM64; - } + if (filetype == f_PE || filetype == f_ELF) { + if (ph.id == PLFM_386) { + if (bits == 64) // x86 64-bit executable + return X64; + if (bits == 32) // x86 32-bit executable + return X86; + } + if (ph.id == PLFM_ARM) { + if (bits == 64) // ARM 64-bit executable + return ARM64; } - return UNSUPPORTED_TYPE; + } + return UNSUPPORTED_TYPE; } //-------------------------------------------------------------------------- // Get input file type (PEI or DXE-like). No reliable way to determine FFS // file type given only its PE/TE image section, so hello heuristics uint8_t guessFileType(uint8_t arch, std::vector *allGuids) { - if (arch == UEFI) { - return FTYPE_DXE_AND_THE_LIKE; - } - segment_t *hdr_seg = get_segm_by_name("HEADER"); - if (hdr_seg == NULL) { - return FTYPE_DXE_AND_THE_LIKE; - } - uint64_t signature = get_wide_word(hdr_seg->start_ea); - bool hasPeiGuids = false; - for (auto guid = allGuids->begin(); guid != allGuids->end(); guid++) { - json guidVal = *guid; - - if (static_cast(guidVal["name"]).find("PEI") != std::string::npos || - static_cast(guidVal["name"]).find("Pei") != std::string::npos) { - hasPeiGuids = true; - break; - } - } - - bool hasPeiInPath = false; - char fileName[0x1000] = {0}; - get_input_file_path(fileName, sizeof(fileName)); - auto fileNameStr = static_cast(fileName); - if ((fileNameStr.find("Pei") != std::string::npos || - fileNameStr.find("pei") != std::string::npos || signature == VZ) && - arch == X86) { - hasPeiInPath = true; - } - - if (signature == VZ || hasPeiGuids) { - msg("[%s] Parsing binary file as PEI, signature = %llx, hasPeiGuids = %d\n", - plugin_name, signature, hasPeiGuids); - return FTYPE_PEI; - } else { - msg("[%s] Parsing binary file as DXE/SMM, signature = %llx, hasPeiGuids = %d\n", - plugin_name, signature, hasPeiGuids); - return FTYPE_DXE_AND_THE_LIKE; - } + if (arch == UEFI) { + return FTYPE_DXE_AND_THE_LIKE; + } + segment_t *hdr_seg = get_segm_by_name("HEADER"); + if (hdr_seg == NULL) { + return FTYPE_DXE_AND_THE_LIKE; + } + uint64_t signature = get_wide_word(hdr_seg->start_ea); + bool hasPeiGuids = false; + for (auto guid = allGuids->begin(); guid != allGuids->end(); guid++) { + json guidVal = *guid; + + if (static_cast(guidVal["name"]).find("PEI") != std::string::npos || + static_cast(guidVal["name"]).find("Pei") != std::string::npos) { + hasPeiGuids = true; + break; + } + } + + bool hasPeiInPath = false; + char fileName[0x1000] = {0}; + get_input_file_path(fileName, sizeof(fileName)); + auto fileNameStr = static_cast(fileName); + if ((fileNameStr.find("Pei") != std::string::npos || + fileNameStr.find("pei") != std::string::npos || signature == VZ) && + arch == X86) { + hasPeiInPath = true; + } + + if (signature == VZ || hasPeiGuids) { + msg("[%s] Parsing binary file as PEI, signature = %llx, hasPeiGuids = %d\n", + g_plugin_name, signature, hasPeiGuids); + return FTYPE_PEI; + } else { + msg("[%s] Parsing binary file as DXE/SMM, signature = %llx, hasPeiGuids = %d\n", + g_plugin_name, signature, hasPeiGuids); + return FTYPE_DXE_AND_THE_LIKE; + } } uint8_t getFileType(std::vector *allGuids) { - uint8_t arch = getInputFileType(); - if (arch == UEFI || arch == X64) { - return FTYPE_DXE_AND_THE_LIKE; - } - auto ftype = guessFileType(arch, allGuids); - auto deflt = ftype == FTYPE_DXE_AND_THE_LIKE; - auto fmt_param = ftype == FTYPE_DXE_AND_THE_LIKE ? "DXE/SMM" : "PEI"; - auto btnId = ask_buttons("DXE/SMM", "PEI", "", deflt, "Parse file as %s", fmt_param); - if (btnId == ASKBTN_YES) { - return FTYPE_DXE_AND_THE_LIKE; - } else { - return FTYPE_PEI; - } -} - -//-------------------------------------------------------------------------- -// Get boot service description comment -std::string getBsComment(uint32_t offset, uint8_t arch) { - uint32_t offset_current; - std::string cmt = "gBS->"; - for (auto i = 0; i < BTABLE_LEN; i++) { - offset_current = boot_services_table[i].offset64; - if (arch == X86) { - offset_current = boot_services_table[i].offset32; - } - if (offset == offset_current) { - cmt += static_cast(boot_services_table[i].name) + "()\n" + - static_cast(boot_services_table[i].prototype) + "\n" + - static_cast(boot_services_table[i].parameters); - break; - } - } - return cmt; -} - -//-------------------------------------------------------------------------- -// Get Pei service description comment (X86 is assumed) -std::string getPeiSvcComment(uint32_t offset) { - std::string cmt = "gPS->"; - for (auto i = 0; i < pei_services_table_size; i++) { - if (offset == pei_services_table[i].offset) { - cmt += static_cast(pei_services_table[i].name) + "()\n" + - static_cast(pei_services_table[i].prototype); - break; - } - } - return cmt; -} - -//-------------------------------------------------------------------------- -// Get PPI service description comment (X86 is assumed) -std::string getPPICallComment(uint32_t offset, std::string name) { - std::string cmt = name + "->"; // VariablePpi - for (auto i = 0; i < variable_ppi_table_size; i++) { - if (offset == variable_ppi_table[i].offset) { - cmt += static_cast(variable_ppi_table[i].name) + "()\n" + - static_cast(variable_ppi_table[i].prototype); - break; - } - } - return cmt; -} - -//-------------------------------------------------------------------------- -// Get SMM service description comment -std::string getSmmVarComment() { - std::string name = "EFI_SMM_VARIABLE_PROTOCOL"; - std::string prototype = "EFI_STATUS (EFIAPI *EFI_GET_VARIABLE)" - "(IN CHAR16 *VariableName, " - "IN EFI_GUID *VendorGuid, " - "OUT UINT32 *Attributes, OPTIONAL " - "IN OUT UINTN *DataSize, " - "OUT VOID *Data OPTIONAL);"; - - std::string cmt = name + "->SmmGetVariable()\n" + prototype; - return cmt; -} - -//-------------------------------------------------------------------------- -// Get runtime service description comment -std::string getRtComment(uint32_t offset, uint8_t arch) { - ea_t offset_arch; - std::string cmt = "gRT->"; - for (auto i = 0; i < RTABLE_LEN; i++) { - offset_arch = runtime_services_table[i].offset64; - if (arch == X86) { - offset_arch = runtime_services_table[i].offset32; - } - if (offset == offset_arch) { - cmt += static_cast(runtime_services_table[i].name) + "()\n" + - static_cast(runtime_services_table[i].prototype) + "\n" + - static_cast(runtime_services_table[i].parameters); - break; - } - } - return cmt; + uint8_t arch = getInputFileType(); + if (arch == UEFI || arch == X64) { + return FTYPE_DXE_AND_THE_LIKE; + } + auto ftype = guessFileType(arch, allGuids); + auto deflt = ftype == FTYPE_DXE_AND_THE_LIKE; + auto fmt_param = ftype == FTYPE_DXE_AND_THE_LIKE ? "DXE/SMM" : "PEI"; + auto btnId = ask_buttons("DXE/SMM", "PEI", "", deflt, "Parse file as %s", fmt_param); + if (btnId == ASKBTN_YES) { + return FTYPE_DXE_AND_THE_LIKE; + } else { + return FTYPE_PEI; + } } //-------------------------------------------------------------------------- // Find address of global gBS var for X64 module for each service ea_t findUnknownBsVarX64(ea_t ea) { - ea_t resAddr = 0; - insn_t insn; - - // Check 10 instructions below - for (int i = 0; i < 10; i++) { - decode_insn(&insn, ea); - if (insn.itype == NN_mov && insn.ops[0].type == o_reg && - insn.ops[0].reg == REG_RAX && insn.ops[1].type == o_mem) { - resAddr = insn.ops[1].addr; - break; - } - ea = prev_head(ea, 0); + ea_t resAddr = 0; + insn_t insn; + + // Check 10 instructions below + for (int i = 0; i < 10; i++) { + decode_insn(&insn, ea); + if (insn.itype == NN_mov && insn.ops[0].type == o_reg && insn.ops[0].reg == REG_RAX && + insn.ops[1].type == o_mem) { + resAddr = insn.ops[1].addr; + break; } - return resAddr; + ea = prev_head(ea, 0); + } + return resAddr; } //-------------------------------------------------------------------------- // Get all xrefs for given address std::vector getXrefs(ea_t addr) { - std::vector xrefs; - ea_t xref = get_first_dref_to(addr); - while (xref != BADADDR) { - xrefs.push_back(xref); - xref = get_next_dref_to(addr, xref); - } - return xrefs; + std::vector xrefs; + ea_t xref = get_first_dref_to(addr); + while (xref != BADADDR) { + xrefs.push_back(xref); + xref = get_next_dref_to(addr, xref); + } + return xrefs; } //-------------------------------------------------------------------------- // Get all xrefs for given array element std::vector getXrefsToArray(ea_t addr) { - ea_t first_ea; - ea_t ea = addr; - while (true) { - auto ptr = get_qword(ea); - auto xrefs = getXrefs(ptr); - if (std::find(xrefs.begin(), xrefs.end(), ea) == xrefs.end()) { - break; - } - first_ea = ea; - ea -= 8; + ea_t first_ea; + ea_t ea = addr; + while (true) { + auto ptr = get_qword(ea); + auto xrefs = getXrefs(ptr); + if (std::find(xrefs.begin(), xrefs.end(), ea) == xrefs.end()) { + break; } - return getXrefs(first_ea); + first_ea = ea; + ea -= 8; + } + return getXrefs(first_ea); } //-------------------------------------------------------------------------- // Wrapper for op_stroff function bool opStroff(ea_t addr, std::string type) { - tinfo_t tinfo; - if (!tinfo.get_named_type(get_idati(), type.c_str())) { - return false; - } + tinfo_t tinfo; + if (!tinfo.get_named_type(get_idati(), type.c_str())) { + return false; + } - // use force_tid() instead of get_tid() - // to import type if it's not imported - tid_t tid = tinfo.force_tid(); - if (tid == BADADDR) { - return false; - } + // use force_tid() instead of get_tid() + // to import type if it's not imported + tid_t tid = tinfo.force_tid(); + if (tid == BADADDR) { + return false; + } - insn_t insn; - decode_insn(&insn, addr); - return op_stroff(insn, 0, &tid, 1, 0); + insn_t insn; + decode_insn(&insn, addr); + return op_stroff(insn, 0, &tid, 1, 0); } //-------------------------------------------------------------------------- // Get pointer to named type and apply it bool setPtrType(ea_t addr, std::string type) { - tinfo_t tinfo; - if (!tinfo.get_named_type(get_idati(), type.c_str())) { - return false; - } - tinfo_t ptrTinfo; - ptrTinfo.create_ptr(tinfo); - apply_tinfo(addr, ptrTinfo, TINFO_DEFINITE); - return true; + tinfo_t tinfo; + if (!tinfo.get_named_type(get_idati(), type.c_str())) { + return false; + } + tinfo_t ptrTinfo; + ptrTinfo.create_ptr(tinfo); + apply_tinfo(addr, ptrTinfo, TINFO_DEFINITE); + return true; } //-------------------------------------------------------------------------- // Set name and apply pointer to named type void setPtrTypeAndName(ea_t ea, std::string name, std::string type) { - set_name(ea, name.c_str(), SN_FORCE); - setPtrType(ea, type.c_str()); + set_name(ea, name.c_str(), SN_FORCE); + setPtrType(ea, type.c_str()); } //-------------------------------------------------------------------------- // Get guids.json file name std::filesystem::path getGuidsJsonFile() { - std::filesystem::path guidsJsonPath; + std::filesystem::path guidsJsonPath; - // check {idadir}/plugins/guids.json - guidsJsonPath /= idadir("plugins"); - guidsJsonPath /= "guids.json"; - if (std::filesystem::exists(guidsJsonPath)) { - return guidsJsonPath; - } - - // check {idadir}/plugins/guids/guids.json - guidsJsonPath.clear(); - guidsJsonPath /= idadir("plugins"); - guidsJsonPath /= "guids"; - guidsJsonPath /= "guids.json"; - if (std::filesystem::exists(guidsJsonPath)) { - return guidsJsonPath; - } - - // Try to load it from the per-user directory. - guidsJsonPath.clear(); - guidsJsonPath /= get_user_idadir(); - guidsJsonPath /= "plugins"; - guidsJsonPath /= "guids.json"; - if (std::filesystem::exists(guidsJsonPath)) { - return guidsJsonPath; - } - - guidsJsonPath.clear(); - guidsJsonPath /= get_user_idadir(); - guidsJsonPath /= "plugins"; - guidsJsonPath /= "guids"; - guidsJsonPath /= "guids.json"; - if (std::filesystem::exists(guidsJsonPath)) { - return guidsJsonPath; - } - - // Does not exist. - guidsJsonPath.clear(); + // check {idadir}/plugins/guids.json + guidsJsonPath /= idadir("plugins"); + guidsJsonPath /= "guids.json"; + if (std::filesystem::exists(guidsJsonPath)) { + return guidsJsonPath; + } + + // check {idadir}/plugins/guids/guids.json + guidsJsonPath.clear(); + guidsJsonPath /= idadir("plugins"); + guidsJsonPath /= "guids"; + guidsJsonPath /= "guids.json"; + if (std::filesystem::exists(guidsJsonPath)) { + return guidsJsonPath; + } + + // Try to load it from the per-user directory. + guidsJsonPath.clear(); + guidsJsonPath /= get_user_idadir(); + guidsJsonPath /= "plugins"; + guidsJsonPath /= "guids.json"; + if (std::filesystem::exists(guidsJsonPath)) { return guidsJsonPath; + } + + guidsJsonPath.clear(); + guidsJsonPath /= get_user_idadir(); + guidsJsonPath /= "plugins"; + guidsJsonPath /= "guids"; + guidsJsonPath /= "guids.json"; + if (std::filesystem::exists(guidsJsonPath)) { + return guidsJsonPath; + } + + // Does not exist. + guidsJsonPath.clear(); + return guidsJsonPath; } //-------------------------------------------------------------------------- // Get json summary file name std::filesystem::path getSummaryFile() { - std::string idbPath; - idbPath = get_path(PATH_TYPE_IDB); - std::filesystem::path logFile; - logFile /= idbPath; - logFile.replace_extension(".json"); - return logFile; + std::string idbPath; + idbPath = get_path(PATH_TYPE_IDB); + std::filesystem::path logFile; + logFile /= idbPath; + logFile.replace_extension(".json"); + return logFile; } //-------------------------------------------------------------------------- // Check for summary json file exist bool summaryJsonExist() { - std::string idbPath; - idbPath = get_path(PATH_TYPE_IDB); - std::filesystem::path logFile; - logFile /= idbPath; - logFile.replace_extension(".json"); - return std::filesystem::exists(logFile); + std::string idbPath; + idbPath = get_path(PATH_TYPE_IDB); + std::filesystem::path logFile; + logFile /= idbPath; + logFile.replace_extension(".json"); + return std::filesystem::exists(logFile); } //-------------------------------------------------------------------------- // Change EFI_SYSTEM_TABLE *SystemTable to EFI_PEI_SERVICES **PeiService // for ModuleEntryPoint void setEntryArgToPeiSvc() { - for (auto idx = 0; idx < get_entry_qty(); idx++) { - uval_t ord = get_entry_ordinal(idx); - ea_t start_ea = get_entry(ord); - tinfo_t tif_ea; - if (guess_tinfo(&tif_ea, start_ea) == GUESS_FUNC_FAILED) { - msg("[%s] guess_tinfo failed, start_ea = 0x%016llX, idx=%d\n", plugin_name, - u64_addr(start_ea), idx); - continue; - } - func_type_data_t funcdata; - if (!tif_ea.get_func_details(&funcdata)) { - msg("[%s] get_func_details failed, %d\n", plugin_name, idx); - continue; - } - tinfo_t tif_pei; - bool res = tif_pei.get_named_type(get_idati(), "EFI_PEI_SERVICES"); - if (!res) { - msg("[%s] get_named_type failed, res = %d, idx=%d\n", plugin_name, res, idx); - continue; - } - tinfo_t ptrTinfo; - tinfo_t ptrPtrTinfo; - ptrTinfo.create_ptr(tif_pei); - ptrPtrTinfo.create_ptr(ptrTinfo); - // funcdata.size() does not work for aarch64 - if (funcdata.size() == 2) { - funcdata[1].type = ptrPtrTinfo; - funcdata[1].name = "PeiServices"; - tinfo_t func_tinfo; - if (!func_tinfo.create_func(funcdata)) { - msg("[%s] create_func failed, idx=%d\n", plugin_name, idx); - continue; - } - if (!apply_tinfo(start_ea, func_tinfo, TINFO_DEFINITE)) { - msg("[%s] apply_tinfo failed, idx=%d\n", plugin_name, idx); - continue; - } - } - } -} - -bool setRetToPeiSvc(ea_t start_ea) { + for (auto idx = 0; idx < get_entry_qty(); idx++) { + uval_t ord = get_entry_ordinal(idx); + ea_t start_ea = get_entry(ord); tinfo_t tif_ea; if (guess_tinfo(&tif_ea, start_ea) == GUESS_FUNC_FAILED) { - msg("[%s] guess_tinfo failed, function = 0x%016llX", plugin_name, - u64_addr(start_ea)); - return false; + msg("[%s] guess_tinfo failed, start_ea = 0x%016llX, idx=%d\n", g_plugin_name, + u64_addr(start_ea), idx); + continue; } - func_type_data_t fi; - if (!tif_ea.get_func_details(&fi)) { - msg("[%s] get_func_details failed, function = 0x%016llX", plugin_name, - u64_addr(start_ea)); - return false; + func_type_data_t funcdata; + if (!tif_ea.get_func_details(&funcdata)) { + msg("[%s] get_func_details failed, %d\n", g_plugin_name, idx); + continue; } tinfo_t tif_pei; bool res = tif_pei.get_named_type(get_idati(), "EFI_PEI_SERVICES"); if (!res) { - msg("[%s] get_named_type failed, res = %d\n", plugin_name, res); - return false; + msg("[%s] get_named_type failed, res = %d, idx=%d\n", g_plugin_name, res, idx); + continue; } tinfo_t ptrTinfo; tinfo_t ptrPtrTinfo; ptrTinfo.create_ptr(tif_pei); ptrPtrTinfo.create_ptr(ptrTinfo); + // funcdata.size() does not work for aarch64 + if (funcdata.size() == 2) { + funcdata[1].type = ptrPtrTinfo; + funcdata[1].name = "PeiServices"; + tinfo_t func_tinfo; + if (!func_tinfo.create_func(funcdata)) { + msg("[%s] create_func failed, idx=%d\n", g_plugin_name, idx); + continue; + } + if (!apply_tinfo(start_ea, func_tinfo, TINFO_DEFINITE)) { + msg("[%s] apply_tinfo failed, idx=%d\n", g_plugin_name, idx); + continue; + } + } + } +} - fi.rettype = ptrPtrTinfo; - - tinfo_t func_tinfo; - if (!func_tinfo.create_func(fi)) { - msg("[%s] create_func failed, function = 0x%016llX", plugin_name, - u64_addr(start_ea)); - return false; - } - if (!apply_tinfo(start_ea, func_tinfo, TINFO_DEFINITE)) { - msg("[%s] apply_tinfo failed, function = 0x%016llX", plugin_name, - u64_addr(start_ea)); - return false; - } - return true; +bool setRetToPeiSvc(ea_t start_ea) { + tinfo_t tif_ea; + if (guess_tinfo(&tif_ea, start_ea) == GUESS_FUNC_FAILED) { + msg("[%s] guess_tinfo failed, function = 0x%016llX", g_plugin_name, + u64_addr(start_ea)); + return false; + } + func_type_data_t fi; + if (!tif_ea.get_func_details(&fi)) { + msg("[%s] get_func_details failed, function = 0x%016llX", g_plugin_name, + u64_addr(start_ea)); + return false; + } + tinfo_t tif_pei; + bool res = tif_pei.get_named_type(get_idati(), "EFI_PEI_SERVICES"); + if (!res) { + msg("[%s] get_named_type failed, res = %d\n", g_plugin_name, res); + return false; + } + tinfo_t ptrTinfo; + tinfo_t ptrPtrTinfo; + ptrTinfo.create_ptr(tif_pei); + ptrPtrTinfo.create_ptr(ptrTinfo); + + fi.rettype = ptrPtrTinfo; + + tinfo_t func_tinfo; + if (!func_tinfo.create_func(fi)) { + msg("[%s] create_func failed, function = 0x%016llX", g_plugin_name, + u64_addr(start_ea)); + return false; + } + if (!apply_tinfo(start_ea, func_tinfo, TINFO_DEFINITE)) { + msg("[%s] apply_tinfo failed, function = 0x%016llX", g_plugin_name, + u64_addr(start_ea)); + return false; + } + return true; } int parseEfiPeiServices4() { - return parse_decls(nullptr, - "struct EFI_PEI_SERVICES_4 {\n" - " EFI_PEI_SERVICES **PeiServices;\n" - " UINT32 BaseAddress;\n" - "};", - msg, HTI_DCL); + return parse_decls(nullptr, + "struct EFI_PEI_SERVICES_4 {\n" + " EFI_PEI_SERVICES **PeiServices;\n" + " UINT32 BaseAddress;\n" + "};", + msg, HTI_DCL); } int parseEfiPeiSidt() { - return parse_decls(nullptr, - "struct EFI_PEI_SIDT {\n" - " UINT16 Limit;\n" - " int *__shifted(EFI_PEI_SERVICES_4, 4) BaseAddress;\n" - "};", - msg, HTI_DCL | HTI_PAK1); + return parse_decls(nullptr, + "struct EFI_PEI_SIDT {\n" + " UINT16 Limit;\n" + " int *__shifted(EFI_PEI_SERVICES_4, 4) BaseAddress;\n" + "};", + msg, HTI_DCL | HTI_PAK1); } //-------------------------------------------------------------------------- // Add EFI_PEI_SERVICES_4 structure bool addStrucForShiftedPtr() { #if IDA_SDK_VERSION < 900 - auto sid = add_struc(BADADDR, "EFI_PEI_SERVICES_4"); - if (sid == BADADDR) { - return false; - } + auto sid = add_struc(BADADDR, "EFI_PEI_SERVICES_4"); + if (sid == BADADDR) { + return false; + } - auto new_struct = get_struc(sid); - if (new_struct == nullptr) { - return false; - } + auto new_struct = get_struc(sid); + if (new_struct == nullptr) { + return false; + } - add_struc_member(new_struct, nullptr, 0, dword_flag(), nullptr, 4); - add_struc_member(new_struct, nullptr, 4, dword_flag(), nullptr, 4); - set_member_name(new_struct, 0, "PeiServices"); - set_member_name(new_struct, 4, "BaseAddress"); + add_struc_member(new_struct, nullptr, 0, dword_flag(), nullptr, 4); + add_struc_member(new_struct, nullptr, 4, dword_flag(), nullptr, 4); + set_member_name(new_struct, 0, "PeiServices"); + set_member_name(new_struct, 4, "BaseAddress"); - tinfo_t tinfo; - if (!tinfo.get_named_type(get_idati(), "EFI_PEI_SERVICES")) { - return false; - } + tinfo_t tinfo; + if (!tinfo.get_named_type(get_idati(), "EFI_PEI_SERVICES")) { + return false; + } - // set type "EFI_PEI_SERVICES **PeiServices" - tinfo_t ptrTinfo; - tinfo_t ptr2Tinfo; - ptrTinfo.create_ptr(tinfo); - ptr2Tinfo.create_ptr(ptrTinfo); + // set type "EFI_PEI_SERVICES **PeiServices" + tinfo_t ptrTinfo; + tinfo_t ptr2Tinfo; + ptrTinfo.create_ptr(tinfo); + ptr2Tinfo.create_ptr(ptrTinfo); - auto member = get_member_by_name(new_struct, "PeiServices"); - set_member_tinfo(new_struct, member, 0, ptr2Tinfo, 0); + auto member = get_member_by_name(new_struct, "PeiServices"); + set_member_tinfo(new_struct, member, 0, ptr2Tinfo, 0); - return true; + return true; #endif - // return true if there are no errors from parse_decls() - return !parseEfiPeiServices4() && !parseEfiPeiSidt(); + // return true if there are no errors from parse_decls() + return !parseEfiPeiServices4() && !parseEfiPeiSidt(); } //-------------------------------------------------------------------------- // Change the value of a number to match the data type uval_t truncImmToDtype(uval_t value, op_dtype_t dtype) { - switch (dtype) { - case dt_byte: - return value & 0xff; - case dt_word: - return value & 0xffff; - case dt_dword: - return value & 0xffffffff; - default: - return value; - } + switch (dtype) { + case dt_byte: + return value & 0xff; + case dt_word: + return value & 0xffff; + case dt_dword: + return value & 0xffffffff; + default: + return value; + } } //-------------------------------------------------------------------------- // Get module name by address qstring getModuleNameLoader(ea_t address) { - segment_t *seg = getseg(address); - qstring seg_name; - get_segm_name(&seg_name, seg); - return seg_name.remove(seg_name.size() - 7, seg_name.size()); + segment_t *seg = getseg(address); + qstring seg_name; + get_segm_name(&seg_name, seg); + return seg_name.remove(seg_name.size() - 7, seg_name.size()); } //-------------------------------------------------------------------------- // Get GUID data by address json getGuidByAddr(ea_t addr) { - return json::array( - {get_wide_dword(addr), get_wide_word(addr + 4), get_wide_word(addr + 6), - get_wide_byte(addr + 8), get_wide_byte(addr + 9), get_wide_byte(addr + 10), - get_wide_byte(addr + 11), get_wide_byte(addr + 12), get_wide_byte(addr + 13), - get_wide_byte(addr + 14), get_wide_byte(addr + 15)}); + return json::array( + {get_wide_dword(addr), get_wide_word(addr + 4), get_wide_word(addr + 6), + get_wide_byte(addr + 8), get_wide_byte(addr + 9), get_wide_byte(addr + 10), + get_wide_byte(addr + 11), get_wide_byte(addr + 12), get_wide_byte(addr + 13), + get_wide_byte(addr + 14), get_wide_byte(addr + 15)}); } //-------------------------------------------------------------------------- // Validate GUID value bool checkGuid(json guid) { - if (static_cast(guid[0]) == 0x00000000 && (uint16_t)guid[1] == 0x0000) { - return false; - } - if (static_cast(guid[0]) == 0xffffffff && (uint16_t)guid[1] == 0xffff) { - return false; - } - return true; + if (static_cast(guid[0]) == 0x00000000 && (uint16_t)guid[1] == 0x0000) { + return false; + } + if (static_cast(guid[0]) == 0xffffffff && (uint16_t)guid[1] == 0xffff) { + return false; + } + return true; } //-------------------------------------------------------------------------- // Convert GUID value to string std::string getGuidFromValue(json guid) { - char guidStr[37] = {0}; - snprintf(guidStr, 37, "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X", - static_cast(guid[0]), static_cast(guid[1]), - static_cast(guid[2]), static_cast(guid[3]), - static_cast(guid[4]), static_cast(guid[5]), - static_cast(guid[6]), static_cast(guid[7]), - static_cast(guid[8]), static_cast(guid[9]), - static_cast(guid[10])); - return static_cast(guidStr); + char guidStr[37] = {0}; + snprintf(guidStr, 37, "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X", + static_cast(guid[0]), static_cast(guid[1]), + static_cast(guid[2]), static_cast(guid[3]), + static_cast(guid[4]), static_cast(guid[5]), + static_cast(guid[6]), static_cast(guid[7]), + static_cast(guid[8]), static_cast(guid[9]), + static_cast(guid[10])); + return static_cast(guidStr); } std::vector unpackGuid(std::string guid) { - std::vector res; - std::string delimiter = "-"; - std::string byte_str; - uint8_t byte; - size_t pos = 0; - - auto index = 0; - while ((pos = guid.find(delimiter)) != std::string::npos) { - std::vector tmp; - auto hex = guid.substr(0, pos); - if (hex.size() % 2) { - break; - } - for (auto i = 0; i < hex.size(); i += 2) { - byte_str = hex.substr(i, 2); - byte = static_cast(strtol(byte_str.c_str(), NULL, 16)); - tmp.push_back(byte); - } - if (index != 3) { - res.insert(res.end(), tmp.rbegin(), tmp.rend()); - } else { - res.insert(res.end(), tmp.begin(), tmp.end()); - } - index += 1; - guid.erase(0, pos + delimiter.size()); - tmp.clear(); + std::vector res; + std::string delimiter = "-"; + std::string byte_str; + uint8_t byte; + size_t pos = 0; + + auto index = 0; + while ((pos = guid.find(delimiter)) != std::string::npos) { + std::vector tmp; + auto hex = guid.substr(0, pos); + if (hex.size() % 2) { + break; + } + for (auto i = 0; i < hex.size(); i += 2) { + byte_str = hex.substr(i, 2); + byte = static_cast(strtol(byte_str.c_str(), NULL, 16)); + tmp.push_back(byte); + } + if (index != 3) { + res.insert(res.end(), tmp.rbegin(), tmp.rend()); + } else { + res.insert(res.end(), tmp.begin(), tmp.end()); } + index += 1; + guid.erase(0, pos + delimiter.size()); + tmp.clear(); + } - for (auto i = 0; i < guid.size(); i += 2) { - byte_str = guid.substr(i, 2); - byte = static_cast(strtol(byte_str.c_str(), NULL, 16)); - res.push_back(byte); - } + for (auto i = 0; i < guid.size(); i += 2) { + byte_str = guid.substr(i, 2); + byte = static_cast(strtol(byte_str.c_str(), NULL, 16)); + res.push_back(byte); + } - return res; + return res; } std::vector searchProtocol(std::string protocol) { - uchar bytes[17] = {0}; - std::vector res; - auto guid_bytes = unpackGuid(protocol); - std::copy(guid_bytes.begin(), guid_bytes.end(), bytes); - ea_t start = 0; - while (true) { + uchar bytes[17] = {0}; + std::vector res; + auto guid_bytes = unpackGuid(protocol); + std::copy(guid_bytes.begin(), guid_bytes.end(), bytes); + ea_t start = 0; + while (true) { #if IDA_SDK_VERSION < 900 - ea_t addr = bin_search2(start, BADADDR, bytes, nullptr, 16, BIN_SEARCH_FORWARD); + ea_t addr = bin_search2(start, BADADDR, bytes, nullptr, 16, BIN_SEARCH_FORWARD); #else - ea_t addr = bin_search3(start, BADADDR, bytes, nullptr, 16, BIN_SEARCH_FORWARD); + ea_t addr = bin_search3(start, BADADDR, bytes, nullptr, 16, BIN_SEARCH_FORWARD); #endif - if (addr == BADADDR) { - break; - } - res.push_back(addr); - start = addr + 16; + if (addr == BADADDR) { + break; } - return res; + res.push_back(addr); + start = addr + 16; + } + return res; } bool checkInstallProtocol(ea_t ea) { - insn_t insn; - // search for `call [REG + offset]` insn - // offset in [0x80, 0xA8, 0x148] - ea_t addr = ea; - for (auto i = 0; i < 16; i++) { - addr = next_head(addr, BADADDR); - decode_insn(&insn, addr); - if ((insn.itype == NN_jmpni || insn.itype == NN_callni) && - insn.ops[0].type == o_displ) { - auto service = insn.ops[0].addr; - // check for InstallProtocolInterface, InstallMultipleProtocolInterfaces, - // SmmInstallProtocolInterface - if (service == 0x80 || service == 0xa8 || service == 0x148) { - return true; - } - } + insn_t insn; + // search for `call [REG + offset]` insn + // offset in [0x80, 0xA8, 0x148] + ea_t addr = ea; + for (auto i = 0; i < 16; i++) { + addr = next_head(addr, BADADDR); + decode_insn(&insn, addr); + if ((insn.itype == NN_jmpni || insn.itype == NN_callni) && + insn.ops[0].type == o_displ) { + auto service = insn.ops[0].addr; + // check for InstallProtocolInterface, InstallMultipleProtocolInterfaces, + // SmmInstallProtocolInterface + if (service == 0x80 || service == 0xa8 || service == 0x148) { + return true; + } } - return false; + } + return false; } //-------------------------------------------------------------------------- // Convert 64-bit value to hex string std::string getHex(uint64_t value) { - char hexstr[21] = {}; - snprintf(hexstr, 21, "%llX", value); - return static_cast(hexstr); + char hexstr[21] = {}; + snprintf(hexstr, 21, "%llX", value); + return static_cast(hexstr); } //-------------------------------------------------------------------------- // Make sure the first argument looks like protocol bool bootServiceProtCheck(ea_t callAddr) { - bool valid = false; - insn_t insn; - auto addr = prev_head(callAddr, 0); + bool valid = false; + insn_t insn; + auto addr = prev_head(callAddr, 0); + decode_insn(&insn, addr); + while (!is_basic_block_end(insn, false)) { + + // for next iteration decode_insn(&insn, addr); - while (!is_basic_block_end(insn, false)) { - - // for next iteration - decode_insn(&insn, addr); - addr = prev_head(addr, 0); - - // check current instruction - if (insn.itype == NN_lea && insn.ops[0].type == o_reg && - insn.ops[0].reg == REG_RCX) { - if (insn.ops[1].type == o_mem) { - // will still be a false positive if the Handle in - // SmmInstallProtocolInterface is a global variable) - valid = true; - } - break; - } + addr = prev_head(addr, 0); + + // check current instruction + if (insn.itype == NN_lea && insn.ops[0].type == o_reg && insn.ops[0].reg == REG_RCX) { + if (insn.ops[1].type == o_mem) { + // will still be a false positive if the Handle in + // SmmInstallProtocolInterface is a global variable) + valid = true; + } + break; } - return valid; + } + return valid; } //-------------------------------------------------------------------------- // Make sure that the address does not belong to the protocol interface bool bootServiceProtCheckXrefs(ea_t callAddr) { - insn_t insn; - for (auto xref : getXrefs(callAddr)) { - decode_insn(&insn, xref); - if (insn.itype == NN_lea && insn.ops[0].type == o_reg && - insn.ops[0].reg == REG_R8) { - // load interface instruction - return false; - } + insn_t insn; + for (auto xref : getXrefs(callAddr)) { + decode_insn(&insn, xref); + if (insn.itype == NN_lea && insn.ops[0].type == o_reg && insn.ops[0].reg == REG_R8) { + // load interface instruction + return false; } - return true; + } + return true; } bool markCopy(ea_t codeAddr, ea_t varAddr, std::string type) { - insn_t insn; - int reg = -1; - ea_t ea = codeAddr; - ea_t varCopy = BADADDR; + insn_t insn; + int reg = -1; + ea_t ea = codeAddr; + ea_t varCopy = BADADDR; + decode_insn(&insn, ea); + + // get `reg` value + if (insn.itype == NN_mov && insn.ops[0].type == o_reg && insn.ops[1].type == o_mem && + insn.ops[1].addr == varAddr) { + reg = insn.ops[0].reg; + } + + if (reg == -1) { + return false; + } + + for (auto i = 0; i < 8; ++i) { + ea = next_head(ea, BADADDR); decode_insn(&insn, ea); - // get `reg` value - if (insn.itype == NN_mov && insn.ops[0].type == o_reg && insn.ops[1].type == o_mem && - insn.ops[1].addr == varAddr) { - reg = insn.ops[0].reg; + if (is_basic_block_end(insn, false)) { + break; } - if (reg == -1) { - return false; + if ((insn.itype == NN_callni || insn.itype == NN_call) || + (insn.ops[0].type == o_reg && insn.ops[0].reg == reg)) { + break; } - for (auto i = 0; i < 8; ++i) { - ea = next_head(ea, BADADDR); - decode_insn(&insn, ea); - - if (is_basic_block_end(insn, false)) { - break; - } - - if ((insn.itype == NN_callni || insn.itype == NN_call) || - (insn.ops[0].type == o_reg && insn.ops[0].reg == reg)) { - break; - } - - // get `varCopy` - if (insn.itype == NN_mov && insn.ops[0].type == o_mem && - insn.ops[1].type == o_reg && insn.ops[1].reg == reg) { - varCopy = insn.ops[0].addr; - msg("[efiXplorer] Found copy for global variable: 0x%016llX\n", u64_addr(ea)); - break; - } + // get `varCopy` + if (insn.itype == NN_mov && insn.ops[0].type == o_mem && insn.ops[1].type == o_reg && + insn.ops[1].reg == reg) { + varCopy = insn.ops[0].addr; + msg("[efiXplorer] Found copy for global variable: 0x%016llX\n", u64_addr(ea)); + break; } + } - if (varCopy == BADADDR) { - return false; - } + if (varCopy == BADADDR) { + return false; + } - std::string name; + std::string name; - if (type == "gSmst") { - setPtrTypeAndName(varCopy, "gSmst", "_EFI_SMM_SYSTEM_TABLE2"); - } + if (type == "gSmst") { + setPtrTypeAndName(varCopy, "gSmst", "_EFI_SMM_SYSTEM_TABLE2"); + } - if (type == "gBS") { - setPtrTypeAndName(varCopy, "gBS", "EFI_BOOT_SERVICES"); - } + if (type == "gBS") { + setPtrTypeAndName(varCopy, "gBS", "EFI_BOOT_SERVICES"); + } - if (type == "gRT") { - setPtrTypeAndName(varCopy, "gRT", "EFI_RUNTIME_SERVICES"); - } + if (type == "gRT") { + setPtrTypeAndName(varCopy, "gRT", "EFI_RUNTIME_SERVICES"); + } - return true; + return true; } bool markCopiesForGlobalVars(std::vector globalVars, std::string type) { - for (auto var : globalVars) { - auto xrefs = getXrefs(var); - for (auto addr : xrefs) { - markCopy(addr, var, type); - } + for (auto var : globalVars) { + auto xrefs = getXrefs(var); + for (auto addr : xrefs) { + markCopy(addr, var, type); } - return true; + } + return true; } //-------------------------------------------------------------------------- // Generate name string from type std::string typeToName(std::string type) { - std::string result; - size_t counter = 0; - for (char const &c : type) { - if ((c >= 'a' && c <= 'z') || (c >= '0' && c <= '9')) { - result.push_back(c); - counter += 1; - continue; - } - - if (c >= 'A' && c <= 'Z') { - if (counter > 0) { - result.push_back(c + 32); - } else - result.push_back(c); - counter += 1; - continue; - } - - if (c == '_') { - counter = 0; - } else { - counter += 1; - } + std::string result; + size_t counter = 0; + for (char const &c : type) { + if ((c >= 'a' && c <= 'z') || (c >= '0' && c <= '9')) { + result.push_back(c); + counter += 1; + continue; + } + + if (c >= 'A' && c <= 'Z') { + if (counter > 0) { + result.push_back(c + 32); + } else + result.push_back(c); + counter += 1; + continue; + } + + if (c == '_') { + counter = 0; + } else { + counter += 1; } - return result; + } + return result; } xreflist_t xrefsToStackVar(ea_t funcEa, qstring varName) { - xreflist_t xrefs_list; + xreflist_t xrefs_list; #if IDA_SDK_VERSION < 900 - struc_t *frame = get_frame(funcEa); - func_t *func = get_func(funcEa); - member_t member; // Get member by name - for (int i = 0; i < frame->memqty; i++) { - member = frame->members[i]; - qstring name; - get_member_name(&name, frame->members[i].id); - if (name == varName) { - build_stkvar_xrefs(&xrefs_list, func, &member); - return xrefs_list; - } - } + struc_t *frame = get_frame(funcEa); + func_t *func = get_func(funcEa); + member_t member; // Get member by name + for (int i = 0; i < frame->memqty; i++) { + member = frame->members[i]; + qstring name; + get_member_name(&name, frame->members[i].id); + if (name == varName) { + build_stkvar_xrefs(&xrefs_list, func, &member); + return xrefs_list; + } + } #endif - // TODO: rewrite for idasdk90 - return xrefs_list; + // TODO: rewrite for idasdk90 + return xrefs_list; } void opstroffForAddress(ea_t ea, qstring typeName) { - insn_t insn; - - for (auto i = 0; i < 16; i++) { - ea = next_head(ea, BADADDR); - decode_insn(&insn, ea); - // Found interface function call - if ((insn.itype == NN_call || insn.itype == NN_callfi || - insn.itype == NN_callni) && - (insn.ops[0].type == o_displ || insn.ops[0].type == o_phrase) && - insn.ops[0].reg == REG_RAX) { - opStroff(ea, static_cast(typeName.c_str())); - msg("[%s] Mark arguments at address 0x%016llX (interface type: %s)\n", - plugin_name, u64_addr(ea), typeName.c_str()); - - // check for EfiSmmBase2Protocol->GetSmstLocation - if (typeName == "EFI_SMM_BASE2_PROTOCOL" && insn.ops[0].type == o_displ && - insn.ops[0].addr == 8) { - if (!addrInVec(g_get_smst_location_calls, ea)) { - g_get_smst_location_calls.push_back(ea); - } - } - - if (typeName == "EFI_SMM_VARIABLE_PROTOCOL" && insn.ops[0].type == o_phrase) { - if (!addrInVec(g_smm_get_variable_calls, ea)) { - g_smm_get_variable_calls.push_back(ea); - } - } - - if (typeName == "EFI_SMM_VARIABLE_PROTOCOL" && insn.ops[0].type == o_displ && - insn.ops[0].addr == 0x10) { - if (!addrInVec(g_smm_set_variable_calls, ea)) { - g_smm_set_variable_calls.push_back(ea); - } - } - - break; + insn_t insn; + + for (auto i = 0; i < 16; i++) { + ea = next_head(ea, BADADDR); + decode_insn(&insn, ea); + // Found interface function call + if ((insn.itype == NN_call || insn.itype == NN_callfi || insn.itype == NN_callni) && + (insn.ops[0].type == o_displ || insn.ops[0].type == o_phrase) && + insn.ops[0].reg == REG_RAX) { + opStroff(ea, static_cast(typeName.c_str())); + msg("[%s] Mark arguments at address 0x%016llX (interface type: %s)\n", + g_plugin_name, u64_addr(ea), typeName.c_str()); + + // check for EfiSmmBase2Protocol->GetSmstLocation + if (typeName == "EFI_SMM_BASE2_PROTOCOL" && insn.ops[0].type == o_displ && + insn.ops[0].addr == 8) { + if (!addrInVec(g_get_smst_location_calls, ea)) { + g_get_smst_location_calls.push_back(ea); } - // If the RAX value is overridden - if (insn.ops[0].reg == REG_RAX) { - break; + } + + if (typeName == "EFI_SMM_VARIABLE_PROTOCOL" && insn.ops[0].type == o_phrase) { + if (!addrInVec(g_smm_get_variable_calls, ea)) { + g_smm_get_variable_calls.push_back(ea); + } + } + + if (typeName == "EFI_SMM_VARIABLE_PROTOCOL" && insn.ops[0].type == o_displ && + insn.ops[0].addr == 0x10) { + if (!addrInVec(g_smm_set_variable_calls, ea)) { + g_smm_set_variable_calls.push_back(ea); } + } + + break; + } + // If the RAX value is overridden + if (insn.ops[0].reg == REG_RAX) { + break; } + } } //-------------------------------------------------------------------------- // Mark the arguments of each function from an interface derived from // a local variable void opstroffForInterface(xreflist_t localXrefs, qstring typeName) { - insn_t insn; - for (auto xref : localXrefs) { - decode_insn(&insn, xref.ea); - if (insn.itype == NN_mov && insn.ops[0].reg == REG_RAX) { - opstroffForAddress(xref.ea, typeName); - } + insn_t insn; + for (auto xref : localXrefs) { + decode_insn(&insn, xref.ea); + if (insn.itype == NN_mov && insn.ops[0].reg == REG_RAX) { + opstroffForAddress(xref.ea, typeName); } + } } //-------------------------------------------------------------------------- // Mark the arguments of each function from an interface derived from // a global variable void opstroffForGlobalInterface(std::vector xrefs, qstring typeName) { - insn_t insn; - for (auto ea : xrefs) { - decode_insn(&insn, ea); - if (insn.itype == NN_mov && insn.ops[0].reg == REG_RAX) { - opstroffForAddress(ea, typeName); - } + insn_t insn; + for (auto ea : xrefs) { + decode_insn(&insn, ea); + if (insn.itype == NN_mov && insn.ops[0].reg == REG_RAX) { + opstroffForAddress(ea, typeName); } + } } bool qwordInVec(std::vector vec, uint64_t value) { - return find(vec.begin(), vec.end(), value) != vec.end(); + return find(vec.begin(), vec.end(), value) != vec.end(); } bool addrInVec(std::vector vec, ea_t addr) { - return find(vec.begin(), vec.end(), addr) != vec.end(); + return find(vec.begin(), vec.end(), addr) != vec.end(); } bool jsonInVec(std::vector vec, json item) { - return find(vec.begin(), vec.end(), item) != vec.end(); + return find(vec.begin(), vec.end(), item) != vec.end(); } bool addrInTables(std::vector gStList, std::vector gBsList, std::vector gRtList, ea_t ea) { - return (addrInVec(gStList, ea) || addrInVec(gBsList, ea) || addrInVec(gRtList, ea)); + return (addrInVec(gStList, ea) || addrInVec(gBsList, ea) || addrInVec(gRtList, ea)); } std::vector findData(ea_t start_ea, ea_t end_ea, uchar *data, size_t len) { - std::vector res; - ea_t start = start_ea; - int counter = 0; - while (true) { + std::vector res; + ea_t start = start_ea; + int counter = 0; + while (true) { #if IDA_SDK_VERSION < 900 - auto ea = bin_search2(start, end_ea, data, nullptr, len, BIN_SEARCH_FORWARD); + auto ea = bin_search2(start, end_ea, data, nullptr, len, BIN_SEARCH_FORWARD); #else - auto ea = bin_search3(start, end_ea, data, nullptr, len, BIN_SEARCH_FORWARD); + auto ea = bin_search3(start, end_ea, data, nullptr, len, BIN_SEARCH_FORWARD); #endif - if (ea == BADADDR) { - break; - } - res.push_back(ea); - start = ea + len; + if (ea == BADADDR) { + break; } - return res; + res.push_back(ea); + start = ea + len; + } + return res; } //-------------------------------------------------------------------------- -// Get wide string by address +// get wide string by address std::string getWideString(ea_t addr) { - std::string res; - int index = 0; - while (get_wide_word(addr + index)) { - auto byte = get_wide_byte(addr + index); - if (byte < 0x20 || byte > 0x7e) { - return "INVALID_STRING"; - } - res.push_back(byte); - index += 2; + std::string res; + int index = 0; + while (get_wide_word(addr + index)) { + auto byte = get_wide_byte(addr + index); + if (byte < 0x20 || byte > 0x7e) { + return "INVALID_STRING"; } - return res; + res.push_back(byte); + index += 2; + } + return res; } //-------------------------------------------------------------------------- // Get EfiGuid by address EfiGuid getGlobalGuid(ea_t addr) { - EfiGuid guid; - guid.data1 = get_wide_dword(addr); - guid.data2 = get_wide_word(addr + 4); - guid.data3 = get_wide_word(addr + 6); - for (auto i = 0; i < 8; i++) { - guid.data4[i] = static_cast(get_wide_byte(addr + 8 + i)); - } - return guid; + EfiGuid guid; + guid.data1 = get_wide_dword(addr); + guid.data2 = get_wide_word(addr + 4); + guid.data3 = get_wide_word(addr + 6); + for (auto i = 0; i < 8; i++) { + guid.data4[i] = static_cast(get_wide_byte(addr + 8 + i)); + } + return guid; } //-------------------------------------------------------------------------- // Get EfiGuid by stack offset EfiGuid getStackGuid(func_t *f, uint64_t offset) { - EfiGuid guid; - insn_t insn; - auto ea = f->start_ea; - int counter = 0; - while (ea <= f->end_ea) { - if (counter == 16) { - break; - } - ea = next_head(ea, BADADDR); - decode_insn(&insn, ea); - if (insn.itype == NN_mov && insn.ops[0].type == o_displ && - (insn.ops[0].reg == REG_RSP || insn.ops[0].reg == REG_RBP) && - insn.ops[1].type == o_imm) { - if (insn.ops[0].addr == offset) { - guid.data1 = insn.ops[1].value; - counter += 4; - continue; - } - if (insn.ops[0].addr == offset + 4) { - guid.data2 = insn.ops[1].value & 0xffff; - guid.data3 = (insn.ops[1].value >> 16) & 0xffff; - counter += 4; - continue; - } - if (insn.ops[0].addr == offset + 8) { - auto dword = insn.ops[1].value; - guid.data4[0] = dword & 0xff; - guid.data4[1] = (dword >> 8) & 0xff; - guid.data4[2] = (dword >> 16) & 0xff; - guid.data4[3] = (dword >> 24) & 0xff; - counter += 4; - continue; - } - if (insn.ops[0].addr == offset + 12) { - auto dword = insn.ops[1].value; - guid.data4[4] = dword & 0xff; - guid.data4[5] = (dword >> 8) & 0xff; - guid.data4[6] = (dword >> 16) & 0xff; - guid.data4[7] = (dword >> 24) & 0xff; - counter += 4; - continue; - } - } - } - return guid; + EfiGuid guid; + insn_t insn; + auto ea = f->start_ea; + int counter = 0; + while (ea <= f->end_ea) { + if (counter == 16) { + break; + } + ea = next_head(ea, BADADDR); + decode_insn(&insn, ea); + if (insn.itype == NN_mov && insn.ops[0].type == o_displ && + (insn.ops[0].reg == REG_RSP || insn.ops[0].reg == REG_RBP) && + insn.ops[1].type == o_imm) { + if (insn.ops[0].addr == offset) { + guid.data1 = insn.ops[1].value; + counter += 4; + continue; + } + if (insn.ops[0].addr == offset + 4) { + guid.data2 = insn.ops[1].value & 0xffff; + guid.data3 = (insn.ops[1].value >> 16) & 0xffff; + counter += 4; + continue; + } + if (insn.ops[0].addr == offset + 8) { + auto dword = insn.ops[1].value; + guid.data4[0] = dword & 0xff; + guid.data4[1] = (dword >> 8) & 0xff; + guid.data4[2] = (dword >> 16) & 0xff; + guid.data4[3] = (dword >> 24) & 0xff; + counter += 4; + continue; + } + if (insn.ops[0].addr == offset + 12) { + auto dword = insn.ops[1].value; + guid.data4[4] = dword & 0xff; + guid.data4[5] = (dword >> 8) & 0xff; + guid.data4[6] = (dword >> 16) & 0xff; + guid.data4[7] = (dword >> 24) & 0xff; + counter += 4; + continue; + } + } + } + return guid; } std::string getTable(std::string service_name) { - for (auto i = 0; i < BTABLE_LEN; i++) { - if (static_cast(boot_services_table[i].name) == service_name) { - return "EFI_BOOT_SERVICES"; - } + for (auto i = 0; i < bootServicesTableAllCount; i++) { + if (static_cast(bootServicesTableAll[i].name) == service_name) { + return "EFI_BOOT_SERVICES"; } - for (auto i = 0; i < RTABLE_LEN; i++) { - if (static_cast(runtime_services_table[i].name) == service_name) { - return "EFI_RUNTIME_SERVICES"; - } + } + for (auto i = 0; i < runtimeServicesTableAllCount; i++) { + if (static_cast(runtimeServicesTableAll[i].name) == service_name) { + return "EFI_RUNTIME_SERVICES"; } - return "OTHER"; + } + return "OTHER"; } std::string lookupBootServiceName(uint64_t offset) { - for (auto i = 0; i < BTABLE_LEN; i++) { - if (boot_services_table[i].offset64 == offset) { - return static_cast(boot_services_table[i].name); - } + for (auto i = 0; i < bootServicesTableAllCount; i++) { + if (bootServicesTableAll[i].offset64 == offset) { + return static_cast(bootServicesTableAll[i].name); } - return "Unknown"; + } + return "Unknown"; } std::string lookupRuntimeServiceName(uint64_t offset) { - for (auto i = 0; i < RTABLE_LEN; i++) { - if (runtime_services_table[i].offset64 == offset) { - return static_cast(runtime_services_table[i].name); - } + for (auto i = 0; i < runtimeServicesTableAllCount; i++) { + if (runtimeServicesTableAll[i].offset64 == offset) { + return static_cast(runtimeServicesTableAll[i].name); } - return "Unknown"; + } + return "Unknown"; } uint64_t u64_addr(ea_t addr) { return static_cast(addr); } @@ -1094,17 +981,17 @@ uint64_t u64_addr(ea_t addr) { return static_cast(addr); } uint32_t u32_addr(ea_t addr) { return static_cast(addr); } uint16_t get_machine_type() { - ea_t pe_offset = get_dword(0x3c); - return get_word(pe_offset + 4); + ea_t pe_offset = get_dword(0x3c); + return get_word(pe_offset + 4); } #if IDA_SDK_VERSION >= 900 tid_t import_type(const til_t *til, int _idx, const char *name) { - tinfo_t tinfo; - if (!tinfo.get_named_type(til, name)) { - return BADADDR; - } + tinfo_t tinfo; + if (!tinfo.get_named_type(til, name)) { + return BADADDR; + } - return tinfo.force_tid(); + return tinfo.force_tid(); } #endif diff --git a/efiXplorer/efiUtils.h b/efiXplorer/efiUtils.h index 4f1c643f..1ed06c5c 100644 --- a/efiXplorer/efiUtils.h +++ b/efiXplorer/efiUtils.h @@ -1,6 +1,6 @@ /* * efiXplorer - * Copyright (C) 2020-2023 Binarly + * Copyright (C) 2020-2024 Binarly * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -53,127 +53,37 @@ #include #endif -using namespace nlohmann; - -#define BTOA(x) ((x) ? "true" : "false") - -#define VZ 0x5A56 -#define MZ 0x5A4D - -enum MachineType { AMD64 = 0x8664, I386 = 0x014C, AARCH64 = 0xaa64 }; - -enum ArchFileType { UNSUPPORTED_TYPE, X86, X64, UEFI, ARM64 }; - -enum FfsFileType { FTYPE_PEI = 6, FTYPE_DXE_AND_THE_LIKE = 7 }; - -enum BootServicesOffset { BS_OFFSET_64BIT = 0x60, BS_OFFSET_32BIT = 0x3c }; - -enum RuntimeServiesOffset { RT_OFFSET_64BIT = 0x58, RT_OFFSET_32BIT = 0x38 }; - -enum Registers32bit { - REG_EAX, - REG_ECX, - REG_EDX, - REG_EBX, - REG_ESP, - REG_EBP, - REG_ESI, - REG_EDI, - REG_AL = 0x10, - REG_DL = 0x12 -}; - -enum Registers64bit { - REG_RAX, - REG_RCX, - REG_RDX, - REG_RBX, - REG_RSP, - REG_RBP, - REG_RSI, - REG_RDI, - REG_R8, - REG_R9, - REG_R10, - REG_R11, - REG_R12, - REG_R13, - REG_R14, -}; - -enum RegistersAarch64 { - REG_C0 = 0, - REG_C13 = 13, - REG_X0 = 129, - REG_X1, - REG_X2, - REG_X3, - REG_X4, - REG_X5, - REG_X6, - REG_X7, - REG_X8, - REG_X9, - REG_X10, - REG_X11, - REG_X12, - REG_X13, - REG_X14, - REG_X15, - REG_X16, - REG_X17, - REG_X18, - REG_X19, - REG_X20, - REG_X21, - REG_X22, - REG_X23, - REG_X24, - REG_X25, - REG_X26, - REG_X27, - REG_X28, - REG_X29, - REG_X30, - REG_XZR, - REG_XSP, - REG_XPC, -}; +#include "efi_defs.h" -enum HelperValues { - GUID_OFFSET_DWORD = 4, - GUID_OFFSET_NONE = 0xffff, - PUSH_NONE = 0xffff, - BAD_REG = 0xffff, -}; +using namespace nlohmann; struct EfiGuid { - uint32_t data1; - uint16_t data2; - uint16_t data3; - uint8_t data4[8]; - std::vector uchar_data() { - std::vector res; - res.push_back(data1 & 0xff); - res.push_back(data1 >> 8 & 0xff); - res.push_back(data1 >> 16 & 0xff); - res.push_back(data1 >> 24 & 0xff); - res.push_back(data2 & 0xff); - res.push_back(data2 >> 8 & 0xff); - res.push_back(data3 & 0xff); - res.push_back(data3 >> 8 & 0xff); - for (auto i = 0; i < 8; i++) { - res.push_back(data4[i]); - } - return res; - } - std::string to_string() { - char res[37] = {0}; - snprintf(res, 37, "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X", data1, - data2, data3, data4[0], data4[1], data4[2], data4[3], data4[4], data4[5], - data4[6], data4[7]); - return static_cast(res); + uint32_t data1; + uint16_t data2; + uint16_t data3; + uint8_t data4[8]; + std::vector uchar_data() { + std::vector res; + res.push_back(data1 & 0xff); + res.push_back(data1 >> 8 & 0xff); + res.push_back(data1 >> 16 & 0xff); + res.push_back(data1 >> 24 & 0xff); + res.push_back(data2 & 0xff); + res.push_back(data2 >> 8 & 0xff); + res.push_back(data3 & 0xff); + res.push_back(data3 >> 8 & 0xff); + for (auto i = 0; i < 8; i++) { + res.push_back(data4[i]); } + return res; + } + std::string to_string() { + char res[37] = {0}; + snprintf(res, 37, "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X", data1, data2, + data3, data4[0], data4[1], data4[2], data4[3], data4[4], data4[5], data4[6], + data4[7]); + return static_cast(res); + } }; // Get input file type @@ -193,21 +103,6 @@ std::vector getXrefsToArray(ea_t addr); // Wrapper for op_stroff function bool opStroff(ea_t addr, std::string type); -// Get boot service description comment -std::string getBsComment(uint32_t offset, uint8_t arch); - -// Get PEI service description comment (X86 is assumed) -std::string getPeiSvcComment(uint32_t offset); - -// Get PPI service description comment (X86 is assumed) -std::string getPPICallComment(uint32_t offset, std::string name); - -// Get SMM service description comment -std::string getSmmVarComment(); - -// Get runtime service description comment -std::string getRtComment(uint32_t offset, uint8_t arch); - // Find address of global gBS variable // for X64 module for each service ea_t findUnknownBsVarX64(ea_t ea); diff --git a/efiXplorer/efiXplorer.cpp b/efiXplorer/efiXplorer.cpp index ed9ff8fd..846b2db9 100644 --- a/efiXplorer/efiXplorer.cpp +++ b/efiXplorer/efiXplorer.cpp @@ -1,6 +1,6 @@ /* * efiXplorer - * Copyright (C) 2020-2023 Binarly + * Copyright (C) 2020-2024 Binarly * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,12 +19,11 @@ * */ -#include "efiXplorer.h" +#include "efixplorer.h" #include "efiAnalyzer.h" #include "efiGlobal.h" #include "efiUi.h" -static const char plugin_name[] = "efiXplorer"; static const char plugin_hotkey[] = "Ctrl+Alt+E"; static const char plugin_comment[] = "This plugin performs automatic analysis of the input UEFI module"; @@ -46,86 +45,86 @@ hexdsp_t *hexdsp = nullptr; //-------------------------------------------------------------------------- static plugmod_t *idaapi init(void) { - uint8_t file_type = getInputFileType(); - if (file_type == UNSUPPORTED_TYPE) { - return PLUGIN_SKIP; - } + uint8_t file_type = getInputFileType(); + if (file_type == UNSUPPORTED_TYPE) { + return PLUGIN_SKIP; + } - msg(welcome_msg); - msg("%s\n\n", COPYRIGHT); + msg(welcome_msg); + msg("%s\n\n", COPYRIGHT); - // Register action - register_action(action_load_report); - attach_action_to_menu("File/Load file/", action_load_report.name, SETMENU_APP); + // Register action + register_action(action_load_report); + attach_action_to_menu("File/Load file/", action_load_report.name, SETMENU_APP); - return PLUGIN_KEEP; + return PLUGIN_KEEP; } //-------------------------------------------------------------------------- bool idaapi run(size_t arg) { - if (arg >> 0 & 1) { // Parse arg value: - // * arg = 0 (000): default (DXE) - // * arg = 1 (001): default (PEI, 32-bit binaries only) - // * arg = 2 (010): disable_ui (DXE) - // * arg = 3 (011): disable_ui (PEI, 32-bit binaries only) - // * arg = 4 (100): disable_vuln_hunt (DXE) - // * arg = 5 (101): disable_vuln_hunt (PEI, 32-bit binaries only) - // * arg = 6 (110): disable_ui & disable_vuln_hunt (DXE) - // * arg = 7 (111): disable_ui & disable_vuln_hunt (PEI, 32-bit binaries only) - g_args.module_type = PEI; - } - - if (arg >> 1 & 1) { - g_args.disable_ui = 1; - } - if (arg >> 2 & 1) { - g_args.disable_vuln_hunt = 1; - } - - msg("[%s] plugin run with argument %lu (sdk version: %d)\n", plugin_name, arg, - IDA_SDK_VERSION); - msg("[%s] disable_ui = %d, disable_vuln_hunt = %d\n", plugin_name, g_args.disable_ui, - g_args.disable_vuln_hunt); - - auto guids_path = getGuidsJsonFile(); - msg("[%s] guids.json exists: %s\n", plugin_name, BTOA(!guids_path.empty())); - - if (guids_path.empty()) { - std::string msg_text = - "guids.json file not found, copy \"guids\" directory to /plugins"; - msg("[%s] %s\n", plugin_name, msg_text.c_str()); - warning("%s: %s\n", plugin_name, msg_text.c_str()); - return false; - } - - uint8_t arch = getInputFileType(); - if (arch == X64) { - msg("[%s] input file is 64-bit module (x86)\n", plugin_name); - EfiAnalysis::efiAnalyzerMainX64(); - } else if (arch == X86) { - msg("[%s] input file is 32-bit module (x86)\n", plugin_name); - EfiAnalysis::efiAnalyzerMainX86(); - } else if (arch == UEFI) { - msg("[%s] input file is UEFI firmware\n", plugin_name); - warning("%s: analysis may take some time, please wait for it to complete\n", - plugin_name); - if (get_machine_type() == AARCH64) { - msg("[%s] analyze AARCH64 modules\n", plugin_name); - EfiAnalysis::efiAnalyzerMainArm(); - } else { - msg("[%s] analyze AMD64 modules\n", plugin_name); - EfiAnalysis::efiAnalyzerMainX64(); - } - } else if (arch == ARM64) { - msg("[%s] input file is 64-bit module (ARM)\n", plugin_name); - EfiAnalysis::efiAnalyzerMainArm(); + if (arg >> 0 & 1) { // Parse arg value: + // * arg = 0 (000): default (DXE) + // * arg = 1 (001): default (PEI, 32-bit binaries only) + // * arg = 2 (010): disable_ui (DXE) + // * arg = 3 (011): disable_ui (PEI, 32-bit binaries only) + // * arg = 4 (100): disable_vuln_hunt (DXE) + // * arg = 5 (101): disable_vuln_hunt (PEI, 32-bit binaries only) + // * arg = 6 (110): disable_ui & disable_vuln_hunt (DXE) + // * arg = 7 (111): disable_ui & disable_vuln_hunt (PEI, 32-bit binaries only) + g_args.module_type = PEI; + } + + if (arg >> 1 & 1) { + g_args.disable_ui = 1; + } + if (arg >> 2 & 1) { + g_args.disable_vuln_hunt = 1; + } + + msg("[%s] plugin run with argument %lu (sdk version: %d)\n", g_plugin_name, arg, + IDA_SDK_VERSION); + msg("[%s] disable_ui = %d, disable_vuln_hunt = %d\n", g_plugin_name, g_args.disable_ui, + g_args.disable_vuln_hunt); + + auto guids_path = getGuidsJsonFile(); + msg("[%s] guids.json exists: %s\n", g_plugin_name, BTOA(!guids_path.empty())); + + if (guids_path.empty()) { + std::string msg_text = + "guids.json file not found, copy \"guids\" directory to /plugins"; + msg("[%s] %s\n", g_plugin_name, msg_text.c_str()); + warning("%s: %s\n", g_plugin_name, msg_text.c_str()); + return false; + } + + uint8_t arch = getInputFileType(); + if (arch == X64) { + msg("[%s] input file is 64-bit module (x86)\n", g_plugin_name); + efi_analysis::efiAnalyzerMainX64(); + } else if (arch == X86) { + msg("[%s] input file is 32-bit module (x86)\n", g_plugin_name); + efi_analysis::efiAnalyzerMainX86(); + } else if (arch == UEFI) { + msg("[%s] input file is UEFI firmware\n", g_plugin_name); + warning("%s: analysis may take some time, please wait for it to complete\n", + g_plugin_name); + if (get_machine_type() == AARCH64) { + msg("[%s] analyze AARCH64 modules\n", g_plugin_name); + efi_analysis::efiAnalyzerMainArm(); + } else { + msg("[%s] analyze AMD64 modules\n", g_plugin_name); + efi_analysis::efiAnalyzerMainX64(); } + } else if (arch == ARM64) { + msg("[%s] input file is 64-bit module (ARM)\n", g_plugin_name); + efi_analysis::efiAnalyzerMainArm(); + } - // Reset arguments - g_args = {DXE_SMM, 0, 0}; + // Reset arguments + g_args = {DXE_SMM, 0, 0}; - return true; + return true; } //-------------------------------------------------------------------------- @@ -138,6 +137,6 @@ plugin_t PLUGIN = { run, // invoke plugin plugin_comment, // long comment about the plugin plugin_help, // multiline help about the plugin - plugin_name, // the preferred short name of the plugin + g_plugin_name, // the preferred short name of the plugin plugin_hotkey // the preferred hotkey to run the plugin }; diff --git a/efiXplorer/efiXplorer.h b/efiXplorer/efiXplorer.h index 5042692c..fcefda64 100644 --- a/efiXplorer/efiXplorer.h +++ b/efiXplorer/efiXplorer.h @@ -1,6 +1,6 @@ /* * efiXplorer - * Copyright (C) 2020-2023 Binarly + * Copyright (C) 2020-2024 Binarly * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -23,4 +23,4 @@ #include "efiUtils.h" -#define COPYRIGHT "(c) 2020-2023, Binarly - https://github.com/binarly-io/efiXplorer" +#define COPYRIGHT "(c) 2020-2024, Binarly - https://github.com/binarly-io/efiXplorer" diff --git a/efiXplorer/tables/efi_services.h b/efiXplorer/efi_defs.cpp similarity index 56% rename from efiXplorer/tables/efi_services.h rename to efiXplorer/efi_defs.cpp index e30b0026..4924afcf 100644 --- a/efiXplorer/tables/efi_services.h +++ b/efiXplorer/efi_defs.cpp @@ -1,6 +1,6 @@ /* * efiXplorer - * Copyright (C) 2020-2022 Binarly + * Copyright (C) 2020-2024 Binarly * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -15,196 +15,13 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * - * efi_services.h - * */ -#pragma once - -#include "stdint.h" - -enum BootServicesOffsets64bit { - RaiseTPLOffset64 = 0x18, - RestoreTPLOffset64 = 0x20, - AllocatePagesOffset64 = 0x28, - FreePagesOffset64 = 0x30, - GetMemoryMapOffset64 = 0x38, - AllocatePoolOffset64 = 0x40, - FreePoolOffset64 = 0x48, - CreateEventOffset64 = 0x50, - SetTimerOffset64 = 0x58, - WaitForEventOffset64 = 0x60, - SignalEventOffset64 = 0x68, - CloseEventOffset64 = 0x70, - CheckEventOffset64 = 0x78, - InstallProtocolInterfaceOffset64 = 0x80, - RenstallProtocolInterfaceOffset64 = 0x88, - UninstallProtocolInterfaceOffset64 = 0x90, - HandleProtocolOffset64 = 0x98, - RegisterProtocolNotifyOffset64 = 0xa8, - LocateHandleOffset64 = 0xb0, - LocateDevicePathOffset64 = 0xb8, - InstallConfigurationTableOffset64 = 0xc0, - LoadImageOffset64 = 0xc8, - StartImageOffset64 = 0xd0, - ExitOffset64 = 0xd8, - UnloadImageOffset64 = 0xe0, - ExitBootServicesOffset64 = 0xe8, - GetNextMonotonicCountOffset64 = 0xf0, - StallOffset64 = 0xf0, - SetWatchdogTimerOffset64 = 0x100, - ConnectControllerOffset64 = 0x108, - DisconnectControllerOffset64 = 0x110, - OpenProtocolOffset64 = 0x118, - CloseProtocolOffset64 = 0x120, - OpenProtocolInformationOffset64 = 0x128, - ProtocolsPerHandleOffset64 = 0x130, - LocateHandleBufferOffset64 = 0x138, - LocateProtocolOffset64 = 0x140, - InstallMultipleProtocolInterfacesOffset64 = 0x148, - UninstallMultipleProtocolInterfacesOffset64 = 0x150, - CalculateCrc32Offset64 = 0x158, - CopyMemOffset64 = 0x160, - SetMemOffset64 = 0x168, - CreateEventExOffset64 = 0x170, -}; - -enum BootServicesOffsets32bit { - RaiseTPLOffset32 = 0x18, - RestoreTPLOffset32 = 0x1c, - AllocatePagesOffset32 = 0x20, - FreePagesOffset32 = 0x24, - GetMemoryMapOffset32 = 0x28, - AllocatePoolOffset32 = 0x2c, - FreePoolOffset32 = 0x30, - CreateEventOffset32 = 0x34, - SetTimerOffset32 = 0x38, - WaitForEventOffset32 = 0x3c, - SignalEventOffset32 = 0x40, - CloseEventOffset32 = 0x44, - CheckEventOffset32 = 0x48, - InstallProtocolInterfaceOffset32 = 0x4c, - RenstallProtocolInterfaceOffset32 = 0x50, - UninstallProtocolInterfaceOffset32 = 0x54, - HandleProtocolOffset32 = 0x58, - RegisterProtocolNotifyOffset32 = 0x60, - LocateHandleOffset32 = 0x64, - LocateDevicePathOffset32 = 0x68, - InstallConfigurationTableOffset32 = 0x6c, - LoadImageOffset32 = 0x70, - StartImageOffset32 = 0x74, - ExitOffset32 = 0x78, - UnloadImageOffset32 = 0x7c, - ExitBootServicesOffset32 = 0x80, - GetNextMonotonicCountOffset32 = 0x84, - StallOffset32 = 0x88, - SetWatchdogTimerOffset32 = 0x8c, - ConnectControllerOffset32 = 0x90, - DisconnectControllerOffset32 = 0x94, - OpenProtocolOffset32 = 0x98, - CloseProtocolOffset32 = 0x9c, - OpenProtocolInformationOffset32 = 0xa0, - ProtocolsPerHandleOffset32 = 0xa4, - LocateHandleBufferOffset32 = 0xa8, - LocateProtocolOffset32 = 0xac, - InstallMultipleProtocolInterfacesOffset32 = 0xb0, - UninstallMultipleProtocolInterfacesOffset32 = 0xb4, - CalculateCrc32Offset32 = 0xb8, - CopyMemOffset32 = 0xbc, - SetMemOffset32 = 0xc0, - CreateEventExOffset32 = 0xc4, -}; - -enum RuntimeServicesOffsets64bit { - GetTimeOffset64 = 0x18, - SetTimeOffset64 = 0x20, - GetWakeupTimeOffset64 = 0x28, - SetWakeupTimeOffset64 = 0x30, - SetVirtualAddressMapOffset64 = 0x38, - ConvertPointerOffset64 = 0x40, - GetVariableOffset64 = 0x48, - GetNextVariableNameOffset64 = 0x50, - SetVariableOffset64 = 0x58, - GetNextHighMonotonicCountOffset64 = 0x60, - ResetSystemOffset64 = 0x68, - UpdateCapsuleOffset64 = 0x70, - QueryCapsuleCapabilitiesOffset64 = 0x78, - QueryVariableInfoOffset64 = 0x80, -}; - -enum RuntimeServicesOffsets32bit { - GetTimeOffset32 = 0x18, - SetTimeOffset32 = 0x1c, - GetWakeupTimeOffset32 = 0x20, - SetWakeupTimeOffset32 = 0x24, - SetVirtualAddressMapOffset32 = 0x28, - ConvertPointerOffset32 = 0x2c, - GetVariableOffset32 = 0x30, - GetNextVariableNameOffset32 = 0x34, - SetVariableOffset32 = 0x38, - GetNextHighMonotonicCountOffset32 = 0x3c, - ResetSystemOffset32 = 0x40, - UpdateCapsuleOffset32 = 0x44, - QueryCapsuleCapabilitiesOffset32 = 0x48, - QueryVariableInfoOffset32 = 0x4c, -}; - -enum SmmServicesOffsets64bit { - SmmInstallConfigurationTableOffset64 = 0x28, - SmmAllocatePoolOffset64 = 0x50, - SmmFreePoolOffset64 = 0x58, - SmmAllocatePagesOffset64 = 0x60, - SmmFreePagesOffset64 = 0x68, - SmmStartupThisApOffset64 = 0x70, - SmmInstallProtocolInterfaceOffset64 = 0xa8, - SmmUninstallProtocolInterfaceOffset64 = 0xb0, - SmmHandleProtocolOffset64 = 0xb8, - SmmRegisterProtocolNotifyOffset64 = 0xc0, - SmmLocateHandleOffset64 = 0xc8, - SmmLocateProtocolOffset64 = 0xd0, - SmiManageOffset64 = 0xd8, - SmiHandlerRegisterOffset64 = 0xe0, - SmiHandlerUnRegisterOffset64 = 0xe8, -}; - -enum SmmServicesOffsets32bit { - SmmInstallConfigurationTableOffset32 = 0x20, - SmmAllocatePoolOffset32 = 0x34, - SmmFreePoolOffset32 = 0x38, - SmmAllocatePagesOffset32 = 0x3c, - SmmFreePagesOffset32 = 0x40, - SmmStartupThisApOffset32 = 0x44, - SmmInstallProtocolInterfaceOffset32 = 0x60, - SmmUninstallProtocolInterfaceOffset32 = 0x64, - SmmHandleProtocolOffset32 = 0x68, - SmmRegisterProtocolNotifyOffset32 = 0x6c, - SmmLocateHandleOffset32 = 0x70, - SmmLocateProtocolOffset32 = 0x74, - SmiManageOffset32 = 0x78, - SmiHandlerRegisterOffset32 = 0x7c, - SmiHandlerUnRegisterOffset32 = 0x80, -}; - -struct service_info_64bit { - char service_name[64]; - uint32_t offset; - uint32_t reg; - uint16_t arg_index; -}; - -struct service_info_32bit { - char service_name[64]; - uint32_t offset; - uint16_t push_number; -}; +#include "efi_defs.h" -struct service { - char service_name[64]; - uint32_t offset64; - uint32_t offset32; -}; +const char *g_plugin_name = "efiXplorer"; -struct service_info_64bit bootServicesTable64[] = { +service_info_64_t bootServicesTable64[] = { {"InstallProtocolInterface", InstallProtocolInterfaceOffset64, REG_RDX, 1}, {"ReinstallProtocolInterface", RenstallProtocolInterfaceOffset64, REG_RDX, 1}, {"UninstallProtocolInterface", UninstallProtocolInterfaceOffset64, REG_RDX, 1}, @@ -220,10 +37,9 @@ struct service_info_64bit bootServicesTable64[] = { REG_RDX, 1}, {"UninstallMultipleProtocolInterfaces", UninstallMultipleProtocolInterfacesOffset64, REG_RDX, 1}}; -size_t bootServicesTable64Length = - sizeof(bootServicesTable64) / sizeof(service_info_64bit); +size_t bootServicesTable64Count = sizeof(bootServicesTable64) / sizeof(service_info_64_t); -struct service_info_32bit bootServicesTable32[] = { +service_info_32_t bootServicesTable32[] = { {"InstallProtocolInterface", InstallProtocolInterfaceOffset32, 2}, {"ReinstallProtocolInterface", RenstallProtocolInterfaceOffset32, 2}, {"UninstallProtocolInterface", UninstallProtocolInterfaceOffset32, 2}, @@ -238,10 +54,9 @@ struct service_info_32bit bootServicesTable32[] = { {"InstallMultipleProtocolInterfaces", InstallMultipleProtocolInterfacesOffset32, 2}, {"UninstallMultipleProtocolInterfaces", UninstallMultipleProtocolInterfacesOffset32, 2}}; -size_t bootServicesTable32Length = - sizeof(bootServicesTable32) / sizeof(service_info_32bit); +size_t bootServicesTable32Count = sizeof(bootServicesTable32) / sizeof(service_info_32_t); -struct service bootServicesTableAll[] = { +service_t bootServicesTableAll[] = { // difficult to check false positives // {"RaiseTPL", RaiseTPLOffset64, RaiseTPLOffset32}, // {"RestoreTPL", RestoreTPLOffset64, RestoreTPLOffset32}, @@ -295,9 +110,9 @@ struct service bootServicesTableAll[] = { {"CopyMem", CopyMemOffset64, CopyMemOffset32}, {"SetMem", SetMemOffset64, SetMemOffset32}, {"CreateEventEx", CreateEventExOffset64, CreateEventExOffset32}}; -size_t bootServicesTableAllLength = sizeof(bootServicesTableAll) / sizeof(service); +size_t bootServicesTableAllCount = sizeof(bootServicesTableAll) / sizeof(service_t); -struct service runtimeServicesTableAll[] = { +service_t runtimeServicesTableAll[] = { {"GetTime", GetTimeOffset64, GetTimeOffset32}, {"SetTime", SetTimeOffset64, SetTimeOffset32}, {"GetWakeupTime", GetWakeupTimeOffset64, GetWakeupTimeOffset32}, @@ -314,18 +129,18 @@ struct service runtimeServicesTableAll[] = { {"QueryCapsuleCapabilities", QueryCapsuleCapabilitiesOffset64, QueryCapsuleCapabilitiesOffset32}, {"QueryVariableInfo", QueryVariableInfoOffset64, QueryVariableInfoOffset32}}; -size_t runtimeServicesTableAllLength = sizeof(runtimeServicesTableAll) / sizeof(service); +size_t runtimeServicesTableAllCount = sizeof(runtimeServicesTableAll) / sizeof(service_t); -struct service_info_64bit smmServicesProt64[] = { +service_info_64_t smmServicesProt64[] = { {"SmmInstallProtocolInterface", SmmInstallProtocolInterfaceOffset64, REG_RDX}, {"SmmUninstallProtocolInterface", SmmUninstallProtocolInterfaceOffset64, REG_RDX}, {"SmmHandleProtocol", SmmHandleProtocolOffset64, REG_RDX}, {"SmmRegisterProtocolNotify", SmmRegisterProtocolNotifyOffset64, REG_RCX}, {"SmmLocateHandle", SmmLocateHandleOffset64, REG_RDX}, {"SmmLocateProtocol", SmmLocateProtocolOffset64, REG_RCX}}; -size_t smmServicesProt64Length = sizeof(smmServicesProt64) / sizeof(service_info_64bit); +size_t smmServicesProt64Count = sizeof(smmServicesProt64) / sizeof(service_info_64_t); -struct service smmServicesTableAll[] = { +service_t smmServicesTableAll[] = { {"SmmInstallConfigurationTable", SmmInstallConfigurationTableOffset64, SmmInstallConfigurationTableOffset32}, {"SmmAllocatePool", SmmAllocatePoolOffset64, SmmAllocatePoolOffset32}, @@ -345,4 +160,65 @@ struct service smmServicesTableAll[] = { {"SmiManage", SmiManageOffset64, SmiManageOffset32}, {"SmiHandlerRegister", SmiHandlerRegisterOffset64, SmiHandlerRegisterOffset32}, {"SmiHandlerUnRegister", SmiHandlerUnRegisterOffset64, SmiHandlerUnRegisterOffset32}}; -size_t smmServicesTableAllLength = sizeof(smmServicesTableAll) / sizeof(service); +size_t smmServicesTableAllCount = sizeof(smmServicesTableAll) / sizeof(service_t); + +service_info_32_t peiServicesTable32[] = {{"InstallPpi", 0x18, 2}, + {"ReInstallPpi", 0x1c, 3}, + {"LocatePpi", 0x20, 2}, + {"NotifyPpi", 0x24, PUSH_NONE}, + {"GetBootMode", 0x28, PUSH_NONE}, + {"SetBootMode", 0x2c, PUSH_NONE}, + {"GetHobList", 0x30, PUSH_NONE}, + {"CreateHob", 0x34, PUSH_NONE}, + {"FfsFindNextVolume", 0x38, PUSH_NONE}, + {"FfsFindNextFile", 0x3c, PUSH_NONE}, + {"FfsFindSectionData", 0x40, PUSH_NONE}, + {"InstallPeiMemory", 0x44, PUSH_NONE}, + {"AllocatePages", 0x48, PUSH_NONE}, + {"AllocatePool", 0x4c, PUSH_NONE}, + {"CopyMem", 0x50, PUSH_NONE}, + {"SetMem", 0x54, PUSH_NONE}, + {"ReportStatusCode", 0x58, PUSH_NONE}, + {"ResetSystem", 0x5c, PUSH_NONE}, + {"CpuIo", 0x60, PUSH_NONE}, + {"PciCfg", 0x64, PUSH_NONE}, + {"FfsFindFileByName", 0x68, PUSH_NONE}, + {"FfsGetFileInfo", 0x6c, PUSH_NONE}, + {"FfsGetVolumeInfo", 0x70, PUSH_NONE}, + {"RegisterForShadow", 0x74, PUSH_NONE}, + {"FindSectionData3", 0x78, PUSH_NONE}, + {"FfsGetFileInfo2", 0x7c, PUSH_NONE}, + {"ResetSystem2", 0x80, PUSH_NONE}}; +size_t peiServicesTable32Count = sizeof(peiServicesTable32) / sizeof(service_info_32_t); + +service_t peiServicesTableAll[] = {{"InstallPpi", 0x18, 0x18}, + {"ReInstallPpi", 0x20, 0x1c}, + {"LocatePpi", 0x28, 0x20}, + {"NotifyPpi", 0x30, 0x24}, + {"GetBootMode", 0x38, 0x28}, + {"SetBootMode", 0x40, 0x2c}, + {"GetHobList", 0x48, 0x30}, + {"CreateHob", 0x50, 0x34}, + {"FfsFindNextVolume", 0x58, 0x38}, + {"FfsFindNextFile", 0x60, 0x3c}, + {"FfsFindSectionData", 0x68, 0x40}, + {"InstallPeiMemory", 0x70, 0x44}, + {"AllocatePages", 0x78, 0x48}, + {"AllocatePool", 0x80, 0x4c}, + {"CopyMem", 0x88, 0x50}, + {"SetMem", 0x90, 0x54}, + {"ReportStatusCode", 0x98, 0x58}, + {"ResetSystem", 0xa0, 0x5c}, + {"CpuIo", 0xa8, 0x60}, + {"PciCfg", 0xb0, 0x64}, + {"FfsFindFileByName", 0xb8, 0x68}, + {"FfsGetFileInfo", 0xc0, 0x6c}, + {"FfsGetVolumeInfo", 0xc8, 0x70}, + {"RegisterForShadow", 0xd0, 0x74}, + {"FindSectionData3", 0xc8, 0x78}, + {"FfsGetFileInfo2", 0xe0, 0x7c}, + {"ResetSystem2", 0xe8, 0x80}}; +size_t peiServicesTableAllCount = sizeof(peiServicesTableAll) / sizeof(service_t); + +service_t variablePpiTableAll[] = {{"GetVariable", 0, 0}, {"NextVariableName", 8, 4}}; +size_t variablePpiTableAllCount = sizeof(variablePpiTableAll) / sizeof(service_t); diff --git a/efiXplorer/efi_defs.h b/efiXplorer/efi_defs.h new file mode 100644 index 00000000..2aff33df --- /dev/null +++ b/efiXplorer/efi_defs.h @@ -0,0 +1,326 @@ +/* + * efiXplorer + * Copyright (C) 2020-2024 Binarly + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#pragma once + +#include +#include + +#define BTOA(x) ((x) ? "true" : "false") + +#define VZ 0x5A56 +#define MZ 0x5A4D + +enum ModuleType { DXE_SMM = 0, PEI = 1 }; + +enum MachineType { AMD64 = 0x8664, I386 = 0x014C, AARCH64 = 0xaa64 }; + +enum ArchFileType { UNSUPPORTED_TYPE, X86, X64, UEFI, ARM64 }; + +enum FfsFileType { FTYPE_PEI = 6, FTYPE_DXE_AND_THE_LIKE = 7 }; + +enum BootServicesOffset { BS_OFFSET_64BIT = 0x60, BS_OFFSET_32BIT = 0x3c }; + +enum RuntimeServiesOffset { RT_OFFSET_64BIT = 0x58, RT_OFFSET_32BIT = 0x38 }; + +enum RegsAmd32 { + REG_EAX, + REG_ECX, + REG_EDX, + REG_EBX, + REG_ESP, + REG_EBP, + REG_ESI, + REG_EDI, + REG_AL = 0x10, + REG_DL = 0x12 +}; + +enum RegsI386 { + REG_RAX, + REG_RCX, + REG_RDX, + REG_RBX, + REG_RSP, + REG_RBP, + REG_RSI, + REG_RDI, + REG_R8, + REG_R9, + REG_R10, + REG_R11, + REG_R12, + REG_R13, + REG_R14, +}; + +enum RegsAarch4 { + REG_C0 = 0, + REG_C13 = 13, + REG_X0 = 129, + REG_X1, + REG_X2, + REG_X3, + REG_X4, + REG_X5, + REG_X6, + REG_X7, + REG_X8, + REG_X9, + REG_X10, + REG_X11, + REG_X12, + REG_X13, + REG_X14, + REG_X15, + REG_X16, + REG_X17, + REG_X18, + REG_X19, + REG_X20, + REG_X21, + REG_X22, + REG_X23, + REG_X24, + REG_X25, + REG_X26, + REG_X27, + REG_X28, + REG_X29, + REG_X30, + REG_XZR, + REG_XSP, + REG_XPC, +}; + +enum HelperValues { + OFFSET_NONE = 0xffff, + PUSH_NONE = 0xffff, + BAD_REG = 0xffff, +}; + +typedef struct service_info_64 { + char name[64]; + uint32_t offset; + uint32_t reg; + uint16_t arg_index; +} service_info_64_t; + +typedef struct service_info_32 { + char name[64]; + uint32_t offset; + uint16_t push_number; +} service_info_32_t; + +typedef struct service { + char name[64]; + uint32_t offset64; + uint32_t offset32; +} service_t; + +enum BootServicesOffsets64 { + RaiseTPLOffset64 = 0x18, + RestoreTPLOffset64 = 0x20, + AllocatePagesOffset64 = 0x28, + FreePagesOffset64 = 0x30, + GetMemoryMapOffset64 = 0x38, + AllocatePoolOffset64 = 0x40, + FreePoolOffset64 = 0x48, + CreateEventOffset64 = 0x50, + SetTimerOffset64 = 0x58, + WaitForEventOffset64 = 0x60, + SignalEventOffset64 = 0x68, + CloseEventOffset64 = 0x70, + CheckEventOffset64 = 0x78, + InstallProtocolInterfaceOffset64 = 0x80, + RenstallProtocolInterfaceOffset64 = 0x88, + UninstallProtocolInterfaceOffset64 = 0x90, + HandleProtocolOffset64 = 0x98, + RegisterProtocolNotifyOffset64 = 0xa8, + LocateHandleOffset64 = 0xb0, + LocateDevicePathOffset64 = 0xb8, + InstallConfigurationTableOffset64 = 0xc0, + LoadImageOffset64 = 0xc8, + StartImageOffset64 = 0xd0, + ExitOffset64 = 0xd8, + UnloadImageOffset64 = 0xe0, + ExitBootServicesOffset64 = 0xe8, + GetNextMonotonicCountOffset64 = 0xf0, + StallOffset64 = 0xf0, + SetWatchdogTimerOffset64 = 0x100, + ConnectControllerOffset64 = 0x108, + DisconnectControllerOffset64 = 0x110, + OpenProtocolOffset64 = 0x118, + CloseProtocolOffset64 = 0x120, + OpenProtocolInformationOffset64 = 0x128, + ProtocolsPerHandleOffset64 = 0x130, + LocateHandleBufferOffset64 = 0x138, + LocateProtocolOffset64 = 0x140, + InstallMultipleProtocolInterfacesOffset64 = 0x148, + UninstallMultipleProtocolInterfacesOffset64 = 0x150, + CalculateCrc32Offset64 = 0x158, + CopyMemOffset64 = 0x160, + SetMemOffset64 = 0x168, + CreateEventExOffset64 = 0x170, +}; + +enum BootServicesOffsets32 { + RaiseTPLOffset32 = 0x18, + RestoreTPLOffset32 = 0x1c, + AllocatePagesOffset32 = 0x20, + FreePagesOffset32 = 0x24, + GetMemoryMapOffset32 = 0x28, + AllocatePoolOffset32 = 0x2c, + FreePoolOffset32 = 0x30, + CreateEventOffset32 = 0x34, + SetTimerOffset32 = 0x38, + WaitForEventOffset32 = 0x3c, + SignalEventOffset32 = 0x40, + CloseEventOffset32 = 0x44, + CheckEventOffset32 = 0x48, + InstallProtocolInterfaceOffset32 = 0x4c, + RenstallProtocolInterfaceOffset32 = 0x50, + UninstallProtocolInterfaceOffset32 = 0x54, + HandleProtocolOffset32 = 0x58, + RegisterProtocolNotifyOffset32 = 0x60, + LocateHandleOffset32 = 0x64, + LocateDevicePathOffset32 = 0x68, + InstallConfigurationTableOffset32 = 0x6c, + LoadImageOffset32 = 0x70, + StartImageOffset32 = 0x74, + ExitOffset32 = 0x78, + UnloadImageOffset32 = 0x7c, + ExitBootServicesOffset32 = 0x80, + GetNextMonotonicCountOffset32 = 0x84, + StallOffset32 = 0x88, + SetWatchdogTimerOffset32 = 0x8c, + ConnectControllerOffset32 = 0x90, + DisconnectControllerOffset32 = 0x94, + OpenProtocolOffset32 = 0x98, + CloseProtocolOffset32 = 0x9c, + OpenProtocolInformationOffset32 = 0xa0, + ProtocolsPerHandleOffset32 = 0xa4, + LocateHandleBufferOffset32 = 0xa8, + LocateProtocolOffset32 = 0xac, + InstallMultipleProtocolInterfacesOffset32 = 0xb0, + UninstallMultipleProtocolInterfacesOffset32 = 0xb4, + CalculateCrc32Offset32 = 0xb8, + CopyMemOffset32 = 0xbc, + SetMemOffset32 = 0xc0, + CreateEventExOffset32 = 0xc4, +}; + +enum RuntimeServicesOffsets64 { + GetTimeOffset64 = 0x18, + SetTimeOffset64 = 0x20, + GetWakeupTimeOffset64 = 0x28, + SetWakeupTimeOffset64 = 0x30, + SetVirtualAddressMapOffset64 = 0x38, + ConvertPointerOffset64 = 0x40, + GetVariableOffset64 = 0x48, + GetNextVariableNameOffset64 = 0x50, + SetVariableOffset64 = 0x58, + GetNextHighMonotonicCountOffset64 = 0x60, + ResetSystemOffset64 = 0x68, + UpdateCapsuleOffset64 = 0x70, + QueryCapsuleCapabilitiesOffset64 = 0x78, + QueryVariableInfoOffset64 = 0x80, +}; + +enum RuntimeServicesOffsets32 { + GetTimeOffset32 = 0x18, + SetTimeOffset32 = 0x1c, + GetWakeupTimeOffset32 = 0x20, + SetWakeupTimeOffset32 = 0x24, + SetVirtualAddressMapOffset32 = 0x28, + ConvertPointerOffset32 = 0x2c, + GetVariableOffset32 = 0x30, + GetNextVariableNameOffset32 = 0x34, + SetVariableOffset32 = 0x38, + GetNextHighMonotonicCountOffset32 = 0x3c, + ResetSystemOffset32 = 0x40, + UpdateCapsuleOffset32 = 0x44, + QueryCapsuleCapabilitiesOffset32 = 0x48, + QueryVariableInfoOffset32 = 0x4c, +}; + +enum SmmServicesOffsets64 { + SmmInstallConfigurationTableOffset64 = 0x28, + SmmAllocatePoolOffset64 = 0x50, + SmmFreePoolOffset64 = 0x58, + SmmAllocatePagesOffset64 = 0x60, + SmmFreePagesOffset64 = 0x68, + SmmStartupThisApOffset64 = 0x70, + SmmInstallProtocolInterfaceOffset64 = 0xa8, + SmmUninstallProtocolInterfaceOffset64 = 0xb0, + SmmHandleProtocolOffset64 = 0xb8, + SmmRegisterProtocolNotifyOffset64 = 0xc0, + SmmLocateHandleOffset64 = 0xc8, + SmmLocateProtocolOffset64 = 0xd0, + SmiManageOffset64 = 0xd8, + SmiHandlerRegisterOffset64 = 0xe0, + SmiHandlerUnRegisterOffset64 = 0xe8, +}; + +enum SmmServicesOffsets32 { + SmmInstallConfigurationTableOffset32 = 0x20, + SmmAllocatePoolOffset32 = 0x34, + SmmFreePoolOffset32 = 0x38, + SmmAllocatePagesOffset32 = 0x3c, + SmmFreePagesOffset32 = 0x40, + SmmStartupThisApOffset32 = 0x44, + SmmInstallProtocolInterfaceOffset32 = 0x60, + SmmUninstallProtocolInterfaceOffset32 = 0x64, + SmmHandleProtocolOffset32 = 0x68, + SmmRegisterProtocolNotifyOffset32 = 0x6c, + SmmLocateHandleOffset32 = 0x70, + SmmLocateProtocolOffset32 = 0x74, + SmiManageOffset32 = 0x78, + SmiHandlerRegisterOffset32 = 0x7c, + SmiHandlerUnRegisterOffset32 = 0x80, +}; + +extern service_info_64_t bootServicesTable64[]; +extern size_t bootServicesTable64Count; + +extern service_info_32_t bootServicesTable32[]; +extern size_t bootServicesTable32Count; + +extern service_t bootServicesTableAll[]; +extern size_t bootServicesTableAllCount; + +extern service_t runtimeServicesTableAll[]; +extern size_t runtimeServicesTableAllCount; + +extern service_info_64_t smmServicesProt64[]; +extern size_t smmServicesProt64Count; + +extern service_t smmServicesTableAll[]; +extern size_t smmServicesTableAllCount; + +extern service_info_32_t peiServicesTable32[]; +extern size_t peiServicesTable32Count; + +extern service_t peiServicesTableAll[]; +extern size_t peiServicesTableAllCount; + +extern service_t variablePpiTableAll[]; +extern size_t variablePpiTableAllCount; + +extern const char *g_plugin_name; diff --git a/efiXplorer/tables/efi_pei_tables.h b/efiXplorer/tables/efi_pei_tables.h deleted file mode 100644 index 155138ac..00000000 --- a/efiXplorer/tables/efi_pei_tables.h +++ /dev/null @@ -1,237 +0,0 @@ -/* - * ______________________.___ - * \_ _____/\_ _____/| | - * | __)_ | __) | | - * | \ | \ | | - * /_______ / \___ / |___| - * \/ \/ - * _________ .__ ____ __. .__ _____ - * / _____/_ _ _|__| ______ _____ | |/ _| ____ |__|/ ____\____ - * \_____ \\ \/ \/ / |/ ___// ___/ | < / \| \ __\/ __ \ - * / \\ /| |\___ \ \___ \ | | \| | \ || | \ ___/ - * /_______ / \/\_/ |__/____ >____ > |____|__ \___| /__||__| \___ > - * \/ \/ \/ \/ \/ \/ - * - * EFI Swiss Knife - * An IDA plugin to improve (U)EFI reversing - * - * Copyright (C) 2016, 2017 Pedro Vilaça (fG!) - reverser@put.as - - * https://reverse.put.as - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * efi_system_tables.h - * - */ - -#pragma once - -#include "stdint.h" - -struct pei_services_entry { - char name[256]; - uint32_t offset; - char description[1024]; - uint32_t nr_args; - char prototype[512]; - uint32_t count; - // arg number with Ppi guid or PUSH_NONE if no Ppi guid applicable - uint16_t ppi_guid_push_number; - // GUID_OFFSET_NONE if the argument is Guid (or if no Guid arg exists) - // Otherwise, if the arg is EFI_PEI_PPI_DESCRIPTOR/EFI_PEI_NOTIFY_DESCRIPTOR, - // offset of Guid field inside a given structure (in bytes). - uint16_t guid_offset; -}; - -struct pei_services_entry pei_services_table[] = { - {"InstallPpi", 0x18, - "This service is the first one provided by the PEI Foundation. This " - "function installs an interface in the PEI PPI database by GUID. The " - "purpose of the service is to publish an interface that other parties can " - "use to call additional PEIMs.", - 2, - "EFI_STATUS(EFIAPI * EFI_PEI_INSTALL_PPI) (IN CONST EFI_PEI_SERVICES " - "**PeiServices, IN CONST EFI_PEI_PPI_DESCRIPTOR *PpiList)", - 0, 2, GUID_OFFSET_DWORD}, - {"ReInstallPpi", 0x1C, - "This function reinstalls an interface in the PEI PPI database by GUID. " - "The purpose of the service is to publish an interface that other parties " - "can use to replace a same-named interface in the protocol database with " - "a different interface.", - 3, - "EFI_STATUS(EFIAPI * EFI_PEI_REINSTALL_PPI) (IN CONST EFI_PEI_SERVICES " - "**PeiServices, IN CONST EFI_PEI_PPI_DESCRIPTOR *OldPpi, IN CONST " - "EFI_PEI_PPI_DESCRIPTOR *NewPpi)", - 0, 3, GUID_OFFSET_DWORD}, - {"LocatePpi", 0x20, - "This function locates an interface in the PEI PPI database by GUID.", 5, - "EFI_STATUS(EFIAPI * EFI_PEI_LOCATE_PPI) (IN CONST EFI_PEI_SERVICES " - "**PeiServices, IN CONST EFI_GUID *Guid, IN UINTN Instance, IN OUT " - "EFI_PEI_PPI_DESCRIPTOR **PpiDescriptor OPTIONAL, IN OUT VOID **Ppi)", - 0, 2, GUID_OFFSET_NONE}, - {"NotifyPpi", 0x24, - "This function installs a notification service to be called back when a " - "given interface is installed or reinstalled. The purpose of the service " - "is to publish an interface that other parties can use to call additional " - "PPIs that may materialize later.", - 2, - "EFI_STATUS(EFIAPI * EFI_PEI_NOTIFY_PPI) (IN CONST EFI_PEI_SERVICES " - "**PeiServices, IN CONST EFI_PEI_NOTIFY_DESCRIPTOR *NotifyList)", - 0, PUSH_NONE, GUID_OFFSET_NONE}, - {"GetBootMode", 0x28, "This function returns the present value of the boot mode.", 2, - "EFI_STATUS(EFIAPI * EFI_PEI_GET_BOOT_MODE) (IN CONST EFI_PEI_SERVICES " - "**PeiServices, OUT EFI_BOOT_MODE *BootMode)", - 0, PUSH_NONE, GUID_OFFSET_NONE}, - {"SetBootMode", 0x2C, "This function sets the value of the boot mode.", 2, - "EFI_STATUS(EFIAPI * EFI_PEI_SET_BOOT_MODE) (IN CONST EFI_PEI_SERVICES " - "**PeiServices, IN EFI_BOOT_MODE BootMode)", - 0, PUSH_NONE, GUID_OFFSET_NONE}, - {"GetHobList", 0x30, - "This function returns the pointer to the list of Hand-Off Blocks (HOBs) " - "in memory.", - 2, - "EFI_STATUS(EFIAPI * EFI_PEI_GET_HOB_LIST) (IN CONST EFI_PEI_SERVICES " - "**PeiServices, OUT VOID **HobList)", - 0, PUSH_NONE, GUID_OFFSET_NONE}, - {"CreateHob", 0x34, - "This service, published by the PEI Foundation, abstracts the creation of " - "a Hand-Off Block's (HOB's) headers.", - 4, - "EFI_STATUS(EFIAPI * EFI_PEI_CREATE_HOB) (IN CONST EFI_PEI_SERVICES " - "**PeiServices, IN UINT16 Type, IN UINT16 Length, IN OUT VOID **Hob)", - 0, PUSH_NONE, GUID_OFFSET_NONE}, - {"FfsFindNextVolume", 0x38, - "The purpose of the service is to abstract the capability of the PEI " - "Foundation to discover instances of firmware volumes in the system. " - "Given the input file pointer, this service searches for the next " - "matching file in the Firmware File System (FFS) volume.", - 3, - "EFI_STATUS (EFIAPI *EFI_PEI_FFS_FIND_NEXT_VOLUME) (IN struct " - "_EFI_PEI_SERVICES **PeiServices, IN UINTN Instance, IN OUT " - "EFI_FIRMWARE_VOLUME_HEADER **FwVolHeader)", - 0, PUSH_NONE, GUID_OFFSET_NONE}, - {"FfsFindNextFile", 0x3C, - "The purpose of the service is to abstract the capability of the PEI " - "Foundation to discover instances of firmware files in the system. Given " - "the input file pointer, this service searches for the next matching file " - "in the Firmware File System (FFS) volume.", - 4, - "EFI_STATUS (EFIAPI *EFI_PEI_FFS_FIND_NEXT_FILE) (IN struct " - "_EFI_PEI_SERVICES **PeiServices, IN EFI_FV_FILETYPE SearchType, IN " - "EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader, IN OUT EFI_FFS_FILE_HEADER " - "**FileHeader);", - 0, PUSH_NONE, GUID_OFFSET_NONE}, - {"FfsFindSectionData", 0x40, - "Given the input file pointer, this service searches for the next " - "matching file in the Firmware File System (FFS) volume.", - 4, - "EFI_STATUS (EFIAPI *EFI_PEI_FFS_FIND_SECTION_DATA) (IN struct " - "_EFI_PEI_SERVICES **PeiServices, IN EFI_SECTION_TYPE SectionType, IN " - "EFI_FFS_FILE_HEADER *FfsFileHeader, IN OUT VOID **SectionData);", - 0, PUSH_NONE, GUID_OFFSET_NONE}, - {"InstallPeiMemory", 0x44, - "This function registers the found memory configuration with the PEI " - "Foundation.", - 3, - "EFI_STATUS(EFIAPI * EFI_PEI_INSTALL_PEI_MEMORY) (IN CONST " - "EFI_PEI_SERVICES **PeiServices, IN EFI_PHYSICAL_ADDRESS MemoryBegin, IN " - "UINT64 MemoryLength)", - 0, PUSH_NONE, GUID_OFFSET_NONE}, - {"AllocatePages", 0x48, - "The purpose of the service is to publish an interface that allows PEIMs " - "to allocate memory ranges that are managed by the PEI Foundation.", - 4, - "EFI_STATUS(EFIAPI * EFI_PEI_ALLOCATE_PAGES) (IN CONST EFI_PEI_SERVICES " - "**PeiServices, IN EFI_MEMORY_TYPE MemoryType, IN UINTN Pages, OUT " - "EFI_PHYSICAL_ADDRESS *Memory)", - 0, PUSH_NONE, GUID_OFFSET_NONE}, - {"AllocatePool", 0x4C, - "The purpose of this service is to publish an interface that allows PEIMs " - "to allocate memory ranges that are managed by the PEI Foundation.", - 3, - " EFI_STATUS(EFIAPI * EFI_PEI_ALLOCATE_POOL) (IN CONST EFI_PEI_SERVICES " - "**PeiServices, IN UINTN Size, OUT VOID **Buffer)", - 0, PUSH_NONE, GUID_OFFSET_NONE}, - {"CopyMem", 0x50, "This service copies the contents of one buffer to another buffer.", - 3, - "VOID(EFIAPI * EFI_PEI_COPY_MEM) (IN VOID *Destination, IN VOID *Source, " - "IN UINTN Length)", - 0, PUSH_NONE, GUID_OFFSET_NONE}, - {"SetMem", 0x54, "The service fills a buffer with a specified value.", 3, - "VOID(EFIAPI * EFI_PEI_SET_MEM) (IN VOID *Buffer, IN UINTN Size, IN UINT8 " - "Value)", - 0, PUSH_NONE, GUID_OFFSET_NONE}, - {"ReportStatusCode", 0x58, - "This service publishes an interface that allows PEIMs to report status codes. \ - ReportStatusCode() is called by PEIMs that wish to report status information on their progress. The principal use model is for a PEIM to emit one of the standard 32-bit error codes. This will allow a platform owner to ascertain the state of the system, especially under conditions where the full consoles might not have been installed.", - 6, - "EFI_STATUS(EFIAPI * EFI_PEI_REPORT_STATUS_CODE) (IN CONST " - "EFI_PEI_SERVICES **PeiServices, IN EFI_STATUS_CODE_TYPE Type, IN " - "EFI_STATUS_CODE_VALUE Value, IN UINT32 Instance, IN CONST EFI_GUID " - "*CallerId OPTIONAL, IN CONST EFI_STATUS_CODE_DATA *Data OPTIONAL)", - 0, PUSH_NONE, GUID_OFFSET_NONE}, - {"ResetSystem", 0x5C, "Resets the entire platform. \ - This service resets the entire platform, including all processors and devices, and reboots the system. This service will never return EFI_SUCCESS.", - 1, - "EFI_STATUS(EFIAPI * EFI_PEI_RESET_SYSTEM) (IN CONST EFI_PEI_SERVICES " - "**PeiServices)", - 0, PUSH_NONE, GUID_OFFSET_NONE}, - {"CpuIo", 0x60, - "Provides an interface that a PEIM can call to execute an I/O " - "transaction. This service is installed by an architectural PEI driver by " - "copying the interface pointer into this table.", - 1, "", 0, PUSH_NONE, GUID_OFFSET_NONE}, - {"PciCfg", 0x64, - "Provides an interface that a PEIM can call to execute PCI Configuration " - "transactions. This service is installed by an architectural PEI driver " - "by copying the interface pointer into this table.", - 1, "", 0, PUSH_NONE, GUID_OFFSET_NONE}}; - -size_t pei_services_table_size = sizeof(pei_services_table) / sizeof(pei_services_entry); - -char variable_ppi_name[] = "VariablePPI"; -struct variable_ppi_entry { - char name[256]; - uint32_t offset; - char description[1024]; - uint32_t nr_args; - char prototype[512]; -}; - -struct variable_ppi_entry variable_ppi_table[] = { - {"GetVariable", 0x0, - "This service retrieves a variable's value using its name and GUID." - "Read the specified variable from the UEFI variable store. If the Data" - "buffer is too small to hold the contents of the variable," - "the error EFI_BUFFER_TOO_SMALL is returned and DataSize is set to the" - "required buffer size to obtain the data.", - 6, - "EFI_STATUS (EFIAPI *EFI_PEI_GET_VARIABLE2)" - "(IN CONSTEFI_PEI_READ_ONLY_VARIABLE2_PPI *This, " - "IN CONST CHAR16 *VariableName, IN CONST EFI_GUID *VariableGuid," - "OUT UINT32 *Attributes, IN OUT UINTN *DataSize, OUT VOID *Data OPTIONAL);"}, - {"NextVariableName", 0x4, - "This function is called multiple times to retrieve the VariableName" - "and VariableGuid of all variables currently available in the system." - "On each call, the previous results are passed into the interface, " - "and, on return, the interface returns the data for the next " - "interface. When the entire variable list has been returned, " - "EFI_NOT_FOUND is returned.", - 4, - "EFI_STATUS (EFIAPI *EFI_PEI_GET_NEXT_VARIABLE_NAME2)" - "(IN CONST EFI_PEI_READ_ONLY_VARIABLE2_PPI *This," - "IN OUT UINTN *VariableNameSize, IN OUT CHAR16 *VariableName," - "IN OUT EFI_GUID *VariableGuid);"}}; - -size_t variable_ppi_table_size = sizeof(variable_ppi_table) / sizeof(variable_ppi_entry); diff --git a/efiXplorer/tables/efi_system_tables.h b/efiXplorer/tables/efi_system_tables.h deleted file mode 100644 index d36a630e..00000000 --- a/efiXplorer/tables/efi_system_tables.h +++ /dev/null @@ -1,597 +0,0 @@ -/* - * ______________________.___ - * \_ _____/\_ _____/| | - * | __)_ | __) | | - * | \ | \ | | - * /_______ / \___ / |___| - * \/ \/ - * _________ .__ ____ __. .__ _____ - * / _____/_ _ _|__| ______ _____ | |/ _| ____ |__|/ ____\____ - * \_____ \\ \/ \/ / |/ ___// ___/ | < / \| \ __\/ __ \ - * / \\ /| |\___ \ \___ \ | | \| | \ || | \ ___/ - * /_______ / \/\_/ |__/____ >____ > |____|__ \___| /__||__| \___ > - * \/ \/ \/ \/ \/ \/ - * - * EFI Swiss Knife - * An IDA plugin to improve (U)EFI reversing - * - * Copyright (C) 2016, 2017 Pedro Vilaça (fG!) - reverser@put.as - - * https://reverse.put.as - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * efi_system_tables.h - * - */ - -#pragma once - -#include "stdint.h" - -#define BTABLE_LEN 43 -#define RTABLE_LEN 14 - -struct services_entry { - char name[256]; - uint32_t offset64; - uint32_t offset32; - char description[1024]; - uint32_t nr_args; - char prototype[512]; - char parameters[2048]; - char rcx_param[256]; - char rdx_param[256]; - char r8_param[256]; - char r9_param[256]; - char stack1_param[256]; - char stack2_param[256]; - char stack3_param[256]; - char stack4_param[256]; - uint32_t count; -}; - -struct services_entry boot_services_table[] = { - {"RaiseTPL", 0x18, 0x18, - "Raises a task's priority level and returns its previous level.", 1, - "EFI_TPL(EFIAPI * EFI_RAISE_TPL) (IN EFI_TPL NewTpl)", - "NewTpl The new task priority level.", "IN EFI_TPL NewTpl", "", "", "", "", "", "", - "", 0}, - {"RestoreTPL", 0x20, 0x1c, "Restores a task's priority level to its previous value.", - 1, "VOID(EFIAPI * EFI_RESTORE_TPL) (IN EFI_TPL OldTpl)", - "OldTpl The previous task priority level to restore.", "IN EFI_TPL OldTpl", "", "", - "", "", "", "", "", 0}, - {"AllocatePages", 0x28, 0x20, "Allocates memory pages from the system.", 4, - "EFI_STATUS(EFIAPI * EFI_ALLOCATE_PAGES) (IN EFI_ALLOCATE_TYPE Type, IN " - "EFI_MEMORY_TYPE MemoryType, IN UINTN Pages, IN OUT EFI_PHYSICAL_ADDRESS " - "*Memory)", - "Type The type of allocation to perform.\n\ -MemoryType The type of memory to allocate.\n\ -Pages The number of contiguous 4 KB pages to allocate.\n\ -Memory The pointer to a physical address. On input, the way in which the address is used depends on the value of Type.", - "IN EFI_ALLOCATE_TYPE Type", "IN EFI_MEMORY_TYPE MemoryType", "IN UINTN Pages", - "IN OUT EFI_PHYSICAL_ADDRESS *Memory", "", "", "", "", 0}, - {"FreePages", 0x30, 0x24, "Frees memory pages.", 2, - "EFI_STATUS(EFIAPI * EFI_FREE_PAGES) (IN EFI_PHYSICAL_ADDRESS Memory, IN " - "UINTN Pages)", - "Memory The base physical address of the pages to be freed.\n\ -Pages The number of contiguous 4 KB pages to free.", - "IN EFI_PHYSICAL_ADDRESS Memory", "IN UINTN Pages", "", "", "", "", "", "", 0}, - {"GetMemoryMap", 0x38, 0x28, "Returns the current memory map.", 5, - "EFI_STATUS(EFIAPI * EFI_GET_MEMORY_MAP) (IN OUT UINTN *MemoryMapSize, IN " - "OUT EFI_MEMORY_DESCRIPTOR *MemoryMap, OUT UINTN *MapKey, OUT UINTN " - "*DescriptorSize, OUT UINT32 *DescriptorVersion)", - "MemoryMapSize A pointer to the size, in bytes, of the MemoryMap buffer. On input, this is the size of the buffer allocated by the caller.\n\ - On output, it is the size of the buffer returned by the firmware if the buffer was large enough, or the size of the buffer\n\ - needed to contain the map if the buffer was too small.\n\ -MemoryMap A pointer to the buffer in which firmware places the current memory map.\n\ -MapKey A pointer to the location in which firmware returns the key for the current memory map.\n\ -DescriptorSize A pointer to the location in which firmware returns the size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.\n\ -DescriptorVersion A pointer to the location in which firmware returns the version number associated with the EFI_MEMORY_DESCRIPTOR.", - "IN OUT UINTN *MemoryMapSize", "IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap", - "OUT UINTN *MapKey", "OUT UINTN *DescriptorSize", "OUT UINT32 *DescriptorVersion", - "", "", "", 0}, - {"AllocatePool", 0x40, 0x2c, "Allocates pool memory.", 3, - "EFI_STATUS(EFIAPI * EFI_ALLOCATE_POOL) (IN EFI_MEMORY_TYPE PoolType, IN " - "UINTN Size, OUT VOID **Buffer)", - "PoolType The type of pool to allocate.\n\ -Size The number of bytes to allocate from the pool.\n\ -Buffer A pointer to a pointer to the allocated buffer if the call succeeds; undefined otherwise.", - "IN EFI_MEMORY_TYPE PoolType", "IN UINTN Size", "OUT VOID **Buffer", "", "", "", "", - "", 0}, - {"FreePool", 0x48, 0x30, "Returns pool memory to the system.", 1, - "EFI_STATUS(EFIAPI * EFI_FREE_POOL) (IN VOID *Buffer)", - "Buffer The pointer to the buffer to free.", "IN VOID *Buffer", "", "", "", "", "", - "", "", 0}, - {"CreateEvent", 0x50, 0x34, "Creates an event.", 5, - "EFI_STATUS(EFIAPI * EFI_CREATE_EVENT) (IN UINT32 Type, IN EFI_TPL " - "NotifyTpl, IN EFI_EVENT_NOTIFY NotifyFunction, IN VOID *NotifyContext, " - "OUT EFI_EVENT *Event)", - "Type The type of event to create and its mode and attributes.\n\ -NotifyTpl The task priority level of event notifications, if needed.\n\ -NotifyFunction The pointer to the event's notification function, if any.\n\ -NotifyContext The pointer to the notification function's context; corresponds to parameter Context in the notification function.\n\ -Event The pointer to the newly created event if the call succeeds; undefined otherwise.", - "IN UINT32 Type", "IN EFI_TPL NotifyTpl", "IN EFI_EVENT_NOTIFY NotifyFunction", - "IN VOID *NotifyContext", "OUT EFI_EVENT *Event", "", "", "", 0}, - {"SetTimer", 0x58, 0x38, - "Sets the type of timer and the trigger time for a timer event.", 3, - "EFI_STATUS(EFIAPI * EFI_SET_TIMER) (IN EFI_EVENT Event, IN " - "EFI_TIMER_DELAY Type, IN UINT64 TriggerTime)", - "Event The timer event that is to be signaled at the specified time.\n\ -Type The type of time that is specified in TriggerTime.\n\ -TriggerTime The number of 100ns units until the timer expires. A TriggerTime of 0 is legal. If Type is TimerRelative and TriggerTime is 0, then the timer event will be signaled on the next timer tick. If Type is TimerPeriodic and TriggerTime is 0, then the timer event will be signaled on every timer tick.", - "IN EFI_EVENT Event", "IN EFI_TIMER_DELAY Type", "IN UINT64 TriggerTime", "", "", "", - "", "", 0}, - {"WaitForEvent", 0x60, 0x3c, "Stops execution until an event is signaled.", 3, - "EFI_STATUS(EFIAPI * EFI_WAIT_FOR_EVENT) (IN UINTN NumberOfEvents, IN " - "EFI_EVENT *Event, OUT UINTN *Index)", - "NumberOfEvents The number of events in the Event array.\n\ -Event An array of EFI_EVENT.\n\ -Index The pointer to the index of the event which satisfied the wait condition.", - "IN UINTN NumberOfEvents", "IN EFI_EVENT *Event", "OUT UINTN *Index", "", "", "", "", - "", 0}, - {"SignalEvent", 0x68, 0x40, "Signals an event.", 1, - "EFI_STATUS(EFIAPI * EFI_SIGNAL_EVENT) (IN EFI_EVENT Event)", - "Event The event to signal.", "IN EFI_EVENT Event", "", "", "", "", "", "", "", 0}, - {"CloseEvent", 0x70, 0x44, "Closes an event.", 1, - "EFI_STATUS(EFIAPI * EFI_CLOSE_EVENT) (IN EFI_EVENT Event)", - "Event The event to close.", "IN EFI_EVENT Event", "", "", "", "", "", "", "", 0}, - {"CheckEvent", 0x78, 0x48, "Checks whether an event is in the signaled state.", 1, - "EFI_STATUS(EFIAPI * EFI_CHECK_EVENT) (IN EFI_EVENT Event)", - "Event The event to check.", "IN EFI_EVENT Event", "", "", "", "", "", "", "", 0}, - {"InstallProtocolInterface", 0x80, 0x4c, - "Installs a protocol interface on a device handle. If the handle does not " - "exist, it is created and added to the list of handles in the system. " - "InstallMultipleProtocolInterfaces() performs more error checking than " - "InstallProtocolInterface(), so it is recommended that " - "InstallMultipleProtocolInterfaces() be used in place of " - "InstallProtocolInterface()", - 4, - "EFI_STATUS(EFIAPI * EFI_INSTALL_PROTOCOL_INTERFACE) (IN OUT EFI_HANDLE " - "*Handle, IN EFI_GUID *Protocol, IN EFI_INTERFACE_TYPE InterfaceType, IN " - "VOID *Interface)", - "Handle A pointer to the EFI_HANDLE on which the interface is to be installed.\n\ -Protocol The numeric ID of the protocol interface.\n\ -InterfaceType Indicates whether Interface is supplied in native form.\n\ -Interface A pointer to the protocol interface.", - "IN OUT EFI_HANDLE *Handle", "IN EFI_GUID *Protocol", - "IN EFI_INTERFACE_TYPE InterfaceType", "IN VOID *Interface", "", "", "", "", 0}, - {"ReinstallProtocolInterface", 0x88, 0x50, - "Reinstalls a protocol interface on a device handle.", 4, - "EFI_STATUS(EFIAPI * EFI_REINSTALL_PROTOCOL_INTERFACE) (IN EFI_HANDLE " - "Handle, IN EFI_GUID *Protocol, IN VOID *OldInterface, IN VOID " - "*NewInterface)", - "Handle Handle on which the interface is to be reinstalled.\n\ -Protocol The numeric ID of the interface.\n\ -OldInterface A pointer to the old interface. NULL can be used if a structure is not associated with Protocol.\n\ -NewInterface A pointer to the new interface.", - "IN EFI_HANDLE Handle", "IN EFI_GUID *Protocol", "IN VOID *OldInterface", - "IN VOID *NewInterface", "", "", "", "", 0}, - {"UninstallProtocolInterface", 0x90, 0x54, - "Removes a protocol interface from a device handle. It is recommended " - "that UninstallMultipleProtocolInterfaces() be used in place of " - "UninstallProtocolInterface().", - 3, - "EFI_STATUS(EFIAPI * EFI_UNINSTALL_PROTOCOL_INTERFACE) (IN EFI_HANDLE " - "Handle, IN EFI_GUID *Protocol, IN VOID *Interface)", - "Handle The handle on which the interface was installed.\n\ -Protocol The numeric ID of the interface.\n\ -Interface A pointer to the interface.", - "IN EFI_HANDLE Handle", "IN EFI_GUID *Protocol", "IN VOID *Interface", "", "", "", - "", "", 0}, - {"HandleProtocol", 0x98, 0x58, - "Queries a handle to determine if it supports a specified protocol.", 3, - "EFI_STATUS(EFIAPI * EFI_HANDLE_PROTOCOL) (IN EFI_HANDLE Handle, IN " - "EFI_GUID *Protocol, OUT VOID **Interface)", - "Handle The handle being queried.\n\ -Protocol The published unique identifier of the protocol.\n\ -Interface Supplies the address where a pointer to the corresponding Protocol Interface is returned.", - "IN EFI_HANDLE Handle", "IN EFI_GUID *Protocol", "OUT VOID **Interface", "", "", "", - "", "", 0}, - {"RegisterProtocolNotify", 0xA8, 0x60, - "Creates an event that is to be signaled whenever an interface is " - "installed for a specified protocol.", - 3, - "EFI_STATUS(EFIAPI * EFI_REGISTER_PROTOCOL_NOTIFY) (IN EFI_GUID " - "*Protocol, IN EFI_EVENT Event, OUT VOID **Registration)", - "Protocol The numeric ID of the protocol for which the event is to be registered.\n\ -Event Event that is to be signaled whenever a protocol interface is registered for Protocol.\n\ -Registration A pointer to a memory location to receive the registration value.", - "IN EFI_GUID *Protocol", "IN EFI_EVENT Event", "OUT VOID **Registration", "", "", "", - "", "", 0}, - {"LocateHandle", 0xB0, 0x64, - "Returns an array of handles that support a specified protocol.", 5, - "EFI_STATUS(EFIAPI * EFI_LOCATE_HANDLE) (IN EFI_LOCATE_SEARCH_TYPE " - "SearchType, IN EFI_GUID *Protocol, OPTIONAL IN VOID *SearchKey, OPTIONAL " - "IN OUT UINTN *BufferSize, OUT EFI_HANDLE *Buffer)", - "SearchType Specifies which handle(s) are to be returned.\n\ -Protocol Specifies the protocol to search by.\n\ -SearchKey Specifies the search key.\n\ -BufferSize On input, the size in bytes of Buffer. On output, the size in bytes of the array returned in Buffer (if the buffer was large enough) or the size, in bytes, of the buffer needed to obtain the array (if the buffer was not large enough).\n\ -Buffer The buffer in which the array is returned.", - "IN EFI_LOCATE_SEARCH_TYPE SearchType", "IN EFI_GUID *Protocol", - "OPTIONAL IN VOID *SearchKey", "OPTIONAL IN OUT UINTN *BufferSize", - "OUT EFI_HANDLE *Buffer", "", "", "", 0}, - {"LocateDevicePath", 0xB8, 0x68, - "Locates the handle to a device on the device path that supports the " - "specified protocol.", - 3, - "EFI_STATUS(EFIAPI * EFI_LOCATE_DEVICE_PATH) (IN EFI_GUID *Protocol, IN " - "OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath, OUT EFI_HANDLE *Device)", - "Protocol Specifies the protocol to search for.\n\ -DevicePath On input, a pointer to a pointer to the device path. On output, the device path pointer is modified to point to the remaining part of the device path.\n\ -Device A pointer to the returned device handle.", - "IN EFI_GUID *Protocol", "IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath", - "OUT EFI_HANDLE *Device", "", "", "", "", "", 0}, - {"InstallConfigurationTable", 0xC0, 0x6c, - "Adds, updates, or removes a configuration table entry from the EFI " - "System Table.", - 2, - "EFI_STATUS(EFIAPI * EFI_INSTALL_CONFIGURATION_TABLE) (IN EFI_GUID *Guid, " - "IN VOID *Table)", - "Guid A pointer to the GUID for the entry to add, update, or remove.\n\ -Table A pointer to the configuration table for the entry to add, update, or remove. May be NULL.", - "IN EFI_GUID *Guid", "IN VOID *Table", "", "", "", "", "", "", 0}, - {"LoadImage", 0xC8, 0x70, "Loads an EFI image into memory.", 6, - "EFI_STATUS(EFIAPI * EFI_IMAGE_LOAD) (IN BOOLEAN BootPolicy, IN " - "EFI_HANDLE ParentImageHandle, IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, " - "IN VOID *SourceBuffer OPTIONAL, IN UINTN SourceSize, OUT EFI_HANDLE " - "*ImageHandle)", - "BootPolicy If TRUE, indicates that the request originates from the boot manager, and that the boot manager is attempting to load FilePath as a boot selection. Ignored if SourceBuffer is not NULL.\n\ -ParentImageHandle The caller's image handle.\n\ -DevicePath The DeviceHandle specific file path from which the image is loaded.\n\ -SourceBuffer If not NULL, a pointer to the memory location containing a copy of the image to be loaded.\n\ -SourceSize The size in bytes of SourceBuffer. Ignored if SourceBuffer is NULL.\n\ -ImageHandle The pointer to the returned image handle that is created when the image is successfully loaded.", - "IN BOOLEAN BootPolicy", "IN EFI_HANDLE ParentImageHandle", - "IN EFI_DEVICE_PATH_PROTOCOL *DevicePath", "IN VOID *SourceBuffer OPTIONAL", - "IN UINTN SourceSize", "OUT EFI_HANDLE *ImageHandle", "", "", 0}, - {"StartImage", 0xD0, 0x74, "Transfers control to a loaded image's entry point.", 3, - "EFI_STATUS(EFIAPI * EFI_IMAGE_START) (IN EFI_HANDLE ImageHandle, OUT " - "UINTN *ExitDataSize, OUT CHAR16 **ExitData OPTIONAL)", - "ImageHandle Handle of image to be started.\n\ -ExitDataSize The pointer to the size, in bytes, of ExitData.\n\ -ExitData The pointer to a pointer to a data buffer that includes a Null-terminated string, optionally followed by additional binary data.", - "IN EFI_HANDLE ImageHandle", "OUT UINTN *ExitDataSize", - "OUT CHAR16 **ExitData OPTIONAL", "", "", "", "", "", 0}, - {"Exit", 0xD8, 0x78, - "Terminates a loaded EFI image and returns control to boot services.", 4, - "EFI_STATUS(EFIAPI * EFI_EXIT) (IN EFI_HANDLE ImageHandle, IN EFI_STATUS " - "ExitStatus, IN UINTN ExitDataSize, IN CHAR16 *ExitData OPTIONAL)", - "ImageHandle Handle that identifies the image. This parameter is passed to the image on entry.\n\ -ExitStatus The image's exit code.\n\ -ExitDataSize The size, in bytes, of ExitData. Ignored if ExitStatus is EFI_SUCCESS.\n\ -ExitData The pointer to a data buffer that includes a Null-terminated string, optionally followed by additional binary data. The string is a description that the caller may use to further indicate the reason for the image's exit. ExitData is only valid if ExitStatus is something other than EFI_SUCCESS. The ExitData buffer must be allocated by calling AllocatePool().", - "IN EFI_HANDLE ImageHandle", "IN EFI_STATUS ExitStatus", "IN UINTN ExitDataSize", - "IN CHAR16 *ExitData OPTIONAL", "", "", "", "", 0}, - {"UnloadImage", 0xE0, 0x7c, "Unloads an image.", 1, - "EFI_STATUS(EFIAPI * EFI_IMAGE_UNLOAD) (IN EFI_HANDLE ImageHandle)", - "ImageHandle Handle that identifies the image to be unloaded.", - "IN EFI_HANDLE ImageHandle", "", "", "", "", "", "", "", 0}, - {"ExitBootServices", 0xE8, 0x80, "Terminates all boot services.", 2, - "EFI_STATUS(EFIAPI * EFI_EXIT_BOOT_SERVICES) (IN EFI_HANDLE ImageHandle, " - "IN UINTN MapKey)", - "ImageHandle Handle that identifies the exiting image.\n\ -MapKey Key to the latest memory map.", - "IN EFI_HANDLE ImageHandle", "IN UINTN MapKey", "", "", "", "", "", "", 0}, - {"GetNextMonotonicCount", 0xF0, 0x84, - "Returns a monotonically increasing count for the platform.", 1, - "EFI_STATUS(EFIAPI * EFI_GET_NEXT_MONOTONIC_COUNT) (OUT UINT64 *Count)", - "Count The pointer to returned value.", "OUT UINT64 *Count", "", "", "", "", "", "", - "", 0}, - {"Stall", 0xF8, 0x88, "Induces a fine-grained stall.", 1, - "EFI_STATUS(EFIAPI * EFI_STALL) (IN UINTN Microseconds)", - "Microseconds The number of microseconds to stall execution.", - "IN UINTN Microseconds", "", "", "", "", "", "", "", 0}, - {"SetWatchdogTimer", 0x100, 0x8c, "Sets the system's watchdog timer.", 4, - "EFI_STATUS(EFIAPI * EFI_SET_WATCHDOG_TIMER) (IN UINTN Timeout, IN UINT64 " - "WatchdogCode, IN UINTN DataSize, IN CHAR16 *WatchdogData OPTIONAL)", - "Timeout The number of seconds to set the watchdog timer to.\n\ -WatchdogCode The numeric code to log on a watchdog timer timeout event.\n\ -DataSize The size, in bytes, of WatchdogData.\n\ -WatchdogData A data buffer that includes a Null-terminated string, optionally followed by additional binary data.", - "IN UINTN Timeout", "IN UINT64 WatchdogCode", "IN UINTN DataSize", - "IN CHAR16 *WatchdogData OPTIONAL", "", "", "", "", 0}, - {"ConnectController", 0x108, 0x90, "Connects one or more drivers to a controller.", 4, - "EFI_STATUS(EFIAPI * EFI_CONNECT_CONTROLLER) (IN EFI_HANDLE " - "ControllerHandle, IN EFI_HANDLE *DriverImageHandle, OPTIONAL IN " - "EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath, OPTIONAL IN BOOLEAN " - "Recursive)", - "ControllerHandle The handle of the controller to which driver(s) are to be connected.\n\ -DriverImageHandle A pointer to an ordered list handles that support the EFI_DRIVER_BINDING_PROTOCOL.\n\ -RemainingDevicePath A pointer to the device path that specifies a child of the controller specified by ControllerHandle.\n\ -Recursive If TRUE, then ConnectController() is called recursively until the entire tree of controllers below the controller specified by ControllerHandle have been created. If FALSE, then the tree of controllers is only expanded one level.", - "IN EFI_HANDLE ControllerHandle", "IN EFI_HANDLE *DriverImageHandle", - "OPTIONAL IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath", - "OPTIONAL IN BOOLEAN Recursive", "", "", "", "", 0}, - {"DisconnectController", 0x110, 0x94, - "Disconnects one or more drivers from a controller.", 3, - "EFI_STATUS(EFIAPI * EFI_DISCONNECT_CONTROLLER) (IN EFI_HANDLE " - "ControllerHandle, IN EFI_HANDLE DriverImageHandle, OPTIONAL IN " - "EFI_HANDLE ChildHandle OPTIONAL)", - "ControllerHandle The handle of the controller from which driver(s) are to be disconnected.\n\ -DriverImageHandle The driver to disconnect from ControllerHandle. If DriverImageHandle is NULL, then all the drivers currently managing ControllerHandle are disconnected from ControllerHandle.\n\ -ChildHandle The handle of the child to destroy. If ChildHandle is NULL, then all the children of ControllerHandle are destroyed before the drivers are disconnected from ControllerHandle.", - "IN EFI_HANDLE ControllerHandle", "IN EFI_HANDLE DriverImageHandle", - "OPTIONAL IN EFI_HANDLE ChildHandle OPTIONAL", "", "", "", "", "", 0}, - {"OpenProtocol", 0x118, 0x98, - "Queries a handle to determine if it supports a specified protocol. If " - "the protocol is supported by the handle, it opens the protocol on behalf " - "of the calling agent.", - 6, - "EFI_STATUS(EFIAPI * EFI_OPEN_PROTOCOL) (IN EFI_HANDLE Handle, IN " - "EFI_GUID *Protocol, OUT VOID **Interface, OPTIONAL IN EFI_HANDLE " - "AgentHandle, IN EFI_HANDLE ControllerHandle, IN UINT32 Attributes)", - "Handle The handle for the protocol interface that is being opened.\n\ -Protocol The published unique identifier of the protocol.\n\ -Interface Supplies the address where a pointer to the corresponding Protocol Interface is returned.\n\ -AgentHandle The handle of the agent that is opening the protocol interface specified by Protocol and Interface.\n\ -ControllerHandle If the agent that is opening a protocol is a driver that follows the UEFI Driver Model, then this parameter is the controller handle that requires the protocol interface. If the agent does not follow the UEFI Driver Model, then this parameter is optional and may be NULL.\n\ -Attributes The open mode of the protocol interface specified by Handle and Protocol.", - "IN EFI_HANDLE Handle", "IN EFI_GUID *Protocol", "OUT VOID **Interface", - "OPTIONAL IN EFI_HANDLE AgentHandle", "IN EFI_HANDLE ControllerHandle", - "IN UINT32 Attributes", "", "", 0}, - {"CloseProtocol", 0x120, 0x9c, - "Closes a protocol on a handle that was opened using OpenProtocol().", 4, - "EFI_STATUS(EFIAPI * EFI_CLOSE_PROTOCOL) (IN EFI_HANDLE Handle, IN " - "EFI_GUID *Protocol, IN EFI_HANDLE AgentHandle, IN EFI_HANDLE " - "ControllerHandle)", - "Handle The handle for the protocol interface that was previously opened with OpenProtocol(), and is now being closed.\n\ -Protocol The published unique identifier of the protocol.\n\ -AgentHandle The handle of the agent that is closing the protocol interface.\n\ -ControllerHandle If the agent that opened a protocol is a driver that follows the UEFI Driver Model, then this parameter is the controller handle that required the protocol interface.", - "IN EFI_HANDLE Handle", "IN EFI_GUID *Protocol", "IN EFI_HANDLE AgentHandle", - "IN EFI_HANDLE ControllerHandle", "", "", "", "", 0}, - {"OpenProtocolInformation", 0x128, 0xa0, - "Retrieves the list of agents that currently have a protocol interface " - "opened.", - 4, - "EFI_STATUS(EFIAPI * EFI_OPEN_PROTOCOL_INFORMATION) (IN EFI_HANDLE " - "Handle, IN EFI_GUID *Protocol, OUT EFI_OPEN_PROTOCOL_INFORMATION_ENTRY " - "**EntryBuffer, OUT UINTN *EntryCount)", - "Handle The handle for the protocol interface that is being queried.\n\ -Protocol The published unique identifier of the protocol.\n\ -EntryBuffer A pointer to a buffer of open protocol information in the form of EFI_OPEN_PROTOCOL_INFORMATION_ENTRY structures.\n\ -EntryCount A pointer to the number of entries in EntryBuffer.", - "IN EFI_HANDLE Handle", "IN EFI_GUID *Protocol", - "OUT EFI_OPEN_PROTOCOL_INFORMATION_ENTRY **EntryBuffer", "OUT UINTN *EntryCount", "", - "", "", "", 0}, - {"ProtocolsPerHandle", 0x130, 0xa4, - "Retrieves the list of protocol interface GUIDs that are installed on a " - "handle in a buffer allocated from pool.", - 3, - "EFI_STATUS(EFIAPI * EFI_PROTOCOLS_PER_HANDLE) (IN EFI_HANDLE Handle, OUT " - "EFI_GUID ***ProtocolBuffer, OUT UINTN *ProtocolBufferCount)", - "Handle The handle from which to retrieve the list of protocol interface GUIDs.\n\ -ProtocolBuffer A pointer to the list of protocol interface GUID pointers that are installed on Handle.\n\ -ProtocolBufferCount A pointer to the number of GUID pointers present in ProtocolBuffer.", - "IN EFI_HANDLE Handle", "OUT EFI_GUID ***ProtocolBuffer", - "OUT UINTN *ProtocolBufferCount", "", "", "", "", "", 0}, - {"LocateHandleBuffer", 0x138, 0xa8, - "Returns an array of handles that support the requested protocol in a " - "buffer allocated from pool.", - 5, - "EFI_STATUS(EFIAPI * EFI_LOCATE_HANDLE_BUFFER) (IN EFI_LOCATE_SEARCH_TYPE " - "SearchType, IN EFI_GUID *Protocol, OPTIONAL IN VOID *SearchKey, OPTIONAL " - "IN OUT UINTN *NoHandles, OUT EFI_HANDLE **Buffer)", - "SearchType Specifies which handle(s) are to be returned.\n\ -Protocol Provides the protocol to search by. This parameter is only valid for a SearchType of ByProtocol.\n\ -SearchKey Supplies the search key depending on the SearchType.\n\ -NoHandles The number of handles returned in Buffer.\n\ -Buffer A pointer to the buffer to return the requested array of handles that support Protocol.", - "IN EFI_LOCATE_SEARCH_TYPE SearchType", "IN EFI_GUID *Protocol", - "OPTIONAL IN VOID *SearchKey", "OPTIONAL IN OUT UINTN *NoHandles", - "OUT EFI_HANDLE **Buffer", "", "", "", 0}, - {"LocateProtocol", 0x140, 0xac, - "Returns the first protocol instance that matches the given protocol.", 3, - "EFI_STATUS(EFIAPI * EFI_LOCATE_PROTOCOL) (IN EFI_GUID *Protocol, IN VOID " - "*Registration, OPTIONAL OUT VOID **Interface)", - "Protocol Provides the protocol to search for.\n\ -Registration Optional registration key returned from RegisterProtocolNotify().\n\ -Interface On return, a pointer to the first interface that matches Protocol and Registration.", - "IN EFI_GUID *Protocol", "IN VOID *Registration", "OPTIONAL OUT VOID **Interface", - "", "", "", "", "", 0}, - {"InstallMultipleProtocolInterfaces", 0x148, 0xb0, - "Installs one or more protocol interfaces into the boot services " - "environment.", - 1, - "EFI_STATUS(EFIAPI * EFI_INSTALL_MULTIPLE_PROTOCOL_INTERFACES) (IN OUT " - "EFI_HANDLE *Handle,...)", - "Handle The pointer to a handle to install the new protocol interfaces on, or a pointer to NULL if a new handle is to be allocated.\n\ -... A variable argument list containing pairs of protocol GUIDs and protocol interfaces.", - "IN OUT EFI_HANDLE *Handle", "", "", "", "", "", "", "", 0}, - {"UninstallMultipleProtocolInterfaces", 0x150, 0xb4, - "Removes one or more protocol interfaces into the boot services " - "environment.", - 1, - "EFI_STATUS(EFIAPI * EFI_UNINSTALL_MULTIPLE_PROTOCOL_INTERFACES) (IN " - "EFI_HANDLE Handle,...)", - "Handle The handle to remove the protocol interfaces from.\n\ -... A variable argument list containing pairs of protocol GUIDs and protocol interfaces.", - "IN EFI_HANDLE Handle", "", "", "", "", "", "", "", 0}, - {"CalculateCrc32", 0x158, 0xb8, - "Computes and returns a 32-bit CRC for a data buffer.", 3, - "EFI_STATUS(EFIAPI * EFI_CALCULATE_CRC32) (IN VOID *Data, IN UINTN " - "DataSize, OUT UINT32 *Crc32)", - "Data A pointer to the buffer on which the 32-bit CRC is to be computed.\n\ -DataSize The number of bytes in the buffer Data.\n\ -Crc32 The 32-bit CRC that was computed for the data buffer specified by Data and DataSize.", - "IN VOID *Data", "IN UINTN DataSize", "OUT UINT32 *Crc32", "", "", "", "", "", 0}, - {"CopyMem", 0x160, 0xbc, "Copies the contents of one buffer to another buffer.", 3, - "VOID(EFIAPI * EFI_COPY_MEM) (IN VOID *Destination, IN VOID *Source, IN " - "UINTN Length)", - "Destination The pointer to the destination buffer of the memory copy.\n\ -Source The pointer to the source buffer of the memory copy.\n\ -Length Number of bytes to copy from Source to Destination.", - "IN VOID *Destination", "IN VOID *Source", "IN UINTN Length", "", "", "", "", "", 0}, - {"SetMem", 0x168, 0xc0, - "The SetMem() function fills a buffer with a specified value.", 3, - "VOID(EFIAPI * EFI_SET_MEM) (IN VOID *Buffer, IN UINTN Size, IN UINT8 " - "Value)", - "Buffer The pointer to the buffer to fill.\n\ -Size Number of bytes in Buffer to fill.\n\ -Value Value to fill Buffer with.", - "IN VOID *Buffer", "IN UINTN Size", "IN UINT8 Value", "", "", "", "", "", 0}, - {"CreateEventEx", 0x170, 0xc4, "Creates an event in a group.", 6, - "EFI_STATUS(EFIAPI * EFI_CREATE_EVENT_EX) (IN UINT32 Type, IN EFI_TPL " - "NotifyTpl, IN EFI_EVENT_NOTIFY NotifyFunction OPTIONAL, IN CONST VOID " - "*NotifyContext OPTIONAL, IN CONST EFI_GUID *EventGroup OPTIONAL, OUT " - "EFI_EVENT *Event)", - "Type The type of event to create and its mode and attributes.\n\ -NotifyTpl The task priority level of event notifications,if needed.\n\ -NotifyFunction The pointer to the event's notification function, if any.\n\ -NotifyContext The pointer to the notification function's context; corresponds to parameter Context in the notification function.\n\ -EventGroup The pointer to the unique identifier of the group to which this event belongs. If this is NULL, then the function behaves as if the parameters were passed to CreateEvent.\n\ -Event The pointer to the newly created event if the call succeeds; undefined otherwise.", - "IN UINT32 Type", "IN EFI_TPL NotifyTpl", - "IN EFI_EVENT_NOTIFY NotifyFunction OPTIONAL", - "IN CONST VOID *NotifyContext OPTIONAL", "IN CONST EFI_GUID *EventGroup OPTIONAL", - "OUT EFI_EVENT *Event", "", "", 0}}; - -struct services_entry runtime_services_table[] = { - {"GetTime", 0x18, 0x18, - "Returns the current time and date information, and the time-keeping " - "capabilities of the hardware platform.", - 2, - "EFI_STATUS(EFIAPI * EFI_GET_TIME) (OUT EFI_TIME *Time, OUT " - "EFI_TIME_CAPABILITIES *Capabilities OPTIONAL)", - "Time A pointer to storage to receive a snapshot of the current time.\n\ -Capabilities An optional pointer to a buffer to receive the real time clock device's capabilities.", - "OUT EFI_TIME *Time", "OUT EFI_TIME_CAPABILITIES *Capabilities OPTIONAL", "", "", "", - "", "", "", 0}, - {"SetTime", 0x20, 0x1c, "Sets the current local time and date information.", 1, - "EFI_STATUS(EFIAPI * EFI_SET_TIME) (IN EFI_TIME *Time)", - "Time A pointer to the current time.", "IN EFI_TIME *Time", "", "", "", "", "", "", - "", 0}, - {"GetWakeupTime", 0x28, 0x20, "Returns the current wakeup alarm clock setting.", 3, - "EFI_STATUS(EFIAPI * EFI_GET_WAKEUP_TIME) (OUT BOOLEAN *Enabled, OUT " - "BOOLEAN *Pending, OUT EFI_TIME *Time)", - "Enabled Indicates if the alarm is currently enabled or disabled.\n\ -Pending Indicates if the alarm signal is pending and requires acknowledgement.\n\ -Time The current alarm setting.", - "OUT BOOLEAN *Enabled", "OUT BOOLEAN *Pending", "OUT EFI_TIME *Time", "", "", "", "", - "", 0}, - {"SetWakeupTime", 0x30, 0x24, "Sets the system wakeup alarm clock time.", 2, - "EFI_STATUS(EFIAPI * EFI_SET_WAKEUP_TIME) (IN BOOLEAN Enable, IN EFI_TIME " - "*Time OPTIONAL)", - "Enabled Enable or disable the wakeup alarm.\n\ -Time If Enable is TRUE, the time to set the wakeup alarm for. If Enable is FALSE, then this parameter is optional, and may be NULL.", - "IN BOOLEAN Enable", "IN EFI_TIME *Time OPTIONAL", "", "", "", "", "", "", 0}, - {"SetVirtualAddressMap", 0x38, 0x28, - "Changes the runtime addressing mode of EFI firmware from physical to " - "virtual.", - 4, - "EFI_STATUS(EFIAPI * EFI_SET_VIRTUAL_ADDRESS_MAP) (IN UINTN " - "MemoryMapSize, IN UINTN DescriptorSize, IN UINT32 DescriptorVersion, IN " - "EFI_MEMORY_DESCRIPTOR *VirtualMap)", - "MemoryMapSize The size in bytes of VirtualMap.\n\ -DescriptorSize The size in bytes of an entry in the VirtualMap.\n\ -DescriptorVersion The version of the structure entries in VirtualMap.\n\ -VirtualMap An array of memory descriptors which contain new virtual address mapping information for all runtime ranges.", - "IN UINTN MemoryMapSize", "IN UINTN DescriptorSize", "IN UINT32 DescriptorVersion", - "IN EFI_MEMORY_DESCRIPTOR *VirtualMap", "", "", "", "", 0}, - {"ConvertPointer", 0x40, 0x2c, - "Determines the new virtual address that is to be used on subsequent " - "memory accesses.", - 2, - "EFI_STATUS(EFIAPI * EFI_CONVERT_POINTER) (IN UINTN DebugDisposition, IN " - "OUT VOID **Address)", - "DebugDisposition Supplies type information for the pointer being converted.\n\ -Address A pointer to a pointer that is to be fixed to be the value needed for the new virtual address mappings being applied.", - "IN UINTN DebugDisposition", "IN OUT VOID **Address", "", "", "", "", "", "", 0}, - {"GetVariable", 0x48, 0x30, "Returns the value of a variable.", 5, - "EFI_STATUS(EFIAPI * EFI_GET_VARIABLE) (IN CHAR16 *VariableName, IN " - "EFI_GUID *VendorGuid, OUT UINT32 *Attributes, OPTIONAL IN OUT UINTN " - "*DataSize, OUT VOID *Data)", - "VariableName A Null-terminated string that is the name of the vendor's variable.\n\ -VendorGuid A unique identifier for the vendor.\n\ -Attributes If not NULL, a pointer to the memory location to return the attributes bitmask for the variable.\n\ -DataSize On input, the size in bytes of the return Data buffer. On output the size of data returned in Data.\n\ -Data The buffer to return the contents of the variable.", - "IN CHAR16 *VariableName", "IN EFI_GUID *VendorGuid", "OUT UINT32 *Attributes", - "OPTIONAL IN OUT UINTN *DataSize", "OUT VOID *Data", "", "", "", 0}, - {"GetNextVariableName", 0x50, 0x3c, "Enumerates the current variable names.", 3, - "EFI_STATUS(EFIAPI * EFI_GET_NEXT_VARIABLE_NAME) (IN OUT UINTN " - "*VariableNameSize, IN OUT CHAR16 *VariableName, IN OUT EFI_GUID " - "*VendorGuid)", - "VariableNameSize The size of the VariableName buffer.\n\ -VariableName On input, supplies the last VariableName that was returned by GetNextVariableName(). On output, returns the Nullterminated string of the current variable.\n\ -VendorGuid On input, supplies the last VendorGuid that was returned by GetNextVariableName(). On output, returns the VendorGuid of the current variable.", - "IN OUT UINTN *VariableNameSize", "IN OUT CHAR16 *VariableName", - "IN OUT EFI_GUID *VendorGuid", "", "", "", "", "", 0}, - {"SetVariable", 0x58, 0x38, "Sets the value of a variable.", 5, - "EFI_STATUS(EFIAPI * EFI_SET_VARIABLE) (IN CHAR16 *VariableName, IN " - "EFI_GUID *VendorGuid, IN UINT32 Attributes, IN UINTN DataSize, IN VOID " - "*Data)", - "VariableName A Null-terminated string that is the name of the vendor's variable. Each VariableName is unique for each VendorGuid. VariableName must contain 1 or more characters. If VariableName is an empty string, then EFI_INVALID_PARAMETER is returned.\n\ -VendorGuid A unique identifier for the vendor.\n\ -Attributes Attributes bitmask to set for the variable.\n\ -DataSize The size in bytes of the Data buffer. Unless the EFI_VARIABLE_APPEND_WRITE, EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS, or EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute is set, a size of zero causes the variable to be deleted. When the EFI_VARIABLE_APPEND_WRITE attribute is set, \nthen a SetVariable() call with a DataSize of zero will not cause any change to the variable value (the timestamp associated with the variable may be updated however even if no new data value is provided,\n see the description of the EFI_VARIABLE_AUTHENTICATION_2 descriptor below. In this case the DataSize will not be zero since the EFI_VARIABLE_AUTHENTICATION_2 descriptor will be populated).\n\ -Data The contents for the variable.", - "IN CHAR16 *VariableName", "IN EFI_GUID *VendorGuid", "IN UINT32 Attributes", - "IN UINTN DataSize", "IN VOID *Data", "", "", "", 0}, - {"GetNextHighMonotonicCount", 0x60, 0x3c, - "Returns the next high 32 bits of the platform's monotonic counter.", 1, - "EFI_STATUS(EFIAPI * EFI_GET_NEXT_HIGH_MONO_COUNT) (OUT UINT32 " - "*HighCount)", - "HighCount The pointer to returned value.", "OUT UINT32 *HighCount", "", "", "", "", - "", "", "", 0}, - {"ResetSystem", 0x68, 0x40, "Resets the entire platform.", 4, - "VOID(EFIAPI * EFI_RESET_SYSTEM) (IN EFI_RESET_TYPE ResetType, IN " - "EFI_STATUS ResetStatus, IN UINTN DataSize, IN VOID *ResetData OPTIONAL)", - "ResetType The type of reset to perform.\n\ -ResetStatus The status code for the reset.\n\ -DataSize The size, in bytes, of WatchdogData.\n\ -ResetData For a ResetType of EfiResetCold, EfiResetWarm, or EfiResetShutdown the data buffer starts with a Null-terminated string, optionally followed by additional binary data.", - "IN EFI_RESET_TYPE ResetType", "IN EFI_STATUS ResetStatus", "IN UINTN DataSize", - "IN VOID *ResetData OPTIONAL", "", "", "", "", 0}, - {"UpdateCapsule", 0x70, 0x44, - "Passes capsules to the firmware with both virtual and physical mapping. " - "Depending on the intended consumption, the firmware may process the " - "capsule immediately. If the payload should persist across a system " - "reset, the reset value returned from EFI_QueryCapsuleCapabilities must " - "be passed into ResetSystem() and will cause the capsule to be processed " - "by the firmware as part of the reset process.", - 3, - "EFI_STATUS(EFIAPI * EFI_UPDATE_CAPSULE) (IN EFI_CAPSULE_HEADER " - "**CapsuleHeaderArray, IN UINTN CapsuleCount, IN EFI_PHYSICAL_ADDRESS " - "ScatterGatherList OPTIONAL)", - "CapsuleHeaderArray Virtual pointer to an array of virtual pointers to the capsules being passed into update capsule.\n\ -CapsuleCount Number of pointers to EFI_CAPSULE_HEADER in CaspuleHeaderArray.\n\ -ScatterGatherList Physical pointer to a set of EFI_CAPSULE_BLOCK_DESCRIPTOR that describes the location in physical memory of a set of capsules.", - "IN EFI_CAPSULE_HEADER **CapsuleHeaderArray", "IN UINTN CapsuleCount", - "IN EFI_PHYSICAL_ADDRESS ScatterGatherList OPTIONAL", "", "", "", "", "", 0}, - {"QueryCapsuleCapabilities", 0x78, 0x48, - "Returns if the capsule can be supported via UpdateCapsule().", 4, - "EFI_STATUS(EFIAPI * EFI_QUERY_CAPSULE_CAPABILITIES) (IN " - "EFI_CAPSULE_HEADER **CapsuleHeaderArray, IN UINTN CapsuleCount, OUT " - "UINT64 *MaximumCapsuleSize, OUT EFI_RESET_TYPE *ResetType)", - "CapsuleHeaderArray Virtual pointer to an array of virtual pointers to the capsules being passed into update capsule.\n\ -CapsuleCount Number of pointers to EFI_CAPSULE_HEADER in CaspuleHeaderArray.\n\ -MaxiumCapsuleSize On output the maximum size that UpdateCapsule() can support as an argument to UpdateCapsule() via CapsuleHeaderArray and ScatterGatherList.\n\ -ResetType Returns the type of reset required for the capsule update.", - "IN EFI_CAPSULE_HEADER **CapsuleHeaderArray", "IN UINTN CapsuleCount", - "OUT UINT64 *MaximumCapsuleSize", "OUT EFI_RESET_TYPE *ResetType", "", "", "", "", - 0}, - {"QueryVariableInfo", 0x80, 0x4c, "Returns information about the EFI variables.", 4, - "EFI_STATUS(EFIAPI * EFI_QUERY_VARIABLE_INFO) (IN UINT32 Attributes, OUT " - "UINT64 *MaximumVariableStorageSize, OUT UINT64 " - "*RemainingVariableStorageSize, OUT UINT64 *MaximumVariableSize)", - "Attributes Attributes bitmask to specify the type of variables on which to return information.\n\ -MaximumVariableStorageSize On output the maximum size of the storage space available for the EFI variables associated with the attributes specified.\n\ -RemainingVariableStorageSize Returns the remaining size of the storage space available for the EFI variables associated with the attributes specified.\n\ -MaximumVariableSize Returns the maximum size of the individual EFI variables associated with the attributes specified.", - "IN UINT32 Attributes", "OUT UINT64 *MaximumVariableStorageSize", - "OUT UINT64 *RemainingVariableStorageSize", "OUT UINT64 *MaximumVariableSize", "", - "", "", "", 0}}; From d0d12e957450e3e3c80f767012520bfdc458470a Mon Sep 17 00:00:00 2001 From: yeggor Date: Wed, 11 Sep 2024 09:11:43 +0200 Subject: [PATCH 09/69] use cc files in efixloader --- efiXloader/CMakeLists.txt | 6 +++--- efiXloader/{efi_loader.cpp => efi_loader.cc} | 0 efiXloader/{pe.cpp => pe.cc} | 0 efiXloader/{pe_manager.cpp => pe_manager.cc} | 0 efiXloader/{uefitool.cpp => uefitool.cc} | 0 efiXloader/{utils.cpp => utils.cc} | 0 6 files changed, 3 insertions(+), 3 deletions(-) rename efiXloader/{efi_loader.cpp => efi_loader.cc} (100%) rename efiXloader/{pe.cpp => pe.cc} (100%) rename efiXloader/{pe_manager.cpp => pe_manager.cc} (100%) rename efiXloader/{uefitool.cpp => uefitool.cc} (100%) rename efiXloader/{utils.cpp => utils.cc} (100%) diff --git a/efiXloader/CMakeLists.txt b/efiXloader/CMakeLists.txt index 17b3a634..c4aa633b 100644 --- a/efiXloader/CMakeLists.txt +++ b/efiXloader/CMakeLists.txt @@ -57,13 +57,13 @@ file( "3rd/uefitool/uefidump.h") # efiLoader sources -file(GLOB efiloader_src "*.h" "*.c" "*.cpp") +file(GLOB efiloader_src "*.h" "*.c" "*.cpp", "*.cc") -add_ida_loader(efiXloader NOEA32 ${PROJECT_SOURCE_DIR}/efi_loader.cpp) +add_ida_loader(efiXloader NOEA32 ${PROJECT_SOURCE_DIR}/efi_loader.cc) set_ida_target_properties(efiXloader PROPERTIES CXX_STANDARD 17) ida_target_include_directories(efiXloader PRIVATE ${IdaSdk_INCLUDE_DIRS}) -add_ida_library(efiXloader_lib ${efiloader_src} ${uefitool_src} uefitool.cpp +add_ida_library(efiXloader_lib ${efiloader_src} ${uefitool_src} uefitool.cc uefitool.h) ida_target_link_libraries(efiXloader efiXloader_lib) diff --git a/efiXloader/efi_loader.cpp b/efiXloader/efi_loader.cc similarity index 100% rename from efiXloader/efi_loader.cpp rename to efiXloader/efi_loader.cc diff --git a/efiXloader/pe.cpp b/efiXloader/pe.cc similarity index 100% rename from efiXloader/pe.cpp rename to efiXloader/pe.cc diff --git a/efiXloader/pe_manager.cpp b/efiXloader/pe_manager.cc similarity index 100% rename from efiXloader/pe_manager.cpp rename to efiXloader/pe_manager.cc diff --git a/efiXloader/uefitool.cpp b/efiXloader/uefitool.cc similarity index 100% rename from efiXloader/uefitool.cpp rename to efiXloader/uefitool.cc diff --git a/efiXloader/utils.cpp b/efiXloader/utils.cc similarity index 100% rename from efiXloader/utils.cpp rename to efiXloader/utils.cc From 5b58877ab36d36e81c0195aaf8b778a9c21386d4 Mon Sep 17 00:00:00 2001 From: yeggor Date: Wed, 11 Sep 2024 09:12:04 +0200 Subject: [PATCH 10/69] rename source files for efixplorer --- .gitignore | 10 +++--- efiXplorer/CMakeLists.txt | 34 +++++++++---------- efiXplorer/efiXplorer.h | 2 +- efiXplorer/{efiAnalyzer.h => efi_analyser.h} | 6 ++-- ...efiAnalyzerArm.cpp => efi_analyser_arm.cc} | 8 ++--- ...efiAnalyzerX86.cpp => efi_analyser_x86.cc} | 10 +++--- efiXplorer/{efi_defs.cpp => efi_defs.cc} | 0 efiXplorer/{efiDeps.cpp => efi_deps.cc} | 2 +- efiXplorer/{efiDeps.h => efi_deps.h} | 2 +- efiXplorer/{efiGlobal.cpp => efi_global.cc} | 2 +- efiXplorer/{efiGlobal.h => efi_global.h} | 2 +- efiXplorer/{efiHexRays.cpp => efi_hexrays.cc} | 2 +- efiXplorer/{efiHexRays.h => efi_hexrays.h} | 2 +- .../{efiSmmUtils.cpp => efi_smm_utils.cc} | 4 +-- efiXplorer/{efiSmmUtils.h => efi_smm_utils.h} | 2 +- efiXplorer/{efiUi.cpp => efi_ui.cc} | 6 ++-- efiXplorer/{efiUi.h => efi_ui.h} | 2 +- efiXplorer/{efiUtils.cpp => efi_utils.cc} | 4 +-- efiXplorer/{efiUtils.h => efi_utils.h} | 0 efiXplorer/{efiXplorer.cpp => efixplorer.cc} | 6 ++-- 20 files changed, 53 insertions(+), 53 deletions(-) rename efiXplorer/{efiAnalyzer.h => efi_analyser.h} (99%) rename efiXplorer/{efiAnalyzerArm.cpp => efi_analyser_arm.cc} (99%) rename efiXplorer/{efiAnalyzerX86.cpp => efi_analyser_x86.cc} (99%) rename efiXplorer/{efi_defs.cpp => efi_defs.cc} (100%) rename efiXplorer/{efiDeps.cpp => efi_deps.cc} (99%) rename efiXplorer/{efiDeps.h => efi_deps.h} (98%) rename efiXplorer/{efiGlobal.cpp => efi_global.cc} (97%) rename efiXplorer/{efiGlobal.h => efi_global.h} (97%) rename efiXplorer/{efiHexRays.cpp => efi_hexrays.cc} (99%) rename efiXplorer/{efiHexRays.h => efi_hexrays.h} (99%) rename efiXplorer/{efiSmmUtils.cpp => efi_smm_utils.cc} (99%) rename efiXplorer/{efiSmmUtils.h => efi_smm_utils.h} (98%) rename efiXplorer/{efiUi.cpp => efi_ui.cc} (99%) rename efiXplorer/{efiUi.h => efi_ui.h} (99%) rename efiXplorer/{efiUtils.cpp => efi_utils.cc} (99%) rename efiXplorer/{efiUtils.h => efi_utils.h} (100%) rename efiXplorer/{efiXplorer.cpp => efixplorer.cc} (98%) diff --git a/.gitignore b/.gitignore index 8414d171..896218e0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,14 +1,14 @@ # Byte-compiled / optimized / DLL files -*$py.class -*.py[cod] __pycache__/ +*.py[cod] +*$py.class # Distribution / packaging -*.egg -*.egg-info/ .eggs/ .installed.cfg .Python +*.egg +*.egg-info/ build/ develop-eggs/ dist/ @@ -44,5 +44,5 @@ venv/ test/ tests -# OSX .DS_Store +*.sh diff --git a/efiXplorer/CMakeLists.txt b/efiXplorer/CMakeLists.txt index 69a94b96..2e6470eb 100644 --- a/efiXplorer/CMakeLists.txt +++ b/efiXplorer/CMakeLists.txt @@ -28,21 +28,21 @@ include_directories(${PROJECT_SOURCE_DIR}/3rd/nlohmann_json) # efiXplorer sources set(efiXplorer_src "efi_defs.h" - "efi_defs.cpp" - "efiAnalyzer.h" - "efiAnalyzerArm.cpp" - "efiAnalyzerX86.cpp" - "efiDeps.cpp" - "efiDeps.h" - "efiGlobal.cpp" - "efiGlobal.h" - "efiSmmUtils.cpp" - "efiSmmUtils.h" - "efiUi.cpp" - "efiUi.h" - "efiUtils.cpp" - "efiUtils.h" - "efixplorer.cpp" + "efi_defs.cc" + "efi_analyser.h" + "efi_analyser_arm.cc" + "efi_analyser_X86.cc" + "efi_deps.cc" + "efi_deps.h" + "efi_global.cc" + "efi_global.h" + "efi_smm_utils.cc" + "efi_smm_utils.h" + "efi_ui.cc" + "efi_ui.h" + "efi_utils.cc" + "efi_utils.h" + "efixplorer.cc" "efixplorer.h" ) @@ -50,10 +50,10 @@ if(HexRaysSdk_ROOT_DIR) add_definitions(-DHEX_RAYS=1) set(HexRaysSdk_INCLUDE_DIRS ${HexRaysSdk_ROOT_DIR}/include) include_directories(${HexRaysSdk_INCLUDE_DIRS}) - list(APPEND efiXplorer_src "efiHexRays.cpp" "efiHexRays.h") + list(APPEND efiXplorer_src "efi_hexrays.cc" "efi_hexrays.h") endif() -add_ida_plugin(efiXplorer ${PROJECT_SOURCE_DIR}/efiXplorer.cpp) +add_ida_plugin(efiXplorer ${PROJECT_SOURCE_DIR}/efixplorer.cc) set_ida_target_properties(efiXplorer PROPERTIES CXX_STANDARD 17) ida_target_include_directories(efiXplorer PRIVATE ${IdaSdk_INCLUDE_DIRS}) diff --git a/efiXplorer/efiXplorer.h b/efiXplorer/efiXplorer.h index fcefda64..f5d066fd 100644 --- a/efiXplorer/efiXplorer.h +++ b/efiXplorer/efiXplorer.h @@ -21,6 +21,6 @@ #pragma once -#include "efiUtils.h" +#include "efi_utils.h" #define COPYRIGHT "(c) 2020-2024, Binarly - https://github.com/binarly-io/efiXplorer" diff --git a/efiXplorer/efiAnalyzer.h b/efiXplorer/efi_analyser.h similarity index 99% rename from efiXplorer/efiAnalyzer.h rename to efiXplorer/efi_analyser.h index 16928fbe..fab54e45 100644 --- a/efiXplorer/efiAnalyzer.h +++ b/efiXplorer/efi_analyser.h @@ -21,12 +21,12 @@ #pragma once -#include "efiSmmUtils.h" -#include "efiUtils.h" #include "efi_defs.h" +#include "efi_smm_utils.h" +#include "efi_utils.h" #ifdef HEX_RAYS -#include "efiHexRays.h" +#include "efi_hexrays.h" #endif namespace efi_analysis { diff --git a/efiXplorer/efiAnalyzerArm.cpp b/efiXplorer/efi_analyser_arm.cc similarity index 99% rename from efiXplorer/efiAnalyzerArm.cpp rename to efiXplorer/efi_analyser_arm.cc index 352c5bd8..e09cdab5 100644 --- a/efiXplorer/efiAnalyzerArm.cpp +++ b/efiXplorer/efi_analyser_arm.cc @@ -20,10 +20,10 @@ * */ -#include "efiAnalyzer.h" -#include "efiGlobal.h" -#include "efiUi.h" -#include "efiUtils.h" +#include "efi_analyser.h" +#include "efi_global.h" +#include "efi_ui.h" +#include "efi_utils.h" using namespace efi_analysis; diff --git a/efiXplorer/efiAnalyzerX86.cpp b/efiXplorer/efi_analyser_x86.cc similarity index 99% rename from efiXplorer/efiAnalyzerX86.cpp rename to efiXplorer/efi_analyser_x86.cc index 4db1b6aa..6a3a48a4 100644 --- a/efiXplorer/efiAnalyzerX86.cpp +++ b/efiXplorer/efi_analyser_x86.cc @@ -20,13 +20,13 @@ * */ -#include "efiAnalyzer.h" -#include "efiGlobal.h" -#include "efiUi.h" -#include "efiUtils.h" +#include "efi_analyser.h" +#include "efi_global.h" +#include "efi_ui.h" +#include "efi_utils.h" #ifdef HEX_RAYS -#include "efiHexRays.h" +#include "efi_hexrays.h" #endif using namespace efi_analysis; diff --git a/efiXplorer/efi_defs.cpp b/efiXplorer/efi_defs.cc similarity index 100% rename from efiXplorer/efi_defs.cpp rename to efiXplorer/efi_defs.cc diff --git a/efiXplorer/efiDeps.cpp b/efiXplorer/efi_deps.cc similarity index 99% rename from efiXplorer/efiDeps.cpp rename to efiXplorer/efi_deps.cc index bf1290d2..e036da2f 100644 --- a/efiXplorer/efiDeps.cpp +++ b/efiXplorer/efi_deps.cc @@ -19,7 +19,7 @@ * */ -#include "efiDeps.h" +#include "efi_deps.h" EfiDependencies::EfiDependencies() { // Read DEPEX (for protocols) from diff --git a/efiXplorer/efiDeps.h b/efiXplorer/efi_deps.h similarity index 98% rename from efiXplorer/efiDeps.h rename to efiXplorer/efi_deps.h index 4d79881c..a947ae0b 100644 --- a/efiXplorer/efiDeps.h +++ b/efiXplorer/efi_deps.h @@ -21,7 +21,7 @@ #pragma once -#include "efiUtils.h" +#include "efi_utils.h" class EfiDependencies { public: diff --git a/efiXplorer/efiGlobal.cpp b/efiXplorer/efi_global.cc similarity index 97% rename from efiXplorer/efiGlobal.cpp rename to efiXplorer/efi_global.cc index 1089359c..97f244f9 100644 --- a/efiXplorer/efiGlobal.cpp +++ b/efiXplorer/efi_global.cc @@ -19,6 +19,6 @@ * */ -#include "efiDeps.h" +#include "efi_deps.h" EfiDependencies g_deps; diff --git a/efiXplorer/efiGlobal.h b/efiXplorer/efi_global.h similarity index 97% rename from efiXplorer/efiGlobal.h rename to efiXplorer/efi_global.h index 788a3e2f..681c6476 100644 --- a/efiXplorer/efiGlobal.h +++ b/efiXplorer/efi_global.h @@ -21,7 +21,7 @@ #pragma once -#include "efiDeps.h" +#include "efi_deps.h" typedef struct args { int module_type; diff --git a/efiXplorer/efiHexRays.cpp b/efiXplorer/efi_hexrays.cc similarity index 99% rename from efiXplorer/efiHexRays.cpp rename to efiXplorer/efi_hexrays.cc index 4d4444d5..ce7099d2 100644 --- a/efiXplorer/efiHexRays.cpp +++ b/efiXplorer/efi_hexrays.cc @@ -19,7 +19,7 @@ * */ -#include "efiHexRays.h" +#include "efi_hexrays.h" // Given a tinfo_t specifying a user-defined type (UDT), look up the specified // field by its name, and retrieve its offset. diff --git a/efiXplorer/efiHexRays.h b/efiXplorer/efi_hexrays.h similarity index 99% rename from efiXplorer/efiHexRays.h rename to efiXplorer/efi_hexrays.h index ff6e176d..202c5326 100644 --- a/efiXplorer/efiHexRays.h +++ b/efiXplorer/efi_hexrays.h @@ -21,7 +21,7 @@ #pragma once -#include "efiUtils.h" +#include "efi_utils.h" uint8_t VariablesInfoExtractAll(func_t *f, ea_t code_addr); bool TrackEntryParams(func_t *f, uint8_t depth); diff --git a/efiXplorer/efiSmmUtils.cpp b/efiXplorer/efi_smm_utils.cc similarity index 99% rename from efiXplorer/efiSmmUtils.cpp rename to efiXplorer/efi_smm_utils.cc index f673f066..5f9badc5 100644 --- a/efiXplorer/efiSmmUtils.cpp +++ b/efiXplorer/efi_smm_utils.cc @@ -19,8 +19,8 @@ * */ -#include "efiSmmUtils.h" -#include "efiGlobal.h" +#include "efi_smm_utils.h" +#include "efi_global.h" //-------------------------------------------------------------------------- // Find and mark gSmst global variable via EFI_SMM_SW_DISPATCH(2)_PROTOCOL_GUID diff --git a/efiXplorer/efiSmmUtils.h b/efiXplorer/efi_smm_utils.h similarity index 98% rename from efiXplorer/efiSmmUtils.h rename to efiXplorer/efi_smm_utils.h index 57aeff95..9cc7efd9 100644 --- a/efiXplorer/efiSmmUtils.h +++ b/efiXplorer/efi_smm_utils.h @@ -21,7 +21,7 @@ #pragma once -#include "efiUtils.h" +#include "efi_utils.h" std::vector findSmstSwDispatch(std::vector gBsList); std::vector findSmstSmmBase(std::vector gBsList); diff --git a/efiXplorer/efiUi.cpp b/efiXplorer/efi_ui.cc similarity index 99% rename from efiXplorer/efiUi.cpp rename to efiXplorer/efi_ui.cc index 729605a4..35be266b 100644 --- a/efiXplorer/efiUi.cpp +++ b/efiXplorer/efi_ui.cc @@ -19,9 +19,9 @@ * */ -#include "efiUi.h" -#include "efiDeps.h" -#include "efiGlobal.h" +#include "efi_ui.h" +#include "efi_deps.h" +#include "efi_global.h" // vulns column widths const int vulns_chooser_t::widths_vulns[] = { diff --git a/efiXplorer/efiUi.h b/efiXplorer/efi_ui.h similarity index 99% rename from efiXplorer/efiUi.h rename to efiXplorer/efi_ui.h index 193133f3..3cd379a1 100644 --- a/efiXplorer/efiUi.h +++ b/efiXplorer/efi_ui.h @@ -21,7 +21,7 @@ #pragma once -#include "efiUtils.h" +#include "efi_utils.h" //------------------------------------------------------------------------- // Vulns chooser diff --git a/efiXplorer/efiUtils.cpp b/efiXplorer/efi_utils.cc similarity index 99% rename from efiXplorer/efiUtils.cpp rename to efiXplorer/efi_utils.cc index 165c0edf..25350603 100644 --- a/efiXplorer/efiUtils.cpp +++ b/efiXplorer/efi_utils.cc @@ -19,9 +19,9 @@ * */ -#include "efiUtils.h" -#include "efiGlobal.h" +#include "efi_utils.h" #include "efi_defs.h" +#include "efi_global.h" // can be used after Hex-Rays based analysis std::vector g_get_smst_location_calls; diff --git a/efiXplorer/efiUtils.h b/efiXplorer/efi_utils.h similarity index 100% rename from efiXplorer/efiUtils.h rename to efiXplorer/efi_utils.h diff --git a/efiXplorer/efiXplorer.cpp b/efiXplorer/efixplorer.cc similarity index 98% rename from efiXplorer/efiXplorer.cpp rename to efiXplorer/efixplorer.cc index 846b2db9..2aed71b0 100644 --- a/efiXplorer/efiXplorer.cpp +++ b/efiXplorer/efixplorer.cc @@ -20,9 +20,9 @@ */ #include "efixplorer.h" -#include "efiAnalyzer.h" -#include "efiGlobal.h" -#include "efiUi.h" +#include "efi_analyser.h" +#include "efi_global.h" +#include "efi_ui.h" static const char plugin_hotkey[] = "Ctrl+Alt+E"; static const char plugin_comment[] = From ad7a6624a6bfb6b21b656a50778123d1a2fa8894 Mon Sep 17 00:00:00 2001 From: yeggor Date: Wed, 11 Sep 2024 09:15:52 +0200 Subject: [PATCH 11/69] remove efixplorer.h --- efiXplorer/CMakeLists.txt | 4 +--- efiXplorer/efiXplorer.h | 26 -------------------------- efiXplorer/efi_defs.h | 2 ++ efiXplorer/efixplorer.cc | 1 - 4 files changed, 3 insertions(+), 30 deletions(-) delete mode 100644 efiXplorer/efiXplorer.h diff --git a/efiXplorer/CMakeLists.txt b/efiXplorer/CMakeLists.txt index 2e6470eb..32ddf7b2 100644 --- a/efiXplorer/CMakeLists.txt +++ b/efiXplorer/CMakeLists.txt @@ -42,9 +42,7 @@ set(efiXplorer_src "efi_ui.h" "efi_utils.cc" "efi_utils.h" - "efixplorer.cc" - "efixplorer.h" -) + "efixplorer.cc") if(HexRaysSdk_ROOT_DIR) add_definitions(-DHEX_RAYS=1) diff --git a/efiXplorer/efiXplorer.h b/efiXplorer/efiXplorer.h deleted file mode 100644 index f5d066fd..00000000 --- a/efiXplorer/efiXplorer.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * efiXplorer - * Copyright (C) 2020-2024 Binarly - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * efiXplorer.h - * - */ - -#pragma once - -#include "efi_utils.h" - -#define COPYRIGHT "(c) 2020-2024, Binarly - https://github.com/binarly-io/efiXplorer" diff --git a/efiXplorer/efi_defs.h b/efiXplorer/efi_defs.h index 2aff33df..d7b832cb 100644 --- a/efiXplorer/efi_defs.h +++ b/efiXplorer/efi_defs.h @@ -22,6 +22,8 @@ #include #include +#define COPYRIGHT "(C) 2020-2024 Binarly - https://github.com/binarly-io/efiXplorer" + #define BTOA(x) ((x) ? "true" : "false") #define VZ 0x5A56 diff --git a/efiXplorer/efixplorer.cc b/efiXplorer/efixplorer.cc index 2aed71b0..03c6ec54 100644 --- a/efiXplorer/efixplorer.cc +++ b/efiXplorer/efixplorer.cc @@ -19,7 +19,6 @@ * */ -#include "efixplorer.h" #include "efi_analyser.h" #include "efi_global.h" #include "efi_ui.h" From 7d4d88469f77bf9493985b6ca770a9d11ec30312 Mon Sep 17 00:00:00 2001 From: yeggor Date: Fri, 13 Sep 2024 23:58:34 +0200 Subject: [PATCH 12/69] update efi_defs --- efiXplorer/efi_defs.h | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/efiXplorer/efi_defs.h b/efiXplorer/efi_defs.h index d7b832cb..1a1eef4f 100644 --- a/efiXplorer/efi_defs.h +++ b/efiXplorer/efi_defs.h @@ -29,17 +29,18 @@ #define VZ 0x5A56 #define MZ 0x5A4D -enum ModuleType { DXE_SMM = 0, PEI = 1 }; +#define BS_OFFSET_64 0x60 +#define BS_OFFSET_32 0x3c +#define RT_OFFSET_64 0x58 +#define RT_OFFSET_32 0x38 -enum MachineType { AMD64 = 0x8664, I386 = 0x014C, AARCH64 = 0xaa64 }; - -enum ArchFileType { UNSUPPORTED_TYPE, X86, X64, UEFI, ARM64 }; +enum class ModuleType { DxeSmm = 0, Pei = 1 }; -enum FfsFileType { FTYPE_PEI = 6, FTYPE_DXE_AND_THE_LIKE = 7 }; +enum class ArchFileType { Unsupported, X8632, X8664, Uefi, Aarch64 }; -enum BootServicesOffset { BS_OFFSET_64BIT = 0x60, BS_OFFSET_32BIT = 0x3c }; +enum class FfsFileType { Unsupported = 0, Pei = 6, DxeAndTheLike = 7 }; -enum RuntimeServiesOffset { RT_OFFSET_64BIT = 0x58, RT_OFFSET_32BIT = 0x38 }; +enum MachineType { AMD64 = 0x8664, I386 = 0x014C, AARCH64 = 0xaa64 }; enum RegsAmd32 { REG_EAX, From 699d02127297909691ade3fb473a46b865c5a017 Mon Sep 17 00:00:00 2001 From: yeggor Date: Fri, 13 Sep 2024 23:59:43 +0200 Subject: [PATCH 13/69] corresponding changes in rest of the files --- efiXplorer/efi_analyser.h | 5 +- efiXplorer/efi_analyser_arm.cc | 16 ++--- efiXplorer/efi_analyser_x86.cc | 59 +++++++++--------- efiXplorer/efi_global.h | 2 +- efiXplorer/efi_utils.cc | 109 +++++++++++++++++---------------- efiXplorer/efi_utils.h | 8 +-- efiXplorer/efixplorer.cc | 21 +++---- 7 files changed, 108 insertions(+), 112 deletions(-) diff --git a/efiXplorer/efi_analyser.h b/efiXplorer/efi_analyser.h index fab54e45..a36053f3 100644 --- a/efiXplorer/efi_analyser.h +++ b/efiXplorer/efi_analyser.h @@ -41,7 +41,9 @@ class EfiAnalyzer { std::vector allPPIs; std::vector allServices; std::vector smiHandlers; - uint8_t arch; + + ArchFileType arch = ArchFileType::Unsupported; + FfsFileType file_type = FfsFileType::Unsupported; void getSegments(); void setStrings(); @@ -62,7 +64,6 @@ class EfiAnalyzer { ea_t callAddress); void dumpInfo(); - uint8_t fileType = 0; json dbProtocols; ea_t base; ea_t startAddress = 0; diff --git a/efiXplorer/efi_analyser_arm.cc b/efiXplorer/efi_analyser_arm.cc index e09cdab5..7a691e1e 100644 --- a/efiXplorer/efi_analyser_arm.cc +++ b/efiXplorer/efi_analyser_arm.cc @@ -66,7 +66,7 @@ void efi_analysis::EfiAnalyzerArm::initialAnalysis() { TrackEntryParams(get_func(ep), 0); #endif /* HEX_RAYS */ } - if (fileType == FTYPE_PEI) { + if (file_type == FfsFileType::Pei) { // setEntryArgToPeiSvc(); } } @@ -464,21 +464,21 @@ bool efi_analysis::efiAnalyzerMainArm() { analyzer.markDataGuids(); if (g_args.disable_ui) { - analyzer.fileType = g_args.module_type == PEI - ? analyzer.fileType = FTYPE_PEI - : analyzer.fileType = FTYPE_DXE_AND_THE_LIKE; + analyzer.file_type = g_args.module_type == ModuleType::Pei + ? analyzer.file_type = FfsFileType::Pei + : analyzer.file_type = FfsFileType::DxeAndTheLike; } else { - analyzer.fileType = getFileType(&analyzer.allGuids); + analyzer.file_type = ask_file_type(&analyzer.allGuids); } - if (analyzer.fileType == FTYPE_PEI) { + if (analyzer.file_type == FfsFileType::Pei) { msg("[efiXplorer] input file is PEI module\n"); } // set the correct name for the entry point and automatically fix the prototype analyzer.initialAnalysis(); - if (analyzer.fileType == FTYPE_DXE_AND_THE_LIKE) { + if (analyzer.file_type == FfsFileType::DxeAndTheLike) { analyzer.initialGlobalVarsDetection(); // detect services @@ -486,7 +486,7 @@ bool efi_analysis::efiAnalyzerMainArm() { // detect protocols analyzer.protocolsDetection(); - } else if (analyzer.fileType == FTYPE_PEI) { + } else if (analyzer.file_type == FfsFileType::Pei) { analyzer.findPeiServicesFunction(); } diff --git a/efiXplorer/efi_analyser_x86.cc b/efiXplorer/efi_analyser_x86.cc index 6a3a48a4..551a3158 100644 --- a/efiXplorer/efi_analyser_x86.cc +++ b/efiXplorer/efi_analyser_x86.cc @@ -63,7 +63,7 @@ std::vector smmGetVariableOverflow; efi_analysis::EfiAnalyzer::EfiAnalyzer() { // 32-bit, 64-bit, ARM or UEFI (in loader instance) - arch = getInputFileType(); + arch = input_file_type(); // get guids.json path guidsJsonPath /= getGuidsJsonFile(); @@ -154,14 +154,12 @@ efi_analysis::EfiAnalyzer::~EfiAnalyzer() { } void efi_analysis::EfiAnalyzer::setStrings() { - - if (fileType == FTYPE_DXE_AND_THE_LIKE) { + if (file_type == FfsFileType::DxeAndTheLike) { if_name = " Protocol name "; if_pl = "protocols"; if_key = "prot_name"; if_tbl = &allProtocols; - - } else if (fileType == FTYPE_PEI) { + } else if (file_type == FfsFileType::Pei) { if_name = " PPI name "; if_pl = "PPIs"; if_key = "ppi_name"; @@ -413,11 +411,11 @@ bool efi_analysis::EfiAnalyzerX86::findSmstPostProcX64() { bool efi_analysis::EfiAnalyzerX86::findBootServicesTables() { // init architecture-specific constants - auto BS_OFFSET = BS_OFFSET_64BIT; + auto BS_OFFSET = BS_OFFSET_64; uint16_t REG_SP = static_cast(REG_RSP); - if (arch == X86) { - BS_OFFSET = BS_OFFSET_32BIT; + if (arch == ArchFileType::X8632) { + BS_OFFSET = BS_OFFSET_32; REG_SP = static_cast(REG_ESP); } @@ -527,11 +525,11 @@ bool efi_analysis::EfiAnalyzerX86::findBootServicesTables() { bool efi_analysis::EfiAnalyzerX86::findRuntimeServicesTables() { // init architecture-specific constants - auto RT_OFFSET = RT_OFFSET_64BIT; + auto RT_OFFSET = RT_OFFSET_64; uint16_t REG_SP = static_cast(REG_RSP); - if (arch == X86) { - RT_OFFSET = RT_OFFSET_32BIT; + if (arch == ArchFileType::X8632) { + RT_OFFSET = RT_OFFSET_32; REG_SP = static_cast(REG_ESP); } @@ -684,7 +682,7 @@ void efi_analysis::EfiAnalyzerX86::getAllBootServices() { // architecture-specific variables auto offset = bootServicesTableAll[j].offset64; - if (arch == X86) { + if (arch == ArchFileType::X8632) { offset = bootServicesTableAll[j].offset32; } @@ -784,7 +782,7 @@ void efi_analysis::EfiAnalyzerX86::getAllRuntimeServices() { // architecture-specific variables auto offset = runtimeServicesTableAll[j].offset64; - if (arch == X86) { + if (arch == ArchFileType::X8632) { offset = runtimeServicesTableAll[j].offset32; } if (service_offset == u32_addr(offset)) { @@ -1289,7 +1287,8 @@ void efi_analysis::EfiAnalyzerX86::findOtherBsTablesX64() { bool efi_analysis::EfiAnalyzer::AddProtocol(std::string serviceName, ea_t guidAddress, ea_t xrefAddress, ea_t callAddress) { - if (arch != UEFI && guidAddress >= startAddress && guidAddress <= endAddress) { + if (arch != ArchFileType::Uefi && guidAddress >= startAddress && + guidAddress <= endAddress) { msg("[%s] wrong service call detection: 0x%016llX\n", g_plugin_name, u64_addr(callAddress)); return false; // filter FP @@ -1304,7 +1303,7 @@ bool efi_analysis::EfiAnalyzer::AddProtocol(std::string serviceName, ea_t guidAd protocol["ea"] = callAddress; qstring moduleName("Current"); - if (getInputFileType() == UEFI) { + if (input_file_type() == ArchFileType::Uefi) { moduleName = getModuleNameLoader(callAddress); } protocol["module"] = static_cast(moduleName.c_str()); @@ -2577,13 +2576,13 @@ void showAllChoosers(efi_analysis::EfiAnalyzerX86 analyzer) { } // open window with protocols - if (analyzer.fileType == FTYPE_PEI) { + if (analyzer.file_type == FfsFileType::Pei) { if (analyzer.allPPIs.size()) { title = "efiXplorer: PPIs"; ppis_show(analyzer.allPPIs, title); } - } else { // FTYPE_DXE_AND_THE_LIKE + } else { // FfsFileType::DxeAndTheLike if (analyzer.allProtocols.size()) { title = "efiXplorer: protocols"; protocols_show(analyzer.allProtocols, title); @@ -2640,7 +2639,7 @@ bool efi_analysis::efiAnalyzerMainX64() { // analyze all auto res = ASKBTN_NO; - if (analyzer.arch == UEFI) { + if (analyzer.arch == ArchFileType::Uefi) { res = ask_yn(1, "Want to further analyze all drivers with auto_mark_range?"); } if (res == ASKBTN_YES && textSegments.size() && dataSegments.size()) { @@ -2657,17 +2656,17 @@ bool efi_analysis::efiAnalyzerMainX64() { analyzer.markLocalGuidsX64(); if (g_args.disable_ui) { - analyzer.fileType = g_args.module_type == PEI - ? analyzer.fileType = FTYPE_PEI - : analyzer.fileType = FTYPE_DXE_AND_THE_LIKE; + analyzer.file_type = g_args.module_type == ModuleType::Pei + ? analyzer.file_type = FfsFileType::Pei + : analyzer.file_type = FfsFileType::DxeAndTheLike; } else { - analyzer.fileType = getFileType(&analyzer.allGuids); + analyzer.file_type = ask_file_type(&analyzer.allGuids); } analyzer.setStrings(); // find global vars for gImageHandle, gST, gBS, gRT, gSmst - if (analyzer.fileType == FTYPE_DXE_AND_THE_LIKE) { + if (analyzer.file_type == FfsFileType::DxeAndTheLike) { analyzer.findImageHandleX64(); analyzer.findSystemTableX64(); analyzer.findBootServicesTables(); @@ -2733,7 +2732,7 @@ bool efi_analysis::efiAnalyzerMainX64() { showAllChoosers(analyzer); } - if (analyzer.arch == UEFI) { + if (analyzer.arch == ArchFileType::Uefi) { // Init public EdiDependencies members g_deps.getProtocolsChooser(analyzer.allProtocols); g_deps.getProtocolsByGuids(analyzer.allProtocols); @@ -2767,16 +2766,16 @@ bool efi_analysis::efiAnalyzerMainX86() { analyzer.markDataGuids(); if (g_args.disable_ui) { - analyzer.fileType = g_args.module_type == PEI - ? analyzer.fileType = FTYPE_PEI - : analyzer.fileType = FTYPE_DXE_AND_THE_LIKE; + analyzer.file_type = g_args.module_type == ModuleType::Pei + ? analyzer.file_type = FfsFileType::Pei + : analyzer.file_type = FfsFileType::DxeAndTheLike; } else { - analyzer.fileType = getFileType(&analyzer.allGuids); + analyzer.file_type = ask_file_type(&analyzer.allGuids); } analyzer.setStrings(); - if (analyzer.fileType == FTYPE_DXE_AND_THE_LIKE) { + if (analyzer.file_type == FfsFileType::DxeAndTheLike) { // find global vars for gST, gBS, gRT analyzer.findBootServicesTables(); @@ -2796,7 +2795,7 @@ bool efi_analysis::efiAnalyzerMainX86() { applyAllTypesForInterfacesSmmServices(analyzer.allProtocols); #endif - } else if (analyzer.fileType == FTYPE_PEI) { + } else if (analyzer.file_type == FfsFileType::Pei) { setEntryArgToPeiSvc(); addStrucForShiftedPtr(); #ifdef HEX_RAYS diff --git a/efiXplorer/efi_global.h b/efiXplorer/efi_global.h index 681c6476..89b44a0a 100644 --- a/efiXplorer/efi_global.h +++ b/efiXplorer/efi_global.h @@ -24,7 +24,7 @@ #include "efi_deps.h" typedef struct args { - int module_type; + ModuleType module_type; int disable_ui; int disable_vuln_hunt; } args_t; diff --git a/efiXplorer/efi_utils.cc b/efiXplorer/efi_utils.cc index 25350603..58ca8867 100644 --- a/efiXplorer/efi_utils.cc +++ b/efiXplorer/efi_utils.cc @@ -58,98 +58,99 @@ void setConstChar16Type(ea_t ea) { } //-------------------------------------------------------------------------- -// Get file format name (fileformatname) -std::string getFileFormatName() { +// get file format name (fileformatname) +std::string file_format_name() { char file_format[256] = {0}; get_file_type_name(file_format, 256); return static_cast(file_format); } //-------------------------------------------------------------------------- -// Get input file type (64-bit, 32-bit image or UEFI firmware) -uint8_t getInputFileType() { +// get input file type (64-bit, 32-bit module or UEFI firmware) +ArchFileType input_file_type() { processor_t &ph = PH; auto filetype = inf_get_filetype(); auto bits = inf_is_64bit() ? 64 : inf_is_32bit_exactly() ? 32 : 16; - // check if input file is UEFI firmware image - if (getFileFormatName().find("UEFI") != std::string::npos) { - return UEFI; + // check if the input file is a UEFI firmware image + if (file_format_name().find("UEFI") != std::string::npos) { + return ArchFileType::Uefi; } if (filetype == f_PE || filetype == f_ELF) { if (ph.id == PLFM_386) { - if (bits == 64) // x86 64-bit executable - return X64; - if (bits == 32) // x86 32-bit executable - return X86; + if (bits == 64) + return ArchFileType::X8664; + if (bits == 32) + return ArchFileType::X8632; } if (ph.id == PLFM_ARM) { - if (bits == 64) // ARM 64-bit executable - return ARM64; + if (bits == 64) + return ArchFileType::Aarch64; } } - return UNSUPPORTED_TYPE; + return ArchFileType::Unsupported; } //-------------------------------------------------------------------------- -// Get input file type (PEI or DXE-like). No reliable way to determine FFS +// get input file type (PEI or DXE-like). No reliable way to determine FFS // file type given only its PE/TE image section, so hello heuristics -uint8_t guessFileType(uint8_t arch, std::vector *allGuids) { - if (arch == UEFI) { - return FTYPE_DXE_AND_THE_LIKE; +FfsFileType guess_file_type(ArchFileType arch, std::vector *all_guids) { + if (arch == ArchFileType::Uefi) { + return FfsFileType::DxeAndTheLike; } + segment_t *hdr_seg = get_segm_by_name("HEADER"); - if (hdr_seg == NULL) { - return FTYPE_DXE_AND_THE_LIKE; + if (hdr_seg == nullptr) { + return FfsFileType::DxeAndTheLike; } + uint64_t signature = get_wide_word(hdr_seg->start_ea); - bool hasPeiGuids = false; - for (auto guid = allGuids->begin(); guid != allGuids->end(); guid++) { - json guidVal = *guid; + bool has_pei_guids = false; + for (auto guid = all_guids->begin(); guid != all_guids->end(); guid++) { + json guid_value = *guid; - if (static_cast(guidVal["name"]).find("PEI") != std::string::npos || - static_cast(guidVal["name"]).find("Pei") != std::string::npos) { - hasPeiGuids = true; + if (static_cast(guid_value["name"]).find("PEI") != std::string::npos) { + has_pei_guids = true; break; } } - bool hasPeiInPath = false; - char fileName[0x1000] = {0}; - get_input_file_path(fileName, sizeof(fileName)); - auto fileNameStr = static_cast(fileName); - if ((fileNameStr.find("Pei") != std::string::npos || - fileNameStr.find("pei") != std::string::npos || signature == VZ) && - arch == X86) { - hasPeiInPath = true; + bool has_pei_in_path = false; + char file_name[0x1000] = {0}; + get_input_file_path(file_name, sizeof(file_name)); + auto file_name_str = static_cast(file_name); + if ((file_name_str.find("Pei") != std::string::npos || + file_name_str.find("pei") != std::string::npos || signature == VZ) && + arch == ArchFileType::X8664) { + has_pei_in_path = true; } - if (signature == VZ || hasPeiGuids) { - msg("[%s] Parsing binary file as PEI, signature = %llx, hasPeiGuids = %d\n", - g_plugin_name, signature, hasPeiGuids); - return FTYPE_PEI; - } else { - msg("[%s] Parsing binary file as DXE/SMM, signature = %llx, hasPeiGuids = %d\n", - g_plugin_name, signature, hasPeiGuids); - return FTYPE_DXE_AND_THE_LIKE; + if (signature == VZ || has_pei_guids) { + msg("[%s] parsing binary file as PEI, signature = %llx, has_pei_guids = %d\n", + g_plugin_name, signature, has_pei_guids); + return FfsFileType::Pei; } + + msg("[%s] parsing binary file as DXE/SMM, signature = %llx, has_pei_guids = %d\n", + g_plugin_name, signature, has_pei_guids); + return FfsFileType::DxeAndTheLike; } -uint8_t getFileType(std::vector *allGuids) { - uint8_t arch = getInputFileType(); - if (arch == UEFI || arch == X64) { - return FTYPE_DXE_AND_THE_LIKE; +FfsFileType ask_file_type(std::vector *all_guids) { + auto arch = input_file_type(); + if (arch == ArchFileType::Uefi || arch == ArchFileType::X8664) { + return FfsFileType::DxeAndTheLike; } - auto ftype = guessFileType(arch, allGuids); - auto deflt = ftype == FTYPE_DXE_AND_THE_LIKE; - auto fmt_param = ftype == FTYPE_DXE_AND_THE_LIKE ? "DXE/SMM" : "PEI"; - auto btnId = ask_buttons("DXE/SMM", "PEI", "", deflt, "Parse file as %s", fmt_param); - if (btnId == ASKBTN_YES) { - return FTYPE_DXE_AND_THE_LIKE; - } else { - return FTYPE_PEI; + auto ftype = guess_file_type(arch, all_guids); + auto deflt = ftype == FfsFileType::DxeAndTheLike; + auto fmt_param = ftype == FfsFileType::DxeAndTheLike ? "DXE/SMM" : "PEI"; + auto btn_id = ask_buttons("DXE/SMM", "PEI", "", deflt, "Parse file as %s", fmt_param); + if (btn_id == ASKBTN_YES) { + return FfsFileType::DxeAndTheLike; } + + return FfsFileType::Pei; } //-------------------------------------------------------------------------- diff --git a/efiXplorer/efi_utils.h b/efiXplorer/efi_utils.h index 1ed06c5c..21ea40cf 100644 --- a/efiXplorer/efi_utils.h +++ b/efiXplorer/efi_utils.h @@ -86,12 +86,8 @@ struct EfiGuid { } }; -// Get input file type -// (64-bit, 32-bit image or UEFI firmware) -uint8_t getInputFileType(); - -// Get image type (PEI or DXE-like) -uint8_t getFileType(std::vector *allGuids); +ArchFileType input_file_type(); +FfsFileType ask_file_type(std::vector *all_guids); // Set EFI_GUID type void setGuidType(ea_t ea); diff --git a/efiXplorer/efixplorer.cc b/efiXplorer/efixplorer.cc index 03c6ec54..d73d1f51 100644 --- a/efiXplorer/efixplorer.cc +++ b/efiXplorer/efixplorer.cc @@ -35,8 +35,7 @@ static const char welcome_msg[] = " ____ _ __ __\n" " /_/\n"; // Default arguments -struct args g_args = {/* module_type */ DXE_SMM, /* disable_ui */ 0, - /* disable_vuln_hunt */ 0}; +struct args g_args = {ModuleType::DxeSmm, 0, 0}; #if IDA_SDK_VERSION < 760 hexdsp_t *hexdsp = nullptr; @@ -44,8 +43,8 @@ hexdsp_t *hexdsp = nullptr; //-------------------------------------------------------------------------- static plugmod_t *idaapi init(void) { - uint8_t file_type = getInputFileType(); - if (file_type == UNSUPPORTED_TYPE) { + ArchFileType file_type = input_file_type(); + if (file_type == ArchFileType::Unsupported) { return PLUGIN_SKIP; } @@ -71,7 +70,7 @@ bool idaapi run(size_t arg) { // * arg = 5 (101): disable_vuln_hunt (PEI, 32-bit binaries only) // * arg = 6 (110): disable_ui & disable_vuln_hunt (DXE) // * arg = 7 (111): disable_ui & disable_vuln_hunt (PEI, 32-bit binaries only) - g_args.module_type = PEI; + g_args.module_type = ModuleType::Pei; } if (arg >> 1 & 1) { @@ -97,14 +96,14 @@ bool idaapi run(size_t arg) { return false; } - uint8_t arch = getInputFileType(); - if (arch == X64) { + ArchFileType arch = input_file_type(); + if (arch == ArchFileType::X8664) { msg("[%s] input file is 64-bit module (x86)\n", g_plugin_name); efi_analysis::efiAnalyzerMainX64(); - } else if (arch == X86) { + } else if (arch == ArchFileType::X8632) { msg("[%s] input file is 32-bit module (x86)\n", g_plugin_name); efi_analysis::efiAnalyzerMainX86(); - } else if (arch == UEFI) { + } else if (arch == ArchFileType::Uefi) { msg("[%s] input file is UEFI firmware\n", g_plugin_name); warning("%s: analysis may take some time, please wait for it to complete\n", g_plugin_name); @@ -115,13 +114,13 @@ bool idaapi run(size_t arg) { msg("[%s] analyze AMD64 modules\n", g_plugin_name); efi_analysis::efiAnalyzerMainX64(); } - } else if (arch == ARM64) { + } else if (arch == ArchFileType::Aarch64) { msg("[%s] input file is 64-bit module (ARM)\n", g_plugin_name); efi_analysis::efiAnalyzerMainArm(); } // Reset arguments - g_args = {DXE_SMM, 0, 0}; + g_args = {ModuleType::DxeSmm, 0, 0}; return true; } From 301eb64be88f99b8acbe20f3ebd3cedeae9d21af Mon Sep 17 00:00:00 2001 From: yeggor Date: Sat, 14 Sep 2024 00:11:27 +0200 Subject: [PATCH 14/69] use consistent spelling --- efiXplorer/efi_analyser.h | 18 ++- efiXplorer/efi_analyser_arm.cc | 71 +++++----- efiXplorer/efi_analyser_x86.cc | 229 ++++++++++++++++----------------- efiXplorer/efi_deps.cc | 2 - efiXplorer/efi_deps.h | 2 - efiXplorer/efi_global.cc | 2 - efiXplorer/efi_global.h | 2 - efiXplorer/efi_hexrays.cc | 2 - efiXplorer/efi_hexrays.h | 2 - efiXplorer/efi_smm_utils.cc | 2 - efiXplorer/efi_smm_utils.h | 2 - efiXplorer/efi_ui.cc | 2 - efiXplorer/efi_ui.h | 2 - efiXplorer/efi_utils.cc | 2 - efiXplorer/efi_utils.h | 4 +- efiXplorer/efixplorer.cc | 20 ++- 16 files changed, 166 insertions(+), 198 deletions(-) diff --git a/efiXplorer/efi_analyser.h b/efiXplorer/efi_analyser.h index a36053f3..694fff60 100644 --- a/efiXplorer/efi_analyser.h +++ b/efiXplorer/efi_analyser.h @@ -15,8 +15,6 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * - * efiAnalyzer.h - * */ #pragma once @@ -31,10 +29,10 @@ namespace efi_analysis { -class EfiAnalyzer { +class EfiAnalyser { public: - EfiAnalyzer(); - ~EfiAnalyzer(); + EfiAnalyser(); + ~EfiAnalyser(); std::vector allGuids; std::vector allProtocols; @@ -232,9 +230,9 @@ class EfiAnalyzer { "NotifyPpi"}; }; -class EfiAnalyzerX86 : public EfiAnalyzer { +class EfiAnalyserX86 : public EfiAnalyser { public: - EfiAnalyzerX86() : EfiAnalyzer() { + EfiAnalyserX86() : EfiAnalyser() { // import necessary types const til_t *idati = get_idati(); import_type(idati, -1, "EFI_GUID"); @@ -282,9 +280,9 @@ class EfiAnalyzerX86 : public EfiAnalyzer { bool InstallMultipleProtocolInterfacesHandler(); }; -class EfiAnalyzerArm : public EfiAnalyzer { +class EfiAnalyserArm : public EfiAnalyser { public: - EfiAnalyzerArm() : EfiAnalyzer() { + EfiAnalyserArm() : EfiAnalyser() { // in order to make it work, it is necessary to copy // uefi.til, uefi64.til files in {idadir}/til/arm/ add_til("uefi64.til", ADDTIL_DEFAULT); @@ -334,4 +332,4 @@ bool efiAnalyzerMainX86(); bool efiAnalyzerMainArm(); }; // namespace efi_analysis -void showAllChoosers(efi_analysis::EfiAnalyzer analyzer); +void showAllChoosers(efi_analysis::EfiAnalyser analyser); diff --git a/efiXplorer/efi_analyser_arm.cc b/efiXplorer/efi_analyser_arm.cc index 7a691e1e..18f83ff1 100644 --- a/efiXplorer/efi_analyser_arm.cc +++ b/efiXplorer/efi_analyser_arm.cc @@ -15,9 +15,6 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * - * efiAnalyzerArm.cpp - * contains ARM specific analysis routines - * */ #include "efi_analyser.h" @@ -32,7 +29,7 @@ std::vector gStListArm; std::vector gBsListArm; std::vector gRtListArm; -void efi_analysis::EfiAnalyzerArm::fixOffsets() { +void efi_analysis::EfiAnalyserArm::fixOffsets() { insn_t insn; for (auto func_addr : funcs) { func_t *f = get_func(func_addr); @@ -56,7 +53,7 @@ void efi_analysis::EfiAnalyzerArm::fixOffsets() { } } -void efi_analysis::EfiAnalyzerArm::initialAnalysis() { +void efi_analysis::EfiAnalyserArm::initialAnalysis() { fixOffsets(); for (auto idx = 0; idx < get_entry_qty(); idx++) { uval_t ord = get_entry_ordinal(idx); @@ -226,7 +223,7 @@ json getService(ea_t addr, uint8_t table_id) { return s; } -void efi_analysis::EfiAnalyzerArm::initialGlobalVarsDetection() { +void efi_analysis::EfiAnalyserArm::initialGlobalVarsDetection() { #ifdef HEX_RAYS // analyze entry point with Hex-Rays for (auto func_addr : funcs) { @@ -293,7 +290,7 @@ void efi_analysis::EfiAnalyzerArm::initialGlobalVarsDetection() { } } -void efi_analysis::EfiAnalyzerArm::servicesDetection() { +void efi_analysis::EfiAnalyserArm::servicesDetection() { #ifdef HEX_RAYS for (auto func_addr : funcs) { @@ -343,7 +340,7 @@ void efi_analysis::EfiAnalyzerArm::servicesDetection() { } } -bool efi_analysis::EfiAnalyzerArm::getProtocol(ea_t address, uint32_t p_reg, +bool efi_analysis::EfiAnalyserArm::getProtocol(ea_t address, uint32_t p_reg, std::string service_name) { ea_t ea = address; insn_t insn; @@ -381,7 +378,7 @@ bool efi_analysis::EfiAnalyzerArm::getProtocol(ea_t address, uint32_t p_reg, return AddProtocol(service_name, guid_addr, code_addr, address); } -void efi_analysis::EfiAnalyzerArm::protocolsDetection() { +void efi_analysis::EfiAnalyserArm::protocolsDetection() { for (auto s : allServices) { std::string service_name = s["service_name"]; for (auto i = 0; i < 13; i++) { @@ -395,7 +392,7 @@ void efi_analysis::EfiAnalyzerArm::protocolsDetection() { } } -void efi_analysis::EfiAnalyzerArm::findPeiServicesFunction() { +void efi_analysis::EfiAnalyserArm::findPeiServicesFunction() { insn_t insn; for (auto start_ea : funcs) { decode_insn(&insn, start_ea); @@ -423,25 +420,25 @@ void efi_analysis::EfiAnalyzerArm::findPeiServicesFunction() { //-------------------------------------------------------------------------- // Show all non-empty choosers windows -void showAllChoosers(efi_analysis::EfiAnalyzerArm analyzer) { +void showAllChoosers(efi_analysis::EfiAnalyserArm analyser) { qstring title; // open window with all services - if (analyzer.allServices.size()) { + if (analyser.allServices.size()) { title = "efiXplorer: services"; - services_show(analyzer.allServices, title); + services_show(analyser.allServices, title); } // open window with data guids - if (analyzer.allGuids.size()) { + if (analyser.allGuids.size()) { qstring title = "efiXplorer: GUIDs"; - guids_show(analyzer.allGuids, title); + guids_show(analyser.allGuids, title); } // open window with protocols - if (analyzer.allProtocols.size()) { + if (analyser.allProtocols.size()) { title = "efiXplorer: protocols"; - protocols_show(analyzer.allProtocols, title); + protocols_show(analyser.allProtocols, title); } } @@ -451,57 +448,57 @@ bool efi_analysis::efiAnalyzerMainArm() { show_wait_box("HIDECANCEL\nAnalyzing module(s) with efiXplorer..."); - efi_analysis::EfiAnalyzerArm analyzer; + efi_analysis::EfiAnalyserArm analyser; while (!auto_is_ok()) { auto_wait(); }; // find .text and .data segments - analyzer.getSegments(); + analyser.getSegments(); // mark GUIDs - analyzer.markDataGuids(); + analyser.markDataGuids(); if (g_args.disable_ui) { - analyzer.file_type = g_args.module_type == ModuleType::Pei - ? analyzer.file_type = FfsFileType::Pei - : analyzer.file_type = FfsFileType::DxeAndTheLike; + analyser.file_type = g_args.module_type == ModuleType::Pei + ? analyser.file_type = FfsFileType::Pei + : analyser.file_type = FfsFileType::DxeAndTheLike; } else { - analyzer.file_type = ask_file_type(&analyzer.allGuids); + analyser.file_type = ask_file_type(&analyser.allGuids); } - if (analyzer.file_type == FfsFileType::Pei) { + if (analyser.file_type == FfsFileType::Pei) { msg("[efiXplorer] input file is PEI module\n"); } // set the correct name for the entry point and automatically fix the prototype - analyzer.initialAnalysis(); + analyser.initialAnalysis(); - if (analyzer.file_type == FfsFileType::DxeAndTheLike) { - analyzer.initialGlobalVarsDetection(); + if (analyser.file_type == FfsFileType::DxeAndTheLike) { + analyser.initialGlobalVarsDetection(); // detect services - analyzer.servicesDetection(); + analyser.servicesDetection(); // detect protocols - analyzer.protocolsDetection(); - } else if (analyzer.file_type == FfsFileType::Pei) { - analyzer.findPeiServicesFunction(); + analyser.protocolsDetection(); + } else if (analyser.file_type == FfsFileType::Pei) { + analyser.findPeiServicesFunction(); } #ifdef HEX_RAYS - for (auto addr : analyzer.funcs) { + for (auto addr : analyser.funcs) { std::vector services = DetectPeiServicesArm(get_func(addr)); for (auto service : services) { - analyzer.allServices.push_back(service); + analyser.allServices.push_back(service); } } - applyAllTypesForInterfacesBootServices(analyzer.allProtocols); + applyAllTypesForInterfacesBootServices(analyser.allProtocols); #endif /* HEX_RAYS */ - showAllChoosers(analyzer); + showAllChoosers(analyser); - analyzer.dumpInfo(); + analyser.dumpInfo(); hide_wait_box(); diff --git a/efiXplorer/efi_analyser_x86.cc b/efiXplorer/efi_analyser_x86.cc index 551a3158..849245a7 100644 --- a/efiXplorer/efi_analyser_x86.cc +++ b/efiXplorer/efi_analyser_x86.cc @@ -15,9 +15,6 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * - * efiAnalyzerX86.cpp - * contains X86 specific analysis routines - * */ #include "efi_analyser.h" @@ -61,7 +58,7 @@ std::vector peiGetVariableOverflow; std::vector getVariableOverflow; std::vector smmGetVariableOverflow; -efi_analysis::EfiAnalyzer::EfiAnalyzer() { +efi_analysis::EfiAnalyser::EfiAnalyser() { // 32-bit, 64-bit, ARM or UEFI (in loader instance) arch = input_file_type(); @@ -118,7 +115,7 @@ efi_analysis::EfiAnalyzer::EfiAnalyzer() { } } -efi_analysis::EfiAnalyzer::~EfiAnalyzer() { +efi_analysis::EfiAnalyser::~EfiAnalyser() { funcs.clear(); gStList.clear(); @@ -153,7 +150,7 @@ efi_analysis::EfiAnalyzer::~EfiAnalyzer() { #endif } -void efi_analysis::EfiAnalyzer::setStrings() { +void efi_analysis::EfiAnalyser::setStrings() { if (file_type == FfsFileType::DxeAndTheLike) { if_name = " Protocol name "; if_pl = "protocols"; @@ -169,7 +166,7 @@ void efi_analysis::EfiAnalyzer::setStrings() { //-------------------------------------------------------------------------- // Get all .text and .data segments -void efi_analysis::EfiAnalyzer::getSegments() { +void efi_analysis::EfiAnalyser::getSegments() { for (segment_t *s = get_first_seg(); s != NULL; s = get_next_seg(s->start_ea)) { qstring seg_name; get_segm_name(&seg_name, s); @@ -210,7 +207,7 @@ void efi_analysis::EfiAnalyzer::getSegments() { //-------------------------------------------------------------------------- // Find gImageHandle address for X64 modules -bool efi_analysis::EfiAnalyzerX86::findImageHandleX64() { +bool efi_analysis::EfiAnalyserX86::findImageHandleX64() { msg("[%s] gImageHandle finding\n", g_plugin_name); insn_t insn; for (int idx = 0; idx < get_entry_qty(); idx++) { @@ -241,7 +238,7 @@ bool efi_analysis::EfiAnalyzerX86::findImageHandleX64() { //-------------------------------------------------------------------------- // Find gST address for X64 modules -bool efi_analysis::EfiAnalyzerX86::findSystemTableX64() { +bool efi_analysis::EfiAnalyserX86::findSystemTableX64() { msg("[%s] gEfiSystemTable finding\n", g_plugin_name); insn_t insn; for (int idx = 0; idx < get_entry_qty(); idx++) { @@ -268,7 +265,7 @@ bool efi_analysis::EfiAnalyzerX86::findSystemTableX64() { //-------------------------------------------------------------------------- // Find and mark gSmst global variable address for X64 module -bool efi_analysis::EfiAnalyzerX86::findSmstX64() { +bool efi_analysis::EfiAnalyserX86::findSmstX64() { msg("[%s] gSmst finding\n", g_plugin_name); std::vector gSmstListSmmBase = findSmstSmmBase(gBsList); std::vector gSmstListSwDispatch = findSmstSwDispatch(gBsList); @@ -289,7 +286,7 @@ bool efi_analysis::EfiAnalyzerX86::findSmstX64() { //-------------------------------------------------------------------------- // Find and mark gSmst global and local variable address for X64 module // after Hex-Rays based analysis -bool efi_analysis::EfiAnalyzerX86::findSmstPostProcX64() { +bool efi_analysis::EfiAnalyserX86::findSmstPostProcX64() { for (auto ea : g_get_smst_location_calls) { msg("[%s] EfiSmmBase2Protocol->GetSmstLocation call: 0x%016llX\n", g_plugin_name, u64_addr(ea)); @@ -408,7 +405,7 @@ bool efi_analysis::EfiAnalyzerX86::findSmstPostProcX64() { //-------------------------------------------------------------------------- // Find gBS addresses for 32-bit/64-bit modules -bool efi_analysis::EfiAnalyzerX86::findBootServicesTables() { +bool efi_analysis::EfiAnalyserX86::findBootServicesTables() { // init architecture-specific constants auto BS_OFFSET = BS_OFFSET_64; @@ -522,7 +519,7 @@ bool efi_analysis::EfiAnalyzerX86::findBootServicesTables() { //-------------------------------------------------------------------------- // Find gRT addresses for X86/X64 modules -bool efi_analysis::EfiAnalyzerX86::findRuntimeServicesTables() { +bool efi_analysis::EfiAnalyserX86::findRuntimeServicesTables() { // init architecture-specific constants auto RT_OFFSET = RT_OFFSET_64; @@ -635,7 +632,7 @@ bool efi_analysis::EfiAnalyzerX86::findRuntimeServicesTables() { //-------------------------------------------------------------------------- // Get all boot services by xrefs for X86/X64 modules -void efi_analysis::EfiAnalyzerX86::getAllBootServices() { +void efi_analysis::EfiAnalyserX86::getAllBootServices() { msg("[%s] BootServices finding (xrefs)\n", g_plugin_name); if (!gBsList.size()) { @@ -736,7 +733,7 @@ void efi_analysis::EfiAnalyzerX86::getAllBootServices() { //-------------------------------------------------------------------------- // Get all runtime services for X86/X64 modules by xrefs -void efi_analysis::EfiAnalyzerX86::getAllRuntimeServices() { +void efi_analysis::EfiAnalyserX86::getAllRuntimeServices() { msg("[%s] RuntimeServices finding (xrefs)\n", g_plugin_name); if (!gRtList.size()) { @@ -821,7 +818,7 @@ void efi_analysis::EfiAnalyzerX86::getAllRuntimeServices() { //-------------------------------------------------------------------------- // Get all smm services for X64 modules -void efi_analysis::EfiAnalyzerX86::getAllSmmServicesX64() { +void efi_analysis::EfiAnalyserX86::getAllSmmServicesX64() { msg("[%s] SmmServices finding (xrefs)\n", g_plugin_name); if (!gSmstList.size()) { @@ -913,7 +910,7 @@ void efi_analysis::EfiAnalyzerX86::getAllSmmServicesX64() { // Currently should cover all PeiServices except EFI_PEI_COPY_MEM, // EFI_PEI_SET_MEM, EFI_PEI_RESET2_SYSTEM, and "Future Installed Services" // (EFI_PEI_FFS_FIND_BY_NAME, etc.) -void efi_analysis::EfiAnalyzerX86::getAllPeiServicesX86() { +void efi_analysis::EfiAnalyserX86::getAllPeiServicesX86() { msg("[%s] PeiServices finding from 0x%016llX to 0x%016llX (all)\n", g_plugin_name, u64_addr(startAddress), u64_addr(endAddress)); ea_t ea = startAddress; @@ -993,7 +990,7 @@ void efi_analysis::EfiAnalyzerX86::getAllPeiServicesX86() { //-------------------------------------------------------------------------- // Get all EFI_PEI_READ_ONLY_VARIABLE2_PPI (GetVariable, NextVariableName) -void efi_analysis::EfiAnalyzerX86::getAllVariablePPICallsX86() { +void efi_analysis::EfiAnalyserX86::getAllVariablePPICallsX86() { msg("[%s] Variable PPI calls finding from 0x%016llX to 0x%016llX (all)\n", g_plugin_name, u64_addr(startAddress), u64_addr(endAddress)); ea_t ea = startAddress; @@ -1055,7 +1052,7 @@ void efi_analysis::EfiAnalyzerX86::getAllVariablePPICallsX86() { //-------------------------------------------------------------------------- // Get PPI names for X86 PEI modules -void efi_analysis::EfiAnalyzerX86::getPpiNamesX86() { +void efi_analysis::EfiAnalyserX86::getPpiNamesX86() { msg("[%s] PPI finding (PEI services)\n", g_plugin_name); ea_t start = startAddress; segment_t *seg_info = get_segm_by_name(".text"); @@ -1157,7 +1154,7 @@ void efi_analysis::EfiAnalyzerX86::getPpiNamesX86() { //-------------------------------------------------------------------------- // Get boot services by protocols for X64 modules -void efi_analysis::EfiAnalyzerX86::getProtBootServicesX64() { +void efi_analysis::EfiAnalyserX86::getProtBootServicesX64() { insn_t insn; for (auto s : textSegments) { msg("[%s] BootServices finding from 0x%016llX to 0x%016llX (protocols)\n", @@ -1218,7 +1215,7 @@ void efi_analysis::EfiAnalyzerX86::getProtBootServicesX64() { //-------------------------------------------------------------------------- // Get boot services by protocols for X86 modules -void efi_analysis::EfiAnalyzerX86::getProtBootServicesX86() { +void efi_analysis::EfiAnalyserX86::getProtBootServicesX86() { msg("[%s] BootServices finding from 0x%016llX to 0x%016llX (protocols)\n", g_plugin_name, u64_addr(startAddress), u64_addr(endAddress)); ea_t ea = startAddress; @@ -1260,7 +1257,7 @@ void efi_analysis::EfiAnalyzerX86::getProtBootServicesX86() { //-------------------------------------------------------------------------- // find other addresses of global gBS vars for X64 modules -void efi_analysis::EfiAnalyzerX86::findOtherBsTablesX64() { +void efi_analysis::EfiAnalyserX86::findOtherBsTablesX64() { msg("[%s] Finding of other addresses of global gBS variables\n", g_plugin_name); for (auto s : allServices) { std::string table_name = s["table_name"]; @@ -1284,7 +1281,7 @@ void efi_analysis::EfiAnalyzerX86::findOtherBsTablesX64() { } } -bool efi_analysis::EfiAnalyzer::AddProtocol(std::string serviceName, ea_t guidAddress, +bool efi_analysis::EfiAnalyser::AddProtocol(std::string serviceName, ea_t guidAddress, ea_t xrefAddress, ea_t callAddress) { if (arch != ArchFileType::Uefi && guidAddress >= startAddress && @@ -1325,7 +1322,7 @@ bool efi_analysis::EfiAnalyzer::AddProtocol(std::string serviceName, ea_t guidAd //-------------------------------------------------------------------------- // Extract protocols from InstallMultipleProtocolInterfaces service call -bool efi_analysis::EfiAnalyzerX86::InstallMultipleProtocolInterfacesHandler() { +bool efi_analysis::EfiAnalyserX86::InstallMultipleProtocolInterfacesHandler() { std::vector addrs = bootServices["InstallMultipleProtocolInterfaces"]; std::map stack_params; insn_t insn; @@ -1409,7 +1406,7 @@ bool efi_analysis::EfiAnalyzerX86::InstallMultipleProtocolInterfacesHandler() { //-------------------------------------------------------------------------- // Get boot services protocols names for X64 modules -void efi_analysis::EfiAnalyzerX86::getBsProtNamesX64() { +void efi_analysis::EfiAnalyserX86::getBsProtNamesX64() { if (!textSegments.size()) { return; } @@ -1486,7 +1483,7 @@ void efi_analysis::EfiAnalyzerX86::getBsProtNamesX64() { //-------------------------------------------------------------------------- // Get boot services protocols names for X86 modules -void efi_analysis::EfiAnalyzerX86::getBsProtNamesX86() { +void efi_analysis::EfiAnalyserX86::getBsProtNamesX86() { msg("[%s] protocols finding (boot services)\n", g_plugin_name); ea_t start = startAddress; segment_t *seg_info = get_segm_by_name(".text"); @@ -1558,7 +1555,7 @@ void efi_analysis::EfiAnalyzerX86::getBsProtNamesX86() { //-------------------------------------------------------------------------- // Get smm services protocols names for X64 modules -void efi_analysis::EfiAnalyzerX86::getSmmProtNamesX64() { +void efi_analysis::EfiAnalyserX86::getSmmProtNamesX64() { if (!textSegments.size()) { return; } @@ -1619,7 +1616,7 @@ void efi_analysis::EfiAnalyzerX86::getSmmProtNamesX64() { //-------------------------------------------------------------------------- // Mark protocols -void efi_analysis::EfiAnalyzer::markInterfaces() { +void efi_analysis::EfiAnalyser::markInterfaces() { msg("[%s] %s marking\n", g_plugin_name, if_pl.c_str()); for (auto ifItemIt = if_tbl->begin(); ifItemIt != if_tbl->end(); ++ifItemIt) { json ifItem = *ifItemIt; @@ -1649,7 +1646,7 @@ void efi_analysis::EfiAnalyzer::markInterfaces() { //-------------------------------------------------------------------------- // Mark GUIDs found in the .text and .data segment -void efi_analysis::EfiAnalyzer::markDataGuids() { +void efi_analysis::EfiAnalyser::markDataGuids() { ea_t ptrSize = inf_is_64bit() ? 8 : 4; auto guids_segments = textSegments; // find GUIDs in .text and .data segments @@ -1715,7 +1712,7 @@ void efi_analysis::EfiAnalyzer::markDataGuids() { //-------------------------------------------------------------------------- // Mark GUIDs found in local variables for X64 modules -void efi_analysis::EfiAnalyzerX86::markLocalGuidsX64() { +void efi_analysis::EfiAnalyserX86::markLocalGuidsX64() { for (auto seg : textSegments) { segment_t *s = seg; ea_t ea = s->start_ea; @@ -1890,7 +1887,7 @@ void findCalloutRec(func_t *func) { //-------------------------------------------------------------------------- // Find SmiHandler function inside SMM drivers -void efi_analysis::EfiAnalyzer::findSwSmiHandlers() { +void efi_analysis::EfiAnalyser::findSwSmiHandlers() { std::map types = { {&sw_guid2, "Sw"}, {&sw_guid, "Sw"}, @@ -1939,7 +1936,7 @@ void efi_analysis::EfiAnalyzer::findSwSmiHandlers() { // Find callouts inside SwSmiHandler function: // * find SwSmiHandler function // * find gBS->service_name and gRT->service_name inside SmiHandler function -bool efi_analysis::EfiAnalyzer::findSmmCallout() { +bool efi_analysis::EfiAnalyser::findSmmCallout() { msg("[%s] Looking for SMM callout\n", g_plugin_name); if (!gBsList.size() && !gRtList.size()) { return false; @@ -1957,7 +1954,7 @@ bool efi_analysis::EfiAnalyzer::findSmmCallout() { return true; } -bool efi_analysis::EfiAnalyzer::findPPIGetVariableStackOveflow() { +bool efi_analysis::EfiAnalyser::findPPIGetVariableStackOveflow() { msg("[%s] Looking for PPI GetVariable buffer overflow, " "allServices.size() = %lu\n", g_plugin_name, allServices.size()); @@ -2125,7 +2122,7 @@ bool efi_analysis::EfiAnalyzer::findPPIGetVariableStackOveflow() { //-------------------------------------------------------------------------- // Find potential stack/heap overflow with double GetVariable calls -bool efi_analysis::EfiAnalyzer::findGetVariableOveflow(std::vector allServices) { +bool efi_analysis::EfiAnalyser::findGetVariableOveflow(std::vector allServices) { msg("[%s] Looking for GetVariable stack/heap overflow\n", g_plugin_name); std::vector getVariableServicesCalls; std::string getVariableStr("GetVariable"); @@ -2259,7 +2256,7 @@ bool efi_analysis::EfiAnalyzer::findGetVariableOveflow(std::vector allServ //-------------------------------------------------------------------------- // Find potential stack/heap overflow with double SmmGetVariable calls -bool efi_analysis::EfiAnalyzer::findSmmGetVariableOveflow() { +bool efi_analysis::EfiAnalyser::findSmmGetVariableOveflow() { msg("[%s] Looking for SmmGetVariable stack/heap overflow\n", g_plugin_name); std::vector smmGetVariableCalls = findSmmGetVariableCalls(dataSegments, &allServices); @@ -2340,7 +2337,7 @@ bool efi_analysis::EfiAnalyzer::findSmmGetVariableOveflow() { return (smmGetVariableOverflow.size() > 0); } -bool efi_analysis::EfiAnalyzer::AnalyzeVariableService(ea_t ea, std::string service_str) { +bool efi_analysis::EfiAnalyser::AnalyzeVariableService(ea_t ea, std::string service_str) { msg("[%s] %s call: 0x%016llX\n", g_plugin_name, service_str.c_str(), u64_addr(ea)); json item; item["addr"] = ea; @@ -2459,7 +2456,7 @@ bool efi_analysis::EfiAnalyzer::AnalyzeVariableService(ea_t ea, std::string serv return true; } -bool efi_analysis::EfiAnalyzer::analyzeNvramVariables() { +bool efi_analysis::EfiAnalyser::analyzeNvramVariables() { msg("[%s] Get NVRAM variables information\n", g_plugin_name); std::vector nvram_services = {"GetVariable", "SetVariable"}; for (auto service_str : nvram_services) { @@ -2490,14 +2487,14 @@ bool efi_analysis::EfiAnalyzer::analyzeNvramVariables() { //-------------------------------------------------------------------------- // Resolve EFI_SMM_CPU_PROTOCOL -bool efi_analysis::EfiAnalyzer::efiSmmCpuProtocolResolver() { +bool efi_analysis::EfiAnalyser::efiSmmCpuProtocolResolver() { readSaveStateCalls = resolveEfiSmmCpuProtocol(stackGuids, dataGuids, &allServices); return true; } //-------------------------------------------------------------------------- // Dump all info to JSON file -void efi_analysis::EfiAnalyzer::dumpInfo() { +void efi_analysis::EfiAnalyser::dumpInfo() { json info; if (gStList.size()) { info["gStList"] = gStList; @@ -2566,39 +2563,39 @@ void efi_analysis::EfiAnalyzer::dumpInfo() { //-------------------------------------------------------------------------- // Show all non-empty choosers windows -void showAllChoosers(efi_analysis::EfiAnalyzerX86 analyzer) { +void showAllChoosers(efi_analysis::EfiAnalyserX86 analyser) { qstring title; // open window with all services - if (analyzer.allServices.size()) { + if (analyser.allServices.size()) { title = "efiXplorer: services"; - services_show(analyzer.allServices, title); + services_show(analyser.allServices, title); } // open window with protocols - if (analyzer.file_type == FfsFileType::Pei) { - if (analyzer.allPPIs.size()) { + if (analyser.file_type == FfsFileType::Pei) { + if (analyser.allPPIs.size()) { title = "efiXplorer: PPIs"; - ppis_show(analyzer.allPPIs, title); + ppis_show(analyser.allPPIs, title); } } else { // FfsFileType::DxeAndTheLike - if (analyzer.allProtocols.size()) { + if (analyser.allProtocols.size()) { title = "efiXplorer: protocols"; - protocols_show(analyzer.allProtocols, title); + protocols_show(analyser.allProtocols, title); } } // open window with data guids - if (analyzer.allGuids.size()) { + if (analyser.allGuids.size()) { qstring title = "efiXplorer: GUIDs"; - guids_show(analyzer.allGuids, title); + guids_show(analyser.allGuids, title); } // open window with NVRAM variables - if (analyzer.nvramVariables.size()) { + if (analyser.nvramVariables.size()) { qstring title = "efiXplorer: NVRAM"; - nvram_show(analyzer.nvramVariables, title); + nvram_show(analyser.nvramVariables, title); } // open window with vulnerabilities @@ -2628,18 +2625,18 @@ void showAllChoosers(efi_analysis::EfiAnalyzerX86 analyzer) { bool efi_analysis::efiAnalyzerMainX64() { show_wait_box("HIDECANCEL\nAnalyzing module(s) with efiXplorer..."); - efi_analysis::EfiAnalyzerX86 analyzer; + efi_analysis::EfiAnalyserX86 analyser; while (!auto_is_ok()) { auto_wait(); }; // find .text and .data segments - analyzer.getSegments(); + analyser.getSegments(); // analyze all auto res = ASKBTN_NO; - if (analyzer.arch == ArchFileType::Uefi) { + if (analyser.arch == ArchFileType::Uefi) { res = ask_yn(1, "Want to further analyze all drivers with auto_mark_range?"); } if (res == ASKBTN_YES && textSegments.size() && dataSegments.size()) { @@ -2652,47 +2649,47 @@ bool efi_analysis::efiAnalyzerMainX64() { } // mark GUIDs - analyzer.markDataGuids(); - analyzer.markLocalGuidsX64(); + analyser.markDataGuids(); + analyser.markLocalGuidsX64(); if (g_args.disable_ui) { - analyzer.file_type = g_args.module_type == ModuleType::Pei - ? analyzer.file_type = FfsFileType::Pei - : analyzer.file_type = FfsFileType::DxeAndTheLike; + analyser.file_type = g_args.module_type == ModuleType::Pei + ? analyser.file_type = FfsFileType::Pei + : analyser.file_type = FfsFileType::DxeAndTheLike; } else { - analyzer.file_type = ask_file_type(&analyzer.allGuids); + analyser.file_type = ask_file_type(&analyser.allGuids); } - analyzer.setStrings(); + analyser.setStrings(); // find global vars for gImageHandle, gST, gBS, gRT, gSmst - if (analyzer.file_type == FfsFileType::DxeAndTheLike) { - analyzer.findImageHandleX64(); - analyzer.findSystemTableX64(); - analyzer.findBootServicesTables(); - analyzer.findRuntimeServicesTables(); + if (analyser.file_type == FfsFileType::DxeAndTheLike) { + analyser.findImageHandleX64(); + analyser.findSystemTableX64(); + analyser.findBootServicesTables(); + analyser.findRuntimeServicesTables(); - analyzer.findSmstX64(); + analyser.findSmstX64(); // find Boot services and Runtime services - analyzer.getProtBootServicesX64(); - analyzer.findOtherBsTablesX64(); - analyzer.getAllBootServices(); - analyzer.getAllRuntimeServices(); + analyser.getProtBootServicesX64(); + analyser.findOtherBsTablesX64(); + analyser.getAllBootServices(); + analyser.getAllRuntimeServices(); - analyzer.getBsProtNamesX64(); + analyser.getBsProtNamesX64(); #ifdef HEX_RAYS - applyAllTypesForInterfacesBootServices(analyzer.allProtocols); - analyzer.findSmstPostProcX64(); + applyAllTypesForInterfacesBootServices(analyser.allProtocols); + analyser.findSmstPostProcX64(); #endif // find SMM services - analyzer.getAllSmmServicesX64(); - analyzer.getSmmProtNamesX64(); + analyser.getAllSmmServicesX64(); + analyser.getSmmProtNamesX64(); // mark protocols - analyzer.markInterfaces(); + analyser.markInterfaces(); // search for copies of global variables markCopiesForGlobalVars(gSmstList, "gSmst"); @@ -2703,39 +2700,39 @@ bool efi_analysis::efiAnalyzerMainX64() { if (!g_args.disable_vuln_hunt) { // find potential SMM callouts - analyzer.findSwSmiHandlers(); - analyzer.findSmmCallout(); + analyser.findSwSmiHandlers(); + analyser.findSmmCallout(); // find potential OOB RW with GetVariable function - analyzer.findGetVariableOveflow(analyzer.allServices); + analyser.findGetVariableOveflow(analyser.allServices); // find potential OOB RW with SmmGetVariable function - analyzer.findSmmGetVariableOveflow(); - analyzer.efiSmmCpuProtocolResolver(); + analyser.findSmmGetVariableOveflow(); + analyser.efiSmmCpuProtocolResolver(); } #ifdef HEX_RAYS - applyAllTypesForInterfacesSmmServices(analyzer.allProtocols); + applyAllTypesForInterfacesSmmServices(analyser.allProtocols); #endif - analyzer.analyzeNvramVariables(); + analyser.analyzeNvramVariables(); } else { msg("[%s] Parsing of 64-bit PEI files is not supported yet\n", g_plugin_name); } // dump info to JSON file - analyzer.dumpInfo(); + analyser.dumpInfo(); // show all choosers windows if (!g_args.disable_ui) { - showAllChoosers(analyzer); + showAllChoosers(analyser); } - if (analyzer.arch == ArchFileType::Uefi) { + if (analyser.arch == ArchFileType::Uefi) { // Init public EdiDependencies members - g_deps.getProtocolsChooser(analyzer.allProtocols); - g_deps.getProtocolsByGuids(analyzer.allProtocols); + g_deps.getProtocolsChooser(analyser.allProtocols); + g_deps.getProtocolsByGuids(analyser.allProtocols); // Save all protocols information to build dependencies attachActionProtocolsDeps(); @@ -2753,73 +2750,73 @@ bool efi_analysis::efiAnalyzerMainX86() { show_wait_box("HIDECANCEL\nAnalyzing module(s) with efiXplorer..."); - efi_analysis::EfiAnalyzerX86 analyzer; + efi_analysis::EfiAnalyserX86 analyser; while (!auto_is_ok()) { auto_wait(); }; // find .text and .data segments - analyzer.getSegments(); + analyser.getSegments(); // mark GUIDs - analyzer.markDataGuids(); + analyser.markDataGuids(); if (g_args.disable_ui) { - analyzer.file_type = g_args.module_type == ModuleType::Pei - ? analyzer.file_type = FfsFileType::Pei - : analyzer.file_type = FfsFileType::DxeAndTheLike; + analyser.file_type = g_args.module_type == ModuleType::Pei + ? analyser.file_type = FfsFileType::Pei + : analyser.file_type = FfsFileType::DxeAndTheLike; } else { - analyzer.file_type = ask_file_type(&analyzer.allGuids); + analyser.file_type = ask_file_type(&analyser.allGuids); } - analyzer.setStrings(); + analyser.setStrings(); - if (analyzer.file_type == FfsFileType::DxeAndTheLike) { + if (analyser.file_type == FfsFileType::DxeAndTheLike) { // find global vars for gST, gBS, gRT - analyzer.findBootServicesTables(); - analyzer.findRuntimeServicesTables(); + analyser.findBootServicesTables(); + analyser.findRuntimeServicesTables(); // find boot services and runtime services - analyzer.getAllRuntimeServices(); - analyzer.getProtBootServicesX86(); - analyzer.getAllBootServices(); + analyser.getAllRuntimeServices(); + analyser.getProtBootServicesX86(); + analyser.getAllBootServices(); // print and mark protocols - analyzer.getBsProtNamesX86(); - analyzer.markInterfaces(); + analyser.getBsProtNamesX86(); + analyser.markInterfaces(); #ifdef HEX_RAYS - applyAllTypesForInterfacesBootServices(analyzer.allProtocols); - applyAllTypesForInterfacesSmmServices(analyzer.allProtocols); + applyAllTypesForInterfacesBootServices(analyser.allProtocols); + applyAllTypesForInterfacesSmmServices(analyser.allProtocols); #endif - } else if (analyzer.file_type == FfsFileType::Pei) { + } else if (analyser.file_type == FfsFileType::Pei) { setEntryArgToPeiSvc(); addStrucForShiftedPtr(); #ifdef HEX_RAYS - for (auto addr : analyzer.funcs) { + for (auto addr : analyser.funcs) { DetectPeiServices(get_func(addr)); } #endif - analyzer.getAllPeiServicesX86(); - analyzer.getPpiNamesX86(); - analyzer.getAllVariablePPICallsX86(); - analyzer.markInterfaces(); + analyser.getAllPeiServicesX86(); + analyser.getPpiNamesX86(); + analyser.getAllVariablePPICallsX86(); + analyser.markInterfaces(); // search for vulnerabilities if (!g_args.disable_vuln_hunt) { - analyzer.findPPIGetVariableStackOveflow(); + analyser.findPPIGetVariableStackOveflow(); } } // dump info to JSON file - analyzer.dumpInfo(); + analyser.dumpInfo(); // show all choosers windows if (!g_args.disable_ui) { - showAllChoosers(analyzer); + showAllChoosers(analyser); } hide_wait_box(); diff --git a/efiXplorer/efi_deps.cc b/efiXplorer/efi_deps.cc index e036da2f..d5d23495 100644 --- a/efiXplorer/efi_deps.cc +++ b/efiXplorer/efi_deps.cc @@ -15,8 +15,6 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * - * efiDeps.cpp - * */ #include "efi_deps.h" diff --git a/efiXplorer/efi_deps.h b/efiXplorer/efi_deps.h index a947ae0b..1ea6a2a9 100644 --- a/efiXplorer/efi_deps.h +++ b/efiXplorer/efi_deps.h @@ -15,8 +15,6 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * - * efiDeps.h - * */ #pragma once diff --git a/efiXplorer/efi_global.cc b/efiXplorer/efi_global.cc index 97f244f9..13772a69 100644 --- a/efiXplorer/efi_global.cc +++ b/efiXplorer/efi_global.cc @@ -15,8 +15,6 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * - * efiGlobal.cpp - * */ #include "efi_deps.h" diff --git a/efiXplorer/efi_global.h b/efiXplorer/efi_global.h index 89b44a0a..44489a0c 100644 --- a/efiXplorer/efi_global.h +++ b/efiXplorer/efi_global.h @@ -15,8 +15,6 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * - * efiGlobal.h - * */ #pragma once diff --git a/efiXplorer/efi_hexrays.cc b/efiXplorer/efi_hexrays.cc index ce7099d2..60681cd3 100644 --- a/efiXplorer/efi_hexrays.cc +++ b/efiXplorer/efi_hexrays.cc @@ -15,8 +15,6 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * - * efiHexRays.cpp - * */ #include "efi_hexrays.h" diff --git a/efiXplorer/efi_hexrays.h b/efiXplorer/efi_hexrays.h index 202c5326..678ec447 100644 --- a/efiXplorer/efi_hexrays.h +++ b/efiXplorer/efi_hexrays.h @@ -15,8 +15,6 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * - * efiHexRays.h - * */ #pragma once diff --git a/efiXplorer/efi_smm_utils.cc b/efiXplorer/efi_smm_utils.cc index 5f9badc5..183c053b 100644 --- a/efiXplorer/efi_smm_utils.cc +++ b/efiXplorer/efi_smm_utils.cc @@ -15,8 +15,6 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * - * efiSmmUtils.cpp - * */ #include "efi_smm_utils.h" diff --git a/efiXplorer/efi_smm_utils.h b/efiXplorer/efi_smm_utils.h index 9cc7efd9..067b1298 100644 --- a/efiXplorer/efi_smm_utils.h +++ b/efiXplorer/efi_smm_utils.h @@ -15,8 +15,6 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * - * efiSmmUtils.h - * */ #pragma once diff --git a/efiXplorer/efi_ui.cc b/efiXplorer/efi_ui.cc index 35be266b..25324b24 100644 --- a/efiXplorer/efi_ui.cc +++ b/efiXplorer/efi_ui.cc @@ -15,8 +15,6 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * - * efiUi.cpp - * */ #include "efi_ui.h" diff --git a/efiXplorer/efi_ui.h b/efiXplorer/efi_ui.h index 3cd379a1..66cea621 100644 --- a/efiXplorer/efi_ui.h +++ b/efiXplorer/efi_ui.h @@ -15,8 +15,6 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * - * efiUi.h - * */ #pragma once diff --git a/efiXplorer/efi_utils.cc b/efiXplorer/efi_utils.cc index 58ca8867..c8fc022c 100644 --- a/efiXplorer/efi_utils.cc +++ b/efiXplorer/efi_utils.cc @@ -15,8 +15,6 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * - * efiUtils.cpp - * */ #include "efi_utils.h" diff --git a/efiXplorer/efi_utils.h b/efiXplorer/efi_utils.h index 21ea40cf..4cf8123a 100644 --- a/efiXplorer/efi_utils.h +++ b/efiXplorer/efi_utils.h @@ -15,8 +15,6 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * - * efiUtils.h - * */ #pragma once @@ -62,6 +60,7 @@ struct EfiGuid { uint16_t data2; uint16_t data3; uint8_t data4[8]; + std::vector uchar_data() { std::vector res; res.push_back(data1 & 0xff); @@ -77,6 +76,7 @@ struct EfiGuid { } return res; } + std::string to_string() { char res[37] = {0}; snprintf(res, 37, "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X", data1, data2, diff --git a/efiXplorer/efixplorer.cc b/efiXplorer/efixplorer.cc index d73d1f51..c93f22d4 100644 --- a/efiXplorer/efixplorer.cc +++ b/efiXplorer/efixplorer.cc @@ -15,8 +15,6 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * - * efiXplorer.cpp - * */ #include "efi_analyser.h" @@ -61,15 +59,15 @@ static plugmod_t *idaapi init(void) { //-------------------------------------------------------------------------- bool idaapi run(size_t arg) { - if (arg >> 0 & 1) { // Parse arg value: - // * arg = 0 (000): default (DXE) - // * arg = 1 (001): default (PEI, 32-bit binaries only) - // * arg = 2 (010): disable_ui (DXE) - // * arg = 3 (011): disable_ui (PEI, 32-bit binaries only) - // * arg = 4 (100): disable_vuln_hunt (DXE) - // * arg = 5 (101): disable_vuln_hunt (PEI, 32-bit binaries only) - // * arg = 6 (110): disable_ui & disable_vuln_hunt (DXE) - // * arg = 7 (111): disable_ui & disable_vuln_hunt (PEI, 32-bit binaries only) + if (arg >> 0 & 1) { // parse arg value: + // - arg = 0 (000): default (DXE) + // - arg = 1 (001): default (PEI, 32-bit binaries only) + // - arg = 2 (010): disable_ui (DXE) + // - arg = 3 (011): disable_ui (PEI, 32-bit binaries only) + // - arg = 4 (100): disable_vuln_hunt (DXE) + // - arg = 5 (101): disable_vuln_hunt (PEI, 32-bit binaries only) + // - arg = 6 (110): disable_ui & disable_vuln_hunt (DXE) + // - arg = 7 (111): disable_ui & disable_vuln_hunt (PEI, 32-bit binaries only) g_args.module_type = ModuleType::Pei; } From 9bbd6916a873f882bab8e12b6d392ad543dfe999 Mon Sep 17 00:00:00 2001 From: yeggor Date: Sat, 14 Sep 2024 00:24:14 +0200 Subject: [PATCH 15/69] fix cmake lists for loader --- efiXloader/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/efiXloader/CMakeLists.txt b/efiXloader/CMakeLists.txt index c4aa633b..c8026415 100644 --- a/efiXloader/CMakeLists.txt +++ b/efiXloader/CMakeLists.txt @@ -57,7 +57,7 @@ file( "3rd/uefitool/uefidump.h") # efiLoader sources -file(GLOB efiloader_src "*.h" "*.c" "*.cpp", "*.cc") +file(GLOB ${efiloader_src} "*.h" "*.c" "*.cpp" "*.cc") add_ida_loader(efiXloader NOEA32 ${PROJECT_SOURCE_DIR}/efi_loader.cc) From b71f6b6092423f0b2d2a4f1910b1c78ef19540d0 Mon Sep 17 00:00:00 2001 From: yeggor Date: Sat, 14 Sep 2024 00:24:44 +0200 Subject: [PATCH 16/69] use consistent spelling in loader and plugin --- efiXloader/efi_loader.cc | 4 ++-- efiXloader/efi_loader.h | 2 +- efiXplorer/efi_analyser.h | 10 +++++----- efiXplorer/efi_analyser_arm.cc | 8 ++++---- efiXplorer/efi_analyser_x86.cc | 24 ++++++++++++------------ efiXplorer/efi_deps.h | 2 +- efiXplorer/efi_smm_utils.cc | 4 ++-- efiXplorer/efixplorer.cc | 14 +++++++------- 8 files changed, 34 insertions(+), 34 deletions(-) diff --git a/efiXloader/efi_loader.cc b/efiXloader/efi_loader.cc index 3abb3bf4..09bfe1e9 100644 --- a/efiXloader/efi_loader.cc +++ b/efiXloader/efi_loader.cc @@ -64,10 +64,10 @@ void idaapi wait(void) { } //------------------------ -// IDA analyzing +// IDA analysing //------------------------ -void inline idaapi reanalyze_all(void) { +void inline idaapi reanalyse_all(void) { plan_range(inf_get_min_ea(), inf_get_max_ea()); auto_wait(); auto_make_proc(inf_get_min_ea()); diff --git a/efiXloader/efi_loader.h b/efiXloader/efi_loader.h index a202f91d..c09eea0f 100644 --- a/efiXloader/efi_loader.h +++ b/efiXloader/efi_loader.h @@ -34,7 +34,7 @@ extern loader_t LDSC; void idaapi load_binary(const char *fname); void idaapi close_and_save_db(const char *fname); -void idaapi reanalyze_all(void); +void idaapi reanalyse_all(void); void idaapi wait(void); void idaapi idb_to_asm(const char *fname); void idaapi clean_db(void); diff --git a/efiXplorer/efi_analyser.h b/efiXplorer/efi_analyser.h index 694fff60..15386fdb 100644 --- a/efiXplorer/efi_analyser.h +++ b/efiXplorer/efi_analyser.h @@ -56,8 +56,8 @@ class EfiAnalyser { bool findPPIGetVariableStackOveflow(); bool findSmmGetVariableOveflow(); bool findSmmCallout(); - bool analyzeNvramVariables(); - bool AnalyzeVariableService(ea_t ea, std::string service_str); + bool analyseNvramVariables(); + bool AnalyseVariableService(ea_t ea, std::string service_str); bool AddProtocol(std::string serviceName, ea_t guidAddress, ea_t xrefAddress, ea_t callAddress); void dumpInfo(); @@ -327,9 +327,9 @@ class EfiAnalyserArm : public EfiAnalyser { {"UninstallMultipleProtocolInterfaces", 0x150, REG_X1, 1}}; }; -bool efiAnalyzerMainX64(); -bool efiAnalyzerMainX86(); -bool efiAnalyzerMainArm(); +bool efiAnalyserMainX64(); +bool efiAnalyserMainX86(); +bool efiAnalyserMainArm(); }; // namespace efi_analysis void showAllChoosers(efi_analysis::EfiAnalyser analyser); diff --git a/efiXplorer/efi_analyser_arm.cc b/efiXplorer/efi_analyser_arm.cc index 18f83ff1..73295487 100644 --- a/efiXplorer/efi_analyser_arm.cc +++ b/efiXplorer/efi_analyser_arm.cc @@ -225,7 +225,7 @@ json getService(ea_t addr, uint8_t table_id) { void efi_analysis::EfiAnalyserArm::initialGlobalVarsDetection() { #ifdef HEX_RAYS - // analyze entry point with Hex-Rays + // analyse entry point with Hex-Rays for (auto func_addr : funcs) { json res = DetectVars(get_func(func_addr)); if (res.contains("gImageHandleList")) { @@ -301,7 +301,7 @@ void efi_analysis::EfiAnalyserArm::servicesDetection() { } #endif /* HEX_RAYS */ - // analyze xrefs to gBS, gRT + // analyse xrefs to gBS, gRT for (auto bs : gBsListArm) { auto xrefs = getXrefs(bs); for (auto ea : xrefs) { @@ -444,9 +444,9 @@ void showAllChoosers(efi_analysis::EfiAnalyserArm analyser) { //-------------------------------------------------------------------------- // Main function for AARCH64 modules -bool efi_analysis::efiAnalyzerMainArm() { +bool efi_analysis::efiAnalyserMainArm() { - show_wait_box("HIDECANCEL\nAnalyzing module(s) with efiXplorer..."); + show_wait_box("HIDECANCEL\nAnalysing module(s) with efiXplorer..."); efi_analysis::EfiAnalyserArm analyser; diff --git a/efiXplorer/efi_analyser_x86.cc b/efiXplorer/efi_analyser_x86.cc index 849245a7..0c171c13 100644 --- a/efiXplorer/efi_analyser_x86.cc +++ b/efiXplorer/efi_analyser_x86.cc @@ -2337,7 +2337,7 @@ bool efi_analysis::EfiAnalyser::findSmmGetVariableOveflow() { return (smmGetVariableOverflow.size() > 0); } -bool efi_analysis::EfiAnalyser::AnalyzeVariableService(ea_t ea, std::string service_str) { +bool efi_analysis::EfiAnalyser::AnalyseVariableService(ea_t ea, std::string service_str) { msg("[%s] %s call: 0x%016llX\n", g_plugin_name, service_str.c_str(), u64_addr(ea)); json item; item["addr"] = ea; @@ -2456,7 +2456,7 @@ bool efi_analysis::EfiAnalyser::AnalyzeVariableService(ea_t ea, std::string serv return true; } -bool efi_analysis::EfiAnalyser::analyzeNvramVariables() { +bool efi_analysis::EfiAnalyser::analyseNvramVariables() { msg("[%s] Get NVRAM variables information\n", g_plugin_name); std::vector nvram_services = {"GetVariable", "SetVariable"}; for (auto service_str : nvram_services) { @@ -2471,15 +2471,15 @@ bool efi_analysis::EfiAnalyser::analyzeNvramVariables() { } sort(var_services.begin(), var_services.end()); for (auto ea : var_services) { - AnalyzeVariableService(ea, service_str); + AnalyseVariableService(ea, service_str); } for (auto ea : g_smm_get_variable_calls) { - AnalyzeVariableService(ea, "EFI_SMM_VARIABLE_PROTOCOL::SmmGetVariable"); + AnalyseVariableService(ea, "EFI_SMM_VARIABLE_PROTOCOL::SmmGetVariable"); } for (auto ea : g_smm_set_variable_calls) { - AnalyzeVariableService(ea, "EFI_SMM_VARIABLE_PROTOCOL::SmmSetVariable"); + AnalyseVariableService(ea, "EFI_SMM_VARIABLE_PROTOCOL::SmmSetVariable"); } } return true; @@ -2622,8 +2622,8 @@ void showAllChoosers(efi_analysis::EfiAnalyserX86 analyser) { //-------------------------------------------------------------------------- // Main function for X64 modules -bool efi_analysis::efiAnalyzerMainX64() { - show_wait_box("HIDECANCEL\nAnalyzing module(s) with efiXplorer..."); +bool efi_analysis::efiAnalyserMainX64() { + show_wait_box("HIDECANCEL\nAnalysing module(s) with efiXplorer..."); efi_analysis::EfiAnalyserX86 analyser; @@ -2634,10 +2634,10 @@ bool efi_analysis::efiAnalyzerMainX64() { // find .text and .data segments analyser.getSegments(); - // analyze all + // analyse all auto res = ASKBTN_NO; if (analyser.arch == ArchFileType::Uefi) { - res = ask_yn(1, "Want to further analyze all drivers with auto_mark_range?"); + res = ask_yn(1, "Want to further analyse all drivers with auto_mark_range?"); } if (res == ASKBTN_YES && textSegments.size() && dataSegments.size()) { segment_t *start_seg = textSegments.at(0); @@ -2715,7 +2715,7 @@ bool efi_analysis::efiAnalyzerMainX64() { applyAllTypesForInterfacesSmmServices(analyser.allProtocols); #endif - analyser.analyzeNvramVariables(); + analyser.analyseNvramVariables(); } else { msg("[%s] Parsing of 64-bit PEI files is not supported yet\n", g_plugin_name); @@ -2746,9 +2746,9 @@ bool efi_analysis::efiAnalyzerMainX64() { //-------------------------------------------------------------------------- // Main function for X86 modules -bool efi_analysis::efiAnalyzerMainX86() { +bool efi_analysis::efiAnalyserMainX86() { - show_wait_box("HIDECANCEL\nAnalyzing module(s) with efiXplorer..."); + show_wait_box("HIDECANCEL\nAnalysing module(s) with efiXplorer..."); efi_analysis::EfiAnalyserX86 analyser; diff --git a/efiXplorer/efi_deps.h b/efiXplorer/efi_deps.h index 1ea6a2a9..3021b587 100644 --- a/efiXplorer/efi_deps.h +++ b/efiXplorer/efi_deps.h @@ -39,7 +39,7 @@ class EfiDependencies { void getProtocolsChooser(std::vector protocols); json getDeps(std::string protocol); // get dependencies for specific protocol void getAdditionalInstallers(); // get installers by protocol GUIDs by searching in - // the firmware and analyzing xrefs + // the firmware and analysing xrefs bool buildModulesSequence(); bool getImagesInfo(); diff --git a/efiXplorer/efi_smm_utils.cc b/efiXplorer/efi_smm_utils.cc index 183c053b..35ea0b1c 100644 --- a/efiXplorer/efi_smm_utils.cc +++ b/efiXplorer/efi_smm_utils.cc @@ -148,7 +148,7 @@ std::vector findSmstSmmBase(std::vector gBsList) { // Find SmiHandler in reg_smi_func function (prefix: Sw, TrapIo, Sx, Gpi, Usb, // StandbyButton, PeriodicTimer, PowerButton) std::vector findSmiHandlers(ea_t address, std::string prefix) { - msg("[%s] Analyze xref to gEfiSmm%sDispatch(2)Protocol: 0x%016llX\n", g_plugin_name, + msg("[%s] Analyse xref to gEfiSmm%sDispatch(2)Protocol: 0x%016llX\n", g_plugin_name, prefix.c_str(), u64_addr(address)); std::vector smiHandlers; @@ -164,7 +164,7 @@ std::vector findSmiHandlers(ea_t address, std::string prefix) { return smiHandlers; } - // Analyze current basic block + // Analyse current basic block auto ea = address; // Search for SmmLocateProtocol diff --git a/efiXplorer/efixplorer.cc b/efiXplorer/efixplorer.cc index c93f22d4..f707aa05 100644 --- a/efiXplorer/efixplorer.cc +++ b/efiXplorer/efixplorer.cc @@ -97,24 +97,24 @@ bool idaapi run(size_t arg) { ArchFileType arch = input_file_type(); if (arch == ArchFileType::X8664) { msg("[%s] input file is 64-bit module (x86)\n", g_plugin_name); - efi_analysis::efiAnalyzerMainX64(); + efi_analysis::efiAnalyserMainX64(); } else if (arch == ArchFileType::X8632) { msg("[%s] input file is 32-bit module (x86)\n", g_plugin_name); - efi_analysis::efiAnalyzerMainX86(); + efi_analysis::efiAnalyserMainX86(); } else if (arch == ArchFileType::Uefi) { msg("[%s] input file is UEFI firmware\n", g_plugin_name); warning("%s: analysis may take some time, please wait for it to complete\n", g_plugin_name); if (get_machine_type() == AARCH64) { - msg("[%s] analyze AARCH64 modules\n", g_plugin_name); - efi_analysis::efiAnalyzerMainArm(); + msg("[%s] analyse AARCH64 modules\n", g_plugin_name); + efi_analysis::efiAnalyserMainArm(); } else { - msg("[%s] analyze AMD64 modules\n", g_plugin_name); - efi_analysis::efiAnalyzerMainX64(); + msg("[%s] analyse AMD64 modules\n", g_plugin_name); + efi_analysis::efiAnalyserMainX64(); } } else if (arch == ArchFileType::Aarch64) { msg("[%s] input file is 64-bit module (ARM)\n", g_plugin_name); - efi_analysis::efiAnalyzerMainArm(); + efi_analysis::efiAnalyserMainArm(); } // Reset arguments From 68cbf7b5afd7f4074bf2d3e737d86c3113637a26 Mon Sep 17 00:00:00 2001 From: yeggor Date: Sat, 14 Sep 2024 00:33:18 +0200 Subject: [PATCH 17/69] use pragma once instead of header guards in efixloader headers --- efiXloader/efi_loader.cc | 1 - efiXloader/efi_loader.h | 6 +----- efiXloader/ida_core.h | 6 +----- efiXloader/pe.h | 6 +----- efiXloader/pe_ida.h | 18 +----------------- efiXloader/pe_manager.cc | 1 - efiXloader/pe_manager.h | 6 +----- efiXloader/uefitool.cc | 1 - efiXloader/uefitool.h | 6 +----- efiXloader/utils.cc | 1 - efiXloader/utils.h | 6 +----- 11 files changed, 7 insertions(+), 51 deletions(-) diff --git a/efiXloader/efi_loader.cc b/efiXloader/efi_loader.cc index 09bfe1e9..4015e05f 100644 --- a/efiXloader/efi_loader.cc +++ b/efiXloader/efi_loader.cc @@ -15,7 +15,6 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * - * efiLoader.cpp */ #include "efi_loader.h" diff --git a/efiXloader/efi_loader.h b/efiXloader/efi_loader.h index c09eea0f..e461346a 100644 --- a/efiXloader/efi_loader.h +++ b/efiXloader/efi_loader.h @@ -15,11 +15,9 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * - * efiLoader.h */ -#ifndef EFILOADER_EFILOADER_H -#define EFILOADER_EFILOADER_H +#pragma once #include "ida_core.h" #include "pe.h" @@ -94,5 +92,3 @@ class driver_chooser_t : public chooser_t { ok = true; }; }; - -#endif // EFILOADER_EFILOADER_H diff --git a/efiXloader/ida_core.h b/efiXloader/ida_core.h index 4dbd21ba..80f57685 100644 --- a/efiXloader/ida_core.h +++ b/efiXloader/ida_core.h @@ -15,11 +15,9 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * - * ida_core.h */ -#ifndef EFILOADER_IDA_CORE_H -#define EFILOADER_IDA_CORE_H +#pragma once #define USE_STANDARD_FILE_FUNCTIONS 1 @@ -152,5 +150,3 @@ inline uint32 readlong(linput_t *li) { inline uint32 mf_readlong(linput_t *li) { return swap32(readlong(li)); } inline uint16 mf_readshort(linput_t *li) { return swap16(readshort(li)); } - -#endif // EFILOADER_IDA_CORE_H diff --git a/efiXloader/pe.h b/efiXloader/pe.h index 6b4d70ab..9b2a4d15 100644 --- a/efiXloader/pe.h +++ b/efiXloader/pe.h @@ -15,11 +15,9 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * - * pe.h */ -#ifndef EFILOADER_PE_H -#define EFILOADER_PE_H +#pragma once // // IDA header @@ -180,5 +178,3 @@ class PE { } // namespace efiloader enum MachineType { AMD64 = 0x8664, I386 = 0x014C, AARCH64 = 0xaa64 }; - -#endif // EFILOADER_PE_H diff --git a/efiXloader/pe_ida.h b/efiXloader/pe_ida.h index a650b481..ca0db774 100644 --- a/efiXloader/pe_ida.h +++ b/efiXloader/pe_ida.h @@ -15,23 +15,9 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * - * pe_ida.h */ -#ifndef EFILOADER_PE_IDA_H -#define EFILOADER_PE_IDA_H - -/* - * Interactive disassembler (IDA). - * Version 3.05 - * Copyright (c) 1990-95 by Ilfak Guilfanov. (2:5020/209@fidonet) - * ALL RIGHTS RESERVED. - * - */ - -// -// Portable Executable file format (MS Windows 95, MS Windows NT) -// +#pragma once #include "ida_core.h" #include @@ -1073,5 +1059,3 @@ const char *get_pe_machine_name(uint16 machine); void print_pe_flags(uint16 flags); #pragma pack(pop) - -#endif // EFILOADER_PE_IDA_H diff --git a/efiXloader/pe_manager.cc b/efiXloader/pe_manager.cc index 19bd9053..e1e2cc58 100644 --- a/efiXloader/pe_manager.cc +++ b/efiXloader/pe_manager.cc @@ -15,7 +15,6 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * - * pe_manager.cpp */ #include "pe_manager.h" diff --git a/efiXloader/pe_manager.h b/efiXloader/pe_manager.h index 304d1313..58cd11d6 100644 --- a/efiXloader/pe_manager.h +++ b/efiXloader/pe_manager.h @@ -15,11 +15,9 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * - * pe_manager.h */ -#ifndef EFILOADER_PE_MANAGER_H -#define EFILOADER_PE_MANAGER_H +#pragma once #include "ida_core.h" #include "pe.h" @@ -52,5 +50,3 @@ class PeManager { void pe_head_to_base(linput_t *li); }; } // namespace efiloader - -#endif // EFILOADER_PE_MANAGER_H diff --git a/efiXloader/uefitool.cc b/efiXloader/uefitool.cc index f7b9b5f3..e3b8426f 100644 --- a/efiXloader/uefitool.cc +++ b/efiXloader/uefitool.cc @@ -15,7 +15,6 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * - * uefitool.cpp */ #include "uefitool.h" diff --git a/efiXloader/uefitool.h b/efiXloader/uefitool.h index 241f5ed1..4f0799f6 100644 --- a/efiXloader/uefitool.h +++ b/efiXloader/uefitool.h @@ -15,11 +15,9 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * - * uefitool.h */ -#ifndef EFILOADER_UEFITOOL_H -#define EFILOADER_UEFITOOL_H +#pragma once #include "3rd/uefitool/common/LZMA/LzmaCompress.h" #include "3rd/uefitool/common/LZMA/LzmaDecompress.h" @@ -145,5 +143,3 @@ class Uefitool { bool machine_type_detected = false; }; } // namespace efiloader - -#endif // EFILOADER_UEFITOOL_H diff --git a/efiXloader/utils.cc b/efiXloader/utils.cc index 08aef36c..dd6c3688 100644 --- a/efiXloader/utils.cc +++ b/efiXloader/utils.cc @@ -15,7 +15,6 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * - * utils.cpp */ #include "utils.h" diff --git a/efiXloader/utils.h b/efiXloader/utils.h index bb7fbeb3..03ea53e0 100644 --- a/efiXloader/utils.h +++ b/efiXloader/utils.h @@ -15,11 +15,9 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * - * utils.h */ -#ifndef EFILOADER_UTILS_H -#define EFILOADER_UTILS_H +#pragma once #include "ida_core.h" #include @@ -39,5 +37,3 @@ class Utils { void skip(memory_deserializer_t *ser, size_t size, size_t count); }; } // namespace efiloader - -#endif // EFILOADER_UTILS_H From 67997b5482f04edbbd11d418afb232118621671a Mon Sep 17 00:00:00 2001 From: yeggor Date: Sat, 14 Sep 2024 01:42:48 +0200 Subject: [PATCH 18/69] refactor efi_utils: change API names convention, minor changes in functions --- efiXplorer/efi_analyser.h | 2 +- efiXplorer/efi_analyser_arm.cc | 78 +++---- efiXplorer/efi_analyser_x86.cc | 384 +++++++++++++++---------------- efiXplorer/efi_defs.cc | 150 +++++++------ efiXplorer/efi_defs.h | 36 +-- efiXplorer/efi_deps.cc | 16 +- efiXplorer/efi_hexrays.cc | 16 +- efiXplorer/efi_hexrays.h | 72 +++--- efiXplorer/efi_smm_utils.cc | 56 ++--- efiXplorer/efi_smm_utils.h | 4 +- efiXplorer/efi_utils.cc | 398 +++++++++++++++++---------------- efiXplorer/efi_utils.h | 150 ++++--------- efiXplorer/efixplorer.cc | 2 +- 13 files changed, 669 insertions(+), 695 deletions(-) diff --git a/efiXplorer/efi_analyser.h b/efiXplorer/efi_analyser.h index 15386fdb..15e12543 100644 --- a/efiXplorer/efi_analyser.h +++ b/efiXplorer/efi_analyser.h @@ -59,7 +59,7 @@ class EfiAnalyser { bool analyseNvramVariables(); bool AnalyseVariableService(ea_t ea, std::string service_str); bool AddProtocol(std::string serviceName, ea_t guidAddress, ea_t xrefAddress, - ea_t callAddress); + ea_t call_address); void dumpInfo(); json dbProtocols; diff --git a/efiXplorer/efi_analyser_arm.cc b/efiXplorer/efi_analyser_arm.cc index 73295487..0b4aebe1 100644 --- a/efiXplorer/efi_analyser_arm.cc +++ b/efiXplorer/efi_analyser_arm.cc @@ -24,10 +24,10 @@ using namespace efi_analysis; -std::vector gImageHandleListArm; -std::vector gStListArm; -std::vector gBsListArm; -std::vector gRtListArm; +std::vector image_handle_list_arm; +std::vector st_list_arm; +std::vector bs_list_arm; +std::vector rt_list_arm; void efi_analysis::EfiAnalyserArm::fixOffsets() { insn_t insn; @@ -64,11 +64,11 @@ void efi_analysis::EfiAnalyserArm::initialAnalysis() { #endif /* HEX_RAYS */ } if (file_type == FfsFileType::Pei) { - // setEntryArgToPeiSvc(); + // set_entry_arg_to_pei_svc(); } } -ea_t getTable(ea_t code_addr, uint64_t offset) { +ea_t get_table_addr(ea_t code_addr, uint64_t offset) { ea_t table = BADADDR; insn_t insn; decode_insn(&insn, code_addr); @@ -169,10 +169,10 @@ json getService(ea_t addr, uint8_t table_id) { insn.ops[0].type == o_reg && insn.ops[0].reg == blr_reg) { s["address"] = ea; if (table_id == 1) { - s["service_name"] = lookupBootServiceName(service_offset); + s["service_name"] = lookup_boot_service_name(service_offset); s["table_name"] = "EFI_BOOT_SERVICES"; } else if (table_id == 2) { - s["service_name"] = lookupRuntimeServiceName(service_offset); + s["service_name"] = lookup_runtime_service_name(service_offset); s["table_name"] = "EFI_RUNTIME_SERVICES"; } else { s["table_name"] = "OTHER"; @@ -207,10 +207,10 @@ json getService(ea_t addr, uint8_t table_id) { insn.ops[1].type == o_displ && insn.ops[1].reg == reg2) { s["address"] = ea; if (table_id == 1) { - s["service_name"] = lookupBootServiceName(insn.ops[1].addr); + s["service_name"] = lookup_boot_service_name(insn.ops[1].addr); s["table_name"] = "EFI_BOOT_SERVICES"; } else if (table_id == 2) { - s["service_name"] = lookupRuntimeServiceName(insn.ops[1].addr); + s["service_name"] = lookup_runtime_service_name(insn.ops[1].addr); s["table_name"] = "EFI_RUNTIME_SERVICES"; } else { s["table_name"] = "OTHER"; @@ -230,29 +230,29 @@ void efi_analysis::EfiAnalyserArm::initialGlobalVarsDetection() { json res = DetectVars(get_func(func_addr)); if (res.contains("gImageHandleList")) { for (auto addr : res["gImageHandleList"]) { - if (!addrInVec(gImageHandleListArm, addr)) { - gImageHandleListArm.push_back(addr); + if (!addr_in_vec(image_handle_list_arm, addr)) { + image_handle_list_arm.push_back(addr); } } } - if (res.contains("gStList")) { - for (auto addr : res["gStList"]) { - if (!addrInVec(gStListArm, addr)) { - gStListArm.push_back(addr); + if (res.contains("st_list")) { + for (auto addr : res["st_list"]) { + if (!addr_in_vec(st_list_arm, addr)) { + st_list_arm.push_back(addr); } } } - if (res.contains("gBsList")) { - for (auto addr : res["gBsList"]) { - if (!addrInVec(gBsListArm, addr)) { - gBsListArm.push_back(addr); + if (res.contains("bs_list")) { + for (auto addr : res["bs_list"]) { + if (!addr_in_vec(bs_list_arm, addr)) { + bs_list_arm.push_back(addr); } } } - if (res.contains("gRtList")) { - for (auto addr : res["gRtList"]) { - if (!addrInVec(gRtListArm, addr)) { - gRtListArm.push_back(addr); + if (res.contains("rt_list")) { + for (auto addr : res["rt_list"]) { + if (!addr_in_vec(rt_list_arm, addr)) { + rt_list_arm.push_back(addr); } } } @@ -268,21 +268,21 @@ void efi_analysis::EfiAnalyserArm::initialGlobalVarsDetection() { auto ea = f->start_ea; while (ea < f->end_ea) { ea = next_head(ea, BADADDR); - ea_t bs = getTable(ea, 0x60); + ea_t bs = get_table_addr(ea, 0x60); if (bs != BADADDR) { msg("[efiXplorer] gBS = 0x%016llX\n", u64_addr(ea)); - setPtrTypeAndName(bs, "gBS", "EFI_BOOT_SERVICES"); - if (!addrInVec(gBsListArm, bs)) { - gBsListArm.push_back(bs); + set_ptr_type_and_name(bs, "gBS", "EFI_BOOT_SERVICES"); + if (!addr_in_vec(bs_list_arm, bs)) { + bs_list_arm.push_back(bs); } continue; } - ea_t rt = getTable(ea, 0x58); + ea_t rt = get_table_addr(ea, 0x58); if (rt != BADADDR) { msg("[efiXplorer] gRT = 0x%016llX\n", u64_addr(ea)); - setPtrTypeAndName(rt, "gRT", "EFI_RUNTIME_SERVICES"); - if (!addrInVec(gRtListArm, rt)) { - gRtListArm.push_back(rt); + set_ptr_type_and_name(rt, "gRT", "EFI_RUNTIME_SERVICES"); + if (!addr_in_vec(rt_list_arm, rt)) { + rt_list_arm.push_back(rt); } continue; } @@ -302,8 +302,8 @@ void efi_analysis::EfiAnalyserArm::servicesDetection() { #endif /* HEX_RAYS */ // analyse xrefs to gBS, gRT - for (auto bs : gBsListArm) { - auto xrefs = getXrefs(bs); + for (auto bs : bs_list_arm) { + auto xrefs = get_xrefs_util(bs); for (auto ea : xrefs) { auto s = getService(ea, 1); if (!s.contains("address")) { @@ -313,15 +313,15 @@ void efi_analysis::EfiAnalyserArm::servicesDetection() { if (name == "Unknown") { continue; } - if (!jsonInVec(allServices, s)) { + if (!json_in_vec(allServices, s)) { msg("[efiXplorer] gBS xref address: 0x%016llX, found new service\n", u64_addr(ea)); allServices.push_back(s); } } } - for (auto rt : gRtListArm) { - auto xrefs = getXrefs(rt); + for (auto rt : rt_list_arm) { + auto xrefs = get_xrefs_util(rt); for (auto ea : xrefs) { auto s = getService(ea, 2); if (!s.contains("address")) { @@ -331,7 +331,7 @@ void efi_analysis::EfiAnalyserArm::servicesDetection() { if (name == "Unknown") { continue; } - if (!jsonInVec(allServices, s)) { + if (!json_in_vec(allServices, s)) { msg("[efiXplorer] gRT xref address: 0x%016llX, found new service\n", u64_addr(ea)); allServices.push_back(s); @@ -413,7 +413,7 @@ void efi_analysis::EfiAnalyserArm::findPeiServicesFunction() { msg("[efiXplorer] found GetPeiServices() function: 0x%016llX\n", u64_addr(start_ea)); set_name(start_ea, "GetPeiServices", SN_FORCE); - setRetToPeiSvc(start_ea); + set_ret_to_pei_svc(start_ea); } } } diff --git a/efiXplorer/efi_analyser_x86.cc b/efiXplorer/efi_analyser_x86.cc index 0c171c13..f1f49e08 100644 --- a/efiXplorer/efi_analyser_x86.cc +++ b/efiXplorer/efi_analyser_x86.cc @@ -32,10 +32,10 @@ extern std::vector g_get_smst_location_calls; extern std::vector g_smm_get_variable_calls; extern std::vector g_smm_set_variable_calls; -std::vector gStList; +std::vector st_list; std::vector gPeiSvcList; -std::vector gBsList; -std::vector gRtList; +std::vector bs_list; +std::vector rt_list; std::vector gSmstList; std::vector gImageHandleList; std::vector gRtServicesList; @@ -63,7 +63,7 @@ efi_analysis::EfiAnalyser::EfiAnalyser() { arch = input_file_type(); // get guids.json path - guidsJsonPath /= getGuidsJsonFile(); + guidsJsonPath /= get_guids_json_file(); // get base address base = get_imagebase(); @@ -118,10 +118,10 @@ efi_analysis::EfiAnalyser::EfiAnalyser() { efi_analysis::EfiAnalyser::~EfiAnalyser() { funcs.clear(); - gStList.clear(); + st_list.clear(); gPeiSvcList.clear(); - gBsList.clear(); - gRtList.clear(); + bs_list.clear(); + rt_list.clear(); gSmstList.clear(); gImageHandleList.clear(); gRtServicesList.clear(); @@ -226,7 +226,7 @@ bool efi_analysis::EfiAnalyserX86::findImageHandleX64() { set_cmt(ea, "EFI_IMAGE_HANDLE gImageHandle", true); // set type and name - setTypeAndName(insn.ops[0].addr, "gImageHandle", "EFI_IMAGE_HANDLE"); + set_type_and_name(insn.ops[0].addr, "gImageHandle", "EFI_IMAGE_HANDLE"); gImageHandleList.push_back(insn.ops[0].addr); break; } @@ -253,8 +253,8 @@ bool efi_analysis::EfiAnalyserX86::findSystemTableX64() { if (insn.itype == NN_mov && insn.ops[1].type == o_reg && insn.ops[1].reg == REG_RDX && insn.ops[0].type == o_mem) { set_cmt(ea, "EFI_SYSTEM_TABLE *gST", true); - setPtrTypeAndName(insn.ops[0].addr, "gST", "EFI_SYSTEM_TABLE"); - gStList.push_back(insn.ops[0].addr); + set_ptr_type_and_name(insn.ops[0].addr, "gST", "EFI_SYSTEM_TABLE"); + st_list.push_back(insn.ops[0].addr); return true; } ea = next_head(ea, BADADDR); @@ -267,8 +267,8 @@ bool efi_analysis::EfiAnalyserX86::findSystemTableX64() { // Find and mark gSmst global variable address for X64 module bool efi_analysis::EfiAnalyserX86::findSmstX64() { msg("[%s] gSmst finding\n", g_plugin_name); - std::vector gSmstListSmmBase = findSmstSmmBase(gBsList); - std::vector gSmstListSwDispatch = findSmstSwDispatch(gBsList); + std::vector gSmstListSmmBase = findSmstSmmBase(bs_list); + std::vector gSmstListSwDispatch = findSmstSwDispatch(bs_list); gSmstList.insert(gSmstList.end(), gSmstListSwDispatch.begin(), gSmstListSwDispatch.end()); gSmstList.insert(gSmstList.end(), gSmstListSmmBase.begin(), gSmstListSmmBase.end()); @@ -332,8 +332,8 @@ bool efi_analysis::EfiAnalyserX86::findSmstPostProcX64() { if (smst_stack.is_null() && smst_addr != BADADDR) { msg("[%s] gSmst: 0x%016llX\n", g_plugin_name, u64_addr(smst_addr)); - if (!addrInVec(gSmstList, smst_addr)) { - setPtrTypeAndName(smst_addr, "gSmst", "_EFI_SMM_SYSTEM_TABLE2"); + if (!addr_in_vec(gSmstList, smst_addr)) { + set_ptr_type_and_name(smst_addr, "gSmst", "_EFI_SMM_SYSTEM_TABLE2"); gSmstList.push_back(smst_addr); } } @@ -387,7 +387,7 @@ bool efi_analysis::EfiAnalyserX86::findSmstPostProcX64() { if (insn.itype == NN_callni && insn.ops[0].type == o_displ && insn.ops[0].reg == smst_reg && insn.ops[0].addr == SmiHandlerRegisterOffset64) { - opStroff(ea, "_EFI_SMM_SYSTEM_TABLE2"); + op_stroff_util(ea, "_EFI_SMM_SYSTEM_TABLE2"); // save child SW SMI handler func_t *handler_func = get_func(rcx_last); if (handler_func != nullptr) { @@ -452,10 +452,10 @@ bool efi_analysis::EfiAnalyserX86::findBootServicesTables() { next_insn.ops[0].phrase == phrase_reg && next_insn.ops[1].type == o_reg && next_insn.ops[1].reg == bsRegister) { baseInsnAddr = ea; - if (!addrInVec(gBsList, var_addr)) { + if (!addr_in_vec(bs_list, var_addr)) { set_cmt(ea, "EFI_BOOT_SERVICES *gBS", true); - setPtrTypeAndName(var_addr, "gBS", "EFI_BOOT_SERVICES"); - gBsList.push_back(var_addr); + set_ptr_type_and_name(var_addr, "gBS", "EFI_BOOT_SERVICES"); + bs_list.push_back(var_addr); } bsFound = true; } @@ -466,10 +466,10 @@ bool efi_analysis::EfiAnalyserX86::findBootServicesTables() { if (insn.ops[1].reg == bsRegister && !bsFound) { baseInsnAddr = ea; var_addr = insn.ops[0].addr; - if (!addrInVec(gBsList, var_addr)) { + if (!addr_in_vec(bs_list, var_addr)) { set_cmt(ea, "EFI_BOOT_SERVICES *gBS", true); - setPtrTypeAndName(var_addr, "gBS", "EFI_BOOT_SERVICES"); - gBsList.push_back(var_addr); + set_ptr_type_and_name(var_addr, "gBS", "EFI_BOOT_SERVICES"); + bs_list.push_back(var_addr); } bsFound = true; } @@ -477,10 +477,10 @@ bool efi_analysis::EfiAnalyserX86::findBootServicesTables() { // here you can also find gST if (insn.ops[1].reg == stRegister && !stFound && stRegister != bsRegister) { var_addr = insn.ops[0].addr; - if (!addrInTables(gStList, gBsList, gRtList, var_addr)) { + if (!addr_in_tables(st_list, bs_list, rt_list, var_addr)) { set_cmt(ea, "EFI_SYSTEM_TABLE *gST", true); - setPtrTypeAndName(var_addr, "gST", "EFI_SYSTEM_TABLE"); - gStList.push_back(var_addr); + set_ptr_type_and_name(var_addr, "gST", "EFI_SYSTEM_TABLE"); + st_list.push_back(var_addr); } stFound = true; } @@ -499,10 +499,10 @@ bool efi_analysis::EfiAnalyserX86::findBootServicesTables() { if (insn.itype == NN_mov && insn.ops[1].type == o_reg && insn.ops[1].reg == stRegister && insn.ops[0].type == o_mem) { var_addr = insn.ops[0].addr; - if (!addrInTables(gStList, gBsList, gRtList, var_addr)) { + if (!addr_in_tables(st_list, bs_list, rt_list, var_addr)) { set_cmt(addr, "EFI_SYSTEM_TABLE *gST", true); - setPtrTypeAndName(var_addr, "gST", "EFI_SYSTEM_TABLE"); - gStList.push_back(var_addr); + set_ptr_type_and_name(var_addr, "gST", "EFI_SYSTEM_TABLE"); + st_list.push_back(var_addr); } stFound = true; break; @@ -514,7 +514,7 @@ bool efi_analysis::EfiAnalyserX86::findBootServicesTables() { } } } - return (gBsList.size() != 0); + return (bs_list.size() != 0); } //-------------------------------------------------------------------------- @@ -566,10 +566,10 @@ bool efi_analysis::EfiAnalyserX86::findRuntimeServicesTables() { next_insn.ops[0].phrase == phrase_reg && next_insn.ops[1].type == o_reg && next_insn.ops[1].reg == rtRegister) { baseInsnAddr = ea; - if (!addrInVec(gRtList, var_addr)) { + if (!addr_in_vec(rt_list, var_addr)) { set_cmt(ea, "EFI_RUNTIME_SERVICES *gRT", true); - setPtrTypeAndName(var_addr, "gRT", "EFI_RUNTIME_SERVICES"); - gRtList.push_back(var_addr); + set_ptr_type_and_name(var_addr, "gRT", "EFI_RUNTIME_SERVICES"); + rt_list.push_back(var_addr); } rtFound = true; } @@ -580,10 +580,10 @@ bool efi_analysis::EfiAnalyserX86::findRuntimeServicesTables() { if (insn.ops[1].reg == rtRegister && !rtFound) { baseInsnAddr = ea; var_addr = insn.ops[0].addr; - if (!addrInVec(gRtList, var_addr)) { + if (!addr_in_vec(rt_list, var_addr)) { set_cmt(ea, "EFI_RUNTIME_SERVICES *gRT", true); - setPtrTypeAndName(var_addr, "gRT", "EFI_RUNTIME_SERVICES"); - gRtList.push_back(var_addr); + set_ptr_type_and_name(var_addr, "gRT", "EFI_RUNTIME_SERVICES"); + rt_list.push_back(var_addr); } rtFound = true; } @@ -591,10 +591,10 @@ bool efi_analysis::EfiAnalyserX86::findRuntimeServicesTables() { // here you can also find gST if (insn.ops[1].reg == stRegister && !stFound && stRegister != rtRegister) { var_addr = insn.ops[0].addr; - if (!addrInTables(gStList, gBsList, gRtList, var_addr)) { + if (!addr_in_tables(st_list, bs_list, rt_list, var_addr)) { set_cmt(ea, "EFI_SYSTEM_TABLE *gST", true); - setPtrTypeAndName(insn.ops[0].addr, "gST", "EFI_SYSTEM_TABLE"); - gStList.push_back(insn.ops[0].addr); + set_ptr_type_and_name(insn.ops[0].addr, "gST", "EFI_SYSTEM_TABLE"); + st_list.push_back(insn.ops[0].addr); } stFound = true; } @@ -612,10 +612,10 @@ bool efi_analysis::EfiAnalyserX86::findRuntimeServicesTables() { decode_insn(&insn, addr); if (insn.itype == NN_mov && insn.ops[1].type == o_reg && insn.ops[1].reg == stRegister && insn.ops[0].type == o_mem) { - if (!addrInTables(gStList, gBsList, gRtList, var_addr)) { + if (!addr_in_tables(st_list, bs_list, rt_list, var_addr)) { set_cmt(addr, "EFI_SYSTEM_TABLE *gST", true); - setPtrTypeAndName(var_addr, "gST", "EFI_SYSTEM_TABLE"); - gStList.push_back(var_addr); + set_ptr_type_and_name(var_addr, "gST", "EFI_SYSTEM_TABLE"); + st_list.push_back(var_addr); } stFound = true; break; @@ -627,7 +627,7 @@ bool efi_analysis::EfiAnalyserX86::findRuntimeServicesTables() { } } } - return (gRtList.size() != 0); + return (rt_list.size() != 0); } //-------------------------------------------------------------------------- @@ -635,17 +635,17 @@ bool efi_analysis::EfiAnalyserX86::findRuntimeServicesTables() { void efi_analysis::EfiAnalyserX86::getAllBootServices() { msg("[%s] BootServices finding (xrefs)\n", g_plugin_name); - if (!gBsList.size()) { + if (!bs_list.size()) { return; } insn_t insn; - for (auto bs : gBsList) { + for (auto bs : bs_list) { msg("[%s] BootServices finding by xrefs to gBS (0x%016llX)\n", g_plugin_name, u64_addr(bs)); - auto xrefs = getXrefs(bs); + auto xrefs = get_xrefs_util(bs); for (auto ea : xrefs) { bool found = false; decode_insn(&insn, ea); @@ -675,12 +675,12 @@ void efi_analysis::EfiAnalyserX86::getAllBootServices() { service_offset = insn.ops[0].addr; } - for (int j = 0; j < bootServicesTableAllCount; j++) { + for (int j = 0; j < g_boot_services_table_all_count; j++) { // architecture-specific variables - auto offset = bootServicesTableAll[j].offset64; + auto offset = g_boot_services_table_all[j].offset64; if (arch == ArchFileType::X8632) { - offset = bootServicesTableAll[j].offset32; + offset = g_boot_services_table_all[j].offset32; } if (service_offset == u32_addr(offset)) { @@ -689,23 +689,23 @@ void efi_analysis::EfiAnalyserX86::getAllBootServices() { // (can be confused with // gSmst->SmmInstallProtocolInterface) if (u32_addr(offset) == RegisterProtocolNotifyOffset64) { - if (!bootServiceProtCheck(addr)) { + if (!check_boot_service_protocol(addr)) { break; } } - opStroff(addr, "EFI_BOOT_SERVICES"); + op_stroff_util(addr, "EFI_BOOT_SERVICES"); msg("[%s] 0x%016llX : %s\n", g_plugin_name, u64_addr(addr), - static_cast(bootServicesTableAll[j].name)); - bootServices[static_cast(bootServicesTableAll[j].name)] + static_cast(g_boot_services_table_all[j].name)); + bootServices[static_cast(g_boot_services_table_all[j].name)] .push_back(addr); // add item to allBootServices json bsItem; bsItem["address"] = addr; bsItem["service_name"] = - static_cast(bootServicesTableAll[j].name); + static_cast(g_boot_services_table_all[j].name); bsItem["table_name"] = static_cast("EFI_BOOT_SERVICES"); bsItem["offset"] = offset; @@ -714,7 +714,7 @@ void efi_analysis::EfiAnalyserX86::getAllBootServices() { get_arg_addrs(&args, addr); bsItem["args"] = args; - if (!jsonInVec(allServices, bsItem)) { + if (!json_in_vec(allServices, bsItem)) { allServices.push_back(bsItem); } @@ -736,13 +736,13 @@ void efi_analysis::EfiAnalyserX86::getAllBootServices() { void efi_analysis::EfiAnalyserX86::getAllRuntimeServices() { msg("[%s] RuntimeServices finding (xrefs)\n", g_plugin_name); - if (!gRtList.size()) { + if (!rt_list.size()) { return; } insn_t insn; - for (auto rt : gRtList) { - auto xrefs = getXrefs(rt); + for (auto rt : rt_list) { + auto xrefs = get_xrefs_util(rt); msg("[%s] RuntimeServices finding by xrefs to gRT (0x%016llX)\n", g_plugin_name, u64_addr(rt)); @@ -775,26 +775,26 @@ void efi_analysis::EfiAnalyserX86::getAllRuntimeServices() { service_offset = insn.ops[0].addr; } - for (int j = 0; j < runtimeServicesTableAllCount; j++) { + for (int j = 0; j < g_runtime_services_table_all_count; j++) { // architecture-specific variables - auto offset = runtimeServicesTableAll[j].offset64; + auto offset = g_runtime_services_table_all[j].offset64; if (arch == ArchFileType::X8632) { - offset = runtimeServicesTableAll[j].offset32; + offset = g_runtime_services_table_all[j].offset32; } if (service_offset == u32_addr(offset)) { - opStroff(addr, "EFI_RUNTIME_SERVICES"); + op_stroff_util(addr, "EFI_RUNTIME_SERVICES"); msg("[%s] 0x%016llX : %s\n", g_plugin_name, u64_addr(addr), - static_cast(runtimeServicesTableAll[j].name)); + static_cast(g_runtime_services_table_all[j].name)); runtimeServicesAll[static_cast( - runtimeServicesTableAll[j].name)] + g_runtime_services_table_all[j].name)] .push_back(addr); // add item to allRuntimeServices json rtItem; rtItem["address"] = addr; rtItem["service_name"] = - static_cast(runtimeServicesTableAll[j].name); + static_cast(g_runtime_services_table_all[j].name); rtItem["table_name"] = static_cast("EFI_RUNTIME_SERVICES"); rtItem["offset"] = offset; @@ -803,7 +803,7 @@ void efi_analysis::EfiAnalyserX86::getAllRuntimeServices() { get_arg_addrs(&args, addr); rtItem["args"] = args; - if (!jsonInVec(allServices, rtItem)) { + if (!json_in_vec(allServices, rtItem)) { allServices.push_back(rtItem); } gRtServicesList.push_back(addr); @@ -827,7 +827,7 @@ void efi_analysis::EfiAnalyserX86::getAllSmmServicesX64() { insn_t insn; for (auto smms : gSmstList) { - auto xrefs = getXrefs(smms); + auto xrefs = get_xrefs_util(smms); msg("[%s] SmmServices finding by xref to gSmst (0x%016llX)\n", g_plugin_name, u64_addr(smms)); @@ -851,10 +851,10 @@ void efi_analysis::EfiAnalyserX86::getAllSmmServicesX64() { // jmp qword ptr [r9+0D0h] if ((insn.itype == NN_callni || insn.itype == NN_jmpni) && insn.ops[0].reg == smst_reg) { - for (int j = 0; j < smmServicesTableAllCount; j++) { - if (insn.ops[0].addr == u32_addr(smmServicesTableAll[j].offset64)) { + for (int j = 0; j < g_smm_services_table_all_count; j++) { + if (insn.ops[0].addr == u32_addr(g_smm_services_table_all[j].offset64)) { - if (u32_addr(smmServicesTableAll[j].offset64) == + if (u32_addr(g_smm_services_table_all[j].offset64) == SmiHandlerRegisterOffset64) { // set name for Handler argument auto smiHandlerAddr = markChildSwSmiHandler(addr); @@ -866,34 +866,34 @@ void efi_analysis::EfiAnalyserX86::getAllSmmServicesX64() { } std::string cmt = - "gSmst->" + static_cast(smmServicesTableAll[j].name); + "gSmst->" + static_cast(g_smm_services_table_all[j].name); set_cmt(addr, cmt.c_str(), true); - opStroff(addr, "_EFI_SMM_SYSTEM_TABLE2"); + op_stroff_util(addr, "_EFI_SMM_SYSTEM_TABLE2"); msg("[%s] 0x%016llX : %s\n", g_plugin_name, u64_addr(addr), - static_cast(smmServicesTableAll[j].name)); + static_cast(g_smm_services_table_all[j].name)); // add address to smmServices[...] if (find(protSmmNames.begin(), protSmmNames.end(), - smmServicesTableAll[j].name) != protSmmNames.end()) { - smmServices[smmServicesTableAll[j].name].push_back(addr); + g_smm_services_table_all[j].name) != protSmmNames.end()) { + smmServices[g_smm_services_table_all[j].name].push_back(addr); } - smmServicesAll[static_cast(smmServicesTableAll[j].name)] + smmServicesAll[static_cast(g_smm_services_table_all[j].name)] .push_back(addr); // add item to allSmmServices json smmsItem; smmsItem["address"] = addr; smmsItem["service_name"] = - static_cast(smmServicesTableAll[j].name); + static_cast(g_smm_services_table_all[j].name); smmsItem["table_name"] = static_cast("_EFI_SMM_SYSTEM_TABLE2"); - smmsItem["offset"] = smmServicesTableAll[j].offset64; + smmsItem["offset"] = g_smm_services_table_all[j].offset64; // add code addresses for arguments eavec_t args; get_arg_addrs(&args, addr); smmsItem["args"] = args; - if (!jsonInVec(allServices, smmsItem)) { + if (!json_in_vec(allServices, smmsItem)) { allServices.push_back(smmsItem); } break; @@ -922,8 +922,8 @@ void efi_analysis::EfiAnalyserX86::getAllPeiServicesX86() { if (insn.itype == NN_callni && (insn.ops[0].reg == REG_EAX || insn.ops[0].reg == REG_ECX || insn.ops[0].reg == REG_EDX)) { - for (int j = 0; j < peiServicesTable32Count; j++) { - if (insn.ops[0].addr == u32_addr(peiServicesTable32[j].offset)) { + for (int j = 0; j < g_pei_services_table32_count; j++) { + if (insn.ops[0].addr == u32_addr(g_pei_services_table32[j].offset)) { bool found_src_reg = false; ea_t address = ea; insn_t aboveInst; @@ -963,21 +963,22 @@ void efi_analysis::EfiAnalyserX86::getAllPeiServicesX86() { // looks like a FP break; } - opStroff(ea, "EFI_PEI_SERVICES"); + op_stroff_util(ea, "EFI_PEI_SERVICES"); msg("[%s] 0x%016llX : %s\n", g_plugin_name, u64_addr(ea), - static_cast(peiServicesTable32[j].name)); - peiServicesAll[static_cast(peiServicesTable32[j].name)] + static_cast(g_pei_services_table32[j].name)); + peiServicesAll[static_cast(g_pei_services_table32[j].name)] .push_back(ea); json psItem; psItem["address"] = ea; - psItem["service_name"] = static_cast(peiServicesTable32[j].name); + psItem["service_name"] = + static_cast(g_pei_services_table32[j].name); psItem["table_name"] = static_cast("EFI_PEI_SERVICES"); - psItem["offset"] = peiServicesTable32[j].offset; + psItem["offset"] = g_pei_services_table32[j].offset; // add code addresses for arguments psItem["args"] = args; - if (!jsonInVec(allServices, psItem)) { + if (!json_in_vec(allServices, psItem)) { allServices.push_back(psItem); } } @@ -1000,8 +1001,8 @@ void efi_analysis::EfiAnalyserX86::getAllVariablePPICallsX86() { ea = next_head(ea, BADADDR); decode_insn(&insn, ea); if (insn.itype == NN_callni && insn.ops[0].type == o_phrase) { - for (int j = 0; j < variablePpiTableAllCount; j++) { - if (insn.ops[0].addr == u32_addr(variablePpiTableAll[j].offset32)) { + for (int j = 0; j < g_variable_ppi_table_all_count; j++) { + if (insn.ops[0].addr == u32_addr(g_variable_ppi_table_all[j].offset32)) { uint16_t ppi_reg = insn.ops[0].reg; insn_t aboveInst; ea_t address = ea; @@ -1019,11 +1020,11 @@ void efi_analysis::EfiAnalyserX86::getAllVariablePPICallsX86() { } if (found_push) { - opStroff(ea, "EFI_PEI_READ_ONLY_VARIABLE2_PPI"); + op_stroff_util(ea, "EFI_PEI_READ_ONLY_VARIABLE2_PPI"); msg("[%s] 0x%016llX : %s\n", g_plugin_name, u64_addr(ea), - static_cast(variablePpiTableAll[j].name)); - std::string ppi_call = - "VariablePPI." + static_cast(variablePpiTableAll[j].name); + static_cast(g_variable_ppi_table_all[j].name)); + std::string ppi_call = "VariablePPI." + static_cast( + g_variable_ppi_table_all[j].name); ppiCallsAll[ppi_call].push_back(ea); // Injecting PPI call as service @@ -1032,14 +1033,14 @@ void efi_analysis::EfiAnalyserX86::getAllVariablePPICallsX86() { ppiItem["service_name"] = ppi_call; ppiItem["table_name"] = static_cast("EFI_PEI_READ_ONLY_VARIABLE2_PPI"); - ppiItem["offset"] = variablePpiTableAll[j].offset32; + ppiItem["offset"] = g_variable_ppi_table_all[j].offset32; // add code addresses for arguments eavec_t args; get_arg_addrs(&args, ea); ppiItem["args"] = args; - if (!jsonInVec(allServices, ppiItem)) { + if (!json_in_vec(allServices, ppiItem)) { allServices.push_back(ppiItem); } } @@ -1059,13 +1060,13 @@ void efi_analysis::EfiAnalyserX86::getPpiNamesX86() { if (seg_info != nullptr) { start = seg_info->start_ea; } - for (int i = 0; i < peiServicesTable32Count; i++) { - if (peiServicesTable32[i].push_number == PUSH_NONE || - !peiServicesAll.contains(peiServicesTableAll[i].name)) { + for (int i = 0; i < g_pei_services_table32_count; i++) { + if (g_pei_services_table32[i].push_number == PUSH_NONE || + !peiServicesAll.contains(g_pei_services_table_all[i].name)) { continue; } - std::vector addrs = peiServicesAll[peiServicesTable32[i].name]; + std::vector addrs = peiServicesAll[g_pei_services_table32[i].name]; // for each PEI service for (auto ea : addrs) { @@ -1078,7 +1079,7 @@ void efi_analysis::EfiAnalyserX86::getPpiNamesX86() { uint16_t pushCounter = 0; msg("[%s] looking for PPIs in the 0x%016llX area (push number: %d)\n", - g_plugin_name, u64_addr(address), peiServicesTable32[i].push_number); + g_plugin_name, u64_addr(address), g_pei_services_table32[i].push_number); // Check current basic block while (true) { @@ -1089,7 +1090,7 @@ void efi_analysis::EfiAnalyserX86::getPpiNamesX86() { pushCounter += 1; } - if (pushCounter == peiServicesTable32[i].push_number && + if (pushCounter == g_pei_services_table32[i].push_number && insn.ops[0].type == o_imm && (insn.ops[0].value & 0xffffffff) >= start && insn.ops[0].value != BADADDR) { // found "push gGuid" insn guidCodeAddress = address; @@ -1109,8 +1110,8 @@ void efi_analysis::EfiAnalyserX86::getPpiNamesX86() { if (found) { msg("[%s] found PPI GUID parameter at 0x%016llX\n", g_plugin_name, u64_addr(guidCodeAddress)); - auto guid = getGuidByAddr(guidDataAddress); - if (!checkGuid(guid)) { + auto guid = get_guid_by_address(guidDataAddress); + if (!valid_guid(guid)) { msg("[%s] Incorrect GUID at 0x%016llX\n", g_plugin_name, u64_addr(guidCodeAddress)); continue; @@ -1120,8 +1121,8 @@ void efi_analysis::EfiAnalyserX86::getPpiNamesX86() { json ppiItem; ppiItem["address"] = guidDataAddress; ppiItem["xref"] = guidCodeAddress; - ppiItem["service"] = peiServicesTableAll[i].name; - ppiItem["guid"] = getGuidFromValue(guid); + ppiItem["service"] = g_pei_services_table_all[i].name; + ppiItem["guid"] = guid_to_string(guid); ppiItem["module"] = "Current"; // find GUID name @@ -1131,7 +1132,7 @@ void efi_analysis::EfiAnalyserX86::getPpiNamesX86() { ppiItem["ppi_name"] = name; // check if item already exists - if (!jsonInVec(allPPIs, ppiItem)) { + if (!json_in_vec(allPPIs, ppiItem)) { allPPIs.push_back(ppiItem); } continue; @@ -1142,7 +1143,7 @@ void efi_analysis::EfiAnalyserX86::getPpiNamesX86() { ppiItem["ppi_name"] = "ProprietaryPpi"; // check if item already exists - if (!jsonInVec(allPPIs, ppiItem)) { + if (!json_in_vec(allPPIs, ppiItem)) { allPPIs.push_back(ppiItem); } continue; @@ -1167,44 +1168,48 @@ void efi_analysis::EfiAnalyserX86::getProtBootServicesX64() { if (insn.itype != NN_callni || insn.ops[0].reg != REG_RAX) { continue; } - for (auto i = 0; i < bootServicesTable64Count; i++) { - if (insn.ops[0].addr != u32_addr(bootServicesTable64[i].offset)) { + for (auto i = 0; i < g_boot_services_table64_count; i++) { + if (insn.ops[0].addr != u32_addr(g_boot_services_table64[i].offset)) { continue; } // additional check for gBS->RegisterProtocolNotify // (can be confused with gSmst->SmmInstallProtocolInterface) - if (u32_addr(bootServicesTable64[i].offset) == RegisterProtocolNotifyOffset64) { - if (!bootServiceProtCheck(ea)) { + if (u32_addr(g_boot_services_table64[i].offset) == + RegisterProtocolNotifyOffset64) { + if (!check_boot_service_protocol(ea)) { break; } } // check that address does not belong to the protocol interface // (gBS != gInterface) - auto bs_addr = findUnknownBsVarX64(ea); - if (addrInVec(gRtList, bs_addr) || !bootServiceProtCheckXrefs(bs_addr)) { + auto bs_addr = find_unknown_bs_var_64(ea); + if (addr_in_vec(rt_list, bs_addr) || + !check_boot_service_protocol_xrefs(bs_addr)) { break; } - opStroff(ea, "EFI_BOOT_SERVICES"); + op_stroff_util(ea, "EFI_BOOT_SERVICES"); msg("[%s] 0x%016llX : %s\n", g_plugin_name, u64_addr(ea), - static_cast(bootServicesTable64[i].name)); - bootServices[static_cast(bootServicesTable64[i].name)].push_back(ea); + static_cast(g_boot_services_table64[i].name)); + bootServices[static_cast(g_boot_services_table64[i].name)].push_back( + ea); // add item to allBootServices json bsItem; bsItem["address"] = ea; - bsItem["service_name"] = static_cast(bootServicesTable64[i].name); + bsItem["service_name"] = + static_cast(g_boot_services_table64[i].name); bsItem["table_name"] = static_cast("EFI_BOOT_SERVICES"); - bsItem["offset"] = bootServicesTable64[i].offset; + bsItem["offset"] = g_boot_services_table64[i].offset; // add code addresses for arguments eavec_t args; get_arg_addrs(&args, ea); bsItem["args"] = args; - if (!jsonInVec(allServices, bsItem)) { + if (!json_in_vec(allServices, bsItem)) { allServices.push_back(bsItem); } break; @@ -1225,27 +1230,28 @@ void efi_analysis::EfiAnalyserX86::getProtBootServicesX86() { ea = next_head(ea, endAddress); decode_insn(&insn, ea); if (insn.itype == NN_callni && insn.ops[0].reg == REG_EAX) { - for (auto i = 0; i < bootServicesTable32Count; i++) { - if (insn.ops[0].addr == u32_addr(bootServicesTable32[i].offset)) { - opStroff(ea, "EFI_BOOT_SERVICES"); + for (auto i = 0; i < g_boot_services_table32_count; i++) { + if (insn.ops[0].addr == u32_addr(g_boot_services_table32[i].offset)) { + op_stroff_util(ea, "EFI_BOOT_SERVICES"); msg("[%s] 0x%016llX : %s\n", g_plugin_name, u64_addr(ea), - static_cast(bootServicesTable32[i].name)); - bootServices[static_cast(bootServicesTable32[i].name)].push_back( - ea); + static_cast(g_boot_services_table32[i].name)); + bootServices[static_cast(g_boot_services_table32[i].name)] + .push_back(ea); // add item to allBootServices json bsItem; bsItem["address"] = ea; - bsItem["service_name"] = static_cast(bootServicesTable32[i].name); + bsItem["service_name"] = + static_cast(g_boot_services_table32[i].name); bsItem["table_name"] = static_cast("EFI_BOOT_SERVICES"); - bsItem["offset"] = bootServicesTable32[i].offset; + bsItem["offset"] = g_boot_services_table32[i].offset; // add code addresses for arguments eavec_t args; get_arg_addrs(&args, ea); bsItem["args"] = args; - if (!jsonInVec(allServices, bsItem)) { + if (!json_in_vec(allServices, bsItem)) { allServices.push_back(bsItem); } break; @@ -1270,38 +1276,38 @@ void efi_analysis::EfiAnalyserX86::findOtherBsTablesX64() { } ea_t addr = static_cast(s["address"]); msg("[%s] current service: 0x%016llX\n", g_plugin_name, u64_addr(addr)); - ea_t addr_bs = findUnknownBsVarX64(addr); - if (!addr_bs || addrInVec(gBsList, addr_bs) || addrInVec(gRtList, addr_bs)) { + ea_t addr_bs = find_unknown_bs_var_64(addr); + if (!addr_bs || addr_in_vec(bs_list, addr_bs) || addr_in_vec(rt_list, addr_bs)) { continue; } msg("[%s] found BootServices table at 0x%016llX, address = 0x%016llX\n", g_plugin_name, u64_addr(addr), u64_addr(addr_bs)); - setPtrTypeAndName(addr_bs, "gBS", "EFI_BOOT_SERVICES"); - gBsList.push_back(addr_bs); + set_ptr_type_and_name(addr_bs, "gBS", "EFI_BOOT_SERVICES"); + bs_list.push_back(addr_bs); } } bool efi_analysis::EfiAnalyser::AddProtocol(std::string serviceName, ea_t guidAddress, - ea_t xrefAddress, ea_t callAddress) { + ea_t xrefAddress, ea_t call_address) { if (arch != ArchFileType::Uefi && guidAddress >= startAddress && guidAddress <= endAddress) { msg("[%s] wrong service call detection: 0x%016llX\n", g_plugin_name, - u64_addr(callAddress)); + u64_addr(call_address)); return false; // filter FP } json protocol; - auto guid = getGuidByAddr(guidAddress); + auto guid = get_guid_by_address(guidAddress); protocol["address"] = guidAddress; protocol["xref"] = xrefAddress; protocol["service"] = serviceName; - protocol["guid"] = getGuidFromValue(guid); - protocol["ea"] = callAddress; + protocol["guid"] = guid_to_string(guid); + protocol["ea"] = call_address; qstring moduleName("Current"); if (input_file_type() == ArchFileType::Uefi) { - moduleName = getModuleNameLoader(callAddress); + moduleName = get_module_name_loader(call_address); } protocol["module"] = static_cast(moduleName.c_str()); @@ -1312,9 +1318,9 @@ bool efi_analysis::EfiAnalyser::AddProtocol(std::string serviceName, ea_t guidAd protocol["prot_name"] = name; } else { protocol["prot_name"] = "UNKNOWN_PROTOCOL_GUID"; - setTypeAndName(guidAddress, "UNKNOWN_PROTOCOL_GUID", "EFI_GUID"); + set_type_and_name(guidAddress, "UNKNOWN_PROTOCOL_GUID", "EFI_GUID"); } - if (!jsonInVec(allProtocols, protocol)) { + if (!json_in_vec(allProtocols, protocol)) { allProtocols.push_back(protocol); } return true; @@ -1416,14 +1422,14 @@ void efi_analysis::EfiAnalyserX86::getBsProtNamesX64() { g_plugin_name, u64_addr(start)); InstallMultipleProtocolInterfacesHandler(); - for (int i = 0; i < bootServicesTable64Count; i++) { + for (int i = 0; i < g_boot_services_table64_count; i++) { - if (bootServicesTable64[i].offset == InstallMultipleProtocolInterfacesOffset64) { + if (g_boot_services_table64[i].offset == InstallMultipleProtocolInterfacesOffset64) { // Handle InstallMultipleProtocolInterfaces separately continue; } - std::vector addrs = bootServices[bootServicesTable64[i].name]; + std::vector addrs = bootServices[g_boot_services_table64[i].name]; for (auto ea : addrs) { ea_t address = ea; msg("[%s] looking for protocols in the 0x%016llX area\n", g_plugin_name, @@ -1444,7 +1450,8 @@ void efi_analysis::EfiAnalyserX86::getBsProtNamesX64() { } if (insn.itype == NN_lea && insn.ops[0].type == o_reg && - insn.ops[0].reg == bootServicesTable64[i].reg && insn.ops[1].type == o_mem) { + insn.ops[0].reg == g_boot_services_table64[i].reg && + insn.ops[1].type == o_mem) { guidCodeAddress = address; guidDataAddress = insn.ops[1].addr; if (insn.ops[1].addr > start && insn.ops[1].addr != BADADDR) { @@ -1454,7 +1461,8 @@ void efi_analysis::EfiAnalyserX86::getBsProtNamesX64() { } if (insn.itype == NN_mov && insn.ops[0].type == o_reg && - insn.ops[0].reg == bootServicesTable64[i].reg && insn.ops[1].type == o_imm) { + insn.ops[0].reg == g_boot_services_table64[i].reg && + insn.ops[1].type == o_imm) { guidCodeAddress = address; guidDataAddress = insn.ops[1].value; if (insn.ops[1].value > start && insn.ops[1].value != BADADDR) { @@ -1468,14 +1476,15 @@ void efi_analysis::EfiAnalyserX86::getBsProtNamesX64() { msg("[%s] getBsProtNamesX64: found protocol GUID parameter at " "0x%016llX\n", g_plugin_name, u64_addr(guidCodeAddress)); - auto guid = getGuidByAddr(guidDataAddress); - if (!checkGuid(guid)) { + auto guid = get_guid_by_address(guidDataAddress); + if (!valid_guid(guid)) { msg("[%s] Incorrect GUID at 0x%016llX\n", g_plugin_name, u64_addr(guidCodeAddress)); continue; } - AddProtocol(bootServicesTable64[i].name, guidDataAddress, guidCodeAddress, ea); + AddProtocol(g_boot_services_table64[i].name, guidDataAddress, guidCodeAddress, + ea); } } } @@ -1490,8 +1499,8 @@ void efi_analysis::EfiAnalyserX86::getBsProtNamesX86() { if (seg_info != nullptr) { start = seg_info->start_ea; } - for (int i = 0; i < bootServicesTable32Count; i++) { - std::vector addrs = bootServices[bootServicesTable32[i].name]; + for (int i = 0; i < g_boot_services_table32_count; i++) { + std::vector addrs = bootServices[g_boot_services_table32[i].name]; // for each boot service for (auto ea : addrs) { @@ -1502,7 +1511,7 @@ void efi_analysis::EfiAnalyserX86::getBsProtNamesX86() { ea_t guidCodeAddress = 0; ea_t guidDataAddress = 0; auto found = false; - uint16_t pushNumber = bootServicesTable32[i].push_number; + uint16_t pushNumber = g_boot_services_table32[i].push_number; // if service is not currently being processed if (pushNumber == PUSH_NONE) { @@ -1540,14 +1549,15 @@ void efi_analysis::EfiAnalyserX86::getBsProtNamesX86() { msg("[%s] getBsProtNamesX86: found protocol GUID parameter at " "0x%016llX\n", g_plugin_name, u64_addr(guidCodeAddress)); - auto guid = getGuidByAddr(guidDataAddress); - if (!checkGuid(guid)) { + auto guid = get_guid_by_address(guidDataAddress); + if (!valid_guid(guid)) { msg("[%s] Incorrect GUID at 0x%016llX\n", g_plugin_name, u64_addr(guidCodeAddress)); continue; } - AddProtocol(bootServicesTable32[i].name, guidDataAddress, guidCodeAddress, ea); + AddProtocol(g_boot_services_table32[i].name, guidDataAddress, guidCodeAddress, + ea); } } } @@ -1563,8 +1573,8 @@ void efi_analysis::EfiAnalyserX86::getSmmProtNamesX64() { ea_t start = s->start_ea; msg("[%s] protocols finding (smm services, start address = 0x%016llX)\n", g_plugin_name, u64_addr(start)); - for (int i = 0; i < smmServicesProt64Count; i++) { - auto addrs = smmServices[smmServicesProt64[i].name]; + for (int i = 0; i < g_smm_services_prot64_count; i++) { + auto addrs = smmServices[g_smm_services_prot64[i].name]; // for each SMM service for (auto ea : addrs) { @@ -1587,7 +1597,7 @@ void efi_analysis::EfiAnalyserX86::getSmmProtNamesX64() { } if (insn.itype == NN_lea && insn.ops[0].type == o_reg && - insn.ops[0].reg == smmServicesProt64[i].reg) { + insn.ops[0].reg == g_smm_services_prot64[i].reg) { guidCodeAddress = address; guidDataAddress = insn.ops[1].addr; if (insn.ops[1].addr > start && insn.ops[1].addr != BADADDR) { @@ -1601,14 +1611,14 @@ void efi_analysis::EfiAnalyserX86::getSmmProtNamesX64() { msg("[%s] getSmmProtNamesX64: found protocol GUID parameter at " "0x%016llX\n", g_plugin_name, u64_addr(guidCodeAddress)); - auto guid = getGuidByAddr(guidDataAddress); - if (!checkGuid(guid)) { + auto guid = get_guid_by_address(guidDataAddress); + if (!valid_guid(guid)) { msg("[%s] Incorrect GUID at 0x%016llX\n", g_plugin_name, u64_addr(guidCodeAddress)); continue; } - AddProtocol(smmServicesProt64[i].name, guidDataAddress, guidCodeAddress, ea); + AddProtocol(g_smm_services_prot64[i].name, guidDataAddress, guidCodeAddress, ea); } } } @@ -1635,7 +1645,7 @@ void efi_analysis::EfiAnalyser::markInterfaces() { if (!marked) { std::string svcName = static_cast(ifItem[if_key]); set_name(address, svcName.c_str(), SN_FORCE); - setGuidType(address); + set_guid_type(address); std::string comment = "EFI_GUID " + svcName; markedInterfaces.push_back(address); msg("[%s] address: 0x%016llX, comment: %s\n", g_plugin_name, u64_addr(address), @@ -1662,22 +1672,22 @@ void efi_analysis::EfiAnalyser::markDataGuids() { ea += 1; continue; } - auto guid = getGuidByAddr(ea); + auto guid = get_guid_by_address(ea); // find GUID name auto it = dbProtocolsMap.find(guid); if (it != dbProtocolsMap.end()) { std::string guidName = it->second; set_name(ea, guidName.c_str(), SN_FORCE); - setGuidType(ea); + set_guid_type(ea); // rename PPI if (guidName.length() > 9 && guidName.rfind("_PPI_GUID") == guidName.length() - 9) { - auto xrefs = getXrefs(ea); + auto xrefs = get_xrefs_util(ea); for (auto addr : xrefs) { std::string ppiName = - "g" + typeToName(guidName.substr(0, guidName.length() - 5)); + "g" + type_to_name(guidName.substr(0, guidName.length() - 5)); ea_t ppiEa = addr - ptrSize; // check flags if (ptrSize == 8 && get_wide_dword(ppiEa + 4)) { @@ -1685,7 +1695,7 @@ void efi_analysis::EfiAnalyser::markDataGuids() { continue; } uint64_t flags = static_cast(get_wide_dword(ppiEa)); - if (!qwordInVec(ppiFlags, flags)) { + if (!uint64_in_vec(ppiFlags, flags)) { continue; } msg("[%s] address: 0x%016llX, PPI: %s\n", g_plugin_name, u64_addr(ppiEa), @@ -1701,7 +1711,7 @@ void efi_analysis::EfiAnalyser::markDataGuids() { json guid_item; guid_item["address"] = ea; guid_item["name"] = guidName; - guid_item["guid"] = getGuidFromValue(guid); + guid_item["guid"] = guid_to_string(guid); allGuids.push_back(guid_item); dataGuids.push_back(guid_item); } @@ -1769,7 +1779,7 @@ void efi_analysis::EfiAnalyserX86::markLocalGuidsX64() { json guid_item; guid_item["address"] = ea; guid_item["name"] = dbItem.key(); - guid_item["guid"] = getGuidFromValue(guid); + guid_item["guid"] = guid_to_string(guid); allGuids.push_back(guid_item); stackGuids.push_back(guid_item); exit = true; @@ -1805,7 +1815,7 @@ void findCalloutRec(func_t *func) { if (insn.itype == NN_mov && insn.ops[0].type == o_reg && insn.ops[1].type == o_mem) { // search for callouts with gBS - if (addrInVec(gBsList, insn.ops[1].addr)) { + if (addr_in_vec(bs_list, insn.ops[1].addr)) { msg("[%s] SMM callout found: 0x%016llX\n", g_plugin_name, u64_addr(ea)); // filter FP auto reg = insn.ops[0].reg; @@ -1833,7 +1843,7 @@ void findCalloutRec(func_t *func) { } // search for callouts with gRT - if (addrInVec(gRtList, insn.ops[1].addr)) { + if (addr_in_vec(rt_list, insn.ops[1].addr)) { msg("[%s] SMM callout found (gRT): 0x%016llX\n", g_plugin_name, u64_addr(ea)); calloutAddrs.push_back(ea); continue; @@ -1844,7 +1854,7 @@ void findCalloutRec(func_t *func) { insn_t insn_xref; bool interface_callout_found = false; // check all xrefs for found global variable - for (auto xref : getXrefs(g_addr)) { + for (auto xref : get_xrefs_util(g_addr)) { // chcek if it looks like interface decode_insn(&insn_xref, xref); if (insn_xref.itype != NN_lea || insn_xref.ops[0].type != o_reg || @@ -1938,7 +1948,7 @@ void efi_analysis::EfiAnalyser::findSwSmiHandlers() { // * find gBS->service_name and gRT->service_name inside SmiHandler function bool efi_analysis::EfiAnalyser::findSmmCallout() { msg("[%s] Looking for SMM callout\n", g_plugin_name); - if (!gBsList.size() && !gRtList.size()) { + if (!bs_list.size() && !rt_list.size()) { return false; } if (!smiHandlers.size() && !childSmiHandlers.size()) { @@ -2192,7 +2202,7 @@ bool efi_analysis::EfiAnalyser::findGetVariableOveflow(std::vector allServ if (insn.itype == NN_mov && insn.ops[0].type == o_reg && insn.ops[1].type == o_mem) { ea_t mem_addr = insn.ops[1].addr; - if (addrInVec(gBsList, mem_addr)) { + if (addr_in_vec(bs_list, mem_addr)) { wrong_detection = true; break; } @@ -2360,10 +2370,10 @@ bool efi_analysis::EfiAnalyser::AnalyseVariableService(ea_t ea, std::string serv insn.ops[1].type == o_mem) { msg("[%s] VariableName address: 0x%016llX\n", g_plugin_name, u64_addr(insn.ops[1].addr)); - std::string var_name = getWideString(insn.ops[1].addr); + std::string var_name = get_wide_string(insn.ops[1].addr); // retype CHAR16 to const CHAR16 to improve pseudocode quality - setConstChar16Type(insn.ops[1].addr); + set_const_char16_type(insn.ops[1].addr); msg("[%s] VariableName: %s\n", g_plugin_name, var_name.c_str()); item["VariableName"] = var_name; @@ -2377,7 +2387,7 @@ bool efi_analysis::EfiAnalyser::AnalyseVariableService(ea_t ea, std::string serv insn.ops[1].type == o_mem) { msg("[%s] VendorGuid address (global): 0x%016llX\n", g_plugin_name, u64_addr(insn.ops[1].addr)); - EfiGuid guid = getGlobalGuid(insn.ops[1].addr); + EfiGuid guid = get_global_guid(insn.ops[1].addr); msg("[%s] GUID: %s\n", g_plugin_name, guid.to_string().c_str()); item["VendorGuid"] = guid.to_string(); guid_found = true; @@ -2389,7 +2399,7 @@ bool efi_analysis::EfiAnalyser::AnalyseVariableService(ea_t ea, std::string serv case REG_RBP: { msg("[%s] VendorGuid address (regarding to RBP): 0x%016llX\n", g_plugin_name, u64_addr(insn.ops[1].addr)); - EfiGuid guid = getStackGuid(f, insn.ops[1].addr); + EfiGuid guid = get_local_guid(f, insn.ops[1].addr); msg("[%s] GUID: %s\n", g_plugin_name, guid.to_string().c_str()); item["VendorGuid"] = guid.to_string(); guid_found = true; @@ -2397,7 +2407,7 @@ bool efi_analysis::EfiAnalyser::AnalyseVariableService(ea_t ea, std::string serv case REG_RSP: { msg("[%s] VendorGuid address (regarding to RSP): 0x%016llX\n", g_plugin_name, u64_addr(insn.ops[1].addr)); - EfiGuid guid = getStackGuid(f, insn.ops[1].addr); + EfiGuid guid = get_local_guid(f, insn.ops[1].addr); msg("[%s] GUID: %s\n", g_plugin_name, guid.to_string().c_str()); item["VendorGuid"] = guid.to_string(); guid_found = true; @@ -2496,14 +2506,14 @@ bool efi_analysis::EfiAnalyser::efiSmmCpuProtocolResolver() { // Dump all info to JSON file void efi_analysis::EfiAnalyser::dumpInfo() { json info; - if (gStList.size()) { - info["gStList"] = gStList; + if (st_list.size()) { + info["st_list"] = st_list; } - if (gBsList.size()) { - info["gBsList"] = gBsList; + if (bs_list.size()) { + info["bs_list"] = bs_list; } - if (gRtList.size()) { - info["gRtList"] = gRtList; + if (rt_list.size()) { + info["rt_list"] = rt_list; } if (gSmstList.size()) { info["gSmstList"] = gSmstList; @@ -2692,9 +2702,9 @@ bool efi_analysis::efiAnalyserMainX64() { analyser.markInterfaces(); // search for copies of global variables - markCopiesForGlobalVars(gSmstList, "gSmst"); - markCopiesForGlobalVars(gBsList, "gBS"); - markCopiesForGlobalVars(gRtList, "gRT"); + mark_copies_for_gvars(gSmstList, "gSmst"); + mark_copies_for_gvars(bs_list, "gBS"); + mark_copies_for_gvars(rt_list, "gRT"); // search for vulnerabilities if (!g_args.disable_vuln_hunt) { @@ -2793,8 +2803,8 @@ bool efi_analysis::efiAnalyserMainX86() { #endif } else if (analyser.file_type == FfsFileType::Pei) { - setEntryArgToPeiSvc(); - addStrucForShiftedPtr(); + set_entry_arg_to_pei_svc(); + add_struct_for_shifted_ptr(); #ifdef HEX_RAYS for (auto addr : analyser.funcs) { DetectPeiServices(get_func(addr)); diff --git a/efiXplorer/efi_defs.cc b/efiXplorer/efi_defs.cc index 4924afcf..765f1287 100644 --- a/efiXplorer/efi_defs.cc +++ b/efiXplorer/efi_defs.cc @@ -21,7 +21,7 @@ const char *g_plugin_name = "efiXplorer"; -service_info_64_t bootServicesTable64[] = { +service_info_64_t g_boot_services_table64[] = { {"InstallProtocolInterface", InstallProtocolInterfaceOffset64, REG_RDX, 1}, {"ReinstallProtocolInterface", RenstallProtocolInterfaceOffset64, REG_RDX, 1}, {"UninstallProtocolInterface", UninstallProtocolInterfaceOffset64, REG_RDX, 1}, @@ -37,9 +37,10 @@ service_info_64_t bootServicesTable64[] = { REG_RDX, 1}, {"UninstallMultipleProtocolInterfaces", UninstallMultipleProtocolInterfacesOffset64, REG_RDX, 1}}; -size_t bootServicesTable64Count = sizeof(bootServicesTable64) / sizeof(service_info_64_t); +size_t g_boot_services_table64_count = + sizeof(g_boot_services_table64) / sizeof(service_info_64_t); -service_info_32_t bootServicesTable32[] = { +service_info_32_t g_boot_services_table32[] = { {"InstallProtocolInterface", InstallProtocolInterfaceOffset32, 2}, {"ReinstallProtocolInterface", RenstallProtocolInterfaceOffset32, 2}, {"UninstallProtocolInterface", UninstallProtocolInterfaceOffset32, 2}, @@ -54,9 +55,10 @@ service_info_32_t bootServicesTable32[] = { {"InstallMultipleProtocolInterfaces", InstallMultipleProtocolInterfacesOffset32, 2}, {"UninstallMultipleProtocolInterfaces", UninstallMultipleProtocolInterfacesOffset32, 2}}; -size_t bootServicesTable32Count = sizeof(bootServicesTable32) / sizeof(service_info_32_t); +size_t g_boot_services_table32_count = + sizeof(g_boot_services_table32) / sizeof(service_info_32_t); -service_t bootServicesTableAll[] = { +service_t g_boot_services_table_all[] = { // difficult to check false positives // {"RaiseTPL", RaiseTPLOffset64, RaiseTPLOffset32}, // {"RestoreTPL", RestoreTPLOffset64, RestoreTPLOffset32}, @@ -110,9 +112,10 @@ service_t bootServicesTableAll[] = { {"CopyMem", CopyMemOffset64, CopyMemOffset32}, {"SetMem", SetMemOffset64, SetMemOffset32}, {"CreateEventEx", CreateEventExOffset64, CreateEventExOffset32}}; -size_t bootServicesTableAllCount = sizeof(bootServicesTableAll) / sizeof(service_t); +size_t g_boot_services_table_all_count = + sizeof(g_boot_services_table_all) / sizeof(service_t); -service_t runtimeServicesTableAll[] = { +service_t g_runtime_services_table_all[] = { {"GetTime", GetTimeOffset64, GetTimeOffset32}, {"SetTime", SetTimeOffset64, SetTimeOffset32}, {"GetWakeupTime", GetWakeupTimeOffset64, GetWakeupTimeOffset32}, @@ -129,18 +132,20 @@ service_t runtimeServicesTableAll[] = { {"QueryCapsuleCapabilities", QueryCapsuleCapabilitiesOffset64, QueryCapsuleCapabilitiesOffset32}, {"QueryVariableInfo", QueryVariableInfoOffset64, QueryVariableInfoOffset32}}; -size_t runtimeServicesTableAllCount = sizeof(runtimeServicesTableAll) / sizeof(service_t); +size_t g_runtime_services_table_all_count = + sizeof(g_runtime_services_table_all) / sizeof(service_t); -service_info_64_t smmServicesProt64[] = { +service_info_64_t g_smm_services_prot64[] = { {"SmmInstallProtocolInterface", SmmInstallProtocolInterfaceOffset64, REG_RDX}, {"SmmUninstallProtocolInterface", SmmUninstallProtocolInterfaceOffset64, REG_RDX}, {"SmmHandleProtocol", SmmHandleProtocolOffset64, REG_RDX}, {"SmmRegisterProtocolNotify", SmmRegisterProtocolNotifyOffset64, REG_RCX}, {"SmmLocateHandle", SmmLocateHandleOffset64, REG_RDX}, {"SmmLocateProtocol", SmmLocateProtocolOffset64, REG_RCX}}; -size_t smmServicesProt64Count = sizeof(smmServicesProt64) / sizeof(service_info_64_t); +size_t g_smm_services_prot64_count = + sizeof(g_smm_services_prot64) / sizeof(service_info_64_t); -service_t smmServicesTableAll[] = { +service_t g_smm_services_table_all[] = { {"SmmInstallConfigurationTable", SmmInstallConfigurationTableOffset64, SmmInstallConfigurationTableOffset32}, {"SmmAllocatePool", SmmAllocatePoolOffset64, SmmAllocatePoolOffset32}, @@ -160,65 +165,70 @@ service_t smmServicesTableAll[] = { {"SmiManage", SmiManageOffset64, SmiManageOffset32}, {"SmiHandlerRegister", SmiHandlerRegisterOffset64, SmiHandlerRegisterOffset32}, {"SmiHandlerUnRegister", SmiHandlerUnRegisterOffset64, SmiHandlerUnRegisterOffset32}}; -size_t smmServicesTableAllCount = sizeof(smmServicesTableAll) / sizeof(service_t); +size_t g_smm_services_table_all_count = + sizeof(g_smm_services_table_all) / sizeof(service_t); -service_info_32_t peiServicesTable32[] = {{"InstallPpi", 0x18, 2}, - {"ReInstallPpi", 0x1c, 3}, - {"LocatePpi", 0x20, 2}, - {"NotifyPpi", 0x24, PUSH_NONE}, - {"GetBootMode", 0x28, PUSH_NONE}, - {"SetBootMode", 0x2c, PUSH_NONE}, - {"GetHobList", 0x30, PUSH_NONE}, - {"CreateHob", 0x34, PUSH_NONE}, - {"FfsFindNextVolume", 0x38, PUSH_NONE}, - {"FfsFindNextFile", 0x3c, PUSH_NONE}, - {"FfsFindSectionData", 0x40, PUSH_NONE}, - {"InstallPeiMemory", 0x44, PUSH_NONE}, - {"AllocatePages", 0x48, PUSH_NONE}, - {"AllocatePool", 0x4c, PUSH_NONE}, - {"CopyMem", 0x50, PUSH_NONE}, - {"SetMem", 0x54, PUSH_NONE}, - {"ReportStatusCode", 0x58, PUSH_NONE}, - {"ResetSystem", 0x5c, PUSH_NONE}, - {"CpuIo", 0x60, PUSH_NONE}, - {"PciCfg", 0x64, PUSH_NONE}, - {"FfsFindFileByName", 0x68, PUSH_NONE}, - {"FfsGetFileInfo", 0x6c, PUSH_NONE}, - {"FfsGetVolumeInfo", 0x70, PUSH_NONE}, - {"RegisterForShadow", 0x74, PUSH_NONE}, - {"FindSectionData3", 0x78, PUSH_NONE}, - {"FfsGetFileInfo2", 0x7c, PUSH_NONE}, - {"ResetSystem2", 0x80, PUSH_NONE}}; -size_t peiServicesTable32Count = sizeof(peiServicesTable32) / sizeof(service_info_32_t); +service_info_32_t g_pei_services_table32[] = {{"InstallPpi", 0x18, 2}, + {"ReInstallPpi", 0x1c, 3}, + {"LocatePpi", 0x20, 2}, + {"NotifyPpi", 0x24, PUSH_NONE}, + {"GetBootMode", 0x28, PUSH_NONE}, + {"SetBootMode", 0x2c, PUSH_NONE}, + {"GetHobList", 0x30, PUSH_NONE}, + {"CreateHob", 0x34, PUSH_NONE}, + {"FfsFindNextVolume", 0x38, PUSH_NONE}, + {"FfsFindNextFile", 0x3c, PUSH_NONE}, + {"FfsFindSectionData", 0x40, PUSH_NONE}, + {"InstallPeiMemory", 0x44, PUSH_NONE}, + {"AllocatePages", 0x48, PUSH_NONE}, + {"AllocatePool", 0x4c, PUSH_NONE}, + {"CopyMem", 0x50, PUSH_NONE}, + {"SetMem", 0x54, PUSH_NONE}, + {"ReportStatusCode", 0x58, PUSH_NONE}, + {"ResetSystem", 0x5c, PUSH_NONE}, + {"CpuIo", 0x60, PUSH_NONE}, + {"PciCfg", 0x64, PUSH_NONE}, + {"FfsFindFileByName", 0x68, PUSH_NONE}, + {"FfsGetFileInfo", 0x6c, PUSH_NONE}, + {"FfsGetVolumeInfo", 0x70, PUSH_NONE}, + {"RegisterForShadow", 0x74, PUSH_NONE}, + {"FindSectionData3", 0x78, PUSH_NONE}, + {"FfsGetFileInfo2", 0x7c, PUSH_NONE}, + {"ResetSystem2", 0x80, PUSH_NONE}}; +size_t g_pei_services_table32_count = + sizeof(g_pei_services_table32) / sizeof(service_info_32_t); -service_t peiServicesTableAll[] = {{"InstallPpi", 0x18, 0x18}, - {"ReInstallPpi", 0x20, 0x1c}, - {"LocatePpi", 0x28, 0x20}, - {"NotifyPpi", 0x30, 0x24}, - {"GetBootMode", 0x38, 0x28}, - {"SetBootMode", 0x40, 0x2c}, - {"GetHobList", 0x48, 0x30}, - {"CreateHob", 0x50, 0x34}, - {"FfsFindNextVolume", 0x58, 0x38}, - {"FfsFindNextFile", 0x60, 0x3c}, - {"FfsFindSectionData", 0x68, 0x40}, - {"InstallPeiMemory", 0x70, 0x44}, - {"AllocatePages", 0x78, 0x48}, - {"AllocatePool", 0x80, 0x4c}, - {"CopyMem", 0x88, 0x50}, - {"SetMem", 0x90, 0x54}, - {"ReportStatusCode", 0x98, 0x58}, - {"ResetSystem", 0xa0, 0x5c}, - {"CpuIo", 0xa8, 0x60}, - {"PciCfg", 0xb0, 0x64}, - {"FfsFindFileByName", 0xb8, 0x68}, - {"FfsGetFileInfo", 0xc0, 0x6c}, - {"FfsGetVolumeInfo", 0xc8, 0x70}, - {"RegisterForShadow", 0xd0, 0x74}, - {"FindSectionData3", 0xc8, 0x78}, - {"FfsGetFileInfo2", 0xe0, 0x7c}, - {"ResetSystem2", 0xe8, 0x80}}; -size_t peiServicesTableAllCount = sizeof(peiServicesTableAll) / sizeof(service_t); +service_t g_pei_services_table_all[] = {{"InstallPpi", 0x18, 0x18}, + {"ReInstallPpi", 0x20, 0x1c}, + {"LocatePpi", 0x28, 0x20}, + {"NotifyPpi", 0x30, 0x24}, + {"GetBootMode", 0x38, 0x28}, + {"SetBootMode", 0x40, 0x2c}, + {"GetHobList", 0x48, 0x30}, + {"CreateHob", 0x50, 0x34}, + {"FfsFindNextVolume", 0x58, 0x38}, + {"FfsFindNextFile", 0x60, 0x3c}, + {"FfsFindSectionData", 0x68, 0x40}, + {"InstallPeiMemory", 0x70, 0x44}, + {"AllocatePages", 0x78, 0x48}, + {"AllocatePool", 0x80, 0x4c}, + {"CopyMem", 0x88, 0x50}, + {"SetMem", 0x90, 0x54}, + {"ReportStatusCode", 0x98, 0x58}, + {"ResetSystem", 0xa0, 0x5c}, + {"CpuIo", 0xa8, 0x60}, + {"PciCfg", 0xb0, 0x64}, + {"FfsFindFileByName", 0xb8, 0x68}, + {"FfsGetFileInfo", 0xc0, 0x6c}, + {"FfsGetVolumeInfo", 0xc8, 0x70}, + {"RegisterForShadow", 0xd0, 0x74}, + {"FindSectionData3", 0xc8, 0x78}, + {"FfsGetFileInfo2", 0xe0, 0x7c}, + {"ResetSystem2", 0xe8, 0x80}}; +size_t g_pei_services_table_all_count = + sizeof(g_pei_services_table_all) / sizeof(service_t); -service_t variablePpiTableAll[] = {{"GetVariable", 0, 0}, {"NextVariableName", 8, 4}}; -size_t variablePpiTableAllCount = sizeof(variablePpiTableAll) / sizeof(service_t); +service_t g_variable_ppi_table_all[] = {{"GetVariable", 0, 0}, + {"NextVariableName", 8, 4}}; +size_t g_variable_ppi_table_all_count = + sizeof(g_variable_ppi_table_all) / sizeof(service_t); diff --git a/efiXplorer/efi_defs.h b/efiXplorer/efi_defs.h index 1a1eef4f..f265a73c 100644 --- a/efiXplorer/efi_defs.h +++ b/efiXplorer/efi_defs.h @@ -299,31 +299,31 @@ enum SmmServicesOffsets32 { SmiHandlerUnRegisterOffset32 = 0x80, }; -extern service_info_64_t bootServicesTable64[]; -extern size_t bootServicesTable64Count; +extern service_info_64_t g_boot_services_table64[]; +extern size_t g_boot_services_table64_count; -extern service_info_32_t bootServicesTable32[]; -extern size_t bootServicesTable32Count; +extern service_info_32_t g_boot_services_table32[]; +extern size_t g_boot_services_table32_count; -extern service_t bootServicesTableAll[]; -extern size_t bootServicesTableAllCount; +extern service_t g_boot_services_table_all[]; +extern size_t g_boot_services_table_all_count; -extern service_t runtimeServicesTableAll[]; -extern size_t runtimeServicesTableAllCount; +extern service_t g_runtime_services_table_all[]; +extern size_t g_runtime_services_table_all_count; -extern service_info_64_t smmServicesProt64[]; -extern size_t smmServicesProt64Count; +extern service_info_64_t g_smm_services_prot64[]; +extern size_t g_smm_services_prot64_count; -extern service_t smmServicesTableAll[]; -extern size_t smmServicesTableAllCount; +extern service_t g_smm_services_table_all[]; +extern size_t g_smm_services_table_all_count; -extern service_info_32_t peiServicesTable32[]; -extern size_t peiServicesTable32Count; +extern service_info_32_t g_pei_services_table32[]; +extern size_t g_pei_services_table32_count; -extern service_t peiServicesTableAll[]; -extern size_t peiServicesTableAllCount; +extern service_t g_pei_services_table_all[]; +extern size_t g_pei_services_table_all_count; -extern service_t variablePpiTableAll[]; -extern size_t variablePpiTableAllCount; +extern service_t g_variable_ppi_table_all[]; +extern size_t g_variable_ppi_table_all_count; extern const char *g_plugin_name; diff --git a/efiXplorer/efi_deps.cc b/efiXplorer/efi_deps.cc index d5d23495..4fc68465 100644 --- a/efiXplorer/efi_deps.cc +++ b/efiXplorer/efi_deps.cc @@ -51,9 +51,9 @@ json EfiDependencies::getDeps(std::string guid) { if (p["guid"] != guid) { continue; } - p["ea"] = getHex(u64_addr(p["ea"])); - p["xref"] = getHex(u64_addr(p["xref"])); - p["address"] = getHex(u64_addr(p["address"])); + p["ea"] = as_hex(u64_addr(p["ea"])); + p["xref"] = as_hex(u64_addr(p["xref"])); + p["address"] = as_hex(u64_addr(p["address"])); if (find(installers.begin(), installers.end(), p["service"]) != installers.end()) { res["installed"].push_back(p); } else { @@ -139,22 +139,22 @@ void EfiDependencies::getProtocolsWithoutInstallers() { void EfiDependencies::getInstallersModules() { // search for this protocols in binary for (auto &protocol : protocolsWithoutInstallers) { - auto addrs = searchProtocol(protocol); + auto addrs = search_protocol(protocol); bool installerFound = false; for (auto addr : addrs) { - auto xrefs = getXrefs(addr); + auto xrefs = get_xrefs_util(addr); if (!xrefs.size()) { continue; } if (xrefs.size() == 1) { func_t *func = get_func(xrefs.at(0)); if (func == nullptr) { - xrefs = getXrefsToArray(xrefs.at(0)); + xrefs = get_xrefs_to_array(xrefs.at(0)); } } for (auto ea : xrefs) { - if (checkInstallProtocol(ea)) { - auto module = getModuleNameLoader(ea); + if (check_install_protocol(ea)) { + auto module = get_module_name_loader(ea); additionalInstallers[protocol] = static_cast(module.c_str()); installerFound = true; break; diff --git a/efiXplorer/efi_hexrays.cc b/efiXplorer/efi_hexrays.cc index 60681cd3..e388d569 100644 --- a/efiXplorer/efi_hexrays.cc +++ b/efiXplorer/efi_hexrays.cc @@ -72,19 +72,19 @@ bool setHexRaysVariableInfoAndHandleInterfaces(ea_t func_addr, lvar_t &ll, tinfo } // Get xrefs to local variable - xreflist_t xrefs = xrefsToStackVar(func_addr, static_cast(name.c_str())); - qstring typeName; + xreflist_t xrefs = xrefs_to_stack_var(func_addr, static_cast(name.c_str())); + qstring type_name; ptr_type_data_t pi; tif.get_ptr_details(&pi); - pi.obj_type.get_type_name(&typeName); + pi.obj_type.get_type_name(&type_name); // Handling all interface functions (to rename function arguments) - opstroffForInterface(xrefs, typeName); + op_stroff_for_interface(xrefs, type_name); return true; } // Utility function to set a Hex-Rays variable name -bool setLvarName(qstring name, lvar_t lvar, ea_t func_addr) { +bool setLvar_name(qstring name, lvar_t lvar, ea_t func_addr) { lvar_saved_info_t lsi; lvar_uservec_t lvuv; @@ -355,9 +355,9 @@ json DetectVars(func_t *f) { vars_detector.apply_to(&cfunc->body, nullptr); res["gImageHandleList"] = vars_detector.gImageHandleList; - res["gStList"] = vars_detector.gStList; - res["gBsList"] = vars_detector.gBsList; - res["gRtList"] = vars_detector.gRtList; + res["st_list"] = vars_detector.st_list; + res["bs_list"] = vars_detector.bs_list; + res["rt_list"] = vars_detector.rt_list; return res; } diff --git a/efiXplorer/efi_hexrays.h b/efiXplorer/efi_hexrays.h index 678ec447..67d8ad5b 100644 --- a/efiXplorer/efi_hexrays.h +++ b/efiXplorer/efi_hexrays.h @@ -27,11 +27,11 @@ json DetectVars(func_t *f); std::vector DetectServices(func_t *f); std::vector DetectPeiServicesArm(func_t *f); bool DetectPeiServices(func_t *f); -bool setLvarName(qstring name, lvar_t lvar, ea_t func_addr); +bool setLvar_name(qstring name, lvar_t lvar, ea_t func_addr); bool applyAllTypesForInterfacesBootServices(std::vector guids); bool applyAllTypesForInterfacesSmmServices(std::vector guids); // unused -bool setHexRaysVariableInfo(ea_t funcEa, lvar_t &ll, tinfo_t tif, std::string name); -bool setHexRaysVariableInfoAndHandleInterfaces(ea_t funcEa, lvar_t &ll, tinfo_t tif, +bool setHexRaysVariableInfo(ea_t func_addr, lvar_t &ll, tinfo_t tif, std::string name); +bool setHexRaysVariableInfoAndHandleInterfaces(ea_t func_addr, lvar_t &ll, tinfo_t tif, std::string name); bool offsetOf(tinfo_t tif, const char *name, unsigned int *offset); bool isPODArray(tinfo_t tif, unsigned int ptrDepth); @@ -560,17 +560,17 @@ class GUIDRetyper : public GUIDRelatedVisitorBase { ++mNumApplied; // Rename global variable - auto name = "g" + typeToName(static_cast(tStr.c_str())); + auto name = "g" + type_to_name(static_cast(tStr.c_str())); set_name(dest_ea, name.c_str(), SN_FORCE); // Get xrefs to global variable - auto xrefs = getXrefs(dest_ea); - qstring typeName; + auto xrefs = get_xrefs_util(dest_ea); + qstring type_name; ptr_type_data_t pi; ptrTif.get_ptr_details(&pi); - pi.obj_type.get_type_name(&typeName); + pi.obj_type.get_type_name(&type_name); // Handling all interface functions (to rename function arguments) - opstroffForGlobalInterface(xrefs, typeName); + op_stroff_for_global_interface(xrefs, type_name); } // For local variables @@ -578,8 +578,8 @@ class GUIDRetyper : public GUIDRelatedVisitorBase { var_ref_t varRef = outArg->v; lvar_t &destVar = varRef.mba->vars[varRef.idx]; // Set the Hex-Rays variable type - auto name = typeToName(static_cast(tStr.c_str())); - setLvarName(static_cast(name.c_str()), destVar, mFuncEa); + auto name = type_to_name(static_cast(tStr.c_str())); + setLvar_name(static_cast(name.c_str()), destVar, mFuncEa); if (setHexRaysVariableInfoAndHandleInterfaces(mFuncEa, destVar, ptrTif, name)) { ++mNumApplied; } @@ -592,7 +592,7 @@ class GUIDRetyper : public GUIDRelatedVisitorBase { // For global variables if (outArg->op == cot_obj) { // Rename global variable - auto name = "g" + typeToName(type_name); + auto name = "g" + type_to_name(type_name); set_name(dest_ea, name.c_str(), SN_FORCE); } @@ -601,8 +601,8 @@ class GUIDRetyper : public GUIDRelatedVisitorBase { var_ref_t varRef = outArg->v; lvar_t &destVar = varRef.mba->vars[varRef.idx]; // Set the Hex-Rays variable type - auto name = typeToName(type_name); - setLvarName(static_cast(name.c_str()), destVar, mFuncEa); + auto name = type_to_name(type_name); + setLvar_name(static_cast(name.c_str()), destVar, mFuncEa); } } }; @@ -731,7 +731,7 @@ class PrototypesFixer : public ctree_visitor_t { if (type_name == qstring("EFI_HANDLE") || type_name == qstring("EFI_SYSTEM_TABLE")) { - if (!addrInVec(child_functions, func_addr)) { + if (!addr_in_vec(child_functions, func_addr)) { child_functions.push_back(func_addr); } // set argument type and name @@ -764,9 +764,9 @@ class VariablesDetector : public ctree_visitor_t { std::vector child_functions; std::vector gImageHandleList; - std::vector gStList; - std::vector gBsList; - std::vector gRtList; + std::vector st_list; + std::vector bs_list; + std::vector rt_list; void SetFuncEa(ea_t ea) { mFuncEa = ea; }; @@ -775,7 +775,7 @@ class VariablesDetector : public ctree_visitor_t { int visit_expr(cexpr_t *e) { if (e->op == cot_asg) { // saving a child function for recursive analysis - if (!addrInVec(child_functions, e->ea)) { + if (!addr_in_vec(child_functions, e->ea)) { child_functions.push_back(e->x->obj_ea); } } @@ -837,27 +837,27 @@ class VariablesDetector : public ctree_visitor_t { ea_t g_addr = e->x->obj_ea; std::string type_name_str = static_cast(type_name.c_str()); if (type_name == qstring("EFI_HANDLE")) { - setTypeAndName(g_addr, "gImageHandle", type_name_str); - if (!addrInVec(gImageHandleList, g_addr)) { + set_type_and_name(g_addr, "gImageHandle", type_name_str); + if (!addr_in_vec(gImageHandleList, g_addr)) { gImageHandleList.push_back(g_addr); } } if (type_name == qstring("EFI_SYSTEM_TABLE")) { - setPtrTypeAndName(g_addr, "gST", type_name_str); - if (!addrInVec(gStList, g_addr)) { - gStList.push_back(g_addr); + set_ptr_type_and_name(g_addr, "gST", type_name_str); + if (!addr_in_vec(st_list, g_addr)) { + st_list.push_back(g_addr); } } if (type_name == qstring("EFI_BOOT_SERVICES")) { - setPtrTypeAndName(g_addr, "gBS", type_name_str); - if (!addrInVec(gBsList, g_addr)) { - gBsList.push_back(g_addr); + set_ptr_type_and_name(g_addr, "gBS", type_name_str); + if (!addr_in_vec(bs_list, g_addr)) { + bs_list.push_back(g_addr); } } if (type_name == qstring("EFI_RUNTIME_SERVICES")) { - setPtrTypeAndName(g_addr, "gRT", type_name_str); - if (!addrInVec(gRtList, g_addr)) { - gRtList.push_back(g_addr); + set_ptr_type_and_name(g_addr, "gRT", type_name_str); + if (!addr_in_vec(rt_list, g_addr)) { + rt_list.push_back(g_addr); } } } @@ -872,7 +872,7 @@ class VariablesDetector : public ctree_visitor_t { } lvar_t &dest_var = var_ref.mba->vars[var_ref.idx]; // Set the Hex-Rays variable type - auto name = typeToName(static_cast(type_name.c_str())); + auto name = type_to_name(static_cast(type_name.c_str())); // setHexRaysVariableInfo(mFuncEa, dest_var, var_type, name); } @@ -922,7 +922,7 @@ class ServicesDetector : public ctree_visitor_t { is_ptr = 0; } - auto service_name = typeToName(static_cast(type_name.c_str())); + auto service_name = type_to_name(static_cast(type_name.c_str())); if (service_name.rfind("Efi", 0) == 0) { service_name = service_name.substr(3); if (service_name == "RaiseTpl") { @@ -940,9 +940,9 @@ class ServicesDetector : public ctree_visitor_t { json s; s["address"] = e->ea; s["service_name"] = service_name; - s["table_name"] = getTable(service_name); + s["table_name"] = get_table_name(service_name); - if (!jsonInVec(services, s)) { + if (!json_in_vec(services, s)) { services.push_back(s); } @@ -1035,7 +1035,7 @@ class PeiServicesDetector : public ctree_visitor_t { } if (call) { - opStroff(e->ea, "EFI_PEI_SERVICES"); + op_stroff_util(e->ea, "EFI_PEI_SERVICES"); } return 0; @@ -1084,7 +1084,7 @@ class PeiServicesDetectorArm : public ctree_visitor_t { if (func_type.substr(0, prefix.length()) == prefix) { func_type.erase(0, prefix.length()); } - service_name = typeToName(func_type); + service_name = type_to_name(func_type); } else { auto s = mPeiServices.find(offset); if (s == mPeiServices.end()) { @@ -1103,7 +1103,7 @@ class PeiServicesDetectorArm : public ctree_visitor_t { s["service_name"] = service_name; s["table_name"] = table_type_name.c_str(); - if (!jsonInVec(services, s)) { + if (!json_in_vec(services, s)) { services.push_back(s); } diff --git a/efiXplorer/efi_smm_utils.cc b/efiXplorer/efi_smm_utils.cc index 35ea0b1c..99b099de 100644 --- a/efiXplorer/efi_smm_utils.cc +++ b/efiXplorer/efi_smm_utils.cc @@ -22,7 +22,7 @@ //-------------------------------------------------------------------------- // Find and mark gSmst global variable via EFI_SMM_SW_DISPATCH(2)_PROTOCOL_GUID -std::vector findSmstSwDispatch(std::vector gBsList) { +std::vector findSmstSwDispatch(std::vector bs_list) { std::vector smst_addrs; EfiGuid guid2 = {0x18a3c6dc, 0x5eea, @@ -34,13 +34,13 @@ std::vector findSmstSwDispatch(std::vector gBsList) { 0x420c, {0xb0, 0x26, 0xdf, 0x99, 0x36, 0x53, 0xf8, 0xbf}}; // EFI_SMM_SW_DISPATCH_PROTOCOL_GUID - std::vector data_addrs = findData(0, BADADDR, guid.uchar_data().data(), 16); - std::vector data2_addrs = findData(0, BADADDR, guid2.uchar_data().data(), 16); + std::vector data_addrs = find_data(0, BADADDR, guid.uchar_data().data(), 16); + std::vector data2_addrs = find_data(0, BADADDR, guid2.uchar_data().data(), 16); data_addrs.insert(data_addrs.end(), data2_addrs.begin(), data2_addrs.end()); for (auto data_addr : data_addrs) { msg("[%s] EFI_SMM_SW_DISPATCH(2)_PROTOCOL_GUID: 0x%016llX\n", g_plugin_name, u64_addr(data_addr)); - std::vector xrefs = getXrefs(data_addr); + std::vector xrefs = get_xrefs_util(data_addr); insn_t insn; for (auto xref : xrefs) { uint16_t smst_reg = 0xffff; // Smst register @@ -73,11 +73,11 @@ std::vector findSmstSwDispatch(std::vector gBsList) { msg("[%s] found gSmst at 0x%016llX, address = 0x%016llX\n", g_plugin_name, u64_addr(cur_addr), u64_addr(insn.ops[1].addr)); res_addr = insn.ops[1].addr; - if (addrInVec(gBsList, res_addr)) { + if (addr_in_vec(bs_list, res_addr)) { continue; } set_cmt(cur_addr, "_EFI_SMM_SYSTEM_TABLE2 *gSmst;", true); - setPtrTypeAndName(res_addr, "gSmst", "_EFI_SMM_SYSTEM_TABLE2"); + set_ptr_type_and_name(res_addr, "gSmst", "_EFI_SMM_SYSTEM_TABLE2"); smst_addrs.push_back(res_addr); break; } @@ -93,18 +93,18 @@ std::vector findSmstSwDispatch(std::vector gBsList) { //-------------------------------------------------------------------------- // Find and mark gSmst global variable via EFI_SMM_BASE2_PROTOCOL_GUID -std::vector findSmstSmmBase(std::vector gBsList) { +std::vector findSmstSmmBase(std::vector bs_list) { std::vector smst_addrs; EfiGuid guid = { 0xf4ccbfb7, 0xf6e0, 0x47fd, {0x9d, 0xd4, 0x10, 0xa8, 0xf1, 0x50, 0xc1, 0x91}}; // EFI_SMM_BASE2_PROTOCOL_GUID - std::vector data_addrs = findData(0, BADADDR, guid.uchar_data().data(), 16); + std::vector data_addrs = find_data(0, BADADDR, guid.uchar_data().data(), 16); for (auto data_addr : data_addrs) { msg("[%s] EFI_SMM_BASE2_PROTOCOL_GUID: 0x%016llX\n", g_plugin_name, u64_addr(data_addr)); - std::vector data_xrefs = getXrefs(data_addr); + std::vector data_xrefs = get_xrefs_util(data_addr); insn_t insn; for (auto xref : data_xrefs) { ea_t res_addr = BADADDR; @@ -128,15 +128,15 @@ std::vector findSmstSmmBase(std::vector gBsList) { } if (!in_smram) { // we found gSmst - if (addrInVec(gBsList, res_addr)) { + if (addr_in_vec(bs_list, res_addr)) { continue; } set_cmt(cur_addr, "_EFI_SMM_SYSTEM_TABLE2 *gSmst;", true); - setPtrTypeAndName(res_addr, "gSmst", "_EFI_SMM_SYSTEM_TABLE2"); + set_ptr_type_and_name(res_addr, "gSmst", "_EFI_SMM_SYSTEM_TABLE2"); smst_addrs.push_back(res_addr); } else { // we found gInSmram - setTypeAndName(res_addr, "gInSmram", "BOOLEAN"); + set_type_and_name(res_addr, "gInSmram", "BOOLEAN"); } } } @@ -289,7 +289,7 @@ std::vector findSmiHandlers(ea_t address, std::string prefix) { std::string prefix_upper; std::transform(prefix.begin(), prefix.end(), prefix_upper.begin(), ::toupper); std::string type = "EFI_SMM_" + prefix_upper + "_DISPATCH2_PROTOCOL"; - opStroff(ea, type); + op_stroff_util(ea, type); } if (insn.itype == NN_retn || insn.itype == NN_int3) { @@ -312,10 +312,10 @@ std::vector findSmiHandlers(ea_t address, std::string prefix) { // call qword ptr [...] std::vector findSmiHandlersSmmDispatch(EfiGuid guid, std::string prefix) { std::vector smiHandlers; - std::vector data_addrs = findData(0, BADADDR, guid.uchar_data().data(), 16); + std::vector data_addrs = find_data(0, BADADDR, guid.uchar_data().data(), 16); msg("[%s] %sSmiHandler function finding\n", g_plugin_name, prefix.c_str()); for (auto data_addr : data_addrs) { - std::vector xrefs = getXrefs(data_addr); + std::vector xrefs = get_xrefs_util(data_addr); for (auto xref : xrefs) { msg("[%s] findSmiHandlers: 0x%016llX\n", g_plugin_name, u64_addr(xref)); @@ -369,10 +369,10 @@ std::vector findSmmGetVariableCalls(std::vector dataSegments, {0x9c, 0xc0, 0x2d, 0x72, 0xcd, 0xd9, 0x98, 0xa7}}; // EFI_SMM_VARIABLE_PROTOCOL_GUID // Find all EFI_GUID EFI_SMM_VARIABLE_PROTOCOL_GUID addresses - std::vector data_addrs = findData(0, BADADDR, guid.uchar_data().data(), 16); + std::vector data_addrs = find_data(0, BADADDR, guid.uchar_data().data(), 16); std::vector gSmmVarAddrs; // Find all gSmmVar variables for (auto data_addr : data_addrs) { - std::vector xrefs = getXrefs(data_addr); + std::vector xrefs = get_xrefs_util(data_addr); for (auto xref : xrefs) { segment_t *seg = getseg(static_cast(xref)); @@ -398,7 +398,7 @@ std::vector findSmmGetVariableCalls(std::vector dataSegments, msg("[%s] gSmmVar address: 0x%016llX\n", g_plugin_name, u64_addr(insn.ops[1].addr)); set_cmt(ea, "EFI_SMM_VARIABLE_PROTOCOL *gSmmVar", true); - setPtrTypeAndName(insn.ops[1].addr, "gSmmVar", "EFI_SMM_VARIABLE_PROTOCOL"); + set_ptr_type_and_name(insn.ops[1].addr, "gSmmVar", "EFI_SMM_VARIABLE_PROTOCOL"); gSmmVarAddrs.push_back(insn.ops[1].addr); break; } @@ -412,7 +412,7 @@ std::vector findSmmGetVariableCalls(std::vector dataSegments, } for (auto smmVarAddr : gSmmVarAddrs) { - std::vector smmVarXrefs = getXrefs(static_cast(smmVarAddr)); + std::vector smmVarXrefs = get_xrefs_util(static_cast(smmVarAddr)); for (auto smmVarXref : smmVarXrefs) { segment_t *seg = getseg(static_cast(smmVarXref)); qstring seg_name; @@ -450,7 +450,7 @@ std::vector findSmmGetVariableCalls(std::vector dataSegments, // Temporarily add a "virtual" smm service call // for easier annotations and UI - opStroff(ea, "EFI_SMM_VARIABLE_PROTOCOL"); + op_stroff_util(ea, "EFI_SMM_VARIABLE_PROTOCOL"); msg("[%s] 0x%016llX : %s\n", g_plugin_name, u64_addr(ea), "SmmGetVariable"); std::string smm_call = "gSmmVar->SmmGetVariable"; json smm_item; @@ -479,7 +479,7 @@ std::vector resolveEfiSmmCpuProtocol(std::vector stackGuids, std::vector *allServices) { std::vector readSaveStateCalls; msg("[%s] Looking for EFI_SMM_CPU_PROTOCOL\n", g_plugin_name); - std::vector codeAddrs; + std::vector code_addrs; std::vector gSmmCpuAddrs; for (auto guid : stackGuids) { std::string name = static_cast(guid["name"]); @@ -488,7 +488,7 @@ std::vector resolveEfiSmmCpuProtocol(std::vector stackGuids, ea_t address = static_cast(guid["address"]); msg("[%s] found EFI_SMM_CPU_PROTOCOL on stack: 0x%016llX\n", g_plugin_name, u64_addr(address)); - codeAddrs.push_back(address); + code_addrs.push_back(address); } for (auto guid : dataGuids) { @@ -498,7 +498,7 @@ std::vector resolveEfiSmmCpuProtocol(std::vector stackGuids, ea_t address = static_cast(guid["address"]); msg("[%s] found EFI_SMM_CPU_PROTOCOL: 0x%016llX\n", g_plugin_name, u64_addr(address)); - std::vector guidXrefs = getXrefs(address); + std::vector guidXrefs = get_xrefs_util(address); for (auto guidXref : guidXrefs) { segment_t *seg = getseg(static_cast(guidXref)); @@ -508,11 +508,11 @@ std::vector resolveEfiSmmCpuProtocol(std::vector stackGuids, if (index == std::string::npos) { continue; } - codeAddrs.push_back(static_cast(guidXref)); + code_addrs.push_back(static_cast(guidXref)); } } - for (auto addr : codeAddrs) { + for (auto addr : code_addrs) { msg("[%s] current address: 0x%016llX\n", g_plugin_name, u64_addr(addr)); insn_t insn; ea_t ea = prev_head(addr, 0); @@ -525,7 +525,7 @@ std::vector resolveEfiSmmCpuProtocol(std::vector stackGuids, msg("[%s] gSmmCpu address: 0x%016llX\n", g_plugin_name, u64_addr(insn.ops[1].addr)); set_cmt(ea, "EFI_SMM_CPU_PROTOCOL *gSmmCpu", true); - setPtrTypeAndName(insn.ops[1].addr, "gSmmCpu", "EFI_SMM_CPU_PROTOCOL"); + set_ptr_type_and_name(insn.ops[1].addr, "gSmmCpu", "EFI_SMM_CPU_PROTOCOL"); gSmmCpuAddrs.push_back(insn.ops[1].addr); break; } @@ -539,7 +539,7 @@ std::vector resolveEfiSmmCpuProtocol(std::vector stackGuids, } for (auto smmCpu : gSmmCpuAddrs) { - std::vector smmCpuXrefs = getXrefs(static_cast(smmCpu)); + std::vector smmCpuXrefs = get_xrefs_util(static_cast(smmCpu)); for (auto smmCpuXref : smmCpuXrefs) { segment_t *seg = getseg(static_cast(smmCpuXref)); @@ -571,7 +571,7 @@ std::vector resolveEfiSmmCpuProtocol(std::vector stackGuids, readSaveStateCalls.push_back(ea); } - opStroff(ea, "EFI_SMM_CPU_PROTOCOL"); + op_stroff_util(ea, "EFI_SMM_CPU_PROTOCOL"); msg("[%s] 0x%016llX : %s\n", g_plugin_name, u64_addr(ea), "gSmmCpu->ReadSaveState"); std::string smm_call = "gSmmCpu->ReadSaveState"; diff --git a/efiXplorer/efi_smm_utils.h b/efiXplorer/efi_smm_utils.h index 067b1298..61e46761 100644 --- a/efiXplorer/efi_smm_utils.h +++ b/efiXplorer/efi_smm_utils.h @@ -21,8 +21,8 @@ #include "efi_utils.h" -std::vector findSmstSwDispatch(std::vector gBsList); -std::vector findSmstSmmBase(std::vector gBsList); +std::vector findSmstSwDispatch(std::vector bs_list); +std::vector findSmstSmmBase(std::vector bs_list); std::vector findSmiHandlers(ea_t address, std::string prefix); std::vector findSmiHandlersSmmDispatch(EfiGuid guid, std::string prefix); std::vector findSmiHandlersSmmDispatchStack(std::vector stackGuids, diff --git a/efiXplorer/efi_utils.cc b/efiXplorer/efi_utils.cc index c8fc022c..e7c1326f 100644 --- a/efiXplorer/efi_utils.cc +++ b/efiXplorer/efi_utils.cc @@ -27,8 +27,8 @@ std::vector g_smm_get_variable_calls; std::vector g_smm_set_variable_calls; //-------------------------------------------------------------------------- -// Set EFI_GUID type -void setGuidType(ea_t ea) { +// set EFI_GUID type +void set_guid_type(ea_t ea) { tinfo_t tinfo; if (tinfo.get_named_type(get_idati(), "EFI_GUID")) { apply_tinfo(ea, tinfo, TINFO_DEFINITE); @@ -36,8 +36,8 @@ void setGuidType(ea_t ea) { } //-------------------------------------------------------------------------- -// Set type and name -void setTypeAndName(ea_t ea, std::string name, std::string type) { +// set type and name +void set_type_and_name(ea_t ea, std::string name, std::string type) { set_name(ea, name.c_str(), SN_FORCE); tinfo_t tinfo; if (tinfo.get_named_type(get_idati(), type.c_str())) { @@ -46,8 +46,8 @@ void setTypeAndName(ea_t ea, std::string name, std::string type) { } //-------------------------------------------------------------------------- -// Set const CHAR16 type -void setConstChar16Type(ea_t ea) { +// set const CHAR16 type +void set_const_char16_type(ea_t ea) { tinfo_t tinfo; if (tinfo.get_named_type(get_idati(), "CHAR16")) { tinfo.set_const(); @@ -56,7 +56,7 @@ void setConstChar16Type(ea_t ea) { } //-------------------------------------------------------------------------- -// get file format name (fileformatname) +// get file format name std::string file_format_name() { char file_format[256] = {0}; get_file_type_name(file_format, 256); @@ -152,27 +152,27 @@ FfsFileType ask_file_type(std::vector *all_guids) { } //-------------------------------------------------------------------------- -// Find address of global gBS var for X64 module for each service -ea_t findUnknownBsVarX64(ea_t ea) { - ea_t resAddr = 0; +// find address of global gBS var for X64 module for each service +ea_t find_unknown_bs_var_64(ea_t ea) { + ea_t res = BADADDR; insn_t insn; - // Check 10 instructions below + // check 10 instructions below for (int i = 0; i < 10; i++) { decode_insn(&insn, ea); if (insn.itype == NN_mov && insn.ops[0].type == o_reg && insn.ops[0].reg == REG_RAX && insn.ops[1].type == o_mem) { - resAddr = insn.ops[1].addr; + res = insn.ops[1].addr; break; } ea = prev_head(ea, 0); } - return resAddr; + return res; } //-------------------------------------------------------------------------- -// Get all xrefs for given address -std::vector getXrefs(ea_t addr) { +// get all xrefs for given address +std::vector get_xrefs_util(ea_t addr) { std::vector xrefs; ea_t xref = get_first_dref_to(addr); while (xref != BADADDR) { @@ -183,25 +183,25 @@ std::vector getXrefs(ea_t addr) { } //-------------------------------------------------------------------------- -// Get all xrefs for given array element -std::vector getXrefsToArray(ea_t addr) { +// get all xrefs for given array element +std::vector get_xrefs_to_array(ea_t addr) { ea_t first_ea; ea_t ea = addr; while (true) { auto ptr = get_qword(ea); - auto xrefs = getXrefs(ptr); + auto xrefs = get_xrefs_util(ptr); if (std::find(xrefs.begin(), xrefs.end(), ea) == xrefs.end()) { break; } first_ea = ea; ea -= 8; } - return getXrefs(first_ea); + return get_xrefs_util(first_ea); } //-------------------------------------------------------------------------- -// Wrapper for op_stroff function -bool opStroff(ea_t addr, std::string type) { +// wrapper for op_stroff function +bool op_stroff_util(ea_t addr, std::string type) { tinfo_t tinfo; if (!tinfo.get_named_type(get_idati(), type.c_str())) { return false; @@ -220,95 +220,95 @@ bool opStroff(ea_t addr, std::string type) { } //-------------------------------------------------------------------------- -// Get pointer to named type and apply it -bool setPtrType(ea_t addr, std::string type) { +// get pointer to named type and apply it +bool set_ptr_type(ea_t addr, std::string type) { tinfo_t tinfo; if (!tinfo.get_named_type(get_idati(), type.c_str())) { return false; } - tinfo_t ptrTinfo; - ptrTinfo.create_ptr(tinfo); - apply_tinfo(addr, ptrTinfo, TINFO_DEFINITE); + tinfo_t p_tinfo; + p_tinfo.create_ptr(tinfo); + apply_tinfo(addr, p_tinfo, TINFO_DEFINITE); return true; } //-------------------------------------------------------------------------- -// Set name and apply pointer to named type -void setPtrTypeAndName(ea_t ea, std::string name, std::string type) { +// set name and apply pointer to named type +void set_ptr_type_and_name(ea_t ea, std::string name, std::string type) { set_name(ea, name.c_str(), SN_FORCE); - setPtrType(ea, type.c_str()); + set_ptr_type(ea, type.c_str()); } //-------------------------------------------------------------------------- -// Get guids.json file name -std::filesystem::path getGuidsJsonFile() { - std::filesystem::path guidsJsonPath; +// get guids.json file name +std::filesystem::path get_guids_json_file() { + std::filesystem::path guids_json_path; // check {idadir}/plugins/guids.json - guidsJsonPath /= idadir("plugins"); - guidsJsonPath /= "guids.json"; - if (std::filesystem::exists(guidsJsonPath)) { - return guidsJsonPath; + guids_json_path /= idadir("plugins"); + guids_json_path /= "guids.json"; + if (std::filesystem::exists(guids_json_path)) { + return guids_json_path; } // check {idadir}/plugins/guids/guids.json - guidsJsonPath.clear(); - guidsJsonPath /= idadir("plugins"); - guidsJsonPath /= "guids"; - guidsJsonPath /= "guids.json"; - if (std::filesystem::exists(guidsJsonPath)) { - return guidsJsonPath; + guids_json_path.clear(); + guids_json_path /= idadir("plugins"); + guids_json_path /= "guids"; + guids_json_path /= "guids.json"; + if (std::filesystem::exists(guids_json_path)) { + return guids_json_path; } - // Try to load it from the per-user directory. - guidsJsonPath.clear(); - guidsJsonPath /= get_user_idadir(); - guidsJsonPath /= "plugins"; - guidsJsonPath /= "guids.json"; - if (std::filesystem::exists(guidsJsonPath)) { - return guidsJsonPath; + // try to load it from the per-user directory. + guids_json_path.clear(); + guids_json_path /= get_user_idadir(); + guids_json_path /= "plugins"; + guids_json_path /= "guids.json"; + if (std::filesystem::exists(guids_json_path)) { + return guids_json_path; } - guidsJsonPath.clear(); - guidsJsonPath /= get_user_idadir(); - guidsJsonPath /= "plugins"; - guidsJsonPath /= "guids"; - guidsJsonPath /= "guids.json"; - if (std::filesystem::exists(guidsJsonPath)) { - return guidsJsonPath; + guids_json_path.clear(); + guids_json_path /= get_user_idadir(); + guids_json_path /= "plugins"; + guids_json_path /= "guids"; + guids_json_path /= "guids.json"; + if (std::filesystem::exists(guids_json_path)) { + return guids_json_path; } - // Does not exist. - guidsJsonPath.clear(); - return guidsJsonPath; + // does not exist + guids_json_path.clear(); + return guids_json_path; } //-------------------------------------------------------------------------- -// Get json summary file name -std::filesystem::path getSummaryFile() { - std::string idbPath; - idbPath = get_path(PATH_TYPE_IDB); - std::filesystem::path logFile; - logFile /= idbPath; - logFile.replace_extension(".json"); - return logFile; +// get json summary file name +std::filesystem::path get_summary_file() { + std::string idb_path; + idb_path = get_path(PATH_TYPE_IDB); + std::filesystem::path log_file; + log_file /= idb_path; + log_file.replace_extension(".json"); + return log_file; } //-------------------------------------------------------------------------- -// Check for summary json file exist -bool summaryJsonExist() { - std::string idbPath; - idbPath = get_path(PATH_TYPE_IDB); - std::filesystem::path logFile; - logFile /= idbPath; - logFile.replace_extension(".json"); - return std::filesystem::exists(logFile); +// check if summary json file exists +bool summary_json_exists() { + std::string idb_path; + idb_path = get_path(PATH_TYPE_IDB); + std::filesystem::path log_file; + log_file /= idb_path; + log_file.replace_extension(".json"); + return std::filesystem::exists(log_file); } //-------------------------------------------------------------------------- -// Change EFI_SYSTEM_TABLE *SystemTable to EFI_PEI_SERVICES **PeiService -// for ModuleEntryPoint -void setEntryArgToPeiSvc() { +// change EFI_SYSTEM_TABLE *SystemTable to EFI_PEI_SERVICES **PeiService +// at ModuleEntryPoint +void set_entry_arg_to_pei_svc() { for (auto idx = 0; idx < get_entry_qty(); idx++) { uval_t ord = get_entry_ordinal(idx); ea_t start_ea = get_entry(ord); @@ -318,24 +318,28 @@ void setEntryArgToPeiSvc() { u64_addr(start_ea), idx); continue; } + func_type_data_t funcdata; if (!tif_ea.get_func_details(&funcdata)) { msg("[%s] get_func_details failed, %d\n", g_plugin_name, idx); continue; } + tinfo_t tif_pei; bool res = tif_pei.get_named_type(get_idati(), "EFI_PEI_SERVICES"); if (!res) { msg("[%s] get_named_type failed, res = %d, idx=%d\n", g_plugin_name, res, idx); continue; } - tinfo_t ptrTinfo; - tinfo_t ptrPtrTinfo; - ptrTinfo.create_ptr(tif_pei); - ptrPtrTinfo.create_ptr(ptrTinfo); + + tinfo_t p_tinfo; + tinfo_t pp_tinfo; + p_tinfo.create_ptr(tif_pei); + pp_tinfo.create_ptr(p_tinfo); + // funcdata.size() does not work for aarch64 if (funcdata.size() == 2) { - funcdata[1].type = ptrPtrTinfo; + funcdata[1].type = pp_tinfo; funcdata[1].name = "PeiServices"; tinfo_t func_tinfo; if (!func_tinfo.create_func(funcdata)) { @@ -350,7 +354,7 @@ void setEntryArgToPeiSvc() { } } -bool setRetToPeiSvc(ea_t start_ea) { +bool set_ret_to_pei_svc(ea_t start_ea) { tinfo_t tif_ea; if (guess_tinfo(&tif_ea, start_ea) == GUESS_FUNC_FAILED) { msg("[%s] guess_tinfo failed, function = 0x%016llX", g_plugin_name, @@ -369,12 +373,12 @@ bool setRetToPeiSvc(ea_t start_ea) { msg("[%s] get_named_type failed, res = %d\n", g_plugin_name, res); return false; } - tinfo_t ptrTinfo; - tinfo_t ptrPtrTinfo; - ptrTinfo.create_ptr(tif_pei); - ptrPtrTinfo.create_ptr(ptrTinfo); + tinfo_t p_tinfo; + tinfo_t pp_tinfo; + p_tinfo.create_ptr(tif_pei); + pp_tinfo.create_ptr(p_tinfo); - fi.rettype = ptrPtrTinfo; + fi.rettype = pp_tinfo; tinfo_t func_tinfo; if (!func_tinfo.create_func(fi)) { @@ -390,7 +394,7 @@ bool setRetToPeiSvc(ea_t start_ea) { return true; } -int parseEfiPeiServices4() { +int parse_efi_pei_svc4() { return parse_decls(nullptr, "struct EFI_PEI_SERVICES_4 {\n" " EFI_PEI_SERVICES **PeiServices;\n" @@ -399,7 +403,7 @@ int parseEfiPeiServices4() { msg, HTI_DCL); } -int parseEfiPeiSidt() { +int parse_efi_pei_sidt() { return parse_decls(nullptr, "struct EFI_PEI_SIDT {\n" " UINT16 Limit;\n" @@ -409,8 +413,8 @@ int parseEfiPeiSidt() { } //-------------------------------------------------------------------------- -// Add EFI_PEI_SERVICES_4 structure -bool addStrucForShiftedPtr() { +// add EFI_PEI_SERVICES_4 structure +bool add_struct_for_shifted_ptr() { #if IDA_SDK_VERSION < 900 auto sid = add_struc(BADADDR, "EFI_PEI_SERVICES_4"); if (sid == BADADDR) { @@ -433,24 +437,24 @@ bool addStrucForShiftedPtr() { } // set type "EFI_PEI_SERVICES **PeiServices" - tinfo_t ptrTinfo; - tinfo_t ptr2Tinfo; - ptrTinfo.create_ptr(tinfo); - ptr2Tinfo.create_ptr(ptrTinfo); + tinfo_t p_tinfo; + tinfo_t pp_tinfo; + p_tinfo.create_ptr(tinfo); + pp_tinfo.create_ptr(p_tinfo); auto member = get_member_by_name(new_struct, "PeiServices"); - set_member_tinfo(new_struct, member, 0, ptr2Tinfo, 0); + set_member_tinfo(new_struct, member, 0, pp_tinfo, 0); return true; #endif // return true if there are no errors from parse_decls() - return !parseEfiPeiServices4() && !parseEfiPeiSidt(); + return !parse_efi_pei_svc4() && !parse_efi_pei_sidt(); } //-------------------------------------------------------------------------- -// Change the value of a number to match the data type -uval_t truncImmToDtype(uval_t value, op_dtype_t dtype) { +// change the value of a number to match the data type +uval_t trunc_imm_to_dtype(uval_t value, op_dtype_t dtype) { switch (dtype) { case dt_byte: return value & 0xff; @@ -464,17 +468,17 @@ uval_t truncImmToDtype(uval_t value, op_dtype_t dtype) { } //-------------------------------------------------------------------------- -// Get module name by address -qstring getModuleNameLoader(ea_t address) { - segment_t *seg = getseg(address); +// get module name by address +qstring get_module_name_loader(ea_t addr) { + segment_t *seg = getseg(addr); qstring seg_name; get_segm_name(&seg_name, seg); return seg_name.remove(seg_name.size() - 7, seg_name.size()); } //-------------------------------------------------------------------------- -// Get GUID data by address -json getGuidByAddr(ea_t addr) { +// get GUID data by address +json get_guid_by_address(ea_t addr) { return json::array( {get_wide_dword(addr), get_wide_word(addr + 4), get_wide_word(addr + 6), get_wide_byte(addr + 8), get_wide_byte(addr + 9), get_wide_byte(addr + 10), @@ -483,8 +487,8 @@ json getGuidByAddr(ea_t addr) { } //-------------------------------------------------------------------------- -// Validate GUID value -bool checkGuid(json guid) { +// validate GUID value +bool valid_guid(json guid) { if (static_cast(guid[0]) == 0x00000000 && (uint16_t)guid[1] == 0x0000) { return false; } @@ -495,28 +499,28 @@ bool checkGuid(json guid) { } //-------------------------------------------------------------------------- -// Convert GUID value to string -std::string getGuidFromValue(json guid) { - char guidStr[37] = {0}; - snprintf(guidStr, 37, "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X", +// convert GUID value to string +std::string guid_to_string(json guid) { + char guid_str[37] = {0}; + snprintf(guid_str, 37, "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X", static_cast(guid[0]), static_cast(guid[1]), static_cast(guid[2]), static_cast(guid[3]), static_cast(guid[4]), static_cast(guid[5]), static_cast(guid[6]), static_cast(guid[7]), static_cast(guid[8]), static_cast(guid[9]), static_cast(guid[10])); - return static_cast(guidStr); + return static_cast(guid_str); } -std::vector unpackGuid(std::string guid) { +std::vector unpack_guid(std::string guid) { std::vector res; - std::string delimiter = "-"; + std::string delim = "-"; std::string byte_str; uint8_t byte; size_t pos = 0; auto index = 0; - while ((pos = guid.find(delimiter)) != std::string::npos) { + while ((pos = guid.find(delim)) != std::string::npos) { std::vector tmp; auto hex = guid.substr(0, pos); if (hex.size() % 2) { @@ -533,7 +537,7 @@ std::vector unpackGuid(std::string guid) { res.insert(res.end(), tmp.begin(), tmp.end()); } index += 1; - guid.erase(0, pos + delimiter.size()); + guid.erase(0, pos + delim.size()); tmp.clear(); } @@ -546,10 +550,10 @@ std::vector unpackGuid(std::string guid) { return res; } -std::vector searchProtocol(std::string protocol) { +std::vector search_protocol(std::string protocol) { uchar bytes[17] = {0}; std::vector res; - auto guid_bytes = unpackGuid(protocol); + auto guid_bytes = unpack_guid(protocol); std::copy(guid_bytes.begin(), guid_bytes.end(), bytes); ea_t start = 0; while (true) { @@ -567,7 +571,7 @@ std::vector searchProtocol(std::string protocol) { return res; } -bool checkInstallProtocol(ea_t ea) { +bool check_install_protocol(ea_t ea) { insn_t insn; // search for `call [REG + offset]` insn // offset in [0x80, 0xA8, 0x148] @@ -589,19 +593,19 @@ bool checkInstallProtocol(ea_t ea) { } //-------------------------------------------------------------------------- -// Convert 64-bit value to hex string -std::string getHex(uint64_t value) { +// convert 64-bit value to hex string +std::string as_hex(uint64_t value) { char hexstr[21] = {}; snprintf(hexstr, 21, "%llX", value); return static_cast(hexstr); } //-------------------------------------------------------------------------- -// Make sure the first argument looks like protocol -bool bootServiceProtCheck(ea_t callAddr) { +// make sure the first argument looks like a protocol +bool check_boot_service_protocol(ea_t call_addr) { bool valid = false; insn_t insn; - auto addr = prev_head(callAddr, 0); + auto addr = prev_head(call_addr, 0); decode_insn(&insn, addr); while (!is_basic_block_end(insn, false)) { @@ -623,10 +627,10 @@ bool bootServiceProtCheck(ea_t callAddr) { } //-------------------------------------------------------------------------- -// Make sure that the address does not belong to the protocol interface -bool bootServiceProtCheckXrefs(ea_t callAddr) { +// make sure that the address does not belong to the protocol interface +bool check_boot_service_protocol_xrefs(ea_t call_addr) { insn_t insn; - for (auto xref : getXrefs(callAddr)) { + for (auto xref : get_xrefs_util(call_addr)) { decode_insn(&insn, xref); if (insn.itype == NN_lea && insn.ops[0].type == o_reg && insn.ops[0].reg == REG_R8) { // load interface instruction @@ -636,16 +640,15 @@ bool bootServiceProtCheckXrefs(ea_t callAddr) { return true; } -bool markCopy(ea_t codeAddr, ea_t varAddr, std::string type) { +bool mark_copy(ea_t code_addr, ea_t var_addr, std::string type) { insn_t insn; int reg = -1; - ea_t ea = codeAddr; - ea_t varCopy = BADADDR; + ea_t ea = code_addr; + ea_t var_copy = BADADDR; decode_insn(&insn, ea); - // get `reg` value if (insn.itype == NN_mov && insn.ops[0].type == o_reg && insn.ops[1].type == o_mem && - insn.ops[1].addr == varAddr) { + insn.ops[1].addr == var_addr) { reg = insn.ops[0].reg; } @@ -666,49 +669,48 @@ bool markCopy(ea_t codeAddr, ea_t varAddr, std::string type) { break; } - // get `varCopy` if (insn.itype == NN_mov && insn.ops[0].type == o_mem && insn.ops[1].type == o_reg && insn.ops[1].reg == reg) { - varCopy = insn.ops[0].addr; - msg("[efiXplorer] Found copy for global variable: 0x%016llX\n", u64_addr(ea)); + var_copy = insn.ops[0].addr; + msg("[efiXplorer] found copy for global variable: 0x%016llX\n", u64_addr(ea)); break; } } - if (varCopy == BADADDR) { + if (var_copy == BADADDR) { return false; } std::string name; if (type == "gSmst") { - setPtrTypeAndName(varCopy, "gSmst", "_EFI_SMM_SYSTEM_TABLE2"); + set_ptr_type_and_name(var_copy, "gSmst", "_EFI_SMM_SYSTEM_TABLE2"); } if (type == "gBS") { - setPtrTypeAndName(varCopy, "gBS", "EFI_BOOT_SERVICES"); + set_ptr_type_and_name(var_copy, "gBS", "EFI_BOOT_SERVICES"); } if (type == "gRT") { - setPtrTypeAndName(varCopy, "gRT", "EFI_RUNTIME_SERVICES"); + set_ptr_type_and_name(var_copy, "gRT", "EFI_RUNTIME_SERVICES"); } return true; } -bool markCopiesForGlobalVars(std::vector globalVars, std::string type) { - for (auto var : globalVars) { - auto xrefs = getXrefs(var); +bool mark_copies_for_gvars(std::vector gvars, std::string type) { + for (auto var : gvars) { + auto xrefs = get_xrefs_util(var); for (auto addr : xrefs) { - markCopy(addr, var, type); + mark_copy(addr, var, type); } } return true; } //-------------------------------------------------------------------------- -// Generate name string from type -std::string typeToName(std::string type) { +// generate name string from type +std::string type_to_name(std::string type) { std::string result; size_t counter = 0; for (char const &c : type) { @@ -736,18 +738,18 @@ std::string typeToName(std::string type) { return result; } -xreflist_t xrefsToStackVar(ea_t funcEa, qstring varName) { +xreflist_t xrefs_to_stack_var(ea_t func_addr, qstring var_name) { xreflist_t xrefs_list; #if IDA_SDK_VERSION < 900 - struc_t *frame = get_frame(funcEa); - func_t *func = get_func(funcEa); + struc_t *frame = get_frame(func_addr); + func_t *func = get_func(func_addr); member_t member; // Get member by name for (int i = 0; i < frame->memqty; i++) { member = frame->members[i]; qstring name; get_member_name(&name, frame->members[i].id); - if (name == varName) { + if (name == var_name) { build_stkvar_xrefs(&xrefs_list, func, &member); return xrefs_list; } @@ -758,44 +760,43 @@ xreflist_t xrefsToStackVar(ea_t funcEa, qstring varName) { return xrefs_list; } -void opstroffForAddress(ea_t ea, qstring typeName) { +void op_stroff_for_addr(ea_t ea, qstring type_name) { insn_t insn; for (auto i = 0; i < 16; i++) { ea = next_head(ea, BADADDR); decode_insn(&insn, ea); - // Found interface function call + // check for interface function call if ((insn.itype == NN_call || insn.itype == NN_callfi || insn.itype == NN_callni) && (insn.ops[0].type == o_displ || insn.ops[0].type == o_phrase) && insn.ops[0].reg == REG_RAX) { - opStroff(ea, static_cast(typeName.c_str())); - msg("[%s] Mark arguments at address 0x%016llX (interface type: %s)\n", - g_plugin_name, u64_addr(ea), typeName.c_str()); + op_stroff_util(ea, static_cast(type_name.c_str())); + msg("[%s] mark arguments at address 0x%016llX (interface type: %s)\n", + g_plugin_name, u64_addr(ea), type_name.c_str()); // check for EfiSmmBase2Protocol->GetSmstLocation - if (typeName == "EFI_SMM_BASE2_PROTOCOL" && insn.ops[0].type == o_displ && + if (type_name == "EFI_SMM_BASE2_PROTOCOL" && insn.ops[0].type == o_displ && insn.ops[0].addr == 8) { - if (!addrInVec(g_get_smst_location_calls, ea)) { + if (!addr_in_vec(g_get_smst_location_calls, ea)) { g_get_smst_location_calls.push_back(ea); } } - if (typeName == "EFI_SMM_VARIABLE_PROTOCOL" && insn.ops[0].type == o_phrase) { - if (!addrInVec(g_smm_get_variable_calls, ea)) { + if (type_name == "EFI_SMM_VARIABLE_PROTOCOL" && insn.ops[0].type == o_phrase) { + if (!addr_in_vec(g_smm_get_variable_calls, ea)) { g_smm_get_variable_calls.push_back(ea); } } - if (typeName == "EFI_SMM_VARIABLE_PROTOCOL" && insn.ops[0].type == o_displ && + if (type_name == "EFI_SMM_VARIABLE_PROTOCOL" && insn.ops[0].type == o_displ && insn.ops[0].addr == 0x10) { - if (!addrInVec(g_smm_set_variable_calls, ea)) { + if (!addr_in_vec(g_smm_set_variable_calls, ea)) { g_smm_set_variable_calls.push_back(ea); } } - break; } - // If the RAX value is overridden + // if the RAX value is overridden if (insn.ops[0].reg == REG_RAX) { break; } @@ -803,49 +804,50 @@ void opstroffForAddress(ea_t ea, qstring typeName) { } //-------------------------------------------------------------------------- -// Mark the arguments of each function from an interface derived from +// mark the arguments of each function from an interface derived from // a local variable -void opstroffForInterface(xreflist_t localXrefs, qstring typeName) { +void op_stroff_for_interface(xreflist_t local_xrefs, qstring type_name) { insn_t insn; - for (auto xref : localXrefs) { + for (auto xref : local_xrefs) { decode_insn(&insn, xref.ea); if (insn.itype == NN_mov && insn.ops[0].reg == REG_RAX) { - opstroffForAddress(xref.ea, typeName); + op_stroff_for_addr(xref.ea, type_name); } } } //-------------------------------------------------------------------------- -// Mark the arguments of each function from an interface derived from +// mark the arguments of each function from an interface derived from // a global variable -void opstroffForGlobalInterface(std::vector xrefs, qstring typeName) { +void op_stroff_for_global_interface(std::vector xrefs, qstring type_name) { insn_t insn; for (auto ea : xrefs) { decode_insn(&insn, ea); if (insn.itype == NN_mov && insn.ops[0].reg == REG_RAX) { - opstroffForAddress(ea, typeName); + op_stroff_for_addr(ea, type_name); } } } -bool qwordInVec(std::vector vec, uint64_t value) { +bool uint64_in_vec(std::vector vec, uint64_t value) { return find(vec.begin(), vec.end(), value) != vec.end(); } -bool addrInVec(std::vector vec, ea_t addr) { +bool addr_in_vec(std::vector vec, ea_t addr) { return find(vec.begin(), vec.end(), addr) != vec.end(); } -bool jsonInVec(std::vector vec, json item) { +bool json_in_vec(std::vector vec, json item) { return find(vec.begin(), vec.end(), item) != vec.end(); } -bool addrInTables(std::vector gStList, std::vector gBsList, - std::vector gRtList, ea_t ea) { - return (addrInVec(gStList, ea) || addrInVec(gBsList, ea) || addrInVec(gRtList, ea)); +bool addr_in_tables(std::vector st_list, std::vector bs_list, + std::vector rt_list, ea_t ea) { + return (addr_in_vec(st_list, ea) || addr_in_vec(bs_list, ea) || + addr_in_vec(rt_list, ea)); } -std::vector findData(ea_t start_ea, ea_t end_ea, uchar *data, size_t len) { +std::vector find_data(ea_t start_ea, ea_t end_ea, uchar *data, size_t len) { std::vector res; ea_t start = start_ea; int counter = 0; @@ -866,7 +868,7 @@ std::vector findData(ea_t start_ea, ea_t end_ea, uchar *data, size_t len) //-------------------------------------------------------------------------- // get wide string by address -std::string getWideString(ea_t addr) { +std::string get_wide_string(ea_t addr) { std::string res; int index = 0; while (get_wide_word(addr + index)) { @@ -881,8 +883,8 @@ std::string getWideString(ea_t addr) { } //-------------------------------------------------------------------------- -// Get EfiGuid by address -EfiGuid getGlobalGuid(ea_t addr) { +// get EfiGuid by address +EfiGuid get_global_guid(ea_t addr) { EfiGuid guid; guid.data1 = get_wide_dword(addr); guid.data2 = get_wide_word(addr + 4); @@ -894,8 +896,8 @@ EfiGuid getGlobalGuid(ea_t addr) { } //-------------------------------------------------------------------------- -// Get EfiGuid by stack offset -EfiGuid getStackGuid(func_t *f, uint64_t offset) { +// get EfiGuid by stack offset +EfiGuid get_local_guid(func_t *f, uint64_t offset) { EfiGuid guid; insn_t insn; auto ea = f->start_ea; @@ -943,35 +945,39 @@ EfiGuid getStackGuid(func_t *f, uint64_t offset) { return guid; } -std::string getTable(std::string service_name) { - for (auto i = 0; i < bootServicesTableAllCount; i++) { - if (static_cast(bootServicesTableAll[i].name) == service_name) { +std::string get_table_name(std::string service_name) { + for (auto i = 0; i < g_boot_services_table_all_count; i++) { + if (static_cast(g_boot_services_table_all[i].name) == service_name) { return "EFI_BOOT_SERVICES"; } } - for (auto i = 0; i < runtimeServicesTableAllCount; i++) { - if (static_cast(runtimeServicesTableAll[i].name) == service_name) { + + for (auto i = 0; i < g_runtime_services_table_all_count; i++) { + if (static_cast(g_runtime_services_table_all[i].name) == service_name) { return "EFI_RUNTIME_SERVICES"; } } - return "OTHER"; + + return "Unknown"; } -std::string lookupBootServiceName(uint64_t offset) { - for (auto i = 0; i < bootServicesTableAllCount; i++) { - if (bootServicesTableAll[i].offset64 == offset) { - return static_cast(bootServicesTableAll[i].name); +std::string lookup_boot_service_name(uint64_t offset) { + for (auto i = 0; i < g_boot_services_table_all_count; i++) { + if (g_boot_services_table_all[i].offset64 == offset) { + return static_cast(g_boot_services_table_all[i].name); } } + return "Unknown"; } -std::string lookupRuntimeServiceName(uint64_t offset) { - for (auto i = 0; i < runtimeServicesTableAllCount; i++) { - if (runtimeServicesTableAll[i].offset64 == offset) { - return static_cast(runtimeServicesTableAll[i].name); +std::string lookup_runtime_service_name(uint64_t offset) { + for (auto i = 0; i < g_runtime_services_table_all_count; i++) { + if (g_runtime_services_table_all[i].offset64 == offset) { + return static_cast(g_runtime_services_table_all[i].name); } } + return "Unknown"; } diff --git a/efiXplorer/efi_utils.h b/efiXplorer/efi_utils.h index 4cf8123a..99db47a6 100644 --- a/efiXplorer/efi_utils.h +++ b/efiXplorer/efi_utils.h @@ -87,118 +87,66 @@ struct EfiGuid { }; ArchFileType input_file_type(); -FfsFileType ask_file_type(std::vector *all_guids); - -// Set EFI_GUID type -void setGuidType(ea_t ea); - -// Get all data xrefs for address -std::vector getXrefs(ea_t addr); -std::vector getXrefsToArray(ea_t addr); - -// Wrapper for op_stroff function -bool opStroff(ea_t addr, std::string type); - -// Find address of global gBS variable -// for X64 module for each service -ea_t findUnknownBsVarX64(ea_t ea); - -// Get pointer to named type and apply it -bool setPtrType(ea_t addr, std::string type); - -// Set name and apply pointer to named type -void setPtrTypeAndName(ea_t ea, std::string name, std::string type); - -// Get guids.json file name -std::filesystem::path getGuidsJsonFile(); - -// Get json summary file name -std::filesystem::path getSummaryFile(); - -// Check for summary json file exist -bool summaryJsonExist(); - -// Change EFI_SYSTEM_TABLE *SystemTable to EFI_PEI_SERVICES **PeiService -// for ModuleEntryPoint -void setEntryArgToPeiSvc(); - -// Set return value type to EFI_PEI_SERVICES **PeiService -// for specified function -bool setRetToPeiSvc(ea_t start_ea); - -// Set type and name -void setTypeAndName(ea_t ea, std::string name, std::string type); - -// Set const CHAR16 type -void setConstChar16Type(ea_t ea); -// Get module name by address -qstring getModuleNameLoader(ea_t address); +bool add_struct_for_shifted_ptr(); +bool addr_in_tables(std::vector st_list, std::vector bs_list, + std::vector rt_list, ea_t ea); +bool addr_in_vec(std::vector vec, ea_t addr); +bool check_boot_service_protocol_xrefs(ea_t call_addr); +bool check_boot_service_protocol(ea_t call_addr); +bool check_install_protocol(ea_t ea); +bool json_in_vec(std::vector vec, json item); +bool mark_copies_for_gvars(std::vector gvars, std::string type); +bool op_stroff_util(ea_t addr, std::string type); +bool set_ptr_type(ea_t addr, std::string type); +bool set_ret_to_pei_svc(ea_t start_ea); +bool summary_json_exists(); +bool uint64_in_vec(std::vector vec, uint64_t value); +bool valid_guid(json guid); + +ea_t find_unknown_bs_var_64(ea_t ea); + +EfiGuid get_global_guid(ea_t addr); +EfiGuid get_local_guid(func_t *f, uint64_t offset); -// Print std::vector object -void printVectorJson(std::vector in); - -// Change the value of a number to match the data type -uval_t truncImmToDtype(uval_t value, op_dtype_t dtype); - -// Get GUID data by address -json getGuidByAddr(ea_t addr); - -// Validate GUID value -bool checkGuid(json guid); - -// Make sure the first argument looks like protocol -bool bootServiceProtCheck(ea_t callAddr); - -// Make sure that the address does not belong to the protocol interface -bool bootServiceProtCheckXrefs(ea_t callAddr); - -// Convert GUID value to string -std::string getGuidFromValue(json guid); - -// Convert string GUID to vector of bytes -std::vector unpackGuid(std::string guid); +FfsFileType ask_file_type(std::vector *all_guids); -// Convert 64-bit value to hex string -std::string getHex(uint64_t value); +json get_guid_by_address(ea_t addr); -// Mark copies for global variables -bool markCopiesForGlobalVars(std::vector globalVars, std::string type); +qstring get_module_name_loader(ea_t addr); -// Generate name string from type -std::string typeToName(std::string type); +std::filesystem::path get_guids_json_file(); +std::filesystem::path get_summary_file(); -// Get XREFs to stack variable -xreflist_t xrefsToStackVar(ea_t funcEa, qstring varName); +std::string as_hex(uint64_t value); +std::string get_table_name(std::string service_name); +std::string get_wide_string(ea_t addr); +std::string guid_to_string(json guid); +std::string lookup_boot_service_name(uint64_t offset); +std::string lookup_runtime_service_name(uint64_t offset); +std::string type_to_name(std::string type); -// Mark the arguments of each function from an interface derived from a local variable -void opstroffForInterface(xreflist_t localXrefs, qstring typeName); +std::vector find_data(ea_t start_ea, ea_t end_ea, uchar *data, size_t len); +std::vector get_xrefs_to_array(ea_t addr); +std::vector get_xrefs_util(ea_t addr); +std::vector search_protocol(std::string protocol); +std::vector unpack_guid(std::string guid); -// Mark the arguments of each function from an interface derived from a global variable -void opstroffForGlobalInterface(std::vector xrefs, qstring typeName); +uint16_t get_machine_type(); +uint32_t u32_addr(ea_t addr); +uint64_t u64_addr(ea_t addr); -// Find wrappers -bool qwordInVec(std::vector vec, uint64_t value); -bool addrInVec(std::vector vec, ea_t addr); -bool jsonInVec(std::vector vec, json item); -bool addrInTables(std::vector gStList, std::vector gBsList, - std::vector gRtList, ea_t ea); +uval_t trunc_imm_to_dtype(uval_t value, op_dtype_t dtype); -// Search protocol GUID bytes in binary -std::vector searchProtocol(std::string protocol); +void op_stroff_for_global_interface(std::vector xrefs, qstring type_name); +void op_stroff_for_interface(xreflist_t local_xrefs, qstring type_name); +void set_const_char16_type(ea_t ea); +void set_entry_arg_to_pei_svc(); +void set_guid_type(ea_t ea); +void set_ptr_type_and_name(ea_t ea, std::string name, std::string type); +void set_type_and_name(ea_t ea, std::string name, std::string type); -bool checkInstallProtocol(ea_t ea); -std::vector findData(ea_t start_ea, ea_t end_ea, uchar *data, size_t len); -std::string getWideString(ea_t addr); -EfiGuid getGlobalGuid(ea_t addr); -EfiGuid getStackGuid(func_t *f, uint64_t offset); -bool addStrucForShiftedPtr(); -std::string getTable(std::string service_name); -std::string lookupBootServiceName(uint64_t offset); -std::string lookupRuntimeServiceName(uint64_t offset); -uint64_t u64_addr(ea_t addr); -uint32_t u32_addr(ea_t addr); -uint16_t get_machine_type(); +xreflist_t xrefs_to_stack_var(ea_t func_addr, qstring var_name); #if IDA_SDK_VERSION >= 900 tid_t import_type(const til_t *til, int _idx, const char *name); diff --git a/efiXplorer/efixplorer.cc b/efiXplorer/efixplorer.cc index f707aa05..b41e2a45 100644 --- a/efiXplorer/efixplorer.cc +++ b/efiXplorer/efixplorer.cc @@ -83,7 +83,7 @@ bool idaapi run(size_t arg) { msg("[%s] disable_ui = %d, disable_vuln_hunt = %d\n", g_plugin_name, g_args.disable_ui, g_args.disable_vuln_hunt); - auto guids_path = getGuidsJsonFile(); + auto guids_path = get_guids_json_file(); msg("[%s] guids.json exists: %s\n", g_plugin_name, BTOA(!guids_path.empty())); if (guids_path.empty()) { From 634e9b75653e8605c3b6e9c4c7e45bc43f731f01 Mon Sep 17 00:00:00 2001 From: yeggor Date: Sat, 14 Sep 2024 04:09:36 +0200 Subject: [PATCH 19/69] refactor efixplorer.cc and rename globals in efi_analyser --- efiXplorer/efi_analyser.h | 2 +- efiXplorer/efi_analyser_arm.cc | 14 +++--- efiXplorer/efi_analyser_x86.cc | 79 +++++++++++++++++----------------- efiXplorer/efi_defs.cc | 2 +- efiXplorer/efi_hexrays.cc | 49 +++++++++++---------- efiXplorer/efi_hexrays.h | 54 +++++++++++------------ efiXplorer/efi_ui.cc | 9 ++-- efiXplorer/efi_utils.cc | 4 +- efiXplorer/efixplorer.cc | 22 +++++----- 9 files changed, 119 insertions(+), 116 deletions(-) diff --git a/efiXplorer/efi_analyser.h b/efiXplorer/efi_analyser.h index 15e12543..0929f751 100644 --- a/efiXplorer/efi_analyser.h +++ b/efiXplorer/efi_analyser.h @@ -248,7 +248,7 @@ class EfiAnalyserX86 : public EfiAnalyser { for (auto idx = 0; idx < get_entry_qty(); idx++) { uval_t ord = get_entry_ordinal(idx); ea_t ep = get_entry(ord); - TrackEntryParams(get_func(ep), 0); + track_entry_params(get_func(ep), 0); } #endif } diff --git a/efiXplorer/efi_analyser_arm.cc b/efiXplorer/efi_analyser_arm.cc index 0b4aebe1..cac25f55 100644 --- a/efiXplorer/efi_analyser_arm.cc +++ b/efiXplorer/efi_analyser_arm.cc @@ -60,7 +60,7 @@ void efi_analysis::EfiAnalyserArm::initialAnalysis() { ea_t ep = get_entry(ord); set_name(ep, "_ModuleEntryPoint", SN_FORCE); #ifdef HEX_RAYS - TrackEntryParams(get_func(ep), 0); + track_entry_params(get_func(ep), 0); #endif /* HEX_RAYS */ } if (file_type == FfsFileType::Pei) { @@ -227,9 +227,9 @@ void efi_analysis::EfiAnalyserArm::initialGlobalVarsDetection() { #ifdef HEX_RAYS // analyse entry point with Hex-Rays for (auto func_addr : funcs) { - json res = DetectVars(get_func(func_addr)); - if (res.contains("gImageHandleList")) { - for (auto addr : res["gImageHandleList"]) { + json res = detect_vars(get_func(func_addr)); + if (res.contains("image_handle_list")) { + for (auto addr : res["image_handle_list"]) { if (!addr_in_vec(image_handle_list_arm, addr)) { image_handle_list_arm.push_back(addr); } @@ -294,7 +294,7 @@ void efi_analysis::EfiAnalyserArm::servicesDetection() { #ifdef HEX_RAYS for (auto func_addr : funcs) { - std::vector services = DetectServices(get_func(func_addr)); + std::vector services = detect_services(get_func(func_addr)); for (auto service : services) { allServices.push_back(service); } @@ -489,12 +489,12 @@ bool efi_analysis::efiAnalyserMainArm() { #ifdef HEX_RAYS for (auto addr : analyser.funcs) { - std::vector services = DetectPeiServicesArm(get_func(addr)); + std::vector services = detect_pei_services_arm(get_func(addr)); for (auto service : services) { analyser.allServices.push_back(service); } } - applyAllTypesForInterfacesBootServices(analyser.allProtocols); + apply_all_types_for_interfaces(analyser.allProtocols); #endif /* HEX_RAYS */ showAllChoosers(analyser); diff --git a/efiXplorer/efi_analyser_x86.cc b/efiXplorer/efi_analyser_x86.cc index f1f49e08..01d223fd 100644 --- a/efiXplorer/efi_analyser_x86.cc +++ b/efiXplorer/efi_analyser_x86.cc @@ -32,13 +32,13 @@ extern std::vector g_get_smst_location_calls; extern std::vector g_smm_get_variable_calls; extern std::vector g_smm_set_variable_calls; -std::vector st_list; -std::vector gPeiSvcList; -std::vector bs_list; -std::vector rt_list; -std::vector gSmstList; -std::vector gImageHandleList; -std::vector gRtServicesList; +std::vector st_list; // gST list (system table addresses) +std::vector ps_list; // gPS list (PEI services addresses) +std::vector bs_list; // gBS list (boot services addresses) +std::vector rt_list; // gRT list (runtime services addresses) +std::vector smst_list; // gSmst list (SMM system table addresses) +std::vector image_handle_list; // gImageHandle list (image handle addresses) +std::vector runtime_services_list; // runtime services list std::vector stackGuids; std::vector dataGuids; @@ -119,12 +119,13 @@ efi_analysis::EfiAnalyser::~EfiAnalyser() { funcs.clear(); st_list.clear(); - gPeiSvcList.clear(); + ps_list.clear(); bs_list.clear(); rt_list.clear(); - gSmstList.clear(); - gImageHandleList.clear(); - gRtServicesList.clear(); + smst_list.clear(); + image_handle_list.clear(); + runtime_services_list.clear(); + stackGuids.clear(); dataGuids.clear(); @@ -167,7 +168,7 @@ void efi_analysis::EfiAnalyser::setStrings() { //-------------------------------------------------------------------------- // Get all .text and .data segments void efi_analysis::EfiAnalyser::getSegments() { - for (segment_t *s = get_first_seg(); s != NULL; s = get_next_seg(s->start_ea)) { + for (segment_t *s = get_first_seg(); s != nullptr; s = get_next_seg(s->start_ea)) { qstring seg_name; get_segm_name(&seg_name, s); @@ -227,7 +228,7 @@ bool efi_analysis::EfiAnalyserX86::findImageHandleX64() { // set type and name set_type_and_name(insn.ops[0].addr, "gImageHandle", "EFI_IMAGE_HANDLE"); - gImageHandleList.push_back(insn.ops[0].addr); + image_handle_list.push_back(insn.ops[0].addr); break; } ea = next_head(ea, endAddress); @@ -267,20 +268,20 @@ bool efi_analysis::EfiAnalyserX86::findSystemTableX64() { // Find and mark gSmst global variable address for X64 module bool efi_analysis::EfiAnalyserX86::findSmstX64() { msg("[%s] gSmst finding\n", g_plugin_name); - std::vector gSmstListSmmBase = findSmstSmmBase(bs_list); - std::vector gSmstListSwDispatch = findSmstSwDispatch(bs_list); - gSmstList.insert(gSmstList.end(), gSmstListSwDispatch.begin(), - gSmstListSwDispatch.end()); - gSmstList.insert(gSmstList.end(), gSmstListSmmBase.begin(), gSmstListSmmBase.end()); + std::vector smst_listSmmBase = findSmstSmmBase(bs_list); + std::vector smst_listSwDispatch = findSmstSwDispatch(bs_list); + smst_list.insert(smst_list.end(), smst_listSwDispatch.begin(), + smst_listSwDispatch.end()); + smst_list.insert(smst_list.end(), smst_listSmmBase.begin(), smst_listSmmBase.end()); // Deduplicate - auto last = std::unique(gSmstList.begin(), gSmstList.end()); - gSmstList.erase(last, gSmstList.end()); + auto last = std::unique(smst_list.begin(), smst_list.end()); + smst_list.erase(last, smst_list.end()); - for (auto smst : gSmstList) { + for (auto smst : smst_list) { msg("[%s] 0x%016llX: gSmst\n", g_plugin_name, u64_addr(smst)); } - return gSmstList.size(); + return smst_list.size(); } //-------------------------------------------------------------------------- @@ -332,9 +333,9 @@ bool efi_analysis::EfiAnalyserX86::findSmstPostProcX64() { if (smst_stack.is_null() && smst_addr != BADADDR) { msg("[%s] gSmst: 0x%016llX\n", g_plugin_name, u64_addr(smst_addr)); - if (!addr_in_vec(gSmstList, smst_addr)) { + if (!addr_in_vec(smst_list, smst_addr)) { set_ptr_type_and_name(smst_addr, "gSmst", "_EFI_SMM_SYSTEM_TABLE2"); - gSmstList.push_back(smst_addr); + smst_list.push_back(smst_addr); } } @@ -806,7 +807,7 @@ void efi_analysis::EfiAnalyserX86::getAllRuntimeServices() { if (!json_in_vec(allServices, rtItem)) { allServices.push_back(rtItem); } - gRtServicesList.push_back(addr); + runtime_services_list.push_back(addr); break; } } @@ -821,12 +822,12 @@ void efi_analysis::EfiAnalyserX86::getAllRuntimeServices() { void efi_analysis::EfiAnalyserX86::getAllSmmServicesX64() { msg("[%s] SmmServices finding (xrefs)\n", g_plugin_name); - if (!gSmstList.size()) { + if (!smst_list.size()) { return; } insn_t insn; - for (auto smms : gSmstList) { + for (auto smms : smst_list) { auto xrefs = get_xrefs_util(smms); msg("[%s] SmmServices finding by xref to gSmst (0x%016llX)\n", g_plugin_name, @@ -1368,7 +1369,7 @@ bool efi_analysis::EfiAnalyserX86::InstallMultipleProtocolInterfacesHandler() { } } - // Exit from loop if found last argument (NULL) + // Exit from loop if found last argument if (insn.itype == NN_xor && insn.ops[0].reg == REG_R9 && insn.ops[1].reg == REG_R9) { check_stack = false; @@ -2433,7 +2434,7 @@ bool efi_analysis::EfiAnalyser::AnalyseVariableService(ea_t ea, std::string serv } else { #ifdef HEX_RAYS // Extract attributes with Hex-Rays SDK - auto res = VariablesInfoExtractAll(f, ea); + auto res = variables_info_extract_all(f, ea); item["Attributes"] = res; std::string attributes_hr = std::string(); if (res == 0xff) { @@ -2515,11 +2516,11 @@ void efi_analysis::EfiAnalyser::dumpInfo() { if (rt_list.size()) { info["rt_list"] = rt_list; } - if (gSmstList.size()) { - info["gSmstList"] = gSmstList; + if (smst_list.size()) { + info["smst_list"] = smst_list; } - if (gImageHandleList.size()) { - info["gImageHandleList"] = gImageHandleList; + if (image_handle_list.size()) { + info["image_handle_list"] = image_handle_list; } if (allPPIs.size()) { info["allPPIs"] = allPPIs; @@ -2690,7 +2691,7 @@ bool efi_analysis::efiAnalyserMainX64() { analyser.getBsProtNamesX64(); #ifdef HEX_RAYS - applyAllTypesForInterfacesBootServices(analyser.allProtocols); + apply_all_types_for_interfaces(analyser.allProtocols); analyser.findSmstPostProcX64(); #endif @@ -2702,7 +2703,7 @@ bool efi_analysis::efiAnalyserMainX64() { analyser.markInterfaces(); // search for copies of global variables - mark_copies_for_gvars(gSmstList, "gSmst"); + mark_copies_for_gvars(smst_list, "gSmst"); mark_copies_for_gvars(bs_list, "gBS"); mark_copies_for_gvars(rt_list, "gRT"); @@ -2722,7 +2723,7 @@ bool efi_analysis::efiAnalyserMainX64() { } #ifdef HEX_RAYS - applyAllTypesForInterfacesSmmServices(analyser.allProtocols); + apply_all_types_for_interfaces_smm(analyser.allProtocols); #endif analyser.analyseNvramVariables(); @@ -2798,8 +2799,8 @@ bool efi_analysis::efiAnalyserMainX86() { analyser.markInterfaces(); #ifdef HEX_RAYS - applyAllTypesForInterfacesBootServices(analyser.allProtocols); - applyAllTypesForInterfacesSmmServices(analyser.allProtocols); + apply_all_types_for_interfaces(analyser.allProtocols); + apply_all_types_for_interfaces_smm(analyser.allProtocols); #endif } else if (analyser.file_type == FfsFileType::Pei) { @@ -2807,7 +2808,7 @@ bool efi_analysis::efiAnalyserMainX86() { add_struct_for_shifted_ptr(); #ifdef HEX_RAYS for (auto addr : analyser.funcs) { - DetectPeiServices(get_func(addr)); + detect_pei_services(get_func(addr)); } #endif analyser.getAllPeiServicesX86(); diff --git a/efiXplorer/efi_defs.cc b/efiXplorer/efi_defs.cc index 765f1287..4bec917f 100644 --- a/efiXplorer/efi_defs.cc +++ b/efiXplorer/efi_defs.cc @@ -59,7 +59,7 @@ size_t g_boot_services_table32_count = sizeof(g_boot_services_table32) / sizeof(service_info_32_t); service_t g_boot_services_table_all[] = { - // difficult to check false positives + // difficult to detect false positives // {"RaiseTPL", RaiseTPLOffset64, RaiseTPLOffset32}, // {"RestoreTPL", RestoreTPLOffset64, RestoreTPLOffset32}, {"AllocatePages", AllocatePagesOffset64, AllocatePagesOffset32}, diff --git a/efiXplorer/efi_hexrays.cc b/efiXplorer/efi_hexrays.cc index e388d569..e150a239 100644 --- a/efiXplorer/efi_hexrays.cc +++ b/efiXplorer/efi_hexrays.cc @@ -19,10 +19,10 @@ #include "efi_hexrays.h" -// Given a tinfo_t specifying a user-defined type (UDT), look up the specified +// given a tinfo_t specifying a user-defined type (UDT), look up the specified // field by its name, and retrieve its offset. -bool offsetOf(tinfo_t tif, const char *name, unsigned int *offset) { - // Get the udt details +bool offset_of(tinfo_t tif, const char *name, unsigned int *offset) { + // get the udt details udt_type_data_t udt; if (!tif.get_udt_details(&udt)) { qstring str; @@ -30,7 +30,7 @@ bool offsetOf(tinfo_t tif, const char *name, unsigned int *offset) { return false; } - // Find the udt member + // find the udt member #if IDA_SDK_VERSION < 840 udt_member_t udm; udm.name = name; @@ -46,14 +46,14 @@ bool offsetOf(tinfo_t tif, const char *name, unsigned int *offset) { return false; } - // Get the offset of the field + // get the offset of the field *offset = static_cast(udt.at(fIdx).offset >> 3ULL); return true; } // Utility function to set a Hex-Rays variable type and set types for the interfaces -bool setHexRaysVariableInfoAndHandleInterfaces(ea_t func_addr, lvar_t &ll, tinfo_t tif, - std::string name) { +bool set_hexrays_var_info_and_handle_interfaces(ea_t func_addr, lvar_t &ll, tinfo_t tif, + std::string name) { lvar_saved_info_t lsi; lsi.ll = ll; lsi.type = tif; @@ -84,7 +84,7 @@ bool setHexRaysVariableInfoAndHandleInterfaces(ea_t func_addr, lvar_t &ll, tinfo } // Utility function to set a Hex-Rays variable name -bool setLvar_name(qstring name, lvar_t lvar, ea_t func_addr) { +bool set_lvar_name(qstring name, lvar_t lvar, ea_t func_addr) { lvar_saved_info_t lsi; lvar_uservec_t lvuv; @@ -98,7 +98,7 @@ bool setLvar_name(qstring name, lvar_t lvar, ea_t func_addr) { } // Utility function to set a Hex-Rays variable type and name -bool setHexRaysVariableInfo(ea_t func_addr, lvar_t &ll, tinfo_t tif, std::string name) { +bool set_hexrays_var_info(ea_t func_addr, lvar_t &ll, tinfo_t tif, std::string name) { lvar_saved_info_t lsi; lsi.ll = ll; lsi.type = tif; @@ -127,7 +127,7 @@ bool setHexRaysVariableInfo(ea_t func_addr, lvar_t &ll, tinfo_t tif, std::string // types, or perhaps pointers to POD types. The final argument allows the // caller to specify the maximum depth "depth" of the pointers. E.g. at // depth 1, "int *[10]" is acceptable. At depth 2, "int **[10]" is acceptable. -bool isPODArray(tinfo_t tif, unsigned int ptrDepth = 0) { +bool is_pod_array(tinfo_t tif, unsigned int ptrDepth = 0) { // If it's not an array, we're done if (!tif.is_array()) return false; @@ -181,13 +181,13 @@ bool isPODArray(tinfo_t tif, unsigned int ptrDepth = 0) { } // Utility function to get a printable qstring from a cexpr_t -const char *Expr2String(cexpr_t *e, qstring *out) { - e->print1(out, NULL); +const char *expr_to_string(cexpr_t *e, qstring *out) { + e->print1(out, nullptr); tag_remove(out); return out->c_str(); } -bool applyAllTypesForInterfacesBootServices(std::vector protocols) { +bool apply_all_types_for_interfaces(std::vector protocols) { if (!init_hexrays_plugin()) { return false; } @@ -237,7 +237,7 @@ bool applyAllTypesForInterfacesBootServices(std::vector protocols) { return true; } -bool applyAllTypesForInterfacesSmmServices(std::vector protocols) { +bool apply_all_types_for_interfaces_smm(std::vector protocols) { if (!init_hexrays_plugin()) { return false; } @@ -285,7 +285,7 @@ bool applyAllTypesForInterfacesSmmServices(std::vector protocols) { return true; } -uint8_t VariablesInfoExtractAll(func_t *f, ea_t code_addr) { +uint8_t variables_info_extract_all(func_t *f, ea_t code_addr) { if (!init_hexrays_plugin()) { return 0xff; } @@ -306,7 +306,7 @@ uint8_t VariablesInfoExtractAll(func_t *f, ea_t code_addr) { return res; } -bool TrackEntryParams(func_t *f, uint8_t depth) { +bool track_entry_params(func_t *f, uint8_t depth) { if (!init_hexrays_plugin()) { return false; } @@ -314,26 +314,29 @@ bool TrackEntryParams(func_t *f, uint8_t depth) { if (depth == 2) { return true; } - // check func + if (f == nullptr) { return false; } + hexrays_failure_t hf; cfuncptr_t cfunc = decompile(f, &hf, DECOMP_NO_WAIT); if (cfunc == nullptr) { return false; } + PrototypesFixer *pf = new PrototypesFixer(); pf->apply_to(&cfunc->body, nullptr); for (auto addr : pf->child_functions) { - TrackEntryParams(get_func(addr), ++depth); + track_entry_params(get_func(addr), ++depth); } + delete pf; return true; } -json DetectVars(func_t *f) { +json detect_vars(func_t *f) { json res; if (!init_hexrays_plugin()) { @@ -354,7 +357,7 @@ json DetectVars(func_t *f) { vars_detector.SetFuncEa(f->start_ea); vars_detector.apply_to(&cfunc->body, nullptr); - res["gImageHandleList"] = vars_detector.gImageHandleList; + res["image_handle_list"] = vars_detector.image_handle_list; res["st_list"] = vars_detector.st_list; res["bs_list"] = vars_detector.bs_list; res["rt_list"] = vars_detector.rt_list; @@ -362,7 +365,7 @@ json DetectVars(func_t *f) { return res; } -std::vector DetectServices(func_t *f) { +std::vector detect_services(func_t *f) { // check func std::vector res; @@ -383,7 +386,7 @@ std::vector DetectServices(func_t *f) { return services_detector.services; } -bool DetectPeiServices(func_t *f) { +bool detect_pei_services(func_t *f) { if (!init_hexrays_plugin()) { return false; } @@ -403,7 +406,7 @@ bool DetectPeiServices(func_t *f) { return true; } -std::vector DetectPeiServicesArm(func_t *f) { +std::vector detect_pei_services_arm(func_t *f) { std::vector res; if (!init_hexrays_plugin()) { diff --git a/efiXplorer/efi_hexrays.h b/efiXplorer/efi_hexrays.h index 67d8ad5b..802f16d3 100644 --- a/efiXplorer/efi_hexrays.h +++ b/efiXplorer/efi_hexrays.h @@ -21,21 +21,21 @@ #include "efi_utils.h" -uint8_t VariablesInfoExtractAll(func_t *f, ea_t code_addr); -bool TrackEntryParams(func_t *f, uint8_t depth); -json DetectVars(func_t *f); -std::vector DetectServices(func_t *f); -std::vector DetectPeiServicesArm(func_t *f); -bool DetectPeiServices(func_t *f); -bool setLvar_name(qstring name, lvar_t lvar, ea_t func_addr); -bool applyAllTypesForInterfacesBootServices(std::vector guids); -bool applyAllTypesForInterfacesSmmServices(std::vector guids); // unused -bool setHexRaysVariableInfo(ea_t func_addr, lvar_t &ll, tinfo_t tif, std::string name); -bool setHexRaysVariableInfoAndHandleInterfaces(ea_t func_addr, lvar_t &ll, tinfo_t tif, - std::string name); -bool offsetOf(tinfo_t tif, const char *name, unsigned int *offset); -bool isPODArray(tinfo_t tif, unsigned int ptrDepth); -const char *Expr2String(cexpr_t *e, qstring *out); +uint8_t variables_info_extract_all(func_t *f, ea_t code_addr); +bool track_entry_params(func_t *f, uint8_t depth); +json detect_vars(func_t *f); +std::vector detect_services(func_t *f); +std::vector detect_pei_services_arm(func_t *f); +bool detect_pei_services(func_t *f); +bool set_lvar_name(qstring name, lvar_t lvar, ea_t func_addr); +bool apply_all_types_for_interfaces(std::vector guids); +bool apply_all_types_for_interfaces_smm(std::vector guids); +bool set_hexrays_var_info(ea_t func_addr, lvar_t &ll, tinfo_t tif, std::string name); +bool set_hexrays_var_info_and_handle_interfaces(ea_t func_addr, lvar_t &ll, tinfo_t tif, + std::string name); +bool offset_of(tinfo_t tif, const char *name, unsigned int *offset); +bool is_pod_array(tinfo_t tif, unsigned int ptrDepth); +const char *expr_to_string(cexpr_t *e, qstring *out); // Description of a function pointer within a structure. Ultimately, this // plugin is looking for calls to specific UEFI functions. This structure @@ -94,7 +94,7 @@ class ServiceDescriptor { // Retrieve the offsets of each named function pointer unsigned int offset; - if (!offsetOf(mType, targets[i].name, &offset)) { + if (!offset_of(mType, targets[i].name, &offset)) { return false; } } @@ -410,10 +410,10 @@ class GUIDRelatedVisitorBase : public ctree_visitor_t { lvar_t destVar = varRef.mba->vars[varRef.idx]; // Ensure that it's an array of POD types, or pointers to them - bool bisPODArray = isPODArray(destVar.tif, 1); + bool bis_pod_array = is_pod_array(destVar.tif, 1); // If it is a POD array, good, we'll take it. - return bisPODArray ? x : nullptr; + return bis_pod_array ? x : nullptr; } // For everything else, we really want it to be a reference: either to a @@ -579,8 +579,8 @@ class GUIDRetyper : public GUIDRelatedVisitorBase { lvar_t &destVar = varRef.mba->vars[varRef.idx]; // Set the Hex-Rays variable type auto name = type_to_name(static_cast(tStr.c_str())); - setLvar_name(static_cast(name.c_str()), destVar, mFuncEa); - if (setHexRaysVariableInfoAndHandleInterfaces(mFuncEa, destVar, ptrTif, name)) { + set_lvar_name(static_cast(name.c_str()), destVar, mFuncEa); + if (set_hexrays_var_info_and_handle_interfaces(mFuncEa, destVar, ptrTif, name)) { ++mNumApplied; } } @@ -602,7 +602,7 @@ class GUIDRetyper : public GUIDRelatedVisitorBase { lvar_t &destVar = varRef.mba->vars[varRef.idx]; // Set the Hex-Rays variable type auto name = type_to_name(type_name); - setLvar_name(static_cast(name.c_str()), destVar, mFuncEa); + set_lvar_name(static_cast(name.c_str()), destVar, mFuncEa); } } }; @@ -741,10 +741,10 @@ class PrototypesFixer : public ctree_visitor_t { auto argid = cf->argidx[i]; lvar_t &arg_var = cf->mba->vars[argid]; // get lvar for argument if (type_name == qstring("EFI_HANDLE")) { - setHexRaysVariableInfo(func_addr, arg_var, arg_type, "ImageHandle"); + set_hexrays_var_info(func_addr, arg_var, arg_type, "ImageHandle"); } if (type_name == qstring("EFI_SYSTEM_TABLE")) { - setHexRaysVariableInfo(func_addr, arg_var, arg_type, "SystemTable"); + set_hexrays_var_info(func_addr, arg_var, arg_type, "SystemTable"); } } } @@ -763,7 +763,7 @@ class VariablesDetector : public ctree_visitor_t { std::vector child_functions; - std::vector gImageHandleList; + std::vector image_handle_list; std::vector st_list; std::vector bs_list; std::vector rt_list; @@ -838,8 +838,8 @@ class VariablesDetector : public ctree_visitor_t { std::string type_name_str = static_cast(type_name.c_str()); if (type_name == qstring("EFI_HANDLE")) { set_type_and_name(g_addr, "gImageHandle", type_name_str); - if (!addr_in_vec(gImageHandleList, g_addr)) { - gImageHandleList.push_back(g_addr); + if (!addr_in_vec(image_handle_list, g_addr)) { + image_handle_list.push_back(g_addr); } } if (type_name == qstring("EFI_SYSTEM_TABLE")) { @@ -873,7 +873,7 @@ class VariablesDetector : public ctree_visitor_t { lvar_t &dest_var = var_ref.mba->vars[var_ref.idx]; // Set the Hex-Rays variable type auto name = type_to_name(static_cast(type_name.c_str())); - // setHexRaysVariableInfo(mFuncEa, dest_var, var_type, name); + // set_hexrays_var_info(mFuncEa, dest_var, var_type, name); } return 0; diff --git a/efiXplorer/efi_ui.cc b/efiXplorer/efi_ui.cc index 25324b24..197658e3 100644 --- a/efiXplorer/efi_ui.cc +++ b/efiXplorer/efi_ui.cc @@ -290,8 +290,9 @@ struct protocols_deps_handler_t : public action_handler_t { }; static protocols_deps_handler_t protocols_deps_ah; -action_desc_t protocols_deps = ACTION_DESC_LITERAL( - "efiXplorer:protocolsDeps", "Show dependencies", &protocols_deps_ah, NULL, NULL, -1); +action_desc_t protocols_deps = + ACTION_DESC_LITERAL("efiXplorer:protocolsDeps", "Show dependencies", + &protocols_deps_ah, nullptr, nullptr, -1); void attachActionProtocolsDeps() { // Attach action in protocols chooser @@ -323,7 +324,7 @@ struct modules_seq_handler_t : public action_handler_t { static modules_seq_handler_t modules_seq_ah; action_desc_t modules_seq = ACTION_DESC_LITERAL("efiXplorer:modulesSeq", "Show the sequence of modules execution", - &modules_seq_ah, NULL, NULL, -1); + &modules_seq_ah, nullptr, nullptr, -1); void attachActionModulesSeq() { // Attach action in protocols chooser @@ -439,4 +440,4 @@ static action_handler_loadreport_t load_report_handler; // Action to load efiXplorer analysis report action_desc_t action_load_report = ACTION_DESC_LITERAL("efiXplorer:loadReport", "efiXplorer analysis report...", - &load_report_handler, NULL, NULL, -1); + &load_report_handler, nullptr, nullptr, -1); diff --git a/efiXplorer/efi_utils.cc b/efiXplorer/efi_utils.cc index e7c1326f..9e517fa7 100644 --- a/efiXplorer/efi_utils.cc +++ b/efiXplorer/efi_utils.cc @@ -528,7 +528,7 @@ std::vector unpack_guid(std::string guid) { } for (auto i = 0; i < hex.size(); i += 2) { byte_str = hex.substr(i, 2); - byte = static_cast(strtol(byte_str.c_str(), NULL, 16)); + byte = static_cast(strtol(byte_str.c_str(), nullptr, 16)); tmp.push_back(byte); } if (index != 3) { @@ -543,7 +543,7 @@ std::vector unpack_guid(std::string guid) { for (auto i = 0; i < guid.size(); i += 2) { byte_str = guid.substr(i, 2); - byte = static_cast(strtol(byte_str.c_str(), NULL, 16)); + byte = static_cast(strtol(byte_str.c_str(), nullptr, 16)); res.push_back(byte); } diff --git a/efiXplorer/efixplorer.cc b/efiXplorer/efixplorer.cc index b41e2a45..a307947c 100644 --- a/efiXplorer/efixplorer.cc +++ b/efiXplorer/efixplorer.cc @@ -21,10 +21,8 @@ #include "efi_global.h" #include "efi_ui.h" -static const char plugin_hotkey[] = "Ctrl+Alt+E"; -static const char plugin_comment[] = - "This plugin performs automatic analysis of the input UEFI module"; -static const char plugin_help[] = +static const char hotkey[] = "Ctrl+Alt+E"; +static const char description[] = "This plugin performs automatic analysis of the input UEFI module"; static const char welcome_msg[] = " ____ _ __ __\n" " ___ / _(_) |/_/__ / /__ _______ ____\n" @@ -127,12 +125,12 @@ bool idaapi run(size_t arg) { // PLUGIN DESCRIPTION BLOCK plugin_t PLUGIN = { IDP_INTERFACE_VERSION, - 0, // plugin flags - init, // initialize plugin - nullptr, // terminate plugin - run, // invoke plugin - plugin_comment, // long comment about the plugin - plugin_help, // multiline help about the plugin - g_plugin_name, // the preferred short name of the plugin - plugin_hotkey // the preferred hotkey to run the plugin + 0, // plugin flags + init, // initialize plugin + nullptr, // terminate plugin + run, // invoke plugin + description, // long comment about the plugin + description, // multiline help about the plugin + g_plugin_name, // the preferred short name of the plugin + hotkey // the preferred hotkey to run the plugin }; From 10c4766203e0d1920de982dcecbc7bc6baadd2ba Mon Sep 17 00:00:00 2001 From: yeggor Date: Sat, 14 Sep 2024 05:26:44 +0200 Subject: [PATCH 20/69] switch to c++20 in cmake, use std::format instead of snprintf --- efiXplorer/CMakeLists.txt | 4 ++-- efiXplorer/efi_analyser_x86.cc | 12 ++++++++---- efiXplorer/efi_utils.cc | 34 ++++++++++++++++------------------ efiXplorer/efi_utils.h | 13 +++++++------ 4 files changed, 33 insertions(+), 30 deletions(-) diff --git a/efiXplorer/CMakeLists.txt b/efiXplorer/CMakeLists.txt index 32ddf7b2..68aac1ff 100644 --- a/efiXplorer/CMakeLists.txt +++ b/efiXplorer/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.7) project(efiXplorer CXX) -set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) @@ -53,7 +53,7 @@ endif() add_ida_plugin(efiXplorer ${PROJECT_SOURCE_DIR}/efixplorer.cc) -set_ida_target_properties(efiXplorer PROPERTIES CXX_STANDARD 17) +set_ida_target_properties(efiXplorer PROPERTIES CXX_STANDARD 20) ida_target_include_directories(efiXplorer PRIVATE ${IdaSdk_INCLUDE_DIRS}) add_ida_library(efiXplorer_lib ${efiXplorer_src}) diff --git a/efiXplorer/efi_analyser_x86.cc b/efiXplorer/efi_analyser_x86.cc index 01d223fd..5854c666 100644 --- a/efiXplorer/efi_analyser_x86.cc +++ b/efiXplorer/efi_analyser_x86.cc @@ -1263,24 +1263,28 @@ void efi_analysis::EfiAnalyserX86::getProtBootServicesX86() { } //-------------------------------------------------------------------------- -// find other addresses of global gBS vars for X64 modules +// find other addresses of gBS variables for X86-64 modules void efi_analysis::EfiAnalyserX86::findOtherBsTablesX64() { - msg("[%s] Finding of other addresses of global gBS variables\n", g_plugin_name); + msg("[%s] find other addresses of gBS variables\n", g_plugin_name); for (auto s : allServices) { std::string table_name = s["table_name"]; - if (table_name.compare(static_cast("EFI_BOOT_SERVICES"))) { + if (table_name.compare("EFI_BOOT_SERVICES")) { continue; } + auto offset = u32_addr(s["offset"]); if (offset < 0xf0) { continue; } + ea_t addr = static_cast(s["address"]); msg("[%s] current service: 0x%016llX\n", g_plugin_name, u64_addr(addr)); ea_t addr_bs = find_unknown_bs_var_64(addr); - if (!addr_bs || addr_in_vec(bs_list, addr_bs) || addr_in_vec(rt_list, addr_bs)) { + + if (addr_bs == BADADDR || addr_in_tables(bs_list, rt_list, addr_bs)) { continue; } + msg("[%s] found BootServices table at 0x%016llX, address = 0x%016llX\n", g_plugin_name, u64_addr(addr), u64_addr(addr_bs)); set_ptr_type_and_name(addr_bs, "gBS", "EFI_BOOT_SERVICES"); diff --git a/efiXplorer/efi_utils.cc b/efiXplorer/efi_utils.cc index 9e517fa7..58778d04 100644 --- a/efiXplorer/efi_utils.cc +++ b/efiXplorer/efi_utils.cc @@ -501,15 +501,14 @@ bool valid_guid(json guid) { //-------------------------------------------------------------------------- // convert GUID value to string std::string guid_to_string(json guid) { - char guid_str[37] = {0}; - snprintf(guid_str, 37, "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X", - static_cast(guid[0]), static_cast(guid[1]), - static_cast(guid[2]), static_cast(guid[3]), - static_cast(guid[4]), static_cast(guid[5]), - static_cast(guid[6]), static_cast(guid[7]), - static_cast(guid[8]), static_cast(guid[9]), - static_cast(guid[10])); - return static_cast(guid_str); + return std::format( + "{:08X}-{:04X}-{:04X}-{:02X}{:02X}-{:02X}{:02X}{:02X}{:02X}{:02X}{:02X}", + static_cast(guid[0]), static_cast(guid[1]), + static_cast(guid[2]), static_cast(guid[3]), + static_cast(guid[4]), static_cast(guid[5]), + static_cast(guid[6]), static_cast(guid[7]), + static_cast(guid[8]), static_cast(guid[9]), + static_cast(guid[10])); } std::vector unpack_guid(std::string guid) { @@ -594,11 +593,7 @@ bool check_install_protocol(ea_t ea) { //-------------------------------------------------------------------------- // convert 64-bit value to hex string -std::string as_hex(uint64_t value) { - char hexstr[21] = {}; - snprintf(hexstr, 21, "%llX", value); - return static_cast(hexstr); -} +std::string as_hex(uint64_t value) { return std::format("{:016X}", value); } //-------------------------------------------------------------------------- // make sure the first argument looks like a protocol @@ -841,10 +836,13 @@ bool json_in_vec(std::vector vec, json item) { return find(vec.begin(), vec.end(), item) != vec.end(); } -bool addr_in_tables(std::vector st_list, std::vector bs_list, - std::vector rt_list, ea_t ea) { - return (addr_in_vec(st_list, ea) || addr_in_vec(bs_list, ea) || - addr_in_vec(rt_list, ea)); +bool addr_in_tables(std::vector t1, std::vector t2, ea_t ea) { + return (addr_in_vec(t1, ea) || addr_in_vec(t2, ea)); +} + +bool addr_in_tables(std::vector t1, std::vector t2, std::vector t3, + ea_t ea) { + return (addr_in_vec(t1, ea) || addr_in_vec(t2, ea) || addr_in_vec(t3, ea)); } std::vector find_data(ea_t start_ea, ea_t end_ea, uchar *data, size_t len) { diff --git a/efiXplorer/efi_utils.h b/efiXplorer/efi_utils.h index 99db47a6..593f1ef7 100644 --- a/efiXplorer/efi_utils.h +++ b/efiXplorer/efi_utils.h @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -77,18 +78,18 @@ struct EfiGuid { return res; } - std::string to_string() { - char res[37] = {0}; - snprintf(res, 37, "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X", data1, data2, - data3, data4[0], data4[1], data4[2], data4[3], data4[4], data4[5], data4[6], - data4[7]); - return static_cast(res); + std::string to_string() const { + return std::format( + "{:08X}-{:04X}-{:04X}-{:02X}{:02X}-{:02X}{:02X}{:02X}{:02X}{:02X}{:02X}", data1, + data2, data3, data4[0], data4[1], data4[2], data4[3], data4[4], data4[5], + data4[6], data4[7]); } }; ArchFileType input_file_type(); bool add_struct_for_shifted_ptr(); +bool addr_in_tables(std::vector bs_list, std::vector rt_list, ea_t ea); bool addr_in_tables(std::vector st_list, std::vector bs_list, std::vector rt_list, ea_t ea); bool addr_in_vec(std::vector vec, ea_t addr); From 0c687b2d58ca6bbbd1b8110c248d858138b4bbe2 Mon Sep 17 00:00:00 2001 From: yeggor Date: Sat, 14 Sep 2024 05:48:58 +0200 Subject: [PATCH 21/69] use aliases for vectors --- efiXplorer/efi_analyser.h | 63 ++++++++++++++------------- efiXplorer/efi_analyser_arm.cc | 12 +++--- efiXplorer/efi_analyser_x86.cc | 78 +++++++++++++++++----------------- efiXplorer/efi_defs.h | 4 +- efiXplorer/efi_deps.cc | 24 +++++------ efiXplorer/efi_deps.h | 6 +-- efiXplorer/efi_hexrays.cc | 12 +++--- efiXplorer/efi_hexrays.h | 28 ++++++------ efiXplorer/efi_smm_utils.cc | 63 +++++++++++++-------------- efiXplorer/efi_smm_utils.h | 19 ++++----- efiXplorer/efi_ui.cc | 33 +++++++------- efiXplorer/efi_ui.h | 32 +++++++------- efiXplorer/efi_utils.cc | 45 ++++++++++---------- efiXplorer/efi_utils.h | 41 +++++++++++------- 14 files changed, 228 insertions(+), 232 deletions(-) diff --git a/efiXplorer/efi_analyser.h b/efiXplorer/efi_analyser.h index 0929f751..8d166a93 100644 --- a/efiXplorer/efi_analyser.h +++ b/efiXplorer/efi_analyser.h @@ -34,11 +34,11 @@ class EfiAnalyser { EfiAnalyser(); ~EfiAnalyser(); - std::vector allGuids; - std::vector allProtocols; - std::vector allPPIs; - std::vector allServices; - std::vector smiHandlers; + json_list_t allGuids; + json_list_t allProtocols; + json_list_t allPPIs; + json_list_t allServices; + func_list_t smiHandlers; ArchFileType arch = ArchFileType::Unsupported; FfsFileType file_type = FfsFileType::Unsupported; @@ -52,7 +52,7 @@ class EfiAnalyser { bool efiSmmCpuProtocolResolver(); void findSwSmiHandlers(); - bool findGetVariableOveflow(std::vector allServices); + bool findGetVariableOveflow(json_list_t allServices); bool findPPIGetVariableStackOveflow(); bool findSmmGetVariableOveflow(); bool findSmmCallout(); @@ -66,7 +66,7 @@ class EfiAnalyser { ea_t base; ea_t startAddress = 0; ea_t endAddress = 0; - std::vector funcs; + ea_list_t funcs; std::filesystem::path guidsJsonPath; std::map dbProtocolsMap; // a map to look up a GUID name by value json bootServices; @@ -76,14 +76,14 @@ class EfiAnalyser { json runtimeServicesAll; json smmServices; json smmServicesAll; - std::vector nvramVariables; - std::vector markedInterfaces; + json_list_t nvramVariables; + ea_list_t markedInterfaces; // Format-dependent interface-related settings (protocols for DXE, PPIs for PEI) std::string if_name; std::string if_pl; std::string if_key; - std::vector *if_tbl; + json_list_t *if_tbl; // EFI_SMM_SW_DISPATCH2_PROTOCOL_GUID EfiGuid sw_guid2 = { @@ -194,7 +194,7 @@ class EfiAnalyser { EfiGuid fch_apu_ras_guid = { 0xf871ee59, 0x29d2, 0x4b15, {0x9e, 0x67, 0xaf, 0x32, 0xcd, 0xc1, 0x41, 0x73}}; - std::vector ppiFlags = { + uint64_list_t ppiFlags = { 0x1, 0x10, 0x11, 0x20, 0x21, 0x30, 0x31, 0x40, 0x41, 0x50, 0x51, 0x60, 0x61, 0x70, 0x71, 0x80000000, 0x80000001, 0x80000010, 0x80000011, 0x80000020, 0x80000021, @@ -203,31 +203,30 @@ class EfiAnalyser { }; // Set boot services that work with protocols - std::vector protBsNames = {"InstallProtocolInterface", - "ReinstallProtocolInterface", - "UninstallProtocolInterface", - "HandleProtocol", - "RegisterProtocolNotify", - "OpenProtocol", - "CloseProtocol", - "OpenProtocolInformation", - "ProtocolsPerHandle", - "LocateHandleBuffer", - "LocateProtocol", - "InstallMultipleProtocolInterfaces", - "UninstallMultipleProtocolInterfaces"}; + string_list_t protBsNames = {"InstallProtocolInterface", + "ReinstallProtocolInterface", + "UninstallProtocolInterface", + "HandleProtocol", + "RegisterProtocolNotify", + "OpenProtocol", + "CloseProtocol", + "OpenProtocolInformation", + "ProtocolsPerHandle", + "LocateHandleBuffer", + "LocateProtocol", + "InstallMultipleProtocolInterfaces", + "UninstallMultipleProtocolInterfaces"}; // Set smm services that work with protocols - std::vector protSmmNames = {"SmmInstallProtocolInterface", - "SmmUninstallProtocolInterface", - "SmmHandleProtocol", - "SmmRegisterProtocolNotify", - "SmmLocateHandle", - "SmmLocateProtocol"}; + string_list_t protSmmNames = {"SmmInstallProtocolInterface", + "SmmUninstallProtocolInterface", + "SmmHandleProtocol", + "SmmRegisterProtocolNotify", + "SmmLocateHandle", + "SmmLocateProtocol"}; // Set of PEI services that work with PPI - std::vector ppiPEINames = {"InstallPpi", "ReInstallPpi", "LocatePpi", - "NotifyPpi"}; + string_list_t ppiPEINames = {"InstallPpi", "ReInstallPpi", "LocatePpi", "NotifyPpi"}; }; class EfiAnalyserX86 : public EfiAnalyser { diff --git a/efiXplorer/efi_analyser_arm.cc b/efiXplorer/efi_analyser_arm.cc index cac25f55..e7b4f2ce 100644 --- a/efiXplorer/efi_analyser_arm.cc +++ b/efiXplorer/efi_analyser_arm.cc @@ -24,10 +24,10 @@ using namespace efi_analysis; -std::vector image_handle_list_arm; -std::vector st_list_arm; -std::vector bs_list_arm; -std::vector rt_list_arm; +ea_list_t image_handle_list_arm; +ea_list_t st_list_arm; +ea_list_t bs_list_arm; +ea_list_t rt_list_arm; void efi_analysis::EfiAnalyserArm::fixOffsets() { insn_t insn; @@ -294,7 +294,7 @@ void efi_analysis::EfiAnalyserArm::servicesDetection() { #ifdef HEX_RAYS for (auto func_addr : funcs) { - std::vector services = detect_services(get_func(func_addr)); + json_list_t services = detect_services(get_func(func_addr)); for (auto service : services) { allServices.push_back(service); } @@ -489,7 +489,7 @@ bool efi_analysis::efiAnalyserMainArm() { #ifdef HEX_RAYS for (auto addr : analyser.funcs) { - std::vector services = detect_pei_services_arm(get_func(addr)); + json_list_t services = detect_pei_services_arm(get_func(addr)); for (auto service : services) { analyser.allServices.push_back(service); } diff --git a/efiXplorer/efi_analyser_x86.cc b/efiXplorer/efi_analyser_x86.cc index 5854c666..7085e281 100644 --- a/efiXplorer/efi_analyser_x86.cc +++ b/efiXplorer/efi_analyser_x86.cc @@ -28,35 +28,35 @@ using namespace efi_analysis; -extern std::vector g_get_smst_location_calls; -extern std::vector g_smm_get_variable_calls; -extern std::vector g_smm_set_variable_calls; +extern ea_list_t g_get_smst_location_calls; +extern ea_list_t g_smm_get_variable_calls; +extern ea_list_t g_smm_set_variable_calls; -std::vector st_list; // gST list (system table addresses) -std::vector ps_list; // gPS list (PEI services addresses) -std::vector bs_list; // gBS list (boot services addresses) -std::vector rt_list; // gRT list (runtime services addresses) -std::vector smst_list; // gSmst list (SMM system table addresses) -std::vector image_handle_list; // gImageHandle list (image handle addresses) -std::vector runtime_services_list; // runtime services list +ea_list_t st_list; // gST list (system table addresses) +ea_list_t ps_list; // gPS list (PEI services addresses) +ea_list_t bs_list; // gBS list (boot services addresses) +ea_list_t rt_list; // gRT list (runtime services addresses) +ea_list_t smst_list; // gSmst list (SMM system table addresses) +ea_list_t image_handle_list; // gImageHandle list (image handle addresses) +ea_list_t runtime_services_list; // runtime services list -std::vector stackGuids; -std::vector dataGuids; +json_list_t stackGuids; +json_list_t dataGuids; // all .text and .data segments for compatibility with the efiLoader -std::vector textSegments; -std::vector dataSegments; +segment_list_t textSegments; +segment_list_t dataSegments; // for smm callouts finding -std::vector calloutAddrs; -std::vector excFunctions; -std::vector childSmiHandlers; -std::vector readSaveStateCalls; +ea_list_t calloutAddrs; +func_list_t excFunctions; +func_list_t childSmiHandlers; +ea_list_t readSaveStateCalls; // for GetVariable stack overflow finding -std::vector peiGetVariableOverflow; -std::vector getVariableOverflow; -std::vector smmGetVariableOverflow; +ea_list_t peiGetVariableOverflow; +ea_list_t getVariableOverflow; +ea_list_t smmGetVariableOverflow; efi_analysis::EfiAnalyser::EfiAnalyser() { // 32-bit, 64-bit, ARM or UEFI (in loader instance) @@ -89,7 +89,7 @@ efi_analysis::EfiAnalyser::EfiAnalyser() { funcs.push_back(func->start_ea); } - std::vector addrs; + ea_list_t addrs; for (auto service : protBsNames) { bootServices[service] = addrs; } @@ -172,8 +172,7 @@ void efi_analysis::EfiAnalyser::getSegments() { qstring seg_name; get_segm_name(&seg_name, s); - std::vector codeSegNames{ - ".text", ".code"}; // for compatibility with ida-efitools2 + string_list_t codeSegNames{".text", ".code"}; // for compatibility with ida-efitools2 for (auto name : codeSegNames) { auto index = seg_name.find(name.c_str()); if (index != std::string::npos) { @@ -268,8 +267,8 @@ bool efi_analysis::EfiAnalyserX86::findSystemTableX64() { // Find and mark gSmst global variable address for X64 module bool efi_analysis::EfiAnalyserX86::findSmstX64() { msg("[%s] gSmst finding\n", g_plugin_name); - std::vector smst_listSmmBase = findSmstSmmBase(bs_list); - std::vector smst_listSwDispatch = findSmstSwDispatch(bs_list); + ea_list_t smst_listSmmBase = findSmstSmmBase(bs_list); + ea_list_t smst_listSwDispatch = findSmstSwDispatch(bs_list); smst_list.insert(smst_list.end(), smst_listSwDispatch.begin(), smst_listSwDispatch.end()); smst_list.insert(smst_list.end(), smst_listSmmBase.begin(), smst_listSmmBase.end()); @@ -1067,7 +1066,7 @@ void efi_analysis::EfiAnalyserX86::getPpiNamesX86() { continue; } - std::vector addrs = peiServicesAll[g_pei_services_table32[i].name]; + ea_list_t addrs = peiServicesAll[g_pei_services_table32[i].name]; // for each PEI service for (auto ea : addrs) { @@ -1334,7 +1333,7 @@ bool efi_analysis::EfiAnalyser::AddProtocol(std::string serviceName, ea_t guidAd //-------------------------------------------------------------------------- // Extract protocols from InstallMultipleProtocolInterfaces service call bool efi_analysis::EfiAnalyserX86::InstallMultipleProtocolInterfacesHandler() { - std::vector addrs = bootServices["InstallMultipleProtocolInterfaces"]; + ea_list_t addrs = bootServices["InstallMultipleProtocolInterfaces"]; std::map stack_params; insn_t insn; @@ -1434,7 +1433,7 @@ void efi_analysis::EfiAnalyserX86::getBsProtNamesX64() { continue; } - std::vector addrs = bootServices[g_boot_services_table64[i].name]; + ea_list_t addrs = bootServices[g_boot_services_table64[i].name]; for (auto ea : addrs) { ea_t address = ea; msg("[%s] looking for protocols in the 0x%016llX area\n", g_plugin_name, @@ -1505,7 +1504,7 @@ void efi_analysis::EfiAnalyserX86::getBsProtNamesX86() { start = seg_info->start_ea; } for (int i = 0; i < g_boot_services_table32_count; i++) { - std::vector addrs = bootServices[g_boot_services_table32[i].name]; + ea_list_t addrs = bootServices[g_boot_services_table32[i].name]; // for each boot service for (auto ea : addrs) { @@ -1973,7 +1972,7 @@ bool efi_analysis::EfiAnalyser::findPPIGetVariableStackOveflow() { msg("[%s] Looking for PPI GetVariable buffer overflow, " "allServices.size() = %lu\n", g_plugin_name, allServices.size()); - std::vector getVariableServicesCalls; + ea_list_t getVariableServicesCalls; std::string getVariableStr("VariablePPI.GetVariable"); for (auto j_service : allServices) { json service = j_service; @@ -2137,9 +2136,9 @@ bool efi_analysis::EfiAnalyser::findPPIGetVariableStackOveflow() { //-------------------------------------------------------------------------- // Find potential stack/heap overflow with double GetVariable calls -bool efi_analysis::EfiAnalyser::findGetVariableOveflow(std::vector allServices) { +bool efi_analysis::EfiAnalyser::findGetVariableOveflow(json_list_t allServices) { msg("[%s] Looking for GetVariable stack/heap overflow\n", g_plugin_name); - std::vector getVariableServicesCalls; + ea_list_t getVariableServicesCalls; std::string getVariableStr("GetVariable"); for (auto j_service : allServices) { json service = j_service; @@ -2273,8 +2272,7 @@ bool efi_analysis::EfiAnalyser::findGetVariableOveflow(std::vector allServ // Find potential stack/heap overflow with double SmmGetVariable calls bool efi_analysis::EfiAnalyser::findSmmGetVariableOveflow() { msg("[%s] Looking for SmmGetVariable stack/heap overflow\n", g_plugin_name); - std::vector smmGetVariableCalls = - findSmmGetVariableCalls(dataSegments, &allServices); + ea_list_t smmGetVariableCalls = findSmmGetVariableCalls(dataSegments, &allServices); sort(smmGetVariableCalls.begin(), smmGetVariableCalls.end()); if (smmGetVariableCalls.size() < 2) { msg("[%s] less than 2 GetVariable calls found\n", g_plugin_name); @@ -2473,9 +2471,9 @@ bool efi_analysis::EfiAnalyser::AnalyseVariableService(ea_t ea, std::string serv bool efi_analysis::EfiAnalyser::analyseNvramVariables() { msg("[%s] Get NVRAM variables information\n", g_plugin_name); - std::vector nvram_services = {"GetVariable", "SetVariable"}; + string_list_t nvram_services = {"GetVariable", "SetVariable"}; for (auto service_str : nvram_services) { - std::vector var_services; + ea_list_t var_services; for (auto j_service : allServices) { json service = j_service; std::string service_name = static_cast(service["service_name"]); @@ -2557,7 +2555,7 @@ void efi_analysis::EfiAnalyser::dumpInfo() { info["vulns"]["smm_get_variable_buffer_overflow"] = smmGetVariableOverflow; } - std::vector smiHandlersAddrs; + json_list_t smiHandlersAddrs; if (smiHandlers.size() > 0) { for (auto f : smiHandlers) { func_t *func = f; @@ -2616,8 +2614,8 @@ void showAllChoosers(efi_analysis::EfiAnalyserX86 analyser) { // open window with vulnerabilities if (calloutAddrs.size() || peiGetVariableOverflow.size() || getVariableOverflow.size() || smmGetVariableOverflow.size()) { - std::vector vulns; - std::map> vulns_map = { + json_list_t vulns; + std::map vulns_map = { {"SmmCallout", calloutAddrs}, {"PeiGetVariableOverflow", peiGetVariableOverflow}, {"DxeGetVariableOverflow", getVariableOverflow}, diff --git a/efiXplorer/efi_defs.h b/efiXplorer/efi_defs.h index f265a73c..5b448ed1 100644 --- a/efiXplorer/efi_defs.h +++ b/efiXplorer/efi_defs.h @@ -19,8 +19,8 @@ #pragma once -#include -#include +#include +#include #define COPYRIGHT "(C) 2020-2024 Binarly - https://github.com/binarly-io/efiXplorer" diff --git a/efiXplorer/efi_deps.cc b/efiXplorer/efi_deps.cc index 4fc68465..725d7d11 100644 --- a/efiXplorer/efi_deps.cc +++ b/efiXplorer/efi_deps.cc @@ -64,7 +64,7 @@ json EfiDependencies::getDeps(std::string guid) { return res; } -void EfiDependencies::getProtocolsByGuids(std::vector protocols) { +void EfiDependencies::getProtocolsByGuids(json_list_t protocols) { for (auto p : protocols) { // check if entry for GUID already exist std::string guid = p["guid"]; @@ -75,7 +75,7 @@ void EfiDependencies::getProtocolsByGuids(std::vector protocols) { } } -void EfiDependencies::getProtocolsChooser(std::vector protocols) { +void EfiDependencies::getProtocolsChooser(json_list_t protocols) { auto i = 0; for (auto p : protocols) { protocolsChooser[i] = p; @@ -121,7 +121,7 @@ bool EfiDependencies::installerFound(std::string protocol) { void EfiDependencies::getProtocolsWithoutInstallers() { // Check DXE_DEPEX and MM_DEPEX - std::vector sections{"EFI_SECTION_DXE_DEPEX", "EFI_SECTION_MM_DEPEX"}; + string_list_t sections{"EFI_SECTION_DXE_DEPEX", "EFI_SECTION_MM_DEPEX"}; for (auto section : sections) { auto images = uefitoolDeps[section]; for (auto &element : images.items()) { @@ -186,7 +186,7 @@ void EfiDependencies::getImages() { qstring seg_name; get_segm_name(&seg_name, s); - std::vector codeSegNames{"_.text", "_.code"}; + string_list_t codeSegNames{"_.text", "_.code"}; for (auto name : codeSegNames) { auto index = seg_name.find(name.c_str()); if (index != std::string::npos) { @@ -203,7 +203,7 @@ void EfiDependencies::getImages() { json EfiDependencies::getImageInfo(std::string image) { json info; - std::vector installedProtocols; + string_list_t installedProtocols; json depsProtocols; std::vector installers({"InstallProtocolInterface", "InstallMultipleProtocolInterfaces", "SmmInstallProtocolInterface"}); @@ -234,7 +234,7 @@ json EfiDependencies::getImageInfo(std::string image) { // Get deps bool found = false; - std::vector sections{"EFI_SECTION_DXE_DEPEX", "EFI_SECTION_MM_DEPEX"}; + string_list_t sections{"EFI_SECTION_DXE_DEPEX", "EFI_SECTION_MM_DEPEX"}; for (auto section : sections) { json deps_images = uefitoolDeps[section]; for (auto &element : deps_images.items()) { @@ -275,7 +275,7 @@ std::string EfiDependencies::getInstaller(std::string protocol) { std::string res; for (auto &e : imagesInfo.items()) { std::string image = e.key(); - std::vector installers = imagesInfo[image]["installed_protocols"]; + string_list_t installers = imagesInfo[image]["installed_protocols"]; if (find(installers.begin(), installers.end(), protocol) != installers.end()) { return image; } @@ -306,7 +306,7 @@ bool EfiDependencies::buildModulesSequence() { continue; } - std::vector installers = imagesInfo[image]["installed_protocols"]; + string_list_t installers = imagesInfo[image]["installed_protocols"]; // if there are no dependencies if (imagesInfo[image]["deps_protocols"].is_null()) { @@ -321,8 +321,8 @@ bool EfiDependencies::buildModulesSequence() { continue; } - std::vector deps = imagesInfo[image]["deps_protocols"]; - std::vector unresolved_deps; + string_list_t deps = imagesInfo[image]["deps_protocols"]; + string_list_t unresolved_deps; bool load = true; for (auto protocol : deps) { if (installed_protocols.find(protocol) != installed_protocols.end()) { @@ -368,7 +368,7 @@ bool EfiDependencies::buildModulesSequence() { continue; } - std::vector deps_protocols = imagesInfo[image]["deps_protocols"]; + string_list_t deps_protocols = imagesInfo[image]["deps_protocols"]; for (auto protocol : deps_protocols) { if (installed_protocols.find(protocol) != installed_protocols.end()) { continue; @@ -402,7 +402,7 @@ bool EfiDependencies::buildModulesSequence() { break; // something went wrong, extra mitigation for an infinite loop } // load installer_image - std::vector current_installers = + string_list_t current_installers = imagesInfo[installer_image]["installed_protocols"]; for (auto protocol : current_installers) { installed_protocols.insert(protocol); diff --git a/efiXplorer/efi_deps.h b/efiXplorer/efi_deps.h index 3021b587..e5a44e90 100644 --- a/efiXplorer/efi_deps.h +++ b/efiXplorer/efi_deps.h @@ -32,11 +32,11 @@ class EfiDependencies { json additionalInstallers; // getAdditionalInstallers result json imagesInfo; // getImagesInfo result json modulesSequence; // buildModulesSequence result - std::vector imagesFromIdb; + string_list_t imagesFromIdb; std::set untrackedProtocols; // Input: protocols from report - void getProtocolsByGuids(std::vector protocols); - void getProtocolsChooser(std::vector protocols); + void getProtocolsByGuids(json_list_t protocols); + void getProtocolsChooser(json_list_t protocols); json getDeps(std::string protocol); // get dependencies for specific protocol void getAdditionalInstallers(); // get installers by protocol GUIDs by searching in // the firmware and analysing xrefs diff --git a/efiXplorer/efi_hexrays.cc b/efiXplorer/efi_hexrays.cc index e150a239..9d9cc066 100644 --- a/efiXplorer/efi_hexrays.cc +++ b/efiXplorer/efi_hexrays.cc @@ -187,7 +187,7 @@ const char *expr_to_string(cexpr_t *e, qstring *out) { return out->c_str(); } -bool apply_all_types_for_interfaces(std::vector protocols) { +bool apply_all_types_for_interfaces(json_list_t protocols) { if (!init_hexrays_plugin()) { return false; } @@ -237,7 +237,7 @@ bool apply_all_types_for_interfaces(std::vector protocols) { return true; } -bool apply_all_types_for_interfaces_smm(std::vector protocols) { +bool apply_all_types_for_interfaces_smm(json_list_t protocols) { if (!init_hexrays_plugin()) { return false; } @@ -365,9 +365,9 @@ json detect_vars(func_t *f) { return res; } -std::vector detect_services(func_t *f) { +json_list_t detect_services(func_t *f) { // check func - std::vector res; + json_list_t res; if (!init_hexrays_plugin()) { return res; @@ -406,8 +406,8 @@ bool detect_pei_services(func_t *f) { return true; } -std::vector detect_pei_services_arm(func_t *f) { - std::vector res; +json_list_t detect_pei_services_arm(func_t *f) { + json_list_t res; if (!init_hexrays_plugin()) { return res; diff --git a/efiXplorer/efi_hexrays.h b/efiXplorer/efi_hexrays.h index 802f16d3..a49bdf9b 100644 --- a/efiXplorer/efi_hexrays.h +++ b/efiXplorer/efi_hexrays.h @@ -24,12 +24,12 @@ uint8_t variables_info_extract_all(func_t *f, ea_t code_addr); bool track_entry_params(func_t *f, uint8_t depth); json detect_vars(func_t *f); -std::vector detect_services(func_t *f); -std::vector detect_pei_services_arm(func_t *f); +json_list_t detect_services(func_t *f); +json_list_t detect_pei_services_arm(func_t *f); bool detect_pei_services(func_t *f); bool set_lvar_name(qstring name, lvar_t lvar, ea_t func_addr); -bool apply_all_types_for_interfaces(std::vector guids); -bool apply_all_types_for_interfaces_smm(std::vector guids); +bool apply_all_types_for_interfaces(json_list_t guids); +bool apply_all_types_for_interfaces_smm(json_list_t guids); bool set_hexrays_var_info(ea_t func_addr, lvar_t &ll, tinfo_t tif, std::string name); bool set_hexrays_var_info_and_handle_interfaces(ea_t func_addr, lvar_t &ll, tinfo_t tif, std::string name); @@ -204,7 +204,7 @@ class GUIDRelatedVisitorBase : public ctree_visitor_t { // We need the function ea when setting Hex-Rays variable types. void SetFuncEa(ea_t ea) { mFuncEa = ea; }; void SetCodeEa(ea_t ea) { mCodeEa = ea; }; - void SetProtocols(std::vector protocols) { mProtocols = protocols; }; + void SetProtocols(json_list_t protocols) { mProtocols = protocols; }; protected: // @@ -216,7 +216,7 @@ class GUIDRelatedVisitorBase : public ctree_visitor_t { ea_t mCodeEa; // Protocols - std::vector mProtocols; + json_list_t mProtocols; // Print debug messages? bool mDebug = false; @@ -660,7 +660,7 @@ class VariablesInfoExtractor : public ctree_visitor_t { class PrototypesFixer : public ctree_visitor_t { public: PrototypesFixer() : ctree_visitor_t(CV_FAST) {}; - std::vector child_functions; + ea_list_t child_functions; // This is the callback function that Hex-Rays invokes for every expression // in the CTREE. @@ -761,12 +761,12 @@ class VariablesDetector : public ctree_visitor_t { public: VariablesDetector() : ctree_visitor_t(CV_FAST) {}; - std::vector child_functions; + ea_list_t child_functions; - std::vector image_handle_list; - std::vector st_list; - std::vector bs_list; - std::vector rt_list; + ea_list_t image_handle_list; + ea_list_t st_list; + ea_list_t bs_list; + ea_list_t rt_list; void SetFuncEa(ea_t ea) { mFuncEa = ea; }; @@ -889,7 +889,7 @@ class ServicesDetector : public ctree_visitor_t { public: ServicesDetector() : ctree_visitor_t(CV_FAST) {}; - std::vector services; + json_list_t services; // This is the callback function that Hex-Rays invokes for every expression // in the CTREE. @@ -1051,7 +1051,7 @@ class PeiServicesDetectorArm : public ctree_visitor_t { public: PeiServicesDetectorArm() : ctree_visitor_t(CV_FAST) {}; - std::vector services; + json_list_t services; // This is the callback function that Hex-Rays invokes for every expression // in the CTREE. diff --git a/efiXplorer/efi_smm_utils.cc b/efiXplorer/efi_smm_utils.cc index 99b099de..6850cff6 100644 --- a/efiXplorer/efi_smm_utils.cc +++ b/efiXplorer/efi_smm_utils.cc @@ -22,8 +22,8 @@ //-------------------------------------------------------------------------- // Find and mark gSmst global variable via EFI_SMM_SW_DISPATCH(2)_PROTOCOL_GUID -std::vector findSmstSwDispatch(std::vector bs_list) { - std::vector smst_addrs; +ea_list_t findSmstSwDispatch(ea_list_t bs_list) { + ea_list_t smst_addrs; EfiGuid guid2 = {0x18a3c6dc, 0x5eea, 0x48c8, @@ -34,13 +34,13 @@ std::vector findSmstSwDispatch(std::vector bs_list) { 0x420c, {0xb0, 0x26, 0xdf, 0x99, 0x36, 0x53, 0xf8, 0xbf}}; // EFI_SMM_SW_DISPATCH_PROTOCOL_GUID - std::vector data_addrs = find_data(0, BADADDR, guid.uchar_data().data(), 16); - std::vector data2_addrs = find_data(0, BADADDR, guid2.uchar_data().data(), 16); + ea_list_t data_addrs = find_data(0, BADADDR, guid.uchar_data().data(), 16); + ea_list_t data2_addrs = find_data(0, BADADDR, guid2.uchar_data().data(), 16); data_addrs.insert(data_addrs.end(), data2_addrs.begin(), data2_addrs.end()); for (auto data_addr : data_addrs) { msg("[%s] EFI_SMM_SW_DISPATCH(2)_PROTOCOL_GUID: 0x%016llX\n", g_plugin_name, u64_addr(data_addr)); - std::vector xrefs = get_xrefs_util(data_addr); + ea_list_t xrefs = get_xrefs_util(data_addr); insn_t insn; for (auto xref : xrefs) { uint16_t smst_reg = 0xffff; // Smst register @@ -93,18 +93,18 @@ std::vector findSmstSwDispatch(std::vector bs_list) { //-------------------------------------------------------------------------- // Find and mark gSmst global variable via EFI_SMM_BASE2_PROTOCOL_GUID -std::vector findSmstSmmBase(std::vector bs_list) { - std::vector smst_addrs; +ea_list_t findSmstSmmBase(ea_list_t bs_list) { + ea_list_t smst_addrs; EfiGuid guid = { 0xf4ccbfb7, 0xf6e0, 0x47fd, {0x9d, 0xd4, 0x10, 0xa8, 0xf1, 0x50, 0xc1, 0x91}}; // EFI_SMM_BASE2_PROTOCOL_GUID - std::vector data_addrs = find_data(0, BADADDR, guid.uchar_data().data(), 16); + ea_list_t data_addrs = find_data(0, BADADDR, guid.uchar_data().data(), 16); for (auto data_addr : data_addrs) { msg("[%s] EFI_SMM_BASE2_PROTOCOL_GUID: 0x%016llX\n", g_plugin_name, u64_addr(data_addr)); - std::vector data_xrefs = get_xrefs_util(data_addr); + ea_list_t data_xrefs = get_xrefs_util(data_addr); insn_t insn; for (auto xref : data_xrefs) { ea_t res_addr = BADADDR; @@ -147,11 +147,11 @@ std::vector findSmstSmmBase(std::vector bs_list) { //-------------------------------------------------------------------------- // Find SmiHandler in reg_smi_func function (prefix: Sw, TrapIo, Sx, Gpi, Usb, // StandbyButton, PeriodicTimer, PowerButton) -std::vector findSmiHandlers(ea_t address, std::string prefix) { +func_list_t findSmiHandlers(ea_t address, std::string prefix) { msg("[%s] Analyse xref to gEfiSmm%sDispatch(2)Protocol: 0x%016llX\n", g_plugin_name, prefix.c_str(), u64_addr(address)); - std::vector smiHandlers; + func_list_t smiHandlers; insn_t insn; // Find Dispatch interface address (via gSmst->SmmLocateProtocol call) @@ -310,12 +310,12 @@ std::vector findSmiHandlers(ea_t address, std::string prefix) { // lea r8, ... // lea rdx, // call qword ptr [...] -std::vector findSmiHandlersSmmDispatch(EfiGuid guid, std::string prefix) { - std::vector smiHandlers; - std::vector data_addrs = find_data(0, BADADDR, guid.uchar_data().data(), 16); +func_list_t findSmiHandlersSmmDispatch(EfiGuid guid, std::string prefix) { + func_list_t smiHandlers; + ea_list_t data_addrs = find_data(0, BADADDR, guid.uchar_data().data(), 16); msg("[%s] %sSmiHandler function finding\n", g_plugin_name, prefix.c_str()); for (auto data_addr : data_addrs) { - std::vector xrefs = get_xrefs_util(data_addr); + ea_list_t xrefs = get_xrefs_util(data_addr); for (auto xref : xrefs) { msg("[%s] findSmiHandlers: 0x%016llX\n", g_plugin_name, u64_addr(xref)); @@ -330,10 +330,9 @@ std::vector findSmiHandlersSmmDispatch(EfiGuid guid, std::string prefi //-------------------------------------------------------------------------- // Find SwSmiHandler function inside SMM drivers in case where // EFI_SMM_SW_DISPATCH(2)_PROTOCOL_GUID is a local variable -std::vector findSmiHandlersSmmDispatchStack(std::vector stackGuids, - std::string prefix) { +func_list_t findSmiHandlersSmmDispatchStack(json_list_t stackGuids, std::string prefix) { // TODO: make it generic - std::vector smiHandlers; + func_list_t smiHandlers; for (auto guid : stackGuids) { std::string name = static_cast(guid["name"]); @@ -356,12 +355,11 @@ std::vector findSmiHandlersSmmDispatchStack(std::vector stackGui //-------------------------------------------------------------------------- // Find gSmmVar->SmmGetVariable calls via EFI_SMM_VARIABLE_PROTOCOL_GUID -std::vector findSmmGetVariableCalls(std::vector dataSegments, - std::vector *allServices) { +ea_list_t findSmmGetVariableCalls(segment_list_t dataSegments, json_list_t *allServices) { msg("[%s] gSmmVar->SmmGetVariable calls finding via " "EFI_SMM_VARIABLE_PROTOCOL_GUID\n", g_plugin_name); - std::vector smmGetVariableCalls; + ea_list_t smmGetVariableCalls; EfiGuid guid = { 0xed32d533, 0x99e6, @@ -369,10 +367,10 @@ std::vector findSmmGetVariableCalls(std::vector dataSegments, {0x9c, 0xc0, 0x2d, 0x72, 0xcd, 0xd9, 0x98, 0xa7}}; // EFI_SMM_VARIABLE_PROTOCOL_GUID // Find all EFI_GUID EFI_SMM_VARIABLE_PROTOCOL_GUID addresses - std::vector data_addrs = find_data(0, BADADDR, guid.uchar_data().data(), 16); - std::vector gSmmVarAddrs; // Find all gSmmVar variables + ea_list_t data_addrs = find_data(0, BADADDR, guid.uchar_data().data(), 16); + ea_list_t gSmmVarAddrs; // Find all gSmmVar variables for (auto data_addr : data_addrs) { - std::vector xrefs = get_xrefs_util(data_addr); + ea_list_t xrefs = get_xrefs_util(data_addr); for (auto xref : xrefs) { segment_t *seg = getseg(static_cast(xref)); @@ -412,7 +410,7 @@ std::vector findSmmGetVariableCalls(std::vector dataSegments, } for (auto smmVarAddr : gSmmVarAddrs) { - std::vector smmVarXrefs = get_xrefs_util(static_cast(smmVarAddr)); + ea_list_t smmVarXrefs = get_xrefs_util(static_cast(smmVarAddr)); for (auto smmVarXref : smmVarXrefs) { segment_t *seg = getseg(static_cast(smmVarXref)); qstring seg_name; @@ -474,13 +472,12 @@ std::vector findSmmGetVariableCalls(std::vector dataSegments, return smmGetVariableCalls; } -std::vector resolveEfiSmmCpuProtocol(std::vector stackGuids, - std::vector dataGuids, - std::vector *allServices) { - std::vector readSaveStateCalls; +ea_list_t resolveEfiSmmCpuProtocol(json_list_t stackGuids, json_list_t dataGuids, + json_list_t *allServices) { + ea_list_t readSaveStateCalls; msg("[%s] Looking for EFI_SMM_CPU_PROTOCOL\n", g_plugin_name); - std::vector code_addrs; - std::vector gSmmCpuAddrs; + ea_list_t code_addrs; + ea_list_t gSmmCpuAddrs; for (auto guid : stackGuids) { std::string name = static_cast(guid["name"]); if (name != "EFI_SMM_CPU_PROTOCOL_GUID") @@ -498,7 +495,7 @@ std::vector resolveEfiSmmCpuProtocol(std::vector stackGuids, ea_t address = static_cast(guid["address"]); msg("[%s] found EFI_SMM_CPU_PROTOCOL: 0x%016llX\n", g_plugin_name, u64_addr(address)); - std::vector guidXrefs = get_xrefs_util(address); + ea_list_t guidXrefs = get_xrefs_util(address); for (auto guidXref : guidXrefs) { segment_t *seg = getseg(static_cast(guidXref)); @@ -539,7 +536,7 @@ std::vector resolveEfiSmmCpuProtocol(std::vector stackGuids, } for (auto smmCpu : gSmmCpuAddrs) { - std::vector smmCpuXrefs = get_xrefs_util(static_cast(smmCpu)); + ea_list_t smmCpuXrefs = get_xrefs_util(static_cast(smmCpu)); for (auto smmCpuXref : smmCpuXrefs) { segment_t *seg = getseg(static_cast(smmCpuXref)); diff --git a/efiXplorer/efi_smm_utils.h b/efiXplorer/efi_smm_utils.h index 61e46761..224c5c6f 100644 --- a/efiXplorer/efi_smm_utils.h +++ b/efiXplorer/efi_smm_utils.h @@ -21,15 +21,12 @@ #include "efi_utils.h" -std::vector findSmstSwDispatch(std::vector bs_list); -std::vector findSmstSmmBase(std::vector bs_list); -std::vector findSmiHandlers(ea_t address, std::string prefix); -std::vector findSmiHandlersSmmDispatch(EfiGuid guid, std::string prefix); -std::vector findSmiHandlersSmmDispatchStack(std::vector stackGuids, - std::string prefix); -std::vector findSmmGetVariableCalls(std::vector dataSegments, - std::vector *allServices); -std::vector resolveEfiSmmCpuProtocol(std::vector stackGuids, - std::vector dataGuids, - std::vector *allServices); +ea_list_t findSmstSwDispatch(ea_list_t bs_list); +ea_list_t findSmstSmmBase(ea_list_t bs_list); +func_list_t findSmiHandlers(ea_t address, std::string prefix); +func_list_t findSmiHandlersSmmDispatch(EfiGuid guid, std::string prefix); +func_list_t findSmiHandlersSmmDispatchStack(json_list_t stackGuids, std::string prefix); +ea_list_t findSmmGetVariableCalls(segment_list_t dataSegments, json_list_t *allServices); +ea_list_t resolveEfiSmmCpuProtocol(json_list_t stackGuids, json_list_t dataGuids, + json_list_t *allServices); ea_t markChildSwSmiHandler(ea_t ea); diff --git a/efiXplorer/efi_ui.cc b/efiXplorer/efi_ui.cc index 197658e3..adfdee1d 100644 --- a/efiXplorer/efi_ui.cc +++ b/efiXplorer/efi_ui.cc @@ -97,8 +97,7 @@ const char *const nvram_chooser_t::header_nvram[] = { "Attributes" // 4 }; -inline nvram_chooser_t::nvram_chooser_t(const char *title_, bool ok, - std::vector nvram) +inline nvram_chooser_t::nvram_chooser_t(const char *title_, bool ok, json_list_t nvram) : chooser_t(0, qnumber(widths_nvram), widths_nvram, header_nvram, title_), list() { CASSERT(qnumber(widths_nvram) == qnumber(header_nvram)); build_list(ok, nvram); @@ -121,8 +120,7 @@ void idaapi nvram_chooser_t::get_row(qstrvec_t *cols_, int *, chooser_item_attrs CASSERT(qnumber(header_nvram) == 5); } -inline vulns_chooser_t::vulns_chooser_t(const char *title_, bool ok, - std::vector vulns) +inline vulns_chooser_t::vulns_chooser_t(const char *title_, bool ok, json_list_t vulns) : chooser_t(0, qnumber(widths_vulns), widths_vulns, header_vulns, title_), list() { CASSERT(qnumber(widths_vulns) == qnumber(header_vulns)); build_list(ok, vulns); @@ -139,8 +137,7 @@ void idaapi vulns_chooser_t::get_row(qstrvec_t *cols_, int *, chooser_item_attrs CASSERT(qnumber(header_vulns) == 2); } -inline guids_chooser_t::guids_chooser_t(const char *title_, bool ok, - std::vector guids) +inline guids_chooser_t::guids_chooser_t(const char *title_, bool ok, json_list_t guids) : chooser_t(0, qnumber(widths_guids), widths_guids, header_guids, title_), list() { CASSERT(qnumber(widths_guids) == qnumber(header_guids)); build_list(ok, guids); @@ -160,7 +157,7 @@ void idaapi guids_chooser_t::get_row(qstrvec_t *cols_, int *, chooser_item_attrs } inline protocols_chooser_t::protocols_chooser_t(const char *title_, bool ok, - std::vector protocols, + json_list_t protocols, std::string name_key_) : chooser_t(0, qnumber(widths_protocols), widths_protocols, header_protocols, title_), list() { @@ -186,7 +183,7 @@ void idaapi protocols_chooser_t::get_row(qstrvec_t *cols_, int *, chooser_item_a CASSERT(qnumber(header_protocols) == 5); } -inline s_chooser_t::s_chooser_t(const char *title_, bool ok, std::vector services) +inline s_chooser_t::s_chooser_t(const char *title_, bool ok, json_list_t services) : chooser_t(0, qnumber(widths_s), widths_s, header_s, title_), list() { CASSERT(qnumber(widths_s) == qnumber(header_s)); build_list(ok, services); @@ -205,7 +202,7 @@ void idaapi s_chooser_t::get_row(qstrvec_t *cols_, int *, chooser_item_attrs_t * CASSERT(qnumber(header_s) == 3); } -bool nvram_show(std::vector nvram, qstring title) { +bool nvram_show(json_list_t nvram, qstring title) { bool ok; // open the window nvram_chooser_t *ch = new nvram_chooser_t(title.c_str(), ok, nvram); @@ -214,7 +211,7 @@ bool nvram_show(std::vector nvram, qstring title) { return true; } -bool vulns_show(std::vector vulns, qstring title) { +bool vulns_show(json_list_t vulns, qstring title) { bool ok; // open the window vulns_chooser_t *ch = new vulns_chooser_t(title.c_str(), ok, vulns); @@ -223,7 +220,7 @@ bool vulns_show(std::vector vulns, qstring title) { return true; } -bool guids_show(std::vector guids, qstring title) { +bool guids_show(json_list_t guids, qstring title) { bool ok; // open the window guids_chooser_t *ch = new guids_chooser_t(title.c_str(), ok, guids); @@ -232,7 +229,7 @@ bool guids_show(std::vector guids, qstring title) { return true; } -bool protocols_show(std::vector protocols, qstring title) { +bool protocols_show(json_list_t protocols, qstring title) { bool ok; // open the window protocols_chooser_t *ch = @@ -242,7 +239,7 @@ bool protocols_show(std::vector protocols, qstring title) { return true; } -bool ppis_show(std::vector ppis, qstring title) { +bool ppis_show(json_list_t ppis, qstring title) { bool ok; // open the window protocols_chooser_t *ch = new protocols_chooser_t(title.c_str(), ok, ppis, "ppi_name"); @@ -251,7 +248,7 @@ bool ppis_show(std::vector ppis, qstring title) { return true; } -bool services_show(std::vector services, qstring title) { +bool services_show(json_list_t services, qstring title) { bool ok; // open the window s_chooser_t *ch = new s_chooser_t(title.c_str(), ok, services); @@ -360,9 +357,9 @@ struct action_handler_loadreport_t : public action_handler_t { } // Initialize vuln types list - std::vector vulnTypes{"smm_callout", "pei_get_variable_buffer_overflow", - "get_variable_buffer_overflow", - "smm_get_variable_buffer_overflow"}; + string_list_t vulnTypes{"smm_callout", "pei_get_variable_buffer_overflow", + "get_variable_buffer_overflow", + "smm_get_variable_buffer_overflow"}; // Show all choosers with data from report qstring title; @@ -395,7 +392,7 @@ struct action_handler_loadreport_t : public action_handler_t { } auto vulns = reportData["vulns"]; if (!vulns.is_null()) { // show vulns - std::vector vulnsRes; + json_list_t vulnsRes; for (auto vulnType : vulnTypes) { // For each vuln type add list of vulns in `vulnsRes` auto vulnAddrs = vulns[vulnType]; diff --git a/efiXplorer/efi_ui.h b/efiXplorer/efi_ui.h index 66cea621..6c231992 100644 --- a/efiXplorer/efi_ui.h +++ b/efiXplorer/efi_ui.h @@ -33,7 +33,7 @@ class vulns_chooser_t : public chooser_t { json chooser_vulns; // this object must be allocated using `new` - vulns_chooser_t(const char *title, bool ok, std::vector vulns); + vulns_chooser_t(const char *title, bool ok, json_list_t vulns); // function that is used to decide whether a new chooser should be opened or // we can use the existing one. The contents of the window are completely @@ -58,7 +58,7 @@ class vulns_chooser_t : public chooser_t { } protected: - void build_list(bool ok, std::vector vulns) { + void build_list(bool ok, json_list_t vulns) { size_t n = 0; for (auto vuln : vulns) { list.push_back(vuln["address"]); @@ -81,7 +81,7 @@ class guids_chooser_t : public chooser_t { json chooser_guids; // this object must be allocated using `new` - guids_chooser_t(const char *title, bool ok, std::vector guids); + guids_chooser_t(const char *title, bool ok, json_list_t guids); // function that is used to decide whether a new chooser should be opened or // we can use the existing one. The contents of the window are completely @@ -106,7 +106,7 @@ class guids_chooser_t : public chooser_t { } protected: - void build_list(bool ok, std::vector guids) { + void build_list(bool ok, json_list_t guids) { size_t n = 0; for (auto guid : guids) { list.push_back(guid["address"]); @@ -130,7 +130,7 @@ class protocols_chooser_t : public chooser_t { std::string name_key; // this object must be allocated using `new` - protocols_chooser_t(const char *title, bool ok, std::vector interfaces, + protocols_chooser_t(const char *title, bool ok, json_list_t interfaces, std::string name_key); // function that is used to decide whether a new chooser should be opened or @@ -156,7 +156,7 @@ class protocols_chooser_t : public chooser_t { } protected: - void build_list(bool ok, std::vector protocols) { + void build_list(bool ok, json_list_t protocols) { size_t n = 0; for (auto protocol : protocols) { list.push_back(protocol["xref"]); @@ -179,7 +179,7 @@ class s_chooser_t : public chooser_t { json chooser_s; // this object must be allocated using `new` - s_chooser_t(const char *title, bool ok, std::vector services); + s_chooser_t(const char *title, bool ok, json_list_t services); // function that is used to decide whether a new chooser should be opened or // we can use the existing one. The contents of the window are completely @@ -204,7 +204,7 @@ class s_chooser_t : public chooser_t { } protected: - void build_list(bool ok, std::vector services) { + void build_list(bool ok, json_list_t services) { size_t n = 0; for (auto j_service : services) { list.push_back(j_service["address"]); @@ -227,7 +227,7 @@ class nvram_chooser_t : public chooser_t { json chooser_nvram; // this object must be allocated using `new` - nvram_chooser_t(const char *title, bool ok, std::vector nvrams); + nvram_chooser_t(const char *title, bool ok, json_list_t nvrams); // function that is used to decide whether a new chooser should be opened or // we can use the existing one. The contents of the window are completely @@ -252,7 +252,7 @@ class nvram_chooser_t : public chooser_t { } protected: - void build_list(bool ok, std::vector nvrams) { + void build_list(bool ok, json_list_t nvrams) { size_t n = 0; for (auto nvram : nvrams) { list.push_back(nvram["addr"]); @@ -265,11 +265,11 @@ class nvram_chooser_t : public chooser_t { extern action_desc_t action_load_report; -bool nvram_show(std::vector nvram, qstring title); -bool vulns_show(std::vector vulns, qstring title); -bool guids_show(std::vector guid, qstring title); -bool protocols_show(std::vector protocols, qstring title); -bool ppis_show(std::vector protocols, qstring title); -bool services_show(std::vector services, qstring title); +bool nvram_show(json_list_t nvram, qstring title); +bool vulns_show(json_list_t vulns, qstring title); +bool guids_show(json_list_t guid, qstring title); +bool protocols_show(json_list_t protocols, qstring title); +bool ppis_show(json_list_t protocols, qstring title); +bool services_show(json_list_t services, qstring title); void attachActionProtocolsDeps(); void attachActionModulesSeq(); diff --git a/efiXplorer/efi_utils.cc b/efiXplorer/efi_utils.cc index 58778d04..80ec58c9 100644 --- a/efiXplorer/efi_utils.cc +++ b/efiXplorer/efi_utils.cc @@ -22,9 +22,9 @@ #include "efi_global.h" // can be used after Hex-Rays based analysis -std::vector g_get_smst_location_calls; -std::vector g_smm_get_variable_calls; -std::vector g_smm_set_variable_calls; +ea_list_t g_get_smst_location_calls; +ea_list_t g_smm_get_variable_calls; +ea_list_t g_smm_set_variable_calls; //-------------------------------------------------------------------------- // set EFI_GUID type @@ -93,7 +93,7 @@ ArchFileType input_file_type() { //-------------------------------------------------------------------------- // get input file type (PEI or DXE-like). No reliable way to determine FFS // file type given only its PE/TE image section, so hello heuristics -FfsFileType guess_file_type(ArchFileType arch, std::vector *all_guids) { +FfsFileType guess_file_type(ArchFileType arch, json_list_t *all_guids) { if (arch == ArchFileType::Uefi) { return FfsFileType::DxeAndTheLike; } @@ -135,7 +135,7 @@ FfsFileType guess_file_type(ArchFileType arch, std::vector *all_guids) { return FfsFileType::DxeAndTheLike; } -FfsFileType ask_file_type(std::vector *all_guids) { +FfsFileType ask_file_type(json_list_t *all_guids) { auto arch = input_file_type(); if (arch == ArchFileType::Uefi || arch == ArchFileType::X8664) { return FfsFileType::DxeAndTheLike; @@ -172,8 +172,8 @@ ea_t find_unknown_bs_var_64(ea_t ea) { //-------------------------------------------------------------------------- // get all xrefs for given address -std::vector get_xrefs_util(ea_t addr) { - std::vector xrefs; +ea_list_t get_xrefs_util(ea_t addr) { + ea_list_t xrefs; ea_t xref = get_first_dref_to(addr); while (xref != BADADDR) { xrefs.push_back(xref); @@ -184,7 +184,7 @@ std::vector get_xrefs_util(ea_t addr) { //-------------------------------------------------------------------------- // get all xrefs for given array element -std::vector get_xrefs_to_array(ea_t addr) { +ea_list_t get_xrefs_to_array(ea_t addr) { ea_t first_ea; ea_t ea = addr; while (true) { @@ -511,8 +511,8 @@ std::string guid_to_string(json guid) { static_cast(guid[10])); } -std::vector unpack_guid(std::string guid) { - std::vector res; +uint8_list_t unpack_guid(std::string guid) { + uint8_list_t res; std::string delim = "-"; std::string byte_str; uint8_t byte; @@ -520,7 +520,7 @@ std::vector unpack_guid(std::string guid) { auto index = 0; while ((pos = guid.find(delim)) != std::string::npos) { - std::vector tmp; + uint8_list_t tmp; auto hex = guid.substr(0, pos); if (hex.size() % 2) { break; @@ -549,9 +549,9 @@ std::vector unpack_guid(std::string guid) { return res; } -std::vector search_protocol(std::string protocol) { +ea_list_t search_protocol(std::string protocol) { uchar bytes[17] = {0}; - std::vector res; + ea_list_t res; auto guid_bytes = unpack_guid(protocol); std::copy(guid_bytes.begin(), guid_bytes.end(), bytes); ea_t start = 0; @@ -693,7 +693,7 @@ bool mark_copy(ea_t code_addr, ea_t var_addr, std::string type) { return true; } -bool mark_copies_for_gvars(std::vector gvars, std::string type) { +bool mark_copies_for_gvars(ea_list_t gvars, std::string type) { for (auto var : gvars) { auto xrefs = get_xrefs_util(var); for (auto addr : xrefs) { @@ -814,7 +814,7 @@ void op_stroff_for_interface(xreflist_t local_xrefs, qstring type_name) { //-------------------------------------------------------------------------- // mark the arguments of each function from an interface derived from // a global variable -void op_stroff_for_global_interface(std::vector xrefs, qstring type_name) { +void op_stroff_for_global_interface(ea_list_t xrefs, qstring type_name) { insn_t insn; for (auto ea : xrefs) { decode_insn(&insn, ea); @@ -824,29 +824,28 @@ void op_stroff_for_global_interface(std::vector xrefs, qstring type_name) } } -bool uint64_in_vec(std::vector vec, uint64_t value) { +bool uint64_in_vec(uint64_list_t vec, uint64_t value) { return find(vec.begin(), vec.end(), value) != vec.end(); } -bool addr_in_vec(std::vector vec, ea_t addr) { +bool addr_in_vec(ea_list_t vec, ea_t addr) { return find(vec.begin(), vec.end(), addr) != vec.end(); } -bool json_in_vec(std::vector vec, json item) { +bool json_in_vec(json_list_t vec, json item) { return find(vec.begin(), vec.end(), item) != vec.end(); } -bool addr_in_tables(std::vector t1, std::vector t2, ea_t ea) { +bool addr_in_tables(ea_list_t t1, ea_list_t t2, ea_t ea) { return (addr_in_vec(t1, ea) || addr_in_vec(t2, ea)); } -bool addr_in_tables(std::vector t1, std::vector t2, std::vector t3, - ea_t ea) { +bool addr_in_tables(ea_list_t t1, ea_list_t t2, ea_list_t t3, ea_t ea) { return (addr_in_vec(t1, ea) || addr_in_vec(t2, ea) || addr_in_vec(t3, ea)); } -std::vector find_data(ea_t start_ea, ea_t end_ea, uchar *data, size_t len) { - std::vector res; +ea_list_t find_data(ea_t start_ea, ea_t end_ea, uchar *data, size_t len) { + ea_list_t res; ea_t start = start_ea; int counter = 0; while (true) { diff --git a/efiXplorer/efi_utils.h b/efiXplorer/efi_utils.h index 593f1ef7..a75359db 100644 --- a/efiXplorer/efi_utils.h +++ b/efiXplorer/efi_utils.h @@ -56,14 +56,23 @@ using namespace nlohmann; +using ea_list_t = std::vector; +using func_list_t = std::vector; +using json_list_t = std::vector; +using segment_list_t = std::vector; +using string_list_t = std::vector; +using uchar_list_t = std::vector; +using uint64_list_t = std::vector; +using uint8_list_t = std::vector; + struct EfiGuid { uint32_t data1; uint16_t data2; uint16_t data3; uint8_t data4[8]; - std::vector uchar_data() { - std::vector res; + uchar_list_t uchar_data() { + uchar_list_t res; res.push_back(data1 & 0xff); res.push_back(data1 >> 8 & 0xff); res.push_back(data1 >> 16 & 0xff); @@ -89,20 +98,19 @@ struct EfiGuid { ArchFileType input_file_type(); bool add_struct_for_shifted_ptr(); -bool addr_in_tables(std::vector bs_list, std::vector rt_list, ea_t ea); -bool addr_in_tables(std::vector st_list, std::vector bs_list, - std::vector rt_list, ea_t ea); -bool addr_in_vec(std::vector vec, ea_t addr); +bool addr_in_tables(ea_list_t t1, ea_list_t t2, ea_t ea); +bool addr_in_tables(ea_list_t t1, ea_list_t t2, ea_list_t t3, ea_t ea); +bool addr_in_vec(ea_list_t vec, ea_t addr); bool check_boot_service_protocol_xrefs(ea_t call_addr); bool check_boot_service_protocol(ea_t call_addr); bool check_install_protocol(ea_t ea); -bool json_in_vec(std::vector vec, json item); -bool mark_copies_for_gvars(std::vector gvars, std::string type); +bool json_in_vec(json_list_t vec, json item); +bool mark_copies_for_gvars(ea_list_t gvars, std::string type); bool op_stroff_util(ea_t addr, std::string type); bool set_ptr_type(ea_t addr, std::string type); bool set_ret_to_pei_svc(ea_t start_ea); bool summary_json_exists(); -bool uint64_in_vec(std::vector vec, uint64_t value); +bool uint64_in_vec(uint64_list_t vec, uint64_t value); bool valid_guid(json guid); ea_t find_unknown_bs_var_64(ea_t ea); @@ -110,7 +118,7 @@ ea_t find_unknown_bs_var_64(ea_t ea); EfiGuid get_global_guid(ea_t addr); EfiGuid get_local_guid(func_t *f, uint64_t offset); -FfsFileType ask_file_type(std::vector *all_guids); +FfsFileType ask_file_type(json_list_t *all_guids); json get_guid_by_address(ea_t addr); @@ -127,19 +135,20 @@ std::string lookup_boot_service_name(uint64_t offset); std::string lookup_runtime_service_name(uint64_t offset); std::string type_to_name(std::string type); -std::vector find_data(ea_t start_ea, ea_t end_ea, uchar *data, size_t len); -std::vector get_xrefs_to_array(ea_t addr); -std::vector get_xrefs_util(ea_t addr); -std::vector search_protocol(std::string protocol); -std::vector unpack_guid(std::string guid); +ea_list_t find_data(ea_t start_ea, ea_t end_ea, uchar *data, size_t len); +ea_list_t get_xrefs_to_array(ea_t addr); +ea_list_t get_xrefs_util(ea_t addr); +ea_list_t search_protocol(std::string protocol); uint16_t get_machine_type(); uint32_t u32_addr(ea_t addr); uint64_t u64_addr(ea_t addr); +uint8_list_t unpack_guid(std::string guid); + uval_t trunc_imm_to_dtype(uval_t value, op_dtype_t dtype); -void op_stroff_for_global_interface(std::vector xrefs, qstring type_name); +void op_stroff_for_global_interface(ea_list_t xrefs, qstring type_name); void op_stroff_for_interface(xreflist_t local_xrefs, qstring type_name); void set_const_char16_type(ea_t ea); void set_entry_arg_to_pei_svc(); From 9755ae76770db7871cea3f22143eeaf3cad1eedd Mon Sep 17 00:00:00 2001 From: yeggor Date: Sat, 14 Sep 2024 05:54:51 +0200 Subject: [PATCH 22/69] remove unused headers from efi_utils --- efiXplorer/efi_utils.h | 5 ----- 1 file changed, 5 deletions(-) diff --git a/efiXplorer/efi_utils.h b/efiXplorer/efi_utils.h index a75359db..1293b6d8 100644 --- a/efiXplorer/efi_utils.h +++ b/efiXplorer/efi_utils.h @@ -22,27 +22,22 @@ // 3rd party #include "json.hpp" -#include #include #include #include #include #include -#include #include #include #include #include #include #include -#include #include #include #include #include #include -#include -#include #if IDA_SDK_VERSION < 900 #include #endif From 8320234ff8d3ce4d59072d350be9cf9a8f1a047a Mon Sep 17 00:00:00 2001 From: yeggor Date: Sun, 15 Sep 2024 20:12:58 +0200 Subject: [PATCH 23/69] fix linter issues for efixplorer --- efiXplorer/.clang-format | 4 +- efiXplorer/efi_analyser.h | 232 +++++++++++++++-------- efiXplorer/efi_analyser_arm.cc | 45 +++-- efiXplorer/efi_analyser_x86.cc | 328 ++++++++++++++++++--------------- efiXplorer/efi_defs.cc | 112 ++++++----- efiXplorer/efi_defs.h | 3 +- efiXplorer/efi_deps.cc | 36 ++-- efiXplorer/efi_deps.h | 10 +- efiXplorer/efi_global.cc | 1 + efiXplorer/efi_hexrays.cc | 18 +- efiXplorer/efi_hexrays.h | 100 +++++----- efiXplorer/efi_smm_utils.cc | 95 +++++----- efiXplorer/efi_smm_utils.h | 11 +- efiXplorer/efi_ui.cc | 68 ++++--- efiXplorer/efi_ui.h | 41 +++-- efiXplorer/efi_utils.cc | 97 ++++++---- efiXplorer/efi_utils.h | 26 +-- efiXplorer/efixplorer.cc | 24 +-- 18 files changed, 736 insertions(+), 515 deletions(-) diff --git a/efiXplorer/.clang-format b/efiXplorer/.clang-format index 92cfffbb..67c0bb48 100644 --- a/efiXplorer/.clang-format +++ b/efiXplorer/.clang-format @@ -1,5 +1,5 @@ --- -Language: Cpp BasedOnStyle: LLVM -ColumnLimit: 90 +ColumnLimit: 80 IndentWidth: 2 +Language: Cpp diff --git a/efiXplorer/efi_analyser.h b/efiXplorer/efi_analyser.h index 8d166a93..bb67d5b3 100644 --- a/efiXplorer/efi_analyser.h +++ b/efiXplorer/efi_analyser.h @@ -27,6 +27,9 @@ #include "efi_hexrays.h" #endif +#include +#include + namespace efi_analysis { class EfiAnalyser { @@ -68,7 +71,8 @@ class EfiAnalyser { ea_t endAddress = 0; ea_list_t funcs; std::filesystem::path guidsJsonPath; - std::map dbProtocolsMap; // a map to look up a GUID name by value + std::map + dbProtocolsMap; // a map to look up a GUID name by value json bootServices; json peiServices; json peiServicesAll; @@ -79,127 +83,208 @@ class EfiAnalyser { json_list_t nvramVariables; ea_list_t markedInterfaces; - // Format-dependent interface-related settings (protocols for DXE, PPIs for PEI) + // Format-dependent interface-related settings (protocols for DXE, PPIs for + // PEI) std::string if_name; std::string if_pl; std::string if_key; json_list_t *if_tbl; // EFI_SMM_SW_DISPATCH2_PROTOCOL_GUID - EfiGuid sw_guid2 = { - 0x18a3c6dc, 0x5eea, 0x48c8, {0xa1, 0xc1, 0xb5, 0x33, 0x89, 0xf9, 0x89, 0x99}}; + EfiGuid sw_guid2 = {0x18a3c6dc, + 0x5eea, + 0x48c8, + {0xa1, 0xc1, 0xb5, 0x33, 0x89, 0xf9, 0x89, 0x99}}; // EFI_SMM_SW_DISPATCH_PROTOCOL_GUID - EfiGuid sw_guid = { - 0xe541b773, 0xdd11, 0x420c, {0xb0, 0x26, 0xdf, 0x99, 0x36, 0x53, 0xf8, 0xbf}}; + EfiGuid sw_guid = {0xe541b773, + 0xdd11, + 0x420c, + {0xb0, 0x26, 0xdf, 0x99, 0x36, 0x53, 0xf8, 0xbf}}; // EFI_SMM_SX_DISPATCH2_PROTOCOL_GUID - EfiGuid sx_guid2 = { - 0x456d2859, 0xa84b, 0x4e47, {0xa2, 0xee, 0x32, 0x76, 0xd8, 0x86, 0x99, 0x7d}}; + EfiGuid sx_guid2 = {0x456d2859, + 0xa84b, + 0x4e47, + {0xa2, 0xee, 0x32, 0x76, 0xd8, 0x86, 0x99, 0x7d}}; // EFI_SMM_SX_DISPATCH_PROTOCOL_GUID - EfiGuid sx_guid = { - 0x14FC52BE, 0x01DC, 0x426C, {0x91, 0xAE, 0xA2, 0x3C, 0x3E, 0x22, 0x0A, 0xE8}}; + EfiGuid sx_guid = {0x14FC52BE, + 0x01DC, + 0x426C, + {0x91, 0xAE, 0xA2, 0x3C, 0x3E, 0x22, 0x0A, 0xE8}}; // EFI_SMM_IO_TRAP_DISPATCH2_PROTOCOL_GUID - EfiGuid io_trap_guid2 = { - 0x58DC368D, 0x7BFA, 0x4E77, {0xAB, 0xBC, 0x0E, 0x29, 0x41, 0x8D, 0xF9, 0x30}}; + EfiGuid io_trap_guid2 = {0x58DC368D, + 0x7BFA, + 0x4E77, + {0xAB, 0xBC, 0x0E, 0x29, 0x41, 0x8D, 0xF9, 0x30}}; // EFI_SMM_IO_TRAP_DISPATCH_PROTOCOL_GUID - EfiGuid io_trap_guid = { - 0xDB7F536B, 0xEDE4, 0x4714, {0xA5, 0xC8, 0xE3, 0x46, 0xEB, 0xAA, 0x20, 0x1D}}; + EfiGuid io_trap_guid = {0xDB7F536B, + 0xEDE4, + 0x4714, + {0xA5, 0xC8, 0xE3, 0x46, 0xEB, 0xAA, 0x20, 0x1D}}; // EFI_SMM_GPI_DISPATCH2_PROTOCOL_GUID - EfiGuid gpi_guid2 = { - 0x25566B03, 0xB577, 0x4CBF, {0x95, 0x8C, 0xED, 0x66, 0x3E, 0xA2, 0x43, 0x80}}; + EfiGuid gpi_guid2 = {0x25566B03, + 0xB577, + 0x4CBF, + {0x95, 0x8C, 0xED, 0x66, 0x3E, 0xA2, 0x43, 0x80}}; // EFI_SMM_GPI_DISPATCH_PROTOCOL_GUID - EfiGuid gpi_guid = { - 0xE0744B81, 0x9513, 0x49CD, {0x8C, 0xEA, 0xE9, 0x24, 0x5E, 0x70, 0x39, 0xDA}}; + EfiGuid gpi_guid = {0xE0744B81, + 0x9513, + 0x49CD, + {0x8C, 0xEA, 0xE9, 0x24, 0x5E, 0x70, 0x39, 0xDA}}; // EFI_SMM_USB_DISPATCH2_PROTOCOL_GUID - EfiGuid usb_guid2 = { - 0xEE9B8D90, 0xC5A6, 0x40A2, {0xBD, 0xE2, 0x52, 0x55, 0x8D, 0x33, 0xCC, 0xA1}}; + EfiGuid usb_guid2 = {0xEE9B8D90, + 0xC5A6, + 0x40A2, + {0xBD, 0xE2, 0x52, 0x55, 0x8D, 0x33, 0xCC, 0xA1}}; // EFI_SMM_USB_DISPATCH_PROTOCOL_GUID - EfiGuid usb_guid = { - 0xA05B6FFD, 0x87AF, 0x4E42, {0x95, 0xC9, 0x62, 0x28, 0xB6, 0x3C, 0xF3, 0xF3}}; + EfiGuid usb_guid = {0xA05B6FFD, + 0x87AF, + 0x4E42, + {0x95, 0xC9, 0x62, 0x28, 0xB6, 0x3C, 0xF3, 0xF3}}; // EFI_SMM_STANDBY_BUTTON_DISPATCH2_PROTOCOL_GUID EfiGuid standby_button_guid2 = { - 0x7300C4A1, 0x43F2, 0x4017, {0xA5, 0x1B, 0xC8, 0x1A, 0x7F, 0x40, 0x58, 0x5B}}; + 0x7300C4A1, + 0x43F2, + 0x4017, + {0xA5, 0x1B, 0xC8, 0x1A, 0x7F, 0x40, 0x58, 0x5B}}; // EFI_SMM_STANDBY_BUTTON_DISPATCH_PROTOCOL_GUID EfiGuid standby_button_guid = { - 0x78965B98, 0xB0BF, 0x449E, {0x8B, 0x22, 0xD2, 0x91, 0x4E, 0x49, 0x8A, 0x98}}; + 0x78965B98, + 0xB0BF, + 0x449E, + {0x8B, 0x22, 0xD2, 0x91, 0x4E, 0x49, 0x8A, 0x98}}; // EFI_SMM_PERIODIC_TIMER_DISPATCH2_PROTOCOL_GUID EfiGuid periodic_timer_guid2 = { - 0x4CEC368E, 0x8E8E, 0x4D71, {0x8B, 0xE1, 0x95, 0x8C, 0x45, 0xFC, 0x8A, 0x53}}; + 0x4CEC368E, + 0x8E8E, + 0x4D71, + {0x8B, 0xE1, 0x95, 0x8C, 0x45, 0xFC, 0x8A, 0x53}}; // EFI_SMM_PERIODIC_TIMER_DISPATCH_PROTOCOL_GUID EfiGuid periodic_timer_guid = { - 0x9CCA03FC, 0x4C9E, 0x4A19, {0x9B, 0x06, 0xED, 0x7B, 0x47, 0x9B, 0xDE, 0x55}}; + 0x9CCA03FC, + 0x4C9E, + 0x4A19, + {0x9B, 0x06, 0xED, 0x7B, 0x47, 0x9B, 0xDE, 0x55}}; // EFI_SMM_POWER_BUTTON_DISPATCH2_PROTOCOL_GUID EfiGuid power_button_guid2 = { - 0x1B1183FA, 0x1823, 0x46A7, {0x88, 0x72, 0x9C, 0x57, 0x87, 0x55, 0x40, 0x9D}}; + 0x1B1183FA, + 0x1823, + 0x46A7, + {0x88, 0x72, 0x9C, 0x57, 0x87, 0x55, 0x40, 0x9D}}; // EFI_SMM_POWER_BUTTON_DISPATCH_PROTOCOL_GUID EfiGuid power_button_guid = { - 0xB709EFA0, 0x47A6, 0x4B41, {0xB9, 0x31, 0x12, 0xEC, 0xE7, 0xA8, 0xEE, 0x56}}; + 0xB709EFA0, + 0x47A6, + 0x4B41, + {0xB9, 0x31, 0x12, 0xEC, 0xE7, 0xA8, 0xEE, 0x56}}; // EFI_SMM_ICHN_DISPATCH_PROTOCOL_GUID - EfiGuid ichn_guid = { - 0xC50B323E, 0x9075, 0x4F2A, {0xAC, 0x8E, 0xD2, 0x59, 0x6A, 0x10, 0x85, 0xCC}}; + EfiGuid ichn_guid = {0xC50B323E, + 0x9075, + 0x4F2A, + {0xAC, 0x8E, 0xD2, 0x59, 0x6A, 0x10, 0x85, 0xCC}}; // EFI_SMM_ICHN_DISPATCH2_PROTOCOL_GUID - EfiGuid ichn_guid2 = { - 0xADF3A128, 0x416D, 0x4060, {0x8D, 0xDF, 0x30, 0xA1, 0xD7, 0xAA, 0xB6, 0x99}}; + EfiGuid ichn_guid2 = {0xADF3A128, + 0x416D, + 0x4060, + {0x8D, 0xDF, 0x30, 0xA1, 0xD7, 0xAA, 0xB6, 0x99}}; // PCH_TCO_SMI_DISPATCH_PROTOCOL_GUID - EfiGuid tco_guid = { - 0x9E71D609, 0x6D24, 0x47FD, {0xB5, 0x72, 0x61, 0x40, 0xF8, 0xD9, 0xC2, 0xA4}}; + EfiGuid tco_guid = {0x9E71D609, + 0x6D24, + 0x47FD, + {0xB5, 0x72, 0x61, 0x40, 0xF8, 0xD9, 0xC2, 0xA4}}; // PCH_PCIE_SMI_DISPATCH_PROTOCOL_GUID - EfiGuid pcie_guid = { - 0x3E7D2B56, 0x3F47, 0x42AA, {0x8F, 0x6B, 0x22, 0xF5, 0x19, 0x81, 0x8D, 0xAB}}; + EfiGuid pcie_guid = {0x3E7D2B56, + 0x3F47, + 0x42AA, + {0x8F, 0x6B, 0x22, 0xF5, 0x19, 0x81, 0x8D, 0xAB}}; // PCH_ACPI_SMI_DISPATCH_PROTOCOL_GUID - EfiGuid acpi_guid = { - 0xD52BB262, 0xF022, 0x49EC, {0x86, 0xD2, 0x7A, 0x29, 0x3A, 0x7A, 0x5, 0x4B}}; + EfiGuid acpi_guid = {0xD52BB262, + 0xF022, + 0x49EC, + {0x86, 0xD2, 0x7A, 0x29, 0x3A, 0x7A, 0x5, 0x4B}}; // PCH_GPIO_UNLOCK_SMI_DISPATCH_PROTOCOL_GUID - EfiGuid gpio_unlock_guid = { - 0x83339EF7, 0x9392, 0x4716, {0x8D, 0x3A, 0xD1, 0xFC, 0x67, 0xCD, 0x55, 0xDB}}; + EfiGuid gpio_unlock_guid = {0x83339EF7, + 0x9392, + 0x4716, + {0x8D, 0x3A, 0xD1, 0xFC, 0x67, 0xCD, 0x55, 0xDB}}; // PCH_SMI_DISPATCH_PROTOCOL_GUID - EfiGuid pch_guid = { - 0xE6A81BBF, 0x873D, 0x47FD, {0xB6, 0xBE, 0x61, 0xB3, 0xE5, 0x72, 0x9, 0x93}}; + EfiGuid pch_guid = {0xE6A81BBF, + 0x873D, + 0x47FD, + {0xB6, 0xBE, 0x61, 0xB3, 0xE5, 0x72, 0x9, 0x93}}; // PCH_ESPI_SMI_DISPATCH_PROTOCOL_GUID - EfiGuid espi_guid = { - 0xB3C14FF3, 0xBAE8, 0x456C, {0x86, 0x31, 0x27, 0xFE, 0x0C, 0xEB, 0x34, 0x0C}}; + EfiGuid espi_guid = {0xB3C14FF3, + 0xBAE8, + 0x456C, + {0x86, 0x31, 0x27, 0xFE, 0x0C, 0xEB, 0x34, 0x0C}}; // EFI_ACPI_EN_DISPATCH_PROTOCOL_GUID - EfiGuid acpi_en_guid = { - 0xBD88EC68, 0xEBE4, 0x4F7B, {0x93, 0x5A, 0x4F, 0x66, 0x66, 0x42, 0xE7, 0x5F}}; + EfiGuid acpi_en_guid = {0xBD88EC68, + 0xEBE4, + 0x4F7B, + {0x93, 0x5A, 0x4F, 0x66, 0x66, 0x42, 0xE7, 0x5F}}; // EFI_ACPI_DIS_DISPATCH_PROTOCOL_GUID - EfiGuid acpi_dis_guid = { - 0x9C939BA6, 0x1FCC, 0x46F6, {0xB4, 0xE1, 0x10, 0x2D, 0xBE, 0x18, 0x65, 0x67}}; + EfiGuid acpi_dis_guid = {0x9C939BA6, + 0x1FCC, + 0x46F6, + {0xB4, 0xE1, 0x10, 0x2D, 0xBE, 0x18, 0x65, 0x67}}; // FCH_SMM_GPI_DISPATCH2_PROTOCOL_GUID - EfiGuid fch_gpi_guid2 = { - 0x7051ab6d, 0x9ec2, 0x42eb, {0xa2, 0x13, 0xde, 0x48, 0x81, 0xf1, 0xf7, 0x87}}; + EfiGuid fch_gpi_guid2 = {0x7051ab6d, + 0x9ec2, + 0x42eb, + {0xa2, 0x13, 0xde, 0x48, 0x81, 0xf1, 0xf7, 0x87}}; // FCH_SMM_IO_TRAP_DISPATCH2_PROTOCOL_GUID - EfiGuid fch_io_trap_guid2 = { - 0x91288fc4, 0xe64b, 0x4ef9, {0xa4, 0x63, 0x66, 0x88, 0x0, 0x71, 0x7f, 0xca}}; + EfiGuid fch_io_trap_guid2 = {0x91288fc4, + 0xe64b, + 0x4ef9, + {0xa4, 0x63, 0x66, 0x88, 0x0, 0x71, 0x7f, 0xca}}; // FCH_SMM_PERIODICAL_DISPATCH2_PROTOCOL_GUID EfiGuid fch_periodical_guid2 = { - 0x736102f1, 0x9584, 0x44e7, {0x82, 0x8a, 0x43, 0x4b, 0x1e, 0x67, 0x5c, 0xc4}}; + 0x736102f1, + 0x9584, + 0x44e7, + {0x82, 0x8a, 0x43, 0x4b, 0x1e, 0x67, 0x5c, 0xc4}}; // FCH_SMM_PWR_BTN_DISPATCH2_PROTOCOL_GUID - EfiGuid fch_pwr_btn_guid2 = { - 0xa365240e, 0x56b0, 0x426d, {0x83, 0xa, 0x30, 0x66, 0xc6, 0x81, 0xbe, 0x9a}}; + EfiGuid fch_pwr_btn_guid2 = {0xa365240e, + 0x56b0, + 0x426d, + {0x83, 0xa, 0x30, 0x66, 0xc6, 0x81, 0xbe, 0x9a}}; // FCH_SMM_SW_DISPATCH2_PROTOCOL_GUID - EfiGuid fch_sw_guid2 = { - 0x881b4ab6, 0x17b0, 0x4bdf, {0x88, 0xe2, 0xd4, 0x29, 0xda, 0x42, 0x5f, 0xfd}}; + EfiGuid fch_sw_guid2 = {0x881b4ab6, + 0x17b0, + 0x4bdf, + {0x88, 0xe2, 0xd4, 0x29, 0xda, 0x42, 0x5f, 0xfd}}; // FCH_SMM_SX_DISPATCH2_PROTOCOL_GUID - EfiGuid fch_sx_guid2 = { - 0x87e2a6cf, 0x91fb, 0x4581, {0x90, 0xa9, 0x6f, 0x50, 0x5d, 0xdc, 0x1c, 0xb2}}; + EfiGuid fch_sx_guid2 = {0x87e2a6cf, + 0x91fb, + 0x4581, + {0x90, 0xa9, 0x6f, 0x50, 0x5d, 0xdc, 0x1c, 0xb2}}; // FCH_SMM_USB_DISPATCH_PROTOCOL_GUID - EfiGuid fch_usb_guid = { - 0x59053b0d, 0xeeb8, 0x4379, {0xb1, 0xc8, 0x14, 0x5f, 0x1b, 0xb, 0xe4, 0xb9}}; + EfiGuid fch_usb_guid = {0x59053b0d, + 0xeeb8, + 0x4379, + {0xb1, 0xc8, 0x14, 0x5f, 0x1b, 0xb, 0xe4, 0xb9}}; // FCH_SMM_USB_DISPATCH2_PROTOCOL_GUID - EfiGuid fch_usb_guid2 = { - 0xfbbb2ea9, 0xce0e, 0x4689, {0xb3, 0xf0, 0xc6, 0xb8, 0xf0, 0x76, 0xbd, 0x20}}; + EfiGuid fch_usb_guid2 = {0xfbbb2ea9, + 0xce0e, + 0x4689, + {0xb3, 0xf0, 0xc6, 0xb8, 0xf0, 0x76, 0xbd, 0x20}}; // FCH_SMM_MISC_DISPATCH_PROTOCOL_GUID - EfiGuid fch_misc_guid = { - 0x13bd659b, 0xb4c6, 0x47da, {0x9b, 0x22, 0x11, 0x50, 0xd4, 0xf3, 0xb, 0xda}}; + EfiGuid fch_misc_guid = {0x13bd659b, + 0xb4c6, + 0x47da, + {0x9b, 0x22, 0x11, 0x50, 0xd4, 0xf3, 0xb, 0xda}}; // FCH_SMM_APU_RAS_DISPATCH_PROTOCOL_GUID - EfiGuid fch_apu_ras_guid = { - 0xf871ee59, 0x29d2, 0x4b15, {0x9e, 0x67, 0xaf, 0x32, 0xcd, 0xc1, 0x41, 0x73}}; + EfiGuid fch_apu_ras_guid = {0xf871ee59, + 0x29d2, + 0x4b15, + {0x9e, 0x67, 0xaf, 0x32, 0xcd, 0xc1, 0x41, 0x73}}; uint64_list_t ppiFlags = { - 0x1, 0x10, 0x11, 0x20, 0x21, 0x30, 0x31, - 0x40, 0x41, 0x50, 0x51, 0x60, 0x61, 0x70, - 0x71, 0x80000000, 0x80000001, 0x80000010, 0x80000011, 0x80000020, 0x80000021, - 0x80000030, 0x80000031, 0x80000040, 0x80000041, 0x80000050, 0x80000051, 0x80000060, - 0x80000061, 0x80000070, 0x80000071, + 0x1, 0x10, 0x11, 0x20, 0x21, 0x30, + 0x31, 0x40, 0x41, 0x50, 0x51, 0x60, + 0x61, 0x70, 0x71, 0x80000000, 0x80000001, 0x80000010, + 0x80000011, 0x80000020, 0x80000021, 0x80000030, 0x80000031, 0x80000040, + 0x80000041, 0x80000050, 0x80000051, 0x80000060, 0x80000061, 0x80000070, + 0x80000071, }; // Set boot services that work with protocols @@ -226,7 +311,8 @@ class EfiAnalyser { "SmmLocateProtocol"}; // Set of PEI services that work with PPI - string_list_t ppiPEINames = {"InstallPpi", "ReInstallPpi", "LocatePpi", "NotifyPpi"}; + string_list_t ppiPEINames = {"InstallPpi", "ReInstallPpi", "LocatePpi", + "NotifyPpi"}; }; class EfiAnalyserX86 : public EfiAnalyser { diff --git a/efiXplorer/efi_analyser_arm.cc b/efiXplorer/efi_analyser_arm.cc index e7b4f2ce..089e2305 100644 --- a/efiXplorer/efi_analyser_arm.cc +++ b/efiXplorer/efi_analyser_arm.cc @@ -22,7 +22,7 @@ #include "efi_ui.h" #include "efi_utils.h" -using namespace efi_analysis; +using efi_analysis::EfiAnalyserArm; ea_list_t image_handle_list_arm; ea_list_t st_list_arm; @@ -72,8 +72,9 @@ ea_t get_table_addr(ea_t code_addr, uint64_t offset) { ea_t table = BADADDR; insn_t insn; decode_insn(&insn, code_addr); - if (insn.itype != ARM_ldr || insn.ops[0].type != o_reg || insn.ops[1].type != o_displ || - insn.ops[1].addr != offset || insn.ops[1].reg == REG_XSP) { + if (insn.itype != ARM_ldr || insn.ops[0].type != o_reg || + insn.ops[1].type != o_displ || insn.ops[1].addr != offset || + insn.ops[1].reg == REG_XSP) { return table; } uint8_t table_reg = insn.ops[0].reg; @@ -152,7 +153,8 @@ json getService(ea_t addr, uint8_t table_id) { json s; insn_t insn; decode_insn(&insn, addr); - if (insn.itype == ARM_ldr && insn.ops[0].type == o_reg && insn.ops[1].type == o_displ) { + if (insn.itype == ARM_ldr && insn.ops[0].type == o_reg && + insn.ops[1].type == o_displ) { ea_t ea = addr; uint8_t blr_reg = 0xff; uint8_t table_reg = insn.ops[0].reg; @@ -165,8 +167,9 @@ json getService(ea_t addr, uint8_t table_id) { service_offset = insn.ops[1].addr; blr_reg = insn.ops[0].reg; } - if (blr_reg != 0xff && service_offset != BADADDR && insn.itype == ARM_blr && - insn.ops[0].type == o_reg && insn.ops[0].reg == blr_reg) { + if (blr_reg != 0xff && service_offset != BADADDR && + insn.itype == ARM_blr && insn.ops[0].type == o_reg && + insn.ops[0].reg == blr_reg) { s["address"] = ea; if (table_id == 1) { s["service_name"] = lookup_boot_service_name(service_offset); @@ -191,7 +194,8 @@ json getService(ea_t addr, uint8_t table_id) { // LDR REG2, [REG1] // ... // LDR REG3, [REG2,#0x28] - if (insn.itype == ARM_adr && insn.ops[0].type == o_reg && insn.ops[1].type == o_imm) { + if (insn.itype == ARM_adr && insn.ops[0].type == o_reg && + insn.ops[1].type == o_imm) { uint8_t reg1 = insn.ops[0].reg; uint8_t reg2 = 0xff; ea_t ea = addr; @@ -291,7 +295,6 @@ void efi_analysis::EfiAnalyserArm::initialGlobalVarsDetection() { } void efi_analysis::EfiAnalyserArm::servicesDetection() { - #ifdef HEX_RAYS for (auto func_addr : funcs) { json_list_t services = detect_services(get_func(func_addr)); @@ -350,19 +353,19 @@ bool efi_analysis::EfiAnalyserArm::getProtocol(ea_t address, uint32_t p_reg, while (true) { ea = prev_head(ea, 0); decode_insn(&insn, ea); - if (insn.itype == ARM_adrl && insn.ops[0].type == o_reg && insn.ops[0].reg == p_reg && - insn.ops[1].type == o_imm) { + if (insn.itype == ARM_adrl && insn.ops[0].type == o_reg && + insn.ops[0].reg == p_reg && insn.ops[1].type == o_imm) { guid_addr = insn.ops[1].value; code_addr = ea; break; } - if (insn.itype == ARM_add && insn.ops[0].type == o_reg && insn.ops[0].reg == p_reg && - insn.ops[1].type == o_reg && insn.ops[1].reg == p_reg && - insn.ops[2].type == o_imm) { + if (insn.itype == ARM_add && insn.ops[0].type == o_reg && + insn.ops[0].reg == p_reg && insn.ops[1].type == o_reg && + insn.ops[1].reg == p_reg && insn.ops[2].type == o_imm) { offset = insn.ops[2].value; } - if (insn.itype == ARM_adrp && insn.ops[0].type == o_reg && insn.ops[0].reg == p_reg && - insn.ops[1].type == o_imm) { + if (insn.itype == ARM_adrp && insn.ops[0].type == o_reg && + insn.ops[0].reg == p_reg && insn.ops[1].type == o_imm) { guid_addr = insn.ops[1].value + offset; code_addr = ea; break; @@ -374,7 +377,8 @@ bool efi_analysis::EfiAnalyserArm::getProtocol(ea_t address, uint32_t p_reg, if (guid_addr == BADADDR || code_addr == BADADDR) { return false; } - msg("[efiXplorer] address: 0x%016llX, found new protocol\n", u64_addr(code_addr)); + msg("[efiXplorer] address: 0x%016llX, found new protocol\n", + u64_addr(code_addr)); return AddProtocol(service_name, guid_addr, code_addr, address); } @@ -382,7 +386,8 @@ void efi_analysis::EfiAnalyserArm::protocolsDetection() { for (auto s : allServices) { std::string service_name = s["service_name"]; for (auto i = 0; i < 13; i++) { - std::string current_name = static_cast(bs_table_aarch64[i].name); + std::string current_name = + static_cast(bs_table_aarch64[i].name); if (current_name != service_name) { continue; } @@ -445,14 +450,13 @@ void showAllChoosers(efi_analysis::EfiAnalyserArm analyser) { //-------------------------------------------------------------------------- // Main function for AARCH64 modules bool efi_analysis::efiAnalyserMainArm() { - show_wait_box("HIDECANCEL\nAnalysing module(s) with efiXplorer..."); efi_analysis::EfiAnalyserArm analyser; while (!auto_is_ok()) { auto_wait(); - }; + } // find .text and .data segments analyser.getSegments(); @@ -472,7 +476,8 @@ bool efi_analysis::efiAnalyserMainArm() { msg("[efiXplorer] input file is PEI module\n"); } - // set the correct name for the entry point and automatically fix the prototype + // set the correct name for the entry point and automatically fix the + // prototype analyser.initialAnalysis(); if (analyser.file_type == FfsFileType::DxeAndTheLike) { diff --git a/efiXplorer/efi_analyser_x86.cc b/efiXplorer/efi_analyser_x86.cc index 7085e281..e0cfd2d5 100644 --- a/efiXplorer/efi_analyser_x86.cc +++ b/efiXplorer/efi_analyser_x86.cc @@ -26,7 +26,8 @@ #include "efi_hexrays.h" #endif -using namespace efi_analysis; +using efi_analysis::EfiAnalyser; +using efi_analysis::EfiAnalyserX86; extern ea_list_t g_get_smst_location_calls; extern ea_list_t g_smm_get_variable_calls; @@ -111,7 +112,8 @@ efi_analysis::EfiAnalyser::EfiAnalyser() { // get reverse dictionary for (auto g = dbProtocols.begin(); g != dbProtocols.end(); ++g) { - dbProtocolsMap[static_cast(g.value())] = static_cast(g.key()); + dbProtocolsMap[static_cast(g.value())] = + static_cast(g.key()); } } @@ -168,11 +170,13 @@ void efi_analysis::EfiAnalyser::setStrings() { //-------------------------------------------------------------------------- // Get all .text and .data segments void efi_analysis::EfiAnalyser::getSegments() { - for (segment_t *s = get_first_seg(); s != nullptr; s = get_next_seg(s->start_ea)) { + for (segment_t *s = get_first_seg(); s != nullptr; + s = get_next_seg(s->start_ea)) { qstring seg_name; get_segm_name(&seg_name, s); - string_list_t codeSegNames{".text", ".code"}; // for compatibility with ida-efitools2 + string_list_t codeSegNames{".text", + ".code"}; // for compatibility with ida-efitools2 for (auto name : codeSegNames) { auto index = seg_name.find(name.c_str()); if (index != std::string::npos) { @@ -211,7 +215,6 @@ bool efi_analysis::EfiAnalyserX86::findImageHandleX64() { msg("[%s] gImageHandle finding\n", g_plugin_name); insn_t insn; for (int idx = 0; idx < get_entry_qty(); idx++) { - // get address of entry point uval_t ord = get_entry_ordinal(idx); ea_t ea = get_entry(ord); @@ -221,8 +224,8 @@ bool efi_analysis::EfiAnalyserX86::findImageHandleX64() { decode_insn(&insn, ea); if (insn.itype == NN_mov && insn.ops[1].type == o_reg && insn.ops[1].reg == REG_RCX && insn.ops[0].type == o_mem) { - msg("[%s] found ImageHandle at 0x%016llX, address = 0x%016llX\n", g_plugin_name, - u64_addr(ea), u64_addr(insn.ops[0].addr)); + msg("[%s] found ImageHandle at 0x%016llX, address = 0x%016llX\n", + g_plugin_name, u64_addr(ea), u64_addr(insn.ops[0].addr)); set_cmt(ea, "EFI_IMAGE_HANDLE gImageHandle", true); // set type and name @@ -242,7 +245,6 @@ bool efi_analysis::EfiAnalyserX86::findSystemTableX64() { msg("[%s] gEfiSystemTable finding\n", g_plugin_name); insn_t insn; for (int idx = 0; idx < get_entry_qty(); idx++) { - // get address of entry point uval_t ord = get_entry_ordinal(idx); ea_t ea = get_entry(ord); @@ -271,7 +273,8 @@ bool efi_analysis::EfiAnalyserX86::findSmstX64() { ea_list_t smst_listSwDispatch = findSmstSwDispatch(bs_list); smst_list.insert(smst_list.end(), smst_listSwDispatch.begin(), smst_listSwDispatch.end()); - smst_list.insert(smst_list.end(), smst_listSmmBase.begin(), smst_listSmmBase.end()); + smst_list.insert(smst_list.end(), smst_listSmmBase.begin(), + smst_listSmmBase.end()); // Deduplicate auto last = std::unique(smst_list.begin(), smst_list.end()); @@ -288,8 +291,8 @@ bool efi_analysis::EfiAnalyserX86::findSmstX64() { // after Hex-Rays based analysis bool efi_analysis::EfiAnalyserX86::findSmstPostProcX64() { for (auto ea : g_get_smst_location_calls) { - msg("[%s] EfiSmmBase2Protocol->GetSmstLocation call: 0x%016llX\n", g_plugin_name, - u64_addr(ea)); + msg("[%s] EfiSmmBase2Protocol->GetSmstLocation call: 0x%016llX\n", + g_plugin_name, u64_addr(ea)); insn_t insn; auto addr = ea; ea_t smst_addr = BADADDR; @@ -340,7 +343,8 @@ bool efi_analysis::EfiAnalyserX86::findSmstPostProcX64() { if (!smst_stack.is_null()) { auto reg = smst_stack["reg"] == REG_RSP ? "RSP" : "RBP"; - msg("[%s] Smst: 0x%016llX, reg = %s\n", g_plugin_name, u64_addr(smst_addr), reg); + msg("[%s] Smst: 0x%016llX, reg = %s\n", g_plugin_name, + u64_addr(smst_addr), reg); // try to extract ChildSwSmiHandler auto counter = 0; @@ -348,7 +352,6 @@ bool efi_analysis::EfiAnalyserX86::findSmstPostProcX64() { uint16_t smst_reg = BAD_REG; uint64_t rcx_last = BADADDR; while (ea < static_cast(smst_stack["end"])) { - counter += 1; if (counter > 500) { break; // just in case @@ -358,7 +361,8 @@ bool efi_analysis::EfiAnalyserX86::findSmstPostProcX64() { decode_insn(&insn, ea); if (insn.itype == NN_mov && insn.ops[0].type == o_reg && - insn.ops[1].type == o_displ && smst_stack["addr"] == insn.ops[1].addr) { + insn.ops[1].type == o_displ && + smst_stack["addr"] == insn.ops[1].addr) { switch (insn.ops[1].reg) { case REG_RSP: if (smst_stack["reg"] == REG_RSP) { @@ -406,7 +410,6 @@ bool efi_analysis::EfiAnalyserX86::findSmstPostProcX64() { //-------------------------------------------------------------------------- // Find gBS addresses for 32-bit/64-bit modules bool efi_analysis::EfiAnalyserX86::findBootServicesTables() { - // init architecture-specific constants auto BS_OFFSET = BS_OFFSET_64; uint16_t REG_SP = static_cast(REG_RSP); @@ -419,8 +422,8 @@ bool efi_analysis::EfiAnalyserX86::findBootServicesTables() { insn_t insn; for (auto seg : textSegments) { segment_t *s = seg; - msg("[%s] gEfiBootServices finding from 0x%016llX to 0x%016llX\n", g_plugin_name, - u64_addr(s->start_ea), u64_addr(s->end_ea)); + msg("[%s] gEfiBootServices finding from 0x%016llX to 0x%016llX\n", + g_plugin_name, u64_addr(s->start_ea), u64_addr(s->end_ea)); ea_t ea = s->start_ea; uint16_t bsRegister = 0; uint16_t stRegister = 0; @@ -448,9 +451,11 @@ bool efi_analysis::EfiAnalyserX86::findBootServicesTables() { auto next_ea = next_head(ea, BADADDR); insn_t next_insn; decode_insn(&next_insn, next_ea); - if (next_insn.itype == NN_mov && next_insn.ops[0].type == o_phrase && + if (next_insn.itype == NN_mov && + next_insn.ops[0].type == o_phrase && next_insn.ops[0].phrase == phrase_reg && - next_insn.ops[1].type == o_reg && next_insn.ops[1].reg == bsRegister) { + next_insn.ops[1].type == o_reg && + next_insn.ops[1].reg == bsRegister) { baseInsnAddr = ea; if (!addr_in_vec(bs_list, var_addr)) { set_cmt(ea, "EFI_BOOT_SERVICES *gBS", true); @@ -475,7 +480,8 @@ bool efi_analysis::EfiAnalyserX86::findBootServicesTables() { } // here you can also find gST - if (insn.ops[1].reg == stRegister && !stFound && stRegister != bsRegister) { + if (insn.ops[1].reg == stRegister && !stFound && + stRegister != bsRegister) { var_addr = insn.ops[0].addr; if (!addr_in_tables(st_list, bs_list, rt_list, var_addr)) { set_cmt(ea, "EFI_SYSTEM_TABLE *gST", true); @@ -497,7 +503,8 @@ bool efi_analysis::EfiAnalyserX86::findBootServicesTables() { addr = prev_head(addr, startAddress); decode_insn(&insn, addr); if (insn.itype == NN_mov && insn.ops[1].type == o_reg && - insn.ops[1].reg == stRegister && insn.ops[0].type == o_mem) { + insn.ops[1].reg == stRegister && + insn.ops[0].type == o_mem) { var_addr = insn.ops[0].addr; if (!addr_in_tables(st_list, bs_list, rt_list, var_addr)) { set_cmt(addr, "EFI_SYSTEM_TABLE *gST", true); @@ -520,7 +527,6 @@ bool efi_analysis::EfiAnalyserX86::findBootServicesTables() { //-------------------------------------------------------------------------- // Find gRT addresses for X86/X64 modules bool efi_analysis::EfiAnalyserX86::findRuntimeServicesTables() { - // init architecture-specific constants auto RT_OFFSET = RT_OFFSET_64; uint16_t REG_SP = static_cast(REG_RSP); @@ -533,8 +539,8 @@ bool efi_analysis::EfiAnalyserX86::findRuntimeServicesTables() { insn_t insn; for (auto seg : textSegments) { segment_t *s = seg; - msg("[%s] gEfiRuntimeServices finding from 0x%016llX to 0x%016llX\n", g_plugin_name, - u64_addr(s->start_ea), u64_addr(s->end_ea)); + msg("[%s] gEfiRuntimeServices finding from 0x%016llX to 0x%016llX\n", + g_plugin_name, u64_addr(s->start_ea), u64_addr(s->end_ea)); ea_t ea = s->start_ea; uint16_t rtRegister = 0; uint16_t stRegister = 0; @@ -562,13 +568,16 @@ bool efi_analysis::EfiAnalyserX86::findRuntimeServicesTables() { auto next_ea = next_head(ea, BADADDR); insn_t next_insn; decode_insn(&next_insn, next_ea); - if (next_insn.itype == NN_mov && next_insn.ops[0].type == o_phrase && + if (next_insn.itype == NN_mov && + next_insn.ops[0].type == o_phrase && next_insn.ops[0].phrase == phrase_reg && - next_insn.ops[1].type == o_reg && next_insn.ops[1].reg == rtRegister) { + next_insn.ops[1].type == o_reg && + next_insn.ops[1].reg == rtRegister) { baseInsnAddr = ea; if (!addr_in_vec(rt_list, var_addr)) { set_cmt(ea, "EFI_RUNTIME_SERVICES *gRT", true); - set_ptr_type_and_name(var_addr, "gRT", "EFI_RUNTIME_SERVICES"); + set_ptr_type_and_name(var_addr, "gRT", + "EFI_RUNTIME_SERVICES"); rt_list.push_back(var_addr); } rtFound = true; @@ -582,18 +591,21 @@ bool efi_analysis::EfiAnalyserX86::findRuntimeServicesTables() { var_addr = insn.ops[0].addr; if (!addr_in_vec(rt_list, var_addr)) { set_cmt(ea, "EFI_RUNTIME_SERVICES *gRT", true); - set_ptr_type_and_name(var_addr, "gRT", "EFI_RUNTIME_SERVICES"); + set_ptr_type_and_name(var_addr, "gRT", + "EFI_RUNTIME_SERVICES"); rt_list.push_back(var_addr); } rtFound = true; } // here you can also find gST - if (insn.ops[1].reg == stRegister && !stFound && stRegister != rtRegister) { + if (insn.ops[1].reg == stRegister && !stFound && + stRegister != rtRegister) { var_addr = insn.ops[0].addr; if (!addr_in_tables(st_list, bs_list, rt_list, var_addr)) { set_cmt(ea, "EFI_SYSTEM_TABLE *gST", true); - set_ptr_type_and_name(insn.ops[0].addr, "gST", "EFI_SYSTEM_TABLE"); + set_ptr_type_and_name(insn.ops[0].addr, "gST", + "EFI_SYSTEM_TABLE"); st_list.push_back(insn.ops[0].addr); } stFound = true; @@ -611,7 +623,8 @@ bool efi_analysis::EfiAnalyserX86::findRuntimeServicesTables() { addr = prev_head(addr, startAddress); decode_insn(&insn, addr); if (insn.itype == NN_mov && insn.ops[1].type == o_reg && - insn.ops[1].reg == stRegister && insn.ops[0].type == o_mem) { + insn.ops[1].reg == stRegister && + insn.ops[0].type == o_mem) { if (!addr_in_tables(st_list, bs_list, rt_list, var_addr)) { set_cmt(addr, "EFI_SYSTEM_TABLE *gST", true); set_ptr_type_and_name(var_addr, "gST", "EFI_SYSTEM_TABLE"); @@ -641,9 +654,8 @@ void efi_analysis::EfiAnalyserX86::getAllBootServices() { insn_t insn; for (auto bs : bs_list) { - - msg("[%s] BootServices finding by xrefs to gBS (0x%016llX)\n", g_plugin_name, - u64_addr(bs)); + msg("[%s] BootServices finding by xrefs to gBS (0x%016llX)\n", + g_plugin_name, u64_addr(bs)); auto xrefs = get_xrefs_util(bs); for (auto ea : xrefs) { @@ -670,13 +682,11 @@ void efi_analysis::EfiAnalyserX86::getAllBootServices() { } if (insn.itype == NN_callni && insn.ops[0].reg == bs_reg) { - if (insn.ops[0].addr) { service_offset = insn.ops[0].addr; } for (int j = 0; j < g_boot_services_table_all_count; j++) { - // architecture-specific variables auto offset = g_boot_services_table_all[j].offset64; if (arch == ArchFileType::X8632) { @@ -684,7 +694,6 @@ void efi_analysis::EfiAnalyserX86::getAllBootServices() { } if (service_offset == u32_addr(offset)) { - // additional check for gBS->RegisterProtocolNotify // (can be confused with // gSmst->SmmInstallProtocolInterface) @@ -698,7 +707,8 @@ void efi_analysis::EfiAnalyserX86::getAllBootServices() { msg("[%s] 0x%016llX : %s\n", g_plugin_name, u64_addr(addr), static_cast(g_boot_services_table_all[j].name)); - bootServices[static_cast(g_boot_services_table_all[j].name)] + bootServices[static_cast( + g_boot_services_table_all[j].name)] .push_back(addr); // add item to allBootServices @@ -706,7 +716,8 @@ void efi_analysis::EfiAnalyserX86::getAllBootServices() { bsItem["address"] = addr; bsItem["service_name"] = static_cast(g_boot_services_table_all[j].name); - bsItem["table_name"] = static_cast("EFI_BOOT_SERVICES"); + bsItem["table_name"] = + static_cast("EFI_BOOT_SERVICES"); bsItem["offset"] = offset; // add code addresses for arguments @@ -744,8 +755,8 @@ void efi_analysis::EfiAnalyserX86::getAllRuntimeServices() { for (auto rt : rt_list) { auto xrefs = get_xrefs_util(rt); - msg("[%s] RuntimeServices finding by xrefs to gRT (0x%016llX)\n", g_plugin_name, - u64_addr(rt)); + msg("[%s] RuntimeServices finding by xrefs to gRT (0x%016llX)\n", + g_plugin_name, u64_addr(rt)); for (auto ea : xrefs) { decode_insn(&insn, ea); @@ -770,13 +781,11 @@ void efi_analysis::EfiAnalyserX86::getAllRuntimeServices() { } if (insn.itype == NN_callni && insn.ops[0].reg == rt_reg) { - if (insn.ops[0].addr) { service_offset = insn.ops[0].addr; } for (int j = 0; j < g_runtime_services_table_all_count; j++) { - // architecture-specific variables auto offset = g_runtime_services_table_all[j].offset64; if (arch == ArchFileType::X8632) { @@ -793,9 +802,10 @@ void efi_analysis::EfiAnalyserX86::getAllRuntimeServices() { // add item to allRuntimeServices json rtItem; rtItem["address"] = addr; - rtItem["service_name"] = - static_cast(g_runtime_services_table_all[j].name); - rtItem["table_name"] = static_cast("EFI_RUNTIME_SERVICES"); + rtItem["service_name"] = static_cast( + g_runtime_services_table_all[j].name); + rtItem["table_name"] = + static_cast("EFI_RUNTIME_SERVICES"); rtItem["offset"] = offset; // add code addresses for arguments @@ -829,8 +839,8 @@ void efi_analysis::EfiAnalyserX86::getAllSmmServicesX64() { for (auto smms : smst_list) { auto xrefs = get_xrefs_util(smms); - msg("[%s] SmmServices finding by xref to gSmst (0x%016llX)\n", g_plugin_name, - u64_addr(smms)); + msg("[%s] SmmServices finding by xref to gSmst (0x%016llX)\n", + g_plugin_name, u64_addr(smms)); for (auto ea : xrefs) { decode_insn(&insn, ea); @@ -852,8 +862,8 @@ void efi_analysis::EfiAnalyserX86::getAllSmmServicesX64() { if ((insn.itype == NN_callni || insn.itype == NN_jmpni) && insn.ops[0].reg == smst_reg) { for (int j = 0; j < g_smm_services_table_all_count; j++) { - if (insn.ops[0].addr == u32_addr(g_smm_services_table_all[j].offset64)) { - + if (insn.ops[0].addr == + u32_addr(g_smm_services_table_all[j].offset64)) { if (u32_addr(g_smm_services_table_all[j].offset64) == SmiHandlerRegisterOffset64) { // set name for Handler argument @@ -866,7 +876,8 @@ void efi_analysis::EfiAnalyserX86::getAllSmmServicesX64() { } std::string cmt = - "gSmst->" + static_cast(g_smm_services_table_all[j].name); + "gSmst->" + + static_cast(g_smm_services_table_all[j].name); set_cmt(addr, cmt.c_str(), true); op_stroff_util(addr, "_EFI_SMM_SYSTEM_TABLE2"); msg("[%s] 0x%016llX : %s\n", g_plugin_name, u64_addr(addr), @@ -874,10 +885,12 @@ void efi_analysis::EfiAnalyserX86::getAllSmmServicesX64() { // add address to smmServices[...] if (find(protSmmNames.begin(), protSmmNames.end(), - g_smm_services_table_all[j].name) != protSmmNames.end()) { + g_smm_services_table_all[j].name) != + protSmmNames.end()) { smmServices[g_smm_services_table_all[j].name].push_back(addr); } - smmServicesAll[static_cast(g_smm_services_table_all[j].name)] + smmServicesAll[static_cast( + g_smm_services_table_all[j].name)] .push_back(addr); // add item to allSmmServices @@ -885,7 +898,8 @@ void efi_analysis::EfiAnalyserX86::getAllSmmServicesX64() { smmsItem["address"] = addr; smmsItem["service_name"] = static_cast(g_smm_services_table_all[j].name); - smmsItem["table_name"] = static_cast("_EFI_SMM_SYSTEM_TABLE2"); + smmsItem["table_name"] = + static_cast("_EFI_SMM_SYSTEM_TABLE2"); smmsItem["offset"] = g_smm_services_table_all[j].offset64; // add code addresses for arguments @@ -911,8 +925,8 @@ void efi_analysis::EfiAnalyserX86::getAllSmmServicesX64() { // EFI_PEI_SET_MEM, EFI_PEI_RESET2_SYSTEM, and "Future Installed Services" // (EFI_PEI_FFS_FIND_BY_NAME, etc.) void efi_analysis::EfiAnalyserX86::getAllPeiServicesX86() { - msg("[%s] PeiServices finding from 0x%016llX to 0x%016llX (all)\n", g_plugin_name, - u64_addr(startAddress), u64_addr(endAddress)); + msg("[%s] PeiServices finding from 0x%016llX to 0x%016llX (all)\n", + g_plugin_name, u64_addr(startAddress), u64_addr(endAddress)); ea_t ea = startAddress; insn_t insn; auto found = false; @@ -949,7 +963,8 @@ void efi_analysis::EfiAnalyserX86::getAllPeiServicesX86() { address = prev_head(address, startAddress); decode_insn(&aboveInst, address); if (aboveInst.itype == NN_push) { - if (aboveInst.ops[0].type == o_reg && aboveInst.ops[0].reg == src_reg) { + if (aboveInst.ops[0].type == o_reg && + aboveInst.ops[0].reg == src_reg) { found_push = true; } break; @@ -966,7 +981,8 @@ void efi_analysis::EfiAnalyserX86::getAllPeiServicesX86() { op_stroff_util(ea, "EFI_PEI_SERVICES"); msg("[%s] 0x%016llX : %s\n", g_plugin_name, u64_addr(ea), static_cast(g_pei_services_table32[j].name)); - peiServicesAll[static_cast(g_pei_services_table32[j].name)] + peiServicesAll[static_cast( + g_pei_services_table32[j].name)] .push_back(ea); json psItem; psItem["address"] = ea; @@ -1002,7 +1018,8 @@ void efi_analysis::EfiAnalyserX86::getAllVariablePPICallsX86() { decode_insn(&insn, ea); if (insn.itype == NN_callni && insn.ops[0].type == o_phrase) { for (int j = 0; j < g_variable_ppi_table_all_count; j++) { - if (insn.ops[0].addr == u32_addr(g_variable_ppi_table_all[j].offset32)) { + if (insn.ops[0].addr == + u32_addr(g_variable_ppi_table_all[j].offset32)) { uint16_t ppi_reg = insn.ops[0].reg; insn_t aboveInst; ea_t address = ea; @@ -1012,7 +1029,8 @@ void efi_analysis::EfiAnalyserX86::getAllVariablePPICallsX86() { address = prev_head(address, startAddress); decode_insn(&aboveInst, address); if (aboveInst.itype == NN_push) { - if (aboveInst.ops[0].type == o_reg && aboveInst.ops[0].reg == ppi_reg) { + if (aboveInst.ops[0].type == o_reg && + aboveInst.ops[0].reg == ppi_reg) { found_push = true; } break; @@ -1023,8 +1041,9 @@ void efi_analysis::EfiAnalyserX86::getAllVariablePPICallsX86() { op_stroff_util(ea, "EFI_PEI_READ_ONLY_VARIABLE2_PPI"); msg("[%s] 0x%016llX : %s\n", g_plugin_name, u64_addr(ea), static_cast(g_variable_ppi_table_all[j].name)); - std::string ppi_call = "VariablePPI." + static_cast( - g_variable_ppi_table_all[j].name); + std::string ppi_call = + "VariablePPI." + + static_cast(g_variable_ppi_table_all[j].name); ppiCallsAll[ppi_call].push_back(ea); // Injecting PPI call as service @@ -1079,7 +1098,8 @@ void efi_analysis::EfiAnalyserX86::getPpiNamesX86() { uint16_t pushCounter = 0; msg("[%s] looking for PPIs in the 0x%016llX area (push number: %d)\n", - g_plugin_name, u64_addr(address), g_pei_services_table32[i].push_number); + g_plugin_name, u64_addr(address), + g_pei_services_table32[i].push_number); // Check current basic block while (true) { @@ -1091,7 +1111,8 @@ void efi_analysis::EfiAnalyserX86::getPpiNamesX86() { } if (pushCounter == g_pei_services_table32[i].push_number && - insn.ops[0].type == o_imm && (insn.ops[0].value & 0xffffffff) >= start && + insn.ops[0].type == o_imm && + (insn.ops[0].value & 0xffffffff) >= start && insn.ops[0].value != BADADDR) { // found "push gGuid" insn guidCodeAddress = address; guidDataAddress = insn.ops[0].value & 0xffffffff; @@ -1105,7 +1126,8 @@ void efi_analysis::EfiAnalyserX86::getPpiNamesX86() { } } - msg("[%s] GUID address: 0x%016llX\n", g_plugin_name, u64_addr(guidDataAddress)); + msg("[%s] GUID address: 0x%016llX\n", g_plugin_name, + u64_addr(guidDataAddress)); if (found) { msg("[%s] found PPI GUID parameter at 0x%016llX\n", g_plugin_name, @@ -1193,8 +1215,8 @@ void efi_analysis::EfiAnalyserX86::getProtBootServicesX64() { op_stroff_util(ea, "EFI_BOOT_SERVICES"); msg("[%s] 0x%016llX : %s\n", g_plugin_name, u64_addr(ea), static_cast(g_boot_services_table64[i].name)); - bootServices[static_cast(g_boot_services_table64[i].name)].push_back( - ea); + bootServices[static_cast(g_boot_services_table64[i].name)] + .push_back(ea); // add item to allBootServices json bsItem; @@ -1235,7 +1257,8 @@ void efi_analysis::EfiAnalyserX86::getProtBootServicesX86() { op_stroff_util(ea, "EFI_BOOT_SERVICES"); msg("[%s] 0x%016llX : %s\n", g_plugin_name, u64_addr(ea), static_cast(g_boot_services_table32[i].name)); - bootServices[static_cast(g_boot_services_table32[i].name)] + bootServices[static_cast( + g_boot_services_table32[i].name)] .push_back(ea); // add item to allBootServices @@ -1291,9 +1314,9 @@ void efi_analysis::EfiAnalyserX86::findOtherBsTablesX64() { } } -bool efi_analysis::EfiAnalyser::AddProtocol(std::string serviceName, ea_t guidAddress, - ea_t xrefAddress, ea_t call_address) { - +bool efi_analysis::EfiAnalyser::AddProtocol(std::string serviceName, + ea_t guidAddress, ea_t xrefAddress, + ea_t call_address) { if (arch != ArchFileType::Uefi && guidAddress >= startAddress && guidAddress <= endAddress) { msg("[%s] wrong service call detection: 0x%016llX\n", g_plugin_name, @@ -1359,7 +1382,8 @@ bool efi_analysis::EfiAnalyserX86::InstallMultipleProtocolInterfacesHandler() { } // Get handle stack/data parameter - if (handle_arg == BADADDR && insn.itype == NN_lea && insn.ops[0].reg == REG_RCX) { + if (handle_arg == BADADDR && insn.itype == NN_lea && + insn.ops[0].reg == REG_RCX) { switch (insn.ops[1].type) { case o_displ: if (insn.ops[1].reg == REG_RSP || insn.ops[1].reg == REG_RBP) { @@ -1388,11 +1412,11 @@ bool efi_analysis::EfiAnalyserX86::InstallMultipleProtocolInterfacesHandler() { if (insn.itype == NN_lea && insn.ops[0].type == o_reg && insn.ops[1].type == o_mem) { - switch (insn.ops[0].reg) { case REG_RDX: case REG_R9: - AddProtocol("InstallMultipleProtocolInterfaces", insn.ops[1].addr, address, ea); + AddProtocol("InstallMultipleProtocolInterfaces", insn.ops[1].addr, + address, ea); found = true; break; case REG_RAX: @@ -1406,7 +1430,8 @@ bool efi_analysis::EfiAnalyserX86::InstallMultipleProtocolInterfacesHandler() { auto index = 0; for (auto const ¶m : stack_params) { if (index++ % 2) { - AddProtocol("InstallMultipleProtocolInterfaces", param.second, param.first, ea); + AddProtocol("InstallMultipleProtocolInterfaces", param.second, + param.first, ea); } } } @@ -1427,8 +1452,8 @@ void efi_analysis::EfiAnalyserX86::getBsProtNamesX64() { InstallMultipleProtocolInterfacesHandler(); for (int i = 0; i < g_boot_services_table64_count; i++) { - - if (g_boot_services_table64[i].offset == InstallMultipleProtocolInterfacesOffset64) { + if (g_boot_services_table64[i].offset == + InstallMultipleProtocolInterfacesOffset64) { // Handle InstallMultipleProtocolInterfaces separately continue; } @@ -1487,8 +1512,8 @@ void efi_analysis::EfiAnalyserX86::getBsProtNamesX64() { continue; } - AddProtocol(g_boot_services_table64[i].name, guidDataAddress, guidCodeAddress, - ea); + AddProtocol(g_boot_services_table64[i].name, guidDataAddress, + guidCodeAddress, ea); } } } @@ -1560,8 +1585,8 @@ void efi_analysis::EfiAnalyserX86::getBsProtNamesX86() { continue; } - AddProtocol(g_boot_services_table32[i].name, guidDataAddress, guidCodeAddress, - ea); + AddProtocol(g_boot_services_table32[i].name, guidDataAddress, + guidCodeAddress, ea); } } } @@ -1575,8 +1600,8 @@ void efi_analysis::EfiAnalyserX86::getSmmProtNamesX64() { } segment_t *s = textSegments.at(0); ea_t start = s->start_ea; - msg("[%s] protocols finding (smm services, start address = 0x%016llX)\n", g_plugin_name, - u64_addr(start)); + msg("[%s] protocols finding (smm services, start address = 0x%016llX)\n", + g_plugin_name, u64_addr(start)); for (int i = 0; i < g_smm_services_prot64_count; i++) { auto addrs = smmServices[g_smm_services_prot64[i].name]; @@ -1622,7 +1647,8 @@ void efi_analysis::EfiAnalyserX86::getSmmProtNamesX64() { continue; } - AddProtocol(g_smm_services_prot64[i].name, guidDataAddress, guidCodeAddress, ea); + AddProtocol(g_smm_services_prot64[i].name, guidDataAddress, + guidCodeAddress, ea); } } } @@ -1652,8 +1678,8 @@ void efi_analysis::EfiAnalyser::markInterfaces() { set_guid_type(address); std::string comment = "EFI_GUID " + svcName; markedInterfaces.push_back(address); - msg("[%s] address: 0x%016llX, comment: %s\n", g_plugin_name, u64_addr(address), - comment.c_str()); + msg("[%s] address: 0x%016llX, comment: %s\n", g_plugin_name, + u64_addr(address), comment.c_str()); } } } @@ -1664,15 +1690,17 @@ void efi_analysis::EfiAnalyser::markDataGuids() { ea_t ptrSize = inf_is_64bit() ? 8 : 4; auto guids_segments = textSegments; // find GUIDs in .text and .data segments - // TODO: scan only the areas between the beginning of the .text segment and the first - // function address (?) - guids_segments.insert(guids_segments.end(), dataSegments.begin(), dataSegments.end()); + // TODO(yeggor): scan only the areas between the beginning of the .text + // segment and the first function address (?) + guids_segments.insert(guids_segments.end(), dataSegments.begin(), + dataSegments.end()); for (auto s : guids_segments) { msg("[%s] marking GUIDs from 0x%016llX to 0x%016llX\n", g_plugin_name, u64_addr(s->start_ea), u64_addr(s->end_ea)); ea_t ea = s->start_ea; while (ea != BADADDR && ea <= s->end_ea - 15) { - if (get_wide_dword(ea) == 0x00000000 || get_wide_dword(ea) == 0xffffffff) { + if (get_wide_dword(ea) == 0x00000000 || + get_wide_dword(ea) == 0xffffffff) { ea += 1; continue; } @@ -1702,15 +1730,15 @@ void efi_analysis::EfiAnalyser::markDataGuids() { if (!uint64_in_vec(ppiFlags, flags)) { continue; } - msg("[%s] address: 0x%016llX, PPI: %s\n", g_plugin_name, u64_addr(ppiEa), - ppiName.c_str()); + msg("[%s] address: 0x%016llX, PPI: %s\n", g_plugin_name, + u64_addr(ppiEa), ppiName.c_str()); set_name(ppiEa, ppiName.c_str(), SN_FORCE); } } std::string comment = "EFI_GUID " + guidName; - msg("[%s] address: 0x%016llX, comment: %s\n", g_plugin_name, u64_addr(ea), - comment.c_str()); + msg("[%s] address: 0x%016llX, comment: %s\n", g_plugin_name, + u64_addr(ea), comment.c_str()); json guid_item; guid_item["address"] = ea; @@ -1759,7 +1787,6 @@ void efi_analysis::EfiAnalyserX86::markLocalGuidsX64() { // check if insn like mov dword ptr [...], data2 if (insn_next.itype == NN_mov && insn_next.ops[0].type == o_displ && insn_next.ops[1].type == o_imm) { - // get guid->Data2 value uint16_t data2 = static_cast(insn_next.ops[1].value); if (data2 == 0x0000 || data2 == 0xffff) { @@ -1769,15 +1796,15 @@ void efi_analysis::EfiAnalyserX86::markLocalGuidsX64() { // found guid->Data1 and guid->Data2 values, try to get // guid name - for (auto dbItem = dbProtocols.begin(); dbItem != dbProtocols.end(); ++dbItem) { + for (auto dbItem = dbProtocols.begin(); dbItem != dbProtocols.end(); + ++dbItem) { auto guid = dbItem.value(); if (data1 == static_cast(guid[0]) && data2 == static_cast(guid[1])) { - // mark local GUID std::string comment = "EFI_GUID " + dbItem.key(); - msg("[%s] address: 0x%016llX, comment: %s\n", g_plugin_name, u64_addr(ea), - comment.c_str()); + msg("[%s] address: 0x%016llX, comment: %s\n", g_plugin_name, + u64_addr(ea), comment.c_str()); set_cmt(ea, comment.c_str(), true); json guid_item; @@ -1803,7 +1830,8 @@ void efi_analysis::EfiAnalyserX86::markLocalGuidsX64() { // Search for callouts recursively void findCalloutRec(func_t *func) { insn_t insn; - for (ea_t ea = func->start_ea; ea < func->end_ea; ea = next_head(ea, BADADDR)) { + for (ea_t ea = func->start_ea; ea < func->end_ea; + ea = next_head(ea, BADADDR)) { decode_insn(&insn, ea); if (insn.itype == NN_call) { ea_t nextFuncAddr = insn.ops[0].addr; @@ -1817,7 +1845,8 @@ void findCalloutRec(func_t *func) { } } - if (insn.itype == NN_mov && insn.ops[0].type == o_reg && insn.ops[1].type == o_mem) { + if (insn.itype == NN_mov && insn.ops[0].type == o_reg && + insn.ops[1].type == o_mem) { // search for callouts with gBS if (addr_in_vec(bs_list, insn.ops[1].addr)) { msg("[%s] SMM callout found: 0x%016llX\n", g_plugin_name, u64_addr(ea)); @@ -1840,7 +1869,8 @@ void findCalloutRec(func_t *func) { } } if (!fp) { - msg("[%s] SMM callout found (gBS): 0x%016llX\n", g_plugin_name, u64_addr(ea)); + msg("[%s] SMM callout found (gBS): 0x%016llX\n", g_plugin_name, + u64_addr(ea)); calloutAddrs.push_back(ea); continue; } @@ -1848,7 +1878,8 @@ void findCalloutRec(func_t *func) { // search for callouts with gRT if (addr_in_vec(rt_list, insn.ops[1].addr)) { - msg("[%s] SMM callout found (gRT): 0x%016llX\n", g_plugin_name, u64_addr(ea)); + msg("[%s] SMM callout found (gRT): 0x%016llX\n", g_plugin_name, + u64_addr(ea)); calloutAddrs.push_back(ea); continue; } @@ -1873,7 +1904,8 @@ void findCalloutRec(func_t *func) { current_addr = next_head(current_addr, BADADDR); decode_insn(&next_insn, current_addr); - if (next_insn.itype == NN_callni && next_insn.ops[0].type == o_displ && + if (next_insn.itype == NN_callni && + next_insn.ops[0].type == o_displ && next_insn.ops[0].reg == REG_RAX) { if (next_insn.ops[0].addr == LocateProtocolOffset64 || next_insn.ops[0].addr == AllocatePoolOffset64) { @@ -1976,7 +2008,8 @@ bool efi_analysis::EfiAnalyser::findPPIGetVariableStackOveflow() { std::string getVariableStr("VariablePPI.GetVariable"); for (auto j_service : allServices) { json service = j_service; - std::string service_name = static_cast(service["service_name"]); + std::string service_name = + static_cast(service["service_name"]); std::string table_name = static_cast(service["table_name"]); ea_t addr = static_cast(service["address"]); if (service_name.compare(getVariableStr) == 0) { @@ -1989,7 +2022,8 @@ bool efi_analysis::EfiAnalyser::findPPIGetVariableStackOveflow() { g_plugin_name, getVariableServicesCalls.size()); sort(getVariableServicesCalls.begin(), getVariableServicesCalls.end()); if (getVariableServicesCalls.size() < 2) { - msg("[%s] less than 2 VariablePPI.GetVariable calls found\n", g_plugin_name); + msg("[%s] less than 2 VariablePPI.GetVariable calls found\n", + g_plugin_name); return false; } ea_t prev_addr = getVariableServicesCalls.at(0); @@ -2006,8 +2040,9 @@ bool efi_analysis::EfiAnalyser::findPPIGetVariableStackOveflow() { insn_t insn; while (ea < curr_addr) { decode_insn(&insn, ea); - if (insn.itype == NN_callni || insn.itype == NN_call || insn.itype == NN_retn || - insn.itype == NN_jmp || insn.itype == NN_jmpni) { + if (insn.itype == NN_callni || insn.itype == NN_call || + insn.itype == NN_retn || insn.itype == NN_jmp || + insn.itype == NN_jmpni) { ok = false; break; } @@ -2136,13 +2171,15 @@ bool efi_analysis::EfiAnalyser::findPPIGetVariableStackOveflow() { //-------------------------------------------------------------------------- // Find potential stack/heap overflow with double GetVariable calls -bool efi_analysis::EfiAnalyser::findGetVariableOveflow(json_list_t allServices) { +bool efi_analysis::EfiAnalyser::findGetVariableOveflow( + json_list_t allServices) { msg("[%s] Looking for GetVariable stack/heap overflow\n", g_plugin_name); ea_list_t getVariableServicesCalls; std::string getVariableStr("GetVariable"); for (auto j_service : allServices) { json service = j_service; - std::string service_name = static_cast(service["service_name"]); + std::string service_name = + static_cast(service["service_name"]); ea_t addr = static_cast(service["address"]); if (service_name.compare(getVariableStr) == 0) { getVariableServicesCalls.push_back(addr); @@ -2158,8 +2195,8 @@ bool efi_analysis::EfiAnalyser::findGetVariableOveflow(json_list_t allServices) insn_t insn; for (auto i = 1; i < getVariableServicesCalls.size(); ++i) { ea_t curr_addr = getVariableServicesCalls.at(i); - msg("[%s] GetVariable_1: 0x%016llX, GetVariable_2: 0x%016llX\n", g_plugin_name, - u64_addr(prev_addr), u64_addr(curr_addr)); + msg("[%s] GetVariable_1: 0x%016llX, GetVariable_2: 0x%016llX\n", + g_plugin_name, u64_addr(prev_addr), u64_addr(curr_addr)); // get dataSizeStackAddr int dataSizeStackAddr = 0; @@ -2189,15 +2226,14 @@ bool efi_analysis::EfiAnalyser::findGetVariableOveflow(json_list_t allServices) dataSizeUseCounter++; } if ((insn.itype == NN_callni && insn.ops[0].addr == 0x48) || - insn.itype == NN_retn || insn.itype == NN_jmp || insn.itype == NN_jmpni || - dataSizeUseCounter > 1) { + insn.itype == NN_retn || insn.itype == NN_jmp || + insn.itype == NN_jmpni || dataSizeUseCounter > 1) { ok = false; break; } ea = next_head(ea, BADADDR); } if (ok) { - // check for wrong GetVariable detection bool wrong_detection = false; ea = prev_head(curr_addr, 0); @@ -2246,7 +2282,6 @@ bool efi_analysis::EfiAnalyser::findGetVariableOveflow(json_list_t allServices) break; if (insn.itype == NN_lea && insn.ops[0].type == o_reg && insn.ops[0].reg == REG_R9) { - ea_t stack_addr = insn.ops[1].addr; sval_t sval = get_spd(func_start, ea) * -1; @@ -2272,7 +2307,8 @@ bool efi_analysis::EfiAnalyser::findGetVariableOveflow(json_list_t allServices) // Find potential stack/heap overflow with double SmmGetVariable calls bool efi_analysis::EfiAnalyser::findSmmGetVariableOveflow() { msg("[%s] Looking for SmmGetVariable stack/heap overflow\n", g_plugin_name); - ea_list_t smmGetVariableCalls = findSmmGetVariableCalls(dataSegments, &allServices); + ea_list_t smmGetVariableCalls = + findSmmGetVariableCalls(dataSegments, &allServices); sort(smmGetVariableCalls.begin(), smmGetVariableCalls.end()); if (smmGetVariableCalls.size() < 2) { msg("[%s] less than 2 GetVariable calls found\n", g_plugin_name); @@ -2283,8 +2319,8 @@ bool efi_analysis::EfiAnalyser::findSmmGetVariableOveflow() { insn_t insn; for (auto i = 1; i < smmGetVariableCalls.size(); ++i) { ea_t curr_addr = smmGetVariableCalls.at(i); - msg("[%s] SmmGetVariable_1: 0x%016llX, SmmGetVariable_2: 0x%016llX\n", g_plugin_name, - u64_addr(prev_addr), u64_addr(curr_addr)); + msg("[%s] SmmGetVariable_1: 0x%016llX, SmmGetVariable_2: 0x%016llX\n", + g_plugin_name, u64_addr(prev_addr), u64_addr(curr_addr)); // get dataSizeStackAddr uint32_t dataSizeStackAddr = 0xffffffff; @@ -2305,8 +2341,8 @@ bool efi_analysis::EfiAnalyser::findSmmGetVariableOveflow() { size_t dataSizeUseCounter = 0; while (ea < curr_addr) { decode_insn(&insn, ea); - if (insn.itype == NN_callni || insn.itype == NN_retn || insn.itype == NN_jmpni || - insn.itype == NN_jmp) { + if (insn.itype == NN_callni || insn.itype == NN_retn || + insn.itype == NN_jmpni || insn.itype == NN_jmp) { ok = false; break; } @@ -2314,7 +2350,6 @@ bool efi_analysis::EfiAnalyser::findSmmGetVariableOveflow() { } if (ok) { - // check DataSize initialization bool init_ok = false; decode_insn(&insn, prev_head(curr_addr, 0)); @@ -2350,8 +2385,10 @@ bool efi_analysis::EfiAnalyser::findSmmGetVariableOveflow() { return (smmGetVariableOverflow.size() > 0); } -bool efi_analysis::EfiAnalyser::AnalyseVariableService(ea_t ea, std::string service_str) { - msg("[%s] %s call: 0x%016llX\n", g_plugin_name, service_str.c_str(), u64_addr(ea)); +bool efi_analysis::EfiAnalyser::AnalyseVariableService( + ea_t ea, std::string service_str) { + msg("[%s] %s call: 0x%016llX\n", g_plugin_name, service_str.c_str(), + u64_addr(ea)); json item; item["addr"] = ea; insn_t insn; @@ -2369,8 +2406,8 @@ bool efi_analysis::EfiAnalyser::AnalyseVariableService(ea_t ea, std::string serv auto addr = args[0]; // Get VariableName decode_insn(&insn, addr); - if (insn.itype == NN_lea && insn.ops[0].type == o_reg && insn.ops[0].reg == REG_RCX && - insn.ops[1].type == o_mem) { + if (insn.itype == NN_lea && insn.ops[0].type == o_reg && + insn.ops[0].reg == REG_RCX && insn.ops[1].type == o_mem) { msg("[%s] VariableName address: 0x%016llX\n", g_plugin_name, u64_addr(insn.ops[1].addr)); std::string var_name = get_wide_string(insn.ops[1].addr); @@ -2386,8 +2423,8 @@ bool efi_analysis::EfiAnalyser::AnalyseVariableService(ea_t ea, std::string serv addr = args[1]; // Get VendorGuid decode_insn(&insn, addr); // If GUID is global variable - if (insn.itype == NN_lea && insn.ops[0].type == o_reg && insn.ops[0].reg == REG_RDX && - insn.ops[1].type == o_mem) { + if (insn.itype == NN_lea && insn.ops[0].type == o_reg && + insn.ops[0].reg == REG_RDX && insn.ops[1].type == o_mem) { msg("[%s] VendorGuid address (global): 0x%016llX\n", g_plugin_name, u64_addr(insn.ops[1].addr)); EfiGuid guid = get_global_guid(insn.ops[1].addr); @@ -2400,16 +2437,16 @@ bool efi_analysis::EfiAnalyser::AnalyseVariableService(ea_t ea, std::string serv insn.ops[0].reg == REG_RDX && insn.ops[1].type == o_displ) { switch (insn.ops[1].reg) { case REG_RBP: { - msg("[%s] VendorGuid address (regarding to RBP): 0x%016llX\n", g_plugin_name, - u64_addr(insn.ops[1].addr)); + msg("[%s] VendorGuid address (regarding to RBP): 0x%016llX\n", + g_plugin_name, u64_addr(insn.ops[1].addr)); EfiGuid guid = get_local_guid(f, insn.ops[1].addr); msg("[%s] GUID: %s\n", g_plugin_name, guid.to_string().c_str()); item["VendorGuid"] = guid.to_string(); guid_found = true; } case REG_RSP: { - msg("[%s] VendorGuid address (regarding to RSP): 0x%016llX\n", g_plugin_name, - u64_addr(insn.ops[1].addr)); + msg("[%s] VendorGuid address (regarding to RSP): 0x%016llX\n", + g_plugin_name, u64_addr(insn.ops[1].addr)); EfiGuid guid = get_local_guid(f, insn.ops[1].addr); msg("[%s] GUID: %s\n", g_plugin_name, guid.to_string().c_str()); item["VendorGuid"] = guid.to_string(); @@ -2427,8 +2464,9 @@ bool efi_analysis::EfiAnalyser::AnalyseVariableService(ea_t ea, std::string serv addr = args[2]; // Get Attributes decode_insn(&insn, addr); - if (insn.itype == NN_xor && insn.ops[0].type == o_reg && insn.ops[1].type == o_reg && - insn.ops[0].reg == insn.ops[1].reg && insn.ops[0].reg == REG_R8) { + if (insn.itype == NN_xor && insn.ops[0].type == o_reg && + insn.ops[1].type == o_reg && insn.ops[0].reg == insn.ops[1].reg && + insn.ops[0].reg == REG_R8) { item["Attributes"] = 0; std::string attributes_hr = "No attributes"; item["AttributesHumanReadable"] = attributes_hr; @@ -2452,7 +2490,8 @@ bool efi_analysis::EfiAnalyser::AnalyseVariableService(ea_t ea, std::string serv } } item["AttributesHumanReadable"] = attributes_hr; - msg("[%s] Attributes: %d (%s)\n", g_plugin_name, res, attributes_hr.c_str()); + msg("[%s] Attributes: %d (%s)\n", g_plugin_name, res, + attributes_hr.c_str()); #else // If Hex-Rays analysis is not used, this feature does not work item["Attributes"] = 0xff; @@ -2476,7 +2515,8 @@ bool efi_analysis::EfiAnalyser::analyseNvramVariables() { ea_list_t var_services; for (auto j_service : allServices) { json service = j_service; - std::string service_name = static_cast(service["service_name"]); + std::string service_name = + static_cast(service["service_name"]); ea_t addr = static_cast(service["address"]); if (!service_name.compare(service_str)) { var_services.push_back(addr); @@ -2501,7 +2541,8 @@ bool efi_analysis::EfiAnalyser::analyseNvramVariables() { //-------------------------------------------------------------------------- // Resolve EFI_SMM_CPU_PROTOCOL bool efi_analysis::EfiAnalyser::efiSmmCpuProtocolResolver() { - readSaveStateCalls = resolveEfiSmmCpuProtocol(stackGuids, dataGuids, &allServices); + readSaveStateCalls = + resolveEfiSmmCpuProtocol(stackGuids, dataGuids, &allServices); return true; } @@ -2642,7 +2683,7 @@ bool efi_analysis::efiAnalyserMainX64() { while (!auto_is_ok()) { auto_wait(); - }; + } // find .text and .data segments analyser.getSegments(); @@ -2650,7 +2691,8 @@ bool efi_analysis::efiAnalyserMainX64() { // analyse all auto res = ASKBTN_NO; if (analyser.arch == ArchFileType::Uefi) { - res = ask_yn(1, "Want to further analyse all drivers with auto_mark_range?"); + res = + ask_yn(1, "Want to further analyse all drivers with auto_mark_range?"); } if (res == ASKBTN_YES && textSegments.size() && dataSegments.size()) { segment_t *start_seg = textSegments.at(0); @@ -2711,7 +2753,6 @@ bool efi_analysis::efiAnalyserMainX64() { // search for vulnerabilities if (!g_args.disable_vuln_hunt) { - // find potential SMM callouts analyser.findSwSmiHandlers(); analyser.findSmmCallout(); @@ -2731,7 +2772,8 @@ bool efi_analysis::efiAnalyserMainX64() { analyser.analyseNvramVariables(); } else { - msg("[%s] Parsing of 64-bit PEI files is not supported yet\n", g_plugin_name); + msg("[%s] Parsing of 64-bit PEI files is not supported yet\n", + g_plugin_name); } // dump info to JSON file @@ -2760,14 +2802,13 @@ bool efi_analysis::efiAnalyserMainX64() { //-------------------------------------------------------------------------- // Main function for X86 modules bool efi_analysis::efiAnalyserMainX86() { - show_wait_box("HIDECANCEL\nAnalysing module(s) with efiXplorer..."); efi_analysis::EfiAnalyserX86 analyser; while (!auto_is_ok()) { auto_wait(); - }; + } // find .text and .data segments analyser.getSegments(); @@ -2786,7 +2827,6 @@ bool efi_analysis::efiAnalyserMainX86() { analyser.setStrings(); if (analyser.file_type == FfsFileType::DxeAndTheLike) { - // find global vars for gST, gBS, gRT analyser.findBootServicesTables(); analyser.findRuntimeServicesTables(); diff --git a/efiXplorer/efi_defs.cc b/efiXplorer/efi_defs.cc index 4bec917f..9d8301ca 100644 --- a/efiXplorer/efi_defs.cc +++ b/efiXplorer/efi_defs.cc @@ -23,8 +23,10 @@ const char *g_plugin_name = "efiXplorer"; service_info_64_t g_boot_services_table64[] = { {"InstallProtocolInterface", InstallProtocolInterfaceOffset64, REG_RDX, 1}, - {"ReinstallProtocolInterface", RenstallProtocolInterfaceOffset64, REG_RDX, 1}, - {"UninstallProtocolInterface", UninstallProtocolInterfaceOffset64, REG_RDX, 1}, + {"ReinstallProtocolInterface", RenstallProtocolInterfaceOffset64, REG_RDX, + 1}, + {"UninstallProtocolInterface", UninstallProtocolInterfaceOffset64, REG_RDX, + 1}, {"HandleProtocol", HandleProtocolOffset64, REG_RDX, 1}, {"RegisterProtocolNotify", RegisterProtocolNotifyOffset64, REG_RCX, 0}, {"OpenProtocol", OpenProtocolOffset64, REG_RDX, 1}, @@ -33,10 +35,10 @@ service_info_64_t g_boot_services_table64[] = { {"OpenProtocolInformation", OpenProtocolInformationOffset64, REG_RDX, 1}, {"LocateHandleBuffer", LocateHandleBufferOffset64, REG_RDX, 1}, {"LocateProtocol", LocateProtocolOffset64, REG_RCX, 0}, - {"InstallMultipleProtocolInterfaces", InstallMultipleProtocolInterfacesOffset64, - REG_RDX, 1}, - {"UninstallMultipleProtocolInterfaces", UninstallMultipleProtocolInterfacesOffset64, - REG_RDX, 1}}; + {"InstallMultipleProtocolInterfaces", + InstallMultipleProtocolInterfacesOffset64, REG_RDX, 1}, + {"UninstallMultipleProtocolInterfaces", + UninstallMultipleProtocolInterfacesOffset64, REG_RDX, 1}}; size_t g_boot_services_table64_count = sizeof(g_boot_services_table64) / sizeof(service_info_64_t); @@ -52,9 +54,10 @@ service_info_32_t g_boot_services_table32[] = { {"OpenProtocolInformation", OpenProtocolInformationOffset32, 2}, {"LocateHandleBuffer", LocateHandleBufferOffset32, 2}, {"LocateProtocol", LocateProtocolOffset32, 1}, - {"InstallMultipleProtocolInterfaces", InstallMultipleProtocolInterfacesOffset32, 2}, - {"UninstallMultipleProtocolInterfaces", UninstallMultipleProtocolInterfacesOffset32, - 2}}; + {"InstallMultipleProtocolInterfaces", + InstallMultipleProtocolInterfacesOffset32, 2}, + {"UninstallMultipleProtocolInterfaces", + UninstallMultipleProtocolInterfacesOffset32, 2}}; size_t g_boot_services_table32_count = sizeof(g_boot_services_table32) / sizeof(service_info_32_t); @@ -96,17 +99,22 @@ service_t g_boot_services_table_all[] = { {"Stall", StallOffset64, StallOffset32}, {"SetWatchdogTimer", SetWatchdogTimerOffset64, SetWatchdogTimerOffset32}, {"ConnectController", ConnectControllerOffset64, ConnectControllerOffset32}, - {"DisconnectController", DisconnectControllerOffset64, DisconnectControllerOffset32}, + {"DisconnectController", DisconnectControllerOffset64, + DisconnectControllerOffset32}, {"OpenProtocol", OpenProtocolOffset64, OpenProtocolOffset32}, {"CloseProtocol", CloseProtocolOffset64, CloseProtocolOffset32}, {"OpenProtocolInformation", OpenProtocolInformationOffset64, OpenProtocolInformationOffset32}, - {"ProtocolsPerHandle", ProtocolsPerHandleOffset64, ProtocolsPerHandleOffset32}, - {"LocateHandleBuffer", LocateHandleBufferOffset64, LocateHandleBufferOffset32}, + {"ProtocolsPerHandle", ProtocolsPerHandleOffset64, + ProtocolsPerHandleOffset32}, + {"LocateHandleBuffer", LocateHandleBufferOffset64, + LocateHandleBufferOffset32}, {"LocateProtocol", LocateProtocolOffset64, LocateProtocolOffset32}, - {"InstallMultipleProtocolInterfaces", InstallMultipleProtocolInterfacesOffset64, + {"InstallMultipleProtocolInterfaces", + InstallMultipleProtocolInterfacesOffset64, InstallMultipleProtocolInterfacesOffset32}, - {"UninstallMultipleProtocolInterfaces", UninstallMultipleProtocolInterfacesOffset64, + {"UninstallMultipleProtocolInterfaces", + UninstallMultipleProtocolInterfacesOffset64, UninstallMultipleProtocolInterfacesOffset32}, {"CalculateCrc32", CalculateCrc32Offset64, CalculateCrc32Offset32}, {"CopyMem", CopyMemOffset64, CopyMemOffset32}, @@ -120,10 +128,12 @@ service_t g_runtime_services_table_all[] = { {"SetTime", SetTimeOffset64, SetTimeOffset32}, {"GetWakeupTime", GetWakeupTimeOffset64, GetWakeupTimeOffset32}, {"SetWakeupTime", SetWakeupTimeOffset64, SetWakeupTimeOffset32}, - {"SetVirtualAddressMap", SetVirtualAddressMapOffset64, SetVirtualAddressMapOffset32}, + {"SetVirtualAddressMap", SetVirtualAddressMapOffset64, + SetVirtualAddressMapOffset32}, {"ConvertPointer", ConvertPointerOffset64, ConvertPointerOffset32}, {"GetVariable", GetVariableOffset64, GetVariableOffset32}, - {"GetNextVariableName", GetNextVariableNameOffset64, GetNextVariableNameOffset32}, + {"GetNextVariableName", GetNextVariableNameOffset64, + GetNextVariableNameOffset32}, {"SetVariable", SetVariableOffset64, SetVariableOffset32}, {"GetNextHighMonotonicCount", GetNextHighMonotonicCountOffset64, GetNextHighMonotonicCountOffset32}, @@ -131,13 +141,16 @@ service_t g_runtime_services_table_all[] = { {"UpdateCapsule", UpdateCapsuleOffset64, UpdateCapsuleOffset32}, {"QueryCapsuleCapabilities", QueryCapsuleCapabilitiesOffset64, QueryCapsuleCapabilitiesOffset32}, - {"QueryVariableInfo", QueryVariableInfoOffset64, QueryVariableInfoOffset32}}; + {"QueryVariableInfo", QueryVariableInfoOffset64, + QueryVariableInfoOffset32}}; size_t g_runtime_services_table_all_count = sizeof(g_runtime_services_table_all) / sizeof(service_t); service_info_64_t g_smm_services_prot64[] = { - {"SmmInstallProtocolInterface", SmmInstallProtocolInterfaceOffset64, REG_RDX}, - {"SmmUninstallProtocolInterface", SmmUninstallProtocolInterfaceOffset64, REG_RDX}, + {"SmmInstallProtocolInterface", SmmInstallProtocolInterfaceOffset64, + REG_RDX}, + {"SmmUninstallProtocolInterface", SmmUninstallProtocolInterfaceOffset64, + REG_RDX}, {"SmmHandleProtocol", SmmHandleProtocolOffset64, REG_RDX}, {"SmmRegisterProtocolNotify", SmmRegisterProtocolNotifyOffset64, REG_RCX}, {"SmmLocateHandle", SmmLocateHandleOffset64, REG_RDX}, @@ -163,38 +176,41 @@ service_t g_smm_services_table_all[] = { {"SmmLocateHandle", SmmLocateHandleOffset64, SmmLocateHandleOffset32}, {"SmmLocateProtocol", SmmLocateProtocolOffset64, SmmLocateProtocolOffset32}, {"SmiManage", SmiManageOffset64, SmiManageOffset32}, - {"SmiHandlerRegister", SmiHandlerRegisterOffset64, SmiHandlerRegisterOffset32}, - {"SmiHandlerUnRegister", SmiHandlerUnRegisterOffset64, SmiHandlerUnRegisterOffset32}}; + {"SmiHandlerRegister", SmiHandlerRegisterOffset64, + SmiHandlerRegisterOffset32}, + {"SmiHandlerUnRegister", SmiHandlerUnRegisterOffset64, + SmiHandlerUnRegisterOffset32}}; size_t g_smm_services_table_all_count = sizeof(g_smm_services_table_all) / sizeof(service_t); -service_info_32_t g_pei_services_table32[] = {{"InstallPpi", 0x18, 2}, - {"ReInstallPpi", 0x1c, 3}, - {"LocatePpi", 0x20, 2}, - {"NotifyPpi", 0x24, PUSH_NONE}, - {"GetBootMode", 0x28, PUSH_NONE}, - {"SetBootMode", 0x2c, PUSH_NONE}, - {"GetHobList", 0x30, PUSH_NONE}, - {"CreateHob", 0x34, PUSH_NONE}, - {"FfsFindNextVolume", 0x38, PUSH_NONE}, - {"FfsFindNextFile", 0x3c, PUSH_NONE}, - {"FfsFindSectionData", 0x40, PUSH_NONE}, - {"InstallPeiMemory", 0x44, PUSH_NONE}, - {"AllocatePages", 0x48, PUSH_NONE}, - {"AllocatePool", 0x4c, PUSH_NONE}, - {"CopyMem", 0x50, PUSH_NONE}, - {"SetMem", 0x54, PUSH_NONE}, - {"ReportStatusCode", 0x58, PUSH_NONE}, - {"ResetSystem", 0x5c, PUSH_NONE}, - {"CpuIo", 0x60, PUSH_NONE}, - {"PciCfg", 0x64, PUSH_NONE}, - {"FfsFindFileByName", 0x68, PUSH_NONE}, - {"FfsGetFileInfo", 0x6c, PUSH_NONE}, - {"FfsGetVolumeInfo", 0x70, PUSH_NONE}, - {"RegisterForShadow", 0x74, PUSH_NONE}, - {"FindSectionData3", 0x78, PUSH_NONE}, - {"FfsGetFileInfo2", 0x7c, PUSH_NONE}, - {"ResetSystem2", 0x80, PUSH_NONE}}; +service_info_32_t g_pei_services_table32[] = { + {"InstallPpi", 0x18, 2}, + {"ReInstallPpi", 0x1c, 3}, + {"LocatePpi", 0x20, 2}, + {"NotifyPpi", 0x24, PUSH_NONE}, + {"GetBootMode", 0x28, PUSH_NONE}, + {"SetBootMode", 0x2c, PUSH_NONE}, + {"GetHobList", 0x30, PUSH_NONE}, + {"CreateHob", 0x34, PUSH_NONE}, + {"FfsFindNextVolume", 0x38, PUSH_NONE}, + {"FfsFindNextFile", 0x3c, PUSH_NONE}, + {"FfsFindSectionData", 0x40, PUSH_NONE}, + {"InstallPeiMemory", 0x44, PUSH_NONE}, + {"AllocatePages", 0x48, PUSH_NONE}, + {"AllocatePool", 0x4c, PUSH_NONE}, + {"CopyMem", 0x50, PUSH_NONE}, + {"SetMem", 0x54, PUSH_NONE}, + {"ReportStatusCode", 0x58, PUSH_NONE}, + {"ResetSystem", 0x5c, PUSH_NONE}, + {"CpuIo", 0x60, PUSH_NONE}, + {"PciCfg", 0x64, PUSH_NONE}, + {"FfsFindFileByName", 0x68, PUSH_NONE}, + {"FfsGetFileInfo", 0x6c, PUSH_NONE}, + {"FfsGetVolumeInfo", 0x70, PUSH_NONE}, + {"RegisterForShadow", 0x74, PUSH_NONE}, + {"FindSectionData3", 0x78, PUSH_NONE}, + {"FfsGetFileInfo2", 0x7c, PUSH_NONE}, + {"ResetSystem2", 0x80, PUSH_NONE}}; size_t g_pei_services_table32_count = sizeof(g_pei_services_table32) / sizeof(service_info_32_t); diff --git a/efiXplorer/efi_defs.h b/efiXplorer/efi_defs.h index 5b448ed1..d31e99c3 100644 --- a/efiXplorer/efi_defs.h +++ b/efiXplorer/efi_defs.h @@ -22,7 +22,8 @@ #include #include -#define COPYRIGHT "(C) 2020-2024 Binarly - https://github.com/binarly-io/efiXplorer" +#define COPYRIGHT \ + "(C) 2020-2024 Binarly - https://github.com/binarly-io/efiXplorer" #define BTOA(x) ((x) ? "true" : "false") diff --git a/efiXplorer/efi_deps.cc b/efiXplorer/efi_deps.cc index 725d7d11..57b7875d 100644 --- a/efiXplorer/efi_deps.cc +++ b/efiXplorer/efi_deps.cc @@ -28,7 +28,7 @@ EfiDependencies::EfiDependencies() { // Read images with GUIDs from // .images.json file if this file exists loadImagesWithGuids(); -}; +} EfiDependencies::~EfiDependencies() { imagesInfo.clear(); @@ -40,11 +40,12 @@ EfiDependencies::~EfiDependencies() { protocolsByGuids.clear(); additionalInstallers.clear(); protocolsWithoutInstallers.clear(); -}; +} json EfiDependencies::getDeps(std::string guid) { json res; - std::vector installers({"InstallProtocolInterface", "InstallMultipleProtocolInterfaces", + std::vector installers({"InstallProtocolInterface", + "InstallMultipleProtocolInterfaces", "SmmInstallProtocolInterface"}); for (auto &it : protocolsChooser.items()) { auto p = it.value(); @@ -54,7 +55,8 @@ json EfiDependencies::getDeps(std::string guid) { p["ea"] = as_hex(u64_addr(p["ea"])); p["xref"] = as_hex(u64_addr(p["xref"])); p["address"] = as_hex(u64_addr(p["address"])); - if (find(installers.begin(), installers.end(), p["service"]) != installers.end()) { + if (find(installers.begin(), installers.end(), p["service"]) != + installers.end()) { res["installed"].push_back(p); } else { res["used"].push_back(p); @@ -155,7 +157,8 @@ void EfiDependencies::getInstallersModules() { for (auto ea : xrefs) { if (check_install_protocol(ea)) { auto module = get_module_name_loader(ea); - additionalInstallers[protocol] = static_cast(module.c_str()); + additionalInstallers[protocol] = + static_cast(module.c_str()); installerFound = true; break; } @@ -182,7 +185,8 @@ void EfiDependencies::getAdditionalInstallers() { } void EfiDependencies::getImages() { - for (segment_t *s = get_first_seg(); s != nullptr; s = get_next_seg(s->start_ea)) { + for (segment_t *s = get_first_seg(); s != nullptr; + s = get_next_seg(s->start_ea)) { qstring seg_name; get_segm_name(&seg_name, s); @@ -205,7 +209,8 @@ json EfiDependencies::getImageInfo(std::string image) { json info; string_list_t installedProtocols; json depsProtocols; - std::vector installers({"InstallProtocolInterface", "InstallMultipleProtocolInterfaces", + std::vector installers({"InstallProtocolInterface", + "InstallMultipleProtocolInterfaces", "SmmInstallProtocolInterface"}); // Get installed protocols @@ -227,7 +232,8 @@ json EfiDependencies::getImageInfo(std::string image) { if (image_name != image) { continue; } - if (find(installers.begin(), installers.end(), p["service"]) != installers.end()) { + if (find(installers.begin(), installers.end(), p["service"]) != + installers.end()) { installedProtocols.push_back(p["guid"]); } } @@ -276,7 +282,8 @@ std::string EfiDependencies::getInstaller(std::string protocol) { for (auto &e : imagesInfo.items()) { std::string image = e.key(); string_list_t installers = imagesInfo[image]["installed_protocols"]; - if (find(installers.begin(), installers.end(), protocol) != installers.end()) { + if (find(installers.begin(), installers.end(), protocol) != + installers.end()) { return image; } } @@ -291,8 +298,8 @@ bool EfiDependencies::buildModulesSequence() { std::set modulesSeq; std::set installed_protocols; - getProtocolsWithoutInstallers(); // hard to find installers for all protocols in - // statiс + getProtocolsWithoutInstallers(); // hard to find installers for all protocols + // in statiс getImagesInfo(); size_t index = 0; @@ -353,9 +360,10 @@ bool EfiDependencies::buildModulesSequence() { } } - if (!changed) { // we are in a loop, we need to load a module that installs the - // most popular protocol - std::map protocols_usage; // get the most popular protocol + if (!changed) { // we are in a loop, we need to load a module that installs + // the most popular protocol + std::map + protocols_usage; // get the most popular protocol for (auto &e : imagesInfo.items()) { std::string image = e.key(); diff --git a/efiXplorer/efi_deps.h b/efiXplorer/efi_deps.h index e5a44e90..31ba0bfb 100644 --- a/efiXplorer/efi_deps.h +++ b/efiXplorer/efi_deps.h @@ -21,10 +21,15 @@ #include "efi_utils.h" +#include +#include +#include + class EfiDependencies { public: EfiDependencies(); ~EfiDependencies(); + json protocolsByGuids; // protocols sorted by GUIDs json protocolsChooser; // numbered json with protocols json uefitoolDeps; @@ -38,8 +43,9 @@ class EfiDependencies { void getProtocolsByGuids(json_list_t protocols); void getProtocolsChooser(json_list_t protocols); json getDeps(std::string protocol); // get dependencies for specific protocol - void getAdditionalInstallers(); // get installers by protocol GUIDs by searching in - // the firmware and analysing xrefs + void + getAdditionalInstallers(); // get installers by protocol GUIDs by searching in + // the firmware and analysing xrefs bool buildModulesSequence(); bool getImagesInfo(); diff --git a/efiXplorer/efi_global.cc b/efiXplorer/efi_global.cc index 13772a69..8a566363 100644 --- a/efiXplorer/efi_global.cc +++ b/efiXplorer/efi_global.cc @@ -17,6 +17,7 @@ * */ +#include "efi_global.h" #include "efi_deps.h" EfiDependencies g_deps; diff --git a/efiXplorer/efi_hexrays.cc b/efiXplorer/efi_hexrays.cc index 9d9cc066..5dbc8478 100644 --- a/efiXplorer/efi_hexrays.cc +++ b/efiXplorer/efi_hexrays.cc @@ -51,9 +51,10 @@ bool offset_of(tinfo_t tif, const char *name, unsigned int *offset) { return true; } -// Utility function to set a Hex-Rays variable type and set types for the interfaces -bool set_hexrays_var_info_and_handle_interfaces(ea_t func_addr, lvar_t &ll, tinfo_t tif, - std::string name) { +// Utility function to set a Hex-Rays variable type and set types for the +// interfaces +bool set_hexrays_var_info_and_handle_interfaces(ea_t func_addr, lvar_t &ll, + tinfo_t tif, std::string name) { lvar_saved_info_t lsi; lsi.ll = ll; lsi.type = tif; @@ -65,14 +66,15 @@ bool set_hexrays_var_info_and_handle_interfaces(ea_t func_addr, lvar_t &ll, tinf sval_t stkoff = ll.get_stkoff(); struc_t *frame = get_frame(func_addr); set_member_name(frame, stkoff, name.c_str()); -#endif // TODO: add support for idasdk90 +#endif // TODO(yeggor): add support for idasdk90 } else { // Modufy user lvar info lsi.name = static_cast(name.c_str()); modify_user_lvar_info(func_addr, MLI_NAME, lsi); } // Get xrefs to local variable - xreflist_t xrefs = xrefs_to_stack_var(func_addr, static_cast(name.c_str())); + xreflist_t xrefs = + xrefs_to_stack_var(func_addr, static_cast(name.c_str())); qstring type_name; ptr_type_data_t pi; tif.get_ptr_details(&pi); @@ -98,7 +100,8 @@ bool set_lvar_name(qstring name, lvar_t lvar, ea_t func_addr) { } // Utility function to set a Hex-Rays variable type and name -bool set_hexrays_var_info(ea_t func_addr, lvar_t &ll, tinfo_t tif, std::string name) { +bool set_hexrays_var_info(ea_t func_addr, lvar_t &ll, tinfo_t tif, + std::string name) { lvar_saved_info_t lsi; lsi.ll = ll; lsi.type = tif; @@ -110,7 +113,7 @@ bool set_hexrays_var_info(ea_t func_addr, lvar_t &ll, tinfo_t tif, std::string n sval_t stkoff = ll.get_stkoff(); struc_t *frame = get_frame(func_addr); set_member_name(frame, stkoff, name.c_str()); -#endif // TODO: add support for idasdk90 +#endif // TODO(yeggor): add support for idasdk90 } else { // Modufy user lvar info lsi.name = static_cast(name.c_str()); modify_user_lvar_info(func_addr, MLI_NAME, lsi); @@ -149,7 +152,6 @@ bool is_pod_array(tinfo_t tif, unsigned int ptrDepth = 0) { // Loop over the user-specified depth while (iDepth > 0) { - // Use typeid last checks. I should clean this up; I'm sure I can get rid // of one of them. bool b1 = is_typeid_last(et.get_realtype()); diff --git a/efiXplorer/efi_hexrays.h b/efiXplorer/efi_hexrays.h index a49bdf9b..ec6280c7 100644 --- a/efiXplorer/efi_hexrays.h +++ b/efiXplorer/efi_hexrays.h @@ -21,6 +21,11 @@ #include "efi_utils.h" +#include +#include +#include +#include + uint8_t variables_info_extract_all(func_t *f, ea_t code_addr); bool track_entry_params(func_t *f, uint8_t depth); json detect_vars(func_t *f); @@ -30,9 +35,10 @@ bool detect_pei_services(func_t *f); bool set_lvar_name(qstring name, lvar_t lvar, ea_t func_addr); bool apply_all_types_for_interfaces(json_list_t guids); bool apply_all_types_for_interfaces_smm(json_list_t guids); -bool set_hexrays_var_info(ea_t func_addr, lvar_t &ll, tinfo_t tif, std::string name); -bool set_hexrays_var_info_and_handle_interfaces(ea_t func_addr, lvar_t &ll, tinfo_t tif, - std::string name); +bool set_hexrays_var_info(ea_t func_addr, lvar_t &ll, tinfo_t tif, + std::string name); +bool set_hexrays_var_info_and_handle_interfaces(ea_t func_addr, lvar_t &ll, + tinfo_t tif, std::string name); bool offset_of(tinfo_t tif, const char *name, unsigned int *offset); bool is_pod_array(tinfo_t tif, unsigned int ptrDepth); const char *expr_to_string(cexpr_t *e, qstring *out); @@ -87,7 +93,6 @@ class ServiceDescriptor { bool InitTargets(TargetFunctionPointer *targets, size_t num) { // Iterate through all targets for (int i = 0; i < num; ++i) { - // Copy the target structure into our local vector TargetFunctionPointer &tgt = mTargets.emplace_back(); tgt = targets[i]; @@ -103,16 +108,17 @@ class ServiceDescriptor { public: // Constructor does nothing - ServiceDescriptor() : mOrdinal(0), bInitialized(false) {}; + ServiceDescriptor() : mOrdinal(0), bInitialized(false) {} // Accessor for ordinal - uint32 GetOrdinal() { return mOrdinal; }; + uint32 GetOrdinal() { return mOrdinal; } // Accessor for name - const char *GetName() { return mName.c_str(); }; + const char *GetName() { return mName.c_str(); } // Needs to be called before the object can be used - bool Initialize(const char *name, TargetFunctionPointer *targets, size_t num) { + bool Initialize(const char *name, TargetFunctionPointer *targets, + size_t num) { if (bInitialized) return true; bInitialized = InitType(name) && InitTargets(targets, num); @@ -155,7 +161,6 @@ class ServiceDescriptorMap { // Add a new ServiceDescriptor to the map. I should change the argument // type to match whatever I change the value type of the map to. bool Register(ServiceDescriptor sd) { - // Get the ordinal from the ServiceDescriptor uint32 ord = sd.GetOrdinal(); @@ -198,13 +203,13 @@ class ServiceDescriptorMap { class GUIDRelatedVisitorBase : public ctree_visitor_t { public: // We need access to a ServiceDescriptorMap from above. - GUIDRelatedVisitorBase(ServiceDescriptorMap &m) - : ctree_visitor_t(CV_FAST), mDebug(true), mServices(m) {}; + explicit GUIDRelatedVisitorBase(ServiceDescriptorMap &m) + : ctree_visitor_t(CV_FAST), mDebug(true), mServices(m) {} // We need the function ea when setting Hex-Rays variable types. - void SetFuncEa(ea_t ea) { mFuncEa = ea; }; - void SetCodeEa(ea_t ea) { mCodeEa = ea; }; - void SetProtocols(json_list_t protocols) { mProtocols = protocols; }; + void SetFuncEa(ea_t ea) { mFuncEa = ea; } + void SetCodeEa(ea_t ea) { mCodeEa = ea; } + void SetProtocols(json_list_t protocols) { mProtocols = protocols; } protected: // @@ -286,7 +291,7 @@ class GUIDRelatedVisitorBase : public ctree_visitor_t { mOutArg = nullptr; mGUIDArgRefTo = nullptr; mGUIDEa = BADADDR; - }; + } // Debug print, if the instance debug variable says to void DebugPrint(const char *fmt, ...) { @@ -294,7 +299,7 @@ class GUIDRelatedVisitorBase : public ctree_visitor_t { va_start(va, fmt); if (mDebug) vmsg(fmt, va); - }; + } // This is the first function called every time the visitor visits an // expression. This function determines if the expression is a call to a @@ -354,12 +359,11 @@ class GUIDRelatedVisitorBase : public ctree_visitor_t { // pointer contained in a structure, where the structure is being // accessed by a pointer. return true; - }; + } // This is the second function called as part of indirect call validation. // Now we want to know: is it a call to something that we're tracking? bool ValidateICallDestination() { - // Look up the structure ordinal and function offset; get the associated // ServiceDescriptor and TargetFunctionPointer (instance variables). if (!mServices.LookupOffset(mOrdinal, mOffset, &mpService, &mpTarget)) @@ -384,7 +388,7 @@ class GUIDRelatedVisitorBase : public ctree_visitor_t { // something that we're tracking, and that Hex-Rays decompiled the call // the way we expected it to. return true; - }; + } // This is a helper function used to get the thing being referred to. What // does that mean? @@ -395,7 +399,6 @@ class GUIDRelatedVisitorBase : public ctree_visitor_t { // does not actually have a "&" when passed as a call argument. There's // a bit of extra logic to check for that case. cexpr_t *GetReferent(cexpr_t *e, const char *desc, bool bAcceptVar) { - // Eat casts cexpr_t *x = e; while (x->op == cot_cast) @@ -425,7 +428,7 @@ class GUIDRelatedVisitorBase : public ctree_visitor_t { // If we get here, we know it's a reference. Return the referent. return x->x; - }; + } // The third function in the validation logic. We already know the // expression is an indirect call to something that we're tracking, and @@ -453,7 +456,7 @@ class GUIDRelatedVisitorBase : public ctree_visitor_t { // number of arguments; and that the GUID argument did in fact point to // a global variable, whose address we now have in an instance variable. return true; - }; + } // Finally, this function combines all three checks above into one single // function. If you call this and it returns true, feel free to access the @@ -479,8 +482,8 @@ class GUIDRelatedVisitorBase : public ctree_visitor_t { // we know about, and setting the types of the output variables accordingly. class GUIDRetyper : public GUIDRelatedVisitorBase { public: - GUIDRetyper(ServiceDescriptorMap &m) : GUIDRelatedVisitorBase(m), mNumApplied(0) {}; - + explicit GUIDRetyper(ServiceDescriptorMap &m) + : GUIDRelatedVisitorBase(m), mNumApplied(0) {} // This is the callback function that Hex-Rays invokes for every expression // in the CTREE. int visit_expr(cexpr_t *e) { @@ -571,16 +574,14 @@ class GUIDRetyper : public GUIDRelatedVisitorBase { pi.obj_type.get_type_name(&type_name); // Handling all interface functions (to rename function arguments) op_stroff_for_global_interface(xrefs, type_name); - } - - // For local variables - else if (outArg->op == cot_var) { + } else if (outArg->op == cot_var) { // For local variables var_ref_t varRef = outArg->v; lvar_t &destVar = varRef.mba->vars[varRef.idx]; // Set the Hex-Rays variable type auto name = type_to_name(static_cast(tStr.c_str())); set_lvar_name(static_cast(name.c_str()), destVar, mFuncEa); - if (set_hexrays_var_info_and_handle_interfaces(mFuncEa, destVar, ptrTif, name)) { + if (set_hexrays_var_info_and_handle_interfaces(mFuncEa, destVar, ptrTif, + name)) { ++mNumApplied; } } @@ -594,10 +595,7 @@ class GUIDRetyper : public GUIDRelatedVisitorBase { // Rename global variable auto name = "g" + type_to_name(type_name); set_name(dest_ea, name.c_str(), SN_FORCE); - } - - // For local variables - else if (outArg->op == cot_var) { + } else if (outArg->op == cot_var) { // For local variables var_ref_t varRef = outArg->v; lvar_t &destVar = varRef.mba->vars[varRef.idx]; // Set the Hex-Rays variable type @@ -609,9 +607,9 @@ class GUIDRetyper : public GUIDRelatedVisitorBase { class VariablesInfoExtractor : public ctree_visitor_t { public: - VariablesInfoExtractor(ea_t code_addr) : ctree_visitor_t(CV_FAST) { + explicit VariablesInfoExtractor(ea_t code_addr) : ctree_visitor_t(CV_FAST) { mCodeAddr = code_addr; - }; + } uint8_t mAttributes = 0xff; @@ -642,7 +640,8 @@ class VariablesInfoExtractor : public ctree_visitor_t { cexpr_t *attributes_arg = &args->at(2); if (attributes_arg->op == cot_num) { if (mDebug) { - msg("[I] Service call: %016llX, Attributes: %02X\n", u64_addr(mCodeAddr), + msg("[I] Service call: %016llX, Attributes: %02X\n", + u64_addr(mCodeAddr), static_cast(attributes_arg->numval())); } attributes_arg->numval(); @@ -659,7 +658,7 @@ class VariablesInfoExtractor : public ctree_visitor_t { class PrototypesFixer : public ctree_visitor_t { public: - PrototypesFixer() : ctree_visitor_t(CV_FAST) {}; + PrototypesFixer() : ctree_visitor_t(CV_FAST) {} ea_list_t child_functions; // This is the callback function that Hex-Rays invokes for every expression @@ -759,7 +758,7 @@ class PrototypesFixer : public ctree_visitor_t { class VariablesDetector : public ctree_visitor_t { public: - VariablesDetector() : ctree_visitor_t(CV_FAST) {}; + VariablesDetector() : ctree_visitor_t(CV_FAST) {} ea_list_t child_functions; @@ -768,7 +767,7 @@ class VariablesDetector : public ctree_visitor_t { ea_list_t bs_list; ea_list_t rt_list; - void SetFuncEa(ea_t ea) { mFuncEa = ea; }; + void SetFuncEa(ea_t ea) { mFuncEa = ea; } // This is the callback function that Hex-Rays invokes for every expression // in the CTREE. @@ -887,7 +886,7 @@ class VariablesDetector : public ctree_visitor_t { class ServicesDetector : public ctree_visitor_t { // detect all services (Boot services, Runtime services, etc) public: - ServicesDetector() : ctree_visitor_t(CV_FAST) {}; + ServicesDetector() : ctree_visitor_t(CV_FAST) {} json_list_t services; @@ -922,7 +921,8 @@ class ServicesDetector : public ctree_visitor_t { is_ptr = 0; } - auto service_name = type_to_name(static_cast(type_name.c_str())); + auto service_name = + type_to_name(static_cast(type_name.c_str())); if (service_name.rfind("Efi", 0) == 0) { service_name = service_name.substr(3); if (service_name == "RaiseTpl") { @@ -956,7 +956,7 @@ class ServicesDetector : public ctree_visitor_t { class PeiServicesDetector : public ctree_visitor_t { // detect and mark all PEI services public: - PeiServicesDetector() : ctree_visitor_t(CV_FAST) {}; + PeiServicesDetector() : ctree_visitor_t(CV_FAST) {} bool make_shifted_ptr(tinfo_t outer, tinfo_t inner, int32 offset, tinfo_t *shifted_tif) { @@ -985,9 +985,10 @@ class PeiServicesDetector : public ctree_visitor_t { var_ref_t var_ref; if (e->op == cot_ptr && e->x->op == cot_cast && e->x->x->op == cot_add && e->x->x->x->op == cot_ptr && e->x->x->x->x->op == cot_ptr && - e->x->x->x->x->x->op == cot_cast && e->x->x->x->x->x->x->op == cot_sub && - e->x->x->x->x->x->x->x->op == cot_var && e->x->x->x->x->x->x->y->op == cot_num && - e->x->x->y->op == cot_num) { + e->x->x->x->x->x->op == cot_cast && + e->x->x->x->x->x->x->op == cot_sub && + e->x->x->x->x->x->x->x->op == cot_var && + e->x->x->x->x->x->x->y->op == cot_num && e->x->x->y->op == cot_num) { // (*ADJ(v2)->PeiServices)->GetHobList( // (const EFI_PEI_SERVICES**)ADJ(v2)->PeiServices, HobList); service_offset = e->x->x->y->numval(); @@ -1005,7 +1006,8 @@ class PeiServicesDetector : public ctree_visitor_t { return 0; } - msg("[efiXplorer] address: 0x%08llX, PEI service detected\n", u64_addr(e->ea)); + msg("[efiXplorer] address: 0x%08llX, PEI service detected\n", + u64_addr(e->ea)); msg("[efiXplorer] delta: %llx\n", u64_addr(pointer_offset)); if (service_offset != BADADDR) { msg("[efiXplorer] service offset: %llx\n", u64_addr(service_offset)); @@ -1049,15 +1051,15 @@ class PeiServicesDetectorArm : public ctree_visitor_t { // detect and mark all PEI services for ARM firmware // tested on Ampere firmware that contains small PEI stack public: - PeiServicesDetectorArm() : ctree_visitor_t(CV_FAST) {}; + PeiServicesDetectorArm() : ctree_visitor_t(CV_FAST) {} json_list_t services; // This is the callback function that Hex-Rays invokes for every expression // in the CTREE. int visit_expr(cexpr_t *e) { - if (!(e->op == cot_call && e->x->op == cot_memptr && e->x->x->op == cot_ptr && - e->x->x->x->op == cot_var)) { + if (!(e->op == cot_call && e->x->op == cot_memptr && + e->x->x->op == cot_ptr && e->x->x->x->op == cot_var)) { return 0; } ea_t offset = e->x->m; diff --git a/efiXplorer/efi_smm_utils.cc b/efiXplorer/efi_smm_utils.cc index 6850cff6..a98dc1e0 100644 --- a/efiXplorer/efi_smm_utils.cc +++ b/efiXplorer/efi_smm_utils.cc @@ -20,6 +20,8 @@ #include "efi_smm_utils.h" #include "efi_global.h" +#include + //-------------------------------------------------------------------------- // Find and mark gSmst global variable via EFI_SMM_SW_DISPATCH(2)_PROTOCOL_GUID ea_list_t findSmstSwDispatch(ea_list_t bs_list) { @@ -70,8 +72,8 @@ ea_list_t findSmstSwDispatch(ea_list_t bs_list) { decode_insn(&insn, cur_addr); if (insn.itype == NN_mov && insn.ops[0].type == o_reg && insn.ops[0].reg == smst_reg && insn.ops[1].type == o_mem) { - msg("[%s] found gSmst at 0x%016llX, address = 0x%016llX\n", g_plugin_name, - u64_addr(cur_addr), u64_addr(insn.ops[1].addr)); + msg("[%s] found gSmst at 0x%016llX, address = 0x%016llX\n", + g_plugin_name, u64_addr(cur_addr), u64_addr(insn.ops[1].addr)); res_addr = insn.ops[1].addr; if (addr_in_vec(bs_list, res_addr)) { continue; @@ -95,11 +97,11 @@ ea_list_t findSmstSwDispatch(ea_list_t bs_list) { // Find and mark gSmst global variable via EFI_SMM_BASE2_PROTOCOL_GUID ea_list_t findSmstSmmBase(ea_list_t bs_list) { ea_list_t smst_addrs; - EfiGuid guid = { - 0xf4ccbfb7, - 0xf6e0, - 0x47fd, - {0x9d, 0xd4, 0x10, 0xa8, 0xf1, 0x50, 0xc1, 0x91}}; // EFI_SMM_BASE2_PROTOCOL_GUID + EfiGuid guid = {0xf4ccbfb7, + 0xf6e0, + 0x47fd, + {0x9d, 0xd4, 0x10, 0xa8, 0xf1, 0x50, 0xc1, + 0x91}}; // EFI_SMM_BASE2_PROTOCOL_GUID ea_list_t data_addrs = find_data(0, BADADDR, guid.uchar_data().data(), 16); for (auto data_addr : data_addrs) { msg("[%s] EFI_SMM_BASE2_PROTOCOL_GUID: 0x%016llX\n", g_plugin_name, @@ -148,8 +150,8 @@ ea_list_t findSmstSmmBase(ea_list_t bs_list) { // Find SmiHandler in reg_smi_func function (prefix: Sw, TrapIo, Sx, Gpi, Usb, // StandbyButton, PeriodicTimer, PowerButton) func_list_t findSmiHandlers(ea_t address, std::string prefix) { - msg("[%s] Analyse xref to gEfiSmm%sDispatch(2)Protocol: 0x%016llX\n", g_plugin_name, - prefix.c_str(), u64_addr(address)); + msg("[%s] Analyse xref to gEfiSmm%sDispatch(2)Protocol: 0x%016llX\n", + g_plugin_name, prefix.c_str(), u64_addr(address)); func_list_t smiHandlers; insn_t insn; @@ -159,8 +161,8 @@ func_list_t findSmiHandlers(ea_t address, std::string prefix) { // Check instruction decode_insn(&insn, address); if (!(insn.ops[0].type == o_reg && insn.ops[0].reg == REG_RCX)) { - msg("[%s] %sSmiHandler: wrong xref to dispatch(2) protocol\n", g_plugin_name, - prefix.c_str()); + msg("[%s] %sSmiHandler: wrong xref to dispatch(2) protocol\n", + g_plugin_name, prefix.c_str()); return smiHandlers; } @@ -180,16 +182,16 @@ func_list_t findSmiHandlers(ea_t address, std::string prefix) { break; } // Interface in stack - if (insn.itype == NN_lea && insn.ops[0].type == o_reg && insn.ops[0].reg == REG_R8 && - insn.ops[1].type == o_displ && + if (insn.itype == NN_lea && insn.ops[0].type == o_reg && + insn.ops[0].reg == REG_R8 && insn.ops[1].type == o_displ && (insn.ops[1].reg == REG_RBP || insn.ops[1].reg == REG_RSP)) { if (dispatch_interface == BADADDR) { dispatch_interface = insn.ops[1].addr; } } // Interface in data - if (insn.itype == NN_lea && insn.ops[0].type == o_reg && insn.ops[0].reg == REG_R8 && - insn.ops[1].type == o_mem) { + if (insn.itype == NN_lea && insn.ops[0].type == o_reg && + insn.ops[0].reg == REG_R8 && insn.ops[1].type == o_mem) { if (dispatch_interface == BADADDR) { dispatch_interface = insn.ops[1].addr; } @@ -225,10 +227,10 @@ func_list_t findSmiHandlers(ea_t address, std::string prefix) { return smiHandlers; } - msg("[%s] Found EfiSmm%sDispatch(2)Protocol interface: 0x%016llX\n", g_plugin_name, - prefix.c_str(), dispatch_interface); + msg("[%s] Found EfiSmm%sDispatch(2)Protocol interface: 0x%016llX\n", + g_plugin_name, prefix.c_str(), dispatch_interface); - // TODO: handle xrefs for globals + // TODO(yeggor): handle xrefs for globals // (fw71.bin.out/SmmHddSecurity-316b1230-0500-4592-8c09-eaba0fb6b07f.smm) // Track interface stack variable @@ -262,8 +264,8 @@ func_list_t findSmiHandlers(ea_t address, std::string prefix) { } // get DispatchFunction address - if (insn.itype == NN_lea && insn.ops[0].type == o_reg && insn.ops[0].reg == REG_RDX && - insn.ops[1].type == o_mem) { + if (insn.itype == NN_lea && insn.ops[0].type == o_reg && + insn.ops[0].reg == REG_RDX && insn.ops[1].type == o_mem) { dispatch_func = insn.ops[1].addr; continue; } @@ -287,7 +289,8 @@ func_list_t findSmiHandlers(ea_t address, std::string prefix) { std::string name = prefix + "SmiHandler"; set_name(dispatch_func, name.c_str(), SN_FORCE); std::string prefix_upper; - std::transform(prefix.begin(), prefix.end(), prefix_upper.begin(), ::toupper); + std::transform(prefix.begin(), prefix.end(), prefix_upper.begin(), + ::toupper); std::string type = "EFI_SMM_" + prefix_upper + "_DISPATCH2_PROTOCOL"; op_stroff_util(ea, type); } @@ -330,8 +333,8 @@ func_list_t findSmiHandlersSmmDispatch(EfiGuid guid, std::string prefix) { //-------------------------------------------------------------------------- // Find SwSmiHandler function inside SMM drivers in case where // EFI_SMM_SW_DISPATCH(2)_PROTOCOL_GUID is a local variable -func_list_t findSmiHandlersSmmDispatchStack(json_list_t stackGuids, std::string prefix) { - // TODO: make it generic +func_list_t findSmiHandlersSmmDispatchStack(json_list_t stackGuids, + std::string prefix) { func_list_t smiHandlers; for (auto guid : stackGuids) { @@ -355,16 +358,17 @@ func_list_t findSmiHandlersSmmDispatchStack(json_list_t stackGuids, std::string //-------------------------------------------------------------------------- // Find gSmmVar->SmmGetVariable calls via EFI_SMM_VARIABLE_PROTOCOL_GUID -ea_list_t findSmmGetVariableCalls(segment_list_t dataSegments, json_list_t *allServices) { +ea_list_t findSmmGetVariableCalls(segment_list_t dataSegments, + json_list_t *allServices) { msg("[%s] gSmmVar->SmmGetVariable calls finding via " "EFI_SMM_VARIABLE_PROTOCOL_GUID\n", g_plugin_name); ea_list_t smmGetVariableCalls; - EfiGuid guid = { - 0xed32d533, - 0x99e6, - 0x4209, - {0x9c, 0xc0, 0x2d, 0x72, 0xcd, 0xd9, 0x98, 0xa7}}; // EFI_SMM_VARIABLE_PROTOCOL_GUID + EfiGuid guid = {0xed32d533, + 0x99e6, + 0x4209, + {0x9c, 0xc0, 0x2d, 0x72, 0xcd, 0xd9, 0x98, + 0xa7}}; // EFI_SMM_VARIABLE_PROTOCOL_GUID // Find all EFI_GUID EFI_SMM_VARIABLE_PROTOCOL_GUID addresses ea_list_t data_addrs = find_data(0, BADADDR, guid.uchar_data().data(), 16); @@ -396,7 +400,8 @@ ea_list_t findSmmGetVariableCalls(segment_list_t dataSegments, json_list_t *allS msg("[%s] gSmmVar address: 0x%016llX\n", g_plugin_name, u64_addr(insn.ops[1].addr)); set_cmt(ea, "EFI_SMM_VARIABLE_PROTOCOL *gSmmVar", true); - set_ptr_type_and_name(insn.ops[1].addr, "gSmmVar", "EFI_SMM_VARIABLE_PROTOCOL"); + set_ptr_type_and_name(insn.ops[1].addr, "gSmmVar", + "EFI_SMM_VARIABLE_PROTOCOL"); gSmmVarAddrs.push_back(insn.ops[1].addr); break; } @@ -437,11 +442,11 @@ ea_list_t findSmmGetVariableCalls(segment_list_t dataSegments, json_list_t *allS if (insn.itype == NN_callni && gSmmVarReg == insn.ops[0].reg && insn.ops[0].addr == 0) { - msg("[%s] gSmmVar->SmmGetVariable found: 0x%016llX\n", g_plugin_name, - u64_addr(ea)); + msg("[%s] gSmmVar->SmmGetVariable found: 0x%016llX\n", + g_plugin_name, u64_addr(ea)); - if (find(smmGetVariableCalls.begin(), smmGetVariableCalls.end(), ea) == - smmGetVariableCalls.end()) { + if (find(smmGetVariableCalls.begin(), smmGetVariableCalls.end(), + ea) == smmGetVariableCalls.end()) { smmGetVariableCalls.push_back(ea); } @@ -449,7 +454,8 @@ ea_list_t findSmmGetVariableCalls(segment_list_t dataSegments, json_list_t *allS // for easier annotations and UI op_stroff_util(ea, "EFI_SMM_VARIABLE_PROTOCOL"); - msg("[%s] 0x%016llX : %s\n", g_plugin_name, u64_addr(ea), "SmmGetVariable"); + msg("[%s] 0x%016llX : %s\n", g_plugin_name, u64_addr(ea), + "SmmGetVariable"); std::string smm_call = "gSmmVar->SmmGetVariable"; json smm_item; smm_item["address"] = ea; @@ -472,7 +478,8 @@ ea_list_t findSmmGetVariableCalls(segment_list_t dataSegments, json_list_t *allS return smmGetVariableCalls; } -ea_list_t resolveEfiSmmCpuProtocol(json_list_t stackGuids, json_list_t dataGuids, +ea_list_t resolveEfiSmmCpuProtocol(json_list_t stackGuids, + json_list_t dataGuids, json_list_t *allServices) { ea_list_t readSaveStateCalls; msg("[%s] Looking for EFI_SMM_CPU_PROTOCOL\n", g_plugin_name); @@ -494,7 +501,8 @@ ea_list_t resolveEfiSmmCpuProtocol(json_list_t stackGuids, json_list_t dataGuids continue; ea_t address = static_cast(guid["address"]); - msg("[%s] found EFI_SMM_CPU_PROTOCOL: 0x%016llX\n", g_plugin_name, u64_addr(address)); + msg("[%s] found EFI_SMM_CPU_PROTOCOL: 0x%016llX\n", g_plugin_name, + u64_addr(address)); ea_list_t guidXrefs = get_xrefs_util(address); for (auto guidXref : guidXrefs) { @@ -522,7 +530,8 @@ ea_list_t resolveEfiSmmCpuProtocol(json_list_t stackGuids, json_list_t dataGuids msg("[%s] gSmmCpu address: 0x%016llX\n", g_plugin_name, u64_addr(insn.ops[1].addr)); set_cmt(ea, "EFI_SMM_CPU_PROTOCOL *gSmmCpu", true); - set_ptr_type_and_name(insn.ops[1].addr, "gSmmCpu", "EFI_SMM_CPU_PROTOCOL"); + set_ptr_type_and_name(insn.ops[1].addr, "gSmmCpu", + "EFI_SMM_CPU_PROTOCOL"); gSmmCpuAddrs.push_back(insn.ops[1].addr); break; } @@ -563,8 +572,8 @@ ea_list_t resolveEfiSmmCpuProtocol(json_list_t stackGuids, json_list_t dataGuids if (insn.itype == NN_callni && gSmmCpuReg == insn.ops[0].reg && insn.ops[0].addr == 0) { - if (find(readSaveStateCalls.begin(), readSaveStateCalls.end(), ea) == - readSaveStateCalls.end()) { + if (find(readSaveStateCalls.begin(), readSaveStateCalls.end(), + ea) == readSaveStateCalls.end()) { readSaveStateCalls.push_back(ea); } @@ -575,7 +584,8 @@ ea_list_t resolveEfiSmmCpuProtocol(json_list_t stackGuids, json_list_t dataGuids json smm_item; smm_item["address"] = ea; smm_item["service_name"] = smm_call; - smm_item["table_name"] = static_cast("EFI_SMM_CPU_PROTOCOL"); + smm_item["table_name"] = + static_cast("EFI_SMM_CPU_PROTOCOL"); smm_item["offset"] = 0; if (find(allServices->begin(), allServices->end(), smm_item) == @@ -602,7 +612,8 @@ ea_t markChildSwSmiHandler(ea_t ea) { addr = prev_head(addr, 0); // check current instruction - if (insn.itype == NN_lea && insn.ops[0].type == o_reg && insn.ops[0].reg == REG_RCX) { + if (insn.itype == NN_lea && insn.ops[0].type == o_reg && + insn.ops[0].reg == REG_RCX) { if (insn.ops[1].type != o_mem) { continue; } diff --git a/efiXplorer/efi_smm_utils.h b/efiXplorer/efi_smm_utils.h index 224c5c6f..4c735331 100644 --- a/efiXplorer/efi_smm_utils.h +++ b/efiXplorer/efi_smm_utils.h @@ -21,12 +21,17 @@ #include "efi_utils.h" +#include + ea_list_t findSmstSwDispatch(ea_list_t bs_list); ea_list_t findSmstSmmBase(ea_list_t bs_list); func_list_t findSmiHandlers(ea_t address, std::string prefix); func_list_t findSmiHandlersSmmDispatch(EfiGuid guid, std::string prefix); -func_list_t findSmiHandlersSmmDispatchStack(json_list_t stackGuids, std::string prefix); -ea_list_t findSmmGetVariableCalls(segment_list_t dataSegments, json_list_t *allServices); -ea_list_t resolveEfiSmmCpuProtocol(json_list_t stackGuids, json_list_t dataGuids, +func_list_t findSmiHandlersSmmDispatchStack(json_list_t stackGuids, + std::string prefix); +ea_list_t findSmmGetVariableCalls(segment_list_t dataSegments, + json_list_t *allServices); +ea_list_t resolveEfiSmmCpuProtocol(json_list_t stackGuids, + json_list_t dataGuids, json_list_t *allServices); ea_t markChildSwSmiHandler(ea_t ea); diff --git a/efiXplorer/efi_ui.cc b/efiXplorer/efi_ui.cc index adfdee1d..3f9c39e2 100644 --- a/efiXplorer/efi_ui.cc +++ b/efiXplorer/efi_ui.cc @@ -97,21 +97,24 @@ const char *const nvram_chooser_t::header_nvram[] = { "Attributes" // 4 }; -inline nvram_chooser_t::nvram_chooser_t(const char *title_, bool ok, json_list_t nvram) - : chooser_t(0, qnumber(widths_nvram), widths_nvram, header_nvram, title_), list() { +inline nvram_chooser_t::nvram_chooser_t(const char *title_, bool ok, + json_list_t nvram) + : chooser_t(0, qnumber(widths_nvram), widths_nvram, header_nvram, title_), + list() { CASSERT(qnumber(widths_nvram) == qnumber(header_nvram)); build_list(ok, nvram); } -void idaapi nvram_chooser_t::get_row(qstrvec_t *cols_, int *, chooser_item_attrs_t *, - size_t n) const { +void idaapi nvram_chooser_t::get_row(qstrvec_t *cols_, int *, + chooser_item_attrs_t *, size_t n) const { ea_t ea = list[n]; qstrvec_t &cols = *cols_; json item = chooser_nvram[n]; std::string name = static_cast(item["VariableName"]); std::string guid = static_cast(item["VendorGuid"]); std::string service = static_cast(item["service"]); - std::string attributes = static_cast(item["AttributesHumanReadable"]); + std::string attributes = + static_cast(item["AttributesHumanReadable"]); cols[0].sprnt("%016llX", u64_addr(ea)); cols[1].sprnt("%s", name.c_str()); cols[2].sprnt("%s", guid.c_str()); @@ -120,14 +123,16 @@ void idaapi nvram_chooser_t::get_row(qstrvec_t *cols_, int *, chooser_item_attrs CASSERT(qnumber(header_nvram) == 5); } -inline vulns_chooser_t::vulns_chooser_t(const char *title_, bool ok, json_list_t vulns) - : chooser_t(0, qnumber(widths_vulns), widths_vulns, header_vulns, title_), list() { +inline vulns_chooser_t::vulns_chooser_t(const char *title_, bool ok, + json_list_t vulns) + : chooser_t(0, qnumber(widths_vulns), widths_vulns, header_vulns, title_), + list() { CASSERT(qnumber(widths_vulns) == qnumber(header_vulns)); build_list(ok, vulns); } -void idaapi vulns_chooser_t::get_row(qstrvec_t *cols_, int *, chooser_item_attrs_t *, - size_t n) const { +void idaapi vulns_chooser_t::get_row(qstrvec_t *cols_, int *, + chooser_item_attrs_t *, size_t n) const { ea_t ea = list[n]; qstrvec_t &cols = *cols_; json item = chooser_vulns[n]; @@ -137,14 +142,16 @@ void idaapi vulns_chooser_t::get_row(qstrvec_t *cols_, int *, chooser_item_attrs CASSERT(qnumber(header_vulns) == 2); } -inline guids_chooser_t::guids_chooser_t(const char *title_, bool ok, json_list_t guids) - : chooser_t(0, qnumber(widths_guids), widths_guids, header_guids, title_), list() { +inline guids_chooser_t::guids_chooser_t(const char *title_, bool ok, + json_list_t guids) + : chooser_t(0, qnumber(widths_guids), widths_guids, header_guids, title_), + list() { CASSERT(qnumber(widths_guids) == qnumber(header_guids)); build_list(ok, guids); } -void idaapi guids_chooser_t::get_row(qstrvec_t *cols_, int *, chooser_item_attrs_t *, - size_t n) const { +void idaapi guids_chooser_t::get_row(qstrvec_t *cols_, int *, + chooser_item_attrs_t *, size_t n) const { ea_t ea = list[n]; qstrvec_t &cols = *cols_; json item = chooser_guids[n]; @@ -159,14 +166,16 @@ void idaapi guids_chooser_t::get_row(qstrvec_t *cols_, int *, chooser_item_attrs inline protocols_chooser_t::protocols_chooser_t(const char *title_, bool ok, json_list_t protocols, std::string name_key_) - : chooser_t(0, qnumber(widths_protocols), widths_protocols, header_protocols, title_), + : chooser_t(0, qnumber(widths_protocols), widths_protocols, + header_protocols, title_), list() { CASSERT(qnumber(widths_protocols) == qnumber(header_protocols)); name_key = name_key_; build_list(ok, protocols); } -void idaapi protocols_chooser_t::get_row(qstrvec_t *cols_, int *, chooser_item_attrs_t *, +void idaapi protocols_chooser_t::get_row(qstrvec_t *cols_, int *, + chooser_item_attrs_t *, size_t n) const { ea_t ea = list[n]; qstrvec_t &cols = *cols_; @@ -183,14 +192,15 @@ void idaapi protocols_chooser_t::get_row(qstrvec_t *cols_, int *, chooser_item_a CASSERT(qnumber(header_protocols) == 5); } -inline s_chooser_t::s_chooser_t(const char *title_, bool ok, json_list_t services) +inline s_chooser_t::s_chooser_t(const char *title_, bool ok, + json_list_t services) : chooser_t(0, qnumber(widths_s), widths_s, header_s, title_), list() { CASSERT(qnumber(widths_s) == qnumber(header_s)); build_list(ok, services); } -void idaapi s_chooser_t::get_row(qstrvec_t *cols_, int *, chooser_item_attrs_t *, - size_t n) const { +void idaapi s_chooser_t::get_row(qstrvec_t *cols_, int *, + chooser_item_attrs_t *, size_t n) const { ea_t ea = list[n]; qstrvec_t &cols = *cols_; json item = chooser_s[n]; @@ -242,7 +252,8 @@ bool protocols_show(json_list_t protocols, qstring title) { bool ppis_show(json_list_t ppis, qstring title) { bool ok; // open the window - protocols_chooser_t *ch = new protocols_chooser_t(title.c_str(), ok, ppis, "ppi_name"); + protocols_chooser_t *ch = + new protocols_chooser_t(title.c_str(), ok, ppis, "ppi_name"); // default cursor position is 0 (first row) ch->choose(); return true; @@ -275,8 +286,8 @@ struct protocols_deps_handler_t : public action_handler_t { // print dependencies for current // protocol in output window std::string s = d.dump(2); - msg("[%s] dependencies for protocol with GUID %s: %s\n", g_plugin_name, guid.c_str(), - s.c_str()); + msg("[%s] dependencies for protocol with GUID %s: %s\n", g_plugin_name, + guid.c_str(), s.c_str()); return 0; } @@ -319,9 +330,9 @@ struct modules_seq_handler_t : public action_handler_t { }; static modules_seq_handler_t modules_seq_ah; -action_desc_t modules_seq = - ACTION_DESC_LITERAL("efiXplorer:modulesSeq", "Show the sequence of modules execution", - &modules_seq_ah, nullptr, nullptr, -1); +action_desc_t modules_seq = ACTION_DESC_LITERAL( + "efiXplorer:modulesSeq", "Show the sequence of modules execution", + &modules_seq_ah, nullptr, nullptr, -1); void attachActionModulesSeq() { // Attach action in protocols chooser @@ -345,7 +356,8 @@ struct action_handler_loadreport_t : public action_handler_t { return -1; } reportPath /= file; - msg("[%s] loading report from %s file\n", g_plugin_name, reportPath.c_str()); + msg("[%s] loading report from %s file\n", g_plugin_name, + reportPath.c_str()); json reportData; try { @@ -435,6 +447,6 @@ static action_handler_loadreport_t load_report_handler; //------------------------------------------------------------------------- // Action to load efiXplorer analysis report -action_desc_t action_load_report = - ACTION_DESC_LITERAL("efiXplorer:loadReport", "efiXplorer analysis report...", - &load_report_handler, nullptr, nullptr, -1); +action_desc_t action_load_report = ACTION_DESC_LITERAL( + "efiXplorer:loadReport", "efiXplorer analysis report...", + &load_report_handler, nullptr, nullptr, -1); diff --git a/efiXplorer/efi_ui.h b/efiXplorer/efi_ui.h index 6c231992..fee0d995 100644 --- a/efiXplorer/efi_ui.h +++ b/efiXplorer/efi_ui.h @@ -21,13 +21,11 @@ #include "efi_utils.h" +#include + //------------------------------------------------------------------------- -// Vulns chooser +// vulns chooser class vulns_chooser_t : public chooser_t { -protected: - static const int widths_vulns[]; - static const char *const header_vulns[]; - public: eavec_t list; json chooser_vulns; @@ -47,8 +45,8 @@ class vulns_chooser_t : public chooser_t { virtual size_t idaapi get_count() const { return list.size(); } // function that generates the list line - virtual void idaapi get_row(qstrvec_t *cols, int *icon_, chooser_item_attrs_t *attrs, - size_t n) const; + virtual void idaapi get_row(qstrvec_t *cols, int *icon_, + chooser_item_attrs_t *attrs, size_t n) const; // function that is called when the user hits `Enter` virtual cbret_t idaapi enter(size_t n) { @@ -58,6 +56,9 @@ class vulns_chooser_t : public chooser_t { } protected: + static const int widths_vulns[]; + static const char *const header_vulns[]; + void build_list(bool ok, json_list_t vulns) { size_t n = 0; for (auto vuln : vulns) { @@ -66,7 +67,7 @@ class vulns_chooser_t : public chooser_t { n++; } ok = true; - }; + } }; //------------------------------------------------------------------------- @@ -95,8 +96,8 @@ class guids_chooser_t : public chooser_t { virtual size_t idaapi get_count() const { return list.size(); } // function that generates the list line - virtual void idaapi get_row(qstrvec_t *cols, int *icon_, chooser_item_attrs_t *attrs, - size_t n) const; + virtual void idaapi get_row(qstrvec_t *cols, int *icon_, + chooser_item_attrs_t *attrs, size_t n) const; // function that is called when the user hits `Enter` virtual cbret_t idaapi enter(size_t n) { @@ -114,7 +115,7 @@ class guids_chooser_t : public chooser_t { n++; } ok = true; - }; + } }; //------------------------------------------------------------------------- @@ -145,8 +146,8 @@ class protocols_chooser_t : public chooser_t { virtual size_t idaapi get_count() const { return list.size(); } // function that generates the list line - virtual void idaapi get_row(qstrvec_t *cols, int *icon_, chooser_item_attrs_t *attrs, - size_t n) const; + virtual void idaapi get_row(qstrvec_t *cols, int *icon_, + chooser_item_attrs_t *attrs, size_t n) const; // function that is called when the user hits `Enter` virtual cbret_t idaapi enter(size_t n) { @@ -164,7 +165,7 @@ class protocols_chooser_t : public chooser_t { n++; } ok = true; - }; + } }; //------------------------------------------------------------------------- @@ -193,8 +194,8 @@ class s_chooser_t : public chooser_t { virtual size_t idaapi get_count() const { return list.size(); } // function that generates the list line - virtual void idaapi get_row(qstrvec_t *cols, int *icon_, chooser_item_attrs_t *attrs, - size_t n) const; + virtual void idaapi get_row(qstrvec_t *cols, int *icon_, + chooser_item_attrs_t *attrs, size_t n) const; // function that is called when the user hits `Enter` virtual cbret_t idaapi enter(size_t n) { @@ -212,7 +213,7 @@ class s_chooser_t : public chooser_t { n++; } ok = true; - }; + } }; //------------------------------------------------------------------------- @@ -241,8 +242,8 @@ class nvram_chooser_t : public chooser_t { virtual size_t idaapi get_count() const { return list.size(); } // function that generates the list line - virtual void idaapi get_row(qstrvec_t *cols, int *icon_, chooser_item_attrs_t *attrs, - size_t n) const; + virtual void idaapi get_row(qstrvec_t *cols, int *icon_, + chooser_item_attrs_t *attrs, size_t n) const; // function that is called when the user hits `Enter` virtual cbret_t idaapi enter(size_t n) { @@ -260,7 +261,7 @@ class nvram_chooser_t : public chooser_t { n++; } ok = true; - }; + } }; extern action_desc_t action_load_report; diff --git a/efiXplorer/efi_utils.cc b/efiXplorer/efi_utils.cc index 80ec58c9..f197ebf8 100644 --- a/efiXplorer/efi_utils.cc +++ b/efiXplorer/efi_utils.cc @@ -21,6 +21,8 @@ #include "efi_defs.h" #include "efi_global.h" +#include + // can be used after Hex-Rays based analysis ea_list_t g_get_smst_location_calls; ea_list_t g_smm_get_variable_calls; @@ -108,7 +110,8 @@ FfsFileType guess_file_type(ArchFileType arch, json_list_t *all_guids) { for (auto guid = all_guids->begin(); guid != all_guids->end(); guid++) { json guid_value = *guid; - if (static_cast(guid_value["name"]).find("PEI") != std::string::npos) { + if (static_cast(guid_value["name"]).find("PEI") != + std::string::npos) { has_pei_guids = true; break; } @@ -125,12 +128,14 @@ FfsFileType guess_file_type(ArchFileType arch, json_list_t *all_guids) { } if (signature == VZ || has_pei_guids) { - msg("[%s] parsing binary file as PEI, signature = %llx, has_pei_guids = %d\n", + msg("[%s] parsing binary file as PEI, signature = %llx, has_pei_guids = " + "%d\n", g_plugin_name, signature, has_pei_guids); return FfsFileType::Pei; } - msg("[%s] parsing binary file as DXE/SMM, signature = %llx, has_pei_guids = %d\n", + msg("[%s] parsing binary file as DXE/SMM, signature = %llx, has_pei_guids = " + "%d\n", g_plugin_name, signature, has_pei_guids); return FfsFileType::DxeAndTheLike; } @@ -143,7 +148,8 @@ FfsFileType ask_file_type(json_list_t *all_guids) { auto ftype = guess_file_type(arch, all_guids); auto deflt = ftype == FfsFileType::DxeAndTheLike; auto fmt_param = ftype == FfsFileType::DxeAndTheLike ? "DXE/SMM" : "PEI"; - auto btn_id = ask_buttons("DXE/SMM", "PEI", "", deflt, "Parse file as %s", fmt_param); + auto btn_id = + ask_buttons("DXE/SMM", "PEI", "", deflt, "Parse file as %s", fmt_param); if (btn_id == ASKBTN_YES) { return FfsFileType::DxeAndTheLike; } @@ -160,8 +166,8 @@ ea_t find_unknown_bs_var_64(ea_t ea) { // check 10 instructions below for (int i = 0; i < 10; i++) { decode_insn(&insn, ea); - if (insn.itype == NN_mov && insn.ops[0].type == o_reg && insn.ops[0].reg == REG_RAX && - insn.ops[1].type == o_mem) { + if (insn.itype == NN_mov && insn.ops[0].type == o_reg && + insn.ops[0].reg == REG_RAX && insn.ops[1].type == o_mem) { res = insn.ops[1].addr; break; } @@ -314,8 +320,8 @@ void set_entry_arg_to_pei_svc() { ea_t start_ea = get_entry(ord); tinfo_t tif_ea; if (guess_tinfo(&tif_ea, start_ea) == GUESS_FUNC_FAILED) { - msg("[%s] guess_tinfo failed, start_ea = 0x%016llX, idx=%d\n", g_plugin_name, - u64_addr(start_ea), idx); + msg("[%s] guess_tinfo failed, start_ea = 0x%016llX, idx=%d\n", + g_plugin_name, u64_addr(start_ea), idx); continue; } @@ -328,7 +334,8 @@ void set_entry_arg_to_pei_svc() { tinfo_t tif_pei; bool res = tif_pei.get_named_type(get_idati(), "EFI_PEI_SERVICES"); if (!res) { - msg("[%s] get_named_type failed, res = %d, idx=%d\n", g_plugin_name, res, idx); + msg("[%s] get_named_type failed, res = %d, idx=%d\n", g_plugin_name, res, + idx); continue; } @@ -479,20 +486,23 @@ qstring get_module_name_loader(ea_t addr) { //-------------------------------------------------------------------------- // get GUID data by address json get_guid_by_address(ea_t addr) { - return json::array( - {get_wide_dword(addr), get_wide_word(addr + 4), get_wide_word(addr + 6), - get_wide_byte(addr + 8), get_wide_byte(addr + 9), get_wide_byte(addr + 10), - get_wide_byte(addr + 11), get_wide_byte(addr + 12), get_wide_byte(addr + 13), - get_wide_byte(addr + 14), get_wide_byte(addr + 15)}); + return json::array({get_wide_dword(addr), get_wide_word(addr + 4), + get_wide_word(addr + 6), get_wide_byte(addr + 8), + get_wide_byte(addr + 9), get_wide_byte(addr + 10), + get_wide_byte(addr + 11), get_wide_byte(addr + 12), + get_wide_byte(addr + 13), get_wide_byte(addr + 14), + get_wide_byte(addr + 15)}); } //-------------------------------------------------------------------------- // validate GUID value bool valid_guid(json guid) { - if (static_cast(guid[0]) == 0x00000000 && (uint16_t)guid[1] == 0x0000) { + if (static_cast(guid[0]) == 0x00000000 && + (uint16_t)guid[1] == 0x0000) { return false; } - if (static_cast(guid[0]) == 0xffffffff && (uint16_t)guid[1] == 0xffff) { + if (static_cast(guid[0]) == 0xffffffff && + (uint16_t)guid[1] == 0xffff) { return false; } return true; @@ -557,9 +567,11 @@ ea_list_t search_protocol(std::string protocol) { ea_t start = 0; while (true) { #if IDA_SDK_VERSION < 900 - ea_t addr = bin_search2(start, BADADDR, bytes, nullptr, 16, BIN_SEARCH_FORWARD); + ea_t addr = + bin_search2(start, BADADDR, bytes, nullptr, 16, BIN_SEARCH_FORWARD); #else - ea_t addr = bin_search3(start, BADADDR, bytes, nullptr, 16, BIN_SEARCH_FORWARD); + ea_t addr = + bin_search3(start, BADADDR, bytes, nullptr, 16, BIN_SEARCH_FORWARD); #endif if (addr == BADADDR) { break; @@ -603,13 +615,13 @@ bool check_boot_service_protocol(ea_t call_addr) { auto addr = prev_head(call_addr, 0); decode_insn(&insn, addr); while (!is_basic_block_end(insn, false)) { - // for next iteration decode_insn(&insn, addr); addr = prev_head(addr, 0); // check current instruction - if (insn.itype == NN_lea && insn.ops[0].type == o_reg && insn.ops[0].reg == REG_RCX) { + if (insn.itype == NN_lea && insn.ops[0].type == o_reg && + insn.ops[0].reg == REG_RCX) { if (insn.ops[1].type == o_mem) { // will still be a false positive if the Handle in // SmmInstallProtocolInterface is a global variable) @@ -627,7 +639,8 @@ bool check_boot_service_protocol_xrefs(ea_t call_addr) { insn_t insn; for (auto xref : get_xrefs_util(call_addr)) { decode_insn(&insn, xref); - if (insn.itype == NN_lea && insn.ops[0].type == o_reg && insn.ops[0].reg == REG_R8) { + if (insn.itype == NN_lea && insn.ops[0].type == o_reg && + insn.ops[0].reg == REG_R8) { // load interface instruction return false; } @@ -642,8 +655,8 @@ bool mark_copy(ea_t code_addr, ea_t var_addr, std::string type) { ea_t var_copy = BADADDR; decode_insn(&insn, ea); - if (insn.itype == NN_mov && insn.ops[0].type == o_reg && insn.ops[1].type == o_mem && - insn.ops[1].addr == var_addr) { + if (insn.itype == NN_mov && insn.ops[0].type == o_reg && + insn.ops[1].type == o_mem && insn.ops[1].addr == var_addr) { reg = insn.ops[0].reg; } @@ -664,10 +677,11 @@ bool mark_copy(ea_t code_addr, ea_t var_addr, std::string type) { break; } - if (insn.itype == NN_mov && insn.ops[0].type == o_mem && insn.ops[1].type == o_reg && - insn.ops[1].reg == reg) { + if (insn.itype == NN_mov && insn.ops[0].type == o_mem && + insn.ops[1].type == o_reg && insn.ops[1].reg == reg) { var_copy = insn.ops[0].addr; - msg("[efiXplorer] found copy for global variable: 0x%016llX\n", u64_addr(ea)); + msg("[efiXplorer] found copy for global variable: 0x%016llX\n", + u64_addr(ea)); break; } } @@ -718,8 +732,9 @@ std::string type_to_name(std::string type) { if (c >= 'A' && c <= 'Z') { if (counter > 0) { result.push_back(c + 32); - } else + } else { result.push_back(c); + } counter += 1; continue; } @@ -751,7 +766,7 @@ xreflist_t xrefs_to_stack_var(ea_t func_addr, qstring var_name) { } #endif - // TODO: rewrite for idasdk90 + // TODO(yeggor): rewrite for idasdk90 return xrefs_list; } @@ -762,7 +777,8 @@ void op_stroff_for_addr(ea_t ea, qstring type_name) { ea = next_head(ea, BADADDR); decode_insn(&insn, ea); // check for interface function call - if ((insn.itype == NN_call || insn.itype == NN_callfi || insn.itype == NN_callni) && + if ((insn.itype == NN_call || insn.itype == NN_callfi || + insn.itype == NN_callni) && (insn.ops[0].type == o_displ || insn.ops[0].type == o_phrase) && insn.ops[0].reg == REG_RAX) { op_stroff_util(ea, static_cast(type_name.c_str())); @@ -770,21 +786,22 @@ void op_stroff_for_addr(ea_t ea, qstring type_name) { g_plugin_name, u64_addr(ea), type_name.c_str()); // check for EfiSmmBase2Protocol->GetSmstLocation - if (type_name == "EFI_SMM_BASE2_PROTOCOL" && insn.ops[0].type == o_displ && - insn.ops[0].addr == 8) { + if (type_name == "EFI_SMM_BASE2_PROTOCOL" && + insn.ops[0].type == o_displ && insn.ops[0].addr == 8) { if (!addr_in_vec(g_get_smst_location_calls, ea)) { g_get_smst_location_calls.push_back(ea); } } - if (type_name == "EFI_SMM_VARIABLE_PROTOCOL" && insn.ops[0].type == o_phrase) { + if (type_name == "EFI_SMM_VARIABLE_PROTOCOL" && + insn.ops[0].type == o_phrase) { if (!addr_in_vec(g_smm_get_variable_calls, ea)) { g_smm_get_variable_calls.push_back(ea); } } - if (type_name == "EFI_SMM_VARIABLE_PROTOCOL" && insn.ops[0].type == o_displ && - insn.ops[0].addr == 0x10) { + if (type_name == "EFI_SMM_VARIABLE_PROTOCOL" && + insn.ops[0].type == o_displ && insn.ops[0].addr == 0x10) { if (!addr_in_vec(g_smm_set_variable_calls, ea)) { g_smm_set_variable_calls.push_back(ea); } @@ -850,9 +867,11 @@ ea_list_t find_data(ea_t start_ea, ea_t end_ea, uchar *data, size_t len) { int counter = 0; while (true) { #if IDA_SDK_VERSION < 900 - auto ea = bin_search2(start, end_ea, data, nullptr, len, BIN_SEARCH_FORWARD); + auto ea = + bin_search2(start, end_ea, data, nullptr, len, BIN_SEARCH_FORWARD); #else - auto ea = bin_search3(start, end_ea, data, nullptr, len, BIN_SEARCH_FORWARD); + auto ea = + bin_search3(start, end_ea, data, nullptr, len, BIN_SEARCH_FORWARD); #endif if (ea == BADADDR) { break; @@ -944,13 +963,15 @@ EfiGuid get_local_guid(func_t *f, uint64_t offset) { std::string get_table_name(std::string service_name) { for (auto i = 0; i < g_boot_services_table_all_count; i++) { - if (static_cast(g_boot_services_table_all[i].name) == service_name) { + if (static_cast(g_boot_services_table_all[i].name) == + service_name) { return "EFI_BOOT_SERVICES"; } } for (auto i = 0; i < g_runtime_services_table_all_count; i++) { - if (static_cast(g_runtime_services_table_all[i].name) == service_name) { + if (static_cast(g_runtime_services_table_all[i].name) == + service_name) { return "EFI_RUNTIME_SERVICES"; } } diff --git a/efiXplorer/efi_utils.h b/efiXplorer/efi_utils.h index 1293b6d8..f90d0faf 100644 --- a/efiXplorer/efi_utils.h +++ b/efiXplorer/efi_utils.h @@ -19,17 +19,19 @@ #pragma once -// 3rd party -#include "json.hpp" +#include "efi_defs.h" + +#include +#include +#include +#include #include #include #include #include #include -#include #include -#include #include #include #include @@ -37,19 +39,19 @@ #include #include #include -#include #if IDA_SDK_VERSION < 900 #include #endif #include - #ifdef HEX_RAYS #include #endif +#include -#include "efi_defs.h" +// 3rd party +#include "json.hpp" -using namespace nlohmann; +using nlohmann::json; using ea_list_t = std::vector; using func_list_t = std::vector; @@ -83,10 +85,10 @@ struct EfiGuid { } std::string to_string() const { - return std::format( - "{:08X}-{:04X}-{:04X}-{:02X}{:02X}-{:02X}{:02X}{:02X}{:02X}{:02X}{:02X}", data1, - data2, data3, data4[0], data4[1], data4[2], data4[3], data4[4], data4[5], - data4[6], data4[7]); + return std::format("{:08X}-{:04X}-{:04X}-{:02X}{:02X}-{:02X}{:02X}{:02X}{:" + "02X}{:02X}{:02X}", + data1, data2, data3, data4[0], data4[1], data4[2], + data4[3], data4[4], data4[5], data4[6], data4[7]); } }; diff --git a/efiXplorer/efixplorer.cc b/efiXplorer/efixplorer.cc index a307947c..0fd53ea7 100644 --- a/efiXplorer/efixplorer.cc +++ b/efiXplorer/efixplorer.cc @@ -30,7 +30,7 @@ static const char welcome_msg[] = " ____ _ __ __\n" "\\__/_//_/_/|_/ .__/_/\\___/_/ \\__/_/\n" " /_/\n"; -// Default arguments +// default arguments struct args g_args = {ModuleType::DxeSmm, 0, 0}; #if IDA_SDK_VERSION < 760 @@ -49,15 +49,16 @@ static plugmod_t *idaapi init(void) { // Register action register_action(action_load_report); - attach_action_to_menu("File/Load file/", action_load_report.name, SETMENU_APP); + attach_action_to_menu("File/Load file/", action_load_report.name, + SETMENU_APP); return PLUGIN_KEEP; } //-------------------------------------------------------------------------- bool idaapi run(size_t arg) { - - if (arg >> 0 & 1) { // parse arg value: + if (arg >> 0 & 1) { + // parse arg value: // - arg = 0 (000): default (DXE) // - arg = 1 (001): default (PEI, 32-bit binaries only) // - arg = 2 (010): disable_ui (DXE) @@ -65,7 +66,8 @@ bool idaapi run(size_t arg) { // - arg = 4 (100): disable_vuln_hunt (DXE) // - arg = 5 (101): disable_vuln_hunt (PEI, 32-bit binaries only) // - arg = 6 (110): disable_ui & disable_vuln_hunt (DXE) - // - arg = 7 (111): disable_ui & disable_vuln_hunt (PEI, 32-bit binaries only) + // - arg = 7 (111): disable_ui & disable_vuln_hunt (PEI, 32-bit binaries + // only) g_args.module_type = ModuleType::Pei; } @@ -76,17 +78,17 @@ bool idaapi run(size_t arg) { g_args.disable_vuln_hunt = 1; } - msg("[%s] plugin run with argument %lu (sdk version: %d)\n", g_plugin_name, arg, - IDA_SDK_VERSION); - msg("[%s] disable_ui = %d, disable_vuln_hunt = %d\n", g_plugin_name, g_args.disable_ui, - g_args.disable_vuln_hunt); + msg("[%s] plugin run with argument %lu (sdk version: %d)\n", g_plugin_name, + arg, IDA_SDK_VERSION); + msg("[%s] disable_ui = %d, disable_vuln_hunt = %d\n", g_plugin_name, + g_args.disable_ui, g_args.disable_vuln_hunt); auto guids_path = get_guids_json_file(); msg("[%s] guids.json exists: %s\n", g_plugin_name, BTOA(!guids_path.empty())); if (guids_path.empty()) { - std::string msg_text = - "guids.json file not found, copy \"guids\" directory to /plugins"; + std::string msg_text = "guids.json file not found, copy \"guids\" " + "directory to /plugins"; msg("[%s] %s\n", g_plugin_name, msg_text.c_str()); warning("%s: %s\n", g_plugin_name, msg_text.c_str()); return false; From efe40ee2a5966f32cffa697cc1e0956ab0984aaa Mon Sep 17 00:00:00 2001 From: yeggor Date: Sun, 15 Sep 2024 20:32:27 +0200 Subject: [PATCH 24/69] fix linter issues for efixloader --- efiXloader/.clang-format | 4 +- efiXloader/efi_loader.cc | 14 ++- efiXloader/efi_loader.h | 13 +-- efiXloader/ida_core.h | 22 +++-- efiXloader/pe.cc | 37 +++++--- efiXloader/pe.h | 44 ++++----- efiXloader/pe_ida.h | 199 ++++++++++++++++++++++----------------- efiXloader/pe_manager.cc | 3 +- efiXloader/pe_manager.h | 6 +- efiXloader/uefitool.cc | 32 ++++--- efiXloader/uefitool.h | 40 ++++---- efiXloader/utils.cc | 11 ++- efiXloader/utils.h | 5 +- 13 files changed, 246 insertions(+), 184 deletions(-) diff --git a/efiXloader/.clang-format b/efiXloader/.clang-format index 92cfffbb..67c0bb48 100644 --- a/efiXloader/.clang-format +++ b/efiXloader/.clang-format @@ -1,5 +1,5 @@ --- -Language: Cpp BasedOnStyle: LLVM -ColumnLimit: 90 +ColumnLimit: 80 IndentWidth: 2 +Language: Cpp diff --git a/efiXloader/efi_loader.cc b/efiXloader/efi_loader.cc index 4015e05f..1725e192 100644 --- a/efiXloader/efi_loader.cc +++ b/efiXloader/efi_loader.cc @@ -18,6 +18,9 @@ */ #include "efi_loader.h" + +#include + #include "uefitool.h" #include "utils.h" @@ -32,7 +35,8 @@ bool first_uefi_image = true; void idaapi load_binary(const char *fname) { load_info_t *ld = NULL; linput_t *li = NULL; - ushort nflags = NEF_SEGS | NEF_RSCS | NEF_NAME | NEF_IMPS | NEF_LALL | NEF_FLAT; + ushort nflags = + NEF_SEGS | NEF_RSCS | NEF_NAME | NEF_IMPS | NEF_LALL | NEF_FLAT; if (first_uefi_image) { nflags |= NEF_FIRST; } @@ -87,8 +91,8 @@ void efi_til_init(const char *til_name) { // IDA loader //------------------------ -static int idaapi accept_file(qstring *fileformatname, qstring *processor, linput_t *li, - const char *filename) { +static int idaapi accept_file(qstring *fileformatname, qstring *processor, + linput_t *li, const char *filename) { efiloader::Utils utils; bytevec_t data; data.resize(qlsize(li)); @@ -141,7 +145,9 @@ void idaapi load_file(linput_t *li, ushort neflag, const char *fileformatname) { } } -static int idaapi move_segm(ea_t from, ea_t to, asize_t, const char *) { return 1; } +static int idaapi move_segm(ea_t from, ea_t to, asize_t, const char *) { + return 1; +} //---------------------------------------------------------------------- // diff --git a/efiXloader/efi_loader.h b/efiXloader/efi_loader.h index e461346a..01caf3f3 100644 --- a/efiXloader/efi_loader.h +++ b/efiXloader/efi_loader.h @@ -19,6 +19,8 @@ #pragma once +#include + #include "ida_core.h" #include "pe.h" #include "pe_manager.h" @@ -39,8 +41,6 @@ void idaapi clean_db(void); void idaapi efi_til_init(); -// UI - class Ui { public: Ui() { ; } @@ -57,7 +57,8 @@ class driver_chooser_t : public chooser_t { qvector drivers_names; /* this object must be allocated using `new` */ - driver_chooser_t(const char *title, bool ok, std::vector drivers); + driver_chooser_t(const char *title, bool ok, + std::vector drivers); /* function that is used to decide whether a new chooser should be opened or * we can use the existing one. The contents of the window are completely @@ -71,8 +72,8 @@ class driver_chooser_t : public chooser_t { virtual size_t idaapi get_count() const { return drivers_names.size(); } /* function that generates the list line */ - virtual void idaapi get_row(qstrvec_t *cols, int *icon_, chooser_item_attrs_t *attrs, - size_t n) const; + virtual void idaapi get_row(qstrvec_t *cols, int *icon_, + chooser_item_attrs_t *attrs, size_t n) const; /* function that is called when the user hits Enter */ virtual cbret_t idaapi enter(size_t n) { @@ -90,5 +91,5 @@ class driver_chooser_t : public chooser_t { n++; } ok = true; - }; + } }; diff --git a/efiXloader/ida_core.h b/efiXloader/ida_core.h index 80f57685..81b5eac8 100644 --- a/efiXloader/ida_core.h +++ b/efiXloader/ida_core.h @@ -21,19 +21,20 @@ #define USE_STANDARD_FILE_FUNCTIONS 1 +#include +#include + #include #include #include #include #include -#include #include #include #include #include #include #include -#include #include #include @@ -91,21 +92,25 @@ bool _validate_array_count(linput_t *li, T *p_cnt, size_t elsize, // Validate a counter taken from the input file. If there are not enough bytes // in the input file, ask the user if we may continue and fix the counter. template -void validate_array_count(linput_t *li, T *p_cnt, size_t elsize, const char *counter_name, - int64 curoff = -1, int64 maxoff = -1) { +void validate_array_count(linput_t *li, T *p_cnt, size_t elsize, + const char *counter_name, int64 curoff = -1, + int64 maxoff = -1) { T old = *p_cnt; if (!_validate_array_count(li, p_cnt, elsize, curoff, maxoff)) { static const char *const format = "AUTOHIDE SESSION\n" "HIDECANCEL\n" - "%s %" FMT_64 "u is incorrect, maximum possible value is %" FMT_64 "u%s"; + "%s %" FMT_64 "u is incorrect, maximum possible value is %" FMT_64 + "u%s"; #ifndef __KERNEL__ - if (ask_yn(ASKBTN_YES, format, counter_name, uint64(old), uint64(*p_cnt), + if (ask_yn(ASKBTN_YES, format, counter_name, static_cast(old), + static_cast(*p_cnt), ". Do you want to continue with the new value?") != ASKBTN_YES) { loader_failure(NULL); } #else - warning(format, counter_name, uint64(old), uint64(*p_cnt), ""); + warning(format, counter_name, static_cast(old), + static_cast(*p_cnt), ""); #endif } } @@ -118,7 +123,8 @@ void validate_array_count_or_die(linput_t *li, T cnt, size_t elsize, const char *counter_name, int64 curoff = -1, int64 maxoff = -1) { if (!_validate_array_count(li, &cnt, elsize, curoff, maxoff)) { - static const char *const format = "%s is incorrect, maximum possible value is %u%s"; + static const char *const format = + "%s is incorrect, maximum possible value is %u%s"; #ifndef __KERNEL__ loader_failure(format, counter_name, uint(cnt), ""); #else diff --git a/efiXloader/pe.cc b/efiXloader/pe.cc index 637c11b8..540ed0a7 100644 --- a/efiXloader/pe.cc +++ b/efiXloader/pe.cc @@ -20,11 +20,13 @@ #include "pe.h" +#include + +#include + #include #include #include -#include -#include #include #define DEBUG @@ -212,8 +214,8 @@ void efiloader::PE::make_entry(ea_t ea) { // PE image pre-processing // -inline size_t efiloader::PE::make_named_word(ea_t ea, const char *name, const char *extra, - size_t count) { +inline size_t efiloader::PE::make_named_word(ea_t ea, const char *name, + const char *extra, size_t count) { if (extra) { add_extra_cmt(ea, true, "%s", extra); } @@ -262,7 +264,8 @@ segment_t *efiloader::PE::make_head_segment(ea_t start, ea_t end, } segment_t *efiloader::PE::make_generic_segment(ea_t seg_ea, ea_t seg_ea_end, - const char *section_name, uint32_t flags) { + const char *section_name, + uint32_t flags) { segment_t *generic_segm = new segment_t; generic_segm->sel = allocate_selector(0x0); generic_segm->start_ea = seg_ea; @@ -336,10 +339,11 @@ ea_t efiloader::PE::process_section_entry(ea_t next_ea) { size_t segm_name_len = get_max_strlit_length(next_ea, STRTYPE_C); if (segm_name_len) { - get_strlit_contents(&segm_names.push_back(), next_ea, segm_name_len, STRTYPE_C); + get_strlit_contents(&segm_names.push_back(), next_ea, segm_name_len, + STRTYPE_C); } else { - // if the segm_name_len is 0, it will trigger a crash on segm_names.pop_back() - // later. + // if the segm_name_len is 0, it will trigger a crash on + // segm_names.pop_back() later. segm_names.push_back("UNKNOWN"); } @@ -392,8 +396,8 @@ ea_t efiloader::PE::process_section_entry(ea_t next_ea) { ea_t seg_ea_end = seg_ea + segm_raw_sizes[0]; msg("[efiXloader]\tprocessing: %s\n", segm_names[0].c_str()); - segments.push_back(make_generic_segment(seg_ea, seg_ea_end, section_name.c_str(), - section_characteristics)); + segments.push_back(make_generic_segment( + seg_ea, seg_ea_end, section_name.c_str(), section_characteristics)); segm_names.pop_back(); segm_sizes.pop_back(); segm_raw_sizes.pop_back(); @@ -406,7 +410,8 @@ void efiloader::PE::setup_ds_selector() { msg("[efiXloader]\tsetting DS ( 0x%016llX ) for %s segment\n", static_cast(data_segment_sel), secs_names[secs_names.size() - 1].c_str()); - segment_t *seg = get_segm_by_name(secs_names[secs_names.size() - 1].c_str()); + segment_t *seg = + get_segm_by_name(secs_names[secs_names.size() - 1].c_str()); set_default_sreg_value(seg, str2reg("DS"), data_segment_sel); } } @@ -427,7 +432,8 @@ void efiloader::PE::preprocess() { ea_t end = ea + qlsize(li); qsnprintf(seg_name, sizeof(seg_name), "%s_%08X", _image_name.c_str(), calc_file_crc32(li)); - qsnprintf(seg_header_name, sizeof(seg_header_name), "%s_HEADER", _image_name.c_str()); + qsnprintf(seg_header_name, sizeof(seg_header_name), "%s_HEADER", + _image_name.c_str()); qsnprintf(image_base_name, sizeof(image_base_name), "%s_IMAGE_BASE", _image_name.c_str()); @@ -438,8 +444,8 @@ void efiloader::PE::preprocess() { return; } push_to_idb(start, end); - segments.push_back( - make_head_segment(image_base, image_base + headers_size, seg_header_name)); + segments.push_back(make_head_segment(image_base, image_base + headers_size, + seg_header_name)); secs_names.push_back(qstring(seg_header_name)); create_word(ea, 2); set_cmt(ea, "PE magic number", 0); @@ -500,7 +506,8 @@ void efiloader::PE::preprocess() { ea = ea + 0x3c; create_dword(ea, 4); if (is_loaded(ea) && get_dword(ea)) { - msg("[efiXloader] making relative offset: 0x%016llX\n", static_cast(ea)); + msg("[efiXloader] making relative offset: 0x%016llX\n", + static_cast(ea)); op_plain_offset(ea, 0, *pe_base); } set_cmt(ea, "File address of new exe header", 0); diff --git a/efiXloader/pe.h b/efiXloader/pe.h index 9b2a4d15..eb9e9c64 100644 --- a/efiXloader/pe.h +++ b/efiXloader/pe.h @@ -19,14 +19,10 @@ #pragma once -// -// IDA header -// +#include + #include "ida_core.h" #include "pe_ida.h" -// -// Utilities -// #include "utils.h" #include @@ -42,8 +38,8 @@ namespace efiloader { class PE { public: - PE(linput_t *i_li, std::basic_string fname, ea_t *base, ushort *sel_base, int ord, - uint16_t mt) { + PE(linput_t *i_li, std::basic_string fname, ea_t *base, + ushort *sel_base, int ord, uint16_t mt) { _image_name = fname.substr(fname.find_last_of("/\\") + 1); msg("[efiXloader] image name is %s\n", _image_name.c_str()); pe_base = base; @@ -74,8 +70,8 @@ class PE { uint32_t number_of_sections; uint32_t number_of_dirs; char *name; - bool is_reloc_dir(uint32_t i) { return i == 5; }; - bool is_debug_dir(uint32_t i) { return i == 6; }; + bool is_reloc_dir(uint32_t i) { return i == 5; } + bool is_debug_dir(uint32_t i) { return i == 6; } void set_64_bit_segm_and_rabase(ea_t ea) { segment_t *tmp_seg = getseg(ea); set_segm_addressing(tmp_seg, 2); @@ -84,7 +80,7 @@ class PE { void set_64_bit(ea_t ea) { segment_t *tmp_seg = getseg(ea); set_segm_addressing(tmp_seg, 2); - }; + } bool is_p32(); bool is_p32_plus(); bool is_pe(); @@ -92,15 +88,15 @@ class PE { bool process(); uint16_t arch(); // data processing - inline size_t make_named_byte(ea_t ea, const char *name, const char *extra = NULL, - size_t count = 1); - inline size_t make_named_word(ea_t ea, const char *name, const char *extra = NULL, - size_t count = 1); - inline size_t make_named_dword(ea_t ea, const char *name, const char *extra = NULL, - size_t count = 1); - inline size_t make_named_qword(ea_t ea, const char *name, const char *extra = NULL, - size_t count = 1); - inline ea_t skip(ea_t ea, qoff64_t off) { return ea + off; }; + inline size_t make_named_byte(ea_t ea, const char *name, + const char *extra = NULL, size_t count = 1); + inline size_t make_named_word(ea_t ea, const char *name, + const char *extra = NULL, size_t count = 1); + inline size_t make_named_dword(ea_t ea, const char *name, + const char *extra = NULL, size_t count = 1); + inline size_t make_named_qword(ea_t ea, const char *name, + const char *extra = NULL, size_t count = 1); + inline ea_t skip(ea_t ea, qoff64_t off) { return ea + off; } // ida db processing void push_to_idb(ea_t start, ea_t end) { // Map header @@ -111,7 +107,7 @@ class PE { start + _sec_headers[i].s_vaddr + _sec_headers[i].s_psize, FILEREG_PATCHABLE); } - }; + } private: qvector segments_ea; @@ -131,7 +127,7 @@ class PE { qvector data_selectors; qvector ds_seg_names; qvector cs_seg_names; - void reset() { qlseek(li, 0); }; + void reset() { qlseek(li, 0); } const char *_machine_name(); // // PE image preprocessing @@ -170,8 +166,8 @@ class PE { qvector segm_names; qvector secs_names; ea_t process_section_entry(ea_t ea); - segment_t *make_generic_segment(ea_t seg_ea, ea_t seg_ea_end, const char *section_name, - uint32_t flags); + segment_t *make_generic_segment(ea_t seg_ea, ea_t seg_ea_end, + const char *section_name, uint32_t flags); segment_t *make_head_segment(ea_t start, ea_t end, const char *name); void setup_ds_selector(); }; diff --git a/efiXloader/pe_ida.h b/efiXloader/pe_ida.h index ca0db774..6faa14ae 100644 --- a/efiXloader/pe_ida.h +++ b/efiXloader/pe_ida.h @@ -19,10 +19,11 @@ #pragma once -#include "ida_core.h" #include #include +#include "ida_core.h" + #pragma pack(push, 1) //----------------------------------------------------------------------- // @@ -39,7 +40,7 @@ template struct peheader_tpl { #define PEEXE_ID 0x4550 // 'PE' followed by two zeroes #define BPEEXE_ID 0x455042 // Borland's extenson for DPMI'host -#define PLEXE_ID \ +#define PLEXE_ID \ 0x4C50 // 'PL', PharLap TNT DOS-Extender Lite file that uses real mode APIs #define TEEXE_ID 0x5A56 // 'VZ', EFI Terse Executable uint16 machine; // 04 This field specifies the type of CPU @@ -92,21 +93,23 @@ template struct peheader_tpl { #define PECPU_TRICORE 0x0520 // TRICORE (Infineon) bool is_64bit_cpu(void) const { - return machine == PECPU_AMD64 || machine == PECPU_IA64 || machine == PECPU_ARM64; + return machine == PECPU_AMD64 || machine == PECPU_IA64 || + machine == PECPU_ARM64; } bool is_pc(void) const { - return machine == PECPU_80386 || machine == PECPU_80486 || machine == PECPU_80586 || - machine == PECPU_AMD64; + return machine == PECPU_80386 || machine == PECPU_80486 || + machine == PECPU_80586 || machine == PECPU_AMD64; } bool is_mips(void) const { - return machine == PECPU_R3000 || machine == PECPU_R6000 || machine == PECPU_R4000 || - machine == PECPU_R10000 || machine == PECPU_WCEMIPSV2 || - machine == PECPU_MIPS16 || machine == PECPU_MIPSFPU || - machine == PECPU_MIPSFPU16; + return machine == PECPU_R3000 || machine == PECPU_R6000 || + machine == PECPU_R4000 || machine == PECPU_R10000 || + machine == PECPU_WCEMIPSV2 || machine == PECPU_MIPS16 || + machine == PECPU_MIPSFPU || machine == PECPU_MIPSFPU16; } bool is_arm(void) const { - return machine == PECPU_ARM || machine == PECPU_ARMI || machine == PECPU_ARMV7; + return machine == PECPU_ARM || machine == PECPU_ARMI || + machine == PECPU_ARMV7; } bool has_code16_bit(void) const { return is_arm() || is_mips(); } @@ -124,10 +127,10 @@ template struct peheader_tpl { #define PEF_UP 0x4000 // File should be run only on a UP machine #define PEF_DLL 0x2000 // Dynamic Link Library (DLL) #define PEF_SYS 0x1000 // System file -#define PEF_NSWAP \ +#define PEF_NSWAP \ 0x0800 // If the image is on network media, fully load it and copy it to the // swap file. -#define PEF_SWAP \ +#define PEF_SWAP \ 0x0400 // If image is on removable media, // copy and run from swap file #define PEF_NODEB 0x0200 // Debugging info stripped @@ -181,17 +184,18 @@ template struct peheader_tpl { uint32 objalign; // 38 The alignment of the objects. This must be a power // of 2 between 512 and 256M inclusive. The default // is 64K. - uint32 filealign; // 3C Alignment factor used to align image pages. - // The alignment factor (in bytes) used to align the - // base of the image pages and to determine the - // granularity of per-object trailing zero pad. - // Larger alignment factors will cost more file space; - // smaller alignment factors will impact demand load - // performance, perhaps significantly. Of the two, - // wasting file space is preferable. This value - // should be a power of 2 between 512 and 64K inclusive. - // Get the file position aligned: -#define FILEALIGN 512 // IDA5.1: it seems that for standard object alignment (if 4096) + uint32 filealign; // 3C Alignment factor used to align image pages. + // The alignment factor (in bytes) used to align the + // base of the image pages and to determine the + // granularity of per-object trailing zero pad. + // Larger alignment factors will cost more file space; + // smaller alignment factors will impact demand load + // performance, perhaps significantly. Of the two, + // wasting file space is preferable. This value + // should be a power of 2 between 512 and 64K inclusive. + // Get the file position aligned: +#define FILEALIGN \ + 512 // IDA5.1: it seems that for standard object alignment (if 4096) // the Windows kernel does not use filealign // (just checks that it is in the valid range) but uses 512 uint32 get_align_mask(void) const { @@ -213,7 +217,9 @@ template struct peheader_tpl { uint16 subsysmajor; // 48 Subsystem major version number. uint16 subsysminor; // 4A Subsystem minor version number. - uint32 subsystem_version(void) const { return (subsysmajor << 16) | subsysminor; } + uint32 subsystem_version(void) const { + return (subsysmajor << 16) | subsysminor; + } uint32 reserved; // 4C uint32 imagesize; // 50 The virtual size (in bytes) of the image. @@ -221,8 +227,8 @@ template struct peheader_tpl { // must be a multiple of Object Align. uint32 allhdrsize; // 54 Total header size. The combined size of the Dos // Header, PE Header and Object Table. - uint32 checksum; // 58 Checksum for entire file. Set to 0 by the linker. - uint16 subsys; // 5C NT Subsystem required to run this image. + uint32 checksum; // 58 Checksum for entire file. Set to 0 by the linker. + uint16 subsys; // 5C NT Subsystem required to run this image. #define PES_UNKNOWN 0x0000 // Unknown #define PES_NATIVE 0x0001 // Native #define PES_WINGUI 0x0002 // Windows GUI @@ -239,29 +245,31 @@ template struct peheader_tpl { #define PES_BOOTAPP 0x0010 // Windows Boot Application bool is_efi(void) const { - return subsys == PES_EFI_APP || subsys == PES_EFI_BDV || subsys == PES_EFI_RDV || - subsys == PES_EFI_ROM; + return subsys == PES_EFI_APP || subsys == PES_EFI_BDV || + subsys == PES_EFI_RDV || subsys == PES_EFI_ROM; } bool is_console_app(void) const { - return subsys == PES_WINCHAR || subsys == PES_OS2CHAR || subsys == PES_POSIX; + return subsys == PES_WINCHAR || subsys == PES_OS2CHAR || + subsys == PES_POSIX; } bool is_userland(void) const { - return subsys == PES_WINGUI || subsys == PES_WINCHAR || subsys == PES_OS2CHAR || - subsys == PES_POSIX || subsys == PES_WINCE; + return subsys == PES_WINGUI || subsys == PES_WINCHAR || + subsys == PES_OS2CHAR || subsys == PES_POSIX || subsys == PES_WINCE; } uint16 dllflags; // 5E Indicates special loader requirements. #define PEL_PINIT 0x0001 // Per-Process Library Initialization. #define PEL_PTERM 0x0002 // Per-Process Library Termination. #define PEL_TINIT 0x0004 // Per-Thread Library Initialization. #define PEL_TTERM 0x0008 // Per-Thread Library Termination. -#define PEL_HIGH_ENT \ +#define PEL_HIGH_ENT \ 0x0020 // Image can handle a high entropy 64-bit virtual address space. #define PEL_DYNAMIC_BASE 0x0040 // The DLL can be relocated at load time. #define PEL_FORCE_INTEGRITY 0x0080 // Code integrity checks are forced. -#define PEF_NX 0x0100 // The image is compatible with data execution prevention (DEP). -#define PEF_NO_ISOLATION \ +#define PEF_NX \ + 0x0100 // The image is compatible with data execution prevention (DEP). +#define PEF_NO_ISOLATION \ 0x0200 // The image is isolation aware, but should not be isolated. -#define PEF_NO_SEH \ +#define PEF_NO_SEH \ 0x0400 // The image does not use structured exception handling (SEH). No // handlers can be called in this image. #define PEL_NO_BIND 0x0800 // Do not bind image @@ -312,7 +320,8 @@ template struct peheader_tpl { typedef peheader_tpl peheader_t; typedef peheader_tpl peheader64_t; -const size_t total_rvatab_size = sizeof(peheader_t) - offsetof(peheader_t, expdir); +const size_t total_rvatab_size = + sizeof(peheader_t) - offsetof(peheader_t, expdir); const size_t total_rvatab_count = total_rvatab_size / sizeof(petab_t); //----------------------------------------------------------------------- @@ -345,22 +354,25 @@ struct diheader_t { // S E C T I O N S // struct pesection_t { - char s_name[8]; /* section name */ - uint32 s_vsize; /* virtual size */ - uint32 s_vaddr; /* virtual address */ - uint32 s_psize; /* physical size */ - int32 s_scnptr; /* file ptr to raw data for section */ - int32 s_relptr; /* file ptr to relocation */ - int32 s_lnnoptr; /* file ptr to line numbers */ - uint16 s_nreloc; /* number of relocation entries */ - uint16 s_nlnno; /* number of line number entries */ - int32 s_flags; /* flags */ -#define PEST_REG 0x00000000 // obsolete: regular: allocated, relocated, loaded -#define PEST_DUMMY 0x00000001 // obsolete: dummy: not allocated, relocated, not loaded -#define PEST_NOLOAD 0x00000002 // obsolete: noload: allocated, relocated, not loaded -#define PEST_GROUP 0x00000004 // obsolete: grouped: formed of input sections -#define PEST_PAD 0x00000008 // obsolete: padding: not allocated, not relocated, loaded -#define PEST_COPY \ + char s_name[8]; /* section name */ + uint32 s_vsize; /* virtual size */ + uint32 s_vaddr; /* virtual address */ + uint32 s_psize; /* physical size */ + int32 s_scnptr; /* file ptr to raw data for section */ + int32 s_relptr; /* file ptr to relocation */ + int32 s_lnnoptr; /* file ptr to line numbers */ + uint16 s_nreloc; /* number of relocation entries */ + uint16 s_nlnno; /* number of line number entries */ + int32 s_flags; /* flags */ +#define PEST_REG 0x00000000 // obsolete: regular: allocated, relocated, loaded +#define PEST_DUMMY \ + 0x00000001 // obsolete: dummy: not allocated, relocated, not loaded +#define PEST_NOLOAD \ + 0x00000002 // obsolete: noload: allocated, relocated, not loaded +#define PEST_GROUP 0x00000004 // obsolete: grouped: formed of input sections +#define PEST_PAD \ + 0x00000008 // obsolete: padding: not allocated, not relocated, loaded +#define PEST_COPY \ 0x00000010 // obsolete: copy: for decision function used // by field update; not // allocated, not relocated, @@ -370,16 +382,19 @@ struct pesection_t { #define PEST_DATA 0x00000040L // section contains data only #define PEST_BSS 0x00000080L // section contains bss only #define PEST_EXCEPT 0x00000100L // obsolete: Exception section -#define PEST_INFO 0x00000200L // Comment: not allocated, not relocated, not loaded -#define PEST_OVER 0x00000400L // obsolete: Overlay: not allocated, relocated, not loaded -#define PEST_LIB 0x00000800L // ".lib" section: treated like PEST_INFO +#define PEST_INFO \ + 0x00000200L // Comment: not allocated, not relocated, not loaded +#define PEST_OVER \ + 0x00000400L // obsolete: Overlay: not allocated, relocated, not loaded +#define PEST_LIB 0x00000800L // ".lib" section: treated like PEST_INFO #define PEST_LOADER 0x00001000L // Loader section: COMDAT #define PEST_DEBUG 0x00002000L // Debug section: #define PEST_TYPCHK 0x00004000L // Type check section: -#define PEST_OVRFLO 0x00008000L // obsolete: RLD and line number overflow sec hdr -#define PEST_F0000 0x000F0000L // Unknown -#define PEST_ALIGN 0x00F00000L // Alignment 2^(x-1): +#define PEST_OVRFLO \ + 0x00008000L // obsolete: RLD and line number overflow sec hdr +#define PEST_F0000 0x000F0000L // Unknown +#define PEST_ALIGN 0x00F00000L // Alignment 2^(x-1): uint32 get_sect_alignment(void) const { int align = ((s_flags >> 20) & 15); return align == 0 ? 0 : (1 << (align - 1)); @@ -389,7 +404,9 @@ struct pesection_t { return align_up(s_vsize ? s_vsize : s_psize, pe.objalign ? pe.objalign : 1); } - asize_t get_psize(const peheader_t &pe) const { return qmin(s_psize, get_vsize(pe)); } + asize_t get_psize(const peheader_t &pe) const { + return qmin(s_psize, get_vsize(pe)); + } #define PEST_1000000 0x01000000L // Unknown #define PEST_DISCARD 0x02000000L // Discardable @@ -452,8 +469,8 @@ struct peimpdir_t { peimpdir_t(void) { memset(this, 0, sizeof(peimpdir_t)); } }; -struct dimpdir_t // delayed load import table -{ +// delayed load import table +struct dimpdir_t { uint32 attrs; // Attributes. #define DIMP_NOBASE 0x0001 // pe.imagebase was not added to addresses uint32 dllname; // Relative virtual address of the name of the DLL @@ -540,9 +557,9 @@ struct function_entry_armv7 { uint32 BeginAddress; // The RVA of the corresponding function uint32 UnwindInfo; // The RVA of the unwind information, including function // length. - // If the low 2 bits are non-zero, then this word represents a - // compacted inline form of the unwind information, - // including function length. + // If the low 2 bits are non-zero, then this word + // represents a compacted inline form of the unwind + // information, including function length. }; // for MIPS and 32-bit Alpha @@ -550,8 +567,8 @@ struct function_entry_alpha { uint32 BeginAddress; // Virtual address of the corresponding function. uint32 EndAddress; // Virtual address of the end of the function. uint32 ExceptionHandler; // Pointer to the exception handler to be executed. - uint32 HandlerData; // Pointer to additional information to be passed to the - // handler. + uint32 HandlerData; // Pointer to additional information to be passed to the + // handler. uint32 PrologEndAddress; // Virtual address of the end of the function's // prolog. }; @@ -564,11 +581,13 @@ typedef enum _UNWIND_OP_CODES { UWOP_SET_FPREG = 3, // FP = RSP + UNWIND_INFO.FPRegOffset*16 UWOP_SAVE_NONVOL = 4, // info == register number, offset/8 in next slot UWOP_SAVE_NONVOL_FAR = 5, // info == register number, offset/8 in next 2 slots - UWOP_SAVE_XMM = 6, // Version 1: info == XMM reg number, offset/8 in next slot - UWOP_EPILOG = 6, // Version 2; code offset is epilog size; - UWOP_SAVE_XMM_FAR = 7, // version 1:info == XMM reg number, offset/8 in next 2 slots - UWOP_SPARE_CODE = 7, // unused ("previously 64-bit UWOP_SAVE_XMM_FAR"); skip 2 slots - UWOP_SAVE_XMM128 = 8, // info == XMM reg number, offset/16 in next slot + UWOP_SAVE_XMM = 6, // Version 1: info == XMM reg number, offset/8 in next slot + UWOP_EPILOG = 6, // Version 2; code offset is epilog size; + UWOP_SAVE_XMM_FAR = + 7, // version 1:info == XMM reg number, offset/8 in next 2 slots + UWOP_SPARE_CODE = + 7, // unused ("previously 64-bit UWOP_SAVE_XMM_FAR"); skip 2 slots + UWOP_SAVE_XMM128 = 8, // info == XMM reg number, offset/16 in next slot UWOP_SAVE_XMM128_FAR = 9, // info == XMM reg number, offset/16 in next 2 slots UWOP_PUSH_MACHFRAME = 10, // info == 0: no error-code, 1: with error code } UNWIND_CODE_OPS; @@ -636,8 +655,10 @@ struct pefixup_t { #define PER_IA64_IMM64 0x9000 -#define PER_MIPS_JMPADDR 0x5000 // base relocation applies to a MIPS jump instruction. -#define PER_MIPS_JMPADDR16 0x9000 // base relocation applies to a MIPS16 jump instruction. +#define PER_MIPS_JMPADDR \ + 0x5000 // base relocation applies to a MIPS jump instruction. +#define PER_MIPS_JMPADDR16 \ + 0x9000 // base relocation applies to a MIPS16 jump instruction. #define PER_ARM_MOV32A 0x5000 // base relocation applies the difference to the // 32-bit value encoded in the immediate fields of @@ -878,14 +899,15 @@ struct rsc_data_entry_t { #define PE_NODE "$ PE header" // netnode name for PE header // value() -> peheader_t // altval(segnum) -> s->start_ea -#define PE_ALT_DBG_FPOS nodeidx_t(-1) // altval() -> translated fpos of debuginfo -#define PE_ALT_IMAGEBASE \ +#define PE_ALT_DBG_FPOS \ + nodeidx_t(-1) // altval() -> translated fpos of debuginfo +#define PE_ALT_IMAGEBASE \ nodeidx_t(-2) // altval() -> loading address (usually pe.imagebase) #define PE_ALT_PEHDR_OFF nodeidx_t(-3) // altval() -> offset of PE header #define PE_ALT_NEFLAGS nodeidx_t(-4) // altval() -> neflags -#define PE_ALT_TDS_LOADED \ +#define PE_ALT_TDS_LOADED \ nodeidx_t(-5) // altval() -> tds already loaded(1) or invalid(-1) -#define PE_ALT_PSXDLL \ +#define PE_ALT_PSXDLL \ nodeidx_t(-6) // altval() -> if POSIX(x86) imports from PSXDLL netnode #define PE_ALT_OVRVA nodeidx_t(-7) // altval() -> overlay rva (if present) #define PE_ALT_OVRSZ nodeidx_t(-8) // altval() -> overlay size (if present) @@ -961,24 +983,24 @@ struct load_config64_t { }; #ifndef IMAGE_GUARD_CF_INSTRUMENTED -#define IMAGE_GUARD_CF_INSTRUMENTED \ +#define IMAGE_GUARD_CF_INSTRUMENTED \ 0x000000100 // Module performs control flow integrity checks using // system-supplied support -#define IMAGE_GUARD_CFW_INSTRUMENTED \ +#define IMAGE_GUARD_CFW_INSTRUMENTED \ 0x000000200 // Module performs control flow and write integrity checks -#define IMAGE_GUARD_CF_FUNCTION_TABLE_PRESENT \ +#define IMAGE_GUARD_CF_FUNCTION_TABLE_PRESENT \ 0x000000400 // Module contains valid control flow target metadata -#define IMAGE_GUARD_SECURITY_COOKIE_UNUSED \ +#define IMAGE_GUARD_SECURITY_COOKIE_UNUSED \ 0x000000800 // Module does not make use of the /GS security cookie -#define IMAGE_GUARD_PROTECT_DELAYLOAD_IAT \ +#define IMAGE_GUARD_PROTECT_DELAYLOAD_IAT \ 0x00001000 // Module supports read only delay load IAT -#define IMAGE_GUARD_DELAYLOAD_IAT_IN_ITS_OWN_SECTION \ +#define IMAGE_GUARD_DELAYLOAD_IAT_IN_ITS_OWN_SECTION \ 0x00002000 // Delayload import table in its own .didat section (with nothing // else in it) that can be freely reprotected -#define IMAGE_GUARD_CF_FUNCTION_TABLE_SIZE_MASK \ +#define IMAGE_GUARD_CF_FUNCTION_TABLE_SIZE_MASK \ 0xF0000000 // Stride of Guard CF function table encoded in these bits // (additional count of bytes per element) -#define IMAGE_GUARD_CF_FUNCTION_TABLE_SIZE_SHIFT \ +#define IMAGE_GUARD_CF_FUNCTION_TABLE_SIZE_SHIFT \ 28 // Shift to right-justify Guard CF function table stride #endif @@ -1034,7 +1056,8 @@ struct teheader_t { uint16 machine; // 02 same as in PE bool is_64bit_cpu(void) const { - return machine == PECPU_AMD64 || machine == PECPU_IA64 || machine == PECPU_ARM64; + return machine == PECPU_AMD64 || machine == PECPU_IA64 || + machine == PECPU_ARM64; } uint8 nobjs; // 04 number of sections @@ -1042,7 +1065,9 @@ struct teheader_t { uint16 strippedsize; // 06 number of bytes removed from the base of the // original image - int32 first_section_pos(int32 peoff) const { return peoff + sizeof(teheader_t); } + int32 first_section_pos(int32 peoff) const { + return peoff + sizeof(teheader_t); + } // value which should be added to the sections' file offsets and RVAs int32 te_adjust() const { return sizeof(teheader_t) - strippedsize; } diff --git a/efiXloader/pe_manager.cc b/efiXloader/pe_manager.cc index e1e2cc58..120b45f7 100644 --- a/efiXloader/pe_manager.cc +++ b/efiXloader/pe_manager.cc @@ -19,7 +19,8 @@ #include "pe_manager.h" -void efiloader::PeManager::process(linput_t *li, std::basic_string fname, int ord) { +void efiloader::PeManager::process(linput_t *li, std::basic_string fname, + int ord) { efiloader::PE pe(li, fname, &pe_base, &pe_sel_base, ord, machine_type); if (pe.good() && pe.is_p32_plus()) { msg("[efiXloader] PE detected\n"); diff --git a/efiXloader/pe_manager.h b/efiXloader/pe_manager.h index 58cd11d6..b03ec579 100644 --- a/efiXloader/pe_manager.h +++ b/efiXloader/pe_manager.h @@ -19,13 +19,15 @@ #pragma once +#include + #include "ida_core.h" #include "pe.h" namespace efiloader { class PeManager { public: - PeManager(uint16_t mt) { + explicit PeManager(uint16_t mt) { inf_set_64bit(); set_imagebase(0x0); if (mt == PECPU_ARM64) { @@ -36,7 +38,7 @@ class PeManager { pe_base = 0; pe_sel_base = 0; machine_type = mt; - }; + } void process(linput_t *li, std::basic_string fname, int ord); uint16_t machine_type; diff --git a/efiXloader/uefitool.cc b/efiXloader/uefitool.cc index e3b8426f..9da705ac 100644 --- a/efiXloader/uefitool.cc +++ b/efiXloader/uefitool.cc @@ -18,15 +18,12 @@ */ #include "uefitool.h" -#include -#include -#include void efiloader::File::print() { msg("[UEFITOOL PARSER] file ( %s ) \n", qname.c_str()); for (int i = 0; i < 0x10; i++) { msg("%02X ", ubytes[i]); - }; + } msg("\n"); } @@ -48,7 +45,8 @@ void efiloader::Uefitool::get_unique_name(qstring &name) { name = new_name; } -void efiloader::Uefitool::get_image_guid(qstring &image_guid, UModelIndex index) { +void efiloader::Uefitool::get_image_guid(qstring &image_guid, + UModelIndex index) { UString guid; UModelIndex guid_index; switch (model.subtype(model.parent(index))) { @@ -66,7 +64,8 @@ void efiloader::Uefitool::get_image_guid(qstring &image_guid, UModelIndex index) } std::vector -efiloader::Uefitool::parseDepexSectionBody(const UModelIndex &index, UString &parsed) { +efiloader::Uefitool::parseDepexSectionBody(const UModelIndex &index, + UString &parsed) { // Adopted from FfsParser::parseDepexSectionBody std::vector res; @@ -130,7 +129,8 @@ efiloader::Uefitool::parseDepexSectionBody(const UModelIndex &index, UString &pa } case EFI_DEP_PUSH: // Check that the rest of depex has correct size - if ((UINT32)body.size() - (UINT32)(current - (const UINT8 *)body.constData()) <= + if ((UINT32)body.size() - + (UINT32)(current - (const UINT8 *)body.constData()) <= EFI_DEP_OPCODE_SIZE + sizeof(EFI_GUID)) { parsed.clear(); return res; @@ -138,7 +138,8 @@ efiloader::Uefitool::parseDepexSectionBody(const UModelIndex &index, UString &pa guid = (const EFI_GUID *)(current + EFI_DEP_OPCODE_SIZE); parsed += UString("\nPUSH ") + guidToUString(readUnaligned(guid)); // Add protocol GUID to result vector - res.push_back(reinterpret_cast(guidToUString(readUnaligned(guid)).data)); + res.push_back( + reinterpret_cast(guidToUString(readUnaligned(guid)).data)); current += EFI_DEP_OPCODE_SIZE + sizeof(EFI_GUID); break; case EFI_DEP_AND: @@ -197,7 +198,8 @@ efiloader::Uefitool::parseAprioriRawSection(const UModelIndex &index) { if (count > 0) { for (UINT32 i = 0; i < count; i++) { const EFI_GUID *guid = (const EFI_GUID *)body.constData() + i; - res.push_back(reinterpret_cast(guidToUString(readUnaligned(guid)).data)); + res.push_back( + reinterpret_cast(guidToUString(readUnaligned(guid)).data)); } } @@ -224,7 +226,8 @@ void efiloader::Uefitool::handle_raw_section(const UModelIndex &index) { if (!parent_file.isValid()) { return; } - UByteArray parent_file_guid(model.header(parent_file).constData(), sizeof(EFI_GUID)); + UByteArray parent_file_guid(model.header(parent_file).constData(), + sizeof(EFI_GUID)); if (parent_file_guid == EFI_PEI_APRIORI_FILE_GUID) { msg("[efiXloader] PEI Apriori file found\n"); get_apriori(index, "PEI_APRIORI_FILE"); @@ -259,11 +262,13 @@ void efiloader::Uefitool::dump(const UModelIndex &index, uint8_t el_type, 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())); + 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 + if (images_guids[guid.c_str()] + .is_null()) { // check if GUID already exists get_unique_name(module_name); images_guids[guid.c_str()] = module_name.c_str(); file->qname.swap(module_name); @@ -311,7 +316,8 @@ void efiloader::Uefitool::dump(const UModelIndex &index, uint8_t el_type, void efiloader::Uefitool::dump(const UModelIndex &index) { USTATUS err; - msg("[UEFITOOL PARSER] file (%s, %s)\n", itemTypeToUString(model.type(index)).data, + 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)) { diff --git a/efiXloader/uefitool.h b/efiXloader/uefitool.h index 4f0799f6..ab04a208 100644 --- a/efiXloader/uefitool.h +++ b/efiXloader/uefitool.h @@ -19,6 +19,18 @@ #pragma once +#include +#ifdef _WIN32 +#include +#else +#include +#endif +#include +#include +#include +#include +#include + #include "3rd/uefitool/common/LZMA/LzmaCompress.h" #include "3rd/uefitool/common/LZMA/LzmaDecompress.h" #include "3rd/uefitool/common/Tiano/EfiTianoCompress.h" @@ -41,14 +53,7 @@ #include "ida_core.h" -#include -#ifdef _WIN32 -#include -#else -#include -#endif - -using namespace nlohmann; +using nlohmann::json; enum FILE_SECTION_TYPE { PE_DEPENDENCY_SECTION = 0, @@ -65,7 +70,7 @@ class File { qname.qclear(); bytes.resize(size_in); memcpy(&bytes[0], data_in, size_in); - }; + } void write() { qstring idb_path(get_path(PATH_TYPE_IDB)); qstring images_path = idb_path + qstring(".efiloader"); @@ -100,7 +105,7 @@ class File { class Uefitool { public: - Uefitool(bytevec_t &data) { + explicit Uefitool(bytevec_t &data) { buffer = (const char *)&data[0]; buffer_size = data.size(); UByteArray ubuffer(buffer, buffer_size); @@ -110,17 +115,19 @@ class Uefitool { } messages = ffs.getMessages(); } - ~Uefitool() {}; + ~Uefitool() {} void show_messages(); - bool messages_occurs() { return !messages.empty(); }; + 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 handle_raw_section(const UModelIndex &index); - bool is_pe_index(const UModelIndex &index) { return model.rowCount(index) == 4; }; + bool is_pe_index(const UModelIndex &index) { + return model.rowCount(index) == 4; + } bool is_file_index(const UModelIndex &index) { return model.type(index) == Types::File; - }; + } void get_unique_name(qstring &image_name); void get_image_guid(qstring &image_guid, UModelIndex index); std::vector parseDepexSectionBody(const UModelIndex &index, @@ -128,8 +135,9 @@ class Uefitool { std::vector parseAprioriRawSection(const UModelIndex &index); void get_deps(UModelIndex index, std::string key); void get_apriori(UModelIndex index, std::string key); - void dump_jsons(); // dump JSON with DEPEX and GUIDs information for each image - json all_deps; // DEPEX information for each image + void + dump_jsons(); // dump JSON with DEPEX and GUIDs information for each image + json all_deps; // DEPEX information for each image json images_guids; // matching the modules to the parent's GUIDs TreeModel model; const char *buffer; diff --git a/efiXloader/utils.cc b/efiXloader/utils.cc index dd6c3688..7417d5b6 100644 --- a/efiXloader/utils.cc +++ b/efiXloader/utils.cc @@ -19,8 +19,9 @@ #include "utils.h" -void efiloader::Utils::show_hex(void *buffer, size_t length, const char *prefix) { - uint8_t *buf = (uint8_t *)buffer; +void efiloader::Utils::show_hex(void *buffer, size_t length, + const char *prefix) { + uint8_t *buf = reinterpret_cast(buffer; msg("[efiXloader] %s = ", prefix); for (int i = 0; i < length; i++) { msg("%02x", buf[i]); @@ -28,7 +29,8 @@ void efiloader::Utils::show_hex(void *buffer, size_t length, const char *prefix) msg("\n"); } -bool efiloader::Utils::find_vol(bytevec_t &frm, std::string &sig, qoff64_t &vol_off) { +bool efiloader::Utils::find_vol(bytevec_t &frm, std::string &sig, + qoff64_t &vol_off) { auto found = std::search(frm.begin(), frm.end(), sig.begin(), sig.end()); if (found != frm.end()) { vol_off = std::distance(frm.begin(), found); @@ -62,7 +64,8 @@ qoff64_t efiloader::Utils::find_vol_test(bytevec_t &data) { return res; } -void efiloader::Utils::skip(memory_deserializer_t *ser, size_t size, size_t count) { +void efiloader::Utils::skip(memory_deserializer_t *ser, size_t size, + size_t count) { switch (size) { case 1: for (int i = 0; i < count; i++) { diff --git a/efiXloader/utils.h b/efiXloader/utils.h index 03ea53e0..b9164ca7 100644 --- a/efiXloader/utils.h +++ b/efiXloader/utils.h @@ -19,17 +19,18 @@ #pragma once -#include "ida_core.h" #include #include #include #include +#include "ida_core.h" + namespace efiloader { class Utils { public: - Utils() { ; }; + Utils() {} void show_hex(void *buffer, size_t length, const char *prefix); bool find_vol(bytevec_t &frm, std::string &sig, qoff64_t &vol_off); qoff64_t find_vol_new(linput_t *li, char *sig); From 1713931b6934ce88168e530b3b3f585a686811ca Mon Sep 17 00:00:00 2001 From: yeggor Date: Mon, 16 Sep 2024 02:20:37 +0200 Subject: [PATCH 25/69] fix efixloader build --- efiXloader/CMakeLists.txt | 2 +- efiXloader/utils.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/efiXloader/CMakeLists.txt b/efiXloader/CMakeLists.txt index c8026415..686cf0c7 100644 --- a/efiXloader/CMakeLists.txt +++ b/efiXloader/CMakeLists.txt @@ -57,7 +57,7 @@ file( "3rd/uefitool/uefidump.h") # efiLoader sources -file(GLOB ${efiloader_src} "*.h" "*.c" "*.cpp" "*.cc") +file(GLOB efiloader_src "*.h" "*.c" "*.cpp" "*.cc") add_ida_loader(efiXloader NOEA32 ${PROJECT_SOURCE_DIR}/efi_loader.cc) diff --git a/efiXloader/utils.cc b/efiXloader/utils.cc index 7417d5b6..85475cb4 100644 --- a/efiXloader/utils.cc +++ b/efiXloader/utils.cc @@ -21,7 +21,7 @@ void efiloader::Utils::show_hex(void *buffer, size_t length, const char *prefix) { - uint8_t *buf = reinterpret_cast(buffer; + uint8_t *buf = reinterpret_cast(buffer); msg("[efiXloader] %s = ", prefix); for (int i = 0; i < length; i++) { msg("%02x", buf[i]); From 36a1588e2d60c9dcb5564e123492cd9ac789079a Mon Sep 17 00:00:00 2001 From: yeggor Date: Mon, 16 Sep 2024 02:43:16 +0200 Subject: [PATCH 26/69] update cmakelists.txt for loader --- efiXloader/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/efiXloader/CMakeLists.txt b/efiXloader/CMakeLists.txt index 686cf0c7..9a28e7c4 100644 --- a/efiXloader/CMakeLists.txt +++ b/efiXloader/CMakeLists.txt @@ -57,7 +57,7 @@ file( "3rd/uefitool/uefidump.h") # efiLoader sources -file(GLOB efiloader_src "*.h" "*.c" "*.cpp" "*.cc") +file(GLOB efiloader_src "*.cc" "*.h") add_ida_loader(efiXloader NOEA32 ${PROJECT_SOURCE_DIR}/efi_loader.cc) From 515a0ab9333d5b05f7b1594cb059899e935d5c4e Mon Sep 17 00:00:00 2001 From: yeggor Date: Tue, 17 Sep 2024 18:57:57 +0100 Subject: [PATCH 27/69] initial refactoring for efi_analysis: - use ida style - refactor efi_analyser_t --- efiXplorer/efi_analyser.h | 445 +++++++++++------------ efiXplorer/efi_analyser_arm.cc | 90 ++--- efiXplorer/efi_analyser_x86.cc | 634 ++++++++++++++++----------------- efiXplorer/efi_defs.h | 36 +- efiXplorer/efi_global.h | 2 +- efiXplorer/efi_smm_utils.cc | 90 +++-- efiXplorer/efi_smm_utils.h | 4 +- efiXplorer/efi_ui.cc | 10 +- efiXplorer/efi_utils.cc | 45 +-- efiXplorer/efi_utils.h | 4 +- efiXplorer/efixplorer.cc | 20 +- 11 files changed, 680 insertions(+), 700 deletions(-) diff --git a/efiXplorer/efi_analyser.h b/efiXplorer/efi_analyser.h index bb67d5b3..de23770c 100644 --- a/efiXplorer/efi_analyser.h +++ b/efiXplorer/efi_analyser.h @@ -32,292 +32,297 @@ namespace efi_analysis { -class EfiAnalyser { +class efi_analyser_t { public: - EfiAnalyser(); - ~EfiAnalyser(); - - json_list_t allGuids; - json_list_t allProtocols; - json_list_t allPPIs; - json_list_t allServices; - func_list_t smiHandlers; - - ArchFileType arch = ArchFileType::Unsupported; - FfsFileType file_type = FfsFileType::Unsupported; - - void getSegments(); - void setStrings(); - - void printInterfaces(); - void markInterfaces(); - void markDataGuids(); - - bool efiSmmCpuProtocolResolver(); - void findSwSmiHandlers(); - bool findGetVariableOveflow(json_list_t allServices); - bool findPPIGetVariableStackOveflow(); - bool findSmmGetVariableOveflow(); - bool findSmmCallout(); - bool analyseNvramVariables(); - bool AnalyseVariableService(ea_t ea, std::string service_str); - bool AddProtocol(std::string serviceName, ea_t guidAddress, ea_t xrefAddress, - ea_t call_address); - void dumpInfo(); - - json dbProtocols; - ea_t base; - ea_t startAddress = 0; - ea_t endAddress = 0; - ea_list_t funcs; - std::filesystem::path guidsJsonPath; - std::map - dbProtocolsMap; // a map to look up a GUID name by value - json bootServices; - json peiServices; - json peiServicesAll; - json ppiCallsAll; - json runtimeServicesAll; - json smmServices; - json smmServicesAll; - json_list_t nvramVariables; - ea_list_t markedInterfaces; - - // Format-dependent interface-related settings (protocols for DXE, PPIs for - // PEI) - std::string if_name; - std::string if_pl; - std::string if_key; - json_list_t *if_tbl; + efi_analyser_t(); + ~efi_analyser_t(); + + ea_list_t m_funcs; + func_list_t m_smi_handlers; + json_list_t m_all_guids; + json_list_t m_all_ppis; + json_list_t m_all_protocols; + json_list_t m_all_services; + json_list_t m_nvram_variables; + + arch_file_type_t m_arch = arch_file_type_t::unsupported; + ffs_file_type_t m_ftype = ffs_file_type_t::unsupported; + + void dump_json(); + void get_segments(); + void set_pvalues(); + void mark_interfaces(); + void mark_data_guids(); + bool smm_cpu_protocol_resolver(); + void find_smi_handlers(); + bool find_double_get_variable(json_list_t m_all_services); + bool find_double_get_variable_pei(); + bool find_double_get_variable_smm(); + bool find_smm_callout(); + bool analyse_nvram_variables(); + +protected: + ea_t m_start_addr = 0; + ea_t m_end_addr = 0; + + // a map to look up a GUID name by value + std::map m_guiddb_map; + json m_guiddb; + + ea_list_t m_marked_interfaces; + json m_boot_services; + json m_pei_services_all; + json m_ppi_calls_all; + json m_runtime_services_all; + json m_smm_services_all; + json m_smm_services; + std::filesystem::path m_guids_json_path; + + // protocol related boot services + string_list_t m_prot_bs_names = {"InstallProtocolInterface", + "ReinstallProtocolInterface", + "UninstallProtocolInterface", + "HandleProtocol", + "RegisterProtocolNotify", + "OpenProtocol", + "CloseProtocol", + "OpenProtocolInformation", + "ProtocolsPerHandle", + "LocateHandleBuffer", + "LocateProtocol", + "InstallMultipleProtocolInterfaces", + "UninstallMultipleProtocolInterfaces"}; + + // protocol related SMM services + string_list_t m_prot_smms_names = {"SmmInstallProtocolInterface", + "SmmUninstallProtocolInterface", + "SmmHandleProtocol", + "SmmRegisterProtocolNotify", + "SmmLocateHandle", + "SmmLocateProtocol"}; + + // protocol related PEI services + string_list_t m_ppi_peis_names = {"InstallPpi", "ReInstallPpi", "LocatePpi", + "NotifyPpi"}; + + bool add_protocol(std::string service_name, ea_t guid_addr, ea_t xref_addr, + ea_t call_addr); + +private: + // format dependent settings + // protocols for DXE/SMM PPIs for PEI + json_list_t *m_ptable; + std::string m_pname; + std::string m_pkey; + + uint64_list_t m_ppi_flags = { + 0x1, 0x10, 0x11, 0x20, 0x21, 0x30, + 0x31, 0x40, 0x41, 0x50, 0x51, 0x60, + 0x61, 0x70, 0x71, 0x80000000, 0x80000001, 0x80000010, + 0x80000011, 0x80000020, 0x80000021, 0x80000030, 0x80000031, 0x80000040, + 0x80000041, 0x80000050, 0x80000051, 0x80000060, 0x80000061, 0x80000070, + 0x80000071, + }; // EFI_SMM_SW_DISPATCH2_PROTOCOL_GUID - EfiGuid sw_guid2 = {0x18a3c6dc, - 0x5eea, - 0x48c8, - {0xa1, 0xc1, 0xb5, 0x33, 0x89, 0xf9, 0x89, 0x99}}; + EfiGuid m_sw_guid2 = {0x18a3c6dc, + 0x5eea, + 0x48c8, + {0xa1, 0xc1, 0xb5, 0x33, 0x89, 0xf9, 0x89, 0x99}}; // EFI_SMM_SW_DISPATCH_PROTOCOL_GUID - EfiGuid sw_guid = {0xe541b773, - 0xdd11, - 0x420c, - {0xb0, 0x26, 0xdf, 0x99, 0x36, 0x53, 0xf8, 0xbf}}; + EfiGuid m_sw_guid = {0xe541b773, + 0xdd11, + 0x420c, + {0xb0, 0x26, 0xdf, 0x99, 0x36, 0x53, 0xf8, 0xbf}}; // EFI_SMM_SX_DISPATCH2_PROTOCOL_GUID - EfiGuid sx_guid2 = {0x456d2859, - 0xa84b, - 0x4e47, - {0xa2, 0xee, 0x32, 0x76, 0xd8, 0x86, 0x99, 0x7d}}; + EfiGuid m_sx_guid2 = {0x456d2859, + 0xa84b, + 0x4e47, + {0xa2, 0xee, 0x32, 0x76, 0xd8, 0x86, 0x99, 0x7d}}; // EFI_SMM_SX_DISPATCH_PROTOCOL_GUID - EfiGuid sx_guid = {0x14FC52BE, - 0x01DC, - 0x426C, - {0x91, 0xAE, 0xA2, 0x3C, 0x3E, 0x22, 0x0A, 0xE8}}; + EfiGuid m_sx_guid = {0x14FC52BE, + 0x01DC, + 0x426C, + {0x91, 0xAE, 0xA2, 0x3C, 0x3E, 0x22, 0x0A, 0xE8}}; // EFI_SMM_IO_TRAP_DISPATCH2_PROTOCOL_GUID - EfiGuid io_trap_guid2 = {0x58DC368D, - 0x7BFA, - 0x4E77, - {0xAB, 0xBC, 0x0E, 0x29, 0x41, 0x8D, 0xF9, 0x30}}; + EfiGuid m_io_trap_guid2 = {0x58DC368D, + 0x7BFA, + 0x4E77, + {0xAB, 0xBC, 0x0E, 0x29, 0x41, 0x8D, 0xF9, 0x30}}; // EFI_SMM_IO_TRAP_DISPATCH_PROTOCOL_GUID - EfiGuid io_trap_guid = {0xDB7F536B, - 0xEDE4, - 0x4714, - {0xA5, 0xC8, 0xE3, 0x46, 0xEB, 0xAA, 0x20, 0x1D}}; + EfiGuid m_io_trap_guid = {0xDB7F536B, + 0xEDE4, + 0x4714, + {0xA5, 0xC8, 0xE3, 0x46, 0xEB, 0xAA, 0x20, 0x1D}}; // EFI_SMM_GPI_DISPATCH2_PROTOCOL_GUID - EfiGuid gpi_guid2 = {0x25566B03, - 0xB577, - 0x4CBF, - {0x95, 0x8C, 0xED, 0x66, 0x3E, 0xA2, 0x43, 0x80}}; + EfiGuid m_gpi_guid2 = {0x25566B03, + 0xB577, + 0x4CBF, + {0x95, 0x8C, 0xED, 0x66, 0x3E, 0xA2, 0x43, 0x80}}; // EFI_SMM_GPI_DISPATCH_PROTOCOL_GUID - EfiGuid gpi_guid = {0xE0744B81, - 0x9513, - 0x49CD, - {0x8C, 0xEA, 0xE9, 0x24, 0x5E, 0x70, 0x39, 0xDA}}; + EfiGuid m_gpi_guid = {0xE0744B81, + 0x9513, + 0x49CD, + {0x8C, 0xEA, 0xE9, 0x24, 0x5E, 0x70, 0x39, 0xDA}}; // EFI_SMM_USB_DISPATCH2_PROTOCOL_GUID - EfiGuid usb_guid2 = {0xEE9B8D90, - 0xC5A6, - 0x40A2, - {0xBD, 0xE2, 0x52, 0x55, 0x8D, 0x33, 0xCC, 0xA1}}; + EfiGuid m_usb_guid2 = {0xEE9B8D90, + 0xC5A6, + 0x40A2, + {0xBD, 0xE2, 0x52, 0x55, 0x8D, 0x33, 0xCC, 0xA1}}; // EFI_SMM_USB_DISPATCH_PROTOCOL_GUID - EfiGuid usb_guid = {0xA05B6FFD, - 0x87AF, - 0x4E42, - {0x95, 0xC9, 0x62, 0x28, 0xB6, 0x3C, 0xF3, 0xF3}}; + EfiGuid m_usb_guid = {0xA05B6FFD, + 0x87AF, + 0x4E42, + {0x95, 0xC9, 0x62, 0x28, 0xB6, 0x3C, 0xF3, 0xF3}}; // EFI_SMM_STANDBY_BUTTON_DISPATCH2_PROTOCOL_GUID - EfiGuid standby_button_guid2 = { + EfiGuid m_standby_button_guid2 = { 0x7300C4A1, 0x43F2, 0x4017, {0xA5, 0x1B, 0xC8, 0x1A, 0x7F, 0x40, 0x58, 0x5B}}; // EFI_SMM_STANDBY_BUTTON_DISPATCH_PROTOCOL_GUID - EfiGuid standby_button_guid = { + EfiGuid m_standby_button_guid = { 0x78965B98, 0xB0BF, 0x449E, {0x8B, 0x22, 0xD2, 0x91, 0x4E, 0x49, 0x8A, 0x98}}; // EFI_SMM_PERIODIC_TIMER_DISPATCH2_PROTOCOL_GUID - EfiGuid periodic_timer_guid2 = { + EfiGuid m_periodic_timer_guid2 = { 0x4CEC368E, 0x8E8E, 0x4D71, {0x8B, 0xE1, 0x95, 0x8C, 0x45, 0xFC, 0x8A, 0x53}}; // EFI_SMM_PERIODIC_TIMER_DISPATCH_PROTOCOL_GUID - EfiGuid periodic_timer_guid = { + EfiGuid m_periodic_timer_guid = { 0x9CCA03FC, 0x4C9E, 0x4A19, {0x9B, 0x06, 0xED, 0x7B, 0x47, 0x9B, 0xDE, 0x55}}; // EFI_SMM_POWER_BUTTON_DISPATCH2_PROTOCOL_GUID - EfiGuid power_button_guid2 = { + EfiGuid m_power_button_guid2 = { 0x1B1183FA, 0x1823, 0x46A7, {0x88, 0x72, 0x9C, 0x57, 0x87, 0x55, 0x40, 0x9D}}; // EFI_SMM_POWER_BUTTON_DISPATCH_PROTOCOL_GUID - EfiGuid power_button_guid = { + EfiGuid m_power_button_guid = { 0xB709EFA0, 0x47A6, 0x4B41, {0xB9, 0x31, 0x12, 0xEC, 0xE7, 0xA8, 0xEE, 0x56}}; // EFI_SMM_ICHN_DISPATCH_PROTOCOL_GUID - EfiGuid ichn_guid = {0xC50B323E, - 0x9075, - 0x4F2A, - {0xAC, 0x8E, 0xD2, 0x59, 0x6A, 0x10, 0x85, 0xCC}}; + EfiGuid m_ichn_guid = {0xC50B323E, + 0x9075, + 0x4F2A, + {0xAC, 0x8E, 0xD2, 0x59, 0x6A, 0x10, 0x85, 0xCC}}; // EFI_SMM_ICHN_DISPATCH2_PROTOCOL_GUID - EfiGuid ichn_guid2 = {0xADF3A128, - 0x416D, - 0x4060, - {0x8D, 0xDF, 0x30, 0xA1, 0xD7, 0xAA, 0xB6, 0x99}}; + EfiGuid m_ichn_guid2 = {0xADF3A128, + 0x416D, + 0x4060, + {0x8D, 0xDF, 0x30, 0xA1, 0xD7, 0xAA, 0xB6, 0x99}}; // PCH_TCO_SMI_DISPATCH_PROTOCOL_GUID - EfiGuid tco_guid = {0x9E71D609, - 0x6D24, - 0x47FD, - {0xB5, 0x72, 0x61, 0x40, 0xF8, 0xD9, 0xC2, 0xA4}}; + EfiGuid m_tco_guid = {0x9E71D609, + 0x6D24, + 0x47FD, + {0xB5, 0x72, 0x61, 0x40, 0xF8, 0xD9, 0xC2, 0xA4}}; // PCH_PCIE_SMI_DISPATCH_PROTOCOL_GUID - EfiGuid pcie_guid = {0x3E7D2B56, - 0x3F47, - 0x42AA, - {0x8F, 0x6B, 0x22, 0xF5, 0x19, 0x81, 0x8D, 0xAB}}; + EfiGuid m_pcie_guid = {0x3E7D2B56, + 0x3F47, + 0x42AA, + {0x8F, 0x6B, 0x22, 0xF5, 0x19, 0x81, 0x8D, 0xAB}}; // PCH_ACPI_SMI_DISPATCH_PROTOCOL_GUID - EfiGuid acpi_guid = {0xD52BB262, - 0xF022, - 0x49EC, - {0x86, 0xD2, 0x7A, 0x29, 0x3A, 0x7A, 0x5, 0x4B}}; + EfiGuid m_acpi_guid = {0xD52BB262, + 0xF022, + 0x49EC, + {0x86, 0xD2, 0x7A, 0x29, 0x3A, 0x7A, 0x5, 0x4B}}; // PCH_GPIO_UNLOCK_SMI_DISPATCH_PROTOCOL_GUID - EfiGuid gpio_unlock_guid = {0x83339EF7, - 0x9392, - 0x4716, - {0x8D, 0x3A, 0xD1, 0xFC, 0x67, 0xCD, 0x55, 0xDB}}; + EfiGuid m_gpio_unlock_guid = { + 0x83339EF7, + 0x9392, + 0x4716, + {0x8D, 0x3A, 0xD1, 0xFC, 0x67, 0xCD, 0x55, 0xDB}}; // PCH_SMI_DISPATCH_PROTOCOL_GUID - EfiGuid pch_guid = {0xE6A81BBF, - 0x873D, - 0x47FD, - {0xB6, 0xBE, 0x61, 0xB3, 0xE5, 0x72, 0x9, 0x93}}; + EfiGuid m_pch_guid = {0xE6A81BBF, + 0x873D, + 0x47FD, + {0xB6, 0xBE, 0x61, 0xB3, 0xE5, 0x72, 0x9, 0x93}}; // PCH_ESPI_SMI_DISPATCH_PROTOCOL_GUID - EfiGuid espi_guid = {0xB3C14FF3, - 0xBAE8, - 0x456C, - {0x86, 0x31, 0x27, 0xFE, 0x0C, 0xEB, 0x34, 0x0C}}; + EfiGuid m_espi_guid = {0xB3C14FF3, + 0xBAE8, + 0x456C, + {0x86, 0x31, 0x27, 0xFE, 0x0C, 0xEB, 0x34, 0x0C}}; // EFI_ACPI_EN_DISPATCH_PROTOCOL_GUID - EfiGuid acpi_en_guid = {0xBD88EC68, - 0xEBE4, - 0x4F7B, - {0x93, 0x5A, 0x4F, 0x66, 0x66, 0x42, 0xE7, 0x5F}}; + EfiGuid m_acpi_en_guid = {0xBD88EC68, + 0xEBE4, + 0x4F7B, + {0x93, 0x5A, 0x4F, 0x66, 0x66, 0x42, 0xE7, 0x5F}}; // EFI_ACPI_DIS_DISPATCH_PROTOCOL_GUID - EfiGuid acpi_dis_guid = {0x9C939BA6, - 0x1FCC, - 0x46F6, - {0xB4, 0xE1, 0x10, 0x2D, 0xBE, 0x18, 0x65, 0x67}}; + EfiGuid m_acpi_dis_guid = {0x9C939BA6, + 0x1FCC, + 0x46F6, + {0xB4, 0xE1, 0x10, 0x2D, 0xBE, 0x18, 0x65, 0x67}}; // FCH_SMM_GPI_DISPATCH2_PROTOCOL_GUID - EfiGuid fch_gpi_guid2 = {0x7051ab6d, - 0x9ec2, - 0x42eb, - {0xa2, 0x13, 0xde, 0x48, 0x81, 0xf1, 0xf7, 0x87}}; + EfiGuid m_fch_gpi_guid2 = {0x7051ab6d, + 0x9ec2, + 0x42eb, + {0xa2, 0x13, 0xde, 0x48, 0x81, 0xf1, 0xf7, 0x87}}; // FCH_SMM_IO_TRAP_DISPATCH2_PROTOCOL_GUID - EfiGuid fch_io_trap_guid2 = {0x91288fc4, - 0xe64b, - 0x4ef9, - {0xa4, 0x63, 0x66, 0x88, 0x0, 0x71, 0x7f, 0xca}}; + EfiGuid m_fch_io_trap_guid2 = { + 0x91288fc4, + 0xe64b, + 0x4ef9, + {0xa4, 0x63, 0x66, 0x88, 0x0, 0x71, 0x7f, 0xca}}; // FCH_SMM_PERIODICAL_DISPATCH2_PROTOCOL_GUID - EfiGuid fch_periodical_guid2 = { + EfiGuid m_fch_periodical_guid2 = { 0x736102f1, 0x9584, 0x44e7, {0x82, 0x8a, 0x43, 0x4b, 0x1e, 0x67, 0x5c, 0xc4}}; // FCH_SMM_PWR_BTN_DISPATCH2_PROTOCOL_GUID - EfiGuid fch_pwr_btn_guid2 = {0xa365240e, - 0x56b0, - 0x426d, - {0x83, 0xa, 0x30, 0x66, 0xc6, 0x81, 0xbe, 0x9a}}; + EfiGuid m_fch_pwr_btn_guid2 = { + 0xa365240e, + 0x56b0, + 0x426d, + {0x83, 0xa, 0x30, 0x66, 0xc6, 0x81, 0xbe, 0x9a}}; // FCH_SMM_SW_DISPATCH2_PROTOCOL_GUID - EfiGuid fch_sw_guid2 = {0x881b4ab6, - 0x17b0, - 0x4bdf, - {0x88, 0xe2, 0xd4, 0x29, 0xda, 0x42, 0x5f, 0xfd}}; + EfiGuid m_fch_sw_guid2 = {0x881b4ab6, + 0x17b0, + 0x4bdf, + {0x88, 0xe2, 0xd4, 0x29, 0xda, 0x42, 0x5f, 0xfd}}; // FCH_SMM_SX_DISPATCH2_PROTOCOL_GUID - EfiGuid fch_sx_guid2 = {0x87e2a6cf, - 0x91fb, - 0x4581, - {0x90, 0xa9, 0x6f, 0x50, 0x5d, 0xdc, 0x1c, 0xb2}}; + EfiGuid m_fch_sx_guid2 = {0x87e2a6cf, + 0x91fb, + 0x4581, + {0x90, 0xa9, 0x6f, 0x50, 0x5d, 0xdc, 0x1c, 0xb2}}; // FCH_SMM_USB_DISPATCH_PROTOCOL_GUID - EfiGuid fch_usb_guid = {0x59053b0d, - 0xeeb8, - 0x4379, - {0xb1, 0xc8, 0x14, 0x5f, 0x1b, 0xb, 0xe4, 0xb9}}; + EfiGuid m_fch_usb_guid = {0x59053b0d, + 0xeeb8, + 0x4379, + {0xb1, 0xc8, 0x14, 0x5f, 0x1b, 0xb, 0xe4, 0xb9}}; // FCH_SMM_USB_DISPATCH2_PROTOCOL_GUID - EfiGuid fch_usb_guid2 = {0xfbbb2ea9, - 0xce0e, - 0x4689, - {0xb3, 0xf0, 0xc6, 0xb8, 0xf0, 0x76, 0xbd, 0x20}}; + EfiGuid m_fch_usb_guid2 = {0xfbbb2ea9, + 0xce0e, + 0x4689, + {0xb3, 0xf0, 0xc6, 0xb8, 0xf0, 0x76, 0xbd, 0x20}}; // FCH_SMM_MISC_DISPATCH_PROTOCOL_GUID - EfiGuid fch_misc_guid = {0x13bd659b, - 0xb4c6, - 0x47da, - {0x9b, 0x22, 0x11, 0x50, 0xd4, 0xf3, 0xb, 0xda}}; + EfiGuid m_fch_misc_guid = {0x13bd659b, + 0xb4c6, + 0x47da, + {0x9b, 0x22, 0x11, 0x50, 0xd4, 0xf3, 0xb, 0xda}}; // FCH_SMM_APU_RAS_DISPATCH_PROTOCOL_GUID - EfiGuid fch_apu_ras_guid = {0xf871ee59, - 0x29d2, - 0x4b15, - {0x9e, 0x67, 0xaf, 0x32, 0xcd, 0xc1, 0x41, 0x73}}; - - uint64_list_t ppiFlags = { - 0x1, 0x10, 0x11, 0x20, 0x21, 0x30, - 0x31, 0x40, 0x41, 0x50, 0x51, 0x60, - 0x61, 0x70, 0x71, 0x80000000, 0x80000001, 0x80000010, - 0x80000011, 0x80000020, 0x80000021, 0x80000030, 0x80000031, 0x80000040, - 0x80000041, 0x80000050, 0x80000051, 0x80000060, 0x80000061, 0x80000070, - 0x80000071, - }; + EfiGuid m_fch_apu_ras_guid = { + 0xf871ee59, + 0x29d2, + 0x4b15, + {0x9e, 0x67, 0xaf, 0x32, 0xcd, 0xc1, 0x41, 0x73}}; - // Set boot services that work with protocols - string_list_t protBsNames = {"InstallProtocolInterface", - "ReinstallProtocolInterface", - "UninstallProtocolInterface", - "HandleProtocol", - "RegisterProtocolNotify", - "OpenProtocol", - "CloseProtocol", - "OpenProtocolInformation", - "ProtocolsPerHandle", - "LocateHandleBuffer", - "LocateProtocol", - "InstallMultipleProtocolInterfaces", - "UninstallMultipleProtocolInterfaces"}; - - // Set smm services that work with protocols - string_list_t protSmmNames = {"SmmInstallProtocolInterface", - "SmmUninstallProtocolInterface", - "SmmHandleProtocol", - "SmmRegisterProtocolNotify", - "SmmLocateHandle", - "SmmLocateProtocol"}; - - // Set of PEI services that work with PPI - string_list_t ppiPEINames = {"InstallPpi", "ReInstallPpi", "LocatePpi", - "NotifyPpi"}; + void print_interfaces(); + bool analyse_variable_service(ea_t ea, std::string service_str); }; -class EfiAnalyserX86 : public EfiAnalyser { +class efi_analyser_x86_t : public efi_analyser_t { public: - EfiAnalyserX86() : EfiAnalyser() { + efi_analyser_x86_t() : efi_analyser_t() { // import necessary types const til_t *idati = get_idati(); import_type(idati, -1, "EFI_GUID"); @@ -365,9 +370,9 @@ class EfiAnalyserX86 : public EfiAnalyser { bool InstallMultipleProtocolInterfacesHandler(); }; -class EfiAnalyserArm : public EfiAnalyser { +class efi_analyser_arm_t : public efi_analyser_t { public: - EfiAnalyserArm() : EfiAnalyser() { + efi_analyser_arm_t() : efi_analyser_t() { // in order to make it work, it is necessary to copy // uefi.til, uefi64.til files in {idadir}/til/arm/ add_til("uefi64.til", ADDTIL_DEFAULT); @@ -379,7 +384,7 @@ class EfiAnalyserArm : public EfiAnalyser { import_type(idati, -1, "EFI_BOOT_SERVICES"); import_type(idati, -1, "EFI_RUNTIME_SERVICES"); } - void fixOffsets(); + void fix_offsets(); void initialAnalysis(); void findBootServicesTables(); void initialGlobalVarsDetection(); @@ -417,4 +422,4 @@ bool efiAnalyserMainX86(); bool efiAnalyserMainArm(); }; // namespace efi_analysis -void showAllChoosers(efi_analysis::EfiAnalyser analyser); +void showAllChoosers(efi_analysis::efi_analyser_t analyser); diff --git a/efiXplorer/efi_analyser_arm.cc b/efiXplorer/efi_analyser_arm.cc index 089e2305..7eed52bc 100644 --- a/efiXplorer/efi_analyser_arm.cc +++ b/efiXplorer/efi_analyser_arm.cc @@ -22,17 +22,17 @@ #include "efi_ui.h" #include "efi_utils.h" -using efi_analysis::EfiAnalyserArm; +using efi_analysis::efi_analyser_arm_t; ea_list_t image_handle_list_arm; ea_list_t st_list_arm; ea_list_t bs_list_arm; ea_list_t rt_list_arm; -void efi_analysis::EfiAnalyserArm::fixOffsets() { +void efi_analysis::efi_analyser_arm_t::fix_offsets() { insn_t insn; - for (auto func_addr : funcs) { - func_t *f = get_func(func_addr); + for (auto faddr : m_funcs) { + func_t *f = get_func(faddr); if (f == nullptr) { continue; } @@ -53,8 +53,8 @@ void efi_analysis::EfiAnalyserArm::fixOffsets() { } } -void efi_analysis::EfiAnalyserArm::initialAnalysis() { - fixOffsets(); +void efi_analysis::efi_analyser_arm_t::initialAnalysis() { + fix_offsets(); for (auto idx = 0; idx < get_entry_qty(); idx++) { uval_t ord = get_entry_ordinal(idx); ea_t ep = get_entry(ord); @@ -63,7 +63,7 @@ void efi_analysis::EfiAnalyserArm::initialAnalysis() { track_entry_params(get_func(ep), 0); #endif /* HEX_RAYS */ } - if (file_type == FfsFileType::Pei) { + if (m_ftype == ffs_file_type_t::pei) { // set_entry_arg_to_pei_svc(); } } @@ -227,10 +227,10 @@ json getService(ea_t addr, uint8_t table_id) { return s; } -void efi_analysis::EfiAnalyserArm::initialGlobalVarsDetection() { +void efi_analysis::efi_analyser_arm_t::initialGlobalVarsDetection() { #ifdef HEX_RAYS // analyse entry point with Hex-Rays - for (auto func_addr : funcs) { + for (auto func_addr : m_funcs) { json res = detect_vars(get_func(func_addr)); if (res.contains("image_handle_list")) { for (auto addr : res["image_handle_list"]) { @@ -264,7 +264,7 @@ void efi_analysis::EfiAnalyserArm::initialGlobalVarsDetection() { #endif /* HEX_RAYS */ // analysis of all functions and search for additional table initializations - for (auto func_addr : funcs) { + for (auto func_addr : m_funcs) { func_t *f = get_func(func_addr); if (f == nullptr) { continue; @@ -294,12 +294,12 @@ void efi_analysis::EfiAnalyserArm::initialGlobalVarsDetection() { } } -void efi_analysis::EfiAnalyserArm::servicesDetection() { +void efi_analysis::efi_analyser_arm_t::servicesDetection() { #ifdef HEX_RAYS - for (auto func_addr : funcs) { + for (auto func_addr : m_funcs) { json_list_t services = detect_services(get_func(func_addr)); for (auto service : services) { - allServices.push_back(service); + m_all_services.push_back(service); } } #endif /* HEX_RAYS */ @@ -316,10 +316,10 @@ void efi_analysis::EfiAnalyserArm::servicesDetection() { if (name == "Unknown") { continue; } - if (!json_in_vec(allServices, s)) { + if (!json_in_vec(m_all_services, s)) { msg("[efiXplorer] gBS xref address: 0x%016llX, found new service\n", u64_addr(ea)); - allServices.push_back(s); + m_all_services.push_back(s); } } } @@ -334,17 +334,17 @@ void efi_analysis::EfiAnalyserArm::servicesDetection() { if (name == "Unknown") { continue; } - if (!json_in_vec(allServices, s)) { + if (!json_in_vec(m_all_services, s)) { msg("[efiXplorer] gRT xref address: 0x%016llX, found new service\n", u64_addr(ea)); - allServices.push_back(s); + m_all_services.push_back(s); } } } } -bool efi_analysis::EfiAnalyserArm::getProtocol(ea_t address, uint32_t p_reg, - std::string service_name) { +bool efi_analysis::efi_analyser_arm_t::getProtocol(ea_t address, uint32_t p_reg, + std::string service_name) { ea_t ea = address; insn_t insn; ea_t offset = BADADDR; @@ -379,11 +379,11 @@ bool efi_analysis::EfiAnalyserArm::getProtocol(ea_t address, uint32_t p_reg, } msg("[efiXplorer] address: 0x%016llX, found new protocol\n", u64_addr(code_addr)); - return AddProtocol(service_name, guid_addr, code_addr, address); + return add_protocol(service_name, guid_addr, code_addr, address); } -void efi_analysis::EfiAnalyserArm::protocolsDetection() { - for (auto s : allServices) { +void efi_analysis::efi_analyser_arm_t::protocolsDetection() { + for (auto s : m_all_services) { std::string service_name = s["service_name"]; for (auto i = 0; i < 13; i++) { std::string current_name = @@ -397,9 +397,9 @@ void efi_analysis::EfiAnalyserArm::protocolsDetection() { } } -void efi_analysis::EfiAnalyserArm::findPeiServicesFunction() { +void efi_analysis::efi_analyser_arm_t::findPeiServicesFunction() { insn_t insn; - for (auto start_ea : funcs) { + for (auto start_ea : m_funcs) { decode_insn(&insn, start_ea); if (!(insn.itype == ARM_mrs && insn.ops[0].type == o_reg && insn.ops[0].reg == REG_X0 && insn.ops[1].type == o_imm && @@ -425,25 +425,25 @@ void efi_analysis::EfiAnalyserArm::findPeiServicesFunction() { //-------------------------------------------------------------------------- // Show all non-empty choosers windows -void showAllChoosers(efi_analysis::EfiAnalyserArm analyser) { +void showAllChoosers(efi_analysis::efi_analyser_arm_t analyser) { qstring title; // open window with all services - if (analyser.allServices.size()) { + if (analyser.m_all_services.size()) { title = "efiXplorer: services"; - services_show(analyser.allServices, title); + services_show(analyser.m_all_services, title); } // open window with data guids - if (analyser.allGuids.size()) { + if (analyser.m_all_guids.size()) { qstring title = "efiXplorer: GUIDs"; - guids_show(analyser.allGuids, title); + guids_show(analyser.m_all_guids, title); } // open window with protocols - if (analyser.allProtocols.size()) { + if (analyser.m_all_protocols.size()) { title = "efiXplorer: protocols"; - protocols_show(analyser.allProtocols, title); + protocols_show(analyser.m_all_protocols, title); } } @@ -452,27 +452,27 @@ void showAllChoosers(efi_analysis::EfiAnalyserArm analyser) { bool efi_analysis::efiAnalyserMainArm() { show_wait_box("HIDECANCEL\nAnalysing module(s) with efiXplorer..."); - efi_analysis::EfiAnalyserArm analyser; + efi_analysis::efi_analyser_arm_t analyser; while (!auto_is_ok()) { auto_wait(); } // find .text and .data segments - analyser.getSegments(); + analyser.get_segments(); // mark GUIDs - analyser.markDataGuids(); + analyser.mark_data_guids(); if (g_args.disable_ui) { - analyser.file_type = g_args.module_type == ModuleType::Pei - ? analyser.file_type = FfsFileType::Pei - : analyser.file_type = FfsFileType::DxeAndTheLike; + analyser.m_ftype = g_args.module_type == module_type_t::pei + ? analyser.m_ftype = ffs_file_type_t::pei + : analyser.m_ftype = ffs_file_type_t::dxe_smm; } else { - analyser.file_type = ask_file_type(&analyser.allGuids); + analyser.m_ftype = ask_file_type(&analyser.m_all_guids); } - if (analyser.file_type == FfsFileType::Pei) { + if (analyser.m_ftype == ffs_file_type_t::pei) { msg("[efiXplorer] input file is PEI module\n"); } @@ -480,7 +480,7 @@ bool efi_analysis::efiAnalyserMainArm() { // prototype analyser.initialAnalysis(); - if (analyser.file_type == FfsFileType::DxeAndTheLike) { + if (analyser.m_ftype == ffs_file_type_t::dxe_smm) { analyser.initialGlobalVarsDetection(); // detect services @@ -488,22 +488,22 @@ bool efi_analysis::efiAnalyserMainArm() { // detect protocols analyser.protocolsDetection(); - } else if (analyser.file_type == FfsFileType::Pei) { + } else if (analyser.m_ftype == ffs_file_type_t::pei) { analyser.findPeiServicesFunction(); } #ifdef HEX_RAYS - for (auto addr : analyser.funcs) { + for (auto addr : analyser.m_funcs) { json_list_t services = detect_pei_services_arm(get_func(addr)); for (auto service : services) { - analyser.allServices.push_back(service); + analyser.m_all_services.push_back(service); } } - apply_all_types_for_interfaces(analyser.allProtocols); + apply_all_types_for_interfaces(analyser.m_all_protocols); #endif /* HEX_RAYS */ showAllChoosers(analyser); - analyser.dumpInfo(); + analyser.dump_json(); hide_wait_box(); diff --git a/efiXplorer/efi_analyser_x86.cc b/efiXplorer/efi_analyser_x86.cc index e0cfd2d5..28670a11 100644 --- a/efiXplorer/efi_analyser_x86.cc +++ b/efiXplorer/efi_analyser_x86.cc @@ -26,8 +26,8 @@ #include "efi_hexrays.h" #endif -using efi_analysis::EfiAnalyser; -using efi_analysis::EfiAnalyserX86; +using efi_analysis::efi_analyser_t; +using efi_analysis::efi_analyser_x86_t; extern ea_list_t g_get_smst_location_calls; extern ea_list_t g_smm_get_variable_calls; @@ -59,15 +59,12 @@ ea_list_t peiGetVariableOverflow; ea_list_t getVariableOverflow; ea_list_t smmGetVariableOverflow; -efi_analysis::EfiAnalyser::EfiAnalyser() { +efi_analysis::efi_analyser_t::efi_analyser_t() { // 32-bit, 64-bit, ARM or UEFI (in loader instance) - arch = input_file_type(); + m_arch = input_file_type(); // get guids.json path - guidsJsonPath /= get_guids_json_file(); - - // get base address - base = get_imagebase(); + m_guids_json_path /= get_guids_json_file(); func_t *start_func = nullptr; func_t *end_func = nullptr; @@ -75,50 +72,50 @@ efi_analysis::EfiAnalyser::EfiAnalyser() { // get start address for scan start_func = getn_func(0); if (start_func) { - startAddress = start_func->start_ea; + m_start_addr = start_func->start_ea; } // get end address for scan end_func = getn_func(get_func_qty() - 1); if (end_func) { - endAddress = end_func->end_ea; + m_end_addr = end_func->end_ea; } - // save all funcs + // save all m_funcs for (auto i = 0; i < get_func_qty(); i++) { auto func = getn_func(i); - funcs.push_back(func->start_ea); + m_funcs.push_back(func->start_ea); } ea_list_t addrs; - for (auto service : protBsNames) { - bootServices[service] = addrs; + for (auto service : m_prot_bs_names) { + m_boot_services[service] = addrs; } - for (auto service : protSmmNames) { - smmServices[service] = addrs; + for (auto service : m_prot_smms_names) { + m_smm_services[service] = addrs; } try { // load protocols from guids.json file - std::ifstream in(guidsJsonPath); - in >> dbProtocols; + std::ifstream in(m_guids_json_path); + in >> m_guiddb; } catch (std::exception &e) { - dbProtocols.clear(); + m_guiddb.clear(); std::string msg_text = "guids.json file is invalid, check its contents"; msg("[%s] %s\n", g_plugin_name, msg_text.c_str()); warning("%s: %s\n", g_plugin_name, msg_text.c_str()); } // get reverse dictionary - for (auto g = dbProtocols.begin(); g != dbProtocols.end(); ++g) { - dbProtocolsMap[static_cast(g.value())] = + for (auto g = m_guiddb.begin(); g != m_guiddb.end(); ++g) { + m_guiddb_map[static_cast(g.value())] = static_cast(g.key()); } } -efi_analysis::EfiAnalyser::~EfiAnalyser() { - funcs.clear(); +efi_analysis::efi_analyser_t::~efi_analyser_t() { + m_funcs.clear(); st_list.clear(); ps_list.clear(); @@ -137,7 +134,7 @@ efi_analysis::EfiAnalyser::~EfiAnalyser() { calloutAddrs.clear(); excFunctions.clear(); readSaveStateCalls.clear(); - smiHandlers.clear(); + m_smi_handlers.clear(); childSmiHandlers.clear(); peiGetVariableOverflow.clear(); @@ -153,23 +150,21 @@ efi_analysis::EfiAnalyser::~EfiAnalyser() { #endif } -void efi_analysis::EfiAnalyser::setStrings() { - if (file_type == FfsFileType::DxeAndTheLike) { - if_name = " Protocol name "; - if_pl = "protocols"; - if_key = "prot_name"; - if_tbl = &allProtocols; - } else if (file_type == FfsFileType::Pei) { - if_name = " PPI name "; - if_pl = "PPIs"; - if_key = "ppi_name"; - if_tbl = &allPPIs; +void efi_analysis::efi_analyser_t::set_pvalues() { + if (m_ftype == ffs_file_type_t::dxe_smm) { + m_pname = "protocols"; + m_pkey = "prot_name"; + m_ptable = &m_all_protocols; + } else if (m_ftype == ffs_file_type_t::pei) { + m_pname = "ppis"; + m_pkey = "ppi_name"; + m_ptable = &m_all_ppis; } } //-------------------------------------------------------------------------- // Get all .text and .data segments -void efi_analysis::EfiAnalyser::getSegments() { +void efi_analysis::efi_analyser_t::get_segments() { for (segment_t *s = get_first_seg(); s != nullptr; s = get_next_seg(s->start_ea)) { qstring seg_name; @@ -211,7 +206,7 @@ void efi_analysis::EfiAnalyser::getSegments() { //-------------------------------------------------------------------------- // Find gImageHandle address for X64 modules -bool efi_analysis::EfiAnalyserX86::findImageHandleX64() { +bool efi_analysis::efi_analyser_x86_t::findImageHandleX64() { msg("[%s] gImageHandle finding\n", g_plugin_name); insn_t insn; for (int idx = 0; idx < get_entry_qty(); idx++) { @@ -226,14 +221,13 @@ bool efi_analysis::EfiAnalyserX86::findImageHandleX64() { insn.ops[1].reg == REG_RCX && insn.ops[0].type == o_mem) { msg("[%s] found ImageHandle at 0x%016llX, address = 0x%016llX\n", g_plugin_name, u64_addr(ea), u64_addr(insn.ops[0].addr)); - set_cmt(ea, "EFI_IMAGE_HANDLE gImageHandle", true); // set type and name set_type_and_name(insn.ops[0].addr, "gImageHandle", "EFI_IMAGE_HANDLE"); image_handle_list.push_back(insn.ops[0].addr); break; } - ea = next_head(ea, endAddress); + ea = next_head(ea, m_end_addr); } } return true; @@ -241,7 +235,7 @@ bool efi_analysis::EfiAnalyserX86::findImageHandleX64() { //-------------------------------------------------------------------------- // Find gST address for X64 modules -bool efi_analysis::EfiAnalyserX86::findSystemTableX64() { +bool efi_analysis::efi_analyser_x86_t::findSystemTableX64() { msg("[%s] gEfiSystemTable finding\n", g_plugin_name); insn_t insn; for (int idx = 0; idx < get_entry_qty(); idx++) { @@ -254,7 +248,6 @@ bool efi_analysis::EfiAnalyserX86::findSystemTableX64() { decode_insn(&insn, ea); if (insn.itype == NN_mov && insn.ops[1].type == o_reg && insn.ops[1].reg == REG_RDX && insn.ops[0].type == o_mem) { - set_cmt(ea, "EFI_SYSTEM_TABLE *gST", true); set_ptr_type_and_name(insn.ops[0].addr, "gST", "EFI_SYSTEM_TABLE"); st_list.push_back(insn.ops[0].addr); return true; @@ -267,7 +260,7 @@ bool efi_analysis::EfiAnalyserX86::findSystemTableX64() { //-------------------------------------------------------------------------- // Find and mark gSmst global variable address for X64 module -bool efi_analysis::EfiAnalyserX86::findSmstX64() { +bool efi_analysis::efi_analyser_x86_t::findSmstX64() { msg("[%s] gSmst finding\n", g_plugin_name); ea_list_t smst_listSmmBase = findSmstSmmBase(bs_list); ea_list_t smst_listSwDispatch = findSmstSwDispatch(bs_list); @@ -289,7 +282,7 @@ bool efi_analysis::EfiAnalyserX86::findSmstX64() { //-------------------------------------------------------------------------- // Find and mark gSmst global and local variable address for X64 module // after Hex-Rays based analysis -bool efi_analysis::EfiAnalyserX86::findSmstPostProcX64() { +bool efi_analysis::efi_analyser_x86_t::findSmstPostProcX64() { for (auto ea : g_get_smst_location_calls) { msg("[%s] EfiSmmBase2Protocol->GetSmstLocation call: 0x%016llX\n", g_plugin_name, u64_addr(ea)); @@ -317,12 +310,10 @@ bool efi_analysis::EfiAnalyserX86::findSmstPostProcX64() { } else { smst_stack["end"] = f->end_ea; } - set_cmt(addr, "_EFI_SMM_SYSTEM_TABLE2 *gSmst;", true); } break; case o_mem: smst_addr = insn.ops[1].addr; - set_cmt(addr, "_EFI_SMM_SYSTEM_TABLE2 *gSmst;", true); break; } } @@ -349,7 +340,7 @@ bool efi_analysis::EfiAnalyserX86::findSmstPostProcX64() { // try to extract ChildSwSmiHandler auto counter = 0; ea_t ea = static_cast(smst_stack["start"]); - uint16_t smst_reg = BAD_REG; + uint16_t smst_reg = BADREG; uint64_t rcx_last = BADADDR; while (ea < static_cast(smst_stack["end"])) { counter += 1; @@ -384,7 +375,7 @@ bool efi_analysis::EfiAnalyserX86::findSmstPostProcX64() { rcx_last = insn.ops[1].addr; } - if (rcx_last == BADADDR || smst_reg == BAD_REG) { + if (rcx_last == BADADDR || smst_reg == BADREG) { continue; } @@ -409,12 +400,12 @@ bool efi_analysis::EfiAnalyserX86::findSmstPostProcX64() { //-------------------------------------------------------------------------- // Find gBS addresses for 32-bit/64-bit modules -bool efi_analysis::EfiAnalyserX86::findBootServicesTables() { +bool efi_analysis::efi_analyser_x86_t::findBootServicesTables() { // init architecture-specific constants auto BS_OFFSET = BS_OFFSET_64; uint16_t REG_SP = static_cast(REG_RSP); - if (arch == ArchFileType::X8632) { + if (m_arch == arch_file_type_t::x86_32) { BS_OFFSET = BS_OFFSET_32; REG_SP = static_cast(REG_ESP); } @@ -429,7 +420,7 @@ bool efi_analysis::EfiAnalyserX86::findBootServicesTables() { uint16_t stRegister = 0; ea_t var_addr = BADADDR; // current global variable address while (ea <= s->end_ea) { - ea = next_head(ea, endAddress); + ea = next_head(ea, m_end_addr); decode_insn(&insn, ea); if (insn.itype == NN_mov && insn.ops[1].type == o_displ && insn.ops[1].phrase != REG_SP) { @@ -442,7 +433,7 @@ bool efi_analysis::EfiAnalyserX86::findBootServicesTables() { // found BS_OFFSET, need to check 10 instructions below for (auto i = 0; i < 10; i++) { - ea = next_head(ea, endAddress); + ea = next_head(ea, m_end_addr); decode_insn(&insn, ea); if (insn.itype == NN_mov && insn.ops[0].type == o_reg && insn.ops[1].type == o_imm) { @@ -458,7 +449,6 @@ bool efi_analysis::EfiAnalyserX86::findBootServicesTables() { next_insn.ops[1].reg == bsRegister) { baseInsnAddr = ea; if (!addr_in_vec(bs_list, var_addr)) { - set_cmt(ea, "EFI_BOOT_SERVICES *gBS", true); set_ptr_type_and_name(var_addr, "gBS", "EFI_BOOT_SERVICES"); bs_list.push_back(var_addr); } @@ -472,7 +462,6 @@ bool efi_analysis::EfiAnalyserX86::findBootServicesTables() { baseInsnAddr = ea; var_addr = insn.ops[0].addr; if (!addr_in_vec(bs_list, var_addr)) { - set_cmt(ea, "EFI_BOOT_SERVICES *gBS", true); set_ptr_type_and_name(var_addr, "gBS", "EFI_BOOT_SERVICES"); bs_list.push_back(var_addr); } @@ -484,7 +473,6 @@ bool efi_analysis::EfiAnalyserX86::findBootServicesTables() { stRegister != bsRegister) { var_addr = insn.ops[0].addr; if (!addr_in_tables(st_list, bs_list, rt_list, var_addr)) { - set_cmt(ea, "EFI_SYSTEM_TABLE *gST", true); set_ptr_type_and_name(var_addr, "gST", "EFI_SYSTEM_TABLE"); st_list.push_back(var_addr); } @@ -500,14 +488,13 @@ bool efi_analysis::EfiAnalyserX86::findBootServicesTables() { // check 8 instructions above baseInsnAddr auto addr = baseInsnAddr; for (auto i = 0; i < 8; i++) { - addr = prev_head(addr, startAddress); + addr = prev_head(addr, m_start_addr); decode_insn(&insn, addr); if (insn.itype == NN_mov && insn.ops[1].type == o_reg && insn.ops[1].reg == stRegister && insn.ops[0].type == o_mem) { var_addr = insn.ops[0].addr; if (!addr_in_tables(st_list, bs_list, rt_list, var_addr)) { - set_cmt(addr, "EFI_SYSTEM_TABLE *gST", true); set_ptr_type_and_name(var_addr, "gST", "EFI_SYSTEM_TABLE"); st_list.push_back(var_addr); } @@ -526,12 +513,12 @@ bool efi_analysis::EfiAnalyserX86::findBootServicesTables() { //-------------------------------------------------------------------------- // Find gRT addresses for X86/X64 modules -bool efi_analysis::EfiAnalyserX86::findRuntimeServicesTables() { +bool efi_analysis::efi_analyser_x86_t::findRuntimeServicesTables() { // init architecture-specific constants auto RT_OFFSET = RT_OFFSET_64; uint16_t REG_SP = static_cast(REG_RSP); - if (arch == ArchFileType::X8632) { + if (m_arch == arch_file_type_t::x86_32) { RT_OFFSET = RT_OFFSET_32; REG_SP = static_cast(REG_ESP); } @@ -546,7 +533,7 @@ bool efi_analysis::EfiAnalyserX86::findRuntimeServicesTables() { uint16_t stRegister = 0; ea_t var_addr = BADADDR; // current global variable address while (ea <= s->end_ea) { - ea = next_head(ea, endAddress); + ea = next_head(ea, m_end_addr); decode_insn(&insn, ea); if (insn.itype == NN_mov && insn.ops[1].type == o_displ && insn.ops[1].phrase != REG_SP) { @@ -559,7 +546,7 @@ bool efi_analysis::EfiAnalyserX86::findRuntimeServicesTables() { // found RT_OFFSET, need to check 10 instructions below for (auto i = 0; i < 10; i++) { - ea = next_head(ea, endAddress); + ea = next_head(ea, m_end_addr); decode_insn(&insn, ea); if (insn.itype == NN_mov && insn.ops[0].type == o_reg && insn.ops[1].type == o_imm) { @@ -575,7 +562,6 @@ bool efi_analysis::EfiAnalyserX86::findRuntimeServicesTables() { next_insn.ops[1].reg == rtRegister) { baseInsnAddr = ea; if (!addr_in_vec(rt_list, var_addr)) { - set_cmt(ea, "EFI_RUNTIME_SERVICES *gRT", true); set_ptr_type_and_name(var_addr, "gRT", "EFI_RUNTIME_SERVICES"); rt_list.push_back(var_addr); @@ -590,7 +576,6 @@ bool efi_analysis::EfiAnalyserX86::findRuntimeServicesTables() { baseInsnAddr = ea; var_addr = insn.ops[0].addr; if (!addr_in_vec(rt_list, var_addr)) { - set_cmt(ea, "EFI_RUNTIME_SERVICES *gRT", true); set_ptr_type_and_name(var_addr, "gRT", "EFI_RUNTIME_SERVICES"); rt_list.push_back(var_addr); @@ -603,7 +588,6 @@ bool efi_analysis::EfiAnalyserX86::findRuntimeServicesTables() { stRegister != rtRegister) { var_addr = insn.ops[0].addr; if (!addr_in_tables(st_list, bs_list, rt_list, var_addr)) { - set_cmt(ea, "EFI_SYSTEM_TABLE *gST", true); set_ptr_type_and_name(insn.ops[0].addr, "gST", "EFI_SYSTEM_TABLE"); st_list.push_back(insn.ops[0].addr); @@ -620,13 +604,12 @@ bool efi_analysis::EfiAnalyserX86::findRuntimeServicesTables() { // check 8 instructions above baseInsnAddr auto addr = baseInsnAddr; for (auto i = 0; i < 8; i++) { - addr = prev_head(addr, startAddress); + addr = prev_head(addr, m_start_addr); decode_insn(&insn, addr); if (insn.itype == NN_mov && insn.ops[1].type == o_reg && insn.ops[1].reg == stRegister && insn.ops[0].type == o_mem) { if (!addr_in_tables(st_list, bs_list, rt_list, var_addr)) { - set_cmt(addr, "EFI_SYSTEM_TABLE *gST", true); set_ptr_type_and_name(var_addr, "gST", "EFI_SYSTEM_TABLE"); st_list.push_back(var_addr); } @@ -645,7 +628,7 @@ bool efi_analysis::EfiAnalyserX86::findRuntimeServicesTables() { //-------------------------------------------------------------------------- // Get all boot services by xrefs for X86/X64 modules -void efi_analysis::EfiAnalyserX86::getAllBootServices() { +void efi_analysis::efi_analyser_x86_t::getAllBootServices() { msg("[%s] BootServices finding (xrefs)\n", g_plugin_name); if (!bs_list.size()) { @@ -689,7 +672,7 @@ void efi_analysis::EfiAnalyserX86::getAllBootServices() { for (int j = 0; j < g_boot_services_table_all_count; j++) { // architecture-specific variables auto offset = g_boot_services_table_all[j].offset64; - if (arch == ArchFileType::X8632) { + if (m_arch == arch_file_type_t::x86_32) { offset = g_boot_services_table_all[j].offset32; } @@ -707,8 +690,8 @@ void efi_analysis::EfiAnalyserX86::getAllBootServices() { msg("[%s] 0x%016llX : %s\n", g_plugin_name, u64_addr(addr), static_cast(g_boot_services_table_all[j].name)); - bootServices[static_cast( - g_boot_services_table_all[j].name)] + m_boot_services[static_cast( + g_boot_services_table_all[j].name)] .push_back(addr); // add item to allBootServices @@ -725,8 +708,8 @@ void efi_analysis::EfiAnalyserX86::getAllBootServices() { get_arg_addrs(&args, addr); bsItem["args"] = args; - if (!json_in_vec(allServices, bsItem)) { - allServices.push_back(bsItem); + if (!json_in_vec(m_all_services, bsItem)) { + m_all_services.push_back(bsItem); } found = true; @@ -744,7 +727,7 @@ void efi_analysis::EfiAnalyserX86::getAllBootServices() { //-------------------------------------------------------------------------- // Get all runtime services for X86/X64 modules by xrefs -void efi_analysis::EfiAnalyserX86::getAllRuntimeServices() { +void efi_analysis::efi_analyser_x86_t::getAllRuntimeServices() { msg("[%s] RuntimeServices finding (xrefs)\n", g_plugin_name); if (!rt_list.size()) { @@ -788,15 +771,15 @@ void efi_analysis::EfiAnalyserX86::getAllRuntimeServices() { for (int j = 0; j < g_runtime_services_table_all_count; j++) { // architecture-specific variables auto offset = g_runtime_services_table_all[j].offset64; - if (arch == ArchFileType::X8632) { + if (m_arch == arch_file_type_t::x86_32) { offset = g_runtime_services_table_all[j].offset32; } if (service_offset == u32_addr(offset)) { op_stroff_util(addr, "EFI_RUNTIME_SERVICES"); msg("[%s] 0x%016llX : %s\n", g_plugin_name, u64_addr(addr), static_cast(g_runtime_services_table_all[j].name)); - runtimeServicesAll[static_cast( - g_runtime_services_table_all[j].name)] + m_runtime_services_all[static_cast( + g_runtime_services_table_all[j].name)] .push_back(addr); // add item to allRuntimeServices @@ -813,8 +796,8 @@ void efi_analysis::EfiAnalyserX86::getAllRuntimeServices() { get_arg_addrs(&args, addr); rtItem["args"] = args; - if (!json_in_vec(allServices, rtItem)) { - allServices.push_back(rtItem); + if (!json_in_vec(m_all_services, rtItem)) { + m_all_services.push_back(rtItem); } runtime_services_list.push_back(addr); break; @@ -828,7 +811,7 @@ void efi_analysis::EfiAnalyserX86::getAllRuntimeServices() { //-------------------------------------------------------------------------- // Get all smm services for X64 modules -void efi_analysis::EfiAnalyserX86::getAllSmmServicesX64() { +void efi_analysis::efi_analyser_x86_t::getAllSmmServicesX64() { msg("[%s] SmmServices finding (xrefs)\n", g_plugin_name); if (!smst_list.size()) { @@ -875,22 +858,19 @@ void efi_analysis::EfiAnalyserX86::getAllSmmServicesX64() { } } - std::string cmt = - "gSmst->" + - static_cast(g_smm_services_table_all[j].name); - set_cmt(addr, cmt.c_str(), true); op_stroff_util(addr, "_EFI_SMM_SYSTEM_TABLE2"); msg("[%s] 0x%016llX : %s\n", g_plugin_name, u64_addr(addr), static_cast(g_smm_services_table_all[j].name)); - // add address to smmServices[...] - if (find(protSmmNames.begin(), protSmmNames.end(), + // add address to m_smm_services[...] + if (find(m_prot_smms_names.begin(), m_prot_smms_names.end(), g_smm_services_table_all[j].name) != - protSmmNames.end()) { - smmServices[g_smm_services_table_all[j].name].push_back(addr); + m_prot_smms_names.end()) { + m_smm_services[g_smm_services_table_all[j].name].push_back( + addr); } - smmServicesAll[static_cast( - g_smm_services_table_all[j].name)] + m_smm_services_all[static_cast( + g_smm_services_table_all[j].name)] .push_back(addr); // add item to allSmmServices @@ -907,8 +887,8 @@ void efi_analysis::EfiAnalyserX86::getAllSmmServicesX64() { get_arg_addrs(&args, addr); smmsItem["args"] = args; - if (!json_in_vec(allServices, smmsItem)) { - allServices.push_back(smmsItem); + if (!json_in_vec(m_all_services, smmsItem)) { + m_all_services.push_back(smmsItem); } break; } @@ -924,13 +904,13 @@ void efi_analysis::EfiAnalyserX86::getAllSmmServicesX64() { // Currently should cover all PeiServices except EFI_PEI_COPY_MEM, // EFI_PEI_SET_MEM, EFI_PEI_RESET2_SYSTEM, and "Future Installed Services" // (EFI_PEI_FFS_FIND_BY_NAME, etc.) -void efi_analysis::EfiAnalyserX86::getAllPeiServicesX86() { +void efi_analysis::efi_analyser_x86_t::getAllPeiServicesX86() { msg("[%s] PeiServices finding from 0x%016llX to 0x%016llX (all)\n", - g_plugin_name, u64_addr(startAddress), u64_addr(endAddress)); - ea_t ea = startAddress; + g_plugin_name, u64_addr(m_start_addr), u64_addr(m_end_addr)); + ea_t ea = m_start_addr; insn_t insn; auto found = false; - while (ea <= endAddress) { + while (ea <= m_end_addr) { ea = next_head(ea, BADADDR); decode_insn(&insn, ea); if (insn.itype == NN_callni && @@ -945,7 +925,7 @@ void efi_analysis::EfiAnalyserX86::getAllPeiServicesX86() { // 15 instructions above for (auto j = 0; j < 15; j++) { - address = prev_head(address, startAddress); + address = prev_head(address, m_start_addr); decode_insn(&aboveInst, address); if (aboveInst.itype == NN_mov && aboveInst.ops[0].type == o_reg && aboveInst.ops[0].reg == insn.ops[0].reg && @@ -960,7 +940,7 @@ void efi_analysis::EfiAnalyserX86::getAllPeiServicesX86() { // 15 instructions above address = ea; for (auto j = 0; j < 15; j++) { - address = prev_head(address, startAddress); + address = prev_head(address, m_start_addr); decode_insn(&aboveInst, address); if (aboveInst.itype == NN_push) { if (aboveInst.ops[0].type == o_reg && @@ -981,8 +961,8 @@ void efi_analysis::EfiAnalyserX86::getAllPeiServicesX86() { op_stroff_util(ea, "EFI_PEI_SERVICES"); msg("[%s] 0x%016llX : %s\n", g_plugin_name, u64_addr(ea), static_cast(g_pei_services_table32[j].name)); - peiServicesAll[static_cast( - g_pei_services_table32[j].name)] + m_pei_services_all[static_cast( + g_pei_services_table32[j].name)] .push_back(ea); json psItem; psItem["address"] = ea; @@ -994,8 +974,8 @@ void efi_analysis::EfiAnalyserX86::getAllPeiServicesX86() { // add code addresses for arguments psItem["args"] = args; - if (!json_in_vec(allServices, psItem)) { - allServices.push_back(psItem); + if (!json_in_vec(m_all_services, psItem)) { + m_all_services.push_back(psItem); } } break; @@ -1007,13 +987,13 @@ void efi_analysis::EfiAnalyserX86::getAllPeiServicesX86() { //-------------------------------------------------------------------------- // Get all EFI_PEI_READ_ONLY_VARIABLE2_PPI (GetVariable, NextVariableName) -void efi_analysis::EfiAnalyserX86::getAllVariablePPICallsX86() { +void efi_analysis::efi_analyser_x86_t::getAllVariablePPICallsX86() { msg("[%s] Variable PPI calls finding from 0x%016llX to 0x%016llX (all)\n", - g_plugin_name, u64_addr(startAddress), u64_addr(endAddress)); - ea_t ea = startAddress; + g_plugin_name, u64_addr(m_start_addr), u64_addr(m_end_addr)); + ea_t ea = m_start_addr; insn_t insn; auto found = false; - while (ea <= endAddress) { + while (ea <= m_end_addr) { ea = next_head(ea, BADADDR); decode_insn(&insn, ea); if (insn.itype == NN_callni && insn.ops[0].type == o_phrase) { @@ -1026,7 +1006,7 @@ void efi_analysis::EfiAnalyserX86::getAllVariablePPICallsX86() { bool found_push = false; for (auto j = 0; j < 15; j++) { - address = prev_head(address, startAddress); + address = prev_head(address, m_start_addr); decode_insn(&aboveInst, address); if (aboveInst.itype == NN_push) { if (aboveInst.ops[0].type == o_reg && @@ -1044,7 +1024,7 @@ void efi_analysis::EfiAnalyserX86::getAllVariablePPICallsX86() { std::string ppi_call = "VariablePPI." + static_cast(g_variable_ppi_table_all[j].name); - ppiCallsAll[ppi_call].push_back(ea); + m_ppi_calls_all[ppi_call].push_back(ea); // Injecting PPI call as service json ppiItem; @@ -1059,8 +1039,8 @@ void efi_analysis::EfiAnalyserX86::getAllVariablePPICallsX86() { get_arg_addrs(&args, ea); ppiItem["args"] = args; - if (!json_in_vec(allServices, ppiItem)) { - allServices.push_back(ppiItem); + if (!json_in_vec(m_all_services, ppiItem)) { + m_all_services.push_back(ppiItem); } } break; @@ -1072,20 +1052,20 @@ void efi_analysis::EfiAnalyserX86::getAllVariablePPICallsX86() { //-------------------------------------------------------------------------- // Get PPI names for X86 PEI modules -void efi_analysis::EfiAnalyserX86::getPpiNamesX86() { +void efi_analysis::efi_analyser_x86_t::getPpiNamesX86() { msg("[%s] PPI finding (PEI services)\n", g_plugin_name); - ea_t start = startAddress; + ea_t start = m_start_addr; segment_t *seg_info = get_segm_by_name(".text"); if (seg_info != nullptr) { start = seg_info->start_ea; } for (int i = 0; i < g_pei_services_table32_count; i++) { if (g_pei_services_table32[i].push_number == PUSH_NONE || - !peiServicesAll.contains(g_pei_services_table_all[i].name)) { + !m_pei_services_all.contains(g_pei_services_table_all[i].name)) { continue; } - ea_list_t addrs = peiServicesAll[g_pei_services_table32[i].name]; + ea_list_t addrs = m_pei_services_all[g_pei_services_table32[i].name]; // for each PEI service for (auto ea : addrs) { @@ -1103,7 +1083,7 @@ void efi_analysis::EfiAnalyserX86::getPpiNamesX86() { // Check current basic block while (true) { - address = prev_head(address, startAddress); + address = prev_head(address, m_start_addr); decode_insn(&insn, address); if (insn.itype == NN_push) { @@ -1148,14 +1128,14 @@ void efi_analysis::EfiAnalyserX86::getPpiNamesX86() { ppiItem["module"] = "Current"; // find GUID name - auto it = dbProtocolsMap.find(guid); - if (it != dbProtocolsMap.end()) { + auto it = m_guiddb_map.find(guid); + if (it != m_guiddb_map.end()) { std::string name = it->second; ppiItem["ppi_name"] = name; // check if item already exists - if (!json_in_vec(allPPIs, ppiItem)) { - allPPIs.push_back(ppiItem); + if (!json_in_vec(m_all_ppis, ppiItem)) { + m_all_ppis.push_back(ppiItem); } continue; } @@ -1165,8 +1145,8 @@ void efi_analysis::EfiAnalyserX86::getPpiNamesX86() { ppiItem["ppi_name"] = "ProprietaryPpi"; // check if item already exists - if (!json_in_vec(allPPIs, ppiItem)) { - allPPIs.push_back(ppiItem); + if (!json_in_vec(m_all_ppis, ppiItem)) { + m_all_ppis.push_back(ppiItem); } continue; } @@ -1177,7 +1157,7 @@ void efi_analysis::EfiAnalyserX86::getPpiNamesX86() { //-------------------------------------------------------------------------- // Get boot services by protocols for X64 modules -void efi_analysis::EfiAnalyserX86::getProtBootServicesX64() { +void efi_analysis::efi_analyser_x86_t::getProtBootServicesX64() { insn_t insn; for (auto s : textSegments) { msg("[%s] BootServices finding from 0x%016llX to 0x%016llX (protocols)\n", @@ -1185,7 +1165,7 @@ void efi_analysis::EfiAnalyserX86::getProtBootServicesX64() { ea_t ea = s->start_ea; uint16_t bsRegister = 0; while (ea <= s->end_ea) { - ea = next_head(ea, endAddress); + ea = next_head(ea, m_end_addr); decode_insn(&insn, ea); if (insn.itype != NN_callni || insn.ops[0].reg != REG_RAX) { continue; @@ -1215,7 +1195,8 @@ void efi_analysis::EfiAnalyserX86::getProtBootServicesX64() { op_stroff_util(ea, "EFI_BOOT_SERVICES"); msg("[%s] 0x%016llX : %s\n", g_plugin_name, u64_addr(ea), static_cast(g_boot_services_table64[i].name)); - bootServices[static_cast(g_boot_services_table64[i].name)] + m_boot_services[static_cast( + g_boot_services_table64[i].name)] .push_back(ea); // add item to allBootServices @@ -1231,8 +1212,8 @@ void efi_analysis::EfiAnalyserX86::getProtBootServicesX64() { get_arg_addrs(&args, ea); bsItem["args"] = args; - if (!json_in_vec(allServices, bsItem)) { - allServices.push_back(bsItem); + if (!json_in_vec(m_all_services, bsItem)) { + m_all_services.push_back(bsItem); } break; } @@ -1242,14 +1223,14 @@ void efi_analysis::EfiAnalyserX86::getProtBootServicesX64() { //-------------------------------------------------------------------------- // Get boot services by protocols for X86 modules -void efi_analysis::EfiAnalyserX86::getProtBootServicesX86() { +void efi_analysis::efi_analyser_x86_t::getProtBootServicesX86() { msg("[%s] BootServices finding from 0x%016llX to 0x%016llX (protocols)\n", - g_plugin_name, u64_addr(startAddress), u64_addr(endAddress)); - ea_t ea = startAddress; + g_plugin_name, u64_addr(m_start_addr), u64_addr(m_end_addr)); + ea_t ea = m_start_addr; insn_t insn; uint16_t bsRegister = 0; - while (ea <= endAddress) { - ea = next_head(ea, endAddress); + while (ea <= m_end_addr) { + ea = next_head(ea, m_end_addr); decode_insn(&insn, ea); if (insn.itype == NN_callni && insn.ops[0].reg == REG_EAX) { for (auto i = 0; i < g_boot_services_table32_count; i++) { @@ -1257,8 +1238,8 @@ void efi_analysis::EfiAnalyserX86::getProtBootServicesX86() { op_stroff_util(ea, "EFI_BOOT_SERVICES"); msg("[%s] 0x%016llX : %s\n", g_plugin_name, u64_addr(ea), static_cast(g_boot_services_table32[i].name)); - bootServices[static_cast( - g_boot_services_table32[i].name)] + m_boot_services[static_cast( + g_boot_services_table32[i].name)] .push_back(ea); // add item to allBootServices @@ -1274,8 +1255,8 @@ void efi_analysis::EfiAnalyserX86::getProtBootServicesX86() { get_arg_addrs(&args, ea); bsItem["args"] = args; - if (!json_in_vec(allServices, bsItem)) { - allServices.push_back(bsItem); + if (!json_in_vec(m_all_services, bsItem)) { + m_all_services.push_back(bsItem); } break; } @@ -1286,9 +1267,9 @@ void efi_analysis::EfiAnalyserX86::getProtBootServicesX86() { //-------------------------------------------------------------------------- // find other addresses of gBS variables for X86-64 modules -void efi_analysis::EfiAnalyserX86::findOtherBsTablesX64() { +void efi_analysis::efi_analyser_x86_t::findOtherBsTablesX64() { msg("[%s] find other addresses of gBS variables\n", g_plugin_name); - for (auto s : allServices) { + for (auto s : m_all_services) { std::string table_name = s["table_name"]; if (table_name.compare("EFI_BOOT_SERVICES")) { continue; @@ -1314,49 +1295,50 @@ void efi_analysis::EfiAnalyserX86::findOtherBsTablesX64() { } } -bool efi_analysis::EfiAnalyser::AddProtocol(std::string serviceName, - ea_t guidAddress, ea_t xrefAddress, - ea_t call_address) { - if (arch != ArchFileType::Uefi && guidAddress >= startAddress && - guidAddress <= endAddress) { +bool efi_analysis::efi_analyser_t::add_protocol(std::string service_name, + ea_t guid_addr, ea_t xref_addr, + ea_t call_addr) { + if (m_arch != arch_file_type_t::uefi && guid_addr >= m_start_addr && + guid_addr <= m_end_addr) { msg("[%s] wrong service call detection: 0x%016llX\n", g_plugin_name, - u64_addr(call_address)); + u64_addr(call_addr)); return false; // filter FP } json protocol; - auto guid = get_guid_by_address(guidAddress); - protocol["address"] = guidAddress; - protocol["xref"] = xrefAddress; - protocol["service"] = serviceName; + auto guid = get_guid_by_address(guid_addr); + protocol["address"] = guid_addr; + protocol["xref"] = xref_addr; + protocol["service"] = service_name; protocol["guid"] = guid_to_string(guid); - protocol["ea"] = call_address; + protocol["ea"] = call_addr; qstring moduleName("Current"); - if (input_file_type() == ArchFileType::Uefi) { - moduleName = get_module_name_loader(call_address); + if (input_file_type() == arch_file_type_t::uefi) { + moduleName = get_module_name_loader(call_addr); } protocol["module"] = static_cast(moduleName.c_str()); // find GUID name - auto it = dbProtocolsMap.find(guid); - if (it != dbProtocolsMap.end()) { + auto it = m_guiddb_map.find(guid); + if (it != m_guiddb_map.end()) { std::string name = it->second; protocol["prot_name"] = name; } else { protocol["prot_name"] = "UNKNOWN_PROTOCOL_GUID"; - set_type_and_name(guidAddress, "UNKNOWN_PROTOCOL_GUID", "EFI_GUID"); + set_type_and_name(guid_addr, "UNKNOWN_PROTOCOL_GUID", "EFI_GUID"); } - if (!json_in_vec(allProtocols, protocol)) { - allProtocols.push_back(protocol); + if (!json_in_vec(m_all_protocols, protocol)) { + m_all_protocols.push_back(protocol); } return true; } //-------------------------------------------------------------------------- // Extract protocols from InstallMultipleProtocolInterfaces service call -bool efi_analysis::EfiAnalyserX86::InstallMultipleProtocolInterfacesHandler() { - ea_list_t addrs = bootServices["InstallMultipleProtocolInterfaces"]; +bool efi_analysis::efi_analyser_x86_t:: + InstallMultipleProtocolInterfacesHandler() { + ea_list_t addrs = m_boot_services["InstallMultipleProtocolInterfaces"]; std::map stack_params; insn_t insn; @@ -1369,7 +1351,7 @@ bool efi_analysis::EfiAnalyserX86::InstallMultipleProtocolInterfacesHandler() { // Check current basic block while (true) { - address = prev_head(address, startAddress); + address = prev_head(address, m_start_addr); decode_insn(&insn, address); if (!check_stack && found) { @@ -1415,8 +1397,8 @@ bool efi_analysis::EfiAnalyserX86::InstallMultipleProtocolInterfacesHandler() { switch (insn.ops[0].reg) { case REG_RDX: case REG_R9: - AddProtocol("InstallMultipleProtocolInterfaces", insn.ops[1].addr, - address, ea); + add_protocol("InstallMultipleProtocolInterfaces", insn.ops[1].addr, + address, ea); found = true; break; case REG_RAX: @@ -1430,8 +1412,8 @@ bool efi_analysis::EfiAnalyserX86::InstallMultipleProtocolInterfacesHandler() { auto index = 0; for (auto const ¶m : stack_params) { if (index++ % 2) { - AddProtocol("InstallMultipleProtocolInterfaces", param.second, - param.first, ea); + add_protocol("InstallMultipleProtocolInterfaces", param.second, + param.first, ea); } } } @@ -1441,7 +1423,7 @@ bool efi_analysis::EfiAnalyserX86::InstallMultipleProtocolInterfacesHandler() { //-------------------------------------------------------------------------- // Get boot services protocols names for X64 modules -void efi_analysis::EfiAnalyserX86::getBsProtNamesX64() { +void efi_analysis::efi_analyser_x86_t::getBsProtNamesX64() { if (!textSegments.size()) { return; } @@ -1458,7 +1440,7 @@ void efi_analysis::EfiAnalyserX86::getBsProtNamesX64() { continue; } - ea_list_t addrs = bootServices[g_boot_services_table64[i].name]; + ea_list_t addrs = m_boot_services[g_boot_services_table64[i].name]; for (auto ea : addrs) { ea_t address = ea; msg("[%s] looking for protocols in the 0x%016llX area\n", g_plugin_name, @@ -1470,7 +1452,7 @@ void efi_analysis::EfiAnalyserX86::getBsProtNamesX64() { // check current basic block while (true) { - address = prev_head(address, startAddress); + address = prev_head(address, m_start_addr); decode_insn(&insn, address); // exit from loop if end of previous basic block found @@ -1512,8 +1494,8 @@ void efi_analysis::EfiAnalyserX86::getBsProtNamesX64() { continue; } - AddProtocol(g_boot_services_table64[i].name, guidDataAddress, - guidCodeAddress, ea); + add_protocol(g_boot_services_table64[i].name, guidDataAddress, + guidCodeAddress, ea); } } } @@ -1521,15 +1503,15 @@ void efi_analysis::EfiAnalyserX86::getBsProtNamesX64() { //-------------------------------------------------------------------------- // Get boot services protocols names for X86 modules -void efi_analysis::EfiAnalyserX86::getBsProtNamesX86() { +void efi_analysis::efi_analyser_x86_t::getBsProtNamesX86() { msg("[%s] protocols finding (boot services)\n", g_plugin_name); - ea_t start = startAddress; + ea_t start = m_start_addr; segment_t *seg_info = get_segm_by_name(".text"); if (seg_info != nullptr) { start = seg_info->start_ea; } for (int i = 0; i < g_boot_services_table32_count; i++) { - ea_list_t addrs = bootServices[g_boot_services_table32[i].name]; + ea_list_t addrs = m_boot_services[g_boot_services_table32[i].name]; // for each boot service for (auto ea : addrs) { @@ -1550,7 +1532,7 @@ void efi_analysis::EfiAnalyserX86::getBsProtNamesX86() { // check current basic block uint16_t pushCounter = 0; while (true) { - address = prev_head(address, startAddress); + address = prev_head(address, m_start_addr); decode_insn(&insn, address); // exit from loop if end of previous basic block found @@ -1585,8 +1567,8 @@ void efi_analysis::EfiAnalyserX86::getBsProtNamesX86() { continue; } - AddProtocol(g_boot_services_table32[i].name, guidDataAddress, - guidCodeAddress, ea); + add_protocol(g_boot_services_table32[i].name, guidDataAddress, + guidCodeAddress, ea); } } } @@ -1594,7 +1576,7 @@ void efi_analysis::EfiAnalyserX86::getBsProtNamesX86() { //-------------------------------------------------------------------------- // Get smm services protocols names for X64 modules -void efi_analysis::EfiAnalyserX86::getSmmProtNamesX64() { +void efi_analysis::efi_analyser_x86_t::getSmmProtNamesX64() { if (!textSegments.size()) { return; } @@ -1603,7 +1585,7 @@ void efi_analysis::EfiAnalyserX86::getSmmProtNamesX64() { msg("[%s] protocols finding (smm services, start address = 0x%016llX)\n", g_plugin_name, u64_addr(start)); for (int i = 0; i < g_smm_services_prot64_count; i++) { - auto addrs = smmServices[g_smm_services_prot64[i].name]; + auto addrs = m_smm_services[g_smm_services_prot64[i].name]; // for each SMM service for (auto ea : addrs) { @@ -1617,7 +1599,7 @@ void efi_analysis::EfiAnalyserX86::getSmmProtNamesX64() { // check current basic block while (true) { - address = prev_head(address, startAddress); + address = prev_head(address, m_start_addr); decode_insn(&insn, address); // exit from loop if end of previous basic block found @@ -1647,8 +1629,8 @@ void efi_analysis::EfiAnalyserX86::getSmmProtNamesX64() { continue; } - AddProtocol(g_smm_services_prot64[i].name, guidDataAddress, - guidCodeAddress, ea); + add_protocol(g_smm_services_prot64[i].name, guidDataAddress, + guidCodeAddress, ea); } } } @@ -1656,16 +1638,17 @@ void efi_analysis::EfiAnalyserX86::getSmmProtNamesX64() { //-------------------------------------------------------------------------- // Mark protocols -void efi_analysis::EfiAnalyser::markInterfaces() { - msg("[%s] %s marking\n", g_plugin_name, if_pl.c_str()); - for (auto ifItemIt = if_tbl->begin(); ifItemIt != if_tbl->end(); ++ifItemIt) { +void efi_analysis::efi_analyser_t::mark_interfaces() { + msg("[%s] %s marking\n", g_plugin_name, m_pname.c_str()); + for (auto ifItemIt = m_ptable->begin(); ifItemIt != m_ptable->end(); + ++ifItemIt) { json ifItem = *ifItemIt; ea_t address = static_cast(ifItem["address"]); // check if guid on this address already marked bool marked = false; - for (auto markedAddress = markedInterfaces.begin(); - markedAddress != markedInterfaces.end(); ++markedAddress) { + for (auto markedAddress = m_marked_interfaces.begin(); + markedAddress != m_marked_interfaces.end(); ++markedAddress) { if (*markedAddress == address) { marked = true; break; @@ -1673,11 +1656,11 @@ void efi_analysis::EfiAnalyser::markInterfaces() { } if (!marked) { - std::string svcName = static_cast(ifItem[if_key]); + std::string svcName = static_cast(ifItem[m_pkey]); set_name(address, svcName.c_str(), SN_FORCE); set_guid_type(address); std::string comment = "EFI_GUID " + svcName; - markedInterfaces.push_back(address); + m_marked_interfaces.push_back(address); msg("[%s] address: 0x%016llX, comment: %s\n", g_plugin_name, u64_addr(address), comment.c_str()); } @@ -1686,7 +1669,7 @@ void efi_analysis::EfiAnalyser::markInterfaces() { //-------------------------------------------------------------------------- // Mark GUIDs found in the .text and .data segment -void efi_analysis::EfiAnalyser::markDataGuids() { +void efi_analysis::efi_analyser_t::mark_data_guids() { ea_t ptrSize = inf_is_64bit() ? 8 : 4; auto guids_segments = textSegments; // find GUIDs in .text and .data segments @@ -1707,8 +1690,8 @@ void efi_analysis::EfiAnalyser::markDataGuids() { auto guid = get_guid_by_address(ea); // find GUID name - auto it = dbProtocolsMap.find(guid); - if (it != dbProtocolsMap.end()) { + auto it = m_guiddb_map.find(guid); + if (it != m_guiddb_map.end()) { std::string guidName = it->second; set_name(ea, guidName.c_str(), SN_FORCE); set_guid_type(ea); @@ -1727,7 +1710,7 @@ void efi_analysis::EfiAnalyser::markDataGuids() { continue; } uint64_t flags = static_cast(get_wide_dword(ppiEa)); - if (!uint64_in_vec(ppiFlags, flags)) { + if (!uint64_in_vec(m_ppi_flags, flags)) { continue; } msg("[%s] address: 0x%016llX, PPI: %s\n", g_plugin_name, @@ -1744,7 +1727,7 @@ void efi_analysis::EfiAnalyser::markDataGuids() { guid_item["address"] = ea; guid_item["name"] = guidName; guid_item["guid"] = guid_to_string(guid); - allGuids.push_back(guid_item); + m_all_guids.push_back(guid_item); dataGuids.push_back(guid_item); } ea += 1; @@ -1754,7 +1737,7 @@ void efi_analysis::EfiAnalyser::markDataGuids() { //-------------------------------------------------------------------------- // Mark GUIDs found in local variables for X64 modules -void efi_analysis::EfiAnalyserX86::markLocalGuidsX64() { +void efi_analysis::efi_analyser_x86_t::markLocalGuidsX64() { for (auto seg : textSegments) { segment_t *s = seg; ea_t ea = s->start_ea; @@ -1796,7 +1779,7 @@ void efi_analysis::EfiAnalyserX86::markLocalGuidsX64() { // found guid->Data1 and guid->Data2 values, try to get // guid name - for (auto dbItem = dbProtocols.begin(); dbItem != dbProtocols.end(); + for (auto dbItem = m_guiddb.begin(); dbItem != m_guiddb.end(); ++dbItem) { auto guid = dbItem.value(); if (data1 == static_cast(guid[0]) && @@ -1805,13 +1788,12 @@ void efi_analysis::EfiAnalyserX86::markLocalGuidsX64() { std::string comment = "EFI_GUID " + dbItem.key(); msg("[%s] address: 0x%016llX, comment: %s\n", g_plugin_name, u64_addr(ea), comment.c_str()); - set_cmt(ea, comment.c_str(), true); json guid_item; guid_item["address"] = ea; guid_item["name"] = dbItem.key(); guid_item["guid"] = guid_to_string(guid); - allGuids.push_back(guid_item); + m_all_guids.push_back(guid_item); stackGuids.push_back(guid_item); exit = true; break; @@ -1932,49 +1914,49 @@ void findCalloutRec(func_t *func) { } //-------------------------------------------------------------------------- -// Find SmiHandler function inside SMM drivers -void efi_analysis::EfiAnalyser::findSwSmiHandlers() { +// find SmiHandler functions in SMM modules +void efi_analysis::efi_analyser_t::find_smi_handlers() { std::map types = { - {&sw_guid2, "Sw"}, - {&sw_guid, "Sw"}, - {&sx_guid2, "Sx"}, - {&sx_guid, "Sx"}, - {&io_trap_guid2, "IoTrap"}, - {&io_trap_guid, "IoTrap"}, - {&gpi_guid2, "Gpi"}, - {&gpi_guid, "Gpi"}, - {&usb_guid2, "Usb"}, - {&usb_guid, "Usb"}, - {&standby_button_guid2, "StandbyButton"}, - {&standby_button_guid, "StandbyButton"}, - {&periodic_timer_guid2, "PeriodicTimer"}, - {&periodic_timer_guid, "PeriodicTimer"}, - {&power_button_guid2, "PowerButton"}, - {&power_button_guid, "PowerButton"}, - {&ichn_guid, "Ichn"}, - {&ichn_guid2, "Ichn"}, - {&tco_guid, "Tco"}, - {&pcie_guid, "Pcie"}, - {&acpi_guid, "Acpi"}, - {&gpio_unlock_guid, "GpioUnlock"}, - {&pch_guid, "Pch"}, - {&espi_guid, "Espi"}, - {&acpi_en_guid, "AcpiEn"}, - {&acpi_dis_guid, "AcpiDis"}, - {&fch_gpi_guid2, "Gpi"}, - {&fch_io_trap_guid2, "IoTrap"}, - {&fch_periodical_guid2, "PeriodicTimer"}, - {&fch_pwr_btn_guid2, "PowerButton"}, - {&fch_sw_guid2, "Sw"}, - {&fch_sx_guid2, "Sx"}, - {&fch_usb_guid2, "Usb"}, - {&fch_usb_guid, "Usb"}, - {&fch_misc_guid, "Misc"}, - {&fch_apu_ras_guid, "ApuRas"}, + {&m_sw_guid2, "Sw"}, + {&m_sw_guid, "Sw"}, + {&m_sx_guid2, "Sx"}, + {&m_sx_guid, "Sx"}, + {&m_io_trap_guid2, "IoTrap"}, + {&m_io_trap_guid, "IoTrap"}, + {&m_gpi_guid2, "Gpi"}, + {&m_gpi_guid, "Gpi"}, + {&m_usb_guid2, "Usb"}, + {&m_usb_guid, "Usb"}, + {&m_standby_button_guid2, "StandbyButton"}, + {&m_standby_button_guid, "StandbyButton"}, + {&m_periodic_timer_guid2, "PeriodicTimer"}, + {&m_periodic_timer_guid, "PeriodicTimer"}, + {&m_power_button_guid2, "PowerButton"}, + {&m_power_button_guid, "PowerButton"}, + {&m_ichn_guid, "Ichn"}, + {&m_ichn_guid2, "Ichn"}, + {&m_tco_guid, "Tco"}, + {&m_pcie_guid, "Pcie"}, + {&m_acpi_guid, "Acpi"}, + {&m_gpio_unlock_guid, "GpioUnlock"}, + {&m_pch_guid, "Pch"}, + {&m_espi_guid, "Espi"}, + {&m_acpi_en_guid, "AcpiEn"}, + {&m_acpi_dis_guid, "AcpiDis"}, + {&m_fch_gpi_guid2, "Gpi"}, + {&m_fch_io_trap_guid2, "IoTrap"}, + {&m_fch_periodical_guid2, "PeriodicTimer"}, + {&m_fch_pwr_btn_guid2, "PowerButton"}, + {&m_fch_sw_guid2, "Sw"}, + {&m_fch_sx_guid2, "Sx"}, + {&m_fch_usb_guid2, "Usb"}, + {&m_fch_usb_guid, "Usb"}, + {&m_fch_misc_guid, "Misc"}, + {&m_fch_apu_ras_guid, "ApuRas"}, }; for (auto &[guid, prefix] : types) { auto res = findSmiHandlersSmmDispatch(*guid, prefix); - smiHandlers.insert(smiHandlers.end(), res.begin(), res.end()); + m_smi_handlers.insert(m_smi_handlers.end(), res.begin(), res.end()); } } @@ -1982,16 +1964,16 @@ void efi_analysis::EfiAnalyser::findSwSmiHandlers() { // Find callouts inside SwSmiHandler function: // * find SwSmiHandler function // * find gBS->service_name and gRT->service_name inside SmiHandler function -bool efi_analysis::EfiAnalyser::findSmmCallout() { +bool efi_analysis::efi_analyser_t::find_smm_callout() { msg("[%s] Looking for SMM callout\n", g_plugin_name); if (!bs_list.size() && !rt_list.size()) { return false; } - if (!smiHandlers.size() && !childSmiHandlers.size()) { + if (!m_smi_handlers.size() && !childSmiHandlers.size()) { msg("[%s] can't find a SwSmiHandler functions\n", g_plugin_name); return false; } - for (auto func : smiHandlers) { + for (auto func : m_smi_handlers) { findCalloutRec(func); } for (auto func : childSmiHandlers) { @@ -2000,13 +1982,13 @@ bool efi_analysis::EfiAnalyser::findSmmCallout() { return true; } -bool efi_analysis::EfiAnalyser::findPPIGetVariableStackOveflow() { +bool efi_analysis::efi_analyser_t::find_double_get_variable_pei() { msg("[%s] Looking for PPI GetVariable buffer overflow, " - "allServices.size() = %lu\n", - g_plugin_name, allServices.size()); + "m_all_services.size() = %lu\n", + g_plugin_name, m_all_services.size()); ea_list_t getVariableServicesCalls; std::string getVariableStr("VariablePPI.GetVariable"); - for (auto j_service : allServices) { + for (auto j_service : m_all_services) { json service = j_service; std::string service_name = static_cast(service["service_name"]); @@ -2016,7 +1998,7 @@ bool efi_analysis::EfiAnalyser::findPPIGetVariableStackOveflow() { getVariableServicesCalls.push_back(addr); } } - msg("[%s] Finished iterating over allServices, " + msg("[%s] Finished iterating over m_all_services, " "getVariableServicesCalls.size() = " "%lu\n", g_plugin_name, getVariableServicesCalls.size()); @@ -2057,7 +2039,7 @@ bool efi_analysis::EfiAnalyser::findPPIGetVariableStackOveflow() { bool datasize_addr_found = false; ea_t address = curr_addr; for (auto j = 0; j < 15; j++) { - address = prev_head(address, startAddress); + address = prev_head(address, m_start_addr); decode_insn(&insn, address); if (insn.itype == NN_push) { pushCounter += 1; @@ -2082,7 +2064,7 @@ bool efi_analysis::EfiAnalyser::findPPIGetVariableStackOveflow() { } for (auto j = 0; j < 15; j++) { - address = prev_head(address, startAddress); + address = prev_head(address, m_start_addr); decode_insn(&insn, address); if (insn.itype == NN_lea && insn.ops[0].type == o_reg && insn.ops[0].reg == arg5_reg && insn.ops[1].type == o_displ) { @@ -2111,7 +2093,7 @@ bool efi_analysis::EfiAnalyser::findPPIGetVariableStackOveflow() { datasize_addr_found = false; address = prev_addr; for (auto j = 0; j < 15; j++) { - address = prev_head(address, startAddress); + address = prev_head(address, m_start_addr); decode_insn(&insn, address); if (insn.itype == NN_push) { pushCounter += 1; @@ -2136,7 +2118,7 @@ bool efi_analysis::EfiAnalyser::findPPIGetVariableStackOveflow() { } for (auto j = 0; j < 15; j++) { - address = prev_head(address, startAddress); + address = prev_head(address, m_start_addr); decode_insn(&insn, address); if (insn.itype == NN_lea && insn.ops[0].type == o_reg && insn.ops[0].reg == arg5_reg && insn.ops[1].type == o_displ) { @@ -2171,12 +2153,12 @@ bool efi_analysis::EfiAnalyser::findPPIGetVariableStackOveflow() { //-------------------------------------------------------------------------- // Find potential stack/heap overflow with double GetVariable calls -bool efi_analysis::EfiAnalyser::findGetVariableOveflow( - json_list_t allServices) { +bool efi_analysis::efi_analyser_t::find_double_get_variable( + json_list_t m_all_services) { msg("[%s] Looking for GetVariable stack/heap overflow\n", g_plugin_name); ea_list_t getVariableServicesCalls; std::string getVariableStr("GetVariable"); - for (auto j_service : allServices) { + for (auto j_service : m_all_services) { json service = j_service; std::string service_name = static_cast(service["service_name"]); @@ -2305,10 +2287,10 @@ bool efi_analysis::EfiAnalyser::findGetVariableOveflow( //-------------------------------------------------------------------------- // Find potential stack/heap overflow with double SmmGetVariable calls -bool efi_analysis::EfiAnalyser::findSmmGetVariableOveflow() { +bool efi_analysis::efi_analyser_t::find_double_get_variable_smm() { msg("[%s] Looking for SmmGetVariable stack/heap overflow\n", g_plugin_name); ea_list_t smmGetVariableCalls = - findSmmGetVariableCalls(dataSegments, &allServices); + findSmmGetVariableCalls(dataSegments, &m_all_services); sort(smmGetVariableCalls.begin(), smmGetVariableCalls.end()); if (smmGetVariableCalls.size() < 2) { msg("[%s] less than 2 GetVariable calls found\n", g_plugin_name); @@ -2385,7 +2367,7 @@ bool efi_analysis::EfiAnalyser::findSmmGetVariableOveflow() { return (smmGetVariableOverflow.size() > 0); } -bool efi_analysis::EfiAnalyser::AnalyseVariableService( +bool efi_analysis::efi_analyser_t::analyse_variable_service( ea_t ea, std::string service_str) { msg("[%s] %s call: 0x%016llX\n", g_plugin_name, service_str.c_str(), u64_addr(ea)); @@ -2502,18 +2484,18 @@ bool efi_analysis::EfiAnalyser::AnalyseVariableService( if (name_found && guid_found) { // if only name or only GUID found, it will // now saved (check the logs) item["service"] = service_str; - nvramVariables.push_back(item); + m_nvram_variables.push_back(item); } return true; } -bool efi_analysis::EfiAnalyser::analyseNvramVariables() { +bool efi_analysis::efi_analyser_t::analyse_nvram_variables() { msg("[%s] Get NVRAM variables information\n", g_plugin_name); string_list_t nvram_services = {"GetVariable", "SetVariable"}; for (auto service_str : nvram_services) { ea_list_t var_services; - for (auto j_service : allServices) { + for (auto j_service : m_all_services) { json service = j_service; std::string service_name = static_cast(service["service_name"]); @@ -2524,15 +2506,15 @@ bool efi_analysis::EfiAnalyser::analyseNvramVariables() { } sort(var_services.begin(), var_services.end()); for (auto ea : var_services) { - AnalyseVariableService(ea, service_str); + analyse_variable_service(ea, service_str); } for (auto ea : g_smm_get_variable_calls) { - AnalyseVariableService(ea, "EFI_SMM_VARIABLE_PROTOCOL::SmmGetVariable"); + analyse_variable_service(ea, "EFI_SMM_VARIABLE_PROTOCOL::SmmGetVariable"); } for (auto ea : g_smm_set_variable_calls) { - AnalyseVariableService(ea, "EFI_SMM_VARIABLE_PROTOCOL::SmmSetVariable"); + analyse_variable_service(ea, "EFI_SMM_VARIABLE_PROTOCOL::SmmSetVariable"); } } return true; @@ -2540,15 +2522,15 @@ bool efi_analysis::EfiAnalyser::analyseNvramVariables() { //-------------------------------------------------------------------------- // Resolve EFI_SMM_CPU_PROTOCOL -bool efi_analysis::EfiAnalyser::efiSmmCpuProtocolResolver() { +bool efi_analysis::efi_analyser_t::smm_cpu_protocol_resolver() { readSaveStateCalls = - resolveEfiSmmCpuProtocol(stackGuids, dataGuids, &allServices); + resolveEfiSmmCpuProtocol(stackGuids, dataGuids, &m_all_services); return true; } //-------------------------------------------------------------------------- // Dump all info to JSON file -void efi_analysis::EfiAnalyser::dumpInfo() { +void efi_analysis::efi_analyser_t::dump_json() { json info; if (st_list.size()) { info["st_list"] = st_list; @@ -2565,20 +2547,20 @@ void efi_analysis::EfiAnalyser::dumpInfo() { if (image_handle_list.size()) { info["image_handle_list"] = image_handle_list; } - if (allPPIs.size()) { - info["allPPIs"] = allPPIs; + if (m_all_ppis.size()) { + info["all_ppis"] = m_all_ppis; } - if (allProtocols.size()) { - info["allProtocols"] = allProtocols; + if (m_all_protocols.size()) { + info["all_protocols"] = m_all_protocols; } - if (allServices.size()) { - info["allServices"] = allServices; + if (m_all_services.size()) { + info["all_services"] = m_all_services; } - if (allGuids.size()) { - info["allGuids"] = allGuids; + if (m_all_guids.size()) { + info["all_guids"] = m_all_guids; } - if (nvramVariables.size()) { - info["nvramVariables"] = nvramVariables; + if (m_nvram_variables.size()) { + info["m_nvram_variables"] = m_nvram_variables; } if (readSaveStateCalls.size()) { info["readSaveStateCalls"] = readSaveStateCalls; @@ -2596,13 +2578,13 @@ void efi_analysis::EfiAnalyser::dumpInfo() { info["vulns"]["smm_get_variable_buffer_overflow"] = smmGetVariableOverflow; } - json_list_t smiHandlersAddrs; - if (smiHandlers.size() > 0) { - for (auto f : smiHandlers) { + json_list_t m_smi_handlersAddrs; + if (m_smi_handlers.size() > 0) { + for (auto f : m_smi_handlers) { func_t *func = f; - smiHandlersAddrs.push_back(func->start_ea); + m_smi_handlersAddrs.push_back(func->start_ea); } - info["smiHandlersAddrs"] = smiHandlersAddrs; + info["m_smi_handlersAddrs"] = m_smi_handlersAddrs; } std::string idbPath; @@ -2617,39 +2599,39 @@ void efi_analysis::EfiAnalyser::dumpInfo() { //-------------------------------------------------------------------------- // Show all non-empty choosers windows -void showAllChoosers(efi_analysis::EfiAnalyserX86 analyser) { +void showAllChoosers(efi_analysis::efi_analyser_x86_t analyser) { qstring title; // open window with all services - if (analyser.allServices.size()) { + if (analyser.m_all_services.size()) { title = "efiXplorer: services"; - services_show(analyser.allServices, title); + services_show(analyser.m_all_services, title); } // open window with protocols - if (analyser.file_type == FfsFileType::Pei) { - if (analyser.allPPIs.size()) { + if (analyser.m_ftype == ffs_file_type_t::pei) { + if (analyser.m_all_ppis.size()) { title = "efiXplorer: PPIs"; - ppis_show(analyser.allPPIs, title); + ppis_show(analyser.m_all_ppis, title); } - } else { // FfsFileType::DxeAndTheLike - if (analyser.allProtocols.size()) { + } else { // ffs_file_type_t::dxe_smm + if (analyser.m_all_protocols.size()) { title = "efiXplorer: protocols"; - protocols_show(analyser.allProtocols, title); + protocols_show(analyser.m_all_protocols, title); } } // open window with data guids - if (analyser.allGuids.size()) { + if (analyser.m_all_guids.size()) { qstring title = "efiXplorer: GUIDs"; - guids_show(analyser.allGuids, title); + guids_show(analyser.m_all_guids, title); } // open window with NVRAM variables - if (analyser.nvramVariables.size()) { + if (analyser.m_nvram_variables.size()) { qstring title = "efiXplorer: NVRAM"; - nvram_show(analyser.nvramVariables, title); + nvram_show(analyser.m_nvram_variables, title); } // open window with vulnerabilities @@ -2679,18 +2661,18 @@ void showAllChoosers(efi_analysis::EfiAnalyserX86 analyser) { bool efi_analysis::efiAnalyserMainX64() { show_wait_box("HIDECANCEL\nAnalysing module(s) with efiXplorer..."); - efi_analysis::EfiAnalyserX86 analyser; + efi_analysis::efi_analyser_x86_t analyser; while (!auto_is_ok()) { auto_wait(); } // find .text and .data segments - analyser.getSegments(); + analyser.get_segments(); // analyse all auto res = ASKBTN_NO; - if (analyser.arch == ArchFileType::Uefi) { + if (analyser.m_arch == arch_file_type_t::uefi) { res = ask_yn(1, "Want to further analyse all drivers with auto_mark_range?"); } @@ -2704,21 +2686,21 @@ bool efi_analysis::efiAnalyserMainX64() { } // mark GUIDs - analyser.markDataGuids(); + analyser.mark_data_guids(); analyser.markLocalGuidsX64(); if (g_args.disable_ui) { - analyser.file_type = g_args.module_type == ModuleType::Pei - ? analyser.file_type = FfsFileType::Pei - : analyser.file_type = FfsFileType::DxeAndTheLike; + analyser.m_ftype = g_args.module_type == module_type_t::pei + ? analyser.m_ftype = ffs_file_type_t::pei + : analyser.m_ftype = ffs_file_type_t::dxe_smm; } else { - analyser.file_type = ask_file_type(&analyser.allGuids); + analyser.m_ftype = ask_file_type(&analyser.m_all_guids); } - analyser.setStrings(); + analyser.set_pvalues(); // find global vars for gImageHandle, gST, gBS, gRT, gSmst - if (analyser.file_type == FfsFileType::DxeAndTheLike) { + if (analyser.m_ftype == ffs_file_type_t::dxe_smm) { analyser.findImageHandleX64(); analyser.findSystemTableX64(); analyser.findBootServicesTables(); @@ -2735,7 +2717,7 @@ bool efi_analysis::efiAnalyserMainX64() { analyser.getBsProtNamesX64(); #ifdef HEX_RAYS - apply_all_types_for_interfaces(analyser.allProtocols); + apply_all_types_for_interfaces(analyser.m_all_protocols); analyser.findSmstPostProcX64(); #endif @@ -2744,7 +2726,7 @@ bool efi_analysis::efiAnalyserMainX64() { analyser.getSmmProtNamesX64(); // mark protocols - analyser.markInterfaces(); + analyser.mark_interfaces(); // search for copies of global variables mark_copies_for_gvars(smst_list, "gSmst"); @@ -2754,22 +2736,22 @@ bool efi_analysis::efiAnalyserMainX64() { // search for vulnerabilities if (!g_args.disable_vuln_hunt) { // find potential SMM callouts - analyser.findSwSmiHandlers(); - analyser.findSmmCallout(); + analyser.find_smi_handlers(); + analyser.find_smm_callout(); // find potential OOB RW with GetVariable function - analyser.findGetVariableOveflow(analyser.allServices); + analyser.find_double_get_variable(analyser.m_all_services); // find potential OOB RW with SmmGetVariable function - analyser.findSmmGetVariableOveflow(); - analyser.efiSmmCpuProtocolResolver(); + analyser.find_double_get_variable_smm(); + analyser.smm_cpu_protocol_resolver(); } #ifdef HEX_RAYS - apply_all_types_for_interfaces_smm(analyser.allProtocols); + apply_all_types_for_interfaces_smm(analyser.m_all_protocols); #endif - analyser.analyseNvramVariables(); + analyser.analyse_nvram_variables(); } else { msg("[%s] Parsing of 64-bit PEI files is not supported yet\n", @@ -2777,17 +2759,17 @@ bool efi_analysis::efiAnalyserMainX64() { } // dump info to JSON file - analyser.dumpInfo(); + analyser.dump_json(); // show all choosers windows if (!g_args.disable_ui) { showAllChoosers(analyser); } - if (analyser.arch == ArchFileType::Uefi) { + if (analyser.m_arch == arch_file_type_t::uefi) { // Init public EdiDependencies members - g_deps.getProtocolsChooser(analyser.allProtocols); - g_deps.getProtocolsByGuids(analyser.allProtocols); + g_deps.getProtocolsChooser(analyser.m_all_protocols); + g_deps.getProtocolsByGuids(analyser.m_all_protocols); // Save all protocols information to build dependencies attachActionProtocolsDeps(); @@ -2804,29 +2786,29 @@ bool efi_analysis::efiAnalyserMainX64() { bool efi_analysis::efiAnalyserMainX86() { show_wait_box("HIDECANCEL\nAnalysing module(s) with efiXplorer..."); - efi_analysis::EfiAnalyserX86 analyser; + efi_analysis::efi_analyser_x86_t analyser; while (!auto_is_ok()) { auto_wait(); } // find .text and .data segments - analyser.getSegments(); + analyser.get_segments(); // mark GUIDs - analyser.markDataGuids(); + analyser.mark_data_guids(); if (g_args.disable_ui) { - analyser.file_type = g_args.module_type == ModuleType::Pei - ? analyser.file_type = FfsFileType::Pei - : analyser.file_type = FfsFileType::DxeAndTheLike; + analyser.m_ftype = g_args.module_type == module_type_t::pei + ? analyser.m_ftype = ffs_file_type_t::pei + : analyser.m_ftype = ffs_file_type_t::dxe_smm; } else { - analyser.file_type = ask_file_type(&analyser.allGuids); + analyser.m_ftype = ask_file_type(&analyser.m_all_guids); } - analyser.setStrings(); + analyser.set_pvalues(); - if (analyser.file_type == FfsFileType::DxeAndTheLike) { + if (analyser.m_ftype == ffs_file_type_t::dxe_smm) { // find global vars for gST, gBS, gRT analyser.findBootServicesTables(); analyser.findRuntimeServicesTables(); @@ -2838,34 +2820,34 @@ bool efi_analysis::efiAnalyserMainX86() { // print and mark protocols analyser.getBsProtNamesX86(); - analyser.markInterfaces(); + analyser.mark_interfaces(); #ifdef HEX_RAYS - apply_all_types_for_interfaces(analyser.allProtocols); - apply_all_types_for_interfaces_smm(analyser.allProtocols); + apply_all_types_for_interfaces(analyser.m_all_protocols); + apply_all_types_for_interfaces_smm(analyser.m_all_protocols); #endif - } else if (analyser.file_type == FfsFileType::Pei) { + } else if (analyser.m_ftype == ffs_file_type_t::pei) { set_entry_arg_to_pei_svc(); add_struct_for_shifted_ptr(); #ifdef HEX_RAYS - for (auto addr : analyser.funcs) { + for (auto addr : analyser.m_funcs) { detect_pei_services(get_func(addr)); } #endif analyser.getAllPeiServicesX86(); analyser.getPpiNamesX86(); analyser.getAllVariablePPICallsX86(); - analyser.markInterfaces(); + analyser.mark_interfaces(); // search for vulnerabilities if (!g_args.disable_vuln_hunt) { - analyser.findPPIGetVariableStackOveflow(); + analyser.find_double_get_variable_pei(); } } // dump info to JSON file - analyser.dumpInfo(); + analyser.dump_json(); // show all choosers windows if (!g_args.disable_ui) { diff --git a/efiXplorer/efi_defs.h b/efiXplorer/efi_defs.h index d31e99c3..4fbb3877 100644 --- a/efiXplorer/efi_defs.h +++ b/efiXplorer/efi_defs.h @@ -35,15 +35,17 @@ #define RT_OFFSET_64 0x58 #define RT_OFFSET_32 0x38 -enum class ModuleType { DxeSmm = 0, Pei = 1 }; +#define BADREG 0xffff +#define OFFSET_NONE 0xffff +#define PUSH_NONE 0xffff -enum class ArchFileType { Unsupported, X8632, X8664, Uefi, Aarch64 }; +enum class arch_file_type_t { unsupported, x86_32, x86_64, aarch64, uefi }; +enum class ffs_file_type_t { unsupported = 0, pei = 6, dxe_smm = 7 }; +enum class module_type_t { dxe_smm = 0, pei = 1 }; -enum class FfsFileType { Unsupported = 0, Pei = 6, DxeAndTheLike = 7 }; +enum machine_type_t { AMD64 = 0x8664, I386 = 0x014C, AARCH64 = 0xaa64 }; -enum MachineType { AMD64 = 0x8664, I386 = 0x014C, AARCH64 = 0xaa64 }; - -enum RegsAmd32 { +enum regs_x86_32_t { REG_EAX, REG_ECX, REG_EDX, @@ -56,7 +58,7 @@ enum RegsAmd32 { REG_DL = 0x12 }; -enum RegsI386 { +enum regs_x86_64_t { REG_RAX, REG_RCX, REG_RDX, @@ -74,7 +76,7 @@ enum RegsI386 { REG_R14, }; -enum RegsAarch4 { +enum regs_aarch64_t { REG_C0 = 0, REG_C13 = 13, REG_X0 = 129, @@ -113,30 +115,24 @@ enum RegsAarch4 { REG_XPC, }; -enum HelperValues { - OFFSET_NONE = 0xffff, - PUSH_NONE = 0xffff, - BAD_REG = 0xffff, -}; - -typedef struct service_info_64 { +struct service_info_64_t { char name[64]; uint32_t offset; uint32_t reg; uint16_t arg_index; -} service_info_64_t; +}; -typedef struct service_info_32 { +struct service_info_32_t { char name[64]; uint32_t offset; uint16_t push_number; -} service_info_32_t; +}; -typedef struct service { +struct service_t { char name[64]; uint32_t offset64; uint32_t offset32; -} service_t; +}; enum BootServicesOffsets64 { RaiseTPLOffset64 = 0x18, diff --git a/efiXplorer/efi_global.h b/efiXplorer/efi_global.h index 44489a0c..241deb17 100644 --- a/efiXplorer/efi_global.h +++ b/efiXplorer/efi_global.h @@ -22,7 +22,7 @@ #include "efi_deps.h" typedef struct args { - ModuleType module_type; + module_type_t module_type; int disable_ui; int disable_vuln_hunt; } args_t; diff --git a/efiXplorer/efi_smm_utils.cc b/efiXplorer/efi_smm_utils.cc index a98dc1e0..9b18a2d3 100644 --- a/efiXplorer/efi_smm_utils.cc +++ b/efiXplorer/efi_smm_utils.cc @@ -78,7 +78,6 @@ ea_list_t findSmstSwDispatch(ea_list_t bs_list) { if (addr_in_vec(bs_list, res_addr)) { continue; } - set_cmt(cur_addr, "_EFI_SMM_SYSTEM_TABLE2 *gSmst;", true); set_ptr_type_and_name(res_addr, "gSmst", "_EFI_SMM_SYSTEM_TABLE2"); smst_addrs.push_back(res_addr); break; @@ -133,7 +132,6 @@ ea_list_t findSmstSmmBase(ea_list_t bs_list) { if (addr_in_vec(bs_list, res_addr)) { continue; } - set_cmt(cur_addr, "_EFI_SMM_SYSTEM_TABLE2 *gSmst;", true); set_ptr_type_and_name(res_addr, "gSmst", "_EFI_SMM_SYSTEM_TABLE2"); smst_addrs.push_back(res_addr); } else { @@ -153,7 +151,7 @@ func_list_t findSmiHandlers(ea_t address, std::string prefix) { msg("[%s] Analyse xref to gEfiSmm%sDispatch(2)Protocol: 0x%016llX\n", g_plugin_name, prefix.c_str(), u64_addr(address)); - func_list_t smiHandlers; + func_list_t m_smi_handlers; insn_t insn; // Find Dispatch interface address (via gSmst->SmmLocateProtocol call) @@ -163,7 +161,7 @@ func_list_t findSmiHandlers(ea_t address, std::string prefix) { if (!(insn.ops[0].type == o_reg && insn.ops[0].reg == REG_RCX)) { msg("[%s] %sSmiHandler: wrong xref to dispatch(2) protocol\n", g_plugin_name, prefix.c_str()); - return smiHandlers; + return m_smi_handlers; } // Analyse current basic block @@ -199,7 +197,7 @@ func_list_t findSmiHandlers(ea_t address, std::string prefix) { } if (!found) { - return smiHandlers; + return m_smi_handlers; } if (dispatch_interface == BADADDR) { @@ -224,7 +222,7 @@ func_list_t findSmiHandlers(ea_t address, std::string prefix) { } if (dispatch_interface == BADADDR) { - return smiHandlers; + return m_smi_handlers; } msg("[%s] Found EfiSmm%sDispatch(2)Protocol interface: 0x%016llX\n", @@ -235,7 +233,7 @@ func_list_t findSmiHandlers(ea_t address, std::string prefix) { // Track interface stack variable ea = address; - uint16_t reg = BAD_REG; + uint16_t reg = BADREG; uint64_t dispatch_func = BADADDR; for (auto i = 0; i < 100; i++) { ea = next_head(ea, BADADDR); @@ -246,20 +244,20 @@ func_list_t findSmiHandlers(ea_t address, std::string prefix) { if (insn.ops[1].addr == dispatch_interface) { reg = insn.ops[0].reg; } else { - reg = BAD_REG; // resetting + reg = BADREG; // resetting } continue; } // resetting (register overwrite or call) - if (reg != BAD_REG && insn.ops[0].type == o_reg && insn.ops[0].reg == reg) { - reg = BAD_REG; + if (reg != BADREG && insn.ops[0].type == o_reg && insn.ops[0].reg == reg) { + reg = BADREG; continue; } // resetting (call) if (insn.itype == NN_call) { - reg = BAD_REG; + reg = BADREG; continue; } @@ -281,9 +279,9 @@ func_list_t findSmiHandlers(ea_t address, std::string prefix) { handler_func = get_func(dispatch_func); // retry } if (handler_func != nullptr) { - smiHandlers.push_back(handler_func); // add in result + m_smi_handlers.push_back(handler_func); // add in result } - reg = BAD_REG; // resetting + reg = BADREG; // resetting // op_stroff + set_name std::string name = prefix + "SmiHandler"; @@ -300,7 +298,7 @@ func_list_t findSmiHandlers(ea_t address, std::string prefix) { } } - return smiHandlers; + return m_smi_handlers; } //-------------------------------------------------------------------------- @@ -314,7 +312,7 @@ func_list_t findSmiHandlers(ea_t address, std::string prefix) { // lea rdx, // call qword ptr [...] func_list_t findSmiHandlersSmmDispatch(EfiGuid guid, std::string prefix) { - func_list_t smiHandlers; + func_list_t m_smi_handlers; ea_list_t data_addrs = find_data(0, BADADDR, guid.uchar_data().data(), 16); msg("[%s] %sSmiHandler function finding\n", g_plugin_name, prefix.c_str()); for (auto data_addr : data_addrs) { @@ -323,11 +321,11 @@ func_list_t findSmiHandlersSmmDispatch(EfiGuid guid, std::string prefix) { for (auto xref : xrefs) { msg("[%s] findSmiHandlers: 0x%016llX\n", g_plugin_name, u64_addr(xref)); auto res = findSmiHandlers(xref, prefix); - smiHandlers.insert(smiHandlers.end(), res.begin(), res.end()); + m_smi_handlers.insert(m_smi_handlers.end(), res.begin(), res.end()); } } - return smiHandlers; + return m_smi_handlers; } //-------------------------------------------------------------------------- @@ -335,7 +333,7 @@ func_list_t findSmiHandlersSmmDispatch(EfiGuid guid, std::string prefix) { // EFI_SMM_SW_DISPATCH(2)_PROTOCOL_GUID is a local variable func_list_t findSmiHandlersSmmDispatchStack(json_list_t stackGuids, std::string prefix) { - func_list_t smiHandlers; + func_list_t m_smi_handlers; for (auto guid : stackGuids) { std::string name = static_cast(guid["name"]); @@ -350,17 +348,17 @@ func_list_t findSmiHandlersSmmDispatchStack(json_list_t stackGuids, "0x%016llX\n", g_plugin_name, u64_addr(address)); auto res = findSmiHandlers(address, prefix); - smiHandlers.insert(smiHandlers.end(), res.begin(), res.end()); + m_smi_handlers.insert(m_smi_handlers.end(), res.begin(), res.end()); } - return smiHandlers; + return m_smi_handlers; } //-------------------------------------------------------------------------- -// Find gSmmVar->SmmGetVariable calls via EFI_SMM_VARIABLE_PROTOCOL_GUID +// Find gSmmVariable->SmmGetVariable calls via EFI_SMM_VARIABLE_PROTOCOL_GUID ea_list_t findSmmGetVariableCalls(segment_list_t dataSegments, - json_list_t *allServices) { - msg("[%s] gSmmVar->SmmGetVariable calls finding via " + json_list_t *m_all_services) { + msg("[%s] gSmmVariable->SmmGetVariable calls finding via " "EFI_SMM_VARIABLE_PROTOCOL_GUID\n", g_plugin_name); ea_list_t smmGetVariableCalls; @@ -372,7 +370,7 @@ ea_list_t findSmmGetVariableCalls(segment_list_t dataSegments, // Find all EFI_GUID EFI_SMM_VARIABLE_PROTOCOL_GUID addresses ea_list_t data_addrs = find_data(0, BADADDR, guid.uchar_data().data(), 16); - ea_list_t gSmmVarAddrs; // Find all gSmmVar variables + ea_list_t gSmmVariableAddrs; // Find all gSmmVariable variables for (auto data_addr : data_addrs) { ea_list_t xrefs = get_xrefs_util(data_addr); @@ -392,57 +390,56 @@ ea_list_t findSmmGetVariableCalls(segment_list_t dataSegments, insn_t insn; ea_t ea = xref; for (auto i = 0; i < 8; i++) { - // Find `lea r8, ` instruction + // Find `lea r8, ` instruction ea = prev_head(ea, 0); decode_insn(&insn, ea); if (insn.itype == NN_lea && insn.ops[0].type == o_reg && insn.ops[0].reg == REG_R8 && insn.ops[1].type == o_mem) { - msg("[%s] gSmmVar address: 0x%016llX\n", g_plugin_name, + msg("[%s] gSmmVariable address: 0x%016llX\n", g_plugin_name, u64_addr(insn.ops[1].addr)); - set_cmt(ea, "EFI_SMM_VARIABLE_PROTOCOL *gSmmVar", true); - set_ptr_type_and_name(insn.ops[1].addr, "gSmmVar", + set_ptr_type_and_name(insn.ops[1].addr, "gSmmVariable", "EFI_SMM_VARIABLE_PROTOCOL"); - gSmmVarAddrs.push_back(insn.ops[1].addr); + gSmmVariableAddrs.push_back(insn.ops[1].addr); break; } } } } - if (!gSmmVarAddrs.size()) { - msg("[%s] can't find gSmmVar addresses\n", g_plugin_name); + if (!gSmmVariableAddrs.size()) { + msg("[%s] can't find gSmmVariable addresses\n", g_plugin_name); return smmGetVariableCalls; } - for (auto smmVarAddr : gSmmVarAddrs) { + for (auto smmVarAddr : gSmmVariableAddrs) { ea_list_t smmVarXrefs = get_xrefs_util(static_cast(smmVarAddr)); for (auto smmVarXref : smmVarXrefs) { segment_t *seg = getseg(static_cast(smmVarXref)); qstring seg_name; get_segm_name(&seg_name, seg); - msg("[%s] gSmmVar xref address: 0x%016llX, segment: %s\n", g_plugin_name, - u64_addr(smmVarXref), seg_name.c_str()); + msg("[%s] gSmmVariable xref address: 0x%016llX, segment: %s\n", + g_plugin_name, u64_addr(smmVarXref), seg_name.c_str()); size_t index = seg_name.find(".text"); if (index == std::string::npos) { continue; } - uint16 gSmmVarReg = 0xffff; + uint16 gSmmVariableReg = 0xffff; insn_t insn; ea_t ea = static_cast(smmVarXref); decode_insn(&insn, ea); if (insn.itype == NN_mov && insn.ops[0].type == o_reg && insn.ops[1].type == o_mem) { - gSmmVarReg = insn.ops[0].reg; + gSmmVariableReg = insn.ops[0].reg; for (auto i = 0; i < 16; i++) { ea = next_head(ea, BADADDR); decode_insn(&insn, ea); - if (insn.itype == NN_callni && gSmmVarReg == insn.ops[0].reg && + if (insn.itype == NN_callni && gSmmVariableReg == insn.ops[0].reg && insn.ops[0].addr == 0) { - msg("[%s] gSmmVar->SmmGetVariable found: 0x%016llX\n", + msg("[%s] gSmmVariable->SmmGetVariable found: 0x%016llX\n", g_plugin_name, u64_addr(ea)); if (find(smmGetVariableCalls.begin(), smmGetVariableCalls.end(), @@ -456,7 +453,7 @@ ea_list_t findSmmGetVariableCalls(segment_list_t dataSegments, op_stroff_util(ea, "EFI_SMM_VARIABLE_PROTOCOL"); msg("[%s] 0x%016llX : %s\n", g_plugin_name, u64_addr(ea), "SmmGetVariable"); - std::string smm_call = "gSmmVar->SmmGetVariable"; + std::string smm_call = "gSmmVariable->SmmGetVariable"; json smm_item; smm_item["address"] = ea; smm_item["service_name"] = smm_call; @@ -464,9 +461,9 @@ ea_list_t findSmmGetVariableCalls(segment_list_t dataSegments, static_cast("EFI_SMM_VARIABLE_PROTOCOL"); smm_item["offset"] = 0; - if (find(allServices->begin(), allServices->end(), smm_item) == - allServices->end()) { - allServices->push_back(smm_item); + if (find(m_all_services->begin(), m_all_services->end(), + smm_item) == m_all_services->end()) { + m_all_services->push_back(smm_item); } break; @@ -480,7 +477,7 @@ ea_list_t findSmmGetVariableCalls(segment_list_t dataSegments, ea_list_t resolveEfiSmmCpuProtocol(json_list_t stackGuids, json_list_t dataGuids, - json_list_t *allServices) { + json_list_t *m_all_services) { ea_list_t readSaveStateCalls; msg("[%s] Looking for EFI_SMM_CPU_PROTOCOL\n", g_plugin_name); ea_list_t code_addrs; @@ -529,7 +526,6 @@ ea_list_t resolveEfiSmmCpuProtocol(json_list_t stackGuids, insn.ops[0].reg == REG_R8 && insn.ops[1].type == o_mem) { msg("[%s] gSmmCpu address: 0x%016llX\n", g_plugin_name, u64_addr(insn.ops[1].addr)); - set_cmt(ea, "EFI_SMM_CPU_PROTOCOL *gSmmCpu", true); set_ptr_type_and_name(insn.ops[1].addr, "gSmmCpu", "EFI_SMM_CPU_PROTOCOL"); gSmmCpuAddrs.push_back(insn.ops[1].addr); @@ -588,9 +584,9 @@ ea_list_t resolveEfiSmmCpuProtocol(json_list_t stackGuids, static_cast("EFI_SMM_CPU_PROTOCOL"); smm_item["offset"] = 0; - if (find(allServices->begin(), allServices->end(), smm_item) == - allServices->end()) { - allServices->push_back(smm_item); + if (find(m_all_services->begin(), m_all_services->end(), + smm_item) == m_all_services->end()) { + m_all_services->push_back(smm_item); } break; diff --git a/efiXplorer/efi_smm_utils.h b/efiXplorer/efi_smm_utils.h index 4c735331..6208a798 100644 --- a/efiXplorer/efi_smm_utils.h +++ b/efiXplorer/efi_smm_utils.h @@ -30,8 +30,8 @@ func_list_t findSmiHandlersSmmDispatch(EfiGuid guid, std::string prefix); func_list_t findSmiHandlersSmmDispatchStack(json_list_t stackGuids, std::string prefix); ea_list_t findSmmGetVariableCalls(segment_list_t dataSegments, - json_list_t *allServices); + json_list_t *m_all_services); ea_list_t resolveEfiSmmCpuProtocol(json_list_t stackGuids, json_list_t dataGuids, - json_list_t *allServices); + json_list_t *m_all_services); ea_t markChildSwSmiHandler(ea_t ea); diff --git a/efiXplorer/efi_ui.cc b/efiXplorer/efi_ui.cc index 3f9c39e2..638274c2 100644 --- a/efiXplorer/efi_ui.cc +++ b/efiXplorer/efi_ui.cc @@ -377,27 +377,27 @@ struct action_handler_loadreport_t : public action_handler_t { qstring title; try { - auto protocols = reportData["allProtocols"]; + auto protocols = reportData["all_protocols"]; if (!protocols.is_null()) { // show protocols title = "efiXplorer: protocols"; protocols_show(protocols, title); } - auto ppis = reportData["allPPIs"]; + auto ppis = reportData["all_ppis"]; if (!ppis.is_null()) { // show PPIs title = "efiXplorer: PPIs"; protocols_show(ppis, title); } - auto services = reportData["allServices"]; + auto services = reportData["all_services"]; if (!services.is_null()) { // show services title = "efiXplorer: services"; services_show(services, title); } - auto guids = reportData["allGuids"]; + auto guids = reportData["all_guids"]; if (!guids.is_null()) { // show GUIDs title = "efiXplorer: GUIDs"; guids_show(guids, title); } - auto nvram = reportData["nvramVariables"]; + auto nvram = reportData["m_nvram_variables"]; if (!nvram.is_null()) { // show NVRAM title = "efiXplorer: NVRAM"; nvram_show(nvram, title); diff --git a/efiXplorer/efi_utils.cc b/efiXplorer/efi_utils.cc index f197ebf8..ba8c20c6 100644 --- a/efiXplorer/efi_utils.cc +++ b/efiXplorer/efi_utils.cc @@ -67,47 +67,48 @@ std::string file_format_name() { //-------------------------------------------------------------------------- // get input file type (64-bit, 32-bit module or UEFI firmware) -ArchFileType input_file_type() { +arch_file_type_t input_file_type() { processor_t &ph = PH; auto filetype = inf_get_filetype(); auto bits = inf_is_64bit() ? 64 : inf_is_32bit_exactly() ? 32 : 16; // check if the input file is a UEFI firmware image if (file_format_name().find("UEFI") != std::string::npos) { - return ArchFileType::Uefi; + return arch_file_type_t::uefi; } if (filetype == f_PE || filetype == f_ELF) { if (ph.id == PLFM_386) { if (bits == 64) - return ArchFileType::X8664; + return arch_file_type_t::x86_64; if (bits == 32) - return ArchFileType::X8632; + return arch_file_type_t::x86_32; } if (ph.id == PLFM_ARM) { if (bits == 64) - return ArchFileType::Aarch64; + return arch_file_type_t::aarch64; } } - return ArchFileType::Unsupported; + return arch_file_type_t::unsupported; } //-------------------------------------------------------------------------- // get input file type (PEI or DXE-like). No reliable way to determine FFS // file type given only its PE/TE image section, so hello heuristics -FfsFileType guess_file_type(ArchFileType arch, json_list_t *all_guids) { - if (arch == ArchFileType::Uefi) { - return FfsFileType::DxeAndTheLike; +ffs_file_type_t guess_file_type(arch_file_type_t arch, + json_list_t *m_all_guids) { + if (arch == arch_file_type_t::uefi) { + return ffs_file_type_t::dxe_smm; } segment_t *hdr_seg = get_segm_by_name("HEADER"); if (hdr_seg == nullptr) { - return FfsFileType::DxeAndTheLike; + return ffs_file_type_t::dxe_smm; } uint64_t signature = get_wide_word(hdr_seg->start_ea); bool has_pei_guids = false; - for (auto guid = all_guids->begin(); guid != all_guids->end(); guid++) { + for (auto guid = m_all_guids->begin(); guid != m_all_guids->end(); guid++) { json guid_value = *guid; if (static_cast(guid_value["name"]).find("PEI") != @@ -123,7 +124,7 @@ FfsFileType guess_file_type(ArchFileType arch, json_list_t *all_guids) { auto file_name_str = static_cast(file_name); if ((file_name_str.find("Pei") != std::string::npos || file_name_str.find("pei") != std::string::npos || signature == VZ) && - arch == ArchFileType::X8664) { + arch == arch_file_type_t::x86_64) { has_pei_in_path = true; } @@ -131,30 +132,30 @@ FfsFileType guess_file_type(ArchFileType arch, json_list_t *all_guids) { msg("[%s] parsing binary file as PEI, signature = %llx, has_pei_guids = " "%d\n", g_plugin_name, signature, has_pei_guids); - return FfsFileType::Pei; + return ffs_file_type_t::pei; } msg("[%s] parsing binary file as DXE/SMM, signature = %llx, has_pei_guids = " "%d\n", g_plugin_name, signature, has_pei_guids); - return FfsFileType::DxeAndTheLike; + return ffs_file_type_t::dxe_smm; } -FfsFileType ask_file_type(json_list_t *all_guids) { +ffs_file_type_t ask_file_type(json_list_t *m_all_guids) { auto arch = input_file_type(); - if (arch == ArchFileType::Uefi || arch == ArchFileType::X8664) { - return FfsFileType::DxeAndTheLike; + if (arch == arch_file_type_t::uefi || arch == arch_file_type_t::x86_64) { + return ffs_file_type_t::dxe_smm; } - auto ftype = guess_file_type(arch, all_guids); - auto deflt = ftype == FfsFileType::DxeAndTheLike; - auto fmt_param = ftype == FfsFileType::DxeAndTheLike ? "DXE/SMM" : "PEI"; + auto ftype = guess_file_type(arch, m_all_guids); + auto deflt = ftype == ffs_file_type_t::dxe_smm; + auto fmt_param = ftype == ffs_file_type_t::dxe_smm ? "DXE/SMM" : "PEI"; auto btn_id = ask_buttons("DXE/SMM", "PEI", "", deflt, "Parse file as %s", fmt_param); if (btn_id == ASKBTN_YES) { - return FfsFileType::DxeAndTheLike; + return ffs_file_type_t::dxe_smm; } - return FfsFileType::Pei; + return ffs_file_type_t::pei; } //-------------------------------------------------------------------------- diff --git a/efiXplorer/efi_utils.h b/efiXplorer/efi_utils.h index f90d0faf..f76004f3 100644 --- a/efiXplorer/efi_utils.h +++ b/efiXplorer/efi_utils.h @@ -92,7 +92,7 @@ struct EfiGuid { } }; -ArchFileType input_file_type(); +arch_file_type_t input_file_type(); bool add_struct_for_shifted_ptr(); bool addr_in_tables(ea_list_t t1, ea_list_t t2, ea_t ea); @@ -115,7 +115,7 @@ ea_t find_unknown_bs_var_64(ea_t ea); EfiGuid get_global_guid(ea_t addr); EfiGuid get_local_guid(func_t *f, uint64_t offset); -FfsFileType ask_file_type(json_list_t *all_guids); +ffs_file_type_t ask_file_type(json_list_t *m_all_guids); json get_guid_by_address(ea_t addr); diff --git a/efiXplorer/efixplorer.cc b/efiXplorer/efixplorer.cc index 0fd53ea7..8fd728fc 100644 --- a/efiXplorer/efixplorer.cc +++ b/efiXplorer/efixplorer.cc @@ -31,7 +31,7 @@ static const char welcome_msg[] = " ____ _ __ __\n" " /_/\n"; // default arguments -struct args g_args = {ModuleType::DxeSmm, 0, 0}; +struct args g_args = {module_type_t::dxe_smm, 0, 0}; #if IDA_SDK_VERSION < 760 hexdsp_t *hexdsp = nullptr; @@ -39,8 +39,8 @@ hexdsp_t *hexdsp = nullptr; //-------------------------------------------------------------------------- static plugmod_t *idaapi init(void) { - ArchFileType file_type = input_file_type(); - if (file_type == ArchFileType::Unsupported) { + arch_file_type_t file_type = input_file_type(); + if (file_type == arch_file_type_t::unsupported) { return PLUGIN_SKIP; } @@ -68,7 +68,7 @@ bool idaapi run(size_t arg) { // - arg = 6 (110): disable_ui & disable_vuln_hunt (DXE) // - arg = 7 (111): disable_ui & disable_vuln_hunt (PEI, 32-bit binaries // only) - g_args.module_type = ModuleType::Pei; + g_args.module_type = module_type_t::pei; } if (arg >> 1 & 1) { @@ -94,14 +94,14 @@ bool idaapi run(size_t arg) { return false; } - ArchFileType arch = input_file_type(); - if (arch == ArchFileType::X8664) { + arch_file_type_t arch = input_file_type(); + if (arch == arch_file_type_t::x86_64) { msg("[%s] input file is 64-bit module (x86)\n", g_plugin_name); efi_analysis::efiAnalyserMainX64(); - } else if (arch == ArchFileType::X8632) { + } else if (arch == arch_file_type_t::x86_32) { msg("[%s] input file is 32-bit module (x86)\n", g_plugin_name); efi_analysis::efiAnalyserMainX86(); - } else if (arch == ArchFileType::Uefi) { + } else if (arch == arch_file_type_t::uefi) { msg("[%s] input file is UEFI firmware\n", g_plugin_name); warning("%s: analysis may take some time, please wait for it to complete\n", g_plugin_name); @@ -112,13 +112,13 @@ bool idaapi run(size_t arg) { msg("[%s] analyse AMD64 modules\n", g_plugin_name); efi_analysis::efiAnalyserMainX64(); } - } else if (arch == ArchFileType::Aarch64) { + } else if (arch == arch_file_type_t::aarch64) { msg("[%s] input file is 64-bit module (ARM)\n", g_plugin_name); efi_analysis::efiAnalyserMainArm(); } // Reset arguments - g_args = {ModuleType::DxeSmm, 0, 0}; + g_args = {module_type_t::dxe_smm, 0, 0}; return true; } From 4ea9b700b7fded29cbf2e3ef26ea43a37b23ee6c Mon Sep 17 00:00:00 2001 From: yeggor Date: Tue, 17 Sep 2024 19:28:16 +0100 Subject: [PATCH 28/69] move show_all_choosers to class --- efiXplorer/efi_analyser.h | 21 +++++++++-------- efiXplorer/efi_analyser_arm.cc | 20 ++++++++-------- efiXplorer/efi_analyser_x86.cc | 42 +++++++++++++++++----------------- efiXplorer/efixplorer.cc | 15 ++++++------ 4 files changed, 50 insertions(+), 48 deletions(-) diff --git a/efiXplorer/efi_analyser.h b/efiXplorer/efi_analyser.h index de23770c..5203aa87 100644 --- a/efiXplorer/efi_analyser.h +++ b/efiXplorer/efi_analyser.h @@ -342,6 +342,8 @@ class efi_analyser_x86_t : public efi_analyser_t { } #endif } + + void show_all_choosers(); bool findImageHandleX64(); bool findSystemTableX64(); bool findBootServicesTables(); @@ -384,16 +386,17 @@ class efi_analyser_arm_t : public efi_analyser_t { import_type(idati, -1, "EFI_BOOT_SERVICES"); import_type(idati, -1, "EFI_RUNTIME_SERVICES"); } + + void findBootServicesTables(); + void findPeiServicesFunction(); void fix_offsets(); void initialAnalysis(); - void findBootServicesTables(); void initialGlobalVarsDetection(); - void servicesDetection(); void protocolsDetection(); - void findPeiServicesFunction(); + void servicesDetection(); + void show_all_choosers(); private: - bool getProtocol(ea_t address, uint32_t p_reg, std::string service_name); struct service_info_64bit { char name[64]; uint32_t offset; @@ -415,11 +418,11 @@ class efi_analyser_arm_t : public efi_analyser_t { {"LocateProtocol", 0x140, REG_X0, 1}, {"InstallMultipleProtocolInterfaces", 0x148, REG_X1, 1}, {"UninstallMultipleProtocolInterfaces", 0x150, REG_X1, 1}}; + + bool getProtocol(ea_t address, uint32_t p_reg, std::string service_name); }; -bool efiAnalyserMainX64(); -bool efiAnalyserMainX86(); -bool efiAnalyserMainArm(); +bool efi_analyse_main_x86_64(); +bool efi_analyse_main_x86_32(); +bool efi_analyse_main_aarch64(); }; // namespace efi_analysis - -void showAllChoosers(efi_analysis::efi_analyser_t analyser); diff --git a/efiXplorer/efi_analyser_arm.cc b/efiXplorer/efi_analyser_arm.cc index 7eed52bc..4215e400 100644 --- a/efiXplorer/efi_analyser_arm.cc +++ b/efiXplorer/efi_analyser_arm.cc @@ -424,32 +424,32 @@ void efi_analysis::efi_analyser_arm_t::findPeiServicesFunction() { } //-------------------------------------------------------------------------- -// Show all non-empty choosers windows -void showAllChoosers(efi_analysis::efi_analyser_arm_t analyser) { +// show all non-empty choosers windows (services, protocols, etc) +void efi_analysis::efi_analyser_arm_t::show_all_choosers() { qstring title; // open window with all services - if (analyser.m_all_services.size()) { + if (m_all_services.size()) { title = "efiXplorer: services"; - services_show(analyser.m_all_services, title); + services_show(m_all_services, title); } // open window with data guids - if (analyser.m_all_guids.size()) { + if (m_all_guids.size()) { qstring title = "efiXplorer: GUIDs"; - guids_show(analyser.m_all_guids, title); + guids_show(m_all_guids, title); } // open window with protocols - if (analyser.m_all_protocols.size()) { + if (m_all_protocols.size()) { title = "efiXplorer: protocols"; - protocols_show(analyser.m_all_protocols, title); + protocols_show(m_all_protocols, title); } } //-------------------------------------------------------------------------- // Main function for AARCH64 modules -bool efi_analysis::efiAnalyserMainArm() { +bool efi_analysis::efi_analyse_main_aarch64() { show_wait_box("HIDECANCEL\nAnalysing module(s) with efiXplorer..."); efi_analysis::efi_analyser_arm_t analyser; @@ -501,8 +501,8 @@ bool efi_analysis::efiAnalyserMainArm() { } apply_all_types_for_interfaces(analyser.m_all_protocols); #endif /* HEX_RAYS */ - showAllChoosers(analyser); + analyser.show_all_choosers(); analyser.dump_json(); hide_wait_box(); diff --git a/efiXplorer/efi_analyser_x86.cc b/efiXplorer/efi_analyser_x86.cc index 28670a11..66f939fe 100644 --- a/efiXplorer/efi_analyser_x86.cc +++ b/efiXplorer/efi_analyser_x86.cc @@ -2598,40 +2598,39 @@ void efi_analysis::efi_analyser_t::dump_json() { } //-------------------------------------------------------------------------- -// Show all non-empty choosers windows -void showAllChoosers(efi_analysis::efi_analyser_x86_t analyser) { +// show all non-empty choosers windows (services, protocols, nvram, etc) +void efi_analysis::efi_analyser_x86_t::show_all_choosers() { qstring title; // open window with all services - if (analyser.m_all_services.size()) { + if (m_all_services.size()) { title = "efiXplorer: services"; - services_show(analyser.m_all_services, title); + services_show(m_all_services, title); } // open window with protocols - if (analyser.m_ftype == ffs_file_type_t::pei) { - if (analyser.m_all_ppis.size()) { + if (m_ftype == ffs_file_type_t::pei) { + if (m_all_ppis.size()) { title = "efiXplorer: PPIs"; - ppis_show(analyser.m_all_ppis, title); + ppis_show(m_all_ppis, title); } - } else { // ffs_file_type_t::dxe_smm - if (analyser.m_all_protocols.size()) { + if (m_all_protocols.size()) { title = "efiXplorer: protocols"; - protocols_show(analyser.m_all_protocols, title); + protocols_show(m_all_protocols, title); } } // open window with data guids - if (analyser.m_all_guids.size()) { + if (m_all_guids.size()) { qstring title = "efiXplorer: GUIDs"; - guids_show(analyser.m_all_guids, title); + guids_show(m_all_guids, title); } // open window with NVRAM variables - if (analyser.m_nvram_variables.size()) { + if (m_nvram_variables.size()) { qstring title = "efiXplorer: NVRAM"; - nvram_show(analyser.m_nvram_variables, title); + nvram_show(m_nvram_variables, title); } // open window with vulnerabilities @@ -2643,6 +2642,7 @@ void showAllChoosers(efi_analysis::efi_analyser_x86_t analyser) { {"PeiGetVariableOverflow", peiGetVariableOverflow}, {"DxeGetVariableOverflow", getVariableOverflow}, {"SmmGetVariableOverflow", smmGetVariableOverflow}}; + for (const auto &[type, addrs] : vulns_map) { for (auto addr : addrs) { json item; @@ -2651,14 +2651,15 @@ void showAllChoosers(efi_analysis::efi_analyser_x86_t analyser) { vulns.push_back(item); } } + qstring title = "efiXplorer: vulns"; vulns_show(vulns, title); } } //-------------------------------------------------------------------------- -// Main function for X64 modules -bool efi_analysis::efiAnalyserMainX64() { +// main function for x86 64-bit modules +bool efi_analysis::efi_analyse_main_x86_64() { show_wait_box("HIDECANCEL\nAnalysing module(s) with efiXplorer..."); efi_analysis::efi_analyser_x86_t analyser; @@ -2763,7 +2764,7 @@ bool efi_analysis::efiAnalyserMainX64() { // show all choosers windows if (!g_args.disable_ui) { - showAllChoosers(analyser); + analyser.show_all_choosers(); } if (analyser.m_arch == arch_file_type_t::uefi) { @@ -2782,8 +2783,8 @@ bool efi_analysis::efiAnalyserMainX64() { } //-------------------------------------------------------------------------- -// Main function for X86 modules -bool efi_analysis::efiAnalyserMainX86() { +// main function for x86 32-bit modules +bool efi_analysis::efi_analyse_main_x86_32() { show_wait_box("HIDECANCEL\nAnalysing module(s) with efiXplorer..."); efi_analysis::efi_analyser_x86_t analyser; @@ -2826,7 +2827,6 @@ bool efi_analysis::efiAnalyserMainX86() { apply_all_types_for_interfaces(analyser.m_all_protocols); apply_all_types_for_interfaces_smm(analyser.m_all_protocols); #endif - } else if (analyser.m_ftype == ffs_file_type_t::pei) { set_entry_arg_to_pei_svc(); add_struct_for_shifted_ptr(); @@ -2851,7 +2851,7 @@ bool efi_analysis::efiAnalyserMainX86() { // show all choosers windows if (!g_args.disable_ui) { - showAllChoosers(analyser); + analyser.show_all_choosers(); } hide_wait_box(); diff --git a/efiXplorer/efixplorer.cc b/efiXplorer/efixplorer.cc index 8fd728fc..4fe87646 100644 --- a/efiXplorer/efixplorer.cc +++ b/efiXplorer/efixplorer.cc @@ -65,9 +65,8 @@ bool idaapi run(size_t arg) { // - arg = 3 (011): disable_ui (PEI, 32-bit binaries only) // - arg = 4 (100): disable_vuln_hunt (DXE) // - arg = 5 (101): disable_vuln_hunt (PEI, 32-bit binaries only) - // - arg = 6 (110): disable_ui & disable_vuln_hunt (DXE) - // - arg = 7 (111): disable_ui & disable_vuln_hunt (PEI, 32-bit binaries - // only) + // - arg = 6 (110): disable_ui & disable_vuln_hunt for DXE + // - arg = 7 (111): disable_ui & disable_vuln_hunt for PEI g_args.module_type = module_type_t::pei; } @@ -97,24 +96,24 @@ bool idaapi run(size_t arg) { arch_file_type_t arch = input_file_type(); if (arch == arch_file_type_t::x86_64) { msg("[%s] input file is 64-bit module (x86)\n", g_plugin_name); - efi_analysis::efiAnalyserMainX64(); + efi_analysis::efi_analyse_main_x86_64(); } else if (arch == arch_file_type_t::x86_32) { msg("[%s] input file is 32-bit module (x86)\n", g_plugin_name); - efi_analysis::efiAnalyserMainX86(); + efi_analysis::efi_analyse_main_x86_32(); } else if (arch == arch_file_type_t::uefi) { msg("[%s] input file is UEFI firmware\n", g_plugin_name); warning("%s: analysis may take some time, please wait for it to complete\n", g_plugin_name); if (get_machine_type() == AARCH64) { msg("[%s] analyse AARCH64 modules\n", g_plugin_name); - efi_analysis::efiAnalyserMainArm(); + efi_analysis::efi_analyse_main_aarch64(); } else { msg("[%s] analyse AMD64 modules\n", g_plugin_name); - efi_analysis::efiAnalyserMainX64(); + efi_analysis::efi_analyse_main_x86_64(); } } else if (arch == arch_file_type_t::aarch64) { msg("[%s] input file is 64-bit module (ARM)\n", g_plugin_name); - efi_analysis::efiAnalyserMainArm(); + efi_analysis::efi_analyse_main_aarch64(); } // Reset arguments From b0242a919dee78e626821bd43fcfdaafad1bec3c Mon Sep 17 00:00:00 2001 From: yeggor Date: Tue, 17 Sep 2024 19:50:28 +0100 Subject: [PATCH 29/69] more refactoring for efi_analysis --- efiXplorer/efi_analyser.h | 58 ++++++++++----------- efiXplorer/efi_analyser_arm.cc | 27 +++++----- efiXplorer/efi_analyser_x86.cc | 94 +++++++++++++++++----------------- 3 files changed, 88 insertions(+), 91 deletions(-) diff --git a/efiXplorer/efi_analyser.h b/efiXplorer/efi_analyser.h index 5203aa87..d3d6209e 100644 --- a/efiXplorer/efi_analyser.h +++ b/efiXplorer/efi_analyser.h @@ -343,33 +343,29 @@ class efi_analyser_x86_t : public efi_analyser_t { #endif } + bool find_boot_services_tables(); + bool find_image_handle64(); + bool find_runtime_services_tables(); + bool find_smst_postproc64(); + bool find_smst64(); + bool find_system_table64(); + void find_other_boot_services_tables64(); + void get_boot_services_all(); + void get_bs_prot_names32(); + void get_bs_prot_names64(); + void get_pei_services_all32(); + void get_ppi_names32(); + void get_prot_boot_services32(); + void get_prot_boot_services64(); + void get_runtime_services_all(); + void get_smm_prot_names64(); + void get_smm_services_all64(); + void get_variable_ppi_calls_all32(); + void mark_local_guids64(); void show_all_choosers(); - bool findImageHandleX64(); - bool findSystemTableX64(); - bool findBootServicesTables(); - bool findRuntimeServicesTables(); - bool findSmstX64(); - bool findSmstPostProcX64(); - void findOtherBsTablesX64(); - - void getProtBootServicesX64(); - void getProtBootServicesX86(); - void getAllBootServices(); - void getAllRuntimeServices(); - void getAllSmmServicesX64(); - - void getBsProtNamesX64(); - void getBsProtNamesX86(); - void getSmmProtNamesX64(); - - void getAllPeiServicesX86(); - void getPpiNamesX86(); - void getAllVariablePPICallsX86(); - - void markLocalGuidsX64(); private: - bool InstallMultipleProtocolInterfacesHandler(); + bool install_multiple_prot_interfaces_analyser(); }; class efi_analyser_arm_t : public efi_analyser_t { @@ -387,13 +383,13 @@ class efi_analyser_arm_t : public efi_analyser_t { import_type(idati, -1, "EFI_RUNTIME_SERVICES"); } - void findBootServicesTables(); - void findPeiServicesFunction(); + void find_boot_services_tables(); + void find_pei_services_function(); void fix_offsets(); - void initialAnalysis(); - void initialGlobalVarsDetection(); - void protocolsDetection(); - void servicesDetection(); + void initial_analysis(); + void initial_gvars_detection(); + void detect_protocols_all(); + void detect_services_all(); void show_all_choosers(); private: @@ -419,7 +415,7 @@ class efi_analyser_arm_t : public efi_analyser_t { {"InstallMultipleProtocolInterfaces", 0x148, REG_X1, 1}, {"UninstallMultipleProtocolInterfaces", 0x150, REG_X1, 1}}; - bool getProtocol(ea_t address, uint32_t p_reg, std::string service_name); + bool get_protocol(ea_t address, uint32_t p_reg, std::string service_name); }; bool efi_analyse_main_x86_64(); diff --git a/efiXplorer/efi_analyser_arm.cc b/efiXplorer/efi_analyser_arm.cc index 4215e400..0357c617 100644 --- a/efiXplorer/efi_analyser_arm.cc +++ b/efiXplorer/efi_analyser_arm.cc @@ -53,7 +53,7 @@ void efi_analysis::efi_analyser_arm_t::fix_offsets() { } } -void efi_analysis::efi_analyser_arm_t::initialAnalysis() { +void efi_analysis::efi_analyser_arm_t::initial_analysis() { fix_offsets(); for (auto idx = 0; idx < get_entry_qty(); idx++) { uval_t ord = get_entry_ordinal(idx); @@ -227,7 +227,7 @@ json getService(ea_t addr, uint8_t table_id) { return s; } -void efi_analysis::efi_analyser_arm_t::initialGlobalVarsDetection() { +void efi_analysis::efi_analyser_arm_t::initial_gvars_detection() { #ifdef HEX_RAYS // analyse entry point with Hex-Rays for (auto func_addr : m_funcs) { @@ -294,7 +294,7 @@ void efi_analysis::efi_analyser_arm_t::initialGlobalVarsDetection() { } } -void efi_analysis::efi_analyser_arm_t::servicesDetection() { +void efi_analysis::efi_analyser_arm_t::detect_services_all() { #ifdef HEX_RAYS for (auto func_addr : m_funcs) { json_list_t services = detect_services(get_func(func_addr)); @@ -343,8 +343,9 @@ void efi_analysis::efi_analyser_arm_t::servicesDetection() { } } -bool efi_analysis::efi_analyser_arm_t::getProtocol(ea_t address, uint32_t p_reg, - std::string service_name) { +bool efi_analysis::efi_analyser_arm_t::get_protocol(ea_t address, + uint32_t p_reg, + std::string service_name) { ea_t ea = address; insn_t insn; ea_t offset = BADADDR; @@ -382,7 +383,7 @@ bool efi_analysis::efi_analyser_arm_t::getProtocol(ea_t address, uint32_t p_reg, return add_protocol(service_name, guid_addr, code_addr, address); } -void efi_analysis::efi_analyser_arm_t::protocolsDetection() { +void efi_analysis::efi_analyser_arm_t::detect_protocols_all() { for (auto s : m_all_services) { std::string service_name = s["service_name"]; for (auto i = 0; i < 13; i++) { @@ -391,13 +392,13 @@ void efi_analysis::efi_analyser_arm_t::protocolsDetection() { if (current_name != service_name) { continue; } - getProtocol(s["address"], bs_table_aarch64[i].reg, service_name); + get_protocol(s["address"], bs_table_aarch64[i].reg, service_name); break; } } } -void efi_analysis::efi_analyser_arm_t::findPeiServicesFunction() { +void efi_analysis::efi_analyser_arm_t::find_pei_services_function() { insn_t insn; for (auto start_ea : m_funcs) { decode_insn(&insn, start_ea); @@ -478,18 +479,18 @@ bool efi_analysis::efi_analyse_main_aarch64() { // set the correct name for the entry point and automatically fix the // prototype - analyser.initialAnalysis(); + analyser.initial_analysis(); if (analyser.m_ftype == ffs_file_type_t::dxe_smm) { - analyser.initialGlobalVarsDetection(); + analyser.initial_gvars_detection(); // detect services - analyser.servicesDetection(); + analyser.detect_services_all(); // detect protocols - analyser.protocolsDetection(); + analyser.detect_protocols_all(); } else if (analyser.m_ftype == ffs_file_type_t::pei) { - analyser.findPeiServicesFunction(); + analyser.find_pei_services_function(); } #ifdef HEX_RAYS diff --git a/efiXplorer/efi_analyser_x86.cc b/efiXplorer/efi_analyser_x86.cc index 66f939fe..52b63038 100644 --- a/efiXplorer/efi_analyser_x86.cc +++ b/efiXplorer/efi_analyser_x86.cc @@ -206,7 +206,7 @@ void efi_analysis::efi_analyser_t::get_segments() { //-------------------------------------------------------------------------- // Find gImageHandle address for X64 modules -bool efi_analysis::efi_analyser_x86_t::findImageHandleX64() { +bool efi_analysis::efi_analyser_x86_t::find_image_handle64() { msg("[%s] gImageHandle finding\n", g_plugin_name); insn_t insn; for (int idx = 0; idx < get_entry_qty(); idx++) { @@ -235,7 +235,7 @@ bool efi_analysis::efi_analyser_x86_t::findImageHandleX64() { //-------------------------------------------------------------------------- // Find gST address for X64 modules -bool efi_analysis::efi_analyser_x86_t::findSystemTableX64() { +bool efi_analysis::efi_analyser_x86_t::find_system_table64() { msg("[%s] gEfiSystemTable finding\n", g_plugin_name); insn_t insn; for (int idx = 0; idx < get_entry_qty(); idx++) { @@ -260,7 +260,7 @@ bool efi_analysis::efi_analyser_x86_t::findSystemTableX64() { //-------------------------------------------------------------------------- // Find and mark gSmst global variable address for X64 module -bool efi_analysis::efi_analyser_x86_t::findSmstX64() { +bool efi_analysis::efi_analyser_x86_t::find_smst64() { msg("[%s] gSmst finding\n", g_plugin_name); ea_list_t smst_listSmmBase = findSmstSmmBase(bs_list); ea_list_t smst_listSwDispatch = findSmstSwDispatch(bs_list); @@ -282,7 +282,7 @@ bool efi_analysis::efi_analyser_x86_t::findSmstX64() { //-------------------------------------------------------------------------- // Find and mark gSmst global and local variable address for X64 module // after Hex-Rays based analysis -bool efi_analysis::efi_analyser_x86_t::findSmstPostProcX64() { +bool efi_analysis::efi_analyser_x86_t::find_smst_postproc64() { for (auto ea : g_get_smst_location_calls) { msg("[%s] EfiSmmBase2Protocol->GetSmstLocation call: 0x%016llX\n", g_plugin_name, u64_addr(ea)); @@ -400,7 +400,7 @@ bool efi_analysis::efi_analyser_x86_t::findSmstPostProcX64() { //-------------------------------------------------------------------------- // Find gBS addresses for 32-bit/64-bit modules -bool efi_analysis::efi_analyser_x86_t::findBootServicesTables() { +bool efi_analysis::efi_analyser_x86_t::find_boot_services_tables() { // init architecture-specific constants auto BS_OFFSET = BS_OFFSET_64; uint16_t REG_SP = static_cast(REG_RSP); @@ -513,7 +513,7 @@ bool efi_analysis::efi_analyser_x86_t::findBootServicesTables() { //-------------------------------------------------------------------------- // Find gRT addresses for X86/X64 modules -bool efi_analysis::efi_analyser_x86_t::findRuntimeServicesTables() { +bool efi_analysis::efi_analyser_x86_t::find_runtime_services_tables() { // init architecture-specific constants auto RT_OFFSET = RT_OFFSET_64; uint16_t REG_SP = static_cast(REG_RSP); @@ -628,7 +628,7 @@ bool efi_analysis::efi_analyser_x86_t::findRuntimeServicesTables() { //-------------------------------------------------------------------------- // Get all boot services by xrefs for X86/X64 modules -void efi_analysis::efi_analyser_x86_t::getAllBootServices() { +void efi_analysis::efi_analyser_x86_t::get_boot_services_all() { msg("[%s] BootServices finding (xrefs)\n", g_plugin_name); if (!bs_list.size()) { @@ -727,7 +727,7 @@ void efi_analysis::efi_analyser_x86_t::getAllBootServices() { //-------------------------------------------------------------------------- // Get all runtime services for X86/X64 modules by xrefs -void efi_analysis::efi_analyser_x86_t::getAllRuntimeServices() { +void efi_analysis::efi_analyser_x86_t::get_runtime_services_all() { msg("[%s] RuntimeServices finding (xrefs)\n", g_plugin_name); if (!rt_list.size()) { @@ -811,7 +811,7 @@ void efi_analysis::efi_analyser_x86_t::getAllRuntimeServices() { //-------------------------------------------------------------------------- // Get all smm services for X64 modules -void efi_analysis::efi_analyser_x86_t::getAllSmmServicesX64() { +void efi_analysis::efi_analyser_x86_t::get_smm_services_all64() { msg("[%s] SmmServices finding (xrefs)\n", g_plugin_name); if (!smst_list.size()) { @@ -904,7 +904,7 @@ void efi_analysis::efi_analyser_x86_t::getAllSmmServicesX64() { // Currently should cover all PeiServices except EFI_PEI_COPY_MEM, // EFI_PEI_SET_MEM, EFI_PEI_RESET2_SYSTEM, and "Future Installed Services" // (EFI_PEI_FFS_FIND_BY_NAME, etc.) -void efi_analysis::efi_analyser_x86_t::getAllPeiServicesX86() { +void efi_analysis::efi_analyser_x86_t::get_pei_services_all32() { msg("[%s] PeiServices finding from 0x%016llX to 0x%016llX (all)\n", g_plugin_name, u64_addr(m_start_addr), u64_addr(m_end_addr)); ea_t ea = m_start_addr; @@ -987,7 +987,7 @@ void efi_analysis::efi_analyser_x86_t::getAllPeiServicesX86() { //-------------------------------------------------------------------------- // Get all EFI_PEI_READ_ONLY_VARIABLE2_PPI (GetVariable, NextVariableName) -void efi_analysis::efi_analyser_x86_t::getAllVariablePPICallsX86() { +void efi_analysis::efi_analyser_x86_t::get_variable_ppi_calls_all32() { msg("[%s] Variable PPI calls finding from 0x%016llX to 0x%016llX (all)\n", g_plugin_name, u64_addr(m_start_addr), u64_addr(m_end_addr)); ea_t ea = m_start_addr; @@ -1052,7 +1052,7 @@ void efi_analysis::efi_analyser_x86_t::getAllVariablePPICallsX86() { //-------------------------------------------------------------------------- // Get PPI names for X86 PEI modules -void efi_analysis::efi_analyser_x86_t::getPpiNamesX86() { +void efi_analysis::efi_analyser_x86_t::get_ppi_names32() { msg("[%s] PPI finding (PEI services)\n", g_plugin_name); ea_t start = m_start_addr; segment_t *seg_info = get_segm_by_name(".text"); @@ -1157,7 +1157,7 @@ void efi_analysis::efi_analyser_x86_t::getPpiNamesX86() { //-------------------------------------------------------------------------- // Get boot services by protocols for X64 modules -void efi_analysis::efi_analyser_x86_t::getProtBootServicesX64() { +void efi_analysis::efi_analyser_x86_t::get_prot_boot_services64() { insn_t insn; for (auto s : textSegments) { msg("[%s] BootServices finding from 0x%016llX to 0x%016llX (protocols)\n", @@ -1223,7 +1223,7 @@ void efi_analysis::efi_analyser_x86_t::getProtBootServicesX64() { //-------------------------------------------------------------------------- // Get boot services by protocols for X86 modules -void efi_analysis::efi_analyser_x86_t::getProtBootServicesX86() { +void efi_analysis::efi_analyser_x86_t::get_prot_boot_services32() { msg("[%s] BootServices finding from 0x%016llX to 0x%016llX (protocols)\n", g_plugin_name, u64_addr(m_start_addr), u64_addr(m_end_addr)); ea_t ea = m_start_addr; @@ -1267,7 +1267,7 @@ void efi_analysis::efi_analyser_x86_t::getProtBootServicesX86() { //-------------------------------------------------------------------------- // find other addresses of gBS variables for X86-64 modules -void efi_analysis::efi_analyser_x86_t::findOtherBsTablesX64() { +void efi_analysis::efi_analyser_x86_t::find_other_boot_services_tables64() { msg("[%s] find other addresses of gBS variables\n", g_plugin_name); for (auto s : m_all_services) { std::string table_name = s["table_name"]; @@ -1337,7 +1337,7 @@ bool efi_analysis::efi_analyser_t::add_protocol(std::string service_name, //-------------------------------------------------------------------------- // Extract protocols from InstallMultipleProtocolInterfaces service call bool efi_analysis::efi_analyser_x86_t:: - InstallMultipleProtocolInterfacesHandler() { + install_multiple_prot_interfaces_analyser() { ea_list_t addrs = m_boot_services["InstallMultipleProtocolInterfaces"]; std::map stack_params; insn_t insn; @@ -1423,7 +1423,7 @@ bool efi_analysis::efi_analyser_x86_t:: //-------------------------------------------------------------------------- // Get boot services protocols names for X64 modules -void efi_analysis::efi_analyser_x86_t::getBsProtNamesX64() { +void efi_analysis::efi_analyser_x86_t::get_bs_prot_names64() { if (!textSegments.size()) { return; } @@ -1432,7 +1432,7 @@ void efi_analysis::efi_analyser_x86_t::getBsProtNamesX64() { msg("[%s] protocols finding (boot services, start address = 0x%016llX)\n", g_plugin_name, u64_addr(start)); - InstallMultipleProtocolInterfacesHandler(); + install_multiple_prot_interfaces_analyser(); for (int i = 0; i < g_boot_services_table64_count; i++) { if (g_boot_services_table64[i].offset == InstallMultipleProtocolInterfacesOffset64) { @@ -1484,7 +1484,7 @@ void efi_analysis::efi_analyser_x86_t::getBsProtNamesX64() { } if (found) { - msg("[%s] getBsProtNamesX64: found protocol GUID parameter at " + msg("[%s] get_bs_prot_names64: found protocol GUID parameter at " "0x%016llX\n", g_plugin_name, u64_addr(guidCodeAddress)); auto guid = get_guid_by_address(guidDataAddress); @@ -1503,7 +1503,7 @@ void efi_analysis::efi_analyser_x86_t::getBsProtNamesX64() { //-------------------------------------------------------------------------- // Get boot services protocols names for X86 modules -void efi_analysis::efi_analyser_x86_t::getBsProtNamesX86() { +void efi_analysis::efi_analyser_x86_t::get_bs_prot_names32() { msg("[%s] protocols finding (boot services)\n", g_plugin_name); ea_t start = m_start_addr; segment_t *seg_info = get_segm_by_name(".text"); @@ -1557,7 +1557,7 @@ void efi_analysis::efi_analyser_x86_t::getBsProtNamesX86() { } if (found) { - msg("[%s] getBsProtNamesX86: found protocol GUID parameter at " + msg("[%s] get_bs_prot_names32: found protocol GUID parameter at " "0x%016llX\n", g_plugin_name, u64_addr(guidCodeAddress)); auto guid = get_guid_by_address(guidDataAddress); @@ -1576,7 +1576,7 @@ void efi_analysis::efi_analyser_x86_t::getBsProtNamesX86() { //-------------------------------------------------------------------------- // Get smm services protocols names for X64 modules -void efi_analysis::efi_analyser_x86_t::getSmmProtNamesX64() { +void efi_analysis::efi_analyser_x86_t::get_smm_prot_names64() { if (!textSegments.size()) { return; } @@ -1619,7 +1619,7 @@ void efi_analysis::efi_analyser_x86_t::getSmmProtNamesX64() { } if (found) { - msg("[%s] getSmmProtNamesX64: found protocol GUID parameter at " + msg("[%s] get_smm_prot_names64: found protocol GUID parameter at " "0x%016llX\n", g_plugin_name, u64_addr(guidCodeAddress)); auto guid = get_guid_by_address(guidDataAddress); @@ -1737,7 +1737,7 @@ void efi_analysis::efi_analyser_t::mark_data_guids() { //-------------------------------------------------------------------------- // Mark GUIDs found in local variables for X64 modules -void efi_analysis::efi_analyser_x86_t::markLocalGuidsX64() { +void efi_analysis::efi_analyser_x86_t::mark_local_guids64() { for (auto seg : textSegments) { segment_t *s = seg; ea_t ea = s->start_ea; @@ -2688,7 +2688,7 @@ bool efi_analysis::efi_analyse_main_x86_64() { // mark GUIDs analyser.mark_data_guids(); - analyser.markLocalGuidsX64(); + analyser.mark_local_guids64(); if (g_args.disable_ui) { analyser.m_ftype = g_args.module_type == module_type_t::pei @@ -2702,29 +2702,29 @@ bool efi_analysis::efi_analyse_main_x86_64() { // find global vars for gImageHandle, gST, gBS, gRT, gSmst if (analyser.m_ftype == ffs_file_type_t::dxe_smm) { - analyser.findImageHandleX64(); - analyser.findSystemTableX64(); - analyser.findBootServicesTables(); - analyser.findRuntimeServicesTables(); + analyser.find_image_handle64(); + analyser.find_system_table64(); + analyser.find_boot_services_tables(); + analyser.find_runtime_services_tables(); - analyser.findSmstX64(); + analyser.find_smst64(); // find Boot services and Runtime services - analyser.getProtBootServicesX64(); - analyser.findOtherBsTablesX64(); - analyser.getAllBootServices(); - analyser.getAllRuntimeServices(); + analyser.get_prot_boot_services64(); + analyser.find_other_boot_services_tables64(); + analyser.get_boot_services_all(); + analyser.get_runtime_services_all(); - analyser.getBsProtNamesX64(); + analyser.get_bs_prot_names64(); #ifdef HEX_RAYS apply_all_types_for_interfaces(analyser.m_all_protocols); - analyser.findSmstPostProcX64(); + analyser.find_smst_postproc64(); #endif // find SMM services - analyser.getAllSmmServicesX64(); - analyser.getSmmProtNamesX64(); + analyser.get_smm_services_all64(); + analyser.get_smm_prot_names64(); // mark protocols analyser.mark_interfaces(); @@ -2811,16 +2811,16 @@ bool efi_analysis::efi_analyse_main_x86_32() { if (analyser.m_ftype == ffs_file_type_t::dxe_smm) { // find global vars for gST, gBS, gRT - analyser.findBootServicesTables(); - analyser.findRuntimeServicesTables(); + analyser.find_boot_services_tables(); + analyser.find_runtime_services_tables(); // find boot services and runtime services - analyser.getAllRuntimeServices(); - analyser.getProtBootServicesX86(); - analyser.getAllBootServices(); + analyser.get_runtime_services_all(); + analyser.get_prot_boot_services32(); + analyser.get_boot_services_all(); // print and mark protocols - analyser.getBsProtNamesX86(); + analyser.get_bs_prot_names32(); analyser.mark_interfaces(); #ifdef HEX_RAYS @@ -2835,9 +2835,9 @@ bool efi_analysis::efi_analyse_main_x86_32() { detect_pei_services(get_func(addr)); } #endif - analyser.getAllPeiServicesX86(); - analyser.getPpiNamesX86(); - analyser.getAllVariablePPICallsX86(); + analyser.get_pei_services_all32(); + analyser.get_ppi_names32(); + analyser.get_variable_ppi_calls_all32(); analyser.mark_interfaces(); // search for vulnerabilities From 3e2a5f583be5af967ff7149f770d0e82712a5377 Mon Sep 17 00:00:00 2001 From: yeggor Date: Tue, 17 Sep 2024 20:30:29 +0100 Subject: [PATCH 30/69] efi_analyser -> efi_analysis --- efiXplorer/CMakeLists.txt | 6 +++--- efiXplorer/{efi_analyser.h => efi_analysis.h} | 9 +-------- efiXplorer/{efi_analyser_arm.cc => efi_analysis_arm.cc} | 2 +- efiXplorer/{efi_analyser_x86.cc => efi_analysis_x86.cc} | 2 +- efiXplorer/efixplorer.cc | 2 +- 5 files changed, 7 insertions(+), 14 deletions(-) rename efiXplorer/{efi_analyser.h => efi_analysis.h} (98%) rename efiXplorer/{efi_analyser_arm.cc => efi_analysis_arm.cc} (99%) rename efiXplorer/{efi_analyser_x86.cc => efi_analysis_x86.cc} (99%) diff --git a/efiXplorer/CMakeLists.txt b/efiXplorer/CMakeLists.txt index 68aac1ff..4d47bb4f 100644 --- a/efiXplorer/CMakeLists.txt +++ b/efiXplorer/CMakeLists.txt @@ -29,9 +29,9 @@ include_directories(${PROJECT_SOURCE_DIR}/3rd/nlohmann_json) set(efiXplorer_src "efi_defs.h" "efi_defs.cc" - "efi_analyser.h" - "efi_analyser_arm.cc" - "efi_analyser_X86.cc" + "efi_analysis.h" + "efi_analysis_arm.cc" + "efi_analysis_x86.cc" "efi_deps.cc" "efi_deps.h" "efi_global.cc" diff --git a/efiXplorer/efi_analyser.h b/efiXplorer/efi_analysis.h similarity index 98% rename from efiXplorer/efi_analyser.h rename to efiXplorer/efi_analysis.h index d3d6209e..41fffe8c 100644 --- a/efiXplorer/efi_analyser.h +++ b/efiXplorer/efi_analysis.h @@ -393,14 +393,7 @@ class efi_analyser_arm_t : public efi_analyser_t { void show_all_choosers(); private: - struct service_info_64bit { - char name[64]; - uint32_t offset; - uint32_t reg; - uint16_t arg_index; - }; - - struct service_info_64bit bs_table_aarch64[13] = { + service_info_64_t bs_table_aarch64[13] = { {"InstallProtocolInterface", 0x80, REG_X1, 1}, {"ReinstallProtocolInterface", 0x88, REG_X1, 1}, {"UninstallProtocolInterface", 0x90, REG_X1, 1}, diff --git a/efiXplorer/efi_analyser_arm.cc b/efiXplorer/efi_analysis_arm.cc similarity index 99% rename from efiXplorer/efi_analyser_arm.cc rename to efiXplorer/efi_analysis_arm.cc index 0357c617..c3881c9f 100644 --- a/efiXplorer/efi_analyser_arm.cc +++ b/efiXplorer/efi_analysis_arm.cc @@ -17,7 +17,7 @@ * */ -#include "efi_analyser.h" +#include "efi_analysis.h" #include "efi_global.h" #include "efi_ui.h" #include "efi_utils.h" diff --git a/efiXplorer/efi_analyser_x86.cc b/efiXplorer/efi_analysis_x86.cc similarity index 99% rename from efiXplorer/efi_analyser_x86.cc rename to efiXplorer/efi_analysis_x86.cc index 52b63038..5ca5dc23 100644 --- a/efiXplorer/efi_analyser_x86.cc +++ b/efiXplorer/efi_analysis_x86.cc @@ -17,7 +17,7 @@ * */ -#include "efi_analyser.h" +#include "efi_analysis.h" #include "efi_global.h" #include "efi_ui.h" #include "efi_utils.h" diff --git a/efiXplorer/efixplorer.cc b/efiXplorer/efixplorer.cc index 4fe87646..70301053 100644 --- a/efiXplorer/efixplorer.cc +++ b/efiXplorer/efixplorer.cc @@ -17,7 +17,7 @@ * */ -#include "efi_analyser.h" +#include "efi_analysis.h" #include "efi_global.h" #include "efi_ui.h" From 1f8e129fe49edd66af08dfbd6102558aff5a779d Mon Sep 17 00:00:00 2001 From: yeggor Date: Tue, 17 Sep 2024 21:22:46 +0100 Subject: [PATCH 31/69] refactor efi_defs: - move types from utils - remove enums with services offsets --- efiXplorer/efi_analysis.h | 259 ++++++++++++------------ efiXplorer/efi_analysis_arm.cc | 8 +- efiXplorer/efi_analysis_x86.cc | 123 ++++++------ efiXplorer/efi_defs.cc | 289 ++++++++++++--------------- efiXplorer/efi_defs.h | 355 ++++++++++++--------------------- efiXplorer/efi_deps.h | 1 - efiXplorer/efi_global.h | 4 +- efiXplorer/efi_hexrays.h | 1 - efiXplorer/efi_smm_utils.cc | 81 ++++---- efiXplorer/efi_smm_utils.h | 3 +- efiXplorer/efi_ui.h | 1 - efiXplorer/efi_utils.cc | 31 ++- efiXplorer/efi_utils.h | 74 +------ efiXplorer/efixplorer.cc | 2 +- 14 files changed, 516 insertions(+), 716 deletions(-) diff --git a/efiXplorer/efi_analysis.h b/efiXplorer/efi_analysis.h index 41fffe8c..fb538d52 100644 --- a/efiXplorer/efi_analysis.h +++ b/efiXplorer/efi_analysis.h @@ -22,11 +22,9 @@ #include "efi_defs.h" #include "efi_smm_utils.h" #include "efi_utils.h" - #ifdef HEX_RAYS #include "efi_hexrays.h" #endif - #include #include @@ -125,192 +123,201 @@ class efi_analyser_t { }; // EFI_SMM_SW_DISPATCH2_PROTOCOL_GUID - EfiGuid m_sw_guid2 = {0x18a3c6dc, - 0x5eea, - 0x48c8, - {0xa1, 0xc1, 0xb5, 0x33, 0x89, 0xf9, 0x89, 0x99}}; + efi_guid_t m_sw_guid2 = {0x18a3c6dc, + 0x5eea, + 0x48c8, + {0xa1, 0xc1, 0xb5, 0x33, 0x89, 0xf9, 0x89, 0x99}}; // EFI_SMM_SW_DISPATCH_PROTOCOL_GUID - EfiGuid m_sw_guid = {0xe541b773, - 0xdd11, - 0x420c, - {0xb0, 0x26, 0xdf, 0x99, 0x36, 0x53, 0xf8, 0xbf}}; + efi_guid_t m_sw_guid = {0xe541b773, + 0xdd11, + 0x420c, + {0xb0, 0x26, 0xdf, 0x99, 0x36, 0x53, 0xf8, 0xbf}}; // EFI_SMM_SX_DISPATCH2_PROTOCOL_GUID - EfiGuid m_sx_guid2 = {0x456d2859, - 0xa84b, - 0x4e47, - {0xa2, 0xee, 0x32, 0x76, 0xd8, 0x86, 0x99, 0x7d}}; + efi_guid_t m_sx_guid2 = {0x456d2859, + 0xa84b, + 0x4e47, + {0xa2, 0xee, 0x32, 0x76, 0xd8, 0x86, 0x99, 0x7d}}; // EFI_SMM_SX_DISPATCH_PROTOCOL_GUID - EfiGuid m_sx_guid = {0x14FC52BE, - 0x01DC, - 0x426C, - {0x91, 0xAE, 0xA2, 0x3C, 0x3E, 0x22, 0x0A, 0xE8}}; + efi_guid_t m_sx_guid = {0x14FC52BE, + 0x01DC, + 0x426C, + {0x91, 0xAE, 0xA2, 0x3C, 0x3E, 0x22, 0x0A, 0xE8}}; // EFI_SMM_IO_TRAP_DISPATCH2_PROTOCOL_GUID - EfiGuid m_io_trap_guid2 = {0x58DC368D, - 0x7BFA, - 0x4E77, - {0xAB, 0xBC, 0x0E, 0x29, 0x41, 0x8D, 0xF9, 0x30}}; + efi_guid_t m_io_trap_guid2 = { + 0x58DC368D, + 0x7BFA, + 0x4E77, + {0xAB, 0xBC, 0x0E, 0x29, 0x41, 0x8D, 0xF9, 0x30}}; // EFI_SMM_IO_TRAP_DISPATCH_PROTOCOL_GUID - EfiGuid m_io_trap_guid = {0xDB7F536B, - 0xEDE4, - 0x4714, - {0xA5, 0xC8, 0xE3, 0x46, 0xEB, 0xAA, 0x20, 0x1D}}; + efi_guid_t m_io_trap_guid = { + 0xDB7F536B, + 0xEDE4, + 0x4714, + {0xA5, 0xC8, 0xE3, 0x46, 0xEB, 0xAA, 0x20, 0x1D}}; // EFI_SMM_GPI_DISPATCH2_PROTOCOL_GUID - EfiGuid m_gpi_guid2 = {0x25566B03, - 0xB577, - 0x4CBF, - {0x95, 0x8C, 0xED, 0x66, 0x3E, 0xA2, 0x43, 0x80}}; + efi_guid_t m_gpi_guid2 = {0x25566B03, + 0xB577, + 0x4CBF, + {0x95, 0x8C, 0xED, 0x66, 0x3E, 0xA2, 0x43, 0x80}}; // EFI_SMM_GPI_DISPATCH_PROTOCOL_GUID - EfiGuid m_gpi_guid = {0xE0744B81, - 0x9513, - 0x49CD, - {0x8C, 0xEA, 0xE9, 0x24, 0x5E, 0x70, 0x39, 0xDA}}; + efi_guid_t m_gpi_guid = {0xE0744B81, + 0x9513, + 0x49CD, + {0x8C, 0xEA, 0xE9, 0x24, 0x5E, 0x70, 0x39, 0xDA}}; // EFI_SMM_USB_DISPATCH2_PROTOCOL_GUID - EfiGuid m_usb_guid2 = {0xEE9B8D90, - 0xC5A6, - 0x40A2, - {0xBD, 0xE2, 0x52, 0x55, 0x8D, 0x33, 0xCC, 0xA1}}; + efi_guid_t m_usb_guid2 = {0xEE9B8D90, + 0xC5A6, + 0x40A2, + {0xBD, 0xE2, 0x52, 0x55, 0x8D, 0x33, 0xCC, 0xA1}}; // EFI_SMM_USB_DISPATCH_PROTOCOL_GUID - EfiGuid m_usb_guid = {0xA05B6FFD, - 0x87AF, - 0x4E42, - {0x95, 0xC9, 0x62, 0x28, 0xB6, 0x3C, 0xF3, 0xF3}}; + efi_guid_t m_usb_guid = {0xA05B6FFD, + 0x87AF, + 0x4E42, + {0x95, 0xC9, 0x62, 0x28, 0xB6, 0x3C, 0xF3, 0xF3}}; // EFI_SMM_STANDBY_BUTTON_DISPATCH2_PROTOCOL_GUID - EfiGuid m_standby_button_guid2 = { + efi_guid_t m_standby_button_guid2 = { 0x7300C4A1, 0x43F2, 0x4017, {0xA5, 0x1B, 0xC8, 0x1A, 0x7F, 0x40, 0x58, 0x5B}}; // EFI_SMM_STANDBY_BUTTON_DISPATCH_PROTOCOL_GUID - EfiGuid m_standby_button_guid = { + efi_guid_t m_standby_button_guid = { 0x78965B98, 0xB0BF, 0x449E, {0x8B, 0x22, 0xD2, 0x91, 0x4E, 0x49, 0x8A, 0x98}}; // EFI_SMM_PERIODIC_TIMER_DISPATCH2_PROTOCOL_GUID - EfiGuid m_periodic_timer_guid2 = { + efi_guid_t m_periodic_timer_guid2 = { 0x4CEC368E, 0x8E8E, 0x4D71, {0x8B, 0xE1, 0x95, 0x8C, 0x45, 0xFC, 0x8A, 0x53}}; // EFI_SMM_PERIODIC_TIMER_DISPATCH_PROTOCOL_GUID - EfiGuid m_periodic_timer_guid = { + efi_guid_t m_periodic_timer_guid = { 0x9CCA03FC, 0x4C9E, 0x4A19, {0x9B, 0x06, 0xED, 0x7B, 0x47, 0x9B, 0xDE, 0x55}}; // EFI_SMM_POWER_BUTTON_DISPATCH2_PROTOCOL_GUID - EfiGuid m_power_button_guid2 = { + efi_guid_t m_power_button_guid2 = { 0x1B1183FA, 0x1823, 0x46A7, {0x88, 0x72, 0x9C, 0x57, 0x87, 0x55, 0x40, 0x9D}}; // EFI_SMM_POWER_BUTTON_DISPATCH_PROTOCOL_GUID - EfiGuid m_power_button_guid = { + efi_guid_t m_power_button_guid = { 0xB709EFA0, 0x47A6, 0x4B41, {0xB9, 0x31, 0x12, 0xEC, 0xE7, 0xA8, 0xEE, 0x56}}; // EFI_SMM_ICHN_DISPATCH_PROTOCOL_GUID - EfiGuid m_ichn_guid = {0xC50B323E, - 0x9075, - 0x4F2A, - {0xAC, 0x8E, 0xD2, 0x59, 0x6A, 0x10, 0x85, 0xCC}}; + efi_guid_t m_ichn_guid = {0xC50B323E, + 0x9075, + 0x4F2A, + {0xAC, 0x8E, 0xD2, 0x59, 0x6A, 0x10, 0x85, 0xCC}}; // EFI_SMM_ICHN_DISPATCH2_PROTOCOL_GUID - EfiGuid m_ichn_guid2 = {0xADF3A128, - 0x416D, - 0x4060, - {0x8D, 0xDF, 0x30, 0xA1, 0xD7, 0xAA, 0xB6, 0x99}}; + efi_guid_t m_ichn_guid2 = {0xADF3A128, + 0x416D, + 0x4060, + {0x8D, 0xDF, 0x30, 0xA1, 0xD7, 0xAA, 0xB6, 0x99}}; // PCH_TCO_SMI_DISPATCH_PROTOCOL_GUID - EfiGuid m_tco_guid = {0x9E71D609, - 0x6D24, - 0x47FD, - {0xB5, 0x72, 0x61, 0x40, 0xF8, 0xD9, 0xC2, 0xA4}}; + efi_guid_t m_tco_guid = {0x9E71D609, + 0x6D24, + 0x47FD, + {0xB5, 0x72, 0x61, 0x40, 0xF8, 0xD9, 0xC2, 0xA4}}; // PCH_PCIE_SMI_DISPATCH_PROTOCOL_GUID - EfiGuid m_pcie_guid = {0x3E7D2B56, - 0x3F47, - 0x42AA, - {0x8F, 0x6B, 0x22, 0xF5, 0x19, 0x81, 0x8D, 0xAB}}; + efi_guid_t m_pcie_guid = {0x3E7D2B56, + 0x3F47, + 0x42AA, + {0x8F, 0x6B, 0x22, 0xF5, 0x19, 0x81, 0x8D, 0xAB}}; // PCH_ACPI_SMI_DISPATCH_PROTOCOL_GUID - EfiGuid m_acpi_guid = {0xD52BB262, - 0xF022, - 0x49EC, - {0x86, 0xD2, 0x7A, 0x29, 0x3A, 0x7A, 0x5, 0x4B}}; + efi_guid_t m_acpi_guid = {0xD52BB262, + 0xF022, + 0x49EC, + {0x86, 0xD2, 0x7A, 0x29, 0x3A, 0x7A, 0x5, 0x4B}}; // PCH_GPIO_UNLOCK_SMI_DISPATCH_PROTOCOL_GUID - EfiGuid m_gpio_unlock_guid = { + efi_guid_t m_gpio_unlock_guid = { 0x83339EF7, 0x9392, 0x4716, {0x8D, 0x3A, 0xD1, 0xFC, 0x67, 0xCD, 0x55, 0xDB}}; // PCH_SMI_DISPATCH_PROTOCOL_GUID - EfiGuid m_pch_guid = {0xE6A81BBF, - 0x873D, - 0x47FD, - {0xB6, 0xBE, 0x61, 0xB3, 0xE5, 0x72, 0x9, 0x93}}; + efi_guid_t m_pch_guid = {0xE6A81BBF, + 0x873D, + 0x47FD, + {0xB6, 0xBE, 0x61, 0xB3, 0xE5, 0x72, 0x9, 0x93}}; // PCH_ESPI_SMI_DISPATCH_PROTOCOL_GUID - EfiGuid m_espi_guid = {0xB3C14FF3, - 0xBAE8, - 0x456C, - {0x86, 0x31, 0x27, 0xFE, 0x0C, 0xEB, 0x34, 0x0C}}; + efi_guid_t m_espi_guid = {0xB3C14FF3, + 0xBAE8, + 0x456C, + {0x86, 0x31, 0x27, 0xFE, 0x0C, 0xEB, 0x34, 0x0C}}; // EFI_ACPI_EN_DISPATCH_PROTOCOL_GUID - EfiGuid m_acpi_en_guid = {0xBD88EC68, - 0xEBE4, - 0x4F7B, - {0x93, 0x5A, 0x4F, 0x66, 0x66, 0x42, 0xE7, 0x5F}}; + efi_guid_t m_acpi_en_guid = { + 0xBD88EC68, + 0xEBE4, + 0x4F7B, + {0x93, 0x5A, 0x4F, 0x66, 0x66, 0x42, 0xE7, 0x5F}}; // EFI_ACPI_DIS_DISPATCH_PROTOCOL_GUID - EfiGuid m_acpi_dis_guid = {0x9C939BA6, - 0x1FCC, - 0x46F6, - {0xB4, 0xE1, 0x10, 0x2D, 0xBE, 0x18, 0x65, 0x67}}; + efi_guid_t m_acpi_dis_guid = { + 0x9C939BA6, + 0x1FCC, + 0x46F6, + {0xB4, 0xE1, 0x10, 0x2D, 0xBE, 0x18, 0x65, 0x67}}; // FCH_SMM_GPI_DISPATCH2_PROTOCOL_GUID - EfiGuid m_fch_gpi_guid2 = {0x7051ab6d, - 0x9ec2, - 0x42eb, - {0xa2, 0x13, 0xde, 0x48, 0x81, 0xf1, 0xf7, 0x87}}; + efi_guid_t m_fch_gpi_guid2 = { + 0x7051ab6d, + 0x9ec2, + 0x42eb, + {0xa2, 0x13, 0xde, 0x48, 0x81, 0xf1, 0xf7, 0x87}}; // FCH_SMM_IO_TRAP_DISPATCH2_PROTOCOL_GUID - EfiGuid m_fch_io_trap_guid2 = { + efi_guid_t m_fch_io_trap_guid2 = { 0x91288fc4, 0xe64b, 0x4ef9, {0xa4, 0x63, 0x66, 0x88, 0x0, 0x71, 0x7f, 0xca}}; // FCH_SMM_PERIODICAL_DISPATCH2_PROTOCOL_GUID - EfiGuid m_fch_periodical_guid2 = { + efi_guid_t m_fch_periodical_guid2 = { 0x736102f1, 0x9584, 0x44e7, {0x82, 0x8a, 0x43, 0x4b, 0x1e, 0x67, 0x5c, 0xc4}}; // FCH_SMM_PWR_BTN_DISPATCH2_PROTOCOL_GUID - EfiGuid m_fch_pwr_btn_guid2 = { + efi_guid_t m_fch_pwr_btn_guid2 = { 0xa365240e, 0x56b0, 0x426d, {0x83, 0xa, 0x30, 0x66, 0xc6, 0x81, 0xbe, 0x9a}}; // FCH_SMM_SW_DISPATCH2_PROTOCOL_GUID - EfiGuid m_fch_sw_guid2 = {0x881b4ab6, - 0x17b0, - 0x4bdf, - {0x88, 0xe2, 0xd4, 0x29, 0xda, 0x42, 0x5f, 0xfd}}; + efi_guid_t m_fch_sw_guid2 = { + 0x881b4ab6, + 0x17b0, + 0x4bdf, + {0x88, 0xe2, 0xd4, 0x29, 0xda, 0x42, 0x5f, 0xfd}}; // FCH_SMM_SX_DISPATCH2_PROTOCOL_GUID - EfiGuid m_fch_sx_guid2 = {0x87e2a6cf, - 0x91fb, - 0x4581, - {0x90, 0xa9, 0x6f, 0x50, 0x5d, 0xdc, 0x1c, 0xb2}}; + efi_guid_t m_fch_sx_guid2 = { + 0x87e2a6cf, + 0x91fb, + 0x4581, + {0x90, 0xa9, 0x6f, 0x50, 0x5d, 0xdc, 0x1c, 0xb2}}; // FCH_SMM_USB_DISPATCH_PROTOCOL_GUID - EfiGuid m_fch_usb_guid = {0x59053b0d, - 0xeeb8, - 0x4379, - {0xb1, 0xc8, 0x14, 0x5f, 0x1b, 0xb, 0xe4, 0xb9}}; + efi_guid_t m_fch_usb_guid = {0x59053b0d, + 0xeeb8, + 0x4379, + {0xb1, 0xc8, 0x14, 0x5f, 0x1b, 0xb, 0xe4, 0xb9}}; // FCH_SMM_USB_DISPATCH2_PROTOCOL_GUID - EfiGuid m_fch_usb_guid2 = {0xfbbb2ea9, - 0xce0e, - 0x4689, - {0xb3, 0xf0, 0xc6, 0xb8, 0xf0, 0x76, 0xbd, 0x20}}; + efi_guid_t m_fch_usb_guid2 = { + 0xfbbb2ea9, + 0xce0e, + 0x4689, + {0xb3, 0xf0, 0xc6, 0xb8, 0xf0, 0x76, 0xbd, 0x20}}; // FCH_SMM_MISC_DISPATCH_PROTOCOL_GUID - EfiGuid m_fch_misc_guid = {0x13bd659b, - 0xb4c6, - 0x47da, - {0x9b, 0x22, 0x11, 0x50, 0xd4, 0xf3, 0xb, 0xda}}; + efi_guid_t m_fch_misc_guid = { + 0x13bd659b, + 0xb4c6, + 0x47da, + {0x9b, 0x22, 0x11, 0x50, 0xd4, 0xf3, 0xb, 0xda}}; // FCH_SMM_APU_RAS_DISPATCH_PROTOCOL_GUID - EfiGuid m_fch_apu_ras_guid = { + efi_guid_t m_fch_apu_ras_guid = { 0xf871ee59, 0x29d2, 0x4b15, @@ -394,19 +401,19 @@ class efi_analyser_arm_t : public efi_analyser_t { private: service_info_64_t bs_table_aarch64[13] = { - {"InstallProtocolInterface", 0x80, REG_X1, 1}, - {"ReinstallProtocolInterface", 0x88, REG_X1, 1}, - {"UninstallProtocolInterface", 0x90, REG_X1, 1}, - {"HandleProtocol", 0x98, REG_X1, 1}, - {"RegisterProtocolNotify", 0xA8, REG_X0, 0}, - {"OpenProtocol", 0x118, REG_X1, 1}, - {"CloseProtocol", 0x120, REG_X1, 1}, - {"ProtocolsPerHandle", 0x128, REG_X1, 1}, - {"OpenProtocolInformation", 0x130, REG_X1, 1}, - {"LocateHandleBuffer", 0x138, REG_X1, 1}, - {"LocateProtocol", 0x140, REG_X0, 1}, - {"InstallMultipleProtocolInterfaces", 0x148, REG_X1, 1}, - {"UninstallMultipleProtocolInterfaces", 0x150, REG_X1, 1}}; + {"InstallProtocolInterface", 0x80, R_X1, 1}, + {"ReinstallProtocolInterface", 0x88, R_X1, 1}, + {"UninstallProtocolInterface", 0x90, R_X1, 1}, + {"HandleProtocol", 0x98, R_X1, 1}, + {"RegisterProtocolNotify", 0xA8, R_X0, 0}, + {"OpenProtocol", 0x118, R_X1, 1}, + {"CloseProtocol", 0x120, R_X1, 1}, + {"ProtocolsPerHandle", 0x128, R_X1, 1}, + {"OpenProtocolInformation", 0x130, R_X1, 1}, + {"LocateHandleBuffer", 0x138, R_X1, 1}, + {"LocateProtocol", 0x140, R_X0, 1}, + {"InstallMultipleProtocolInterfaces", 0x148, R_X1, 1}, + {"UninstallMultipleProtocolInterfaces", 0x150, R_X1, 1}}; bool get_protocol(ea_t address, uint32_t p_reg, std::string service_name); }; diff --git a/efiXplorer/efi_analysis_arm.cc b/efiXplorer/efi_analysis_arm.cc index c3881c9f..72eb2437 100644 --- a/efiXplorer/efi_analysis_arm.cc +++ b/efiXplorer/efi_analysis_arm.cc @@ -74,7 +74,7 @@ ea_t get_table_addr(ea_t code_addr, uint64_t offset) { decode_insn(&insn, code_addr); if (insn.itype != ARM_ldr || insn.ops[0].type != o_reg || insn.ops[1].type != o_displ || insn.ops[1].addr != offset || - insn.ops[1].reg == REG_XSP) { + insn.ops[1].reg == R_XSP) { return table; } uint8_t table_reg = insn.ops[0].reg; @@ -403,10 +403,10 @@ void efi_analysis::efi_analyser_arm_t::find_pei_services_function() { for (auto start_ea : m_funcs) { decode_insn(&insn, start_ea); if (!(insn.itype == ARM_mrs && insn.ops[0].type == o_reg && - insn.ops[0].reg == REG_X0 && insn.ops[1].type == o_imm && + insn.ops[0].reg == R_X0 && insn.ops[1].type == o_imm && insn.ops[1].value == 0x3 && insn.ops[2].type == o_idpspec3 && - insn.ops[2].reg == REG_C13 && insn.ops[3].type == o_idpspec3 && - insn.ops[3].reg == REG_C0 && insn.ops[4].type == o_imm && + insn.ops[2].reg == R_C13 && insn.ops[3].type == o_idpspec3 && + insn.ops[3].reg == R_C0 && insn.ops[4].type == o_imm && insn.ops[4].value == 0x2)) { continue; } diff --git a/efiXplorer/efi_analysis_x86.cc b/efiXplorer/efi_analysis_x86.cc index 5ca5dc23..62fdb807 100644 --- a/efiXplorer/efi_analysis_x86.cc +++ b/efiXplorer/efi_analysis_x86.cc @@ -21,7 +21,6 @@ #include "efi_global.h" #include "efi_ui.h" #include "efi_utils.h" - #ifdef HEX_RAYS #include "efi_hexrays.h" #endif @@ -218,7 +217,7 @@ bool efi_analysis::efi_analyser_x86_t::find_image_handle64() { for (auto i = 0; i < 8; i++) { decode_insn(&insn, ea); if (insn.itype == NN_mov && insn.ops[1].type == o_reg && - insn.ops[1].reg == REG_RCX && insn.ops[0].type == o_mem) { + insn.ops[1].reg == R_RCX && insn.ops[0].type == o_mem) { msg("[%s] found ImageHandle at 0x%016llX, address = 0x%016llX\n", g_plugin_name, u64_addr(ea), u64_addr(insn.ops[0].addr)); @@ -247,7 +246,7 @@ bool efi_analysis::efi_analyser_x86_t::find_system_table64() { for (int i = 0; i < 16; i++) { decode_insn(&insn, ea); if (insn.itype == NN_mov && insn.ops[1].type == o_reg && - insn.ops[1].reg == REG_RDX && insn.ops[0].type == o_mem) { + insn.ops[1].reg == R_RDX && insn.ops[0].type == o_mem) { set_ptr_type_and_name(insn.ops[0].addr, "gST", "EFI_SYSTEM_TABLE"); st_list.push_back(insn.ops[0].addr); return true; @@ -295,10 +294,10 @@ bool efi_analysis::efi_analyser_x86_t::find_smst_postproc64() { decode_insn(&insn, addr); if (insn.itype == NN_lea && insn.ops[0].type == o_reg && - insn.ops[0].reg == REG_RDX) { + insn.ops[0].reg == R_RDX) { switch (insn.ops[1].type) { case o_displ: - if (insn.ops[1].reg == REG_RSP || insn.ops[1].reg == REG_RBP) { + if (insn.ops[1].reg == R_RSP || insn.ops[1].reg == R_RBP) { smst_addr = insn.ops[1].addr; smst_stack["addr"] = smst_addr; smst_stack["reg"] = insn.ops[1].reg; @@ -333,14 +332,14 @@ bool efi_analysis::efi_analyser_x86_t::find_smst_postproc64() { } if (!smst_stack.is_null()) { - auto reg = smst_stack["reg"] == REG_RSP ? "RSP" : "RBP"; + auto reg = smst_stack["reg"] == R_RSP ? "RSP" : "RBP"; msg("[%s] Smst: 0x%016llX, reg = %s\n", g_plugin_name, u64_addr(smst_addr), reg); // try to extract ChildSwSmiHandler auto counter = 0; ea_t ea = static_cast(smst_stack["start"]); - uint16_t smst_reg = BADREG; + uint16_t smst_reg = NONE_REG; uint64_t rcx_last = BADADDR; while (ea < static_cast(smst_stack["end"])) { counter += 1; @@ -355,13 +354,13 @@ bool efi_analysis::efi_analyser_x86_t::find_smst_postproc64() { insn.ops[1].type == o_displ && smst_stack["addr"] == insn.ops[1].addr) { switch (insn.ops[1].reg) { - case REG_RSP: - if (smst_stack["reg"] == REG_RSP) { + case R_RSP: + if (smst_stack["reg"] == R_RSP) { smst_reg = insn.ops[0].reg; } break; - case REG_RBP: - if (smst_stack["reg"] == REG_RBP) { + case R_RBP: + if (smst_stack["reg"] == R_RBP) { smst_reg = insn.ops[0].reg; } default: @@ -371,17 +370,16 @@ bool efi_analysis::efi_analyser_x86_t::find_smst_postproc64() { // Save potencial ChildSwSmiHandler address if (insn.itype == NN_lea && insn.ops[0].type == o_reg && - insn.ops[0].reg == REG_RCX && insn.ops[1].type == o_mem) { + insn.ops[0].reg == R_RCX && insn.ops[1].type == o_mem) { rcx_last = insn.ops[1].addr; } - if (rcx_last == BADADDR || smst_reg == BADREG) { + if (rcx_last == BADADDR || smst_reg == NONE_REG) { continue; } if (insn.itype == NN_callni && insn.ops[0].type == o_displ && - insn.ops[0].reg == smst_reg && - insn.ops[0].addr == SmiHandlerRegisterOffset64) { + insn.ops[0].reg == smst_reg && insn.ops[0].addr == 0xe0) { op_stroff_util(ea, "_EFI_SMM_SYSTEM_TABLE2"); // save child SW SMI handler func_t *handler_func = get_func(rcx_last); @@ -403,11 +401,11 @@ bool efi_analysis::efi_analyser_x86_t::find_smst_postproc64() { bool efi_analysis::efi_analyser_x86_t::find_boot_services_tables() { // init architecture-specific constants auto BS_OFFSET = BS_OFFSET_64; - uint16_t REG_SP = static_cast(REG_RSP); + uint16_t R_SP = static_cast(R_RSP); if (m_arch == arch_file_type_t::x86_32) { BS_OFFSET = BS_OFFSET_32; - REG_SP = static_cast(REG_ESP); + R_SP = static_cast(R_ESP); } insn_t insn; @@ -423,7 +421,7 @@ bool efi_analysis::efi_analyser_x86_t::find_boot_services_tables() { ea = next_head(ea, m_end_addr); decode_insn(&insn, ea); if (insn.itype == NN_mov && insn.ops[1].type == o_displ && - insn.ops[1].phrase != REG_SP) { + insn.ops[1].phrase != R_SP) { if (insn.ops[0].type == o_reg && insn.ops[1].addr == BS_OFFSET) { auto bsFound = false; auto stFound = false; @@ -516,11 +514,11 @@ bool efi_analysis::efi_analyser_x86_t::find_boot_services_tables() { bool efi_analysis::efi_analyser_x86_t::find_runtime_services_tables() { // init architecture-specific constants auto RT_OFFSET = RT_OFFSET_64; - uint16_t REG_SP = static_cast(REG_RSP); + uint16_t R_SP = static_cast(R_RSP); if (m_arch == arch_file_type_t::x86_32) { RT_OFFSET = RT_OFFSET_32; - REG_SP = static_cast(REG_ESP); + R_SP = static_cast(R_ESP); } insn_t insn; @@ -536,7 +534,7 @@ bool efi_analysis::efi_analyser_x86_t::find_runtime_services_tables() { ea = next_head(ea, m_end_addr); decode_insn(&insn, ea); if (insn.itype == NN_mov && insn.ops[1].type == o_displ && - insn.ops[1].phrase != REG_SP) { + insn.ops[1].phrase != R_SP) { if (insn.ops[0].type == o_reg && insn.ops[1].addr == RT_OFFSET) { rtRegister = insn.ops[0].reg; stRegister = insn.ops[1].phrase; @@ -680,7 +678,7 @@ void efi_analysis::efi_analyser_x86_t::get_boot_services_all() { // additional check for gBS->RegisterProtocolNotify // (can be confused with // gSmst->SmmInstallProtocolInterface) - if (u32_addr(offset) == RegisterProtocolNotifyOffset64) { + if (u32_addr(offset) == 0xa8) { if (!check_boot_service_protocol(addr)) { break; } @@ -847,8 +845,7 @@ void efi_analysis::efi_analyser_x86_t::get_smm_services_all64() { for (int j = 0; j < g_smm_services_table_all_count; j++) { if (insn.ops[0].addr == u32_addr(g_smm_services_table_all[j].offset64)) { - if (u32_addr(g_smm_services_table_all[j].offset64) == - SmiHandlerRegisterOffset64) { + if (u32_addr(g_smm_services_table_all[j].offset64) == 0xe0) { // set name for Handler argument auto smiHandlerAddr = markChildSwSmiHandler(addr); // save SMI handler @@ -914,8 +911,8 @@ void efi_analysis::efi_analyser_x86_t::get_pei_services_all32() { ea = next_head(ea, BADADDR); decode_insn(&insn, ea); if (insn.itype == NN_callni && - (insn.ops[0].reg == REG_EAX || insn.ops[0].reg == REG_ECX || - insn.ops[0].reg == REG_EDX)) { + (insn.ops[0].reg == R_EAX || insn.ops[0].reg == R_ECX || + insn.ops[0].reg == R_EDX)) { for (int j = 0; j < g_pei_services_table32_count; j++) { if (insn.ops[0].addr == u32_addr(g_pei_services_table32[j].offset)) { bool found_src_reg = false; @@ -1060,7 +1057,7 @@ void efi_analysis::efi_analyser_x86_t::get_ppi_names32() { start = seg_info->start_ea; } for (int i = 0; i < g_pei_services_table32_count; i++) { - if (g_pei_services_table32[i].push_number == PUSH_NONE || + if (g_pei_services_table32[i].push_number == NONE_PUSH || !m_pei_services_all.contains(g_pei_services_table_all[i].name)) { continue; } @@ -1167,7 +1164,7 @@ void efi_analysis::efi_analyser_x86_t::get_prot_boot_services64() { while (ea <= s->end_ea) { ea = next_head(ea, m_end_addr); decode_insn(&insn, ea); - if (insn.itype != NN_callni || insn.ops[0].reg != REG_RAX) { + if (insn.itype != NN_callni || insn.ops[0].reg != R_RAX) { continue; } for (auto i = 0; i < g_boot_services_table64_count; i++) { @@ -1177,8 +1174,7 @@ void efi_analysis::efi_analyser_x86_t::get_prot_boot_services64() { // additional check for gBS->RegisterProtocolNotify // (can be confused with gSmst->SmmInstallProtocolInterface) - if (u32_addr(g_boot_services_table64[i].offset) == - RegisterProtocolNotifyOffset64) { + if (u32_addr(g_boot_services_table64[i].offset) == 0xa8) { if (!check_boot_service_protocol(ea)) { break; } @@ -1232,7 +1228,7 @@ void efi_analysis::efi_analyser_x86_t::get_prot_boot_services32() { while (ea <= m_end_addr) { ea = next_head(ea, m_end_addr); decode_insn(&insn, ea); - if (insn.itype == NN_callni && insn.ops[0].reg == REG_EAX) { + if (insn.itype == NN_callni && insn.ops[0].reg == R_EAX) { for (auto i = 0; i < g_boot_services_table32_count; i++) { if (insn.ops[0].addr == u32_addr(g_boot_services_table32[i].offset)) { op_stroff_util(ea, "EFI_BOOT_SERVICES"); @@ -1365,10 +1361,10 @@ bool efi_analysis::efi_analyser_x86_t:: // Get handle stack/data parameter if (handle_arg == BADADDR && insn.itype == NN_lea && - insn.ops[0].reg == REG_RCX) { + insn.ops[0].reg == R_RCX) { switch (insn.ops[1].type) { case o_displ: - if (insn.ops[1].reg == REG_RSP || insn.ops[1].reg == REG_RBP) { + if (insn.ops[1].reg == R_RSP || insn.ops[1].reg == R_RBP) { handle_arg = insn.ops[1].addr; } break; @@ -1379,13 +1375,13 @@ bool efi_analysis::efi_analyser_x86_t:: } // Exit from loop if found last argument - if (insn.itype == NN_xor && insn.ops[0].reg == REG_R9 && - insn.ops[1].reg == REG_R9) { + if (insn.itype == NN_xor && insn.ops[0].reg == R_R9 && + insn.ops[1].reg == R_R9) { check_stack = false; } if (insn.itype == NN_and && insn.ops[0].type == o_displ && - (insn.ops[0].reg == REG_RSP || insn.ops[0].reg == REG_RBP) && + (insn.ops[0].reg == R_RSP || insn.ops[0].reg == R_RBP) && insn.ops[0].addr != handle_arg && insn.ops[1].type == o_imm && insn.ops[1].value == 0) { check_stack = false; @@ -1395,13 +1391,13 @@ bool efi_analysis::efi_analyser_x86_t:: if (insn.itype == NN_lea && insn.ops[0].type == o_reg && insn.ops[1].type == o_mem) { switch (insn.ops[0].reg) { - case REG_RDX: - case REG_R9: + case R_RDX: + case R_R9: add_protocol("InstallMultipleProtocolInterfaces", insn.ops[1].addr, address, ea); found = true; break; - case REG_RAX: + case R_RAX: stack_params.insert(std::make_pair(address, insn.ops[1].addr)); break; } @@ -1434,8 +1430,7 @@ void efi_analysis::efi_analyser_x86_t::get_bs_prot_names64() { install_multiple_prot_interfaces_analyser(); for (int i = 0; i < g_boot_services_table64_count; i++) { - if (g_boot_services_table64[i].offset == - InstallMultipleProtocolInterfacesOffset64) { + if (g_boot_services_table64[i].offset == 0x148) { // Handle InstallMultipleProtocolInterfaces separately continue; } @@ -1525,7 +1520,7 @@ void efi_analysis::efi_analyser_x86_t::get_bs_prot_names32() { uint16_t pushNumber = g_boot_services_table32[i].push_number; // if service is not currently being processed - if (pushNumber == PUSH_NONE) { + if (pushNumber == NONE_PUSH) { break; } @@ -1842,7 +1837,7 @@ void findCalloutRec(func_t *func) { decode_insn(&next_insn, addr); if ((next_insn.itype == NN_jmpni || next_insn.itype == NN_callni) && next_insn.ops[0].type == o_displ && next_insn.ops[0].reg == reg && - next_insn.ops[0].addr == FreePoolOffset64) { + next_insn.ops[0].addr == 0x48) { fp = true; break; } @@ -1875,7 +1870,7 @@ void findCalloutRec(func_t *func) { // chcek if it looks like interface decode_insn(&insn_xref, xref); if (insn_xref.itype != NN_lea || insn_xref.ops[0].type != o_reg || - insn_xref.ops[0].reg != REG_R8) { + insn_xref.ops[0].reg != R_R8) { continue; } @@ -1888,9 +1883,9 @@ void findCalloutRec(func_t *func) { if (next_insn.itype == NN_callni && next_insn.ops[0].type == o_displ && - next_insn.ops[0].reg == REG_RAX) { - if (next_insn.ops[0].addr == LocateProtocolOffset64 || - next_insn.ops[0].addr == AllocatePoolOffset64) { + next_insn.ops[0].reg == R_RAX) { + if (next_insn.ops[0].addr == 0x140 || + next_insn.ops[0].addr == 0x40) { // found callout msg("[%s] SMM callout found (usage of memory controlled by " "the attacker inside SMI handler): 0x%016llX\n", @@ -1916,7 +1911,7 @@ void findCalloutRec(func_t *func) { //-------------------------------------------------------------------------- // find SmiHandler functions in SMM modules void efi_analysis::efi_analyser_t::find_smi_handlers() { - std::map types = { + std::map types = { {&m_sw_guid2, "Sw"}, {&m_sw_guid, "Sw"}, {&m_sx_guid2, "Sx"}, @@ -2187,7 +2182,7 @@ bool efi_analysis::efi_analyser_t::find_double_get_variable( for (auto i = 0; i < 10; ++i) { decode_insn(&insn, ea); if (insn.itype == NN_lea && insn.ops[0].type == o_reg && - insn.ops[0].reg == REG_R9) { + insn.ops[0].reg == R_R9) { dataSizeStackAddr = insn.ops[1].addr; dataSizeOpReg = insn.ops[1].phrase; break; @@ -2237,7 +2232,7 @@ bool efi_analysis::efi_analyser_t::find_double_get_variable( decode_insn(&insn, prev_head(curr_addr, 0)); if (!wrong_detection && !(insn.itype == NN_mov && insn.ops[0].type == o_displ && - (insn.ops[0].phrase == REG_RSP || insn.ops[0].phrase == REG_RBP) && + (insn.ops[0].phrase == R_RSP || insn.ops[0].phrase == R_RBP) && (insn.ops[0].addr == dataSizeStackAddr))) { init_ok = true; } @@ -2253,7 +2248,7 @@ bool efi_analysis::efi_analyser_t::find_double_get_variable( } uint16 stack_base_reg = 0xFF; decode_insn(&insn, func_start->start_ea); - if (insn.itype == NN_mov && insn.ops[1].is_reg(REG_RSP) && + if (insn.itype == NN_mov && insn.ops[1].is_reg(R_RSP) && insn.ops[0].type == o_reg) { stack_base_reg = insn.ops[0].reg; } @@ -2263,7 +2258,7 @@ bool efi_analysis::efi_analyser_t::find_double_get_variable( if (insn.itype == NN_call) break; if (insn.itype == NN_lea && insn.ops[0].type == o_reg && - insn.ops[0].reg == REG_R9) { + insn.ops[0].reg == R_R9) { ea_t stack_addr = insn.ops[1].addr; sval_t sval = get_spd(func_start, ea) * -1; @@ -2310,7 +2305,7 @@ bool efi_analysis::efi_analyser_t::find_double_get_variable_smm() { for (auto i = 0; i < 10; ++i) { decode_insn(&insn, ea); if (insn.itype == NN_lea && insn.ops[0].type == o_reg && - insn.ops[0].reg == REG_R9) { + insn.ops[0].reg == R_R9) { dataSizeStackAddr = insn.ops[1].addr; break; } @@ -2336,7 +2331,7 @@ bool efi_analysis::efi_analyser_t::find_double_get_variable_smm() { bool init_ok = false; decode_insn(&insn, prev_head(curr_addr, 0)); if (!(insn.itype == NN_mov && insn.ops[0].type == o_displ && - (insn.ops[0].phrase == REG_RSP || insn.ops[0].phrase == REG_RBP))) { + (insn.ops[0].phrase == R_RSP || insn.ops[0].phrase == R_RBP))) { init_ok = true; } @@ -2347,7 +2342,7 @@ bool efi_analysis::efi_analyser_t::find_double_get_variable_smm() { for (auto i = 0; i < 10; ++i) { decode_insn(&insn, ea); if (insn.itype == NN_lea && insn.ops[0].type == o_reg && - insn.ops[0].reg == REG_R9) { + insn.ops[0].reg == R_R9) { if (dataSizeStackAddr == insn.ops[1].addr) { smmGetVariableOverflow.push_back(curr_addr); msg("[%s] \toverflow can occur here: 0x%016llX\n", g_plugin_name, @@ -2389,7 +2384,7 @@ bool efi_analysis::efi_analyser_t::analyse_variable_service( auto addr = args[0]; // Get VariableName decode_insn(&insn, addr); if (insn.itype == NN_lea && insn.ops[0].type == o_reg && - insn.ops[0].reg == REG_RCX && insn.ops[1].type == o_mem) { + insn.ops[0].reg == R_RCX && insn.ops[1].type == o_mem) { msg("[%s] VariableName address: 0x%016llX\n", g_plugin_name, u64_addr(insn.ops[1].addr)); std::string var_name = get_wide_string(insn.ops[1].addr); @@ -2406,30 +2401,30 @@ bool efi_analysis::efi_analyser_t::analyse_variable_service( decode_insn(&insn, addr); // If GUID is global variable if (insn.itype == NN_lea && insn.ops[0].type == o_reg && - insn.ops[0].reg == REG_RDX && insn.ops[1].type == o_mem) { + insn.ops[0].reg == R_RDX && insn.ops[1].type == o_mem) { msg("[%s] VendorGuid address (global): 0x%016llX\n", g_plugin_name, u64_addr(insn.ops[1].addr)); - EfiGuid guid = get_global_guid(insn.ops[1].addr); + efi_guid_t guid = get_global_guid(insn.ops[1].addr); msg("[%s] GUID: %s\n", g_plugin_name, guid.to_string().c_str()); item["VendorGuid"] = guid.to_string(); guid_found = true; } // If GUID is local variable if (!guid_found && insn.itype == NN_lea && insn.ops[0].type == o_reg && - insn.ops[0].reg == REG_RDX && insn.ops[1].type == o_displ) { + insn.ops[0].reg == R_RDX && insn.ops[1].type == o_displ) { switch (insn.ops[1].reg) { - case REG_RBP: { + case R_RBP: { msg("[%s] VendorGuid address (regarding to RBP): 0x%016llX\n", g_plugin_name, u64_addr(insn.ops[1].addr)); - EfiGuid guid = get_local_guid(f, insn.ops[1].addr); + efi_guid_t guid = get_local_guid(f, insn.ops[1].addr); msg("[%s] GUID: %s\n", g_plugin_name, guid.to_string().c_str()); item["VendorGuid"] = guid.to_string(); guid_found = true; } - case REG_RSP: { + case R_RSP: { msg("[%s] VendorGuid address (regarding to RSP): 0x%016llX\n", g_plugin_name, u64_addr(insn.ops[1].addr)); - EfiGuid guid = get_local_guid(f, insn.ops[1].addr); + efi_guid_t guid = get_local_guid(f, insn.ops[1].addr); msg("[%s] GUID: %s\n", g_plugin_name, guid.to_string().c_str()); item["VendorGuid"] = guid.to_string(); guid_found = true; @@ -2448,7 +2443,7 @@ bool efi_analysis::efi_analyser_t::analyse_variable_service( decode_insn(&insn, addr); if (insn.itype == NN_xor && insn.ops[0].type == o_reg && insn.ops[1].type == o_reg && insn.ops[0].reg == insn.ops[1].reg && - insn.ops[0].reg == REG_R8) { + insn.ops[0].reg == R_R8) { item["Attributes"] = 0; std::string attributes_hr = "No attributes"; item["AttributesHumanReadable"] = attributes_hr; diff --git a/efiXplorer/efi_defs.cc b/efiXplorer/efi_defs.cc index 9d8301ca..7135df4e 100644 --- a/efiXplorer/efi_defs.cc +++ b/efiXplorer/efi_defs.cc @@ -22,164 +22,129 @@ const char *g_plugin_name = "efiXplorer"; service_info_64_t g_boot_services_table64[] = { - {"InstallProtocolInterface", InstallProtocolInterfaceOffset64, REG_RDX, 1}, - {"ReinstallProtocolInterface", RenstallProtocolInterfaceOffset64, REG_RDX, - 1}, - {"UninstallProtocolInterface", UninstallProtocolInterfaceOffset64, REG_RDX, - 1}, - {"HandleProtocol", HandleProtocolOffset64, REG_RDX, 1}, - {"RegisterProtocolNotify", RegisterProtocolNotifyOffset64, REG_RCX, 0}, - {"OpenProtocol", OpenProtocolOffset64, REG_RDX, 1}, - {"CloseProtocol", CloseProtocolOffset64, REG_RDX, 1}, - {"ProtocolsPerHandle", ProtocolsPerHandleOffset64, REG_RDX, 1}, - {"OpenProtocolInformation", OpenProtocolInformationOffset64, REG_RDX, 1}, - {"LocateHandleBuffer", LocateHandleBufferOffset64, REG_RDX, 1}, - {"LocateProtocol", LocateProtocolOffset64, REG_RCX, 0}, - {"InstallMultipleProtocolInterfaces", - InstallMultipleProtocolInterfacesOffset64, REG_RDX, 1}, - {"UninstallMultipleProtocolInterfaces", - UninstallMultipleProtocolInterfacesOffset64, REG_RDX, 1}}; + {"InstallProtocolInterface", 0x80, R_RDX, 1}, + {"ReinstallProtocolInterface", 0x88, R_RDX, 1}, + {"UninstallProtocolInterface", 0x90, R_RDX, 1}, + {"HandleProtocol", 0x98, R_RDX, 1}, + {"RegisterProtocolNotify", 0xa8, R_RCX, 0}, + {"OpenProtocol", 0x118, R_RDX, 1}, + {"CloseProtocol", 0x120, R_RDX, 1}, + {"ProtocolsPerHandle", 0x130, R_RDX, 1}, + {"OpenProtocolInformation", 0x128, R_RDX, 1}, + {"LocateHandleBuffer", 0x138, R_RDX, 1}, + {"LocateProtocol", 0x140, R_RCX, 0}, + {"InstallMultipleProtocolInterfaces", 0x148, R_RDX, 1}, + {"UninstallMultipleProtocolInterfaces", 0x150, R_RDX, 1}}; size_t g_boot_services_table64_count = sizeof(g_boot_services_table64) / sizeof(service_info_64_t); service_info_32_t g_boot_services_table32[] = { - {"InstallProtocolInterface", InstallProtocolInterfaceOffset32, 2}, - {"ReinstallProtocolInterface", RenstallProtocolInterfaceOffset32, 2}, - {"UninstallProtocolInterface", UninstallProtocolInterfaceOffset32, 2}, - {"HandleProtocol", HandleProtocolOffset32, 2}, - {"RegisterProtocolNotify", RegisterProtocolNotifyOffset32, 1}, - {"OpenProtocol", OpenProtocolOffset32, 2}, - {"CloseProtocol", CloseProtocolOffset32, 2}, - {"ProtocolsPerHandle", ProtocolsPerHandleOffset32, 2}, - {"OpenProtocolInformation", OpenProtocolInformationOffset32, 2}, - {"LocateHandleBuffer", LocateHandleBufferOffset32, 2}, - {"LocateProtocol", LocateProtocolOffset32, 1}, - {"InstallMultipleProtocolInterfaces", - InstallMultipleProtocolInterfacesOffset32, 2}, - {"UninstallMultipleProtocolInterfaces", - UninstallMultipleProtocolInterfacesOffset32, 2}}; + {"InstallProtocolInterface", 0x4c, 2}, + {"ReinstallProtocolInterface", 0x50, 2}, + {"UninstallProtocolInterface", 0x54, 2}, + {"HandleProtocol", 0x58, 2}, + {"RegisterProtocolNotify", 0x60, 1}, + {"OpenProtocol", 0x98, 2}, + {"CloseProtocol", 0x9c, 2}, + {"ProtocolsPerHandle", 0xa4, 2}, + {"OpenProtocolInformation", 0xa0, 2}, + {"LocateHandleBuffer", 0xa8, 2}, + {"LocateProtocol", 0xac, 1}, + {"InstallMultipleProtocolInterfaces", 0xb0, 2}, + {"UninstallMultipleProtocolInterfaces", 0xb4, 2}}; size_t g_boot_services_table32_count = sizeof(g_boot_services_table32) / sizeof(service_info_32_t); service_t g_boot_services_table_all[] = { - // difficult to detect false positives - // {"RaiseTPL", RaiseTPLOffset64, RaiseTPLOffset32}, - // {"RestoreTPL", RestoreTPLOffset64, RestoreTPLOffset32}, - {"AllocatePages", AllocatePagesOffset64, AllocatePagesOffset32}, - {"FreePages", FreePagesOffset64, FreePagesOffset32}, - {"GetMemoryMap", GetMemoryMapOffset64, GetMemoryMapOffset32}, - {"AllocatePool", AllocatePoolOffset64, AllocatePoolOffset32}, - {"FreePool", FreePoolOffset64, FreePoolOffset32}, - {"CreateEvent", CreateEventOffset64, CreateEventOffset32}, - {"SetTimer", SetTimerOffset64, SetTimerOffset32}, - {"WaitForEvent", WaitForEventOffset64, WaitForEventOffset32}, - {"SignalEvent", SignalEventOffset64, SignalEventOffset32}, - {"CloseEvent", CloseEventOffset64, CloseEventOffset32}, - {"CheckEvent", CheckEventOffset64, CheckEventOffset32}, - {"InstallProtocolInterface", InstallProtocolInterfaceOffset64, - InstallProtocolInterfaceOffset32}, - {"ReinstallProtocolInterface", RenstallProtocolInterfaceOffset64, - RenstallProtocolInterfaceOffset32}, - {"UninstallProtocolInterface", UninstallProtocolInterfaceOffset64, - UninstallProtocolInterfaceOffset32}, - {"HandleProtocol", HandleProtocolOffset64, HandleProtocolOffset32}, - {"RegisterProtocolNotify", RegisterProtocolNotifyOffset64, - RegisterProtocolNotifyOffset32}, - {"LocateHandle", LocateHandleOffset64, LocateHandleOffset32}, - {"LocateDevicePath", LocateDevicePathOffset64, LocateDevicePathOffset32}, - {"InstallConfigurationTable", InstallConfigurationTableOffset64, - InstallConfigurationTableOffset32}, - {"LoadImage", LoadImageOffset64, LoadImageOffset32}, - {"StartImage", StartImageOffset64, StartImageOffset32}, - {"Exit", ExitOffset64, ExitOffset32}, - {"UnloadImage", UnloadImageOffset64, UnloadImageOffset32}, - {"ExitBootServices", ExitBootServicesOffset64, ExitBootServicesOffset32}, - {"GetNextMonotonicCount", GetNextMonotonicCountOffset64, - GetNextMonotonicCountOffset32}, - {"Stall", StallOffset64, StallOffset32}, - {"SetWatchdogTimer", SetWatchdogTimerOffset64, SetWatchdogTimerOffset32}, - {"ConnectController", ConnectControllerOffset64, ConnectControllerOffset32}, - {"DisconnectController", DisconnectControllerOffset64, - DisconnectControllerOffset32}, - {"OpenProtocol", OpenProtocolOffset64, OpenProtocolOffset32}, - {"CloseProtocol", CloseProtocolOffset64, CloseProtocolOffset32}, - {"OpenProtocolInformation", OpenProtocolInformationOffset64, - OpenProtocolInformationOffset32}, - {"ProtocolsPerHandle", ProtocolsPerHandleOffset64, - ProtocolsPerHandleOffset32}, - {"LocateHandleBuffer", LocateHandleBufferOffset64, - LocateHandleBufferOffset32}, - {"LocateProtocol", LocateProtocolOffset64, LocateProtocolOffset32}, - {"InstallMultipleProtocolInterfaces", - InstallMultipleProtocolInterfacesOffset64, - InstallMultipleProtocolInterfacesOffset32}, - {"UninstallMultipleProtocolInterfaces", - UninstallMultipleProtocolInterfacesOffset64, - UninstallMultipleProtocolInterfacesOffset32}, - {"CalculateCrc32", CalculateCrc32Offset64, CalculateCrc32Offset32}, - {"CopyMem", CopyMemOffset64, CopyMemOffset32}, - {"SetMem", SetMemOffset64, SetMemOffset32}, - {"CreateEventEx", CreateEventExOffset64, CreateEventExOffset32}}; + // skip RaiseTPL and RestoreTPL to avoid FPs + {"AllocatePages", 0x28, 0x20}, + {"FreePages", 0x30, 0x24}, + {"GetMemoryMap", 0x38, 0x28}, + {"AllocatePool", 0x40, 0x2c}, + {"FreePool", 0x48, 0x30}, + {"CreateEvent", 0x50, 0x34}, + {"SetTimer", 0x58, 0x38}, + {"WaitForEvent", 0x60, 0x3c}, + {"SignalEvent", 0x68, 0x40}, + {"CloseEvent", 0x70, 0x44}, + {"CheckEvent", 0x78, 0x48}, + {"InstallProtocolInterface", 0x80, 0x4c}, + {"ReinstallProtocolInterface", 0x88, 0x50}, + {"UninstallProtocolInterface", 0x90, 0x54}, + {"HandleProtocol", 0x98, 0x58}, + {"RegisterProtocolNotify", 0xa8, 0x60}, + {"LocateHandle", 0xb0, 0x64}, + {"LocateDevicePath", 0xb8, 0x68}, + {"InstallConfigurationTable", 0xc0, 0x6c}, + {"LoadImage", 0xc8, 0x70}, + {"StartImage", 0xd0, 0x74}, + {"Exit", 0xd8, 0x78}, + {"UnloadImage", 0xe0, 0x7c}, + {"ExitBootServices", 0xe8, 0x80}, + {"GetNextMonotonicCount", 0xf0, 0x84}, + {"Stall", 0xf8, 0x88}, + {"SetWatchdogTimer", 0x100, 0x8c}, + {"ConnectController", 0x108, 0x90}, + {"DisconnectController", 0x110, 0x94}, + {"OpenProtocol", 0x118, 0x98}, + {"CloseProtocol", 0x120, 0x9c}, + {"OpenProtocolInformation", 0x128, 0xa0}, + {"ProtocolsPerHandle", 0x130, 0xa4}, + {"LocateHandleBuffer", 0x138, 0xa8}, + {"LocateProtocol", 0x140, 0xac}, + {"InstallMultipleProtocolInterfaces", 0x148, 0xb0}, + {"UninstallMultipleProtocolInterfaces", 0x150, 0xb4}, + {"CalculateCrc32", 0x158, 0xb8}, + {"CopyMem", 0x160, 0xbc}, + {"SetMem", 0x168, 0xc0}, + {"CreateEventEx", 0x170, 0xc4}}; size_t g_boot_services_table_all_count = sizeof(g_boot_services_table_all) / sizeof(service_t); service_t g_runtime_services_table_all[] = { - {"GetTime", GetTimeOffset64, GetTimeOffset32}, - {"SetTime", SetTimeOffset64, SetTimeOffset32}, - {"GetWakeupTime", GetWakeupTimeOffset64, GetWakeupTimeOffset32}, - {"SetWakeupTime", SetWakeupTimeOffset64, SetWakeupTimeOffset32}, - {"SetVirtualAddressMap", SetVirtualAddressMapOffset64, - SetVirtualAddressMapOffset32}, - {"ConvertPointer", ConvertPointerOffset64, ConvertPointerOffset32}, - {"GetVariable", GetVariableOffset64, GetVariableOffset32}, - {"GetNextVariableName", GetNextVariableNameOffset64, - GetNextVariableNameOffset32}, - {"SetVariable", SetVariableOffset64, SetVariableOffset32}, - {"GetNextHighMonotonicCount", GetNextHighMonotonicCountOffset64, - GetNextHighMonotonicCountOffset32}, - {"ResetSystem", ResetSystemOffset64, ResetSystemOffset32}, - {"UpdateCapsule", UpdateCapsuleOffset64, UpdateCapsuleOffset32}, - {"QueryCapsuleCapabilities", QueryCapsuleCapabilitiesOffset64, - QueryCapsuleCapabilitiesOffset32}, - {"QueryVariableInfo", QueryVariableInfoOffset64, - QueryVariableInfoOffset32}}; + {"GetTime", 0x18, 0x18}, + {"SetTime", 0x20, 0x1c}, + {"GetWakeupTime", 0x28, 0x20}, + {"SetWakeupTime", 0x30, 0x24}, + {"SetVirtualAddressMap", 0x38, 0x28}, + {"ConvertPointer", 0x40, 0x2c}, + {"GetVariable", 0x48, 0x30}, + {"GetNextVariableName", 0x50, 0x34}, + {"SetVariable", 0x58, 0x38}, + {"GetNextHighMonotonicCount", 0x60, 0x3c}, + {"ResetSystem", 0x68, 0x40}, + {"UpdateCapsule", 0x70, 0x44}, + {"QueryCapsuleCapabilities", 0x78, 0x48}, + {"QueryVariableInfo", 0x80, 0x4c}}; size_t g_runtime_services_table_all_count = sizeof(g_runtime_services_table_all) / sizeof(service_t); service_info_64_t g_smm_services_prot64[] = { - {"SmmInstallProtocolInterface", SmmInstallProtocolInterfaceOffset64, - REG_RDX}, - {"SmmUninstallProtocolInterface", SmmUninstallProtocolInterfaceOffset64, - REG_RDX}, - {"SmmHandleProtocol", SmmHandleProtocolOffset64, REG_RDX}, - {"SmmRegisterProtocolNotify", SmmRegisterProtocolNotifyOffset64, REG_RCX}, - {"SmmLocateHandle", SmmLocateHandleOffset64, REG_RDX}, - {"SmmLocateProtocol", SmmLocateProtocolOffset64, REG_RCX}}; + {"SmmInstallProtocolInterface", 0xa8, R_RDX}, + {"SmmUninstallProtocolInterface", 0xb0, R_RDX}, + {"SmmHandleProtocol", 0xb8, R_RDX}, + {"SmmRegisterProtocolNotify", 0xc0, R_RCX}, + {"SmmLocateHandle", 0xc8, R_RDX}, + {"SmmLocateProtocol", 0xd0, R_RCX}}; size_t g_smm_services_prot64_count = sizeof(g_smm_services_prot64) / sizeof(service_info_64_t); service_t g_smm_services_table_all[] = { - {"SmmInstallConfigurationTable", SmmInstallConfigurationTableOffset64, - SmmInstallConfigurationTableOffset32}, - {"SmmAllocatePool", SmmAllocatePoolOffset64, SmmAllocatePoolOffset32}, - {"SmmFreePool", SmmFreePoolOffset64, SmmFreePoolOffset32}, - {"SmmAllocatePages", SmmAllocatePagesOffset64, SmmAllocatePagesOffset32}, - {"SmmFreePages", SmmFreePagesOffset64, SmmFreePagesOffset32}, - {"SmmStartupThisAp", SmmStartupThisApOffset64, SmmStartupThisApOffset32}, - {"SmmInstallProtocolInterface", SmmInstallProtocolInterfaceOffset64, - SmmInstallProtocolInterfaceOffset32}, - {"SmmUninstallProtocolInterface", SmmUninstallProtocolInterfaceOffset64, - SmmUninstallProtocolInterfaceOffset32}, - {"SmmHandleProtocol", SmmHandleProtocolOffset64, SmmHandleProtocolOffset32}, - {"SmmRegisterProtocolNotify", SmmRegisterProtocolNotifyOffset64, - SmmRegisterProtocolNotifyOffset32}, - {"SmmLocateHandle", SmmLocateHandleOffset64, SmmLocateHandleOffset32}, - {"SmmLocateProtocol", SmmLocateProtocolOffset64, SmmLocateProtocolOffset32}, - {"SmiManage", SmiManageOffset64, SmiManageOffset32}, - {"SmiHandlerRegister", SmiHandlerRegisterOffset64, - SmiHandlerRegisterOffset32}, - {"SmiHandlerUnRegister", SmiHandlerUnRegisterOffset64, - SmiHandlerUnRegisterOffset32}}; + {"SmmInstallConfigurationTable", 0x28, 0x20}, + {"SmmAllocatePool", 0x50, 0x34}, + {"SmmFreePool", 0x58, 0x38}, + {"SmmAllocatePages", 0x60, 0x3c}, + {"SmmFreePages", 0x68, 0x40}, + {"SmmStartupThisAp", 0x70, 0x44}, + {"SmmInstallProtocolInterface", 0xa8, 0x60}, + {"SmmUninstallProtocolInterface", 0xb0, 0x64}, + {"SmmHandleProtocol", 0xb8, 0x68}, + {"SmmRegisterProtocolNotify", 0xc0, 0x6c}, + {"SmmLocateHandle", 0xc8, 0x70}, + {"SmmLocateProtocol", 0xd0, 0x74}, + {"SmiManage", 0xd8, 0x78}, + {"SmiHandlerRegister", 0xe0, 0x7c}, + {"SmiHandlerUnRegister", 0xe8, 0x80}}; size_t g_smm_services_table_all_count = sizeof(g_smm_services_table_all) / sizeof(service_t); @@ -187,30 +152,30 @@ service_info_32_t g_pei_services_table32[] = { {"InstallPpi", 0x18, 2}, {"ReInstallPpi", 0x1c, 3}, {"LocatePpi", 0x20, 2}, - {"NotifyPpi", 0x24, PUSH_NONE}, - {"GetBootMode", 0x28, PUSH_NONE}, - {"SetBootMode", 0x2c, PUSH_NONE}, - {"GetHobList", 0x30, PUSH_NONE}, - {"CreateHob", 0x34, PUSH_NONE}, - {"FfsFindNextVolume", 0x38, PUSH_NONE}, - {"FfsFindNextFile", 0x3c, PUSH_NONE}, - {"FfsFindSectionData", 0x40, PUSH_NONE}, - {"InstallPeiMemory", 0x44, PUSH_NONE}, - {"AllocatePages", 0x48, PUSH_NONE}, - {"AllocatePool", 0x4c, PUSH_NONE}, - {"CopyMem", 0x50, PUSH_NONE}, - {"SetMem", 0x54, PUSH_NONE}, - {"ReportStatusCode", 0x58, PUSH_NONE}, - {"ResetSystem", 0x5c, PUSH_NONE}, - {"CpuIo", 0x60, PUSH_NONE}, - {"PciCfg", 0x64, PUSH_NONE}, - {"FfsFindFileByName", 0x68, PUSH_NONE}, - {"FfsGetFileInfo", 0x6c, PUSH_NONE}, - {"FfsGetVolumeInfo", 0x70, PUSH_NONE}, - {"RegisterForShadow", 0x74, PUSH_NONE}, - {"FindSectionData3", 0x78, PUSH_NONE}, - {"FfsGetFileInfo2", 0x7c, PUSH_NONE}, - {"ResetSystem2", 0x80, PUSH_NONE}}; + {"NotifyPpi", 0x24, NONE_PUSH}, + {"GetBootMode", 0x28, NONE_PUSH}, + {"SetBootMode", 0x2c, NONE_PUSH}, + {"GetHobList", 0x30, NONE_PUSH}, + {"CreateHob", 0x34, NONE_PUSH}, + {"FfsFindNextVolume", 0x38, NONE_PUSH}, + {"FfsFindNextFile", 0x3c, NONE_PUSH}, + {"FfsFindSectionData", 0x40, NONE_PUSH}, + {"InstallPeiMemory", 0x44, NONE_PUSH}, + {"AllocatePages", 0x48, NONE_PUSH}, + {"AllocatePool", 0x4c, NONE_PUSH}, + {"CopyMem", 0x50, NONE_PUSH}, + {"SetMem", 0x54, NONE_PUSH}, + {"ReportStatusCode", 0x58, NONE_PUSH}, + {"ResetSystem", 0x5c, NONE_PUSH}, + {"CpuIo", 0x60, NONE_PUSH}, + {"PciCfg", 0x64, NONE_PUSH}, + {"FfsFindFileByName", 0x68, NONE_PUSH}, + {"FfsGetFileInfo", 0x6c, NONE_PUSH}, + {"FfsGetVolumeInfo", 0x70, NONE_PUSH}, + {"RegisterForShadow", 0x74, NONE_PUSH}, + {"FindSectionData3", 0x78, NONE_PUSH}, + {"FfsGetFileInfo2", 0x7c, NONE_PUSH}, + {"ResetSystem2", 0x80, NONE_PUSH}}; size_t g_pei_services_table32_count = sizeof(g_pei_services_table32) / sizeof(service_info_32_t); diff --git a/efiXplorer/efi_defs.h b/efiXplorer/efi_defs.h index 4fbb3877..b33fe4da 100644 --- a/efiXplorer/efi_defs.h +++ b/efiXplorer/efi_defs.h @@ -21,6 +21,36 @@ #include #include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if IDA_SDK_VERSION < 900 +#include +#endif +#include +#ifdef HEX_RAYS +#include +#endif + +#include + +using nlohmann::json; #define COPYRIGHT \ "(C) 2020-2024 Binarly - https://github.com/binarly-io/efiXplorer" @@ -35,9 +65,9 @@ #define RT_OFFSET_64 0x58 #define RT_OFFSET_32 0x38 -#define BADREG 0xffff -#define OFFSET_NONE 0xffff -#define PUSH_NONE 0xffff +#define NONE_REG 0xffff +#define NONE_OFFSET 0xffff +#define NONE_PUSH 0xffff enum class arch_file_type_t { unsupported, x86_32, x86_64, aarch64, uefi }; enum class ffs_file_type_t { unsupported = 0, pei = 6, dxe_smm = 7 }; @@ -46,73 +76,73 @@ enum class module_type_t { dxe_smm = 0, pei = 1 }; enum machine_type_t { AMD64 = 0x8664, I386 = 0x014C, AARCH64 = 0xaa64 }; enum regs_x86_32_t { - REG_EAX, - REG_ECX, - REG_EDX, - REG_EBX, - REG_ESP, - REG_EBP, - REG_ESI, - REG_EDI, - REG_AL = 0x10, - REG_DL = 0x12 + R_EAX, + R_ECX, + R_EDX, + R_EBX, + R_ESP, + R_EBP, + R_ESI, + R_EDI, + R_AL = 0x10, + R_DL = 0x12 }; enum regs_x86_64_t { - REG_RAX, - REG_RCX, - REG_RDX, - REG_RBX, - REG_RSP, - REG_RBP, - REG_RSI, - REG_RDI, - REG_R8, - REG_R9, - REG_R10, - REG_R11, - REG_R12, - REG_R13, - REG_R14, + R_RAX, + R_RCX, + R_RDX, + R_RBX, + R_RSP, + R_RBP, + R_RSI, + R_RDI, + R_R8, + R_R9, + R_R10, + R_R11, + R_R12, + R_R13, + R_R14, }; enum regs_aarch64_t { - REG_C0 = 0, - REG_C13 = 13, - REG_X0 = 129, - REG_X1, - REG_X2, - REG_X3, - REG_X4, - REG_X5, - REG_X6, - REG_X7, - REG_X8, - REG_X9, - REG_X10, - REG_X11, - REG_X12, - REG_X13, - REG_X14, - REG_X15, - REG_X16, - REG_X17, - REG_X18, - REG_X19, - REG_X20, - REG_X21, - REG_X22, - REG_X23, - REG_X24, - REG_X25, - REG_X26, - REG_X27, - REG_X28, - REG_X29, - REG_X30, - REG_XZR, - REG_XSP, - REG_XPC, + R_C0 = 0, + R_C13 = 13, + R_X0 = 129, + R_X1, + R_X2, + R_X3, + R_X4, + R_X5, + R_X6, + R_X7, + R_X8, + R_X9, + R_X10, + R_X11, + R_X12, + R_X13, + R_X14, + R_X15, + R_X16, + R_X17, + R_X18, + R_X19, + R_X20, + R_X21, + R_X22, + R_X23, + R_X24, + R_X25, + R_X26, + R_X27, + R_X28, + R_X29, + R_X30, + R_XZR, + R_XSP, + R_XPC, }; struct service_info_64_t { @@ -134,166 +164,43 @@ struct service_t { uint32_t offset32; }; -enum BootServicesOffsets64 { - RaiseTPLOffset64 = 0x18, - RestoreTPLOffset64 = 0x20, - AllocatePagesOffset64 = 0x28, - FreePagesOffset64 = 0x30, - GetMemoryMapOffset64 = 0x38, - AllocatePoolOffset64 = 0x40, - FreePoolOffset64 = 0x48, - CreateEventOffset64 = 0x50, - SetTimerOffset64 = 0x58, - WaitForEventOffset64 = 0x60, - SignalEventOffset64 = 0x68, - CloseEventOffset64 = 0x70, - CheckEventOffset64 = 0x78, - InstallProtocolInterfaceOffset64 = 0x80, - RenstallProtocolInterfaceOffset64 = 0x88, - UninstallProtocolInterfaceOffset64 = 0x90, - HandleProtocolOffset64 = 0x98, - RegisterProtocolNotifyOffset64 = 0xa8, - LocateHandleOffset64 = 0xb0, - LocateDevicePathOffset64 = 0xb8, - InstallConfigurationTableOffset64 = 0xc0, - LoadImageOffset64 = 0xc8, - StartImageOffset64 = 0xd0, - ExitOffset64 = 0xd8, - UnloadImageOffset64 = 0xe0, - ExitBootServicesOffset64 = 0xe8, - GetNextMonotonicCountOffset64 = 0xf0, - StallOffset64 = 0xf0, - SetWatchdogTimerOffset64 = 0x100, - ConnectControllerOffset64 = 0x108, - DisconnectControllerOffset64 = 0x110, - OpenProtocolOffset64 = 0x118, - CloseProtocolOffset64 = 0x120, - OpenProtocolInformationOffset64 = 0x128, - ProtocolsPerHandleOffset64 = 0x130, - LocateHandleBufferOffset64 = 0x138, - LocateProtocolOffset64 = 0x140, - InstallMultipleProtocolInterfacesOffset64 = 0x148, - UninstallMultipleProtocolInterfacesOffset64 = 0x150, - CalculateCrc32Offset64 = 0x158, - CopyMemOffset64 = 0x160, - SetMemOffset64 = 0x168, - CreateEventExOffset64 = 0x170, -}; - -enum BootServicesOffsets32 { - RaiseTPLOffset32 = 0x18, - RestoreTPLOffset32 = 0x1c, - AllocatePagesOffset32 = 0x20, - FreePagesOffset32 = 0x24, - GetMemoryMapOffset32 = 0x28, - AllocatePoolOffset32 = 0x2c, - FreePoolOffset32 = 0x30, - CreateEventOffset32 = 0x34, - SetTimerOffset32 = 0x38, - WaitForEventOffset32 = 0x3c, - SignalEventOffset32 = 0x40, - CloseEventOffset32 = 0x44, - CheckEventOffset32 = 0x48, - InstallProtocolInterfaceOffset32 = 0x4c, - RenstallProtocolInterfaceOffset32 = 0x50, - UninstallProtocolInterfaceOffset32 = 0x54, - HandleProtocolOffset32 = 0x58, - RegisterProtocolNotifyOffset32 = 0x60, - LocateHandleOffset32 = 0x64, - LocateDevicePathOffset32 = 0x68, - InstallConfigurationTableOffset32 = 0x6c, - LoadImageOffset32 = 0x70, - StartImageOffset32 = 0x74, - ExitOffset32 = 0x78, - UnloadImageOffset32 = 0x7c, - ExitBootServicesOffset32 = 0x80, - GetNextMonotonicCountOffset32 = 0x84, - StallOffset32 = 0x88, - SetWatchdogTimerOffset32 = 0x8c, - ConnectControllerOffset32 = 0x90, - DisconnectControllerOffset32 = 0x94, - OpenProtocolOffset32 = 0x98, - CloseProtocolOffset32 = 0x9c, - OpenProtocolInformationOffset32 = 0xa0, - ProtocolsPerHandleOffset32 = 0xa4, - LocateHandleBufferOffset32 = 0xa8, - LocateProtocolOffset32 = 0xac, - InstallMultipleProtocolInterfacesOffset32 = 0xb0, - UninstallMultipleProtocolInterfacesOffset32 = 0xb4, - CalculateCrc32Offset32 = 0xb8, - CopyMemOffset32 = 0xbc, - SetMemOffset32 = 0xc0, - CreateEventExOffset32 = 0xc4, -}; - -enum RuntimeServicesOffsets64 { - GetTimeOffset64 = 0x18, - SetTimeOffset64 = 0x20, - GetWakeupTimeOffset64 = 0x28, - SetWakeupTimeOffset64 = 0x30, - SetVirtualAddressMapOffset64 = 0x38, - ConvertPointerOffset64 = 0x40, - GetVariableOffset64 = 0x48, - GetNextVariableNameOffset64 = 0x50, - SetVariableOffset64 = 0x58, - GetNextHighMonotonicCountOffset64 = 0x60, - ResetSystemOffset64 = 0x68, - UpdateCapsuleOffset64 = 0x70, - QueryCapsuleCapabilitiesOffset64 = 0x78, - QueryVariableInfoOffset64 = 0x80, -}; - -enum RuntimeServicesOffsets32 { - GetTimeOffset32 = 0x18, - SetTimeOffset32 = 0x1c, - GetWakeupTimeOffset32 = 0x20, - SetWakeupTimeOffset32 = 0x24, - SetVirtualAddressMapOffset32 = 0x28, - ConvertPointerOffset32 = 0x2c, - GetVariableOffset32 = 0x30, - GetNextVariableNameOffset32 = 0x34, - SetVariableOffset32 = 0x38, - GetNextHighMonotonicCountOffset32 = 0x3c, - ResetSystemOffset32 = 0x40, - UpdateCapsuleOffset32 = 0x44, - QueryCapsuleCapabilitiesOffset32 = 0x48, - QueryVariableInfoOffset32 = 0x4c, -}; - -enum SmmServicesOffsets64 { - SmmInstallConfigurationTableOffset64 = 0x28, - SmmAllocatePoolOffset64 = 0x50, - SmmFreePoolOffset64 = 0x58, - SmmAllocatePagesOffset64 = 0x60, - SmmFreePagesOffset64 = 0x68, - SmmStartupThisApOffset64 = 0x70, - SmmInstallProtocolInterfaceOffset64 = 0xa8, - SmmUninstallProtocolInterfaceOffset64 = 0xb0, - SmmHandleProtocolOffset64 = 0xb8, - SmmRegisterProtocolNotifyOffset64 = 0xc0, - SmmLocateHandleOffset64 = 0xc8, - SmmLocateProtocolOffset64 = 0xd0, - SmiManageOffset64 = 0xd8, - SmiHandlerRegisterOffset64 = 0xe0, - SmiHandlerUnRegisterOffset64 = 0xe8, -}; - -enum SmmServicesOffsets32 { - SmmInstallConfigurationTableOffset32 = 0x20, - SmmAllocatePoolOffset32 = 0x34, - SmmFreePoolOffset32 = 0x38, - SmmAllocatePagesOffset32 = 0x3c, - SmmFreePagesOffset32 = 0x40, - SmmStartupThisApOffset32 = 0x44, - SmmInstallProtocolInterfaceOffset32 = 0x60, - SmmUninstallProtocolInterfaceOffset32 = 0x64, - SmmHandleProtocolOffset32 = 0x68, - SmmRegisterProtocolNotifyOffset32 = 0x6c, - SmmLocateHandleOffset32 = 0x70, - SmmLocateProtocolOffset32 = 0x74, - SmiManageOffset32 = 0x78, - SmiHandlerRegisterOffset32 = 0x7c, - SmiHandlerUnRegisterOffset32 = 0x80, +using ea_list_t = std::vector; +using func_list_t = std::vector; +using json_list_t = std::vector; +using segment_list_t = std::vector; +using string_list_t = std::vector; +using uchar_list_t = std::vector; +using uint64_list_t = std::vector; +using uint8_list_t = std::vector; + +struct efi_guid_t { + uint32_t data1; + uint16_t data2; + uint16_t data3; + uint8_t data4[8]; + + uchar_list_t uchar_data() { + uchar_list_t res; + res.push_back(data1 & 0xff); + res.push_back(data1 >> 8 & 0xff); + res.push_back(data1 >> 16 & 0xff); + res.push_back(data1 >> 24 & 0xff); + res.push_back(data2 & 0xff); + res.push_back(data2 >> 8 & 0xff); + res.push_back(data3 & 0xff); + res.push_back(data3 >> 8 & 0xff); + for (auto i = 0; i < 8; i++) { + res.push_back(data4[i]); + } + return res; + } + + std::string to_string() const { + return std::format("{:08X}-{:04X}-{:04X}-{:02X}{:02X}-" + "{:02X}{:02X}{:02X}{:02X}{:02X}{:02X}", + data1, data2, data3, data4[0], data4[1], data4[2], + data4[3], data4[4], data4[5], data4[6], data4[7]); + } }; extern service_info_64_t g_boot_services_table64[]; diff --git a/efiXplorer/efi_deps.h b/efiXplorer/efi_deps.h index 31ba0bfb..14e910c8 100644 --- a/efiXplorer/efi_deps.h +++ b/efiXplorer/efi_deps.h @@ -20,7 +20,6 @@ #pragma once #include "efi_utils.h" - #include #include #include diff --git a/efiXplorer/efi_global.h b/efiXplorer/efi_global.h index 241deb17..22e74f6e 100644 --- a/efiXplorer/efi_global.h +++ b/efiXplorer/efi_global.h @@ -21,11 +21,11 @@ #include "efi_deps.h" -typedef struct args { +struct args_t { module_type_t module_type; int disable_ui; int disable_vuln_hunt; -} args_t; +}; extern args_t g_args; extern EfiDependencies g_deps; diff --git a/efiXplorer/efi_hexrays.h b/efiXplorer/efi_hexrays.h index ec6280c7..d36a0d03 100644 --- a/efiXplorer/efi_hexrays.h +++ b/efiXplorer/efi_hexrays.h @@ -20,7 +20,6 @@ #pragma once #include "efi_utils.h" - #include #include #include diff --git a/efiXplorer/efi_smm_utils.cc b/efiXplorer/efi_smm_utils.cc index 9b18a2d3..69c3ba0d 100644 --- a/efiXplorer/efi_smm_utils.cc +++ b/efiXplorer/efi_smm_utils.cc @@ -18,24 +18,24 @@ */ #include "efi_smm_utils.h" -#include "efi_global.h" +#include "efi_global.h" #include //-------------------------------------------------------------------------- // Find and mark gSmst global variable via EFI_SMM_SW_DISPATCH(2)_PROTOCOL_GUID ea_list_t findSmstSwDispatch(ea_list_t bs_list) { ea_list_t smst_addrs; - EfiGuid guid2 = {0x18a3c6dc, - 0x5eea, - 0x48c8, - {0xa1, 0xc1, 0xb5, 0x33, 0x89, 0xf9, 0x89, - 0x99}}; // EFI_SMM_SW_DISPATCH2_PROTOCOL_GUID - EfiGuid guid = {0xe541b773, - 0xdd11, - 0x420c, - {0xb0, 0x26, 0xdf, 0x99, 0x36, 0x53, 0xf8, - 0xbf}}; // EFI_SMM_SW_DISPATCH_PROTOCOL_GUID + efi_guid_t guid2 = {0x18a3c6dc, + 0x5eea, + 0x48c8, + {0xa1, 0xc1, 0xb5, 0x33, 0x89, 0xf9, 0x89, + 0x99}}; // EFI_SMM_SW_DISPATCH2_PROTOCOL_GUID + efi_guid_t guid = {0xe541b773, + 0xdd11, + 0x420c, + {0xb0, 0x26, 0xdf, 0x99, 0x36, 0x53, 0xf8, + 0xbf}}; // EFI_SMM_SW_DISPATCH_PROTOCOL_GUID ea_list_t data_addrs = find_data(0, BADADDR, guid.uchar_data().data(), 16); ea_list_t data2_addrs = find_data(0, BADADDR, guid2.uchar_data().data(), 16); data_addrs.insert(data_addrs.end(), data2_addrs.begin(), data2_addrs.end()); @@ -96,11 +96,11 @@ ea_list_t findSmstSwDispatch(ea_list_t bs_list) { // Find and mark gSmst global variable via EFI_SMM_BASE2_PROTOCOL_GUID ea_list_t findSmstSmmBase(ea_list_t bs_list) { ea_list_t smst_addrs; - EfiGuid guid = {0xf4ccbfb7, - 0xf6e0, - 0x47fd, - {0x9d, 0xd4, 0x10, 0xa8, 0xf1, 0x50, 0xc1, - 0x91}}; // EFI_SMM_BASE2_PROTOCOL_GUID + efi_guid_t guid = {0xf4ccbfb7, + 0xf6e0, + 0x47fd, + {0x9d, 0xd4, 0x10, 0xa8, 0xf1, 0x50, 0xc1, + 0x91}}; // EFI_SMM_BASE2_PROTOCOL_GUID ea_list_t data_addrs = find_data(0, BADADDR, guid.uchar_data().data(), 16); for (auto data_addr : data_addrs) { msg("[%s] EFI_SMM_BASE2_PROTOCOL_GUID: 0x%016llX\n", g_plugin_name, @@ -116,7 +116,7 @@ ea_list_t findSmstSmmBase(ea_list_t bs_list) { cur_addr = next_head(cur_addr, BADADDR); decode_insn(&insn, cur_addr); if (insn.itype == NN_lea && insn.ops[0].type == o_reg && - insn.ops[0].reg == REG_RDX && insn.ops[1].type == o_mem) { + insn.ops[0].reg == R_RDX && insn.ops[1].type == o_mem) { res_addr = insn.ops[1].addr; msg("[%s] found gSmst/gInSmram at 0x%016llX, address = 0x%016llX\n", g_plugin_name, u64_addr(cur_addr), u64_addr(res_addr)); @@ -158,7 +158,7 @@ func_list_t findSmiHandlers(ea_t address, std::string prefix) { // Check instruction decode_insn(&insn, address); - if (!(insn.ops[0].type == o_reg && insn.ops[0].reg == REG_RCX)) { + if (!(insn.ops[0].type == o_reg && insn.ops[0].reg == R_RCX)) { msg("[%s] %sSmiHandler: wrong xref to dispatch(2) protocol\n", g_plugin_name, prefix.c_str()); return m_smi_handlers; @@ -181,15 +181,15 @@ func_list_t findSmiHandlers(ea_t address, std::string prefix) { } // Interface in stack if (insn.itype == NN_lea && insn.ops[0].type == o_reg && - insn.ops[0].reg == REG_R8 && insn.ops[1].type == o_displ && - (insn.ops[1].reg == REG_RBP || insn.ops[1].reg == REG_RSP)) { + insn.ops[0].reg == R_R8 && insn.ops[1].type == o_displ && + (insn.ops[1].reg == R_RBP || insn.ops[1].reg == R_RSP)) { if (dispatch_interface == BADADDR) { dispatch_interface = insn.ops[1].addr; } } // Interface in data if (insn.itype == NN_lea && insn.ops[0].type == o_reg && - insn.ops[0].reg == REG_R8 && insn.ops[1].type == o_mem) { + insn.ops[0].reg == R_R8 && insn.ops[1].type == o_mem) { if (dispatch_interface == BADADDR) { dispatch_interface = insn.ops[1].addr; } @@ -207,14 +207,14 @@ func_list_t findSmiHandlers(ea_t address, std::string prefix) { decode_insn(&insn, ea); // Interface in stack if (insn.itype == NN_lea && insn.ops[0].type == o_reg && - insn.ops[0].reg == REG_R8 && insn.ops[1].type == o_displ && - (insn.ops[1].reg == REG_RBP || insn.ops[1].reg == REG_RSP)) { + insn.ops[0].reg == R_R8 && insn.ops[1].type == o_displ && + (insn.ops[1].reg == R_RBP || insn.ops[1].reg == R_RSP)) { dispatch_interface = insn.ops[1].addr; break; } // Interface in data if (insn.itype == NN_lea && insn.ops[0].type == o_reg && - insn.ops[0].reg == REG_R8 && insn.ops[1].type == o_mem) { + insn.ops[0].reg == R_R8 && insn.ops[1].type == o_mem) { dispatch_interface = insn.ops[1].addr; break; } @@ -233,7 +233,7 @@ func_list_t findSmiHandlers(ea_t address, std::string prefix) { // Track interface stack variable ea = address; - uint16_t reg = BADREG; + uint16_t reg = NONE_REG; uint64_t dispatch_func = BADADDR; for (auto i = 0; i < 100; i++) { ea = next_head(ea, BADADDR); @@ -244,26 +244,27 @@ func_list_t findSmiHandlers(ea_t address, std::string prefix) { if (insn.ops[1].addr == dispatch_interface) { reg = insn.ops[0].reg; } else { - reg = BADREG; // resetting + reg = NONE_REG; // resetting } continue; } // resetting (register overwrite or call) - if (reg != BADREG && insn.ops[0].type == o_reg && insn.ops[0].reg == reg) { - reg = BADREG; + if (reg != NONE_REG && insn.ops[0].type == o_reg && + insn.ops[0].reg == reg) { + reg = NONE_REG; continue; } // resetting (call) if (insn.itype == NN_call) { - reg = BADREG; + reg = NONE_REG; continue; } // get DispatchFunction address if (insn.itype == NN_lea && insn.ops[0].type == o_reg && - insn.ops[0].reg == REG_RDX && insn.ops[1].type == o_mem) { + insn.ops[0].reg == R_RDX && insn.ops[1].type == o_mem) { dispatch_func = insn.ops[1].addr; continue; } @@ -281,7 +282,7 @@ func_list_t findSmiHandlers(ea_t address, std::string prefix) { if (handler_func != nullptr) { m_smi_handlers.push_back(handler_func); // add in result } - reg = BADREG; // resetting + reg = NONE_REG; // resetting // op_stroff + set_name std::string name = prefix + "SmiHandler"; @@ -311,7 +312,7 @@ func_list_t findSmiHandlers(ea_t address, std::string prefix) { // lea r8, ... // lea rdx, // call qword ptr [...] -func_list_t findSmiHandlersSmmDispatch(EfiGuid guid, std::string prefix) { +func_list_t findSmiHandlersSmmDispatch(efi_guid_t guid, std::string prefix) { func_list_t m_smi_handlers; ea_list_t data_addrs = find_data(0, BADADDR, guid.uchar_data().data(), 16); msg("[%s] %sSmiHandler function finding\n", g_plugin_name, prefix.c_str()); @@ -362,11 +363,11 @@ ea_list_t findSmmGetVariableCalls(segment_list_t dataSegments, "EFI_SMM_VARIABLE_PROTOCOL_GUID\n", g_plugin_name); ea_list_t smmGetVariableCalls; - EfiGuid guid = {0xed32d533, - 0x99e6, - 0x4209, - {0x9c, 0xc0, 0x2d, 0x72, 0xcd, 0xd9, 0x98, - 0xa7}}; // EFI_SMM_VARIABLE_PROTOCOL_GUID + efi_guid_t guid = {0xed32d533, + 0x99e6, + 0x4209, + {0x9c, 0xc0, 0x2d, 0x72, 0xcd, 0xd9, 0x98, + 0xa7}}; // EFI_SMM_VARIABLE_PROTOCOL_GUID // Find all EFI_GUID EFI_SMM_VARIABLE_PROTOCOL_GUID addresses ea_list_t data_addrs = find_data(0, BADADDR, guid.uchar_data().data(), 16); @@ -394,7 +395,7 @@ ea_list_t findSmmGetVariableCalls(segment_list_t dataSegments, ea = prev_head(ea, 0); decode_insn(&insn, ea); if (insn.itype == NN_lea && insn.ops[0].type == o_reg && - insn.ops[0].reg == REG_R8 && insn.ops[1].type == o_mem) { + insn.ops[0].reg == R_R8 && insn.ops[1].type == o_mem) { msg("[%s] gSmmVariable address: 0x%016llX\n", g_plugin_name, u64_addr(insn.ops[1].addr)); set_ptr_type_and_name(insn.ops[1].addr, "gSmmVariable", @@ -523,7 +524,7 @@ ea_list_t resolveEfiSmmCpuProtocol(json_list_t stackGuids, // Find 'lea r8, ' instruction decode_insn(&insn, ea); if (insn.itype == NN_lea && insn.ops[0].type == o_reg && - insn.ops[0].reg == REG_R8 && insn.ops[1].type == o_mem) { + insn.ops[0].reg == R_R8 && insn.ops[1].type == o_mem) { msg("[%s] gSmmCpu address: 0x%016llX\n", g_plugin_name, u64_addr(insn.ops[1].addr)); set_ptr_type_and_name(insn.ops[1].addr, "gSmmCpu", @@ -609,7 +610,7 @@ ea_t markChildSwSmiHandler(ea_t ea) { // check current instruction if (insn.itype == NN_lea && insn.ops[0].type == o_reg && - insn.ops[0].reg == REG_RCX) { + insn.ops[0].reg == R_RCX) { if (insn.ops[1].type != o_mem) { continue; } diff --git a/efiXplorer/efi_smm_utils.h b/efiXplorer/efi_smm_utils.h index 6208a798..ca5d8c2e 100644 --- a/efiXplorer/efi_smm_utils.h +++ b/efiXplorer/efi_smm_utils.h @@ -20,13 +20,12 @@ #pragma once #include "efi_utils.h" - #include ea_list_t findSmstSwDispatch(ea_list_t bs_list); ea_list_t findSmstSmmBase(ea_list_t bs_list); func_list_t findSmiHandlers(ea_t address, std::string prefix); -func_list_t findSmiHandlersSmmDispatch(EfiGuid guid, std::string prefix); +func_list_t findSmiHandlersSmmDispatch(efi_guid_t guid, std::string prefix); func_list_t findSmiHandlersSmmDispatchStack(json_list_t stackGuids, std::string prefix); ea_list_t findSmmGetVariableCalls(segment_list_t dataSegments, diff --git a/efiXplorer/efi_ui.h b/efiXplorer/efi_ui.h index fee0d995..f3b7a3f9 100644 --- a/efiXplorer/efi_ui.h +++ b/efiXplorer/efi_ui.h @@ -20,7 +20,6 @@ #pragma once #include "efi_utils.h" - #include //------------------------------------------------------------------------- diff --git a/efiXplorer/efi_utils.cc b/efiXplorer/efi_utils.cc index ba8c20c6..e71cbeda 100644 --- a/efiXplorer/efi_utils.cc +++ b/efiXplorer/efi_utils.cc @@ -18,9 +18,8 @@ */ #include "efi_utils.h" -#include "efi_defs.h" -#include "efi_global.h" +#include "efi_global.h" #include // can be used after Hex-Rays based analysis @@ -168,7 +167,7 @@ ea_t find_unknown_bs_var_64(ea_t ea) { for (int i = 0; i < 10; i++) { decode_insn(&insn, ea); if (insn.itype == NN_mov && insn.ops[0].type == o_reg && - insn.ops[0].reg == REG_RAX && insn.ops[1].type == o_mem) { + insn.ops[0].reg == R_RAX && insn.ops[1].type == o_mem) { res = insn.ops[1].addr; break; } @@ -622,7 +621,7 @@ bool check_boot_service_protocol(ea_t call_addr) { // check current instruction if (insn.itype == NN_lea && insn.ops[0].type == o_reg && - insn.ops[0].reg == REG_RCX) { + insn.ops[0].reg == R_RCX) { if (insn.ops[1].type == o_mem) { // will still be a false positive if the Handle in // SmmInstallProtocolInterface is a global variable) @@ -641,7 +640,7 @@ bool check_boot_service_protocol_xrefs(ea_t call_addr) { for (auto xref : get_xrefs_util(call_addr)) { decode_insn(&insn, xref); if (insn.itype == NN_lea && insn.ops[0].type == o_reg && - insn.ops[0].reg == REG_R8) { + insn.ops[0].reg == R_R8) { // load interface instruction return false; } @@ -781,7 +780,7 @@ void op_stroff_for_addr(ea_t ea, qstring type_name) { if ((insn.itype == NN_call || insn.itype == NN_callfi || insn.itype == NN_callni) && (insn.ops[0].type == o_displ || insn.ops[0].type == o_phrase) && - insn.ops[0].reg == REG_RAX) { + insn.ops[0].reg == R_RAX) { op_stroff_util(ea, static_cast(type_name.c_str())); msg("[%s] mark arguments at address 0x%016llX (interface type: %s)\n", g_plugin_name, u64_addr(ea), type_name.c_str()); @@ -810,7 +809,7 @@ void op_stroff_for_addr(ea_t ea, qstring type_name) { break; } // if the RAX value is overridden - if (insn.ops[0].reg == REG_RAX) { + if (insn.ops[0].reg == R_RAX) { break; } } @@ -823,7 +822,7 @@ void op_stroff_for_interface(xreflist_t local_xrefs, qstring type_name) { insn_t insn; for (auto xref : local_xrefs) { decode_insn(&insn, xref.ea); - if (insn.itype == NN_mov && insn.ops[0].reg == REG_RAX) { + if (insn.itype == NN_mov && insn.ops[0].reg == R_RAX) { op_stroff_for_addr(xref.ea, type_name); } } @@ -836,7 +835,7 @@ void op_stroff_for_global_interface(ea_list_t xrefs, qstring type_name) { insn_t insn; for (auto ea : xrefs) { decode_insn(&insn, ea); - if (insn.itype == NN_mov && insn.ops[0].reg == REG_RAX) { + if (insn.itype == NN_mov && insn.ops[0].reg == R_RAX) { op_stroff_for_addr(ea, type_name); } } @@ -900,9 +899,9 @@ std::string get_wide_string(ea_t addr) { } //-------------------------------------------------------------------------- -// get EfiGuid by address -EfiGuid get_global_guid(ea_t addr) { - EfiGuid guid; +// get efi_guid_t by address +efi_guid_t get_global_guid(ea_t addr) { + efi_guid_t guid; guid.data1 = get_wide_dword(addr); guid.data2 = get_wide_word(addr + 4); guid.data3 = get_wide_word(addr + 6); @@ -913,9 +912,9 @@ EfiGuid get_global_guid(ea_t addr) { } //-------------------------------------------------------------------------- -// get EfiGuid by stack offset -EfiGuid get_local_guid(func_t *f, uint64_t offset) { - EfiGuid guid; +// get efi_guid_t by stack offset +efi_guid_t get_local_guid(func_t *f, uint64_t offset) { + efi_guid_t guid; insn_t insn; auto ea = f->start_ea; int counter = 0; @@ -926,7 +925,7 @@ EfiGuid get_local_guid(func_t *f, uint64_t offset) { ea = next_head(ea, BADADDR); decode_insn(&insn, ea); if (insn.itype == NN_mov && insn.ops[0].type == o_displ && - (insn.ops[0].reg == REG_RSP || insn.ops[0].reg == REG_RBP) && + (insn.ops[0].reg == R_RSP || insn.ops[0].reg == R_RBP) && insn.ops[1].type == o_imm) { if (insn.ops[0].addr == offset) { guid.data1 = insn.ops[1].value; diff --git a/efiXplorer/efi_utils.h b/efiXplorer/efi_utils.h index f76004f3..3744830f 100644 --- a/efiXplorer/efi_utils.h +++ b/efiXplorer/efi_utils.h @@ -20,77 +20,7 @@ #pragma once #include "efi_defs.h" - -#include -#include #include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if IDA_SDK_VERSION < 900 -#include -#endif -#include -#ifdef HEX_RAYS -#include -#endif -#include - -// 3rd party -#include "json.hpp" - -using nlohmann::json; - -using ea_list_t = std::vector; -using func_list_t = std::vector; -using json_list_t = std::vector; -using segment_list_t = std::vector; -using string_list_t = std::vector; -using uchar_list_t = std::vector; -using uint64_list_t = std::vector; -using uint8_list_t = std::vector; - -struct EfiGuid { - uint32_t data1; - uint16_t data2; - uint16_t data3; - uint8_t data4[8]; - - uchar_list_t uchar_data() { - uchar_list_t res; - res.push_back(data1 & 0xff); - res.push_back(data1 >> 8 & 0xff); - res.push_back(data1 >> 16 & 0xff); - res.push_back(data1 >> 24 & 0xff); - res.push_back(data2 & 0xff); - res.push_back(data2 >> 8 & 0xff); - res.push_back(data3 & 0xff); - res.push_back(data3 >> 8 & 0xff); - for (auto i = 0; i < 8; i++) { - res.push_back(data4[i]); - } - return res; - } - - std::string to_string() const { - return std::format("{:08X}-{:04X}-{:04X}-{:02X}{:02X}-{:02X}{:02X}{:02X}{:" - "02X}{:02X}{:02X}", - data1, data2, data3, data4[0], data4[1], data4[2], - data4[3], data4[4], data4[5], data4[6], data4[7]); - } -}; arch_file_type_t input_file_type(); @@ -112,8 +42,8 @@ bool valid_guid(json guid); ea_t find_unknown_bs_var_64(ea_t ea); -EfiGuid get_global_guid(ea_t addr); -EfiGuid get_local_guid(func_t *f, uint64_t offset); +efi_guid_t get_global_guid(ea_t addr); +efi_guid_t get_local_guid(func_t *f, uint64_t offset); ffs_file_type_t ask_file_type(json_list_t *m_all_guids); diff --git a/efiXplorer/efixplorer.cc b/efiXplorer/efixplorer.cc index 70301053..92b68271 100644 --- a/efiXplorer/efixplorer.cc +++ b/efiXplorer/efixplorer.cc @@ -31,7 +31,7 @@ static const char welcome_msg[] = " ____ _ __ __\n" " /_/\n"; // default arguments -struct args g_args = {module_type_t::dxe_smm, 0, 0}; +args_t g_args = {module_type_t::dxe_smm, 0, 0}; #if IDA_SDK_VERSION < 760 hexdsp_t *hexdsp = nullptr; From 9167b637d607fa76f4aaf69ff2997ba2fdbdc71e Mon Sep 17 00:00:00 2001 From: yeggor Date: Tue, 17 Sep 2024 22:58:19 +0100 Subject: [PATCH 32/69] wrap utils in efi_utils namespace --- efiXplorer/efi_analysis_arm.cc | 44 ++-- efiXplorer/efi_analysis_x86.cc | 203 ++++++++-------- efiXplorer/efi_deps.cc | 16 +- efiXplorer/efi_hexrays.cc | 6 +- efiXplorer/efi_hexrays.h | 49 ++-- efiXplorer/efi_smm_utils.cc | 55 +++-- efiXplorer/efi_utils.cc | 416 ++++++++++++++++----------------- efiXplorer/efi_utils.h | 26 +-- efiXplorer/efixplorer.cc | 6 +- 9 files changed, 416 insertions(+), 405 deletions(-) diff --git a/efiXplorer/efi_analysis_arm.cc b/efiXplorer/efi_analysis_arm.cc index 72eb2437..b1442ffc 100644 --- a/efiXplorer/efi_analysis_arm.cc +++ b/efiXplorer/efi_analysis_arm.cc @@ -22,8 +22,6 @@ #include "efi_ui.h" #include "efi_utils.h" -using efi_analysis::efi_analyser_arm_t; - ea_list_t image_handle_list_arm; ea_list_t st_list_arm; ea_list_t bs_list_arm; @@ -64,7 +62,7 @@ void efi_analysis::efi_analyser_arm_t::initial_analysis() { #endif /* HEX_RAYS */ } if (m_ftype == ffs_file_type_t::pei) { - // set_entry_arg_to_pei_svc(); + // efi_utils::set_entry_arg_to_pei_svc(); } } @@ -172,10 +170,12 @@ json getService(ea_t addr, uint8_t table_id) { insn.ops[0].reg == blr_reg) { s["address"] = ea; if (table_id == 1) { - s["service_name"] = lookup_boot_service_name(service_offset); + s["service_name"] = + efi_utils::lookup_boot_service_name(service_offset); s["table_name"] = "EFI_BOOT_SERVICES"; } else if (table_id == 2) { - s["service_name"] = lookup_runtime_service_name(service_offset); + s["service_name"] = + efi_utils::lookup_runtime_service_name(service_offset); s["table_name"] = "EFI_RUNTIME_SERVICES"; } else { s["table_name"] = "OTHER"; @@ -211,10 +211,12 @@ json getService(ea_t addr, uint8_t table_id) { insn.ops[1].type == o_displ && insn.ops[1].reg == reg2) { s["address"] = ea; if (table_id == 1) { - s["service_name"] = lookup_boot_service_name(insn.ops[1].addr); + s["service_name"] = + efi_utils::lookup_boot_service_name(insn.ops[1].addr); s["table_name"] = "EFI_BOOT_SERVICES"; } else if (table_id == 2) { - s["service_name"] = lookup_runtime_service_name(insn.ops[1].addr); + s["service_name"] = + efi_utils::lookup_runtime_service_name(insn.ops[1].addr); s["table_name"] = "EFI_RUNTIME_SERVICES"; } else { s["table_name"] = "OTHER"; @@ -234,28 +236,28 @@ void efi_analysis::efi_analyser_arm_t::initial_gvars_detection() { json res = detect_vars(get_func(func_addr)); if (res.contains("image_handle_list")) { for (auto addr : res["image_handle_list"]) { - if (!addr_in_vec(image_handle_list_arm, addr)) { + if (!efi_utils::addr_in_vec(image_handle_list_arm, addr)) { image_handle_list_arm.push_back(addr); } } } if (res.contains("st_list")) { for (auto addr : res["st_list"]) { - if (!addr_in_vec(st_list_arm, addr)) { + if (!efi_utils::addr_in_vec(st_list_arm, addr)) { st_list_arm.push_back(addr); } } } if (res.contains("bs_list")) { for (auto addr : res["bs_list"]) { - if (!addr_in_vec(bs_list_arm, addr)) { + if (!efi_utils::addr_in_vec(bs_list_arm, addr)) { bs_list_arm.push_back(addr); } } } if (res.contains("rt_list")) { for (auto addr : res["rt_list"]) { - if (!addr_in_vec(rt_list_arm, addr)) { + if (!efi_utils::addr_in_vec(rt_list_arm, addr)) { rt_list_arm.push_back(addr); } } @@ -275,8 +277,8 @@ void efi_analysis::efi_analyser_arm_t::initial_gvars_detection() { ea_t bs = get_table_addr(ea, 0x60); if (bs != BADADDR) { msg("[efiXplorer] gBS = 0x%016llX\n", u64_addr(ea)); - set_ptr_type_and_name(bs, "gBS", "EFI_BOOT_SERVICES"); - if (!addr_in_vec(bs_list_arm, bs)) { + efi_utils::set_ptr_type_and_name(bs, "gBS", "EFI_BOOT_SERVICES"); + if (!efi_utils::addr_in_vec(bs_list_arm, bs)) { bs_list_arm.push_back(bs); } continue; @@ -284,8 +286,8 @@ void efi_analysis::efi_analyser_arm_t::initial_gvars_detection() { ea_t rt = get_table_addr(ea, 0x58); if (rt != BADADDR) { msg("[efiXplorer] gRT = 0x%016llX\n", u64_addr(ea)); - set_ptr_type_and_name(rt, "gRT", "EFI_RUNTIME_SERVICES"); - if (!addr_in_vec(rt_list_arm, rt)) { + efi_utils::set_ptr_type_and_name(rt, "gRT", "EFI_RUNTIME_SERVICES"); + if (!efi_utils::addr_in_vec(rt_list_arm, rt)) { rt_list_arm.push_back(rt); } continue; @@ -306,7 +308,7 @@ void efi_analysis::efi_analyser_arm_t::detect_services_all() { // analyse xrefs to gBS, gRT for (auto bs : bs_list_arm) { - auto xrefs = get_xrefs_util(bs); + auto xrefs = efi_utils::get_xrefs(bs); for (auto ea : xrefs) { auto s = getService(ea, 1); if (!s.contains("address")) { @@ -316,7 +318,7 @@ void efi_analysis::efi_analyser_arm_t::detect_services_all() { if (name == "Unknown") { continue; } - if (!json_in_vec(m_all_services, s)) { + if (!efi_utils::json_in_vec(m_all_services, s)) { msg("[efiXplorer] gBS xref address: 0x%016llX, found new service\n", u64_addr(ea)); m_all_services.push_back(s); @@ -324,7 +326,7 @@ void efi_analysis::efi_analyser_arm_t::detect_services_all() { } } for (auto rt : rt_list_arm) { - auto xrefs = get_xrefs_util(rt); + auto xrefs = efi_utils::get_xrefs(rt); for (auto ea : xrefs) { auto s = getService(ea, 2); if (!s.contains("address")) { @@ -334,7 +336,7 @@ void efi_analysis::efi_analyser_arm_t::detect_services_all() { if (name == "Unknown") { continue; } - if (!json_in_vec(m_all_services, s)) { + if (!efi_utils::json_in_vec(m_all_services, s)) { msg("[efiXplorer] gRT xref address: 0x%016llX, found new service\n", u64_addr(ea)); m_all_services.push_back(s); @@ -419,7 +421,7 @@ void efi_analysis::efi_analyser_arm_t::find_pei_services_function() { msg("[efiXplorer] found GetPeiServices() function: 0x%016llX\n", u64_addr(start_ea)); set_name(start_ea, "GetPeiServices", SN_FORCE); - set_ret_to_pei_svc(start_ea); + efi_utils::set_ret_to_pei_svc(start_ea); } } } @@ -470,7 +472,7 @@ bool efi_analysis::efi_analyse_main_aarch64() { ? analyser.m_ftype = ffs_file_type_t::pei : analyser.m_ftype = ffs_file_type_t::dxe_smm; } else { - analyser.m_ftype = ask_file_type(&analyser.m_all_guids); + analyser.m_ftype = efi_utils::ask_file_type(&analyser.m_all_guids); } if (analyser.m_ftype == ffs_file_type_t::pei) { diff --git a/efiXplorer/efi_analysis_x86.cc b/efiXplorer/efi_analysis_x86.cc index 62fdb807..adbfbebc 100644 --- a/efiXplorer/efi_analysis_x86.cc +++ b/efiXplorer/efi_analysis_x86.cc @@ -25,9 +25,6 @@ #include "efi_hexrays.h" #endif -using efi_analysis::efi_analyser_t; -using efi_analysis::efi_analyser_x86_t; - extern ea_list_t g_get_smst_location_calls; extern ea_list_t g_smm_get_variable_calls; extern ea_list_t g_smm_set_variable_calls; @@ -60,10 +57,10 @@ ea_list_t smmGetVariableOverflow; efi_analysis::efi_analyser_t::efi_analyser_t() { // 32-bit, 64-bit, ARM or UEFI (in loader instance) - m_arch = input_file_type(); + m_arch = efi_utils::input_file_type(); // get guids.json path - m_guids_json_path /= get_guids_json_file(); + m_guids_json_path /= efi_utils::get_guids_json_file(); func_t *start_func = nullptr; func_t *end_func = nullptr; @@ -222,7 +219,8 @@ bool efi_analysis::efi_analyser_x86_t::find_image_handle64() { g_plugin_name, u64_addr(ea), u64_addr(insn.ops[0].addr)); // set type and name - set_type_and_name(insn.ops[0].addr, "gImageHandle", "EFI_IMAGE_HANDLE"); + efi_utils::set_type_and_name(insn.ops[0].addr, "gImageHandle", + "EFI_IMAGE_HANDLE"); image_handle_list.push_back(insn.ops[0].addr); break; } @@ -247,7 +245,8 @@ bool efi_analysis::efi_analyser_x86_t::find_system_table64() { decode_insn(&insn, ea); if (insn.itype == NN_mov && insn.ops[1].type == o_reg && insn.ops[1].reg == R_RDX && insn.ops[0].type == o_mem) { - set_ptr_type_and_name(insn.ops[0].addr, "gST", "EFI_SYSTEM_TABLE"); + efi_utils::set_ptr_type_and_name(insn.ops[0].addr, "gST", + "EFI_SYSTEM_TABLE"); st_list.push_back(insn.ops[0].addr); return true; } @@ -325,8 +324,9 @@ bool efi_analysis::efi_analyser_x86_t::find_smst_postproc64() { if (smst_stack.is_null() && smst_addr != BADADDR) { msg("[%s] gSmst: 0x%016llX\n", g_plugin_name, u64_addr(smst_addr)); - if (!addr_in_vec(smst_list, smst_addr)) { - set_ptr_type_and_name(smst_addr, "gSmst", "_EFI_SMM_SYSTEM_TABLE2"); + if (!efi_utils::addr_in_vec(smst_list, smst_addr)) { + efi_utils::set_ptr_type_and_name(smst_addr, "gSmst", + "_EFI_SMM_SYSTEM_TABLE2"); smst_list.push_back(smst_addr); } } @@ -380,7 +380,7 @@ bool efi_analysis::efi_analyser_x86_t::find_smst_postproc64() { if (insn.itype == NN_callni && insn.ops[0].type == o_displ && insn.ops[0].reg == smst_reg && insn.ops[0].addr == 0xe0) { - op_stroff_util(ea, "_EFI_SMM_SYSTEM_TABLE2"); + efi_utils::op_stroff(ea, "_EFI_SMM_SYSTEM_TABLE2"); // save child SW SMI handler func_t *handler_func = get_func(rcx_last); if (handler_func != nullptr) { @@ -446,8 +446,9 @@ bool efi_analysis::efi_analyser_x86_t::find_boot_services_tables() { next_insn.ops[1].type == o_reg && next_insn.ops[1].reg == bsRegister) { baseInsnAddr = ea; - if (!addr_in_vec(bs_list, var_addr)) { - set_ptr_type_and_name(var_addr, "gBS", "EFI_BOOT_SERVICES"); + if (!efi_utils::addr_in_vec(bs_list, var_addr)) { + efi_utils::set_ptr_type_and_name(var_addr, "gBS", + "EFI_BOOT_SERVICES"); bs_list.push_back(var_addr); } bsFound = true; @@ -459,8 +460,9 @@ bool efi_analysis::efi_analyser_x86_t::find_boot_services_tables() { if (insn.ops[1].reg == bsRegister && !bsFound) { baseInsnAddr = ea; var_addr = insn.ops[0].addr; - if (!addr_in_vec(bs_list, var_addr)) { - set_ptr_type_and_name(var_addr, "gBS", "EFI_BOOT_SERVICES"); + if (!efi_utils::addr_in_vec(bs_list, var_addr)) { + efi_utils::set_ptr_type_and_name(var_addr, "gBS", + "EFI_BOOT_SERVICES"); bs_list.push_back(var_addr); } bsFound = true; @@ -470,8 +472,10 @@ bool efi_analysis::efi_analyser_x86_t::find_boot_services_tables() { if (insn.ops[1].reg == stRegister && !stFound && stRegister != bsRegister) { var_addr = insn.ops[0].addr; - if (!addr_in_tables(st_list, bs_list, rt_list, var_addr)) { - set_ptr_type_and_name(var_addr, "gST", "EFI_SYSTEM_TABLE"); + if (!efi_utils::addr_in_tables(st_list, bs_list, rt_list, + var_addr)) { + efi_utils::set_ptr_type_and_name(var_addr, "gST", + "EFI_SYSTEM_TABLE"); st_list.push_back(var_addr); } stFound = true; @@ -492,8 +496,10 @@ bool efi_analysis::efi_analyser_x86_t::find_boot_services_tables() { insn.ops[1].reg == stRegister && insn.ops[0].type == o_mem) { var_addr = insn.ops[0].addr; - if (!addr_in_tables(st_list, bs_list, rt_list, var_addr)) { - set_ptr_type_and_name(var_addr, "gST", "EFI_SYSTEM_TABLE"); + if (!efi_utils::addr_in_tables(st_list, bs_list, rt_list, + var_addr)) { + efi_utils::set_ptr_type_and_name(var_addr, "gST", + "EFI_SYSTEM_TABLE"); st_list.push_back(var_addr); } stFound = true; @@ -559,9 +565,9 @@ bool efi_analysis::efi_analyser_x86_t::find_runtime_services_tables() { next_insn.ops[1].type == o_reg && next_insn.ops[1].reg == rtRegister) { baseInsnAddr = ea; - if (!addr_in_vec(rt_list, var_addr)) { - set_ptr_type_and_name(var_addr, "gRT", - "EFI_RUNTIME_SERVICES"); + if (!efi_utils::addr_in_vec(rt_list, var_addr)) { + efi_utils::set_ptr_type_and_name(var_addr, "gRT", + "EFI_RUNTIME_SERVICES"); rt_list.push_back(var_addr); } rtFound = true; @@ -573,9 +579,9 @@ bool efi_analysis::efi_analyser_x86_t::find_runtime_services_tables() { if (insn.ops[1].reg == rtRegister && !rtFound) { baseInsnAddr = ea; var_addr = insn.ops[0].addr; - if (!addr_in_vec(rt_list, var_addr)) { - set_ptr_type_and_name(var_addr, "gRT", - "EFI_RUNTIME_SERVICES"); + if (!efi_utils::addr_in_vec(rt_list, var_addr)) { + efi_utils::set_ptr_type_and_name(var_addr, "gRT", + "EFI_RUNTIME_SERVICES"); rt_list.push_back(var_addr); } rtFound = true; @@ -585,9 +591,10 @@ bool efi_analysis::efi_analyser_x86_t::find_runtime_services_tables() { if (insn.ops[1].reg == stRegister && !stFound && stRegister != rtRegister) { var_addr = insn.ops[0].addr; - if (!addr_in_tables(st_list, bs_list, rt_list, var_addr)) { - set_ptr_type_and_name(insn.ops[0].addr, "gST", - "EFI_SYSTEM_TABLE"); + if (!efi_utils::addr_in_tables(st_list, bs_list, rt_list, + var_addr)) { + efi_utils::set_ptr_type_and_name(insn.ops[0].addr, "gST", + "EFI_SYSTEM_TABLE"); st_list.push_back(insn.ops[0].addr); } stFound = true; @@ -607,8 +614,10 @@ bool efi_analysis::efi_analyser_x86_t::find_runtime_services_tables() { if (insn.itype == NN_mov && insn.ops[1].type == o_reg && insn.ops[1].reg == stRegister && insn.ops[0].type == o_mem) { - if (!addr_in_tables(st_list, bs_list, rt_list, var_addr)) { - set_ptr_type_and_name(var_addr, "gST", "EFI_SYSTEM_TABLE"); + if (!efi_utils::addr_in_tables(st_list, bs_list, rt_list, + var_addr)) { + efi_utils::set_ptr_type_and_name(var_addr, "gST", + "EFI_SYSTEM_TABLE"); st_list.push_back(var_addr); } stFound = true; @@ -638,7 +647,7 @@ void efi_analysis::efi_analyser_x86_t::get_boot_services_all() { msg("[%s] BootServices finding by xrefs to gBS (0x%016llX)\n", g_plugin_name, u64_addr(bs)); - auto xrefs = get_xrefs_util(bs); + auto xrefs = efi_utils::get_xrefs(bs); for (auto ea : xrefs) { bool found = false; decode_insn(&insn, ea); @@ -679,12 +688,12 @@ void efi_analysis::efi_analyser_x86_t::get_boot_services_all() { // (can be confused with // gSmst->SmmInstallProtocolInterface) if (u32_addr(offset) == 0xa8) { - if (!check_boot_service_protocol(addr)) { + if (!efi_utils::check_boot_service_protocol(addr)) { break; } } - op_stroff_util(addr, "EFI_BOOT_SERVICES"); + efi_utils::op_stroff(addr, "EFI_BOOT_SERVICES"); msg("[%s] 0x%016llX : %s\n", g_plugin_name, u64_addr(addr), static_cast(g_boot_services_table_all[j].name)); @@ -706,7 +715,7 @@ void efi_analysis::efi_analyser_x86_t::get_boot_services_all() { get_arg_addrs(&args, addr); bsItem["args"] = args; - if (!json_in_vec(m_all_services, bsItem)) { + if (!efi_utils::json_in_vec(m_all_services, bsItem)) { m_all_services.push_back(bsItem); } @@ -734,7 +743,7 @@ void efi_analysis::efi_analyser_x86_t::get_runtime_services_all() { insn_t insn; for (auto rt : rt_list) { - auto xrefs = get_xrefs_util(rt); + auto xrefs = efi_utils::get_xrefs(rt); msg("[%s] RuntimeServices finding by xrefs to gRT (0x%016llX)\n", g_plugin_name, u64_addr(rt)); @@ -773,7 +782,7 @@ void efi_analysis::efi_analyser_x86_t::get_runtime_services_all() { offset = g_runtime_services_table_all[j].offset32; } if (service_offset == u32_addr(offset)) { - op_stroff_util(addr, "EFI_RUNTIME_SERVICES"); + efi_utils::op_stroff(addr, "EFI_RUNTIME_SERVICES"); msg("[%s] 0x%016llX : %s\n", g_plugin_name, u64_addr(addr), static_cast(g_runtime_services_table_all[j].name)); m_runtime_services_all[static_cast( @@ -794,7 +803,7 @@ void efi_analysis::efi_analyser_x86_t::get_runtime_services_all() { get_arg_addrs(&args, addr); rtItem["args"] = args; - if (!json_in_vec(m_all_services, rtItem)) { + if (!efi_utils::json_in_vec(m_all_services, rtItem)) { m_all_services.push_back(rtItem); } runtime_services_list.push_back(addr); @@ -818,7 +827,7 @@ void efi_analysis::efi_analyser_x86_t::get_smm_services_all64() { insn_t insn; for (auto smms : smst_list) { - auto xrefs = get_xrefs_util(smms); + auto xrefs = efi_utils::get_xrefs(smms); msg("[%s] SmmServices finding by xref to gSmst (0x%016llX)\n", g_plugin_name, u64_addr(smms)); @@ -855,7 +864,7 @@ void efi_analysis::efi_analyser_x86_t::get_smm_services_all64() { } } - op_stroff_util(addr, "_EFI_SMM_SYSTEM_TABLE2"); + efi_utils::op_stroff(addr, "_EFI_SMM_SYSTEM_TABLE2"); msg("[%s] 0x%016llX : %s\n", g_plugin_name, u64_addr(addr), static_cast(g_smm_services_table_all[j].name)); @@ -884,7 +893,7 @@ void efi_analysis::efi_analyser_x86_t::get_smm_services_all64() { get_arg_addrs(&args, addr); smmsItem["args"] = args; - if (!json_in_vec(m_all_services, smmsItem)) { + if (!efi_utils::json_in_vec(m_all_services, smmsItem)) { m_all_services.push_back(smmsItem); } break; @@ -955,7 +964,7 @@ void efi_analysis::efi_analyser_x86_t::get_pei_services_all32() { // looks like a FP break; } - op_stroff_util(ea, "EFI_PEI_SERVICES"); + efi_utils::op_stroff(ea, "EFI_PEI_SERVICES"); msg("[%s] 0x%016llX : %s\n", g_plugin_name, u64_addr(ea), static_cast(g_pei_services_table32[j].name)); m_pei_services_all[static_cast( @@ -971,7 +980,7 @@ void efi_analysis::efi_analyser_x86_t::get_pei_services_all32() { // add code addresses for arguments psItem["args"] = args; - if (!json_in_vec(m_all_services, psItem)) { + if (!efi_utils::json_in_vec(m_all_services, psItem)) { m_all_services.push_back(psItem); } } @@ -1015,7 +1024,7 @@ void efi_analysis::efi_analyser_x86_t::get_variable_ppi_calls_all32() { } if (found_push) { - op_stroff_util(ea, "EFI_PEI_READ_ONLY_VARIABLE2_PPI"); + efi_utils::op_stroff(ea, "EFI_PEI_READ_ONLY_VARIABLE2_PPI"); msg("[%s] 0x%016llX : %s\n", g_plugin_name, u64_addr(ea), static_cast(g_variable_ppi_table_all[j].name)); std::string ppi_call = @@ -1036,7 +1045,7 @@ void efi_analysis::efi_analyser_x86_t::get_variable_ppi_calls_all32() { get_arg_addrs(&args, ea); ppiItem["args"] = args; - if (!json_in_vec(m_all_services, ppiItem)) { + if (!efi_utils::json_in_vec(m_all_services, ppiItem)) { m_all_services.push_back(ppiItem); } } @@ -1109,8 +1118,8 @@ void efi_analysis::efi_analyser_x86_t::get_ppi_names32() { if (found) { msg("[%s] found PPI GUID parameter at 0x%016llX\n", g_plugin_name, u64_addr(guidCodeAddress)); - auto guid = get_guid_by_address(guidDataAddress); - if (!valid_guid(guid)) { + auto guid = efi_utils::get_guid_by_address(guidDataAddress); + if (!efi_utils::valid_guid(guid)) { msg("[%s] Incorrect GUID at 0x%016llX\n", g_plugin_name, u64_addr(guidCodeAddress)); continue; @@ -1121,7 +1130,7 @@ void efi_analysis::efi_analyser_x86_t::get_ppi_names32() { ppiItem["address"] = guidDataAddress; ppiItem["xref"] = guidCodeAddress; ppiItem["service"] = g_pei_services_table_all[i].name; - ppiItem["guid"] = guid_to_string(guid); + ppiItem["guid"] = efi_utils::guid_to_string(guid); ppiItem["module"] = "Current"; // find GUID name @@ -1131,7 +1140,7 @@ void efi_analysis::efi_analyser_x86_t::get_ppi_names32() { ppiItem["ppi_name"] = name; // check if item already exists - if (!json_in_vec(m_all_ppis, ppiItem)) { + if (!efi_utils::json_in_vec(m_all_ppis, ppiItem)) { m_all_ppis.push_back(ppiItem); } continue; @@ -1142,7 +1151,7 @@ void efi_analysis::efi_analyser_x86_t::get_ppi_names32() { ppiItem["ppi_name"] = "ProprietaryPpi"; // check if item already exists - if (!json_in_vec(m_all_ppis, ppiItem)) { + if (!efi_utils::json_in_vec(m_all_ppis, ppiItem)) { m_all_ppis.push_back(ppiItem); } continue; @@ -1175,20 +1184,20 @@ void efi_analysis::efi_analyser_x86_t::get_prot_boot_services64() { // additional check for gBS->RegisterProtocolNotify // (can be confused with gSmst->SmmInstallProtocolInterface) if (u32_addr(g_boot_services_table64[i].offset) == 0xa8) { - if (!check_boot_service_protocol(ea)) { + if (!efi_utils::check_boot_service_protocol(ea)) { break; } } // check that address does not belong to the protocol interface // (gBS != gInterface) - auto bs_addr = find_unknown_bs_var_64(ea); - if (addr_in_vec(rt_list, bs_addr) || - !check_boot_service_protocol_xrefs(bs_addr)) { + auto bs_addr = efi_utils::find_unknown_bs_var_64(ea); + if (efi_utils::addr_in_vec(rt_list, bs_addr) || + !efi_utils::check_boot_service_protocol_xrefs(bs_addr)) { break; } - op_stroff_util(ea, "EFI_BOOT_SERVICES"); + efi_utils::op_stroff(ea, "EFI_BOOT_SERVICES"); msg("[%s] 0x%016llX : %s\n", g_plugin_name, u64_addr(ea), static_cast(g_boot_services_table64[i].name)); m_boot_services[static_cast( @@ -1208,7 +1217,7 @@ void efi_analysis::efi_analyser_x86_t::get_prot_boot_services64() { get_arg_addrs(&args, ea); bsItem["args"] = args; - if (!json_in_vec(m_all_services, bsItem)) { + if (!efi_utils::json_in_vec(m_all_services, bsItem)) { m_all_services.push_back(bsItem); } break; @@ -1231,7 +1240,7 @@ void efi_analysis::efi_analyser_x86_t::get_prot_boot_services32() { if (insn.itype == NN_callni && insn.ops[0].reg == R_EAX) { for (auto i = 0; i < g_boot_services_table32_count; i++) { if (insn.ops[0].addr == u32_addr(g_boot_services_table32[i].offset)) { - op_stroff_util(ea, "EFI_BOOT_SERVICES"); + efi_utils::op_stroff(ea, "EFI_BOOT_SERVICES"); msg("[%s] 0x%016llX : %s\n", g_plugin_name, u64_addr(ea), static_cast(g_boot_services_table32[i].name)); m_boot_services[static_cast( @@ -1251,7 +1260,7 @@ void efi_analysis::efi_analyser_x86_t::get_prot_boot_services32() { get_arg_addrs(&args, ea); bsItem["args"] = args; - if (!json_in_vec(m_all_services, bsItem)) { + if (!efi_utils::json_in_vec(m_all_services, bsItem)) { m_all_services.push_back(bsItem); } break; @@ -1278,15 +1287,16 @@ void efi_analysis::efi_analyser_x86_t::find_other_boot_services_tables64() { ea_t addr = static_cast(s["address"]); msg("[%s] current service: 0x%016llX\n", g_plugin_name, u64_addr(addr)); - ea_t addr_bs = find_unknown_bs_var_64(addr); + ea_t addr_bs = efi_utils::find_unknown_bs_var_64(addr); - if (addr_bs == BADADDR || addr_in_tables(bs_list, rt_list, addr_bs)) { + if (addr_bs == BADADDR || + efi_utils::addr_in_tables(bs_list, rt_list, addr_bs)) { continue; } msg("[%s] found BootServices table at 0x%016llX, address = 0x%016llX\n", g_plugin_name, u64_addr(addr), u64_addr(addr_bs)); - set_ptr_type_and_name(addr_bs, "gBS", "EFI_BOOT_SERVICES"); + efi_utils::set_ptr_type_and_name(addr_bs, "gBS", "EFI_BOOT_SERVICES"); bs_list.push_back(addr_bs); } } @@ -1302,16 +1312,16 @@ bool efi_analysis::efi_analyser_t::add_protocol(std::string service_name, } json protocol; - auto guid = get_guid_by_address(guid_addr); + auto guid = efi_utils::get_guid_by_address(guid_addr); protocol["address"] = guid_addr; protocol["xref"] = xref_addr; protocol["service"] = service_name; - protocol["guid"] = guid_to_string(guid); + protocol["guid"] = efi_utils::guid_to_string(guid); protocol["ea"] = call_addr; qstring moduleName("Current"); - if (input_file_type() == arch_file_type_t::uefi) { - moduleName = get_module_name_loader(call_addr); + if (efi_utils::input_file_type() == arch_file_type_t::uefi) { + moduleName = efi_utils::get_module_name_loader(call_addr); } protocol["module"] = static_cast(moduleName.c_str()); @@ -1322,9 +1332,10 @@ bool efi_analysis::efi_analyser_t::add_protocol(std::string service_name, protocol["prot_name"] = name; } else { protocol["prot_name"] = "UNKNOWN_PROTOCOL_GUID"; - set_type_and_name(guid_addr, "UNKNOWN_PROTOCOL_GUID", "EFI_GUID"); + efi_utils::set_type_and_name(guid_addr, "UNKNOWN_PROTOCOL_GUID", + "EFI_GUID"); } - if (!json_in_vec(m_all_protocols, protocol)) { + if (!efi_utils::json_in_vec(m_all_protocols, protocol)) { m_all_protocols.push_back(protocol); } return true; @@ -1482,8 +1493,8 @@ void efi_analysis::efi_analyser_x86_t::get_bs_prot_names64() { msg("[%s] get_bs_prot_names64: found protocol GUID parameter at " "0x%016llX\n", g_plugin_name, u64_addr(guidCodeAddress)); - auto guid = get_guid_by_address(guidDataAddress); - if (!valid_guid(guid)) { + auto guid = efi_utils::get_guid_by_address(guidDataAddress); + if (!efi_utils::valid_guid(guid)) { msg("[%s] Incorrect GUID at 0x%016llX\n", g_plugin_name, u64_addr(guidCodeAddress)); continue; @@ -1555,8 +1566,8 @@ void efi_analysis::efi_analyser_x86_t::get_bs_prot_names32() { msg("[%s] get_bs_prot_names32: found protocol GUID parameter at " "0x%016llX\n", g_plugin_name, u64_addr(guidCodeAddress)); - auto guid = get_guid_by_address(guidDataAddress); - if (!valid_guid(guid)) { + auto guid = efi_utils::get_guid_by_address(guidDataAddress); + if (!efi_utils::valid_guid(guid)) { msg("[%s] Incorrect GUID at 0x%016llX\n", g_plugin_name, u64_addr(guidCodeAddress)); continue; @@ -1617,8 +1628,8 @@ void efi_analysis::efi_analyser_x86_t::get_smm_prot_names64() { msg("[%s] get_smm_prot_names64: found protocol GUID parameter at " "0x%016llX\n", g_plugin_name, u64_addr(guidCodeAddress)); - auto guid = get_guid_by_address(guidDataAddress); - if (!valid_guid(guid)) { + auto guid = efi_utils::get_guid_by_address(guidDataAddress); + if (!efi_utils::valid_guid(guid)) { msg("[%s] Incorrect GUID at 0x%016llX\n", g_plugin_name, u64_addr(guidCodeAddress)); continue; @@ -1653,7 +1664,7 @@ void efi_analysis::efi_analyser_t::mark_interfaces() { if (!marked) { std::string svcName = static_cast(ifItem[m_pkey]); set_name(address, svcName.c_str(), SN_FORCE); - set_guid_type(address); + efi_utils::set_guid_type(address); std::string comment = "EFI_GUID " + svcName; m_marked_interfaces.push_back(address); msg("[%s] address: 0x%016llX, comment: %s\n", g_plugin_name, @@ -1682,22 +1693,22 @@ void efi_analysis::efi_analyser_t::mark_data_guids() { ea += 1; continue; } - auto guid = get_guid_by_address(ea); + auto guid = efi_utils::get_guid_by_address(ea); // find GUID name auto it = m_guiddb_map.find(guid); if (it != m_guiddb_map.end()) { std::string guidName = it->second; set_name(ea, guidName.c_str(), SN_FORCE); - set_guid_type(ea); + efi_utils::set_guid_type(ea); // rename PPI if (guidName.length() > 9 && guidName.rfind("_PPI_GUID") == guidName.length() - 9) { - auto xrefs = get_xrefs_util(ea); + auto xrefs = efi_utils::get_xrefs(ea); for (auto addr : xrefs) { - std::string ppiName = - "g" + type_to_name(guidName.substr(0, guidName.length() - 5)); + std::string ppiName = "g" + efi_utils::type_to_name(guidName.substr( + 0, guidName.length() - 5)); ea_t ppiEa = addr - ptrSize; // check flags if (ptrSize == 8 && get_wide_dword(ppiEa + 4)) { @@ -1705,7 +1716,7 @@ void efi_analysis::efi_analyser_t::mark_data_guids() { continue; } uint64_t flags = static_cast(get_wide_dword(ppiEa)); - if (!uint64_in_vec(m_ppi_flags, flags)) { + if (!efi_utils::uint64_in_vec(m_ppi_flags, flags)) { continue; } msg("[%s] address: 0x%016llX, PPI: %s\n", g_plugin_name, @@ -1721,7 +1732,7 @@ void efi_analysis::efi_analyser_t::mark_data_guids() { json guid_item; guid_item["address"] = ea; guid_item["name"] = guidName; - guid_item["guid"] = guid_to_string(guid); + guid_item["guid"] = efi_utils::guid_to_string(guid); m_all_guids.push_back(guid_item); dataGuids.push_back(guid_item); } @@ -1787,7 +1798,7 @@ void efi_analysis::efi_analyser_x86_t::mark_local_guids64() { json guid_item; guid_item["address"] = ea; guid_item["name"] = dbItem.key(); - guid_item["guid"] = guid_to_string(guid); + guid_item["guid"] = efi_utils::guid_to_string(guid); m_all_guids.push_back(guid_item); stackGuids.push_back(guid_item); exit = true; @@ -1825,7 +1836,7 @@ void findCalloutRec(func_t *func) { if (insn.itype == NN_mov && insn.ops[0].type == o_reg && insn.ops[1].type == o_mem) { // search for callouts with gBS - if (addr_in_vec(bs_list, insn.ops[1].addr)) { + if (efi_utils::addr_in_vec(bs_list, insn.ops[1].addr)) { msg("[%s] SMM callout found: 0x%016llX\n", g_plugin_name, u64_addr(ea)); // filter FP auto reg = insn.ops[0].reg; @@ -1854,7 +1865,7 @@ void findCalloutRec(func_t *func) { } // search for callouts with gRT - if (addr_in_vec(rt_list, insn.ops[1].addr)) { + if (efi_utils::addr_in_vec(rt_list, insn.ops[1].addr)) { msg("[%s] SMM callout found (gRT): 0x%016llX\n", g_plugin_name, u64_addr(ea)); calloutAddrs.push_back(ea); @@ -1866,7 +1877,7 @@ void findCalloutRec(func_t *func) { insn_t insn_xref; bool interface_callout_found = false; // check all xrefs for found global variable - for (auto xref : get_xrefs_util(g_addr)) { + for (auto xref : efi_utils::get_xrefs(g_addr)) { // chcek if it looks like interface decode_insn(&insn_xref, xref); if (insn_xref.itype != NN_lea || insn_xref.ops[0].type != o_reg || @@ -2219,7 +2230,7 @@ bool efi_analysis::efi_analyser_t::find_double_get_variable( if (insn.itype == NN_mov && insn.ops[0].type == o_reg && insn.ops[1].type == o_mem) { ea_t mem_addr = insn.ops[1].addr; - if (addr_in_vec(bs_list, mem_addr)) { + if (efi_utils::addr_in_vec(bs_list, mem_addr)) { wrong_detection = true; break; } @@ -2387,10 +2398,10 @@ bool efi_analysis::efi_analyser_t::analyse_variable_service( insn.ops[0].reg == R_RCX && insn.ops[1].type == o_mem) { msg("[%s] VariableName address: 0x%016llX\n", g_plugin_name, u64_addr(insn.ops[1].addr)); - std::string var_name = get_wide_string(insn.ops[1].addr); + std::string var_name = efi_utils::get_wide_string(insn.ops[1].addr); // retype CHAR16 to const CHAR16 to improve pseudocode quality - set_const_char16_type(insn.ops[1].addr); + efi_utils::set_const_char16_type(insn.ops[1].addr); msg("[%s] VariableName: %s\n", g_plugin_name, var_name.c_str()); item["VariableName"] = var_name; @@ -2404,7 +2415,7 @@ bool efi_analysis::efi_analyser_t::analyse_variable_service( insn.ops[0].reg == R_RDX && insn.ops[1].type == o_mem) { msg("[%s] VendorGuid address (global): 0x%016llX\n", g_plugin_name, u64_addr(insn.ops[1].addr)); - efi_guid_t guid = get_global_guid(insn.ops[1].addr); + efi_guid_t guid = efi_utils::get_global_guid(insn.ops[1].addr); msg("[%s] GUID: %s\n", g_plugin_name, guid.to_string().c_str()); item["VendorGuid"] = guid.to_string(); guid_found = true; @@ -2416,7 +2427,7 @@ bool efi_analysis::efi_analyser_t::analyse_variable_service( case R_RBP: { msg("[%s] VendorGuid address (regarding to RBP): 0x%016llX\n", g_plugin_name, u64_addr(insn.ops[1].addr)); - efi_guid_t guid = get_local_guid(f, insn.ops[1].addr); + efi_guid_t guid = efi_utils::get_local_guid(f, insn.ops[1].addr); msg("[%s] GUID: %s\n", g_plugin_name, guid.to_string().c_str()); item["VendorGuid"] = guid.to_string(); guid_found = true; @@ -2424,7 +2435,7 @@ bool efi_analysis::efi_analyser_t::analyse_variable_service( case R_RSP: { msg("[%s] VendorGuid address (regarding to RSP): 0x%016llX\n", g_plugin_name, u64_addr(insn.ops[1].addr)); - efi_guid_t guid = get_local_guid(f, insn.ops[1].addr); + efi_guid_t guid = efi_utils::get_local_guid(f, insn.ops[1].addr); msg("[%s] GUID: %s\n", g_plugin_name, guid.to_string().c_str()); item["VendorGuid"] = guid.to_string(); guid_found = true; @@ -2690,7 +2701,7 @@ bool efi_analysis::efi_analyse_main_x86_64() { ? analyser.m_ftype = ffs_file_type_t::pei : analyser.m_ftype = ffs_file_type_t::dxe_smm; } else { - analyser.m_ftype = ask_file_type(&analyser.m_all_guids); + analyser.m_ftype = efi_utils::ask_file_type(&analyser.m_all_guids); } analyser.set_pvalues(); @@ -2725,9 +2736,9 @@ bool efi_analysis::efi_analyse_main_x86_64() { analyser.mark_interfaces(); // search for copies of global variables - mark_copies_for_gvars(smst_list, "gSmst"); - mark_copies_for_gvars(bs_list, "gBS"); - mark_copies_for_gvars(rt_list, "gRT"); + efi_utils::mark_copies_for_gvars(smst_list, "gSmst"); + efi_utils::mark_copies_for_gvars(bs_list, "gBS"); + efi_utils::mark_copies_for_gvars(rt_list, "gRT"); // search for vulnerabilities if (!g_args.disable_vuln_hunt) { @@ -2799,7 +2810,7 @@ bool efi_analysis::efi_analyse_main_x86_32() { ? analyser.m_ftype = ffs_file_type_t::pei : analyser.m_ftype = ffs_file_type_t::dxe_smm; } else { - analyser.m_ftype = ask_file_type(&analyser.m_all_guids); + analyser.m_ftype = efi_utils::ask_file_type(&analyser.m_all_guids); } analyser.set_pvalues(); @@ -2823,8 +2834,8 @@ bool efi_analysis::efi_analyse_main_x86_32() { apply_all_types_for_interfaces_smm(analyser.m_all_protocols); #endif } else if (analyser.m_ftype == ffs_file_type_t::pei) { - set_entry_arg_to_pei_svc(); - add_struct_for_shifted_ptr(); + efi_utils::set_entry_arg_to_pei_svc(); + efi_utils::add_struct_for_shifted_ptr(); #ifdef HEX_RAYS for (auto addr : analyser.m_funcs) { detect_pei_services(get_func(addr)); diff --git a/efiXplorer/efi_deps.cc b/efiXplorer/efi_deps.cc index 57b7875d..7464d0df 100644 --- a/efiXplorer/efi_deps.cc +++ b/efiXplorer/efi_deps.cc @@ -52,9 +52,9 @@ json EfiDependencies::getDeps(std::string guid) { if (p["guid"] != guid) { continue; } - p["ea"] = as_hex(u64_addr(p["ea"])); - p["xref"] = as_hex(u64_addr(p["xref"])); - p["address"] = as_hex(u64_addr(p["address"])); + p["ea"] = efi_utils::as_hex(u64_addr(p["ea"])); + p["xref"] = efi_utils::as_hex(u64_addr(p["xref"])); + p["address"] = efi_utils::as_hex(u64_addr(p["address"])); if (find(installers.begin(), installers.end(), p["service"]) != installers.end()) { res["installed"].push_back(p); @@ -141,22 +141,22 @@ void EfiDependencies::getProtocolsWithoutInstallers() { void EfiDependencies::getInstallersModules() { // search for this protocols in binary for (auto &protocol : protocolsWithoutInstallers) { - auto addrs = search_protocol(protocol); + auto addrs = efi_utils::search_protocol(protocol); bool installerFound = false; for (auto addr : addrs) { - auto xrefs = get_xrefs_util(addr); + auto xrefs = efi_utils::get_xrefs(addr); if (!xrefs.size()) { continue; } if (xrefs.size() == 1) { func_t *func = get_func(xrefs.at(0)); if (func == nullptr) { - xrefs = get_xrefs_to_array(xrefs.at(0)); + xrefs = efi_utils::get_xrefs_to_array(xrefs.at(0)); } } for (auto ea : xrefs) { - if (check_install_protocol(ea)) { - auto module = get_module_name_loader(ea); + if (efi_utils::check_install_protocol(ea)) { + auto module = efi_utils::get_module_name_loader(ea); additionalInstallers[protocol] = static_cast(module.c_str()); installerFound = true; diff --git a/efiXplorer/efi_hexrays.cc b/efiXplorer/efi_hexrays.cc index 5dbc8478..eccaad35 100644 --- a/efiXplorer/efi_hexrays.cc +++ b/efiXplorer/efi_hexrays.cc @@ -73,14 +73,14 @@ bool set_hexrays_var_info_and_handle_interfaces(ea_t func_addr, lvar_t &ll, } // Get xrefs to local variable - xreflist_t xrefs = - xrefs_to_stack_var(func_addr, static_cast(name.c_str())); + xreflist_t xrefs = efi_utils::xrefs_to_stack_var( + func_addr, static_cast(name.c_str())); qstring type_name; ptr_type_data_t pi; tif.get_ptr_details(&pi); pi.obj_type.get_type_name(&type_name); // Handling all interface functions (to rename function arguments) - op_stroff_for_interface(xrefs, type_name); + efi_utils::op_stroff_for_interface(xrefs, type_name); return true; } diff --git a/efiXplorer/efi_hexrays.h b/efiXplorer/efi_hexrays.h index d36a0d03..4ecfc730 100644 --- a/efiXplorer/efi_hexrays.h +++ b/efiXplorer/efi_hexrays.h @@ -562,22 +562,24 @@ class GUIDRetyper : public GUIDRelatedVisitorBase { ++mNumApplied; // Rename global variable - auto name = "g" + type_to_name(static_cast(tStr.c_str())); + auto name = + "g" + efi_utils::type_to_name(static_cast(tStr.c_str())); set_name(dest_ea, name.c_str(), SN_FORCE); // Get xrefs to global variable - auto xrefs = get_xrefs_util(dest_ea); + auto xrefs = efi_utils::get_xrefs(dest_ea); qstring type_name; ptr_type_data_t pi; ptrTif.get_ptr_details(&pi); pi.obj_type.get_type_name(&type_name); // Handling all interface functions (to rename function arguments) - op_stroff_for_global_interface(xrefs, type_name); + efi_utils::op_stroff_for_global_interface(xrefs, type_name); } else if (outArg->op == cot_var) { // For local variables var_ref_t varRef = outArg->v; lvar_t &destVar = varRef.mba->vars[varRef.idx]; // Set the Hex-Rays variable type - auto name = type_to_name(static_cast(tStr.c_str())); + auto name = + efi_utils::type_to_name(static_cast(tStr.c_str())); set_lvar_name(static_cast(name.c_str()), destVar, mFuncEa); if (set_hexrays_var_info_and_handle_interfaces(mFuncEa, destVar, ptrTif, name)) { @@ -592,13 +594,13 @@ class GUIDRetyper : public GUIDRelatedVisitorBase { // For global variables if (outArg->op == cot_obj) { // Rename global variable - auto name = "g" + type_to_name(type_name); + auto name = "g" + efi_utils::type_to_name(type_name); set_name(dest_ea, name.c_str(), SN_FORCE); } else if (outArg->op == cot_var) { // For local variables var_ref_t varRef = outArg->v; lvar_t &destVar = varRef.mba->vars[varRef.idx]; // Set the Hex-Rays variable type - auto name = type_to_name(type_name); + auto name = efi_utils::type_to_name(type_name); set_lvar_name(static_cast(name.c_str()), destVar, mFuncEa); } } @@ -729,7 +731,7 @@ class PrototypesFixer : public ctree_visitor_t { if (type_name == qstring("EFI_HANDLE") || type_name == qstring("EFI_SYSTEM_TABLE")) { - if (!addr_in_vec(child_functions, func_addr)) { + if (!efi_utils::addr_in_vec(child_functions, func_addr)) { child_functions.push_back(func_addr); } // set argument type and name @@ -773,7 +775,7 @@ class VariablesDetector : public ctree_visitor_t { int visit_expr(cexpr_t *e) { if (e->op == cot_asg) { // saving a child function for recursive analysis - if (!addr_in_vec(child_functions, e->ea)) { + if (!efi_utils::addr_in_vec(child_functions, e->ea)) { child_functions.push_back(e->x->obj_ea); } } @@ -835,26 +837,26 @@ class VariablesDetector : public ctree_visitor_t { ea_t g_addr = e->x->obj_ea; std::string type_name_str = static_cast(type_name.c_str()); if (type_name == qstring("EFI_HANDLE")) { - set_type_and_name(g_addr, "gImageHandle", type_name_str); - if (!addr_in_vec(image_handle_list, g_addr)) { + efi_utils::set_type_and_name(g_addr, "gImageHandle", type_name_str); + if (!efi_utils::addr_in_vec(image_handle_list, g_addr)) { image_handle_list.push_back(g_addr); } } if (type_name == qstring("EFI_SYSTEM_TABLE")) { - set_ptr_type_and_name(g_addr, "gST", type_name_str); - if (!addr_in_vec(st_list, g_addr)) { + efi_utils::set_ptr_type_and_name(g_addr, "gST", type_name_str); + if (!efi_utils::addr_in_vec(st_list, g_addr)) { st_list.push_back(g_addr); } } if (type_name == qstring("EFI_BOOT_SERVICES")) { - set_ptr_type_and_name(g_addr, "gBS", type_name_str); - if (!addr_in_vec(bs_list, g_addr)) { + efi_utils::set_ptr_type_and_name(g_addr, "gBS", type_name_str); + if (!efi_utils::addr_in_vec(bs_list, g_addr)) { bs_list.push_back(g_addr); } } if (type_name == qstring("EFI_RUNTIME_SERVICES")) { - set_ptr_type_and_name(g_addr, "gRT", type_name_str); - if (!addr_in_vec(rt_list, g_addr)) { + efi_utils::set_ptr_type_and_name(g_addr, "gRT", type_name_str); + if (!efi_utils::addr_in_vec(rt_list, g_addr)) { rt_list.push_back(g_addr); } } @@ -870,7 +872,8 @@ class VariablesDetector : public ctree_visitor_t { } lvar_t &dest_var = var_ref.mba->vars[var_ref.idx]; // Set the Hex-Rays variable type - auto name = type_to_name(static_cast(type_name.c_str())); + auto name = + efi_utils::type_to_name(static_cast(type_name.c_str())); // set_hexrays_var_info(mFuncEa, dest_var, var_type, name); } @@ -921,7 +924,7 @@ class ServicesDetector : public ctree_visitor_t { } auto service_name = - type_to_name(static_cast(type_name.c_str())); + efi_utils::type_to_name(static_cast(type_name.c_str())); if (service_name.rfind("Efi", 0) == 0) { service_name = service_name.substr(3); if (service_name == "RaiseTpl") { @@ -939,9 +942,9 @@ class ServicesDetector : public ctree_visitor_t { json s; s["address"] = e->ea; s["service_name"] = service_name; - s["table_name"] = get_table_name(service_name); + s["table_name"] = efi_utils::get_table_name(service_name); - if (!json_in_vec(services, s)) { + if (!efi_utils::json_in_vec(services, s)) { services.push_back(s); } @@ -1036,7 +1039,7 @@ class PeiServicesDetector : public ctree_visitor_t { } if (call) { - op_stroff_util(e->ea, "EFI_PEI_SERVICES"); + efi_utils::op_stroff(e->ea, "EFI_PEI_SERVICES"); } return 0; @@ -1085,7 +1088,7 @@ class PeiServicesDetectorArm : public ctree_visitor_t { if (func_type.substr(0, prefix.length()) == prefix) { func_type.erase(0, prefix.length()); } - service_name = type_to_name(func_type); + service_name = efi_utils::type_to_name(func_type); } else { auto s = mPeiServices.find(offset); if (s == mPeiServices.end()) { @@ -1104,7 +1107,7 @@ class PeiServicesDetectorArm : public ctree_visitor_t { s["service_name"] = service_name; s["table_name"] = table_type_name.c_str(); - if (!json_in_vec(services, s)) { + if (!efi_utils::json_in_vec(services, s)) { services.push_back(s); } diff --git a/efiXplorer/efi_smm_utils.cc b/efiXplorer/efi_smm_utils.cc index 69c3ba0d..7b09c7dd 100644 --- a/efiXplorer/efi_smm_utils.cc +++ b/efiXplorer/efi_smm_utils.cc @@ -36,13 +36,15 @@ ea_list_t findSmstSwDispatch(ea_list_t bs_list) { 0x420c, {0xb0, 0x26, 0xdf, 0x99, 0x36, 0x53, 0xf8, 0xbf}}; // EFI_SMM_SW_DISPATCH_PROTOCOL_GUID - ea_list_t data_addrs = find_data(0, BADADDR, guid.uchar_data().data(), 16); - ea_list_t data2_addrs = find_data(0, BADADDR, guid2.uchar_data().data(), 16); + ea_list_t data_addrs = + efi_utils::find_data(0, BADADDR, guid.uchar_data().data(), 16); + ea_list_t data2_addrs = + efi_utils::find_data(0, BADADDR, guid2.uchar_data().data(), 16); data_addrs.insert(data_addrs.end(), data2_addrs.begin(), data2_addrs.end()); for (auto data_addr : data_addrs) { msg("[%s] EFI_SMM_SW_DISPATCH(2)_PROTOCOL_GUID: 0x%016llX\n", g_plugin_name, u64_addr(data_addr)); - ea_list_t xrefs = get_xrefs_util(data_addr); + ea_list_t xrefs = efi_utils::get_xrefs(data_addr); insn_t insn; for (auto xref : xrefs) { uint16_t smst_reg = 0xffff; // Smst register @@ -75,10 +77,11 @@ ea_list_t findSmstSwDispatch(ea_list_t bs_list) { msg("[%s] found gSmst at 0x%016llX, address = 0x%016llX\n", g_plugin_name, u64_addr(cur_addr), u64_addr(insn.ops[1].addr)); res_addr = insn.ops[1].addr; - if (addr_in_vec(bs_list, res_addr)) { + if (efi_utils::addr_in_vec(bs_list, res_addr)) { continue; } - set_ptr_type_and_name(res_addr, "gSmst", "_EFI_SMM_SYSTEM_TABLE2"); + efi_utils::set_ptr_type_and_name(res_addr, "gSmst", + "_EFI_SMM_SYSTEM_TABLE2"); smst_addrs.push_back(res_addr); break; } @@ -101,11 +104,12 @@ ea_list_t findSmstSmmBase(ea_list_t bs_list) { 0x47fd, {0x9d, 0xd4, 0x10, 0xa8, 0xf1, 0x50, 0xc1, 0x91}}; // EFI_SMM_BASE2_PROTOCOL_GUID - ea_list_t data_addrs = find_data(0, BADADDR, guid.uchar_data().data(), 16); + ea_list_t data_addrs = + efi_utils::find_data(0, BADADDR, guid.uchar_data().data(), 16); for (auto data_addr : data_addrs) { msg("[%s] EFI_SMM_BASE2_PROTOCOL_GUID: 0x%016llX\n", g_plugin_name, u64_addr(data_addr)); - ea_list_t data_xrefs = get_xrefs_util(data_addr); + ea_list_t data_xrefs = efi_utils::get_xrefs(data_addr); insn_t insn; for (auto xref : data_xrefs) { ea_t res_addr = BADADDR; @@ -129,14 +133,15 @@ ea_list_t findSmstSmmBase(ea_list_t bs_list) { } if (!in_smram) { // we found gSmst - if (addr_in_vec(bs_list, res_addr)) { + if (efi_utils::addr_in_vec(bs_list, res_addr)) { continue; } - set_ptr_type_and_name(res_addr, "gSmst", "_EFI_SMM_SYSTEM_TABLE2"); + efi_utils::set_ptr_type_and_name(res_addr, "gSmst", + "_EFI_SMM_SYSTEM_TABLE2"); smst_addrs.push_back(res_addr); } else { // we found gInSmram - set_type_and_name(res_addr, "gInSmram", "BOOLEAN"); + efi_utils::set_type_and_name(res_addr, "gInSmram", "BOOLEAN"); } } } @@ -291,7 +296,7 @@ func_list_t findSmiHandlers(ea_t address, std::string prefix) { std::transform(prefix.begin(), prefix.end(), prefix_upper.begin(), ::toupper); std::string type = "EFI_SMM_" + prefix_upper + "_DISPATCH2_PROTOCOL"; - op_stroff_util(ea, type); + efi_utils::op_stroff(ea, type); } if (insn.itype == NN_retn || insn.itype == NN_int3) { @@ -314,10 +319,11 @@ func_list_t findSmiHandlers(ea_t address, std::string prefix) { // call qword ptr [...] func_list_t findSmiHandlersSmmDispatch(efi_guid_t guid, std::string prefix) { func_list_t m_smi_handlers; - ea_list_t data_addrs = find_data(0, BADADDR, guid.uchar_data().data(), 16); + ea_list_t data_addrs = + efi_utils::find_data(0, BADADDR, guid.uchar_data().data(), 16); msg("[%s] %sSmiHandler function finding\n", g_plugin_name, prefix.c_str()); for (auto data_addr : data_addrs) { - ea_list_t xrefs = get_xrefs_util(data_addr); + ea_list_t xrefs = efi_utils::get_xrefs(data_addr); for (auto xref : xrefs) { msg("[%s] findSmiHandlers: 0x%016llX\n", g_plugin_name, u64_addr(xref)); @@ -370,10 +376,11 @@ ea_list_t findSmmGetVariableCalls(segment_list_t dataSegments, 0xa7}}; // EFI_SMM_VARIABLE_PROTOCOL_GUID // Find all EFI_GUID EFI_SMM_VARIABLE_PROTOCOL_GUID addresses - ea_list_t data_addrs = find_data(0, BADADDR, guid.uchar_data().data(), 16); + ea_list_t data_addrs = + efi_utils::find_data(0, BADADDR, guid.uchar_data().data(), 16); ea_list_t gSmmVariableAddrs; // Find all gSmmVariable variables for (auto data_addr : data_addrs) { - ea_list_t xrefs = get_xrefs_util(data_addr); + ea_list_t xrefs = efi_utils::get_xrefs(data_addr); for (auto xref : xrefs) { segment_t *seg = getseg(static_cast(xref)); @@ -398,8 +405,8 @@ ea_list_t findSmmGetVariableCalls(segment_list_t dataSegments, insn.ops[0].reg == R_R8 && insn.ops[1].type == o_mem) { msg("[%s] gSmmVariable address: 0x%016llX\n", g_plugin_name, u64_addr(insn.ops[1].addr)); - set_ptr_type_and_name(insn.ops[1].addr, "gSmmVariable", - "EFI_SMM_VARIABLE_PROTOCOL"); + efi_utils::set_ptr_type_and_name(insn.ops[1].addr, "gSmmVariable", + "EFI_SMM_VARIABLE_PROTOCOL"); gSmmVariableAddrs.push_back(insn.ops[1].addr); break; } @@ -413,7 +420,7 @@ ea_list_t findSmmGetVariableCalls(segment_list_t dataSegments, } for (auto smmVarAddr : gSmmVariableAddrs) { - ea_list_t smmVarXrefs = get_xrefs_util(static_cast(smmVarAddr)); + ea_list_t smmVarXrefs = efi_utils::get_xrefs(static_cast(smmVarAddr)); for (auto smmVarXref : smmVarXrefs) { segment_t *seg = getseg(static_cast(smmVarXref)); qstring seg_name; @@ -451,7 +458,7 @@ ea_list_t findSmmGetVariableCalls(segment_list_t dataSegments, // Temporarily add a "virtual" smm service call // for easier annotations and UI - op_stroff_util(ea, "EFI_SMM_VARIABLE_PROTOCOL"); + efi_utils::op_stroff(ea, "EFI_SMM_VARIABLE_PROTOCOL"); msg("[%s] 0x%016llX : %s\n", g_plugin_name, u64_addr(ea), "SmmGetVariable"); std::string smm_call = "gSmmVariable->SmmGetVariable"; @@ -501,7 +508,7 @@ ea_list_t resolveEfiSmmCpuProtocol(json_list_t stackGuids, ea_t address = static_cast(guid["address"]); msg("[%s] found EFI_SMM_CPU_PROTOCOL: 0x%016llX\n", g_plugin_name, u64_addr(address)); - ea_list_t guidXrefs = get_xrefs_util(address); + ea_list_t guidXrefs = efi_utils::get_xrefs(address); for (auto guidXref : guidXrefs) { segment_t *seg = getseg(static_cast(guidXref)); @@ -527,8 +534,8 @@ ea_list_t resolveEfiSmmCpuProtocol(json_list_t stackGuids, insn.ops[0].reg == R_R8 && insn.ops[1].type == o_mem) { msg("[%s] gSmmCpu address: 0x%016llX\n", g_plugin_name, u64_addr(insn.ops[1].addr)); - set_ptr_type_and_name(insn.ops[1].addr, "gSmmCpu", - "EFI_SMM_CPU_PROTOCOL"); + efi_utils::set_ptr_type_and_name(insn.ops[1].addr, "gSmmCpu", + "EFI_SMM_CPU_PROTOCOL"); gSmmCpuAddrs.push_back(insn.ops[1].addr); break; } @@ -542,7 +549,7 @@ ea_list_t resolveEfiSmmCpuProtocol(json_list_t stackGuids, } for (auto smmCpu : gSmmCpuAddrs) { - ea_list_t smmCpuXrefs = get_xrefs_util(static_cast(smmCpu)); + ea_list_t smmCpuXrefs = efi_utils::get_xrefs(static_cast(smmCpu)); for (auto smmCpuXref : smmCpuXrefs) { segment_t *seg = getseg(static_cast(smmCpuXref)); @@ -574,7 +581,7 @@ ea_list_t resolveEfiSmmCpuProtocol(json_list_t stackGuids, readSaveStateCalls.push_back(ea); } - op_stroff_util(ea, "EFI_SMM_CPU_PROTOCOL"); + efi_utils::op_stroff(ea, "EFI_SMM_CPU_PROTOCOL"); msg("[%s] 0x%016llX : %s\n", g_plugin_name, u64_addr(ea), "gSmmCpu->ReadSaveState"); std::string smm_call = "gSmmCpu->ReadSaveState"; diff --git a/efiXplorer/efi_utils.cc b/efiXplorer/efi_utils.cc index e71cbeda..a11d04fe 100644 --- a/efiXplorer/efi_utils.cc +++ b/efiXplorer/efi_utils.cc @@ -27,35 +27,6 @@ ea_list_t g_get_smst_location_calls; ea_list_t g_smm_get_variable_calls; ea_list_t g_smm_set_variable_calls; -//-------------------------------------------------------------------------- -// set EFI_GUID type -void set_guid_type(ea_t ea) { - tinfo_t tinfo; - if (tinfo.get_named_type(get_idati(), "EFI_GUID")) { - apply_tinfo(ea, tinfo, TINFO_DEFINITE); - } -} - -//-------------------------------------------------------------------------- -// set type and name -void set_type_and_name(ea_t ea, std::string name, std::string type) { - set_name(ea, name.c_str(), SN_FORCE); - tinfo_t tinfo; - if (tinfo.get_named_type(get_idati(), type.c_str())) { - apply_tinfo(ea, tinfo, TINFO_DEFINITE); - } -} - -//-------------------------------------------------------------------------- -// set const CHAR16 type -void set_const_char16_type(ea_t ea) { - tinfo_t tinfo; - if (tinfo.get_named_type(get_idati(), "CHAR16")) { - tinfo.set_const(); - apply_tinfo(ea, tinfo, TINFO_DEFINITE); - } -} - //-------------------------------------------------------------------------- // get file format name std::string file_format_name() { @@ -64,33 +35,6 @@ std::string file_format_name() { return static_cast(file_format); } -//-------------------------------------------------------------------------- -// get input file type (64-bit, 32-bit module or UEFI firmware) -arch_file_type_t input_file_type() { - processor_t &ph = PH; - auto filetype = inf_get_filetype(); - auto bits = inf_is_64bit() ? 64 : inf_is_32bit_exactly() ? 32 : 16; - - // check if the input file is a UEFI firmware image - if (file_format_name().find("UEFI") != std::string::npos) { - return arch_file_type_t::uefi; - } - - if (filetype == f_PE || filetype == f_ELF) { - if (ph.id == PLFM_386) { - if (bits == 64) - return arch_file_type_t::x86_64; - if (bits == 32) - return arch_file_type_t::x86_32; - } - if (ph.id == PLFM_ARM) { - if (bits == 64) - return arch_file_type_t::aarch64; - } - } - return arch_file_type_t::unsupported; -} - //-------------------------------------------------------------------------- // get input file type (PEI or DXE-like). No reliable way to determine FFS // file type given only its PE/TE image section, so hello heuristics @@ -140,8 +84,142 @@ ffs_file_type_t guess_file_type(arch_file_type_t arch, return ffs_file_type_t::dxe_smm; } -ffs_file_type_t ask_file_type(json_list_t *m_all_guids) { - auto arch = input_file_type(); +int parse_efi_pei_svc4() { + return parse_decls(nullptr, + "struct EFI_PEI_SERVICES_4 {\n" + " EFI_PEI_SERVICES **PeiServices;\n" + " UINT32 BaseAddress;\n" + "};", + msg, HTI_DCL); +} + +int parse_efi_pei_sidt() { + return parse_decls(nullptr, + "struct EFI_PEI_SIDT {\n" + " UINT16 Limit;\n" + " int *__shifted(EFI_PEI_SERVICES_4, 4) BaseAddress;\n" + "};", + msg, HTI_DCL | HTI_PAK1); +} + +bool mark_copy(ea_t code_addr, ea_t var_addr, std::string type) { + insn_t insn; + int reg = -1; + ea_t ea = code_addr; + ea_t var_copy = BADADDR; + decode_insn(&insn, ea); + + if (insn.itype == NN_mov && insn.ops[0].type == o_reg && + insn.ops[1].type == o_mem && insn.ops[1].addr == var_addr) { + reg = insn.ops[0].reg; + } + + if (reg == -1) { + return false; + } + + for (auto i = 0; i < 8; ++i) { + ea = next_head(ea, BADADDR); + decode_insn(&insn, ea); + + if (is_basic_block_end(insn, false)) { + break; + } + + if ((insn.itype == NN_callni || insn.itype == NN_call) || + (insn.ops[0].type == o_reg && insn.ops[0].reg == reg)) { + break; + } + + if (insn.itype == NN_mov && insn.ops[0].type == o_mem && + insn.ops[1].type == o_reg && insn.ops[1].reg == reg) { + var_copy = insn.ops[0].addr; + msg("[efiXplorer] found copy for global variable: 0x%016llX\n", + u64_addr(ea)); + break; + } + } + + if (var_copy == BADADDR) { + return false; + } + + std::string name; + + if (type == "gSmst") { + efi_utils::set_ptr_type_and_name(var_copy, "gSmst", + "_EFI_SMM_SYSTEM_TABLE2"); + } + + if (type == "gBS") { + efi_utils::set_ptr_type_and_name(var_copy, "gBS", "EFI_BOOT_SERVICES"); + } + + if (type == "gRT") { + efi_utils::set_ptr_type_and_name(var_copy, "gRT", "EFI_RUNTIME_SERVICES"); + } + + return true; +} + +//-------------------------------------------------------------------------- +// set EFI_GUID type +void efi_utils::set_guid_type(ea_t ea) { + tinfo_t tinfo; + if (tinfo.get_named_type(get_idati(), "EFI_GUID")) { + apply_tinfo(ea, tinfo, TINFO_DEFINITE); + } +} + +//-------------------------------------------------------------------------- +// set type and name +void efi_utils::set_type_and_name(ea_t ea, std::string name, std::string type) { + set_name(ea, name.c_str(), SN_FORCE); + tinfo_t tinfo; + if (tinfo.get_named_type(get_idati(), type.c_str())) { + apply_tinfo(ea, tinfo, TINFO_DEFINITE); + } +} + +//-------------------------------------------------------------------------- +// set const CHAR16 type +void efi_utils::set_const_char16_type(ea_t ea) { + tinfo_t tinfo; + if (tinfo.get_named_type(get_idati(), "CHAR16")) { + tinfo.set_const(); + apply_tinfo(ea, tinfo, TINFO_DEFINITE); + } +} + +//-------------------------------------------------------------------------- +// get input file type (64-bit, 32-bit module or UEFI firmware) +arch_file_type_t efi_utils::input_file_type() { + processor_t &ph = PH; + auto filetype = inf_get_filetype(); + auto bits = inf_is_64bit() ? 64 : inf_is_32bit_exactly() ? 32 : 16; + + // check if the input file is a UEFI firmware image + if (file_format_name().find("UEFI") != std::string::npos) { + return arch_file_type_t::uefi; + } + + if (filetype == f_PE || filetype == f_ELF) { + if (ph.id == PLFM_386) { + if (bits == 64) + return arch_file_type_t::x86_64; + if (bits == 32) + return arch_file_type_t::x86_32; + } + if (ph.id == PLFM_ARM) { + if (bits == 64) + return arch_file_type_t::aarch64; + } + } + return arch_file_type_t::unsupported; +} + +ffs_file_type_t efi_utils::ask_file_type(json_list_t *m_all_guids) { + auto arch = efi_utils::input_file_type(); if (arch == arch_file_type_t::uefi || arch == arch_file_type_t::x86_64) { return ffs_file_type_t::dxe_smm; } @@ -159,7 +237,7 @@ ffs_file_type_t ask_file_type(json_list_t *m_all_guids) { //-------------------------------------------------------------------------- // find address of global gBS var for X64 module for each service -ea_t find_unknown_bs_var_64(ea_t ea) { +ea_t efi_utils::find_unknown_bs_var_64(ea_t ea) { ea_t res = BADADDR; insn_t insn; @@ -178,7 +256,7 @@ ea_t find_unknown_bs_var_64(ea_t ea) { //-------------------------------------------------------------------------- // get all xrefs for given address -ea_list_t get_xrefs_util(ea_t addr) { +ea_list_t efi_utils::get_xrefs(ea_t addr) { ea_list_t xrefs; ea_t xref = get_first_dref_to(addr); while (xref != BADADDR) { @@ -190,24 +268,24 @@ ea_list_t get_xrefs_util(ea_t addr) { //-------------------------------------------------------------------------- // get all xrefs for given array element -ea_list_t get_xrefs_to_array(ea_t addr) { +ea_list_t efi_utils::get_xrefs_to_array(ea_t addr) { ea_t first_ea; ea_t ea = addr; while (true) { auto ptr = get_qword(ea); - auto xrefs = get_xrefs_util(ptr); + auto xrefs = efi_utils::get_xrefs(ptr); if (std::find(xrefs.begin(), xrefs.end(), ea) == xrefs.end()) { break; } first_ea = ea; ea -= 8; } - return get_xrefs_util(first_ea); + return efi_utils::get_xrefs(first_ea); } //-------------------------------------------------------------------------- // wrapper for op_stroff function -bool op_stroff_util(ea_t addr, std::string type) { +bool efi_utils::op_stroff(ea_t addr, std::string type) { tinfo_t tinfo; if (!tinfo.get_named_type(get_idati(), type.c_str())) { return false; @@ -227,7 +305,7 @@ bool op_stroff_util(ea_t addr, std::string type) { //-------------------------------------------------------------------------- // get pointer to named type and apply it -bool set_ptr_type(ea_t addr, std::string type) { +bool efi_utils::set_ptr_type(ea_t addr, std::string type) { tinfo_t tinfo; if (!tinfo.get_named_type(get_idati(), type.c_str())) { return false; @@ -240,14 +318,15 @@ bool set_ptr_type(ea_t addr, std::string type) { //-------------------------------------------------------------------------- // set name and apply pointer to named type -void set_ptr_type_and_name(ea_t ea, std::string name, std::string type) { +void efi_utils::set_ptr_type_and_name(ea_t ea, std::string name, + std::string type) { set_name(ea, name.c_str(), SN_FORCE); - set_ptr_type(ea, type.c_str()); + efi_utils::set_ptr_type(ea, type.c_str()); } //-------------------------------------------------------------------------- // get guids.json file name -std::filesystem::path get_guids_json_file() { +std::filesystem::path efi_utils::get_guids_json_file() { std::filesystem::path guids_json_path; // check {idadir}/plugins/guids.json @@ -291,7 +370,7 @@ std::filesystem::path get_guids_json_file() { //-------------------------------------------------------------------------- // get json summary file name -std::filesystem::path get_summary_file() { +std::filesystem::path efi_utils::get_summary_file() { std::string idb_path; idb_path = get_path(PATH_TYPE_IDB); std::filesystem::path log_file; @@ -302,7 +381,7 @@ std::filesystem::path get_summary_file() { //-------------------------------------------------------------------------- // check if summary json file exists -bool summary_json_exists() { +bool efi_utils::summary_json_exists() { std::string idb_path; idb_path = get_path(PATH_TYPE_IDB); std::filesystem::path log_file; @@ -314,7 +393,7 @@ bool summary_json_exists() { //-------------------------------------------------------------------------- // change EFI_SYSTEM_TABLE *SystemTable to EFI_PEI_SERVICES **PeiService // at ModuleEntryPoint -void set_entry_arg_to_pei_svc() { +void efi_utils::set_entry_arg_to_pei_svc() { for (auto idx = 0; idx < get_entry_qty(); idx++) { uval_t ord = get_entry_ordinal(idx); ea_t start_ea = get_entry(ord); @@ -361,7 +440,7 @@ void set_entry_arg_to_pei_svc() { } } -bool set_ret_to_pei_svc(ea_t start_ea) { +bool efi_utils::set_ret_to_pei_svc(ea_t start_ea) { tinfo_t tif_ea; if (guess_tinfo(&tif_ea, start_ea) == GUESS_FUNC_FAILED) { msg("[%s] guess_tinfo failed, function = 0x%016llX", g_plugin_name, @@ -401,27 +480,9 @@ bool set_ret_to_pei_svc(ea_t start_ea) { return true; } -int parse_efi_pei_svc4() { - return parse_decls(nullptr, - "struct EFI_PEI_SERVICES_4 {\n" - " EFI_PEI_SERVICES **PeiServices;\n" - " UINT32 BaseAddress;\n" - "};", - msg, HTI_DCL); -} - -int parse_efi_pei_sidt() { - return parse_decls(nullptr, - "struct EFI_PEI_SIDT {\n" - " UINT16 Limit;\n" - " int *__shifted(EFI_PEI_SERVICES_4, 4) BaseAddress;\n" - "};", - msg, HTI_DCL | HTI_PAK1); -} - //-------------------------------------------------------------------------- // add EFI_PEI_SERVICES_4 structure -bool add_struct_for_shifted_ptr() { +bool efi_utils::add_struct_for_shifted_ptr() { #if IDA_SDK_VERSION < 900 auto sid = add_struc(BADADDR, "EFI_PEI_SERVICES_4"); if (sid == BADADDR) { @@ -459,24 +520,9 @@ bool add_struct_for_shifted_ptr() { return !parse_efi_pei_svc4() && !parse_efi_pei_sidt(); } -//-------------------------------------------------------------------------- -// change the value of a number to match the data type -uval_t trunc_imm_to_dtype(uval_t value, op_dtype_t dtype) { - switch (dtype) { - case dt_byte: - return value & 0xff; - case dt_word: - return value & 0xffff; - case dt_dword: - return value & 0xffffffff; - default: - return value; - } -} - //-------------------------------------------------------------------------- // get module name by address -qstring get_module_name_loader(ea_t addr) { +qstring efi_utils::get_module_name_loader(ea_t addr) { segment_t *seg = getseg(addr); qstring seg_name; get_segm_name(&seg_name, seg); @@ -485,7 +531,7 @@ qstring get_module_name_loader(ea_t addr) { //-------------------------------------------------------------------------- // get GUID data by address -json get_guid_by_address(ea_t addr) { +json efi_utils::get_guid_by_address(ea_t addr) { return json::array({get_wide_dword(addr), get_wide_word(addr + 4), get_wide_word(addr + 6), get_wide_byte(addr + 8), get_wide_byte(addr + 9), get_wide_byte(addr + 10), @@ -496,21 +542,16 @@ json get_guid_by_address(ea_t addr) { //-------------------------------------------------------------------------- // validate GUID value -bool valid_guid(json guid) { - if (static_cast(guid[0]) == 0x00000000 && - (uint16_t)guid[1] == 0x0000) { - return false; - } - if (static_cast(guid[0]) == 0xffffffff && - (uint16_t)guid[1] == 0xffff) { - return false; - } - return true; +bool efi_utils::valid_guid(json guid) { + auto data0 = static_cast(guid[0]); + auto data1 = static_cast(guid[1]); + + return (!data0 && !data1) || (data0 == 0xffffffff && data1 == 0xffff); } //-------------------------------------------------------------------------- // convert GUID value to string -std::string guid_to_string(json guid) { +std::string efi_utils::guid_to_string(json guid) { return std::format( "{:08X}-{:04X}-{:04X}-{:02X}{:02X}-{:02X}{:02X}{:02X}{:02X}{:02X}{:02X}", static_cast(guid[0]), static_cast(guid[1]), @@ -521,7 +562,7 @@ std::string guid_to_string(json guid) { static_cast(guid[10])); } -uint8_list_t unpack_guid(std::string guid) { +uint8_list_t efi_utils::unpack_guid(std::string guid) { uint8_list_t res; std::string delim = "-"; std::string byte_str; @@ -559,10 +600,10 @@ uint8_list_t unpack_guid(std::string guid) { return res; } -ea_list_t search_protocol(std::string protocol) { +ea_list_t efi_utils::search_protocol(std::string protocol) { uchar bytes[17] = {0}; ea_list_t res; - auto guid_bytes = unpack_guid(protocol); + auto guid_bytes = efi_utils::unpack_guid(protocol); std::copy(guid_bytes.begin(), guid_bytes.end(), bytes); ea_t start = 0; while (true) { @@ -582,7 +623,7 @@ ea_list_t search_protocol(std::string protocol) { return res; } -bool check_install_protocol(ea_t ea) { +bool efi_utils::check_install_protocol(ea_t ea) { insn_t insn; // search for `call [REG + offset]` insn // offset in [0x80, 0xA8, 0x148] @@ -605,11 +646,13 @@ bool check_install_protocol(ea_t ea) { //-------------------------------------------------------------------------- // convert 64-bit value to hex string -std::string as_hex(uint64_t value) { return std::format("{:016X}", value); } +std::string efi_utils::as_hex(uint64_t value) { + return std::format("{:016X}", value); +} //-------------------------------------------------------------------------- // make sure the first argument looks like a protocol -bool check_boot_service_protocol(ea_t call_addr) { +bool efi_utils::check_boot_service_protocol(ea_t call_addr) { bool valid = false; insn_t insn; auto addr = prev_head(call_addr, 0); @@ -635,9 +678,9 @@ bool check_boot_service_protocol(ea_t call_addr) { //-------------------------------------------------------------------------- // make sure that the address does not belong to the protocol interface -bool check_boot_service_protocol_xrefs(ea_t call_addr) { +bool efi_utils::check_boot_service_protocol_xrefs(ea_t call_addr) { insn_t insn; - for (auto xref : get_xrefs_util(call_addr)) { + for (auto xref : efi_utils::get_xrefs(call_addr)) { decode_insn(&insn, xref); if (insn.itype == NN_lea && insn.ops[0].type == o_reg && insn.ops[0].reg == R_R8) { @@ -648,68 +691,9 @@ bool check_boot_service_protocol_xrefs(ea_t call_addr) { return true; } -bool mark_copy(ea_t code_addr, ea_t var_addr, std::string type) { - insn_t insn; - int reg = -1; - ea_t ea = code_addr; - ea_t var_copy = BADADDR; - decode_insn(&insn, ea); - - if (insn.itype == NN_mov && insn.ops[0].type == o_reg && - insn.ops[1].type == o_mem && insn.ops[1].addr == var_addr) { - reg = insn.ops[0].reg; - } - - if (reg == -1) { - return false; - } - - for (auto i = 0; i < 8; ++i) { - ea = next_head(ea, BADADDR); - decode_insn(&insn, ea); - - if (is_basic_block_end(insn, false)) { - break; - } - - if ((insn.itype == NN_callni || insn.itype == NN_call) || - (insn.ops[0].type == o_reg && insn.ops[0].reg == reg)) { - break; - } - - if (insn.itype == NN_mov && insn.ops[0].type == o_mem && - insn.ops[1].type == o_reg && insn.ops[1].reg == reg) { - var_copy = insn.ops[0].addr; - msg("[efiXplorer] found copy for global variable: 0x%016llX\n", - u64_addr(ea)); - break; - } - } - - if (var_copy == BADADDR) { - return false; - } - - std::string name; - - if (type == "gSmst") { - set_ptr_type_and_name(var_copy, "gSmst", "_EFI_SMM_SYSTEM_TABLE2"); - } - - if (type == "gBS") { - set_ptr_type_and_name(var_copy, "gBS", "EFI_BOOT_SERVICES"); - } - - if (type == "gRT") { - set_ptr_type_and_name(var_copy, "gRT", "EFI_RUNTIME_SERVICES"); - } - - return true; -} - -bool mark_copies_for_gvars(ea_list_t gvars, std::string type) { +bool efi_utils::mark_copies_for_gvars(ea_list_t gvars, std::string type) { for (auto var : gvars) { - auto xrefs = get_xrefs_util(var); + auto xrefs = efi_utils::get_xrefs(var); for (auto addr : xrefs) { mark_copy(addr, var, type); } @@ -719,7 +703,7 @@ bool mark_copies_for_gvars(ea_list_t gvars, std::string type) { //-------------------------------------------------------------------------- // generate name string from type -std::string type_to_name(std::string type) { +std::string efi_utils::type_to_name(std::string type) { std::string result; size_t counter = 0; for (char const &c : type) { @@ -748,7 +732,7 @@ std::string type_to_name(std::string type) { return result; } -xreflist_t xrefs_to_stack_var(ea_t func_addr, qstring var_name) { +xreflist_t efi_utils::xrefs_to_stack_var(ea_t func_addr, qstring var_name) { xreflist_t xrefs_list; #if IDA_SDK_VERSION < 900 @@ -781,28 +765,28 @@ void op_stroff_for_addr(ea_t ea, qstring type_name) { insn.itype == NN_callni) && (insn.ops[0].type == o_displ || insn.ops[0].type == o_phrase) && insn.ops[0].reg == R_RAX) { - op_stroff_util(ea, static_cast(type_name.c_str())); + efi_utils::op_stroff(ea, static_cast(type_name.c_str())); msg("[%s] mark arguments at address 0x%016llX (interface type: %s)\n", g_plugin_name, u64_addr(ea), type_name.c_str()); // check for EfiSmmBase2Protocol->GetSmstLocation if (type_name == "EFI_SMM_BASE2_PROTOCOL" && insn.ops[0].type == o_displ && insn.ops[0].addr == 8) { - if (!addr_in_vec(g_get_smst_location_calls, ea)) { + if (!efi_utils::addr_in_vec(g_get_smst_location_calls, ea)) { g_get_smst_location_calls.push_back(ea); } } if (type_name == "EFI_SMM_VARIABLE_PROTOCOL" && insn.ops[0].type == o_phrase) { - if (!addr_in_vec(g_smm_get_variable_calls, ea)) { + if (!efi_utils::addr_in_vec(g_smm_get_variable_calls, ea)) { g_smm_get_variable_calls.push_back(ea); } } if (type_name == "EFI_SMM_VARIABLE_PROTOCOL" && insn.ops[0].type == o_displ && insn.ops[0].addr == 0x10) { - if (!addr_in_vec(g_smm_set_variable_calls, ea)) { + if (!efi_utils::addr_in_vec(g_smm_set_variable_calls, ea)) { g_smm_set_variable_calls.push_back(ea); } } @@ -818,7 +802,8 @@ void op_stroff_for_addr(ea_t ea, qstring type_name) { //-------------------------------------------------------------------------- // mark the arguments of each function from an interface derived from // a local variable -void op_stroff_for_interface(xreflist_t local_xrefs, qstring type_name) { +void efi_utils::op_stroff_for_interface(xreflist_t local_xrefs, + qstring type_name) { insn_t insn; for (auto xref : local_xrefs) { decode_insn(&insn, xref.ea); @@ -831,7 +816,8 @@ void op_stroff_for_interface(xreflist_t local_xrefs, qstring type_name) { //-------------------------------------------------------------------------- // mark the arguments of each function from an interface derived from // a global variable -void op_stroff_for_global_interface(ea_list_t xrefs, qstring type_name) { +void efi_utils::op_stroff_for_global_interface(ea_list_t xrefs, + qstring type_name) { insn_t insn; for (auto ea : xrefs) { decode_insn(&insn, ea); @@ -841,27 +827,30 @@ void op_stroff_for_global_interface(ea_list_t xrefs, qstring type_name) { } } -bool uint64_in_vec(uint64_list_t vec, uint64_t value) { +bool efi_utils::uint64_in_vec(uint64_list_t vec, uint64_t value) { return find(vec.begin(), vec.end(), value) != vec.end(); } -bool addr_in_vec(ea_list_t vec, ea_t addr) { +bool efi_utils::addr_in_vec(ea_list_t vec, ea_t addr) { return find(vec.begin(), vec.end(), addr) != vec.end(); } -bool json_in_vec(json_list_t vec, json item) { +bool efi_utils::json_in_vec(json_list_t vec, json item) { return find(vec.begin(), vec.end(), item) != vec.end(); } -bool addr_in_tables(ea_list_t t1, ea_list_t t2, ea_t ea) { - return (addr_in_vec(t1, ea) || addr_in_vec(t2, ea)); +bool efi_utils::addr_in_tables(ea_list_t t1, ea_list_t t2, ea_t ea) { + return (efi_utils::addr_in_vec(t1, ea) || efi_utils::addr_in_vec(t2, ea)); } -bool addr_in_tables(ea_list_t t1, ea_list_t t2, ea_list_t t3, ea_t ea) { - return (addr_in_vec(t1, ea) || addr_in_vec(t2, ea) || addr_in_vec(t3, ea)); +bool efi_utils::addr_in_tables(ea_list_t t1, ea_list_t t2, ea_list_t t3, + ea_t ea) { + return (efi_utils::addr_in_vec(t1, ea) || efi_utils::addr_in_vec(t2, ea) || + efi_utils::addr_in_vec(t3, ea)); } -ea_list_t find_data(ea_t start_ea, ea_t end_ea, uchar *data, size_t len) { +ea_list_t efi_utils::find_data(ea_t start_ea, ea_t end_ea, uchar *data, + size_t len) { ea_list_t res; ea_t start = start_ea; int counter = 0; @@ -884,7 +873,7 @@ ea_list_t find_data(ea_t start_ea, ea_t end_ea, uchar *data, size_t len) { //-------------------------------------------------------------------------- // get wide string by address -std::string get_wide_string(ea_t addr) { +std::string efi_utils::get_wide_string(ea_t addr) { std::string res; int index = 0; while (get_wide_word(addr + index)) { @@ -900,7 +889,7 @@ std::string get_wide_string(ea_t addr) { //-------------------------------------------------------------------------- // get efi_guid_t by address -efi_guid_t get_global_guid(ea_t addr) { +efi_guid_t efi_utils::get_global_guid(ea_t addr) { efi_guid_t guid; guid.data1 = get_wide_dword(addr); guid.data2 = get_wide_word(addr + 4); @@ -913,7 +902,7 @@ efi_guid_t get_global_guid(ea_t addr) { //-------------------------------------------------------------------------- // get efi_guid_t by stack offset -efi_guid_t get_local_guid(func_t *f, uint64_t offset) { +efi_guid_t efi_utils::get_local_guid(func_t *f, uint64_t offset) { efi_guid_t guid; insn_t insn; auto ea = f->start_ea; @@ -961,7 +950,7 @@ efi_guid_t get_local_guid(func_t *f, uint64_t offset) { return guid; } -std::string get_table_name(std::string service_name) { +std::string efi_utils::get_table_name(std::string service_name) { for (auto i = 0; i < g_boot_services_table_all_count; i++) { if (static_cast(g_boot_services_table_all[i].name) == service_name) { @@ -979,7 +968,7 @@ std::string get_table_name(std::string service_name) { return "Unknown"; } -std::string lookup_boot_service_name(uint64_t offset) { +std::string efi_utils::lookup_boot_service_name(uint64_t offset) { for (auto i = 0; i < g_boot_services_table_all_count; i++) { if (g_boot_services_table_all[i].offset64 == offset) { return static_cast(g_boot_services_table_all[i].name); @@ -989,7 +978,7 @@ std::string lookup_boot_service_name(uint64_t offset) { return "Unknown"; } -std::string lookup_runtime_service_name(uint64_t offset) { +std::string efi_utils::lookup_runtime_service_name(uint64_t offset) { for (auto i = 0; i < g_runtime_services_table_all_count; i++) { if (g_runtime_services_table_all[i].offset64 == offset) { return static_cast(g_runtime_services_table_all[i].name); @@ -999,15 +988,14 @@ std::string lookup_runtime_service_name(uint64_t offset) { return "Unknown"; } -uint64_t u64_addr(ea_t addr) { return static_cast(addr); } - -uint32_t u32_addr(ea_t addr) { return static_cast(addr); } - uint16_t get_machine_type() { ea_t pe_offset = get_dword(0x3c); return get_word(pe_offset + 4); } +uint32_t u32_addr(ea_t addr) { return static_cast(addr); } +uint64_t u64_addr(ea_t addr) { return static_cast(addr); } + #if IDA_SDK_VERSION >= 900 tid_t import_type(const til_t *til, int _idx, const char *name) { tinfo_t tinfo; diff --git a/efiXplorer/efi_utils.h b/efiXplorer/efi_utils.h index 3744830f..dd28cd78 100644 --- a/efiXplorer/efi_utils.h +++ b/efiXplorer/efi_utils.h @@ -22,24 +22,30 @@ #include "efi_defs.h" #include +namespace efi_utils { arch_file_type_t input_file_type(); bool add_struct_for_shifted_ptr(); -bool addr_in_tables(ea_list_t t1, ea_list_t t2, ea_t ea); bool addr_in_tables(ea_list_t t1, ea_list_t t2, ea_list_t t3, ea_t ea); +bool addr_in_tables(ea_list_t t1, ea_list_t t2, ea_t ea); bool addr_in_vec(ea_list_t vec, ea_t addr); bool check_boot_service_protocol_xrefs(ea_t call_addr); bool check_boot_service_protocol(ea_t call_addr); bool check_install_protocol(ea_t ea); bool json_in_vec(json_list_t vec, json item); bool mark_copies_for_gvars(ea_list_t gvars, std::string type); -bool op_stroff_util(ea_t addr, std::string type); +bool op_stroff(ea_t addr, std::string type); bool set_ptr_type(ea_t addr, std::string type); bool set_ret_to_pei_svc(ea_t start_ea); bool summary_json_exists(); bool uint64_in_vec(uint64_list_t vec, uint64_t value); bool valid_guid(json guid); +ea_list_t find_data(ea_t start_ea, ea_t end_ea, uchar *data, size_t len); +ea_list_t get_xrefs_to_array(ea_t addr); +ea_list_t get_xrefs(ea_t addr); +ea_list_t search_protocol(std::string protocol); + ea_t find_unknown_bs_var_64(ea_t ea); efi_guid_t get_global_guid(ea_t addr); @@ -62,19 +68,8 @@ std::string lookup_boot_service_name(uint64_t offset); std::string lookup_runtime_service_name(uint64_t offset); std::string type_to_name(std::string type); -ea_list_t find_data(ea_t start_ea, ea_t end_ea, uchar *data, size_t len); -ea_list_t get_xrefs_to_array(ea_t addr); -ea_list_t get_xrefs_util(ea_t addr); -ea_list_t search_protocol(std::string protocol); - -uint16_t get_machine_type(); -uint32_t u32_addr(ea_t addr); -uint64_t u64_addr(ea_t addr); - uint8_list_t unpack_guid(std::string guid); -uval_t trunc_imm_to_dtype(uval_t value, op_dtype_t dtype); - void op_stroff_for_global_interface(ea_list_t xrefs, qstring type_name); void op_stroff_for_interface(xreflist_t local_xrefs, qstring type_name); void set_const_char16_type(ea_t ea); @@ -84,6 +79,11 @@ void set_ptr_type_and_name(ea_t ea, std::string name, std::string type); void set_type_and_name(ea_t ea, std::string name, std::string type); xreflist_t xrefs_to_stack_var(ea_t func_addr, qstring var_name); +} // namespace efi_utils + +uint16_t get_machine_type(); +uint32_t u32_addr(ea_t addr); +uint64_t u64_addr(ea_t addr); #if IDA_SDK_VERSION >= 900 tid_t import_type(const til_t *til, int _idx, const char *name); diff --git a/efiXplorer/efixplorer.cc b/efiXplorer/efixplorer.cc index 92b68271..db37a009 100644 --- a/efiXplorer/efixplorer.cc +++ b/efiXplorer/efixplorer.cc @@ -39,7 +39,7 @@ hexdsp_t *hexdsp = nullptr; //-------------------------------------------------------------------------- static plugmod_t *idaapi init(void) { - arch_file_type_t file_type = input_file_type(); + arch_file_type_t file_type = efi_utils::input_file_type(); if (file_type == arch_file_type_t::unsupported) { return PLUGIN_SKIP; } @@ -82,7 +82,7 @@ bool idaapi run(size_t arg) { msg("[%s] disable_ui = %d, disable_vuln_hunt = %d\n", g_plugin_name, g_args.disable_ui, g_args.disable_vuln_hunt); - auto guids_path = get_guids_json_file(); + auto guids_path = efi_utils::get_guids_json_file(); msg("[%s] guids.json exists: %s\n", g_plugin_name, BTOA(!guids_path.empty())); if (guids_path.empty()) { @@ -93,7 +93,7 @@ bool idaapi run(size_t arg) { return false; } - arch_file_type_t arch = input_file_type(); + arch_file_type_t arch = efi_utils::input_file_type(); if (arch == arch_file_type_t::x86_64) { msg("[%s] input file is 64-bit module (x86)\n", g_plugin_name); efi_analysis::efi_analyse_main_x86_64(); From 1705d183c3b64e32869459811258c712dccd785e Mon Sep 17 00:00:00 2001 From: yeggor Date: Wed, 18 Sep 2024 00:17:46 +0100 Subject: [PATCH 33/69] add efi_utils::log, use it instead of msg in efi_utils and efixplorer --- efiXplorer/efi_utils.cc | 87 ++++++++++++++++++++-------------------- efiXplorer/efi_utils.h | 2 + efiXplorer/efixplorer.cc | 31 ++++++-------- 3 files changed, 58 insertions(+), 62 deletions(-) diff --git a/efiXplorer/efi_utils.cc b/efiXplorer/efi_utils.cc index a11d04fe..f3b0a7a8 100644 --- a/efiXplorer/efi_utils.cc +++ b/efiXplorer/efi_utils.cc @@ -62,9 +62,11 @@ ffs_file_type_t guess_file_type(arch_file_type_t arch, } bool has_pei_in_path = false; - char file_name[0x1000] = {0}; + + char file_name[256] = {0}; get_input_file_path(file_name, sizeof(file_name)); auto file_name_str = static_cast(file_name); + if ((file_name_str.find("Pei") != std::string::npos || file_name_str.find("pei") != std::string::npos || signature == VZ) && arch == arch_file_type_t::x86_64) { @@ -72,15 +74,12 @@ ffs_file_type_t guess_file_type(arch_file_type_t arch, } if (signature == VZ || has_pei_guids) { - msg("[%s] parsing binary file as PEI, signature = %llx, has_pei_guids = " - "%d\n", - g_plugin_name, signature, has_pei_guids); + efi_utils::log("analysing binary file as PEI, signature: %llx\n", + signature); return ffs_file_type_t::pei; } - msg("[%s] parsing binary file as DXE/SMM, signature = %llx, has_pei_guids = " - "%d\n", - g_plugin_name, signature, has_pei_guids); + efi_utils::log("analysing binary file as DXE/SMM\n"); return ffs_file_type_t::dxe_smm; } @@ -134,8 +133,8 @@ bool mark_copy(ea_t code_addr, ea_t var_addr, std::string type) { if (insn.itype == NN_mov && insn.ops[0].type == o_mem && insn.ops[1].type == o_reg && insn.ops[1].reg == reg) { var_copy = insn.ops[0].addr; - msg("[efiXplorer] found copy for global variable: 0x%016llX\n", - u64_addr(ea)); + efi_utils::log("found copy for global variable: 0x%016llX\n", + u64_addr(ea)); break; } } @@ -162,6 +161,20 @@ bool mark_copy(ea_t code_addr, ea_t var_addr, std::string type) { return true; } +//-------------------------------------------------------------------------- +// msg wrapper +int efi_utils::log(const char *fmt, ...) { + auto nbytes = msg("[%s] ", g_plugin_name); + + va_list va; + va_start(va, fmt); + + nbytes += vmsg(fmt, va); + + va_end(va); + return nbytes; +} + //-------------------------------------------------------------------------- // set EFI_GUID type void efi_utils::set_guid_type(ea_t ea) { @@ -227,7 +240,7 @@ ffs_file_type_t efi_utils::ask_file_type(json_list_t *m_all_guids) { auto deflt = ftype == ffs_file_type_t::dxe_smm; auto fmt_param = ftype == ffs_file_type_t::dxe_smm ? "DXE/SMM" : "PEI"; auto btn_id = - ask_buttons("DXE/SMM", "PEI", "", deflt, "Parse file as %s", fmt_param); + ask_buttons("DXE/SMM", "PEI", "", deflt, "Analyse file as %s", fmt_param); if (btn_id == ASKBTN_YES) { return ffs_file_type_t::dxe_smm; } @@ -399,22 +412,17 @@ void efi_utils::set_entry_arg_to_pei_svc() { ea_t start_ea = get_entry(ord); tinfo_t tif_ea; if (guess_tinfo(&tif_ea, start_ea) == GUESS_FUNC_FAILED) { - msg("[%s] guess_tinfo failed, start_ea = 0x%016llX, idx=%d\n", - g_plugin_name, u64_addr(start_ea), idx); continue; } func_type_data_t funcdata; if (!tif_ea.get_func_details(&funcdata)) { - msg("[%s] get_func_details failed, %d\n", g_plugin_name, idx); continue; } tinfo_t tif_pei; bool res = tif_pei.get_named_type(get_idati(), "EFI_PEI_SERVICES"); if (!res) { - msg("[%s] get_named_type failed, res = %d, idx=%d\n", g_plugin_name, res, - idx); continue; } @@ -427,13 +435,12 @@ void efi_utils::set_entry_arg_to_pei_svc() { if (funcdata.size() == 2) { funcdata[1].type = pp_tinfo; funcdata[1].name = "PeiServices"; - tinfo_t func_tinfo; - if (!func_tinfo.create_func(funcdata)) { - msg("[%s] create_func failed, idx=%d\n", g_plugin_name, idx); + tinfo_t f_tinfo; + if (!f_tinfo.create_func(funcdata)) { continue; } - if (!apply_tinfo(start_ea, func_tinfo, TINFO_DEFINITE)) { - msg("[%s] apply_tinfo failed, idx=%d\n", g_plugin_name, idx); + + if (!apply_tinfo(start_ea, f_tinfo, TINFO_DEFINITE)) { continue; } } @@ -443,20 +450,14 @@ void efi_utils::set_entry_arg_to_pei_svc() { bool efi_utils::set_ret_to_pei_svc(ea_t start_ea) { tinfo_t tif_ea; if (guess_tinfo(&tif_ea, start_ea) == GUESS_FUNC_FAILED) { - msg("[%s] guess_tinfo failed, function = 0x%016llX", g_plugin_name, - u64_addr(start_ea)); return false; } func_type_data_t fi; if (!tif_ea.get_func_details(&fi)) { - msg("[%s] get_func_details failed, function = 0x%016llX", g_plugin_name, - u64_addr(start_ea)); return false; } tinfo_t tif_pei; - bool res = tif_pei.get_named_type(get_idati(), "EFI_PEI_SERVICES"); - if (!res) { - msg("[%s] get_named_type failed, res = %d\n", g_plugin_name, res); + if (!tif_pei.get_named_type(get_idati(), "EFI_PEI_SERVICES")) { return false; } tinfo_t p_tinfo; @@ -466,17 +467,15 @@ bool efi_utils::set_ret_to_pei_svc(ea_t start_ea) { fi.rettype = pp_tinfo; - tinfo_t func_tinfo; - if (!func_tinfo.create_func(fi)) { - msg("[%s] create_func failed, function = 0x%016llX", g_plugin_name, - u64_addr(start_ea)); + tinfo_t f_tinfo; + if (!f_tinfo.create_func(fi)) { return false; } - if (!apply_tinfo(start_ea, func_tinfo, TINFO_DEFINITE)) { - msg("[%s] apply_tinfo failed, function = 0x%016llX", g_plugin_name, - u64_addr(start_ea)); + + if (!apply_tinfo(start_ea, f_tinfo, TINFO_DEFINITE)) { return false; } + return true; } @@ -625,7 +624,7 @@ ea_list_t efi_utils::search_protocol(std::string protocol) { bool efi_utils::check_install_protocol(ea_t ea) { insn_t insn; - // search for `call [REG + offset]` insn + // search for `call [R + offset]` insn // offset in [0x80, 0xA8, 0x148] ea_t addr = ea; for (auto i = 0; i < 16; i++) { @@ -651,11 +650,11 @@ std::string efi_utils::as_hex(uint64_t value) { } //-------------------------------------------------------------------------- -// make sure the first argument looks like a protocol +// make sure that the first argument looks like a protocol bool efi_utils::check_boot_service_protocol(ea_t call_addr) { bool valid = false; - insn_t insn; auto addr = prev_head(call_addr, 0); + insn_t insn; decode_insn(&insn, addr); while (!is_basic_block_end(insn, false)) { // for next iteration @@ -766,8 +765,9 @@ void op_stroff_for_addr(ea_t ea, qstring type_name) { (insn.ops[0].type == o_displ || insn.ops[0].type == o_phrase) && insn.ops[0].reg == R_RAX) { efi_utils::op_stroff(ea, static_cast(type_name.c_str())); - msg("[%s] mark arguments at address 0x%016llX (interface type: %s)\n", - g_plugin_name, u64_addr(ea), type_name.c_str()); + efi_utils::log( + "mark arguments at address 0x%016llX (interface type: %s)\n", + u64_addr(ea), type_name.c_str()); // check for EfiSmmBase2Protocol->GetSmstLocation if (type_name == "EFI_SMM_BASE2_PROTOCOL" && @@ -792,6 +792,7 @@ void op_stroff_for_addr(ea_t ea, qstring type_name) { } break; } + // if the RAX value is overridden if (insn.ops[0].reg == R_RAX) { break; @@ -879,7 +880,7 @@ std::string efi_utils::get_wide_string(ea_t addr) { while (get_wide_word(addr + index)) { auto byte = get_wide_byte(addr + index); if (byte < 0x20 || byte > 0x7e) { - return "INVALID_STRING"; + return "invalid string"; } res.push_back(byte); index += 2; @@ -965,7 +966,7 @@ std::string efi_utils::get_table_name(std::string service_name) { } } - return "Unknown"; + return "unknown"; } std::string efi_utils::lookup_boot_service_name(uint64_t offset) { @@ -975,7 +976,7 @@ std::string efi_utils::lookup_boot_service_name(uint64_t offset) { } } - return "Unknown"; + return "unknown"; } std::string efi_utils::lookup_runtime_service_name(uint64_t offset) { @@ -985,7 +986,7 @@ std::string efi_utils::lookup_runtime_service_name(uint64_t offset) { } } - return "Unknown"; + return "unknown"; } uint16_t get_machine_type() { diff --git a/efiXplorer/efi_utils.h b/efiXplorer/efi_utils.h index dd28cd78..e251e838 100644 --- a/efiXplorer/efi_utils.h +++ b/efiXplorer/efi_utils.h @@ -79,6 +79,8 @@ void set_ptr_type_and_name(ea_t ea, std::string name, std::string type); void set_type_and_name(ea_t ea, std::string name, std::string type); xreflist_t xrefs_to_stack_var(ea_t func_addr, qstring var_name); + +int log(const char *fmt, ...); } // namespace efi_utils uint16_t get_machine_type(); diff --git a/efiXplorer/efixplorer.cc b/efiXplorer/efixplorer.cc index db37a009..92c91cb1 100644 --- a/efiXplorer/efixplorer.cc +++ b/efiXplorer/efixplorer.cc @@ -47,7 +47,7 @@ static plugmod_t *idaapi init(void) { msg(welcome_msg); msg("%s\n\n", COPYRIGHT); - // Register action + // register action register_action(action_load_report); attach_action_to_menu("File/Load file/", action_load_report.name, SETMENU_APP); @@ -77,46 +77,39 @@ bool idaapi run(size_t arg) { g_args.disable_vuln_hunt = 1; } - msg("[%s] plugin run with argument %lu (sdk version: %d)\n", g_plugin_name, - arg, IDA_SDK_VERSION); - msg("[%s] disable_ui = %d, disable_vuln_hunt = %d\n", g_plugin_name, - g_args.disable_ui, g_args.disable_vuln_hunt); + efi_utils::log("plugin run with argument %lu (sdk version: %d)\n", arg, + IDA_SDK_VERSION); auto guids_path = efi_utils::get_guids_json_file(); - msg("[%s] guids.json exists: %s\n", g_plugin_name, BTOA(!guids_path.empty())); - if (guids_path.empty()) { - std::string msg_text = "guids.json file not found, copy \"guids\" " - "directory to /plugins"; - msg("[%s] %s\n", g_plugin_name, msg_text.c_str()); - warning("%s: %s\n", g_plugin_name, msg_text.c_str()); + warning("%s: %s\n", g_plugin_name, + "guids.json file not found, copy guids.json to plugins"); return false; } arch_file_type_t arch = efi_utils::input_file_type(); if (arch == arch_file_type_t::x86_64) { - msg("[%s] input file is 64-bit module (x86)\n", g_plugin_name); + efi_utils::log("input file is x86 64-bit module\n"); efi_analysis::efi_analyse_main_x86_64(); } else if (arch == arch_file_type_t::x86_32) { - msg("[%s] input file is 32-bit module (x86)\n", g_plugin_name); + efi_utils::log("input file is x86 32-bit module\n"); efi_analysis::efi_analyse_main_x86_32(); } else if (arch == arch_file_type_t::uefi) { - msg("[%s] input file is UEFI firmware\n", g_plugin_name); - warning("%s: analysis may take some time, please wait for it to complete\n", + warning("%s: input file is UEFI firmware, analysis can be time consuming\n", g_plugin_name); if (get_machine_type() == AARCH64) { - msg("[%s] analyse AARCH64 modules\n", g_plugin_name); + efi_utils::log("[%s] analyse ARM64 modules\n"); efi_analysis::efi_analyse_main_aarch64(); } else { - msg("[%s] analyse AMD64 modules\n", g_plugin_name); + efi_utils::log("[%s] analyse AMD64 modules\n", g_plugin_name); efi_analysis::efi_analyse_main_x86_64(); } } else if (arch == arch_file_type_t::aarch64) { - msg("[%s] input file is 64-bit module (ARM)\n", g_plugin_name); + efi_utils::log("[%s] input file is ARM 64-bit module\n"); efi_analysis::efi_analyse_main_aarch64(); } - // Reset arguments + // reset arguments g_args = {module_type_t::dxe_smm, 0, 0}; return true; From 1f701bd6eec48cc6b061b7c0e2b4c3dea584c2d7 Mon Sep 17 00:00:00 2001 From: yeggor Date: Wed, 18 Sep 2024 17:23:41 +0100 Subject: [PATCH 34/69] move bs_table_aarch64 to efi_defs --- efiXplorer/efi_analysis.h | 15 --------------- efiXplorer/efi_analysis_arm.cc | 9 +++++---- efiXplorer/efi_defs.cc | 17 +++++++++++++++++ efiXplorer/efi_defs.h | 3 +++ 4 files changed, 25 insertions(+), 19 deletions(-) diff --git a/efiXplorer/efi_analysis.h b/efiXplorer/efi_analysis.h index fb538d52..d8a36fc4 100644 --- a/efiXplorer/efi_analysis.h +++ b/efiXplorer/efi_analysis.h @@ -400,21 +400,6 @@ class efi_analyser_arm_t : public efi_analyser_t { void show_all_choosers(); private: - service_info_64_t bs_table_aarch64[13] = { - {"InstallProtocolInterface", 0x80, R_X1, 1}, - {"ReinstallProtocolInterface", 0x88, R_X1, 1}, - {"UninstallProtocolInterface", 0x90, R_X1, 1}, - {"HandleProtocol", 0x98, R_X1, 1}, - {"RegisterProtocolNotify", 0xA8, R_X0, 0}, - {"OpenProtocol", 0x118, R_X1, 1}, - {"CloseProtocol", 0x120, R_X1, 1}, - {"ProtocolsPerHandle", 0x128, R_X1, 1}, - {"OpenProtocolInformation", 0x130, R_X1, 1}, - {"LocateHandleBuffer", 0x138, R_X1, 1}, - {"LocateProtocol", 0x140, R_X0, 1}, - {"InstallMultipleProtocolInterfaces", 0x148, R_X1, 1}, - {"UninstallMultipleProtocolInterfaces", 0x150, R_X1, 1}}; - bool get_protocol(ea_t address, uint32_t p_reg, std::string service_name); }; diff --git a/efiXplorer/efi_analysis_arm.cc b/efiXplorer/efi_analysis_arm.cc index b1442ffc..799c3edb 100644 --- a/efiXplorer/efi_analysis_arm.cc +++ b/efiXplorer/efi_analysis_arm.cc @@ -219,7 +219,7 @@ json getService(ea_t addr, uint8_t table_id) { efi_utils::lookup_runtime_service_name(insn.ops[1].addr); s["table_name"] = "EFI_RUNTIME_SERVICES"; } else { - s["table_name"] = "OTHER"; + s["table_name"] = "unknown"; } return s; } @@ -388,13 +388,14 @@ bool efi_analysis::efi_analyser_arm_t::get_protocol(ea_t address, void efi_analysis::efi_analyser_arm_t::detect_protocols_all() { for (auto s : m_all_services) { std::string service_name = s["service_name"]; - for (auto i = 0; i < 13; i++) { + for (auto i = 0; i < g_boot_services_table_aarch64_count; i++) { std::string current_name = - static_cast(bs_table_aarch64[i].name); + static_cast(g_boot_services_table_aarch64[i].name); if (current_name != service_name) { continue; } - get_protocol(s["address"], bs_table_aarch64[i].reg, service_name); + get_protocol(s["address"], g_boot_services_table_aarch64[i].reg, + service_name); break; } } diff --git a/efiXplorer/efi_defs.cc b/efiXplorer/efi_defs.cc index 7135df4e..31c0e768 100644 --- a/efiXplorer/efi_defs.cc +++ b/efiXplorer/efi_defs.cc @@ -21,6 +21,23 @@ const char *g_plugin_name = "efiXplorer"; +service_info_64_t g_boot_services_table_aarch64[] = { + {"InstallProtocolInterface", 0x80, R_X1, 1}, + {"ReinstallProtocolInterface", 0x88, R_X1, 1}, + {"UninstallProtocolInterface", 0x90, R_X1, 1}, + {"HandleProtocol", 0x98, R_X1, 1}, + {"RegisterProtocolNotify", 0xA8, R_X0, 0}, + {"OpenProtocol", 0x118, R_X1, 1}, + {"CloseProtocol", 0x120, R_X1, 1}, + {"ProtocolsPerHandle", 0x128, R_X1, 1}, + {"OpenProtocolInformation", 0x130, R_X1, 1}, + {"LocateHandleBuffer", 0x138, R_X1, 1}, + {"LocateProtocol", 0x140, R_X0, 1}, + {"InstallMultipleProtocolInterfaces", 0x148, R_X1, 1}, + {"UninstallMultipleProtocolInterfaces", 0x150, R_X1, 1}}; +size_t g_boot_services_table_aarch64_count = + sizeof(g_boot_services_table_aarch64) / sizeof(service_info_64_t); + service_info_64_t g_boot_services_table64[] = { {"InstallProtocolInterface", 0x80, R_RDX, 1}, {"ReinstallProtocolInterface", 0x88, R_RDX, 1}, diff --git a/efiXplorer/efi_defs.h b/efiXplorer/efi_defs.h index b33fe4da..653b1fd2 100644 --- a/efiXplorer/efi_defs.h +++ b/efiXplorer/efi_defs.h @@ -203,6 +203,9 @@ struct efi_guid_t { } }; +extern service_info_64_t g_boot_services_table_aarch64[]; +extern size_t g_boot_services_table_aarch64_count; + extern service_info_64_t g_boot_services_table64[]; extern size_t g_boot_services_table64_count; From 1abca93ee6e89556c5adf789f06806994c929d64 Mon Sep 17 00:00:00 2001 From: yeggor Date: Wed, 18 Sep 2024 20:46:40 +0100 Subject: [PATCH 35/69] refactor smm_utils: add namespace, use efi_utils::log, clean up the code --- efiXplorer/efi_analysis_arm.cc | 36 ++-- efiXplorer/efi_analysis_x86.cc | 221 ++++++++++---------- efiXplorer/efi_smm_utils.cc | 357 ++++++++++++++++----------------- efiXplorer/efi_smm_utils.h | 26 +-- efiXplorer/efi_ui.cc | 4 +- efiXplorer/efi_utils.cc | 8 +- 6 files changed, 318 insertions(+), 334 deletions(-) diff --git a/efiXplorer/efi_analysis_arm.cc b/efiXplorer/efi_analysis_arm.cc index 799c3edb..a8e2af2b 100644 --- a/efiXplorer/efi_analysis_arm.cc +++ b/efiXplorer/efi_analysis_arm.cc @@ -147,7 +147,7 @@ ea_t get_table_addr(ea_t code_addr, uint64_t offset) { return table; } -json getService(ea_t addr, uint8_t table_id) { +json get_service(ea_t addr, uint8_t table_id) { json s; insn_t insn; decode_insn(&insn, addr); @@ -219,7 +219,7 @@ json getService(ea_t addr, uint8_t table_id) { efi_utils::lookup_runtime_service_name(insn.ops[1].addr); s["table_name"] = "EFI_RUNTIME_SERVICES"; } else { - s["table_name"] = "unknown"; + s["table_name"] = "Unknown"; } return s; } @@ -265,7 +265,7 @@ void efi_analysis::efi_analyser_arm_t::initial_gvars_detection() { } #endif /* HEX_RAYS */ - // analysis of all functions and search for additional table initializations + // analysis of all functions and search for additional table initialisations for (auto func_addr : m_funcs) { func_t *f = get_func(func_addr); if (f == nullptr) { @@ -276,7 +276,7 @@ void efi_analysis::efi_analyser_arm_t::initial_gvars_detection() { ea = next_head(ea, BADADDR); ea_t bs = get_table_addr(ea, 0x60); if (bs != BADADDR) { - msg("[efiXplorer] gBS = 0x%016llX\n", u64_addr(ea)); + efi_utils::log("gBS: 0x%016llX\n", u64_addr(ea)); efi_utils::set_ptr_type_and_name(bs, "gBS", "EFI_BOOT_SERVICES"); if (!efi_utils::addr_in_vec(bs_list_arm, bs)) { bs_list_arm.push_back(bs); @@ -285,7 +285,7 @@ void efi_analysis::efi_analyser_arm_t::initial_gvars_detection() { } ea_t rt = get_table_addr(ea, 0x58); if (rt != BADADDR) { - msg("[efiXplorer] gRT = 0x%016llX\n", u64_addr(ea)); + efi_utils::log("gRT: 0x%016llX\n", u64_addr(ea)); efi_utils::set_ptr_type_and_name(rt, "gRT", "EFI_RUNTIME_SERVICES"); if (!efi_utils::addr_in_vec(rt_list_arm, rt)) { rt_list_arm.push_back(rt); @@ -310,7 +310,7 @@ void efi_analysis::efi_analyser_arm_t::detect_services_all() { for (auto bs : bs_list_arm) { auto xrefs = efi_utils::get_xrefs(bs); for (auto ea : xrefs) { - auto s = getService(ea, 1); + auto s = get_service(ea, 1); if (!s.contains("address")) { continue; } @@ -319,8 +319,7 @@ void efi_analysis::efi_analyser_arm_t::detect_services_all() { continue; } if (!efi_utils::json_in_vec(m_all_services, s)) { - msg("[efiXplorer] gBS xref address: 0x%016llX, found new service\n", - u64_addr(ea)); + efi_utils::log("found new boot service at 0x%016llX\n", u64_addr(ea)); m_all_services.push_back(s); } } @@ -328,7 +327,7 @@ void efi_analysis::efi_analyser_arm_t::detect_services_all() { for (auto rt : rt_list_arm) { auto xrefs = efi_utils::get_xrefs(rt); for (auto ea : xrefs) { - auto s = getService(ea, 2); + auto s = get_service(ea, 2); if (!s.contains("address")) { continue; } @@ -337,8 +336,8 @@ void efi_analysis::efi_analyser_arm_t::detect_services_all() { continue; } if (!efi_utils::json_in_vec(m_all_services, s)) { - msg("[efiXplorer] gRT xref address: 0x%016llX, found new service\n", - u64_addr(ea)); + efi_utils::log("found new runtime service at 0x%016llX\n", + u64_addr(ea)); m_all_services.push_back(s); } } @@ -380,8 +379,7 @@ bool efi_analysis::efi_analyser_arm_t::get_protocol(ea_t address, if (guid_addr == BADADDR || code_addr == BADADDR) { return false; } - msg("[efiXplorer] address: 0x%016llX, found new protocol\n", - u64_addr(code_addr)); + efi_utils::log("found new protocol at 0x%016llX\n", u64_addr(code_addr)); return add_protocol(service_name, guid_addr, code_addr, address); } @@ -419,8 +417,8 @@ void efi_analysis::efi_analyser_arm_t::find_pei_services_function() { } decode_insn(&insn, end_ea); if (insn.itype == ARM_ret) { - msg("[efiXplorer] found GetPeiServices() function: 0x%016llX\n", - u64_addr(start_ea)); + efi_utils::log("found GetPeiServices() function at 0x%016llX\n", + u64_addr(start_ea)); set_name(start_ea, "GetPeiServices", SN_FORCE); efi_utils::set_ret_to_pei_svc(start_ea); } @@ -434,19 +432,19 @@ void efi_analysis::efi_analyser_arm_t::show_all_choosers() { // open window with all services if (m_all_services.size()) { - title = "efiXplorer: services"; + title = "efi: services"; services_show(m_all_services, title); } // open window with data guids if (m_all_guids.size()) { - qstring title = "efiXplorer: GUIDs"; + qstring title = "efi: GUIDs"; guids_show(m_all_guids, title); } // open window with protocols if (m_all_protocols.size()) { - title = "efiXplorer: protocols"; + title = "efi: protocols"; protocols_show(m_all_protocols, title); } } @@ -477,7 +475,7 @@ bool efi_analysis::efi_analyse_main_aarch64() { } if (analyser.m_ftype == ffs_file_type_t::pei) { - msg("[efiXplorer] input file is PEI module\n"); + efi_utils::log("input file is PEI module\n"); } // set the correct name for the entry point and automatically fix the diff --git a/efiXplorer/efi_analysis_x86.cc b/efiXplorer/efi_analysis_x86.cc index adbfbebc..ff9224c1 100644 --- a/efiXplorer/efi_analysis_x86.cc +++ b/efiXplorer/efi_analysis_x86.cc @@ -37,23 +37,23 @@ ea_list_t smst_list; // gSmst list (SMM system table addresses) ea_list_t image_handle_list; // gImageHandle list (image handle addresses) ea_list_t runtime_services_list; // runtime services list -json_list_t stackGuids; -json_list_t dataGuids; +json_list_t data_guids; +json_list_t stack_guids; // all .text and .data segments for compatibility with the efiLoader -segment_list_t textSegments; -segment_list_t dataSegments; +segment_list_t code_segs; +segment_list_t data_segs; // for smm callouts finding -ea_list_t calloutAddrs; -func_list_t excFunctions; -func_list_t childSmiHandlers; -ea_list_t readSaveStateCalls; +ea_list_t callout_addrs; +ea_list_t read_save_state_calls; +func_list_t child_smi_handlers; +func_list_t exc_funcs; // for GetVariable stack overflow finding -ea_list_t peiGetVariableOverflow; -ea_list_t getVariableOverflow; -ea_list_t smmGetVariableOverflow; +ea_list_t double_get_variable_pei; +ea_list_t double_get_variable_smm; +ea_list_t double_get_variable; efi_analysis::efi_analyser_t::efi_analyser_t() { // 32-bit, 64-bit, ARM or UEFI (in loader instance) @@ -121,21 +121,21 @@ efi_analysis::efi_analyser_t::~efi_analyser_t() { image_handle_list.clear(); runtime_services_list.clear(); - stackGuids.clear(); - dataGuids.clear(); + stack_guids.clear(); + data_guids.clear(); - textSegments.clear(); - dataSegments.clear(); + code_segs.clear(); + data_segs.clear(); - calloutAddrs.clear(); - excFunctions.clear(); - readSaveStateCalls.clear(); + callout_addrs.clear(); + exc_funcs.clear(); + read_save_state_calls.clear(); m_smi_handlers.clear(); - childSmiHandlers.clear(); + child_smi_handlers.clear(); - peiGetVariableOverflow.clear(); - getVariableOverflow.clear(); - smmGetVariableOverflow.clear(); + double_get_variable_pei.clear(); + double_get_variable.clear(); + double_get_variable_smm.clear(); g_get_smst_location_calls.clear(); g_smm_get_variable_calls.clear(); @@ -175,26 +175,26 @@ void efi_analysis::efi_analyser_t::get_segments() { // in order for decompilation to work properly s->perm = (SEGPERM_READ | SEGPERM_WRITE | SEGPERM_EXEC); set_segm_class(s, "DATA"); - textSegments.push_back(s); + code_segs.push_back(s); continue; } } auto index = seg_name.find(".data"); if (index != std::string::npos) { - dataSegments.push_back(s); + data_segs.push_back(s); continue; } } // print all .text and .code segments addresses - for (auto seg : textSegments) { + for (auto seg : code_segs) { segment_t *s = seg; msg("[%s] code segment: 0x%016llX\n", g_plugin_name, u64_addr(s->start_ea)); } // print all .data segments addresses - for (auto seg : dataSegments) { + for (auto seg : data_segs) { segment_t *s = seg; msg("[%s] data segment: 0x%016llX\n", g_plugin_name, u64_addr(s->start_ea)); } @@ -260,8 +260,8 @@ bool efi_analysis::efi_analyser_x86_t::find_system_table64() { // Find and mark gSmst global variable address for X64 module bool efi_analysis::efi_analyser_x86_t::find_smst64() { msg("[%s] gSmst finding\n", g_plugin_name); - ea_list_t smst_listSmmBase = findSmstSmmBase(bs_list); - ea_list_t smst_listSwDispatch = findSmstSwDispatch(bs_list); + ea_list_t smst_listSmmBase = efi_smm_utils::find_smst_smm_base(bs_list); + ea_list_t smst_listSwDispatch = efi_smm_utils::find_smst_sw_dispatch(bs_list); smst_list.insert(smst_list.end(), smst_listSwDispatch.begin(), smst_listSwDispatch.end()); smst_list.insert(smst_list.end(), smst_listSmmBase.begin(), @@ -384,7 +384,7 @@ bool efi_analysis::efi_analyser_x86_t::find_smst_postproc64() { // save child SW SMI handler func_t *handler_func = get_func(rcx_last); if (handler_func != nullptr) { - childSmiHandlers.push_back(handler_func); + child_smi_handlers.push_back(handler_func); set_name(rcx_last, "ChildSwSmiHandler", SN_FORCE); break; } @@ -409,7 +409,7 @@ bool efi_analysis::efi_analyser_x86_t::find_boot_services_tables() { } insn_t insn; - for (auto seg : textSegments) { + for (auto seg : code_segs) { segment_t *s = seg; msg("[%s] gEfiBootServices finding from 0x%016llX to 0x%016llX\n", g_plugin_name, u64_addr(s->start_ea), u64_addr(s->end_ea)); @@ -528,7 +528,7 @@ bool efi_analysis::efi_analyser_x86_t::find_runtime_services_tables() { } insn_t insn; - for (auto seg : textSegments) { + for (auto seg : code_segs) { segment_t *s = seg; msg("[%s] gEfiRuntimeServices finding from 0x%016llX to 0x%016llX\n", g_plugin_name, u64_addr(s->start_ea), u64_addr(s->end_ea)); @@ -704,10 +704,8 @@ void efi_analysis::efi_analyser_x86_t::get_boot_services_all() { // add item to allBootServices json bsItem; bsItem["address"] = addr; - bsItem["service_name"] = - static_cast(g_boot_services_table_all[j].name); - bsItem["table_name"] = - static_cast("EFI_BOOT_SERVICES"); + bsItem["service_name"] = g_boot_services_table_all[j].name; + bsItem["table_name"] = "EFI_BOOT_SERVICES"; bsItem["offset"] = offset; // add code addresses for arguments @@ -792,10 +790,8 @@ void efi_analysis::efi_analyser_x86_t::get_runtime_services_all() { // add item to allRuntimeServices json rtItem; rtItem["address"] = addr; - rtItem["service_name"] = static_cast( - g_runtime_services_table_all[j].name); - rtItem["table_name"] = - static_cast("EFI_RUNTIME_SERVICES"); + rtItem["service_name"] = g_runtime_services_table_all[j].name; + rtItem["table_name"] = "EFI_RUNTIME_SERVICES"; rtItem["offset"] = offset; // add code addresses for arguments @@ -856,11 +852,12 @@ void efi_analysis::efi_analyser_x86_t::get_smm_services_all64() { u32_addr(g_smm_services_table_all[j].offset64)) { if (u32_addr(g_smm_services_table_all[j].offset64) == 0xe0) { // set name for Handler argument - auto smiHandlerAddr = markChildSwSmiHandler(addr); + auto smiHandlerAddr = + efi_smm_utils::mark_child_sw_smi_handlers(addr); // save SMI handler func_t *childSmiHandler = get_func(smiHandlerAddr); if (childSmiHandler != nullptr) { - childSmiHandlers.push_back(childSmiHandler); + child_smi_handlers.push_back(childSmiHandler); } } @@ -882,10 +879,8 @@ void efi_analysis::efi_analyser_x86_t::get_smm_services_all64() { // add item to allSmmServices json smmsItem; smmsItem["address"] = addr; - smmsItem["service_name"] = - static_cast(g_smm_services_table_all[j].name); - smmsItem["table_name"] = - static_cast("_EFI_SMM_SYSTEM_TABLE2"); + smmsItem["service_name"] = g_smm_services_table_all[j].name; + smmsItem["table_name"] = "_EFI_SMM_SYSTEM_TABLE2"; smmsItem["offset"] = g_smm_services_table_all[j].offset64; // add code addresses for arguments @@ -972,9 +967,8 @@ void efi_analysis::efi_analyser_x86_t::get_pei_services_all32() { .push_back(ea); json psItem; psItem["address"] = ea; - psItem["service_name"] = - static_cast(g_pei_services_table32[j].name); - psItem["table_name"] = static_cast("EFI_PEI_SERVICES"); + psItem["service_name"] = g_pei_services_table32[j].name; + psItem["table_name"] = "EFI_PEI_SERVICES"; psItem["offset"] = g_pei_services_table32[j].offset; // add code addresses for arguments @@ -1036,8 +1030,7 @@ void efi_analysis::efi_analyser_x86_t::get_variable_ppi_calls_all32() { json ppiItem; ppiItem["address"] = ea; ppiItem["service_name"] = ppi_call; - ppiItem["table_name"] = - static_cast("EFI_PEI_READ_ONLY_VARIABLE2_PPI"); + ppiItem["table_name"] = "EFI_PEI_READ_ONLY_VARIABLE2_PPI"; ppiItem["offset"] = g_variable_ppi_table_all[j].offset32; // add code addresses for arguments @@ -1165,7 +1158,7 @@ void efi_analysis::efi_analyser_x86_t::get_ppi_names32() { // Get boot services by protocols for X64 modules void efi_analysis::efi_analyser_x86_t::get_prot_boot_services64() { insn_t insn; - for (auto s : textSegments) { + for (auto s : code_segs) { msg("[%s] BootServices finding from 0x%016llX to 0x%016llX (protocols)\n", g_plugin_name, u64_addr(s->start_ea), u64_addr(s->end_ea)); ea_t ea = s->start_ea; @@ -1207,9 +1200,8 @@ void efi_analysis::efi_analyser_x86_t::get_prot_boot_services64() { // add item to allBootServices json bsItem; bsItem["address"] = ea; - bsItem["service_name"] = - static_cast(g_boot_services_table64[i].name); - bsItem["table_name"] = static_cast("EFI_BOOT_SERVICES"); + bsItem["service_name"] = g_boot_services_table64[i].name; + bsItem["table_name"] = "EFI_BOOT_SERVICES"; bsItem["offset"] = g_boot_services_table64[i].offset; // add code addresses for arguments @@ -1250,9 +1242,8 @@ void efi_analysis::efi_analyser_x86_t::get_prot_boot_services32() { // add item to allBootServices json bsItem; bsItem["address"] = ea; - bsItem["service_name"] = - static_cast(g_boot_services_table32[i].name); - bsItem["table_name"] = static_cast("EFI_BOOT_SERVICES"); + bsItem["service_name"] = g_boot_services_table32[i].name; + bsItem["table_name"] = "EFI_BOOT_SERVICES"; bsItem["offset"] = g_boot_services_table32[i].offset; // add code addresses for arguments @@ -1431,10 +1422,10 @@ bool efi_analysis::efi_analyser_x86_t:: //-------------------------------------------------------------------------- // Get boot services protocols names for X64 modules void efi_analysis::efi_analyser_x86_t::get_bs_prot_names64() { - if (!textSegments.size()) { + if (!code_segs.size()) { return; } - segment_t *s = textSegments.at(0); + segment_t *s = code_segs.at(0); ea_t start = s->start_ea; msg("[%s] protocols finding (boot services, start address = 0x%016llX)\n", g_plugin_name, u64_addr(start)); @@ -1583,10 +1574,10 @@ void efi_analysis::efi_analyser_x86_t::get_bs_prot_names32() { //-------------------------------------------------------------------------- // Get smm services protocols names for X64 modules void efi_analysis::efi_analyser_x86_t::get_smm_prot_names64() { - if (!textSegments.size()) { + if (!code_segs.size()) { return; } - segment_t *s = textSegments.at(0); + segment_t *s = code_segs.at(0); ea_t start = s->start_ea; msg("[%s] protocols finding (smm services, start address = 0x%016llX)\n", g_plugin_name, u64_addr(start)); @@ -1677,12 +1668,12 @@ void efi_analysis::efi_analyser_t::mark_interfaces() { // Mark GUIDs found in the .text and .data segment void efi_analysis::efi_analyser_t::mark_data_guids() { ea_t ptrSize = inf_is_64bit() ? 8 : 4; - auto guids_segments = textSegments; + auto guids_segments = code_segs; // find GUIDs in .text and .data segments // TODO(yeggor): scan only the areas between the beginning of the .text // segment and the first function address (?) - guids_segments.insert(guids_segments.end(), dataSegments.begin(), - dataSegments.end()); + guids_segments.insert(guids_segments.end(), data_segs.begin(), + data_segs.end()); for (auto s : guids_segments) { msg("[%s] marking GUIDs from 0x%016llX to 0x%016llX\n", g_plugin_name, u64_addr(s->start_ea), u64_addr(s->end_ea)); @@ -1734,7 +1725,7 @@ void efi_analysis::efi_analyser_t::mark_data_guids() { guid_item["name"] = guidName; guid_item["guid"] = efi_utils::guid_to_string(guid); m_all_guids.push_back(guid_item); - dataGuids.push_back(guid_item); + data_guids.push_back(guid_item); } ea += 1; } @@ -1744,7 +1735,7 @@ void efi_analysis::efi_analyser_t::mark_data_guids() { //-------------------------------------------------------------------------- // Mark GUIDs found in local variables for X64 modules void efi_analysis::efi_analyser_x86_t::mark_local_guids64() { - for (auto seg : textSegments) { + for (auto seg : code_segs) { segment_t *s = seg; ea_t ea = s->start_ea; insn_t insn; @@ -1800,7 +1791,7 @@ void efi_analysis::efi_analyser_x86_t::mark_local_guids64() { guid_item["name"] = dbItem.key(); guid_item["guid"] = efi_utils::guid_to_string(guid); m_all_guids.push_back(guid_item); - stackGuids.push_back(guid_item); + stack_guids.push_back(guid_item); exit = true; break; } @@ -1825,9 +1816,9 @@ void findCalloutRec(func_t *func) { ea_t nextFuncAddr = insn.ops[0].addr; func_t *nextFunc = get_func(nextFuncAddr); if (nextFunc) { - auto it = std::find(excFunctions.begin(), excFunctions.end(), nextFunc); - if (it == excFunctions.end()) { - excFunctions.push_back(nextFunc); + auto it = std::find(exc_funcs.begin(), exc_funcs.end(), nextFunc); + if (it == exc_funcs.end()) { + exc_funcs.push_back(nextFunc); findCalloutRec(nextFunc); } } @@ -1859,7 +1850,7 @@ void findCalloutRec(func_t *func) { if (!fp) { msg("[%s] SMM callout found (gBS): 0x%016llX\n", g_plugin_name, u64_addr(ea)); - calloutAddrs.push_back(ea); + callout_addrs.push_back(ea); continue; } } @@ -1868,7 +1859,7 @@ void findCalloutRec(func_t *func) { if (efi_utils::addr_in_vec(rt_list, insn.ops[1].addr)) { msg("[%s] SMM callout found (gRT): 0x%016llX\n", g_plugin_name, u64_addr(ea)); - calloutAddrs.push_back(ea); + callout_addrs.push_back(ea); continue; } @@ -1901,7 +1892,7 @@ void findCalloutRec(func_t *func) { msg("[%s] SMM callout found (usage of memory controlled by " "the attacker inside SMI handler): 0x%016llX\n", g_plugin_name, u64_addr(ea)); - calloutAddrs.push_back(ea); + callout_addrs.push_back(ea); interface_callout_found = true; } // else: FP break; @@ -1961,7 +1952,7 @@ void efi_analysis::efi_analyser_t::find_smi_handlers() { {&m_fch_apu_ras_guid, "ApuRas"}, }; for (auto &[guid, prefix] : types) { - auto res = findSmiHandlersSmmDispatch(*guid, prefix); + auto res = efi_smm_utils::find_smi_handlers_dispatch(*guid, prefix); m_smi_handlers.insert(m_smi_handlers.end(), res.begin(), res.end()); } } @@ -1975,14 +1966,14 @@ bool efi_analysis::efi_analyser_t::find_smm_callout() { if (!bs_list.size() && !rt_list.size()) { return false; } - if (!m_smi_handlers.size() && !childSmiHandlers.size()) { + if (!m_smi_handlers.size() && !child_smi_handlers.size()) { msg("[%s] can't find a SwSmiHandler functions\n", g_plugin_name); return false; } for (auto func : m_smi_handlers) { findCalloutRec(func); } - for (auto func : childSmiHandlers) { + for (auto func : child_smi_handlers) { findCalloutRec(func); } return true; @@ -2063,7 +2054,7 @@ bool efi_analysis::efi_analyser_t::find_double_get_variable_pei() { } if (same_datasize) { - peiGetVariableOverflow.push_back(curr_addr); + double_get_variable_pei.push_back(curr_addr); msg("[%s] overflow can occur here: 0x%016llX\n", g_plugin_name, u64_addr(curr_addr)); continue; @@ -2087,7 +2078,7 @@ bool efi_analysis::efi_analyser_t::find_double_get_variable_pei() { if (!datasize_addr_found) { // if datasize wasn't found, just let the pattern // trigger - for manual review - peiGetVariableOverflow.push_back(curr_addr); + double_get_variable_pei.push_back(curr_addr); msg("[%s] overflow can occur here: 0x%016llX\n", g_plugin_name, u64_addr(curr_addr)); continue; @@ -2117,7 +2108,7 @@ bool efi_analysis::efi_analyser_t::find_double_get_variable_pei() { } if (same_datasize) { - peiGetVariableOverflow.push_back(curr_addr); + double_get_variable_pei.push_back(curr_addr); msg("[%s] overflow can occur here: 0x%016llX\n", g_plugin_name, u64_addr(curr_addr)); continue; @@ -2141,11 +2132,11 @@ bool efi_analysis::efi_analyser_t::find_double_get_variable_pei() { (prev_datasize_addr == curr_datasize_addr)); if (!datasize_addr_found) { - peiGetVariableOverflow.push_back(curr_addr); + double_get_variable_pei.push_back(curr_addr); msg("[%s] overflow can occur here: 0x%016llX\n", g_plugin_name, u64_addr(curr_addr)); } else if (prev_datasize_addr == curr_datasize_addr) { - peiGetVariableOverflow.push_back(curr_addr); + double_get_variable_pei.push_back(curr_addr); msg("[%s] overflow can occur here: 0x%016llX " "(prev_datasize_addr == " "curr_datasize_addr)\n", @@ -2154,7 +2145,7 @@ bool efi_analysis::efi_analyser_t::find_double_get_variable_pei() { } prev_addr = curr_addr; } - return (peiGetVariableOverflow.size() > 0); + return (double_get_variable_pei.size() > 0); } //-------------------------------------------------------------------------- @@ -2255,7 +2246,7 @@ bool efi_analysis::efi_analyser_t::find_double_get_variable( // for (auto i = 0; i < 10; ++i) { func_t *func_start = get_func(ea); if (func_start == nullptr) { - return (getVariableOverflow.size() > 0); + return (double_get_variable.size() > 0); } uint16 stack_base_reg = 0xFF; decode_insn(&insn, func_start->start_ea); @@ -2276,7 +2267,7 @@ bool efi_analysis::efi_analyser_t::find_double_get_variable( if ((insn.ops[1].phrase == stack_base_reg && (sval + stack_addr) == dataSizeStackAddr) || (dataSizeStackAddr == insn.ops[1].addr)) { - getVariableOverflow.push_back(curr_addr); + double_get_variable.push_back(curr_addr); msg("[%s] \toverflow can occur here: 0x%016llX\n", g_plugin_name, u64_addr(curr_addr)); break; @@ -2288,25 +2279,25 @@ bool efi_analysis::efi_analyser_t::find_double_get_variable( } prev_addr = curr_addr; } - return (getVariableOverflow.size() > 0); + return (double_get_variable.size() > 0); } //-------------------------------------------------------------------------- // Find potential stack/heap overflow with double SmmGetVariable calls bool efi_analysis::efi_analyser_t::find_double_get_variable_smm() { msg("[%s] Looking for SmmGetVariable stack/heap overflow\n", g_plugin_name); - ea_list_t smmGetVariableCalls = - findSmmGetVariableCalls(dataSegments, &m_all_services); - sort(smmGetVariableCalls.begin(), smmGetVariableCalls.end()); - if (smmGetVariableCalls.size() < 2) { + ea_list_t smm_get_variable_calls = + efi_smm_utils::find_smm_get_variable_calls(data_segs, &m_all_services); + sort(smm_get_variable_calls.begin(), smm_get_variable_calls.end()); + if (smm_get_variable_calls.size() < 2) { msg("[%s] less than 2 GetVariable calls found\n", g_plugin_name); return false; } - ea_t prev_addr = smmGetVariableCalls.at(0); + ea_t prev_addr = smm_get_variable_calls.at(0); ea_t ea; insn_t insn; - for (auto i = 1; i < smmGetVariableCalls.size(); ++i) { - ea_t curr_addr = smmGetVariableCalls.at(i); + for (auto i = 1; i < smm_get_variable_calls.size(); ++i) { + ea_t curr_addr = smm_get_variable_calls.at(i); msg("[%s] SmmGetVariable_1: 0x%016llX, SmmGetVariable_2: 0x%016llX\n", g_plugin_name, u64_addr(prev_addr), u64_addr(curr_addr)); @@ -2355,7 +2346,7 @@ bool efi_analysis::efi_analyser_t::find_double_get_variable_smm() { if (insn.itype == NN_lea && insn.ops[0].type == o_reg && insn.ops[0].reg == R_R9) { if (dataSizeStackAddr == insn.ops[1].addr) { - smmGetVariableOverflow.push_back(curr_addr); + double_get_variable_smm.push_back(curr_addr); msg("[%s] \toverflow can occur here: 0x%016llX\n", g_plugin_name, u64_addr(curr_addr)); break; @@ -2370,7 +2361,7 @@ bool efi_analysis::efi_analyser_t::find_double_get_variable_smm() { } prev_addr = curr_addr; } - return (smmGetVariableOverflow.size() > 0); + return (double_get_variable_smm.size() > 0); } bool efi_analysis::efi_analyser_t::analyse_variable_service( @@ -2529,8 +2520,8 @@ bool efi_analysis::efi_analyser_t::analyse_nvram_variables() { //-------------------------------------------------------------------------- // Resolve EFI_SMM_CPU_PROTOCOL bool efi_analysis::efi_analyser_t::smm_cpu_protocol_resolver() { - readSaveStateCalls = - resolveEfiSmmCpuProtocol(stackGuids, dataGuids, &m_all_services); + read_save_state_calls = efi_smm_utils::resolve_efi_smm_cpu_protocol( + stack_guids, data_guids, &m_all_services); return true; } @@ -2568,20 +2559,20 @@ void efi_analysis::efi_analyser_t::dump_json() { if (m_nvram_variables.size()) { info["m_nvram_variables"] = m_nvram_variables; } - if (readSaveStateCalls.size()) { - info["readSaveStateCalls"] = readSaveStateCalls; + if (read_save_state_calls.size()) { + info["read_save_state_calls"] = read_save_state_calls; } - if (calloutAddrs.size()) { - info["vulns"]["smm_callout"] = calloutAddrs; + if (callout_addrs.size()) { + info["vulns"]["smm_callout"] = callout_addrs; } - if (peiGetVariableOverflow.size()) { - info["vulns"]["pei_get_variable_buffer_overflow"] = peiGetVariableOverflow; + if (double_get_variable_pei.size()) { + info["vulns"]["pei_get_variable_buffer_overflow"] = double_get_variable_pei; } - if (getVariableOverflow.size()) { - info["vulns"]["get_variable_buffer_overflow"] = getVariableOverflow; + if (double_get_variable.size()) { + info["vulns"]["get_variable_buffer_overflow"] = double_get_variable; } - if (smmGetVariableOverflow.size()) { - info["vulns"]["smm_get_variable_buffer_overflow"] = smmGetVariableOverflow; + if (double_get_variable_smm.size()) { + info["vulns"]["smm_get_variable_buffer_overflow"] = double_get_variable_smm; } json_list_t m_smi_handlersAddrs; @@ -2640,14 +2631,14 @@ void efi_analysis::efi_analyser_x86_t::show_all_choosers() { } // open window with vulnerabilities - if (calloutAddrs.size() || peiGetVariableOverflow.size() || - getVariableOverflow.size() || smmGetVariableOverflow.size()) { + if (callout_addrs.size() || double_get_variable_pei.size() || + double_get_variable.size() || double_get_variable_smm.size()) { json_list_t vulns; std::map vulns_map = { - {"SmmCallout", calloutAddrs}, - {"PeiGetVariableOverflow", peiGetVariableOverflow}, - {"DxeGetVariableOverflow", getVariableOverflow}, - {"SmmGetVariableOverflow", smmGetVariableOverflow}}; + {"SmmCallout", callout_addrs}, + {"PeiGetVariableOverflow", double_get_variable_pei}, + {"DxeGetVariableOverflow", double_get_variable}, + {"SmmGetVariableOverflow", double_get_variable_smm}}; for (const auto &[type, addrs] : vulns_map) { for (auto addr : addrs) { @@ -2683,9 +2674,9 @@ bool efi_analysis::efi_analyse_main_x86_64() { res = ask_yn(1, "Want to further analyse all drivers with auto_mark_range?"); } - if (res == ASKBTN_YES && textSegments.size() && dataSegments.size()) { - segment_t *start_seg = textSegments.at(0); - segment_t *end_seg = dataSegments.at(dataSegments.size() - 1); + if (res == ASKBTN_YES && code_segs.size() && data_segs.size()) { + segment_t *start_seg = code_segs.at(0); + segment_t *end_seg = data_segs.at(data_segs.size() - 1); ea_t start_ea = start_seg->start_ea; ea_t end_ea = end_seg->end_ea; auto_mark_range(start_ea, end_ea, AU_USED); diff --git a/efiXplorer/efi_smm_utils.cc b/efiXplorer/efi_smm_utils.cc index 7b09c7dd..492e747c 100644 --- a/efiXplorer/efi_smm_utils.cc +++ b/efiXplorer/efi_smm_utils.cc @@ -23,8 +23,9 @@ #include //-------------------------------------------------------------------------- -// Find and mark gSmst global variable via EFI_SMM_SW_DISPATCH(2)_PROTOCOL_GUID -ea_list_t findSmstSwDispatch(ea_list_t bs_list) { +// find and mark gSmst global variable via +// EFI_SMM_SW_DISPATCH_PROTOCOL_GUID/EFI_SMM_SW_DISPATCH2_PROTOCOL_GUID +ea_list_t efi_smm_utils::find_smst_sw_dispatch(ea_list_t bs_list) { ea_list_t smst_addrs; efi_guid_t guid2 = {0x18a3c6dc, 0x5eea, @@ -36,18 +37,21 @@ ea_list_t findSmstSwDispatch(ea_list_t bs_list) { 0x420c, {0xb0, 0x26, 0xdf, 0x99, 0x36, 0x53, 0xf8, 0xbf}}; // EFI_SMM_SW_DISPATCH_PROTOCOL_GUID + ea_list_t data_addrs = efi_utils::find_data(0, BADADDR, guid.uchar_data().data(), 16); ea_list_t data2_addrs = efi_utils::find_data(0, BADADDR, guid2.uchar_data().data(), 16); data_addrs.insert(data_addrs.end(), data2_addrs.begin(), data2_addrs.end()); + for (auto data_addr : data_addrs) { - msg("[%s] EFI_SMM_SW_DISPATCH(2)_PROTOCOL_GUID: 0x%016llX\n", g_plugin_name, - u64_addr(data_addr)); + efi_utils::log("SMM dispatch protocol GUID: 0x%016llX\n", + u64_addr(data_addr)); ea_list_t xrefs = efi_utils::get_xrefs(data_addr); insn_t insn; for (auto xref : xrefs) { - uint16_t smst_reg = 0xffff; // Smst register + // smst register + uint16_t smst_reg = 0xffff; ea_t cur_addr = xref; while (true) { cur_addr = next_head(cur_addr, BADADDR); @@ -64,7 +68,8 @@ ea_list_t findSmstSwDispatch(ea_list_t bs_list) { } if (smst_reg == 0xffff) { - continue; // smst_reg not found + // smst register not found + continue; } ea_t res_addr = BADADDR; @@ -74,8 +79,8 @@ ea_list_t findSmstSwDispatch(ea_list_t bs_list) { decode_insn(&insn, cur_addr); if (insn.itype == NN_mov && insn.ops[0].type == o_reg && insn.ops[0].reg == smst_reg && insn.ops[1].type == o_mem) { - msg("[%s] found gSmst at 0x%016llX, address = 0x%016llX\n", - g_plugin_name, u64_addr(cur_addr), u64_addr(insn.ops[1].addr)); + efi_utils::log("found gSmst at 0x%016llX, address = 0x%016llX\n", + u64_addr(cur_addr), u64_addr(insn.ops[1].addr)); res_addr = insn.ops[1].addr; if (efi_utils::addr_in_vec(bs_list, res_addr)) { continue; @@ -96,8 +101,8 @@ ea_list_t findSmstSwDispatch(ea_list_t bs_list) { } //-------------------------------------------------------------------------- -// Find and mark gSmst global variable via EFI_SMM_BASE2_PROTOCOL_GUID -ea_list_t findSmstSmmBase(ea_list_t bs_list) { +// find and mark gSmst global variable via EFI_SMM_BASE2_PROTOCOL_GUID +ea_list_t efi_smm_utils::find_smst_smm_base(ea_list_t bs_list) { ea_list_t smst_addrs; efi_guid_t guid = {0xf4ccbfb7, 0xf6e0, @@ -107,8 +112,7 @@ ea_list_t findSmstSmmBase(ea_list_t bs_list) { ea_list_t data_addrs = efi_utils::find_data(0, BADADDR, guid.uchar_data().data(), 16); for (auto data_addr : data_addrs) { - msg("[%s] EFI_SMM_BASE2_PROTOCOL_GUID: 0x%016llX\n", g_plugin_name, - u64_addr(data_addr)); + efi_utils::log("SMM base protocol GUID: 0x%016llX\n", u64_addr(data_addr)); ea_list_t data_xrefs = efi_utils::get_xrefs(data_addr); insn_t insn; for (auto xref : data_xrefs) { @@ -122,8 +126,9 @@ ea_list_t findSmstSmmBase(ea_list_t bs_list) { if (insn.itype == NN_lea && insn.ops[0].type == o_reg && insn.ops[0].reg == R_RDX && insn.ops[1].type == o_mem) { res_addr = insn.ops[1].addr; - msg("[%s] found gSmst/gInSmram at 0x%016llX, address = 0x%016llX\n", - g_plugin_name, u64_addr(cur_addr), u64_addr(res_addr)); + efi_utils::log( + "found gSmst/InSmram at 0x%016llX, address = 0x%016llX\n", + u64_addr(cur_addr), u64_addr(res_addr)); } if (res_addr != BADADDR && insn.itype == NN_callni && insn.ops[0].type == o_phrase && !insn.ops[0].addr) { @@ -132,7 +137,7 @@ ea_list_t findSmstSmmBase(ea_list_t bs_list) { } } if (!in_smram) { - // we found gSmst + // found gSmst if (efi_utils::addr_in_vec(bs_list, res_addr)) { continue; } @@ -140,7 +145,7 @@ ea_list_t findSmstSmmBase(ea_list_t bs_list) { "_EFI_SMM_SYSTEM_TABLE2"); smst_addrs.push_back(res_addr); } else { - // we found gInSmram + // found gInSmram efi_utils::set_type_and_name(res_addr, "gInSmram", "BOOLEAN"); } } @@ -150,29 +155,27 @@ ea_list_t findSmstSmmBase(ea_list_t bs_list) { } //-------------------------------------------------------------------------- -// Find SmiHandler in reg_smi_func function (prefix: Sw, TrapIo, Sx, Gpi, Usb, -// StandbyButton, PeriodicTimer, PowerButton) -func_list_t findSmiHandlers(ea_t address, std::string prefix) { - msg("[%s] Analyse xref to gEfiSmm%sDispatch(2)Protocol: 0x%016llX\n", - g_plugin_name, prefix.c_str(), u64_addr(address)); +// find SmiHandler in reg_smi_func function, +// prefix: Sw, TrapIo, Sx, Gpi, Usb, StandbyButton, PeriodicTimer, ... +func_list_t efi_smm_utils::find_smi_handlers(ea_t address, std::string prefix) { + efi_utils::log("analyse xref to SMM %sDispatch protocol: 0x%016llX\n", + prefix.c_str(), u64_addr(address)); - func_list_t m_smi_handlers; + func_list_t smi_handlers; insn_t insn; - // Find Dispatch interface address (via gSmst->SmmLocateProtocol call) + // find Dispatch interface address (via gSmst->SmmLocateProtocol call) - // Check instruction + // check instruction decode_insn(&insn, address); if (!(insn.ops[0].type == o_reg && insn.ops[0].reg == R_RCX)) { - msg("[%s] %sSmiHandler: wrong xref to dispatch(2) protocol\n", - g_plugin_name, prefix.c_str()); - return m_smi_handlers; + return smi_handlers; } - // Analyse current basic block + // analyse current basic block auto ea = address; - // Search for SmmLocateProtocol + // search for SmmLocateProtocol bool found = false; uint64_t dispatch_interface = BADADDR; while (!is_basic_block_end(insn, false)) { @@ -181,10 +184,10 @@ func_list_t findSmiHandlers(ea_t address, std::string prefix) { if (insn.itype == NN_callni && insn.ops[0].type == o_displ && insn.ops[0].addr == 0xd0) { found = true; - msg("[%s] %sSmiHandler: found = true\n", g_plugin_name, prefix.c_str()); + efi_utils::log("found %sSmiHandler\n", prefix.c_str()); break; } - // Interface in stack + // interface is a local variable if (insn.itype == NN_lea && insn.ops[0].type == o_reg && insn.ops[0].reg == R_R8 && insn.ops[1].type == o_displ && (insn.ops[1].reg == R_RBP || insn.ops[1].reg == R_RSP)) { @@ -192,7 +195,7 @@ func_list_t findSmiHandlers(ea_t address, std::string prefix) { dispatch_interface = insn.ops[1].addr; } } - // Interface in data + // interface is a global variable if (insn.itype == NN_lea && insn.ops[0].type == o_reg && insn.ops[0].reg == R_R8 && insn.ops[1].type == o_mem) { if (dispatch_interface == BADADDR) { @@ -202,7 +205,7 @@ func_list_t findSmiHandlers(ea_t address, std::string prefix) { } if (!found) { - return m_smi_handlers; + return smi_handlers; } if (dispatch_interface == BADADDR) { @@ -210,14 +213,14 @@ func_list_t findSmiHandlers(ea_t address, std::string prefix) { while (!is_basic_block_end(insn, false)) { ea = prev_head(ea, 0); decode_insn(&insn, ea); - // Interface in stack + // interface is stack variable if (insn.itype == NN_lea && insn.ops[0].type == o_reg && insn.ops[0].reg == R_R8 && insn.ops[1].type == o_displ && (insn.ops[1].reg == R_RBP || insn.ops[1].reg == R_RSP)) { dispatch_interface = insn.ops[1].addr; break; } - // Interface in data + // interface is global variable if (insn.itype == NN_lea && insn.ops[0].type == o_reg && insn.ops[0].reg == R_R8 && insn.ops[1].type == o_mem) { dispatch_interface = insn.ops[1].addr; @@ -227,23 +230,23 @@ func_list_t findSmiHandlers(ea_t address, std::string prefix) { } if (dispatch_interface == BADADDR) { - return m_smi_handlers; + return smi_handlers; } - msg("[%s] Found EfiSmm%sDispatch(2)Protocol interface: 0x%016llX\n", - g_plugin_name, prefix.c_str(), dispatch_interface); + efi_utils::log("found SMM %sDispatch protocol interface at: 0x%016llX\n", + prefix.c_str(), dispatch_interface); // TODO(yeggor): handle xrefs for globals // (fw71.bin.out/SmmHddSecurity-316b1230-0500-4592-8c09-eaba0fb6b07f.smm) - // Track interface stack variable + // track interface stack variable ea = address; uint16_t reg = NONE_REG; uint64_t dispatch_func = BADADDR; for (auto i = 0; i < 100; i++) { ea = next_head(ea, BADADDR); decode_insn(&insn, ea); - // get Interface base register + // get interface base register if (insn.itype == NN_mov && insn.ops[0].type == o_reg && (insn.ops[1].type == o_displ || insn.ops[1].type == o_mem)) { if (insn.ops[1].addr == dispatch_interface) { @@ -275,27 +278,28 @@ func_list_t findSmiHandlers(ea_t address, std::string prefix) { } if (insn.itype == NN_callni && insn.ops[0].type == o_phrase && insn.ops[0].reg == reg) { - msg("[%s] Found EfiSmm%sDispatch2Protocol->Register call (0x%016llX)\n", - g_plugin_name, prefix.c_str(), u64_addr(ea)); - msg("[%s] %sSmiHandler: 0x%016llX\n", g_plugin_name, prefix.c_str(), - dispatch_func); + efi_utils::log("Register(): 0x%016llX, %sSmiHandler: 0x%016llX\n", + u64_addr(ea), prefix.c_str(), dispatch_func); auto handler_func = get_func(dispatch_func); if (handler_func == nullptr) { add_func(dispatch_func); // create function handler_func = get_func(dispatch_func); // retry } if (handler_func != nullptr) { - m_smi_handlers.push_back(handler_func); // add in result + smi_handlers.push_back(handler_func); // add in result } reg = NONE_REG; // resetting // op_stroff + set_name - std::string name = prefix + "SmiHandler"; + auto name = std::format("{}SmiHandler", prefix); set_name(dispatch_func, name.c_str(), SN_FORCE); + std::string prefix_upper; std::transform(prefix.begin(), prefix.end(), prefix_upper.begin(), ::toupper); - std::string type = "EFI_SMM_" + prefix_upper + "_DISPATCH2_PROTOCOL"; + std::string type = + std::format("EFI_SMM_{}_DISPATCH2_PROTOCOL", prefix_upper); + efi_utils::op_stroff(ea, type); } @@ -304,45 +308,45 @@ func_list_t findSmiHandlers(ea_t address, std::string prefix) { } } - return m_smi_handlers; + return smi_handlers; } //-------------------------------------------------------------------------- -// Find {Prefix}SmiHandler function inside SMM drivers -// * find GUID -// * get xrefs to GUID -// * xref will be inside RegSwSmi function -// * find SmiHandler by pattern (instructions may be out of order) -// lea r9, ... -// lea r8, ... -// lea rdx, -// call qword ptr [...] -func_list_t findSmiHandlersSmmDispatch(efi_guid_t guid, std::string prefix) { - func_list_t m_smi_handlers; +// find {Prefix}SmiHandler function inside SMM drivers +// - find GUID +// - get xrefs to GUID +// - xref will be inside RegSwSmi function +// - find SmiHandler by pattern (instructions may be out of order) +// lea r9, ... +// lea r8, ... +// lea rdx, +// call qword ptr [...] +func_list_t efi_smm_utils::find_smi_handlers_dispatch(efi_guid_t guid, + std::string prefix) { + func_list_t smi_handlers; ea_list_t data_addrs = efi_utils::find_data(0, BADADDR, guid.uchar_data().data(), 16); - msg("[%s] %sSmiHandler function finding\n", g_plugin_name, prefix.c_str()); for (auto data_addr : data_addrs) { ea_list_t xrefs = efi_utils::get_xrefs(data_addr); for (auto xref : xrefs) { - msg("[%s] findSmiHandlers: 0x%016llX\n", g_plugin_name, u64_addr(xref)); - auto res = findSmiHandlers(xref, prefix); - m_smi_handlers.insert(m_smi_handlers.end(), res.begin(), res.end()); + auto res = efi_smm_utils::find_smi_handlers(xref, prefix); + smi_handlers.insert(smi_handlers.end(), res.begin(), res.end()); } } - return m_smi_handlers; + return smi_handlers; } //-------------------------------------------------------------------------- -// Find SwSmiHandler function inside SMM drivers in case where -// EFI_SMM_SW_DISPATCH(2)_PROTOCOL_GUID is a local variable -func_list_t findSmiHandlersSmmDispatchStack(json_list_t stackGuids, - std::string prefix) { - func_list_t m_smi_handlers; - - for (auto guid : stackGuids) { +// find SwSmiHandler function inside SMM drivers in case where +// EFI_SMM_SW_DISPATCH{2}_PROTOCOL_GUID is a local variable +func_list_t +efi_smm_utils::find_smi_handlers_dispatch_stack(json_list_t stack_guids, + std::string prefix) { + func_list_t smi_handlers; + + for (auto guid : stack_guids) { std::string name = static_cast(guid["name"]); if (name != "EFI_SMM_SW_DISPATCH2_PROTOCOL_GUID" && @@ -351,44 +355,43 @@ func_list_t findSmiHandlersSmmDispatchStack(json_list_t stackGuids, } ea_t address = static_cast(guid["address"]); - msg("[%s] found EFI_SMM_SW_DISPATCH(2)_PROTOCOL_GUID on stack: " - "0x%016llX\n", - g_plugin_name, u64_addr(address)); - auto res = findSmiHandlers(address, prefix); - m_smi_handlers.insert(m_smi_handlers.end(), res.begin(), res.end()); + efi_utils::log( + "found EFI_SMM_SW_DISPATCH{2}_PROTOCOL_GUID on stack: 0x%016llX\n", + u64_addr(address)); + auto res = efi_smm_utils::find_smi_handlers(address, prefix); + smi_handlers.insert(smi_handlers.end(), res.begin(), res.end()); } - return m_smi_handlers; + return smi_handlers; } //-------------------------------------------------------------------------- // Find gSmmVariable->SmmGetVariable calls via EFI_SMM_VARIABLE_PROTOCOL_GUID -ea_list_t findSmmGetVariableCalls(segment_list_t dataSegments, - json_list_t *m_all_services) { - msg("[%s] gSmmVariable->SmmGetVariable calls finding via " - "EFI_SMM_VARIABLE_PROTOCOL_GUID\n", - g_plugin_name); - ea_list_t smmGetVariableCalls; +ea_list_t +efi_smm_utils::find_smm_get_variable_calls(segment_list_t data_segs, + json_list_t *all_services) { + ea_list_t smm_get_variable_calls; efi_guid_t guid = {0xed32d533, 0x99e6, 0x4209, {0x9c, 0xc0, 0x2d, 0x72, 0xcd, 0xd9, 0x98, 0xa7}}; // EFI_SMM_VARIABLE_PROTOCOL_GUID - // Find all EFI_GUID EFI_SMM_VARIABLE_PROTOCOL_GUID addresses + // find all EFI_SMM_VARIABLE_PROTOCOL_GUID addresses ea_list_t data_addrs = efi_utils::find_data(0, BADADDR, guid.uchar_data().data(), 16); - ea_list_t gSmmVariableAddrs; // Find all gSmmVariable variables + + // find all gSmmVariable variables + ea_list_t smm_variable_addrs; for (auto data_addr : data_addrs) { ea_list_t xrefs = efi_utils::get_xrefs(data_addr); for (auto xref : xrefs) { - segment_t *seg = getseg(static_cast(xref)); + segment_t *seg = getseg(xref); qstring seg_name; get_segm_name(&seg_name, seg); - msg("[%s] EFI_SMM_VARIABLE_PROTOCOL_GUID xref address: 0x%016llX, " - "segment: %s\n", - g_plugin_name, u64_addr(xref), seg_name.c_str()); + efi_utils::log("found EFI_SMM_VARIABLE_PROTOCOL_GUID xref at 0x%016llX\n", + u64_addr(xref)); size_t index = seg_name.find(".text"); if (index == std::string::npos) { @@ -398,80 +401,76 @@ ea_list_t findSmmGetVariableCalls(segment_list_t dataSegments, insn_t insn; ea_t ea = xref; for (auto i = 0; i < 8; i++) { - // Find `lea r8, ` instruction + // search for `lea r8, {gSmmVariable}` instruction ea = prev_head(ea, 0); decode_insn(&insn, ea); if (insn.itype == NN_lea && insn.ops[0].type == o_reg && insn.ops[0].reg == R_R8 && insn.ops[1].type == o_mem) { - msg("[%s] gSmmVariable address: 0x%016llX\n", g_plugin_name, - u64_addr(insn.ops[1].addr)); + efi_utils::log("gSmmVariable: 0x%016llX\n", + u64_addr(insn.ops[1].addr)); efi_utils::set_ptr_type_and_name(insn.ops[1].addr, "gSmmVariable", "EFI_SMM_VARIABLE_PROTOCOL"); - gSmmVariableAddrs.push_back(insn.ops[1].addr); + smm_variable_addrs.push_back(insn.ops[1].addr); break; } } } } - if (!gSmmVariableAddrs.size()) { - msg("[%s] can't find gSmmVariable addresses\n", g_plugin_name); - return smmGetVariableCalls; + if (!smm_variable_addrs.size()) { + efi_utils::log("gSmmVariable not found\n"); + return smm_get_variable_calls; } - for (auto smmVarAddr : gSmmVariableAddrs) { - ea_list_t smmVarXrefs = efi_utils::get_xrefs(static_cast(smmVarAddr)); - for (auto smmVarXref : smmVarXrefs) { - segment_t *seg = getseg(static_cast(smmVarXref)); + for (auto smm_variable_addr : smm_variable_addrs) { + ea_list_t smm_variable_xrefs = efi_utils::get_xrefs(smm_variable_addr); + for (auto smm_variable_xref : smm_variable_xrefs) { + segment_t *seg = getseg(smm_variable_xref); qstring seg_name; get_segm_name(&seg_name, seg); - msg("[%s] gSmmVariable xref address: 0x%016llX, segment: %s\n", - g_plugin_name, u64_addr(smmVarXref), seg_name.c_str()); + efi_utils::log("found gSmmVariable xref at 0x%016llX\n", + u64_addr(smm_variable_xref)); size_t index = seg_name.find(".text"); if (index == std::string::npos) { continue; } - uint16 gSmmVariableReg = 0xffff; + uint16 smm_variable_reg = NONE_REG; insn_t insn; - ea_t ea = static_cast(smmVarXref); + ea_t ea = smm_variable_xref; decode_insn(&insn, ea); if (insn.itype == NN_mov && insn.ops[0].type == o_reg && insn.ops[1].type == o_mem) { - gSmmVariableReg = insn.ops[0].reg; + smm_variable_reg = insn.ops[0].reg; for (auto i = 0; i < 16; i++) { ea = next_head(ea, BADADDR); decode_insn(&insn, ea); - if (insn.itype == NN_callni && gSmmVariableReg == insn.ops[0].reg && + if (insn.itype == NN_callni && smm_variable_reg == insn.ops[0].reg && insn.ops[0].addr == 0) { - msg("[%s] gSmmVariable->SmmGetVariable found: 0x%016llX\n", - g_plugin_name, u64_addr(ea)); - - if (find(smmGetVariableCalls.begin(), smmGetVariableCalls.end(), - ea) == smmGetVariableCalls.end()) { - smmGetVariableCalls.push_back(ea); + if (find(smm_get_variable_calls.begin(), + smm_get_variable_calls.end(), + ea) == smm_get_variable_calls.end()) { + smm_get_variable_calls.push_back(ea); } - // Temporarily add a "virtual" smm service call + // temporarily add a "virtual" SMM service call // for easier annotations and UI - efi_utils::op_stroff(ea, "EFI_SMM_VARIABLE_PROTOCOL"); - msg("[%s] 0x%016llX : %s\n", g_plugin_name, u64_addr(ea), - "SmmGetVariable"); - std::string smm_call = "gSmmVariable->SmmGetVariable"; - json smm_item; - smm_item["address"] = ea; - smm_item["service_name"] = smm_call; - smm_item["table_name"] = - static_cast("EFI_SMM_VARIABLE_PROTOCOL"); - smm_item["offset"] = 0; - - if (find(m_all_services->begin(), m_all_services->end(), - smm_item) == m_all_services->end()) { - m_all_services->push_back(smm_item); + efi_utils::log("found SmmGetVariable call at 0x%016llX\n", + u64_addr(ea)); + + json service; + service["address"] = ea; + service["service_name"] = "gSmmVariable->SmmGetVariable"; + service["table_name"] = "EFI_SMM_VARIABLE_PROTOCOL"; + service["offset"] = 0; + + if (find(all_services->begin(), all_services->end(), service) == + all_services->end()) { + all_services->push_back(service); } break; @@ -480,79 +479,75 @@ ea_list_t findSmmGetVariableCalls(segment_list_t dataSegments, } } } - return smmGetVariableCalls; + return smm_get_variable_calls; } -ea_list_t resolveEfiSmmCpuProtocol(json_list_t stackGuids, - json_list_t dataGuids, - json_list_t *m_all_services) { - ea_list_t readSaveStateCalls; - msg("[%s] Looking for EFI_SMM_CPU_PROTOCOL\n", g_plugin_name); +ea_list_t +efi_smm_utils::resolve_efi_smm_cpu_protocol(json_list_t stack_guids, + json_list_t data_guids, + json_list_t *all_services) { + ea_list_t read_save_state_calls; ea_list_t code_addrs; - ea_list_t gSmmCpuAddrs; - for (auto guid : stackGuids) { - std::string name = static_cast(guid["name"]); - if (name != "EFI_SMM_CPU_PROTOCOL_GUID") + ea_list_t smm_cpu_addrs; + for (auto guid : stack_guids) { + if (static_cast(guid["name"]) != "EFI_SMM_CPU_PROTOCOL_GUID") continue; ea_t address = static_cast(guid["address"]); - msg("[%s] found EFI_SMM_CPU_PROTOCOL on stack: 0x%016llX\n", g_plugin_name, - u64_addr(address)); + efi_utils::log("found EFI_SMM_CPU_PROTOCOL on stack at 0x%016llX\n", + u64_addr(address)); code_addrs.push_back(address); } - for (auto guid : dataGuids) { - std::string name = static_cast(guid["name"]); - if (name != "EFI_SMM_CPU_PROTOCOL_GUID") + for (auto guid : data_guids) { + if (static_cast(guid["name"]) != "EFI_SMM_CPU_PROTOCOL_GUID") continue; ea_t address = static_cast(guid["address"]); - msg("[%s] found EFI_SMM_CPU_PROTOCOL: 0x%016llX\n", g_plugin_name, - u64_addr(address)); - ea_list_t guidXrefs = efi_utils::get_xrefs(address); + efi_utils::log("found EFI_SMM_CPU_PROTOCOL at 0x%016llX\n", + u64_addr(address)); + ea_list_t guid_xrefs = efi_utils::get_xrefs(address); - for (auto guidXref : guidXrefs) { - segment_t *seg = getseg(static_cast(guidXref)); + for (auto guid_xref : guid_xrefs) { + segment_t *seg = getseg(static_cast(guid_xref)); qstring seg_name; get_segm_name(&seg_name, seg); size_t index = seg_name.find(".text"); if (index == std::string::npos) { continue; } - code_addrs.push_back(static_cast(guidXref)); + code_addrs.push_back(static_cast(guid_xref)); } } for (auto addr : code_addrs) { - msg("[%s] current address: 0x%016llX\n", g_plugin_name, u64_addr(addr)); insn_t insn; ea_t ea = prev_head(addr, 0); for (auto i = 0; i < 8; i++) { - // Find 'lea r8, ' instruction + // find 'lea r8, {gSmmCpu}' instruction decode_insn(&insn, ea); if (insn.itype == NN_lea && insn.ops[0].type == o_reg && insn.ops[0].reg == R_R8 && insn.ops[1].type == o_mem) { - msg("[%s] gSmmCpu address: 0x%016llX\n", g_plugin_name, - u64_addr(insn.ops[1].addr)); + efi_utils::log("gSmmCpu: 0x%016llX\n", u64_addr(insn.ops[1].addr)); efi_utils::set_ptr_type_and_name(insn.ops[1].addr, "gSmmCpu", "EFI_SMM_CPU_PROTOCOL"); - gSmmCpuAddrs.push_back(insn.ops[1].addr); + smm_cpu_addrs.push_back(insn.ops[1].addr); break; } ea = prev_head(ea, 0); } } - if (!gSmmCpuAddrs.size()) { - msg("[%s] can't find gSmmCpu addresses\n", g_plugin_name); - return readSaveStateCalls; + if (!smm_cpu_addrs.size()) { + efi_utils::log("gSmmCpu not found\n"); + return read_save_state_calls; } - for (auto smmCpu : gSmmCpuAddrs) { - ea_list_t smmCpuXrefs = efi_utils::get_xrefs(static_cast(smmCpu)); + for (auto smm_cpu_addr : smm_cpu_addrs) { + ea_list_t smm_cpu_xrefs = efi_utils::get_xrefs(smm_cpu_addr); - for (auto smmCpuXref : smmCpuXrefs) { - segment_t *seg = getseg(static_cast(smmCpuXref)); + for (auto smm_cpu_xref : smm_cpu_xrefs) { + segment_t *seg = getseg(smm_cpu_xref); qstring seg_name; get_segm_name(&seg_name, seg); size_t index = seg_name.find(".text"); @@ -561,40 +556,38 @@ ea_list_t resolveEfiSmmCpuProtocol(json_list_t stackGuids, continue; } - uint16_t gSmmCpuReg = 0xffff; + uint16_t smm_cpu_reg = NONE_REG; insn_t insn; - ea_t ea = static_cast(smmCpuXref); + ea_t ea = smm_cpu_xref; decode_insn(&insn, ea); if (insn.itype == NN_mov && insn.ops[0].type == o_reg && insn.ops[1].type == o_mem) { - gSmmCpuReg = insn.ops[0].reg; + smm_cpu_reg = insn.ops[0].reg; for (auto i = 0; i < 16; i++) { ea = next_head(ea, BADADDR); decode_insn(&insn, ea); - if (insn.itype == NN_callni && gSmmCpuReg == insn.ops[0].reg && + if (insn.itype == NN_callni && smm_cpu_reg == insn.ops[0].reg && insn.ops[0].addr == 0) { - if (find(readSaveStateCalls.begin(), readSaveStateCalls.end(), - ea) == readSaveStateCalls.end()) { - readSaveStateCalls.push_back(ea); + if (find(read_save_state_calls.begin(), read_save_state_calls.end(), + ea) == read_save_state_calls.end()) { + read_save_state_calls.push_back(ea); } efi_utils::op_stroff(ea, "EFI_SMM_CPU_PROTOCOL"); - msg("[%s] 0x%016llX : %s\n", g_plugin_name, u64_addr(ea), - "gSmmCpu->ReadSaveState"); - std::string smm_call = "gSmmCpu->ReadSaveState"; - json smm_item; - smm_item["address"] = ea; - smm_item["service_name"] = smm_call; - smm_item["table_name"] = - static_cast("EFI_SMM_CPU_PROTOCOL"); - smm_item["offset"] = 0; - - if (find(m_all_services->begin(), m_all_services->end(), - smm_item) == m_all_services->end()) { - m_all_services->push_back(smm_item); + efi_utils::log("gSmmCpu->ReadSaveState: 0x%016llX\n", u64_addr(ea)); + + json service; + service["address"] = ea; + service["service_name"] = "gSmmCpu->ReadSaveState"; + service["table_name"] = "EFI_SMM_CPU_PROTOCOL"; + service["offset"] = 0; + + if (find(all_services->begin(), all_services->end(), service) == + all_services->end()) { + all_services->push_back(service); } break; @@ -603,10 +596,10 @@ ea_list_t resolveEfiSmmCpuProtocol(json_list_t stackGuids, } } } - return readSaveStateCalls; + return read_save_state_calls; } -ea_t markChildSwSmiHandler(ea_t ea) { +ea_t efi_smm_utils::mark_child_sw_smi_handlers(ea_t ea) { insn_t insn; auto addr = prev_head(ea, 0); decode_insn(&insn, addr); diff --git a/efiXplorer/efi_smm_utils.h b/efiXplorer/efi_smm_utils.h index ca5d8c2e..39506aba 100644 --- a/efiXplorer/efi_smm_utils.h +++ b/efiXplorer/efi_smm_utils.h @@ -22,15 +22,17 @@ #include "efi_utils.h" #include -ea_list_t findSmstSwDispatch(ea_list_t bs_list); -ea_list_t findSmstSmmBase(ea_list_t bs_list); -func_list_t findSmiHandlers(ea_t address, std::string prefix); -func_list_t findSmiHandlersSmmDispatch(efi_guid_t guid, std::string prefix); -func_list_t findSmiHandlersSmmDispatchStack(json_list_t stackGuids, - std::string prefix); -ea_list_t findSmmGetVariableCalls(segment_list_t dataSegments, - json_list_t *m_all_services); -ea_list_t resolveEfiSmmCpuProtocol(json_list_t stackGuids, - json_list_t dataGuids, - json_list_t *m_all_services); -ea_t markChildSwSmiHandler(ea_t ea); +namespace efi_smm_utils { +ea_list_t find_smst_sw_dispatch(ea_list_t bs_list); +ea_list_t find_smst_smm_base(ea_list_t bs_list); +func_list_t find_smi_handlers(ea_t address, std::string prefix); +func_list_t find_smi_handlers_dispatch(efi_guid_t guid, std::string prefix); +func_list_t find_smi_handlers_dispatch_stack(json_list_t stack_guids, + std::string prefix); +ea_list_t find_smm_get_variable_calls(segment_list_t data_segs, + json_list_t *all_services); +ea_list_t resolve_efi_smm_cpu_protocol(json_list_t stack_guids, + json_list_t data_guids, + json_list_t *all_services); +ea_t mark_child_sw_smi_handlers(ea_t ea); +} // namespace efi_smm_utils diff --git a/efiXplorer/efi_ui.cc b/efiXplorer/efi_ui.cc index 638274c2..ce581fce 100644 --- a/efiXplorer/efi_ui.cc +++ b/efiXplorer/efi_ui.cc @@ -204,8 +204,8 @@ void idaapi s_chooser_t::get_row(qstrvec_t *cols_, int *, ea_t ea = list[n]; qstrvec_t &cols = *cols_; json item = chooser_s[n]; - std::string service_name = static_cast(item["service_name"]); - std::string table_name = static_cast(item["table_name"]); + std::string service_name = item["service_name"]; + std::string table_name = item["table_name"]; cols[0].sprnt("%016llX", u64_addr(ea)); cols[1].sprnt("%s", service_name.c_str()); cols[2].sprnt("%s", table_name.c_str()); diff --git a/efiXplorer/efi_utils.cc b/efiXplorer/efi_utils.cc index f3b0a7a8..ba34bc28 100644 --- a/efiXplorer/efi_utils.cc +++ b/efiXplorer/efi_utils.cc @@ -737,7 +737,7 @@ xreflist_t efi_utils::xrefs_to_stack_var(ea_t func_addr, qstring var_name) { #if IDA_SDK_VERSION < 900 struc_t *frame = get_frame(func_addr); func_t *func = get_func(func_addr); - member_t member; // Get member by name + member_t member; // get member by name for (int i = 0; i < frame->memqty; i++) { member = frame->members[i]; qstring name; @@ -966,7 +966,7 @@ std::string efi_utils::get_table_name(std::string service_name) { } } - return "unknown"; + return "Unknown"; } std::string efi_utils::lookup_boot_service_name(uint64_t offset) { @@ -976,7 +976,7 @@ std::string efi_utils::lookup_boot_service_name(uint64_t offset) { } } - return "unknown"; + return "Unknown"; } std::string efi_utils::lookup_runtime_service_name(uint64_t offset) { @@ -986,7 +986,7 @@ std::string efi_utils::lookup_runtime_service_name(uint64_t offset) { } } - return "unknown"; + return "Unknown"; } uint16_t get_machine_type() { From e2cde228a42079f0ea9aa22629114323d094fa50 Mon Sep 17 00:00:00 2001 From: yeggor Date: Wed, 18 Sep 2024 20:51:31 +0100 Subject: [PATCH 36/69] efi_utils: fix guid validation function --- efiXplorer/efi_analysis_x86.cc | 8 ++++---- efiXplorer/efi_utils.cc | 3 ++- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/efiXplorer/efi_analysis_x86.cc b/efiXplorer/efi_analysis_x86.cc index ff9224c1..7d4bb4b7 100644 --- a/efiXplorer/efi_analysis_x86.cc +++ b/efiXplorer/efi_analysis_x86.cc @@ -1113,7 +1113,7 @@ void efi_analysis::efi_analyser_x86_t::get_ppi_names32() { u64_addr(guidCodeAddress)); auto guid = efi_utils::get_guid_by_address(guidDataAddress); if (!efi_utils::valid_guid(guid)) { - msg("[%s] Incorrect GUID at 0x%016llX\n", g_plugin_name, + msg("[%s] incorrect GUID at 0x%016llX\n", g_plugin_name, u64_addr(guidCodeAddress)); continue; } @@ -1486,7 +1486,7 @@ void efi_analysis::efi_analyser_x86_t::get_bs_prot_names64() { g_plugin_name, u64_addr(guidCodeAddress)); auto guid = efi_utils::get_guid_by_address(guidDataAddress); if (!efi_utils::valid_guid(guid)) { - msg("[%s] Incorrect GUID at 0x%016llX\n", g_plugin_name, + msg("[%s] incorrect GUID at 0x%016llX\n", g_plugin_name, u64_addr(guidCodeAddress)); continue; } @@ -1559,7 +1559,7 @@ void efi_analysis::efi_analyser_x86_t::get_bs_prot_names32() { g_plugin_name, u64_addr(guidCodeAddress)); auto guid = efi_utils::get_guid_by_address(guidDataAddress); if (!efi_utils::valid_guid(guid)) { - msg("[%s] Incorrect GUID at 0x%016llX\n", g_plugin_name, + msg("[%s] incorrect GUID at 0x%016llX\n", g_plugin_name, u64_addr(guidCodeAddress)); continue; } @@ -1621,7 +1621,7 @@ void efi_analysis::efi_analyser_x86_t::get_smm_prot_names64() { g_plugin_name, u64_addr(guidCodeAddress)); auto guid = efi_utils::get_guid_by_address(guidDataAddress); if (!efi_utils::valid_guid(guid)) { - msg("[%s] Incorrect GUID at 0x%016llX\n", g_plugin_name, + msg("[%s] incorrect GUID at 0x%016llX\n", g_plugin_name, u64_addr(guidCodeAddress)); continue; } diff --git a/efiXplorer/efi_utils.cc b/efiXplorer/efi_utils.cc index ba34bc28..fe77efe9 100644 --- a/efiXplorer/efi_utils.cc +++ b/efiXplorer/efi_utils.cc @@ -545,7 +545,8 @@ bool efi_utils::valid_guid(json guid) { auto data0 = static_cast(guid[0]); auto data1 = static_cast(guid[1]); - return (!data0 && !data1) || (data0 == 0xffffffff && data1 == 0xffff); + auto invalid = (!data0 && !data1) || (data0 == 0xffffffff && data1 == 0xffff); + return !invalid; } //-------------------------------------------------------------------------- From 2a95252b74826de3b4f868af01a30467d9bb4038 Mon Sep 17 00:00:00 2001 From: yeggor Date: Wed, 18 Sep 2024 20:55:07 +0100 Subject: [PATCH 37/69] revert titles in efi_analyser_arm_t::show_all_choosers --- efiXplorer/efi_analysis_arm.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/efiXplorer/efi_analysis_arm.cc b/efiXplorer/efi_analysis_arm.cc index a8e2af2b..224d907b 100644 --- a/efiXplorer/efi_analysis_arm.cc +++ b/efiXplorer/efi_analysis_arm.cc @@ -432,19 +432,19 @@ void efi_analysis::efi_analyser_arm_t::show_all_choosers() { // open window with all services if (m_all_services.size()) { - title = "efi: services"; + title = "efiXplorer: services"; services_show(m_all_services, title); } // open window with data guids if (m_all_guids.size()) { - qstring title = "efi: GUIDs"; + qstring title = "efiXplorer: GUIDs"; guids_show(m_all_guids, title); } // open window with protocols if (m_all_protocols.size()) { - title = "efi: protocols"; + title = "efiXplorer: protocols"; protocols_show(m_all_protocols, title); } } From 2e1ee97f6ad53eb40486f56059ba46608b91b803 Mon Sep 17 00:00:00 2001 From: yeggor Date: Thu, 19 Sep 2024 04:05:56 +0100 Subject: [PATCH 38/69] refactor efi_ui, efi_deps --- efiXplorer/efi_analysis_arm.cc | 6 +- efiXplorer/efi_analysis_x86.cc | 20 +-- efiXplorer/efi_defs.h | 2 + efiXplorer/efi_deps.cc | 238 +++++++++++++++++---------------- efiXplorer/efi_deps.h | 64 ++++----- efiXplorer/efi_global.cc | 2 +- efiXplorer/efi_global.h | 2 +- efiXplorer/efi_ui.cc | 181 ++++++++++++------------- efiXplorer/efi_ui.h | 30 ++--- 9 files changed, 274 insertions(+), 271 deletions(-) diff --git a/efiXplorer/efi_analysis_arm.cc b/efiXplorer/efi_analysis_arm.cc index 224d907b..aa60bf82 100644 --- a/efiXplorer/efi_analysis_arm.cc +++ b/efiXplorer/efi_analysis_arm.cc @@ -433,19 +433,19 @@ void efi_analysis::efi_analyser_arm_t::show_all_choosers() { // open window with all services if (m_all_services.size()) { title = "efiXplorer: services"; - services_show(m_all_services, title); + show_services(m_all_services, title); } // open window with data guids if (m_all_guids.size()) { qstring title = "efiXplorer: GUIDs"; - guids_show(m_all_guids, title); + show_guids(m_all_guids, title); } // open window with protocols if (m_all_protocols.size()) { title = "efiXplorer: protocols"; - protocols_show(m_all_protocols, title); + show_protocols(m_all_protocols, title); } } diff --git a/efiXplorer/efi_analysis_x86.cc b/efiXplorer/efi_analysis_x86.cc index 7d4bb4b7..32f1eeec 100644 --- a/efiXplorer/efi_analysis_x86.cc +++ b/efiXplorer/efi_analysis_x86.cc @@ -2602,32 +2602,32 @@ void efi_analysis::efi_analyser_x86_t::show_all_choosers() { // open window with all services if (m_all_services.size()) { title = "efiXplorer: services"; - services_show(m_all_services, title); + show_services(m_all_services, title); } // open window with protocols if (m_ftype == ffs_file_type_t::pei) { if (m_all_ppis.size()) { title = "efiXplorer: PPIs"; - ppis_show(m_all_ppis, title); + show_ppis(m_all_ppis, title); } } else { // ffs_file_type_t::dxe_smm if (m_all_protocols.size()) { title = "efiXplorer: protocols"; - protocols_show(m_all_protocols, title); + show_protocols(m_all_protocols, title); } } // open window with data guids if (m_all_guids.size()) { qstring title = "efiXplorer: GUIDs"; - guids_show(m_all_guids, title); + show_guids(m_all_guids, title); } // open window with NVRAM variables if (m_nvram_variables.size()) { qstring title = "efiXplorer: NVRAM"; - nvram_show(m_nvram_variables, title); + show_nvram(m_nvram_variables, title); } // open window with vulnerabilities @@ -2650,7 +2650,7 @@ void efi_analysis::efi_analyser_x86_t::show_all_choosers() { } qstring title = "efiXplorer: vulns"; - vulns_show(vulns, title); + show_vulns(vulns, title); } } @@ -2766,12 +2766,12 @@ bool efi_analysis::efi_analyse_main_x86_64() { if (analyser.m_arch == arch_file_type_t::uefi) { // Init public EdiDependencies members - g_deps.getProtocolsChooser(analyser.m_all_protocols); - g_deps.getProtocolsByGuids(analyser.m_all_protocols); + g_deps.get_protocols_chooser(analyser.m_all_protocols); + g_deps.get_protocols_by_guids(analyser.m_all_protocols); // Save all protocols information to build dependencies - attachActionProtocolsDeps(); - attachActionModulesSeq(); + attach_action_protocols_deps(); + attach_action_modules_seq(); } hide_wait_box(); diff --git a/efiXplorer/efi_defs.h b/efiXplorer/efi_defs.h index 653b1fd2..49cab6e5 100644 --- a/efiXplorer/efi_defs.h +++ b/efiXplorer/efi_defs.h @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -169,6 +170,7 @@ using func_list_t = std::vector; using json_list_t = std::vector; using segment_list_t = std::vector; using string_list_t = std::vector; +using string_set_t = std::set; using uchar_list_t = std::vector; using uint64_list_t = std::vector; using uint8_list_t = std::vector; diff --git a/efiXplorer/efi_deps.cc b/efiXplorer/efi_deps.cc index 7464d0df..18e7989d 100644 --- a/efiXplorer/efi_deps.cc +++ b/efiXplorer/efi_deps.cc @@ -19,35 +19,35 @@ #include "efi_deps.h" -EfiDependencies::EfiDependencies() { - // Read DEPEX (for protocols) from +efi_deps_t::efi_deps_t() { + // read DEPEX (for protocols) from // .deps.json file if this file exists - loadDepsFromUefiTool(); - // Get images names from IDB - getImages(); - // Read images with GUIDs from + load_deps_from_uefitool(); + // get modules names from IDB + get_modules(); + // read modules with GUIDs from // .images.json file if this file exists - loadImagesWithGuids(); + load_modules_with_guids(); } -EfiDependencies::~EfiDependencies() { - imagesInfo.clear(); - imagesGuids.clear(); - imagesFromIdb.clear(); - uefitoolDeps.clear(); - modulesSequence.clear(); - protocolsChooser.clear(); - protocolsByGuids.clear(); - additionalInstallers.clear(); - protocolsWithoutInstallers.clear(); +efi_deps_t::~efi_deps_t() { + m_modules_info.clear(); + m_modules_guids.clear(); + m_modules_from_idb.clear(); + m_uefitool_deps.clear(); + m_modules_sequence.clear(); + m_protocols_chooser.clear(); + m_protocols_by_guids.clear(); + m_additional_installers.clear(); + m_protocols_without_installers.clear(); } -json EfiDependencies::getDeps(std::string guid) { +json efi_deps_t::get_deps_for(std::string guid) { json res; std::vector installers({"InstallProtocolInterface", "InstallMultipleProtocolInterfaces", "SmmInstallProtocolInterface"}); - for (auto &it : protocolsChooser.items()) { + for (auto &it : m_protocols_chooser.items()) { auto p = it.value(); if (p["guid"] != guid) { continue; @@ -66,26 +66,26 @@ json EfiDependencies::getDeps(std::string guid) { return res; } -void EfiDependencies::getProtocolsByGuids(json_list_t protocols) { +void efi_deps_t::get_protocols_by_guids(json_list_t protocols) { for (auto p : protocols) { // check if entry for GUID already exist std::string guid = p["guid"]; - auto deps = protocolsByGuids[guid]; + auto deps = m_protocols_by_guids[guid]; if (deps.is_null()) { - protocolsByGuids[guid] = getDeps(guid); + m_protocols_by_guids[guid] = get_deps_for(guid); } } } -void EfiDependencies::getProtocolsChooser(json_list_t protocols) { +void efi_deps_t::get_protocols_chooser(json_list_t protocols) { auto i = 0; for (auto p : protocols) { - protocolsChooser[i] = p; + m_protocols_chooser[i] = p; ++i; } } -bool EfiDependencies::loadDepsFromUefiTool() { +bool efi_deps_t::load_deps_from_uefitool() { std::filesystem::path deps_json; deps_json /= get_path(PATH_TYPE_IDB); deps_json.replace_extension(".deps.json"); @@ -93,11 +93,11 @@ bool EfiDependencies::loadDepsFromUefiTool() { return false; } std::ifstream file(deps_json); - file >> uefitoolDeps; + file >> m_uefitool_deps; return true; } -bool EfiDependencies::loadImagesWithGuids() { +bool efi_deps_t::load_modules_with_guids() { std::filesystem::path images_json; images_json /= get_path(PATH_TYPE_IDB); images_json.replace_extension(".images.json"); @@ -105,44 +105,41 @@ bool EfiDependencies::loadImagesWithGuids() { return false; } std::ifstream file(images_json); - file >> imagesGuids; + file >> m_modules_guids; return true; } -bool EfiDependencies::installerFound(std::string protocol) { - auto deps_prot = protocolsByGuids[protocol]; +bool efi_deps_t::installer_found(std::string protocol) { + auto deps_prot = m_protocols_by_guids[protocol]; if (deps_prot.is_null()) { return false; } auto installers = deps_prot["installed"]; - if (installers.is_null()) { - return false; - } - return true; + return installers.is_null(); } -void EfiDependencies::getProtocolsWithoutInstallers() { - // Check DXE_DEPEX and MM_DEPEX +void efi_deps_t::get_protocols_without_installers() { + // check DXE_DEPEX and MM_DEPEX string_list_t sections{"EFI_SECTION_DXE_DEPEX", "EFI_SECTION_MM_DEPEX"}; for (auto section : sections) { - auto images = uefitoolDeps[section]; + auto images = m_uefitool_deps[section]; for (auto &element : images.items()) { auto protocols = element.value(); for (auto p : protocols) { std::string ps = static_cast(p); - if (!installerFound(ps)) { - protocolsWithoutInstallers.insert(ps); + if (!installer_found(ps)) { + m_protocols_without_installers.insert(ps); } } } } } -void EfiDependencies::getInstallersModules() { +void efi_deps_t::get_installers_modules() { // search for this protocols in binary - for (auto &protocol : protocolsWithoutInstallers) { + for (auto &protocol : m_protocols_without_installers) { auto addrs = efi_utils::search_protocol(protocol); - bool installerFound = false; + bool installer_found = false; for (auto addr : addrs) { auto xrefs = efi_utils::get_xrefs(addr); if (!xrefs.size()) { @@ -157,41 +154,40 @@ void EfiDependencies::getInstallersModules() { for (auto ea : xrefs) { if (efi_utils::check_install_protocol(ea)) { auto module = efi_utils::get_module_name_loader(ea); - additionalInstallers[protocol] = + m_additional_installers[protocol] = static_cast(module.c_str()); - installerFound = true; + installer_found = true; break; } } - if (installerFound) { + if (installer_found) { break; } } - if (!installerFound) { - untrackedProtocols.insert(protocol); + if (!installer_found) { + m_untracked_protocols.insert(protocol); } } } -void EfiDependencies::getAdditionalInstallers() { - getProtocolsWithoutInstallers(); - getInstallersModules(); - std::string installers = additionalInstallers.dump(2); - msg("Additional installers: %s\n", installers.c_str()); - msg("Untracked protocols:\n"); - for (auto &protocol : untrackedProtocols) { - msg("%s\n", protocol.c_str()); +void efi_deps_t::get_additional_installers() { + get_protocols_without_installers(); + get_installers_modules(); + std::string installers = m_additional_installers.dump(2); + efi_utils::log("additional installers: %s\n", installers.c_str()); + for (auto &protocol : m_untracked_protocols) { + efi_utils::log("untracked protocol: %s\n", protocol.c_str()); } } -void EfiDependencies::getImages() { +void efi_deps_t::get_modules() { for (segment_t *s = get_first_seg(); s != nullptr; s = get_next_seg(s->start_ea)) { qstring seg_name; get_segm_name(&seg_name, s); - string_list_t codeSegNames{"_.text", "_.code"}; - for (auto name : codeSegNames) { + string_list_t cseg_names{"_.text", "_.code"}; + for (auto name : cseg_names) { auto index = seg_name.find(name.c_str()); if (index != std::string::npos) { std::string image_name = @@ -199,31 +195,32 @@ void EfiDependencies::getImages() { if (!image_name.rfind("_", 0)) { image_name = image_name.erase(0, 1); } - imagesFromIdb.push_back(image_name); + m_modules_from_idb.push_back(image_name); } } } } -json EfiDependencies::getImageInfo(std::string image) { +json efi_deps_t::get_module_info(std::string image) { json info; - string_list_t installedProtocols; - json depsProtocols; + json deps_protocols; + string_list_t installed_protocols; std::vector installers({"InstallProtocolInterface", "InstallMultipleProtocolInterfaces", "SmmInstallProtocolInterface"}); - // Get installed protocols - for (auto &p : additionalInstallers.items()) { // check additional installers - std::string adInstImage = p.value(); - std::string adInstProtocol = p.key(); - if (adInstImage == image) { - installedProtocols.push_back(adInstProtocol); + // get installed protocols + for (auto &p : + m_additional_installers.items()) { // check additional installers + std::string ad_installer_image = p.value(); + std::string ad_installer_protocol = p.key(); + if (ad_installer_image == image) { + installed_protocols.push_back(ad_installer_protocol); break; } } - for (auto &element : protocolsChooser.items()) { // check efiXplorer report + for (auto &element : m_protocols_chooser.items()) { // check efiXplorer report json p = element.value(); std::string image_name = p["module"]; if (!image_name.rfind("_", 0)) { @@ -234,24 +231,24 @@ json EfiDependencies::getImageInfo(std::string image) { } if (find(installers.begin(), installers.end(), p["service"]) != installers.end()) { - installedProtocols.push_back(p["guid"]); + installed_protocols.push_back(p["guid"]); } } - // Get deps + // get dependencies bool found = false; string_list_t sections{"EFI_SECTION_DXE_DEPEX", "EFI_SECTION_MM_DEPEX"}; for (auto section : sections) { - json deps_images = uefitoolDeps[section]; + json deps_images = m_uefitool_deps[section]; for (auto &element : deps_images.items()) { std::string dimage_guid = element.key(); - if (imagesGuids[dimage_guid].is_null()) { - // Can not get name for image + if (m_modules_guids[dimage_guid].is_null()) { + // can not get name for image continue; } - std::string dimage_name = imagesGuids[dimage_guid]; + std::string dimage_name = m_modules_guids[dimage_guid]; if (dimage_name == image) { - depsProtocols = element.value(); + deps_protocols = element.value(); found = true; break; } @@ -261,27 +258,27 @@ json EfiDependencies::getImageInfo(std::string image) { } } - info["installed_protocols"] = installedProtocols; - info["deps_protocols"] = depsProtocols; + info["installed_protocols"] = installed_protocols; + info["deps_protocols"] = deps_protocols; return info; } -bool EfiDependencies::getImagesInfo() { - if (imagesInfo.size()) { +bool efi_deps_t::get_modules_info() { + if (m_modules_info.size()) { return true; } - for (auto image : imagesFromIdb) { - imagesInfo[image] = getImageInfo(image); + for (auto image : m_modules_from_idb) { + m_modules_info[image] = get_module_info(image); } return true; } -std::string EfiDependencies::getInstaller(std::string protocol) { +std::string efi_deps_t::get_installer(std::string protocol) { std::string res; - for (auto &e : imagesInfo.items()) { + for (auto &e : m_modules_info.items()) { std::string image = e.key(); - string_list_t installers = imagesInfo[image]["installed_protocols"]; + string_list_t installers = m_modules_info[image]["installed_protocols"]; if (find(installers.begin(), installers.end(), protocol) != installers.end()) { return image; @@ -290,53 +287,53 @@ std::string EfiDependencies::getInstaller(std::string protocol) { return res; } -bool EfiDependencies::buildModulesSequence() { - if (modulesSequence.size()) { +bool efi_deps_t::build_modules_sequence() { + if (m_modules_sequence.size()) { return true; } - std::set modulesSeq; - std::set installed_protocols; + string_set_t module_seq; + string_set_t installed_protocols; - getProtocolsWithoutInstallers(); // hard to find installers for all protocols - // in statiс - getImagesInfo(); + get_protocols_without_installers(); // hard to find installers for all + // protocols in statiс + get_modules_info(); size_t index = 0; - while (modulesSeq.size() != imagesInfo.size()) { + while (module_seq.size() != m_modules_info.size()) { bool changed = false; - for (auto &e : imagesInfo.items()) { + for (auto &e : m_modules_info.items()) { std::string image = e.key(); // current module // check if the image is already loaded - if (modulesSeq.find(image) != modulesSeq.end()) { + if (module_seq.find(image) != module_seq.end()) { continue; } - string_list_t installers = imagesInfo[image]["installed_protocols"]; + string_list_t installers = m_modules_info[image]["installed_protocols"]; // if there are no dependencies - if (imagesInfo[image]["deps_protocols"].is_null()) { + if (m_modules_info[image]["deps_protocols"].is_null()) { for (auto protocol : installers) { installed_protocols.insert(protocol); } - modulesSeq.insert(image); + module_seq.insert(image); json info; info["module"] = image; - modulesSequence[index++] = info; + m_modules_sequence[index++] = info; changed = true; continue; } - string_list_t deps = imagesInfo[image]["deps_protocols"]; + string_list_t deps = m_modules_info[image]["deps_protocols"]; string_list_t unresolved_deps; bool load = true; for (auto protocol : deps) { if (installed_protocols.find(protocol) != installed_protocols.end()) { continue; } - if (protocolsWithoutInstallers.find(protocol) != - protocolsWithoutInstallers.end()) { + if (m_protocols_without_installers.find(protocol) != + m_protocols_without_installers.end()) { unresolved_deps.push_back(protocol); continue; } @@ -348,14 +345,14 @@ bool EfiDependencies::buildModulesSequence() { for (auto protocol : installers) { installed_protocols.insert(protocol); } - modulesSeq.insert(image); + module_seq.insert(image); json info; info["image"] = image; info["deps"] = deps; if (unresolved_deps.size()) { info["unresolved_deps"] = unresolved_deps; } - modulesSequence[index++] = info; + m_modules_sequence[index++] = info; changed = true; } } @@ -364,25 +361,25 @@ bool EfiDependencies::buildModulesSequence() { // the most popular protocol std::map protocols_usage; // get the most popular protocol - for (auto &e : imagesInfo.items()) { + for (auto &e : m_modules_info.items()) { std::string image = e.key(); // check if the image is already loaded - if (modulesSeq.find(image) != modulesSeq.end()) { + if (module_seq.find(image) != module_seq.end()) { continue; } - if (imagesInfo[image]["deps_protocols"].is_null()) { + if (m_modules_info[image]["deps_protocols"].is_null()) { continue; } - string_list_t deps_protocols = imagesInfo[image]["deps_protocols"]; + string_list_t deps_protocols = m_modules_info[image]["deps_protocols"]; for (auto protocol : deps_protocols) { if (installed_protocols.find(protocol) != installed_protocols.end()) { continue; } - if (protocolsWithoutInstallers.find(protocol) != - protocolsWithoutInstallers.end()) { + if (m_protocols_without_installers.find(protocol) != + m_protocols_without_installers.end()) { continue; } if (protocols_usage.find(protocol) == protocols_usage.end()) { @@ -392,6 +389,7 @@ bool EfiDependencies::buildModulesSequence() { } } } + std::string mprotocol; size_t mnum = 0; for (auto const &[prot, counter] : protocols_usage) { @@ -400,26 +398,30 @@ bool EfiDependencies::buildModulesSequence() { mprotocol = static_cast(prot); } } + if (!mnum) { break; // the most popular protocol was not found } + // find installer module for mprotocol - std::string installer_image = getInstaller(mprotocol); + std::string installer_image = get_installer(mprotocol); if (!installer_image.size()) { - msg("Can not find installer for protocol %s\n", mprotocol.c_str()); - break; // something went wrong, extra mitigation for an infinite loop + efi_utils::log("can not find installer for protocol %s\n", + mprotocol.c_str()); + break; } - // load installer_image + + // load installer module string_list_t current_installers = - imagesInfo[installer_image]["installed_protocols"]; + m_modules_info[installer_image]["installed_protocols"]; for (auto protocol : current_installers) { installed_protocols.insert(protocol); } - modulesSeq.insert(installer_image); + module_seq.insert(installer_image); json info; info["image"] = installer_image; - info["deps"] = imagesInfo[installer_image]["deps_protocols"]; - modulesSequence[index++] = info; + info["deps"] = m_modules_info[installer_image]["deps_protocols"]; + m_modules_sequence[index++] = info; } } diff --git a/efiXplorer/efi_deps.h b/efiXplorer/efi_deps.h index 14e910c8..f1436ae3 100644 --- a/efiXplorer/efi_deps.h +++ b/efiXplorer/efi_deps.h @@ -21,41 +21,43 @@ #include "efi_utils.h" #include -#include #include -class EfiDependencies { +class efi_deps_t { public: - EfiDependencies(); - ~EfiDependencies(); + efi_deps_t(); + ~efi_deps_t(); - json protocolsByGuids; // protocols sorted by GUIDs - json protocolsChooser; // numbered json with protocols - json uefitoolDeps; - json imagesGuids; - json additionalInstallers; // getAdditionalInstallers result - json imagesInfo; // getImagesInfo result - json modulesSequence; // buildModulesSequence result - string_list_t imagesFromIdb; - std::set untrackedProtocols; - // Input: protocols from report - void getProtocolsByGuids(json_list_t protocols); - void getProtocolsChooser(json_list_t protocols); - json getDeps(std::string protocol); // get dependencies for specific protocol - void - getAdditionalInstallers(); // get installers by protocol GUIDs by searching in - // the firmware and analysing xrefs - bool buildModulesSequence(); - bool getImagesInfo(); + json m_additional_installers; + json m_modules_guids; + json m_modules_info; + json m_modules_sequence; + json m_protocols_by_guids; + json m_protocols_chooser; + json m_uefitool_deps; + string_list_t m_modules_from_idb; + string_set_t m_untracked_protocols; + + // input: protocols from report + void get_protocols_by_guids(json_list_t protocols); + void get_protocols_chooser(json_list_t protocols); + // get dependencies for specific protocol + json get_deps_for(std::string protocol); + // get installers by protocol GUIDs by searching + // in the firmware and analysing xrefs + void get_additional_installers(); + bool build_modules_sequence(); + bool get_modules_info(); private: - void getImages(); - std::set protocolsWithoutInstallers; - void getProtocolsWithoutInstallers(); - void getInstallersModules(); - bool loadDepsFromUefiTool(); - bool loadImagesWithGuids(); - bool installerFound(std::string protocol); - json getImageInfo(std::string image); - std::string getInstaller(std::string protocol); + string_set_t m_protocols_without_installers; + + void get_modules(); + void get_protocols_without_installers(); + void get_installers_modules(); + bool load_deps_from_uefitool(); + bool load_modules_with_guids(); + bool installer_found(std::string protocol); + json get_module_info(std::string image); + std::string get_installer(std::string protocol); }; diff --git a/efiXplorer/efi_global.cc b/efiXplorer/efi_global.cc index 8a566363..b4cbe431 100644 --- a/efiXplorer/efi_global.cc +++ b/efiXplorer/efi_global.cc @@ -20,4 +20,4 @@ #include "efi_global.h" #include "efi_deps.h" -EfiDependencies g_deps; +efi_deps_t g_deps; diff --git a/efiXplorer/efi_global.h b/efiXplorer/efi_global.h index 22e74f6e..6cf686bd 100644 --- a/efiXplorer/efi_global.h +++ b/efiXplorer/efi_global.h @@ -28,4 +28,4 @@ struct args_t { }; extern args_t g_args; -extern EfiDependencies g_deps; +extern efi_deps_t g_deps; diff --git a/efiXplorer/efi_ui.cc b/efiXplorer/efi_ui.cc index ce581fce..91f9329b 100644 --- a/efiXplorer/efi_ui.cc +++ b/efiXplorer/efi_ui.cc @@ -48,7 +48,7 @@ const char *const guids_chooser_t::header_guids[] = { }; // protocols column widths -const int protocols_chooser_t::widths_protocols[] = { +const int m_protocols_chooser_t::widths_protocols[] = { 16, // Address 32, // GUID 32, // Name @@ -57,7 +57,7 @@ const int protocols_chooser_t::widths_protocols[] = { }; // protocols column headers -const char *const protocols_chooser_t::header_protocols[] = { +const char *const m_protocols_chooser_t::header_protocols[] = { "Address", // 0 "GUID", // 1 "Name", // 2 @@ -66,14 +66,14 @@ const char *const protocols_chooser_t::header_protocols[] = { }; // services column widths -const int s_chooser_t::widths_s[] = { +const int services_chooser_t::widths_s[] = { 16, // Address 32, // Service name 32, // Table name }; // services column headers -const char *const s_chooser_t::header_s[] = { +const char *const services_chooser_t::header_s[] = { "Address", // 0 "Service name", // 1 "Table name" // 2 @@ -163,9 +163,9 @@ void idaapi guids_chooser_t::get_row(qstrvec_t *cols_, int *, CASSERT(qnumber(header_guids) == 3); } -inline protocols_chooser_t::protocols_chooser_t(const char *title_, bool ok, - json_list_t protocols, - std::string name_key_) +inline m_protocols_chooser_t::m_protocols_chooser_t(const char *title_, bool ok, + json_list_t protocols, + std::string name_key_) : chooser_t(0, qnumber(widths_protocols), widths_protocols, header_protocols, title_), list() { @@ -174,9 +174,9 @@ inline protocols_chooser_t::protocols_chooser_t(const char *title_, bool ok, build_list(ok, protocols); } -void idaapi protocols_chooser_t::get_row(qstrvec_t *cols_, int *, - chooser_item_attrs_t *, - size_t n) const { +void idaapi m_protocols_chooser_t::get_row(qstrvec_t *cols_, int *, + chooser_item_attrs_t *, + size_t n) const { ea_t ea = list[n]; qstrvec_t &cols = *cols_; json item = chooser_protocols[n]; @@ -192,15 +192,16 @@ void idaapi protocols_chooser_t::get_row(qstrvec_t *cols_, int *, CASSERT(qnumber(header_protocols) == 5); } -inline s_chooser_t::s_chooser_t(const char *title_, bool ok, - json_list_t services) +inline services_chooser_t::services_chooser_t(const char *title_, bool ok, + json_list_t services) : chooser_t(0, qnumber(widths_s), widths_s, header_s, title_), list() { CASSERT(qnumber(widths_s) == qnumber(header_s)); build_list(ok, services); } -void idaapi s_chooser_t::get_row(qstrvec_t *cols_, int *, - chooser_item_attrs_t *, size_t n) const { +void idaapi services_chooser_t::get_row(qstrvec_t *cols_, int *, + chooser_item_attrs_t *, + size_t n) const { ea_t ea = list[n]; qstrvec_t &cols = *cols_; json item = chooser_s[n]; @@ -212,7 +213,7 @@ void idaapi s_chooser_t::get_row(qstrvec_t *cols_, int *, CASSERT(qnumber(header_s) == 3); } -bool nvram_show(json_list_t nvram, qstring title) { +bool show_nvram(json_list_t nvram, qstring title) { bool ok; // open the window nvram_chooser_t *ch = new nvram_chooser_t(title.c_str(), ok, nvram); @@ -221,7 +222,7 @@ bool nvram_show(json_list_t nvram, qstring title) { return true; } -bool vulns_show(json_list_t vulns, qstring title) { +bool show_vulns(json_list_t vulns, qstring title) { bool ok; // open the window vulns_chooser_t *ch = new vulns_chooser_t(title.c_str(), ok, vulns); @@ -230,7 +231,7 @@ bool vulns_show(json_list_t vulns, qstring title) { return true; } -bool guids_show(json_list_t guids, qstring title) { +bool show_guids(json_list_t guids, qstring title) { bool ok; // open the window guids_chooser_t *ch = new guids_chooser_t(title.c_str(), ok, guids); @@ -239,41 +240,41 @@ bool guids_show(json_list_t guids, qstring title) { return true; } -bool protocols_show(json_list_t protocols, qstring title) { +bool show_protocols(json_list_t protocols, qstring title) { bool ok; // open the window - protocols_chooser_t *ch = - new protocols_chooser_t(title.c_str(), ok, protocols, "prot_name"); + m_protocols_chooser_t *ch = + new m_protocols_chooser_t(title.c_str(), ok, protocols, "prot_name"); // default cursor position is 0 (first row) ch->choose(); return true; } -bool ppis_show(json_list_t ppis, qstring title) { +bool show_ppis(json_list_t ppis, qstring title) { bool ok; // open the window - protocols_chooser_t *ch = - new protocols_chooser_t(title.c_str(), ok, ppis, "ppi_name"); + m_protocols_chooser_t *ch = + new m_protocols_chooser_t(title.c_str(), ok, ppis, "ppi_name"); // default cursor position is 0 (first row) ch->choose(); return true; } -bool services_show(json_list_t services, qstring title) { +bool show_services(json_list_t services, qstring title) { bool ok; // open the window - s_chooser_t *ch = new s_chooser_t(title.c_str(), ok, services); + services_chooser_t *ch = new services_chooser_t(title.c_str(), ok, services); // default cursor position is 0 (first row) ch->choose(); return true; } //------------------------------------------------------------------------- -// Action handler for protocols dependencies +// action handler for protocols dependencies struct protocols_deps_handler_t : public action_handler_t { virtual int idaapi activate(action_activation_ctx_t *ctx) { auto n = ctx->chooser_selection.at(0); - json info = g_deps.protocolsChooser[n]; + json info = g_deps.m_protocols_chooser[n]; if (info.is_null()) { return -1; // protocol not found @@ -281,13 +282,12 @@ struct protocols_deps_handler_t : public action_handler_t { // get dependencies for protocol std::string guid = info["guid"]; - json d = g_deps.protocolsByGuids[guid]; + json d = g_deps.m_protocols_by_guids[guid]; - // print dependencies for current - // protocol in output window + // print dependencies for current protocol in output window std::string s = d.dump(2); - msg("[%s] dependencies for protocol with GUID %s: %s\n", g_plugin_name, - guid.c_str(), s.c_str()); + efi_utils::log("dependencies for protocol with GUID %s: %s\n", guid.c_str(), + s.c_str()); return 0; } @@ -299,14 +299,14 @@ struct protocols_deps_handler_t : public action_handler_t { static protocols_deps_handler_t protocols_deps_ah; action_desc_t protocols_deps = - ACTION_DESC_LITERAL("efiXplorer:protocolsDeps", "Show dependencies", + ACTION_DESC_LITERAL("efiXplorer:dependencies", "Show dependencies", &protocols_deps_ah, nullptr, nullptr, -1); -void attachActionProtocolsDeps() { - // Attach action in protocols chooser +void attach_action_protocols_deps() { + // attach action in protocols chooser TWidget *widget = find_widget("efiXplorer: protocols"); if (widget == nullptr) { - msg("[%s] can not find efiXplorer: protocols chooser", g_plugin_name); + efi_utils::log("can not find protocols chooser"); return; } register_action(protocols_deps); @@ -314,12 +314,12 @@ void attachActionProtocolsDeps() { } //------------------------------------------------------------------------- -// Action handler for showing the sequence of modules execution +// action handler for showing the sequence of modules execution struct modules_seq_handler_t : public action_handler_t { virtual int idaapi activate(action_activation_ctx_t *ctx) { - g_deps.buildModulesSequence(); - std::string s = g_deps.modulesSequence.dump(2); - msg("[%s] sequence of modules execution: %s\n", g_plugin_name, s.c_str()); + g_deps.build_modules_sequence(); + std::string s = g_deps.m_modules_sequence.dump(2); + efi_utils::log("sequence of modules execution: %s\n", s.c_str()); return 0; } @@ -331,14 +331,14 @@ struct modules_seq_handler_t : public action_handler_t { static modules_seq_handler_t modules_seq_ah; action_desc_t modules_seq = ACTION_DESC_LITERAL( - "efiXplorer:modulesSeq", "Show the sequence of modules execution", + "efiXplorer:modules", "Show the sequence of modules execution", &modules_seq_ah, nullptr, nullptr, -1); -void attachActionModulesSeq() { - // Attach action in protocols chooser +void attach_action_modules_seq() { + // attach action in protocols chooser TWidget *widget = find_widget("efiXplorer: protocols"); if (widget == nullptr) { - msg("[%s] can not find efiXplorer: protocols chooser", g_plugin_name); + efi_utils::log("can not find protocols chooser"); return; } register_action(modules_seq); @@ -349,90 +349,87 @@ void attachActionModulesSeq() { // Action handler (load efiXplorer analysis report) struct action_handler_loadreport_t : public action_handler_t { virtual int idaapi activate(action_activation_ctx_t *ctx) { - std::filesystem::path reportPath; + std::filesystem::path summary_path; char *file = ask_file(false, "*.json", "Load efiXplorer analysis report"); if (file == nullptr) { - msg("[%s] report file not specified\n", g_plugin_name); + efi_utils::log("analysis report file is not specified\n"); return -1; } - reportPath /= file; - msg("[%s] loading report from %s file\n", g_plugin_name, - reportPath.c_str()); + summary_path /= file; + efi_utils::log("loading report from %s file\n", summary_path.c_str()); - json reportData; + json summary; try { - std::ifstream in(reportPath); - in >> reportData; + std::ifstream in(summary_path); + in >> summary; } catch (std::exception &e) { - msg("[%s] report file is invalid, check its contents\n", g_plugin_name); + efi_utils::log("report file is invalid\n"); return -1; } - // Initialize vuln types list - string_list_t vulnTypes{"smm_callout", "pei_get_variable_buffer_overflow", - "get_variable_buffer_overflow", - "smm_get_variable_buffer_overflow"}; + // initialise vuln types list + string_list_t vuln_types{"smm_callout", "pei_get_variable_buffer_overflow", + "get_variable_buffer_overflow", + "smm_get_variable_buffer_overflow"}; - // Show all choosers with data from report + // show all choosers with data from report qstring title; try { - auto protocols = reportData["all_protocols"]; + auto protocols = summary["all_protocols"]; if (!protocols.is_null()) { // show protocols title = "efiXplorer: protocols"; - protocols_show(protocols, title); + show_protocols(protocols, title); } - auto ppis = reportData["all_ppis"]; + auto ppis = summary["all_ppis"]; if (!ppis.is_null()) { // show PPIs title = "efiXplorer: PPIs"; - protocols_show(ppis, title); + show_protocols(ppis, title); } - auto services = reportData["all_services"]; + auto services = summary["all_services"]; if (!services.is_null()) { // show services title = "efiXplorer: services"; - services_show(services, title); + show_services(services, title); } - auto guids = reportData["all_guids"]; + auto guids = summary["all_guids"]; if (!guids.is_null()) { // show GUIDs title = "efiXplorer: GUIDs"; - guids_show(guids, title); + show_guids(guids, title); } - auto nvram = reportData["m_nvram_variables"]; + auto nvram = summary["m_nvram_variables"]; if (!nvram.is_null()) { // show NVRAM title = "efiXplorer: NVRAM"; - nvram_show(nvram, title); + show_nvram(nvram, title); } - auto vulns = reportData["vulns"]; + auto vulns = summary["vulns"]; if (!vulns.is_null()) { // show vulns - json_list_t vulnsRes; - for (auto vulnType : vulnTypes) { - // For each vuln type add list of vulns in `vulnsRes` - auto vulnAddrs = vulns[vulnType]; - if (vulnAddrs.is_null()) { + json_list_t vulns_res; + for (auto vuln_type : vuln_types) { + auto vuln_addr = vulns[vuln_type]; + if (vuln_addr.is_null()) { continue; } - for (auto addr : vulnAddrs) { - json item; - item["type"] = vulnType; - item["address"] = addr; - vulnsRes.push_back(item); + for (auto addr : vuln_addr) { + json vuln; + vuln["type"] = vuln_type; + vuln["address"] = addr; + vulns_res.push_back(vuln); } } - if (vulnsRes.size()) { + if (vulns_res.size()) { title = "efiXplorer: vulns"; - vulns_show(vulnsRes, title); + show_vulns(vulns_res, title); } } - // Init public EdiDependencies members - g_deps.getProtocolsChooser(protocols); - g_deps.getProtocolsByGuids(protocols); + g_deps.get_protocols_chooser(protocols); + g_deps.get_protocols_by_guids(protocols); - // Save all protocols information to build dependencies - attachActionProtocolsDeps(); - attachActionModulesSeq(); + // save all protocols information to build dependencies + attach_action_protocols_deps(); + attach_action_modules_seq(); } catch (std::exception &e) { - msg("[%s] report file is invalid, check its contents\n", g_plugin_name); + efi_utils::log("report file is invalid\n"); return -1; } @@ -446,7 +443,7 @@ struct action_handler_loadreport_t : public action_handler_t { static action_handler_loadreport_t load_report_handler; //------------------------------------------------------------------------- -// Action to load efiXplorer analysis report -action_desc_t action_load_report = ACTION_DESC_LITERAL( - "efiXplorer:loadReport", "efiXplorer analysis report...", - &load_report_handler, nullptr, nullptr, -1); +// action to load efiXplorer analysis report +action_desc_t action_load_report = + ACTION_DESC_LITERAL("efiXplorer:report", "efiXplorer analysis report...", + &load_report_handler, nullptr, nullptr, -1); diff --git a/efiXplorer/efi_ui.h b/efiXplorer/efi_ui.h index f3b7a3f9..9fc9f0f3 100644 --- a/efiXplorer/efi_ui.h +++ b/efiXplorer/efi_ui.h @@ -118,8 +118,8 @@ class guids_chooser_t : public chooser_t { }; //------------------------------------------------------------------------- -// Protocols chooser -class protocols_chooser_t : public chooser_t { +// protocols chooser +class m_protocols_chooser_t : public chooser_t { protected: static const int widths_protocols[]; static const char *const header_protocols[]; @@ -130,8 +130,8 @@ class protocols_chooser_t : public chooser_t { std::string name_key; // this object must be allocated using `new` - protocols_chooser_t(const char *title, bool ok, json_list_t interfaces, - std::string name_key); + m_protocols_chooser_t(const char *title, bool ok, json_list_t interfaces, + std::string name_key); // function that is used to decide whether a new chooser should be opened or // we can use the existing one. The contents of the window are completely @@ -168,8 +168,8 @@ class protocols_chooser_t : public chooser_t { }; //------------------------------------------------------------------------- -// Service chooser (address : service_name) -class s_chooser_t : public chooser_t { +// service chooser (address : service_name) +class services_chooser_t : public chooser_t { protected: static const int widths_s[]; static const char *const header_s[]; @@ -179,7 +179,7 @@ class s_chooser_t : public chooser_t { json chooser_s; // this object must be allocated using `new` - s_chooser_t(const char *title, bool ok, json_list_t services); + services_chooser_t(const char *title, bool ok, json_list_t services); // function that is used to decide whether a new chooser should be opened or // we can use the existing one. The contents of the window are completely @@ -265,11 +265,11 @@ class nvram_chooser_t : public chooser_t { extern action_desc_t action_load_report; -bool nvram_show(json_list_t nvram, qstring title); -bool vulns_show(json_list_t vulns, qstring title); -bool guids_show(json_list_t guid, qstring title); -bool protocols_show(json_list_t protocols, qstring title); -bool ppis_show(json_list_t protocols, qstring title); -bool services_show(json_list_t services, qstring title); -void attachActionProtocolsDeps(); -void attachActionModulesSeq(); +bool show_nvram(json_list_t nvram, qstring title); +bool show_vulns(json_list_t vulns, qstring title); +bool show_guids(json_list_t guid, qstring title); +bool show_protocols(json_list_t protocols, qstring title); +bool show_ppis(json_list_t protocols, qstring title); +bool show_services(json_list_t services, qstring title); +void attach_action_protocols_deps(); +void attach_action_modules_seq(); From 52799ddcbdc80d6739f58b96e86a00e148912cfa Mon Sep 17 00:00:00 2001 From: yeggor Date: Fri, 20 Sep 2024 04:08:05 +0100 Subject: [PATCH 39/69] refactor efi_hexrays: - use consistent style - add efi_hexrays namespace --- efiXplorer/efi_analysis.h | 2 +- efiXplorer/efi_analysis_arm.cc | 10 +- efiXplorer/efi_analysis_x86.cc | 12 +- efiXplorer/efi_hexrays.cc | 195 ++++---- efiXplorer/efi_hexrays.h | 806 ++++++++++++++++----------------- 5 files changed, 505 insertions(+), 520 deletions(-) diff --git a/efiXplorer/efi_analysis.h b/efiXplorer/efi_analysis.h index d8a36fc4..7e350146 100644 --- a/efiXplorer/efi_analysis.h +++ b/efiXplorer/efi_analysis.h @@ -345,7 +345,7 @@ class efi_analyser_x86_t : public efi_analyser_t { for (auto idx = 0; idx < get_entry_qty(); idx++) { uval_t ord = get_entry_ordinal(idx); ea_t ep = get_entry(ord); - track_entry_params(get_func(ep), 0); + efi_hexrays::track_entry_params(get_func(ep), 0); } #endif } diff --git a/efiXplorer/efi_analysis_arm.cc b/efiXplorer/efi_analysis_arm.cc index aa60bf82..50d72b65 100644 --- a/efiXplorer/efi_analysis_arm.cc +++ b/efiXplorer/efi_analysis_arm.cc @@ -58,7 +58,7 @@ void efi_analysis::efi_analyser_arm_t::initial_analysis() { ea_t ep = get_entry(ord); set_name(ep, "_ModuleEntryPoint", SN_FORCE); #ifdef HEX_RAYS - track_entry_params(get_func(ep), 0); + efi_hexrays::track_entry_params(get_func(ep), 0); #endif /* HEX_RAYS */ } if (m_ftype == ffs_file_type_t::pei) { @@ -233,7 +233,7 @@ void efi_analysis::efi_analyser_arm_t::initial_gvars_detection() { #ifdef HEX_RAYS // analyse entry point with Hex-Rays for (auto func_addr : m_funcs) { - json res = detect_vars(get_func(func_addr)); + json res = efi_hexrays::detect_vars(get_func(func_addr)); if (res.contains("image_handle_list")) { for (auto addr : res["image_handle_list"]) { if (!efi_utils::addr_in_vec(image_handle_list_arm, addr)) { @@ -299,7 +299,7 @@ void efi_analysis::efi_analyser_arm_t::initial_gvars_detection() { void efi_analysis::efi_analyser_arm_t::detect_services_all() { #ifdef HEX_RAYS for (auto func_addr : m_funcs) { - json_list_t services = detect_services(get_func(func_addr)); + json_list_t services = efi_hexrays::detect_services(get_func(func_addr)); for (auto service : services) { m_all_services.push_back(service); } @@ -496,12 +496,12 @@ bool efi_analysis::efi_analyse_main_aarch64() { #ifdef HEX_RAYS for (auto addr : analyser.m_funcs) { - json_list_t services = detect_pei_services_arm(get_func(addr)); + json_list_t services = efi_hexrays::detect_pei_services_arm(get_func(addr)); for (auto service : services) { analyser.m_all_services.push_back(service); } } - apply_all_types_for_interfaces(analyser.m_all_protocols); + efi_hexrays::apply_all_types_for_interfaces(analyser.m_all_protocols); #endif /* HEX_RAYS */ analyser.show_all_choosers(); diff --git a/efiXplorer/efi_analysis_x86.cc b/efiXplorer/efi_analysis_x86.cc index 32f1eeec..9b5bd054 100644 --- a/efiXplorer/efi_analysis_x86.cc +++ b/efiXplorer/efi_analysis_x86.cc @@ -2453,7 +2453,7 @@ bool efi_analysis::efi_analyser_t::analyse_variable_service( } else { #ifdef HEX_RAYS // Extract attributes with Hex-Rays SDK - auto res = variables_info_extract_all(f, ea); + auto res = efi_hexrays::variables_info_extract_all(f, ea); item["Attributes"] = res; std::string attributes_hr = std::string(); if (res == 0xff) { @@ -2715,7 +2715,7 @@ bool efi_analysis::efi_analyse_main_x86_64() { analyser.get_bs_prot_names64(); #ifdef HEX_RAYS - apply_all_types_for_interfaces(analyser.m_all_protocols); + efi_hexrays::apply_all_types_for_interfaces(analyser.m_all_protocols); analyser.find_smst_postproc64(); #endif @@ -2746,7 +2746,7 @@ bool efi_analysis::efi_analyse_main_x86_64() { } #ifdef HEX_RAYS - apply_all_types_for_interfaces_smm(analyser.m_all_protocols); + efi_hexrays::apply_all_types_for_interfaces_smm(analyser.m_all_protocols); #endif analyser.analyse_nvram_variables(); @@ -2821,15 +2821,15 @@ bool efi_analysis::efi_analyse_main_x86_32() { analyser.mark_interfaces(); #ifdef HEX_RAYS - apply_all_types_for_interfaces(analyser.m_all_protocols); - apply_all_types_for_interfaces_smm(analyser.m_all_protocols); + efi_hexrays::apply_all_types_for_interfaces(analyser.m_all_protocols); + efi_hexrays::apply_all_types_for_interfaces_smm(analyser.m_all_protocols); #endif } else if (analyser.m_ftype == ffs_file_type_t::pei) { efi_utils::set_entry_arg_to_pei_svc(); efi_utils::add_struct_for_shifted_ptr(); #ifdef HEX_RAYS for (auto addr : analyser.m_funcs) { - detect_pei_services(get_func(addr)); + efi_hexrays::detect_pei_services(get_func(addr)); } #endif analyser.get_pei_services_all32(); diff --git a/efiXplorer/efi_hexrays.cc b/efiXplorer/efi_hexrays.cc index eccaad35..aa270493 100644 --- a/efiXplorer/efi_hexrays.cc +++ b/efiXplorer/efi_hexrays.cc @@ -21,7 +21,8 @@ // given a tinfo_t specifying a user-defined type (UDT), look up the specified // field by its name, and retrieve its offset. -bool offset_of(tinfo_t tif, const char *name, unsigned int *offset) { +bool efi_hexrays::offset_of(tinfo_t tif, const char *name, + unsigned int *offset) { // get the udt details udt_type_data_t udt; if (!tif.get_udt_details(&udt)) { @@ -51,17 +52,19 @@ bool offset_of(tinfo_t tif, const char *name, unsigned int *offset) { return true; } -// Utility function to set a Hex-Rays variable type and set types for the +// utility function to set a Hex-Rays variable type and set types for the // interfaces -bool set_hexrays_var_info_and_handle_interfaces(ea_t func_addr, lvar_t &ll, - tinfo_t tif, std::string name) { +bool efi_hexrays::set_hexrays_var_info_and_handle_interfaces(ea_t func_addr, + lvar_t &ll, + tinfo_t tif, + std::string name) { lvar_saved_info_t lsi; lsi.ll = ll; lsi.type = tif; modify_user_lvar_info(func_addr, MLI_TYPE, lsi); - // Set lvar name - if (ll.is_stk_var()) { // Rename local variable on stack + // set lvar name + if (ll.is_stk_var()) { // rename local variable on stack #if IDA_SDK_VERSION < 900 sval_t stkoff = ll.get_stkoff(); struc_t *frame = get_frame(func_addr); @@ -72,21 +75,21 @@ bool set_hexrays_var_info_and_handle_interfaces(ea_t func_addr, lvar_t &ll, modify_user_lvar_info(func_addr, MLI_NAME, lsi); } - // Get xrefs to local variable + // get xrefs to local variable xreflist_t xrefs = efi_utils::xrefs_to_stack_var( func_addr, static_cast(name.c_str())); qstring type_name; ptr_type_data_t pi; tif.get_ptr_details(&pi); pi.obj_type.get_type_name(&type_name); - // Handling all interface functions (to rename function arguments) + // handling all interface functions (to rename function arguments) efi_utils::op_stroff_for_interface(xrefs, type_name); return true; } -// Utility function to set a Hex-Rays variable name -bool set_lvar_name(qstring name, lvar_t lvar, ea_t func_addr) { +// utility function to set a Hex-Rays variable name +bool efi_hexrays::set_lvar_name(qstring name, lvar_t lvar, ea_t func_addr) { lvar_saved_info_t lsi; lvar_uservec_t lvuv; @@ -99,22 +102,22 @@ bool set_lvar_name(qstring name, lvar_t lvar, ea_t func_addr) { return true; } -// Utility function to set a Hex-Rays variable type and name -bool set_hexrays_var_info(ea_t func_addr, lvar_t &ll, tinfo_t tif, - std::string name) { +// utility function to set a Hex-Rays variable type and name +bool efi_hexrays::set_hexrays_var_info(ea_t func_addr, lvar_t &ll, tinfo_t tif, + std::string name) { lvar_saved_info_t lsi; lsi.ll = ll; lsi.type = tif; modify_user_lvar_info(func_addr, MLI_TYPE, lsi); - // Set lvar name - if (ll.is_stk_var()) { // Rename local variable on stack + // set lvar name + if (ll.is_stk_var()) { // rename local variable on stack #if IDA_SDK_VERSION < 900 sval_t stkoff = ll.get_stkoff(); struc_t *frame = get_frame(func_addr); set_member_name(frame, stkoff, name.c_str()); #endif // TODO(yeggor): add support for idasdk90 - } else { // Modufy user lvar info + } else { // modufy user lvar info lsi.name = static_cast(name.c_str()); modify_user_lvar_info(func_addr, MLI_NAME, lsi); } @@ -122,97 +125,96 @@ bool set_hexrays_var_info(ea_t func_addr, lvar_t &ll, tinfo_t tif, return true; } -// I added this bit of logic when I noticed that sometimes Hex-Rays will -// aggressively create arrays on the stack. So, I wanted to apply types to +// I added this bit of logic when I noticed that sometimes Hex-Rays +// will aggressively create arrays on the stack. So, I wanted to apply types to // stack "variables" (whose pointers are passed to the protocol location // functions), but according to Hex-Rays, they weren't "variables", they // were arrays. This bit of logic generically detects arrays of either POD // types, or perhaps pointers to POD types. The final argument allows the // caller to specify the maximum depth "depth" of the pointers. E.g. at // depth 1, "int *[10]" is acceptable. At depth 2, "int **[10]" is acceptable. -bool is_pod_array(tinfo_t tif, unsigned int ptrDepth = 0) { - // If it's not an array, we're done +bool efi_hexrays::is_pod_array(tinfo_t tif, unsigned int ptr_depth = 0) { + // if it's not an array, we're done if (!tif.is_array()) return false; qstring tstr; - // If it is an array, we should be able to get its array details. + // if it is an array, we should be able to get its array details. array_type_data_t atd; if (!tif.get_array_details(&atd)) { tif.get_type_name(&tstr); return false; } - // Get the element type from the array + // get the element type from the array tinfo_t et = atd.elem_type; - // Start off with depth + 1, so the loop will execute at least once - int iDepth = ptrDepth + 1; + // start off with depth + 1, so the loop will execute at least once + int depth = ptr_depth + 1; - // Loop over the user-specified depth - while (iDepth > 0) { - // Use typeid last checks. I should clean this up; I'm sure I can get rid - // of one of them. + // loop over the user-specified depth + while (depth > 0) { + // use typeid last checks. I should clean this up; I'm sure I + // can get rid of one of them. bool b1 = is_typeid_last(et.get_realtype()); bool b2 = et.is_decl_last(); - // Debug printing et.get_type_name(&tstr); - // If it was an integer type, return true + // if it was an integer type, return true if (b1 || b2) return true; - // Otherwise, this is where the "pointer depth" comes in. - // If we haven't exhausted the pointer depth, - if (--iDepth > 0) { - // Remove one layer of indirection from the element type + // otherwise, this is where the "pointer depth" comes in + // if we haven't exhausted the pointer depth, + if (--depth > 0) { + // remove one layer of indirection from the element type if (et.is_ptr()) et = remove_pointer(et); - // Unless it's not a pointer, then return false. + // unless it's not a pointer, then return false else return false; } } - // If the array wasn't pointers of POD types up to the specified depth, we - // failed. Return false. + // if the array wasn't pointers of POD types up to the specified depth, we + // failed return false; } -// Utility function to get a printable qstring from a cexpr_t -const char *expr_to_string(cexpr_t *e, qstring *out) { +// utility function to get a printable qstring from a cexpr_t +const char *efi_hexrays::expr_to_string(cexpr_t *e, qstring *out) { e->print1(out, nullptr); tag_remove(out); return out->c_str(); } -bool apply_all_types_for_interfaces(json_list_t protocols) { +bool efi_hexrays::apply_all_types_for_interfaces(json_list_t protocols) { if (!init_hexrays_plugin()) { return false; } - // Descriptors for EFI_BOOT_SERVICES functions - struct TargetFunctionPointer BootServicesFunctions[5]{ + // descriptors for EFI_BOOT_SERVICES functions + struct target_funcptr_t boot_services_functions[5]{ {"InstallProtocolInterface", 0x80, 4, 1, 3}, {"HandleProtocol", 0x98, 3, 1, 2}, {"OpenProtocol", 0x118, 6, 1, 2}, {"LocateProtocol", 0x140, 3, 0, 2}, {"InstallMultipleProtocolInterfaces", 0x148, 4, 1, 2}}; - // Initialize - ServiceDescriptor sdBs; - sdBs.Initialize("EFI_BOOT_SERVICES", BootServicesFunctions, 5); + // initialise + service_descriptor_t sd_bs; + sd_bs.initialise("EFI_BOOT_SERVICES", boot_services_functions, 5); - ServiceDescriptorMap mBs; - mBs.Register(sdBs); + service_descriptor_map_t bs; + bs.register_sd(sd_bs); - GUIDRetyper retyperBs(mBs); - retyperBs.SetProtocols(protocols); + guid_retyper_t bs_retyper(bs); + bs_retyper.set_protocols(protocols); - // Handle all protocols + // handle all protocols for (auto protocol : protocols) { auto code_addr = protocol["ea"]; auto service = protocol["service"]; @@ -222,43 +224,43 @@ bool apply_all_types_for_interfaces(json_list_t protocols) { continue; } - retyperBs.SetCodeEa(code_addr); - retyperBs.SetFuncEa(f->start_ea); + bs_retyper.set_code_ea(code_addr); + bs_retyper.set_func_ea(f->start_ea); hexrays_failure_t hf; cfuncptr_t cfunc = decompile(f, &hf, DECOMP_NO_WAIT); - // Сheck that the function is decompiled + // check that the function is decompiled if (cfunc == nullptr) { continue; } - retyperBs.apply_to(&cfunc->body, nullptr); + bs_retyper.apply_to(&cfunc->body, nullptr); } return true; } -bool apply_all_types_for_interfaces_smm(json_list_t protocols) { +bool efi_hexrays::apply_all_types_for_interfaces_smm(json_list_t protocols) { if (!init_hexrays_plugin()) { return false; } - // Descriptors for _EFI_SMM_SYSTEM_TABLE2 functions - struct TargetFunctionPointer SmmServicesFunctions[2]{ + // descriptors for _EFI_SMM_SYSTEM_TABLE2 functions + struct target_funcptr_t smm_services_functions[2]{ {"SmmHandleProtocol", 0xb8, 3, 1, 2}, {"SmmLocateProtocol", 0xd0, 3, 0, 2}, }; - // Initialize - ServiceDescriptor sdSmm; - sdSmm.Initialize("_EFI_SMM_SYSTEM_TABLE2", SmmServicesFunctions, 2); + // initialise + service_descriptor_t sd_smm; + sd_smm.initialise("_EFI_SMM_SYSTEM_TABLE2", smm_services_functions, 2); - ServiceDescriptorMap mSmm; - mSmm.Register(sdSmm); + service_descriptor_map_t smm; + smm.register_sd(sd_smm); - GUIDRetyper retyperSmm(mSmm); - retyperSmm.SetProtocols(protocols); + guid_retyper_t smm_retyper(smm); + smm_retyper.set_protocols(protocols); // Handle all protocols for (auto protocol : protocols) { @@ -270,45 +272,46 @@ bool apply_all_types_for_interfaces_smm(json_list_t protocols) { continue; } - retyperSmm.SetCodeEa(code_addr); - retyperSmm.SetFuncEa(f->start_ea); + smm_retyper.set_code_ea(code_addr); + smm_retyper.set_func_ea(f->start_ea); hexrays_failure_t hf; cfuncptr_t cfunc = decompile(f, &hf, DECOMP_NO_WAIT); - // Сheck that the function is decompiled + // check that the function is decompiled if (cfunc == nullptr) { continue; } - retyperSmm.apply_to(&cfunc->body, nullptr); + smm_retyper.apply_to(&cfunc->body, nullptr); } return true; } -uint8_t variables_info_extract_all(func_t *f, ea_t code_addr) { +uint8_t efi_hexrays::variables_info_extract_all(func_t *f, ea_t code_addr) { if (!init_hexrays_plugin()) { return 0xff; } - // check func if (f == nullptr) { return 0xff; } - VariablesInfoExtractor extractor(code_addr); + + variables_info_extractor_t extractor(code_addr); hexrays_failure_t hf; cfuncptr_t cfunc = decompile(f, &hf, DECOMP_NO_WAIT); - // Сheck that the function is decompiled + + // check that the function is decompiled if (cfunc == nullptr) { return 0xff; } + extractor.apply_to(&cfunc->body, nullptr); - auto res = extractor.mAttributes; - return res; + return extractor.m_attributes; } -bool track_entry_params(func_t *f, uint8_t depth) { +bool efi_hexrays::track_entry_params(func_t *f, uint8_t depth) { if (!init_hexrays_plugin()) { return false; } @@ -327,10 +330,10 @@ bool track_entry_params(func_t *f, uint8_t depth) { return false; } - PrototypesFixer *pf = new PrototypesFixer(); + prototypes_fixer_t *pf = new prototypes_fixer_t(); pf->apply_to(&cfunc->body, nullptr); - for (auto addr : pf->child_functions) { - track_entry_params(get_func(addr), ++depth); + for (auto addr : pf->m_child_functions) { + efi_hexrays::track_entry_params(get_func(addr), ++depth); } delete pf; @@ -338,37 +341,36 @@ bool track_entry_params(func_t *f, uint8_t depth) { return true; } -json detect_vars(func_t *f) { +json efi_hexrays::detect_vars(func_t *f) { json res; if (!init_hexrays_plugin()) { return res; } - // check func if (f == nullptr) { return res; } - VariablesDetector vars_detector; + + variables_detector_t vars_detector; hexrays_failure_t hf; cfuncptr_t cfunc = decompile(f, &hf, DECOMP_NO_WAIT); if (cfunc == nullptr) { return res; } - vars_detector.SetFuncEa(f->start_ea); + vars_detector.set_func_ea(f->start_ea); vars_detector.apply_to(&cfunc->body, nullptr); - res["image_handle_list"] = vars_detector.image_handle_list; - res["st_list"] = vars_detector.st_list; - res["bs_list"] = vars_detector.bs_list; - res["rt_list"] = vars_detector.rt_list; + res["image_handle_list"] = vars_detector.m_image_handle_list; + res["st_list"] = vars_detector.m_st_list; + res["bs_list"] = vars_detector.m_bs_list; + res["rt_list"] = vars_detector.m_rt_list; return res; } -json_list_t detect_services(func_t *f) { - // check func +json_list_t efi_hexrays::detect_services(func_t *f) { json_list_t res; if (!init_hexrays_plugin()) { @@ -378,17 +380,19 @@ json_list_t detect_services(func_t *f) { if (f == nullptr) { return res; } - ServicesDetector services_detector; + + services_detector_t services_detector; hexrays_failure_t hf; cfuncptr_t cfunc = decompile(f, &hf, DECOMP_NO_WAIT); if (cfunc == nullptr) { return res; } + services_detector.apply_to(&cfunc->body, nullptr); - return services_detector.services; + return services_detector.m_services; } -bool detect_pei_services(func_t *f) { +bool efi_hexrays::detect_pei_services(func_t *f) { if (!init_hexrays_plugin()) { return false; } @@ -397,18 +401,19 @@ bool detect_pei_services(func_t *f) { return false; } - PeiServicesDetector pei_services_detector; + pei_services_detector_t pei_services_detector; hexrays_failure_t hf; cfuncptr_t cfunc = decompile(f, &hf, DECOMP_NO_WAIT); if (cfunc == nullptr) { return false; } + pei_services_detector.apply_to(&cfunc->body, nullptr); return true; } -json_list_t detect_pei_services_arm(func_t *f) { +json_list_t efi_hexrays::detect_pei_services_arm(func_t *f) { json_list_t res; if (!init_hexrays_plugin()) { @@ -419,12 +424,12 @@ json_list_t detect_pei_services_arm(func_t *f) { return res; } - PeiServicesDetectorArm pei_services_detector_arm; + pei_services_detector_arm_t pei_services_detector_arm; hexrays_failure_t hf; cfuncptr_t cfunc = decompile(f, &hf, DECOMP_NO_WAIT); if (cfunc == nullptr) { return res; } pei_services_detector_arm.apply_to(&cfunc->body, nullptr); - return pei_services_detector_arm.services; + return pei_services_detector_arm.m_services; } diff --git a/efiXplorer/efi_hexrays.h b/efiXplorer/efi_hexrays.h index 4ecfc730..6fd6aeb9 100644 --- a/efiXplorer/efi_hexrays.h +++ b/efiXplorer/efi_hexrays.h @@ -25,6 +25,7 @@ #include #include +namespace efi_hexrays { uint8_t variables_info_extract_all(func_t *f, ea_t code_addr); bool track_entry_params(func_t *f, uint8_t depth); json detect_vars(func_t *f); @@ -39,66 +40,66 @@ bool set_hexrays_var_info(ea_t func_addr, lvar_t &ll, tinfo_t tif, bool set_hexrays_var_info_and_handle_interfaces(ea_t func_addr, lvar_t &ll, tinfo_t tif, std::string name); bool offset_of(tinfo_t tif, const char *name, unsigned int *offset); -bool is_pod_array(tinfo_t tif, unsigned int ptrDepth); +bool is_pod_array(tinfo_t tif, unsigned int ptr_depth); const char *expr_to_string(cexpr_t *e, qstring *out); -// Description of a function pointer within a structure. Ultimately, this +// description of a function pointer within a structure. Ultimately, this // plugin is looking for calls to specific UEFI functions. This structure // describes basic information about those functions: -struct TargetFunctionPointer { - const char *name; // Name of function pointer in structure - int offset; // Offset of function pointer (filled in later) - unsigned int nArgs; // Number of expected arguments - unsigned int nGUIDArg; // Which argument has the EFI_GUID * - unsigned int nOutArg; // Which argument retrieves the output +struct target_funcptr_t { + const char *name; // name of function pointer in structure + int offset; // offset of function pointer (filled in later) + unsigned int args; // number of expected arguments + unsigned int guid_arg; // which argument has the EFI_GUID * + unsigned int out_arg; // which argument retrieves the output }; -// This class holds all function pointer descriptors for one structure, as well -// as providing a utility to look up function pointers by offset. -class ServiceDescriptor { - // Instance data +// this class holds all function pointer descriptors for one structure, as well +// as providing a utility to look up function pointers by offset +class service_descriptor_t { + // instance data protected: - // The type of the containing structure (e.g. EFI_BOOT_SERVICES) - tinfo_t mType; + // the type of the containing structure (e.g. EFI_BOOT_SERVICES) + tinfo_t m_type; - // The name of the type (e.g. "EFI_BOOT_SERVICES") - qstring mName; + // the name of the type (e.g. "EFI_BOOT_SERVICES") + qstring m_name; - // The ordinal of the type (e.g. 4) - uint32 mOrdinal; + // the ordinal of the type (e.g. 4) + uint32 m_ordinal; - // A vector of the structures above, copied, and with the offsets filled in - std::vector mTargets; + // a vector of the structures above, copied, and with the offsets filled in + std::vector m_targets; - bool bInitialized; + bool b_initialised; - // Ensure we can look up the type that this instance describes - bool InitType(const char *name) { - // Import type + // ensure we can look up the type that this instance describes + bool init_type(const char *name) { + // import type import_type(get_idati(), -1, name); - // Get type by name - if (!mType.get_named_type(get_idati(), name)) + // get type by name + if (!m_type.get_named_type(get_idati(), name)) return false; - // Save ordinal and name - mOrdinal = mType.get_ordinal(); - mName = name; + // save ordinal and name + m_ordinal = m_type.get_ordinal(); + m_name = name; return true; } - // Look up the offsets for all function pointer targets; save the results - // in the vector. Return false if offset lookup fails. - bool InitTargets(TargetFunctionPointer *targets, size_t num) { - // Iterate through all targets + // look up the offsets for all function pointer targets; save the results + // in the vector; return false if offset lookup fails + bool init_targets(target_funcptr_t *targets, size_t num) { + // iterate through all targets for (int i = 0; i < num; ++i) { - // Copy the target structure into our local vector - TargetFunctionPointer &tgt = mTargets.emplace_back(); + // copy the target structure into our local vector + target_funcptr_t &tgt = m_targets.emplace_back(); tgt = targets[i]; - // Retrieve the offsets of each named function pointer + // retrieve the offsets of each named function pointer unsigned int offset; - if (!offset_of(mType, targets[i].name, &offset)) { + if (!offset_of(m_type, targets[i].name, &offset)) { return false; } } @@ -106,522 +107,501 @@ class ServiceDescriptor { } public: - // Constructor does nothing - ServiceDescriptor() : mOrdinal(0), bInitialized(false) {} + // constructor does nothing + service_descriptor_t() : m_ordinal(0), b_initialised(false) {} - // Accessor for ordinal - uint32 GetOrdinal() { return mOrdinal; } + // accessor for ordinal + uint32 get_ordinal() { return m_ordinal; } - // Accessor for name - const char *GetName() { return mName.c_str(); } + // accessor for name + const char *get_name() { return m_name.c_str(); } - // Needs to be called before the object can be used - bool Initialize(const char *name, TargetFunctionPointer *targets, - size_t num) { - if (bInitialized) + // needs to be called before the object can be used + bool initialise(const char *name, target_funcptr_t *targets, size_t num) { + if (b_initialised) return true; - bInitialized = InitType(name) && InitTargets(targets, num); - return bInitialized; + b_initialised = init_type(name) && init_targets(targets, num); + return b_initialised; } - // After initialization, look up a target by offset - bool LookupOffset(unsigned int offset, TargetFunctionPointer **tgt) { - // Iterating through a vector generally is inefficient compared to a map, - // but there are at most 3 function pointers so far, so it outweighs the - // overhead of the associative containers. - for (auto &it : mTargets) { + // after initialisation, look up a target by offset + bool lookup_offset(unsigned int offset, target_funcptr_t **tgt) { + // iterating through a vector generally is inefficient compared + // to a map, but there are at most 3 function pointers so far, so it + // outweighs the overhead of the associative containers. + for (auto &it : m_targets) { // Match by offset if (it.offset == offset) { *tgt = ⁢ return true; } } - // If we don't find it, it's not necessarily "bad" from the point of view - // of the plugin's logic. After all, we're looking at every access to the - // selected structures, and so, quite rightly, we'll want to ignore the - // function pointers that we're not tracking. + // if we don't find it, it's not necessarily "bad" from the + // point of view of the plugin's logic. After all, we're looking at every + // access to the selected structures, and so, quite rightly, we'll want to + // ignore the function pointers that we're not tracking. return false; } }; -// This class manages multiple instances of the class above. Each such -// structure is associated with the ordinal of its containing structure type. -// Then, when the Hex-Rays visitor needs to look up a function pointer access -// into a structure, it just passes the structure ordinal and offset. This -// class looks up the ServiceDescriptor in a map by ordinal, and then looks up -// the offset if that succeeded. -class ServiceDescriptorMap { +// this class manages multiple instances of the class above. Each +// such structure is associated with the ordinal of its containing structure +// type. Then, when the Hex-Rays visitor needs to look up a function pointer +// access into a structure, it just passes the structure ordinal and offset. +// This class looks up the service_descriptor_t in a map by ordinal, and then +// looks up the offset if that succeeded. +class service_descriptor_map_t { protected: - // Our map for looking up ServiceDescriptor structures. I should probably - // change the value type to a pointer. - std::map mServices; + // our map for looking up service_descriptor_t structures. I + // should probably change the value type to a pointer. + std::map m_services; public: - // Add a new ServiceDescriptor to the map. I should change the argument - // type to match whatever I change the value type of the map to. - bool Register(ServiceDescriptor sd) { - // Get the ordinal from the ServiceDescriptor - uint32 ord = sd.GetOrdinal(); - - // Are we already tracking this structure? - if (mServices.find(ord) != mServices.end()) { + // add a new service_descriptor_t to the map. I should change the + // argument type to match whatever I change the value type of the map to. + bool register_sd(service_descriptor_t sd) { + // get the ordinal from the service_descriptor_t + uint32 ord = sd.get_ordinal(); + + // are we already tracking this structure? + if (m_services.find(ord) != m_services.end()) { return false; } - // If not, register it. Get rid of std::move - mServices[ord] = std::move(sd); + // if not, register it. Get rid of std::move + m_services[ord] = std::move(sd); return true; } - // This function could be protected, but whatever. Given an ordinal, get - // the tracked ServiceDescriptor, if applicable. - bool LookupOrdinal(uint32 ord, ServiceDescriptor **sd) { - auto it = mServices.find(ord); - if (it == mServices.end()) { + // this function could be protected, but whatever. Given an ordinal, get + // the tracked service_descriptor_t, if applicable + bool lookup_ordinal(uint32 ord, service_descriptor_t **sd) { + auto it = m_services.find(ord); + if (it == m_services.end()) { return false; } *sd = &it->second; return true; } - // This is the high-level function that clients call. Given a structure + // this is the high-level function that clients call. Given a structure // ordinal and offset of a function pointer, see if it's something we're // tracking. If so, get pointers to the tracked objects and return true. - bool LookupOffset(uint32 ord, unsigned int offset, ServiceDescriptor **sd, - TargetFunctionPointer **tgt) { - if (!LookupOrdinal(ord, sd)) + bool lookup_offset(uint32 ord, unsigned int offset, service_descriptor_t **sd, + target_funcptr_t **tgt) { + if (!lookup_ordinal(ord, sd)) return false; - if (!(*sd)->LookupOffset(offset, tgt)) + if (!(*sd)->lookup_offset(offset, tgt)) return false; return true; } }; -// Base class for two visitors that require similar functionality. Here we +// base class for two visitors that require similar functionality. Here we // collect all of the common data and functionality that will be used by both // of those visitors. This allows the derivatives to be very succinct. -class GUIDRelatedVisitorBase : public ctree_visitor_t { +class guid_related_visitor_base_t : public ctree_visitor_t { public: - // We need access to a ServiceDescriptorMap from above. - explicit GUIDRelatedVisitorBase(ServiceDescriptorMap &m) - : ctree_visitor_t(CV_FAST), mDebug(true), mServices(m) {} + // we need access to a service_descriptor_map_t from above + explicit guid_related_visitor_base_t(service_descriptor_map_t &m) + : ctree_visitor_t(CV_FAST), m_debug(true), m_services(m) {} - // We need the function ea when setting Hex-Rays variable types. - void SetFuncEa(ea_t ea) { mFuncEa = ea; } - void SetCodeEa(ea_t ea) { mCodeEa = ea; } - void SetProtocols(json_list_t protocols) { mProtocols = protocols; } + // we need the function ea when setting Hex-Rays variable types + void set_func_ea(ea_t ea) { m_func_ea = ea; } + void set_code_ea(ea_t ea) { m_code_ea = ea; } + void set_protocols(json_list_t protocols) { m_protocols = protocols; } protected: - // - // Persistent variables - // - - // Function address - ea_t mFuncEa; - ea_t mCodeEa; - - // Protocols - json_list_t mProtocols; + ea_t m_func_ea; + ea_t m_code_ea; + json_list_t m_protocols; + bool m_debug = false; - // Print debug messages? - bool mDebug = false; - - // Used for looking up calls to function pointers in structures - ServiceDescriptorMap &mServices; + // used for looking up calls to function pointers in structures + service_descriptor_map_t &m_services; // - // State variables, cleared on every iteration. I debated with myself + // state variables, cleared on every iteration. I debated with myself // whether this was a nasty design decision. I think it's fine. These // variables are only valid to access after the client has called - // ValidateCallAndGUID, and it returned true. If you called that and it + // validate_call_and_guid, and it returned true. If you called that and it // returned false, these will be in an inconsistent state. Don't touch them // if that's the case. // - // Address of the indirect function call - ea_t mEa; - - // The pointer type that's being accessed (that of the structure) - tinfo_t mTif; + // address of the indirect function call + ea_t m_ea; - // The structure type, with the pointer indirection removed - tinfo_t mTifNoPtr; + // the pointer type that's being accessed (that of the structure) + tinfo_t m_tif; - // The ServiceDescriptor for the containing structure - ServiceDescriptor *mpService; + // the structure type, with the pointer indirection removed + tinfo_t m_tif_noptr; - // The ordinal of the structure type - uint32 mOrdinal; + // the service_descriptor_t for the containing structure + service_descriptor_t *m_service; - // The offset of the function pointer in the structure - unsigned int mOffset; + // the ordinal of the structure type + uint32 m_ordinal; - // Details about the target of the indirect call (e.g. name) - TargetFunctionPointer *mpTarget; + // the offset of the function pointer in the structure + unsigned int m_offset; - // The list of arguments for the indirect call - carglist_t *mArgs; + // details about the target of the indirect call (e.g. name) + target_funcptr_t *m_target; - // The argument that specifies the GUID for the indirect call - cexpr_t *mGUIDArg; + // the list of arguments for the indirect call + carglist_t *m_args; - // The argument that gets the output for the indirect call - cexpr_t *mOutArg; + // the argument that specifies the GUID for the indirect call + cexpr_t *m_guid_arg; - // The GUID argument will be &x; this is x - cexpr_t *mGUIDArgRefTo; + // the argument that gets the output for the indirect call + cexpr_t *m_out_arg; - // The address of the GUID being passed to the indirect call - ea_t mGUIDEa; + // the GUID argument will be &x; this is x + cexpr_t *m_guid_arg_ref_to; - // This function clears all the state variables above. Technically, it - // doesn't need to exist, since the flow of logic in the functions below - // always write to them before reading to them. But, it seems like good - // programming practice not to have stale values, anyway. - void Clear() { - mEa = BADADDR; - mTif.clear(); - mTifNoPtr.clear(); - mpService = nullptr; - mOrdinal = 0; - mOffset = -1; - mpTarget = nullptr; - mArgs = nullptr; - mGUIDArg = nullptr; - mOutArg = nullptr; - mGUIDArgRefTo = nullptr; - mGUIDEa = BADADDR; - } + // the address of the GUID being passed to the indirect call + ea_t m_guid_ea; - // Debug print, if the instance debug variable says to - void DebugPrint(const char *fmt, ...) { - va_list va; - va_start(va, fmt); - if (mDebug) - vmsg(fmt, va); + void clear() { + m_ea = BADADDR; + m_tif.clear(); + m_tif_noptr.clear(); + m_service = nullptr; + m_ordinal = 0; + m_offset = -1; + m_target = nullptr; + m_args = nullptr; + m_guid_arg = nullptr; + m_out_arg = nullptr; + m_guid_arg_ref_to = nullptr; + m_guid_ea = BADADDR; } - // This is the first function called every time the visitor visits an + // this is the first function called every time the visitor visits an // expression. This function determines if the expression is a call to a - // function pointer contained in a structure. - bool GetICallOrdAndOffset(cexpr_t *e) { - // Set instance variable for call address - mEa = e->ea; + // function pointer contained in a structure + bool get_call_ord_and_offset(cexpr_t *e) { + // set instance variable for call address + m_ea = e->ea; - if (mEa != mCodeEa) { + if (m_ea != m_code_ea) { return false; } - // If it's not a call, we're done. + // if it's not a call, we're done if (e->op != cot_call) return false; - // Set instance variable with call arguments - mArgs = e->a; + // set instance variable with call arguments + m_args = e->a; - // If it's a direct call, we're done. - cexpr_t *callDest = e->x; - if (callDest->op == cot_obj) + // if it's a direct call, we're done + cexpr_t *call_dest = e->x; + if (call_dest->op == cot_obj) return false; - // Eat any casts on the type of what's being called - while (callDest->op == cot_cast) - callDest = callDest->x; + // eat any casts on the type of what's being called + while (call_dest->op == cot_cast) + call_dest = call_dest->x; - // If the destination is not a member of a structure, we're done. - if (callDest->op != cot_memptr) + // if the destination is not a member of a structure, we're done + if (call_dest->op != cot_memptr) return false; - // Set instance variable with type of structure containing pointer - mTif = callDest->x->type; + // set instance variable with type of structure containing pointer + m_tif = call_dest->x->type; - // Ensure that the structure is being accessed via pointer, and not as a + // ensure that the structure is being accessed via pointer, and not as a // reference (i.e., through a structure held on the stack as a local - // variable). - if (!mTif.is_ptr()) { + // variable) + if (!m_tif.is_ptr()) { return false; } - // Remove pointer from containing structure type, set instance variable - mTifNoPtr = remove_pointer(mTif); + // remove pointer from containing structure type, set instance variable + m_tif_noptr = remove_pointer(m_tif); - // Get the ordinal of the structure - mOrdinal = mTifNoPtr.get_ordinal(); + // get the ordinal of the structure + m_ordinal = m_tif_noptr.get_ordinal(); - // If we can't get a type for the structure, that's bad - if (mOrdinal == 0) + // if we can't get a type for the structure, that's bad + if (m_ordinal == 0) return false; - // Get the offset of the function pointer in the structure - mOffset = callDest->m; + // get the offset of the function pointer in the structure + m_offset = call_dest->m; - // Okay: now we know we're dealing with an indirect call to a function + // now we know we're dealing with an indirect call to a function // pointer contained in a structure, where the structure is being - // accessed by a pointer. + // accessed by a pointer return true; } - // This is the second function called as part of indirect call validation. + // this is the second function called as part of indirect call validation. // Now we want to know: is it a call to something that we're tracking? - bool ValidateICallDestination() { - // Look up the structure ordinal and function offset; get the associated - // ServiceDescriptor and TargetFunctionPointer (instance variables). - if (!mServices.LookupOffset(mOrdinal, mOffset, &mpService, &mpTarget)) + bool validate_call_destination() { + // look up the structure ordinal and function offset; get the associated + // service_descriptor_t and target_funcptr_t (instance variables) + if (!m_services.lookup_offset(m_ordinal, m_offset, &m_service, &m_target)) return false; - // Great, it was something that we were tracking. Now, sanity-check the + // it was something that we were tracking. Now, sanity-check the // number of arguments on the function call. (Hex-Rays might have gotten - // this wrong. The user can fix it via "set call type".) - size_t mArgsSize = mArgs->size(); - size_t nArgs = mpTarget->nArgs; - if (mArgsSize != nArgs) { + // this wrong. The user can fix it via "set call type") + size_t args_size = m_args->size(); + size_t args = m_target->args; + if (args_size != args) { return false; } - // The TargetFunctionPointer tells us which argument takes an EFI_GUID *, + // the target_funcptr_t tells us which argument takes an EFI_GUID *, // and which one retrieves the output. Get those arguments, and save them - // as instance variables. - mGUIDArg = &mArgs->at(mpTarget->nGUIDArg); - mOutArg = &mArgs->at(mpTarget->nOutArg); + // as instance variables + m_guid_arg = &m_args->at(m_target->guid_arg); + m_out_arg = &m_args->at(m_target->out_arg); - // Great; now we know that the expression is an indirect call to + // now we know that the expression is an indirect call to // something that we're tracking, and that Hex-Rays decompiled the call - // the way we expected it to. + // the way we expected it to return true; } - // This is a helper function used to get the thing being referred to. What - // does that mean? + // this is a helper function used to get the thing being referred to. What + // does that m_ean? // - // * For GUID arguments, we'll usually have &globvar. Return globvar. - // * For output arguments, we'll usually have &globvar or &locvar. Due to + // * for GUID arguments, we'll usually have &globvar. Return globvar + // * for output arguments, we'll usually have &globvar or &locvar. Due to // Hex-Rays internal heuristics, we might end up with "locarray", which // does not actually have a "&" when passed as a call argument. There's - // a bit of extra logic to check for that case. - cexpr_t *GetReferent(cexpr_t *e, const char *desc, bool bAcceptVar) { + // a bit of extra logic to check for that case + cexpr_t *get_referent(cexpr_t *e, const char *desc, bool b_accept_var) { // Eat casts cexpr_t *x = e; while (x->op == cot_cast) x = x->x; qstring estr; - // If we're accepting local variables, and this is a variable (note: not + // if we're accepting local variables, and this is a variable (note: not // a *reference* to a variable) - if (bAcceptVar && x->op == cot_var) { - // Get the variable details - var_ref_t varRef = x->v; - lvar_t destVar = varRef.mba->vars[varRef.idx]; + if (b_accept_var && x->op == cot_var) { + // get the variable details + var_ref_t var_ref = x->v; + lvar_t dest_var = var_ref.mba->vars[var_ref.idx]; - // Ensure that it's an array of POD types, or pointers to them - bool bis_pod_array = is_pod_array(destVar.tif, 1); + // ensure that it's an array of POD types, or pointers to them + bool bis_pod_array = is_pod_array(dest_var.tif, 1); - // If it is a POD array, good, we'll take it. + // if it is a POD array, good, we'll take it return bis_pod_array ? x : nullptr; } - // For everything else, we really want it to be a reference: either to a + // for everything else, we really want it to be a reference: either to a // global or local variable. If it's not a reference, we can't get the - // referent, so fail. + // referent, so fail if (x->op != cot_ref) { return nullptr; } - // If we get here, we know it's a reference. Return the referent. + // if we get here, we know it's a reference. Return the referent. return x->x; } - // The third function in the validation logic. We already know the + // the third function in the validation logic. We already know the // expression is an indirect call to something that we're tracking, and // that Hex-Rays' decompilation matches on the number of arguments. Now, // we validate that the GUID argument does in fact point to a global - // variable. - bool ValidateGUIDArgument() { - // Does the GUID argument point to a local variable? - mGUIDArgRefTo = GetReferent(mGUIDArg, "GUID", false); - if (!mGUIDArgRefTo) + // variable + bool validate_guid_arg() { + // does the GUID argument point to a local variable? + m_guid_arg_ref_to = get_referent(m_guid_arg, "GUID", false); + if (!m_guid_arg_ref_to) return false; - // If we get here, we know it was a reference to *something*. Ensure that - // something is a global variable. - if (mGUIDArgRefTo->op != cot_obj) { + // if we get here, we know it was a reference to *something*. Ensure that + // something is a global variable + if (m_guid_arg_ref_to->op != cot_obj) { return false; } - // Save the address of the global variable to which the GUID argument is - // pointing. - mGUIDEa = mGUIDArgRefTo->obj_ea; + // save the address of the global variable to which the GUID argument is + // pointing + m_guid_ea = m_guid_arg_ref_to->obj_ea; - // Great; now we know we're dealing with an indirect call to something + // now we know we're dealing with an indirect call to something // we're tracking; that Hex-Rays decompiled the call with the proper // number of arguments; and that the GUID argument did in fact point to // a global variable, whose address we now have in an instance variable. return true; } - // Finally, this function combines all three checks above into one single + // finally, this function combines all three checks above into one single // function. If you call this and it returns true, feel free to access the // instance variables, as they are guaranteed to be valid. If it returns - // false, they aren't, so don't touch them. - bool ValidateCallAndGUID(cexpr_t *e) { + // false, they aren't, so don't touch them + bool validate_call_and_guid(cexpr_t *e) { // Reset all instance variables. Not strictly necessary; call it // "defensive programming". - Clear(); + clear(); - // Validate according to the logic above. - if (!GetICallOrdAndOffset(e) || !ValidateICallDestination() || - !ValidateGUIDArgument()) - return false; - - // Good, all checks passed - return true; + // validate according to the logic above + return (get_call_ord_and_offset(e) && validate_call_destination() && + validate_guid_arg()); } }; -// Now that we've implemented all that validation logic, this class is pretty +// now that we've implemented all that validation logic, this class is pretty // simple. This one is responsible for ensuring that the GUID is something that -// we know about, and setting the types of the output variables accordingly. -class GUIDRetyper : public GUIDRelatedVisitorBase { +// we know about, and setting the types of the output variables accordingly +class guid_retyper_t : public guid_related_visitor_base_t { public: - explicit GUIDRetyper(ServiceDescriptorMap &m) - : GUIDRelatedVisitorBase(m), mNumApplied(0) {} - // This is the callback function that Hex-Rays invokes for every expression - // in the CTREE. + explicit guid_retyper_t(service_descriptor_map_t &m) + : guid_related_visitor_base_t(m), m_num_applied(0) {} + + // this is the callback function that Hex-Rays invokes for every expression + // in the CTREE int visit_expr(cexpr_t *e) { - // Perform the checks from GUIDRelatedVisitorBase. If they fail, we're - // not equipped to deal with this expression, so bail out. - if (!ValidateCallAndGUID(e)) + // perform the checks from guid_related_visitor_base_t. If they fail, we're + // not equipped to deal with this expression, so bail out + if (!validate_call_and_guid(e)) return 0; - mGUIDArgRefTo = GetReferent(mGUIDArg, "GUID", false); - if (mGUIDArgRefTo == nullptr) + m_guid_arg_ref_to = get_referent(m_guid_arg, "GUID", false); + if (m_guid_arg_ref_to == nullptr) return 0; - ea_t guidAddr = mGUIDArgRefTo->obj_ea; + ea_t guidAddr = m_guid_arg_ref_to->obj_ea; - // Get interface type name - std::string GUIDName; - for (auto g : mProtocols) { + // get interface type name + std::string guid_name; + for (auto g : m_protocols) { if (guidAddr == g["address"]) { - GUIDName = g["prot_name"]; + guid_name = g["prot_name"]; break; } } - if (GUIDName.empty()) { + if (guid_name.empty()) { return 0; } - std::string interfaceTypeName = GUIDName.substr(0, GUIDName.find("_GUID")); - if (!interfaceTypeName.find("FCH_")) { + std::string interface_type_name = + guid_name.substr(0, guid_name.find("_GUID")); + if (!interface_type_name.find("FCH_")) { // convert FCH_SMM_* dispatcher type to EFI_SMM_* dispatcher type - interfaceTypeName.replace(0, 4, "EFI_"); + interface_type_name.replace(0, 4, "EFI_"); } - // Need to get the type for the interface variable here + // need to get the type for the interface variable here tinfo_t tif; - import_type(get_idati(), -1, interfaceTypeName.c_str()); - if (!tif.get_named_type(get_idati(), interfaceTypeName.c_str())) { - // Get the referent for the interface argument. - cexpr_t *outArgReferent = GetReferent(mOutArg, "ptr", true); - if (outArgReferent == nullptr) + import_type(get_idati(), -1, interface_type_name.c_str()); + if (!tif.get_named_type(get_idati(), interface_type_name.c_str())) { + // get the referent for the interface argument + cexpr_t *out_arg_referent = get_referent(m_out_arg, "ptr", true); + if (out_arg_referent == nullptr) return 0; - ApplyName(outArgReferent, interfaceTypeName); + apply_name(out_arg_referent, interface_type_name); return 0; } - qstring tStr; - if (!tif.get_type_name(&tStr)) { + qstring tstr; + if (!tif.get_type_name(&tstr)) { return 0; } - tinfo_t tifGuidPtr; - if (!tifGuidPtr.create_ptr(tif)) { + tinfo_t tif_guid_ptr; + if (!tif_guid_ptr.create_ptr(tif)) { return 0; } - // Get the referent for the interface argument. - cexpr_t *outArgReferent = GetReferent(mOutArg, "ptr", true); - if (outArgReferent == nullptr) + // get the referent for the interface argument + cexpr_t *out_arg_referent = get_referent(m_out_arg, "ptr", true); + if (out_arg_referent == nullptr) return 0; - // Apply the type to the output referent. - ApplyType(outArgReferent, tifGuidPtr, tStr); + // apply the type to the output referent + apply_type(out_arg_referent, tif_guid_ptr, tstr); return 1; } protected: - unsigned int mNumApplied; + unsigned int m_num_applied; - // Given an expression (either a local or global variable) and a type to + // given an expression (either a local or global variable) and a type to // apply, apply the type. This is just a bit of IDA/Hex-Rays type system - // skullduggery. - void ApplyType(cexpr_t *outArg, tinfo_t ptrTif, qstring tStr) { + // skullduggery + void apply_type(cexpr_t *outArg, tinfo_t ptrTif, qstring tstr) { ea_t dest_ea = outArg->obj_ea; - // For global variables + // for global variables if (outArg->op == cot_obj) { - // Just apply the type information to the address + // just apply the type information to the address apply_tinfo(dest_ea, ptrTif, TINFO_DEFINITE); - ++mNumApplied; + ++m_num_applied; - // Rename global variable + // rename global variable auto name = - "g" + efi_utils::type_to_name(static_cast(tStr.c_str())); + "g" + efi_utils::type_to_name(static_cast(tstr.c_str())); set_name(dest_ea, name.c_str(), SN_FORCE); - // Get xrefs to global variable + // get xrefs to global variable auto xrefs = efi_utils::get_xrefs(dest_ea); qstring type_name; ptr_type_data_t pi; ptrTif.get_ptr_details(&pi); pi.obj_type.get_type_name(&type_name); - // Handling all interface functions (to rename function arguments) + + // handling all interface functions (to rename function arguments) efi_utils::op_stroff_for_global_interface(xrefs, type_name); - } else if (outArg->op == cot_var) { // For local variables - var_ref_t varRef = outArg->v; - lvar_t &destVar = varRef.mba->vars[varRef.idx]; - // Set the Hex-Rays variable type + } else if (outArg->op == cot_var) { // for local variables + var_ref_t var_ref = outArg->v; + lvar_t &dest_var = var_ref.mba->vars[var_ref.idx]; + + // set the Hex-Rays variable type auto name = - efi_utils::type_to_name(static_cast(tStr.c_str())); - set_lvar_name(static_cast(name.c_str()), destVar, mFuncEa); - if (set_hexrays_var_info_and_handle_interfaces(mFuncEa, destVar, ptrTif, - name)) { - ++mNumApplied; + efi_utils::type_to_name(static_cast(tstr.c_str())); + set_lvar_name(static_cast(name.c_str()), dest_var, m_func_ea); + if (set_hexrays_var_info_and_handle_interfaces(m_func_ea, dest_var, + ptrTif, name)) { + ++m_num_applied; } } } - void ApplyName(cexpr_t *outArg, std::string type_name) { + void apply_name(cexpr_t *outArg, std::string type_name) { ea_t dest_ea = outArg->obj_ea; - // For global variables + // for global variables if (outArg->op == cot_obj) { - // Rename global variable + // rename global variable auto name = "g" + efi_utils::type_to_name(type_name); set_name(dest_ea, name.c_str(), SN_FORCE); - } else if (outArg->op == cot_var) { // For local variables - var_ref_t varRef = outArg->v; - lvar_t &destVar = varRef.mba->vars[varRef.idx]; - // Set the Hex-Rays variable type + } else if (outArg->op == cot_var) { // for local variables + var_ref_t var_ref = outArg->v; + lvar_t &dest_var = var_ref.mba->vars[var_ref.idx]; + // set the Hex-Rays variable type auto name = efi_utils::type_to_name(type_name); - set_lvar_name(static_cast(name.c_str()), destVar, mFuncEa); + set_lvar_name(static_cast(name.c_str()), dest_var, m_func_ea); } } }; -class VariablesInfoExtractor : public ctree_visitor_t { +class variables_info_extractor_t : public ctree_visitor_t { public: - explicit VariablesInfoExtractor(ea_t code_addr) : ctree_visitor_t(CV_FAST) { - mCodeAddr = code_addr; + explicit variables_info_extractor_t(ea_t code_addr) + : ctree_visitor_t(CV_FAST) { + m_code_addr = code_addr; } - uint8_t mAttributes = 0xff; + uint8_t m_attributes = 0xff; - // This is the callback function that Hex-Rays invokes for every expression - // in the CTREE. + // this is the callback function that Hex-Rays invokes for every expression + // in the CTREE int visit_expr(cexpr_t *e) { - if (mCodeAddr == BADADDR) { + if (m_code_addr == BADADDR) { return 0; } - if (e->ea != mCodeAddr) { + if (e->ea != m_code_addr) { return 0; } @@ -640,30 +620,30 @@ class VariablesInfoExtractor : public ctree_visitor_t { cexpr_t *attributes_arg = &args->at(2); if (attributes_arg->op == cot_num) { - if (mDebug) { - msg("[I] Service call: %016llX, Attributes: %02X\n", - u64_addr(mCodeAddr), - static_cast(attributes_arg->numval())); + if (m_debug) { + efi_utils::log("service call: %016llX, attributes: %02X\n", + u64_addr(m_code_addr), + static_cast(attributes_arg->numval())); } attributes_arg->numval(); - mAttributes = static_cast(attributes_arg->numval()); + m_attributes = static_cast(attributes_arg->numval()); } return 0; } protected: - ea_t mCodeAddr = BADADDR; - bool mDebug = false; + ea_t m_code_addr = BADADDR; + bool m_debug = false; }; -class PrototypesFixer : public ctree_visitor_t { +class prototypes_fixer_t : public ctree_visitor_t { public: - PrototypesFixer() : ctree_visitor_t(CV_FAST) {} - ea_list_t child_functions; + prototypes_fixer_t() : ctree_visitor_t(CV_FAST) {} + ea_list_t m_child_functions; - // This is the callback function that Hex-Rays invokes for every expression - // in the CTREE. + // this is the callback function that Hex-Rays invokes for every expression + // in the CTREE int visit_expr(cexpr_t *e) { if (e->op != cot_call) return 0; @@ -672,8 +652,9 @@ class PrototypesFixer : public ctree_visitor_t { if (e->x->op != cot_obj) { return 0; } - if (mDebug) { - msg("[I] Child function address: %016llX\n", u64_addr(e->x->obj_ea)); + if (m_debug) { + efi_utils::log("child function address: %016llX\n", + u64_addr(e->x->obj_ea)); } carglist_t *args = e->a; @@ -694,7 +675,9 @@ class PrototypesFixer : public ctree_visitor_t { return 0; } - msg("[I] Call address: 0x%016llX\n", u64_addr(e->ea)); + if (m_debug) { + efi_utils::log("call address: 0x%016llX\n", u64_addr(e->ea)); + } for (auto i = 0; i < args->size(); i++) { cexpr_t *arg = &args->at(i); if (arg->op == cot_cast || arg->op == cot_var) { @@ -717,27 +700,28 @@ class PrototypesFixer : public ctree_visitor_t { bool is_ptr = false; if (!arg_type.get_type_name(&type_name)) { if (!arg_type_no_ptr.get_type_name(&type_name)) { - // msg("[E] Can not get type name: 0x%016llX\n", u64_addr(e->ea)); continue; } is_ptr = true; } if (is_ptr) { - msg("[I] Arg #%d, type = %s *\n", i, type_name.c_str()); + efi_utils::log("arg #%d, type = %s *\n", i, type_name.c_str()); } else { - msg("[I] Arg #%d, type = %s\n", i, type_name.c_str()); + efi_utils::log("arg #%d, type = %s\n", i, type_name.c_str()); } if (type_name == qstring("EFI_HANDLE") || type_name == qstring("EFI_SYSTEM_TABLE")) { - if (!efi_utils::addr_in_vec(child_functions, func_addr)) { - child_functions.push_back(func_addr); + if (!efi_utils::addr_in_vec(m_child_functions, func_addr)) { + m_child_functions.push_back(func_addr); } + // set argument type and name if (cf->argidx.size() <= i) { return 0; } + auto argid = cf->argidx[i]; lvar_t &arg_var = cf->mba->vars[argid]; // get lvar for argument if (type_name == qstring("EFI_HANDLE")) { @@ -754,29 +738,29 @@ class PrototypesFixer : public ctree_visitor_t { } protected: - bool mDebug = true; + bool m_debug = true; }; -class VariablesDetector : public ctree_visitor_t { +class variables_detector_t : public ctree_visitor_t { public: - VariablesDetector() : ctree_visitor_t(CV_FAST) {} + variables_detector_t() : ctree_visitor_t(CV_FAST) {} - ea_list_t child_functions; + ea_list_t m_child_functions; - ea_list_t image_handle_list; - ea_list_t st_list; - ea_list_t bs_list; - ea_list_t rt_list; + ea_list_t m_image_handle_list; + ea_list_t m_st_list; + ea_list_t m_bs_list; + ea_list_t m_rt_list; - void SetFuncEa(ea_t ea) { mFuncEa = ea; } + void set_func_ea(ea_t ea) { m_func_ea = ea; } - // This is the callback function that Hex-Rays invokes for every expression - // in the CTREE. + // this is the callback function that Hex-Rays invokes for every expression + // in the CTREE int visit_expr(cexpr_t *e) { if (e->op == cot_asg) { // saving a child function for recursive analysis - if (!efi_utils::addr_in_vec(child_functions, e->ea)) { - child_functions.push_back(e->x->obj_ea); + if (!efi_utils::addr_in_vec(m_child_functions, e->ea)) { + m_child_functions.push_back(e->x->obj_ea); } } @@ -821,15 +805,14 @@ class VariablesDetector : public ctree_visitor_t { bool is_ptr = false; if (!var_type.get_type_name(&type_name)) { if (!var_type_no_ptr.get_type_name(&type_name)) { - // msg("[E] can not get type name: 0x%016llX\n", u64_addr(e->ea)); return 0; } is_ptr = true; } - if (mDebug) { - msg("[I] code address: 0x%016llX, type name: %s\n", u64_addr(e->ea), - type_name.c_str()); + if (m_debug) { + efi_utils::log("code address: 0x%016llX, type name: %s\n", + u64_addr(e->ea), type_name.c_str()); } if (global_var) { @@ -838,26 +821,26 @@ class VariablesDetector : public ctree_visitor_t { std::string type_name_str = static_cast(type_name.c_str()); if (type_name == qstring("EFI_HANDLE")) { efi_utils::set_type_and_name(g_addr, "gImageHandle", type_name_str); - if (!efi_utils::addr_in_vec(image_handle_list, g_addr)) { - image_handle_list.push_back(g_addr); + if (!efi_utils::addr_in_vec(m_image_handle_list, g_addr)) { + m_image_handle_list.push_back(g_addr); } } if (type_name == qstring("EFI_SYSTEM_TABLE")) { efi_utils::set_ptr_type_and_name(g_addr, "gST", type_name_str); - if (!efi_utils::addr_in_vec(st_list, g_addr)) { - st_list.push_back(g_addr); + if (!efi_utils::addr_in_vec(m_st_list, g_addr)) { + m_st_list.push_back(g_addr); } } if (type_name == qstring("EFI_BOOT_SERVICES")) { efi_utils::set_ptr_type_and_name(g_addr, "gBS", type_name_str); - if (!efi_utils::addr_in_vec(bs_list, g_addr)) { - bs_list.push_back(g_addr); + if (!efi_utils::addr_in_vec(m_bs_list, g_addr)) { + m_bs_list.push_back(g_addr); } } if (type_name == qstring("EFI_RUNTIME_SERVICES")) { efi_utils::set_ptr_type_and_name(g_addr, "gRT", type_name_str); - if (!efi_utils::addr_in_vec(rt_list, g_addr)) { - rt_list.push_back(g_addr); + if (!efi_utils::addr_in_vec(m_rt_list, g_addr)) { + m_rt_list.push_back(g_addr); } } } @@ -870,30 +853,32 @@ class VariablesDetector : public ctree_visitor_t { if (e->y->op == cot_cast) { var_ref = e->y->x->v; } + lvar_t &dest_var = var_ref.mba->vars[var_ref.idx]; - // Set the Hex-Rays variable type + + // set the Hex-Rays variable type auto name = efi_utils::type_to_name(static_cast(type_name.c_str())); - // set_hexrays_var_info(mFuncEa, dest_var, var_type, name); + // set_hexrays_var_info(m_func_ea, dest_var, var_type, name); } return 0; } protected: - bool mDebug = true; - ea_t mFuncEa = BADADDR; + bool m_debug = true; + ea_t m_func_ea = BADADDR; }; -class ServicesDetector : public ctree_visitor_t { +class services_detector_t : public ctree_visitor_t { // detect all services (Boot services, Runtime services, etc) public: - ServicesDetector() : ctree_visitor_t(CV_FAST) {} + services_detector_t() : ctree_visitor_t(CV_FAST) {} - json_list_t services; + json_list_t m_services; - // This is the callback function that Hex-Rays invokes for every expression - // in the CTREE. + // this is the callback function that Hex-Rays invokes for every expression + // in the CTREE int visit_expr(cexpr_t *e) { if (e->op != cot_call) { return 0; @@ -907,6 +892,7 @@ class ServicesDetector : public ctree_visitor_t { auto e_func = e->x->x; tinfo_t func_type; tinfo_t func_type_no_ptr; + func_type = e_func->type; if (func_type.is_ptr()) { @@ -937,28 +923,26 @@ class ServicesDetector : public ctree_visitor_t { msg("[efiXplorer] address: 0x%016llX, service type: %s, service name: %s\n", u64_addr(e->ea), type_name.c_str(), service_name.c_str()); - // append service - // add item to allBootServices json s; s["address"] = e->ea; s["service_name"] = service_name; s["table_name"] = efi_utils::get_table_name(service_name); - if (!efi_utils::json_in_vec(services, s)) { - services.push_back(s); + if (!efi_utils::json_in_vec(m_services, s)) { + m_services.push_back(s); } return 0; } protected: - bool mDebug = true; + bool m_debug = true; }; -class PeiServicesDetector : public ctree_visitor_t { +class pei_services_detector_t : public ctree_visitor_t { // detect and mark all PEI services public: - PeiServicesDetector() : ctree_visitor_t(CV_FAST) {} + pei_services_detector_t() : ctree_visitor_t(CV_FAST) {} bool make_shifted_ptr(tinfo_t outer, tinfo_t inner, int32 offset, tinfo_t *shifted_tif) { @@ -978,8 +962,8 @@ class PeiServicesDetector : public ctree_visitor_t { return modify_user_lvar_info(func_ea, MLI_TYPE, lsi); } - // This is the callback function that Hex-Rays invokes for every expression - // in the CTREE. + // this is the callback function that Hex-Rays invokes for every expression + // in the CTREE int visit_expr(cexpr_t *e) { auto pointer_offset = BADADDR; auto service_offset = BADADDR; @@ -1008,17 +992,12 @@ class PeiServicesDetector : public ctree_visitor_t { return 0; } - msg("[efiXplorer] address: 0x%08llX, PEI service detected\n", - u64_addr(e->ea)); - msg("[efiXplorer] delta: %llx\n", u64_addr(pointer_offset)); - if (service_offset != BADADDR) { - msg("[efiXplorer] service offset: %llx\n", u64_addr(service_offset)); - } - if (pointer_offset != 4) { return 0; } + efi_utils::log("PEI service detected at 0x%08llX\n", u64_addr(e->ea)); + tinfo_t outer; if (!outer.get_named_type(get_idati(), "EFI_PEI_SERVICES_4", BTF_STRUCT)) { return 0; @@ -1035,7 +1014,7 @@ class PeiServicesDetector : public ctree_visitor_t { return 0; } if (set_var_type(func->start_ea, dest_var, shifted_tif)) { - msg("[efiXplorer] shifted pointer applied (0x%08llX)\n", u64_addr(e->ea)); + efi_utils::log("shifted pointer applied at 0x%08llX\n", u64_addr(e->ea)); } if (call) { @@ -1046,19 +1025,19 @@ class PeiServicesDetector : public ctree_visitor_t { } protected: - bool mDebug = true; + bool m_debug = true; }; -class PeiServicesDetectorArm : public ctree_visitor_t { +class pei_services_detector_arm_t : public ctree_visitor_t { // detect and mark all PEI services for ARM firmware // tested on Ampere firmware that contains small PEI stack public: - PeiServicesDetectorArm() : ctree_visitor_t(CV_FAST) {} + pei_services_detector_arm_t() : ctree_visitor_t(CV_FAST) {} - json_list_t services; + json_list_t m_services; - // This is the callback function that Hex-Rays invokes for every expression - // in the CTREE. + // this is the callback function that Hex-Rays invokes for every expression + // in the CTREE int visit_expr(cexpr_t *e) { if (!(e->op == cot_call && e->x->op == cot_memptr && e->x->x->op == cot_ptr && e->x->x->x->op == cot_var)) { @@ -1090,16 +1069,16 @@ class PeiServicesDetectorArm : public ctree_visitor_t { } service_name = efi_utils::type_to_name(func_type); } else { - auto s = mPeiServices.find(offset); - if (s == mPeiServices.end()) { + auto s = m_pei_services.find(offset); + if (s == m_pei_services.end()) { return 0; } service_name = s->second; } - if (mDebug) { - msg("[efiXplorer] 0x%08llX: %s service detected (offset: %d): %s\n", - u64_addr(e->ea), table_type_name.c_str(), u32_addr(offset), - service_name.c_str()); + if (m_debug) { + efi_utils::log("0x%08llX: %s service detected (offset: %d): %s\n", + u64_addr(e->ea), table_type_name.c_str(), u32_addr(offset), + service_name.c_str()); } json s; @@ -1107,16 +1086,16 @@ class PeiServicesDetectorArm : public ctree_visitor_t { s["service_name"] = service_name; s["table_name"] = table_type_name.c_str(); - if (!efi_utils::json_in_vec(services, s)) { - services.push_back(s); + if (!efi_utils::json_in_vec(m_services, s)) { + m_services.push_back(s); } return 0; } protected: - bool mDebug = true; - std::map mPeiServices = { + bool m_debug = true; + std::map m_pei_services = { {0x18, "InstallPpi"}, {0x20, "ReInstallPpi"}, {0x28, "LocatePpi"}, @@ -1146,3 +1125,4 @@ class PeiServicesDetectorArm : public ctree_visitor_t { {0xE8, "ResetSystem3"}, }; }; +} // namespace efi_hexrays From 3ece3350b8ae45fb97d0bb840b37bda97190dd28 Mon Sep 17 00:00:00 2001 From: yeggor Date: Fri, 20 Sep 2024 05:22:23 +0100 Subject: [PATCH 40/69] initial refactoring for efi_analysis_x86 --- efiXplorer/efi_analysis_x86.cc | 634 +++++++++++++++------------------ efiXplorer/efi_hexrays.h | 7 +- 2 files changed, 301 insertions(+), 340 deletions(-) diff --git a/efiXplorer/efi_analysis_x86.cc b/efiXplorer/efi_analysis_x86.cc index 9b5bd054..cd15eb4a 100644 --- a/efiXplorer/efi_analysis_x86.cc +++ b/efiXplorer/efi_analysis_x86.cc @@ -98,9 +98,7 @@ efi_analysis::efi_analyser_t::efi_analyser_t() { in >> m_guiddb; } catch (std::exception &e) { m_guiddb.clear(); - std::string msg_text = "guids.json file is invalid, check its contents"; - msg("[%s] %s\n", g_plugin_name, msg_text.c_str()); - warning("%s: %s\n", g_plugin_name, msg_text.c_str()); + warning("%s: %s\n", g_plugin_name, "guids.json file is invalid"); } // get reverse dictionary @@ -159,16 +157,16 @@ void efi_analysis::efi_analyser_t::set_pvalues() { } //-------------------------------------------------------------------------- -// Get all .text and .data segments +// get all .text and .data segments void efi_analysis::efi_analyser_t::get_segments() { for (segment_t *s = get_first_seg(); s != nullptr; s = get_next_seg(s->start_ea)) { qstring seg_name; get_segm_name(&seg_name, s); - string_list_t codeSegNames{".text", - ".code"}; // for compatibility with ida-efitools2 - for (auto name : codeSegNames) { + string_list_t code_seg_names{ + ".text", ".code"}; // for compatibility with ida-efitools2 + for (auto name : code_seg_names) { auto index = seg_name.find(name.c_str()); if (index != std::string::npos) { // fix permissions and class for code segment @@ -190,35 +188,33 @@ void efi_analysis::efi_analyser_t::get_segments() { // print all .text and .code segments addresses for (auto seg : code_segs) { segment_t *s = seg; - msg("[%s] code segment: 0x%016llX\n", g_plugin_name, u64_addr(s->start_ea)); + efi_utils::log("code segment: 0x%016llX\n", u64_addr(s->start_ea)); } // print all .data segments addresses for (auto seg : data_segs) { segment_t *s = seg; - msg("[%s] data segment: 0x%016llX\n", g_plugin_name, u64_addr(s->start_ea)); + efi_utils::log("data segment: 0x%016llX\n", u64_addr(s->start_ea)); } } +// TODO(yeggor): +// merge find_image_handle64 and find_system_table64 + //-------------------------------------------------------------------------- -// Find gImageHandle address for X64 modules +// find gImageHandle address for 64-bit modules bool efi_analysis::efi_analyser_x86_t::find_image_handle64() { - msg("[%s] gImageHandle finding\n", g_plugin_name); insn_t insn; for (int idx = 0; idx < get_entry_qty(); idx++) { // get address of entry point uval_t ord = get_entry_ordinal(idx); ea_t ea = get_entry(ord); - // EFI_IMAGE_HANDLE finding, first 8 instructions checking + // search for EFI_IMAGE_HANDLE, check 8 instructions for (auto i = 0; i < 8; i++) { decode_insn(&insn, ea); if (insn.itype == NN_mov && insn.ops[1].type == o_reg && insn.ops[1].reg == R_RCX && insn.ops[0].type == o_mem) { - msg("[%s] found ImageHandle at 0x%016llX, address = 0x%016llX\n", - g_plugin_name, u64_addr(ea), u64_addr(insn.ops[0].addr)); - - // set type and name efi_utils::set_type_and_name(insn.ops[0].addr, "gImageHandle", "EFI_IMAGE_HANDLE"); image_handle_list.push_back(insn.ops[0].addr); @@ -231,16 +227,15 @@ bool efi_analysis::efi_analyser_x86_t::find_image_handle64() { } //-------------------------------------------------------------------------- -// Find gST address for X64 modules +// find gST address for 64-bit modules bool efi_analysis::efi_analyser_x86_t::find_system_table64() { - msg("[%s] gEfiSystemTable finding\n", g_plugin_name); insn_t insn; for (int idx = 0; idx < get_entry_qty(); idx++) { // get address of entry point uval_t ord = get_entry_ordinal(idx); ea_t ea = get_entry(ord); - // EFI_SYSTEM_TABLE finding, first 16 instructions checking + // search for EFI_SYSTEM_TABLE, check 16 instructions for (int i = 0; i < 16; i++) { decode_insn(&insn, ea); if (insn.itype == NN_mov && insn.ops[1].type == o_reg && @@ -257,33 +252,34 @@ bool efi_analysis::efi_analyser_x86_t::find_system_table64() { } //-------------------------------------------------------------------------- -// Find and mark gSmst global variable address for X64 module +// find and mark gSmst global variable for 64-bit modules bool efi_analysis::efi_analyser_x86_t::find_smst64() { - msg("[%s] gSmst finding\n", g_plugin_name); - ea_list_t smst_listSmmBase = efi_smm_utils::find_smst_smm_base(bs_list); - ea_list_t smst_listSwDispatch = efi_smm_utils::find_smst_sw_dispatch(bs_list); - smst_list.insert(smst_list.end(), smst_listSwDispatch.begin(), - smst_listSwDispatch.end()); - smst_list.insert(smst_list.end(), smst_listSmmBase.begin(), - smst_listSmmBase.end()); - - // Deduplicate + ea_list_t smst_list_smm_base = efi_smm_utils::find_smst_smm_base(bs_list); + ea_list_t smst_list_sw_dispatch = + efi_smm_utils::find_smst_sw_dispatch(bs_list); + smst_list.insert(smst_list.end(), smst_list_sw_dispatch.begin(), + smst_list_sw_dispatch.end()); + smst_list.insert(smst_list.end(), smst_list_smm_base.begin(), + smst_list_smm_base.end()); + + // deduplicate auto last = std::unique(smst_list.begin(), smst_list.end()); smst_list.erase(last, smst_list.end()); for (auto smst : smst_list) { - msg("[%s] 0x%016llX: gSmst\n", g_plugin_name, u64_addr(smst)); + efi_utils::log("0x%016llX: gSmst\n", u64_addr(smst)); } - return smst_list.size(); + + return !smst_list.empty(); } //-------------------------------------------------------------------------- -// Find and mark gSmst global and local variable address for X64 module -// after Hex-Rays based analysis +// find and mark gSmst global and local variable address for 64-bit +// modules after Hex-Rays based analysis bool efi_analysis::efi_analyser_x86_t::find_smst_postproc64() { for (auto ea : g_get_smst_location_calls) { - msg("[%s] EfiSmmBase2Protocol->GetSmstLocation call: 0x%016llX\n", - g_plugin_name, u64_addr(ea)); + efi_utils::log("EfiSmmBase2Protocol->GetSmstLocation call: 0x%016llX\n", + u64_addr(ea)); insn_t insn; auto addr = ea; ea_t smst_addr = BADADDR; @@ -316,14 +312,14 @@ bool efi_analysis::efi_analyser_x86_t::find_smst_postproc64() { } } - // Exit loop if end of previous basic block found + // exit loop if end of previous basic block found if (is_basic_block_end(insn, false)) { break; } } if (smst_stack.is_null() && smst_addr != BADADDR) { - msg("[%s] gSmst: 0x%016llX\n", g_plugin_name, u64_addr(smst_addr)); + efi_utils::log(" gSmst: 0x%016llX\n", u64_addr(smst_addr)); if (!efi_utils::addr_in_vec(smst_list, smst_addr)) { efi_utils::set_ptr_type_and_name(smst_addr, "gSmst", "_EFI_SMM_SYSTEM_TABLE2"); @@ -333,8 +329,8 @@ bool efi_analysis::efi_analyser_x86_t::find_smst_postproc64() { if (!smst_stack.is_null()) { auto reg = smst_stack["reg"] == R_RSP ? "RSP" : "RBP"; - msg("[%s] Smst: 0x%016llX, reg = %s\n", g_plugin_name, - u64_addr(smst_addr), reg); + efi_utils::log(" Smst: 0x%016llX, reg = %s\n", u64_addr(smst_addr), + reg); // try to extract ChildSwSmiHandler auto counter = 0; @@ -368,7 +364,7 @@ bool efi_analysis::efi_analyser_x86_t::find_smst_postproc64() { } } - // Save potencial ChildSwSmiHandler address + // save potencial ChildSwSmiHandler address if (insn.itype == NN_lea && insn.ops[0].type == o_reg && insn.ops[0].reg == R_RCX && insn.ops[1].type == o_mem) { rcx_last = insn.ops[1].addr; @@ -381,6 +377,7 @@ bool efi_analysis::efi_analyser_x86_t::find_smst_postproc64() { if (insn.itype == NN_callni && insn.ops[0].type == o_displ && insn.ops[0].reg == smst_reg && insn.ops[0].addr == 0xe0) { efi_utils::op_stroff(ea, "_EFI_SMM_SYSTEM_TABLE2"); + // save child SW SMI handler func_t *handler_func = get_func(rcx_last); if (handler_func != nullptr) { @@ -397,9 +394,9 @@ bool efi_analysis::efi_analyser_x86_t::find_smst_postproc64() { } //-------------------------------------------------------------------------- -// Find gBS addresses for 32-bit/64-bit modules +// find gBS addresses for 32-bit and 64-bit modules bool efi_analysis::efi_analyser_x86_t::find_boot_services_tables() { - // init architecture-specific constants + // init architecture specific constants auto BS_OFFSET = BS_OFFSET_64; uint16_t R_SP = static_cast(R_RSP); @@ -411,11 +408,9 @@ bool efi_analysis::efi_analyser_x86_t::find_boot_services_tables() { insn_t insn; for (auto seg : code_segs) { segment_t *s = seg; - msg("[%s] gEfiBootServices finding from 0x%016llX to 0x%016llX\n", - g_plugin_name, u64_addr(s->start_ea), u64_addr(s->end_ea)); ea_t ea = s->start_ea; - uint16_t bsRegister = 0; - uint16_t stRegister = 0; + uint16_t bs_reg = 0; + uint16_t st_reg = 0; ea_t var_addr = BADADDR; // current global variable address while (ea <= s->end_ea) { ea = next_head(ea, m_end_addr); @@ -423,13 +418,13 @@ bool efi_analysis::efi_analyser_x86_t::find_boot_services_tables() { if (insn.itype == NN_mov && insn.ops[1].type == o_displ && insn.ops[1].phrase != R_SP) { if (insn.ops[0].type == o_reg && insn.ops[1].addr == BS_OFFSET) { - auto bsFound = false; - auto stFound = false; - ea_t baseInsnAddr = BADADDR; - bsRegister = insn.ops[0].reg; - stRegister = insn.ops[1].phrase; + auto bs_found = false; + auto st_found = false; + ea_t base_insn_addr = BADADDR; + bs_reg = insn.ops[0].reg; + st_reg = insn.ops[1].phrase; - // found BS_OFFSET, need to check 10 instructions below + // found BS_OFFSET, check 10 instructions below for (auto i = 0; i < 10; i++) { ea = next_head(ea, m_end_addr); decode_insn(&insn, ea); @@ -444,33 +439,32 @@ bool efi_analysis::efi_analyser_x86_t::find_boot_services_tables() { next_insn.ops[0].type == o_phrase && next_insn.ops[0].phrase == phrase_reg && next_insn.ops[1].type == o_reg && - next_insn.ops[1].reg == bsRegister) { - baseInsnAddr = ea; + next_insn.ops[1].reg == bs_reg) { + base_insn_addr = ea; if (!efi_utils::addr_in_vec(bs_list, var_addr)) { efi_utils::set_ptr_type_and_name(var_addr, "gBS", "EFI_BOOT_SERVICES"); bs_list.push_back(var_addr); } - bsFound = true; + bs_found = true; } } if (insn.itype == NN_mov && insn.ops[1].type == o_reg && insn.ops[0].type == o_mem) { - if (insn.ops[1].reg == bsRegister && !bsFound) { - baseInsnAddr = ea; + if (insn.ops[1].reg == bs_reg && !bs_found) { + base_insn_addr = ea; var_addr = insn.ops[0].addr; if (!efi_utils::addr_in_vec(bs_list, var_addr)) { efi_utils::set_ptr_type_and_name(var_addr, "gBS", "EFI_BOOT_SERVICES"); bs_list.push_back(var_addr); } - bsFound = true; + bs_found = true; } // here you can also find gST - if (insn.ops[1].reg == stRegister && !stFound && - stRegister != bsRegister) { + if (insn.ops[1].reg == st_reg && !st_found && st_reg != bs_reg) { var_addr = insn.ops[0].addr; if (!efi_utils::addr_in_tables(st_list, bs_list, rt_list, var_addr)) { @@ -478,23 +472,22 @@ bool efi_analysis::efi_analyser_x86_t::find_boot_services_tables() { "EFI_SYSTEM_TABLE"); st_list.push_back(var_addr); } - stFound = true; + st_found = true; } } - if (bsFound && stFound) { + if (bs_found && st_found) { break; } - if (bsFound && !stFound) { - // check 8 instructions above baseInsnAddr - auto addr = baseInsnAddr; + if (bs_found && !st_found) { + // check 8 instructions above base_insn_addr + auto addr = base_insn_addr; for (auto i = 0; i < 8; i++) { addr = prev_head(addr, m_start_addr); decode_insn(&insn, addr); if (insn.itype == NN_mov && insn.ops[1].type == o_reg && - insn.ops[1].reg == stRegister && - insn.ops[0].type == o_mem) { + insn.ops[1].reg == st_reg && insn.ops[0].type == o_mem) { var_addr = insn.ops[0].addr; if (!efi_utils::addr_in_tables(st_list, bs_list, rt_list, var_addr)) { @@ -502,7 +495,7 @@ bool efi_analysis::efi_analyser_x86_t::find_boot_services_tables() { "EFI_SYSTEM_TABLE"); st_list.push_back(var_addr); } - stFound = true; + st_found = true; break; } } @@ -512,13 +505,13 @@ bool efi_analysis::efi_analyser_x86_t::find_boot_services_tables() { } } } - return (bs_list.size() != 0); + return !bs_list.empty(); } //-------------------------------------------------------------------------- -// Find gRT addresses for X86/X64 modules +// find gRT addresses for 32-bit and 64-bit modules bool efi_analysis::efi_analyser_x86_t::find_runtime_services_tables() { - // init architecture-specific constants + // init architecture specific constants auto RT_OFFSET = RT_OFFSET_64; uint16_t R_SP = static_cast(R_RSP); @@ -530,11 +523,9 @@ bool efi_analysis::efi_analyser_x86_t::find_runtime_services_tables() { insn_t insn; for (auto seg : code_segs) { segment_t *s = seg; - msg("[%s] gEfiRuntimeServices finding from 0x%016llX to 0x%016llX\n", - g_plugin_name, u64_addr(s->start_ea), u64_addr(s->end_ea)); ea_t ea = s->start_ea; - uint16_t rtRegister = 0; - uint16_t stRegister = 0; + uint16_t rt_register = 0; + uint16_t st_reg = 0; ea_t var_addr = BADADDR; // current global variable address while (ea <= s->end_ea) { ea = next_head(ea, m_end_addr); @@ -542,13 +533,13 @@ bool efi_analysis::efi_analyser_x86_t::find_runtime_services_tables() { if (insn.itype == NN_mov && insn.ops[1].type == o_displ && insn.ops[1].phrase != R_SP) { if (insn.ops[0].type == o_reg && insn.ops[1].addr == RT_OFFSET) { - rtRegister = insn.ops[0].reg; - stRegister = insn.ops[1].phrase; - auto rtFound = false; - auto stFound = false; - ea_t baseInsnAddr; + rt_register = insn.ops[0].reg; + st_reg = insn.ops[1].phrase; + auto rt_found = false; + auto st_found = false; + ea_t base_insn_addr; - // found RT_OFFSET, need to check 10 instructions below + // found RT_OFFSET, check 10 instructions below for (auto i = 0; i < 10; i++) { ea = next_head(ea, m_end_addr); decode_insn(&insn, ea); @@ -563,33 +554,33 @@ bool efi_analysis::efi_analyser_x86_t::find_runtime_services_tables() { next_insn.ops[0].type == o_phrase && next_insn.ops[0].phrase == phrase_reg && next_insn.ops[1].type == o_reg && - next_insn.ops[1].reg == rtRegister) { - baseInsnAddr = ea; + next_insn.ops[1].reg == rt_register) { + base_insn_addr = ea; if (!efi_utils::addr_in_vec(rt_list, var_addr)) { efi_utils::set_ptr_type_and_name(var_addr, "gRT", "EFI_RUNTIME_SERVICES"); rt_list.push_back(var_addr); } - rtFound = true; + rt_found = true; } } if (insn.itype == NN_mov && insn.ops[1].type == o_reg && insn.ops[0].type == o_mem) { - if (insn.ops[1].reg == rtRegister && !rtFound) { - baseInsnAddr = ea; + if (insn.ops[1].reg == rt_register && !rt_found) { + base_insn_addr = ea; var_addr = insn.ops[0].addr; if (!efi_utils::addr_in_vec(rt_list, var_addr)) { efi_utils::set_ptr_type_and_name(var_addr, "gRT", "EFI_RUNTIME_SERVICES"); rt_list.push_back(var_addr); } - rtFound = true; + rt_found = true; } // here you can also find gST - if (insn.ops[1].reg == stRegister && !stFound && - stRegister != rtRegister) { + if (insn.ops[1].reg == st_reg && !st_found && + st_reg != rt_register) { var_addr = insn.ops[0].addr; if (!efi_utils::addr_in_tables(st_list, bs_list, rt_list, var_addr)) { @@ -597,30 +588,29 @@ bool efi_analysis::efi_analyser_x86_t::find_runtime_services_tables() { "EFI_SYSTEM_TABLE"); st_list.push_back(insn.ops[0].addr); } - stFound = true; + st_found = true; } } - if (rtFound && stFound) { + if (rt_found && st_found) { break; } - if (rtFound && !stFound) { - // check 8 instructions above baseInsnAddr - auto addr = baseInsnAddr; + if (rt_found && !st_found) { + // check 8 instructions above base_insn_addr + auto addr = base_insn_addr; for (auto i = 0; i < 8; i++) { addr = prev_head(addr, m_start_addr); decode_insn(&insn, addr); if (insn.itype == NN_mov && insn.ops[1].type == o_reg && - insn.ops[1].reg == stRegister && - insn.ops[0].type == o_mem) { + insn.ops[1].reg == st_reg && insn.ops[0].type == o_mem) { if (!efi_utils::addr_in_tables(st_list, bs_list, rt_list, var_addr)) { efi_utils::set_ptr_type_and_name(var_addr, "gST", "EFI_SYSTEM_TABLE"); st_list.push_back(var_addr); } - stFound = true; + st_found = true; break; } } @@ -630,23 +620,19 @@ bool efi_analysis::efi_analyser_x86_t::find_runtime_services_tables() { } } } - return (rt_list.size() != 0); + + return !rt_list.empty(); } //-------------------------------------------------------------------------- -// Get all boot services by xrefs for X86/X64 modules +// get all boot services by xrefs for 32-bit and 64-bit modules void efi_analysis::efi_analyser_x86_t::get_boot_services_all() { - msg("[%s] BootServices finding (xrefs)\n", g_plugin_name); - - if (!bs_list.size()) { + if (bs_list.empty()) { return; } insn_t insn; for (auto bs : bs_list) { - msg("[%s] BootServices finding by xrefs to gBS (0x%016llX)\n", - g_plugin_name, u64_addr(bs)); - auto xrefs = efi_utils::get_xrefs(bs); for (auto ea : xrefs) { bool found = false; @@ -685,8 +671,7 @@ void efi_analysis::efi_analyser_x86_t::get_boot_services_all() { if (service_offset == u32_addr(offset)) { // additional check for gBS->RegisterProtocolNotify - // (can be confused with - // gSmst->SmmInstallProtocolInterface) + // (can be confused with gSmst->SmmInstallProtocolInterface) if (u32_addr(offset) == 0xa8) { if (!efi_utils::check_boot_service_protocol(addr)) { break; @@ -694,27 +679,26 @@ void efi_analysis::efi_analyser_x86_t::get_boot_services_all() { } efi_utils::op_stroff(addr, "EFI_BOOT_SERVICES"); + efi_utils::log("0x%016llX: %s\n", u64_addr(addr), + g_boot_services_table_all[j].name); - msg("[%s] 0x%016llX : %s\n", g_plugin_name, u64_addr(addr), - static_cast(g_boot_services_table_all[j].name)); m_boot_services[static_cast( g_boot_services_table_all[j].name)] .push_back(addr); - // add item to allBootServices - json bsItem; - bsItem["address"] = addr; - bsItem["service_name"] = g_boot_services_table_all[j].name; - bsItem["table_name"] = "EFI_BOOT_SERVICES"; - bsItem["offset"] = offset; + json s; + s["address"] = addr; + s["service_name"] = g_boot_services_table_all[j].name; + s["table_name"] = "EFI_BOOT_SERVICES"; + s["offset"] = offset; // add code addresses for arguments eavec_t args; get_arg_addrs(&args, addr); - bsItem["args"] = args; + s["args"] = args; - if (!efi_utils::json_in_vec(m_all_services, bsItem)) { - m_all_services.push_back(bsItem); + if (!efi_utils::json_in_vec(m_all_services, s)) { + m_all_services.push_back(s); } found = true; @@ -722,6 +706,7 @@ void efi_analysis::efi_analyser_x86_t::get_boot_services_all() { } } } + if (found) { break; } @@ -731,21 +716,15 @@ void efi_analysis::efi_analyser_x86_t::get_boot_services_all() { } //-------------------------------------------------------------------------- -// Get all runtime services for X86/X64 modules by xrefs +// get all runtime services for 32-bit and 64-bit modules by xrefs void efi_analysis::efi_analyser_x86_t::get_runtime_services_all() { - msg("[%s] RuntimeServices finding (xrefs)\n", g_plugin_name); - - if (!rt_list.size()) { + if (rt_list.empty()) { return; } insn_t insn; for (auto rt : rt_list) { auto xrefs = efi_utils::get_xrefs(rt); - - msg("[%s] RuntimeServices finding by xrefs to gRT (0x%016llX)\n", - g_plugin_name, u64_addr(rt)); - for (auto ea : xrefs) { decode_insn(&insn, ea); @@ -774,33 +753,33 @@ void efi_analysis::efi_analyser_x86_t::get_runtime_services_all() { } for (int j = 0; j < g_runtime_services_table_all_count; j++) { - // architecture-specific variables + // architecture specific variables auto offset = g_runtime_services_table_all[j].offset64; if (m_arch == arch_file_type_t::x86_32) { offset = g_runtime_services_table_all[j].offset32; } if (service_offset == u32_addr(offset)) { efi_utils::op_stroff(addr, "EFI_RUNTIME_SERVICES"); - msg("[%s] 0x%016llX : %s\n", g_plugin_name, u64_addr(addr), - static_cast(g_runtime_services_table_all[j].name)); + efi_utils::log("0x%016llX: %s\n", u64_addr(addr), + g_runtime_services_table_all[j].name); + m_runtime_services_all[static_cast( g_runtime_services_table_all[j].name)] .push_back(addr); - // add item to allRuntimeServices - json rtItem; - rtItem["address"] = addr; - rtItem["service_name"] = g_runtime_services_table_all[j].name; - rtItem["table_name"] = "EFI_RUNTIME_SERVICES"; - rtItem["offset"] = offset; + json s; + s["address"] = addr; + s["service_name"] = g_runtime_services_table_all[j].name; + s["table_name"] = "EFI_RUNTIME_SERVICES"; + s["offset"] = offset; // add code addresses for arguments eavec_t args; get_arg_addrs(&args, addr); - rtItem["args"] = args; + s["args"] = args; - if (!efi_utils::json_in_vec(m_all_services, rtItem)) { - m_all_services.push_back(rtItem); + if (!efi_utils::json_in_vec(m_all_services, s)) { + m_all_services.push_back(s); } runtime_services_list.push_back(addr); break; @@ -813,21 +792,15 @@ void efi_analysis::efi_analyser_x86_t::get_runtime_services_all() { } //-------------------------------------------------------------------------- -// Get all smm services for X64 modules +// get all SMM services for 64-bit modules void efi_analysis::efi_analyser_x86_t::get_smm_services_all64() { - msg("[%s] SmmServices finding (xrefs)\n", g_plugin_name); - - if (!smst_list.size()) { + if (smst_list.empty()) { return; } insn_t insn; for (auto smms : smst_list) { auto xrefs = efi_utils::get_xrefs(smms); - - msg("[%s] SmmServices finding by xref to gSmst (0x%016llX)\n", - g_plugin_name, u64_addr(smms)); - for (auto ea : xrefs) { decode_insn(&insn, ea); @@ -843,7 +816,7 @@ void efi_analysis::efi_analyser_x86_t::get_smm_services_all64() { for (auto i = 0; i < 10; i++) { addr = next_head(addr, BADADDR); decode_insn(&insn, addr); - // Add NN_jmpni insn type to handle such cases + // add NN_jmpni insn type to handle such cases // jmp qword ptr [r9+0D0h] if ((insn.itype == NN_callni || insn.itype == NN_jmpni) && insn.ops[0].reg == smst_reg) { @@ -852,20 +825,20 @@ void efi_analysis::efi_analyser_x86_t::get_smm_services_all64() { u32_addr(g_smm_services_table_all[j].offset64)) { if (u32_addr(g_smm_services_table_all[j].offset64) == 0xe0) { // set name for Handler argument - auto smiHandlerAddr = + auto smi_handler_addr = efi_smm_utils::mark_child_sw_smi_handlers(addr); // save SMI handler - func_t *childSmiHandler = get_func(smiHandlerAddr); - if (childSmiHandler != nullptr) { - child_smi_handlers.push_back(childSmiHandler); + func_t *child_smi_handler = get_func(smi_handler_addr); + if (child_smi_handler != nullptr) { + child_smi_handlers.push_back(child_smi_handler); } } efi_utils::op_stroff(addr, "_EFI_SMM_SYSTEM_TABLE2"); - msg("[%s] 0x%016llX : %s\n", g_plugin_name, u64_addr(addr), - static_cast(g_smm_services_table_all[j].name)); + efi_utils::log("0x%016llX: %s\n", u64_addr(addr), + g_smm_services_table_all[j].name); - // add address to m_smm_services[...] + // add address to m_smm_services if (find(m_prot_smms_names.begin(), m_prot_smms_names.end(), g_smm_services_table_all[j].name) != m_prot_smms_names.end()) { @@ -877,19 +850,19 @@ void efi_analysis::efi_analyser_x86_t::get_smm_services_all64() { .push_back(addr); // add item to allSmmServices - json smmsItem; - smmsItem["address"] = addr; - smmsItem["service_name"] = g_smm_services_table_all[j].name; - smmsItem["table_name"] = "_EFI_SMM_SYSTEM_TABLE2"; - smmsItem["offset"] = g_smm_services_table_all[j].offset64; + json s; + s["address"] = addr; + s["service_name"] = g_smm_services_table_all[j].name; + s["table_name"] = "_EFI_SMM_SYSTEM_TABLE2"; + s["offset"] = g_smm_services_table_all[j].offset64; // add code addresses for arguments eavec_t args; get_arg_addrs(&args, addr); - smmsItem["args"] = args; + s["args"] = args; - if (!efi_utils::json_in_vec(m_all_services, smmsItem)) { - m_all_services.push_back(smmsItem); + if (!efi_utils::json_in_vec(m_all_services, s)) { + m_all_services.push_back(s); } break; } @@ -901,13 +874,8 @@ void efi_analysis::efi_analyser_x86_t::get_smm_services_all64() { } //-------------------------------------------------------------------------- -// Get all Pei services for X86 modules -// Currently should cover all PeiServices except EFI_PEI_COPY_MEM, -// EFI_PEI_SET_MEM, EFI_PEI_RESET2_SYSTEM, and "Future Installed Services" -// (EFI_PEI_FFS_FIND_BY_NAME, etc.) +// get all PEI services for 32-bit modules void efi_analysis::efi_analyser_x86_t::get_pei_services_all32() { - msg("[%s] PeiServices finding from 0x%016llX to 0x%016llX (all)\n", - g_plugin_name, u64_addr(m_start_addr), u64_addr(m_end_addr)); ea_t ea = m_start_addr; insn_t insn; auto found = false; @@ -921,18 +889,18 @@ void efi_analysis::efi_analyser_x86_t::get_pei_services_all32() { if (insn.ops[0].addr == u32_addr(g_pei_services_table32[j].offset)) { bool found_src_reg = false; ea_t address = ea; - insn_t aboveInst; - uint16_t src_reg = 0xffff; + insn_t a_insn; + uint16_t src_reg = NONE_REG; // 15 instructions above for (auto j = 0; j < 15; j++) { address = prev_head(address, m_start_addr); - decode_insn(&aboveInst, address); - if (aboveInst.itype == NN_mov && aboveInst.ops[0].type == o_reg && - aboveInst.ops[0].reg == insn.ops[0].reg && - aboveInst.ops[1].type == o_phrase) { + decode_insn(&a_insn, address); + if (a_insn.itype == NN_mov && a_insn.ops[0].type == o_reg && + a_insn.ops[0].reg == insn.ops[0].reg && + a_insn.ops[1].type == o_phrase) { found_src_reg = true; - src_reg = aboveInst.ops[1].reg; + src_reg = a_insn.ops[1].reg; } } @@ -942,10 +910,9 @@ void efi_analysis::efi_analyser_x86_t::get_pei_services_all32() { address = ea; for (auto j = 0; j < 15; j++) { address = prev_head(address, m_start_addr); - decode_insn(&aboveInst, address); - if (aboveInst.itype == NN_push) { - if (aboveInst.ops[0].type == o_reg && - aboveInst.ops[0].reg == src_reg) { + decode_insn(&a_insn, address); + if (a_insn.itype == NN_push) { + if (a_insn.ops[0].type == o_reg && a_insn.ops[0].reg == src_reg) { found_push = true; } break; @@ -959,23 +926,26 @@ void efi_analysis::efi_analyser_x86_t::get_pei_services_all32() { // looks like a FP break; } + efi_utils::op_stroff(ea, "EFI_PEI_SERVICES"); - msg("[%s] 0x%016llX : %s\n", g_plugin_name, u64_addr(ea), - static_cast(g_pei_services_table32[j].name)); + efi_utils::log("0x%016llX: %s\n", u64_addr(ea), + g_pei_services_table32[j].name); + m_pei_services_all[static_cast( g_pei_services_table32[j].name)] .push_back(ea); - json psItem; - psItem["address"] = ea; - psItem["service_name"] = g_pei_services_table32[j].name; - psItem["table_name"] = "EFI_PEI_SERVICES"; - psItem["offset"] = g_pei_services_table32[j].offset; + + json s; + s["address"] = ea; + s["service_name"] = g_pei_services_table32[j].name; + s["table_name"] = "EFI_PEI_SERVICES"; + s["offset"] = g_pei_services_table32[j].offset; // add code addresses for arguments - psItem["args"] = args; + s["args"] = args; - if (!efi_utils::json_in_vec(m_all_services, psItem)) { - m_all_services.push_back(psItem); + if (!efi_utils::json_in_vec(m_all_services, s)) { + m_all_services.push_back(s); } } break; @@ -986,10 +956,8 @@ void efi_analysis::efi_analyser_x86_t::get_pei_services_all32() { } //-------------------------------------------------------------------------- -// Get all EFI_PEI_READ_ONLY_VARIABLE2_PPI (GetVariable, NextVariableName) +// get all EFI_PEI_READ_ONLY_VARIABLE2_PPI (GetVariable, NextVariableName) void efi_analysis::efi_analyser_x86_t::get_variable_ppi_calls_all32() { - msg("[%s] Variable PPI calls finding from 0x%016llX to 0x%016llX (all)\n", - g_plugin_name, u64_addr(m_start_addr), u64_addr(m_end_addr)); ea_t ea = m_start_addr; insn_t insn; auto found = false; @@ -1001,16 +969,15 @@ void efi_analysis::efi_analyser_x86_t::get_variable_ppi_calls_all32() { if (insn.ops[0].addr == u32_addr(g_variable_ppi_table_all[j].offset32)) { uint16_t ppi_reg = insn.ops[0].reg; - insn_t aboveInst; + insn_t a_insn; ea_t address = ea; bool found_push = false; for (auto j = 0; j < 15; j++) { address = prev_head(address, m_start_addr); - decode_insn(&aboveInst, address); - if (aboveInst.itype == NN_push) { - if (aboveInst.ops[0].type == o_reg && - aboveInst.ops[0].reg == ppi_reg) { + decode_insn(&a_insn, address); + if (a_insn.itype == NN_push) { + if (a_insn.ops[0].type == o_reg && a_insn.ops[0].reg == ppi_reg) { found_push = true; } break; @@ -1019,27 +986,26 @@ void efi_analysis::efi_analyser_x86_t::get_variable_ppi_calls_all32() { if (found_push) { efi_utils::op_stroff(ea, "EFI_PEI_READ_ONLY_VARIABLE2_PPI"); - msg("[%s] 0x%016llX : %s\n", g_plugin_name, u64_addr(ea), - static_cast(g_variable_ppi_table_all[j].name)); + efi_utils::log("0x%016llX: %s\n", u64_addr(ea), + g_variable_ppi_table_all[j].name); + std::string ppi_call = - "VariablePPI." + - static_cast(g_variable_ppi_table_all[j].name); + std::format("VariablePPI.{}", g_variable_ppi_table_all[j].name); m_ppi_calls_all[ppi_call].push_back(ea); - // Injecting PPI call as service - json ppiItem; - ppiItem["address"] = ea; - ppiItem["service_name"] = ppi_call; - ppiItem["table_name"] = "EFI_PEI_READ_ONLY_VARIABLE2_PPI"; - ppiItem["offset"] = g_variable_ppi_table_all[j].offset32; + json s; + s["address"] = ea; + s["service_name"] = ppi_call; + s["table_name"] = "EFI_PEI_READ_ONLY_VARIABLE2_PPI"; + s["offset"] = g_variable_ppi_table_all[j].offset32; // add code addresses for arguments eavec_t args; get_arg_addrs(&args, ea); - ppiItem["args"] = args; + s["args"] = args; - if (!efi_utils::json_in_vec(m_all_services, ppiItem)) { - m_all_services.push_back(ppiItem); + if (!efi_utils::json_in_vec(m_all_services, s)) { + m_all_services.push_back(s); } } break; @@ -1050,9 +1016,8 @@ void efi_analysis::efi_analyser_x86_t::get_variable_ppi_calls_all32() { } //-------------------------------------------------------------------------- -// Get PPI names for X86 PEI modules +// get PPI names for 32-bit PEI modules void efi_analysis::efi_analyser_x86_t::get_ppi_names32() { - msg("[%s] PPI finding (PEI services)\n", g_plugin_name); ea_t start = m_start_addr; segment_t *seg_info = get_segm_by_name(".text"); if (seg_info != nullptr) { @@ -1071,81 +1036,76 @@ void efi_analysis::efi_analyser_x86_t::get_ppi_names32() { ea_t address = ea; insn_t insn; - ea_t guidCodeAddress = 0; - ea_t guidDataAddress = 0; + ea_t guid_code_address = 0; + ea_t guid_data_address = 0; auto found = false; - uint16_t pushCounter = 0; - msg("[%s] looking for PPIs in the 0x%016llX area (push number: %d)\n", - g_plugin_name, u64_addr(address), - g_pei_services_table32[i].push_number); + uint16_t push_counter = 0; + efi_utils::log( + "looking for PPIs in the 0x%016llX area (push number: %d)\n", + u64_addr(address), g_pei_services_table32[i].push_number); - // Check current basic block + // check current basic block while (true) { address = prev_head(address, m_start_addr); decode_insn(&insn, address); if (insn.itype == NN_push) { - pushCounter += 1; + push_counter += 1; } - if (pushCounter == g_pei_services_table32[i].push_number && + if (push_counter == g_pei_services_table32[i].push_number && insn.ops[0].type == o_imm && (insn.ops[0].value & 0xffffffff) >= start && - insn.ops[0].value != BADADDR) { // found "push gGuid" insn - guidCodeAddress = address; - guidDataAddress = insn.ops[0].value & 0xffffffff; + insn.ops[0].value != BADADDR) { + // found `push {GUID}` instruction + guid_code_address = address; + guid_data_address = insn.ops[0].value & 0xffffffff; found = true; break; } - // Exit loop if end of previous basic block found + // exit loop if end of previous basic block found if (is_basic_block_end(insn, false)) { break; } } - msg("[%s] GUID address: 0x%016llX\n", g_plugin_name, - u64_addr(guidDataAddress)); - if (found) { - msg("[%s] found PPI GUID parameter at 0x%016llX\n", g_plugin_name, - u64_addr(guidCodeAddress)); - auto guid = efi_utils::get_guid_by_address(guidDataAddress); + efi_utils::log("[%s] found PPI GUID parameter at 0x%016llX\n", + u64_addr(guid_code_address)); + auto guid = efi_utils::get_guid_by_address(guid_data_address); if (!efi_utils::valid_guid(guid)) { - msg("[%s] incorrect GUID at 0x%016llX\n", g_plugin_name, - u64_addr(guidCodeAddress)); continue; } - // get PPI item - json ppiItem; - ppiItem["address"] = guidDataAddress; - ppiItem["xref"] = guidCodeAddress; - ppiItem["service"] = g_pei_services_table_all[i].name; - ppiItem["guid"] = efi_utils::guid_to_string(guid); - ppiItem["module"] = "Current"; + json s; + s["address"] = guid_data_address; + s["xref"] = guid_code_address; + s["service"] = g_pei_services_table_all[i].name; + s["guid"] = efi_utils::guid_to_string(guid); + s["module"] = "Current"; // find GUID name auto it = m_guiddb_map.find(guid); if (it != m_guiddb_map.end()) { std::string name = it->second; - ppiItem["ppi_name"] = name; + s["ppi_name"] = name; // check if item already exists - if (!efi_utils::json_in_vec(m_all_ppis, ppiItem)) { - m_all_ppis.push_back(ppiItem); + if (!efi_utils::json_in_vec(m_all_ppis, s)) { + m_all_ppis.push_back(s); } continue; } - // proprietary PPI - if (ppiItem["ppi_name"].is_null()) { - ppiItem["ppi_name"] = "ProprietaryPpi"; + // unknown PPI + if (s["ppi_name"].is_null()) { + s["ppi_name"] = "UNKNOWN_PPI"; // check if item already exists - if (!efi_utils::json_in_vec(m_all_ppis, ppiItem)) { - m_all_ppis.push_back(ppiItem); + if (!efi_utils::json_in_vec(m_all_ppis, s)) { + m_all_ppis.push_back(s); } continue; } @@ -1162,7 +1122,7 @@ void efi_analysis::efi_analyser_x86_t::get_prot_boot_services64() { msg("[%s] BootServices finding from 0x%016llX to 0x%016llX (protocols)\n", g_plugin_name, u64_addr(s->start_ea), u64_addr(s->end_ea)); ea_t ea = s->start_ea; - uint16_t bsRegister = 0; + uint16_t bs_reg = 0; while (ea <= s->end_ea) { ea = next_head(ea, m_end_addr); decode_insn(&insn, ea); @@ -1198,19 +1158,19 @@ void efi_analysis::efi_analyser_x86_t::get_prot_boot_services64() { .push_back(ea); // add item to allBootServices - json bsItem; - bsItem["address"] = ea; - bsItem["service_name"] = g_boot_services_table64[i].name; - bsItem["table_name"] = "EFI_BOOT_SERVICES"; - bsItem["offset"] = g_boot_services_table64[i].offset; + json s; + s["address"] = ea; + s["service_name"] = g_boot_services_table64[i].name; + s["table_name"] = "EFI_BOOT_SERVICES"; + s["offset"] = g_boot_services_table64[i].offset; // add code addresses for arguments eavec_t args; get_arg_addrs(&args, ea); - bsItem["args"] = args; + s["args"] = args; - if (!efi_utils::json_in_vec(m_all_services, bsItem)) { - m_all_services.push_back(bsItem); + if (!efi_utils::json_in_vec(m_all_services, s)) { + m_all_services.push_back(s); } break; } @@ -1225,7 +1185,7 @@ void efi_analysis::efi_analyser_x86_t::get_prot_boot_services32() { g_plugin_name, u64_addr(m_start_addr), u64_addr(m_end_addr)); ea_t ea = m_start_addr; insn_t insn; - uint16_t bsRegister = 0; + uint16_t bs_reg = 0; while (ea <= m_end_addr) { ea = next_head(ea, m_end_addr); decode_insn(&insn, ea); @@ -1240,19 +1200,19 @@ void efi_analysis::efi_analyser_x86_t::get_prot_boot_services32() { .push_back(ea); // add item to allBootServices - json bsItem; - bsItem["address"] = ea; - bsItem["service_name"] = g_boot_services_table32[i].name; - bsItem["table_name"] = "EFI_BOOT_SERVICES"; - bsItem["offset"] = g_boot_services_table32[i].offset; + json s; + s["address"] = ea; + s["service_name"] = g_boot_services_table32[i].name; + s["table_name"] = "EFI_BOOT_SERVICES"; + s["offset"] = g_boot_services_table32[i].offset; // add code addresses for arguments eavec_t args; get_arg_addrs(&args, ea); - bsItem["args"] = args; + s["args"] = args; - if (!efi_utils::json_in_vec(m_all_services, bsItem)) { - m_all_services.push_back(bsItem); + if (!efi_utils::json_in_vec(m_all_services, s)) { + m_all_services.push_back(s); } break; } @@ -1443,8 +1403,8 @@ void efi_analysis::efi_analyser_x86_t::get_bs_prot_names64() { msg("[%s] looking for protocols in the 0x%016llX area\n", g_plugin_name, u64_addr(address)); insn_t insn; - ea_t guidCodeAddress = 0; - ea_t guidDataAddress = 0; + ea_t guid_code_address = 0; + ea_t guid_data_address = 0; auto found = false; // check current basic block @@ -1460,8 +1420,8 @@ void efi_analysis::efi_analyser_x86_t::get_bs_prot_names64() { if (insn.itype == NN_lea && insn.ops[0].type == o_reg && insn.ops[0].reg == g_boot_services_table64[i].reg && insn.ops[1].type == o_mem) { - guidCodeAddress = address; - guidDataAddress = insn.ops[1].addr; + guid_code_address = address; + guid_data_address = insn.ops[1].addr; if (insn.ops[1].addr > start && insn.ops[1].addr != BADADDR) { found = true; break; @@ -1471,8 +1431,8 @@ void efi_analysis::efi_analyser_x86_t::get_bs_prot_names64() { if (insn.itype == NN_mov && insn.ops[0].type == o_reg && insn.ops[0].reg == g_boot_services_table64[i].reg && insn.ops[1].type == o_imm) { - guidCodeAddress = address; - guidDataAddress = insn.ops[1].value; + guid_code_address = address; + guid_data_address = insn.ops[1].value; if (insn.ops[1].value > start && insn.ops[1].value != BADADDR) { found = true; break; @@ -1483,16 +1443,16 @@ void efi_analysis::efi_analyser_x86_t::get_bs_prot_names64() { if (found) { msg("[%s] get_bs_prot_names64: found protocol GUID parameter at " "0x%016llX\n", - g_plugin_name, u64_addr(guidCodeAddress)); - auto guid = efi_utils::get_guid_by_address(guidDataAddress); + g_plugin_name, u64_addr(guid_code_address)); + auto guid = efi_utils::get_guid_by_address(guid_data_address); if (!efi_utils::valid_guid(guid)) { msg("[%s] incorrect GUID at 0x%016llX\n", g_plugin_name, - u64_addr(guidCodeAddress)); + u64_addr(guid_code_address)); continue; } - add_protocol(g_boot_services_table64[i].name, guidDataAddress, - guidCodeAddress, ea); + add_protocol(g_boot_services_table64[i].name, guid_data_address, + guid_code_address, ea); } } } @@ -1516,8 +1476,8 @@ void efi_analysis::efi_analyser_x86_t::get_bs_prot_names32() { msg("[%s] looking for protocols in the 0x%016llX area\n", g_plugin_name, u64_addr(address)); insn_t insn; - ea_t guidCodeAddress = 0; - ea_t guidDataAddress = 0; + ea_t guid_code_address = 0; + ea_t guid_data_address = 0; auto found = false; uint16_t pushNumber = g_boot_services_table32[i].push_number; @@ -1527,7 +1487,7 @@ void efi_analysis::efi_analyser_x86_t::get_bs_prot_names32() { } // check current basic block - uint16_t pushCounter = 0; + uint16_t push_counter = 0; while (true) { address = prev_head(address, m_start_addr); decode_insn(&insn, address); @@ -1538,13 +1498,13 @@ void efi_analysis::efi_analyser_x86_t::get_bs_prot_names32() { } if (insn.itype == NN_push) { - pushCounter += 1; - if (pushCounter > pushNumber) { + push_counter += 1; + if (push_counter > pushNumber) { break; } - if (pushCounter == pushNumber) { - guidCodeAddress = address; - guidDataAddress = insn.ops[0].value; + if (push_counter == pushNumber) { + guid_code_address = address; + guid_data_address = insn.ops[0].value; if (insn.ops[0].value > start && insn.ops[0].value != BADADDR) { found = true; break; @@ -1556,16 +1516,16 @@ void efi_analysis::efi_analyser_x86_t::get_bs_prot_names32() { if (found) { msg("[%s] get_bs_prot_names32: found protocol GUID parameter at " "0x%016llX\n", - g_plugin_name, u64_addr(guidCodeAddress)); - auto guid = efi_utils::get_guid_by_address(guidDataAddress); + g_plugin_name, u64_addr(guid_code_address)); + auto guid = efi_utils::get_guid_by_address(guid_data_address); if (!efi_utils::valid_guid(guid)) { msg("[%s] incorrect GUID at 0x%016llX\n", g_plugin_name, - u64_addr(guidCodeAddress)); + u64_addr(guid_code_address)); continue; } - add_protocol(g_boot_services_table32[i].name, guidDataAddress, - guidCodeAddress, ea); + add_protocol(g_boot_services_table32[i].name, guid_data_address, + guid_code_address, ea); } } } @@ -1590,8 +1550,8 @@ void efi_analysis::efi_analyser_x86_t::get_smm_prot_names64() { msg("[%s] looking for protocols in the 0x%016llX area\n", g_plugin_name, u64_addr(address)); insn_t insn; - ea_t guidCodeAddress = 0; - ea_t guidDataAddress = 0; + ea_t guid_code_address = 0; + ea_t guid_data_address = 0; auto found = false; // check current basic block @@ -1606,8 +1566,8 @@ void efi_analysis::efi_analyser_x86_t::get_smm_prot_names64() { if (insn.itype == NN_lea && insn.ops[0].type == o_reg && insn.ops[0].reg == g_smm_services_prot64[i].reg) { - guidCodeAddress = address; - guidDataAddress = insn.ops[1].addr; + guid_code_address = address; + guid_data_address = insn.ops[1].addr; if (insn.ops[1].addr > start && insn.ops[1].addr != BADADDR) { found = true; break; @@ -1618,16 +1578,16 @@ void efi_analysis::efi_analyser_x86_t::get_smm_prot_names64() { if (found) { msg("[%s] get_smm_prot_names64: found protocol GUID parameter at " "0x%016llX\n", - g_plugin_name, u64_addr(guidCodeAddress)); - auto guid = efi_utils::get_guid_by_address(guidDataAddress); + g_plugin_name, u64_addr(guid_code_address)); + auto guid = efi_utils::get_guid_by_address(guid_data_address); if (!efi_utils::valid_guid(guid)) { msg("[%s] incorrect GUID at 0x%016llX\n", g_plugin_name, - u64_addr(guidCodeAddress)); + u64_addr(guid_code_address)); continue; } - add_protocol(g_smm_services_prot64[i].name, guidDataAddress, - guidCodeAddress, ea); + add_protocol(g_smm_services_prot64[i].name, guid_data_address, + guid_code_address, ea); } } } @@ -1806,8 +1766,8 @@ void efi_analysis::efi_analyser_x86_t::mark_local_guids64() { } //-------------------------------------------------------------------------- -// Search for callouts recursively -void findCalloutRec(func_t *func) { +// search for callouts recursively +void find_callout_rec(func_t *func) { insn_t insn; for (ea_t ea = func->start_ea; ea < func->end_ea; ea = next_head(ea, BADADDR)) { @@ -1819,7 +1779,7 @@ void findCalloutRec(func_t *func) { auto it = std::find(exc_funcs.begin(), exc_funcs.end(), nextFunc); if (it == exc_funcs.end()) { exc_funcs.push_back(nextFunc); - findCalloutRec(nextFunc); + find_callout_rec(nextFunc); } } } @@ -1911,7 +1871,7 @@ void findCalloutRec(func_t *func) { } //-------------------------------------------------------------------------- -// find SmiHandler functions in SMM modules +// find SMI handlers void efi_analysis::efi_analyser_t::find_smi_handlers() { std::map types = { {&m_sw_guid2, "Sw"}, @@ -1971,10 +1931,10 @@ bool efi_analysis::efi_analyser_t::find_smm_callout() { return false; } for (auto func : m_smi_handlers) { - findCalloutRec(func); + find_callout_rec(func); } for (auto func : child_smi_handlers) { - findCalloutRec(func); + find_callout_rec(func); } return true; } @@ -2030,7 +1990,7 @@ bool efi_analysis::efi_analyser_t::find_double_get_variable_pei() { if (ok) { bool same_datasize = false; uint16_t pushNumber = 5; - uint16_t pushCounter = 0; + uint16_t push_counter = 0; uint16_t arg5_reg = 0xffff; ea_t curr_datasize_addr = 0xffff; bool datasize_addr_found = false; @@ -2039,8 +1999,8 @@ bool efi_analysis::efi_analyser_t::find_double_get_variable_pei() { address = prev_head(address, m_start_addr); decode_insn(&insn, address); if (insn.itype == NN_push) { - pushCounter += 1; - if (pushCounter == pushNumber) { + push_counter += 1; + if (push_counter == pushNumber) { if (insn.ops[0].type == o_reg) { arg5_reg = insn.ops[0].reg; } else { @@ -2084,7 +2044,7 @@ bool efi_analysis::efi_analyser_t::find_double_get_variable_pei() { continue; } - pushCounter = 0; + push_counter = 0; arg5_reg = 0xffff; ea_t prev_datasize_addr = 0xffff; datasize_addr_found = false; @@ -2093,8 +2053,8 @@ bool efi_analysis::efi_analyser_t::find_double_get_variable_pei() { address = prev_head(address, m_start_addr); decode_insn(&insn, address); if (insn.itype == NN_push) { - pushCounter += 1; - if (pushCounter == pushNumber) { + push_counter += 1; + if (push_counter == pushNumber) { if (insn.ops[0].type == o_reg) { arg5_reg = insn.ops[0].reg; } else { @@ -2487,8 +2447,9 @@ bool efi_analysis::efi_analyser_t::analyse_variable_service( return true; } +//-------------------------------------------------------------------------- +// analyse NVRAM variables bool efi_analysis::efi_analyser_t::analyse_nvram_variables() { - msg("[%s] Get NVRAM variables information\n", g_plugin_name); string_list_t nvram_services = {"GetVariable", "SetVariable"}; for (auto service_str : nvram_services) { ea_list_t var_services; @@ -2518,7 +2479,7 @@ bool efi_analysis::efi_analyser_t::analyse_nvram_variables() { } //-------------------------------------------------------------------------- -// Resolve EFI_SMM_CPU_PROTOCOL +// resolve EFI_SMM_CPU_PROTOCOL bool efi_analysis::efi_analyser_t::smm_cpu_protocol_resolver() { read_save_state_calls = efi_smm_utils::resolve_efi_smm_cpu_protocol( stack_guids, data_guids, &m_all_services); @@ -2526,7 +2487,7 @@ bool efi_analysis::efi_analyser_t::smm_cpu_protocol_resolver() { } //-------------------------------------------------------------------------- -// Dump all info to JSON file +// dump all info to JSON file void efi_analysis::efi_analyser_t::dump_json() { json info; if (st_list.size()) { @@ -2575,23 +2536,24 @@ void efi_analysis::efi_analyser_t::dump_json() { info["vulns"]["smm_get_variable_buffer_overflow"] = double_get_variable_smm; } - json_list_t m_smi_handlersAddrs; - if (m_smi_handlers.size() > 0) { + json_list_t smi_handlers_addrs; + if (!m_smi_handlers.empty()) { for (auto f : m_smi_handlers) { func_t *func = f; - m_smi_handlersAddrs.push_back(func->start_ea); + smi_handlers_addrs.push_back(func->start_ea); } - info["m_smi_handlersAddrs"] = m_smi_handlersAddrs; + info["smi_handlers_addrs"] = smi_handlers_addrs; } - std::string idbPath; - idbPath = get_path(PATH_TYPE_IDB); - std::filesystem::path logFile; - logFile /= idbPath; - logFile.replace_extension(".json"); - std::ofstream out(logFile); - out << std::setw(4) << info << std::endl; - msg("[%s] the log is saved in a JSON file\n", g_plugin_name); + std::string idb_path; + idb_path = get_path(PATH_TYPE_IDB); + std::filesystem::path log_file; + log_file /= idb_path; + log_file.replace_extension(".json"); + std::ofstream out(log_file); + out << std::setw(2) << info << std::endl; + + efi_utils::log("the log is saved in a JSON file\n"); } //-------------------------------------------------------------------------- @@ -2636,16 +2598,16 @@ void efi_analysis::efi_analyser_x86_t::show_all_choosers() { json_list_t vulns; std::map vulns_map = { {"SmmCallout", callout_addrs}, - {"PeiGetVariableOverflow", double_get_variable_pei}, - {"DxeGetVariableOverflow", double_get_variable}, - {"SmmGetVariableOverflow", double_get_variable_smm}}; + {"DoubleGetVariablePei", double_get_variable_pei}, + {"DoubleGetVariable", double_get_variable}, + {"DoubleGetVariableSmm", double_get_variable_smm}}; for (const auto &[type, addrs] : vulns_map) { for (auto addr : addrs) { - json item; - item["type"] = type; - item["address"] = addr; - vulns.push_back(item); + json v; + v["type"] = type; + v["address"] = addr; + vulns.push_back(v); } } @@ -2671,8 +2633,7 @@ bool efi_analysis::efi_analyse_main_x86_64() { // analyse all auto res = ASKBTN_NO; if (analyser.m_arch == arch_file_type_t::uefi) { - res = - ask_yn(1, "Want to further analyse all drivers with auto_mark_range?"); + res = ask_yn(1, "Do you want to analyse all modules with auto_mark_range?"); } if (res == ASKBTN_YES && code_segs.size() && data_segs.size()) { segment_t *start_seg = code_segs.at(0); @@ -2752,8 +2713,7 @@ bool efi_analysis::efi_analyse_main_x86_64() { analyser.analyse_nvram_variables(); } else { - msg("[%s] Parsing of 64-bit PEI files is not supported yet\n", - g_plugin_name); + efi_utils::log("analysis of x86 64-bit PEI files is not supported\n"); } // dump info to JSON file diff --git a/efiXplorer/efi_hexrays.h b/efiXplorer/efi_hexrays.h index 6fd6aeb9..73002c5f 100644 --- a/efiXplorer/efi_hexrays.h +++ b/efiXplorer/efi_hexrays.h @@ -903,7 +903,6 @@ class services_detector_t : public ctree_visitor_t { bool is_ptr = false; if (!func_type.get_type_name(&type_name)) { if (!func_type_no_ptr.get_type_name(&type_name)) { - // msg("[E] can not get type name: 0x%016llX\n", u64_addr(e->ea)); return 0; } is_ptr = 0; @@ -920,8 +919,10 @@ class services_detector_t : public ctree_visitor_t { service_name = "RestoreTPL"; } } - msg("[efiXplorer] address: 0x%016llX, service type: %s, service name: %s\n", - u64_addr(e->ea), type_name.c_str(), service_name.c_str()); + if (m_debug) { + efi_utils::log("address: 0x%016llX, service type: %s, service name: %s\n", + u64_addr(e->ea), type_name.c_str(), service_name.c_str()); + } json s; s["address"] = e->ea; From d69e28fd241c90716d84ace2c8f06f4a18d6a6ca Mon Sep 17 00:00:00 2001 From: yeggor Date: Fri, 20 Sep 2024 05:47:12 +0100 Subject: [PATCH 41/69] refactor more functions from efi_analysis_x86 --- efiXplorer/efi_analysis_x86.cc | 122 +++++++++++++++------------------ efiXplorer/efi_utils.cc | 4 +- efiXplorer/efi_utils.h | 2 +- 3 files changed, 60 insertions(+), 68 deletions(-) diff --git a/efiXplorer/efi_analysis_x86.cc b/efiXplorer/efi_analysis_x86.cc index cd15eb4a..47ae1a3e 100644 --- a/efiXplorer/efi_analysis_x86.cc +++ b/efiXplorer/efi_analysis_x86.cc @@ -922,7 +922,7 @@ void efi_analysis::efi_analyser_x86_t::get_pei_services_all32() { if (found_src_reg && found_push) { eavec_t args; get_arg_addrs(&args, ea); - if (!args.size()) { + if (args.empty()) { // looks like a FP break; } @@ -1042,7 +1042,7 @@ void efi_analysis::efi_analyser_x86_t::get_ppi_names32() { uint16_t push_counter = 0; efi_utils::log( - "looking for PPIs in the 0x%016llX area (push number: %d)\n", + "search for PPIs in the 0x%016llX area (push number: %d)\n", u64_addr(address), g_pei_services_table32[i].push_number); // check current basic block @@ -1115,12 +1115,10 @@ void efi_analysis::efi_analyser_x86_t::get_ppi_names32() { } //-------------------------------------------------------------------------- -// Get boot services by protocols for X64 modules +// get boot services by protocols for 64-bit modules void efi_analysis::efi_analyser_x86_t::get_prot_boot_services64() { insn_t insn; for (auto s : code_segs) { - msg("[%s] BootServices finding from 0x%016llX to 0x%016llX (protocols)\n", - g_plugin_name, u64_addr(s->start_ea), u64_addr(s->end_ea)); ea_t ea = s->start_ea; uint16_t bs_reg = 0; while (ea <= s->end_ea) { @@ -1144,20 +1142,20 @@ void efi_analysis::efi_analyser_x86_t::get_prot_boot_services64() { // check that address does not belong to the protocol interface // (gBS != gInterface) - auto bs_addr = efi_utils::find_unknown_bs_var_64(ea); + auto bs_addr = efi_utils::find_unknown_bs_var64(ea); if (efi_utils::addr_in_vec(rt_list, bs_addr) || !efi_utils::check_boot_service_protocol_xrefs(bs_addr)) { break; } efi_utils::op_stroff(ea, "EFI_BOOT_SERVICES"); - msg("[%s] 0x%016llX : %s\n", g_plugin_name, u64_addr(ea), - static_cast(g_boot_services_table64[i].name)); + efi_utils::log("0x%016llX: %s\n", u64_addr(ea), + g_boot_services_table64[i].name); + m_boot_services[static_cast( g_boot_services_table64[i].name)] .push_back(ea); - // add item to allBootServices json s; s["address"] = ea; s["service_name"] = g_boot_services_table64[i].name; @@ -1179,10 +1177,8 @@ void efi_analysis::efi_analyser_x86_t::get_prot_boot_services64() { } //-------------------------------------------------------------------------- -// Get boot services by protocols for X86 modules +// get boot services by protocols for 64-bit modules void efi_analysis::efi_analyser_x86_t::get_prot_boot_services32() { - msg("[%s] BootServices finding from 0x%016llX to 0x%016llX (protocols)\n", - g_plugin_name, u64_addr(m_start_addr), u64_addr(m_end_addr)); ea_t ea = m_start_addr; insn_t insn; uint16_t bs_reg = 0; @@ -1193,13 +1189,13 @@ void efi_analysis::efi_analyser_x86_t::get_prot_boot_services32() { for (auto i = 0; i < g_boot_services_table32_count; i++) { if (insn.ops[0].addr == u32_addr(g_boot_services_table32[i].offset)) { efi_utils::op_stroff(ea, "EFI_BOOT_SERVICES"); - msg("[%s] 0x%016llX : %s\n", g_plugin_name, u64_addr(ea), - static_cast(g_boot_services_table32[i].name)); + efi_utils::log("0x%016llX: %s\n", u64_addr(ea), + g_boot_services_table32[i].name); + m_boot_services[static_cast( g_boot_services_table32[i].name)] .push_back(ea); - // add item to allBootServices json s; s["address"] = ea; s["service_name"] = g_boot_services_table32[i].name; @@ -1222,9 +1218,8 @@ void efi_analysis::efi_analyser_x86_t::get_prot_boot_services32() { } //-------------------------------------------------------------------------- -// find other addresses of gBS variables for X86-64 modules +// find other addresses of gBS variables for 64-bit modules void efi_analysis::efi_analyser_x86_t::find_other_boot_services_tables64() { - msg("[%s] find other addresses of gBS variables\n", g_plugin_name); for (auto s : m_all_services) { std::string table_name = s["table_name"]; if (table_name.compare("EFI_BOOT_SERVICES")) { @@ -1237,63 +1232,66 @@ void efi_analysis::efi_analyser_x86_t::find_other_boot_services_tables64() { } ea_t addr = static_cast(s["address"]); - msg("[%s] current service: 0x%016llX\n", g_plugin_name, u64_addr(addr)); - ea_t addr_bs = efi_utils::find_unknown_bs_var_64(addr); + ea_t addr_bs = efi_utils::find_unknown_bs_var64(addr); if (addr_bs == BADADDR || efi_utils::addr_in_tables(bs_list, rt_list, addr_bs)) { continue; } - msg("[%s] found BootServices table at 0x%016llX, address = 0x%016llX\n", - g_plugin_name, u64_addr(addr), u64_addr(addr_bs)); + efi_utils::log( + "found boot services table at 0x%016llX, address = 0x%016llX\n", + u64_addr(addr), u64_addr(addr_bs)); + efi_utils::set_ptr_type_and_name(addr_bs, "gBS", "EFI_BOOT_SERVICES"); + bs_list.push_back(addr_bs); } } +//-------------------------------------------------------------------------- +// add protocol in protocols list bool efi_analysis::efi_analyser_t::add_protocol(std::string service_name, ea_t guid_addr, ea_t xref_addr, ea_t call_addr) { if (m_arch != arch_file_type_t::uefi && guid_addr >= m_start_addr && guid_addr <= m_end_addr) { - msg("[%s] wrong service call detection: 0x%016llX\n", g_plugin_name, - u64_addr(call_addr)); return false; // filter FP } - json protocol; + json p; auto guid = efi_utils::get_guid_by_address(guid_addr); - protocol["address"] = guid_addr; - protocol["xref"] = xref_addr; - protocol["service"] = service_name; - protocol["guid"] = efi_utils::guid_to_string(guid); - protocol["ea"] = call_addr; + p["address"] = guid_addr; + p["xref"] = xref_addr; + p["service"] = service_name; + p["guid"] = efi_utils::guid_to_string(guid); + p["ea"] = call_addr; - qstring moduleName("Current"); + qstring module_name("Current"); if (efi_utils::input_file_type() == arch_file_type_t::uefi) { - moduleName = efi_utils::get_module_name_loader(call_addr); + module_name = efi_utils::get_module_name_loader(call_addr); } - protocol["module"] = static_cast(moduleName.c_str()); + + p["module"] = module_name.c_str(); // find GUID name auto it = m_guiddb_map.find(guid); if (it != m_guiddb_map.end()) { std::string name = it->second; - protocol["prot_name"] = name; + p["prot_name"] = name; } else { - protocol["prot_name"] = "UNKNOWN_PROTOCOL_GUID"; + p["prot_name"] = "UNKNOWN_PROTOCOL_GUID"; efi_utils::set_type_and_name(guid_addr, "UNKNOWN_PROTOCOL_GUID", "EFI_GUID"); } - if (!efi_utils::json_in_vec(m_all_protocols, protocol)) { - m_all_protocols.push_back(protocol); + if (!efi_utils::json_in_vec(m_all_protocols, p)) { + m_all_protocols.push_back(p); } return true; } //-------------------------------------------------------------------------- -// Extract protocols from InstallMultipleProtocolInterfaces service call +// extract protocols from InstallMultipleProtocolInterfaces service call bool efi_analysis::efi_analyser_x86_t:: install_multiple_prot_interfaces_analyser() { ea_list_t addrs = m_boot_services["InstallMultipleProtocolInterfaces"]; @@ -1307,7 +1305,7 @@ bool efi_analysis::efi_analyser_x86_t:: ea_t handle_arg = BADADDR; stack_params.clear(); - // Check current basic block + // check current basic block while (true) { address = prev_head(address, m_start_addr); decode_insn(&insn, address); @@ -1316,12 +1314,12 @@ bool efi_analysis::efi_analyser_x86_t:: break; // installed only one protocol } - // Exit loop if end of previous basic block found + // exit loop if end of previous basic block found if (is_basic_block_end(insn, false)) { break; } - // Get handle stack/data parameter + // get handle stack/data parameter if (handle_arg == BADADDR && insn.itype == NN_lea && insn.ops[0].reg == R_RCX) { switch (insn.ops[1].type) { @@ -1336,7 +1334,7 @@ bool efi_analysis::efi_analyser_x86_t:: } } - // Exit from loop if found last argument + // exit loop if last argument found if (insn.itype == NN_xor && insn.ops[0].reg == R_R9 && insn.ops[1].reg == R_R9) { check_stack = false; @@ -1366,7 +1364,7 @@ bool efi_analysis::efi_analyser_x86_t:: } } - // Enumerate all stack params + // enumerate all stack params auto index = 0; for (auto const ¶m : stack_params) { if (index++ % 2) { @@ -1380,28 +1378,27 @@ bool efi_analysis::efi_analyser_x86_t:: } //-------------------------------------------------------------------------- -// Get boot services protocols names for X64 modules +// get boot services protocols names for 64-bit modules void efi_analysis::efi_analyser_x86_t::get_bs_prot_names64() { - if (!code_segs.size()) { + if (code_segs.empty()) { return; } segment_t *s = code_segs.at(0); ea_t start = s->start_ea; - msg("[%s] protocols finding (boot services, start address = 0x%016llX)\n", - g_plugin_name, u64_addr(start)); install_multiple_prot_interfaces_analyser(); + for (int i = 0; i < g_boot_services_table64_count; i++) { if (g_boot_services_table64[i].offset == 0x148) { - // Handle InstallMultipleProtocolInterfaces separately + // handle InstallMultipleProtocolInterfaces separately continue; } ea_list_t addrs = m_boot_services[g_boot_services_table64[i].name]; for (auto ea : addrs) { ea_t address = ea; - msg("[%s] looking for protocols in the 0x%016llX area\n", g_plugin_name, - u64_addr(address)); + efi_utils::log("search for protocols in the 0x%016llX area\n", + u64_addr(address)); insn_t insn; ea_t guid_code_address = 0; ea_t guid_data_address = 0; @@ -1412,7 +1409,7 @@ void efi_analysis::efi_analyser_x86_t::get_bs_prot_names64() { address = prev_head(address, m_start_addr); decode_insn(&insn, address); - // exit from loop if end of previous basic block found + // exit loop if end of previous basic block found if (is_basic_block_end(insn, false)) { break; } @@ -1441,13 +1438,10 @@ void efi_analysis::efi_analyser_x86_t::get_bs_prot_names64() { } if (found) { - msg("[%s] get_bs_prot_names64: found protocol GUID parameter at " - "0x%016llX\n", - g_plugin_name, u64_addr(guid_code_address)); + efi_utils::log("found protocol GUID at 0x%016llX\n", + u64_addr(guid_code_address)); auto guid = efi_utils::get_guid_by_address(guid_data_address); if (!efi_utils::valid_guid(guid)) { - msg("[%s] incorrect GUID at 0x%016llX\n", g_plugin_name, - u64_addr(guid_code_address)); continue; } @@ -1473,7 +1467,7 @@ void efi_analysis::efi_analyser_x86_t::get_bs_prot_names32() { // for each boot service for (auto ea : addrs) { ea_t address = ea; - msg("[%s] looking for protocols in the 0x%016llX area\n", g_plugin_name, + msg("[%s] search for protocols in the 0x%016llX area\n", g_plugin_name, u64_addr(address)); insn_t insn; ea_t guid_code_address = 0; @@ -1534,9 +1528,10 @@ void efi_analysis::efi_analyser_x86_t::get_bs_prot_names32() { //-------------------------------------------------------------------------- // Get smm services protocols names for X64 modules void efi_analysis::efi_analyser_x86_t::get_smm_prot_names64() { - if (!code_segs.size()) { + if (code_segs.empty()) { return; } + segment_t *s = code_segs.at(0); ea_t start = s->start_ea; msg("[%s] protocols finding (smm services, start address = 0x%016llX)\n", @@ -1547,7 +1542,7 @@ void efi_analysis::efi_analyser_x86_t::get_smm_prot_names64() { // for each SMM service for (auto ea : addrs) { ea_t address = ea; - msg("[%s] looking for protocols in the 0x%016llX area\n", g_plugin_name, + msg("[%s] search for protocols in the 0x%016llX area\n", g_plugin_name, u64_addr(address)); insn_t insn; ea_t guid_code_address = 0; @@ -1918,16 +1913,13 @@ void efi_analysis::efi_analyser_t::find_smi_handlers() { } //-------------------------------------------------------------------------- -// Find callouts inside SwSmiHandler function: -// * find SwSmiHandler function -// * find gBS->service_name and gRT->service_name inside SmiHandler function +// find callouts inside SwSmiHandler functions bool efi_analysis::efi_analyser_t::find_smm_callout() { - msg("[%s] Looking for SMM callout\n", g_plugin_name); - if (!bs_list.size() && !rt_list.size()) { + efi_utils::log("search for SMM callouts\n"); + if (bs_list.empty() && rt_list.empty()) { return false; } - if (!m_smi_handlers.size() && !child_smi_handlers.size()) { - msg("[%s] can't find a SwSmiHandler functions\n", g_plugin_name); + if (m_smi_handlers.empty() && child_smi_handlers.empty()) { return false; } for (auto func : m_smi_handlers) { diff --git a/efiXplorer/efi_utils.cc b/efiXplorer/efi_utils.cc index fe77efe9..011a4a1d 100644 --- a/efiXplorer/efi_utils.cc +++ b/efiXplorer/efi_utils.cc @@ -249,8 +249,8 @@ ffs_file_type_t efi_utils::ask_file_type(json_list_t *m_all_guids) { } //-------------------------------------------------------------------------- -// find address of global gBS var for X64 module for each service -ea_t efi_utils::find_unknown_bs_var_64(ea_t ea) { +// find address of global gBS var for x86 64-bit module for each service +ea_t efi_utils::find_unknown_bs_var64(ea_t ea) { ea_t res = BADADDR; insn_t insn; diff --git a/efiXplorer/efi_utils.h b/efiXplorer/efi_utils.h index e251e838..a5920402 100644 --- a/efiXplorer/efi_utils.h +++ b/efiXplorer/efi_utils.h @@ -46,7 +46,7 @@ ea_list_t get_xrefs_to_array(ea_t addr); ea_list_t get_xrefs(ea_t addr); ea_list_t search_protocol(std::string protocol); -ea_t find_unknown_bs_var_64(ea_t ea); +ea_t find_unknown_bs_var64(ea_t ea); efi_guid_t get_global_guid(ea_t addr); efi_guid_t get_local_guid(func_t *f, uint64_t offset); From 8c51cb13ae0208601e030b83457bd31f00ba602d Mon Sep 17 00:00:00 2001 From: yeggor Date: Fri, 20 Sep 2024 19:58:24 +0100 Subject: [PATCH 42/69] refactor get_bs_prot_names32, get_smm_prot_names64, annotate_protocol_guids, annotate_data_guids --- efiXplorer/efi_analysis.h | 6 +- efiXplorer/efi_analysis_arm.cc | 2 +- efiXplorer/efi_analysis_x86.cc | 159 ++++++++++++++------------------- 3 files changed, 70 insertions(+), 97 deletions(-) diff --git a/efiXplorer/efi_analysis.h b/efiXplorer/efi_analysis.h index 7e350146..39e86b78 100644 --- a/efiXplorer/efi_analysis.h +++ b/efiXplorer/efi_analysis.h @@ -49,8 +49,8 @@ class efi_analyser_t { void dump_json(); void get_segments(); void set_pvalues(); - void mark_interfaces(); - void mark_data_guids(); + void annotate_protocol_guids(); + void annotate_data_guids(); bool smm_cpu_protocol_resolver(); void find_smi_handlers(); bool find_double_get_variable(json_list_t m_all_services); @@ -67,7 +67,7 @@ class efi_analyser_t { std::map m_guiddb_map; json m_guiddb; - ea_list_t m_marked_interfaces; + ea_list_t m_annotated_protocols; json m_boot_services; json m_pei_services_all; json m_ppi_calls_all; diff --git a/efiXplorer/efi_analysis_arm.cc b/efiXplorer/efi_analysis_arm.cc index 50d72b65..75cf07c9 100644 --- a/efiXplorer/efi_analysis_arm.cc +++ b/efiXplorer/efi_analysis_arm.cc @@ -464,7 +464,7 @@ bool efi_analysis::efi_analyse_main_aarch64() { analyser.get_segments(); // mark GUIDs - analyser.mark_data_guids(); + analyser.annotate_data_guids(); if (g_args.disable_ui) { analyser.m_ftype = g_args.module_type == module_type_t::pei diff --git a/efiXplorer/efi_analysis_x86.cc b/efiXplorer/efi_analysis_x86.cc index 47ae1a3e..13387ed1 100644 --- a/efiXplorer/efi_analysis_x86.cc +++ b/efiXplorer/efi_analysis_x86.cc @@ -1072,7 +1072,7 @@ void efi_analysis::efi_analyser_x86_t::get_ppi_names32() { } if (found) { - efi_utils::log("[%s] found PPI GUID parameter at 0x%016llX\n", + efi_utils::log("found PPI GUID parameter at 0x%016llX\n", u64_addr(guid_code_address)); auto guid = efi_utils::get_guid_by_address(guid_data_address); if (!efi_utils::valid_guid(guid)) { @@ -1453,9 +1453,8 @@ void efi_analysis::efi_analyser_x86_t::get_bs_prot_names64() { } //-------------------------------------------------------------------------- -// Get boot services protocols names for X86 modules +// get boot services protocols names for 32-bit modules void efi_analysis::efi_analyser_x86_t::get_bs_prot_names32() { - msg("[%s] protocols finding (boot services)\n", g_plugin_name); ea_t start = m_start_addr; segment_t *seg_info = get_segm_by_name(".text"); if (seg_info != nullptr) { @@ -1467,16 +1466,16 @@ void efi_analysis::efi_analyser_x86_t::get_bs_prot_names32() { // for each boot service for (auto ea : addrs) { ea_t address = ea; - msg("[%s] search for protocols in the 0x%016llX area\n", g_plugin_name, - u64_addr(address)); + efi_utils::log("search for protocols in the 0x%016llX area\n", + u64_addr(address)); insn_t insn; ea_t guid_code_address = 0; ea_t guid_data_address = 0; auto found = false; - uint16_t pushNumber = g_boot_services_table32[i].push_number; + uint16_t push_number = g_boot_services_table32[i].push_number; // if service is not currently being processed - if (pushNumber == NONE_PUSH) { + if (push_number == NONE_PUSH) { break; } @@ -1493,10 +1492,10 @@ void efi_analysis::efi_analyser_x86_t::get_bs_prot_names32() { if (insn.itype == NN_push) { push_counter += 1; - if (push_counter > pushNumber) { + if (push_counter > push_number) { break; } - if (push_counter == pushNumber) { + if (push_counter == push_number) { guid_code_address = address; guid_data_address = insn.ops[0].value; if (insn.ops[0].value > start && insn.ops[0].value != BADADDR) { @@ -1508,13 +1507,10 @@ void efi_analysis::efi_analyser_x86_t::get_bs_prot_names32() { } if (found) { - msg("[%s] get_bs_prot_names32: found protocol GUID parameter at " - "0x%016llX\n", - g_plugin_name, u64_addr(guid_code_address)); + efi_utils::log("found protocol GUID at 0x%016llX\n", + u64_addr(guid_code_address)); auto guid = efi_utils::get_guid_by_address(guid_data_address); if (!efi_utils::valid_guid(guid)) { - msg("[%s] incorrect GUID at 0x%016llX\n", g_plugin_name, - u64_addr(guid_code_address)); continue; } @@ -1526,7 +1522,7 @@ void efi_analysis::efi_analyser_x86_t::get_bs_prot_names32() { } //-------------------------------------------------------------------------- -// Get smm services protocols names for X64 modules +// get SMM services protocols names for 64-bit modules void efi_analysis::efi_analyser_x86_t::get_smm_prot_names64() { if (code_segs.empty()) { return; @@ -1534,16 +1530,14 @@ void efi_analysis::efi_analyser_x86_t::get_smm_prot_names64() { segment_t *s = code_segs.at(0); ea_t start = s->start_ea; - msg("[%s] protocols finding (smm services, start address = 0x%016llX)\n", - g_plugin_name, u64_addr(start)); for (int i = 0; i < g_smm_services_prot64_count; i++) { auto addrs = m_smm_services[g_smm_services_prot64[i].name]; // for each SMM service for (auto ea : addrs) { ea_t address = ea; - msg("[%s] search for protocols in the 0x%016llX area\n", g_plugin_name, - u64_addr(address)); + efi_utils::log("search for protocols in the 0x%016llX area\n", + u64_addr(address)); insn_t insn; ea_t guid_code_address = 0; ea_t guid_data_address = 0; @@ -1571,13 +1565,10 @@ void efi_analysis::efi_analyser_x86_t::get_smm_prot_names64() { } if (found) { - msg("[%s] get_smm_prot_names64: found protocol GUID parameter at " - "0x%016llX\n", - g_plugin_name, u64_addr(guid_code_address)); + efi_utils::log("found protocol GUID at 0x%016llX\n", + u64_addr(guid_code_address)); auto guid = efi_utils::get_guid_by_address(guid_data_address); if (!efi_utils::valid_guid(guid)) { - msg("[%s] incorrect GUID at 0x%016llX\n", g_plugin_name, - u64_addr(guid_code_address)); continue; } @@ -1589,49 +1580,29 @@ void efi_analysis::efi_analyser_x86_t::get_smm_prot_names64() { } //-------------------------------------------------------------------------- -// Mark protocols -void efi_analysis::efi_analyser_t::mark_interfaces() { - msg("[%s] %s marking\n", g_plugin_name, m_pname.c_str()); - for (auto ifItemIt = m_ptable->begin(); ifItemIt != m_ptable->end(); - ++ifItemIt) { - json ifItem = *ifItemIt; - ea_t address = static_cast(ifItem["address"]); - - // check if guid on this address already marked - bool marked = false; - for (auto markedAddress = m_marked_interfaces.begin(); - markedAddress != m_marked_interfaces.end(); ++markedAddress) { - if (*markedAddress == address) { - marked = true; - break; - } +// annotate protocol GUIDs +void efi_analysis::efi_analyser_t::annotate_protocol_guids() { + for (const auto &prot : *m_ptable) { + ea_t addr = static_cast(prot["address"]); + if (efi_utils::addr_in_vec(m_annotated_protocols, addr)) { + continue; } - if (!marked) { - std::string svcName = static_cast(ifItem[m_pkey]); - set_name(address, svcName.c_str(), SN_FORCE); - efi_utils::set_guid_type(address); - std::string comment = "EFI_GUID " + svcName; - m_marked_interfaces.push_back(address); - msg("[%s] address: 0x%016llX, comment: %s\n", g_plugin_name, - u64_addr(address), comment.c_str()); - } + std::string name = static_cast(prot[m_pkey]); + set_name(addr, name.c_str(), SN_FORCE); + efi_utils::set_guid_type(addr); + m_annotated_protocols.push_back(addr); } } //-------------------------------------------------------------------------- -// Mark GUIDs found in the .text and .data segment -void efi_analysis::efi_analyser_t::mark_data_guids() { - ea_t ptrSize = inf_is_64bit() ? 8 : 4; +// annotate GUIDs found in the .text and .data segment +void efi_analysis::efi_analyser_t::annotate_data_guids() { + ea_t ptrsize = inf_is_64bit() ? 8 : 4; auto guids_segments = code_segs; - // find GUIDs in .text and .data segments - // TODO(yeggor): scan only the areas between the beginning of the .text - // segment and the first function address (?) guids_segments.insert(guids_segments.end(), data_segs.begin(), data_segs.end()); for (auto s : guids_segments) { - msg("[%s] marking GUIDs from 0x%016llX to 0x%016llX\n", g_plugin_name, - u64_addr(s->start_ea), u64_addr(s->end_ea)); ea_t ea = s->start_ea; while (ea != BADADDR && ea <= s->end_ea - 15) { if (get_wide_dword(ea) == 0x00000000 || @@ -1644,44 +1615,46 @@ void efi_analysis::efi_analyser_t::mark_data_guids() { // find GUID name auto it = m_guiddb_map.find(guid); if (it != m_guiddb_map.end()) { - std::string guidName = it->second; - set_name(ea, guidName.c_str(), SN_FORCE); + std::string guid_name = it->second; + set_name(ea, guid_name.c_str(), SN_FORCE); efi_utils::set_guid_type(ea); // rename PPI - if (guidName.length() > 9 && - guidName.rfind("_PPI_GUID") == guidName.length() - 9) { + if (guid_name.length() > 9 && + guid_name.rfind("_PPI_GUID") == guid_name.length() - 9) { auto xrefs = efi_utils::get_xrefs(ea); for (auto addr : xrefs) { - std::string ppiName = "g" + efi_utils::type_to_name(guidName.substr( - 0, guidName.length() - 5)); - ea_t ppiEa = addr - ptrSize; + std::string type_name = guid_name.substr(0, guid_name.length() - 5); + std::string ppi_name = + std::format("g{}", efi_utils::type_to_name(type_name)); + + ea_t ppi_ea = addr - ptrsize; + // check flags - if (ptrSize == 8 && get_wide_dword(ppiEa + 4)) { + if (ptrsize == 8 && get_wide_dword(ppi_ea + 4)) { // 4 high bytes must be 0 continue; } - uint64_t flags = static_cast(get_wide_dword(ppiEa)); + + uint64_t flags = static_cast(get_wide_dword(ppi_ea)); if (!efi_utils::uint64_in_vec(m_ppi_flags, flags)) { continue; } - msg("[%s] address: 0x%016llX, PPI: %s\n", g_plugin_name, - u64_addr(ppiEa), ppiName.c_str()); - set_name(ppiEa, ppiName.c_str(), SN_FORCE); + + efi_utils::log("found %s PPI at 0x%016llX\n", ppi_name.c_str(), + u64_addr(ppi_ea)); + set_name(ppi_ea, ppi_name.c_str(), SN_FORCE); } } - std::string comment = "EFI_GUID " + guidName; - msg("[%s] address: 0x%016llX, comment: %s\n", g_plugin_name, - u64_addr(ea), comment.c_str()); - - json guid_item; - guid_item["address"] = ea; - guid_item["name"] = guidName; - guid_item["guid"] = efi_utils::guid_to_string(guid); - m_all_guids.push_back(guid_item); - data_guids.push_back(guid_item); + json g; + g["address"] = ea; + g["name"] = guid_name; + g["guid"] = efi_utils::guid_to_string(guid); + m_all_guids.push_back(g); + data_guids.push_back(g); } + ea += 1; } } @@ -1741,12 +1714,12 @@ void efi_analysis::efi_analyser_x86_t::mark_local_guids64() { msg("[%s] address: 0x%016llX, comment: %s\n", g_plugin_name, u64_addr(ea), comment.c_str()); - json guid_item; - guid_item["address"] = ea; - guid_item["name"] = dbItem.key(); - guid_item["guid"] = efi_utils::guid_to_string(guid); - m_all_guids.push_back(guid_item); - stack_guids.push_back(guid_item); + json g; + g["address"] = ea; + g["name"] = dbItem.key(); + g["guid"] = efi_utils::guid_to_string(guid); + m_all_guids.push_back(g); + stack_guids.push_back(g); exit = true; break; } @@ -1981,7 +1954,7 @@ bool efi_analysis::efi_analyser_t::find_double_get_variable_pei() { } if (ok) { bool same_datasize = false; - uint16_t pushNumber = 5; + uint16_t push_number = 5; uint16_t push_counter = 0; uint16_t arg5_reg = 0xffff; ea_t curr_datasize_addr = 0xffff; @@ -1992,7 +1965,7 @@ bool efi_analysis::efi_analyser_t::find_double_get_variable_pei() { decode_insn(&insn, address); if (insn.itype == NN_push) { push_counter += 1; - if (push_counter == pushNumber) { + if (push_counter == push_number) { if (insn.ops[0].type == o_reg) { arg5_reg = insn.ops[0].reg; } else { @@ -2046,7 +2019,7 @@ bool efi_analysis::efi_analyser_t::find_double_get_variable_pei() { decode_insn(&insn, address); if (insn.itype == NN_push) { push_counter += 1; - if (push_counter == pushNumber) { + if (push_counter == push_number) { if (insn.ops[0].type == o_reg) { arg5_reg = insn.ops[0].reg; } else { @@ -2637,7 +2610,7 @@ bool efi_analysis::efi_analyse_main_x86_64() { } // mark GUIDs - analyser.mark_data_guids(); + analyser.annotate_data_guids(); analyser.mark_local_guids64(); if (g_args.disable_ui) { @@ -2677,7 +2650,7 @@ bool efi_analysis::efi_analyse_main_x86_64() { analyser.get_smm_prot_names64(); // mark protocols - analyser.mark_interfaces(); + analyser.annotate_protocol_guids(); // search for copies of global variables efi_utils::mark_copies_for_gvars(smst_list, "gSmst"); @@ -2746,7 +2719,7 @@ bool efi_analysis::efi_analyse_main_x86_32() { analyser.get_segments(); // mark GUIDs - analyser.mark_data_guids(); + analyser.annotate_data_guids(); if (g_args.disable_ui) { analyser.m_ftype = g_args.module_type == module_type_t::pei @@ -2770,7 +2743,7 @@ bool efi_analysis::efi_analyse_main_x86_32() { // print and mark protocols analyser.get_bs_prot_names32(); - analyser.mark_interfaces(); + analyser.annotate_protocol_guids(); #ifdef HEX_RAYS efi_hexrays::apply_all_types_for_interfaces(analyser.m_all_protocols); @@ -2787,7 +2760,7 @@ bool efi_analysis::efi_analyse_main_x86_32() { analyser.get_pei_services_all32(); analyser.get_ppi_names32(); analyser.get_variable_ppi_calls_all32(); - analyser.mark_interfaces(); + analyser.annotate_protocol_guids(); // search for vulnerabilities if (!g_args.disable_vuln_hunt) { From fcc595b4b94be63781ee3e848599fbb59e185327 Mon Sep 17 00:00:00 2001 From: yeggor Date: Fri, 20 Sep 2024 20:34:36 +0100 Subject: [PATCH 43/69] refactor find_local_guids64 and callouts detection --- efiXplorer/efi_analysis.h | 2 +- efiXplorer/efi_analysis_x86.cc | 83 ++++++++++++++-------------------- 2 files changed, 34 insertions(+), 51 deletions(-) diff --git a/efiXplorer/efi_analysis.h b/efiXplorer/efi_analysis.h index 39e86b78..5eb5d275 100644 --- a/efiXplorer/efi_analysis.h +++ b/efiXplorer/efi_analysis.h @@ -368,7 +368,7 @@ class efi_analyser_x86_t : public efi_analyser_t { void get_smm_prot_names64(); void get_smm_services_all64(); void get_variable_ppi_calls_all32(); - void mark_local_guids64(); + void find_local_guids64(); void show_all_choosers(); private: diff --git a/efiXplorer/efi_analysis_x86.cc b/efiXplorer/efi_analysis_x86.cc index 13387ed1..96402f7f 100644 --- a/efiXplorer/efi_analysis_x86.cc +++ b/efiXplorer/efi_analysis_x86.cc @@ -1038,12 +1038,8 @@ void efi_analysis::efi_analyser_x86_t::get_ppi_names32() { insn_t insn; ea_t guid_code_address = 0; ea_t guid_data_address = 0; - auto found = false; - uint16_t push_counter = 0; - efi_utils::log( - "search for PPIs in the 0x%016llX area (push number: %d)\n", - u64_addr(address), g_pei_services_table32[i].push_number); + auto found = false; // check current basic block while (true) { @@ -1397,8 +1393,6 @@ void efi_analysis::efi_analyser_x86_t::get_bs_prot_names64() { ea_list_t addrs = m_boot_services[g_boot_services_table64[i].name]; for (auto ea : addrs) { ea_t address = ea; - efi_utils::log("search for protocols in the 0x%016llX area\n", - u64_addr(address)); insn_t insn; ea_t guid_code_address = 0; ea_t guid_data_address = 0; @@ -1466,8 +1460,6 @@ void efi_analysis::efi_analyser_x86_t::get_bs_prot_names32() { // for each boot service for (auto ea : addrs) { ea_t address = ea; - efi_utils::log("search for protocols in the 0x%016llX area\n", - u64_addr(address)); insn_t insn; ea_t guid_code_address = 0; ea_t guid_data_address = 0; @@ -1536,8 +1528,6 @@ void efi_analysis::efi_analyser_x86_t::get_smm_prot_names64() { // for each SMM service for (auto ea : addrs) { ea_t address = ea; - efi_utils::log("search for protocols in the 0x%016llX area\n", - u64_addr(address)); insn_t insn; ea_t guid_code_address = 0; ea_t guid_data_address = 0; @@ -1661,28 +1651,26 @@ void efi_analysis::efi_analyser_t::annotate_data_guids() { } //-------------------------------------------------------------------------- -// Mark GUIDs found in local variables for X64 modules -void efi_analysis::efi_analyser_x86_t::mark_local_guids64() { +// find GUIDs stored in local variables for 64-bit modules +void efi_analysis::efi_analyser_x86_t::find_local_guids64() { for (auto seg : code_segs) { segment_t *s = seg; ea_t ea = s->start_ea; insn_t insn; insn_t insn_next; - msg("[%s] local GUIDs finding from 0x%016llX to 0x%016llX\n", g_plugin_name, - u64_addr(s->start_ea), u64_addr(s->end_ea)); while (ea <= s->end_ea) { ea = next_head(ea, BADADDR); decode_insn(&insn, ea); - // check if insn like mov dword ptr [...], data1 + // check if insn like `mov dword ptr [...], data1` if (!(insn.itype == NN_mov && insn.ops[0].type == o_displ && insn.ops[1].type == o_imm)) { continue; } - // get guid->Data1 value + // get guid->data1 value uint32_t data1 = u32_addr(insn.ops[1].value); - if (data1 == 0x00000000 || data1 == 0xffffffff) { + if (!data1 || data1 == 0xffffffff) { ea = next_head(ea, BADADDR); continue; } @@ -1692,31 +1680,29 @@ void efi_analysis::efi_analyser_x86_t::mark_local_guids64() { for (auto i = 0; i < 4; i++) { auto ea_next = next_head(ea, BADADDR); decode_insn(&insn_next, ea_next); - // check if insn like mov dword ptr [...], data2 + // check if insn like `mov dword ptr [...], data2` if (insn_next.itype == NN_mov && insn_next.ops[0].type == o_displ && insn_next.ops[1].type == o_imm) { - // get guid->Data2 value + // get guid->data2 value uint16_t data2 = static_cast(insn_next.ops[1].value); - if (data2 == 0x0000 || data2 == 0xffff) { + if (!data2 || data2 == 0xffff) { ea = next_head(ea, BADADDR); continue; } - // found guid->Data1 and guid->Data2 values, try to get - // guid name - for (auto dbItem = m_guiddb.begin(); dbItem != m_guiddb.end(); - ++dbItem) { - auto guid = dbItem.value(); + // found guid->data1 and guid->data2 values + // try to get GUID name + for (const auto &[name, guid] : m_guiddb.items()) { if (data1 == static_cast(guid[0]) && data2 == static_cast(guid[1])) { - // mark local GUID - std::string comment = "EFI_GUID " + dbItem.key(); - msg("[%s] address: 0x%016llX, comment: %s\n", g_plugin_name, - u64_addr(ea), comment.c_str()); + auto name_str = static_cast(name); + set_cmt(ea, name.c_str(), true); + efi_utils::log("found local GUID %s at 0x%016llX\n", name.c_str(), + u64_addr(ea)); json g; g["address"] = ea; - g["name"] = dbItem.key(); + g["name"] = name; g["guid"] = efi_utils::guid_to_string(guid); m_all_guids.push_back(g); stack_guids.push_back(g); @@ -1741,13 +1727,13 @@ void find_callout_rec(func_t *func) { ea = next_head(ea, BADADDR)) { decode_insn(&insn, ea); if (insn.itype == NN_call) { - ea_t nextFuncAddr = insn.ops[0].addr; - func_t *nextFunc = get_func(nextFuncAddr); - if (nextFunc) { - auto it = std::find(exc_funcs.begin(), exc_funcs.end(), nextFunc); + ea_t next_func_addr = insn.ops[0].addr; + func_t *next_func = get_func(next_func_addr); + if (next_func) { + auto it = std::find(exc_funcs.begin(), exc_funcs.end(), next_func); if (it == exc_funcs.end()) { - exc_funcs.push_back(nextFunc); - find_callout_rec(nextFunc); + exc_funcs.push_back(next_func); + find_callout_rec(next_func); } } } @@ -1756,7 +1742,6 @@ void find_callout_rec(func_t *func) { insn.ops[1].type == o_mem) { // search for callouts with gBS if (efi_utils::addr_in_vec(bs_list, insn.ops[1].addr)) { - msg("[%s] SMM callout found: 0x%016llX\n", g_plugin_name, u64_addr(ea)); // filter FP auto reg = insn.ops[0].reg; auto addr = ea; @@ -1776,8 +1761,8 @@ void find_callout_rec(func_t *func) { } } if (!fp) { - msg("[%s] SMM callout found (gBS): 0x%016llX\n", g_plugin_name, - u64_addr(ea)); + efi_utils::log("found SMM callout via boot services at 0x%016llX\n", + u64_addr(ea)); callout_addrs.push_back(ea); continue; } @@ -1785,8 +1770,8 @@ void find_callout_rec(func_t *func) { // search for callouts with gRT if (efi_utils::addr_in_vec(rt_list, insn.ops[1].addr)) { - msg("[%s] SMM callout found (gRT): 0x%016llX\n", g_plugin_name, - u64_addr(ea)); + efi_utils::log("found SMM callout via runtime services at 0x%016llX\n", + u64_addr(ea)); callout_addrs.push_back(ea); continue; } @@ -1794,7 +1779,7 @@ void find_callout_rec(func_t *func) { // search for usage of interfaces installed with gBS->LocateProtocol() auto g_addr = insn.ops[1].addr; insn_t insn_xref; - bool interface_callout_found = false; + bool found = false; // check all xrefs for found global variable for (auto xref : efi_utils::get_xrefs(g_addr)) { // chcek if it looks like interface @@ -1816,12 +1801,10 @@ void find_callout_rec(func_t *func) { next_insn.ops[0].reg == R_RAX) { if (next_insn.ops[0].addr == 0x140 || next_insn.ops[0].addr == 0x40) { - // found callout - msg("[%s] SMM callout found (usage of memory controlled by " - "the attacker inside SMI handler): 0x%016llX\n", - g_plugin_name, u64_addr(ea)); + efi_utils::log("found SMM callout via interface at 0x%016llX\n", + u64_addr(ea)); callout_addrs.push_back(ea); - interface_callout_found = true; + found = true; } // else: FP break; } @@ -1830,7 +1813,7 @@ void find_callout_rec(func_t *func) { break; } } - if (interface_callout_found) { + if (found) { break; } } @@ -2611,7 +2594,7 @@ bool efi_analysis::efi_analyse_main_x86_64() { // mark GUIDs analyser.annotate_data_guids(); - analyser.mark_local_guids64(); + analyser.find_local_guids64(); if (g_args.disable_ui) { analyser.m_ftype = g_args.module_type == module_type_t::pei From e3ade80e6ed8bb108748a62e2fde4fc73010a092 Mon Sep 17 00:00:00 2001 From: yeggor Date: Fri, 20 Sep 2024 23:43:47 +0100 Subject: [PATCH 44/69] finalise intial refactoring for efi_analysis_x86 --- efiXplorer/efi_analysis_x86.cc | 312 ++++++++++++++++----------------- 1 file changed, 150 insertions(+), 162 deletions(-) diff --git a/efiXplorer/efi_analysis_x86.cc b/efiXplorer/efi_analysis_x86.cc index 96402f7f..be200ee2 100644 --- a/efiXplorer/efi_analysis_x86.cc +++ b/efiXplorer/efi_analysis_x86.cc @@ -849,7 +849,6 @@ void efi_analysis::efi_analyser_x86_t::get_smm_services_all64() { g_smm_services_table_all[j].name)] .push_back(addr); - // add item to allSmmServices json s; s["address"] = addr; s["service_name"] = g_smm_services_table_all[j].name; @@ -1088,7 +1087,6 @@ void efi_analysis::efi_analyser_x86_t::get_ppi_names32() { std::string name = it->second; s["ppi_name"] = name; - // check if item already exists if (!efi_utils::json_in_vec(m_all_ppis, s)) { m_all_ppis.push_back(s); } @@ -1099,7 +1097,6 @@ void efi_analysis::efi_analyser_x86_t::get_ppi_names32() { if (s["ppi_name"].is_null()) { s["ppi_name"] = "UNKNOWN_PPI"; - // check if item already exists if (!efi_utils::json_in_vec(m_all_ppis, s)) { m_all_ppis.push_back(s); } @@ -1695,7 +1692,7 @@ void efi_analysis::efi_analyser_x86_t::find_local_guids64() { for (const auto &[name, guid] : m_guiddb.items()) { if (data1 == static_cast(guid[0]) && data2 == static_cast(guid[1])) { - auto name_str = static_cast(name); + std::string name_str = name; set_cmt(ea, name.c_str(), true); efi_utils::log("found local GUID %s at 0x%016llX\n", name.c_str(), u64_addr(ea)); @@ -1871,7 +1868,6 @@ void efi_analysis::efi_analyser_t::find_smi_handlers() { //-------------------------------------------------------------------------- // find callouts inside SwSmiHandler functions bool efi_analysis::efi_analyser_t::find_smm_callout() { - efi_utils::log("search for SMM callouts\n"); if (bs_list.empty() && rt_list.empty()) { return false; } @@ -1887,41 +1883,36 @@ bool efi_analysis::efi_analyser_t::find_smm_callout() { return true; } +//-------------------------------------------------------------------------- +// find potential double GetVariable patterns in PEI modules bool efi_analysis::efi_analyser_t::find_double_get_variable_pei() { - msg("[%s] Looking for PPI GetVariable buffer overflow, " - "m_all_services.size() = %lu\n", - g_plugin_name, m_all_services.size()); - ea_list_t getVariableServicesCalls; - std::string getVariableStr("VariablePPI.GetVariable"); + ea_list_t get_variable_services_calls; + std::string get_variable_str("VariablePPI.GetVariable"); + for (auto j_service : m_all_services) { json service = j_service; - std::string service_name = - static_cast(service["service_name"]); - std::string table_name = static_cast(service["table_name"]); + std::string service_name = service["service_name"]; + std::string table_name = service["table_name"]; ea_t addr = static_cast(service["address"]); - if (service_name.compare(getVariableStr) == 0) { - getVariableServicesCalls.push_back(addr); + if (service_name.compare(get_variable_str) == 0) { + get_variable_services_calls.push_back(addr); } } - msg("[%s] Finished iterating over m_all_services, " - "getVariableServicesCalls.size() = " - "%lu\n", - g_plugin_name, getVariableServicesCalls.size()); - sort(getVariableServicesCalls.begin(), getVariableServicesCalls.end()); - if (getVariableServicesCalls.size() < 2) { - msg("[%s] less than 2 VariablePPI.GetVariable calls found\n", - g_plugin_name); + + sort(get_variable_services_calls.begin(), get_variable_services_calls.end()); + if (get_variable_services_calls.size() < 2) { return false; } - ea_t prev_addr = getVariableServicesCalls.at(0); - for (auto i = 1; i < getVariableServicesCalls.size(); ++i) { - ea_t curr_addr = getVariableServicesCalls.at(i); - msg("[%s] VariablePPI.GetVariable_1: 0x%016llX, " - "VariablePPI.GetVariable_2: " - "0x%016llX\n", - g_plugin_name, u64_addr(prev_addr), u64_addr(curr_addr)); - // check code from GetVariable_1 to GetVariable_2 + ea_t prev_addr = get_variable_services_calls.at(0); + for (auto i = 1; i < get_variable_services_calls.size(); ++i) { + ea_t curr_addr = get_variable_services_calls.at(i); + efi_utils::log("first call to VariablePPI.GetVariable: 0x%016llX\n", + u64_addr(prev_addr)); + efi_utils::log("second call to VariablePPI.GetVariable: 0x%016llX\n", + u64_addr(curr_addr)); + + // check code from first call to second call ea_t ea = next_head(prev_addr, BADADDR); bool ok = true; insn_t insn; @@ -1935,11 +1926,12 @@ bool efi_analysis::efi_analyser_t::find_double_get_variable_pei() { } ea = next_head(ea, BADADDR); } + if (ok) { bool same_datasize = false; uint16_t push_number = 5; uint16_t push_counter = 0; - uint16_t arg5_reg = 0xffff; + uint16_t arg5_reg = NONE_REG; ea_t curr_datasize_addr = 0xffff; bool datasize_addr_found = false; ea_t address = curr_addr; @@ -1952,7 +1944,7 @@ bool efi_analysis::efi_analyser_t::find_double_get_variable_pei() { if (insn.ops[0].type == o_reg) { arg5_reg = insn.ops[0].reg; } else { - // if it's not push , just let the pattern + // if it's not `push {reg}`, just let the pattern // trigger - for manual review same_datasize = true; } @@ -1963,8 +1955,8 @@ bool efi_analysis::efi_analyser_t::find_double_get_variable_pei() { if (same_datasize) { double_get_variable_pei.push_back(curr_addr); - msg("[%s] overflow can occur here: 0x%016llX\n", g_plugin_name, - u64_addr(curr_addr)); + efi_utils::log("overflow may occur here: 0x%016llX\n", + u64_addr(curr_addr)); continue; } @@ -1979,21 +1971,17 @@ bool efi_analysis::efi_analyser_t::find_double_get_variable_pei() { } } - msg("[%s] curr_datasize_addr = 0x%016llX, datasize_addr_found = " - "%d\n", - g_plugin_name, u64_addr(curr_datasize_addr), datasize_addr_found); - if (!datasize_addr_found) { // if datasize wasn't found, just let the pattern // trigger - for manual review double_get_variable_pei.push_back(curr_addr); - msg("[%s] overflow can occur here: 0x%016llX\n", g_plugin_name, - u64_addr(curr_addr)); + efi_utils::log("overflow may occur here: 0x%016llX\n", + u64_addr(curr_addr)); continue; } push_counter = 0; - arg5_reg = 0xffff; + arg5_reg = NONE_REG; ea_t prev_datasize_addr = 0xffff; datasize_addr_found = false; address = prev_addr; @@ -2006,7 +1994,7 @@ bool efi_analysis::efi_analyser_t::find_double_get_variable_pei() { if (insn.ops[0].type == o_reg) { arg5_reg = insn.ops[0].reg; } else { - // if it's not push , just let the pattern + // if it's not `push {reg}`, just let the pattern // trigger - for manual review same_datasize = true; } @@ -2017,8 +2005,8 @@ bool efi_analysis::efi_analyser_t::find_double_get_variable_pei() { if (same_datasize) { double_get_variable_pei.push_back(curr_addr); - msg("[%s] overflow can occur here: 0x%016llX\n", g_plugin_name, - u64_addr(curr_addr)); + efi_utils::log("overflow may occur here: 0x%016llX\n", + u64_addr(curr_addr)); continue; } @@ -2033,93 +2021,88 @@ bool efi_analysis::efi_analyser_t::find_double_get_variable_pei() { } } - msg("[%s] prev_datasize_addr = 0x%016llX, datasize_addr_found = " - "%d, " - "(prev_datasize_addr == curr_datasize_addr) = %d\n", - g_plugin_name, u64_addr(prev_datasize_addr), datasize_addr_found, - (prev_datasize_addr == curr_datasize_addr)); - if (!datasize_addr_found) { double_get_variable_pei.push_back(curr_addr); - msg("[%s] overflow can occur here: 0x%016llX\n", g_plugin_name, - u64_addr(curr_addr)); + efi_utils::log("overflow may occur here: 0x%016llX\n", + u64_addr(curr_addr)); } else if (prev_datasize_addr == curr_datasize_addr) { double_get_variable_pei.push_back(curr_addr); - msg("[%s] overflow can occur here: 0x%016llX " - "(prev_datasize_addr == " - "curr_datasize_addr)\n", - g_plugin_name, u64_addr(curr_addr)); + efi_utils::log("overflow may occur here: 0x%016llX\n", + u64_addr(curr_addr)); } } prev_addr = curr_addr; } - return (double_get_variable_pei.size() > 0); + return !double_get_variable_pei.empty(); } //-------------------------------------------------------------------------- -// Find potential stack/heap overflow with double GetVariable calls +// find potential double GetVariable patterns bool efi_analysis::efi_analyser_t::find_double_get_variable( json_list_t m_all_services) { - msg("[%s] Looking for GetVariable stack/heap overflow\n", g_plugin_name); - ea_list_t getVariableServicesCalls; - std::string getVariableStr("GetVariable"); + ea_list_t get_variable_services_calls; + std::string get_variable_str("GetVariable"); + for (auto j_service : m_all_services) { json service = j_service; std::string service_name = static_cast(service["service_name"]); ea_t addr = static_cast(service["address"]); - if (service_name.compare(getVariableStr) == 0) { - getVariableServicesCalls.push_back(addr); + if (service_name.compare(get_variable_str) == 0) { + get_variable_services_calls.push_back(addr); } } - sort(getVariableServicesCalls.begin(), getVariableServicesCalls.end()); - if (getVariableServicesCalls.size() < 2) { - msg("[%s] less than 2 GetVariable calls found\n", g_plugin_name); + + sort(get_variable_services_calls.begin(), get_variable_services_calls.end()); + if (get_variable_services_calls.size() < 2) { return false; } - ea_t prev_addr = getVariableServicesCalls.at(0); + ea_t ea; insn_t insn; - for (auto i = 1; i < getVariableServicesCalls.size(); ++i) { - ea_t curr_addr = getVariableServicesCalls.at(i); - msg("[%s] GetVariable_1: 0x%016llX, GetVariable_2: 0x%016llX\n", - g_plugin_name, u64_addr(prev_addr), u64_addr(curr_addr)); - - // get dataSizeStackAddr - int dataSizeStackAddr = 0; - uint16 dataSizeOpReg = 0xFF; + ea_t prev_addr = get_variable_services_calls.at(0); + for (auto i = 1; i < get_variable_services_calls.size(); ++i) { + ea_t curr_addr = get_variable_services_calls.at(i); + efi_utils::log("first call to GetVariable: 0x%016llX\n", + u64_addr(prev_addr)); + efi_utils::log("second call to GetVariable: 0x%016llX\n", + u64_addr(curr_addr)); + + int datasize_stack_addr = 0; + uint16 datasize_op_reg = 0xFF; ea = prev_head(curr_addr, 0); for (auto i = 0; i < 10; ++i) { decode_insn(&insn, ea); if (insn.itype == NN_lea && insn.ops[0].type == o_reg && insn.ops[0].reg == R_R9) { - dataSizeStackAddr = insn.ops[1].addr; - dataSizeOpReg = insn.ops[1].phrase; + datasize_stack_addr = insn.ops[1].addr; + datasize_op_reg = insn.ops[1].phrase; break; } ea = prev_head(ea, 0); } - // check code from GetVariable_1 to GetVariable_2 + // check code from first call to second call ea = next_head(prev_addr, BADADDR); bool ok = true; - size_t dataSizeUseCounter = 0; + size_t datasize_user_count = 0; while (ea < curr_addr) { decode_insn(&insn, ea); - if (((dataSizeStackAddr == insn.ops[0].addr) && - (dataSizeOpReg == insn.ops[0].phrase)) || - ((dataSizeStackAddr == insn.ops[1].addr) && - (dataSizeOpReg == insn.ops[1].phrase))) { - dataSizeUseCounter++; + if (((datasize_stack_addr == insn.ops[0].addr) && + (datasize_op_reg == insn.ops[0].phrase)) || + ((datasize_stack_addr == insn.ops[1].addr) && + (datasize_op_reg == insn.ops[1].phrase))) { + datasize_user_count++; } if ((insn.itype == NN_callni && insn.ops[0].addr == 0x48) || insn.itype == NN_retn || insn.itype == NN_jmp || - insn.itype == NN_jmpni || dataSizeUseCounter > 1) { + insn.itype == NN_jmpni || datasize_user_count > 1) { ok = false; break; } ea = next_head(ea, BADADDR); } + if (ok) { // check for wrong GetVariable detection bool wrong_detection = false; @@ -2137,26 +2120,25 @@ bool efi_analysis::efi_analyser_t::find_double_get_variable( ea = prev_head(ea, 0); } - // check DataSize initialization + // check DataSize initialisation bool init_ok = false; decode_insn(&insn, prev_head(curr_addr, 0)); if (!wrong_detection && !(insn.itype == NN_mov && insn.ops[0].type == o_displ && (insn.ops[0].phrase == R_RSP || insn.ops[0].phrase == R_RBP) && - (insn.ops[0].addr == dataSizeStackAddr))) { + (insn.ops[0].addr == datasize_stack_addr))) { init_ok = true; } - // check that the DataSize argument variable is the same for two - // calls + // check that the DataSize argument variable is the same for two calls if (init_ok) { ea = prev_head(prev_addr, 0); - // for (auto i = 0; i < 10; ++i) { func_t *func_start = get_func(ea); if (func_start == nullptr) { return (double_get_variable.size() > 0); } - uint16 stack_base_reg = 0xFF; + + uint16 stack_base_reg = 0xff; decode_insn(&insn, func_start->start_ea); if (insn.itype == NN_mov && insn.ops[1].is_reg(R_RSP) && insn.ops[0].type == o_reg) { @@ -2173,11 +2155,11 @@ bool efi_analysis::efi_analyser_t::find_double_get_variable( sval_t sval = get_spd(func_start, ea) * -1; if ((insn.ops[1].phrase == stack_base_reg && - (sval + stack_addr) == dataSizeStackAddr) || - (dataSizeStackAddr == insn.ops[1].addr)) { + (sval + stack_addr) == datasize_stack_addr) || + (datasize_stack_addr == insn.ops[1].addr)) { double_get_variable.push_back(curr_addr); - msg("[%s] \toverflow can occur here: 0x%016llX\n", g_plugin_name, - u64_addr(curr_addr)); + efi_utils::log("overflow may occur here: 0x%016llX\n", + u64_addr(curr_addr)); break; } } @@ -2187,45 +2169,45 @@ bool efi_analysis::efi_analyser_t::find_double_get_variable( } prev_addr = curr_addr; } - return (double_get_variable.size() > 0); + return !double_get_variable.empty(); } //-------------------------------------------------------------------------- -// Find potential stack/heap overflow with double SmmGetVariable calls +// find potential double GetVariable patterns in SMM modules bool efi_analysis::efi_analyser_t::find_double_get_variable_smm() { - msg("[%s] Looking for SmmGetVariable stack/heap overflow\n", g_plugin_name); ea_list_t smm_get_variable_calls = efi_smm_utils::find_smm_get_variable_calls(data_segs, &m_all_services); sort(smm_get_variable_calls.begin(), smm_get_variable_calls.end()); + if (smm_get_variable_calls.size() < 2) { - msg("[%s] less than 2 GetVariable calls found\n", g_plugin_name); return false; } + ea_t prev_addr = smm_get_variable_calls.at(0); ea_t ea; insn_t insn; for (auto i = 1; i < smm_get_variable_calls.size(); ++i) { ea_t curr_addr = smm_get_variable_calls.at(i); - msg("[%s] SmmGetVariable_1: 0x%016llX, SmmGetVariable_2: 0x%016llX\n", - g_plugin_name, u64_addr(prev_addr), u64_addr(curr_addr)); + efi_utils::log("first call to SmmGetVariable: 0x%016llX\n", + u64_addr(prev_addr)); + efi_utils::log("second call to SmmGetVariable: 0x%016llX\n", + u64_addr(curr_addr)); - // get dataSizeStackAddr - uint32_t dataSizeStackAddr = 0xffffffff; + uint32_t datasize_stack_addr = 0xffffffff; ea = prev_head(curr_addr, 0); for (auto i = 0; i < 10; ++i) { decode_insn(&insn, ea); if (insn.itype == NN_lea && insn.ops[0].type == o_reg && insn.ops[0].reg == R_R9) { - dataSizeStackAddr = insn.ops[1].addr; + datasize_stack_addr = insn.ops[1].addr; break; } ea = prev_head(ea, 0); } - // check code from SmmGetVariable_1 to SmmGetVariable_2 + // check code from first call to second call ea = next_head(prev_addr, BADADDR); bool ok = true; - size_t dataSizeUseCounter = 0; while (ea < curr_addr) { decode_insn(&insn, ea); if (insn.itype == NN_callni || insn.itype == NN_retn || @@ -2237,7 +2219,7 @@ bool efi_analysis::efi_analyser_t::find_double_get_variable_smm() { } if (ok) { - // check DataSize initialization + // check DataSize initialisation bool init_ok = false; decode_insn(&insn, prev_head(curr_addr, 0)); if (!(insn.itype == NN_mov && insn.ops[0].type == o_displ && @@ -2245,23 +2227,19 @@ bool efi_analysis::efi_analyser_t::find_double_get_variable_smm() { init_ok = true; } - // check that the DataSize argument variable is the same for two - // calls + // check that the DataSize argument variable is the same for two calls if (init_ok) { ea = prev_head(prev_addr, 0); for (auto i = 0; i < 10; ++i) { decode_insn(&insn, ea); if (insn.itype == NN_lea && insn.ops[0].type == o_reg && insn.ops[0].reg == R_R9) { - if (dataSizeStackAddr == insn.ops[1].addr) { + if (datasize_stack_addr == insn.ops[1].addr) { double_get_variable_smm.push_back(curr_addr); - msg("[%s] \toverflow can occur here: 0x%016llX\n", g_plugin_name, - u64_addr(curr_addr)); + efi_utils::log("overflow may occur here: 0x%016llX\n", + u64_addr(curr_addr)); break; } - msg("[%s] \tDataSize argument variable is not the " - "same: 0x%016llX\n", - g_plugin_name, u64_addr(curr_addr)); } ea = prev_head(ea, 0); } @@ -2269,74 +2247,84 @@ bool efi_analysis::efi_analyser_t::find_double_get_variable_smm() { } prev_addr = curr_addr; } - return (double_get_variable_smm.size() > 0); + return !double_get_variable_smm.empty(); } +//-------------------------------------------------------------------------- +// analyse calls to GetVariable/SetVariable to extract variables information bool efi_analysis::efi_analyser_t::analyse_variable_service( ea_t ea, std::string service_str) { - msg("[%s] %s call: 0x%016llX\n", g_plugin_name, service_str.c_str(), - u64_addr(ea)); - json item; - item["addr"] = ea; - insn_t insn; - bool name_found = false; - bool guid_found = false; func_t *f = get_func(ea); if (f == nullptr) { return false; } + + efi_utils::log("analysing %s call at 0x%016llX\n", service_str.c_str(), + u64_addr(ea)); + eavec_t args; get_arg_addrs(&args, ea); if (args.size() < 3) { return false; } - auto addr = args[0]; // Get VariableName + json v; + v["addr"] = ea; + + insn_t insn; + bool name_found = false; + bool guid_found = false; + + // variable name argument + auto addr = args[0]; decode_insn(&insn, addr); + if (insn.itype == NN_lea && insn.ops[0].type == o_reg && insn.ops[0].reg == R_RCX && insn.ops[1].type == o_mem) { - msg("[%s] VariableName address: 0x%016llX\n", g_plugin_name, - u64_addr(insn.ops[1].addr)); std::string var_name = efi_utils::get_wide_string(insn.ops[1].addr); // retype CHAR16 to const CHAR16 to improve pseudocode quality efi_utils::set_const_char16_type(insn.ops[1].addr); + efi_utils::log(" VariableName: %s (at 0x%016llX)\n", var_name.c_str(), + u64_addr(insn.ops[1].addr)); - msg("[%s] VariableName: %s\n", g_plugin_name, var_name.c_str()); - item["VariableName"] = var_name; + v["VariableName"] = var_name; name_found = true; } - addr = args[1]; // Get VendorGuid + // vendor GUID argument + addr = args[1]; decode_insn(&insn, addr); - // If GUID is global variable + + // if GUID is a global variable if (insn.itype == NN_lea && insn.ops[0].type == o_reg && insn.ops[0].reg == R_RDX && insn.ops[1].type == o_mem) { - msg("[%s] VendorGuid address (global): 0x%016llX\n", g_plugin_name, - u64_addr(insn.ops[1].addr)); efi_guid_t guid = efi_utils::get_global_guid(insn.ops[1].addr); - msg("[%s] GUID: %s\n", g_plugin_name, guid.to_string().c_str()); - item["VendorGuid"] = guid.to_string(); + efi_utils::log(" VendorGuid: %s (at 0x%016llX)\n", + guid.to_string().c_str(), u64_addr(insn.ops[1].addr)); + + v["VendorGuid"] = guid.to_string(); guid_found = true; } - // If GUID is local variable + + // if GUID is local variable if (!guid_found && insn.itype == NN_lea && insn.ops[0].type == o_reg && insn.ops[0].reg == R_RDX && insn.ops[1].type == o_displ) { switch (insn.ops[1].reg) { case R_RBP: { - msg("[%s] VendorGuid address (regarding to RBP): 0x%016llX\n", - g_plugin_name, u64_addr(insn.ops[1].addr)); efi_guid_t guid = efi_utils::get_local_guid(f, insn.ops[1].addr); - msg("[%s] GUID: %s\n", g_plugin_name, guid.to_string().c_str()); - item["VendorGuid"] = guid.to_string(); + efi_utils::log(" VendorGuid: %s, RBP offset: 0x%016llX\n", + guid.to_string().c_str(), u64_addr(insn.ops[1].addr)); + + v["VendorGuid"] = guid.to_string(); guid_found = true; } case R_RSP: { - msg("[%s] VendorGuid address (regarding to RSP): 0x%016llX\n", - g_plugin_name, u64_addr(insn.ops[1].addr)); efi_guid_t guid = efi_utils::get_local_guid(f, insn.ops[1].addr); - msg("[%s] GUID: %s\n", g_plugin_name, guid.to_string().c_str()); - item["VendorGuid"] = guid.to_string(); + efi_utils::log(" VendorGuid: %s, RSP offset: 0x%016llX\n", + guid.to_string().c_str(), u64_addr(insn.ops[1].addr)); + + v["VendorGuid"] = guid.to_string(); guid_found = true; } } @@ -2349,23 +2337,24 @@ bool efi_analysis::efi_analyser_t::analyse_variable_service( {0x00000008, "HARDWARE_ERROR_RECORD"}, {0x00000010, "AUTHENTICATED_WRITE_ACCESS"}}; - addr = args[2]; // Get Attributes + addr = args[2]; // attributes argument decode_insn(&insn, addr); + if (insn.itype == NN_xor && insn.ops[0].type == o_reg && insn.ops[1].type == o_reg && insn.ops[0].reg == insn.ops[1].reg && insn.ops[0].reg == R_R8) { - item["Attributes"] = 0; std::string attributes_hr = "No attributes"; - item["AttributesHumanReadable"] = attributes_hr; - msg("[%s] Attributes: %d (%s)\n", g_plugin_name, 0, attributes_hr.c_str()); + v["Attributes"] = 0; + v["AttributesHumanReadable"] = attributes_hr; + efi_utils::log(" Attributes: %s\n", attributes_hr.c_str()); } else { #ifdef HEX_RAYS - // Extract attributes with Hex-Rays SDK + // extract attributes with Hex-Rays SDK auto res = efi_hexrays::variables_info_extract_all(f, ea); - item["Attributes"] = res; - std::string attributes_hr = std::string(); + v["Attributes"] = res; + std::string attributes_hr; if (res == 0xff) { - attributes_hr = "Unknown attributes"; + attributes_hr = "Unknown"; } else { for (auto &[attr, attr_def] : attributes_defs) { if (res & attr & 0x0f) { @@ -2376,20 +2365,19 @@ bool efi_analysis::efi_analyser_t::analyse_variable_service( attributes_hr = attributes_hr.substr(0, attributes_hr.size() - 3); } } - item["AttributesHumanReadable"] = attributes_hr; - msg("[%s] Attributes: %d (%s)\n", g_plugin_name, res, - attributes_hr.c_str()); + v["AttributesHumanReadable"] = attributes_hr; + efi_utils::log(" Attributes: %s (%d)\n", attributes_hr.c_str(), res); #else - // If Hex-Rays analysis is not used, this feature does not work - item["Attributes"] = 0xff; - item["AttributesHumanReadable"] = "Unknown attributes"; + // use stubs when hex-rays analysis is disabled + v["Attributes"] = 0xff; + v["AttributesHumanReadable"] = "Unknown"; #endif } - if (name_found && guid_found) { // if only name or only GUID found, it will - // now saved (check the logs) - item["service"] = service_str; - m_nvram_variables.push_back(item); + // if only the name or GUID is found, it will not be saved + if (name_found && guid_found) { + v["service"] = service_str; + m_nvram_variables.push_back(v); } return true; From 64dbc94401965b30f43fb020653ec559e877597b Mon Sep 17 00:00:00 2001 From: yeggor Date: Sun, 22 Sep 2024 04:05:04 +0100 Subject: [PATCH 45/69] use PRIx64/PRIX64 format specifiers for addresses --- efiXplorer/efi_analysis_arm.cc | 15 +++--- efiXplorer/efi_analysis_x86.cc | 91 ++++++++++++++++++---------------- efiXplorer/efi_defs.h | 1 + efiXplorer/efi_hexrays.h | 16 +++--- efiXplorer/efi_smm_utils.cc | 44 ++++++++-------- efiXplorer/efi_ui.cc | 10 ++-- efiXplorer/efi_utils.cc | 8 +-- 7 files changed, 98 insertions(+), 87 deletions(-) diff --git a/efiXplorer/efi_analysis_arm.cc b/efiXplorer/efi_analysis_arm.cc index 75cf07c9..54b94dd3 100644 --- a/efiXplorer/efi_analysis_arm.cc +++ b/efiXplorer/efi_analysis_arm.cc @@ -276,7 +276,7 @@ void efi_analysis::efi_analyser_arm_t::initial_gvars_detection() { ea = next_head(ea, BADADDR); ea_t bs = get_table_addr(ea, 0x60); if (bs != BADADDR) { - efi_utils::log("gBS: 0x%016llX\n", u64_addr(ea)); + efi_utils::log("gBS: 0x%" PRIx64 "\n", u64_addr(ea)); efi_utils::set_ptr_type_and_name(bs, "gBS", "EFI_BOOT_SERVICES"); if (!efi_utils::addr_in_vec(bs_list_arm, bs)) { bs_list_arm.push_back(bs); @@ -285,7 +285,7 @@ void efi_analysis::efi_analyser_arm_t::initial_gvars_detection() { } ea_t rt = get_table_addr(ea, 0x58); if (rt != BADADDR) { - efi_utils::log("gRT: 0x%016llX\n", u64_addr(ea)); + efi_utils::log("gRT: 0x%" PRIx64 "\n", u64_addr(ea)); efi_utils::set_ptr_type_and_name(rt, "gRT", "EFI_RUNTIME_SERVICES"); if (!efi_utils::addr_in_vec(rt_list_arm, rt)) { rt_list_arm.push_back(rt); @@ -319,7 +319,8 @@ void efi_analysis::efi_analyser_arm_t::detect_services_all() { continue; } if (!efi_utils::json_in_vec(m_all_services, s)) { - efi_utils::log("found new boot service at 0x%016llX\n", u64_addr(ea)); + efi_utils::log("found new boot service at 0x%" PRIx64 "\n", + u64_addr(ea)); m_all_services.push_back(s); } } @@ -336,7 +337,7 @@ void efi_analysis::efi_analyser_arm_t::detect_services_all() { continue; } if (!efi_utils::json_in_vec(m_all_services, s)) { - efi_utils::log("found new runtime service at 0x%016llX\n", + efi_utils::log("found new runtime service at 0x%" PRIx64 "\n", u64_addr(ea)); m_all_services.push_back(s); } @@ -379,7 +380,7 @@ bool efi_analysis::efi_analyser_arm_t::get_protocol(ea_t address, if (guid_addr == BADADDR || code_addr == BADADDR) { return false; } - efi_utils::log("found new protocol at 0x%016llX\n", u64_addr(code_addr)); + efi_utils::log("found new protocol at 0x%" PRIx64 "\n", u64_addr(code_addr)); return add_protocol(service_name, guid_addr, code_addr, address); } @@ -417,7 +418,7 @@ void efi_analysis::efi_analyser_arm_t::find_pei_services_function() { } decode_insn(&insn, end_ea); if (insn.itype == ARM_ret) { - efi_utils::log("found GetPeiServices() function at 0x%016llX\n", + efi_utils::log("found GetPeiServices() function at 0x%" PRIx64 "\n", u64_addr(start_ea)); set_name(start_ea, "GetPeiServices", SN_FORCE); efi_utils::set_ret_to_pei_svc(start_ea); @@ -450,7 +451,7 @@ void efi_analysis::efi_analyser_arm_t::show_all_choosers() { } //-------------------------------------------------------------------------- -// Main function for AARCH64 modules +// main function for AARCH64 modules bool efi_analysis::efi_analyse_main_aarch64() { show_wait_box("HIDECANCEL\nAnalysing module(s) with efiXplorer..."); diff --git a/efiXplorer/efi_analysis_x86.cc b/efiXplorer/efi_analysis_x86.cc index be200ee2..6aa0ab22 100644 --- a/efiXplorer/efi_analysis_x86.cc +++ b/efiXplorer/efi_analysis_x86.cc @@ -188,13 +188,13 @@ void efi_analysis::efi_analyser_t::get_segments() { // print all .text and .code segments addresses for (auto seg : code_segs) { segment_t *s = seg; - efi_utils::log("code segment: 0x%016llX\n", u64_addr(s->start_ea)); + efi_utils::log("code segment: 0x%" PRIx64 "\n", u64_addr(s->start_ea)); } // print all .data segments addresses for (auto seg : data_segs) { segment_t *s = seg; - efi_utils::log("data segment: 0x%016llX\n", u64_addr(s->start_ea)); + efi_utils::log("data segment: 0x%" PRIx64 "\n", u64_addr(s->start_ea)); } } @@ -267,7 +267,7 @@ bool efi_analysis::efi_analyser_x86_t::find_smst64() { smst_list.erase(last, smst_list.end()); for (auto smst : smst_list) { - efi_utils::log("0x%016llX: gSmst\n", u64_addr(smst)); + efi_utils::log("0x%" PRIx64 ": gSmst\n", u64_addr(smst)); } return !smst_list.empty(); @@ -278,7 +278,7 @@ bool efi_analysis::efi_analyser_x86_t::find_smst64() { // modules after Hex-Rays based analysis bool efi_analysis::efi_analyser_x86_t::find_smst_postproc64() { for (auto ea : g_get_smst_location_calls) { - efi_utils::log("EfiSmmBase2Protocol->GetSmstLocation call: 0x%016llX\n", + efi_utils::log("EfiSmmBase2Protocol->GetSmstLocation call: 0x%" PRIx64 "\n", u64_addr(ea)); insn_t insn; auto addr = ea; @@ -319,7 +319,7 @@ bool efi_analysis::efi_analyser_x86_t::find_smst_postproc64() { } if (smst_stack.is_null() && smst_addr != BADADDR) { - efi_utils::log(" gSmst: 0x%016llX\n", u64_addr(smst_addr)); + efi_utils::log(" gSmst: 0x%" PRIx64 "\n", u64_addr(smst_addr)); if (!efi_utils::addr_in_vec(smst_list, smst_addr)) { efi_utils::set_ptr_type_and_name(smst_addr, "gSmst", "_EFI_SMM_SYSTEM_TABLE2"); @@ -329,7 +329,7 @@ bool efi_analysis::efi_analyser_x86_t::find_smst_postproc64() { if (!smst_stack.is_null()) { auto reg = smst_stack["reg"] == R_RSP ? "RSP" : "RBP"; - efi_utils::log(" Smst: 0x%016llX, reg = %s\n", u64_addr(smst_addr), + efi_utils::log(" Smst: 0x%" PRIx64 ", reg = %s\n", u64_addr(smst_addr), reg); // try to extract ChildSwSmiHandler @@ -679,7 +679,7 @@ void efi_analysis::efi_analyser_x86_t::get_boot_services_all() { } efi_utils::op_stroff(addr, "EFI_BOOT_SERVICES"); - efi_utils::log("0x%016llX: %s\n", u64_addr(addr), + efi_utils::log("0x%" PRIx64 ": %s\n", u64_addr(addr), g_boot_services_table_all[j].name); m_boot_services[static_cast( @@ -760,7 +760,7 @@ void efi_analysis::efi_analyser_x86_t::get_runtime_services_all() { } if (service_offset == u32_addr(offset)) { efi_utils::op_stroff(addr, "EFI_RUNTIME_SERVICES"); - efi_utils::log("0x%016llX: %s\n", u64_addr(addr), + efi_utils::log("0x%" PRIx64 ": %s\n", u64_addr(addr), g_runtime_services_table_all[j].name); m_runtime_services_all[static_cast( @@ -835,7 +835,7 @@ void efi_analysis::efi_analyser_x86_t::get_smm_services_all64() { } efi_utils::op_stroff(addr, "_EFI_SMM_SYSTEM_TABLE2"); - efi_utils::log("0x%016llX: %s\n", u64_addr(addr), + efi_utils::log("0x%" PRIx64 ": %s\n", u64_addr(addr), g_smm_services_table_all[j].name); // add address to m_smm_services @@ -927,7 +927,7 @@ void efi_analysis::efi_analyser_x86_t::get_pei_services_all32() { } efi_utils::op_stroff(ea, "EFI_PEI_SERVICES"); - efi_utils::log("0x%016llX: %s\n", u64_addr(ea), + efi_utils::log("0x%" PRIx64 ": %s\n", u64_addr(ea), g_pei_services_table32[j].name); m_pei_services_all[static_cast( @@ -985,7 +985,7 @@ void efi_analysis::efi_analyser_x86_t::get_variable_ppi_calls_all32() { if (found_push) { efi_utils::op_stroff(ea, "EFI_PEI_READ_ONLY_VARIABLE2_PPI"); - efi_utils::log("0x%016llX: %s\n", u64_addr(ea), + efi_utils::log("0x%" PRIx64 ": %s\n", u64_addr(ea), g_variable_ppi_table_all[j].name); std::string ppi_call = @@ -1067,7 +1067,7 @@ void efi_analysis::efi_analyser_x86_t::get_ppi_names32() { } if (found) { - efi_utils::log("found PPI GUID parameter at 0x%016llX\n", + efi_utils::log("found PPI GUID parameter at 0x%" PRIx64 "\n", u64_addr(guid_code_address)); auto guid = efi_utils::get_guid_by_address(guid_data_address); if (!efi_utils::valid_guid(guid)) { @@ -1142,7 +1142,7 @@ void efi_analysis::efi_analyser_x86_t::get_prot_boot_services64() { } efi_utils::op_stroff(ea, "EFI_BOOT_SERVICES"); - efi_utils::log("0x%016llX: %s\n", u64_addr(ea), + efi_utils::log("0x%" PRIx64 ": %s\n", u64_addr(ea), g_boot_services_table64[i].name); m_boot_services[static_cast( @@ -1182,7 +1182,7 @@ void efi_analysis::efi_analyser_x86_t::get_prot_boot_services32() { for (auto i = 0; i < g_boot_services_table32_count; i++) { if (insn.ops[0].addr == u32_addr(g_boot_services_table32[i].offset)) { efi_utils::op_stroff(ea, "EFI_BOOT_SERVICES"); - efi_utils::log("0x%016llX: %s\n", u64_addr(ea), + efi_utils::log("0x%" PRIx64 ": %s\n", u64_addr(ea), g_boot_services_table32[i].name); m_boot_services[static_cast( @@ -1232,9 +1232,9 @@ void efi_analysis::efi_analyser_x86_t::find_other_boot_services_tables64() { continue; } - efi_utils::log( - "found boot services table at 0x%016llX, address = 0x%016llX\n", - u64_addr(addr), u64_addr(addr_bs)); + efi_utils::log("found boot services table at 0x%" PRIx64 + ", address = 0x%" PRIx64 "\n", + u64_addr(addr), u64_addr(addr_bs)); efi_utils::set_ptr_type_and_name(addr_bs, "gBS", "EFI_BOOT_SERVICES"); @@ -1429,7 +1429,7 @@ void efi_analysis::efi_analyser_x86_t::get_bs_prot_names64() { } if (found) { - efi_utils::log("found protocol GUID at 0x%016llX\n", + efi_utils::log("found protocol GUID at 0x%" PRIx64 "\n", u64_addr(guid_code_address)); auto guid = efi_utils::get_guid_by_address(guid_data_address); if (!efi_utils::valid_guid(guid)) { @@ -1496,7 +1496,7 @@ void efi_analysis::efi_analyser_x86_t::get_bs_prot_names32() { } if (found) { - efi_utils::log("found protocol GUID at 0x%016llX\n", + efi_utils::log("found protocol GUID at 0x%" PRIx64 "\n", u64_addr(guid_code_address)); auto guid = efi_utils::get_guid_by_address(guid_data_address); if (!efi_utils::valid_guid(guid)) { @@ -1552,7 +1552,7 @@ void efi_analysis::efi_analyser_x86_t::get_smm_prot_names64() { } if (found) { - efi_utils::log("found protocol GUID at 0x%016llX\n", + efi_utils::log("found protocol GUID at 0x%" PRIx64 "\n", u64_addr(guid_code_address)); auto guid = efi_utils::get_guid_by_address(guid_data_address); if (!efi_utils::valid_guid(guid)) { @@ -1628,7 +1628,7 @@ void efi_analysis::efi_analyser_t::annotate_data_guids() { continue; } - efi_utils::log("found %s PPI at 0x%016llX\n", ppi_name.c_str(), + efi_utils::log("found %s PPI at 0x%" PRIx64 "\n", ppi_name.c_str(), u64_addr(ppi_ea)); set_name(ppi_ea, ppi_name.c_str(), SN_FORCE); } @@ -1694,8 +1694,8 @@ void efi_analysis::efi_analyser_x86_t::find_local_guids64() { data2 == static_cast(guid[1])) { std::string name_str = name; set_cmt(ea, name.c_str(), true); - efi_utils::log("found local GUID %s at 0x%016llX\n", name.c_str(), - u64_addr(ea)); + efi_utils::log("found local GUID %s at 0x%" PRIx64 "\n", + name.c_str(), u64_addr(ea)); json g; g["address"] = ea; @@ -1758,7 +1758,8 @@ void find_callout_rec(func_t *func) { } } if (!fp) { - efi_utils::log("found SMM callout via boot services at 0x%016llX\n", + efi_utils::log("found SMM callout via boot services at 0x%" PRIx64 + "\n", u64_addr(ea)); callout_addrs.push_back(ea); continue; @@ -1767,7 +1768,8 @@ void find_callout_rec(func_t *func) { // search for callouts with gRT if (efi_utils::addr_in_vec(rt_list, insn.ops[1].addr)) { - efi_utils::log("found SMM callout via runtime services at 0x%016llX\n", + efi_utils::log("found SMM callout via runtime services at 0x%" PRIx64 + "\n", u64_addr(ea)); callout_addrs.push_back(ea); continue; @@ -1798,7 +1800,8 @@ void find_callout_rec(func_t *func) { next_insn.ops[0].reg == R_RAX) { if (next_insn.ops[0].addr == 0x140 || next_insn.ops[0].addr == 0x40) { - efi_utils::log("found SMM callout via interface at 0x%016llX\n", + efi_utils::log("found SMM callout via interface at 0x%" PRIx64 + "\n", u64_addr(ea)); callout_addrs.push_back(ea); found = true; @@ -1907,9 +1910,9 @@ bool efi_analysis::efi_analyser_t::find_double_get_variable_pei() { ea_t prev_addr = get_variable_services_calls.at(0); for (auto i = 1; i < get_variable_services_calls.size(); ++i) { ea_t curr_addr = get_variable_services_calls.at(i); - efi_utils::log("first call to VariablePPI.GetVariable: 0x%016llX\n", + efi_utils::log("first call to VariablePPI.GetVariable: 0x%" PRIx64 "\n", u64_addr(prev_addr)); - efi_utils::log("second call to VariablePPI.GetVariable: 0x%016llX\n", + efi_utils::log("second call to VariablePPI.GetVariable: 0x%" PRIx64 "\n", u64_addr(curr_addr)); // check code from first call to second call @@ -1955,7 +1958,7 @@ bool efi_analysis::efi_analyser_t::find_double_get_variable_pei() { if (same_datasize) { double_get_variable_pei.push_back(curr_addr); - efi_utils::log("overflow may occur here: 0x%016llX\n", + efi_utils::log("overflow may occur here: 0x%" PRIx64 "\n", u64_addr(curr_addr)); continue; } @@ -1975,7 +1978,7 @@ bool efi_analysis::efi_analyser_t::find_double_get_variable_pei() { // if datasize wasn't found, just let the pattern // trigger - for manual review double_get_variable_pei.push_back(curr_addr); - efi_utils::log("overflow may occur here: 0x%016llX\n", + efi_utils::log("overflow may occur here: 0x%" PRIx64 "\n", u64_addr(curr_addr)); continue; } @@ -2005,7 +2008,7 @@ bool efi_analysis::efi_analyser_t::find_double_get_variable_pei() { if (same_datasize) { double_get_variable_pei.push_back(curr_addr); - efi_utils::log("overflow may occur here: 0x%016llX\n", + efi_utils::log("overflow may occur here: 0x%" PRIx64 "\n", u64_addr(curr_addr)); continue; } @@ -2023,11 +2026,11 @@ bool efi_analysis::efi_analyser_t::find_double_get_variable_pei() { if (!datasize_addr_found) { double_get_variable_pei.push_back(curr_addr); - efi_utils::log("overflow may occur here: 0x%016llX\n", + efi_utils::log("overflow may occur here: 0x%" PRIx64 "\n", u64_addr(curr_addr)); } else if (prev_datasize_addr == curr_datasize_addr) { double_get_variable_pei.push_back(curr_addr); - efi_utils::log("overflow may occur here: 0x%016llX\n", + efi_utils::log("overflow may occur here: 0x%" PRIx64 "\n", u64_addr(curr_addr)); } } @@ -2063,9 +2066,9 @@ bool efi_analysis::efi_analyser_t::find_double_get_variable( ea_t prev_addr = get_variable_services_calls.at(0); for (auto i = 1; i < get_variable_services_calls.size(); ++i) { ea_t curr_addr = get_variable_services_calls.at(i); - efi_utils::log("first call to GetVariable: 0x%016llX\n", + efi_utils::log("first call to GetVariable: 0x%" PRIx64 "\n", u64_addr(prev_addr)); - efi_utils::log("second call to GetVariable: 0x%016llX\n", + efi_utils::log("second call to GetVariable: 0x%" PRIx64 "\n", u64_addr(curr_addr)); int datasize_stack_addr = 0; @@ -2158,7 +2161,7 @@ bool efi_analysis::efi_analyser_t::find_double_get_variable( (sval + stack_addr) == datasize_stack_addr) || (datasize_stack_addr == insn.ops[1].addr)) { double_get_variable.push_back(curr_addr); - efi_utils::log("overflow may occur here: 0x%016llX\n", + efi_utils::log("overflow may occur here: 0x%" PRIx64 "\n", u64_addr(curr_addr)); break; } @@ -2188,9 +2191,9 @@ bool efi_analysis::efi_analyser_t::find_double_get_variable_smm() { insn_t insn; for (auto i = 1; i < smm_get_variable_calls.size(); ++i) { ea_t curr_addr = smm_get_variable_calls.at(i); - efi_utils::log("first call to SmmGetVariable: 0x%016llX\n", + efi_utils::log("first call to SmmGetVariable: 0x%" PRIx64 "\n", u64_addr(prev_addr)); - efi_utils::log("second call to SmmGetVariable: 0x%016llX\n", + efi_utils::log("second call to SmmGetVariable: 0x%" PRIx64 "\n", u64_addr(curr_addr)); uint32_t datasize_stack_addr = 0xffffffff; @@ -2236,7 +2239,7 @@ bool efi_analysis::efi_analyser_t::find_double_get_variable_smm() { insn.ops[0].reg == R_R9) { if (datasize_stack_addr == insn.ops[1].addr) { double_get_variable_smm.push_back(curr_addr); - efi_utils::log("overflow may occur here: 0x%016llX\n", + efi_utils::log("overflow may occur here: 0x%" PRIx64 "\n", u64_addr(curr_addr)); break; } @@ -2259,7 +2262,7 @@ bool efi_analysis::efi_analyser_t::analyse_variable_service( return false; } - efi_utils::log("analysing %s call at 0x%016llX\n", service_str.c_str(), + efi_utils::log("analysing %s call at 0x%" PRIx64 "\n", service_str.c_str(), u64_addr(ea)); eavec_t args; @@ -2285,7 +2288,7 @@ bool efi_analysis::efi_analyser_t::analyse_variable_service( // retype CHAR16 to const CHAR16 to improve pseudocode quality efi_utils::set_const_char16_type(insn.ops[1].addr); - efi_utils::log(" VariableName: %s (at 0x%016llX)\n", var_name.c_str(), + efi_utils::log(" VariableName: %s (at 0x%" PRIx64 ")\n", var_name.c_str(), u64_addr(insn.ops[1].addr)); v["VariableName"] = var_name; @@ -2300,7 +2303,7 @@ bool efi_analysis::efi_analyser_t::analyse_variable_service( if (insn.itype == NN_lea && insn.ops[0].type == o_reg && insn.ops[0].reg == R_RDX && insn.ops[1].type == o_mem) { efi_guid_t guid = efi_utils::get_global_guid(insn.ops[1].addr); - efi_utils::log(" VendorGuid: %s (at 0x%016llX)\n", + efi_utils::log(" VendorGuid: %s (at 0x%" PRIx64 ")\n", guid.to_string().c_str(), u64_addr(insn.ops[1].addr)); v["VendorGuid"] = guid.to_string(); @@ -2313,7 +2316,7 @@ bool efi_analysis::efi_analyser_t::analyse_variable_service( switch (insn.ops[1].reg) { case R_RBP: { efi_guid_t guid = efi_utils::get_local_guid(f, insn.ops[1].addr); - efi_utils::log(" VendorGuid: %s, RBP offset: 0x%016llX\n", + efi_utils::log(" VendorGuid: %s, RBP offset: 0x%" PRIx64 "\n", guid.to_string().c_str(), u64_addr(insn.ops[1].addr)); v["VendorGuid"] = guid.to_string(); @@ -2321,7 +2324,7 @@ bool efi_analysis::efi_analyser_t::analyse_variable_service( } case R_RSP: { efi_guid_t guid = efi_utils::get_local_guid(f, insn.ops[1].addr); - efi_utils::log(" VendorGuid: %s, RSP offset: 0x%016llX\n", + efi_utils::log(" VendorGuid: %s, RSP offset: 0x%" PRIx64 "\n", guid.to_string().c_str(), u64_addr(insn.ops[1].addr)); v["VendorGuid"] = guid.to_string(); diff --git a/efiXplorer/efi_defs.h b/efiXplorer/efi_defs.h index 49cab6e5..44a89e8a 100644 --- a/efiXplorer/efi_defs.h +++ b/efiXplorer/efi_defs.h @@ -19,6 +19,7 @@ #pragma once +#include #include #include #include diff --git a/efiXplorer/efi_hexrays.h b/efiXplorer/efi_hexrays.h index 73002c5f..eaca5d2d 100644 --- a/efiXplorer/efi_hexrays.h +++ b/efiXplorer/efi_hexrays.h @@ -653,7 +653,7 @@ class prototypes_fixer_t : public ctree_visitor_t { return 0; } if (m_debug) { - efi_utils::log("child function address: %016llX\n", + efi_utils::log("child function address: 0x%" PRIx64 "\n", u64_addr(e->x->obj_ea)); } @@ -676,7 +676,7 @@ class prototypes_fixer_t : public ctree_visitor_t { } if (m_debug) { - efi_utils::log("call address: 0x%016llX\n", u64_addr(e->ea)); + efi_utils::log("call address: 0x%" PRIx64 "\n", u64_addr(e->ea)); } for (auto i = 0; i < args->size(); i++) { cexpr_t *arg = &args->at(i); @@ -811,7 +811,7 @@ class variables_detector_t : public ctree_visitor_t { } if (m_debug) { - efi_utils::log("code address: 0x%016llX, type name: %s\n", + efi_utils::log("code address: 0x%" PRIx64 ", type name: %s\n", u64_addr(e->ea), type_name.c_str()); } @@ -920,7 +920,8 @@ class services_detector_t : public ctree_visitor_t { } } if (m_debug) { - efi_utils::log("address: 0x%016llX, service type: %s, service name: %s\n", + efi_utils::log("address: 0x%" PRIx64 + ", service type: %s, service name: %s\n", u64_addr(e->ea), type_name.c_str(), service_name.c_str()); } @@ -997,7 +998,7 @@ class pei_services_detector_t : public ctree_visitor_t { return 0; } - efi_utils::log("PEI service detected at 0x%08llX\n", u64_addr(e->ea)); + efi_utils::log("PEI service detected at 0x%" PRIx64 "\n", u64_addr(e->ea)); tinfo_t outer; if (!outer.get_named_type(get_idati(), "EFI_PEI_SERVICES_4", BTF_STRUCT)) { @@ -1015,7 +1016,8 @@ class pei_services_detector_t : public ctree_visitor_t { return 0; } if (set_var_type(func->start_ea, dest_var, shifted_tif)) { - efi_utils::log("shifted pointer applied at 0x%08llX\n", u64_addr(e->ea)); + efi_utils::log("shifted pointer applied at 0x%" PRIx64 "\n", + u64_addr(e->ea)); } if (call) { @@ -1077,7 +1079,7 @@ class pei_services_detector_arm_t : public ctree_visitor_t { service_name = s->second; } if (m_debug) { - efi_utils::log("0x%08llX: %s service detected (offset: %d): %s\n", + efi_utils::log("0x%" PRIx64 ": %s service detected (offset: %d): %s\n", u64_addr(e->ea), table_type_name.c_str(), u32_addr(offset), service_name.c_str()); } diff --git a/efiXplorer/efi_smm_utils.cc b/efiXplorer/efi_smm_utils.cc index 492e747c..ec094c14 100644 --- a/efiXplorer/efi_smm_utils.cc +++ b/efiXplorer/efi_smm_utils.cc @@ -45,13 +45,13 @@ ea_list_t efi_smm_utils::find_smst_sw_dispatch(ea_list_t bs_list) { data_addrs.insert(data_addrs.end(), data2_addrs.begin(), data2_addrs.end()); for (auto data_addr : data_addrs) { - efi_utils::log("SMM dispatch protocol GUID: 0x%016llX\n", + efi_utils::log("SMM dispatch protocol GUID: 0x%" PRIx64 "\n", u64_addr(data_addr)); ea_list_t xrefs = efi_utils::get_xrefs(data_addr); insn_t insn; for (auto xref : xrefs) { // smst register - uint16_t smst_reg = 0xffff; + uint16_t smst_reg = NONE_REG; ea_t cur_addr = xref; while (true) { cur_addr = next_head(cur_addr, BADADDR); @@ -67,7 +67,7 @@ ea_list_t efi_smm_utils::find_smst_sw_dispatch(ea_list_t bs_list) { } } - if (smst_reg == 0xffff) { + if (smst_reg == NONE_REG) { // smst register not found continue; } @@ -79,7 +79,8 @@ ea_list_t efi_smm_utils::find_smst_sw_dispatch(ea_list_t bs_list) { decode_insn(&insn, cur_addr); if (insn.itype == NN_mov && insn.ops[0].type == o_reg && insn.ops[0].reg == smst_reg && insn.ops[1].type == o_mem) { - efi_utils::log("found gSmst at 0x%016llX, address = 0x%016llX\n", + efi_utils::log("found gSmst at 0x%" PRIx64 ", address = 0x%" PRIx64 + "\n", u64_addr(cur_addr), u64_addr(insn.ops[1].addr)); res_addr = insn.ops[1].addr; if (efi_utils::addr_in_vec(bs_list, res_addr)) { @@ -112,7 +113,8 @@ ea_list_t efi_smm_utils::find_smst_smm_base(ea_list_t bs_list) { ea_list_t data_addrs = efi_utils::find_data(0, BADADDR, guid.uchar_data().data(), 16); for (auto data_addr : data_addrs) { - efi_utils::log("SMM base protocol GUID: 0x%016llX\n", u64_addr(data_addr)); + efi_utils::log("SMM base protocol GUID: 0x%" PRIx64 "\n", + u64_addr(data_addr)); ea_list_t data_xrefs = efi_utils::get_xrefs(data_addr); insn_t insn; for (auto xref : data_xrefs) { @@ -126,9 +128,9 @@ ea_list_t efi_smm_utils::find_smst_smm_base(ea_list_t bs_list) { if (insn.itype == NN_lea && insn.ops[0].type == o_reg && insn.ops[0].reg == R_RDX && insn.ops[1].type == o_mem) { res_addr = insn.ops[1].addr; - efi_utils::log( - "found gSmst/InSmram at 0x%016llX, address = 0x%016llX\n", - u64_addr(cur_addr), u64_addr(res_addr)); + efi_utils::log("found gSmst/InSmram at 0x%" PRIx64 + ", address = 0x%" PRIx64 "\n", + u64_addr(cur_addr), u64_addr(res_addr)); } if (res_addr != BADADDR && insn.itype == NN_callni && insn.ops[0].type == o_phrase && !insn.ops[0].addr) { @@ -158,7 +160,7 @@ ea_list_t efi_smm_utils::find_smst_smm_base(ea_list_t bs_list) { // find SmiHandler in reg_smi_func function, // prefix: Sw, TrapIo, Sx, Gpi, Usb, StandbyButton, PeriodicTimer, ... func_list_t efi_smm_utils::find_smi_handlers(ea_t address, std::string prefix) { - efi_utils::log("analyse xref to SMM %sDispatch protocol: 0x%016llX\n", + efi_utils::log("analyse xref to SMM %sDispatch protocol: 0x%" PRIx64 "\n", prefix.c_str(), u64_addr(address)); func_list_t smi_handlers; @@ -233,7 +235,7 @@ func_list_t efi_smm_utils::find_smi_handlers(ea_t address, std::string prefix) { return smi_handlers; } - efi_utils::log("found SMM %sDispatch protocol interface at: 0x%016llX\n", + efi_utils::log("found SMM %sDispatch protocol interface at: 0x%" PRIx64 "\n", prefix.c_str(), dispatch_interface); // TODO(yeggor): handle xrefs for globals @@ -278,7 +280,7 @@ func_list_t efi_smm_utils::find_smi_handlers(ea_t address, std::string prefix) { } if (insn.itype == NN_callni && insn.ops[0].type == o_phrase && insn.ops[0].reg == reg) { - efi_utils::log("Register(): 0x%016llX, %sSmiHandler: 0x%016llX\n", + efi_utils::log("Register(): 0x%" PRIx64 ", %sSmiHandler: 0x%" PRIx64 "\n", u64_addr(ea), prefix.c_str(), dispatch_func); auto handler_func = get_func(dispatch_func); if (handler_func == nullptr) { @@ -356,7 +358,7 @@ efi_smm_utils::find_smi_handlers_dispatch_stack(json_list_t stack_guids, ea_t address = static_cast(guid["address"]); efi_utils::log( - "found EFI_SMM_SW_DISPATCH{2}_PROTOCOL_GUID on stack: 0x%016llX\n", + "found EFI_SMM_SW_DISPATCH{2}_PROTOCOL_GUID on stack: 0x%" PRIx64 "\n", u64_addr(address)); auto res = efi_smm_utils::find_smi_handlers(address, prefix); smi_handlers.insert(smi_handlers.end(), res.begin(), res.end()); @@ -390,7 +392,8 @@ efi_smm_utils::find_smm_get_variable_calls(segment_list_t data_segs, segment_t *seg = getseg(xref); qstring seg_name; get_segm_name(&seg_name, seg); - efi_utils::log("found EFI_SMM_VARIABLE_PROTOCOL_GUID xref at 0x%016llX\n", + efi_utils::log("found EFI_SMM_VARIABLE_PROTOCOL_GUID xref at 0x%" PRIx64 + "\n", u64_addr(xref)); size_t index = seg_name.find(".text"); @@ -406,7 +409,7 @@ efi_smm_utils::find_smm_get_variable_calls(segment_list_t data_segs, decode_insn(&insn, ea); if (insn.itype == NN_lea && insn.ops[0].type == o_reg && insn.ops[0].reg == R_R8 && insn.ops[1].type == o_mem) { - efi_utils::log("gSmmVariable: 0x%016llX\n", + efi_utils::log("gSmmVariable: 0x%" PRIx64 "\n", u64_addr(insn.ops[1].addr)); efi_utils::set_ptr_type_and_name(insn.ops[1].addr, "gSmmVariable", "EFI_SMM_VARIABLE_PROTOCOL"); @@ -428,7 +431,7 @@ efi_smm_utils::find_smm_get_variable_calls(segment_list_t data_segs, segment_t *seg = getseg(smm_variable_xref); qstring seg_name; get_segm_name(&seg_name, seg); - efi_utils::log("found gSmmVariable xref at 0x%016llX\n", + efi_utils::log("found gSmmVariable xref at 0x%" PRIx64 "\n", u64_addr(smm_variable_xref)); size_t index = seg_name.find(".text"); @@ -459,7 +462,7 @@ efi_smm_utils::find_smm_get_variable_calls(segment_list_t data_segs, // temporarily add a "virtual" SMM service call // for easier annotations and UI efi_utils::op_stroff(ea, "EFI_SMM_VARIABLE_PROTOCOL"); - efi_utils::log("found SmmGetVariable call at 0x%016llX\n", + efi_utils::log("found SmmGetVariable call at 0x%" PRIx64 "\n", u64_addr(ea)); json service; @@ -493,7 +496,7 @@ efi_smm_utils::resolve_efi_smm_cpu_protocol(json_list_t stack_guids, if (static_cast(guid["name"]) != "EFI_SMM_CPU_PROTOCOL_GUID") continue; ea_t address = static_cast(guid["address"]); - efi_utils::log("found EFI_SMM_CPU_PROTOCOL on stack at 0x%016llX\n", + efi_utils::log("found EFI_SMM_CPU_PROTOCOL on stack at 0x%" PRIx64 "\n", u64_addr(address)); code_addrs.push_back(address); } @@ -503,7 +506,7 @@ efi_smm_utils::resolve_efi_smm_cpu_protocol(json_list_t stack_guids, continue; ea_t address = static_cast(guid["address"]); - efi_utils::log("found EFI_SMM_CPU_PROTOCOL at 0x%016llX\n", + efi_utils::log("found EFI_SMM_CPU_PROTOCOL at 0x%" PRIx64 "\n", u64_addr(address)); ea_list_t guid_xrefs = efi_utils::get_xrefs(address); @@ -528,7 +531,7 @@ efi_smm_utils::resolve_efi_smm_cpu_protocol(json_list_t stack_guids, decode_insn(&insn, ea); if (insn.itype == NN_lea && insn.ops[0].type == o_reg && insn.ops[0].reg == R_R8 && insn.ops[1].type == o_mem) { - efi_utils::log("gSmmCpu: 0x%016llX\n", u64_addr(insn.ops[1].addr)); + efi_utils::log("gSmmCpu: 0x%" PRIx64 "\n", u64_addr(insn.ops[1].addr)); efi_utils::set_ptr_type_and_name(insn.ops[1].addr, "gSmmCpu", "EFI_SMM_CPU_PROTOCOL"); smm_cpu_addrs.push_back(insn.ops[1].addr); @@ -577,7 +580,8 @@ efi_smm_utils::resolve_efi_smm_cpu_protocol(json_list_t stack_guids, } efi_utils::op_stroff(ea, "EFI_SMM_CPU_PROTOCOL"); - efi_utils::log("gSmmCpu->ReadSaveState: 0x%016llX\n", u64_addr(ea)); + efi_utils::log("gSmmCpu->ReadSaveState: 0x%" PRIx64 "\n", + u64_addr(ea)); json service; service["address"] = ea; diff --git a/efiXplorer/efi_ui.cc b/efiXplorer/efi_ui.cc index 91f9329b..ed966d07 100644 --- a/efiXplorer/efi_ui.cc +++ b/efiXplorer/efi_ui.cc @@ -115,7 +115,7 @@ void idaapi nvram_chooser_t::get_row(qstrvec_t *cols_, int *, std::string service = static_cast(item["service"]); std::string attributes = static_cast(item["AttributesHumanReadable"]); - cols[0].sprnt("%016llX", u64_addr(ea)); + cols[0].sprnt("%016" PRIX64, u64_addr(ea)); cols[1].sprnt("%s", name.c_str()); cols[2].sprnt("%s", guid.c_str()); cols[3].sprnt("%s", service.c_str()); @@ -137,7 +137,7 @@ void idaapi vulns_chooser_t::get_row(qstrvec_t *cols_, int *, qstrvec_t &cols = *cols_; json item = chooser_vulns[n]; std::string type = static_cast(item["type"]); - cols[0].sprnt("%016llX", u64_addr(ea)); + cols[0].sprnt("%016" PRIX64, u64_addr(ea)); cols[1].sprnt("%s", type.c_str()); CASSERT(qnumber(header_vulns) == 2); } @@ -157,7 +157,7 @@ void idaapi guids_chooser_t::get_row(qstrvec_t *cols_, int *, json item = chooser_guids[n]; std::string guid = static_cast(item["guid"]); std::string name = static_cast(item["name"]); - cols[0].sprnt("%016llX", u64_addr(ea)); + cols[0].sprnt("%016" PRIX64, u64_addr(ea)); cols[1].sprnt("%s", guid.c_str()); cols[2].sprnt("%s", name.c_str()); CASSERT(qnumber(header_guids) == 3); @@ -184,7 +184,7 @@ void idaapi m_protocols_chooser_t::get_row(qstrvec_t *cols_, int *, std::string service = static_cast(item["service"]); std::string protGuid = static_cast(item["guid"]); std::string moduleName = static_cast(item["module"]); - cols[0].sprnt("%016llX", u64_addr(ea)); + cols[0].sprnt("%016" PRIX64, u64_addr(ea)); cols[1].sprnt("%s", protGuid.c_str()); cols[2].sprnt("%s", name.c_str()); cols[3].sprnt("%s", service.c_str()); @@ -207,7 +207,7 @@ void idaapi services_chooser_t::get_row(qstrvec_t *cols_, int *, json item = chooser_s[n]; std::string service_name = item["service_name"]; std::string table_name = item["table_name"]; - cols[0].sprnt("%016llX", u64_addr(ea)); + cols[0].sprnt("%016" PRIX64, u64_addr(ea)); cols[1].sprnt("%s", service_name.c_str()); cols[2].sprnt("%s", table_name.c_str()); CASSERT(qnumber(header_s) == 3); diff --git a/efiXplorer/efi_utils.cc b/efiXplorer/efi_utils.cc index 011a4a1d..ddc0501b 100644 --- a/efiXplorer/efi_utils.cc +++ b/efiXplorer/efi_utils.cc @@ -133,7 +133,7 @@ bool mark_copy(ea_t code_addr, ea_t var_addr, std::string type) { if (insn.itype == NN_mov && insn.ops[0].type == o_mem && insn.ops[1].type == o_reg && insn.ops[1].reg == reg) { var_copy = insn.ops[0].addr; - efi_utils::log("found copy for global variable: 0x%016llX\n", + efi_utils::log("found copy for global variable: 0x%" PRIx64 "\n", u64_addr(ea)); break; } @@ -766,9 +766,9 @@ void op_stroff_for_addr(ea_t ea, qstring type_name) { (insn.ops[0].type == o_displ || insn.ops[0].type == o_phrase) && insn.ops[0].reg == R_RAX) { efi_utils::op_stroff(ea, static_cast(type_name.c_str())); - efi_utils::log( - "mark arguments at address 0x%016llX (interface type: %s)\n", - u64_addr(ea), type_name.c_str()); + efi_utils::log("mark arguments at address 0x%" PRIx64 + " (interface type: %s)\n", + u64_addr(ea), type_name.c_str()); // check for EfiSmmBase2Protocol->GetSmstLocation if (type_name == "EFI_SMM_BASE2_PROTOCOL" && From 436b79ed754fae13fbe33b535266c407c2de6450 Mon Sep 17 00:00:00 2001 From: yeggor Date: Sun, 22 Sep 2024 19:22:21 +0100 Subject: [PATCH 46/69] move globals to efi_analyser_t --- efiXplorer/efi_analysis.h | 55 ++++-- efiXplorer/efi_analysis_x86.cc | 320 +++++++++++++++------------------ 2 files changed, 191 insertions(+), 184 deletions(-) diff --git a/efiXplorer/efi_analysis.h b/efiXplorer/efi_analysis.h index 5eb5d275..31884bd7 100644 --- a/efiXplorer/efi_analysis.h +++ b/efiXplorer/efi_analysis.h @@ -35,7 +35,13 @@ class efi_analyser_t { efi_analyser_t(); ~efi_analyser_t(); + ea_list_t m_bs_list; // gBS list (boot services addresses) + ea_list_t m_rt_list; // gRT list (runtime services addresses) + ea_list_t m_smst_list; // gSmst list (SMM system table addresses) + ea_list_t m_st_list; // gST list (system table addresses) + ea_list_t m_funcs; + func_list_t m_smi_handlers; json_list_t m_all_guids; json_list_t m_all_ppis; @@ -43,6 +49,11 @@ class efi_analyser_t { json_list_t m_all_services; json_list_t m_nvram_variables; + // all .text and .data segments + // for compatibility with the efixloader + segment_list_t m_code_segs; + segment_list_t m_data_segs; + arch_file_type_t m_arch = arch_file_type_t::unsupported; ffs_file_type_t m_ftype = ffs_file_type_t::unsupported; @@ -53,10 +64,6 @@ class efi_analyser_t { void annotate_data_guids(); bool smm_cpu_protocol_resolver(); void find_smi_handlers(); - bool find_double_get_variable(json_list_t m_all_services); - bool find_double_get_variable_pei(); - bool find_double_get_variable_smm(); - bool find_smm_callout(); bool analyse_nvram_variables(); protected: @@ -67,13 +74,6 @@ class efi_analyser_t { std::map m_guiddb_map; json m_guiddb; - ea_list_t m_annotated_protocols; - json m_boot_services; - json m_pei_services_all; - json m_ppi_calls_all; - json m_runtime_services_all; - json m_smm_services_all; - json m_smm_services; std::filesystem::path m_guids_json_path; // protocol related boot services @@ -103,6 +103,32 @@ class efi_analyser_t { string_list_t m_ppi_peis_names = {"InstallPpi", "ReInstallPpi", "LocatePpi", "NotifyPpi"}; + // data and stack guids + json_list_t m_data_guids; + json_list_t m_stack_guids; + + ea_list_t m_annotated_protocols; + json m_boot_services; + json m_pei_services_all; + json m_ppi_calls_all; + json m_runtime_services_all; + json m_smm_services_all; + json m_smm_services; + + ea_list_t m_image_handle_list; // gImageHandle list (image handle addresses) + ea_list_t m_runtime_services_list; // runtime services list + + // for SMM callout scanners + ea_list_t m_callout_addrs; + ea_list_t m_read_save_state_calls; + func_list_t m_child_smi_handlers; + func_list_t m_exc_funcs; + + // for double GetVariable scanners + ea_list_t m_double_get_variable_pei; + ea_list_t m_double_get_variable_smm; + ea_list_t m_double_get_variable; + bool add_protocol(std::string service_name, ea_t guid_addr, ea_t xref_addr, ea_t call_addr); @@ -351,11 +377,16 @@ class efi_analyser_x86_t : public efi_analyser_t { } bool find_boot_services_tables(); + bool find_double_get_variable_pei(); + bool find_double_get_variable_smm(); + bool find_double_get_variable(); bool find_image_handle64(); bool find_runtime_services_tables(); + bool find_smm_callout(); bool find_smst_postproc64(); bool find_smst64(); bool find_system_table64(); + void find_local_guids64(); void find_other_boot_services_tables64(); void get_boot_services_all(); void get_bs_prot_names32(); @@ -368,10 +399,10 @@ class efi_analyser_x86_t : public efi_analyser_t { void get_smm_prot_names64(); void get_smm_services_all64(); void get_variable_ppi_calls_all32(); - void find_local_guids64(); void show_all_choosers(); private: + void find_callout_rec(func_t *func); bool install_multiple_prot_interfaces_analyser(); }; diff --git a/efiXplorer/efi_analysis_x86.cc b/efiXplorer/efi_analysis_x86.cc index 6aa0ab22..42bc87bf 100644 --- a/efiXplorer/efi_analysis_x86.cc +++ b/efiXplorer/efi_analysis_x86.cc @@ -29,32 +29,6 @@ extern ea_list_t g_get_smst_location_calls; extern ea_list_t g_smm_get_variable_calls; extern ea_list_t g_smm_set_variable_calls; -ea_list_t st_list; // gST list (system table addresses) -ea_list_t ps_list; // gPS list (PEI services addresses) -ea_list_t bs_list; // gBS list (boot services addresses) -ea_list_t rt_list; // gRT list (runtime services addresses) -ea_list_t smst_list; // gSmst list (SMM system table addresses) -ea_list_t image_handle_list; // gImageHandle list (image handle addresses) -ea_list_t runtime_services_list; // runtime services list - -json_list_t data_guids; -json_list_t stack_guids; - -// all .text and .data segments for compatibility with the efiLoader -segment_list_t code_segs; -segment_list_t data_segs; - -// for smm callouts finding -ea_list_t callout_addrs; -ea_list_t read_save_state_calls; -func_list_t child_smi_handlers; -func_list_t exc_funcs; - -// for GetVariable stack overflow finding -ea_list_t double_get_variable_pei; -ea_list_t double_get_variable_smm; -ea_list_t double_get_variable; - efi_analysis::efi_analyser_t::efi_analyser_t() { // 32-bit, 64-bit, ARM or UEFI (in loader instance) m_arch = efi_utils::input_file_type(); @@ -111,29 +85,28 @@ efi_analysis::efi_analyser_t::efi_analyser_t() { efi_analysis::efi_analyser_t::~efi_analyser_t() { m_funcs.clear(); - st_list.clear(); - ps_list.clear(); - bs_list.clear(); - rt_list.clear(); - smst_list.clear(); - image_handle_list.clear(); - runtime_services_list.clear(); + m_st_list.clear(); + m_bs_list.clear(); + m_rt_list.clear(); + m_smst_list.clear(); + m_image_handle_list.clear(); + m_runtime_services_list.clear(); - stack_guids.clear(); - data_guids.clear(); + m_stack_guids.clear(); + m_data_guids.clear(); - code_segs.clear(); - data_segs.clear(); + m_code_segs.clear(); + m_data_segs.clear(); - callout_addrs.clear(); - exc_funcs.clear(); - read_save_state_calls.clear(); + m_callout_addrs.clear(); + m_exc_funcs.clear(); + m_read_save_state_calls.clear(); m_smi_handlers.clear(); - child_smi_handlers.clear(); + m_child_smi_handlers.clear(); - double_get_variable_pei.clear(); - double_get_variable.clear(); - double_get_variable_smm.clear(); + m_double_get_variable_pei.clear(); + m_double_get_variable.clear(); + m_double_get_variable_smm.clear(); g_get_smst_location_calls.clear(); g_smm_get_variable_calls.clear(); @@ -173,26 +146,26 @@ void efi_analysis::efi_analyser_t::get_segments() { // in order for decompilation to work properly s->perm = (SEGPERM_READ | SEGPERM_WRITE | SEGPERM_EXEC); set_segm_class(s, "DATA"); - code_segs.push_back(s); + m_code_segs.push_back(s); continue; } } auto index = seg_name.find(".data"); if (index != std::string::npos) { - data_segs.push_back(s); + m_data_segs.push_back(s); continue; } } // print all .text and .code segments addresses - for (auto seg : code_segs) { + for (auto seg : m_code_segs) { segment_t *s = seg; efi_utils::log("code segment: 0x%" PRIx64 "\n", u64_addr(s->start_ea)); } // print all .data segments addresses - for (auto seg : data_segs) { + for (auto seg : m_data_segs) { segment_t *s = seg; efi_utils::log("data segment: 0x%" PRIx64 "\n", u64_addr(s->start_ea)); } @@ -217,7 +190,7 @@ bool efi_analysis::efi_analyser_x86_t::find_image_handle64() { insn.ops[1].reg == R_RCX && insn.ops[0].type == o_mem) { efi_utils::set_type_and_name(insn.ops[0].addr, "gImageHandle", "EFI_IMAGE_HANDLE"); - image_handle_list.push_back(insn.ops[0].addr); + m_image_handle_list.push_back(insn.ops[0].addr); break; } ea = next_head(ea, m_end_addr); @@ -242,7 +215,7 @@ bool efi_analysis::efi_analyser_x86_t::find_system_table64() { insn.ops[1].reg == R_RDX && insn.ops[0].type == o_mem) { efi_utils::set_ptr_type_and_name(insn.ops[0].addr, "gST", "EFI_SYSTEM_TABLE"); - st_list.push_back(insn.ops[0].addr); + m_st_list.push_back(insn.ops[0].addr); return true; } ea = next_head(ea, BADADDR); @@ -254,23 +227,23 @@ bool efi_analysis::efi_analyser_x86_t::find_system_table64() { //-------------------------------------------------------------------------- // find and mark gSmst global variable for 64-bit modules bool efi_analysis::efi_analyser_x86_t::find_smst64() { - ea_list_t smst_list_smm_base = efi_smm_utils::find_smst_smm_base(bs_list); + ea_list_t smst_list_smm_base = efi_smm_utils::find_smst_smm_base(m_bs_list); ea_list_t smst_list_sw_dispatch = - efi_smm_utils::find_smst_sw_dispatch(bs_list); - smst_list.insert(smst_list.end(), smst_list_sw_dispatch.begin(), - smst_list_sw_dispatch.end()); - smst_list.insert(smst_list.end(), smst_list_smm_base.begin(), - smst_list_smm_base.end()); + efi_smm_utils::find_smst_sw_dispatch(m_bs_list); + m_smst_list.insert(m_smst_list.end(), smst_list_sw_dispatch.begin(), + smst_list_sw_dispatch.end()); + m_smst_list.insert(m_smst_list.end(), smst_list_smm_base.begin(), + smst_list_smm_base.end()); // deduplicate - auto last = std::unique(smst_list.begin(), smst_list.end()); - smst_list.erase(last, smst_list.end()); + auto last = std::unique(m_smst_list.begin(), m_smst_list.end()); + m_smst_list.erase(last, m_smst_list.end()); - for (auto smst : smst_list) { + for (auto smst : m_smst_list) { efi_utils::log("0x%" PRIx64 ": gSmst\n", u64_addr(smst)); } - return !smst_list.empty(); + return !m_smst_list.empty(); } //-------------------------------------------------------------------------- @@ -320,10 +293,10 @@ bool efi_analysis::efi_analyser_x86_t::find_smst_postproc64() { if (smst_stack.is_null() && smst_addr != BADADDR) { efi_utils::log(" gSmst: 0x%" PRIx64 "\n", u64_addr(smst_addr)); - if (!efi_utils::addr_in_vec(smst_list, smst_addr)) { + if (!efi_utils::addr_in_vec(m_smst_list, smst_addr)) { efi_utils::set_ptr_type_and_name(smst_addr, "gSmst", "_EFI_SMM_SYSTEM_TABLE2"); - smst_list.push_back(smst_addr); + m_smst_list.push_back(smst_addr); } } @@ -381,7 +354,7 @@ bool efi_analysis::efi_analyser_x86_t::find_smst_postproc64() { // save child SW SMI handler func_t *handler_func = get_func(rcx_last); if (handler_func != nullptr) { - child_smi_handlers.push_back(handler_func); + m_child_smi_handlers.push_back(handler_func); set_name(rcx_last, "ChildSwSmiHandler", SN_FORCE); break; } @@ -406,7 +379,7 @@ bool efi_analysis::efi_analyser_x86_t::find_boot_services_tables() { } insn_t insn; - for (auto seg : code_segs) { + for (auto seg : m_code_segs) { segment_t *s = seg; ea_t ea = s->start_ea; uint16_t bs_reg = 0; @@ -441,10 +414,10 @@ bool efi_analysis::efi_analyser_x86_t::find_boot_services_tables() { next_insn.ops[1].type == o_reg && next_insn.ops[1].reg == bs_reg) { base_insn_addr = ea; - if (!efi_utils::addr_in_vec(bs_list, var_addr)) { + if (!efi_utils::addr_in_vec(m_bs_list, var_addr)) { efi_utils::set_ptr_type_and_name(var_addr, "gBS", "EFI_BOOT_SERVICES"); - bs_list.push_back(var_addr); + m_bs_list.push_back(var_addr); } bs_found = true; } @@ -455,10 +428,10 @@ bool efi_analysis::efi_analyser_x86_t::find_boot_services_tables() { if (insn.ops[1].reg == bs_reg && !bs_found) { base_insn_addr = ea; var_addr = insn.ops[0].addr; - if (!efi_utils::addr_in_vec(bs_list, var_addr)) { + if (!efi_utils::addr_in_vec(m_bs_list, var_addr)) { efi_utils::set_ptr_type_and_name(var_addr, "gBS", "EFI_BOOT_SERVICES"); - bs_list.push_back(var_addr); + m_bs_list.push_back(var_addr); } bs_found = true; } @@ -466,11 +439,11 @@ bool efi_analysis::efi_analyser_x86_t::find_boot_services_tables() { // here you can also find gST if (insn.ops[1].reg == st_reg && !st_found && st_reg != bs_reg) { var_addr = insn.ops[0].addr; - if (!efi_utils::addr_in_tables(st_list, bs_list, rt_list, + if (!efi_utils::addr_in_tables(m_st_list, m_bs_list, m_rt_list, var_addr)) { efi_utils::set_ptr_type_and_name(var_addr, "gST", "EFI_SYSTEM_TABLE"); - st_list.push_back(var_addr); + m_st_list.push_back(var_addr); } st_found = true; } @@ -489,11 +462,11 @@ bool efi_analysis::efi_analyser_x86_t::find_boot_services_tables() { if (insn.itype == NN_mov && insn.ops[1].type == o_reg && insn.ops[1].reg == st_reg && insn.ops[0].type == o_mem) { var_addr = insn.ops[0].addr; - if (!efi_utils::addr_in_tables(st_list, bs_list, rt_list, - var_addr)) { + if (!efi_utils::addr_in_tables(m_st_list, m_bs_list, + m_rt_list, var_addr)) { efi_utils::set_ptr_type_and_name(var_addr, "gST", "EFI_SYSTEM_TABLE"); - st_list.push_back(var_addr); + m_st_list.push_back(var_addr); } st_found = true; break; @@ -505,7 +478,7 @@ bool efi_analysis::efi_analyser_x86_t::find_boot_services_tables() { } } } - return !bs_list.empty(); + return !m_bs_list.empty(); } //-------------------------------------------------------------------------- @@ -521,7 +494,7 @@ bool efi_analysis::efi_analyser_x86_t::find_runtime_services_tables() { } insn_t insn; - for (auto seg : code_segs) { + for (auto seg : m_code_segs) { segment_t *s = seg; ea_t ea = s->start_ea; uint16_t rt_register = 0; @@ -556,10 +529,10 @@ bool efi_analysis::efi_analyser_x86_t::find_runtime_services_tables() { next_insn.ops[1].type == o_reg && next_insn.ops[1].reg == rt_register) { base_insn_addr = ea; - if (!efi_utils::addr_in_vec(rt_list, var_addr)) { + if (!efi_utils::addr_in_vec(m_rt_list, var_addr)) { efi_utils::set_ptr_type_and_name(var_addr, "gRT", "EFI_RUNTIME_SERVICES"); - rt_list.push_back(var_addr); + m_rt_list.push_back(var_addr); } rt_found = true; } @@ -570,10 +543,10 @@ bool efi_analysis::efi_analyser_x86_t::find_runtime_services_tables() { if (insn.ops[1].reg == rt_register && !rt_found) { base_insn_addr = ea; var_addr = insn.ops[0].addr; - if (!efi_utils::addr_in_vec(rt_list, var_addr)) { + if (!efi_utils::addr_in_vec(m_rt_list, var_addr)) { efi_utils::set_ptr_type_and_name(var_addr, "gRT", "EFI_RUNTIME_SERVICES"); - rt_list.push_back(var_addr); + m_rt_list.push_back(var_addr); } rt_found = true; } @@ -582,11 +555,11 @@ bool efi_analysis::efi_analyser_x86_t::find_runtime_services_tables() { if (insn.ops[1].reg == st_reg && !st_found && st_reg != rt_register) { var_addr = insn.ops[0].addr; - if (!efi_utils::addr_in_tables(st_list, bs_list, rt_list, + if (!efi_utils::addr_in_tables(m_st_list, m_bs_list, m_rt_list, var_addr)) { efi_utils::set_ptr_type_and_name(insn.ops[0].addr, "gST", "EFI_SYSTEM_TABLE"); - st_list.push_back(insn.ops[0].addr); + m_st_list.push_back(insn.ops[0].addr); } st_found = true; } @@ -604,11 +577,11 @@ bool efi_analysis::efi_analyser_x86_t::find_runtime_services_tables() { decode_insn(&insn, addr); if (insn.itype == NN_mov && insn.ops[1].type == o_reg && insn.ops[1].reg == st_reg && insn.ops[0].type == o_mem) { - if (!efi_utils::addr_in_tables(st_list, bs_list, rt_list, - var_addr)) { + if (!efi_utils::addr_in_tables(m_st_list, m_bs_list, + m_rt_list, var_addr)) { efi_utils::set_ptr_type_and_name(var_addr, "gST", "EFI_SYSTEM_TABLE"); - st_list.push_back(var_addr); + m_st_list.push_back(var_addr); } st_found = true; break; @@ -621,18 +594,18 @@ bool efi_analysis::efi_analyser_x86_t::find_runtime_services_tables() { } } - return !rt_list.empty(); + return !m_rt_list.empty(); } //-------------------------------------------------------------------------- // get all boot services by xrefs for 32-bit and 64-bit modules void efi_analysis::efi_analyser_x86_t::get_boot_services_all() { - if (bs_list.empty()) { + if (m_bs_list.empty()) { return; } insn_t insn; - for (auto bs : bs_list) { + for (auto bs : m_bs_list) { auto xrefs = efi_utils::get_xrefs(bs); for (auto ea : xrefs) { bool found = false; @@ -718,12 +691,12 @@ void efi_analysis::efi_analyser_x86_t::get_boot_services_all() { //-------------------------------------------------------------------------- // get all runtime services for 32-bit and 64-bit modules by xrefs void efi_analysis::efi_analyser_x86_t::get_runtime_services_all() { - if (rt_list.empty()) { + if (m_rt_list.empty()) { return; } insn_t insn; - for (auto rt : rt_list) { + for (auto rt : m_rt_list) { auto xrefs = efi_utils::get_xrefs(rt); for (auto ea : xrefs) { decode_insn(&insn, ea); @@ -781,7 +754,7 @@ void efi_analysis::efi_analyser_x86_t::get_runtime_services_all() { if (!efi_utils::json_in_vec(m_all_services, s)) { m_all_services.push_back(s); } - runtime_services_list.push_back(addr); + m_runtime_services_list.push_back(addr); break; } } @@ -794,12 +767,12 @@ void efi_analysis::efi_analyser_x86_t::get_runtime_services_all() { //-------------------------------------------------------------------------- // get all SMM services for 64-bit modules void efi_analysis::efi_analyser_x86_t::get_smm_services_all64() { - if (smst_list.empty()) { + if (m_smst_list.empty()) { return; } insn_t insn; - for (auto smms : smst_list) { + for (auto smms : m_smst_list) { auto xrefs = efi_utils::get_xrefs(smms); for (auto ea : xrefs) { decode_insn(&insn, ea); @@ -830,7 +803,7 @@ void efi_analysis::efi_analyser_x86_t::get_smm_services_all64() { // save SMI handler func_t *child_smi_handler = get_func(smi_handler_addr); if (child_smi_handler != nullptr) { - child_smi_handlers.push_back(child_smi_handler); + m_child_smi_handlers.push_back(child_smi_handler); } } @@ -1111,7 +1084,7 @@ void efi_analysis::efi_analyser_x86_t::get_ppi_names32() { // get boot services by protocols for 64-bit modules void efi_analysis::efi_analyser_x86_t::get_prot_boot_services64() { insn_t insn; - for (auto s : code_segs) { + for (auto s : m_code_segs) { ea_t ea = s->start_ea; uint16_t bs_reg = 0; while (ea <= s->end_ea) { @@ -1136,7 +1109,7 @@ void efi_analysis::efi_analyser_x86_t::get_prot_boot_services64() { // check that address does not belong to the protocol interface // (gBS != gInterface) auto bs_addr = efi_utils::find_unknown_bs_var64(ea); - if (efi_utils::addr_in_vec(rt_list, bs_addr) || + if (efi_utils::addr_in_vec(m_rt_list, bs_addr) || !efi_utils::check_boot_service_protocol_xrefs(bs_addr)) { break; } @@ -1228,7 +1201,7 @@ void efi_analysis::efi_analyser_x86_t::find_other_boot_services_tables64() { ea_t addr_bs = efi_utils::find_unknown_bs_var64(addr); if (addr_bs == BADADDR || - efi_utils::addr_in_tables(bs_list, rt_list, addr_bs)) { + efi_utils::addr_in_tables(m_bs_list, m_rt_list, addr_bs)) { continue; } @@ -1238,7 +1211,7 @@ void efi_analysis::efi_analyser_x86_t::find_other_boot_services_tables64() { efi_utils::set_ptr_type_and_name(addr_bs, "gBS", "EFI_BOOT_SERVICES"); - bs_list.push_back(addr_bs); + m_bs_list.push_back(addr_bs); } } @@ -1373,10 +1346,10 @@ bool efi_analysis::efi_analyser_x86_t:: //-------------------------------------------------------------------------- // get boot services protocols names for 64-bit modules void efi_analysis::efi_analyser_x86_t::get_bs_prot_names64() { - if (code_segs.empty()) { + if (m_code_segs.empty()) { return; } - segment_t *s = code_segs.at(0); + segment_t *s = m_code_segs.at(0); ea_t start = s->start_ea; install_multiple_prot_interfaces_analyser(); @@ -1513,11 +1486,11 @@ void efi_analysis::efi_analyser_x86_t::get_bs_prot_names32() { //-------------------------------------------------------------------------- // get SMM services protocols names for 64-bit modules void efi_analysis::efi_analyser_x86_t::get_smm_prot_names64() { - if (code_segs.empty()) { + if (m_code_segs.empty()) { return; } - segment_t *s = code_segs.at(0); + segment_t *s = m_code_segs.at(0); ea_t start = s->start_ea; for (int i = 0; i < g_smm_services_prot64_count; i++) { auto addrs = m_smm_services[g_smm_services_prot64[i].name]; @@ -1586,9 +1559,9 @@ void efi_analysis::efi_analyser_t::annotate_protocol_guids() { // annotate GUIDs found in the .text and .data segment void efi_analysis::efi_analyser_t::annotate_data_guids() { ea_t ptrsize = inf_is_64bit() ? 8 : 4; - auto guids_segments = code_segs; - guids_segments.insert(guids_segments.end(), data_segs.begin(), - data_segs.end()); + auto guids_segments = m_code_segs; + guids_segments.insert(guids_segments.end(), m_data_segs.begin(), + m_data_segs.end()); for (auto s : guids_segments) { ea_t ea = s->start_ea; while (ea != BADADDR && ea <= s->end_ea - 15) { @@ -1639,7 +1612,7 @@ void efi_analysis::efi_analyser_t::annotate_data_guids() { g["name"] = guid_name; g["guid"] = efi_utils::guid_to_string(guid); m_all_guids.push_back(g); - data_guids.push_back(g); + m_data_guids.push_back(g); } ea += 1; @@ -1650,7 +1623,7 @@ void efi_analysis::efi_analyser_t::annotate_data_guids() { //-------------------------------------------------------------------------- // find GUIDs stored in local variables for 64-bit modules void efi_analysis::efi_analyser_x86_t::find_local_guids64() { - for (auto seg : code_segs) { + for (auto seg : m_code_segs) { segment_t *s = seg; ea_t ea = s->start_ea; insn_t insn; @@ -1702,7 +1675,7 @@ void efi_analysis::efi_analyser_x86_t::find_local_guids64() { g["name"] = name; g["guid"] = efi_utils::guid_to_string(guid); m_all_guids.push_back(g); - stack_guids.push_back(g); + m_stack_guids.push_back(g); exit = true; break; } @@ -1718,7 +1691,7 @@ void efi_analysis::efi_analyser_x86_t::find_local_guids64() { //-------------------------------------------------------------------------- // search for callouts recursively -void find_callout_rec(func_t *func) { +void efi_analysis::efi_analyser_x86_t::find_callout_rec(func_t *func) { insn_t insn; for (ea_t ea = func->start_ea; ea < func->end_ea; ea = next_head(ea, BADADDR)) { @@ -1727,9 +1700,9 @@ void find_callout_rec(func_t *func) { ea_t next_func_addr = insn.ops[0].addr; func_t *next_func = get_func(next_func_addr); if (next_func) { - auto it = std::find(exc_funcs.begin(), exc_funcs.end(), next_func); - if (it == exc_funcs.end()) { - exc_funcs.push_back(next_func); + auto it = std::find(m_exc_funcs.begin(), m_exc_funcs.end(), next_func); + if (it == m_exc_funcs.end()) { + m_exc_funcs.push_back(next_func); find_callout_rec(next_func); } } @@ -1738,7 +1711,7 @@ void find_callout_rec(func_t *func) { if (insn.itype == NN_mov && insn.ops[0].type == o_reg && insn.ops[1].type == o_mem) { // search for callouts with gBS - if (efi_utils::addr_in_vec(bs_list, insn.ops[1].addr)) { + if (efi_utils::addr_in_vec(m_bs_list, insn.ops[1].addr)) { // filter FP auto reg = insn.ops[0].reg; auto addr = ea; @@ -1761,17 +1734,17 @@ void find_callout_rec(func_t *func) { efi_utils::log("found SMM callout via boot services at 0x%" PRIx64 "\n", u64_addr(ea)); - callout_addrs.push_back(ea); + m_callout_addrs.push_back(ea); continue; } } // search for callouts with gRT - if (efi_utils::addr_in_vec(rt_list, insn.ops[1].addr)) { + if (efi_utils::addr_in_vec(m_rt_list, insn.ops[1].addr)) { efi_utils::log("found SMM callout via runtime services at 0x%" PRIx64 "\n", u64_addr(ea)); - callout_addrs.push_back(ea); + m_callout_addrs.push_back(ea); continue; } @@ -1803,7 +1776,7 @@ void find_callout_rec(func_t *func) { efi_utils::log("found SMM callout via interface at 0x%" PRIx64 "\n", u64_addr(ea)); - callout_addrs.push_back(ea); + m_callout_addrs.push_back(ea); found = true; } // else: FP break; @@ -1870,17 +1843,17 @@ void efi_analysis::efi_analyser_t::find_smi_handlers() { //-------------------------------------------------------------------------- // find callouts inside SwSmiHandler functions -bool efi_analysis::efi_analyser_t::find_smm_callout() { - if (bs_list.empty() && rt_list.empty()) { +bool efi_analysis::efi_analyser_x86_t::find_smm_callout() { + if (m_bs_list.empty() && m_rt_list.empty()) { return false; } - if (m_smi_handlers.empty() && child_smi_handlers.empty()) { + if (m_smi_handlers.empty() && m_child_smi_handlers.empty()) { return false; } for (auto func : m_smi_handlers) { find_callout_rec(func); } - for (auto func : child_smi_handlers) { + for (auto func : m_child_smi_handlers) { find_callout_rec(func); } return true; @@ -1888,7 +1861,7 @@ bool efi_analysis::efi_analyser_t::find_smm_callout() { //-------------------------------------------------------------------------- // find potential double GetVariable patterns in PEI modules -bool efi_analysis::efi_analyser_t::find_double_get_variable_pei() { +bool efi_analysis::efi_analyser_x86_t::find_double_get_variable_pei() { ea_list_t get_variable_services_calls; std::string get_variable_str("VariablePPI.GetVariable"); @@ -1957,7 +1930,7 @@ bool efi_analysis::efi_analyser_t::find_double_get_variable_pei() { } if (same_datasize) { - double_get_variable_pei.push_back(curr_addr); + m_double_get_variable_pei.push_back(curr_addr); efi_utils::log("overflow may occur here: 0x%" PRIx64 "\n", u64_addr(curr_addr)); continue; @@ -1977,7 +1950,7 @@ bool efi_analysis::efi_analyser_t::find_double_get_variable_pei() { if (!datasize_addr_found) { // if datasize wasn't found, just let the pattern // trigger - for manual review - double_get_variable_pei.push_back(curr_addr); + m_double_get_variable_pei.push_back(curr_addr); efi_utils::log("overflow may occur here: 0x%" PRIx64 "\n", u64_addr(curr_addr)); continue; @@ -2007,7 +1980,7 @@ bool efi_analysis::efi_analyser_t::find_double_get_variable_pei() { } if (same_datasize) { - double_get_variable_pei.push_back(curr_addr); + m_double_get_variable_pei.push_back(curr_addr); efi_utils::log("overflow may occur here: 0x%" PRIx64 "\n", u64_addr(curr_addr)); continue; @@ -2025,24 +1998,23 @@ bool efi_analysis::efi_analyser_t::find_double_get_variable_pei() { } if (!datasize_addr_found) { - double_get_variable_pei.push_back(curr_addr); + m_double_get_variable_pei.push_back(curr_addr); efi_utils::log("overflow may occur here: 0x%" PRIx64 "\n", u64_addr(curr_addr)); } else if (prev_datasize_addr == curr_datasize_addr) { - double_get_variable_pei.push_back(curr_addr); + m_double_get_variable_pei.push_back(curr_addr); efi_utils::log("overflow may occur here: 0x%" PRIx64 "\n", u64_addr(curr_addr)); } } prev_addr = curr_addr; } - return !double_get_variable_pei.empty(); + return !m_double_get_variable_pei.empty(); } //-------------------------------------------------------------------------- // find potential double GetVariable patterns -bool efi_analysis::efi_analyser_t::find_double_get_variable( - json_list_t m_all_services) { +bool efi_analysis::efi_analyser_x86_t::find_double_get_variable() { ea_list_t get_variable_services_calls; std::string get_variable_str("GetVariable"); @@ -2115,7 +2087,7 @@ bool efi_analysis::efi_analyser_t::find_double_get_variable( if (insn.itype == NN_mov && insn.ops[0].type == o_reg && insn.ops[1].type == o_mem) { ea_t mem_addr = insn.ops[1].addr; - if (efi_utils::addr_in_vec(bs_list, mem_addr)) { + if (efi_utils::addr_in_vec(m_bs_list, mem_addr)) { wrong_detection = true; break; } @@ -2138,7 +2110,7 @@ bool efi_analysis::efi_analyser_t::find_double_get_variable( ea = prev_head(prev_addr, 0); func_t *func_start = get_func(ea); if (func_start == nullptr) { - return (double_get_variable.size() > 0); + return !m_double_get_variable.empty(); } uint16 stack_base_reg = 0xff; @@ -2160,7 +2132,7 @@ bool efi_analysis::efi_analyser_t::find_double_get_variable( if ((insn.ops[1].phrase == stack_base_reg && (sval + stack_addr) == datasize_stack_addr) || (datasize_stack_addr == insn.ops[1].addr)) { - double_get_variable.push_back(curr_addr); + m_double_get_variable.push_back(curr_addr); efi_utils::log("overflow may occur here: 0x%" PRIx64 "\n", u64_addr(curr_addr)); break; @@ -2172,14 +2144,14 @@ bool efi_analysis::efi_analyser_t::find_double_get_variable( } prev_addr = curr_addr; } - return !double_get_variable.empty(); + return !m_double_get_variable.empty(); } //-------------------------------------------------------------------------- // find potential double GetVariable patterns in SMM modules -bool efi_analysis::efi_analyser_t::find_double_get_variable_smm() { +bool efi_analysis::efi_analyser_x86_t::find_double_get_variable_smm() { ea_list_t smm_get_variable_calls = - efi_smm_utils::find_smm_get_variable_calls(data_segs, &m_all_services); + efi_smm_utils::find_smm_get_variable_calls(m_data_segs, &m_all_services); sort(smm_get_variable_calls.begin(), smm_get_variable_calls.end()); if (smm_get_variable_calls.size() < 2) { @@ -2238,7 +2210,7 @@ bool efi_analysis::efi_analyser_t::find_double_get_variable_smm() { if (insn.itype == NN_lea && insn.ops[0].type == o_reg && insn.ops[0].reg == R_R9) { if (datasize_stack_addr == insn.ops[1].addr) { - double_get_variable_smm.push_back(curr_addr); + m_double_get_variable_smm.push_back(curr_addr); efi_utils::log("overflow may occur here: 0x%" PRIx64 "\n", u64_addr(curr_addr)); break; @@ -2250,7 +2222,7 @@ bool efi_analysis::efi_analyser_t::find_double_get_variable_smm() { } prev_addr = curr_addr; } - return !double_get_variable_smm.empty(); + return !m_double_get_variable_smm.empty(); } //-------------------------------------------------------------------------- @@ -2420,8 +2392,8 @@ bool efi_analysis::efi_analyser_t::analyse_nvram_variables() { //-------------------------------------------------------------------------- // resolve EFI_SMM_CPU_PROTOCOL bool efi_analysis::efi_analyser_t::smm_cpu_protocol_resolver() { - read_save_state_calls = efi_smm_utils::resolve_efi_smm_cpu_protocol( - stack_guids, data_guids, &m_all_services); + m_read_save_state_calls = efi_smm_utils::resolve_efi_smm_cpu_protocol( + m_stack_guids, m_data_guids, &m_all_services); return true; } @@ -2429,20 +2401,20 @@ bool efi_analysis::efi_analyser_t::smm_cpu_protocol_resolver() { // dump all info to JSON file void efi_analysis::efi_analyser_t::dump_json() { json info; - if (st_list.size()) { - info["st_list"] = st_list; + if (m_st_list.size()) { + info["st_list"] = m_st_list; } - if (bs_list.size()) { - info["bs_list"] = bs_list; + if (m_bs_list.size()) { + info["bs_list"] = m_bs_list; } - if (rt_list.size()) { - info["rt_list"] = rt_list; + if (m_rt_list.size()) { + info["rt_list"] = m_rt_list; } - if (smst_list.size()) { - info["smst_list"] = smst_list; + if (m_smst_list.size()) { + info["smst_list"] = m_smst_list; } - if (image_handle_list.size()) { - info["image_handle_list"] = image_handle_list; + if (m_image_handle_list.size()) { + info["image_handle_list"] = m_image_handle_list; } if (m_all_ppis.size()) { info["all_ppis"] = m_all_ppis; @@ -2459,20 +2431,22 @@ void efi_analysis::efi_analyser_t::dump_json() { if (m_nvram_variables.size()) { info["m_nvram_variables"] = m_nvram_variables; } - if (read_save_state_calls.size()) { - info["read_save_state_calls"] = read_save_state_calls; + if (m_read_save_state_calls.size()) { + info["read_save_state_calls"] = m_read_save_state_calls; } - if (callout_addrs.size()) { - info["vulns"]["smm_callout"] = callout_addrs; + if (m_callout_addrs.size()) { + info["vulns"]["smm_callout"] = m_callout_addrs; } - if (double_get_variable_pei.size()) { - info["vulns"]["pei_get_variable_buffer_overflow"] = double_get_variable_pei; + if (m_double_get_variable_pei.size()) { + info["vulns"]["pei_get_variable_buffer_overflow"] = + m_double_get_variable_pei; } - if (double_get_variable.size()) { - info["vulns"]["get_variable_buffer_overflow"] = double_get_variable; + if (m_double_get_variable.size()) { + info["vulns"]["get_variable_buffer_overflow"] = m_double_get_variable; } - if (double_get_variable_smm.size()) { - info["vulns"]["smm_get_variable_buffer_overflow"] = double_get_variable_smm; + if (m_double_get_variable_smm.size()) { + info["vulns"]["smm_get_variable_buffer_overflow"] = + m_double_get_variable_smm; } json_list_t smi_handlers_addrs; @@ -2532,14 +2506,14 @@ void efi_analysis::efi_analyser_x86_t::show_all_choosers() { } // open window with vulnerabilities - if (callout_addrs.size() || double_get_variable_pei.size() || - double_get_variable.size() || double_get_variable_smm.size()) { + if (m_callout_addrs.size() || m_double_get_variable_pei.size() || + m_double_get_variable.size() || m_double_get_variable_smm.size()) { json_list_t vulns; std::map vulns_map = { - {"SmmCallout", callout_addrs}, - {"DoubleGetVariablePei", double_get_variable_pei}, - {"DoubleGetVariable", double_get_variable}, - {"DoubleGetVariableSmm", double_get_variable_smm}}; + {"SmmCallout", m_callout_addrs}, + {"DoubleGetVariablePei", m_double_get_variable_pei}, + {"DoubleGetVariable", m_double_get_variable}, + {"DoubleGetVariableSmm", m_double_get_variable_smm}}; for (const auto &[type, addrs] : vulns_map) { for (auto addr : addrs) { @@ -2574,9 +2548,11 @@ bool efi_analysis::efi_analyse_main_x86_64() { if (analyser.m_arch == arch_file_type_t::uefi) { res = ask_yn(1, "Do you want to analyse all modules with auto_mark_range?"); } - if (res == ASKBTN_YES && code_segs.size() && data_segs.size()) { - segment_t *start_seg = code_segs.at(0); - segment_t *end_seg = data_segs.at(data_segs.size() - 1); + if (res == ASKBTN_YES && analyser.m_code_segs.size() && + analyser.m_data_segs.size()) { + segment_t *start_seg = analyser.m_code_segs.at(0); + segment_t *end_seg = + analyser.m_data_segs.at(analyser.m_data_segs.size() - 1); ea_t start_ea = start_seg->start_ea; ea_t end_ea = end_seg->end_ea; auto_mark_range(start_ea, end_ea, AU_USED); @@ -2627,9 +2603,9 @@ bool efi_analysis::efi_analyse_main_x86_64() { analyser.annotate_protocol_guids(); // search for copies of global variables - efi_utils::mark_copies_for_gvars(smst_list, "gSmst"); - efi_utils::mark_copies_for_gvars(bs_list, "gBS"); - efi_utils::mark_copies_for_gvars(rt_list, "gRT"); + efi_utils::mark_copies_for_gvars(analyser.m_smst_list, "gSmst"); + efi_utils::mark_copies_for_gvars(analyser.m_bs_list, "gBS"); + efi_utils::mark_copies_for_gvars(analyser.m_rt_list, "gRT"); // search for vulnerabilities if (!g_args.disable_vuln_hunt) { @@ -2638,7 +2614,7 @@ bool efi_analysis::efi_analyse_main_x86_64() { analyser.find_smm_callout(); // find potential OOB RW with GetVariable function - analyser.find_double_get_variable(analyser.m_all_services); + analyser.find_double_get_variable(); // find potential OOB RW with SmmGetVariable function analyser.find_double_get_variable_smm(); From 8101532d91c6f931985c228cabc77688aa8c55bd Mon Sep 17 00:00:00 2001 From: yeggor Date: Sun, 22 Sep 2024 19:48:18 +0100 Subject: [PATCH 47/69] minor fixes in smm_utils functions --- efiXplorer/efi_analysis_x86.cc | 4 ++-- efiXplorer/efi_smm_utils.cc | 34 +++++++++++++++------------------- 2 files changed, 17 insertions(+), 21 deletions(-) diff --git a/efiXplorer/efi_analysis_x86.cc b/efiXplorer/efi_analysis_x86.cc index 42bc87bf..bbb48c18 100644 --- a/efiXplorer/efi_analysis_x86.cc +++ b/efiXplorer/efi_analysis_x86.cc @@ -2640,11 +2640,11 @@ bool efi_analysis::efi_analyse_main_x86_64() { } if (analyser.m_arch == arch_file_type_t::uefi) { - // Init public EdiDependencies members + // init public EdiDependencies members g_deps.get_protocols_chooser(analyser.m_all_protocols); g_deps.get_protocols_by_guids(analyser.m_all_protocols); - // Save all protocols information to build dependencies + // save all protocols information to build dependencies attach_action_protocols_deps(); attach_action_modules_seq(); } diff --git a/efiXplorer/efi_smm_utils.cc b/efiXplorer/efi_smm_utils.cc index ec094c14..0297c560 100644 --- a/efiXplorer/efi_smm_utils.cc +++ b/efiXplorer/efi_smm_utils.cc @@ -421,7 +421,6 @@ efi_smm_utils::find_smm_get_variable_calls(segment_list_t data_segs, } if (!smm_variable_addrs.size()) { - efi_utils::log("gSmmVariable not found\n"); return smm_get_variable_calls; } @@ -465,15 +464,14 @@ efi_smm_utils::find_smm_get_variable_calls(segment_list_t data_segs, efi_utils::log("found SmmGetVariable call at 0x%" PRIx64 "\n", u64_addr(ea)); - json service; - service["address"] = ea; - service["service_name"] = "gSmmVariable->SmmGetVariable"; - service["table_name"] = "EFI_SMM_VARIABLE_PROTOCOL"; - service["offset"] = 0; + json s; + s["address"] = ea; + s["service_name"] = "gSmmVariable->SmmGetVariable"; + s["table_name"] = "EFI_SMM_VARIABLE_PROTOCOL"; + s["offset"] = 0; - if (find(all_services->begin(), all_services->end(), service) == - all_services->end()) { - all_services->push_back(service); + if (!efi_utils::json_in_vec(*all_services, s)) { + all_services->push_back(s); } break; @@ -541,8 +539,7 @@ efi_smm_utils::resolve_efi_smm_cpu_protocol(json_list_t stack_guids, } } - if (!smm_cpu_addrs.size()) { - efi_utils::log("gSmmCpu not found\n"); + if (smm_cpu_addrs.empty()) { return read_save_state_calls; } @@ -583,15 +580,14 @@ efi_smm_utils::resolve_efi_smm_cpu_protocol(json_list_t stack_guids, efi_utils::log("gSmmCpu->ReadSaveState: 0x%" PRIx64 "\n", u64_addr(ea)); - json service; - service["address"] = ea; - service["service_name"] = "gSmmCpu->ReadSaveState"; - service["table_name"] = "EFI_SMM_CPU_PROTOCOL"; - service["offset"] = 0; + json s; + s["address"] = ea; + s["service_name"] = "gSmmCpu->ReadSaveState"; + s["table_name"] = "EFI_SMM_CPU_PROTOCOL"; + s["offset"] = 0; - if (find(all_services->begin(), all_services->end(), service) == - all_services->end()) { - all_services->push_back(service); + if (!efi_utils::json_in_vec(*all_services, s)) { + all_services->push_back(s); } break; From 04abd3e32fe09c1d9d425ebda92e52f807eee94c Mon Sep 17 00:00:00 2001 From: yeggor Date: Sun, 22 Sep 2024 20:48:53 +0100 Subject: [PATCH 48/69] monor refactoring for efi_deps, add get_apriori_modules() function --- efiXplorer/efi_deps.cc | 143 +++++++++++++++++++++------------------ efiXplorer/efi_deps.h | 13 ++-- efiXplorer/efixplorer.cc | 2 +- 3 files changed, 87 insertions(+), 71 deletions(-) diff --git a/efiXplorer/efi_deps.cc b/efiXplorer/efi_deps.cc index 18e7989d..7c4078b0 100644 --- a/efiXplorer/efi_deps.cc +++ b/efiXplorer/efi_deps.cc @@ -26,20 +26,20 @@ efi_deps_t::efi_deps_t() { // get modules names from IDB get_modules(); // read modules with GUIDs from - // .images.json file if this file exists + // .modules.json file if this file exists load_modules_with_guids(); } efi_deps_t::~efi_deps_t() { - m_modules_info.clear(); - m_modules_guids.clear(); + m_additional_installers.clear(); m_modules_from_idb.clear(); - m_uefitool_deps.clear(); + m_modules_guids.clear(); + m_modules_info.clear(); m_modules_sequence.clear(); - m_protocols_chooser.clear(); m_protocols_by_guids.clear(); - m_additional_installers.clear(); + m_protocols_chooser.clear(); m_protocols_without_installers.clear(); + m_uefitool_deps.clear(); } json efi_deps_t::get_deps_for(std::string guid) { @@ -98,13 +98,13 @@ bool efi_deps_t::load_deps_from_uefitool() { } bool efi_deps_t::load_modules_with_guids() { - std::filesystem::path images_json; - images_json /= get_path(PATH_TYPE_IDB); - images_json.replace_extension(".images.json"); - if (!std::filesystem::exists(images_json)) { + std::filesystem::path modules_json; + modules_json /= get_path(PATH_TYPE_IDB); + modules_json.replace_extension(".modules.json"); + if (!std::filesystem::exists(modules_json)) { return false; } - std::ifstream file(images_json); + std::ifstream file(modules_json); file >> m_modules_guids; return true; } @@ -122,11 +122,10 @@ void efi_deps_t::get_protocols_without_installers() { // check DXE_DEPEX and MM_DEPEX string_list_t sections{"EFI_SECTION_DXE_DEPEX", "EFI_SECTION_MM_DEPEX"}; for (auto section : sections) { - auto images = m_uefitool_deps[section]; - for (auto &element : images.items()) { + auto modules = m_uefitool_deps[section]; + for (auto &element : modules.items()) { auto protocols = element.value(); - for (auto p : protocols) { - std::string ps = static_cast(p); + for (std::string ps : protocols) { if (!installer_found(ps)) { m_protocols_without_installers.insert(ps); } @@ -190,18 +189,18 @@ void efi_deps_t::get_modules() { for (auto name : cseg_names) { auto index = seg_name.find(name.c_str()); if (index != std::string::npos) { - std::string image_name = + std::string module_name = static_cast(seg_name.c_str()).substr(0, index); - if (!image_name.rfind("_", 0)) { - image_name = image_name.erase(0, 1); + if (!module_name.rfind("_", 0)) { + module_name = module_name.erase(0, 1); } - m_modules_from_idb.push_back(image_name); + m_modules_from_idb.insert(module_name); } } } } -json efi_deps_t::get_module_info(std::string image) { +json efi_deps_t::get_module_info(std::string module) { json info; json deps_protocols; string_list_t installed_protocols; @@ -212,9 +211,9 @@ json efi_deps_t::get_module_info(std::string image) { // get installed protocols for (auto &p : m_additional_installers.items()) { // check additional installers - std::string ad_installer_image = p.value(); + std::string ad_installer_module = p.value(); std::string ad_installer_protocol = p.key(); - if (ad_installer_image == image) { + if (ad_installer_module == module) { installed_protocols.push_back(ad_installer_protocol); break; } @@ -222,11 +221,11 @@ json efi_deps_t::get_module_info(std::string image) { for (auto &element : m_protocols_chooser.items()) { // check efiXplorer report json p = element.value(); - std::string image_name = p["module"]; - if (!image_name.rfind("_", 0)) { - image_name = image_name.erase(0, 1); + std::string module_name = p["module"]; + if (!module_name.rfind("_", 0)) { + module_name = module_name.erase(0, 1); } - if (image_name != image) { + if (module_name != module) { continue; } if (find(installers.begin(), installers.end(), p["service"]) != @@ -239,15 +238,15 @@ json efi_deps_t::get_module_info(std::string image) { bool found = false; string_list_t sections{"EFI_SECTION_DXE_DEPEX", "EFI_SECTION_MM_DEPEX"}; for (auto section : sections) { - json deps_images = m_uefitool_deps[section]; - for (auto &element : deps_images.items()) { - std::string dimage_guid = element.key(); - if (m_modules_guids[dimage_guid].is_null()) { - // can not get name for image + json deps_modules = m_uefitool_deps[section]; + for (auto &element : deps_modules.items()) { + std::string dmodule_guid = element.key(); + if (m_modules_guids[dmodule_guid].is_null()) { + // can not get name for module continue; } - std::string dimage_name = m_modules_guids[dimage_guid]; - if (dimage_name == image) { + std::string dmodule_name = m_modules_guids[dmodule_guid]; + if (dmodule_name == module) { deps_protocols = element.value(); found = true; break; @@ -264,27 +263,43 @@ json efi_deps_t::get_module_info(std::string image) { return info; } +string_set_t efi_deps_t::get_apriori_modules() { + string_set_t apriori_modules; + string_list_t files{"DXE_APRIORI_FILE"}; + for (auto file : files) { + auto modules = m_uefitool_deps[file]; + for (auto &mguid : modules) { + std::string module = m_modules_guids[mguid]; + apriori_modules.insert(module); + efi_utils::log("module from %s: %s\n", file.c_str(), module.c_str()); + } + } + + return apriori_modules; +} + bool efi_deps_t::get_modules_info() { - if (m_modules_info.size()) { + if (!m_modules_info.empty()) { return true; } - for (auto image : m_modules_from_idb) { - m_modules_info[image] = get_module_info(image); + + for (auto module : m_modules_from_idb) { + m_modules_info[module] = get_module_info(module); } return true; } std::string efi_deps_t::get_installer(std::string protocol) { - std::string res; for (auto &e : m_modules_info.items()) { - std::string image = e.key(); - string_list_t installers = m_modules_info[image]["installed_protocols"]; + std::string module = e.key(); + string_list_t installers = m_modules_info[module]["installed_protocols"]; if (find(installers.begin(), installers.end(), protocol) != installers.end()) { - return image; + return module; } } - return res; + + return std::string(); } bool efi_deps_t::build_modules_sequence() { @@ -295,37 +310,37 @@ bool efi_deps_t::build_modules_sequence() { string_set_t module_seq; string_set_t installed_protocols; - get_protocols_without_installers(); // hard to find installers for all - // protocols in statiс + // it's difficult to find installers for all the protocols statically + get_protocols_without_installers(); get_modules_info(); size_t index = 0; while (module_seq.size() != m_modules_info.size()) { bool changed = false; for (auto &e : m_modules_info.items()) { - std::string image = e.key(); // current module + std::string module = e.key(); // current module - // check if the image is already loaded - if (module_seq.find(image) != module_seq.end()) { + // check if the module is already loaded + if (module_seq.find(module) != module_seq.end()) { continue; } - string_list_t installers = m_modules_info[image]["installed_protocols"]; + string_list_t installers = m_modules_info[module]["installed_protocols"]; // if there are no dependencies - if (m_modules_info[image]["deps_protocols"].is_null()) { + if (m_modules_info[module]["deps_protocols"].is_null()) { for (auto protocol : installers) { installed_protocols.insert(protocol); } - module_seq.insert(image); + module_seq.insert(module); json info; - info["module"] = image; + info["module"] = module; m_modules_sequence[index++] = info; changed = true; continue; } - string_list_t deps = m_modules_info[image]["deps_protocols"]; + string_list_t deps = m_modules_info[module]["deps_protocols"]; string_list_t unresolved_deps; bool load = true; for (auto protocol : deps) { @@ -345,9 +360,9 @@ bool efi_deps_t::build_modules_sequence() { for (auto protocol : installers) { installed_protocols.insert(protocol); } - module_seq.insert(image); + module_seq.insert(module); json info; - info["image"] = image; + info["module"] = module; info["deps"] = deps; if (unresolved_deps.size()) { info["unresolved_deps"] = unresolved_deps; @@ -362,18 +377,18 @@ bool efi_deps_t::build_modules_sequence() { std::map protocols_usage; // get the most popular protocol for (auto &e : m_modules_info.items()) { - std::string image = e.key(); + std::string module = e.key(); - // check if the image is already loaded - if (module_seq.find(image) != module_seq.end()) { + // check if the module is already loaded + if (module_seq.find(module) != module_seq.end()) { continue; } - if (m_modules_info[image]["deps_protocols"].is_null()) { + if (m_modules_info[module]["deps_protocols"].is_null()) { continue; } - string_list_t deps_protocols = m_modules_info[image]["deps_protocols"]; + string_list_t deps_protocols = m_modules_info[module]["deps_protocols"]; for (auto protocol : deps_protocols) { if (installed_protocols.find(protocol) != installed_protocols.end()) { continue; @@ -404,8 +419,8 @@ bool efi_deps_t::build_modules_sequence() { } // find installer module for mprotocol - std::string installer_image = get_installer(mprotocol); - if (!installer_image.size()) { + std::string installer_module = get_installer(mprotocol); + if (!installer_module.size()) { efi_utils::log("can not find installer for protocol %s\n", mprotocol.c_str()); break; @@ -413,14 +428,14 @@ bool efi_deps_t::build_modules_sequence() { // load installer module string_list_t current_installers = - m_modules_info[installer_image]["installed_protocols"]; + m_modules_info[installer_module]["installed_protocols"]; for (auto protocol : current_installers) { installed_protocols.insert(protocol); } - module_seq.insert(installer_image); + module_seq.insert(installer_module); json info; - info["image"] = installer_image; - info["deps"] = m_modules_info[installer_image]["deps_protocols"]; + info["module"] = installer_module; + info["deps"] = m_modules_info[installer_module]["deps_protocols"]; m_modules_sequence[index++] = info; } } diff --git a/efiXplorer/efi_deps.h b/efiXplorer/efi_deps.h index f1436ae3..c08089b0 100644 --- a/efiXplorer/efi_deps.h +++ b/efiXplorer/efi_deps.h @@ -35,7 +35,7 @@ class efi_deps_t { json m_protocols_by_guids; json m_protocols_chooser; json m_uefitool_deps; - string_list_t m_modules_from_idb; + string_set_t m_modules_from_idb; string_set_t m_untracked_protocols; // input: protocols from report @@ -52,12 +52,13 @@ class efi_deps_t { private: string_set_t m_protocols_without_installers; - void get_modules(); - void get_protocols_without_installers(); - void get_installers_modules(); + bool installer_found(std::string protocol); bool load_deps_from_uefitool(); bool load_modules_with_guids(); - bool installer_found(std::string protocol); - json get_module_info(std::string image); + json get_module_info(std::string module); std::string get_installer(std::string protocol); + string_set_t get_apriori_modules(); + void get_installers_modules(); + void get_modules(); + void get_protocols_without_installers(); }; diff --git a/efiXplorer/efixplorer.cc b/efiXplorer/efixplorer.cc index 92c91cb1..554caecb 100644 --- a/efiXplorer/efixplorer.cc +++ b/efiXplorer/efixplorer.cc @@ -116,7 +116,7 @@ bool idaapi run(size_t arg) { } //-------------------------------------------------------------------------- -// PLUGIN DESCRIPTION BLOCK +// plugin description block plugin_t PLUGIN = { IDP_INTERFACE_VERSION, 0, // plugin flags From fb0dfd73bba46a8e8e06a18536c8aafcd35b0f2e Mon Sep 17 00:00:00 2001 From: yeggor Date: Sun, 22 Sep 2024 20:50:21 +0100 Subject: [PATCH 49/69] fix comment --- efiXplorer/efi_deps.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/efiXplorer/efi_deps.cc b/efiXplorer/efi_deps.cc index 7c4078b0..512c12c4 100644 --- a/efiXplorer/efi_deps.cc +++ b/efiXplorer/efi_deps.cc @@ -26,7 +26,7 @@ efi_deps_t::efi_deps_t() { // get modules names from IDB get_modules(); // read modules with GUIDs from - // .modules.json file if this file exists + // .images.json file if this file exists load_modules_with_guids(); } From 8d3be3ae835c79b37c11a63362ca0a60a275d33c Mon Sep 17 00:00:00 2001 From: yeggor Date: Sun, 22 Sep 2024 20:59:19 +0100 Subject: [PATCH 50/69] fix modules path from efixloader --- efiXplorer/efi_deps.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/efiXplorer/efi_deps.cc b/efiXplorer/efi_deps.cc index 512c12c4..a00eb1f4 100644 --- a/efiXplorer/efi_deps.cc +++ b/efiXplorer/efi_deps.cc @@ -100,7 +100,7 @@ bool efi_deps_t::load_deps_from_uefitool() { bool efi_deps_t::load_modules_with_guids() { std::filesystem::path modules_json; modules_json /= get_path(PATH_TYPE_IDB); - modules_json.replace_extension(".modules.json"); + modules_json.replace_extension(".images.json"); if (!std::filesystem::exists(modules_json)) { return false; } From 476cf9f36026601b4d93fd4c8e687690dd399dae Mon Sep 17 00:00:00 2001 From: yeggor Date: Mon, 23 Sep 2024 04:16:29 +0100 Subject: [PATCH 51/69] minor fix for findidasdk.cmake --- cmake/FindIdaSdk.cmake | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/cmake/FindIdaSdk.cmake b/cmake/FindIdaSdk.cmake index c06d4c3c..6cd33240 100644 --- a/cmake/FindIdaSdk.cmake +++ b/cmake/FindIdaSdk.cmake @@ -60,10 +60,9 @@ include(CMakeParseArguments) include(FindPackageHandleStandardArgs) option(USE_LD_CLASSIC "Use -ld_classic option" OFF) -if(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang") - if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "15.0.0") - set(USE_LD_CLASSIC ON) - endif() +if(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang" + AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "15.0.0") + set(USE_LD_CLASSIC ON) endif() find_path( From 802301a59c01c005b6f68ff41d802a1828210a60 Mon Sep 17 00:00:00 2001 From: yeggor Date: Mon, 23 Sep 2024 04:20:12 +0100 Subject: [PATCH 52/69] rename OTHER table name to Unknown --- efiXplorer/efi_analysis_arm.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/efiXplorer/efi_analysis_arm.cc b/efiXplorer/efi_analysis_arm.cc index 54b94dd3..d262cb53 100644 --- a/efiXplorer/efi_analysis_arm.cc +++ b/efiXplorer/efi_analysis_arm.cc @@ -178,7 +178,7 @@ json get_service(ea_t addr, uint8_t table_id) { efi_utils::lookup_runtime_service_name(service_offset); s["table_name"] = "EFI_RUNTIME_SERVICES"; } else { - s["table_name"] = "OTHER"; + s["table_name"] = "Unknown"; } return s; } From 40bbcbb0e4d0fa351dea7aed6cb6d4b04757b465 Mon Sep 17 00:00:00 2001 From: yeggor Date: Mon, 23 Sep 2024 10:04:42 +0100 Subject: [PATCH 53/69] remove casts to std::string --- efiXplorer/efi_analysis_x86.cc | 38 ++++++++++++---------------------- 1 file changed, 13 insertions(+), 25 deletions(-) diff --git a/efiXplorer/efi_analysis_x86.cc b/efiXplorer/efi_analysis_x86.cc index bbb48c18..6515ecc9 100644 --- a/efiXplorer/efi_analysis_x86.cc +++ b/efiXplorer/efi_analysis_x86.cc @@ -77,8 +77,7 @@ efi_analysis::efi_analyser_t::efi_analyser_t() { // get reverse dictionary for (auto g = m_guiddb.begin(); g != m_guiddb.end(); ++g) { - m_guiddb_map[static_cast(g.value())] = - static_cast(g.key()); + m_guiddb_map[g.value()] = g.key(); } } @@ -655,9 +654,8 @@ void efi_analysis::efi_analyser_x86_t::get_boot_services_all() { efi_utils::log("0x%" PRIx64 ": %s\n", u64_addr(addr), g_boot_services_table_all[j].name); - m_boot_services[static_cast( - g_boot_services_table_all[j].name)] - .push_back(addr); + m_boot_services[g_boot_services_table_all[j].name].push_back( + addr); json s; s["address"] = addr; @@ -736,8 +734,7 @@ void efi_analysis::efi_analyser_x86_t::get_runtime_services_all() { efi_utils::log("0x%" PRIx64 ": %s\n", u64_addr(addr), g_runtime_services_table_all[j].name); - m_runtime_services_all[static_cast( - g_runtime_services_table_all[j].name)] + m_runtime_services_all[g_runtime_services_table_all[j].name] .push_back(addr); json s; @@ -818,9 +815,8 @@ void efi_analysis::efi_analyser_x86_t::get_smm_services_all64() { m_smm_services[g_smm_services_table_all[j].name].push_back( addr); } - m_smm_services_all[static_cast( - g_smm_services_table_all[j].name)] - .push_back(addr); + m_smm_services_all[g_smm_services_table_all[j].name].push_back( + addr); json s; s["address"] = addr; @@ -903,9 +899,7 @@ void efi_analysis::efi_analyser_x86_t::get_pei_services_all32() { efi_utils::log("0x%" PRIx64 ": %s\n", u64_addr(ea), g_pei_services_table32[j].name); - m_pei_services_all[static_cast( - g_pei_services_table32[j].name)] - .push_back(ea); + m_pei_services_all[g_pei_services_table32[j].name].push_back(ea); json s; s["address"] = ea; @@ -1118,9 +1112,7 @@ void efi_analysis::efi_analyser_x86_t::get_prot_boot_services64() { efi_utils::log("0x%" PRIx64 ": %s\n", u64_addr(ea), g_boot_services_table64[i].name); - m_boot_services[static_cast( - g_boot_services_table64[i].name)] - .push_back(ea); + m_boot_services[g_boot_services_table64[i].name].push_back(ea); json s; s["address"] = ea; @@ -1158,9 +1150,7 @@ void efi_analysis::efi_analyser_x86_t::get_prot_boot_services32() { efi_utils::log("0x%" PRIx64 ": %s\n", u64_addr(ea), g_boot_services_table32[i].name); - m_boot_services[static_cast( - g_boot_services_table32[i].name)] - .push_back(ea); + m_boot_services[g_boot_services_table32[i].name].push_back(ea); json s; s["address"] = ea; @@ -1548,7 +1538,7 @@ void efi_analysis::efi_analyser_t::annotate_protocol_guids() { continue; } - std::string name = static_cast(prot[m_pkey]); + std::string name = prot[m_pkey]; set_name(addr, name.c_str(), SN_FORCE); efi_utils::set_guid_type(addr); m_annotated_protocols.push_back(addr); @@ -2020,8 +2010,7 @@ bool efi_analysis::efi_analyser_x86_t::find_double_get_variable() { for (auto j_service : m_all_services) { json service = j_service; - std::string service_name = - static_cast(service["service_name"]); + std::string service_name = service["service_name"]; ea_t addr = static_cast(service["address"]); if (service_name.compare(get_variable_str) == 0) { get_variable_services_calls.push_back(addr); @@ -2366,8 +2355,7 @@ bool efi_analysis::efi_analyser_t::analyse_nvram_variables() { ea_list_t var_services; for (auto j_service : m_all_services) { json service = j_service; - std::string service_name = - static_cast(service["service_name"]); + std::string service_name = service["service_name"]; ea_t addr = static_cast(service["address"]); if (!service_name.compare(service_str)) { var_services.push_back(addr); @@ -2582,7 +2570,7 @@ bool efi_analysis::efi_analyse_main_x86_64() { analyser.find_smst64(); - // find Boot services and Runtime services + // find boot services and runtime services analyser.get_prot_boot_services64(); analyser.find_other_boot_services_tables64(); analyser.get_boot_services_all(); From c307b2bffda16f15c4f4753ccbb0c55a9a6ed049 Mon Sep 17 00:00:00 2001 From: yeggor Date: Mon, 23 Sep 2024 11:05:15 +0100 Subject: [PATCH 54/69] improve detection of smm services --- efiXplorer/efi_analysis_x86.cc | 34 +++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/efiXplorer/efi_analysis_x86.cc b/efiXplorer/efi_analysis_x86.cc index 6515ecc9..79a8b2f0 100644 --- a/efiXplorer/efi_analysis_x86.cc +++ b/efiXplorer/efi_analysis_x86.cc @@ -772,28 +772,48 @@ void efi_analysis::efi_analyser_x86_t::get_smm_services_all64() { for (auto smms : m_smst_list) { auto xrefs = efi_utils::get_xrefs(smms); for (auto ea : xrefs) { - decode_insn(&insn, ea); + auto addr = ea; + decode_insn(&insn, addr); if (!(insn.itype == NN_mov && insn.ops[1].type == o_mem && insn.ops[1].addr == smms)) { continue; } + efi_utils::log("analysing xref to smst at 0x%" PRIx64 "\n", + u64_addr(addr)); + auto smst_reg = insn.ops[0].reg; + uint32_t offset = 0; - // 10 instructions below - auto addr = ea; - for (auto i = 0; i < 10; i++) { + while (!is_basic_block_end(insn, false) || addr == ea) { addr = next_head(addr, BADADDR); decode_insn(&insn, addr); + + // handle cases like this + // mov rax, cs:gSmst + // mov rax, [rax+0E0h] <- we are here + // ... + // call rax + if (insn.itype == NN_mov && insn.ops[0].reg == smst_reg && + (insn.ops[1].type == o_displ || insn.ops[1].type == o_phrase) && + insn.ops[1].reg == smst_reg) { + offset = u32_addr(insn.ops[1].addr); + } + // add NN_jmpni insn type to handle such cases // jmp qword ptr [r9+0D0h] if ((insn.itype == NN_callni || insn.itype == NN_jmpni) && insn.ops[0].reg == smst_reg) { + // if instruction is not call smst_reg, rewrite the offset + if (insn.ops[0].type != o_reg) { + offset = insn.ops[0].addr; + } + for (int j = 0; j < g_smm_services_table_all_count; j++) { - if (insn.ops[0].addr == - u32_addr(g_smm_services_table_all[j].offset64)) { - if (u32_addr(g_smm_services_table_all[j].offset64) == 0xe0) { + if (offset == g_smm_services_table_all[j].offset64) { + // handle SmiHandlerRegister service call + if (g_smm_services_table_all[j].offset64 == 0xe0) { // set name for Handler argument auto smi_handler_addr = efi_smm_utils::mark_child_sw_smi_handlers(addr); From 0938719ade39a41755515966df3d5f21bb197da9 Mon Sep 17 00:00:00 2001 From: yeggor Date: Mon, 23 Sep 2024 12:04:24 +0100 Subject: [PATCH 55/69] minor fixes --- efiXplorer/efi_analysis_x86.cc | 13 +++++-------- efiXplorer/efi_hexrays.h | 7 +++---- efiXplorer/efi_smm_utils.cc | 4 ++-- 3 files changed, 10 insertions(+), 14 deletions(-) diff --git a/efiXplorer/efi_analysis_x86.cc b/efiXplorer/efi_analysis_x86.cc index 79a8b2f0..f129fe3b 100644 --- a/efiXplorer/efi_analysis_x86.cc +++ b/efiXplorer/efi_analysis_x86.cc @@ -780,9 +780,6 @@ void efi_analysis::efi_analyser_x86_t::get_smm_services_all64() { continue; } - efi_utils::log("analysing xref to smst at 0x%" PRIx64 "\n", - u64_addr(addr)); - auto smst_reg = insn.ops[0].reg; uint32_t offset = 0; @@ -975,8 +972,8 @@ void efi_analysis::efi_analyser_x86_t::get_variable_ppi_calls_all32() { efi_utils::log("0x%" PRIx64 ": %s\n", u64_addr(ea), g_variable_ppi_table_all[j].name); - std::string ppi_call = - std::format("VariablePPI.{}", g_variable_ppi_table_all[j].name); + std::string ppi_call = std::format( + "VariablePPI->{}", g_variable_ppi_table_all[j].name); m_ppi_calls_all[ppi_call].push_back(ea); json s; @@ -1873,7 +1870,7 @@ bool efi_analysis::efi_analyser_x86_t::find_smm_callout() { // find potential double GetVariable patterns in PEI modules bool efi_analysis::efi_analyser_x86_t::find_double_get_variable_pei() { ea_list_t get_variable_services_calls; - std::string get_variable_str("VariablePPI.GetVariable"); + std::string get_variable_str("VariablePPI->GetVariable"); for (auto j_service : m_all_services) { json service = j_service; @@ -1893,9 +1890,9 @@ bool efi_analysis::efi_analyser_x86_t::find_double_get_variable_pei() { ea_t prev_addr = get_variable_services_calls.at(0); for (auto i = 1; i < get_variable_services_calls.size(); ++i) { ea_t curr_addr = get_variable_services_calls.at(i); - efi_utils::log("first call to VariablePPI.GetVariable: 0x%" PRIx64 "\n", + efi_utils::log("first call to VariablePPI->GetVariable: 0x%" PRIx64 "\n", u64_addr(prev_addr)); - efi_utils::log("second call to VariablePPI.GetVariable: 0x%" PRIx64 "\n", + efi_utils::log("second call to VariablePPI->GetVariable: 0x%" PRIx64 "\n", u64_addr(curr_addr)); // check code from first call to second call diff --git a/efiXplorer/efi_hexrays.h b/efiXplorer/efi_hexrays.h index eaca5d2d..ac35fe08 100644 --- a/efiXplorer/efi_hexrays.h +++ b/efiXplorer/efi_hexrays.h @@ -214,7 +214,7 @@ class guid_related_visitor_base_t : public ctree_visitor_t { ea_t m_func_ea; ea_t m_code_ea; json_list_t m_protocols; - bool m_debug = false; + bool m_debug = true; // used for looking up calls to function pointers in structures service_descriptor_map_t &m_services; @@ -634,7 +634,7 @@ class variables_info_extractor_t : public ctree_visitor_t { protected: ea_t m_code_addr = BADADDR; - bool m_debug = false; + bool m_debug = true; }; class prototypes_fixer_t : public ctree_visitor_t { @@ -908,8 +908,7 @@ class services_detector_t : public ctree_visitor_t { is_ptr = 0; } - auto service_name = - efi_utils::type_to_name(static_cast(type_name.c_str())); + auto service_name = efi_utils::type_to_name(type_name.c_str()); if (service_name.rfind("Efi", 0) == 0) { service_name = service_name.substr(3); if (service_name == "RaiseTpl") { diff --git a/efiXplorer/efi_smm_utils.cc b/efiXplorer/efi_smm_utils.cc index 0297c560..e79f6fa8 100644 --- a/efiXplorer/efi_smm_utils.cc +++ b/efiXplorer/efi_smm_utils.cc @@ -215,7 +215,7 @@ func_list_t efi_smm_utils::find_smi_handlers(ea_t address, std::string prefix) { while (!is_basic_block_end(insn, false)) { ea = prev_head(ea, 0); decode_insn(&insn, ea); - // interface is stack variable + // interface is local variable if (insn.itype == NN_lea && insn.ops[0].type == o_reg && insn.ops[0].reg == R_R8 && insn.ops[1].type == o_displ && (insn.ops[1].reg == R_RBP || insn.ops[1].reg == R_RSP)) { @@ -349,7 +349,7 @@ efi_smm_utils::find_smi_handlers_dispatch_stack(json_list_t stack_guids, func_list_t smi_handlers; for (auto guid : stack_guids) { - std::string name = static_cast(guid["name"]); + std::string name = guid["name"]; if (name != "EFI_SMM_SW_DISPATCH2_PROTOCOL_GUID" && name != "EFI_SMM_SW_DISPATCH_PROTOCOL_GUID") { From 1c00198c36e7b6eb923a5d72c89cac1bcdae877a Mon Sep 17 00:00:00 2001 From: yeggor Date: Mon, 23 Sep 2024 14:45:11 +0100 Subject: [PATCH 56/69] minor fixes for efi_hexrays --- efiXplorer/efi_hexrays.cc | 31 ++++++++++--------------------- efiXplorer/efi_hexrays.h | 18 ++++++------------ efiXplorer/efi_utils.cc | 9 ++++++--- 3 files changed, 22 insertions(+), 36 deletions(-) diff --git a/efiXplorer/efi_hexrays.cc b/efiXplorer/efi_hexrays.cc index aa270493..0a77495c 100644 --- a/efiXplorer/efi_hexrays.cc +++ b/efiXplorer/efi_hexrays.cc @@ -35,20 +35,20 @@ bool efi_hexrays::offset_of(tinfo_t tif, const char *name, #if IDA_SDK_VERSION < 840 udt_member_t udm; udm.name = name; - int fIdx = tif.find_udt_member(&udm, STRMEM_NAME); + int fidx = tif.find_udt_member(&udm, STRMEM_NAME); #else udm_t udm; udm.name = name; - int fIdx = tif.find_udm(&udm, STRMEM_NAME); + int fidx = tif.find_udm(&udm, STRMEM_NAME); #endif - if (fIdx < 0) { + if (fidx < 0) { qstring tstr; tif.get_type_name(&tstr); return false; } // get the offset of the field - *offset = static_cast(udt.at(fIdx).offset >> 3ULL); + *offset = static_cast(udt.at(fidx).offset >> 3ULL); return true; } @@ -61,28 +61,17 @@ bool efi_hexrays::set_hexrays_var_info_and_handle_interfaces(ea_t func_addr, lvar_saved_info_t lsi; lsi.ll = ll; lsi.type = tif; + lsi.name = name.c_str(); modify_user_lvar_info(func_addr, MLI_TYPE, lsi); - // set lvar name - if (ll.is_stk_var()) { // rename local variable on stack -#if IDA_SDK_VERSION < 900 - sval_t stkoff = ll.get_stkoff(); - struc_t *frame = get_frame(func_addr); - set_member_name(frame, stkoff, name.c_str()); -#endif // TODO(yeggor): add support for idasdk90 - } else { // Modufy user lvar info - lsi.name = static_cast(name.c_str()); - modify_user_lvar_info(func_addr, MLI_NAME, lsi); - } - - // get xrefs to local variable - xreflist_t xrefs = efi_utils::xrefs_to_stack_var( - func_addr, static_cast(name.c_str())); - qstring type_name; ptr_type_data_t pi; tif.get_ptr_details(&pi); + + qstring type_name; pi.obj_type.get_type_name(&type_name); - // handling all interface functions (to rename function arguments) + + // handle all interface functions (to rename function arguments) + xreflist_t xrefs = efi_utils::xrefs_to_stack_var(func_addr, name.c_str()); efi_utils::op_stroff_for_interface(xrefs, type_name); return true; diff --git a/efiXplorer/efi_hexrays.h b/efiXplorer/efi_hexrays.h index ac35fe08..0ee3aa51 100644 --- a/efiXplorer/efi_hexrays.h +++ b/efiXplorer/efi_hexrays.h @@ -620,11 +620,6 @@ class variables_info_extractor_t : public ctree_visitor_t { cexpr_t *attributes_arg = &args->at(2); if (attributes_arg->op == cot_num) { - if (m_debug) { - efi_utils::log("service call: %016llX, attributes: %02X\n", - u64_addr(m_code_addr), - static_cast(attributes_arg->numval())); - } attributes_arg->numval(); m_attributes = static_cast(attributes_arg->numval()); } @@ -818,26 +813,26 @@ class variables_detector_t : public ctree_visitor_t { if (global_var) { // extract variable data ea_t g_addr = e->x->obj_ea; - std::string type_name_str = static_cast(type_name.c_str()); - if (type_name == qstring("EFI_HANDLE")) { + std::string type_name_str = type_name.c_str(); + if (type_name == "EFI_HANDLE") { efi_utils::set_type_and_name(g_addr, "gImageHandle", type_name_str); if (!efi_utils::addr_in_vec(m_image_handle_list, g_addr)) { m_image_handle_list.push_back(g_addr); } } - if (type_name == qstring("EFI_SYSTEM_TABLE")) { + if (type_name == "EFI_SYSTEM_TABLE") { efi_utils::set_ptr_type_and_name(g_addr, "gST", type_name_str); if (!efi_utils::addr_in_vec(m_st_list, g_addr)) { m_st_list.push_back(g_addr); } } - if (type_name == qstring("EFI_BOOT_SERVICES")) { + if (type_name == "EFI_BOOT_SERVICES") { efi_utils::set_ptr_type_and_name(g_addr, "gBS", type_name_str); if (!efi_utils::addr_in_vec(m_bs_list, g_addr)) { m_bs_list.push_back(g_addr); } } - if (type_name == qstring("EFI_RUNTIME_SERVICES")) { + if (type_name == "EFI_RUNTIME_SERVICES") { efi_utils::set_ptr_type_and_name(g_addr, "gRT", type_name_str); if (!efi_utils::addr_in_vec(m_rt_list, g_addr)) { m_rt_list.push_back(g_addr); @@ -857,8 +852,7 @@ class variables_detector_t : public ctree_visitor_t { lvar_t &dest_var = var_ref.mba->vars[var_ref.idx]; // set the Hex-Rays variable type - auto name = - efi_utils::type_to_name(static_cast(type_name.c_str())); + auto name = efi_utils::type_to_name(type_name.c_str()); // set_hexrays_var_info(m_func_ea, dest_var, var_type, name); } diff --git a/efiXplorer/efi_utils.cc b/efiXplorer/efi_utils.cc index ddc0501b..ca77d0b7 100644 --- a/efiXplorer/efi_utils.cc +++ b/efiXplorer/efi_utils.cc @@ -733,6 +733,9 @@ std::string efi_utils::type_to_name(std::string type) { } xreflist_t efi_utils::xrefs_to_stack_var(ea_t func_addr, qstring var_name) { + efi_utils::log("get xrefs to stack variable %s at 0x%" PRIx64 "\n", + var_name.c_str(), func_addr); + xreflist_t xrefs_list; #if IDA_SDK_VERSION < 900 @@ -748,9 +751,9 @@ xreflist_t efi_utils::xrefs_to_stack_var(ea_t func_addr, qstring var_name) { return xrefs_list; } } -#endif - +#else // TODO(yeggor): rewrite for idasdk90 +#endif return xrefs_list; } @@ -765,7 +768,7 @@ void op_stroff_for_addr(ea_t ea, qstring type_name) { insn.itype == NN_callni) && (insn.ops[0].type == o_displ || insn.ops[0].type == o_phrase) && insn.ops[0].reg == R_RAX) { - efi_utils::op_stroff(ea, static_cast(type_name.c_str())); + efi_utils::op_stroff(ea, type_name.c_str()); efi_utils::log("mark arguments at address 0x%" PRIx64 " (interface type: %s)\n", u64_addr(ea), type_name.c_str()); From 8ef710e826a55e0d67bd0bdd9c64b250af7658f1 Mon Sep 17 00:00:00 2001 From: yeggor Date: Mon, 23 Sep 2024 18:44:12 +0100 Subject: [PATCH 57/69] improve set_hexrays_var_info and xrefs_to_stack_var for IDA_SDK_VERSION < 900 --- efiXplorer/efi_hexrays.cc | 81 +++++++++++++++++++++++---------------- efiXplorer/efi_hexrays.h | 6 +-- efiXplorer/efi_utils.cc | 26 +++++++------ 3 files changed, 64 insertions(+), 49 deletions(-) diff --git a/efiXplorer/efi_hexrays.cc b/efiXplorer/efi_hexrays.cc index 0a77495c..76d0f80c 100644 --- a/efiXplorer/efi_hexrays.cc +++ b/efiXplorer/efi_hexrays.cc @@ -52,31 +52,6 @@ bool efi_hexrays::offset_of(tinfo_t tif, const char *name, return true; } -// utility function to set a Hex-Rays variable type and set types for the -// interfaces -bool efi_hexrays::set_hexrays_var_info_and_handle_interfaces(ea_t func_addr, - lvar_t &ll, - tinfo_t tif, - std::string name) { - lvar_saved_info_t lsi; - lsi.ll = ll; - lsi.type = tif; - lsi.name = name.c_str(); - modify_user_lvar_info(func_addr, MLI_TYPE, lsi); - - ptr_type_data_t pi; - tif.get_ptr_details(&pi); - - qstring type_name; - pi.obj_type.get_type_name(&type_name); - - // handle all interface functions (to rename function arguments) - xreflist_t xrefs = efi_utils::xrefs_to_stack_var(func_addr, name.c_str()); - efi_utils::op_stroff_for_interface(xrefs, type_name); - - return true; -} - // utility function to set a Hex-Rays variable name bool efi_hexrays::set_lvar_name(qstring name, lvar_t lvar, ea_t func_addr) { lvar_saved_info_t lsi; @@ -94,26 +69,64 @@ bool efi_hexrays::set_lvar_name(qstring name, lvar_t lvar, ea_t func_addr) { // utility function to set a Hex-Rays variable type and name bool efi_hexrays::set_hexrays_var_info(ea_t func_addr, lvar_t &ll, tinfo_t tif, std::string name) { - lvar_saved_info_t lsi; - lsi.ll = ll; - lsi.type = tif; - modify_user_lvar_info(func_addr, MLI_TYPE, lsi); - // set lvar name if (ll.is_stk_var()) { // rename local variable on stack #if IDA_SDK_VERSION < 900 sval_t stkoff = ll.get_stkoff(); + struc_t *frame = get_frame(func_addr); - set_member_name(frame, stkoff, name.c_str()); -#endif // TODO(yeggor): add support for idasdk90 - } else { // modufy user lvar info - lsi.name = static_cast(name.c_str()); + if (frame == nullptr) { + return false; + } + + if (!set_member_name(frame, stkoff, name.c_str())) { + return false; + } + + member_t *member = get_member_by_name(frame, name.c_str()); + if (member != nullptr) { + set_member_tinfo(frame, member, 0, tif, 0); + } +#else + // TODO(yeggor): add support for idasdk90 +#endif + } else { + lvar_saved_info_t lsi; + lsi.ll = ll; + + // modufy user lvar type + lsi.type = tif; + modify_user_lvar_info(func_addr, MLI_TYPE, lsi); + + // modufy user lvar name + lsi.name = name.c_str(); modify_user_lvar_info(func_addr, MLI_NAME, lsi); } return true; } +// utility function to set a Hex-Rays variable type and set types for the +// interfaces +bool efi_hexrays::set_hexrays_var_info_and_handle_interfaces(ea_t func_addr, + lvar_t &ll, + tinfo_t tif, + std::string name) { + set_hexrays_var_info(func_addr, ll, tif, name); + + ptr_type_data_t pi; + tif.get_ptr_details(&pi); + + qstring type_name; + pi.obj_type.get_type_name(&type_name); + + // handle all interface functions (to rename function arguments) + xreflist_t xrefs = efi_utils::xrefs_to_stack_var(func_addr, name.c_str()); + efi_utils::op_stroff_for_interface(xrefs, type_name); + + return true; +} + // I added this bit of logic when I noticed that sometimes Hex-Rays // will aggressively create arrays on the stack. So, I wanted to apply types to // stack "variables" (whose pointers are passed to the protocol location diff --git a/efiXplorer/efi_hexrays.h b/efiXplorer/efi_hexrays.h index 0ee3aa51..6e458d55 100644 --- a/efiXplorer/efi_hexrays.h +++ b/efiXplorer/efi_hexrays.h @@ -371,8 +371,8 @@ class guid_related_visitor_base_t : public ctree_visitor_t { // this is a helper function used to get the thing being referred to. What // does that m_ean? // - // * for GUID arguments, we'll usually have &globvar. Return globvar - // * for output arguments, we'll usually have &globvar or &locvar. Due to + // - for GUID arguments, we'll usually have &globvar. Return globvar + // - for output arguments, we'll usually have &globvar or &locvar. Due to // Hex-Rays internal heuristics, we might end up with "locarray", which // does not actually have a "&" when passed as a call argument. There's // a bit of extra logic to check for that case @@ -853,7 +853,7 @@ class variables_detector_t : public ctree_visitor_t { // set the Hex-Rays variable type auto name = efi_utils::type_to_name(type_name.c_str()); - // set_hexrays_var_info(m_func_ea, dest_var, var_type, name); + set_hexrays_var_info(m_func_ea, dest_var, var_type, name); } return 0; diff --git a/efiXplorer/efi_utils.cc b/efiXplorer/efi_utils.cc index ca77d0b7..0d07a225 100644 --- a/efiXplorer/efi_utils.cc +++ b/efiXplorer/efi_utils.cc @@ -732,24 +732,26 @@ std::string efi_utils::type_to_name(std::string type) { return result; } -xreflist_t efi_utils::xrefs_to_stack_var(ea_t func_addr, qstring var_name) { +xreflist_t efi_utils::xrefs_to_stack_var(ea_t func_addr, qstring name) { efi_utils::log("get xrefs to stack variable %s at 0x%" PRIx64 "\n", - var_name.c_str(), func_addr); + name.c_str(), func_addr); xreflist_t xrefs_list; #if IDA_SDK_VERSION < 900 struc_t *frame = get_frame(func_addr); - func_t *func = get_func(func_addr); - member_t member; // get member by name - for (int i = 0; i < frame->memqty; i++) { - member = frame->members[i]; - qstring name; - get_member_name(&name, frame->members[i].id); - if (name == var_name) { - build_stkvar_xrefs(&xrefs_list, func, &member); - return xrefs_list; - } + if (frame == nullptr) { + return xrefs_list; + } + + func_t *f = get_func(func_addr); + if (f == nullptr) { + return xrefs_list; + } + + member_t *member = get_member_by_name(frame, name.c_str()); + if (member != nullptr) { + build_stkvar_xrefs(&xrefs_list, f, member); } #else // TODO(yeggor): rewrite for idasdk90 From 1f491409cb0acd15b3449ad111c1cdc27d5a903d Mon Sep 17 00:00:00 2001 From: yeggor Date: Mon, 23 Sep 2024 20:27:00 +0100 Subject: [PATCH 58/69] port set_hexrays_var_info to idasdk90 --- efiXplorer/efi_hexrays.cc | 50 ++++++++++++++++++++++++++++++++++++--- efiXplorer/efi_hexrays.h | 25 ++++++++++---------- efiXplorer/efi_utils.cc | 29 ++--------------------- efiXplorer/efi_utils.h | 3 +-- 4 files changed, 63 insertions(+), 44 deletions(-) diff --git a/efiXplorer/efi_hexrays.cc b/efiXplorer/efi_hexrays.cc index 76d0f80c..77b63055 100644 --- a/efiXplorer/efi_hexrays.cc +++ b/efiXplorer/efi_hexrays.cc @@ -48,10 +48,37 @@ bool efi_hexrays::offset_of(tinfo_t tif, const char *name, } // get the offset of the field - *offset = static_cast(udt.at(fidx).offset >> 3ULL); + *offset = static_cast(udt.at(fidx).offset * get_ptrsize()); return true; } +xreflist_t efi_hexrays::xrefs_to_stack_var(ea_t func_addr, qstring name) { + efi_utils::log("get xrefs to stack variable %s at 0x%" PRIx64 "\n", + name.c_str(), func_addr); + + xreflist_t xrefs_list; + +#if IDA_SDK_VERSION < 900 + struc_t *frame = get_frame(func_addr); + if (frame == nullptr) { + return xrefs_list; + } + + func_t *f = get_func(func_addr); + if (f == nullptr) { + return xrefs_list; + } + + member_t *member = get_member_by_name(frame, name.c_str()); + if (member != nullptr) { + build_stkvar_xrefs(&xrefs_list, f, member); + } +#else + // TODO(yeggor): rewrite for idasdk90 +#endif + return xrefs_list; +} + // utility function to set a Hex-Rays variable name bool efi_hexrays::set_lvar_name(qstring name, lvar_t lvar, ea_t func_addr) { lvar_saved_info_t lsi; @@ -88,7 +115,24 @@ bool efi_hexrays::set_hexrays_var_info(ea_t func_addr, lvar_t &ll, tinfo_t tif, set_member_tinfo(frame, member, 0, tif, 0); } #else - // TODO(yeggor): add support for idasdk90 + sval_t stkoff = ll.get_stkoff(); + + func_t *f = get_func(func_addr); + if (f == nullptr) { + return false; + } + + tinfo_t frame; + frame.get_func_frame(f); + if (frame.empty()) { + return false; + } + + ssize_t stkvar_idx = frame.find_udm(stkoff * get_ptrsize()); + if (stkvar_idx != -1) { + frame.rename_udm(stkvar_idx, name.c_str()); + frame.set_udm_type(stkvar_idx, tif); + } #endif } else { lvar_saved_info_t lsi; @@ -121,7 +165,7 @@ bool efi_hexrays::set_hexrays_var_info_and_handle_interfaces(ea_t func_addr, pi.obj_type.get_type_name(&type_name); // handle all interface functions (to rename function arguments) - xreflist_t xrefs = efi_utils::xrefs_to_stack_var(func_addr, name.c_str()); + xreflist_t xrefs = xrefs_to_stack_var(func_addr, name.c_str()); efi_utils::op_stroff_for_interface(xrefs, type_name); return true; diff --git a/efiXplorer/efi_hexrays.h b/efiXplorer/efi_hexrays.h index 6e458d55..9e463af2 100644 --- a/efiXplorer/efi_hexrays.h +++ b/efiXplorer/efi_hexrays.h @@ -26,22 +26,23 @@ #include namespace efi_hexrays { -uint8_t variables_info_extract_all(func_t *f, ea_t code_addr); -bool track_entry_params(func_t *f, uint8_t depth); -json detect_vars(func_t *f); -json_list_t detect_services(func_t *f); -json_list_t detect_pei_services_arm(func_t *f); -bool detect_pei_services(func_t *f); -bool set_lvar_name(qstring name, lvar_t lvar, ea_t func_addr); -bool apply_all_types_for_interfaces(json_list_t guids); bool apply_all_types_for_interfaces_smm(json_list_t guids); -bool set_hexrays_var_info(ea_t func_addr, lvar_t &ll, tinfo_t tif, - std::string name); +bool apply_all_types_for_interfaces(json_list_t guids); +bool detect_pei_services(func_t *f); +bool is_pod_array(tinfo_t tif, unsigned int ptr_depth); +bool offset_of(tinfo_t tif, const char *name, unsigned int *offset); bool set_hexrays_var_info_and_handle_interfaces(ea_t func_addr, lvar_t &ll, tinfo_t tif, std::string name); -bool offset_of(tinfo_t tif, const char *name, unsigned int *offset); -bool is_pod_array(tinfo_t tif, unsigned int ptr_depth); +bool set_hexrays_var_info(ea_t func_addr, lvar_t &ll, tinfo_t tif, + std::string name); +bool set_lvar_name(qstring name, lvar_t lvar, ea_t func_addr); +bool track_entry_params(func_t *f, uint8_t depth); const char *expr_to_string(cexpr_t *e, qstring *out); +json detect_vars(func_t *f); +json_list_t detect_pei_services_arm(func_t *f); +json_list_t detect_services(func_t *f); +uint8_t variables_info_extract_all(func_t *f, ea_t code_addr); +xreflist_t xrefs_to_stack_var(ea_t func_addr, qstring name); // description of a function pointer within a structure. Ultimately, this // plugin is looking for calls to specific UEFI functions. This structure diff --git a/efiXplorer/efi_utils.cc b/efiXplorer/efi_utils.cc index 0d07a225..ebe80080 100644 --- a/efiXplorer/efi_utils.cc +++ b/efiXplorer/efi_utils.cc @@ -732,33 +732,6 @@ std::string efi_utils::type_to_name(std::string type) { return result; } -xreflist_t efi_utils::xrefs_to_stack_var(ea_t func_addr, qstring name) { - efi_utils::log("get xrefs to stack variable %s at 0x%" PRIx64 "\n", - name.c_str(), func_addr); - - xreflist_t xrefs_list; - -#if IDA_SDK_VERSION < 900 - struc_t *frame = get_frame(func_addr); - if (frame == nullptr) { - return xrefs_list; - } - - func_t *f = get_func(func_addr); - if (f == nullptr) { - return xrefs_list; - } - - member_t *member = get_member_by_name(frame, name.c_str()); - if (member != nullptr) { - build_stkvar_xrefs(&xrefs_list, f, member); - } -#else - // TODO(yeggor): rewrite for idasdk90 -#endif - return xrefs_list; -} - void op_stroff_for_addr(ea_t ea, qstring type_name) { insn_t insn; @@ -1003,6 +976,8 @@ uint16_t get_machine_type() { uint32_t u32_addr(ea_t addr) { return static_cast(addr); } uint64_t u64_addr(ea_t addr) { return static_cast(addr); } +size_t get_ptrsize() { return inf_is_64bit() ? 8 : 4; } + #if IDA_SDK_VERSION >= 900 tid_t import_type(const til_t *til, int _idx, const char *name) { tinfo_t tinfo; diff --git a/efiXplorer/efi_utils.h b/efiXplorer/efi_utils.h index a5920402..0d28e884 100644 --- a/efiXplorer/efi_utils.h +++ b/efiXplorer/efi_utils.h @@ -78,14 +78,13 @@ void set_guid_type(ea_t ea); void set_ptr_type_and_name(ea_t ea, std::string name, std::string type); void set_type_and_name(ea_t ea, std::string name, std::string type); -xreflist_t xrefs_to_stack_var(ea_t func_addr, qstring var_name); - int log(const char *fmt, ...); } // namespace efi_utils uint16_t get_machine_type(); uint32_t u32_addr(ea_t addr); uint64_t u64_addr(ea_t addr); +size_t get_ptrsize(); #if IDA_SDK_VERSION >= 900 tid_t import_type(const til_t *til, int _idx, const char *name); From bd0f8ab66a1703c73cb9695671f9f47b7c0fc60a Mon Sep 17 00:00:00 2001 From: yeggor Date: Mon, 23 Sep 2024 21:56:05 +0100 Subject: [PATCH 59/69] initial port of xrefs_to_stack_var to idasdk90, fix offsets --- efiXplorer/efi_hexrays.cc | 27 +++++++++++++++++++++------ efiXplorer/efi_hexrays.h | 2 +- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/efiXplorer/efi_hexrays.cc b/efiXplorer/efi_hexrays.cc index 77b63055..4ba401a8 100644 --- a/efiXplorer/efi_hexrays.cc +++ b/efiXplorer/efi_hexrays.cc @@ -47,12 +47,13 @@ bool efi_hexrays::offset_of(tinfo_t tif, const char *name, return false; } - // get the offset of the field - *offset = static_cast(udt.at(fidx).offset * get_ptrsize()); + // get the offset of the field in bytes + *offset = static_cast(udt.at(fidx).offset >> 3); return true; } -xreflist_t efi_hexrays::xrefs_to_stack_var(ea_t func_addr, qstring name) { +xreflist_t efi_hexrays::xrefs_to_stack_var(ea_t func_addr, lvar_t &ll, + qstring name) { efi_utils::log("get xrefs to stack variable %s at 0x%" PRIx64 "\n", name.c_str(), func_addr); @@ -74,7 +75,21 @@ xreflist_t efi_hexrays::xrefs_to_stack_var(ea_t func_addr, qstring name) { build_stkvar_xrefs(&xrefs_list, f, member); } #else - // TODO(yeggor): rewrite for idasdk90 + sval_t stkoff = ll.get_stkoff(); + + func_t *f = get_func(func_addr); + if (f == nullptr) { + return xrefs_list; + } + + // based on processor_t::lvar_off() from frame.hpp + range_t lvars; + get_frame_part(&lvars, f, FPC_LVARS); + uval_t frameoff = stkoff - lvars.end_ea; + efi_utils::log("stkoff: %x, frameoff: %d\n", stkoff, frameoff); + + build_stkvar_xrefs(&xrefs_list, f, frameoff, frameoff + get_ptrsize()); + #endif return xrefs_list; } @@ -128,7 +143,7 @@ bool efi_hexrays::set_hexrays_var_info(ea_t func_addr, lvar_t &ll, tinfo_t tif, return false; } - ssize_t stkvar_idx = frame.find_udm(stkoff * get_ptrsize()); + ssize_t stkvar_idx = frame.find_udm(stkoff << 3); if (stkvar_idx != -1) { frame.rename_udm(stkvar_idx, name.c_str()); frame.set_udm_type(stkvar_idx, tif); @@ -165,7 +180,7 @@ bool efi_hexrays::set_hexrays_var_info_and_handle_interfaces(ea_t func_addr, pi.obj_type.get_type_name(&type_name); // handle all interface functions (to rename function arguments) - xreflist_t xrefs = xrefs_to_stack_var(func_addr, name.c_str()); + xreflist_t xrefs = xrefs_to_stack_var(func_addr, ll, name.c_str()); efi_utils::op_stroff_for_interface(xrefs, type_name); return true; diff --git a/efiXplorer/efi_hexrays.h b/efiXplorer/efi_hexrays.h index 9e463af2..0d644086 100644 --- a/efiXplorer/efi_hexrays.h +++ b/efiXplorer/efi_hexrays.h @@ -42,7 +42,7 @@ json detect_vars(func_t *f); json_list_t detect_pei_services_arm(func_t *f); json_list_t detect_services(func_t *f); uint8_t variables_info_extract_all(func_t *f, ea_t code_addr); -xreflist_t xrefs_to_stack_var(ea_t func_addr, qstring name); +xreflist_t xrefs_to_stack_var(ea_t func_addr, lvar_t &ll, qstring name); // description of a function pointer within a structure. Ultimately, this // plugin is looking for calls to specific UEFI functions. This structure From feb4f305a4ff0fb5e7b3844bddd8c1b49a08708f Mon Sep 17 00:00:00 2001 From: yeggor Date: Mon, 23 Sep 2024 22:04:53 +0100 Subject: [PATCH 60/69] use stkoff for build_stkvar_xrefs --- efiXplorer/efi_hexrays.cc | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/efiXplorer/efi_hexrays.cc b/efiXplorer/efi_hexrays.cc index 4ba401a8..f925187c 100644 --- a/efiXplorer/efi_hexrays.cc +++ b/efiXplorer/efi_hexrays.cc @@ -82,13 +82,7 @@ xreflist_t efi_hexrays::xrefs_to_stack_var(ea_t func_addr, lvar_t &ll, return xrefs_list; } - // based on processor_t::lvar_off() from frame.hpp - range_t lvars; - get_frame_part(&lvars, f, FPC_LVARS); - uval_t frameoff = stkoff - lvars.end_ea; - efi_utils::log("stkoff: %x, frameoff: %d\n", stkoff, frameoff); - - build_stkvar_xrefs(&xrefs_list, f, frameoff, frameoff + get_ptrsize()); + build_stkvar_xrefs(&xrefs_list, f, stkoff, stkoff + get_ptrsize()); #endif return xrefs_list; From 71901124f4819bc31cdc4b62e53a61d70228a0ba Mon Sep 17 00:00:00 2001 From: yeggor Date: Tue, 24 Sep 2024 00:46:34 +0100 Subject: [PATCH 61/69] remove unnecessary casts --- efiXplorer/efi_analysis_arm.cc | 3 +-- efiXplorer/efi_analysis_x86.cc | 26 +++++++++++------------ efiXplorer/efi_hexrays.h | 38 ++++++++++++++++------------------ efiXplorer/efi_smm_utils.cc | 14 ++++++------- efiXplorer/efi_ui.cc | 23 ++++++++++---------- 5 files changed, 50 insertions(+), 54 deletions(-) diff --git a/efiXplorer/efi_analysis_arm.cc b/efiXplorer/efi_analysis_arm.cc index d262cb53..2992521d 100644 --- a/efiXplorer/efi_analysis_arm.cc +++ b/efiXplorer/efi_analysis_arm.cc @@ -388,8 +388,7 @@ void efi_analysis::efi_analyser_arm_t::detect_protocols_all() { for (auto s : m_all_services) { std::string service_name = s["service_name"]; for (auto i = 0; i < g_boot_services_table_aarch64_count; i++) { - std::string current_name = - static_cast(g_boot_services_table_aarch64[i].name); + std::string current_name = g_boot_services_table_aarch64[i].name; if (current_name != service_name) { continue; } diff --git a/efiXplorer/efi_analysis_x86.cc b/efiXplorer/efi_analysis_x86.cc index f129fe3b..385318a2 100644 --- a/efiXplorer/efi_analysis_x86.cc +++ b/efiXplorer/efi_analysis_x86.cc @@ -306,10 +306,10 @@ bool efi_analysis::efi_analyser_x86_t::find_smst_postproc64() { // try to extract ChildSwSmiHandler auto counter = 0; - ea_t ea = static_cast(smst_stack["start"]); + ea_t ea = smst_stack["start"]; uint16_t smst_reg = NONE_REG; uint64_t rcx_last = BADADDR; - while (ea < static_cast(smst_stack["end"])) { + while (ea < smst_stack["end"]) { counter += 1; if (counter > 500) { break; // just in case @@ -370,11 +370,11 @@ bool efi_analysis::efi_analyser_x86_t::find_smst_postproc64() { bool efi_analysis::efi_analyser_x86_t::find_boot_services_tables() { // init architecture specific constants auto BS_OFFSET = BS_OFFSET_64; - uint16_t R_SP = static_cast(R_RSP); + uint16_t R_SP = R_RSP; if (m_arch == arch_file_type_t::x86_32) { BS_OFFSET = BS_OFFSET_32; - R_SP = static_cast(R_ESP); + R_SP = R_ESP; } insn_t insn; @@ -485,11 +485,11 @@ bool efi_analysis::efi_analyser_x86_t::find_boot_services_tables() { bool efi_analysis::efi_analyser_x86_t::find_runtime_services_tables() { // init architecture specific constants auto RT_OFFSET = RT_OFFSET_64; - uint16_t R_SP = static_cast(R_RSP); + uint16_t R_SP = R_RSP; if (m_arch == arch_file_type_t::x86_32) { RT_OFFSET = RT_OFFSET_32; - R_SP = static_cast(R_ESP); + R_SP = R_ESP; } insn_t insn; @@ -1204,7 +1204,7 @@ void efi_analysis::efi_analyser_x86_t::find_other_boot_services_tables64() { continue; } - ea_t addr = static_cast(s["address"]); + ea_t addr = s["address"]; ea_t addr_bs = efi_utils::find_unknown_bs_var64(addr); if (addr_bs == BADADDR || @@ -1550,7 +1550,7 @@ void efi_analysis::efi_analyser_x86_t::get_smm_prot_names64() { // annotate protocol GUIDs void efi_analysis::efi_analyser_t::annotate_protocol_guids() { for (const auto &prot : *m_ptable) { - ea_t addr = static_cast(prot["address"]); + ea_t addr = prot["address"]; if (efi_utils::addr_in_vec(m_annotated_protocols, addr)) { continue; } @@ -1603,7 +1603,7 @@ void efi_analysis::efi_analyser_t::annotate_data_guids() { continue; } - uint64_t flags = static_cast(get_wide_dword(ppi_ea)); + uint64_t flags = get_wide_dword(ppi_ea); if (!efi_utils::uint64_in_vec(m_ppi_flags, flags)) { continue; } @@ -1661,7 +1661,7 @@ void efi_analysis::efi_analyser_x86_t::find_local_guids64() { if (insn_next.itype == NN_mov && insn_next.ops[0].type == o_displ && insn_next.ops[1].type == o_imm) { // get guid->data2 value - uint16_t data2 = static_cast(insn_next.ops[1].value); + uint16_t data2 = insn_next.ops[1].value; if (!data2 || data2 == 0xffff) { ea = next_head(ea, BADADDR); continue; @@ -1876,7 +1876,7 @@ bool efi_analysis::efi_analyser_x86_t::find_double_get_variable_pei() { json service = j_service; std::string service_name = service["service_name"]; std::string table_name = service["table_name"]; - ea_t addr = static_cast(service["address"]); + ea_t addr = service["address"]; if (service_name.compare(get_variable_str) == 0) { get_variable_services_calls.push_back(addr); } @@ -2028,7 +2028,7 @@ bool efi_analysis::efi_analyser_x86_t::find_double_get_variable() { for (auto j_service : m_all_services) { json service = j_service; std::string service_name = service["service_name"]; - ea_t addr = static_cast(service["address"]); + ea_t addr = service["address"]; if (service_name.compare(get_variable_str) == 0) { get_variable_services_calls.push_back(addr); } @@ -2373,7 +2373,7 @@ bool efi_analysis::efi_analyser_t::analyse_nvram_variables() { for (auto j_service : m_all_services) { json service = j_service; std::string service_name = service["service_name"]; - ea_t addr = static_cast(service["address"]); + ea_t addr = service["address"]; if (!service_name.compare(service_str)) { var_services.push_back(addr); } diff --git a/efiXplorer/efi_hexrays.h b/efiXplorer/efi_hexrays.h index 0d644086..031f195c 100644 --- a/efiXplorer/efi_hexrays.h +++ b/efiXplorer/efi_hexrays.h @@ -530,58 +530,56 @@ class guid_retyper_t : public guid_related_visitor_base_t { // given an expression (either a local or global variable) and a type to // apply, apply the type. This is just a bit of IDA/Hex-Rays type system // skullduggery - void apply_type(cexpr_t *outArg, tinfo_t ptrTif, qstring tstr) { - ea_t dest_ea = outArg->obj_ea; + void apply_type(cexpr_t *out_arg, tinfo_t ptr_tif, qstring tstr) { + ea_t dest_ea = out_arg->obj_ea; // for global variables - if (outArg->op == cot_obj) { + if (out_arg->op == cot_obj) { // just apply the type information to the address - apply_tinfo(dest_ea, ptrTif, TINFO_DEFINITE); + apply_tinfo(dest_ea, ptr_tif, TINFO_DEFINITE); ++m_num_applied; // rename global variable - auto name = - "g" + efi_utils::type_to_name(static_cast(tstr.c_str())); + auto name = "g" + efi_utils::type_to_name(tstr.c_str()); set_name(dest_ea, name.c_str(), SN_FORCE); // get xrefs to global variable auto xrefs = efi_utils::get_xrefs(dest_ea); qstring type_name; ptr_type_data_t pi; - ptrTif.get_ptr_details(&pi); + ptr_tif.get_ptr_details(&pi); pi.obj_type.get_type_name(&type_name); // handling all interface functions (to rename function arguments) efi_utils::op_stroff_for_global_interface(xrefs, type_name); - } else if (outArg->op == cot_var) { // for local variables - var_ref_t var_ref = outArg->v; + } else if (out_arg->op == cot_var) { // for local variables + var_ref_t var_ref = out_arg->v; lvar_t &dest_var = var_ref.mba->vars[var_ref.idx]; // set the Hex-Rays variable type - auto name = - efi_utils::type_to_name(static_cast(tstr.c_str())); - set_lvar_name(static_cast(name.c_str()), dest_var, m_func_ea); + auto name = efi_utils::type_to_name(tstr.c_str()); + set_lvar_name(name.c_str(), dest_var, m_func_ea); if (set_hexrays_var_info_and_handle_interfaces(m_func_ea, dest_var, - ptrTif, name)) { + ptr_tif, name)) { ++m_num_applied; } } } - void apply_name(cexpr_t *outArg, std::string type_name) { - ea_t dest_ea = outArg->obj_ea; + void apply_name(cexpr_t *out_arg, std::string type_name) { + ea_t dest_ea = out_arg->obj_ea; // for global variables - if (outArg->op == cot_obj) { + if (out_arg->op == cot_obj) { // rename global variable auto name = "g" + efi_utils::type_to_name(type_name); set_name(dest_ea, name.c_str(), SN_FORCE); - } else if (outArg->op == cot_var) { // for local variables - var_ref_t var_ref = outArg->v; + } else if (out_arg->op == cot_var) { // for local variables + var_ref_t var_ref = out_arg->v; lvar_t &dest_var = var_ref.mba->vars[var_ref.idx]; // set the Hex-Rays variable type auto name = efi_utils::type_to_name(type_name); - set_lvar_name(static_cast(name.c_str()), dest_var, m_func_ea); + set_lvar_name(name.c_str(), dest_var, m_func_ea); } } }; @@ -1059,7 +1057,7 @@ class pei_services_detector_arm_t : public ctree_visitor_t { qstring func_type_name; tinfo_t service_type = e->x->type; service_type.get_type_name(&func_type_name); - std::string func_type = static_cast(func_type_name.c_str()); + std::string func_type = func_type_name.c_str(); std::string prefix = "EFI_PEI_"; if (func_type.substr(0, prefix.length()) == prefix) { func_type.erase(0, prefix.length()); diff --git a/efiXplorer/efi_smm_utils.cc b/efiXplorer/efi_smm_utils.cc index e79f6fa8..9e5ebb17 100644 --- a/efiXplorer/efi_smm_utils.cc +++ b/efiXplorer/efi_smm_utils.cc @@ -356,7 +356,7 @@ efi_smm_utils::find_smi_handlers_dispatch_stack(json_list_t stack_guids, continue; } - ea_t address = static_cast(guid["address"]); + ea_t address = guid["address"]; efi_utils::log( "found EFI_SMM_SW_DISPATCH{2}_PROTOCOL_GUID on stack: 0x%" PRIx64 "\n", u64_addr(address)); @@ -491,32 +491,32 @@ efi_smm_utils::resolve_efi_smm_cpu_protocol(json_list_t stack_guids, ea_list_t code_addrs; ea_list_t smm_cpu_addrs; for (auto guid : stack_guids) { - if (static_cast(guid["name"]) != "EFI_SMM_CPU_PROTOCOL_GUID") + if (guid["name"] != "EFI_SMM_CPU_PROTOCOL_GUID") continue; - ea_t address = static_cast(guid["address"]); + ea_t address = guid["address"]; efi_utils::log("found EFI_SMM_CPU_PROTOCOL on stack at 0x%" PRIx64 "\n", u64_addr(address)); code_addrs.push_back(address); } for (auto guid : data_guids) { - if (static_cast(guid["name"]) != "EFI_SMM_CPU_PROTOCOL_GUID") + if (guid["name"] != "EFI_SMM_CPU_PROTOCOL_GUID") continue; - ea_t address = static_cast(guid["address"]); + ea_t address = guid["address"]; efi_utils::log("found EFI_SMM_CPU_PROTOCOL at 0x%" PRIx64 "\n", u64_addr(address)); ea_list_t guid_xrefs = efi_utils::get_xrefs(address); for (auto guid_xref : guid_xrefs) { - segment_t *seg = getseg(static_cast(guid_xref)); + segment_t *seg = getseg(guid_xref); qstring seg_name; get_segm_name(&seg_name, seg); size_t index = seg_name.find(".text"); if (index == std::string::npos) { continue; } - code_addrs.push_back(static_cast(guid_xref)); + code_addrs.push_back(guid_xref); } } diff --git a/efiXplorer/efi_ui.cc b/efiXplorer/efi_ui.cc index ed966d07..24884068 100644 --- a/efiXplorer/efi_ui.cc +++ b/efiXplorer/efi_ui.cc @@ -110,11 +110,10 @@ void idaapi nvram_chooser_t::get_row(qstrvec_t *cols_, int *, ea_t ea = list[n]; qstrvec_t &cols = *cols_; json item = chooser_nvram[n]; - std::string name = static_cast(item["VariableName"]); - std::string guid = static_cast(item["VendorGuid"]); - std::string service = static_cast(item["service"]); - std::string attributes = - static_cast(item["AttributesHumanReadable"]); + std::string name = item["VariableName"]; + std::string guid = item["VendorGuid"]; + std::string service = item["service"]; + std::string attributes = item["AttributesHumanReadable"]; cols[0].sprnt("%016" PRIX64, u64_addr(ea)); cols[1].sprnt("%s", name.c_str()); cols[2].sprnt("%s", guid.c_str()); @@ -136,7 +135,7 @@ void idaapi vulns_chooser_t::get_row(qstrvec_t *cols_, int *, ea_t ea = list[n]; qstrvec_t &cols = *cols_; json item = chooser_vulns[n]; - std::string type = static_cast(item["type"]); + std::string type = item["type"]; cols[0].sprnt("%016" PRIX64, u64_addr(ea)); cols[1].sprnt("%s", type.c_str()); CASSERT(qnumber(header_vulns) == 2); @@ -155,8 +154,8 @@ void idaapi guids_chooser_t::get_row(qstrvec_t *cols_, int *, ea_t ea = list[n]; qstrvec_t &cols = *cols_; json item = chooser_guids[n]; - std::string guid = static_cast(item["guid"]); - std::string name = static_cast(item["name"]); + std::string guid = item["guid"]; + std::string name = item["name"]; cols[0].sprnt("%016" PRIX64, u64_addr(ea)); cols[1].sprnt("%s", guid.c_str()); cols[2].sprnt("%s", name.c_str()); @@ -180,10 +179,10 @@ void idaapi m_protocols_chooser_t::get_row(qstrvec_t *cols_, int *, ea_t ea = list[n]; qstrvec_t &cols = *cols_; json item = chooser_protocols[n]; - std::string name = static_cast(item[name_key]); - std::string service = static_cast(item["service"]); - std::string protGuid = static_cast(item["guid"]); - std::string moduleName = static_cast(item["module"]); + std::string name = item[name_key]; + std::string service = item["service"]; + std::string protGuid = item["guid"]; + std::string moduleName = item["module"]; cols[0].sprnt("%016" PRIX64, u64_addr(ea)); cols[1].sprnt("%s", protGuid.c_str()); cols[2].sprnt("%s", name.c_str()); From 4fe40b6f0a91fe0f8cce6bab25cef19939e4f2bc Mon Sep 17 00:00:00 2001 From: yeggor Date: Tue, 24 Sep 2024 00:53:03 +0100 Subject: [PATCH 62/69] set EFI_SMM_HANDLER_ENTRY_POINT2 type for SMI handlers --- efiXplorer/efi_smm_utils.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/efiXplorer/efi_smm_utils.cc b/efiXplorer/efi_smm_utils.cc index 9e5ebb17..a5655fd7 100644 --- a/efiXplorer/efi_smm_utils.cc +++ b/efiXplorer/efi_smm_utils.cc @@ -294,7 +294,8 @@ func_list_t efi_smm_utils::find_smi_handlers(ea_t address, std::string prefix) { // op_stroff + set_name auto name = std::format("{}SmiHandler", prefix); - set_name(dispatch_func, name.c_str(), SN_FORCE); + efi_utils::set_type_and_name(dispatch_func, name.c_str(), + "EFI_SMM_HANDLER_ENTRY_POINT2"); std::string prefix_upper; std::transform(prefix.begin(), prefix.end(), prefix_upper.begin(), @@ -458,8 +459,6 @@ efi_smm_utils::find_smm_get_variable_calls(segment_list_t data_segs, smm_get_variable_calls.push_back(ea); } - // temporarily add a "virtual" SMM service call - // for easier annotations and UI efi_utils::op_stroff(ea, "EFI_SMM_VARIABLE_PROTOCOL"); efi_utils::log("found SmmGetVariable call at 0x%" PRIx64 "\n", u64_addr(ea)); @@ -614,7 +613,8 @@ ea_t efi_smm_utils::mark_child_sw_smi_handlers(ea_t ea) { if (insn.ops[1].type != o_mem) { continue; } - set_name(insn.ops[1].addr, "ChildSwSmiHandler", SN_FORCE); + efi_utils::set_type_and_name(insn.ops[1].addr, "ChildSwSmiHandler", + "EFI_SMM_HANDLER_ENTRY_POINT2"); return insn.ops[1].addr; } } From a83485d654981c3d2fa5544d8beb693b05818d9c Mon Sep 17 00:00:00 2001 From: yeggor Date: Tue, 24 Sep 2024 01:05:14 +0100 Subject: [PATCH 63/69] remove unnecessary casts --- efiXplorer/efi_deps.cc | 7 +++---- efiXplorer/efi_utils.cc | 28 +++++++++++++--------------- 2 files changed, 16 insertions(+), 19 deletions(-) diff --git a/efiXplorer/efi_deps.cc b/efiXplorer/efi_deps.cc index a00eb1f4..e3ebf8ad 100644 --- a/efiXplorer/efi_deps.cc +++ b/efiXplorer/efi_deps.cc @@ -153,8 +153,7 @@ void efi_deps_t::get_installers_modules() { for (auto ea : xrefs) { if (efi_utils::check_install_protocol(ea)) { auto module = efi_utils::get_module_name_loader(ea); - m_additional_installers[protocol] = - static_cast(module.c_str()); + m_additional_installers[protocol] = module.c_str(); installer_found = true; break; } @@ -409,8 +408,8 @@ bool efi_deps_t::build_modules_sequence() { size_t mnum = 0; for (auto const &[prot, counter] : protocols_usage) { if (counter > mnum) { - mnum = static_cast(counter); - mprotocol = static_cast(prot); + mnum = counter; + mprotocol = prot; } } diff --git a/efiXplorer/efi_utils.cc b/efiXplorer/efi_utils.cc index ebe80080..e8c71b2f 100644 --- a/efiXplorer/efi_utils.cc +++ b/efiXplorer/efi_utils.cc @@ -32,7 +32,7 @@ ea_list_t g_smm_set_variable_calls; std::string file_format_name() { char file_format[256] = {0}; get_file_type_name(file_format, 256); - return static_cast(file_format); + return file_format; } //-------------------------------------------------------------------------- @@ -65,7 +65,7 @@ ffs_file_type_t guess_file_type(arch_file_type_t arch, char file_name[256] = {0}; get_input_file_path(file_name, sizeof(file_name)); - auto file_name_str = static_cast(file_name); + std::string file_name_str = file_name; if ((file_name_str.find("Pei") != std::string::npos || file_name_str.find("pei") != std::string::npos || signature == VZ) && @@ -542,8 +542,8 @@ json efi_utils::get_guid_by_address(ea_t addr) { //-------------------------------------------------------------------------- // validate GUID value bool efi_utils::valid_guid(json guid) { - auto data0 = static_cast(guid[0]); - auto data1 = static_cast(guid[1]); + uint32_t data0 = guid[0]; + uint32_t data1 = guid[1]; auto invalid = (!data0 && !data1) || (data0 == 0xffffffff && data1 == 0xffff); return !invalid; @@ -578,7 +578,7 @@ uint8_list_t efi_utils::unpack_guid(std::string guid) { } for (auto i = 0; i < hex.size(); i += 2) { byte_str = hex.substr(i, 2); - byte = static_cast(strtol(byte_str.c_str(), nullptr, 16)); + byte = strtol(byte_str.c_str(), nullptr, 16); tmp.push_back(byte); } if (index != 3) { @@ -593,7 +593,7 @@ uint8_list_t efi_utils::unpack_guid(std::string guid) { for (auto i = 0; i < guid.size(); i += 2) { byte_str = guid.substr(i, 2); - byte = static_cast(strtol(byte_str.c_str(), nullptr, 16)); + byte = strtol(byte_str.c_str(), nullptr, 16); res.push_back(byte); } @@ -875,7 +875,7 @@ efi_guid_t efi_utils::get_global_guid(ea_t addr) { guid.data2 = get_wide_word(addr + 4); guid.data3 = get_wide_word(addr + 6); for (auto i = 0; i < 8; i++) { - guid.data4[i] = static_cast(get_wide_byte(addr + 8 + i)); + guid.data4[i] = get_wide_byte(addr + 8 + i); } return guid; } @@ -932,15 +932,13 @@ efi_guid_t efi_utils::get_local_guid(func_t *f, uint64_t offset) { std::string efi_utils::get_table_name(std::string service_name) { for (auto i = 0; i < g_boot_services_table_all_count; i++) { - if (static_cast(g_boot_services_table_all[i].name) == - service_name) { + if (g_boot_services_table_all[i].name == service_name) { return "EFI_BOOT_SERVICES"; } } for (auto i = 0; i < g_runtime_services_table_all_count; i++) { - if (static_cast(g_runtime_services_table_all[i].name) == - service_name) { + if (g_runtime_services_table_all[i].name == service_name) { return "EFI_RUNTIME_SERVICES"; } } @@ -951,7 +949,7 @@ std::string efi_utils::get_table_name(std::string service_name) { std::string efi_utils::lookup_boot_service_name(uint64_t offset) { for (auto i = 0; i < g_boot_services_table_all_count; i++) { if (g_boot_services_table_all[i].offset64 == offset) { - return static_cast(g_boot_services_table_all[i].name); + return g_boot_services_table_all[i].name; } } @@ -961,7 +959,7 @@ std::string efi_utils::lookup_boot_service_name(uint64_t offset) { std::string efi_utils::lookup_runtime_service_name(uint64_t offset) { for (auto i = 0; i < g_runtime_services_table_all_count; i++) { if (g_runtime_services_table_all[i].offset64 == offset) { - return static_cast(g_runtime_services_table_all[i].name); + return g_runtime_services_table_all[i].name; } } @@ -973,8 +971,8 @@ uint16_t get_machine_type() { return get_word(pe_offset + 4); } -uint32_t u32_addr(ea_t addr) { return static_cast(addr); } -uint64_t u64_addr(ea_t addr) { return static_cast(addr); } +uint32_t u32_addr(ea_t addr) { return addr; } +uint64_t u64_addr(ea_t addr) { return addr; } size_t get_ptrsize() { return inf_is_64bit() ? 8 : 4; } From 6b3f5d90c44176e5731724cb531b9c8f07c410a3 Mon Sep 17 00:00:00 2001 From: yeggor Date: Tue, 24 Sep 2024 03:57:33 +0100 Subject: [PATCH 64/69] minor changes --- efiXplorer/efi_hexrays.cc | 1 - efiXplorer/efi_utils.cc | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/efiXplorer/efi_hexrays.cc b/efiXplorer/efi_hexrays.cc index f925187c..f9403f8b 100644 --- a/efiXplorer/efi_hexrays.cc +++ b/efiXplorer/efi_hexrays.cc @@ -105,7 +105,6 @@ bool efi_hexrays::set_lvar_name(qstring name, lvar_t lvar, ea_t func_addr) { // utility function to set a Hex-Rays variable type and name bool efi_hexrays::set_hexrays_var_info(ea_t func_addr, lvar_t &ll, tinfo_t tif, std::string name) { - // set lvar name if (ll.is_stk_var()) { // rename local variable on stack #if IDA_SDK_VERSION < 900 sval_t stkoff = ll.get_stkoff(); diff --git a/efiXplorer/efi_utils.cc b/efiXplorer/efi_utils.cc index e8c71b2f..0b52b06a 100644 --- a/efiXplorer/efi_utils.cc +++ b/efiXplorer/efi_utils.cc @@ -513,10 +513,10 @@ bool efi_utils::add_struct_for_shifted_ptr() { set_member_tinfo(new_struct, member, 0, pp_tinfo, 0); return true; -#endif - +#else // return true if there are no errors from parse_decls() return !parse_efi_pei_svc4() && !parse_efi_pei_sidt(); +#endif } //-------------------------------------------------------------------------- From 2c1373ee3da97e03fbf135a2f4ba25b1d3079e8f Mon Sep 17 00:00:00 2001 From: yeggor Date: Wed, 25 Sep 2024 20:23:09 +0100 Subject: [PATCH 65/69] add compatibility with idasdk90-rc1 --- efiXplorer/efi_utils.cc | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/efiXplorer/efi_utils.cc b/efiXplorer/efi_utils.cc index 0b52b06a..91fc05c2 100644 --- a/efiXplorer/efi_utils.cc +++ b/efiXplorer/efi_utils.cc @@ -612,7 +612,7 @@ ea_list_t efi_utils::search_protocol(std::string protocol) { bin_search2(start, BADADDR, bytes, nullptr, 16, BIN_SEARCH_FORWARD); #else ea_t addr = - bin_search3(start, BADADDR, bytes, nullptr, 16, BIN_SEARCH_FORWARD); + bin_search(start, BADADDR, bytes, nullptr, 16, BIN_SEARCH_FORWARD); #endif if (addr == BADADDR) { break; @@ -839,8 +839,7 @@ ea_list_t efi_utils::find_data(ea_t start_ea, ea_t end_ea, uchar *data, auto ea = bin_search2(start, end_ea, data, nullptr, len, BIN_SEARCH_FORWARD); #else - auto ea = - bin_search3(start, end_ea, data, nullptr, len, BIN_SEARCH_FORWARD); + auto ea = bin_search(start, end_ea, data, nullptr, len, BIN_SEARCH_FORWARD); #endif if (ea == BADADDR) { break; From 72a2e46dee4537dd32c84b2d3130ae08d628088a Mon Sep 17 00:00:00 2001 From: yeggor Date: Mon, 30 Sep 2024 15:42:29 +0100 Subject: [PATCH 66/69] update readme --- README.md | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 6ba10a09..7b7a243d 100644 --- a/README.md +++ b/README.md @@ -2,16 +2,16 @@ [![efiXplorer CI](https://github.com/binarly-io/efiXplorer/actions/workflows/ci-build.yml/badge.svg)](https://github.com/binarly-io/efiXplorer/actions)

- efiXlorer Logo + efiXlorer Logo

**efiXplorer** - IDA plugin for UEFI firmware analysis and reverse engineering automation -__Supported versions of Hex-Rays products:__ everytime we focus on last versions of IDA and Decompiler because we try to use most recent features from new SDK releases. That means we tested only on recent versions of Hex-Rays products and do not guarantee stable work on previous generations. +**Supported versions of Hex-Rays products:** everytime we focus on last versions of IDA and Decompiler because we try to use most recent features from new SDK releases. That means we tested only on recent versions of Hex-Rays products and do not guarantee stable work on previous generations. -__Why not IDApython:__ all code developed in C++ because it's a more stable and performant way to support a complex plugin and get full power of most recent SDK's features. +**Why not IDApython:** all code developed in C++ because it's a more stable and performant way to support a complex plugin and get full power of most recent SDK's features. -__Supported Platforms:__ Windows, Linux and OSX. +**Supported Platforms:** Windows, Linux and OSX. ## [efiXplorer core features](https://github.com/binarly-io/efiXplorer/wiki/efiXplorer-features) @@ -21,17 +21,17 @@ __Supported Platforms:__ Windows, Linux and OSX. ## Publications -* [efiXplorer: Hunting for UEFI Firmware Vulnerabilities at Scale with Automated Static Analysis](https://i.blackhat.com/eu-20/Wednesday/eu-20-Labunets-efiXplorer-Hunting-For-UEFI-Firmware-Vulnerabilities-At-Scale-With-Automated-Static-Analysis.pdf) -* [Static analysis-based recovery of service function calls in UEFI firmware](https://github.com/binarly-io/Research_Publications/blob/main/EKO_2020/EKO_2020_efiXplorer.pdf) -* [How efiXplorer helping to solve challenges in reverse engineering of UEFI firmware](https://www.youtube.com/watch?v=FFGQJBmRkLw) +- [efiXplorer: Hunting for UEFI Firmware Vulnerabilities at Scale with Automated Static Analysis](https://i.blackhat.com/eu-20/Wednesday/eu-20-Labunets-efiXplorer-Hunting-For-UEFI-Firmware-Vulnerabilities-At-Scale-With-Automated-Static-Analysis.pdf) +- [Static analysis-based recovery of service function calls in UEFI firmware](https://github.com/binarly-io/Research_Publications/blob/main/EKO_2020/EKO_2020_efiXplorer.pdf) +- [How efiXplorer helping to solve challenges in reverse engineering of UEFI firmware](https://www.youtube.com/watch?v=FFGQJBmRkLw) ## References -* https://github.com/LongSoft/UEFITool -* https://github.com/yeggor/uefi_retool -* https://github.com/gdbinit/EFISwissKnife -* https://github.com/snare/ida-efiutils -* https://github.com/al3xtjames/ghidra-firmware-utils -* https://github.com/DSecurity/efiSeek -* https://github.com/p-state/ida-efitools2 -* https://github.com/zznop/bn-uefi-helper +- https://github.com/LongSoft/UEFITool +- https://github.com/yeggor/uefi_retool +- https://github.com/gdbinit/EFISwissKnife +- https://github.com/snare/ida-efiutils +- https://github.com/al3xtjames/ghidra-firmware-utils +- https://github.com/DSecurity/efiSeek +- https://github.com/p-state/ida-efitools2 +- https://github.com/zznop/bn-uefi-helper From 7b78f562a646de911079656c612a2c3ffd1d0cbd Mon Sep 17 00:00:00 2001 From: yeggor Date: Thu, 26 Sep 2024 05:06:33 +0100 Subject: [PATCH 67/69] remove std::format usage --- efiXplorer/CMakeLists.txt | 2 +- efiXplorer/efi_analysis_x86.cc | 8 ++++---- efiXplorer/efi_defs.h | 11 ++++++----- efiXplorer/efi_smm_utils.cc | 5 ++--- efiXplorer/efi_utils.cc | 22 +++++++++++++--------- 5 files changed, 26 insertions(+), 22 deletions(-) diff --git a/efiXplorer/CMakeLists.txt b/efiXplorer/CMakeLists.txt index 4d47bb4f..6a506eee 100644 --- a/efiXplorer/CMakeLists.txt +++ b/efiXplorer/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.7) project(efiXplorer CXX) -set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) diff --git a/efiXplorer/efi_analysis_x86.cc b/efiXplorer/efi_analysis_x86.cc index 385318a2..bc822fbc 100644 --- a/efiXplorer/efi_analysis_x86.cc +++ b/efiXplorer/efi_analysis_x86.cc @@ -972,8 +972,9 @@ void efi_analysis::efi_analyser_x86_t::get_variable_ppi_calls_all32() { efi_utils::log("0x%" PRIx64 ": %s\n", u64_addr(ea), g_variable_ppi_table_all[j].name); - std::string ppi_call = std::format( - "VariablePPI->{}", g_variable_ppi_table_all[j].name); + std::string ppi_call = + "VariablePPI->" + + static_cast(g_variable_ppi_table_all[j].name); m_ppi_calls_all[ppi_call].push_back(ea); json s; @@ -1592,8 +1593,7 @@ void efi_analysis::efi_analyser_t::annotate_data_guids() { auto xrefs = efi_utils::get_xrefs(ea); for (auto addr : xrefs) { std::string type_name = guid_name.substr(0, guid_name.length() - 5); - std::string ppi_name = - std::format("g{}", efi_utils::type_to_name(type_name)); + std::string ppi_name = "g" + efi_utils::type_to_name(type_name); ea_t ppi_ea = addr - ptrsize; diff --git a/efiXplorer/efi_defs.h b/efiXplorer/efi_defs.h index 44a89e8a..617e5269 100644 --- a/efiXplorer/efi_defs.h +++ b/efiXplorer/efi_defs.h @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include @@ -199,10 +198,12 @@ struct efi_guid_t { } std::string to_string() const { - return std::format("{:08X}-{:04X}-{:04X}-{:02X}{:02X}-" - "{:02X}{:02X}{:02X}{:02X}{:02X}{:02X}", - data1, data2, data3, data4[0], data4[1], data4[2], - data4[3], data4[4], data4[5], data4[6], data4[7]); + char res[37] = {0}; + snprintf(res, sizeof(res), + "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X", data1, data2, + data3, data4[0], data4[1], data4[2], data4[3], data4[4], data4[5], + data4[6], data4[7]); + return res; } }; diff --git a/efiXplorer/efi_smm_utils.cc b/efiXplorer/efi_smm_utils.cc index a5655fd7..15c19f8b 100644 --- a/efiXplorer/efi_smm_utils.cc +++ b/efiXplorer/efi_smm_utils.cc @@ -293,15 +293,14 @@ func_list_t efi_smm_utils::find_smi_handlers(ea_t address, std::string prefix) { reg = NONE_REG; // resetting // op_stroff + set_name - auto name = std::format("{}SmiHandler", prefix); + auto name = prefix + "SmiHandler"; efi_utils::set_type_and_name(dispatch_func, name.c_str(), "EFI_SMM_HANDLER_ENTRY_POINT2"); std::string prefix_upper; std::transform(prefix.begin(), prefix.end(), prefix_upper.begin(), ::toupper); - std::string type = - std::format("EFI_SMM_{}_DISPATCH2_PROTOCOL", prefix_upper); + std::string type = "EFI_SMM_" + prefix_upper + "_DISPATCH2_PROTOCOL"; efi_utils::op_stroff(ea, type); } diff --git a/efiXplorer/efi_utils.cc b/efiXplorer/efi_utils.cc index 91fc05c2..45e063bd 100644 --- a/efiXplorer/efi_utils.cc +++ b/efiXplorer/efi_utils.cc @@ -552,14 +552,16 @@ bool efi_utils::valid_guid(json guid) { //-------------------------------------------------------------------------- // convert GUID value to string std::string efi_utils::guid_to_string(json guid) { - return std::format( - "{:08X}-{:04X}-{:04X}-{:02X}{:02X}-{:02X}{:02X}{:02X}{:02X}{:02X}{:02X}", - static_cast(guid[0]), static_cast(guid[1]), - static_cast(guid[2]), static_cast(guid[3]), - static_cast(guid[4]), static_cast(guid[5]), - static_cast(guid[6]), static_cast(guid[7]), - static_cast(guid[8]), static_cast(guid[9]), - static_cast(guid[10])); + char guid_str[37] = {0}; + snprintf(guid_str, sizeof(guid_str), + "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X", + static_cast(guid[0]), static_cast(guid[1]), + static_cast(guid[2]), static_cast(guid[3]), + static_cast(guid[4]), static_cast(guid[5]), + static_cast(guid[6]), static_cast(guid[7]), + static_cast(guid[8]), static_cast(guid[9]), + static_cast(guid[10])); + return guid_str; } uint8_list_t efi_utils::unpack_guid(std::string guid) { @@ -647,7 +649,9 @@ bool efi_utils::check_install_protocol(ea_t ea) { //-------------------------------------------------------------------------- // convert 64-bit value to hex string std::string efi_utils::as_hex(uint64_t value) { - return std::format("{:016X}", value); + char hexstr[21] = {}; + snprintf(hexstr, sizeof(hexstr), "%" PRIX64, value); + return hexstr; } //-------------------------------------------------------------------------- From 022948315d99bbdc70da0f169d8766befb56c9cf Mon Sep 17 00:00:00 2001 From: yeggor Date: Thu, 26 Sep 2024 05:11:42 +0100 Subject: [PATCH 68/69] minor fixes --- efiXplorer/efi_defs.h | 6 +++--- efiXplorer/efi_utils.cc | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/efiXplorer/efi_defs.h b/efiXplorer/efi_defs.h index 617e5269..9308c2d1 100644 --- a/efiXplorer/efi_defs.h +++ b/efiXplorer/efi_defs.h @@ -198,12 +198,12 @@ struct efi_guid_t { } std::string to_string() const { - char res[37] = {0}; - snprintf(res, sizeof(res), + char guid_str[37] = {0}; + snprintf(guid_str, sizeof(guid_str), "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X", data1, data2, data3, data4[0], data4[1], data4[2], data4[3], data4[4], data4[5], data4[6], data4[7]); - return res; + return guid_str; } }; diff --git a/efiXplorer/efi_utils.cc b/efiXplorer/efi_utils.cc index 45e063bd..ae9f8772 100644 --- a/efiXplorer/efi_utils.cc +++ b/efiXplorer/efi_utils.cc @@ -649,7 +649,7 @@ bool efi_utils::check_install_protocol(ea_t ea) { //-------------------------------------------------------------------------- // convert 64-bit value to hex string std::string efi_utils::as_hex(uint64_t value) { - char hexstr[21] = {}; + char hexstr[21] = {0}; snprintf(hexstr, sizeof(hexstr), "%" PRIX64, value); return hexstr; } From b949176a6a56b55aa5c9f2a8dd2cc8ab385ce75a Mon Sep 17 00:00:00 2001 From: yeggor Date: Mon, 30 Sep 2024 17:10:33 +0100 Subject: [PATCH 69/69] fix windows build --- efiXplorer/3rd/nlohmann_json/json.hpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/efiXplorer/3rd/nlohmann_json/json.hpp b/efiXplorer/3rd/nlohmann_json/json.hpp index 7ceca624..d47e1362 100644 --- a/efiXplorer/3rd/nlohmann_json/json.hpp +++ b/efiXplorer/3rd/nlohmann_json/json.hpp @@ -13952,7 +13952,11 @@ class json_pointer const char* p = s.c_str(); char* p_end = nullptr; errno = 0; // strtoull doesn't reset errno +#if defined(_MSC_VER) + const unsigned long long res = strtoull(p, &p_end, 10); // NOLINT(runtime/int) +#else const unsigned long long res = std::strtoull(p, &p_end, 10); // NOLINT(runtime/int) +#endif if (p == p_end // invalid input or empty string || errno == ERANGE // out of range || JSON_HEDLEY_UNLIKELY(static_cast(p_end - p) != s.size())) // incomplete read