.dataセグメントにある構造体のメンバの値を書き換えることはできるか

悩んでいます。→とりあえずできました。

オイラ的な最近の話題の一つとして、MySQL文字コードのとある制御用フラグ(escape_with_backslash_is_dangerous)があるんですが、

CHARSET_INFO my_charset_sjis_japanese_ci=
{
    13,0,0,             /* number */
    MY_CS_COMPILED|MY_CS_PRIMARY|MY_CS_STRNXFRM,        /* state      */
    "sjis",             /* cs name    */
    "sjis_japanese_ci", /* name */
    "",                 /* comment    */
    NULL,               /* tailoring */
    ctype_sjis,
    to_lower_sjis,
    to_upper_sjis,
    sort_order_sjis,
    NULL,               /* contractions */
    NULL,               /* sort_order_big*/
    NULL,               /* tab_to_uni   */
    NULL,               /* tab_from_uni */
    my_unicase_default, /* caseinfo     */
    NULL,               /* state_map    */
    NULL,               /* ident_map    */
    1,                  /* strxfrm_multiply */
    1,                  /* caseup_multiply  */
    1,                  /* casedn_multiply  */
    1,                  /* mbminlen   */
    2,                  /* mbmaxlen */
    0,                  /* min_sort_char */
    255,                /* max_sort_char */
    ' ',                /* pad char      */
    0,                  /* escape_with_backslash_is_dangerous */
    &my_charset_handler,
    &my_collation_ci_handler
};

このescape_with_backslash_is_dangerousをbinary hack的に0から1に書き換える方法はないかと思案しています。

nm+grepでmy_charset_sjis_japanese_ciがデータセクションに入っているのを確認できます。

mir@t43:~/tritonn/show/install/bin$ nm --demangl mysqld | grep my_charset_sjis_japanese_ci
085b4aa0 D my_charset_sjis_japanese_ci

アドレスが0x085b4aa0となっていて、sizeof(my_charset_sjis_japanese_ci) = 108なので、

mir@t43:~/tritonn/show/install/bin$ objdump -s --start-address=0x085b4aa0 --stop-address=0x085b4b0c mysqld

mysqld:     ファイル形式 elf32-i386

セクション .data の内容:
 85b4aa0 0d000000 00000000 00000000 61000000  ............a...
 85b4ab0 32494e08 37494e08 48494e08 00000000  2IN.7IN.HIN.....
 85b4ac0 60495a08 804a5a08 804b5a08 804c5a08  `IZ..JZ..KZ..LZ.
 85b4ad0 00000000 00000000 00000000 00000000  ................
 85b4ae0 605c5d08 00000000 00000000 01000000  `\].............
 85b4af0 01010000 01000000 02000000 0000ff00  ................
 85b4b00 20000000 204a5b08 e0495b08            ... J[..I[.

たぶんこれがmy_charset_sjis_japanese_ciなんだと思うのですが、これを、

 85b4aa0 0d000000 00000000 00000000 61000000  ............a...
 85b4ab0 32494e08 37494e08 48494e08 00000000  2IN.7IN.HIN.....
 85b4ac0 60495a08 804a5a08 804b5a08 804c5a08  `IZ..JZ..KZ..LZ.
 85b4ad0 00000000 00000000 00000000 00000000  ................
 85b4ae0 605c5d08 00000000 00000000 01000000  `\].............
 85b4af0 01010000 01000000 02000000 0000ff00  ................
 85b4b00 20010000 204a5b08 e0495b08            ... J[..I[.

こうしたい訳です。何か良い方法はないですかね。

readelfによれば、.dataセクションはファイルオフセット0x49e580からのようです。

mir@t43:~/tritonn/show/install/bin$ readelf -S mysqld
37 個のセクションヘッダ、始点オフセット 0x130e71c:

Section Headers:
  [番] 名前              タイプ          アドレス Off    サイズ ES Flg Lk Inf Al
  [23] .data             PROGBITS        084e6580 49e580 113e0c 00  WA  0   0 32

書き換えたいバイトのアドレスは、0x085b4b01で、.dataの先頭が0x084e6580だから、差し引き、、、

0x085b4b01 - 0x084e6580 = 0xCE581

となって、ファイルオフセットでいうと、

0x49e580 + 0xCE581 = 0x56CB01

ということで、hexdump -Cした内容で見ると、、、

0056caa0  0d 00 00 00 00 00 00 00  00 00 00 00 61 00 00 00  |............a...|
0056cab0  32 49 4e 08 37 49 4e 08  48 49 4e 08 00 00 00 00  |2IN.7IN.HIN.....|
0056cac0  60 49 5a 08 80 4a 5a 08  80 4b 5a 08 80 4c 5a 08  |`IZ..JZ..KZ..LZ.|
0056cad0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
0056cae0  60 5c 5d 08 00 00 00 00  00 00 00 00 01 00 00 00  |`\].............|
0056caf0  01 01 00 00 01 00 00 00  02 00 00 00 00 00 ff 00  |................|
0056cb00  20 00 00 00 20 4a 5b 08  e0 49 5b 08 00 00 00 00  | ... J[..I[.....|

ここですね。

ここで、my ubuntuバイナリエディタが入っていないことに気づくw 適当にいくつか入れる(bbe, beav, biew, bvi)。

あと「バイナリファイル 書き換え」でぐぐったら楽しそうな資料を発見したので載せておきます。

http://gotom.jp/~gotom/pub/2005-12-binary-2.0/Binary2.0Conf-presen/gotom.pdf

# 良くみたら、これbinary2.0カンファレンスで講演した方の資料ですな。

bviで0x0056CB01に飛んで00を01に書き換え。確認すると書き換わってた。

セクション .data の内容:
 85b4aa0 0d000000 00000000 00000000 61000000  ............a...
 85b4ab0 32494e08 37494e08 48494e08 00000000  2IN.7IN.HIN.....
 85b4ac0 60495a08 804a5a08 804b5a08 804c5a08  `IZ..JZ..KZ..LZ.
 85b4ad0 00000000 00000000 00000000 00000000  ................
 85b4ae0 605c5d08 00000000 00000000 01000000  `\].............
 85b4af0 01010000 01000000 02000000 0000ff00  ................
 85b4b00 20010000 204a5b08 e0495b08            ... J[..I[.

で、この「任意のファイルアドレスの値を書き換える」ってのをエディタ上でなくコマンドライン上でやるにはどーしたらいいんだろう。それができれば、ここまでの作業をスクリプト化して、フラグ書き換えパッチとかできそーなんですが。

bvi -s 0x0056CB01 -e 0x0056CB01 -f hoge mysqld

hogeに上手いこと書いたらいけそーな気がするが、hogeが上手くかけず、、、今日はここで撃沈。



改変したいバイナリとまったく同じバイナリを用意できるなら、bsdiff/bspatchでいいね。というか用意できるならそもそもreadelfとかいらねーかw
http://x68000.q-e-d.net/~68user/unix/pickup?bsdiff