Borland C++ 5.5 Compilerで学ぶWin32記号プログラミング

takesako
2010-12-17

こんばんわ。id:TAKESAKOです。

連日の投稿になってしまいますが、せっかく前日に80386のプログラミングテクニックを覚えたので、
Win32 Trackに対抗して、Borland C++ 5.5 Compilerで記号プログラミングをしてみましょう。

char main[]="`%[_-]%-```%`-_-`[_][_]_[-~-%#-[,~]-#[],-][_--_[_%`________-_"
"`~#--)_]-`]~`-`#-[-`]`[`]]]]]]]]),_-]_%%-,#)--)_----_%,--[%,`_]]_]][-,-)~"
"--`-`-),][---~`-`-_%`][[_]][-_`[%-~%#]-~`%)-)~#---_%-`____]_]-,_%%-,~_--)"
"~[,-%]])-#-]#`]_[[_[]-)%[]-)#%~-__~_-)]`~--~`[`][]][_]-%-~%-%)_%-,~[)--%#"
",--%,)`]_[[][]-`~[`-[],%-[[-#-~]-#-#--#`]__]_[]-%_,--#_~--#`,#-]~~%-[~[#`"
"_[]_[_[-]]]`--~_`-))`#-~,-#-%#%#`_]_]_]]---_%---~---%_#-,[~`-,%][`_][]__]"
"-]),)-~`%`-,~~`--`-`-~%~``[[_]][]-]`#]---`--,-~,-%_%)-%,%-`[[][]]]-[--%-%"
"`,#-_~][-#[~#-%`~#`[][[[][-%[~--]_~#--%)_-,%#_-_`#]`[__]]__--_][-,_,~-,,~"
"~-,,~_-,))``___[]]_,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"
",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,";

最後の,,,,,,,,,,,,,,,,の繰り返しは自己書き換え用のパディング領域です。sub命令なのでalレジスタの値が変わってしまいますが、2バイトコードのnop的な役割で使用しています。

デモ

WindowsXP日本語版SP2のBorland C++ 5.5 Compilerでしか動作しませんが、動きましたね。

自己展開コード

前回と同じ原理で、以下のWindows XP SP2シェルコードがスタック上に展開されます。

00000000  31 C0             xor eax,eax
00000002  50                push eax
00000003  E8 0E 00 00 00    call label_16
00000008  48 65 6C 6C 6F    db "Hello"
0000000C  2C 20 57 6F 72    db ", wor"
00000012  6C 64 21 00       dd "ld!",0
label_16:
00000016  E8 0E 00 00 00    call label_29
0000001B  41 56 54 6F 6B    db "AVTok"
00000020  79 6F 20 32 30    db "yo 20"
00000025  31 30 21 00       db "10!",0
label_29:
00000029  50                push eax
0000002A  B871EA3F77        mov eax,0x773fea71 ; MessageBoxA @ user32.dll
0000002F  FFD0              call eax
00000031  B8EF2A2576        mov eax,0x76252aef ; ExitProcess @ kernel32.dll
00000036  FFD0              call eax

DLLの各種APIを絶対アドレスで呼び出しています。

WindowsXP日本語版SP2における絶対アドレス

  • user32.dll の MessageBoxA は 0x773fea71
  • kernel32.dll の ExitProcess は 0x76252aef

ですよね。わかります。試験に出るので暗記しておきましょう。

引き算SUB命令のopcode表

インテルのx86マニュアルを見ると0x08~0x7Fの範囲のopcode表は以下の通りです。

 +--+--------+--------+--------+--------+--------+--------+--------+--------+
 |  |    0   |    1   |    2   |    3   |    4   |    5   |    6   |    7   |
 +--+--------+--------+--------+--------+--------+--------+--------+--------+
 | 0|                         ADD                         |PUSH    |POP     |
 |  |mb+=rb  |mw+=rw  |rb+=rmb |rw+=rmw |al+=ib  |ax+=iw  |es      |es      |
 +--+--------+--------+--------+--------+--------+--------+--------+--------+
 | 1|                         ADC                         |PUSH    |POP     |
 |  |mb+=rb  |mw+=rw  |rb+=rmb |rw+=rmw |al+=ib  |ax+=iw  |ss      |ss      |
 +--+--------+--------+--------+--------+--------+--------+--------+--------+
 | 2|                         AND                         |        |DAA     |
 |  |mb&=rb  |mw&=rw  |rb&=rmb |rw&=rmw |al&=ib  |ax&=iw  |es:     |        |
 +--+--------+--------+--------+--------+--------+--------+--------+--------+
 | 3|                         XOR                         |        |AAA     |
 |  |mb^=rb  |mw^=rw  |rb^=rmb |rw^=rmw |al^=ib  |ax^=iw  |ss:     |        |
 +--+--------+--------+--------+--------+--------+--------+--------+--------+
 | 4|                                  INC                                  |
 |  |ax++    |cx++    |dx++    |bx++    |sp++    |bp++    |si++    |di++    |
 +--+--------+--------+--------+--------+--------+--------+--------+--------+
 | 5|                                 PUSH                                  |
 |  |ax      |cx      |dx      |bx      |sp      |bp      |si      |di      |
 +--+--------+--------+--------+--------+--------+--------+--------+--------+
 | 6|PUSHA   |POPA    |BOUND   |ARPL    |        |        |Operand |Address |
 |  |        |        |rw,md   |rmw,rw  |fs:     |gs:     |Size    |Size    |
 +--+--------+--------+--------+--------+--------+--------+--------+--------+
 | 7|JO      |JNO     |JC/JB/  |JNC/JNB/|JZ/JE   |JNZ/JNE |JNA/JBE |JA/JNBE |
 |  |rs      |rs      |JNAE  rs|JAE   rs|rs      |rs      |rs      |rs      |
 +--+--------+--------+--------+--------+--------+--------+--------+--------+

 +--+--------+--------+--------+--------+--------+--------+--------+--------+
 |  |    8   |    9   |    A   |    B   |    C   |    D   |    E   |    F   |
 +--+--------+--------+--------+--------+--------+--------+--------+--------+
 | 0|                         OR                          |PUSH    |2Byte   |
 |  |mb|=rb  |mw|=rw  |rb|=rmb |rw|=rmw |al|=ib  |ax|=iw  |cs      |OPcode  |
 +--+--------+--------+--------+--------+--------+--------+--------+--------+
 | 1|                         SBB                         |PUSH    |POP     |
 |  |mb-=rb  |mw-=rw  |rb-=rmb |rw-=rmw |al-=ib  |ax-=iw  |ds      |ds      |
 +--+--------+--------+--------+--------+--------+--------+--------+--------+
 | 2|                         SUB                         |        |DAS     |
 |  |mb-=rb  |mw-=rw  |rb-=rmb |rw-=rmw |al-=ib  |ax-=iw  |cs:     |        |
 +--+--------+--------+--------+--------+--------+--------+--------+--------+
 | 3|                         CMP                         |        |AAS     |
 |  |f=mb-rb |f=mw-rw |f=rb-rmb|f=rw-rmw|f=al-ib |f=ax-iw |ds:     |        |
 +--+--------+--------+--------+--------+--------+--------+--------+--------+
 | 4|                                  DEC                                  |
 |  |ax--    |cx--    |dx--    |bx--    |sp--    |bp--    |si--    |di--    |
 +--+--------+--------+--------+--------+--------+--------+--------+--------+
 | 5|                                  POP                                  |
 |  |ax      |cx      |dx      |bx      |sp      |bp      |si      |di      |
 +--+--------+--------+--------+--------+--------+--------+--------+--------+
 | 6|PUSH    |IMUL rw=|PUSH    |IMUL rw=|INSB    |INSW    |OUTSB   |OUTSW   |
 |  |iw      |rmw*iw  |ib      |rmw*ib  |        |        |        |        |
 +--+--------+--------+--------+--------+--------+--------+--------+--------+
 | 7|JS      |JNS     |JP/JPE  |JNP/JPO |JL/JNGE |JNL/JGE |JNG/JLE |JG/JNLE |
 |  |rs      |rs      |rs      |rs      |rs      |rs      |rs      |rs      |
 +--+--------+--------+--------+--------+--------+--------+--------+--------+

ちょうど0x28~0x2Dの範囲がSUB命令の1バイト目となっていますね。

28 29 2A 2B 2C 2D
(  )  *  +  ,  -

10文字記号限定

プログラムのソースをよく見るとわかるのですが、x86で使っている記号の文字が10種類しかありません。

# % ) , - [ ] _ ` ~

これらの記号をASCIIコードを数値とみなして0から引き算して数を作ってみます。

SUB×1

[130,160,161,163,165,211,212,215,219,221,]

SUB×2

[4,34,35,37,39,64,65,66,67,68,69,70,72,74,85,86,89,93,95,115,116,117,118,119,
120,121,122,123,124,125,126,128,130,166,167,168,170,171,174,175,176,177,178,
180,182,184,186,]

SUB×3

[0,2,4,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,37,39,40,41,42,44,
45,48,49,50,51,52,54,56,58,60,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,
85,86,87,88,89,90,91,93,95,121,122,123,124,125,126,127,129,130,131,132,133,
134,135,136,137,138,139,140,141,142,143,145,147,149,151,164,165,167,169,194,
195,196,197,198,199,200,202,204,215,216,219,223,224,225,226,227,228,229,230,
231,232,233,234,235,237,239,245,246,247,248,249,250,251,252,253,254,255,]

SUB×4

[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,19,21,23,25,26,27,28,29,30,31,
32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,
58,60,68,69,70,71,72,73,74,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,
92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,
113,114,116,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,
135,136,137,138,139,140,141,142,143,144,146,148,149,150,151,152,153,154,155,
156,157,158,159,160,161,162,163,164,165,167,169,170,171,172,174,175,178,179,
180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,
199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,
218,219,220,221,223,225,230,231,232,233,234,235,236,237,238,239,240,241,242,
243,244,245,246,247,248,249,250,251,252,253,254,255,]

SUB×5

[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,
29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,
55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,
81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,
105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,
124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,
143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,
162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,
181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,
200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,
219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,
238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255]

このように5回の引き算を行えば、0~255の任意の数値を作成することができます。

次回予告

勘の良い人ならすぐにわかると思いますが、引き算の回数を増やせばもっと記号の種類を減らせるかもしれませんね。最後は極限の7文字まで減らした記号プログラミングを試してみたいと思います。