Skip to content

Commit

Permalink
update loader:
Browse files Browse the repository at this point in the history
- handle cases when module body is compressed
- handle cases when UI section is located before PE
- minor fixes
  • Loading branch information
yeggor committed Nov 5, 2024
1 parent ef4d5e1 commit 0d84855
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 68 deletions.
3 changes: 2 additions & 1 deletion efiXloader/efi_loader.cc
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,8 @@ void idaapi load_file(linput_t *li, ushort neflag, const char *fileformatname) {
msg("[efiXloader] machine type: %04x\n", uefiParser.machine_type);
efiloader::PeManager peManager(uefiParser.machine_type);

add_til("uefi.til", ADDTIL_DEFAULT);
// add_til("uefi.til", ADDTIL_DEFAULT);
// we currently only handle 64-bit binaries with the EFI loader
add_til("uefi64.til", ADDTIL_DEFAULT);

msg("processing UEFI binaries:\n");
Expand Down
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
112 changes: 58 additions & 54 deletions efiXloader/uefitool.cc
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
#include "uefitool.h"

void efiloader::File::print() {
msg("[UEFITOOL PARSER] file ( %s ) \n", qname.c_str());
msg("[UEFITOOL PARSER] file ( %s ) \n", module_name.c_str());
for (int i = 0; i < 0x10; i++) {
msg("%02X ", ubytes[i]);
}
Expand All @@ -34,7 +34,7 @@ void efiloader::Uefitool::show_messages() {
}

void efiloader::Uefitool::get_unique_name(qstring &name) {
// If the given name is already in use, create a new one
// if the given name is already in use, create a new one
qstring new_name = name;
std::string suf;
int index = 0;
Expand All @@ -50,8 +50,16 @@ void efiloader::Uefitool::get_image_guid(qstring &image_guid,
UString guid;
UModelIndex guid_index;
switch (model.subtype(model.parent(index))) {
case EFI_SECTION_COMPRESSION:
case EFI_SECTION_GUID_DEFINED:
if (model.type(model.parent(index)) == Types::File) {
guid_index = model.parent(index);
} else {
guid_index = model.parent(model.parent(index));
}
if (model.subtype(guid_index) == EFI_SECTION_COMPRESSION)
guid_index = model.parent(guid_index);
break;
case EFI_SECTION_COMPRESSION:
guid_index = model.parent(model.parent(index));
break;
default:
Expand All @@ -74,15 +82,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 +123,7 @@ efiloader::Uefitool::parse_depex_section_body(const UModelIndex &index,
break;
}

// Parse the rest of depex
// parse the rest of depex
while (current - (const UINT8 *)body.constData() < body.size()) {
switch (*current) {
case EFI_DEP_BEFORE: {
Expand All @@ -128,7 +136,7 @@ efiloader::Uefitool::parse_depex_section_body(const UModelIndex &index,
return res;
}
case EFI_DEP_PUSH:
// Check that the rest of depex has correct size
// check that the rest of depex has correct size
if ((UINT32)body.size() -
(UINT32)(current - (const UINT8 *)body.constData()) <=
EFI_DEP_OPCODE_SIZE + sizeof(EFI_GUID)) {
Expand All @@ -137,7 +145,7 @@ efiloader::Uefitool::parse_depex_section_body(const UModelIndex &index,
}
guid = (const EFI_GUID *)(current + EFI_DEP_OPCODE_SIZE);
parsed += UString("\nPUSH ") + guidToUString(readUnaligned(guid));
// Add protocol GUID to result vector
// add protocol GUID to result vector
res.push_back(
reinterpret_cast<char *>(guidToUString(readUnaligned(guid)).data));
current += EFI_DEP_OPCODE_SIZE + sizeof(EFI_GUID);
Expand Down Expand Up @@ -165,7 +173,7 @@ efiloader::Uefitool::parse_depex_section_body(const UModelIndex &index,
case EFI_DEP_END:
parsed += UString("\nEND");
current += EFI_DEP_OPCODE_SIZE;
// Check that END is the last opcode
// check that END is the last opcode
if (current - (const UINT8 *)body.constData() < body.size()) {
parsed.clear();
}
Expand All @@ -181,15 +189,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 +225,7 @@ void efiloader::Uefitool::set_machine_type(UByteArray pe_body) {
}
if (*(uint32_t *)(data + _pe_header_off) == 0x4550) {
machine_type = *(uint16_t *)(data + _pe_header_off + 4);
machine_type_detected = true;
machine_type_initialised = true;
}
}

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

void efiloader::Uefitool::dump(const UModelIndex &index, uint8_t el_type,
inline void get_module_name(qstring &module_name, efiloader::File *file) {
utf16_utf8(&module_name,
reinterpret_cast<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 +263,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 +295,43 @@ void efiloader::Uefitool::dump(const UModelIndex &index, uint8_t el_type,
case EFI_SECTION_VERSION:
break;
default:
// if there is no UI section, then the image name is GUID
if ((file->is_pe || file->is_te) && !file->has_ui) {
get_image_guid(module_name, index);
file->qname.swap(module_name);
file->write();
files.push_back(file);
if (module_name.size()) {
// save image to the images_guids
images_guids[module_name.c_str()] = {{"name", module_name.c_str()},
{"kind", get_kind(index)}};
}
}
break;
}

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

dump(index);
}

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

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

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

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

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

out.replace_extension("").replace_extension(".images.json");
std::ofstream out_guids(out);
out_guids << std::setw(2) << images_guids << std::endl;
out_guids << std::setw(2) << all_modules << std::endl;
}
30 changes: 18 additions & 12 deletions efiXloader/uefitool.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ class File {
public:
File() {}
void set_data(char *data_in, uint32_t size_in) {
qname.qclear();
module_name.qclear();
bytes.resize(size_in);
memcpy(&bytes[0], data_in, size_in);
}
Expand All @@ -79,8 +79,9 @@ class File {
#else
mkdir(images_path.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
#endif
if (!qname.empty()) {
qstring image_path = images_path + qstring("/") + qstring(qname.c_str());
if (!module_name.empty()) {
qstring image_path =
images_path + qstring("/") + qstring(module_name.c_str());
std::ofstream file;
file.open(image_path.c_str(), std::ios::out | std::ios::binary);
file.write(ubytes.constData(), ubytes.size());
Expand All @@ -89,15 +90,21 @@ class File {
}
}
void print();
bool is_ok() {
return !module_name.empty() && !module_guid.empty() && !module_kind.empty();
}

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;
qstring module_guid;
qstring module_kind;
qstring module_name;
bool is_pe = false;
bool is_te = false;
bool has_ui = false;
Expand All @@ -120,7 +127,7 @@ class Uefitool {
bool messages_occurs() { return !messages.empty(); }
void dump();
void dump(const UModelIndex &index);
void dump(const UModelIndex &index, uint8_t el_type, File *pe_file);
void dump(const UModelIndex &index, int i, File *pe_file);
void handle_raw_section(const UModelIndex &index);
bool is_pe_index(const UModelIndex &index) {
return model.rowCount(index) == 4;
Expand All @@ -136,24 +143,23 @@ class Uefitool {
void get_deps(UModelIndex index, std::string key);
void get_apriori(UModelIndex index, std::string key);
void dump_jsons();
void set_machine_type(UByteArray pe_body);

// DEPEX information for each image
json all_deps;
json all_modules;
std::vector<efiloader::File *> files;
std::set<qstring> unique_names;

json images_guids;
TreeModel model;
const char *buffer;
uint32_t buffer_size;
std::vector<std::pair<UString, UModelIndex>> messages;
std::set<qstring> unique_names;
std::vector<efiloader::File *> files;
USTATUS err;
void set_machine_type(UByteArray pe_body);
uint16_t machine_type = 0xffff;
bool machine_type_detected = false;
bool machine_type_initialised = false;

private:
std::string get_kind(const UModelIndex &index) {
qstring get_kind(const UModelIndex &index) {
return fileTypeToUString(model.subtype(index.parent())).toLocal8Bit();
}
};
Expand Down

0 comments on commit 0d84855

Please sign in to comment.