|
|
@ -32,3 +32,50 @@ You can call functions that do not reference absolute addresses. This last sente
|
|
|
|
is not the same (nor is the PML4E index the same).
|
|
|
|
is not the same (nor is the PML4E index the same).
|
|
|
|
|
|
|
|
|
|
|
|
My suggestion is you call only small functions if you want to call functions.
|
|
|
|
My suggestion is you call only small functions if you want to call functions.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Example
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Since all of the games memory is mapped into your process you can simply walk the games PEB for loaded modules. Here is an example of how to do that.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```cpp
|
|
|
|
|
|
|
|
auto get_module_base(vdm::vdm_ctx* v_ctx, nasa::injector_ctx* rinjector,
|
|
|
|
|
|
|
|
std::uint32_t pid, const wchar_t* module_name) -> std::uintptr_t
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
const auto ppeb =
|
|
|
|
|
|
|
|
reinterpret_cast<PPEB>(
|
|
|
|
|
|
|
|
rinjector->translate(
|
|
|
|
|
|
|
|
reinterpret_cast<std::uintptr_t>(v_ctx->get_peb(pid))));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const auto ldr_data =
|
|
|
|
|
|
|
|
reinterpret_cast<PPEB_LDR_DATA>(
|
|
|
|
|
|
|
|
rinjector->translate(reinterpret_cast<std::uintptr_t>(ppeb->Ldr)));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
auto current_entry =
|
|
|
|
|
|
|
|
reinterpret_cast<LIST_ENTRY*>(
|
|
|
|
|
|
|
|
rinjector->translate(reinterpret_cast<std::uintptr_t>(
|
|
|
|
|
|
|
|
ldr_data->InMemoryOrderModuleList.Flink)));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const auto list_head = &ldr_data->InMemoryOrderModuleList;
|
|
|
|
|
|
|
|
while (current_entry != list_head)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
const auto current_entry_data =
|
|
|
|
|
|
|
|
reinterpret_cast<PLDR_DATA_TABLE_ENTRY>(
|
|
|
|
|
|
|
|
reinterpret_cast<std::uintptr_t>(current_entry) - sizeof LIST_ENTRY);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const auto entry_module_name =
|
|
|
|
|
|
|
|
reinterpret_cast<const wchar_t*>(
|
|
|
|
|
|
|
|
rinjector->translate(
|
|
|
|
|
|
|
|
reinterpret_cast<std::uintptr_t>(
|
|
|
|
|
|
|
|
reinterpret_cast<PUNICODE_STRING>(
|
|
|
|
|
|
|
|
reinterpret_cast<std::uintptr_t>(
|
|
|
|
|
|
|
|
¤t_entry_data->FullDllName) + sizeof UNICODE_STRING)->Buffer)));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!_wcsicmp(entry_module_name, module_name))
|
|
|
|
|
|
|
|
return reinterpret_cast<std::uintptr_t>(current_entry_data->DllBase);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
current_entry = reinterpret_cast<LIST_ENTRY*>(
|
|
|
|
|
|
|
|
rinjector->translate(reinterpret_cast<std::uintptr_t>(current_entry->Flink)));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return {};
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
```
|