Skip to content

Commit

Permalink
Merge pull request #95 from binarly-io/fix/loader
Browse files Browse the repository at this point in the history
update loader
  • Loading branch information
yeggor authored Nov 6, 2024
2 parents ef4d5e1 + 0bfdb68 commit dca0d07
Show file tree
Hide file tree
Showing 7 changed files with 89 additions and 95 deletions.
19 changes: 10 additions & 9 deletions efiXloader/efi_loader.cc
Original file line number Diff line number Diff line change
Expand Up @@ -115,32 +115,33 @@ void idaapi load_file(linput_t *li, ushort neflag, const char *fileformatname) {
}
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("uefi.til", ADDTIL_DEFAULT);
// we currently only handle 64-bit binaries with the EFI loader
add_til("uefi64.til", ADDTIL_DEFAULT);

msg("processing UEFI binaries:\n");
msg("[efiXloader] 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());
msg("[efiXloader] 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");
msg("[efiXloader] can not parse input firmware\n");
}

plugin_t *findpat = find_plugin("patfind", true);
if (findpat) {
msg("Running the Find functions plugin\n");
msg("[efiXloader] running the patfind plugin\n");
run_plugin(findpat, 0);
}
}
Expand All @@ -166,8 +167,8 @@ loader_t LDSC = {
load_file,
// create output file from the database.
// this function may be absent.
NULL,
nullptr,
// take care of a moved segment (fix up relocations, for example)
NULL,
NULL,
nullptr,
nullptr,
};
2 changes: 1 addition & 1 deletion efiXloader/efi_loader.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ class driver_chooser_t : public chooser_t {
void build_list(bool ok, std::vector<efiloader::File *> files) {
size_t n = 0;
for (auto file : files) {
drivers_names.push_back(qstring(file->qname));
drivers_names.push_back(qstring(file->module_name));
n++;
}
ok = true;
Expand Down
5 changes: 1 addition & 4 deletions efiXloader/pe.cc
Original file line number Diff line number Diff line change
Expand Up @@ -394,7 +394,7 @@ ea_t efiloader::PE::process_section_entry(ea_t next_ea) {

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());
msg("[efiXloader] processing: %s\n", segm_names[0].c_str());

segments.push_back(make_generic_segment(
seg_ea, seg_ea_end, section_name.c_str(), section_characteristics));
Expand All @@ -407,9 +407,6 @@ ea_t efiloader::PE::process_section_entry(ea_t 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<uint64_t>(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);
Expand Down
1 change: 0 additions & 1 deletion efiXloader/pe.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ class PE {
PE(linput_t *i_li, std::basic_string<char> 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;
Expand Down
6 changes: 1 addition & 5 deletions efiXloader/pe_manager.cc
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,9 @@

void efiloader::PeManager::process(linput_t *li, std::basic_string<char> fname,
int ord) {
// 32-bit modules and modules in the TE format will not be loaded
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");
}
}
120 changes: 58 additions & 62 deletions efiXloader/uefitool.cc
Original file line number Diff line number Diff line change
Expand Up @@ -19,22 +19,14 @@

#include "uefitool.h"

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

void efiloader::Uefitool::show_messages() {
for (size_t i = 0; i < messages.size(); i++) {
msg("[UEFITOOL PARSER] %s\n", messages[i].first.toLocal8Bit());
msg("[uefitool] %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
// if the given name is already in use, create a new one
qstring new_name = name;
std::string suf;
int index = 0;
Expand All @@ -50,8 +42,16 @@ void efiloader::Uefitool::get_image_guid(qstring &image_guid,
UString guid;
UModelIndex guid_index;
switch (model.subtype(model.parent(index))) {
case EFI_SECTION_COMPRESSION:
case EFI_SECTION_GUID_DEFINED:
if (model.type(model.parent(index)) == Types::File) {
guid_index = model.parent(index);
} else {
guid_index = model.parent(model.parent(index));
}
if (model.subtype(guid_index) == EFI_SECTION_COMPRESSION)
guid_index = model.parent(guid_index);
break;
case EFI_SECTION_COMPRESSION:
guid_index = model.parent(model.parent(index));
break;
default:
Expand All @@ -74,15 +74,15 @@ efiloader::Uefitool::parse_depex_section_body(const UModelIndex &index,

UByteArray body = model.body(index);

// Check data to be present
// check data to be present
if (body.size() < 2) { // 2 is a minimal sane value, i.e TRUE + END
return res;
}

const EFI_GUID *guid;
const UINT8 *current = (const UINT8 *)body.constData();

// Special cases of first opcode
// special cases of first opcode
switch (*current) {
case EFI_DEP_BEFORE:
if (body.size() != 2 * EFI_DEP_OPCODE_SIZE + sizeof(EFI_GUID)) {
Expand Down Expand Up @@ -115,7 +115,7 @@ efiloader::Uefitool::parse_depex_section_body(const UModelIndex &index,
break;
}

// Parse the rest of depex
// parse the rest of depex
while (current - (const UINT8 *)body.constData() < body.size()) {
switch (*current) {
case EFI_DEP_BEFORE: {
Expand All @@ -128,7 +128,7 @@ efiloader::Uefitool::parse_depex_section_body(const UModelIndex &index,
return res;
}
case EFI_DEP_PUSH:
// Check that the rest of depex has correct size
// check that the rest of depex has correct size
if ((UINT32)body.size() -
(UINT32)(current - (const UINT8 *)body.constData()) <=
EFI_DEP_OPCODE_SIZE + sizeof(EFI_GUID)) {
Expand All @@ -137,7 +137,7 @@ efiloader::Uefitool::parse_depex_section_body(const UModelIndex &index,
}
guid = (const EFI_GUID *)(current + EFI_DEP_OPCODE_SIZE);
parsed += UString("\nPUSH ") + guidToUString(readUnaligned(guid));
// Add protocol GUID to result vector
// add protocol GUID to result vector
res.push_back(
reinterpret_cast<char *>(guidToUString(readUnaligned(guid)).data));
current += EFI_DEP_OPCODE_SIZE + sizeof(EFI_GUID);
Expand Down Expand Up @@ -165,7 +165,7 @@ efiloader::Uefitool::parse_depex_section_body(const UModelIndex &index,
case EFI_DEP_END:
parsed += UString("\nEND");
current += EFI_DEP_OPCODE_SIZE;
// Check that END is the last opcode
// check that END is the last opcode
if (current - (const UINT8 *)body.constData() < body.size()) {
parsed.clear();
}
Expand All @@ -181,15 +181,15 @@ efiloader::Uefitool::parse_depex_section_body(const UModelIndex &index,

std::vector<std::string>
efiloader::Uefitool::parse_apriori_raw_section(const UModelIndex &index) {
// Adopted from FfsParser::parseDepexSectionBody
// adopted from FfsParser::parseDepexSectionBody
std::vector<std::string> res;

if (!index.isValid())
return res;

UByteArray body = model.body(index);

// Sanity check
// sanity check
if (body.size() % sizeof(EFI_GUID)) {
return res;
}
Expand Down Expand Up @@ -217,7 +217,7 @@ void efiloader::Uefitool::set_machine_type(UByteArray pe_body) {
}
if (*(uint32_t *)(data + _pe_header_off) == 0x4550) {
machine_type = *(uint16_t *)(data + _pe_header_off + 4);
machine_type_detected = true;
machine_type_initialised = true;
}
}

Expand All @@ -238,10 +238,15 @@ void efiloader::Uefitool::handle_raw_section(const UModelIndex &index) {
}
}

void efiloader::Uefitool::dump(const UModelIndex &index, uint8_t el_type,
inline void get_module_name(qstring &module_name, efiloader::File *file) {
utf16_utf8(&module_name,
reinterpret_cast<const wchar16_t *>(file->uname.data()));
}

void efiloader::Uefitool::dump(const UModelIndex &index, int i,
efiloader::File *file) {
qstring module_name("");
qstring guid("");
qstring name;
qstring guid;

switch (model.subtype(index)) {
case EFI_SECTION_RAW:
Expand All @@ -250,42 +255,26 @@ void efiloader::Uefitool::dump(const UModelIndex &index, uint8_t el_type,
case EFI_SECTION_TE:
file->is_te = true;
file->ubytes = model.body(index);
file->module_kind = get_kind(index);
break;
case EFI_SECTION_PE32:
file->is_pe = true;
file->ubytes = model.body(index);
if (!machine_type_detected) {
file->module_kind = get_kind(index);
if (!machine_type_initialised) {
set_machine_type(model.body(index));
}
break;
case EFI_SECTION_USER_INTERFACE:
file->has_ui = true;
if (file->is_pe || file->is_te) {
file->uname = model.body(index);
utf16_utf8(&module_name,
reinterpret_cast<const wchar16_t *>(file->uname.data()));
if (module_name.size()) {
// save image to the images_guids
get_image_guid(guid, index);
if (images_guids[guid.c_str()]
.is_null()) { // check if GUID already exists
get_unique_name(module_name);
images_guids[guid.c_str()] = {{"name", module_name.c_str()},
{"kind", get_kind(index)}};
file->qname.swap(module_name);
file->write();
files.push_back(file);
}
}
}
file->uname = model.body(index);
break;
case EFI_SECTION_COMPRESSION:
case EFI_SECTION_GUID_DEFINED:
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;
Expand All @@ -298,35 +287,43 @@ void efiloader::Uefitool::dump(const UModelIndex &index, uint8_t el_type,
case EFI_SECTION_VERSION:
break;
default:
// if there is no UI section, then the image name is GUID
if ((file->is_pe || file->is_te) && !file->has_ui) {
get_image_guid(module_name, index);
file->qname.swap(module_name);
file->write();
files.push_back(file);
if (module_name.size()) {
// save image to the images_guids
images_guids[module_name.c_str()] = {{"name", module_name.c_str()},
{"kind", get_kind(index)}};
}
}
break;
}

return dump(index);
// update file
if (file->is_pe || file->is_te) {
get_image_guid(guid, index);
if (file->has_ui) {
// get module name from UI section
get_module_name(name, file);
} else {
// use module GUID as module name
name = guid;
}
file->module_name.swap(name);
file->module_guid.swap(guid);
}

dump(index);
}

void efiloader::Uefitool::dump(const UModelIndex &index) {
USTATUS err;
msg("[UEFITOOL PARSER] file (%s, %s)\n",
itemTypeToUString(model.type(index)).data,
itemSubtypeToUString(model.type(index), model.subtype(index)).data);
msg("[UEFITOOL PARSER] number of items: %#x\n", model.rowCount(index));

if (is_file_index(index)) {
efiloader::File *file = new File;
for (int i = 0; i < model.rowCount(index); i++) {
dump(index.child(i, 0), i, file);
}

// append file
if (file->is_ok()) {
all_modules[file->module_guid.c_str()] = {
{"name", file->module_name.c_str()},
{"kind", file->module_kind.c_str()}};
file->write();
files.push_back(file);
}
} else {
for (int i = 0; i < model.rowCount(index); i++) {
dump(index.child(i, 0));
Expand Down Expand Up @@ -363,7 +360,6 @@ void efiloader::Uefitool::get_apriori(UModelIndex index, std::string key) {

void efiloader::Uefitool::dump_jsons() {
// dump JSON with DEPEX and GUIDs information for each image

std::filesystem::path out;
out /= get_path(PATH_TYPE_IDB);
out.replace_extension(".deps.json");
Expand All @@ -372,5 +368,5 @@ void efiloader::Uefitool::dump_jsons() {

out.replace_extension("").replace_extension(".images.json");
std::ofstream out_guids(out);
out_guids << std::setw(2) << images_guids << std::endl;
out_guids << std::setw(2) << all_modules << std::endl;
}
Loading

0 comments on commit dca0d07

Please sign in to comment.