Skip to content

Commit

Permalink
Merge pull request #133 from azure9:main
Browse files Browse the repository at this point in the history
PiperOrigin-RevId: 684067469
Change-Id: I4f7eab5a1aed44c366811393518701811c4de4b5
  • Loading branch information
copybara-github committed Oct 9, 2024
2 parents dd6f724 + 459e505 commit 624377d
Show file tree
Hide file tree
Showing 5 changed files with 184 additions and 18 deletions.
10 changes: 10 additions & 0 deletions ida/digest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "third_party/zynamics/binexport/ida/begin_idasdk.inc" // NOLINT
#include <nalt.hpp> // NOLINT
#include <netnode.hpp> // NOLINT
#include <idp.hpp> // NOLINT
#include "third_party/zynamics/binexport/ida/end_idasdk.inc" // NOLINT
// clang-format on

Expand All @@ -32,8 +33,12 @@ absl::StatusOr<std::string> GetInputFileSha256() {
std::string hash(kNumSha256Bytes, '\0');
auto* hash_uchar = reinterpret_cast<uchar*>(&hash[0]);
if (!retrieve_input_file_sha256(hash_uchar) &&
#if IDP_INTERFACE_VERSION >= 900
(netnode_supval(0, RIDX_SHA256, hash_uchar, kNumSha256Bytes, 'S') !=
#else
// b/186782665: IDA 7.5 and lower use the root_node instead.
(root_node.supval(RIDX_SHA256, hash_uchar, kNumSha256Bytes) !=
#endif
kNumSha256Bytes)) {
return absl::InternalError("Failed to load SHA256 hash of input file");
}
Expand All @@ -45,8 +50,13 @@ absl::StatusOr<std::string> GetInputFileMd5() {
std::string hash(kNumMd5Bytes, '\0');
auto* hash_uchar = reinterpret_cast<uchar*>(&hash[0]);
if (!retrieve_input_file_md5(hash_uchar) &&
#if IDP_INTERFACE_VERSION >= 900
(netnode_supval(0, RIDX_MD5, hash_uchar, kNumMd5Bytes, 'S') !=
kNumMd5Bytes)) {
#else
// b/186782665: IDA 7.5 and lower use the root_node instead.
(root_node.supval(RIDX_MD5, hash_uchar, kNumMd5Bytes) != kNumMd5Bytes)) {
#endif
return absl::InternalError("Failed to load MD5 hash of input file");
}
return absl::AsciiStrToLower(absl::BytesToHexString(hash));
Expand Down
8 changes: 6 additions & 2 deletions ida/flow_analysis.cc
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,19 @@
#include "third_party/zynamics/binexport/ida/begin_idasdk.inc" // NOLINT
#include <idp.hpp> // NOLINT
#include <allins.hpp> // NOLINT
#include <enum.hpp> // NOLINT
#include <frame.hpp> // NOLINT
#include <ida.hpp> // NOLINT
#include <lines.hpp> // NOLINT
#include <name.hpp> // NOLINT
#include <segment.hpp> // NOLINT
#include <struct.hpp> // NOLINT
#include <typeinf.hpp> // NOLINT
#include <ua.hpp> // NOLINT
#if IDP_INTERFACE_VERSION >= 900
#define ph PH
#else
#include <enum.hpp> // NOLINT
#include <struct.hpp> // NOLINT
#endif
#include "third_party/zynamics/binexport/ida/end_idasdk.inc" // NOLINT
// clang-format on

Expand Down
3 changes: 3 additions & 0 deletions ida/main_plugin.cc
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@
#include <idp.hpp> // NOLINT
#include <kernwin.hpp> // NOLINT
#include <loader.hpp> // NOLINT
#if IDP_INTERFACE_VERSION >= 900
#define ph PH
#endif
#include "third_party/zynamics/binexport/ida/end_idasdk.inc" // NOLINT
// clang-format on

Expand Down
176 changes: 160 additions & 16 deletions ida/names.cc
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

#include "third_party/zynamics/binexport/ida/names.h"

#include <algorithm>
#include <cinttypes>
#include <cstddef>
#include <cstring>
Expand All @@ -26,17 +27,21 @@
#include "third_party/zynamics/binexport/ida/begin_idasdk.inc" // NOLINT
#include <idp.hpp> // NOLINT
#include <allins.hpp> // NOLINT
#include <enum.hpp> // NOLINT
#include <frame.hpp> // NOLINT
#include <ida.hpp> // NOLINT
#include <lines.hpp> // NOLINT
#include <name.hpp> // NOLINT
#include <nalt.hpp> // NOLINT
#include <netnode.hpp> // NOLINT
#include <segment.hpp> // NOLINT
#include <struct.hpp> // NOLINT
#include <typeinf.hpp> // NOLINT
#include <ua.hpp> // NOLINT
#if IDP_INTERFACE_VERSION >= 900
#define ph PH
#else
#include <enum.hpp> // NOLINT
#include <struct.hpp> // NOLINT
#endif
#include "third_party/zynamics/binexport/ida/end_idasdk.inc" // NOLINT
// clang-format on

Expand Down Expand Up @@ -136,8 +141,12 @@ absl::optional<std::string> GetArchitectureName() {
std::string GetModuleName() {
std::string path(QMAXPATH, '\0');
if (get_input_file_path(&path[0], QMAXPATH) == 0) {
#if IDP_INTERFACE_VERSION >= 900
netnode_valstr(0, &path[0], QMAXPATH);
#else
// b/186782665: IDA 7.5 and lower use the root_node instead.
root_node.valstr(&path[0], QMAXPATH);
#endif
}
path.resize(std::strlen(path.data()));
return Basename(path);
Expand Down Expand Up @@ -274,6 +283,62 @@ std::string GetVariableName(const insn_t& instruction, uint8_t operand_num) {
return "";
}

#if IDP_INTERFACE_VERSION >= 900
func_t* function = get_func(instruction.ea);
if (!function) {
return "";
}

tinfo_t frame;
if (!get_func_frame(&frame, function)) {
return "";
}

ea_t offset = calc_stkvar_struc_offset(function, instruction, operand_num);

udt_type_data_t udt_data;
if (!frame.get_udt_details(&udt_data)) {
return "";
}
// Find the base member (variable or structure)
const udm_t* base_member = nullptr;
for (const auto& member : udt_data) {
if (member.offset / 8 <= offset &&
(member.offset / 8 + member.size / 8) > offset) {
base_member = &member;
break;
}
}

if (base_member) {
std::string result = ToString(base_member->name);

if (ea_t member_offset = offset - (base_member->offset / 8);
member_offset > 0) {
// Handle nested structures
if (base_member->type.is_struct()) {
udt_type_data_t nested_udt_data;
if (base_member->type.get_udt_details(&nested_udt_data)) {
for (const auto& nested_member : nested_udt_data) {
if (nested_member.offset / 8 == member_offset) {
return absl::StrCat(result, ".", ToString(nested_member.name));
}
}
}
}

// If it's not a nested structure or we couldn't find the exact member,
// append the offset
absl::StrAppend(&result, "+", IdaHexify(member_offset));
}

return result;
}

// If we couldn't find a matching member, return a generic name with the
// offset
return absl::StrCat("var_", IdaHexify(offset));
#else
const member_t* stack_variable =
get_stkvar(0, instruction, instruction.ops[operand_num],
instruction.ops[operand_num].addr);
Expand Down Expand Up @@ -338,27 +403,59 @@ std::string GetVariableName(const insn_t& instruction, uint8_t operand_num) {
return result;
}
return "";
#endif
}

std::string GetGlobalStructureName(Address address, Address instance_address,
uint8_t operand_num) {
std::string instance_name;

tid_t id[MAXSTRUCPATH];
memset(id, 0, sizeof(id));
adiff_t disp = 0;
adiff_t delta = 0;

int num_structs = get_struct_operand(&disp, &delta, id, address, operand_num);
#if IDP_INTERFACE_VERSION >= 900
if (num_structs > 0) {
tinfo_t tif;
if (get_tinfo(&tif, id[0])) {
qstring ida_name;
if (get_name(&ida_name, instance_address - disp) ||
tif.get_type_name(&ida_name)) {
instance_name = ToString(ida_name);
}

udt_type_data_t udt_data;
if (tif.get_udt_details(&udt_data)) {
for (const udm_t& udm : udt_data) {
if (udm.offset < disp) {
continue;
}
absl::StrAppend(&instance_name, ".", ToString(udm.name));
disp -= udm.size;

if (!udm.type.is_struct()) {
break;
}
tif = udm.type;
if (!tif.get_udt_details(&udt_data)) {
break;
}
}
}
}
}
#else
if (num_structs > 0) {
// Special case for the first index - this may be an instance name instead
// of a type name.
const struc_t* structure = get_struc(id[0]);
if (structure) {
// First try to get a global variable instance name.
// Second, fall back to just the structure type name.
qstring ida_name;
if (get_name(&ida_name, instance_address - disp) ||
get_struc_name(&ida_name, id[0])) {
if (qstring ida_name; get_name(&ida_name, instance_address - disp) ||
get_struc_name(&ida_name, id[0])) {
instance_name = ToString(ida_name);
}
}
Expand All @@ -373,6 +470,7 @@ std::string GetGlobalStructureName(Address address, Address instance_address,
structure = get_sptr(member);
}
}
#endif
return instance_name;
}

Expand Down Expand Up @@ -471,23 +569,37 @@ void GetRegularComments(Address address, Comments* comments) {
void GetEnumComments(Address address,
Comments* comments) { // @bug: there is an get_enum_cmt
// function in IDA as well!
#if IDP_INTERFACE_VERSION >= 900
if (is_enum0(get_flags(address)) || is_enum1(get_flags(address))) {
tinfo_t tif;
if (get_tinfo(&tif, address) && tif.is_enum()) {
qstring enum_name;
if (tif.get_type_name(&enum_name)) {
comments->emplace_back(address, is_enum0(get_flags(address)) ? 0 : 1,
CallGraph::CacheString(ToString(enum_name)),
Comment::ENUM, /*repeatable=*/false);
}
}
}
#else
uint8_t serial;
if (is_enum0(get_flags(address))) {
int id = get_enum_id(&serial, address, 0);
if (id != BADNODE) {
comments->emplace_back(
address, 0, CallGraph::CacheString(ToString(get_enum_name(id))),
Comment::ENUM, false);
Comment::ENUM, /*repeatable=*/false);
}
}
if (is_enum1(get_flags(address))) {
int id = get_enum_id(&serial, address, 1);
if (id != BADNODE) {
comments->emplace_back(
address, 1, CallGraph::CacheString(ToString(get_enum_name(id))),
Comment::ENUM, false);
Comment::ENUM, /*repeatable=*/false);
}
}
#endif
}

bool GetLineComment(Address address, int n, std::string* output) {
Expand Down Expand Up @@ -578,18 +690,49 @@ struct FunctionCache {
if (!function) {
return;
}
#if IDP_INTERFACE_VERSION >= 900
tinfo_t frame_tif;
if (!get_func_frame(&frame_tif, function)) {
return;
}

udt_type_data_t udt_data;
if (!frame_tif.get_udt_details(&udt_data)) {
return;
}

// IDA sometimes returns excessively large offsets (billions) we must
// prevent looping forever in those cases
size_t last_success = 0;
const size_t max_offset =
std::min(frame_tif.get_size(),
size_t(64 * 1024 /* Max stack size for analysis */));
for (const udm_t& member : udt_data) {
if (member.offset >= max_offset || last_success - member.offset >= 1024) {
break;
}
if (member.is_special_member()) {
continue;
}

if (!member.name.empty()) {
local_vars[member.offset] = ToString(member.name);
last_success = member.offset + member.size;
}
}
#else
struc_t* frame = get_frame(function);
if (!frame) {
return;
}

// @bug: IDA sometimes returns excessively large offsets (billions)
// we must prevent looping forever in those cases
size_t lastSuccess = 0;
const size_t maxOffset =
std::min(static_cast<size_t>(get_max_offset(frame)),
static_cast<size_t>(1024 * 64));
for (size_t i = 0; i < maxOffset && lastSuccess - i < 1024;) {
// IDA sometimes returns excessively large offsets (billions) we must
// prevent looping forever in those cases
size_t last_success = 0;
const size_t max_offset = std::min(
static_cast<size_t>(get_max_offset(frame)),
static_cast<size_t>(64 * 1024 /* Max stack size for analysis */));
for (size_t i = 0; i < max_offset && last_success - i < 1024;) {
const member_t* member = get_member(frame, i);
if (!member || is_special_member(member->id)) {
++i;
Expand All @@ -600,14 +743,15 @@ struct FunctionCache {
qstring ida_name(get_member_name(member->id));
if (!ida_name.empty()) {
i += std::max(static_cast<asize_t>(1), get_member_size(member));
lastSuccess = i;
last_success = i;
continue;
}

local_vars[offset] = ToString(ida_name);
i += std::max(static_cast<asize_t>(1), get_member_size(member));
lastSuccess = i;
last_success = i;
}
#endif
}

func_t* function;
Expand Down
5 changes: 5 additions & 0 deletions ida/ui.cc
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@

// clang-format off
#include "third_party/zynamics/binexport/ida/begin_idasdk.inc" // NOLINT
#include <idp.hpp> // NOLINT
#include <expr.hpp> // NOLINT
#include <kernwin.hpp> // NOLINT
#include "third_party/zynamics/binexport/ida/end_idasdk.inc" // NOLINT
Expand Down Expand Up @@ -62,7 +63,11 @@ void WaitBox::ReplaceText(absl::string_view message) const {
ReplaceWaitBoxRequest(const WaitBox& wait_box, absl::string_view message)
: wait_box(wait_box), message(message) {}

#if IDP_INTERFACE_VERSION >= 900
ssize_t idaapi execute() override {
#else
int idaapi execute() override {
#endif
replace_wait_box("%s",
FormatMessage(message, wait_box.cancellable_).c_str());
return 0;
Expand Down

0 comments on commit 624377d

Please sign in to comment.