VMProtect は、新世代のソフトウェア保護ユーティリティです。VMProtect は、Delphi、Borland C Builder、Visual C/C++、Visual Basic (ネイティブ)、Virtual Pascal、および XCode コンパイラをサポートします。
一方、VMProtect には、Windows および Mac OS X 実行可能ファイルで動作する逆アセンブラが組み込まれており、コンパイラによって作成された MAP ファイルをリンクして、保護するコード フラグメントを迅速に選択することもできます。
アプリケーション保護タスクを簡単に自動化するために、VMProtect には組み込みのスクリプト言語が実装されています。VMProtect は、Windows ファミリ (Windows 2000 以降) および Mac OSX (バージョン 10.6 以降) の 32/64 ビット オペレーティング システムを完全にサポートしています。重要なのは、VMProtect は、ターゲット プラットフォームに関係なく、あらゆる種類の実行可能ファイルをサポートしていることです。つまり、Windows バージョンは Mac OS X バージョンを処理でき、その逆も同様です。
シリアル番号の構造
シリアル番号はブロックで構成されます。各ブロックは識別子バイトで始まり、ブロックの内容と可能な長さを示します。最後のブロックには 255 個の識別子があり、最後のブロックを除くシーケンス番号のチェックサムが含まれます。
ブロックのタイプに応じて、長さは定数または可変長になります。後者の場合、長さはチャンク識別子の後のバイトで指定されます。各ブロックの正確な形式については以下で説明します。
ブロックフォーマット
ID | 名前 | サイズ (バイト) | 説明 | 例 |
---|---|---|---|---|
0×01 | バージョン | 1 | このブロックにはバージョンのシリアル番号が含まれており、サイズは 1 バイトです。バージョンは 1 である必要があります。 | 01 01 |
0×02 | ユーザー名 | 1 + N | このブロックには、UTF-8 でエンコードされたユーザー名が含まれています。ユーザー名の前に、ユーザー名の長さを格納するための 1 バイトがあります。したがって、ユーザー名の合計の長さは 255 バイトを超えることはできません。末尾の 0 は必要ありません。 | 02 04 4A 5F 48 4E |
0×03 | Eメール | 1 + N | このブロックには、UTF-8 でエンコードされたユーザーの電子メールが含まれています。電子メールの前には、長さを示すために 1 バイトが使用されます。したがって、電子メールの合計の長さは 255 バイトを超えることはできません。末尾の 0 は必要ありません。 | 03 07 61 40 62 2E 63 6F 6D |
0×04 | ハードウェア識別子 | 1 + N | このブロックには、VMProtectGetCurrentHWID() 関数によって返されたハードウェア識別子が含まれています。この関数は、base-64 文字列を返します。この文字列のデコードされたバージョンがシリアル番号に組み込まれます。データ ブロックの長さは 4 の倍数である必要があり、データ ブロックの前に長さバイトがあります。最大データ ブロック長は 32 バイトです。 | 04 08 E1 E2 E3 E4 A1 A2 A3 A4 |
0×05 | ライセンスの有効期限 | 4 | このブロックにはシリアル番号の有効期限が含まれており、日付の形式は次のとおりです。 | 05 01 0A 07 はい |
0×06 | 最大動作時間 | 1 | このブロックには 1 バイトが含まれており、プログラムが実行できる時間を分単位で保持します。したがって、最大時間は 255 分になります。 | 06 05 |
0×07 | 製品コード | 8 | このブロックには、VMProtect によって作成された製品コード (8 バイト) が含まれており、製品パラメータとともにエクスポートされます。データは Base-64 エンコードでエクスポートされ、シリアル番号に入れる前にバイト配列にデコードする必要があります。配列のサイズは正確に 8 バイトである必要があります。存在しない場合、保護されたプログラムは正しく動作しません。 | 07 01 02 03 04 05 06 07 08 |
0×08 | ユーザーデータ | 1 + N | このブロックには、最大 255 バイトのカスタム ユーザー データが含まれます。このデータはライセンス システムによって分析されず、VMProtectGetSerialNumberData() 関数が呼び出されたときに返されます。データ ブロックの前に、ユーザー データのサイズを保持するバイトがあります。 | 08 05 01 02 03 04 05 |
0×09 | 最大ビルド日 | 4 | このブロックには、アプリケーションの最大ビルド日が含まれます。そのフォーマットを以下に説明します。 | 09 01 0A 07 はい |
0xFF | チェックサム | 4 | このブロックにはシーケンス番号のチェックサムが含まれています。このブロックは最後のブロックの前にあり、前のすべてのブロックに対してチェックサムが計算されます。チェックサムの計算メカニズムは以下のとおりです。 | FF 01 02 03 04 |
日付の保存形式
日付はシリアル番号にダブルワード (0xYYYYMMDD) として保存されます。上位ワードには年が含まれ、下位ワードには日と月が含まれます。バイトは、低位から高位へのリトルエンディアン表記に従います。レコードの最初のバイトへのポインターを指定すると、次のコードを使用して日付の読み取りまたは書き込みを行うことができます。
バイト *pDate = 0xNNNNNN; // 日付アドレス *(DWORD *)pDate = (2010 << 16) | (10 << 8) | 1; // 2010 年 10 月 1 日 DWORD dwExp = *(DWORD *)pDate;
チェックサム計算
シリアル番号のチェックサムは、SHA-1 ハッシュ アルゴリズムを使用して計算されます。結果は 5 つの 32 ビット ワードになります。最初のワードは、シリアル番号のチェックサムとリトルエンディアン番号 (低位から高位) の両方として使用されます。SHA-1 ハッシュの文字列表現はビッグ エンディアンを使用します。数値は上位バイトから下位バイトに進むため、SHA-1 ハッシュが文字列関数 (PHP など) によって生成される場合、ハッシュの最初の 4 バイトは反転される必要があります。 。
その他の情報
ライセンス システムでは、上記以外の番号のブロックは無視されます。新しいバージョンでは新しいブロックが追加される可能性があります。占有されていない識別子を使用して新しいブロックを作成することはお勧めしません! まず、これにより、新しいバージョンの認証システムではキーが機能しなくなる可能性があります。第二に、保護されたプログラムはいずれにしてもこれらのブロックの値を読み取ることができません。追加情報をキーに保存するには、代わりに userdata フィールドを渡します。
シリアル番号にはソルトがありません。ソルトは、同じ入力データにキーを提供するために設計されたランダムな情報です。このタスクは暗号化アルゴリズムに課せられます。たとえば、ある範囲のキーを組織に販売する場合、ユーザー名フィールド (「会社」LLC、10 個のキーの 1 つ) に別のインデックスを追加したり、この情報を適切な形式でユーザー データ フィールドに挿入したりできます。
上記はいくつかのキージェネレーターの共有です。ご質問がございましたら、コメント欄にメッセージを残してください~