環境
Mac / gcc / gdb / binutils
対象になるコードをビルド
#include <stdio.h>
#include <stdbool.h>
static bool superduperUltimateCheckMethod() {
bool response = false; // ミス、本当はtrueを返すのが正しかった。。。
return response;
}
int main() {
printf("%s", superduperUltimateCheckMethod() ? ";D" : ":(");
return 0;
}
こうして
gcc -g main.c -o bin
ズドン。
一応動作チェック。
./bin
:(
当然 superduperUltimateCheckMethod
は常に false を返してくる実装になっているので、渋い顔文字が出力されます。
求める正しい挙動は ;D が出力される事です。
本来ならばコードを修正する所ですが、今回はこのバイナリ自体を弄って正しい挙動を実現してみます。
「コード・・・バグっちゃったね・・・///」
待って!あきらめるのはまだ早いよ!
(略)
実際にどのHexを修正するか確認する。
gobjdump -d bin
(略)
0000000100000f70 <_superduperUltimateCheckMethod>:
(略)
100000f74: c6 45 ff 00 movb $0x0,-0x1(%rbp) // これだ!
正しくは $0x1 となって居ないとちゃんと動作しない部分が、上記のコードのミスで $0x0 となっていますね。
目的は、Hex上の「00」を「01」に治すだけ!
では修正に向けて、早速viでバイナリの中身を見てみましょう。
vi bin
:%!xxd
42 0000290: 626f 6c5f 7074 7200 5f5f 4441 5441 0000 bol_ptr.__DATA..
43 00002a0: 0000 0000 0000 0000 0010 0000 0100 0000 ................
44 00002b0: 1000 0000 0000 0000 0010 0000 0300 0000 ................
45 00002c0: 0000 0000 0000 0000 0600 0000 0100 0000 ................
46 00002d0: 0000 0000 0000 0000 5f5f 6c61 5f73 796d ........__la_sym
47 00002e0: 626f 6c5f 7074 7200 5f5f 4441 5441 0000 bol_ptr.__DATA..
48 00002f0: 0000 0000 0000 0000 1010 0000 0100 0000 ................
49 0000300: 0800 0000 0000 0000 1010 0000 0300 0000 ................
50 0000310: 0000 0000 0000 0000 0700 0000 0300 0000 ................
51 0000320: 0000 0000 0000 0000 1900 0000 4800 0000 ............H...
52 0000330: 5f5f 4c49 4e4b 4544 4954 0000 0000 0000 __LINKEDIT......
なるほど!!
:%s/00/&/gn
8803 matches on 551 lines
なるほど、わからん!
何処のオフセットに位置しているか調べる
gobjdump -x bin
(略)
索引名 サイズ VMA LMA File off Algn
0 .text 00000062 0000000100000f20 0000000100000f20 00000f20 2**4
(略)
SYMBOL TABLE:
(略)
0000000100000f70 d 24 FUN 01 0000 _superduperUltimateCheckMethod
太字になっている所が大事な所です。
私の環境での結果を見やすく纏めると
VMA = 0000000100000f20
fileOff = 00000f20
targetSymbol = 0000000100000f70
となります。
targetOffset = fileOff + (targetSymbol - VMA)
の公式を元に計算すると、私の環境では
f70 との結果が出ました。
つまり、 「00 を 01 に変更する必要があるオフセット位置は "f70"」 という事まで分かりました。
実際にHexを弄る。
vi bin
:%!xxd
:/f70
248 0000f70: 5548 89e5 c645 ff 00 8a45 ff24 010f b6c0 UH...E...E.$....
やったぜ。
今回修正対象になるのは 「00」 なので、一目瞭然です。
viでここを 「01」 に変更して保存します。
248 0000f70: 5548 89e5 c645 ff 01 8a45 ff24 010f b6c0 UH...E...E.$....
:%!xxd -r
弄くったものを確認してみる。
gobjdump -d bin
(略)
0000000100000f70 <_superduperUltimateCheckMethod>:
(略)
100000f74: c6 45 ff 01 movb $0x1,-0x1(%rbp) // ちゃんと $0x1 に変わってる!!
ズドン
./bin
;D
笑顔あったけぇ・・・