diff options
author | Vas Crabb <vas@vastheman.com> | 2021-09-22 09:42:10 +1000 |
---|---|---|
committer | Vas Crabb <vas@vastheman.com> | 2021-09-22 09:42:10 +1000 |
commit | 45d893eaa55fd4db870642f406cba4a8cbac04b4 (patch) | |
tree | 06e1c3901df8e19722661b6063413bd29f2171d7 /src/lib/util | |
parent | 2bfa21eb2a6fd9af7429a347026c50aec045f590 (diff) |
util/delegate.cpp: Recognise a couple more MSVC thunks.
The MSVC C++ ABI doesn't reserve the first vtable entry for classes
without a virtual destructor, so the instruction to load the virtual
member function address may not need an immediate displacement.
Also recognise virtual member function call thunks for AArch64.
Diffstat (limited to 'src/lib/util')
-rw-r--r-- | src/lib/util/delegate.cpp | 35 |
1 files changed, 29 insertions, 6 deletions
diff --git a/src/lib/util/delegate.cpp b/src/lib/util/delegate.cpp index 346ba1283a0..cedb8e60bd8 100644 --- a/src/lib/util/delegate.cpp +++ b/src/lib/util/delegate.cpp @@ -142,25 +142,27 @@ delegate_generic_function delegate_mfp_msvc::adjust_this_pointer(delegate_generi object = reinterpret_cast<delegate_generic_class *>(byteptr); // walk past recognisable thunks - std::uint8_t const *func = reinterpret_cast<std::uint8_t const *>(m_function); #if defined(__x86_64__) || defined(_M_X64) + std::uint8_t const *func = reinterpret_cast<std::uint8_t const *>(m_function); while (true) { if (0xe9 == func[0]) { - // absolute jump with 32-bit displacement + // relative jump with 32-bit displacement (typically a resolved PLT entry) LOG("Found relative jump at %p ", func); func += 5 + *reinterpret_cast<std::int32_t const *>(func + 1); LOG("redirecting to %p\n", func); } - else if ((0x48 == func[0]) && (0x8b == func[1]) && (0x01 == func[2]) && (0xff == func[3]) && ((0x60 == func[4]) || (0xa0 == func[4]))) + else if ((0x48 == func[0]) && (0x8b == func[1]) && (0x01 == func[2]) && (0xff == func[3]) && ((0x20 == func[4]) || (0x60 == func[4]) || (0xa0 == func[4]))) { // virtual function call thunk - mov rax,QWORD PTR [rcx] ; jmp QWORD PTR [rax+...] LOG("Found virtual member function thunk at %p ", func); std::uint8_t const *const vptr = *reinterpret_cast<std::uint8_t const *const *>(object); - if (0x60 == func[4]) + if (0x20 == func[4]) // no displacement + func = *reinterpret_cast<std::uint8_t const *const *>(vptr); + else if (0x60 == func[4]) // 8-bit displacement func = *reinterpret_cast<std::uint8_t const *const *>(vptr + *reinterpret_cast<std::int8_t const *>(func + 5)); - else + else // 32-bit displacement func = *reinterpret_cast<std::uint8_t const *const *>(vptr + *reinterpret_cast<std::int32_t const *>(func + 5)); LOG("redirecting to %p\n", func); } @@ -170,8 +172,29 @@ delegate_generic_function delegate_mfp_msvc::adjust_this_pointer(delegate_generi break; } } -#endif return reinterpret_cast<delegate_generic_function>(std::uintptr_t(func)); +#elif defined(__aarch64__) || defined(_M_ARM64) + std::uint32_t const *func = reinterpret_cast<std::uint32_t const *>(m_function); + while (true) + { + if ((0xf9400010 == func[0]) && (0xf9400210 == (func[1] & 0xffc003ff)) && (0xd61f0200 == func[2])) + { + // virtual function call thunk - ldr xip0,[x0] ; ldr xip0,[x0,#...] ; br xip0 + LOG("Found virtual member function thunk at %p ", func); + std::uint32_t const *const *const vptr = *reinterpret_cast<std::uint32_t const *const *const *>(object); + func = vptr[(func[1] & 0x003ffc00) >> 10]; + LOG("redirecting to %p\n", func); + } + else + { + // not something we can easily bypass + break; + } + } + return reinterpret_cast<delegate_generic_function>(std::uintptr_t(func)); +#else + return reinterpret_cast<delegate_generic_function>(m_function); +#endif } } // namespace util::detail |