![[ksnctf] Lives out [ksnctf] Lives out](/images/4/3/3/1/d/4331d2cce072e291075b8c2812eddba57a02a88e-27.png)
ksnctfにチャレンジ 第27問目です。
※ksnctfは常駐型のCTFサイトです。 ※問題のページはコチラです。
リバースエンジニアリング問題です。 対象のプログラムがPE64形式つまり Windowsの64bitアプリケーション ということで各種ツールに慣れていなかったり、なんとなく敬遠していたりで 飛ばしていましたが、重い腰を上げて取り組んでみました。
プログラムを起動すると ライフゲームらしきドットがチカチカ し始めます。問題ページのヒントには
Can you switch all the lights off?
とありますが、もちろんプログラムの特性上全部の輝点を 消すのはむりなので当然プログラム中の判定部分を探せ、 ということでしょう。
まずは VisualStudioで livesout.exe のプロセスにアタッチして 一時停止ボタンをポチポチ押しつつ動作を探って行き、 同時に snowman を使ってなんちゃってC++のコードに直しました。
x86コードならIDA Proで片付くはずですがFree版は x86_64が弄れないのでこのあたり面倒です。
VisualStudioの逆アセンブル画面とsnowmanの画面を見比べて Callで呼び出している API名なども確認していきます。
00007FF737E311C0 lea rcx,[rsp+60h]
00007FF737E311C5 call qword ptr [7FF737E331D0h]
00007FF737E311CB lea rcx,[rsp+60h]
00007FF737E311D0 call qword ptr [7FF737E33210h]
00007FF737E311D6 lea rcx,[rsp+60h]
00007FF737E311DB xor r9d,r9d
00007FF737E311DE xor r8d,r8d
00007FF737E311E1 xor edx,edx
00007FF737E311E3 call qword ptr [7FF737E331B0h]
00007FF737E311E9 test eax,eax
00007FF737E311EB jne 00007FF737E311C0
Snowmanの画面の↑この部分を見比べれば
この部分はもともとWinアプリの
メッセージループに相当する場所だとわかります。
同じようにして snowmanを軽く参考にしつつVisualStudioでブレークポイントを 打って調べていきます。
7FF7'37E31220 からが主な部分で snowmanの出力コードから
SetTime
PostQuitMessage
BeginPaint
CreateSolidBrush
SelectObject
Rectangle
DeleteObject
InvalidateRect
DefWindowProcW
EndPaint
TextOutW
このようなAPIが呼び出されていることがわかります。 ここで明らかに怪しいのが
TextOutW
当然これですね。
Livesout.exeでは基本的に文字列を表示することは ないはずなのでこれがFLAGを表示している可能性が大です。
TextOutWは
00007FF737E31728 lea r9,[rbp+160h] ←なんらかの文字列
00007FF737E3172F xor r8d,r8d ← 表示y座標 0
00007FF737E31732 xor edx,edx ← 表示x座標 0
00007FF737E31734 mov rcx,rbx ← hdc?
00007FF737E31737 mov dword ptr [rsp+20h],15h ← 文字数が 0x15 = 21 FLAG_{16文字}とあってる!
00007FF737E3173F call qword ptr [7FF737E33010h] ← TextOutW()
この部分で呼ばれていて、 座標 (0,0) に 21文字の文字列を表示するようになってます これは確定っぽいです。
この部分の前のコードをどんどん遡っていくと なにやらmovdqa命令を連発してメモリにデータを作っているようなので ここでFLAG文字列を構成しているのでしょう。
問題はこの部分の直前
00007FF737E3155E test r11b,r11b
00007FF737E31561 je 00007FF737E31745
00007FF737E31567 movdqa xmm0,xmmword ptr [7FF737E332B0h]
…以下 movdaqaいっぱい
紆余曲折して
00007FF737E3173F call qword ptr [7FF737E33010h] ← TextOutW()
ここです。
test命令の結果常にゼロフラグ=1 になるので直後の je は常に 有効でいずこかへ飛んでいってしまいます。 ここを書き換えれば良さそうです。
というわけでこういうときは うさみみハリケーンの出番です。
うさみみハリケーンのデバッグから [選択範囲を逆アセンブル] を選んで問題の JE命令部分
7FF7'37E31561 -- 7FF7'37E31566
を逆アセンブル このジャンプ命令を NOP(0x90) で埋め尽くして潰してしまいます。
すると TextOutW() に到達するようになって 画面に FLAG文字列が表示されるようになりました。