void gum_module_enumerate_ranges (const gchar * module_name, GumPageProtection prot, GumFoundRangeFunc func, gpointer user_data) { HANDLE this_process = GetCurrentProcess (); HMODULE module; MODULEINFO mi; guint8 * cur_base_address, * end_address; module = get_module_handle_utf8 (module_name); if (module == NULL) return; if (!GetModuleInformation (this_process, module, &mi, sizeof (mi))) return; cur_base_address = (guint8 *) mi.lpBaseOfDll; end_address = (guint8 *) mi.lpBaseOfDll + mi.SizeOfImage; do { MEMORY_BASIC_INFORMATION mbi; SIZE_T ret; ret = VirtualQuery (cur_base_address, &mbi, sizeof (mbi)); g_assert (ret != 0); if (mbi.Protect != 0) { GumPageProtection cur_prot; cur_prot = gum_page_protection_from_windows (mbi.Protect); if ((cur_prot & prot) == prot) { GumMemoryRange range; GumRangeDetails details; range.base_address = GUM_ADDRESS (cur_base_address); range.size = mbi.RegionSize; details.range = ⦥ details.prot = cur_prot; details.file = NULL; /* TODO */ if (!func (&details, user_data)) return; } } cur_base_address += mbi.RegionSize; } while (cur_base_address < end_address); }
static gboolean gum_memory_get_protection (GumAddress address, gsize len, GumPageProtection * prot) { gboolean success = FALSE; MEMORY_BASIC_INFORMATION mbi; if (prot == NULL) { GumPageProtection ignored_prot; return gum_memory_get_protection (address, len, &ignored_prot); } *prot = GUM_PAGE_NO_ACCESS; if (len > 1) { GumAddress page_size, start_page, end_page, cur_page; page_size = gum_query_page_size (); start_page = address & ~(page_size - 1); end_page = (address + len - 1) & ~(page_size - 1); success = gum_memory_get_protection (start_page, 1, prot); for (cur_page = start_page + page_size; cur_page != end_page + page_size; cur_page += page_size) { GumPageProtection cur_prot; if (gum_memory_get_protection (cur_page, 1, &cur_prot)) { success = TRUE; *prot &= cur_prot; } else { *prot = GUM_PAGE_NO_ACCESS; break; } } return success; } success = VirtualQuery (GSIZE_TO_POINTER (address), &mbi, sizeof (mbi)) != 0; if (success) *prot = gum_page_protection_from_windows (mbi.Protect); return success; }
void gum_process_enumerate_ranges (GumPageProtection prot, GumFoundRangeFunc func, gpointer user_data) { guint8 * cur_base_address; cur_base_address = NULL; while (TRUE) { MEMORY_BASIC_INFORMATION mbi; SIZE_T ret; ret = VirtualQuery (cur_base_address, &mbi, sizeof (mbi)); if (ret == 0) break; if (mbi.Protect != 0 && (mbi.Protect & PAGE_GUARD) == 0) { GumPageProtection cur_prot; cur_prot = gum_page_protection_from_windows (mbi.Protect); if ((cur_prot & prot) == prot) { GumMemoryRange range; GumRangeDetails details; range.base_address = GUM_ADDRESS (cur_base_address); range.size = mbi.RegionSize; details.range = ⦥ details.prot = cur_prot; details.file = NULL; /* TODO */ if (!func (&details, user_data)) return; } } cur_base_address += mbi.RegionSize; } }
static gboolean gum_memory_access_monitor_on_exception (GumExceptionDetails * details, gpointer user_data) { GumMemoryAccessMonitor * self = GUM_MEMORY_ACCESS_MONITOR_CAST (user_data); const GumMemoryAccessMonitorPrivate * priv = self->priv; GumMemoryAccessDetails d; guint i; d.operation = details->memory.operation; d.from = details->address; d.address = details->memory.address; for (i = 0; i != priv->num_pages; i++) { const GumPageDetails * page = &priv->pages_details[i]; const GumMemoryRange * r = &priv->ranges[page->range_index]; guint operation_mask; guint operations_reported; guint pages_remaining; if ((page->address <= d.address) && ((guint8 *) page->address + priv->page_size > (guint8*) d.address)) { /* make sure that we don't misinterpret access violation / page guard */ if (page->is_guarded) { if (details->type != GUM_EXCEPTION_GUARD_PAGE) return FALSE; } else if (details->type == GUM_EXCEPTION_ACCESS_VIOLATION) { GumPageProtection gum_original_protection = gum_page_protection_from_windows (page->original_protection); switch (d.operation) { case GUM_MEMOP_READ: if ((gum_original_protection & GUM_PAGE_READ) == 0) return FALSE; break; case GUM_MEMOP_WRITE: if ((gum_original_protection & GUM_PAGE_WRITE) == 0) return FALSE; break; case GUM_MEMOP_EXECUTE: if ((gum_original_protection & GUM_PAGE_EXECUTE) == 0) return FALSE; break; default: g_assert_not_reached(); } } else return FALSE; /* restore the original protection if needed */ if (priv->auto_reset && !page->is_guarded) { DWORD old_prot; /* may be called multiple times in case of simultaneous access * but it should not be a problem */ VirtualProtect ( (guint8 *) d.address - (((guintptr) d.address) % priv->page_size), priv->page_size, page->original_protection, &old_prot); } /* if an operation was already reported, don't report it. */ operation_mask = 1 << d.operation; operations_reported = g_atomic_int_or (&page->completed, operation_mask); if ((operations_reported != 0) && priv->auto_reset) return FALSE; pages_remaining; if (!operations_reported) pages_remaining = g_atomic_int_add (&priv->pages_remaining, -1) - 1; else pages_remaining = g_atomic_int_get (&priv->pages_remaining); d.pages_completed = priv->pages_total - pages_remaining; d.range_index = page->range_index; d.page_index = (guint8 *) d.address - (guint8 *) r->base_address; d.page_index = d.page_index / priv->page_size; d.pages_total = priv->pages_total; priv->notify_func (self, &d, priv->notify_data); return TRUE; } } return FALSE; }