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 d开发者_运维知识库isassembly 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!
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.
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.
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.)
精彩评论