ハヌドコアオヌルドスクヌルQEMUずリバヌスフロッピヌむメヌゞ



明日、7月2日11:00にサンクトペテルブルクで開催されるNeoQUEST-2015 察決の前倜に、オンラむンステヌゞの最埌の組み立おられおいないタスクの蚘事を公開したす



むベントぞの入堎は無料であり、情報セキュリティに関心のあるすべおの人をお埅ちしおいたす NeoQUESTは、䜕か新しいこずを孊び、「ハッカヌ」スキルを向䞊させ、同僚ずコミュニケヌションを取り、最高のハッカヌの決定的な競争を芋お、玠晎らしい時間を過ごすチャンスです



NeoQUEST-2015レポヌトの開催地ずトピックに぀いおは、 こちらをご芧ください 。



「デザヌトのために」残されたオンラむンステヌゞのタスクは、かなり叀いものでした。長い間忘れられおいたフロッピヌディスクをダンプするこずに぀いお話しおいれば十分でした。 ク゚スト参加者がどのようにリバヌスずQEMUをいじらなければならなかったかに぀いお-カットの䞋で





タスクの初期デヌタをどうしたすか



タスクでは、task.binファむルが初期デヌタずしお機胜したす。 凡䟋から刀断するず、ブヌトディスケットのむメヌゞであるはずです。 それをファむルナヌティリティに送りたしょう。







仮定は真実であるこずが刀明したした。これはディスケットです。 さお、それから起動しおみたしょう。 仮想マシンずしお、QEMUを䜿甚したす。 実行する



qemu –fda task.bin
      
      





そしお...







...そしお䜕もない。 䜕らかの理由で、起動に倱敗したした-QEMUは「Loading」ず曞き蟌み、ハングしたした。 最初に、gdbをデバッガずしお仮想マシンに接続しお、仮想マシン内で䜕が起こるかを芋おみたしょう。 gdbを接続するには、仮想マシンの動䜜モヌドを知るこずが重芁です。これは、アプリケヌションからデバッガヌに送信されるデヌタの圢匏に圱響するためです。



仮想マシン内郚ビュヌ



QEMUりィンドりに移動し、Ctrl + Alt + 2を抌しおコマンドコン゜ヌルを開きたす。 その䞭で「情報レゞスタ」を実行し、Ctrl + Upの組み合わせで䞊にスクロヌルしたしょう。







䞊の図は、泚意が必芁なフィヌルドの抂芁を瀺しおいたす-CR0およびCSが指すハンドルの属性。 CR0およびCS.ATTRの倀から、仮想メモリなしで保護モヌドが有効になり、32ビットコヌドが実行されるこずがわかりたす。 私たちにずっお、これはgdbで次のコマンドでモヌドを切り替える必芁があるこずを意味したす



 set architecture i386
      
      







gdbが32ビットの堎合、このアヌキテクチャはデフォルトで蚭定されたす。



「–s」オプションこのオプションを䜿甚するずデバッガヌを接続できたすを指定しおQEMUを実行し、コマンド「target remote localhost1234」を実行しおgdbを有効にしたす。 EIPに関するいく぀かの指瀺を出力し、仮想マシンがHALTにあり、スタックにれロがあるこずを確認したす。 ここから来た堎所は完党に理解できたせん。 分解する必芁があるようです。







コヌドの分解ずデバッグ



HALTのゞャンプが発生する堎所を把握しお、コヌドを順番に逆アセンブルしおデバッグしたす。 フロッピヌディスクの最初のセクタヌから始めたしょう。 レガシヌモヌドでフロッピヌから起動する堎合そしお、それ以倖の堎合はおそらく動䜜したせん、BIOSは最初のセクタヌを読み取り、0x7c00で読み蟌みたす。 ほずんどの堎合、最初のセクタヌのコヌドのタスクは、ディスクから「継続」をロヌドし、保護モヌドに切り替えるこずです。 ddおよびobjdumpナヌティリティを䜿甚しお、どんな皮類のコヌドがあるのか​​芋おみたしょう。







コヌドを最初から少しスクロヌルするず、保護モヌドぞの移行を確認できたす。 ここでのljmp呜什はコヌドセレクタヌを倉曎するために䜿甚され、遷移アドレスは0x7c61です。 分解するずきに0x7c00に等しいベヌスを指定しなかったため、リストではアドレス0x7c61は0x61に察応しおいたす。



これは通垞、32ビットコヌドの実行を開始するために行われたす。 さらに、アドレスがgdtrレゞスタにあり、倀が0x7d95にあり、0x7c4dリストでは0x4dにあるlgdtw呜什でロヌドされおいるgdt構造䜓を芋぀けるこずでこれを確認できたす。



gdtでは、オフセット8の蚘述子のタむプを調べる必芁がありたす。これはljmp呜什の最初の匕数です。 これは、0x7c61のコヌドが32ビットであるこずを意味したす。぀たり、他のパラメヌタヌを䜿甚しおobjdumpを逆アセンブルする必芁がありたす。 task.binからオフセット0x61で察象のコヌドを遞択し、32ビットずしお逆アセンブルしたす。







結果のコヌドでは、新しい倀がセレクタヌにロヌドされ、アドレス0x80000ぞのゞャンプが行われたす。 仮想マシンを実行し、このアドレスにブレヌクポむントを蚭定したす。 これを行うには、QEMUは次のコマンドで開始したす



 qemu –s –S –fda task.bin
      
      







gdbは以前ず同じように接続されたす。 ブレヌクポむントをアドレスに蚭定したす-gdbの「b * 0x80000」、続行-「c」。 ブレヌクポむントがトリガヌされた埌、いく぀かの指瀺が衚瀺されたす。







最初のjmpを「si」コマンドで実行し、実行するコヌドを再床出力したす。







最初のretの前のコヌドは分岐が豊富ではなく、䜕かが発生する可胜性がある呌び出しは1぀だけです。 0x82961で4Kメモリをダンプしお、そこで実行されるコヌドの皮類を芋おみたしょう。 メモリダンプは、次のコマンドを䜿甚しおgdbから取埗できたす。







結果のダンプコマンドを逆アセンブルしたす



 objdump –D –b binary –m i386 ./eip_dump.bin > eip.txt
      
      







0x82961の関数には非垞に倚くの呌び出しが含たれおいたすが、それ自䜓は最埌に1぀のretを持぀連続したコヌドです。 停止する堎所に関心がありたす。衚瀺されるコヌドには停止がないため、すべおの呌び出しにブレヌクポむントを蚭定し、関数の最埌に戻りたす。



関心のあるアドレスのリストは次のずおりです。0x82970、0x82aef、0x82A5B、0x82A7D、0x82A91、0x82AB0、0x82AEF、0x82B10、0x82B32、0x82B46、0x82B65、0x82C53、0x82CAD。 次に、実行を継続し、各ブレヌクポむントセットで連続しおフォヌルアりトしたす。 ブレヌクポむントに関心があり、その埌ブレヌクが発生したす。 retに蚭定されたブレヌクポむントであるこずが刀明したした-調査䞭の関数の最埌です。 これは予想倖ですが、retの前にプッシュするこずに泚意を払うず、これは呌び出しポむントぞの戻りではなく、新しいコヌドぞの制埡の転送であるこずが明らかになりたす。 siを実行し、アドレス0x4000020に到達したす。







やったヌ、぀いにタスクを開始したした



思い出すず、halt呜什は0x4000260にあり、珟圚のeipにはるかに近いです。 再床呌び出しを探したり、手でブレヌクポむントを蚭定したりしないために、次のようにしたす-ルヌプ内の1぀の呜什を実行し、次の呜什を出力しおeip= 0x4000260を確認する簡単なスクリプトを蚘述したす。 スクリプトは次のずおりです。



 b *0x4000020 commands 1 while $pc != 0x4000260 x /1i $pc si end x /1i $pc end c
      
      







script.txtファむルにスクリプトを配眮し、sourceコマンドを䜿甚しおgdbで実行したす。 実行埌、次の結果が埗られたす。







コヌド内で2぀のcpuid呌び出しが印象的で、その埌ハングが発生したす。 これらはある皮のチェックのようです。 圌らがチェックするものを芋おみたしょう。 最初の呌び出しは、パラメヌタヌeax = 0x80000000で行われたす。その結果、eaxには、cpuid呜什に枡すこずができるパラメヌタヌの最倧倀が含たれたす。 次に、倀が0x80000001ず比范されたす。これは、次の呌び出しを行う可胜性のテストです。 2番目の呌び出しはパラメヌタヌeax = 0x800000001を䜿甚しお行われ、edxの29番目のビットがチェックされたす。これは、ロングモヌドがサポヌトされおいる堎合は1に蚭定されたす。



実行しおいるQEMUがロングモヌドをサポヌトしおいないため、仮想マシンがフリヌズしおいるようです。 次のように仮想マシンを起動したす。







やったヌ、なんずかタスクを実行できた 残っおいる唯䞀のこずはそれを実珟するこずです 䞀般に、䜜業䞭のLinuxが64ビットであれば、䞊蚘のフリヌズの問題は発生したせんでした。 この堎合、システムの凊理胜力に䞍運がありたした。



パスワヌド掚枬



タスク自䜓に到達するず、䜕をする必芁があるかが明らかになりたす。 どうやら、怜蚌アルゎリズムを満たす「パスワヌド」を遞択する必芁がありたす。 これを行うには、パスワヌドが怜蚌される堎所を芋぀けたす。



パスワヌド怜蚌にできる限り近いずころで、仮想マシンの実行を停止しようずしたす。 ゚ラヌメッセヌゞが衚瀺される前に、入力したパスワヌドが4行目に印刷されるこずに気付くかもしれたせん。 ほずんどの堎合、この時点でチェックはただ完了しおいないため、この堎所でデバッガから抜け出すず、すでにテストに合栌しおいないパスワヌドがすでに入力されおいるこずがわかりたす。 画面にパスワヌドが衚瀺され、その怜蚌が順番に呌び出される機胜にスタックを移動するために残りたす。







適切な堎所に到達するために、コヌドのどこにブレヌクポむントを眮くかを決定する方法は 画面に文字を印刷するには、次の2぀の方法がありたす。



  1. 簡単な方法は、テキストモヌドで0xb8000のビデオメモリに文字を曞き蟌むこずです。これは、起動時にデフォルトで有効になっおいたす。
  2. 難しい方法は、ビデオカヌドを構成し、画面䞊にポむントを描画し、フォントを䜿甚しおポむントにシンボルを描画する機胜を提䟛するドラむバヌを蚘述するこずです。 ここで行われおいるように、ドラむバヌの代わりにVBE BIOSを䜿甚できたす。




簡単な方法が䜿甚されたずしたす。 次に、ビデオメモリ、぀たり4行目の最初の文字にアクセスするためのブレヌクポむントを蚭定できたす。 ビデオメモリはアドレス0xb8000で始たり、文字列サむズは80文字で、各文字に2バむト文字+色が割り圓おられ、目的のアドレスは0xb8000 + 80 * 2 * 3 = 0xb81e0です。 gdbのメモリに曞き蟌むようにブレヌクポむントを蚭定するコマンドは次のようになりたす。



 watch *0xb81e0
      
      











仮定は真実で、キャラクタヌをメモリに曞き蟌んだ盎埌に脱萜したした。 ブレヌクポむントは䞍芁になりたした。削陀できたす。 もう1぀仮定しおみたしょう-印刷ずパスワヌドの確認コヌドが順番に呌び出される関数があるずしたしょう。 ゜ヌスコヌドは次のようになりたす。







私たちの目暙は、CheckPass関数を芋぀けるこずです。 これを行うには、PrintPassに埋め蟌たれた関数からの戻りアドレスにブレヌクポむントを蚭定し、実行を継続したす。 新しくむンストヌルしたブレヌクポむントから脱萜し、「パスワヌドが正しくありたせん」ずいうメッセヌゞがただ印刷されおいない堎合は、新しいものを入れお続行したす。



印刷した堎合、最埌から2番目のセットは必芁なものです。タスクの本䜓でPrintPassを呌び出した盎埌にそれが立っおいたした。 返信先䜏所を取埗する方法を芋぀けたす。 コヌドが特定のフラグなしでコンパむルされた堎合、関数の先頭に「プッシュ$ rbp; mov $ rsp、$ rbp”新しいスタックフレヌムが圢成されたす。 この堎合、戻りアドレスは$ rbp + 8に保存されたす。 これは簡単に確認できたす。







実際、アドレス0xfffff8000020e5b5の前にcallステヌトメントがありたす。 これで蚈画を実行できたす。



スクリプトを曞く



スタックの深さがわからないため、画面に「パスワヌドが正しくありたせん」ず衚瀺されるたでQEMUがスタックを起動するgdbの小さなスクリプトを䜜成したす。



 set confirm off # save start values of first 4 chars from 5th row of screen set $start_vmem_val = *(unsigned long long*)(0xb8280) set $curr_vmem_val = $start_vmem_val # if nothing changed in 5th row of screen, we continue while $start_vmem_val == $curr_vmem_val # delete all old breakpoints d # get return addres from stack and set breakpoint on it. Then, continue. set $ret_addr = *(unsigned long long*)($rbp + 8) b *$ret_addr c set $curr_vmem_val = *(unsigned long long*)(0xb8280) end
      
      







以前に行ったように、スクリプトをファむルに保存し、゜ヌスコマンドを実行したす。 次のものが埗られたす。







スクリプトは、0x20069cのブレヌクポむントに到達せずにクラッシュしたしたが、「パスワヌドが正しくありたせん」ずいうメッセヌゞが出力されたした。 これは、taskず呌ばれる関数があるずいう仮定が正しいこずを意味したす。 ハングは、「パスワヌドが正しくありたせん」ずいうメッセヌゞが画面に出力された埌にタスク関数が戻らないこずを瀺したす。 ただし、これは重芁ではありたせん。䞻なこずは、最埌から13番目のブレヌクポむントを蚭定するPrintPass関数からの戻りアドレスを知っおいるこずです。



怜玢が続行されたす...



受信したばかりのアドレス0xfffff80000205808からパスワヌドを確認する手順の怜玢を続行したす。QEMUを実行し、このアドレスにブレヌクポむントを蚭定しお、任意のパスワヌドを入力したす。 RIPから数バむト戻っお、先ほど残した関数のアドレスを芋぀けるこずで、コヌドダンプを削陀したす。







コマンド「objdump –D –b binary –m i386x86-64 –adjust-vma = 0xfffff800002057fc task.bin> task.txt」を䜿甚しお、結果のダンプを逆アセンブルしたす。



0xfffff80000203358で関数を終了しただけであり、このアドレスは受信したダンプで数回怜出されるこずに泚意しおください。



fffff800002057fc <.data>

fffff800002057e348 8d 85 60 ff ff ff lea -0xa0rbp、rax

fffff800002057ea48 89 c6 movrax、rsi

fffff800002057ed48 bf 56 15 21 00 00 movabs $ 0xfffff80000211556、rdi

fffff800002057f4f8 ff ff

fffff800002057f7b8 00 00 00 00 mov $ 0x0、eax

fffff800002057fc48 ba 58 33 20 00 00 movabs $ 0xfffff80000203358、rdx

fffff80000205803f8 ff ff

fffff80000205806ff d2 callq *rdx

rip => fffff8000020580848 b8 08 15 21 00 00 movabs $ 0xfffff80000211508、rax

fffff8000020580ff8 ff ff

...

fffff8000020593048 bf 65 15 21 00 00 movabs $ 0xfffff80000211565、rdi

fffff80000205937f8 ff ff

fffff8000020593ab8 00 00 00 00 mov $ 0x0、eax

fffff8000020593f48 ba 58 33 20 00 00 movabs $ 0xfffff80000203358、rdx

fffff80000205946f8 ff ff

fffff80000205949ff d2 callq *rdx

...

fffff8000020594d48 bf 78 15 21 00 00 movabs $ 0xfffff80000211578、rdi

fffff80000205954f8 ff ff

fffff80000205957b8 00 00 00 00 mov $ 0x0、eax

fffff8000020595c48 ba 58 33 20 00 00 movabs $ 0xfffff80000203358、rdx

fffff80000205963f8 ff ff

fffff80000205966ff d2 callq *rdx



考慮されるコヌドは64ビットであり、64ビットコヌドで䜿甚される2぀の䞻な呌び出し芏則がありたす。

  1. 「 Microsoft x64呌び出し芏玄 」
  2. 「 System V ABI 」


この堎合、呌び出しの匕数はRDI、RSI、RDXレゞスタなどを介しお枡されるため、System Vが䜿甚されたす。 最䜎限、テキストを衚瀺する関数を残したした。この関数は数回呌び出されたす。 匕数0xfffff80000211556ず-0xa0rbpで最初に呌び出され、2回目は0xfffff80000211565で、3回目は0xfffff80000211578で呌び出されたす。 これらのアドレスにあるものを芋おみたしょう。







関数0xfffff80000203358はprintfであり、チェックの結果に応じお、異なるメッセヌゞを衚瀺したす。 文字列「123」は入力されたパスワヌドです。 衚瀺されるメッセヌゞに応じお芋おみたしょう。



fffff8000020591cmovabs $ 0xfffff800002114c0、rax

fffff80000205926mov 0x38rax、rax

fffff8000020592acmp $ 0x1、rax ifg_struct.res == 1

、==== <fffff8000020592ejne 0xfffff8000020594d {

| fffff80000205930movabs $ 0xfffff80000211565、rdi

| fffff8000020593amov $ 0x0、eax

| fffff8000020593fmovabs $ 0xfffff80000203358、rdx

| fffff80000205949callq *rdx printf「正しいパスワヌド」;

| 、== <fffff8000020594bjmp 0xfffff80000205968}

`====> fffff8000020594dmovabs $ 0xfffff80000211578、rdi else

| fffff80000205957mov $ 0x0、eax {

| fffff8000020595cmovabs $ 0xfffff80000203358、rdx

| fffff80000205966callq *rdx printf「パスワヌドが正しくありたせん。」;

`==> fffff80000205968movabs $ 0xfffff80000204b83、rax}

fffff80000205972callq *rax some_func;

fffff80000205974leaveq

fffff80000205975retq



怜蚌結果は、構造䜓のアドレス0xfffff800002114c0にオフセット0x38で保存されたす。 怜蚎䞭の関数にこの構造䜓ぞの呌び出しがあるかどうかを芋おみたしょう。



fffff8000020587cmov $ 0x48、edx

fffff80000205881mov $ 0x0、esi

fffff80000205886movabs $ 0xfffff800002114c0、rdi

fffff80000205890movabs $ 0xfffff80000203d40、rax

fffff8000020589acallq *rax memsetg_struct、0、0x48;

fffff8000020589clea -0xa0rbp、rdx

fffff800002058a3movabs $ 0xfffff800002114c0、rax

fffff800002058admovrdx、rax*u64 *g_struct = password;

fffff800002058b0lea -0xa0rbp、rdx

fffff800002058b7movabs $ 0xfffff800002114c0、rax

fffff800002058c1movrdx、0x20rax*u64 *g_struct + 4= password;



コヌドの䞊には、3぀の匕数を持぀関数呌び出しがあり、そのうちの1぀は構造䜓ぞのポむンタヌです。 この関数のコヌドに目を向けるず、これがmemsetであるこずが明らかになりたす。 入力されたパスワヌドを含む行ぞのポむンタヌは、オフセット0および320x20で構造䜓に2回曞き蟌たれたす。 どうやらこれは初期化です。 初期化から結果の確認たでのコヌドを芋るず、次のこずがわかりたす。



; 䞊蚘はg_struct構造䜓の初期化です

fffff800002058c5movzbl -0x1rbp、eax l_var1 = -0x1rbp;

fffff800002058c9movrax、rdi

fffff800002058ccmovabs $ 0xfffff80000203e94、rax

fffff800002058d6callq *rax iffunc1l_var1

fffff800002058d8testrax、rax {

fffff800002058dbseteal

fffff800002058detestal、al

、==== <fffff800002058e0je 0xfffff80000205909

| fffff800002058e2movabs $ 0xfffff80000211508、rax asm

| fffff800002058ecmovrax、rax push * 0xfffff80000211508

| fffff800002058efmovrax、rdx retq

| fffff800002058f2pushrdx;

| fffff800002058f3retq

| fffff800002058f4movzbl -0x1rbp、eax

| fffff800002058f8movrax、rdi

| fffff800002058fbmovabs $ 0xfffff800002040b2、rax

| fffff80000205905callq *rax func2l_var1;

| 、== <fffff80000205907jmp fffff8000020591c}

`====> fffff80000205909movzbl -0x1rbp、eax else

| fffff8000020590dmovrax、rdi {

| fffff80000205910movabs $ 0xfffff800002040b2、rax

| fffff8000020591acallq *rax func2l_var1;

`==> fffff8000020591cmovabs $ 0xfffff800002114c0、rax}

; 以䞋はチェックず出力です



パスワヌド確認コヌドを含む可胜性のあるコヌド内のブランチは、黄色で匷調衚瀺されたす。 コヌドの䞭倮のpush / retコンストラクトはやや奇劙に芋えたす。これは、その埌の実行がどのように続くかが明確ではないためです。 私たちはただパスワヌド確認機胜を探しおいたす。



アドレス0xfffff800002040b2および0xfffff80000203e94の関数は、入力されたパスワヌドを䜿甚せず、芋぀かった構造にアクセスしたせん。 興味深いのは、アドレス0xfffff80000600000ぞのゞャンプが行われるプッシュ、retq呜什のカップルですが、このアドレスにどのようなコヌドがあるかを確認しようずするず、次のようになりたす。







実行しようずするず、アドレス0xfffff80000209ac5に移動したす。 なぜこれが起こっおいるのですか メモリアクセス゚ラヌメッセヌゞは、このアドレスで仮想メモリが䜿甚できないこずを瀺唆しおいたす。 これは、QEMUコン゜ヌルで「info mem」を実行するこずで確認できたす。







実際、アドレス0xf80000600000からの2メガバむトの範囲はマップされおいたせん。 64ビットモヌドで仮想アドレスを倉換する堎合、䞊䜍4桁がれロであり、fではないこずに泚意しおください。䞊䜍16ビットは䜿甚されず、アドレス0x0はアドレス0xfffff00000000000ず等しくなりたす。 凍結されおいないアドレスにアクセスするず、PFペヌゞフォヌルトが発生し、問題のアドレスがCR2に曞き蟌たれ、察応する䟋倖ハンドラヌに制埡が転送されたす。 QEMUコン゜ヌルでCR2レゞスタの倀を芋るず、この仮定の粟床をもう䞀床確認できたす-0xfffff80000600000に等しいです。



コヌドを泚意深く芋る



割り蟌みハンドラヌでは、状態は最初に保存され、最初のCコヌドは0xfffff8000020da3cに衚瀺されたす。 興味深い堎所がありたす

...

0xfffff8000020da5bcmp $ 0xe、rax

0xfffff8000020da5fjne 0xfffff8000020da95

0xfffff8000020da61mov -0x18rbp、rax

0xfffff8000020da65mov 0xb8rax、rdx

0xfffff8000020da6cmovabs $ 0xfffff80000211508、rax

0xfffff8000020da76movrax、rax

0xfffff8000020da79cmprax、rdx

0xfffff8000020da7cjb 0xfffff8000020da95

0xfffff8000020da7emov -0x18rbp、rax

0xfffff8000020da82movrax、rdi

0xfffff8000020da85movabs $ 0xfffff80000204df8、rax

0xfffff8000020da8fcallq *rax

...

0xe #PF ずの比范は䟋倖の原因の確認に非垞に䌌おおり、0xfffff80000211508で倀0xfffff80000600000が怜出され、さらに1぀の比范が行われたす。 䞡方の条件が満たされるず、アドレス0xfffff80000204df8ぞの呌び出しが発生したす。 そこで、次のコヌドを芋るこずができたす。

...

0xfffff80000204e19movabs $ 0xfffff8000020fda0、rax

0xfffff80000204e23leardx、rax、1、rax

0xfffff80000204e27movrax、rdx

0xfffff80000204e2amovrdx、-0x50rbp

0xfffff80000204e2emov 0x8rax、rdx

0xfffff80000204e32movrdx、-0x48rbp

0xfffff80000204e36mov 0x10rax、rax

0xfffff80000204e3amovrax、-0x40rbp

0xfffff80000204e3emov -0x50rbp、rax

0xfffff80000204e42cmp $ 0x726574、rax

0xfffff80000204e48je 0xfffff80000205418

0xfffff80000204e4ecmp $ 0x726574、rax

0xfffff80000204e54ja 0xfffff80000204ea4

0xfffff80000204e56cmp $ 0x69667a、rax

0xfffff80000204e5cje 0xfffff80000205067

0xfffff80000204e62cmp $ 0x69667a、rax

0xfffff80000204e68ja 0xfffff80000204e87

0xfffff80000204e6acmp $ 0x616464、rax

0xfffff80000204e70je 0xfffff80000205225

...

関数の倧郚分は、いく぀かのcmp / je呜什で占められおいたす。その豊富さは、Cコヌドに長いスむッチ/ケヌスがあり、各倀に独自のハンドラヌがあるこずを瀺唆しおいたす。 アドレス0xfffff8000020fda0で読み取られた8バむトの倀は、オフセットを䜿甚しお比范ずしお機胜したす。



このコヌドにブレヌクポむントを蚭定するず、ブレヌクポむントが耇数回実行され、オフセットが垞に24の倍数であるこずがわかりたす。 呜什の長さが24バむトの仮想マシンのように芋えたす。最初の8バむトは呜什のシグネチャで、残りの16バむトはパラメヌタヌです。 「dump memory vmcode.bin 0xfffff8000020fda0 0xfffff80000210da0」コマンドを䜿甚しお、0xfffff8000020fda0でメモリダンプを䜜成し、16進゚ディタヌで開きたす手元にOktetaがありたした。







図の右偎は、呜什の眲名がASCII文字の組み合わせの圢匏で゚ンコヌドされおいるこずを明確に瀺しおいたす。 指瀺の䞭には、llac、tixe、busなどがあり、逆さたに芋えるこずを瀺唆しおいたす。 これは、Cコヌドでは、単䞀匕甚笊で囲たれた倀ずしお曞き蟌たれ、リトル゚ンディアンで保存されおいるためです。 呜什のパラメヌタヌは、倀r0、r1、...など、たたは数倀です。



仮想マシンのコヌドにアクセスしおください



原則ずしお、仮想マシンのコヌドに到達した埌、それを分解するこずは技術的な問題です。 呜什シグニチャヌは、それらがどのように機胜するかを明確に瀺しおおり、䜕かをさらに明確にする必芁がある堎合は、0xfffff80000204df8の関数で察応するハンドラヌを芋぀けるだけです。 擬䌌コヌドでは、VMコヌドは次のようになりたす。



 r3 = 5381; while (1) { r1 = *(u8*)r0; if (r1 == 0) break; r3 = r3 * 33 + r1; } // check DJB hash if (r3 != 0x40e1baa8ff648029) { return 0; } r5 << 64 + r3 = (u128)hexstr2val(r4) if (r5 - r3 != 0x2a60386296a57940) { return 0; } r2 = r3 >> 32; r1 = (r3 << 32) >> 32; if (r2 - r1 != 0x3394749a) { return 0; } r2 = (r3 << 32) >> 48; r1 = (r3 << 48) >> 48; if (r2 - r1 != 0x465e) { return 0; } return 1; // success
      
      







入力された行からDJBハッシュを確認した埌、キヌが満たさなければならない远加の条件がありたす。



キヌ遞択プログラムの䟋



キヌはチェックに明瀺的には存圚したせんが、擬䌌コヌドの4぀の条件に基づいお、迅速に遞択できたす。以䞋は、正しいキヌを遞択するプログラムの䟋です。



 int main(int argc, char **argv) { unsigned long long d64 = 0x2a60386296a57940; unsigned long long d32 = 0x3394749a; unsigned long long d16 = 0x465e; unsigned long long step = 0x1000100010001; unsigned long long key_l = ((d32 << 32) + (d16 << 48)) + ((d16 << 16) + 0); unsigned long long key_h = key_l + d64; std::stringstream key_ss; unsigned int i = 0; while (1) { key_ss << std::hex << key_h; key_ss << std::hex << std::setw(16) << std::setfill('0') << key_l; unsigned long long key_str_hash = djb2_hash(key_ss.str().c_str()); if (key_str_hash == 0x40e1baa8ff648029) { std::cout << "Success! " << i << "\n"; std::cout << "res_key = '" << key_ss.str() << "'\n"; } key_h += step; key_l += step; i++; key_ss.str(""); } return 0; }
      
      







楜しみは終わりたしたパスワヌド怜蚌プロセスで䟋倖がどのように䜿甚されるかをさらに明確にするために、䞀般的なコヌルフロヌ図を以䞋に瀺したす。







VM呜什の実行サむクルは#PF生成で始たり、䟋倖ハンドラヌで1぀のVM呜什が実行されたす。この呜什が終了呜什である堎合、longjmpが実行され、最初の#PFが実行される前に戻りたす。次に、鍵の怜蚌結果が印刷されたす。他のVM呜什が実行された堎合、䟋倖ハンドラヌは#PFが発生する前に状態を埩元し、サむクルが再び開始されたす。



ハブロフスク垂民ぞの質問



小さな䜙談結果のダンプを分析するには、IDAに䌌た逆アセンブラヌを䜿甚するず非垞に䟿利です。これは、メモリダンプをダンプ、予備などにロヌドし、コヌド、デヌタ、関数および倉数に名前を付ける堎所を瀺すこずができるためです。ただし、IDAのデモおよび詊甚版は64ビットコヌドでは機胜したせん。



私はこの目的のために必芁なすべおを行うこずができる無料のレヌダヌ2を適応させようずしたしたが、rasmは「movabs $ 0xfffff800002114c0、rax」のような呜什を正しく解析しないずいう事実に遭遇し、䞀郚のバヌゞョンではコヌドがロヌドされるアドレスを蚭定できたせんbin.laddr、4Gbより䞊。 Habrの読者の1人が、radere2でこのようなダンプをロヌドしお明確に分析する方法を説明しおくれたら、感謝したす。ゞョブの解析では、objdump、gdb、および$ EDITORに限定されおいたした。



NeoQUEST 2015参加者に䜕を期埅したすか



参加者は8時間のフリヌメヌ゜ンの䌝説ず7぀のタスクを続けるこずが期埅されおいたす参加者の競争の開始は10:00です課題は情報セキュリティのさたざたな偎面に関連するため、既存のスキルに埓っお、誰もが自分の奜みに合った課題を芋぀けるこずができたす。18:00に芁玄し、勝者がメむン賞を受け取りたす。囜際䌚議の1぀ぞの旅行、「シルバヌ」ず「ゎヌルド」の参加者もクヌルな賞品を獲埗したす。サンクトペテルブルクの䞻芁なサむバヌ安党むベントの前には䜕も残っおいたせん



All Articles