具有内联汇编和访问c变量的多线程

时间:2011-09-18 14:11:23

标签: c multithreading assembly x86 brute-force

我正在使用内联汇编来构造一组密码,我将使用这些密码对给定的哈希进行暴力破解。我使用此website作为构造密码的参考。

这在单线程环境中完美运行。它产生无限量的递增密码。

由于我只掌握了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
......

Edit2

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;
} 

2 个答案:

答案 0 :(得分:2)

由于您已经在使用pthread,另一个选择是将由多个线程修改的变量转换为每线程变量(特定于线程的数据)。见pthread_getspecific OpenGroup manpage。这种方式的工作方式如下:

在主线程中(在创建其他线程之前),执行:

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;

或创建/使用多个键,每个变量一个;在这种情况下,您不会获得str容器/双重间接/附加malloc

使用gcc inline asm的英特尔汇编语法是,嗯,不是很好;特别是,指定输入/输出操作数并不容易。我认为要使用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"
    ...

这样,它就变得无锁,代价是使用更多内存(每个线程一个明文/ charsetTable),以及额外函数调用(pthread_getspecific())的费用。另外,如果您执行上述操作,请确保free()通过pthread_atexit() {{1}}每个帖子的特定数据,否则您将泄露。

如果您的函数执行速度很快,那么锁定是一个更简单的解决方案,因为您不需要线程特定数据的所有设置/清理开销;如果函数是慢速或非常频繁地调用,则锁定将成为瓶颈 - 在这种情况下,TSD的内存/访问开销是合理的。您的里程可能会有所不同。

答案 1 :(得分:1)

使用内联汇编块之外的互斥锁保护此功能。