Skip to content

Detour fails when prologue contains Inline call to read SP idiom #217

@acidicoala

Description

@acidicoala

Take a look at this failing test case: https://github.com/stevemk14ebr/PolyHook_2_0/actions/runs/18138324882/job/51622654184#step:8:10

[+] Info: Original function:
59d57b20 [1]: 53                                      push ebx
59d57b21 [3]: 83 ec 08                                sub esp, 0x08
59d57b24 [5]: e8 00 00 00 00                          call 0x59D57B29 -> 59d57b29
59d57b29 [1]: 5b                                      pop ebx
59d57b2a [6]: 81 c3 cb d4 18 00                       add ebx, 0x18D4CB
...

The following 2 instructions together comprise an idiom for reading the SP register. It's similar to the case in #215, but this time it is inlined in the function prologue.

59d57b24 [5]: e8 00 00 00 00                          call 0x59D57B29 -> 59d57b29
59d57b29 [1]: 5b                                      pop ebx

Polyhook chooses the following prologue:

59d57b20 [1]: 53                                      push ebx
59d57b21 [3]: 83 ec 08                                sub esp, 0x08
59d57b24 [5]: e8 00 00 00 00                          call 0x59D57B29 -> 59d57b29

With the resulting trampoline being

[+] Info: Trampoline:
5b12f4a0 [1]: 53                                      push ebx
5b12f4a1 [3]: 83 ec 08                                sub esp, 0x08
5b12f4a4 [5]: e8 00 00 00 00                          call 0x5B12F4A9 -> 5b12f4a9
5b12f4a9 [5]: e9 7b 86 c2 fe                          jmp 0x59D57B29 -> 59d57b29

Thus, if we try to call the original function, after trampoline jump the pop instruction at 59d57b29 will write to ebx register address 5b12f4a9 (i.e. inside trampoline jump table) instead of 59d57b29 (i.e. inside original function) that it should have had. This corruption leads to segmentation fault soon-after.

I propose a fix similar to that in #216, where we replace the call instruction with push imm32, where imm32 is the intended address. So in this case the end result would like this:

[+] Info: Trampoline:
5b12f4a0 [1]: 53                                      push ebx
5b12f4a1 [3]: 83 ec 08                                sub esp, 0x08
5b12f4a4 [5]: e8 00 00 00 00                          push 0x59d57b29
5b12f4a9 [5]: e9 7b 86 c2 fe                          jmp 0x59D57B29 -> 59d57b29

The implementation will consts of 2 parts:

  1. Recognize call next_address; pop reg as the inline call to read SP idiom
  2. Replace the call instruction with push imm32.

Also, a corresponding condition has to be added to the Detour::followJmp function to ignore such call instructions, since they would be rewritten.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions