There are several ways you can achieve this. I assume you don't have source code of the executable, otherwise you would just tell the compiler to for example generate few nop
s for you after the call
opcode, so you would simply patch the call without any data shifting.
As you said, you could replace the call with long call (but as far as I know all calls on x86-32 takes 4+1 bytes of space, no matter if they are relative or absolute) and shift all the instructions below because there is sometimes free space between functions generated by compiler (eg filed with 0xCC), but then you would need to fix all jumps/calls to addresses that are affected by your shift. Doing this you have to remember that there may be dynamicaly generated jump-tables/calls that you would also need to replace.
The better approach would be to hook that function and apply short prolog and epilog to your payload. I will try to explain how it can be done. Let's say you have following assembly instructions:
0069DDCC | 8B00 | mov eax,dword ptr ds:[eax]
0069DDCE | 8B50 24 | mov edx,dword ptr ds:[eax+24]
0069DDD1 | A1 00506F00 | mov eax,dword ptr ds:[6F5000]
0069DDD6 | 8B00 | mov eax,dword ptr ds:[eax]
And you want to redirect the code flow at 0x69DDCE
to your function that is located at 0xDEADBEEF
. As you can see the instruction at 0x69DDCE
is 3 bytes long, but the long jmp is actually 5 bytes long. After patching the 5 bytes our code looks like:
0069DDCC | 8B00 | mov eax,dword ptr ds:[eax]
0069DDCE | E9 1CE143DE | jmp DEADBEEF
0069DDD3 | 5C | pop esp
0069DDD4 | 6F | outsd
0069DDD5 | 008B 00E81770 | add byte ptr ds:[ebx+7017E800],cl
This is because we have partially overwritten the mov eax,dword ptr ds:[6F5000]
so our code will change the behavior after returning from your function at 0xDEADBEEF
. The thing we need to do here is to NOP
the instruction totally, so in fact we need to patch 8 bytes (mov edx,dword ptr ds:[eax+24]
+ mov eax,dword ptr ds:[6F5000]
), so it will look like this:
0069DDCC | 8B00 | mov eax,dword ptr ds:[eax]
0069DDCE | E9 1CE143DE | jmp DEADBEEF
0069DDD3 | 90 | nop
0069DDD4 | 90 | nop
0069DDD5 | 90 | nop
0069DDD6 | 8B00 | mov eax,dword ptr ds:[eax]
Now we need to prepare our payload at 0xDEADBEEF
. Keep in mind that you have removed two instructions from the original code, so you need to execute them at some point, also note the address where we should restore the original code flow, which is 0x69DDD6
. If you plan to modify the registers in your payload you need to save them, the best would be probably to call the pushad/pushfd, so the final payload at 0xDEADBEEF
can look like this
pushad
pushfd
; your code
popfd
popad
mov edx,dword ptr ds:[eax+24]
mov eax,dword ptr ds:[6F5000]
jmp 0x69DDD6
The mov
s in the payload are the ones you have deleted from original code, and the jmp 0x69DDD6
is the place where you should restore the original flow. Keep in mind that if you write something to the program memory in your code you may change the way program executes if it will use your changed data at some point. Otherwise the program should continue normally after jumping back from your function.