cursey / safetyhook

C++23 procedure hooking library.

Home Page:https://cursey.dev/safetyhook

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Mid-function hook fails on 'JL rel8' instruction

llm96 opened this issue · comments

commented

I'm trying to place a mid-function hook on the jl instruction here, but the detour code is causing a crash. I've hooked somewhere else as a workaround, but was curious as to whether it's a library issue or if this was just a bad place to put it.

1803C9F59 - 7C 53                 - jl 1803C9FAE
1803C9F5B - 48 8B 84 24 90020000  - mov rax,[rsp+00000290]
1803C9F63 - 83 38 3C              - cmp dword ptr [rax],3C { 60 }
hook = builder.create_mid(reinterpret_cast<void*>(0x1803C9F59), [] (safetyhook::Context& ctx) {});

Here's what everything looks like after the hook is created:

1803C9F59 - E9 B160C2FF           - jmp 17FFF000F { ->->1A601FB0000 }
1803C9F5E - 90                    - nop 
1803C9F5F - 90                    - nop 
1803C9F60 - 90                    - nop 
1803C9F61 - 90                    - nop 
1803C9F62 - 90                    - nop 
1803C9F63 - 83 38 3C              - cmp dword ptr [rax],3C { 60 }
17FFF000F - FF25 00000000 0000FB01A6010000 - jmp 1A601FB0000
1A601FB0000 - 54                    - push rsp
1A601FB0001 - 55                    - push rbp
1A601FB0002 - 50                    - push rax
1A601FB0003 - 53                    - push rbx
1A601FB0004 - 51                    - push rcx
1A601FB0005 - 52                    - push rdx
1A601FB0006 - 56                    - push rsi
1A601FB0007 - 57                    - push rdi
1A601FB0008 - 41 50                 - push r8
1A601FB000A - 41 51                 - push r9
1A601FB000C - 41 52                 - push r10
1A601FB000E - 41 53                 - push r11
1A601FB0010 - 41 54                 - push r12
1A601FB0012 - 41 55                 - push r13
1A601FB0014 - 41 56                 - push r14
1A601FB0016 - 41 57                 - push r15
1A601FB0018 - 9C                    - pushfq 
1A601FB0019 - 48 8D 0C 24           - lea rcx,[rsp]
1A601FB001D - 48 83 EC 28           - sub rsp,28 { 40 }
1A601FB0021 - 48 F7 C4 08000000     - test rsp,00000008 { 8 }
1A601FB0028 - 0F84 10000000         - je 1A601FB003E
1A601FB002E - 48 83 EC 08           - sub rsp,08 { 8 }
1A601FB0032 - 48 C7 C3 30000000     - mov rbx,00000030 { 48 }
1A601FB0039 - E9 07000000           - jmp 1A601FB0045
1A601FB003E - 48 C7 C3 28000000     - mov rbx,00000028 { 40 }
1A601FB0045 - FF 15 22000000        - call qword ptr [1A601FB006D] { ->demo_hooks.dll+CE6C0 }
1A601FB004B - 48 01 DC              - add rsp,rbx
1A601FB004E - 9D                    - popfq 
1A601FB004F - 41 5F                 - pop r15
1A601FB0051 - 41 5E                 - pop r14
1A601FB0053 - 41 5D                 - pop r13
1A601FB0055 - 41 5C                 - pop r12
1A601FB0057 - 41 5B                 - pop r11
1A601FB0059 - 41 5A                 - pop r10
1A601FB005B - 41 59                 - pop r9
1A601FB005D - 41 58                 - pop r8
1A601FB005F - 5F                    - pop rdi
1A601FB0060 - 5E                    - pop rsi
1A601FB0061 - 5A                    - pop rdx
1A601FB0062 - 59                    - pop rcx
1A601FB0063 - 5B                    - pop rbx
1A601FB0064 - 58                    - pop rax
1A601FB0065 - 5D                    - pop rbp
1A601FB0066 - 5C                    - pop rsp
1A601FB0067 - FF 25 08000000        - jmp qword ptr [1A601FB0075] { ->17FFF0000 }
1A601FB006D - C0 E6 D3              - shl dh,-2D { 211 }
1A601FB0070 - EB FD                 - jmp 1A601FB006F
1A601FB0072 - 7F 00                 - jg 1A601FB0074
1A601FB0074 - 00 00                 - add [rax],al
1A601FB0076 - 00 FF                 - add bh,bh
1A601FB0078 - 7F 01                 - jg 1A601FB007B
1A601FB007A - 00 00                 - add [rax],al

But here's where things go wrong:

17FFF0000 - 7C 53                 - jl 17FFF0055                ; jumps into a bunch of zeroes and crashes here
17FFF0002 - 48 8B 84 24 90020000  - mov rax,[rsp+00000290]
17FFF000A - E9 549F3D00           - jmp 1803C9F63
17FFF000F - FF25 00000000 0000FB01A6010000 - jmp 1A601FB0000

Either way, thanks for your work on this library! It's made prototyping things a lot faster. 👍

commented

my guess is we aren’t converting those short jmps properly and it tries jumping into code that doesn’t exist (i.e it expects original code to be there). we would have to convert those short jumps into normal jumps and hope it works? im not sure though, it gets a bit complicated. unless someone wants to fix these, your only solution for now is to avoid short jumps.

Yep. Like @angelfor3v3r said, short jumps don't work within the trampoline. It would be easy enough to convert a short jump into a near jump for the typical case (typical being that the trampoline was created by the e9_hook function meaning its within +- 2GB of the target). It would be challenging to fully support though for all cases.

  • What happens when the trampoline was created by ff_hook? The trampoline is no longer within +- 2GB so you can't encode the instruction any longer. Guess it would just fail at this point.
  • What happens if the short jump actually needs to jump to somewhere within code copied to the trampoline? You would need to keep track to make sure you're only expanding jumps that actually need it.

I think in this case it should just fail if short jumps are ending up within the trampoline. It's better than causing a crash. It would be nice to support them for the typical case as well though.

This commit (e82fdcd) should now cause hooks to fail instead of crash when a short jump is being placed within the trampoline. Not an ideal fix, but better than crashing for now. I'll look into adding support for short jumps on e9_hook in the future.

Closing this since after e82fdcd I don't plan on addressing short branch compatibility any time soon.