LINE CTF 2024へ、一人チームrotation
で参加しました。そのwrite-up記事です。またおまけとして、Binary Ninjaを初めて触ったのでIDAとのふんわり比較も記述しています。
また、今回からお試しとして、IDAの解析結果ファイル*.i64
等をGitHubで公開してみることにしました。https://github.com/Tan90909090/ctf-writeups/tree/main/LINE_CTF_2024をご参照ください。
2024/04/02(火) 01:00頃追記: BrownFlagChecker
問題の元ソースコードが公開されています: Black-Frost/LineCtf2024
- コンテスト概要
- 結果
- 環境
- 解けた問題
- 感想
- おまけ: Binary Ninja FreeとIDA Freeの、機能面や逆コンパイル結果の比較
- Binary Ninjaのオフライン逆コンパイルが嬉しい
- Binary NinjaもIDAもキーボードショートカットはだいたい同じ、一部違うので注意
- Binary NinjaはNTOSKRNL関係の構造体定義を持っている
- Binary NinjaはIMAGE_DOS_HEADER構造体の定義を持っていない?
- Binary Ninjaは逆コンパイル結果にもアドレス表示があって嬉しい
- Binary Ninjaはnot命令の逆コンパイルを!演算子としてしまっている
- Binary Ninjaは1つの文中に多くの関数呼び出しを含めることがある
- Binary Ninjaは構造体ポインター経由の多段アクセスのメンバー認識がちょっと弱そう
- Binary Ninjaの多段分岐表示が読みやすいかも
- Binary Ninjaのグローバル変数や配列の表示が分かりやすい
コンテスト概要
2024/03/23(土) 09:00 +09:00 - 2024/03/24(日) 09:00 +09:00 の24時間開催でした。他ルールはトップページから引用します:
Information - Name: LINE CTF 2024 - Schedule: March 23, 2024, 09:00 AM ~ March 24, 2024, 09:00 AM (UTC+9) - Style: Jeopardy-style (Team Competition @ Online) - Organizer: Security team at LY Corporation - Discord: https://discord.gg/jqFhg4TVpK - Contact: dl_ctf@linecorp.com - Bugbounty: https://hackerone.com/line - Prizes: - 🥇1st: $5,000 - 🥈2nd: $3,000 - 🥉3rd: $2,000 Rules - Do not participate and play on multiple teams. - Do not share flags or any hints. - Do not ask other players who are not on the same team for hints on challenges via DM, etc. - Do not attack scoreboard server or our infra. (e.g. DoS) - Do not do scanning. - The flag format is LINECTF{[0-9a-f]{32}} - There is no team size limit - The displayed amount of prize money will be transferred in USD. LINE will bear the transfer cost. - We will ask for your PII for payment of rewards and checking of anti-social forces - For residents in Japan, we will ask your My Number for payment records - We will not support the multiple transfer accounts. Only one bank account can receive the rewards - We reserve the right to ban and disqualify any teams breaking any of these rules - The Top 3 will need to send us (dl_ctf@linecorp.com) a writeup until 2024.03.25 09:00 (UTC+9) - Unfortunately, due to current geopolitical events, participants from Russia are NOT eligible to receive prize money
上記ルール中では出題ジャンルの言及はありませんが、Discordサーバーへ参加するとCATEGORIES
としてpwn
、web
、rev
、crypto
、misc
チャンネルが最初からあったため、推測はできました。なお競技開始後に分かったことですが、ジャンルごとの出題問題数には大きな差がありました:
- web: 12問
- misc: 3問(welcome問題含む)
- pwn: 2問
- rev: 1問
- crypto: 1問
結果
正の得点を得ている865チーム中、222点で107位でした。
環境
WindowsのWSL2(Ubuntu 22.04)などを使って取り組みました。また、rev問題でバイナリ実行用のWindowsマシンには、Download a Windows virtual machine - Windows app development | Microsoft Developerのものを使いました。
Windows
c:\>ver Microsoft Windows [Version 10.0.19045.4170] c:\>wsl -l -v NAME STATE VERSION * Ubuntu-22.04 Running 2 kali-linux Stopped 2 docker-desktop Stopped 2 docker-desktop-data Stopped 2 c:\>
他ソフト
- IDA Free Version 8.4.240320 Windows x64 (64-bit address size)(Free版IDAでもversion 7頃からx64バイナリを、version 8.2からはx86バイナリもクラウドベースの逆コンパイルができます)
- Binary Ninja Free 4.0.4958-Stable
- Microsoft Visual Studio Community 2022 (64-bit) - Current Version 17.8.3
WSL2(Ubuntu 22.04)
$ cat /proc/version Linux version 5.15.146.1-microsoft-standard-WSL2 (root@65c757a075e2) (gcc (GCC) 11.2.0, GNU ld (GNU Binutils) 2.37) #1 SMP Thu Jan 11 04:09:03 UTC 2024 $ cat /etc/os-release PRETTY_NAME="Ubuntu 22.04.4 LTS" NAME="Ubuntu" VERSION_ID="22.04" VERSION="22.04.4 LTS (Jammy Jellyfish)" VERSION_CODENAME=jammy ID=ubuntu ID_LIKE=debian HOME_URL="https://www.ubuntu.com/" SUPPORT_URL="https://help.ubuntu.com/" BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/" PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy" UBUNTU_CODENAME=jammy $ python3 --version Python 3.10.12 $ python3 -m pip show pycryptodome | grep Version Version: 3.14.1 $
解けた問題
[misc] welcome (821 teams solved, 1 point)
Welcome to the LINE CTF 2024! We hope you enjoy. LINECTF{6240995c64f58fe13d72d80760551344}
書かれていたフラグを提出して正解できました: LINECTF{6240995c64f58fe13d72d80760551344}
[rev] BrownFlagChecker (17 teams solved, 221 points)
Brown the Bear just learned about how people protect their games from cheaters. He wants to try those techniques, but he doesn't know how to make a game...
配布ファイルとして、バイナリ2つと、起動方法等の説明がありました:
$ file * BrownFlagChecker.exe: PE32+ executable (console) x86-64, for MS Windows BrownProtector.sys: PE32+ executable (native) x86-64, for MS Windows README.md: ASCII text, with CRLF line terminators $ cat README.md This challenge should be run in a Windows 10 or 11 VM, with `Secure Boot` disabled. You must enable `Test mode` in the VM (See what is `Test mode` here: https://learn.microsoft.com/en-us/windows-hardware/drivers/install/the-testsigning-boot-configuration-option) To enable `Test mode`, run the following command in an administrator command prompt. ``` bcdedit.exe -set TESTSIGNING ON ``` After that, reboot your VM. The binary must also be run in an administrator command prompt. $
はい、.sys
ファイルがあります。WindowsのKernel Mode Driver(KMD)を使った問題です!以降、私の本問題の理解を記述していきますが、私はKMDの知識がほとんどありません。誤り等あればコメント等で教えていただければ嬉しいです。
実行環境の準備
README.md
にあるとおり、本問題のバイナリ群は、Test mode
に設定したWindows VMでの実行が想定されています。私は普段、細々とした実行にはWindows Sandboxを使っていますが、Test mode
設定にするため再起動が必要だったり、そもそもThe boot configuration data store could not be opened.
The requested system device cannot be found.
エラーでだめでした。
「確かMicrosoft社は評価用のものを配布していたはず」とGoogle検索するとDownload a Windows virtual machine - Windows app development | Microsoft Developerを見つけました。VirtualBox用ovaファイルをダウンロードしてインポートして起動しました。README.md
の通りにTest mode
設定も成功して、無事に本問題のバイナリを起動できました:
c:\Users\User\Desktop\work>BrownFlagChecker.exe NtLoadDriver failed with code: 0xc000010e c:\Users\User\Desktop\work>BrownFlagChecker.exe Welcome! Give me the key and I will give you the flag: test Wrong! But here is a clue just for you: https://rb.gy/i6drqn c:\Users\User\Desktop\work>
たまにNtLoadDriver
などでエラーになることがありますが、何度か実行すれば正常にフラグ入力ができました。これで動作検証できる環境を用意できました。
ひたすら読解
BrownFlagChecker.exe
とBrownProtector.sys
の処理を、頑張ってひたすら読み解いていきました。
BrownFlagChecker.exe
は一般的なEXEなので、Free版IDAで問題なく解析できました。ただBrownProtector.sys
はKMDなのでDRIVER_OBJECT型などのKMD用の構造体を多用していますが、Free版IDAではそれらの構造体定義が含まれていないようでした。そこで最近公開されたBinary NinjaのFree版を試しにインストールして読ませてみると、DRIVER_OBJECT
は適切に認識してくれました。もう少し調べると、Binary Ninjaはntoskrnl
からインポートしている型は認識してくれましたが、WDFLDR
からインポートしている型(WDF_BIND_INFO
)は含まれていないようでした(Microsoftドキュメントも特段無さそうでした)。WDFLDR
関連の型は少なかったので、ググってReactOSでの型定義を参考に、自分で定義しました。一方で、逆コンパイル結果はFree版IDAの方が見やすい傾向であったため、BrownProtector.sys
処理内容の解析にはFree版IDAとFree版Binary Ninjaを併用しました。比較して思ったことは本記事最後に参考として記述します。
制御やデータの流れの理解
ひたすら読解した結果、BrownFlagChecker.exe
起動後は以下の流れであることが分かりました:
- (
BrownFlagChecker.exe
の0x140003B36
付近)IsDebuggerPresent
がFALSE
を返す場合の分岐の後で、CreateProcessA
でBrownFlagChecker.exe
をもう1つ起動します。この際dwCreationFlags
にDEBUG_ONLY_THIS_PROCESS
を指定しています。そのためか、子プロセス側は一旦サスペンド状態で起動するようです。以降、大本の起動側を「親プロセス」、CreateProcessA
により新たに起動された側を「子プロセス」と表現します。 - (親プロセス、
BrownFlagChecker.exe
の140001AF0
付近)CREATE_PROCESS_DEBUG_EVENT
時の分岐で呼び出す関数の中で、BrownProtector.sys
を、サービス登録したり、SeLoadDriverPrivilege
特権を取得してからのNtLoadDriver
で読み込んだりします。 - (親プロセス、
BrownProtector.sys
の0x140001034
付近)DRIVER_OBJECT
メンバーの、DriverUnload
、MajorFunction[IRP_MJ_DEVICE_CONTROL]
、MajorFunction[IRP_MJ_CREATE]
、MajorFunction[IRP_MJ_CLOSE]
に関数ポインターを設定したり、デバイスの初期設定を行ったりしているようです。本問題では、MajorFunction[IRP_MJ_DEVICE_CONTROL]
へ登録している関数(0x140001180
)が重要です。 - (親プロセス、
BrownFlagChecker.exe
の0x14000340C
付近)CreateFileA
でデバイスを開き、DeviceIoControl
で制御コード0x224000
を送信します。 - (親プロセス、
BrownProtector.sys
の0x14000142b
付近)PsGetCurrentProcessId
で親プロセスのPIDを取得して保持します。また、耐解析チェックを行います。チェック結果に問題なければ引数のバッファへ0x1337
を書き込みます。(問題があれば0xdead
を書き込み、BrownFlagChecker.exe
側で判定しています。以降も同様です。) - (親プロセス、
BrownFlagChecker.exe
の0x14000346D
付近)VirtualAlloc
で確保したバッファ20個へ固定値を格納します。ここでは格納するだけで、後で使います。ContinueDebugEvent
で子プロセスを続行させます(実質ここで子プロセスは始めて動作開始するはずです)。WaitForDebugEvent
で子プロセスのイベントを待ちます。 - (子プロセス、
BrownFlagChecker.exe
の0x140003A79
付近)IsDebuggerPresent
がTRUE
を返す場合の分岐の後で、0x1400031E0
の関数を呼び出します。 - (子プロセス、
BrownFlagChecker.exe
の0x140003260
付近)CreateFileA
でデバイスを開き、DeviceIoControl
で制御コード0x224004
を送信します。 - (子プロセス、
BrownProtector.sys
の0x1400013e4
付近)自身のプロセスの親プロセスのPIDが、先ほど取得した親プロセス側のPIDであることを検証します。PsGetCurrentProcessId
とPsGetCurrentThreadId
で、子プロセス側のPIDやTIDを取得して保持します。ObRegisterCallbacks
を使った何かの耐解析用らしいコールバックの設定が成功すれば、引数のバッファへ0x1337
を書き込みます。 - (子プロセス、
BrownFlagChecker.exe
の0x14000328B
付近)RAX
レジスタに1
を設定した状態で、idiv
命令で0除算を行います。例外が発生し、Debuggerである親プロセス側へ移行します。 - (親プロセス、
BrownFlagChecker.exe
の0x140003966
付近)STATUS_INTEGER_DIVIDE_BY_ZERO
時の分岐の中で、printf
でユーザー入力を促し、scanf
でユーザー入力を取得します。ユーザー入力が64文字である場合は、ユーザー入力内容と先ほど構築した固定値を含むバッファを、DeviceIoControl
で制御コード0x224008
で送信します。 - (親プロセス、
BrownProtector.sys
の0x140001387
付近)PIDチェックや耐解析チェックを行った後、受信データをグローバル変数に保持します。その後にCR3
レジスタの内容とMmGetVirtualForPhysical
を使って、何かをしています(詳細分からず)。SetThreadContext
で子プロセスのRIPを調整してから、ContinueDebugEvent
で子プロセスを続行させます。WaitForDebugEvent
で子プロセスのイベントを待ちます。 - (子プロセス、
BrownFlagChecker.exe
の0x1400032BE
付近)DeviceIoControl
で制御コード0x22400C
を送信します。 - (子プロセス、
BrownProtector.sys
の0x1400012eb
付近)PIDチェックやTIDチェックを行った後、先ほど保持した親プロセスからの入力を、MmAllocateContiguousMemory
やMmGetPhysicalAddress
、MmGetVirtualForPhysical
などを使って、何かをしています(詳細分からず)。引数のバッファへ0x1337
を書き込みます。 - (子プロセス、
BrownFlagChecker.exe
の0x140001E80
付近)DeviceIoControl
で制御コード0x224010
を送信します。 - (子プロセス、
BrownProtector.sys
の0x140001265
付近)PIDチェックやTIDチェック、耐解析チェックをした後、CR3
レジスタの内容とMmGetVirtualForPhysical
、rdtsc
命令を使って何かのアドレスを計算しています(詳細分からず)。計算結果を引数のバッファへ書き込みます。 - (子プロセス、
BrownFlagChecker.exe
の0x140001F1C
付近)DeviceIoControl
によりバッファに書き込まれたアドレスから計算したアドレスをsrc
として、memcpy
でコピーします。その後、DeviceIoControl
で制御コード0x224014
を送信します。- このあたりから「3文字長の文字列をスタック上に構築」しているように見える処理がありますが、実際は文字列ではなく8バイト整数型として使用します。
- (子プロセス、
BrownProtector.sys
の0x14000123f
付近)CR3
レジスタの内容とMmGetVirtualForPhysical
を使って何かをしています(詳細分からず)。 - (子プロセス、
BrownFlagChecker.exe
の0x140001F50
付近)「DeviceIoControl
で制御コード0x224010
を送信して、バッファに書き込まれたアドレスから計算したアドレスから読み込んで色々して、DeviceIoControl
で制御コード0x224014
を送信」を9回行います。 - (子プロセス、
BrownFlagChecker.exe
の0x140002741
付近)「DeviceIoControl
で制御コード0x224010
を送信して、バッファに書き込まれたアドレスから計算したアドレスを第2引数としてmemcmp
で比較して正誤判定し、DeviceIoControl
で制御コード0x224014
を送信」を行います。 - (子プロセス、
BrownFlagChecker.exe
の0x1400032E5
付近)EAX
の内容を、正解なら2
に、誤りなら3
に設定してから、idiv
命令で0除算を行います。例外が発生し、Debuggerである親プロセス側へ移行します。 - (親プロセス、
BrownFlagChecker.exe
の0x14000393F
付近)STATUS_INTEGER_DIVIDE_BY_ZERO
時の分岐の中で、子プロセスの例外発生時のEAX
レジスタ内容が2なら、入力内容を使ってフラグを復号して表示します。 - その後、諸々の終了時処理を行います。省略します。
このように、親プロセスであるDebuggerと子プロセスであるDebuggeeが、DeviceIoControl
経由でアドレスをやり取りしている、ものすごい問題でした。CR3
レジスタに関連する処理を全く理解できていませんが、もしかしたら手動でページングのようなことをしているのかもしれません。
なお、BrownFlagChecker.exe
の0x140003A05
付近には「子プロセスがSTATUS_ACCESS_VIOLATION
になった場合には、SetThreadContext
でRIP
を8増やしてから続行させる」処理が存在します。どこかでAccess Violationが起こることを前提としているようですが、具体的にどこなのかは分かりませんでした。
耐解析機構の理解
本問題には多数の耐解析機構が存在します。それらにより、本問題の難易度が上がっています。
BrownFlagChecker.exe
の子プロセス側は、Debuggeeとして動作します。1プロセスにアタッチできるDebuggerは1つだけであるため、「他にデバッガーを起動して子プロセスへアタッチ」が出来ません。- KMDには署名が必須なはずです。
BrownProtector.sys
にもデジタル署名が付与されており、コード部分等を改ざんしようものなら署名が無効になってしまって読み込めなくなるはずです。 BrownProtector.sys
には、多数の耐解析機構が実装されています:- 適切な順番で
DeviceIoControl
の各種制御コードが送られることや、各種制御コード送信時のPIDやTIDを検証します。 0x140001808
の関数では、ZwQueryInformationProcess
にProcessDebugPort
を指定してデバッグポート番号を取得し、それが0であることを検証しています。(NtQueryInformationProcess functionによると、ring 3デバッガー(=ユーザーランドデバッガー?)がアタッチされている場合に非0になるようです。)0x140001864
の関数では、CR0
レジスタの値とCR4
レジスタの値が特定の状態であることを検証しています(詳細分からず)。より具体的には、CR0 < 0 && (CR4 & 0x1000) == 0LL
がtrue
であることを検証しています。0x140001554
の関数では、ObRegisterCallbacks
を使って、ObjectTypeがPsProcessType
かPsThreadType
であるものについて、何かコールバックを設定しています(詳細分からず)。0x14000165C
の関数では、以下のようにBrownFlagChecker.exe
の改ざん検知を行っています:PEB::ImageBaseAddress
(=BrownFlagChecker.exe
の読み込みアドレス)を取得- 取得結果からPE構造をたどって、
.text
セクションの位置とサイズを取得 .text
セクション全体からハッシュ値を計算して、特定の値であることを検証
- 適切な順番で
0x14000165C
の関数で計算するハッシュ値は、0x140001000
の以下の関数で計算しています:
unsigned int __fastcall __pure SomeHashProc(const BYTE *pByteArray, __int64 qwLength) { unsigned int dwHash; // r9d unsigned __int64 byteCurrent; // r8 for ( dwHash = -1; qwLength; --qwLength ) { byteCurrent = *pByteArray++; dwHash = g_dwValueArraySize256[(unsigned __int8)dwHash ^ byteCurrent] ^ (dwHash >> 8); } return ~dwHash; }
暗号学的ハッシュ関数ではないはずですが、テーブルを使った値変換を含むため、「.text
セクションの一部を改ざんつつ、ハッシュ値が特定の値になるよう帳尻を合わせる」ことは難しいか面倒なように思います。 ← 終了後のDiscord書き込みで気付きましたが、CRC32を計算しているようです。CRC32なら意図的な衝突方法もあるかもしれません。
DLL Injection + IAT Hookingを使ったデータ内容確認
さて本問題を解くためには、子プロセスが最後の方に行っている、「DeviceIoControl
等経由で取得、計算したアドレスからの読み込み」の内容を是非確認したいです。前述したように本問題では多数の耐解析機構が搭載されていますが、「DLL InjectionしてDLLを読み込ませてBrownFlagChecker.exe
のIAT内容をDLL内部の自作関数へ改ざんすれば、.text
セクション内容はそのままに、BrownFlagChecker.exe
のAPI呼び出し時に色々状態を確認できそう」と考えました。以前にDLL Injection + IAT Hookingを試した事があったので、その時のソースコードを引っ張ってきて試したら無事に動いてくれました。使ったソースコードはGitHubに置いています。
本手法を使う上で注意が必要だった点です:
- 前述した通り、親プロセスが子プロセスを起動する際、
CreateProcessA
のdwCreationFlags
引数にDEBUG_ONLY_THIS_PROCESS
を指定しています。また、DLL Injectionする際は、CREATE_SUSPENDED
を指定して起動することが定石です。ただ、CREATE_SUSPENDED | DEBUG_ONLY_THIS_PROCESS
を指定してしまうと、CreateRemoteThread
用途で起動したスレッドもサスペンド状態になってしまうようでした。最終的に「CreateProcessA
にCREATE_SUSPENDED
のみを指定して起動して、CreateRemoteThread
でDLL Injectionして、その後DebugActiveProcess
でアタッチ」することで、うまく動作しました。 - 通常の
CreateProcessA
による子プロセスの起動では、親子でコンソールを共有します。ただ親子それぞれの出力が出力が1文字単位で混ざることがあったため、CreateProcessA
のdwCreationFlags
引数にCREATE_NEW_CONSOLE
を追加することで、親子でコンソールを分離しました。 - よく分かっていませんが、アクセス予定のメモリ領域を
VirtualQuery
関数で調べるとPAGE_NOACCESS
らしかったのですが、正常にアクセスできました。どういうことか全然分かっていません。 - 親プロセスが子プロセスを
TerminateProcess
しようとしたりするため、その前にSleep(INFINITE)
させるようにしました。 - 本手法を施した状態で正しくフラグ入力できる状況が、10回起動して1回あるかどうかでした。正しく動かない状況では、
NtLoadDriver failed with code: 0xc000010e
となったり、どこかでフリーズしたり、scanf
による入力箇所を通っているはずなのに入力がないものと扱われて即失敗ルートを取ったりしました。うまくいかない理由が全然分かっていませんが、何回か実行すればそのうち動いたのであまり気にしませんでした。 - 稀に、実行途中にGuest VMが丸ごとフリーズすることがありました。その場合はVMを再起動しました。
本手法を使って分かった点です:
- 子プロセスが、1回目の制御コード
0x224010
経由で取得する内容は、親プロセスで入力した内容そのものした。その内容をmemcpy
でコピーします。 - 子プロセスが、2回目~11回目の制御コード
0x224010
経由で取得する内容は、完全固定値でした。親プロセスが最初の方に構築している固定内容バッファの内容が特定の順序で入れ替わって反映されているようでした。 - 子プロセス最後の
memcmp
で比較している内容は、第1引数が入力に依存した内容で、第2引数は固定値でした。 memcpy
の第1引数のアドレスを保持しておいて、制御コード0x224014
のDeviceIoControl
時にそのアドレスを確認することで、9段階の加工中の状態を確認できました。最終的なソルバー開発時に役立ちました。
本手法を使った出力の例です(x64/DebugビルドのBrownFlagCheckerInjector.exe
とBrownFlagCheckerHook.dll
を使っています):
- 親プロセス側:
C:\Users\User\Desktop\work>dir Volume in drive C is Windows Volume Serial Number is ACBD-83FF Directory of C:\Users\User\Desktop\work 03/26/2024 11:07 PM <DIR> . 03/23/2024 12:25 PM <DIR> .. 03/23/2024 08:51 AM 26,112 BrownFlagChecker.exe 03/25/2024 03:10 AM 2,622,976 BrownFlagCheckerHook.dll 03/24/2024 02:29 AM 2,113,536 BrownFlagCheckerInjector.exe 03/11/2024 06:40 AM 15,640 BrownProtector.sys 4 File(s) 4,778,264 bytes 2 Dir(s) 83,701,641,216 bytes free C:\Users\User\Desktop\work>BrownFlagCheckerInjector.exe this is main.cpp (DEBUG) VirtualAllocEx (DEBUG) WriteProcessMemory (DEBUG) GetModuleHandleW (DEBUG) GetProcAddress (DEBUG) pLoadLibraryW : 00007FFB699A8BE0 (DEBUG) CreateRemoteThread (DEBUG) threadId : 7612 (DEBUG) WaitForSingleObject after GetModuleFileNameW, result: c:\Users\User\Desktop\work\BrownFlagCheckerHook.dll exeImage exeFile Succeeded to hook DeviceIoControl Succeeded to hook GetThreadContext Succeeded to hook SetThreadContext Succeeded to hook CreateProcessA Succeeded to hook memcpy Succeeded to hook memcmp Succeeded to hook puts Succeeded to hook TerminateProcess Succeeded to hook ExitProcess (DEBUG) GetExitCodeThread CreateProcessA before CreateProcessA after, result = 1 CreateProcessA hook child process , lpProcessInformation->dwProcessId: 7636 (DEBUG) VirtualAllocEx (DEBUG) WriteProcessMemory (DEBUG) GetModuleHandleW (DEBUG) GetProcAddress (DEBUG) pLoadLibraryW : 00007FFB699A8BE0 (DEBUG) CreateRemoteThread (DEBUG) threadId : 7644 (DEBUG) WaitForSingleObject (DEBUG) GetExitCodeThread CreateProcessA DebugActiveProcess CreateProcessA DebugActiveProcess, result = 1 CreateProcessA ResumeThread CreateProcessA ResumeThread, result = 2 CreateProcessA complete DeviceIoControl after, received: 0x37, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, GetThreadContext after, lpContext->Rax: 1, lpContext->Rip: 5368722059 Welcome! Give me the key and I will give you the flag: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa DeviceIoControl after, received: SetThreadContext before, lpContext->Rax: 0, lpContext->Rip: 5368722065 GetThreadContext after, lpContext->Rax: 3, lpContext->Rip: 5368722149 Wrong! But here is a clue just for you: https://rb.gy/i6drqn puts! Wait!
- 子プロセス側:
after GetModuleFileNameW, result: c:\Users\User\Desktop\work\BrownFlagCheckerHook.dll exeImage exeFile Succeeded to hook DeviceIoControl Succeeded to hook GetThreadContext Succeeded to hook SetThreadContext Succeeded to hook CreateProcessA Succeeded to hook memcpy Succeeded to hook memcmp Succeeded to hook puts Succeeded to hook TerminateProcess Succeeded to hook ExitProcess DeviceIoControl after, received: 0x37, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, DeviceIoControl after, received: 0x37, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, DeviceIoControl after, received: 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, DeviceIoControl(code: 0x224010) addr: 0x7e0595547000 (GUY): 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, memcpy, dest( 0x180000) = src(0x7e0595547000) : 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, DeviceIoControl before, dwIoControlCode: 224014, current dest content: 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, DeviceIoControl after, received: DeviceIoControl after, received: 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, DeviceIoControl(code: 0x224010) addr: 0x68574f43000 (COW): 0x62, 0x4e, 0xb3, 0x30, 0xd7, 0x63, 0x9b, 0x94, 0x5c, 0xec, 0x45, 0x15, 0xc7, 0xf5, 0x53, 0x58, DeviceIoControl(code: 0x224010) addr: 0x68544142000 (BAT): 0xd9, 0xae, 0xcb, 0x5a, 0xd8, 0xfc, 0x84, 0xf3, 0xaa, 0xc5, 0x8b, 0x9d, 0x08, 0x2d, 0x1d, 0x8f, DeviceIoControl before, dwIoControlCode: 224014, current dest content: 0x2e, 0xb1, 0x78, 0xfe, 0x4e, 0xe6, 0x32, 0x34, 0x4e, 0x89, 0x19, 0xf0, 0x0b, 0x58, 0x91, 0xd7, 0x89, 0x2e, 0x8a, 0xb0, 0x83, 0x45, 0x9e, 0xb8, 0x48, 0x8d, 0x1e, 0x44, 0xd6, 0x66, 0x1d, 0x00, 0x19, 0x90, 0x1a, 0xe2, 0x8d, 0xaf, 0xe1, 0xa4, 0x59, 0x41, 0x65, 0x61, 0xf3, 0x8c, 0xd7, 0x88, 0xc1, 0xad, 0x34, 0xb9, 0x10, 0x7b, 0x8a, 0x68, 0x99, 0x55, 0xc1, 0x95, 0x7a, 0x31, 0x56, 0xbe, DeviceIoControl after, received: DeviceIoControl after, received: 0x8c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, DeviceIoControl(code: 0x224010) addr: 0x460455945000 (EYE): 0xf5, 0xd1, 0x5c, 0x5a, 0xb2, 0xe9, 0x6b, 0x21, 0xe7, 0x2c, 0x74, 0xfa, 0x11, 0x00, 0x02, 0xdc, DeviceIoControl(code: 0x224010) addr: 0x460455053000 (SPE): 0xf5, 0x18, 0xb9, 0x72, 0x69, 0x4c, 0x79, 0xcc, 0xc4, 0x13, 0x8b, 0xe0, 0x39, 0x66, 0x9e, 0x59, DeviceIoControl before, dwIoControlCode: 224014, current dest content: 0xca, 0x1e, 0xb2, 0xc0, 0xda, 0xc3, 0x82, 0xbf, 0x04, 0x82, 0x14, 0xdb, 0xcc, 0x02, 0xcc, 0xa8, 0xbd, 0x6f, 0xb0, 0xc8, 0x1c, 0xc0, 0xf0, 0x56, 0x9d, 0x9d, 0xa0, 0xa1, 0x4a, 0x8a, 0x49, 0xaf, 0x8c, 0x77, 0x75, 0x45, 0x36, 0x4e, 0x74, 0x03, 0xc0, 0x1c, 0xc5, 0x6c, 0x78, 0x09, 0x78, 0xb9, 0x18, 0x06, 0x5a, 0x1b, 0x4a, 0x9a, 0x52, 0x11, 0x6f, 0xc4, 0xa8, 0x75, 0x3f, 0xf1, 0xef, 0xc3, DeviceIoControl after, received: DeviceIoControl after, received: 0x35, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, DeviceIoControl(code: 0x224010) addr: 0x1a8434241000 (ABC): 0xe4, 0x49, 0x63, 0x70, 0xe9, 0x36, 0x53, 0x8d, 0x9c, 0x14, 0xca, 0xf0, 0x03, 0xbc, 0x2b, 0x3d, DeviceIoControl(code: 0x224010) addr: 0x1a84e4957000 (WIN): 0xcf, 0x74, 0x4d, 0xef, 0x49, 0xbb, 0x74, 0xaa, 0x96, 0x6e, 0xe7, 0xf5, 0x63, 0x09, 0x67, 0x89, DeviceIoControl before, dwIoControlCode: 224014, current dest content: 0x32, 0xeb, 0xb1, 0xbe, 0xce, 0x6c, 0xd7, 0x75, 0xf2, 0x8d, 0x40, 0x73, 0x07, 0xfe, 0x7a, 0x73, 0x65, 0x2d, 0xa2, 0x05, 0xff, 0xde, 0x21, 0xa7, 0x04, 0x3c, 0xaf, 0x6f, 0x8a, 0xe1, 0x71, 0xc5, 0x5f, 0xa2, 0x87, 0x73, 0xf6, 0x09, 0x22, 0xe2, 0x0a, 0xb9, 0x34, 0xd5, 0x58, 0xf2, 0xd2, 0x0b, 0xeb, 0xea, 0xdc, 0x2c, 0x26, 0xf9, 0x5e, 0xfb, 0xe8, 0x25, 0x2e, 0xf4, 0x4e, 0x64, 0x4e, 0x07, DeviceIoControl after, received: DeviceIoControl after, received: 0x97, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, DeviceIoControl(code: 0x224010) addr: 0x4b8454349000 (ICE): 0x9e, 0xd6, 0x67, 0xb3, 0x8d, 0x13, 0x8d, 0xe7, 0x49, 0x73, 0x52, 0xf8, 0xb4, 0x56, 0xf8, 0x58, DeviceIoControl(code: 0x224010) addr: 0x4b8595243000 (CRY): 0x69, 0x9e, 0xbb, 0x61, 0x9f, 0xab, 0x1c, 0x14, 0x3c, 0x8e, 0x09, 0xc3, 0x36, 0xfc, 0xf8, 0xf8, DeviceIoControl before, dwIoControlCode: 224014, current dest content: 0x11, 0xc2, 0x60, 0xe3, 0xf4, 0x27, 0xf3, 0x41, 0x5f, 0x48, 0xd2, 0xe3, 0xd2, 0x55, 0x6c, 0x94, 0x13, 0x2c, 0xf0, 0xf7, 0x6b, 0xe6, 0x56, 0x8b, 0xfc, 0x5a, 0x43, 0xb3, 0x9f, 0x57, 0x4b, 0x63, 0xea, 0x44, 0x52, 0x3c, 0x51, 0x99, 0xb7, 0x03, 0x66, 0x34, 0x42, 0x52, 0xb3, 0x80, 0x9e, 0xab, 0xad, 0x19, 0xe9, 0x68, 0xba, 0xb6, 0xfd, 0x10, 0x08, 0xc7, 0x63, 0x1d, 0x45, 0x17, 0xc8, 0x0b, DeviceIoControl after, received: DeviceIoControl after, received: 0xf3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, DeviceIoControl(code: 0x224010) addr: 0x798474f44000 (DOG): 0xbb, 0xbd, 0xaa, 0x45, 0x34, 0xcf, 0x75, 0xca, 0xd7, 0xd3, 0x1c, 0x13, 0x05, 0x3e, 0x63, 0x4e, DeviceIoControl(code: 0x224010) addr: 0x798544143000 (CAT): 0x60, 0x3a, 0xe7, 0x7b, 0x24, 0xda, 0x70, 0x6f, 0x99, 0x2a, 0xee, 0xb2, 0x1a, 0x96, 0xc6, 0x33, DeviceIoControl before, dwIoControlCode: 224014, current dest content: 0xae, 0x29, 0xd2, 0x05, 0x32, 0x06, 0x4c, 0x3a, 0x74, 0x35, 0x66, 0xce, 0x43, 0x4c, 0xb4, 0x99, 0xec, 0x56, 0xaf, 0x2f, 0xdf, 0x50, 0x79, 0x29, 0x21, 0x17, 0x0c, 0xdd, 0xe3, 0xe7, 0xed, 0xdf, 0x67, 0x9d, 0x14, 0x48, 0x78, 0xad, 0xf3, 0xb6, 0x35, 0x4f, 0xe5, 0xb9, 0x0b, 0x7c, 0xd8, 0x20, 0x05, 0xb6, 0x9c, 0xba, 0xa5, 0xcc, 0xb4, 0x6e, 0x5a, 0x0d, 0xd8, 0x7c, 0x97, 0xc8, 0xd2, 0x15, DeviceIoControl after, received: DeviceIoControl after, received: 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, DeviceIoControl(code: 0x224010) addr: 0x4084b5441000 (ATK): 0x01, 0x50, 0xb0, 0x60, 0x47, 0xe2, 0x0c, 0xf6, 0xa3, 0xbd, 0x9c, 0x41, 0xb0, 0x61, 0x9e, 0x34, DeviceIoControl(code: 0x224010) addr: 0x4084d4956000 (VIM): 0x6e, 0x31, 0xfa, 0x55, 0xe0, 0x39, 0x27, 0xfa, 0x2b, 0x90, 0x78, 0xb6, 0xc6, 0x72, 0x69, 0xdf, DeviceIoControl before, dwIoControlCode: 224014, current dest content: 0x93, 0x40, 0xbc, 0x5a, 0x76, 0x2b, 0xb4, 0xd0, 0x7a, 0xe5, 0x4b, 0x46, 0x5c, 0x4b, 0xd7, 0xbe, 0xfc, 0xf5, 0x74, 0xd0, 0x56, 0x61, 0xb4, 0xd3, 0xb7, 0xdf, 0x85, 0xda, 0xf1, 0xf9, 0xf9, 0x84, 0x3c, 0x78, 0x00, 0xa9, 0x5b, 0xe6, 0xaa, 0x72, 0x73, 0x5f, 0x6b, 0xa0, 0x62, 0x66, 0xb7, 0xe5, 0xc1, 0x06, 0xbd, 0x73, 0x5f, 0x6e, 0xdd, 0x36, 0x3a, 0x3b, 0xcf, 0x80, 0x8a, 0x80, 0x88, 0x71, DeviceIoControl after, received: DeviceIoControl after, received: 0xcc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, DeviceIoControl(code: 0x224010) addr: 0x660444552000 (RED): 0xef, 0xaf, 0xa1, 0x44, 0x7b, 0xc8, 0xdd, 0xf8, 0x1f, 0x9c, 0x3a, 0xf8, 0xcc, 0xc2, 0x57, 0x8b, DeviceIoControl(code: 0x224010) addr: 0x66050495a000 (ZIP): 0xcb, 0xdd, 0x86, 0x3e, 0x1f, 0x03, 0xe5, 0x2f, 0xa3, 0xb1, 0xd7, 0xf4, 0x6e, 0xa8, 0x30, 0xd0, DeviceIoControl before, dwIoControlCode: 224014, current dest content: 0x2e, 0x39, 0xc9, 0x98, 0x40, 0x03, 0xdc, 0x52, 0xb6, 0x7d, 0xf3, 0x33, 0x9a, 0x81, 0xbb, 0x32, 0x0a, 0x9e, 0xfd, 0x7a, 0x78, 0xa6, 0x1c, 0x1e, 0x9c, 0x16, 0x25, 0xc0, 0x26, 0xe0, 0x0f, 0xd3, 0xe9, 0xc1, 0x0e, 0x35, 0xbd, 0x10, 0x55, 0xe8, 0xbf, 0x2c, 0x3d, 0x93, 0xa0, 0x82, 0xc7, 0x45, 0x0b, 0x21, 0xeb, 0x3a, 0xc2, 0xab, 0x30, 0x1b, 0xfb, 0x87, 0xc7, 0xd2, 0xa2, 0x27, 0x7a, 0xf8, DeviceIoControl after, received: DeviceIoControl after, received: 0xec, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, DeviceIoControl(code: 0x224010) addr: 0x760535251000 (QRS): 0x71, 0x29, 0x2c, 0x0e, 0x6b, 0x2f, 0x3f, 0x2f, 0xd9, 0x71, 0x11, 0xb2, 0x4b, 0x63, 0x42, 0xf4, DeviceIoControl(code: 0x224010) addr: 0x760464544000 (DEF): 0x2e, 0x44, 0xd1, 0x84, 0xe7, 0x05, 0x4a, 0x7a, 0xa7, 0x67, 0x53, 0x8a, 0xd3, 0xca, 0x61, 0xd9, DeviceIoControl before, dwIoControlCode: 224014, current dest content: 0x08, 0x20, 0xbd, 0x5a, 0x2e, 0x1f, 0x31, 0x80, 0x0f, 0x14, 0x99, 0x77, 0xa8, 0x8a, 0xa9, 0xb7, 0x53, 0xed, 0xfb, 0x26, 0x37, 0x84, 0x47, 0xce, 0x90, 0x04, 0x64, 0xc8, 0xce, 0xae, 0x3c, 0x93, 0xa4, 0xb6, 0x75, 0xcc, 0x5f, 0x85, 0x1b, 0x00, 0x89, 0x06, 0x47, 0x29, 0x3f, 0xa5, 0x08, 0x27, 0xe3, 0xb3, 0xd3, 0x97, 0x3d, 0x9b, 0x7b, 0x3f, 0x7a, 0xb4, 0x64, 0x78, 0x4b, 0x8a, 0xa3, 0x2e, DeviceIoControl after, received: DeviceIoControl after, received: 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, DeviceIoControl(code: 0x224010) addr: 0x804f4f4d000 (MOO): 0xfb, 0xa7, 0x3c, 0xa3, 0xe8, 0x8d, 0x3c, 0x74, 0xda, 0xcb, 0x32, 0x84, 0x85, 0xec, 0x2a, 0xed, DeviceIoControl(code: 0x224010) addr: 0x80524941000 (AIR): 0x72, 0x5e, 0xa8, 0x4d, 0x26, 0x47, 0x8d, 0xaf, 0xa6, 0x8e, 0xad, 0x9b, 0xfd, 0xbe, 0x52, 0x6f, DeviceIoControl before, dwIoControlCode: 224014, current dest content: 0xa8, 0x7d, 0xf8, 0xac, 0x32, 0xd3, 0x77, 0x1a, 0x35, 0x8b, 0x21, 0x83, 0x4a, 0xd1, 0x1c, 0x92, 0xd0, 0x92, 0x16, 0x20, 0x6a, 0x07, 0x17, 0x57, 0xc1, 0xc0, 0xdd, 0x14, 0x54, 0x10, 0x1e, 0x23, 0xbf, 0x7c, 0x07, 0xe8, 0xea, 0xd9, 0x64, 0x69, 0x0a, 0x13, 0x74, 0x4f, 0xb4, 0x65, 0x56, 0x72, 0x0b, 0x70, 0xfb, 0xa7, 0xb2, 0xc6, 0xce, 0x06, 0xe7, 0x5e, 0x22, 0xb4, 0x2c, 0x01, 0xa4, 0x6f, DeviceIoControl after, received: DeviceIoControl after, received: 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, DeviceIoControl(code: 0x224010) addr: 0x1a0474745000 (EGG): 0xe2, 0x42, 0xf1, 0x42, 0x1d, 0x2a, 0xae, 0xc7, 0xc1, 0xec, 0x19, 0x6a, 0x43, 0x45, 0x77, 0xe2, memcmp, buffer1: 0xa8, 0x7d, 0xf8, 0xac, 0x32, 0xd3, 0x77, 0x1a, 0x35, 0x8b, 0x21, 0x83, 0x4a, 0xd1, 0x1c, 0x92, 0xd0, 0x92, 0x16, 0x20, 0x6a, 0x07, 0x17, 0x57, 0xc1, 0xc0, 0xdd, 0x14, 0x54, 0x10, 0x1e, 0x23, 0xbf, 0x7c, 0x07, 0xe8, 0xea, 0xd9, 0x64, 0x69, 0x0a, 0x13, 0x74, 0x4f, 0xb4, 0x65, 0x56, 0x72, 0x0b, 0x70, 0xfb, 0xa7, 0xb2, 0xc6, 0xce, 0x06, 0xe7, 0x5e, 0x22, 0xb4, 0x2c, 0x01, 0xa4, 0x6f, buffer2: 0xe2, 0x42, 0xf1, 0x42, 0x1d, 0x2a, 0xae, 0xc7, 0xc1, 0xec, 0x19, 0x6a, 0x43, 0x45, 0x77, 0xe2, 0x05, 0xd3, 0x91, 0xe3, 0x72, 0x59, 0x6b, 0xaa, 0x96, 0x41, 0x08, 0x4d, 0x8e, 0x91, 0x46, 0xf3, 0x5f, 0x86, 0xb2, 0x2a, 0x05, 0xb2, 0x2a, 0x8a, 0x08, 0x9b, 0xfc, 0x66, 0x2b, 0x07, 0xe4, 0x3d, 0xec, 0x57, 0xfa, 0x1c, 0x8a, 0xfd, 0xbb, 0x08, 0x78, 0x06, 0xdb, 0x78, 0x35, 0x4f, 0x5b, 0xe0, DeviceIoControl before, dwIoControlCode: 224014, current dest content: 0xa8, 0x7d, 0xf8, 0xac, 0x32, 0xd3, 0x77, 0x1a, 0x35, 0x8b, 0x21, 0x83, 0x4a, 0xd1, 0x1c, 0x92, 0xd0, 0x92, 0x16, 0x20, 0x6a, 0x07, 0x17, 0x57, 0xc1, 0xc0, 0xdd, 0x14, 0x54, 0x10, 0x1e, 0x23, 0xbf, 0x7c, 0x07, 0xe8, 0xea, 0xd9, 0x64, 0x69, 0x0a, 0x13, 0x74, 0x4f, 0xb4, 0x65, 0x56, 0x72, 0x0b, 0x70, 0xfb, 0xa7, 0xb2, 0xc6, 0xce, 0x06, 0xe7, 0x5e, 0x22, 0xb4, 0x2c, 0x01, 0xa4, 0x6f, DeviceIoControl after, received:
あとは、入力内容がどのように加工されるかを解明できれば、正解となる入力内容を逆算できそうです。
子プロセスの入力内容の加工処理の解析
結論から書くと、0x140001F50
以降で、入力をAES-128-CBCで9回暗号化していました。鍵およびIVは、制御コード0x224010
経由で取得する固定値を使用しています。AES-128-CBCと判断した経緯です:
0x140005330
からの256バイト配列は、AESのS-boxです。これは、配列最初の方の63 7C 77 7B F2 6B 6F C5
でGoogle検索するとRijndael S-box - Wikipediaがヒットしたことで分かりました。0x140005530
からの16バイト配列は、AESのrconと呼ばれているもののようです。これは、配列最初の方の8D 01 02 04 08 10 20 40
をGoogle検索するとAES128 in Ruby 1.9.2がヒットしたことで分かりました。なおヒット結果では16バイトすべて非0ですが、本問題では後ろ5バイトが0x00です。「多分AES-128では今ある値だけで十分で、AES-192やAES-256では16バイト全部必要なんでしょう」と考えて流しました。0x140001000
の関数は、AESの鍵展開を行う関数のようです。これは、関数中でS-boxもrconも使われており、処理内容もAES128 in Ruby 1.9.2のものと「なんとなく似ている気がする」と思って判断しました。0x1400016A0
の関数は、AES-128で1ブロックを暗号化する関数のようです。これは、tiny-AES-c/aes.c at master · kokke/tiny-AES-cと見比べて「各段階を適切な順序で行っていそう」と思って判断しました。- 暗号利用モードはCBCのようです。これは
0x140001FEE
付近の以下の逆コンパイル結果をひたすら追跡して判断しました(同様の箇所が後ろに8個、全9個ありますが、すべて流れは同様のようです):
addr_1 = Child_DeviceIoControl_0x224010(); // ここからしばらく、PAGE_NOACCESSへアクセスしようとする → どんな魔法なのかちゃんと取得できているらしい qmemcpy(&g_qwStr3, "BAT", 3); qmemcpy(&g_qwStr4, "COW", 3); pbyteArrayCurrentBlockSrc = (_OWORD *)(addr_1 + (g_qwStr4 << 12));// COW側から16バイト読み込み MayBe_AesKeySchedule(byteArrayExpandedKey, (const _BYTE *)(addr_1 + (g_qwStr3 << 12)));// BAT側からAES鍵の値を読み込み *(_OWORD *)byteArrayCurrentBlockSrc = *pbyteArrayCurrentBlockSrc;// COW側から16バイト読み込み、直接代入 pbyteArrayCurrentBlockDest = pAllocatedSize0x1000; pbyteArrayCurrentBlockForXor = byteArrayCurrentBlockSrcCopy;// 単なるアドレスの代入だけ dwRestBlockCount1 = 4LL; *(_OWORD *)byteArrayCurrentBlockSrcCopy = *(_OWORD *)byteArrayCurrentBlockSrc; do { pbyteArrayCurrentBlockDest_1 = pbyteArrayCurrentBlockDest;// 16ずつ4回増える qwOffset = pbyteArrayCurrentBlockForXor - pbyteArrayCurrentBlockDest; dwRestCount2 = 16LL; do { *pbyteArrayCurrentBlockDest_1 ^= pbyteArrayCurrentBlockDest_1[qwOffset];// offset側加算結果を合わせて、実質「pbyteArrayCurrentBlockForXor[i]」相当 ++pbyteArrayCurrentBlockDest_1; --dwRestCount2; } while ( dwRestCount2 ); MayBe_Aes128Encrypt(pbyteArrayCurrentBlockDest, byteArrayExpandedKey); pbyteArrayCurrentBlockForXor = pbyteArrayCurrentBlockDest;// これCBCモードでは? pbyteArrayCurrentBlockDest += 16; // 16ずつ4回増える --dwRestBlockCount1; } while ( dwRestBlockCount1 ); *(_OWORD *)byteArrayCurrentBlockSrcCopy = *(_OWORD *)pbyteArrayCurrentBlockForXor;// この代入なにか意味ある?この後別の代入で上書きされてないか? DeviceIoControl(g_Child_hDevice, 0x224014u, 0LL, 0, 0LL, 0, 0LL, 0LL);
- AES-128-CBCと仮定して、入力を暗号化する手順を再現したら、確認結果のバイト列と一致しました。
なお、最終的な「入力内容を使ったフラグの復号」では、入力内容のMD5をAES鍵の一部に使っているようでした。そのため「フラグ復号結果がそれらしくなるように入力内容を逆算」は不可能だと思います。
ソルバーと実行結果とフラグ
最終的な、「64文字のa
を入力として与えた場合の変換結果が想定したものになることの検証」「正解となる入力の逆算」を行うスクリプトです(試行錯誤中内容もそのまま掲載します):
#!/usr/bin/env python3 from Crypto.Cipher import AES test_input_a64 = bytearray(b"a" * 64) assert len(test_input_a64) == 64 # 制御コード`0x224010`経由で取得する内容 extracted_keys = [ # (COW, BAT)などが9回 (bytes([0x62, 0x4e, 0xb3, 0x30, 0xd7, 0x63, 0x9b, 0x94, 0x5c, 0xec, 0x45, 0x15, 0xc7, 0xf5, 0x53, 0x58,]), bytes([0xd9, 0xae, 0xcb, 0x5a, 0xd8, 0xfc, 0x84, 0xf3, 0xaa, 0xc5, 0x8b, 0x9d, 0x08, 0x2d, 0x1d, 0x8f,])), (bytes([0xf5, 0xd1, 0x5c, 0x5a, 0xb2, 0xe9, 0x6b, 0x21, 0xe7, 0x2c, 0x74, 0xfa, 0x11, 0x00, 0x02, 0xdc,]), bytes([0xf5, 0x18, 0xb9, 0x72, 0x69, 0x4c, 0x79, 0xcc, 0xc4, 0x13, 0x8b, 0xe0, 0x39, 0x66, 0x9e, 0x59,])), (bytes([0xe4, 0x49, 0x63, 0x70, 0xe9, 0x36, 0x53, 0x8d, 0x9c, 0x14, 0xca, 0xf0, 0x03, 0xbc, 0x2b, 0x3d,]), bytes([0xcf, 0x74, 0x4d, 0xef, 0x49, 0xbb, 0x74, 0xaa, 0x96, 0x6e, 0xe7, 0xf5, 0x63, 0x09, 0x67, 0x89,])), (bytes([0x9e, 0xd6, 0x67, 0xb3, 0x8d, 0x13, 0x8d, 0xe7, 0x49, 0x73, 0x52, 0xf8, 0xb4, 0x56, 0xf8, 0x58,]), bytes([0x69, 0x9e, 0xbb, 0x61, 0x9f, 0xab, 0x1c, 0x14, 0x3c, 0x8e, 0x09, 0xc3, 0x36, 0xfc, 0xf8, 0xf8,])), (bytes([0xbb, 0xbd, 0xaa, 0x45, 0x34, 0xcf, 0x75, 0xca, 0xd7, 0xd3, 0x1c, 0x13, 0x05, 0x3e, 0x63, 0x4e,]), bytes([0x60, 0x3a, 0xe7, 0x7b, 0x24, 0xda, 0x70, 0x6f, 0x99, 0x2a, 0xee, 0xb2, 0x1a, 0x96, 0xc6, 0x33,])), (bytes([0x01, 0x50, 0xb0, 0x60, 0x47, 0xe2, 0x0c, 0xf6, 0xa3, 0xbd, 0x9c, 0x41, 0xb0, 0x61, 0x9e, 0x34,]), bytes([0x6e, 0x31, 0xfa, 0x55, 0xe0, 0x39, 0x27, 0xfa, 0x2b, 0x90, 0x78, 0xb6, 0xc6, 0x72, 0x69, 0xdf,])), (bytes([0xef, 0xaf, 0xa1, 0x44, 0x7b, 0xc8, 0xdd, 0xf8, 0x1f, 0x9c, 0x3a, 0xf8, 0xcc, 0xc2, 0x57, 0x8b,]), bytes([0xcb, 0xdd, 0x86, 0x3e, 0x1f, 0x03, 0xe5, 0x2f, 0xa3, 0xb1, 0xd7, 0xf4, 0x6e, 0xa8, 0x30, 0xd0,])), (bytes([0x71, 0x29, 0x2c, 0x0e, 0x6b, 0x2f, 0x3f, 0x2f, 0xd9, 0x71, 0x11, 0xb2, 0x4b, 0x63, 0x42, 0xf4,]), bytes([0x2e, 0x44, 0xd1, 0x84, 0xe7, 0x05, 0x4a, 0x7a, 0xa7, 0x67, 0x53, 0x8a, 0xd3, 0xca, 0x61, 0xd9,])), (bytes([0xfb, 0xa7, 0x3c, 0xa3, 0xe8, 0x8d, 0x3c, 0x74, 0xda, 0xcb, 0x32, 0x84, 0x85, 0xec, 0x2a, 0xed,]), bytes([0x72, 0x5e, 0xa8, 0x4d, 0x26, 0x47, 0x8d, 0xaf, 0xa6, 0x8e, 0xad, 0x9b, 0xfd, 0xbe, 0x52, 0x6f,])), ] def encrypt(test_input): for (index, (iv_for_ecnrypt, key_for_encrypt)) in enumerate(extracted_keys): print(f"{index = }") assert len(test_input) == 64 assert len(iv_for_ecnrypt) == 16 assert len(key_for_encrypt) == 16 cipher_for_encrypt = AES.new(key_for_encrypt, AES.MODE_CBC, iv=iv_for_ecnrypt) test_input = bytearray(cipher_for_encrypt.encrypt(test_input)) return test_input encrypted_test_input_a64 = encrypt(test_input_a64) # a64個与えた場合のmemcmp第1引数の内容 last_expected_a64 = bytes([0xa8, 0x7d, 0xf8, 0xac, 0x32, 0xd3, 0x77, 0x1a, 0x35, 0x8b, 0x21, 0x83, 0x4a, 0xd1, 0x1c, 0x92, 0xd0, 0x92, 0x16, 0x20, 0x6a, 0x07, 0x17, 0x57, 0xc1, 0xc0, 0xdd, 0x14, 0x54, 0x10, 0x1e, 0x23, 0xbf, 0x7c, 0x07, 0xe8, 0xea, 0xd9, 0x64, 0x69, 0x0a, 0x13, 0x74, 0x4f, 0xb4, 0x65, 0x56, 0x72, 0x0b, 0x70, 0xfb, 0xa7, 0xb2, 0xc6, 0xce, 0x06, 0xe7, 0x5e, 0x22, 0xb4, 0x2c, 0x01, 0xa4, 0x6f,]) assert len(last_expected_a64) print(f"{encrypted_test_input_a64.hex() = }") print(f"{last_expected_a64.hex() = }") print(f"{(encrypted_test_input_a64 == last_expected_a64) = }") print() print() print() def decrypt(input_for_decrypt): for (iv_for_decrypt, key_for_decrypt) in reversed(extracted_keys): cipher_for_decrypt = AES.new(key_for_decrypt, AES.MODE_CBC, iv_for_decrypt) input_for_decrypt = bytearray(cipher_for_decrypt.decrypt(input_for_decrypt)) return input_for_decrypt # memcmpの第2引数の内容 last_expected_flag = bytearray([0xe2, 0x42, 0xf1, 0x42, 0x1d, 0x2a, 0xae, 0xc7, 0xc1, 0xec, 0x19, 0x6a, 0x43, 0x45, 0x77, 0xe2, 0x05, 0xd3, 0x91, 0xe3, 0x72, 0x59, 0x6b, 0xaa, 0x96, 0x41, 0x08, 0x4d, 0x8e, 0x91, 0x46, 0xf3, 0x5f, 0x86, 0xb2, 0x2a, 0x05, 0xb2, 0x2a, 0x8a, 0x08, 0x9b, 0xfc, 0x66, 0x2b, 0x07, 0xe4, 0x3d, 0xec, 0x57, 0xfa, 0x1c, 0x8a, 0xfd, 0xbb, 0x08, 0x78, 0x06, 0xdb, 0x78, 0x35, 0x4f, 0x5b, 0xe0,]) a = bytearray(last_expected_a64) a = decrypt(a) print(a == test_input_a64) print(decrypt(last_expected_flag))
実行しました:
$ ./solve.py index = 0 index = 1 index = 2 index = 3 index = 4 index = 5 index = 6 index = 7 index = 8 encrypted_test_input_a64.hex() = 'a87df8ac32d3771a358b21834ad11c92d09216206a071757c1c0dd1454101e23bf7c07e8ead964690a13744fb46556720b70fba7b2c6ce06e75e22b42c01a46f' last_expected_a64.hex() = 'a87df8ac32d3771a358b21834ad11c92d09216206a071757c1c0dd1454101e23bf7c07e8ead964690a13744fb46556720b70fba7b2c6ce06e75e22b42c01a46f' (encrypted_test_input_a64 == last_expected_a64) = True True bytearray(b'H4VIn9_7Hi5_KEY_ME4n5_you_4rE_che47In9_ON_me_7f6301e1920cb86cf8e') $
逆算できた正解の入力を実際に与えました:
c:\Users\User\Desktop\work>BrownFlagChecker.exe Welcome! Give me the key and I will give you the flag: H4VIn9_7Hi5_KEY_ME4n5_you_4rE_che47In9_ON_me_7f6301e1920cb86cf8e Correct. Here is your flag Flag: LINECTF{72f9fc0fdf5129a4930286e5b9794e10} c:\Users\User\Desktop\work>
フラグを入手できました: LINECTF{72f9fc0fdf5129a4930286e5b9794e10}
感想
- Web問題に非常に注力しているコンテストで驚きました。
- ただ私が読んだ問題はwelcome問題とrev問題だけです。他の問題は全く見れていません。すみません……。
- 今回のrev問題で、初めてカーネルモードドライバーを読みました。新鮮でした!
- KMD関連の知識がなさすぎて、どのAPIや処理が重要なのかも何も分かっておらず、使っているAPIを全部調べました。初々しい感覚を味わいました。
- rev問題の耐解析機構が山盛りだったので、想定解法含めて、どのような解法があるのか気になりました。
- Discordの書き込みによると、
cheat engine's DBVM
というものでブレークポイントを設定できて、レジスタ内容を確認できたとのことです。また、WinDbgでカーネルデバッグを試みた方もおられるようです。
- Discordの書き込みによると、
- 親プロセスのメモリ領域を、子プロセスから参照しているようで、ちょっと全く理解が追いつきませんでした!
- 親プロセス側の仮想アドレスを物理アドレスへ変換して、子プロセス側で物理アドレスを仮想アドレスに戻していたのでしょうか?カーネルモードは非常に強大な力を持っていそうです!
- Binary Ninjaを初めて使いました。キーボードショートカットの多くがIDAと共通だったのもあり、すぐに使えて便利でした。機能面の比較はおまけとして後述します。
おまけ: Binary Ninja FreeとIDA Freeの、機能面や逆コンパイル結果の比較
rev問題のBrownProtector.sys
解析のために、Free版Binary NinjaとFree版IDAを併用しました。初めてBinary Ninjaを使ったので、メモがてら、触り心地やIDAとの比較を紹介します。前述している通り、以下のバージョンを使用しています。
- IDA Free Version 8.4.240320 Windows x64 (64-bit address size)
- Binary Ninja Free 4.0.4958-Stable
Binary Ninjaのオフライン逆コンパイルが嬉しい
Binary NinjaはFree版でも逆コンパイル機能があります。また、オフラインで実行しているらしく、逆コンパイル表示も一瞬でしてくれます。
IDAのFree版の逆コンパイル機能はクラウドベースです。そのためサーバーと通信する待ち時間が必要です。また、時折No Response
などのエラーが発生して、逆コンパイルできないときがあります。そのような場合でもしばらく待ったり、IDAを再起動したりすればまた逆コンパイルできるようになりますが、たまに待たされる点は注意が必要ですし、集中できているときに食らったりすると険しい顔になったりします。
Binary NinjaもIDAもキーボードショートカットはだいたい同じ、一部違うので注意
Binary Ninjaの初期設定状態でも、以下のキーボードショートカットはIDAと同様に使えて助かりました:
n
: 変数名等の変更y
: 変数や関数への型付け*
: 変数の配列サイズの設定;
: コメントの追加r
: カーソル位置の定数を文字型に変更m
: カーソル位置の定数を列挙型に変更g
: 指定アドレスへジャンプEsc
: ジャンプ元へ戻るF5
: 疑似Cコードへの逆コンパイルx
: Binary Ninjaでは左下のCross Refferences
箇所にフォーカスが移ります。Cross Refferences
箇所には、常にカーソル位置のシンボルの相互参照が一覧表示されていますし、そこからジャンプできます。そのため、IDAの「カーソル位置の相互参照一覧を表示し、そこからジャンプ」と同様に操作できます。
なお、初期状態では以下のキーボードショートカットはIDAとは異なりました:
h
: Binary Ninjaでは、Hex Dump画面への行き来に使用します。IDAでは、カーソル位置の定数の基数を変更します。IDAのノリで押して、うっかりHex Dumpを見るたびに笑顔になれます。Binary Ninjaでの基数変換は、定数を右クリックして、Display as
メニュー以下から設定できます。Ctrl+W
: Binary Ninjaではおそらく未割り当てです。IDAでは作業状況の保存です。手癖で入力しても何も起こらず安心です。Ctrl+S
: Binary Ninjaでは作業状態を保存します。IDAではジャンプ先セグメントの選択です。これはBinary Ninjaの方が直感的に思います。
Binary NinjaはNTOSKRNL関係の構造体定義を持っている
Binary Ninjaは、BrownProtector.sys
のエントリーポイントであるNTSTATUS _start(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
を正しく認識しました。DRIVER_OBJECT
構造体の定義も正しく認識しているようで、0x140001047
付近のDRIVER_OBJECT
の初期化処理も、ファイル読み込み直後から正しく認識してくれました:
140001047 arg1->DriverUnload = sub_1400010e0 14000105b arg1->MajorFunction[0xe] = sub_140001180 140001069 arg1->MajorFunction[0] = sub_140001160 14000106d arg1->MajorFunction[2] = sub_140001160
なお、Binary Ninjaでも、WdfVersionBind
で使用するWDF_BIND_INFO
構造体など、WDFLDR
由来のデータ構造の定義は持っていないようです。
Free版IDAでは、どうにもDRIVER_OBJECT
構造体含めて、NTOSKRNL
由来のデータ構造の定義を持っていないようです。
Binary NinjaはIMAGE_DOS_HEADER
構造体の定義を持っていない?
IDAでは、IMAGE_DOS_HEADER
構造体等、PE関連のデータ構造の定義を持っています。一方で、Binary NinjaはIMAGE_DOS_HEADER
構造体を使おうとしても、Error parsing specified type
エラーで認識しませんでした:
自前で定義を与えるか、タイプライブラリ等を追加することで認識させられると思いますが、少なくとも初期状態では認識してくれないようです。
Binary Ninjaは逆コンパイル結果にもアドレス表示があって嬉しい
たまに「逆コンパイル結果のここはどのアドレスに対応するのか」を知りたいときがあります。Binary Ninjaでは、逆コンパイル結果画面の左端に、おおよそ対応するアドレスが表示されているのですぐに分かります。
IDAの場合は、逆コンパイル画面そのものにはアドレス表示はありません。ただ、逆コンパイル画面(Pseudocode-A
タブ等)の右クリックメニューでSynchronized with→IDA View-A
を選択しておくと、逆コンパイル画面の選択業と、逆アセンブル画面での選択行が同期するようになるため、タブ切り替えですぐ分かりはします。
Binary Ninjaはnot
命令の逆コンパイルを!
演算子としてしまっている
0x14000102c
周辺に、以下の処理があります:
14000102c 41f7d1 not r9d 14000102f 418bc1 mov eax, r9d 140001032 c3 retn
Binary Ninjaの逆コンパイル結果では、return !(dwHash);
と、not
命令をC言語の論理否定である!
演算子と表示してしまっています。逆コンパイル結果だけを見ると重大な誤解をしてしまいそうです。
IDAの逆コンパイル結果では、return ~dwHash;
と、not
命令をC言語の1の補数にする~
演算子に、正しく表示しています。
Binary Ninjaは1つの文中に多くの関数呼び出しを含めることがある
0x140001c6a
付近の処理を、Binary Ninjaは以下のように込み入った1つの文で表示します:
int64_t rcx_10 = *(uint64_t*)(MmGetVirtualForPhysical((*(uint64_t*)(MmGetVirtualForPhysical((__mov_cr_gpr64_cr(cr3) & 0xfffffffff000)) + (((qwUserspaceAddr >> 0x27) & 0x1ff) << 3)) & 0xfffffffff000)) + (((qwUserspaceAddr >> 0x1e) & 0x1ff) << 3));
IDAは以下のように、関数呼び出し単位ごとに分割して表示します:
qwCr3 = __readcr3(); VirtualForPhysical = MmGetVirtualForPhysical(qwCr3 & 0xFFFFFFFFF000LL); v4 = *(_QWORD *)(MmGetVirtualForPhysical(*(_QWORD *)(VirtualForPhysical + 8 * ((qwUserspaceAddr >> 39) & 0x1FF)) & 0xFFFFFFFFF000LL) + 8 * ((qwUserspaceAddr >> 30) & 0x1FF));
Binary Ninjaは構造体ポインター経由の多段アクセスのメンバー認識がちょっと弱そう
0x1400016ed
付近に、PROCESS_BASIC_INFORMATION::PebBaseAddress
を経由して、PEB::ImageBaseAddress
にアクセスする処理があります:
1400016ed 488b442448 mov rax, qword [rsp+0x48 {var_38.PebBaseAddress}] 1400016f2 488b4010 mov rax, qword [rax+0x10]
Binary Ninjaの逆コンパイル表示はrax_2 = *(uint64_t*)(pbi.PebBaseAddress + 0x10);
です。PROCESS_BASIC_INFORMATION::PebBaseAddress
までのアクセスを認識していますが、PEB
経由でのアクセス先を認識できていません。
IDAの逆コンパイル表示はreturn pbi.PebBaseAddress->ImageBaseAddress;
と、構造体メンバーの多段アクセスも適切に認識できています。
Binary Ninjaの多段分岐表示が読みやすいかも
0x140001180
(DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL]
へ登録している関数)で、以下の分岐があります:
1400011c0 81ea00402200 sub edx, 0x224000 1400011c6 0f8458020000 je 0x140001424 {"L9=U1"} 1400011cc 83ea04 sub edx, 0x4 1400011cf 0f8403020000 je 0x1400013d8 1400011d5 83ea04 sub edx, 0x4 1400011d8 0f849c010000 je 0x14000137a 1400011de 83ea04 sub edx, 0x4 1400011e1 0f84f7000000 je 0x1400012de 1400011e7 83ea04 sub edx, 0x4 1400011ea 746c je 0x140001258 1400011ec 83fa04 cmp edx, 0x4 1400011ef 0f859c020000 jne 0x140001491
Binary Ninjaの逆コンパイル結果は、アセンブリ内容を素直に翻訳しているのかもしれませんが、以下のように素直に見やすいif-else分岐です:
1400011c6 if (dwMayBeCode == 0x224000) 1400011c6 { // 内容中略 1400011c6 } 1400011c6 else 1400011c6 { 1400011cf if (dwMayBeCode == 0x224004) 1400011cf { // 内容中略 1400011cf } 1400011d8 if (dwMayBeCode == 0x224008) 1400011d8 { // 内容中略 1400011d8 } 1400011d8 else 1400011d8 { 1400011e1 if (dwMayBeCode == 0x22400c) 1400011e1 { // 内容中略 1400011ea } 1400011ea else if (((dwMayBeCode == 0x224014 && PsGetCurrentProcessId() == g_hCurrentProcess_WhenCode0x224004_MustBeChild) && (PsGetCurrentThreadId() == g_hCurrentThread_MustBeChild && g_bSomeFlag_SetWhenCode0x224010 != 0))) 1400011ef { // 内容中略 1400011ef } 1400011d8 } 1400011c6 }
IDAの逆コンパイル結果は、「この分岐はどの場合の処理なのか」が分かりづらく、しばしばコメントで補足したくなる分岐です:
if ( *(_DWORD *)(v2 + 24) == 0x224000 ) { // 内容中略 } if ( *(_DWORD *)(v2 + 24) == 0x224004 ) { // 内容中略 } if ( *(_DWORD *)(v2 + 24) != 0x224008 ) { if ( *(_DWORD *)(v2 + 24) != 0x22400C ) { if ( *(_DWORD *)(v2 + 24) != 0x224010 ) { if ( *(_DWORD *)(v2 + 24) == 0x224014 && PsGetCurrentProcessId() == g_currentProcessId2 && PsGetCurrentThreadId() == g_currentThreadId2 && g_bSomeFlag_SetWhenCode0x224010 ) { // 内容中略 } goto LABEL_43; } // 内容省略、0x224010に対応する処理 } // 内容省略、0x22400Cに対応する処理 } // 内容省略、0x224008に対応する処理
Binary Ninjaのグローバル変数や配列の表示が分かりやすい
0x140004000
以降にはCRC32用のテーブルがあります。Biniary Ninjaでは、indexごとに値を表示してくれて読みやすいです:
.data section started {0x140004000-0x140005200} 140004000 uint32_t g_dwCrc32TableSize256[0x100] = 140004000 { 140004000 [0x00] = 0x00000000 140004004 [0x01] = 0x77073096 140004008 [0x02] = 0xee0e612c 14000400c [0x03] = 0x990951ba (後略)
IDAでは型付けこそできますが、逆アセンブル表示のままのせいか、「どのindexがどの数値だろう」と思うことがあります:
.data:0000000140004000 ; _DWORD g_dwCrc32TableSize256[256] .data:0000000140004000 00 00 00 00 96 30 07 77 2C 61 0E g_dwCrc32TableSize256 dd 0, 77073096h, 0EE0E612Ch, 990951BAh, 76DC419h, 706AF48Fh .data:0000000140004000 EE BA 51 09 99 19 C4 6D 07 8F F4… ; DATA XREF: CalculateCrc32+1B↑o .data:0000000140004018 35 A5 63 E9 A3 95 64 9E 32 88 DB… dd 0E963A535h, 9E6495A3h, 0EDB8832h, 79DCB8A4h, 0E0D5E91Eh .data:000000014000402C 88 D9 D2 97 2B 4C B6 09 BD 7C B1… dd 97D2D988h, 9B64C2Bh, 7EB17CBDh, 0E7B82D07h, 90BF1D91h (後略)
同様に、0x140004400
にはUNICODE_STRING
型のグローバル変数があります。Binary Ninjaでは、型を与えることで、メンバー名と内容を対応して表示してくれます:
140004400 UNICODE_STRING g_UnicodeStringDeviceName = 140004400 { 140004400 USHORT Length = 0x38 140004402 USHORT MaximumLength = 0x3a 140004408 PWCH Buffer = g_wstrDeviceName {u"\Device\BrownProtectorDevice"} 140004410 }
IDAでは、型を設定することで1まとめには表示してくれますが、「どのメンバーが何の値を取るんだろう」と思うことがあります:
.data:0000000140004400 ; UNICODE_STRING g_UnicodeStringDeviceName .data:0000000140004400 38 00 3A 00 00 00 00 00 60 31 00 g_UnicodeStringDeviceName UNICODE_STRING <38h, 3Ah, offset aDeviceBrownpro> .data:0000000140004400 40 01 00 00 00 ; DATA XREF: InitializeDriverObjectAndDevice+17↑o .data:0000000140004400 ; InitializeDriverObjectAndDevice+76↑o .data:0000000140004400 ; "\\Device\\BrownProtectorDevice"