TransWikia.com

Injecting C++ code, while also maximizing compatibility with other injections

Reverse Engineering Asked by FiftyTifty on September 30, 2021

Using the New Vegas Script Extender C++ API for Fallout New Vegas, I am able to write to the process’ memory directly at runtime through a .dll plugin that’s loaded by the NVSE injector. But it is not a debugger, like CheatEngine, so there’s no automatic handling of inserting new code to an existing assembly function.

Beginning of the assembly function, TryOpenPipboy, I want to inject code into: https://i.imgur.com/MQUrbXa.png

EquipPlayerPipboy() function I want to inject: https://i.imgur.com/IjmMRFU.png

The game has a loop called MainUILoop which runs every frame, and when the player presses tab without holding it down, TryOpenPipboy is called.

My guess is that I need to somehow create a new empty block of memory, edit a copy of the original TryOpenPipboy function, then replace all TryOpenPipboy calls with my modified variant. But that would make a hard incompatibility with any other NVSE plugins that also modify the MainUILoop in any way, as well as any that edit TryOpenPipboy.

Edit: Another possible way would be to change the jmp assembly to my C++ function, then call TryOpenPipboy from my function. That would mean TryOpenPipboy is still called, but is unmodified, increasing potential compatibility.

So how should I go about doing this?

3 Answers

So basically you just want a hook? There are a huge number of ways to achieve this but the simplest is probably a JMP hook. I'm happy to explain the details of how it works if you want, but I suggest just using an existing library like MinHook either way. Note that if this game is online then it's very likely you'll be kicked or banned, CRC hashes on code sections is about the simplest detection of unwanted modifications you can have.

Answered by Pickle Rick on September 30, 2021

Intel PIN in Probe Mode can do just. You can inject C code and PIN will even handle the context switching for you.

Answered by MkInitCpIO on September 30, 2021

If you just want to run code before or after TryOpenPipboy is called, you can overwrite the prologue of the function with a jmp to your function. Before you overwrite it, copy the instructions in the prologue to a new memory buffer, and add a jump to the rest of the function on the end, this is called a trampoline. You can use the trampoline to call the original function.

Before:

:originalFunction
push ebp ;55
mov ebp, esp ;89 E5
sub esp, 0x40 ;83 EC 40
;...
ret

After patching:

:originalFunction
jmp yourFunction ;?? ?? ?? ?? ??
nop ;this used to be the 0x40 byte at the end
:trampolinetarget
;...
ret

yourFunction:
;do stuff
call trampoline ;calls the original function
;do stuff
ret

trampoline:
push ebp
mov ebp, esp
sub esp, 0x40
jmp trampolinetarget

If something else tries to hook the original function, they'll just overwrite that jmp instruction, and their trampoline will call your function. Microsoft's Detours library can handle all of this for you.

Answered by Avery3R on September 30, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP