3

インライン アセンブリを使用して一連のパスワードを作成しています。これを使用して、特定のハッシュに対してブルート フォースを実行します。パスワードの作成にあたっては、 こちらのサイトを参考にさせていただきました。

これは、シングルスレッド環境で問題なく動作しています。無限に増加するパスワードを生成します。

私はasmの基本的な知識しか持っていないので、その考え方は理解できます。gcc は ATT を使用するため、次のようにコンパイルします。-masm=intel

プログラムをマルチスレッド化しようとしているときに、このアプローチがうまくいかない可能性があることに気付きました。
次のコードは 2 つのグローバル C 変数を使用してますが、これが問題である可能性があります。

__asm__("pushad\n\t"
    "mov edi, offset plaintext\n\t" <---- global variable
    "mov ebx, offset charsetTable\n\t" <---- again
    "L1: movzx eax, byte ptr [edi]\n\t"
    "    movzx eax, byte ptr [charsetTable+eax]\n\t"
    "    cmp al, 0\n\t"
    "    je L2\n\t"
    "    mov [edi],al\n\t"
    "    jmp L3\n\t"
    "L2: xlat\n\t"
    "    mov [edi],al\n\t"
    "    inc edi\n\t"
    "    jmp L1\n\t"
    "L3: popad\n\t");

プレーンテキスト変数で非決定論的な結果が生成されます。

すべてのスレッドが独自のプレーンテキスト変数にアクセスするという回避策を作成するにはどうすればよいですか? (これが問題であれば...)。

拡張アセンブリを使用するためにこのコードを変更しようとしましたが、毎回失敗しました。おそらく、すべてのチュートリアルで ATT 構文が使用されているためです。

私は今数時間立ち往生しているので、本当に助けていただければ幸いです:(

編集: 2 つのスレッドでプログラムを実行し、asm 命令の直後にプレーンテキストの内容を出力すると、次のようになり
b
b
d
d
f
f
ます。

編集2

pthread_create(&thread[i], NULL, crack, (void *) &args[i]))
[...]
void *crack(void *arg) {
struct threadArgs *param = arg;
struct crypt_data crypt; // storage for reentrant version of crypt(3)

char *tmpHash = NULL;

size_t len = strlen(param->methodAndSalt);
size_t cipherlen = strlen(param->cipher);

crypt.initialized = 0;

for(int i = 0; i <= LIMIT; i++) {
    // intel syntax      
    __asm__ ("pushad\n\t"
    //mov edi, offset %0\n\t"
    "mov edi, offset plaintext\n\t"
    "mov ebx, offset charsetTable\n\t"
    "L1: movzx eax, byte ptr [edi]\n\t"
    "    movzx eax, byte ptr [charsetTable+eax]\n\t"
    "    cmp al, 0\n\t"
    "    je L2\n\t"
    "    mov [edi],al\n\t"
    "    jmp L3\n\t"
    "L2: xlat\n\t"
    "    mov [edi],al\n\t"
    "    inc edi\n\t"
    "    jmp L1\n\t"
    "L3: popad\n\t");

    tmpHash = crypt_r(plaintext, param->methodAndSalt, &crypt);
    if(0 == memcmp(tmpHash+len, param->cipher, cipherlen)) {
        printf("success: %s\n", plaintext);
        break;
    }
}
return 0;
} 
4

2 に答える 2

2

すでに pthreads を使用しているので、別のオプションは、複数のスレッドによって変更される変数をスレッドごとの変数 (スレッド固有のデータ) にすることです。pthread_getspecificOpenGroup のマンページを参照してください。これが機能する方法は次のようになります。

メイン スレッドで (他のスレッドを作成する前に)、次の操作を行います。

static pthread_key_y tsd_key;
(void)pthread_key_create(&tsd_key);    /* unlikely to fail; handle if you want */

plaintext次に、 /charsetTable変数 (またはその他の変数)を使用する各スレッド内で、次のようにします。

struct { char *plainText, char *charsetTable } *str =
    pthread_getspecific(tsd_key);

if (str == NULL) {
    str = malloc(2 * sizeof(char *));
    str.plainText = malloc(size_of_plaintext);
    str.charsetTable = malloc(size_of_charsetTable);
    initialize(str.plainText);          /* put the data for this thread in */
    initialize(str.charsetTable);       /* ditto */
    pthread_setspecific(tsd_key, str);
}
char *plaintext = str.plainText;
char *charsetTable = str.charsetTable;

または、そのような変数ごとに1つずつ、複数のキーを作成/使用します。その場合、strcontainer / double indirection / additionalは得られませんmalloc

gcc inline asm を使用した Intel アセンブリ構文は、うーん、あまり良くありません。特に、入出力オペランドの指定は簡単ではありません。メカニズムを使用するにはpthread_getspecific、コードを次のように変更すると思います。

__asm__("pushad\n\t"
    "push tsd_key\n\t"               <---- threadspecific data key (arg to call)
    "call pthread_getspecific\n\t"   <---- gets "str" as per above
    "add esp, 4\n\t"                 <---- get rid of the func argument
    "mov edi, [eax]\n\t"             <---- first ptr == "plainText"
    "mov ebx, [eax + 4]\n\t"         <---- 2nd ptr == "charsetTable"
    ...

そうすれば、より多くのメモリ (スレッドごとに 1 つの平文 / charsetTable) を使用し、追加の関数呼び出し (へ) を犠牲にして、ロックフリーになりますpthread_getspecific()。また、上記を行う場合は、free()各スレッドの特定のデータを 経由pthread_atexit()で取得するようにしてください。そうしないと、リークが発生します。

関数の実行が高速な場合、ロックはスレッド固有のデータのすべてのセットアップ/クリーンアップ オーバーヘッドを必要としないため、はるかに単純なソリューションです。関数が遅いか非常に頻繁に呼び出される場合、ロックがボトルネックになります。その場合、TSD のメモリ/アクセス オーバーヘッドは正当化されます。あなたのマイレージは異なる場合があります。

于 2011-09-19T16:09:13.200 に答える
1

この関数は、インライン アセンブリ ブロックの外側でミューテックスを使用して保護します。

于 2011-09-18T14:23:03.660 に答える