構造体編集(新型32ビット版「UsaMimi32.exe」および64ビット版「UsaMimi64.exe」用)
構造体編集の概要・基本操作
●概要と注意点■概要 「構造体」とは、数値や文字列など色々な形式のデータを、ひとつの型としてまとめたものといえます。一般的なソフトウェアやマルウェアおよびPCゲーム等では、プログラムの処理で使用する数値や文字列等のデータ群を構造体で管理することがあります。当機能を用いることで、解析対象が使用する、プロセスメモリ上の構造体を構成するデータ群に対し、内容の一括表示や一括書き換えを容易に行うことが可能になります。つまり、ByteやDWordやFloatといった各種の数値表現形式の数値、各種文字コードの文字列および、ビット列といった異なる型のデータ群を、あらかじめ指定していた内容で一括して書き換えることができる訳です。この書き換える対象のデータ群は、アドレスが離れていたり、モジュール相対アドレスあるいは、ポインタを使用するケースでも対応可能です。各種の数値表現形式や文字コードおよびビット等については、「基礎用語解説」を参照してください。 当ソフトウェアには、複数の数値や文字列をグループ化して検索する「グループ検索」機能を実装しています。構造体では、構成する複数の数値や文字列がたいてい近接していることから、「グループ検索」で目的の構造体のアドレスを確実に検索可能なケースがあります。なお、「グループ検索」での検索時には、検索時間の短縮を図るため、できるだけヒット数が少ない特徴的なデータを指定してください。特にヒット数が多いバイナリデータ「FF」や「00」を検索条件に指定すると、検索時間が大幅に伸びる可能性があります。 また、当ソフトウェアには、特定アドレスに格納された指定形式の数値を、時系列で表示し変化を確認できる「特定アドレス格納値の時系列状況推移を表示」機能も実装しています。この機能を併用することで、当機能による構造体の解析の効率化が見込まれます。 参考:プログラミングにおける構造体の定義例 struct { BYTE Age[9]; //[9]はBYTE(符号なし1バイト)の値が9つ並ぶ配列を意味する WORD Weight; //配列指定でなければ1つの値 DWORD ColorARGB; QWORD TailLength; double PurrPerDay; wchar_t Name[42]; //[42]はwchar(Unicode文字)で42字分の配列を意味する } Neko; //構造体名参考までに、当ヘルプの基礎用語解説「基礎用語 バイナリファイルの解析」には、PNG画像ファイルのヘッダを構造体として解析している例があります。ただしこれは、プロセスメモリ上のバイナリデータではなく、バイナリファイルのバイナリデータを解析しています。 プログラミングでは、構造体を構成する変数は「メンバ(member)」と呼びます。当機能では、構造体を構成する変数を「項目」と表示し、この項目を、「名前」や「コメント」、色々なデータ形式である「要素」とその数である「要素数」で定義しています。 ■注意点 QWORDの値には、9223372036854775807(0x7FFFFFFFFFFFFFFF)を超える値は指定できません。 FloatとDoubleは、「123」「123.456」など通常の数値入力に加え、「7.2499434846656525e+078」といった形式での入力も可能です。 連続するBit(2進数Byte)の入力や表示は、誤認識を避けるため常に1バイト単位で行います。例えばBitが4つ並ぶ配列でも、DWORDとみなして32ビットのビット列で表示するわけではありません。 Windows ANSI/Unicode(UTF-16LE)/UTF-8文字列の指定や現在値表示は255文字が上限です。 |
●参考スクリーンショット
●基本的な操作の流れ
■リスト上のカラム部分を操作 リスト上の「アドレス」や「項目名」といったカラム部分をドラッグで入れ替えて、表示順序を一時的に変更することができます。また、特定カラムの右側境界をダブルクリックすると、リスト上の特定カラム以下に格納されている文字列の最大幅で、同カラムの横幅が調整されます。また、リスト左上にある「列幅を調整」チェックボックスで、全てのカラムが、格納されている文字列の最大幅で横幅が調整されます。 ■構造体のアドレスを指定 「上アドレスに変更」ボタンで、構造体先頭アドレスを指定アドレスに変更します。「相対表示」チェックボックスがチェックされているならば、各項目のアドレスを、構造体先頭アドレスからの相対値で表示します。 「上アドレスに変更」ボタン押し下げ時に、指定アドレスが「+20000」といった「+」で始まる場合は、EXEモジュール先頭からの相対アドレスとみなしてアドレス変更を行います。 Shiftキーを押しながら「上アドレスに変更」で、構造体先頭ではなく、リスト上の選択項目のアドレスを指定アドレスに変更します。これにより、構造体先頭アドレスは自動的に修正され、その修正されたアドレスを指定アドレス欄に表示します。 ■構造体定義ファイルの読み込みと保存 プログラミングに馴染みのない方でも構造体の定義を容易に扱えるように、当機能で扱う構造体定義ファイルは、テキストエディタ等で編集しやすいCSV形式のテキストファイルとしました。このCSVファイルを手動で作成あるいは編集するときは、文字コードが正確に判別可能な「BOM付きUTF-16LE」あるいは「BOM付きUTF-8」を指定して保存してください。当機能では、「定義ファイルを読み込み」ボタンでの、構造体定義ファイルの読み込みは文字コードUnicode(UTF-16LE)/UTF-8/Windows ANSI(Shift_JIS)に対応しています。また、「下を定義ファイルに保存」ボタンでの、構造体定義ファイルの書き込み時には文字コードUnicode(UTF-16LE)で保存します。なお、UTF-8への対応は簡易的なものであり、UTF-8/Windows ANSIのCSVならば、読み込み後にいったん保存してUnicode(UTF-16LE)化した上で再読み込みされることをお勧めします。 当機能のダイアログを閉じる際に、それまでに項目の追加・挿入・上書き・削除のいずれかが行われ、かつ構造体定義ファイルとして保存されていない場合は、同ファイルとして保存するかを尋ねるメッセージボックスを表示します。 項目の要素の形式は、手動でCSVファイルを作成時あるいは編集時の入力ミスを避けるため、簡略化して数値で指定できるようにしました。 実際のソースコード上では、要素の形式を以下のように定義しています。「//」の後に続く数字が、項目の要素の形式それぞれに割り当てた数値を意味します。なお、符号ありの1/2/4/8バイトの値には、「char/short/int/int64」という呼び方もあります。 TCHAR* Typename[] = { L"1Byte(Byte)", //0 L"2Bytes(Word)", //1 L"4Bytes(DWord)", //2 L"8Bytes(QWord)", //3 L"1Byte(符号あり)", //4 //char L"2Bytes(符号あり)", //5 //short L"4Bytes(符号あり)", //6 //int L"8Bytes(符号あり)", //7 //int64 L"Float", //8 L"Double", //9 L"Bit(2進数Byte)", //10 L"16進数byte", //11 L"16進数word", //12 L"16進数dword", //13 L"16進数qword", //14 L"Windows ANSI", //15 L"Unicode(UTF-16LE)", //16 L"UTF-8", //17 L"パディング", //18 L"*1Byte(Byte)", //19 L"*2Bytes(Word)", //20 L"*4Bytes(DWord)", //21 L"*8Bytes(QWord)", //22 L"*1Byte(符号あり)", //23 L"*2Bytes(符号あり)", //24 L"*4Bytes(符号あり)", //25 L"*8Bytes(符号あり)", //26 L"*Float", //27 L"*Double", //28 L"*Bit(2進数Byte)", //29 L"*16進数byte", //30 L"*16進数word", //31 L"*16進数dword", //32 L"*16進数qword", //33 L"*Windows ANSI", //34 L"*Unicode(UTF-16LE)",//35 L"*UTF-8", //36; L"アドレス指定", //37 };構造体定義ファイルの手動での編集に役立つよう、「上のスクリーンショットで使用した構造体定義ファイル記述例」を用意しました。 ■構造体の項目を追加・編集 「サンプル項目群を追加」ボタンで、サンプルとなるDWordの項目群をリスト末尾に追加します。このサンプル項目群は、構造体の定義を作成していく雛形としての使用を想定しています。Shiftキーを押しながらこのボタンを押し下げると、ボタン左側で選択された要素の形式と指定された要素数からなる項目群を追加します。 項目名、要素の形式と数およびコメントを指定して、「指定内容で項目追加」ボタンで指定項目をリスト末尾に追加します。「指定内容で項目挿入」ボタンではリスト上の選択位置に指定項目を挿入します。挿入位置指定のためのリスト上での項目選択は、Shiftキーを押しながら行ってください。「(下選択項目を)上書き」ボタンで、リスト上で選択された項目を指定内容で上書きします。リスト上で項目選択後に、「要素と数」のコンボボックスで形式名を変更すると、選択形式に応じた現在値を表示しますので、どの形式が適切かの判断に活用可能です。 要素の形式のうち、「パディング」は変数のアドレス調整用の「詰め物」です。この場合プロセスメモリの読み書きは行いません。要素数のバイト数でパディングのサイズを指定します。パディングは解析不要な項目の指定や、構造体の要素をDWord境界/QWord境界/16バイト境界にアラインメント(要素のアドレスを境界上に調整)することに使用可能です。実際にアプリケーションが使用する構造体で、メモリ上のアクセスの容易さなどによりアラインメントが行われた場合は、要素間に使用しないバイト列が生成されることがあります。例えば、64ビットの数値を末尾0か8のアドレスに配置するために、QWordやDoubleの要素の直前に使用しないバイト列が生成されます。 要素の形式のうち、形式名の先頭が「*」のものはポインタとして処理します。つまり、項目のアドレス以降には特定アドレスを指す値が格納されているとして、その特定アドレスに格納された値を現在値として表示します。項目の要素形式サイズがアドレスのサイズ(32ビットアプリケーションでは4バイト、64ビットでは8バイト)となるため、アプリケーションが32ビットか64ビットかで、構造体の構成とサイズが変化することに注意してください。形式名でポインタが指定された場合は、ポインタに格納されたアドレスの値は表示しませんが、このポインタに格納されたアドレスの値を、そのまま「16進数dword」形式または「16進数qword」形式の値として取得し表示することは可能です。この場合、ポインタのアドレスである項目をリスト上で選択し、「要素と数」のコンボボックスで形式名「16進数dword」または「16進数qword」を選択すると、現在値としてポインタに格納されたアドレスの値を表示します。 要素の形式のうち、「アドレス指定」は指定項目以降のアドレスを強制的に変更します。この「アドレス指定」で項目のアドレスを変更した結果は、以降の項目のアドレスにも適用されます。たとえば項目名を「0001'40202000」('は省略可、「」は不要)とすれば、項目のアドレスを0001'40202000に指定します。EXEモジュールやその他のモジュールの先頭アドレスからの相対アドレスを指定する場合は、モジュール名を半角「<>」でくくって、「<Nyanko42.dll>+205040」という形式で指定します(「」は不要)。この場合、+以降のオフセット(相対値)の値は、16進数で指定します(0xは省略可)。モジュール名は、メニューの「デバッグ」→「モジュール別参照関数表示」で参照・取得可能です。アドレス指定の構文の後に有意文字列を追加する、「0001'40202000 パラメータ」といった使い方も可能ですが、この場合はアドレス指定構文の誤認識が生じないよう、必ず半角スペースなどで有意文字列と区切ってください。 「アドレス指定」で、「*XXXXXXXX」形式で数値が指定された場合は、この指定値をポインタのアドレスとみなして、このアドレスに格納された値を項目のアドレスに指定します。「*」だけといった数値が指定されない場合つまり指定アドレスの値がゼロならば、その項目のアドレスをポインタのアドレスとみなして、項目のアドレスに格納された値で項目のアドレスを変更します。さらに「*XXXXXXXX+XXXX」形式で、ポインタに格納された値に+以降のオフセットの値を加算した結果で、項目のアドレスを変更します。通常オフセットは後方つまり加算となりますが、オフセットを前方に指定つまり減算する「*XXXXXXXX-XXXX」形式にも対応しています。 このポインタ指定は、モジュール先頭アドレスからの相対アドレスをポインタとする、「*<Nyanko42.dll>+205040」(「」は不要)という形式での指定も可能ですが、この形式はポインタに格納された値を取得するものであり、取得した値にオフセットを加算できません。そのため必要に応じて、「<Nyanko42.dll>+205040」で項目のアドレスをポインタのアドレスに変更してから、指定アドレスの値がゼロすなわち、項目のアドレスをポインタとして格納値を読み込み、さらにオフセットを加算する「*+XXXXXXXX」形式と組み合わせます。ポインタ指定を行うことで、ポインタ格納アドレス以降にある別の構造体の内容を表示することが容易になります。また、ポインタ指定とオフセットの組み合わせは、ポインタに格納されたアドレスから特定オフセットにある変数の表示や書き換えに加え、「ポインタ+オフセット」が何段にも連なる多重ポインタの解析にも有用です。多重ポインタを1段ごとに展開し、ポインタ先それぞれで構造体の内容を表示するという段階的なアプローチも可能です。 要素の形式が「アドレス指定」の項目は、その用途上で不要と考えられる、構造体先頭アドレスからの相対値表示は行いません。 参考:多重ポインタでパラメータのアドレスを取得する例(保存したCSVファイルの内容) *000140202000+20,37,0,ポインタとオフセットを指定, *+20,37,0,オフセットを指定, *+30,37,0,オフセットを指定, パラメータ,2,1,, アドレス指定時などで、項目のアドレスが不正なアドレスとなった場合は、項目のアドレス文字列の背景を赤色で表示します。不正なアドレスとなる原因は、指定ミスだけではなく、ポインタやオフセットの動的変更などもありえます。 項目名の先頭に特定の半角文字を指定することで、要素の形式の指定時と類似した処理結果を実現します。ただしこの機能は、項目名でアドレスを指定する、要素の形式「アドレス指定」とは併用できません。 項目名の先頭が半角「>」で、リスト上での項目色を変更し強調表示ができるようにしています。 項目名の先頭が半角「*」の場合も、要素の形式名先頭が「*」の場合と同様に、現在値をポインタ格納アドレスとして処理します。 項目名の先頭が半角「#」ならば、その項目はパディング(詰め物)として扱います。要素の形式で「パディング」を指定した場合と異なり、要素の形式を選択可能ですので、たとえば「8Bytes(QWord)」で要素数2を指定して16バイトのパディングを指定することができます。 項目名の先頭が半角「[」で、指定項目以降のアドレスを強制的に変更します。たとえば項目名を「 [0001'40202000] HP」とすれば、項目のアドレスを0001'40202000に指定します。もし、「 [+2020] 」といった「 [+XXXXXXXX] 」形式で数値が指定された場合は、この16進数の指定値にEXEモジュール先頭アドレスを加算した、EXEモジュール相対アドレスを項目のアドレスに指定します。なお、指定アドレス値の誤認識防止のため、アドレスは括弧[]でくくってください。このアドレス指定は簡易的なものであり、通常は要素の形式「アドレス指定」を使用してください。 項目名の先頭が半角「&」で、かつ「相対表示」チェックボックスがチェックされているならば、その項目を相対アドレス表示の基点(相対値はゼロ)に追加指定します。この新しい基点はいくつでも追加することができます。この追加指定は、特に要素の形式「アドレス指定」で項目のアドレスを変更した後に、その項目に続く「アドレス指定」以外の項目に使用することを想定しています。 リスト上で項目を右クリックすると、その項目のアドレス文字列をクリップボードにコピーします。 ■項目の現在値取得と書き換え 「更新」ボタン押し下げあるいはShiftキーを押しながら「更新」ボタン押し下げ時に、項目の現在値を再取得して、項目追加・挿入・上書き時からの変化があれば現在値の数値を赤色で表示します。Ctrlキーを押しながら「更新」ボタンで、全項目の現在値を再取得し、なおかつ、記録値も現在値に合わせて更新して変化の有無をリセットし、この時点から新たに現在値の変化の有無を監視します。なお、解析対象のウィンドウをアクティブにした後などの、当機能のダイアログを再アクティブにしたタイミングで、自動的に全項目の現在値を再取得して、変化した現在値の数値を赤色表示します。リスト上で選択されている項目は字の色変化が分からないことに注意してください。 「コメントで」ボタンあるいは「入力内容で」ボタンで、コメントあるいは現在値として入力された内容を使って、現在値の書き換えを行います。 書き換えに用いる整数値の指定は、10進数または16進数で行います。16進数の場合は「0x42」という形式で指定します。また、数値の書き換えは、数値の配列すなわちシーケンスに対応しています。たとえば、「1 2 3」と半角スペースで区切って連続した数値を入力し、「コメントで」あるいは「入力内容で」ボタンで現在値を書き換えると、指定した要素の形式で、数値1、数値2、数値3と並べて一度に書き込みます。この際、入力した配列の2番目以降は、要素の数を超えているかチェックせずに書き込みます。この仕様は、次の項目以降も含めてシーケンスで一度に書き換えたいケースを想定したものです。 ■項目の自動書き換え 「チェック項目をコメントで自動書き換え」チェックボックスを有効にすると、リスト上でチェックされている項目だけを取得して、そのコメントで指定された内容を使って現在値を書き換えます。この書き換えは右側コンボボックスで指定した秒数毎に行います。ただし、自動書き換え中は、誤操作を回避する等の理由により、アドレス指定の項目はチェックの有無に関わらず処理されます。そのため、複数のアドレス指定項目をチェックの有無で使い分けることはできません。また、自動書き換え時には、指定された更新周期ごとに現在値の取得と表示も行います。 自動書き換え用の項目が多数かつ更新周期が短い場合に、書き換え処理が追いつかなくなりエラーが発生する可能性があります。また、自動書き換えのオンとオフや、自動書き換え中での更新周期の変更を、高頻度で繰り返した場合、内部的な排他処理が適切に行われずエラーが発生する可能性があります。これらの場合は即座に自動書き換え処理を中断します。 自動書き換え中は、意図しないプロセスメモリ書き込み処理が生じないよう、項目の挿入や移動など一部のボタンを無効化します。この仕様は、特に多重ポインタの展開時を想定して実装しています。 自動書き換えを行う際には、事前に各項目の内容が適切か確認されることをお勧めします。特に、構造体先頭アドレスの指定が正しいかの確認に加え、ポインタや多重ポインタの指定時はポインタ格納値が適切なアドレスかも確認してください。 自動書き換え中に当ダイアログを閉じた場合は、即座に自動書き換え処理を中断するため、中断によりプロセスメモリ書き換えが意図しない状況にならないよう注意してください。 ■項目の削除 「(下選択項目を)削除」ボタンで選択された項目を削除します。 「下全項目を削除」ボタンは、そのまま押し下げるとリスト上の全項目を削除しますが、Shiftキーを押しながらボタン押し下げで選択項目より上の項目を削除し、Ctrlキーを押しながらボタン押し下げで選択項目より下の項目を削除します。選択項目より上の項目を削除すると、残された項目のアドレスが、削除した項目の占有サイズ分移動することに注意してください。 ■その他の操作(画面上部) 「縮小表示」ボタンは、画面の縮小表示と通常表示を切り替えます。「最前面」チェックボックスは、画面の最前面表示の切り替えを行います。 ■当ソフトウェアの他機能との連携について 構造体のアドレスをEXEモジュール相対アドレスで指定するケースでは、同梱のPEダンパー兼PEエディタ 「UMPE」(32ビット版PEファイル用UMPE.exeと64ビット版PEファイル用UMPE64.exe)を使って、EXEファイルのASLR設定を無効にすることで、EXEモジュールの先頭アドレスを固定アドレス化することも可能です。この操作の詳細は「ASLRの無効化」を参照してください。 当機能での自動書き換えと類似の機能として、「固定化書き換え」機能(メニュー「編集」下)や、「改造コード実行」機能(メニュー「編集」下)の自動更新および、ダンプ表示画面で選択範囲バイナリデータをコピー後に自動貼り付けによる自動書き換えを行う機能があります。必要に応じて当機能と使い分けてください。 構造体編集機能で任意の項目を左クリックすると、ダンプ表示画面での選択アドレスを変更します。さらに、ダンプ表示画面で範囲選択後にコピーで、選択されたバイナリデータを、C/C++言語での配列指定形式で記述した文字列としてコピーすることが可能です。この場合、あらかじめメニューの「編集」→「オプション」の「ダンプ表示ウィンドウ設定」タブで、コピーする形式をC/C++言語の配列形式に指定しておきます。 構造体先頭アドレス以降のダンプ表示に加えて、ポインタの展開先アドレスなど別のアドレス以降もダンプ表示画面で表示したい場合は、あらかじめメイン画面でメニュー「ウィンドウ」→「新しいウィンドウを開く」、さらに「並べて表示」でダンプ表示画面を複数表示しておきます。これで、リストで選択された項目のアドレス以降は1番目のダンプ表示画面で表示されることに加えて、別のアドレス以降をアクティブにしたダンプ表示画面で表示可能です。この、別のアドレス以降のダンプ表示は、項目を右クリックでアドレス文字列をクリップボードにコピー後、メイン画面のメニュー「移動」→「同上クリップボードからアドレスを取得」で行います。 ▲複数アドレスのダンプ表示例 |