views:

141

answers:

3

Hi all,

I've got an executable file (C++, i386, compiled under MacOS/X Tiger, if it matters) that contains a bug. The fix for the bug is straightforward -- there's a place in the code where it calls fork() and it shouldn't. Because the fix is simple, and because recompiling the executable from scratch would be difficult at this point (don't ask), I'd like to just patch the executable/binary file directly.

As a first step towards that, I ran "otool -tV MyExecutableName" on my executable, and voila, I found this in the disassembly output:

./MyExecutableName:
(__TEXT,__text) section
[... many lines omitted ...]
0002ce0d        subl    $0x10,%esp
0002ce10        calll   0x0051adac
0002ce15        movzbl  0x14(%ebp),%esi
0002ce19        calll   0x00850ac9      ; symbol stub for: _fork
0002ce1e        cmpl    $0x00,%eax
0002ce21        jll     0x0002cf02
0002ce27        jle     0x0002ce34
[... many more lines omitted ...]

So what I'd like to do is replace the opcode at line 0002ce19, so that instead of calll'ing _fork, it simply jumps unconditionally to the failure case (i.e. it should act as if fork() had returned -1)

Unfortunately, I'm a complete newbie at disassembly/binary patching, so I'm not sure how to go about doing this. In particular, my questions are:

1) What bytes should I write into locations 0002ce19 through 0002xe1d to get what I want? I assume it would be the assembled equivalent of "jmp 0x0002cf02", but how do I figure out what those bytes are?

2) The offsets printed by "otool -tV" appear to be offsets into the __TEXT segment of the executable. How can I figure out the byte-delta between the printed offsets and the top of the file, so that I can edit/patch the correct bytes within the file?

Thanks for any advice you can give!

+3  A: 

I'm not familiar with the MacOS/X but I can give you some hints.

The proper way to fix it, is to use a disassembler to patch your file.

0002ce19        calll   0x00850ac9

can be replaced with

0002ce19        movl   eax, -1 ; mov eax, 0xFFFFFFFF

The offsets you see are relative, so you can not find them in the file.
For example, jll 0x0002cf02 is actually jll 0x000000DF

If I'm correct, the below code block

0002ce19        calll   0x00850ac9      ; symbol stub for: _fork
0002ce1e        cmpl    $0x00,%eax
0002ce21        jll     0x0002cf02
0002ce27        jle     0x0002ce34

will have this assembled form (20 bytes):

0x  E8   AB3C8200
    83F8 00
    0F8C DF000000
    0F84 0B000000

If that sequence is unique in the file then you can try to change the E8AB3C8200 to B8FFFFFFFF, if you can't use a disassembler.

Nick D
It worked like a charm! Thanks so much for your help!
Jeremy Friesner
@Jeremy Friesner, I'm glad I could help :)
Nick D
+1  A: 

otx and Hex Fiend will be your friends. otx will give you a disassembly with file-relative offsets, and Hex Fiend will let you patch out the jump. Remember that 0x90 is the (x86) opcode for NOP, so 9090909090 is an appropriate replacement for the fork() call. (Just keep in mind that it won't generate a return value, so something weird may end up in eax.)

+1  A: 

Probably the easiest would be to put mov $-1, %eax in place of the call. You can find out what bytes that corresponds to by putting it in a .s file, compiling it, and dumping the result, padding with nops if it is shorter than the patch location. I get "b8 ff ff ff ff", which just fits.

You can find the start of __TEXT by running otool -l and looking for the offset.

Keith Randall