Skip to content

Commit

Permalink
Merge pull request #97 from binarly-io/feature/efi-enums
Browse files Browse the repository at this point in the history
resolve enum values from MACRO_EFI for x86 and ARM binaries
  • Loading branch information
yeggor authored Nov 23, 2024
2 parents 746ef87 + ebba657 commit ad123af
Show file tree
Hide file tree
Showing 3 changed files with 164 additions and 35 deletions.
49 changes: 43 additions & 6 deletions efiXplorer/efi_analysis.h
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,10 @@ class efi_analyser_t {
ea_list_t m_double_get_variable_smm;
ea_list_t m_double_get_variable;

// mask and masked value for MACRO_EFI enum value detection
uint64_t m_mask = 0;
uint64_t m_masked_value = 0;

bool add_protocol(std::string service_name, ea_t guid_addr, ea_t xref_addr,
ea_t call_addr);

Expand Down Expand Up @@ -367,6 +371,12 @@ class efi_analyser_x86_t : public efi_analyser_t {
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");

tinfo_t tinfo;
if (tinfo.get_named_type(idati, "MACRO_EFI")) {
m_macro_efi_tid = tinfo.force_tid();
}

#ifdef HEX_RAYS
for (auto idx = 0; idx < get_entry_qty(); idx++) {
uval_t ord = get_entry_ordinal(idx);
Expand Down Expand Up @@ -399,11 +409,17 @@ 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 set_operands_repr();
void show_all_choosers();

private:
void find_callout_rec(func_t *func);
tid_t m_macro_efi_tid;
uint64_t m_mask = 0;
uint64_t m_masked_value = 0;

bool install_multiple_prot_interfaces_analyser();
bool set_enums_repr(ea_t ea, insn_t insn);
void find_callout_rec(func_t *func);
};

class efi_analyser_arm_t : public efi_analyser_t {
Expand All @@ -414,24 +430,45 @@ class efi_analyser_arm_t : public efi_analyser_t {
add_til("uefi64.til", ADDTIL_DEFAULT);

const til_t *idati = get_idati();
import_type(idati, -1, "EFI_BOOT_SERVICES");
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_SYSTEM_TABLE");

tinfo_t tinfo;
if (tinfo.get_named_type(idati, "MACRO_EFI")) {
m_macro_efi_tid = tinfo.force_tid();
}
}

~efi_analyser_arm_t() {
m_image_handle_list.clear();
m_st_list_arm.clear();
m_bs_list_arm.clear();
m_rt_list_arm.clear();
}

void detect_protocols_all();
void detect_services_all();
void find_boot_services_tables();
void find_pei_services_function();
void fix_offsets();
void initial_analysis();
void initial_gvars_detection();
void detect_protocols_all();
void detect_services_all();
void set_operands_repr();
void show_all_choosers();

private:
ea_list_t m_image_handle_list_arm;
ea_list_t m_st_list_arm;
ea_list_t m_bs_list_arm;
ea_list_t m_rt_list_arm;

tid_t m_macro_efi_tid;

bool get_protocol(ea_t address, uint32_t p_reg, std::string service_name);
bool set_enums_repr(ea_t ea, insn_t insn);
bool set_offsets_repr(ea_t ea, insn_t insn);
};

bool efi_analyse_main_x86_64();
Expand Down
90 changes: 61 additions & 29 deletions efiXplorer/efi_analysis_arm.cc
Original file line number Diff line number Diff line change
Expand Up @@ -22,37 +22,69 @@
#include "efi_ui.h"
#include "efi_utils.h"

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;
bool efi_analysis::efi_analyser_arm_t::set_enums_repr(ea_t ea, insn_t insn) {
// apply enum values from MACRO_EFI

void efi_analysis::efi_analyser_arm_t::fix_offsets() {
if (m_macro_efi_tid == BADADDR) {
return false;
}

if (insn.itype != ARM_mov && insn.itype != ARM_movl) {
return false;
}

if (insn.ops[0].type != o_reg) {
return false;
}

int index = 1;
if ((insn.ops[index].value & m_mask) == m_masked_value) {
op_enum(ea, index, m_macro_efi_tid, 0);
return true;
}

return false;
}

bool efi_analysis::efi_analyser_arm_t::set_offsets_repr(ea_t ea, insn_t insn) {
if (insn.itype == ARM_str) {
return false;
}

for (int i = 0; i < 2; i++) {
if (insn.ops[i].type == o_displ) {
op_num(ea, i);
}
}

return true;
}

void efi_analysis::efi_analyser_arm_t::set_operands_repr() {
insn_t insn;
for (auto faddr : m_funcs) {
func_t *f = get_func(faddr);

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);
}

// set offsets representation
set_offsets_repr(ea, insn);

// set enums representation
set_enums_repr(ea, insn);
}
}
}

void efi_analysis::efi_analyser_arm_t::initial_analysis() {
fix_offsets();
set_operands_repr();
for (auto idx = 0; idx < get_entry_qty(); idx++) {
uval_t ord = get_entry_ordinal(idx);
ea_t ep = get_entry(ord);
Expand Down Expand Up @@ -240,29 +272,29 @@ void efi_analysis::efi_analyser_arm_t::initial_gvars_detection() {
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)) {
image_handle_list_arm.push_back(addr);
if (!efi_utils::addr_in_vec(m_image_handle_list_arm, addr)) {
m_image_handle_list_arm.push_back(addr);
}
}
}
if (res.contains("st_list")) {
for (auto addr : res["st_list"]) {
if (!efi_utils::addr_in_vec(st_list_arm, addr)) {
st_list_arm.push_back(addr);
if (!efi_utils::addr_in_vec(m_st_list_arm, addr)) {
m_st_list_arm.push_back(addr);
}
}
}
if (res.contains("bs_list")) {
for (auto addr : res["bs_list"]) {
if (!efi_utils::addr_in_vec(bs_list_arm, addr)) {
bs_list_arm.push_back(addr);
if (!efi_utils::addr_in_vec(m_bs_list_arm, addr)) {
m_bs_list_arm.push_back(addr);
}
}
}
if (res.contains("rt_list")) {
for (auto addr : res["rt_list"]) {
if (!efi_utils::addr_in_vec(rt_list_arm, addr)) {
rt_list_arm.push_back(addr);
if (!efi_utils::addr_in_vec(m_rt_list_arm, addr)) {
m_rt_list_arm.push_back(addr);
}
}
}
Expand All @@ -282,17 +314,17 @@ void efi_analysis::efi_analyser_arm_t::initial_gvars_detection() {
if (bs != BADADDR) {
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);
if (!efi_utils::addr_in_vec(m_bs_list_arm, bs)) {
m_bs_list_arm.push_back(bs);
}
continue;
}
ea_t rt = get_table_addr(ea, 0x58);
if (rt != BADADDR) {
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);
if (!efi_utils::addr_in_vec(m_rt_list_arm, rt)) {
m_rt_list_arm.push_back(rt);
}
continue;
}
Expand All @@ -311,7 +343,7 @@ void efi_analysis::efi_analyser_arm_t::detect_services_all() {
#endif /* HEX_RAYS */

// analyse xrefs to gBS, gRT
for (auto bs : bs_list_arm) {
for (auto bs : m_bs_list_arm) {
auto xrefs = efi_utils::get_xrefs(bs);
for (auto ea : xrefs) {
auto s = get_service(ea, 1);
Expand All @@ -329,7 +361,7 @@ void efi_analysis::efi_analyser_arm_t::detect_services_all() {
}
}
}
for (auto rt : rt_list_arm) {
for (auto rt : m_rt_list_arm) {
auto xrefs = efi_utils::get_xrefs(rt);
for (auto ea : xrefs) {
auto s = get_service(ea, 2);
Expand Down
60 changes: 60 additions & 0 deletions efiXplorer/efi_analysis_x86.cc
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,18 @@ efi_analysis::efi_analyser_t::efi_analyser_t() {
for (auto g = m_guiddb.begin(); g != m_guiddb.end(); ++g) {
m_guiddb_map[g.value()] = g.key();
}

// set mask and masked value for MACRO_EFI enum value detection
if (m_arch == arch_file_type_t::x86_32) {
m_mask = 0xffffff00;
m_masked_value = 0x80000000;
} else {
// arch_file_type_t::x86_64
// arch_file_type_t::aarch64,
// rch_file_type_t::uefi -- as only 64-bit binaries are loaded
m_mask = 0xffffffffffffff00;
m_masked_value = 0x8000000000000000;
}
}

efi_analysis::efi_analyser_t::~efi_analyser_t() {
Expand Down Expand Up @@ -2231,6 +2243,48 @@ bool efi_analysis::efi_analyser_x86_t::find_double_get_variable_smm() {
return !m_double_get_variable_smm.empty();
}

//--------------------------------------------------------------------------
// apply enum values from MACRO_EFI
bool efi_analysis::efi_analyser_x86_t::set_enums_repr(ea_t ea, insn_t insn) {
if (m_macro_efi_tid == BADADDR) {
return false;
}

if (insn.itype != NN_mov || insn.ops[0].type != o_reg) {
return false;
}

int index = 1;
if ((insn.ops[index].value & m_mask) == m_masked_value) {
op_enum(ea, index, m_macro_efi_tid, 0);
return true;
}

return false;
}

//--------------------------------------------------------------------------
// set operands representation
void efi_analysis::efi_analyser_x86_t::set_operands_repr() {
insn_t insn;
for (auto faddr : m_funcs) {
func_t *f = get_func(faddr);

if (f == nullptr) {
continue;
}

ea_t ea = f->start_ea;
while (ea < f->end_ea) {
ea = next_head(ea, BADADDR);
decode_insn(&insn, ea);

// set enums representation
set_enums_repr(ea, insn);
}
}
}

//--------------------------------------------------------------------------
// analyse calls to GetVariable/SetVariable to extract variables information
bool efi_analysis::efi_analyser_t::analyse_variable_service(
Expand Down Expand Up @@ -2568,6 +2622,9 @@ bool efi_analysis::efi_analyse_main_x86_64() {
analyser.annotate_data_guids();
analyser.find_local_guids64();

// set operands representation
analyser.set_operands_repr();

if (g_args.disable_ui) {
analyser.m_ftype = g_args.module_type == module_type_t::pei
? analyser.m_ftype = ffs_file_type_t::pei
Expand Down Expand Up @@ -2676,6 +2733,9 @@ bool efi_analysis::efi_analyse_main_x86_32() {
// mark GUIDs
analyser.annotate_data_guids();

// set operands representation
analyser.set_operands_repr();

if (g_args.disable_ui) {
analyser.m_ftype = g_args.module_type == module_type_t::pei
? analyser.m_ftype = ffs_file_type_t::pei
Expand Down

0 comments on commit ad123af

Please sign in to comment.