20 декабря 2012 г.

SHA-1 BrutForcer

Продолжим тему про брутфорсеры. Написал на асемблере программу для взлома SHA1 хешей. Алгоритм вычисляется на проце, а не на видео карте, так как не разбирался с работой CUDA и т.п. движков на асме. По этому алгоритм достаточно медленный по сравнению с вычислениями на видео картах, но зато работает на любом компе.

Как обычно, программа исключительно для ознакомления и использование на свой страх и риск, к стати  по этому алгоритм намеренно замедлен, но ускорить его не проблема, выкинув некоторое количество кода. Естественно алгоритм и код можно улучшить, так что на истину в последней инстанции не претендую.

В принципе в программе ничего сложного нет, алгоритм SHA-1 я расписывал раньше. Это тупо обертка на алгоритм со свистелочками и перделочками.
Единственное, что в нем наверно интересно, это алгоритм перебора, который я и опишу:
Состоит из двух процессов, первый это верхний уровень рекурскии.
Второй это собственно сам алгоритм рекурсии.
Итак, процесс верхнего уровня рекурсии:

topLVL    proc uses eax ebx ecx edx esi edi countSym:DWORD, pBrutaddr:DWORD
    lea        esi, tempdict ; в esi - адрес временно словаря
    mov        edi, pBrutaddr ; в edi - адрес массива со ссылками на позиции в словаре
    xor        ecx, ecx ; нулим ecx
    mov        DWORD PTR [edi], esi ; копируем ссылку на нулевую позицию в словаре
    
@@:    
    invoke    compileString, offset string, offset pBrut  ; вычисляем строчку
    invoke    CalcKey, offset string ; вычисляем SHA-1 хэш
    invoke    CheckSHA, offset sha1H0, offset tmpH0 ; сравниваем хэши

    inc        DWORD PTR [edi] ; сдвигаем словарь на 1 позицию
    inc        ecx  ; увеличиваем ecx
    .if        ecx == countSym ; сравниваем счетчик с количеством позиций в словаре
        jmp        @f ; если достигли конца словаря - прыгаем на выход
    .endif
    
    jmp        @b ; двигаем на следующую позицию
@@:
    lea        esi, dict ; возвращаем ссылку на словарь
    
    ret
    
topLVL endp

А теперь основное тело алгоритма перебора:
Permute    proc uses ebx ecx edx esi edi countSym:DWORD, recur:DWORD, pBrutaddr:DWORD
    lea        esi, tempdict ; в esi ссылка на временный словарь
    mov        edi, pBrutaddr ; в edi адрес на массив сылок на словарь
    
    .if    recur == 0 ; если рекурсия равна нулю, выполняем этот иф
        invoke    topLVL, countSym, pBrutaddr ; выполняем процесс верхнего уровня рекурсии
        mov        eax, recur ; в eax помещаем текущую глубину рекурсии
        inc        eax ; увеличиваем на 1
        mov        ebx, pBrutaddr ; в ebx кладем текущий адрес на позицию в массиве
        add        ebx, 4h ; увеличиваем его на 4
        invoke    Permute, countSym, eax, ebx ; вызываем рекурсию с параметрами выше
        mov        DWORD PTR [edi], esi ; копируем в текущую рекурсию нулевую позицию массива
        jmp        exitTopLvl ; прыгаем на выход
    .endif
    
    
    mov        eax, esi ; в eax копируем esi
    add        eax, countSym ; прибавляем количество символов в словрае, чтобы знать где окончание перебора
    
    .if        DWORD PTR [edi-4h] == eax && DWORD PTR [edi] == 0 ; если предущая ссылка достигла окончания массива и текущая равна нулю
        mov        DWORD PTR [edi], esi ; делаем вывод, что нужно создать следующий уровень рекурсии
    .elseif
        .if DWORD PTR [edi] == eax ; если текущая ссылка стала равна указателю на окончание массива
            mov        eax, recur ; в eax помещаем текущую глубину рекурсии
            inc        eax ; увеличиваем на 1
            mov        ebx, pBrutaddr ; в ebx кладем текущий адрес на позицию в массиве
            add        ebx, 4h ; увеличиваем его на 4
            invoke    Permute, countSym, eax, ebx ; вызываем рекурсию с параметрами выше
            mov        DWORD PTR [edi], esi ; копируем в текущую рекурсию нулевую позицию массива
        .elseif ; если еще не достигли окончания массива
            inc        DWORD PTR [edi] ; увеличиваем на 1 текущий указатель на позицию массива
        .endif
        
    .endif
    
exitTopLvl:
    mov        eax, countSym ; в eax копируем количество элементов в массиве словаря
    dec        eax ; уменьшаем eax на 1
    .if    recur > eax ; если глубина рекурсии стала больше чем количество элементов в массиве словаря
        mov        recKey, -1h ; в recKey копируем -1, как флаг окончания перебора
    .endif
    
    ret
Permute endp

Ну вот в принципе и все на сегодня, как обычно код можно найти на pastebin
И искходники с программой целиком на депозитфилес.

2 комментария:

  1. bearchik, а есть вообще возможность работать с видеокартой на асме? Слышал про CUDA, OpenCL, но хочется все таки низкоуровневого...

    ОтветитьУдалить
  2. Ну на асме можно работать с чем угодно, был бы компилятор и возможность подлезть каким то образом.
    Но для начала необходимо получить даташыты и спеки того проца подо что пишешь, так как например в видяхах явно стоит не х86 процы и соответственно большинство команд от x86 не подойдут. У меня руки просто не доходят позаниматься видяшными GPU, народ весь как раз пишет для Nvidia на CUDA, а для AMD(ATI) на OpenCL, но они все используют готовые фреймворки на C++. Надо качнуть какойнить фреймворк да посмотреть, что там полезного можно нарыть.

    ОтветитьУдалить