Skip to content

Commit

Permalink
Utility: Add is_executable utility to replace IsBadCodePtr
Browse files Browse the repository at this point in the history
  • Loading branch information
cursey committed Jun 14, 2023
1 parent 39da1ce commit fc0cb36
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 1 deletion.
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ set(safetyhook_SOURCES
"src/inline_hook.cpp"
"src/mid_hook.cpp"
"src/thread_freezer.cpp"
"src/utility.cpp"
"src/vmt_hook.cpp"
cmake.toml
)
Expand Down
2 changes: 2 additions & 0 deletions include/safetyhook/utility.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,6 @@ template <typename T> constexpr void store(uint8_t* address, const T& value) {

template <typename T>
concept FnPtr = requires(T f) { std::is_pointer_v<T>&& std::is_function_v<std::remove_pointer_t<T>>; };

bool is_executable(uint8_t* address);
} // namespace safetyhook
52 changes: 52 additions & 0 deletions src/utility.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
#include <Windows.h>

#include <safetyhook/utility.hpp>

namespace safetyhook {
bool is_page_executable(uint8_t* address) {
MEMORY_BASIC_INFORMATION mbi;

if (VirtualQuery(address, &mbi, sizeof(mbi)) == 0) {
return false;
}

const auto executable_protect = PAGE_EXECUTE | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY;

return (mbi.Protect & executable_protect) != 0;
}

bool is_executable(uint8_t* address) {
LPVOID image_base_ptr;

if (RtlPcToFileHeader(address, &image_base_ptr) == nullptr) {
return is_page_executable(address);
}

// Just check if the section is executable.
const auto image_base = reinterpret_cast<uint8_t*>(image_base_ptr);
const auto* dos_hdr = reinterpret_cast<const IMAGE_DOS_HEADER*>(image_base);

if (dos_hdr->e_magic != IMAGE_DOS_SIGNATURE) {
return is_page_executable(address);
}

const auto* nt_hdr = reinterpret_cast<const IMAGE_NT_HEADERS*>(image_base + dos_hdr->e_lfanew);

if (nt_hdr->Signature != IMAGE_NT_SIGNATURE) {
return is_page_executable(address);
}

const auto* section_hdr = IMAGE_FIRST_SECTION(nt_hdr);

for (auto i = 0; i < nt_hdr->FileHeader.NumberOfSections; ++i) {
const auto* section = &section_hdr[i];

if (address >= image_base + section->VirtualAddress &&
address < image_base + section->VirtualAddress + section->Misc.VirtualSize) {
return (section->Characteristics & IMAGE_SCN_MEM_EXECUTE) != 0;
}
}

return is_page_executable(address);
}
} // namespace safetyhook
2 changes: 1 addition & 1 deletion src/vmt_hook.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ std::expected<VmtHook, VmtHook::Error> VmtHook::create(void* object) {
// Count the number of virtual method pointers. We start at one to account for the RTTI pointer.
auto num_vmt_entries = 1;

for (auto vm = original_vmt; !IsBadCodePtr(reinterpret_cast<FARPROC>(*vm)); ++vm) {
for (auto vm = original_vmt; is_executable(*vm); ++vm) {
++num_vmt_entries;
}

Expand Down

0 comments on commit fc0cb36

Please sign in to comment.