Wednesday, April 6, 2011

x86 jump to an address

As an assignment for a security class, I am trying to use __asm__("jmp 0xbffff994"); in my code, but when I disassemble things in gdb, the instruction is changed to jmp 0xc8047e2a. Any idea why and how can I jump to a particular address?

From stackoverflow
  • I think what you are trying to do is a security problem. Your compiler is using offsets to prevent your program from doing something harmful.

    Martin : Yeah, I am doing an exploit for a security class :)
    Mark : What? How can that protect the program?
    Daniel A. White : It would protect your program from accessing outside of itself.
    Mark : At best, it would turn a pointer that happened to be valid into an invalid pointer, but it could equally do the opposite. Relocation is not about security. Are you thinking of ASLR?
    Evan Teran : Sorry Daniel, not correct, the problem is that there is x86 instruction to jmp to a direct offset. the jmp instruction takes an *offset*, a register, or a memory expression. in this case, the assembler treated the constant as an offset. That means that it is relative to the address of the instruction.
  • Daniel Explains why your jump is not the same you programmed. It has to do with object files and linking.

    if you want to jump to a particular address, it's best to patch the jump using a Debugger or Disassembler.

  • Probably because it's a jumping to a relative address, and the linker or loader has moved your code. Try putting the address into a variable, and then do:

    jmp dword [var]
    

    or alternatively:

    push 0xbffff994
    ret
    
    Evan Teran : *that* is the correct answer, also note that: "mov eax, 0x11223344; jmp eax"; will also work and is likely the most straight forward.
    Mark : very true, but he might be using fastcall (I'm not sure of the significance of 0xbffff994).
    Martin : The PUSH RET combination works! Thank you!
    Evan Teran : 0xbffff994 likely = a location on the stack on a linux box :-P
  • On my system (gcc version 4.2.4, Ubuntu) this looks fine on the disassmbley (insight):

    int main()
    {
    asm("jmp 0xbffff994"); 
    return 0;
    };       
    

    results of the disassmbley (insight):

            0x8048344       :                 lea    0x4(%esp),%ecx
    -       0x8048348       :               and    $0xfffffff0,%esp
    -       0x804834b       :               pushl  -0x4(%ecx)
    -       0x804834e       :              push   %ebp
    -       0x804834f       :              mov    %esp,%ebp
    -       0x8048351       :              push   %ecx
    -       0x8048352       :              jmp    0xbffff994
    -       0x8048357       :              mov    $0x0,%eax
    -       0x804835c       :              pop    %ecx
    -       0x804835d       :              pop    %ebp
    -       0x804835e       :              lea    -0x4(%ecx),%esp
    -       0x8048361       :              ret
    
    Evan Teran : I would guess that that disassembler is showing the offset of the jmp and not its actual target. (the jmp instruction takes an offset relative to eip when you give it a 32-bit immediate operand).
    Liran Orevi : Why would you guess that? is there a way to test it? it is running as a graphical interface with GDB below.
    Mark : Or it could be that there's no relocation. However, if you dump the opcodes with the assembly you'll be able to see the offset.
    Liran Orevi : I see this 8048352: e9 3d 76 fb b7 jmp bffff994 <_end+0xb7fb6454> can't find the _end label, but it looks mighty close to the end of the program.
  • It is hard to determine the exact address upon compile time, have you tried using labels? It is much more common to use them with jmp.

    example:

    start:
     jmp exit
    
    exit:
     ret
    
  • I would recommend using a hex editor and simply changing the value if it's just a one time thing.

0 comments:

Post a Comment