web-dev-qa-db-ja.com

exeまたはdllの文字列を非表示にする方法は?

バイナリからハードコードされた文字列を抽出できることを発見しました。
たとえば、 Process Explorer のプロパティビューには、3文字を超えるすべての文字列が表示されます。

これは、単純にテストするために作成した単純な実行可能ファイルのコードです。

#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0501
#endif
#include <stdio.h>
#include <tchar.h>
#include <Windows.h>

int _tmain(int argc, _TCHAR* argv[])
{
    _TCHAR* hiddenString1 =_T("4537774B-CC80-4eda-B3E4-7A9EE77991F5");
    _TCHAR* hiddenString2 =_T("hidden_password_or_whatever");
    for (int i= 0; i<argc; i++) {
        if (0 == _tcscmp(argv[i],hiddenString1)) {
            _tprintf (_T("The guid argument is correct.\n")); }
        else if (0 == _tcscmp(argv[i],hiddenString2)) {
            _tprintf (_T("Do something here.\n")); }
    }

    _tprintf (_T("This is a visible string.\n"));
    //Keep Running
    Sleep(60000);
    return 0;
}

文字列は、対応する実行可能ファイルから明確に抽出できます。
alt text

文字列を見つけるのは少し簡単すぎると思います。

私の質問は次のとおりです。

  1. simply非表示hiddenString1またはhiddenString2の方法実行可能ファイル?
  2. あいまいな隠し入力を使用するよりも、「チートコード」を使用するより安全な方法はありますか?
30
Winz

防御プログラミングのより広い世界へようこそ。

いくつかのオプションがありますが、それらはすべて何らかの形の難読化に依存していると思います。これは完璧ではありませんが、少なくとも何かです。

  1. ストレート文字列値の代わりに、テキストを他のバイナリ形式(hex?)で格納できます。

  2. アプリに保存されている文字列を暗号化し、実行時に復号化できます。

  3. それらをコード内のさまざまなポイントに分割し、後で再構成することができます。

またはそれらのいくつかの組み合わせ。

一部の攻撃は、実際のバイナリを確認するよりもさらに進んでいることに注意してください。プログラムの実行中に、プログラムのメモリアドレス空間を調査する場合があります。 MSは 。Net 2.0のSecureString と呼ばれるものを思いついた。目的は、アプリの実行中に文字列を暗号化しておくことです。

4番目のアイデアは、文字列をアプリ自体に保存するのではなく、制御するサーバーに送信される検証コードに依存することです。サーバー上で、それが正当な「チートコード」であるかどうかを確認できます。

29
NotMe

実行可能ファイル内のデータを不明瞭にする方法はたくさんあります。ここにある他の人は良い解決策を投稿しています-いくつかは他よりも強力です。そのリストには追加しません。

ただ注意してください:それはすべて猫とマウスのゲームです:それは不可能から保証誰もあなたの「秘密」を見つけられないということです。

暗号化やその他のトリックをどれだけ使用しても、どんなに努力やお金をかけても。それを隠すのにいくつの「NASA​​/MIT/CIA/NSA」タイプが関係していても。

それはすべて単純な物理学に帰着します:
anyユーザーが実行可能ファイルからシークレットを引き出して「再表示」することが不可能な場合、コンピューターはそれを再表示することもでき、プログラムはそれを使用できなくなります。十分なインセンティブを持つ適度に熟練した開発者なら誰でも、秘密を明らかにする方法を見つけるでしょう。

実行可能ファイルをユーザーに渡した瞬間、ユーザーは秘密を見つけるために必要なすべてを持っています。

あなたが望むことができる最善のことは、秘密を明らかにすることを非常に難しくして、秘密を知ることから得られる利益が面倒な価値がなくなるようにすることです。

したがって、データが公開されるのが単に「良くない」場合、または公開された結果が単に「不便」である場合は、データを隠そうとしても問題ありません。ただし、プログラムに「マスタークライアントデータベースのパスワード」、秘密鍵、またはその他の重要な秘密を隠すことさえ考えないでください。あなたはできません。

プログラムが何らかの形で必要とするが、決して公開情報にならない(秘密鍵など)本当に非常に重要な秘密情報がある場合は、プログラムを制御下のリモートサーバーと通信させ、適切な認証および承認制御を適用する必要があります( つまり、承認された人またはコンピューターのみがサーバーにリクエストを送信できることを確認し)、そのサーバーに秘密を保持させて使用させます。

18
Euro Micelli

最も簡単な方法は、xorやrot-13のような些細なもので暗号化し、使用時にその場で復号化することです。それはそれらのカジュアルな表示を排除しますが、それは逆転の経験が豊富な人を止めることはありません。

9
Rob K

これらの方法に加えて、Chrisは、ハッシュアルゴリズムを使用することもできると述べています。正しいIDが指定されているかどうかを確認するだけの場合は、実際にはID全体をプログラムに保存する必要はありません。

  • 比較する文字列/パスワード/ IDのハッシュ(MD5、SHAなど)を作成し、「salt」値を追加します。これをプログラムに保存します
  • プログラムの実行時に、入力文字列/パスワード/ IDに対して同じアルゴリズムを実行し、2つのハッシュを比較して、それらが一致するかどうかを確認します。

このように、実際のテキストがプログラムに保存されることはなく、ハッシュアルゴリズムは一方向のみであるため、プログラムをリバースエンジニアリングして元のテキストを見つけることはできません。

6
Andre Miller

私も隠したいhttpリクエストのURLがあります。

アプリがリクエストを行っている場合、これを隠す意味はありません。フィドラー、httpアナライザー、またはその他の無料ですぐに利用できる数十の方法の1つなどのアプリを実行すると、アプリが作成しているすべてのトラフィックが表示されます。

5
CaffGeek

他の人に見られたくない特定の文字列がある場合は、それを暗号化し、実行時に復号化します。

GUIDを他の人に見られたくない場合は、文字列から作成するのではなく、バイトから作成します。

const GUID SecretGuid = 
      { 0x4537774B, 0xCC80, 0x4eda, { 0x7A, 0x9E, 0xE7, 0x79, 0x91, 0xF5 } };
2
Ian Boyd

すべてのシークレットコードはGUIDですか、それとも単なる例ですか?

おそらくあなたの秘密をバイナリGUIDとして保存します:

const GUID SecretGuid =
    { 0x4537774B, 0xCC80, 0x4eda, { 0x7A, 0x9E, 0xE7, 0x79, 0x91, 0xF5 } };

次に、提供されたGUIDを文字列からバイナリ形式に変換し、2つのバイナリGUIDを比較します。

2
Kevin Newman

最善の方法は、パスワードまたは非表示にするその他の文字列をchar配列としてコーディングすることです。例えば:

std::string s1 = "Hello";   // This will show up in exe in hex editor
char* s2 = "World";   // this will show up in exe in hex editor
char s3[] = {'G', 'O', 'D'}; // this will not show up in exe in hex editor.
1

これが私がこの目的のために使用する方法です。まず、 Strings ツールを Sysinternals で使用して、EXEまたはDLLで文字列を表示します。次に、 次の小さなツール記事 を参照)を使用して、これらの文字列を、数式として格納されている文字のスクランブル配列に置き換えます。例:文字列の代わりに: "これはテストです"次のコードを配置します:(これは このツール によって自動的に生成されます)

WCHAR T1[28];
 T1[22] = 69;
 T1[15] = 121 - 17;
 T1[9] = L':' + -26;
 T1[12] = L't' - 1;
 T1[6] = 116 - 1;
 T1[17] = 117 - 12;
 T1[3] = 116 - 1;
 T1[14] = L'' - 3;
 T1[13] = L'w' - 3;
 T1[23] = 69;
 T1[26] = L'Y' + 3;
 T1[19] = 111 + 0;
 T1[21] = L'k' - 34;
 T1[27] = L'\\' - 8;
 T1[20] = L'B' + 32;
 T1[4] = 42 + -10;
 T1[25] = L'm' - 17;
 T1[16] = L'H' + 18;
 T1[18] = L'A' + 56;
 T1[24] = 68;
 T1[1] = 105 - 1;
 T1[11] = L'k' - 6;
 T1[10] = 66 + 50;
 T1[2] = 105;
 T1[0] = 117 - 1;
 T1[5] = L'k' - 2;
 T1[8] = 89 + 8;
 T1[7] = 32;

この問題には多くの解決策があり、それらのどれも(私のものを含めて)完璧ではありませんが、機密性の高い文字列をスクランブル、偽装、および非表示にする方法があります。もちろん、実行時に暗号化して復号化することもできますが(この記事を参照)、実行可能ファイルのビットとバイトの中でこれらの文字列を非表示にすることがより重要であり、機能します。ツールを実行した後、実行可能ファイルに「これはテストです」が見つかりません。

1