3

I'm debugging a Mac OS X 64bit app with GDB. I see that jumping over a chunk of code solves all my problems.

But:

How can I patch the executable file to implement the jump? I want the app to automatically jump to a defined point in the code without the debugger.

This is what I want to do:

At address 0x1000027a9 (given by the debugger) jump to address 0x100003b6e. I'm trying very hard to do it via HexEdit, but with no success. I read anywhere about jmp to absolute addresses opcodes (FF seems the right opcode, but it's a call, not a jump...) but nothing works. Bad access, segfault.

How can I do that?

1201ProgramAlarm
  • 32,384
  • 7
  • 42
  • 56
John White
  • 917
  • 1
  • 12
  • 26
  • The usual ways of doing this are: 1) fix the code & rebuild, 2) file a bug with the app vendor. Why are you trying to patch this yourself? – Mat Feb 17 '13 at 13:49
  • You need something like this when you have a very old app with no support from a company that's gone. Of course filling a bug report would have solved my problems. – John White Jun 08 '15 at 07:21

1 Answers1

5

What you want is not a call, but a jmp, and you want a direct jmp. Direct jumps usually use an addressing relative to the next instruction's address (see my answer to SO question: How encode a relative short jmp in x86). Relative to the end of the jump instruction is another way to look at it.

So, you are at 0x1000027a9 and want to jump to 0x100003b6e.

0x100003b6e - 0x1000027a9 = 0x000013C5 = 5061d, so that definitively doesn't fit in a short jump (rel8 in Intel documentation), but you need jmp rel32. It would fit in rel16 too, but that's not supported in x86-64 (in 64-bit mode).

So, you want a jmp rel32. This is encoded relative to the next instruction after jmp, and as the length of the instruction is 5 bytes (E9 xx xx xx xx), rel32 will be 0x000013C0. As x86 is a little-endian architecture, it is encoded as E9 C0 13 00 00.

To confirm this, I assembled a small test executable with NASM and disassembled it with ndisasm (note I left first 0x10000000 bytes out, but as the jump is relative, it doesn't change anything in the encoding):

000027A8  90                nop
000027A9  E9C0130000        jmp dword 0x3b6e ; this is the instruction you need.
000027AE  90                nop
Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
nrz
  • 10,435
  • 4
  • 39
  • 71
  • WORKS!! THANK YOU SO MUCH! Where can I learn more about x86 assembly? I found some material online, but it's rather incomplete or very old. – John White Feb 17 '13 at 15:06
  • I find Introduction to 64 Bit Intel Assembly Language Programming for Linux quite useful. As OS/X and Linux use the same System V ABI and function calls, I think it should work for OS/X too almost completely. There are more materials for 32-bit code, but as you have a 64-bit system, I really recommend to learn straight x86-64, it's much more convenient (more and bigger registers that make your life as a programmer a lot more comfortable). [Programming from the Ground Up Book](http://savannah.nongnu.org/projects/pgubook/) may also be useful, even though I dislike AT&T syntax. – nrz Feb 17 '13 at 15:22
  • Great! Done the same way for the 32bit code and it worked like a charm. Looks like I initially forgot the architecture was little-endian... – John White Feb 17 '13 at 16:30
  • Terminology: relative to next instruction's *address* might be better. RIP during execution of an instruction points to the end of that instruction, for the purposes of RIP-relative addressing modes like `[RIP + 0]`. So if you think about it this way, the "next instruction's `rip`" would be the end of the next instruction, not the end of the branch. – Peter Cordes Apr 17 '19 at 23:06