20

What are some alternatives to the x86 call instruction? Maybe something like a push of the return address then a jump?

Also is their a command for obtaining the current position in memory?

rick
  • 201
  • 1
  • 2
  • 3
  • 2
    Check out [this answer](http://stackoverflow.com/questions/3341248/how-do-i-write-simple-inline-asm-instruction-from-c-on-linux-64-bit/3344243#3344243) along with the ambient question. – Kerrek SB Aug 15 '11 at 01:42

3 Answers3

26

The call instruction actually does this for you. For example call my_func would do something like:

push ret_address
jmp my_func

A subsequent ret call would just use the address you just pushed to jmp back in a sense. Is there a specific reason that you don't want to use call or is it not available for you? For current position in memory you can try to read the eip register (can't write to it).

Zion
  • 1,562
  • 13
  • 32
Jesus Ramos
  • 22,940
  • 10
  • 58
  • 88
  • I'm injecting a asm code stub that calls internal functions withing another process (using C#). Basically was wondering if their would be a more elegant way of calling that said function without disrupting any registers or the stack (so as to preserve them before the call.) Another solution i used is just to write a jump instruction follow by the function address statically (sorta how windows handles dll functions.) However this meant keeping track of the buffer size of the injected code, which in my opinion is inelegant but looks like that is the only option at the moment. – rick Aug 15 '11 at 02:12
  • Also i think i can use an indirect call. – rick Aug 15 '11 at 02:13
  • Yeah you can use an indirect call, something else you can use a jump detour if you want to replace the function call altogether and have it execute your code instead. – Jesus Ramos Aug 15 '11 at 02:14
  • In addition to a jump detour, if it is needed to replace the function call altogether, you can patch relevant call/jump offsets directly in the code. The custom replacement function should have the same signature as the original one. Of course this does not work for indirect calls and jumps but it can still be helpful. – Eugene Aug 16 '11 at 07:02
  • 9
    You **can** write to the EIP register, the instruction is just not called MOV but JMP. – Bo Persson Aug 16 '11 at 16:12
  • I was just thinking about it a little bit. Couldn't one just do a relative call of zero offset then just pop the return address? Problem is it sacrifices a register. – rick Aug 16 '11 at 18:42
  • @Bo can you? I thought there were mechanisms to prevent this in some OS I might be wrong though as I've never really tried to write anything to EIP since the processor itself handles it. – Jesus Ramos Aug 16 '11 at 19:15
  • @rick, yes, you can. The trick Kerrek SB referred to in the comment to your question does just that: `call $0x5; pop %ebx`. And yes, clobbering of `%ebx` can be a problem but it's usually manageable. What to do depends on how you plan to use that saved value of the instruction pointer. – Eugene Aug 16 '11 at 20:35
  • You can prevent the clobbering of a register by just using `[esp]`. For example, `jmp +0x5; pop eax; xor ecx, ebx` can be replaced with `jmp +0x5; xor ecx, [esp]`. When you're done with the address, just do `add esp, 4` (or `sub esp, 4` on an upward growing stack). – Polynomial Oct 30 '11 at 21:03
  • @JesusRamos: A jump / call or ret instruction is literally setting EIP, making the CPU execute something other than the next instruction. If it were true you'd never written EIP, that would mean all code you'd ever written was straight-line with no branching, including not returning anywhere. (Could be possible if you'd only ever written inline asm and let the compiler make loops / conditionals). See also [Why can't you set the instruction pointer directly?](https://stackoverflow.com/a/41150027) / [Reading program counter directly](https://stackoverflow.com/q/599968) – Peter Cordes Dec 12 '21 at 06:24
  • e.g. `ret` is just how x86 spells "pop eip". – Peter Cordes Dec 12 '21 at 06:25
7

You can just push a dword value and jmp to the procedure. The push would be the return address :

push return_address (push eax if address in eax)
jmp call_address

Remember to also push arguments if they exist for that particular call.

What do you mean by current position in memory ? I suppose that you mean the current instruction pointer. You cannot get that directly, but you can use a seh handler(structured exception handler) to get that value upon causing a handled exception.

Spyros
  • 46,820
  • 25
  • 86
  • 129
3

If I don't get something mixed up I would say it depends. As you can see here there are near and far calls, but let's just consider the near call. There are again two possibilities

E8 <offset> # relative
FF <address> # absolute

whereas FF means an absolute "jump" and E8 indeed means relative to current eip.

So if you have e.g.

E8 32 45 ab 6f

which means

call 0x3245ab6f

This would translate to

push %eip
add $0x3245ab6f, %eip

and not

push %eip
jmp $0x3245ab6f
whymatter
  • 755
  • 8
  • 18
  • Note that `call` pushes the address of one-past-the-end of itself, i.e. the address of the next instruction. x86 doesn't have an architecturally-visible `%eip`, so you should at least comment your pseudo-code to explain that your `%eip` is the already-incremented EIP, after adding the length of the call instruction. (But yes, the relative displacement is relative to the end of the instruction, i.e. the return address, just like for 64-bit RIP-relative addressing.) – Peter Cordes Oct 30 '17 at 05:52