Posted
In the past tutorials, we learned how memory works, how pointers work in C/C++ and how we can use them to our advantage.
Now that you know how it works, I'm going to teach you what trampoline hooks are( note that this is one of multiple trampoline hooking methods. I've posted other methods of it on my github and here before. ), how they work, and why they're useful. Let's start off with the why:
Let's say you want to run your code each time the game calls a certain function or runs a certain piece of code, that's exactly what a trampoline hook lets you achieve.
How:
It works by overwriting 5 or more bytes ( 5 is the amount of bytes required for a relative JMP instruction ) of the specific code or function we want to hook and using those overwritten bytes to jump to our code we want to execute, and after executing our code, execute the overwritten code ( so that the game works as normal ) and proceed to jump to the next instruction after the instructions we executed to continue execution.
They get the name trampoline hook ( also known as a detour ) because you're jumping from code to code, sort of like a trampoline where you jump, go in the air, then go back down to where you originally were.
Here's my implementation of a basic trampoline hook:
std::uint32_t tramp_hook( void* hook_addr, void* new_func, std::uint32_t instr_size )
{
constexpr auto jmp_instr_size = 5; // minimum size required for a JMP instruction
DWORD vp_old_prot{ 0u };
VirtualProtect( hook_addr, instr_size, PAGE_EXECUTE_READWRITE, &vp_old_prot ); // In order to overwrite code, we need proper access.
std::memset( hook_addr, 0x90, instr_size ); // setting the bytes we will overwrite to 0x90 / nop ( no operation )
const auto rel_addr = ( reinterpret_cast< std::uint32_t>( new_func ) - reinterpret_cast< std::uint32_t >( hook_addr ) ) - jmp_instr_size; // relative address calculation. in a relative jmp / call, the result of this calculation will be used by the CPU to add to the EIP ( instruction pointer ).
*( static_cast< std::uint8_t* >( hook_addr ) ) = 0xE9; // overwriting a byte to the JMP opcode ( 0xE9 )
*( reinterpret_cast < std::uint32_t* >( reinterpret_cast< std::uint32_t >( hook_addr ) + 1) ) = rel_addr; // setting the result of our relative address calculation as the relative jmp operand.
VirtualProtect( hook_addr, instr_size, vp_old_prot, nullptr ); / resetting our access
return reinterpret_cast< std::uint32_t >( hook_addr ) + 5; // returning the address next instruction to be executed to be used later
}
https://media.discordapp.net/attachments/1044764388546068510/1051935933836050482/Signature_4.png
Did I mention I use arch btw?
Replied
That's ugly code.
Cancel
Post
Replied
Nice lesson, the code looks simple and easy to read. Nice, I love how you implemented comments into your code to show/make a better understanding of how the code works.
Cancel
Post
Replied
Cancel
Post
https://media.discordapp.net/attachments/1044764388546068510/1051935933836050482/Signature_4.png
Replied
@luxiferrwoo How about I just modify your code?
std::uintptr_t tramp_hook(void* target, void* new_func, std::size_t size)
{
DWORD old {};
VirtualProtect(target, size, PAGE_EXECUTE_READWRITE, &old);
std::memset(target, 0x90, size);
const auto rel_addr = (reinterpret_cast<std::uintptr_t>(new_func) - reinterpret_cast<std::uintptr_t>(target)) - 5;
*static_cast<std::uint8_t*>(target) = 0xE9;
*reinterpret_cast<std::uintptr_t*>(reinterpret_cast<std::uintptr_t>(target) + 1) = rel_addr;
VirtualProtect(target, size, old, nullptr);
return reinterpret_cast<std::uintptr_t>(target) + 5;
}
Also fix your .clang-format file lmfao
Cancel
Post
Replied
legit all you did was change formatting lol
also my formatting is fine, i love it :kiss.
Cancel
Post
https://media.discordapp.net/attachments/1044764388546068510/1051935933836050482/Signature_4.png
Replied
@luxiferrwoo I removed your sh|tty practices and did what you do most of the time (modifying other peoples code)
Why?
https://cdn.discordapp.com/attachments/1014484696463323168/1020553806620131339/unknown.png
That 0u is ugly and unnecessary
https://cdn.discordapp.com/attachments/1014484696463323168/1020678778357305426/unknown.png
Using the Variable here but not on the return statement (lol)?
https://cdn.discordapp.com/attachments/1014484696463323168/1020553891726762004/unknown.png
https://cdn.discordapp.com/attachments/1014484696463323168/1020553994889859154/unknown.png
What the fu€k
https://cdn.discordapp.com/attachments/1014484696463323168/1020679343787221063/unknown.png
std::uintptr_t exists
https://cdn.discordapp.com/attachments/1014484696463323168/1020679638416109640/unknown.png
https://cdn.discordapp.com/attachments/1014484696463323168/1020679590965948466/unknown.png
https://cdn.discordapp.com/attachments/1014484696463323168/1020679855718813738/unknown.png
https://cdn.discordapp.com/attachments/1014484696463323168/1020680977472831488/unknown.png
https://cdn.discordapp.com/attachments/1014484696463323168/1020681091574665286/unknown.png
Cancel
Post
Replied
what do you mean most of the time I'm modifying other people's code??? what??
the only repositories I have asked for help on are the signature scanner ( which I have completely modified and rewritten but haven't yet released publicly and don't plan to ), which was just 0x90 showing me a better way of doing it and then I further improved it privately, from 1400ms to 300ms and a better way for checking for a function end ( 0x90 ). the rest is all written by me lol, not only that but every single piece of code that isn't mine, has been credited completely.
to answer your questions:
1. it's for clarity, this is a tutorial, why would I not explain the meaning of why I'm using 5 in code as well as in text?
2. the 0u is completely preference lol, nice one
it's funny how you call me out for using uint32_t yet in your "modified" version, you legit use it aswell?
https://media.discordapp.net/attachments/798043651309699122/1020686372136296508/unknown.png you forgot to change from uint32_t here to uintptr_t
In most if not all of my github repositories you'll see me using std::uint32_t which is a practice I have since changed to uintptr_t a while ago, way before you made this reply, but haven't updated any of the repositories to use std::uintptr_t so even if I do update one it'll probably remain the same anyways.
your only "valid" argument is using std::uintptr_t instead of std::uint32_t and that's fine since I have already quit that habit before I even made this thread
and your little comment about me modifying other people's code is weird, since not only have they been credited, the "modified code" you're talking about is the ret_function_bytes function and the signature scanner, both from 0x90 and one that has been thrown out and improved ( by me ) lol, you're acting like I completely copied code and changed formatting.
Cancel
Post
https://media.discordapp.net/attachments/1044764388546068510/1051935933836050482/Signature_4.png
Replied
blame wrd forums for the spacing on lines but blame me for the spaces in parentheses and < > and etc
Cancel
Post
https://media.discordapp.net/attachments/1044764388546068510/1051935933836050482/Signature_4.png
Users viewing this thread:
( Members: 0, Guests: 1, Total: 1 )
Cancel
Post