WeSeong ログイン
← 記事一覧に戻る
CPUとセキュリティ

OLLYDBGを用いた実習と、CPU、メモリに関する追加情報

OLLYDBGを用いた実習と、CPU、メモリに関する追加情報

Ⅰ. 概要

これまでの投稿に続き、CPUとメモリに関する内容で不足していた部分を補完します。PEViewプログラムを使用して、PE(Portable Executable)の構造を調べます。Ollydbgプログラムを使用して、コンパイルされたプロセスの動作を観察し、操作を試みます。



Ⅱ. CPUとメモリ

CPU詳細については、過去の投稿を参照してください。CPUはデュアルコア、ヘキサコアなど様々な種類がありますが、それぞれのコアが個別のレジスタを持っているため、現代の マルチタスク(複数の作業を同時に行うこと)作業が容易になりました。ここで重要なのは、マルチプロセッサとCPUのデュアルコア、ヘキサコアなどは異なる概念であるということです。プロセッサはCPUのようなハードウェアデバイスを指すため、マルチプロセッサとは、CPUが2つ以上搭載されていることを意味します。一方、コアはCPUの中に含まれるものです。つまり、 マルチプロセッサ2つ以上のCPUがあり、それぞれのCPUは、ヘキサコアのように複数のコアを持つことができる。


メモリの構造について改めて説明します。


このような仕組みで、カーネルはハードウェアと信号をやり取りしています。 シェルユーザーからの指示を受け、それに応じて特定のデバイスを制御する役割を担います。そのため、すべてのオペレーティングシステムは、シェルを通じてカーネルに指示を出し、コンピュータのスピーカー、モニター、ネットワークカードなどのハードウェアを制御します。以前のLinuxでは

[SK Telecom SeSAC、ソウル1期] 仮想マシン、Linux、Ubuntu

これは学んだ内容ですが、より詳細に整理したので、参考にしてください。セキュリティ上の理由から、ハードウェアへの直接的なアクセスはできません。つまり、カーネルを通じてドライバにアクセスし、カーネルにアクセスするにはシェルを使用する必要があります。シェルは、機械語を理解していない私たちのようなユーザーが、カーネルやハードウェアに対してコマンドを実行できるようにする、一種のインターフェースです。 親と子の関係しかし、もしウェブ開発の経験があるなら、このような構造を思い浮かべやすいかもしれません。メインのシェルがあり、このシェルから様々なプログラムのシェルを作成できます。 メインプロセスこれは 子プロセスこれを作成し、動作させるものです。Windows のメインシェルは「

'explorer.exe'私たちがブラウザを開いたり、WordやPowerPointなどのアプリケーションを実行したりする際、メインのシェルを経由して動作します。新たに作成されたシェルは、子プロセスとして機能し、その中にメインスレッドと子スレッドがそれぞれプログラムの機能を実行します。 メインスレッドこれはプロセス全体の管理を担当します。 子プロセスそれぞれの機能は、個別に担当しています。


* Windows のプロセス管理モジュールを作成する際に役立つ Python モジュールがあります。Python の WMI モジュールを活用することも、面白いのでお勧めします。


カーネルに関する説明が長くなりましたが、改めてメモリについて説明します。メモリは、主に以下の構造で構成されています。 「スタック領域 - ヒープ領域 - データ領域 - コード領域」 順番に並んでいると考えるだけで構いません。実際、データ領域とコード領域は順番が重要ではないため、上記の写真のように構成されています。その理由は、データ領域が… グローバル変数や静的変数が格納される場所そして、コード領域は、文字通り プロセス実行に関連するコードが保存されている。しかし、スタック領域とヒープ領域では、順番が重要です。 メモリのアドレスは、下位ビットが小さい順に、上位ビットが大きい順に配置されています。スタック領域は、ヒープ領域よりも低い位置にあります。 高いアドレスから低いアドレスへ保存実現可能です。一方、ヒップホップの分野は 低いアドレスから高いアドレスへの保存実現されるということです。スタック領域は 地域変数やパラメータを保存そして、重要な情報はいつでも参照できるように整理しておくことが重要です。 動的に割り当てられ、インスタンスこれらの情報は保存されています。



Ⅲ. ポータブル実行ファイル

以前の投稿でも触れましたが、Windowsの実行ファイル(プロセス)はPE構造で構成されています。 構造体これについて理解しておくと役立ちます。構造体は、リストやJSON形式のようなものを、バイト単位で分割して、プログラムのコードやデータを表現します。この構造体を表示する方法は、ヘッダーによって異なります。ZIPファイルやPEファイル、MFT、VBRなど、それぞれ異なる様々な形式で表現できます。 ヘッダー構造ヘッダーには、バイトごとに区切られており、どのバイトがどのような機能や役割を持ち、実際のデータとは何か、といった詳細な情報が記載されています。(類似した構造があります。)


これらはすでに簡単に説明されていますが、PE構造を表示するプログラムを使用することで、ヘッダーの種類と分類を確認し、実際のアドレス値も把握することができます。ヘッダーには固定値のものもありますが、動的な値も存在します。そのため、分析する際には、各バイトがどのような内容であるかを把握することが重要です。そこで、プロセスの流れを簡単に操作する実習を行うことを目的とします。


  1. ゼロフラッグの不正行為

このサンプルプログラムの場合、実際の実行コードは401000番の住所から開始されます。そこで、ブレークポイントを設定し、F9キー(ブレークポイントまでの一連の実行)を押して、401000番の住所に移動します。Zero Flagは、比較演算を行う際に、一致する場合は1を返し、一致しない場合は0を返します。


この赤い部分を見ると、アセンブリ言語のCMP(比較命令)を使用して、JNZ(比較演算の結果が等しくない場合に、次の処理をスキップする)を実行しています。そのため、F7、F8キーでプログラムを実行する際に


もし1に修正されると、比較演算の結果が同じであると認識され、次の処理に進むようになります。


  1. JNZ 命令の変更

もし、Zero Flagを変更するのではなく、JNZ命令をJE、JZ(比較演算の結果が等しい場合に次の処理をスキップする)に変更することは可能でしょうか?もちろん可能です。


このような流れで、プロセスがスムーズに進行している様子が確認できます。この方法で命令を変更する方法は2つあります。写真に示されているように、JE、JZ命令は16進数で75です。この値を74に変更するか、またはJE、JZという命令自体を入力して変更することができます。


  1. プロセスロジックの住所変更

これらの写真に詳しく見てみると、「Sample_0」の後に「00401079」が表示されていることがわかります。「Sample_0」の前の部分はプログラム名であり、「00401079」の後の部分は、JNZ命令を実行する際に実行されるコードのアドレスを示しています。もしこのコードのアドレスを「401000」に変更した場合、どのような結果になるでしょうか?



写真のように、401000から401048までの数字が無限に繰り返されることになります。


※ 401000、401048などの住所は、厳密には オフセットこれは、メモリ内の特定の場所から、相対的な場所を特定するための機能です。このオフセット機能は非常に有用なので、覚えておくと役立ちます。


  1. HxDを使用して、比較演算のデータ変更

これは、開発者が作成した比較演算の結果を、Hex Editor (HxD) を使用して実際に変更することを意味します。


赤い部分は実際の比較値であり、上記では `GetLocalTime` 関数を使用して現在時刻を取得しています。また、PE構造におけるBase Codeの開始位置が1000であることがわかります。さらに、写真に示されている16進数の7D5が、アドレス401040にあることもわかります。先頭に400000が付いているのは、プロセスのメモリ開始位置を示しており、実際のコードはBase Codeを基に1000から始まるため、HxDで1040の場所にアクセスすると…


このような形式で確認できます。次に、この値を現在の年、月、日に変換し、残りの0と20を現在の日付に置き換えることで完了です。


その後、再度 OllyDbg を実行して動作を確認すると、


このように、値が変更され、CMP比較演算を正常に通過している様子を確認できます。



※ このプロセスは、メモリに割り当てられ、アドレス値を参照しながら、変数を利用したり、関数を実行したり、データを処理したりします。スタック領域は、高いアドレスから始まり、LIFO(Last In, First Out:最後に格納されたものが最初に取り出される)構造で、徐々に低いアドレスに格納されます。そのため、コードの開始アドレスを見ると サブ 指示として ESP(エスペ)114を引いているところですが、ESP(エクスプレス・インジレジスタ)は、スタック領域の最下部(つまり、最後のメモリ位置)から114を引くことで、メモリ空間を確保します。これは少し理解が難しいかもしれませんが、 これは、上から下へ処理を進めるため、また、高いアドレスから低いアドレスへ移動するため、関数が動作するために必要なメモリ(114)を確保する仕組みです。



おまけ

新たに始めたアプリケーションの理解と活用は、先週のネットワークの問題よりもさらに難しく感じました… 💰 私は、フォレンジックやリバースエンジニアリングの経験がほとんどないため、この分野に簡単に取り組むのは難しいと感じました。しかし、この1週間を乗り越えたと思っています… 🤣 もちろん、理解できたかどうかは別の話ですが😅、今後、いくつかの投稿を通して、学習内容を整理していきたいと思います。