Оригинальный DVD-ROM: eXeL@B DVD !
eXeL@B ВИДЕОКУРС !

ВИДЕОКУРС ВЗЛОМ
выпущен 12 ноября!


УЗНАТЬ БОЛЬШЕ >>
Домой | Статьи | RAR-cтатьи | FAQ | Форум | Скачать | Видеокурс
Новичку | Ссылки | Программирование | Интервью | Архив | Связь

NET Password revealer - Подбирать код не обязательно...

Обсудить статью на форуме

Массу крэкерских инструментов, видеоуроков и статей вы сможете найти на видеокурсе от нашего сайта. Подробнее здесь.

        Согласитесь, что вы иногда попадали в ситуацию, когда необходимо узнать, сколько же на интернет карте осталось времени, а карту выбросили или потеряли. А так как у вас ещё и Windows не 9x, то и пароль за звёздочками не открыть. Вот тут то и придёт на помощь эта прога, название которой NET Password Revealer. Если конкретнее, то версия 1.1 build 1.1.0.1. Но вот что странно, она, например, у меня показала пароль <evaluation copy>, а я точно помню, что он был другой. Что же надо, чтобы она правильные пароли показывала? А надо вот что:

          SoftIce + IceExt - под XP желательно версии 4.27 и IceExt 0.40;
          IDA Pro;
          PE Tools v1.4, версия 1.5 ещё альфа, много глюков;
          ImpRec;
          WinHex, или что больше нравится;

        Сперва, конечно, надо узнать, чем всё это запаковано. PE Sniffer показывает нам ASProtect 1.2 - халява полная. Не понимаю, какой смысл в таком протекторе, уж лучше бы UPX'ом запаковали, размер бы меньше был. Начинаем с места создания импорта, ловить легче всего по GetProcAddress например на UpdateWindow - bpx GetProcAddress if (@(@(esp+8))==61647055). После выхода из этой функции мы должны оказаться между двумя вызовами GetModuleHandleA. Если это так, значит это создание импорта. Здесь же можно определить IAT по строкам:

mov edx, [edi]
mov [edx], eax

        Смотрим адреса повыше чем текущий edx и видим, что начало IAT - 447000, т.е. для ImpRec IAT RVA - 47000. Затем начинаем трассировать F10, предварительно выйдя из цикла создания импорта. Если ошиблись, то быстро это место можно найти так: после срабатывания бряка на GetProcAddress выходим оттуда и можно жать несколько раз F12, пока не будет видно инструкцию popad. Ставим на неё бряк и всё, можно удалить всё, что понаставили bc * и трассировать дальше. Из ntdll можно выйти по bpm fs:0, после первого же попадания в эту библиотеку мы видим переход по адресу ebp-14, это где-то на A3FC63. Этот адрес надо запомнить(чтобы в случае ошибки быстро сюда попасть). После него продолжается код распаковщика, его можно только по F8 трассировать, а то там бывают call'ы без возврата и после F10 на таком call'е прога благополучно запускается, чего нам бы сейчас не хотелось. В коде будет даже SEH конструкция, ктороая обходится также по bpm fs:0. После неё немного потрассировав код видим замечательные инструкции:

popad
jmp eax

        Причём eax здесь равен 414E9D - чистой воды OEP, причём все байты вначале на месте. Зацикливаем прогу, например через !suspend, и снимаем дамп. Теперь можно даже и !resume ввести, ну если конечно !suspend вводили. Выставляем правильную точку входа дампу и берёмся за импорт. Размер определяется легко - адрес последней правильной функции + 4 - IAT RVA. Здесь он получился 564. После trace level 1 осталось до невозможности много неопределённых функций - одна(!!!). Её адрес - A3C424, в айсе хорошо просматривается вызов GetProcAddress, вот её в таблицу и впишем. Всё, импорт готов. Можно восстанавливать, но уж очень сильно хочется секции аспра выкинуть. Здесь, как и в ISO Commander'е придётся сохранять ресурсы в файл, потом удалять секции, потом Rebuild PE, потом ...(В общем найдите статью про ISO Commander, там это подробно описано). Ну сделали? Если сделали, то можно и импорт восстановить. В опциях лучше снять флажки import by ordinal и create new iat. Теперь получаем полностью работоспособный дамп, настала очередь дизассемблирования(лучше отдельную копию для этого сделайте). А пока IDA работает, найдём процедуру проверки кода, например по bpx GetWindowTextA, всё же на на дельфях написано, должны нормальные функции вызываться. 4375A9, 4127E0 - вот здесь уже есть что-то похожее на процедуру проверки. Дальше видно, что если длина(а что ещё может с 16 сравниваться?) не та, то вызывается метод CDialog:OnOk, а если та, то проверка продолжается. Что же дальше делать? В таких случаях лучше действовать с конца, поэтому листаем вниз, и видим ссылку на строку "Registration complete successfully !" по адресу 412CBF. Чуть выше видим сравнение строк. Только вот чего-то не брякается по этому адресу, видимо код не удовлетворяет ещё каким-то условиям(я набирал сначала 1234567890123456). Придётся смотреть. Например здесь:

seg000:0041285E mov dl, [esi+ebp] ; ebp - начало строки с кодом, esi - номер символа
seg000:00412861 xor eax, eax
seg000:00412861 xor eax, eax seg000:00412863 mov bl, dl ; символ в bl
seg000:00412865 mov cl, al
seg000:00412867 sar bl, cl ; делим код символа на (2^al)
seg000:00412869 and bl, 1
seg000:0041286C cmp bl, 1
seg000:0041286F jnz short loc_0_412875 ; если первый бит символа установлен, то переход
seg000:00412871 inc byte ptr [esp+0FCh+var_E0] ; в противном случае инкрементируется переменная
; в переменной собирается сумма неустановленных битов по всем
; символам кода
seg000:00412875 loc_0_412875: ; CODE XREF: sub_0_412790+DF
seg000:00412875 inc eax
seg000:00412876 cmp eax, 8
seg000:00412879 jl short loc_0_412863 ; переход, если al меньше 8
seg000:0041287B inc esi
seg000:0041287C cmp esi, 10h
seg000:0041287F jl short loc_0_41285E ; переход, пока не будет обработан последний символ кода

        В этом куске кода образовалась сумма нулевых битов в коде в переменной var_E0. Смотрим ещё ниже.

seg000:00412881 xor eax, eax ; eax=0
seg000:00412883 mov [esp+0FCh+var_C8], eax
seg000:00412887 mov [esp+0FCh+var_C4], eax
seg000:0041288B mov [esp+0FCh+var_C0], eax
seg000:0041288F mov [esp+0FCh+var_BC], eax ; обнуление таблицы X1
seg000:00412893 loc_0_412893: ; CODE XREF: sub_0_412790+159
seg000:00412893 cmp eax, 0Fh
seg000:00412896 ja short loc_0_4128E5 ; переход, если eax больше 15
seg000:00412898 xor edx, edx
seg000:0041289A mov dl, ds:byte_0_412FC0[eax] ; чтение символа под номером eax из массива
seg000:004128A0 jmp ds:off_0_412FAC[edx*4] ; переход по таблице указателей в зависимости от прочитанного символа
seg000:004128A7 loc_0_4128A7: ; DATA XREF: seg000:00412FAC
seg000:004128A7 test byte ptr [ebp+0], 2 ; Индекс в таблице указателей 0
seg000:004128AB jz short loc_0_4128E5 ; переход, если в первом символе кода не установлен второй бит
seg000:004128AD mov [esp+0FCh+var_C8], 80h ; в противном случае X1[4]=80h
seg000:004128B5 jmp short loc_0_4128E5
seg000:004128B7 ; ---------------------------------------------------------------------------
seg000:004128B7 loc_0_4128B7: ; CODE XREF: sub_0_412790+110
seg000:004128B7 ; DATA XREF: seg000:00412FB0
seg000:004128B7 test byte ptr [ebp+5], 4 ; индекс в таблице указателей - 1
seg000:004128BB jz short loc_0_4128E5 ; переход, если в шестом символе кода не будет установлен третий бит
seg000:004128BD mov [esp+0FCh+var_C4], 100h ; в противном случае X1[3]=100h
seg000:004128C5 jmp short loc_0_4128E5
seg000:004128C7 ; ---------------------------------------------------------------------------
seg000:004128C7 loc_0_4128C7: ; CODE XREF: sub_0_412790+110
seg000:004128C7 ; DATA XREF: seg000:00412FB4
seg000:004128C7 test byte ptr [ebp+0Ah], 8 ; индекс в таблице указателей - 2
seg000:004128CB jz short loc_0_4128E5 ; переход, если не установлен 4 бит в 11 символе кода
seg000:004128CD mov [esp+0FCh+var_C0], 200h ; X1[2]=200h
seg000:004128D5 jmp short loc_0_4128E5
seg000:004128D7 ; ---------------------------------------------------------------------------
seg000:004128D7 loc_0_4128D7: ; CODE XREF: sub_0_412790+110
seg000:004128D7 ; DATA XREF: seg000:00412FB8o
seg000:004128D7 test byte ptr [ebp+0Fh], 10h ; индекс в таблице указателей 3
seg000:004128DB jz short loc_0_4128E5 ; переход, если не установлен 5 бит в последнем символе кода
seg000:004128DD mov [esp+0FCh+var_BC], 400h ; X1[1]=400h
seg000:004128E5 loc_0_4128E5: ; CODE XREF: sub_0_412790+106
seg000:004128E5 ; sub_0_412790+110 ...
seg000:004128E5 inc eax
seg000:004128E6 cmp eax, 10h
seg000:004128E9 jl short loc_0_412893 ; переход, пока вся таблица указателей не будет пройдена
seg000:004128EB fld ds:dbl_0_4479A0 ; помещение в стек числа 2(double)
seg000:004128F1 fld qword ptr ds:dword_0_447998 ; помещение в стек числа 10(double)
seg000:004128F7 call __CIpow ; возведение 2 в степень 10, в стеке 1024(double)
seg000:004128FC call __ftol ; преобразование double в DWORD, в eax - 1024
seg000:00412901 mov cl, [ebp+0] ; в cl - первый символ кода
seg000:00412904 mov bx, ax ; bx=1024
seg000:00412907 mov al, [ebp+0Ah] ; в al - 11 символ кода
seg000:0041290A and ecx, 2 ; оставляем в ecx только второй бит
seg000:0041290D imul ecx, [esp+0FCh+var_C8] ; умножаем ecx на X1[4]
seg000:0041290D ; может быть 0(если второй бит 1 символа - 0)
seg000:0041290D ; или 100h(если это бит установлен)
seg000:00412912 and eax, 8 ; в eax остаётся только 4 бит
seg000:00412915 mov dl, [ebp+5] ; в dl - шестой символ
seg000:00412918 imul eax, [esp+0FCh+var_C0] ; умножаем eax на X1[2] - зависит от 5 бита 11 символа кода
seg000:00412918 ; может быть 0(если не установлен 5 бит 11 символа)
seg000:00412918 ; или 1000h(если он установлен)
seg000:0041291D mov esi, [esp+0FCh+var_C4] ; в esi - X1[3] - зависит от 3 бита 6 символа кода
seg000:00412921 and edx, 4 ; оставляем в edx 3 бит
seg000:00412924 add eax, ecx ; варианты - 0, 100h, 1000h, 1100h
seg000:00412926 mov cl, [ebp+0Fh] ; в cl - последний символ кода
seg000:00412929 imul edx, esi ; обработка 6 символа, варианты - 0 или 400h
seg000:0041292C and ecx, 10h ; в ecx оставляем 5 бит
seg000:0041292F add eax, edx ; варианты: 0, 400h, 100h, 500h, 1000h, 1400h, 1100h, 1500h
seg000:00412931 imul ecx, [esp+0FCh+var_BC] ; варианты - 0, 4000h
seg000:00412936 mov edx, ebx ; в edx -1024 (400h)
seg000:00412938 add eax, ecx ; варианты: 0, 100h, 400h, 500h, 1000h, 1100h, 1400h, 1500h, 4000h,
seg000:00412938 ; 4100h, 4400h, 4500h, 5000h, 5100h, 5400h, 5500h
seg000:0041293A and edx, 0FFFFh ; не меняет значение edx - всё равно 1024 или 400h
seg000:00412940 add edx, esi ; в edx - 400h или 500h
seg000:00412942 cmp eax, edx ; результаты - 100(1 символ), 400(6 символ),
seg000:00412942 ; 1000(11 символ), 4000(последний символ)
seg000:00412944 jz short loc_0_412952 ; 1 символ, 2 бит и 6 символ, 3 бит должны быть установлены
seg000:00412946 mov ecx, edi
seg000:00412948 call ?OnOK@CDialog@@MAEXXZ ; CDialog::OnOK(void)
seg000:0041294D jmp loc_0_412F6C
seg000:00412952 ; ---------------------------------------------------------------------------
seg000:00412952 loc_0_412952: ; CODE XREF: sub_0_412790+1B4j
seg000:00412952 mov eax, [esp+0FCh+var_E0] ; получаем сумму неустановленых битов кода (0 - 128)
seg000:00412956 and eax, 0FFh ; (зачем?)
seg000:0041295B and eax, 80000001h ; если эта сумма чётная, в eax - 0, если нечётная - 1
seg000:00412960 jns short loc_0_412967 ; переход выполняется
seg000:00412962 dec eax
seg000:00412963 or eax, 0FFFFFFFEh
seg000:00412966 inc eax
seg000:00412967 loc_0_412967: ; CODE XREF: sub_0_412790+1D0
seg000:00412967 jz short loc_0_412975 ; число неустановленных битов в коде должно быть чётно
seg000:00412969 mov ecx, edi
seg000:0041296B call ?OnOK@CDialog@@MAEXXZ ; CDialog::OnOK(void)
seg000:00412970 jmp loc_0_412F6C

На основе всего этого я подобрал код 2234577890A2345A - нужные биты в 1 и 6 символах установлены, а в 11 и последнем символе сброшены. Сумма чётных битов естесственно чётная. Теперь можно ставить бряк на 412C8E, он будет работать. Видно что сравнивается какая-то строка с большим списком строк. Теперь, если подумать, то обязательно понимаешь, что та самая строка есть преобразованная из введённого кода. В общем я защиту эту хорошо поизучал, здесь бы помог бы только сложный алгоритм подбора, т.е. что-то типа брутфорса. Здесь авторы постарались. Но как можно не додуматься, что если любую строку из этой таблицы заменить например на a594f67e8662037ebf85efccd390d178, то прога будет зарегистрирована? Видимо не пришло это в голову разработчикам... Ну чтож, вычисляем Raw offset к примеру 454FC1, получится 531C1. В WinHex'е вводим по этому адресу нужную строку, затем запускаем прогу, вводим наш старый знакомый код, и видим наконец-то свои пароли!!!

        Теперь к разработчикам. Если вы ещё не слышали, то, как известно, стойкость защиты определяется самым слабым её звеном. Если пытаться подбирать пароль, то защита действительно очень хорошая, но оставлять в открытую строки для сравнения пароля нельзя. Иначе их можно быдет подменить.

автор: dragon, который естесственно не несёт ответственности за противозаконное использование данных материалов.
мылить сюда: dtdcs@mail.ru

24 июля 2003 г.

Обсуждение статьи: NET Password revealer - Подбирать код не обязательно... >>>


Материалы находятся на сайте https://exelab.ru



Оригинальный DVD-ROM: eXeL@B DVD !


Вы находитесь на EXELAB.rU
Проект ReactOS