mirror of
https://github.com/momo5502/emulator.git
synced 2026-01-18 03:13:55 +00:00
Simplify import watching (#524)
This commit is contained in:
@@ -209,54 +209,6 @@ namespace
|
||||
}
|
||||
}
|
||||
|
||||
bool is_thread_alive(const analysis_context& c, const uint32_t thread_id)
|
||||
{
|
||||
for (const auto& t : c.win_emu->process.threads | std::views::values)
|
||||
{
|
||||
if (t.id == thread_id)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void update_import_access(analysis_context& c, const uint64_t address)
|
||||
{
|
||||
if (c.accessed_imports.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& t = c.win_emu->current_thread();
|
||||
for (auto entry = c.accessed_imports.begin(); entry != c.accessed_imports.end();)
|
||||
{
|
||||
auto& a = *entry;
|
||||
const auto is_same_thread = t.id == a.thread_id;
|
||||
|
||||
if (is_same_thread && address == a.address)
|
||||
{
|
||||
entry = c.accessed_imports.erase(entry);
|
||||
continue;
|
||||
}
|
||||
|
||||
constexpr auto inst_delay = 100u;
|
||||
const auto execution_delay_reached = is_same_thread && a.access_inst_count + inst_delay <= t.executed_instructions;
|
||||
|
||||
if (!execution_delay_reached && is_thread_alive(c, a.thread_id))
|
||||
{
|
||||
++entry;
|
||||
continue;
|
||||
}
|
||||
|
||||
c.win_emu->log.print(color::green, "Import read access without execution: %s (%s) at 0x%" PRIx64 " (%s)\n",
|
||||
a.import_name.c_str(), a.import_module.c_str(), a.access_rip, a.accessor_module.c_str());
|
||||
|
||||
entry = c.accessed_imports.erase(entry);
|
||||
}
|
||||
}
|
||||
|
||||
bool is_return(const disassembler& d, const emulator& emu, const uint64_t address)
|
||||
{
|
||||
std::array<uint8_t, MAX_INSTRUCTION_BYTES> instruction_bytes{};
|
||||
@@ -297,7 +249,6 @@ namespace
|
||||
void handle_instruction(analysis_context& c, const uint64_t address)
|
||||
{
|
||||
auto& win_emu = *c.win_emu;
|
||||
update_import_access(c, address);
|
||||
|
||||
#if defined(OS_EMSCRIPTEN) && !defined(MOMO_EMSCRIPTEN_SUPPORT_NODEJS)
|
||||
if ((win_emu.get_executed_instructions() % 0x20000) == 0)
|
||||
@@ -501,52 +452,33 @@ namespace
|
||||
auto min = std::numeric_limits<uint64_t>::max();
|
||||
auto max = std::numeric_limits<uint64_t>::min();
|
||||
|
||||
for (const auto& imports : import_list | std::views::values)
|
||||
for (const auto& import_thunk : import_list | std::views::keys)
|
||||
{
|
||||
for (const auto& import : imports)
|
||||
{
|
||||
min = std::min(import.address, min);
|
||||
max = std::max(import.address, max);
|
||||
}
|
||||
min = std::min(import_thunk, min);
|
||||
max = std::max(import_thunk, max);
|
||||
}
|
||||
|
||||
c.win_emu->emu().hook_memory_read(min, max - min, [&c](const uint64_t address, const void*, size_t) {
|
||||
const auto& import_list = c.win_emu->mod_manager.executable->imports;
|
||||
const auto& watched_module = *c.win_emu->mod_manager.executable;
|
||||
const auto& accessor_module = *c.win_emu->mod_manager.executable;
|
||||
|
||||
const auto rip = c.win_emu->emu().read_instruction_pointer();
|
||||
if (!c.win_emu->mod_manager.executable->contains(rip))
|
||||
|
||||
if (!accessor_module.contains(rip))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (const auto& [module_name, imports] : import_list)
|
||||
const auto sym = watched_module.imports.find(address);
|
||||
if (sym == watched_module.imports.end())
|
||||
{
|
||||
for (const auto& import : imports)
|
||||
{
|
||||
if (address != import.address)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
accessed_import access{};
|
||||
|
||||
access.address = c.win_emu->emu().read_memory<uint64_t>(address);
|
||||
|
||||
access.access_rip = c.win_emu->emu().read_instruction_pointer();
|
||||
access.accessor_module = c.win_emu->mod_manager.find_name(access.access_rip);
|
||||
|
||||
access.import_name = import.name;
|
||||
access.import_module = module_name;
|
||||
|
||||
const auto& t = c.win_emu->current_thread();
|
||||
access.thread_id = t.id;
|
||||
access.access_inst_count = t.executed_instructions;
|
||||
|
||||
c.accessed_imports.push_back(std::move(access));
|
||||
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& module_name = watched_module.imported_modules[sym->second.module_index];
|
||||
|
||||
c.win_emu->log.print(color::green, "Import read access: %s (%s) at 0x%" PRIx64 " (%s)\n", sym->second.name.c_str(),
|
||||
module_name.c_str(), rip, accessor_module.name.c_str());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,17 +22,6 @@ struct analysis_settings
|
||||
string_set ignored_functions{};
|
||||
};
|
||||
|
||||
struct accessed_import
|
||||
{
|
||||
uint64_t address{};
|
||||
uint32_t thread_id{};
|
||||
uint64_t access_rip{};
|
||||
uint64_t access_inst_count{};
|
||||
std::string accessor_module{};
|
||||
std::string import_name{};
|
||||
std::string import_module{};
|
||||
};
|
||||
|
||||
struct analysis_context
|
||||
{
|
||||
const analysis_settings* settings{};
|
||||
@@ -43,7 +32,6 @@ struct analysis_context
|
||||
|
||||
disassembler d{};
|
||||
std::unordered_map<uint32_t, uint64_t> instructions{};
|
||||
std::vector<accessed_import> accessed_imports{};
|
||||
std::set<uint64_t> rdtsc_cache{};
|
||||
std::set<uint64_t> rdtscp_cache{};
|
||||
std::set<std::pair<uint64_t, uint32_t>> cpuid_cache{};
|
||||
|
||||
@@ -12,11 +12,12 @@ struct exported_symbol
|
||||
struct imported_symbol
|
||||
{
|
||||
std::string name{};
|
||||
uint64_t address{};
|
||||
size_t module_index{};
|
||||
};
|
||||
|
||||
using exported_symbols = std::vector<exported_symbol>;
|
||||
using imported_symbols = std::map<std::string, std::vector<imported_symbol>>;
|
||||
using imported_symbols = std::unordered_map<uint64_t, imported_symbol>;
|
||||
using imported_module_list = std::vector<std::string>;
|
||||
using address_name_mapping = std::map<uint64_t, std::string>;
|
||||
|
||||
struct mapped_section
|
||||
@@ -36,6 +37,7 @@ struct mapped_module
|
||||
|
||||
exported_symbols exports{};
|
||||
imported_symbols imports{};
|
||||
imported_module_list imported_modules{};
|
||||
address_name_mapping address_names{};
|
||||
|
||||
std::vector<mapped_section> sections{};
|
||||
|
||||
@@ -48,8 +48,8 @@ namespace
|
||||
break;
|
||||
}
|
||||
|
||||
const auto module_name = buffer.as_string(descriptor.Name);
|
||||
auto& imports = binary.imports[module_name];
|
||||
const auto module_index = binary.imported_modules.size();
|
||||
binary.imported_modules.push_back(buffer.as_string(descriptor.Name));
|
||||
|
||||
auto original_thunk_data = buffer.as<IMAGE_THUNK_DATA64>(descriptor.FirstThunk);
|
||||
if (descriptor.OriginalFirstThunk)
|
||||
@@ -65,11 +65,12 @@ namespace
|
||||
break;
|
||||
}
|
||||
|
||||
imported_symbol sym{};
|
||||
|
||||
static_assert(sizeof(IMAGE_THUNK_DATA64) == sizeof(uint64_t));
|
||||
const auto thunk_rva = descriptor.FirstThunk + sizeof(IMAGE_THUNK_DATA64) * j;
|
||||
sym.address = thunk_rva + binary.image_base;
|
||||
const auto thunk_address = thunk_rva + binary.image_base;
|
||||
|
||||
auto& sym = binary.imports[thunk_address];
|
||||
sym.module_index = module_index;
|
||||
|
||||
if (IMAGE_SNAP_BY_ORDINAL64(original_thunk.u1.Ordinal))
|
||||
{
|
||||
@@ -80,8 +81,6 @@ namespace
|
||||
sym.name =
|
||||
buffer.as_string(static_cast<size_t>(original_thunk.u1.AddressOfData + offsetof(IMAGE_IMPORT_BY_NAME, Name)));
|
||||
}
|
||||
|
||||
imports.push_back(std::move(sym));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user