Исследование защиты программы AXE Advanced Hex Editor
Скриншот программы AXE Advanced Hex Editor
AXE Advanced Hex Editor - продвинутый шестнадцатеричный редактор с множеством функций, поддержкой скриптового языка, разбором структур, возможностью работать с файлами неограниченного размера и еще целой кучей всяких приятных плюшек. Разработка программы уже давно прекращена, офсайт тоже не отвечает, оплатить лицензию негде (если вы вдруг решили это сделать). Значит мы можем с чистой совестью поковыряться в его бинарных потрошках.
Скачиваем дистрибутив, устанавливаем. Главный исполняемый файл ничем не защищен и не упакован, отправляем его в дизассемблер. А пока посмотрим на систему регистрации и триальности. На ввод неправильных регистрационных данных программа реагирует вот таким безграмотным сообщением:
Сообщение о неправильной регистрации
Попробуем найти эту строчку в исполняемом файле. Ничего не найдено. Ни в ASCII, ни в юникоде, никак. Ладно, план "А" не сработал, переходим к плану "Б". Посмотрим, что у нас находится в ресурсах:
Строки в ресурсах
Ну прям все как-то слишком идеально выглядит. Есть строчки о правильной регистрации, есть строчки о триальном статусе программы, есть их индексы... Нет только одного - прямых указателей на эти индексы. То есть мы не можем определить, откуда в исполняемом файле идет обращение к этим строкам. Похоже, что автор программы не по наслышке знаком с реверсной инженерией и предусмотрел защиту против новичков и базовых методов взлома. Приходится признать, что план "Б" тоже потерпел неудачу и на очереди план "В". Посмотрим на диалоговое окно "О программе" в ресурсах:
ID элемента диалогового окна
Тут логика простая. Если есть диалоговые окна и известны индексы их элементов, то в исполняемом файле должны быть видны какие-нибудь манипуляции с ними. Конкретно нас интересует установка регистрационного имени в окно "О программе". Для триальной версии это будет строка "Trial", для зарегистрированной, очевидно, должно быть имя пользователя, адрес email или что-то подобное. Индекс этого элемента диалогового окна - 1120 в десятичной или 460h в шестнадцатеричной системе счисления. Поищем в дизассемблере участок кода, где используется это значение и где неподалеку есть функции установки текста в диалоговом окне. Второе вхождение по строке "460h" наводит нас на такой код:
Code (Assembler) : Убрать нумерацию
- .text:00431794 push edi
- .text:00431795 mov byte ptr [esp+0D0h+var_4], 6
- .text:0043179D push ebp
- .text:0043179E call ?AfxGetApp@@YGPAVCWinApp@@XZ
- .text:004317A3 mov ecx, eax
- ; Вызвать функцию проверки
- .text:004317A5 call sub_42F620
- ; Если она вернула EAX=0, то переход
- .text:004317AA cmp eax, ebx
- .text:004317AC push edi ; int
- .text:004317AD jz short loc_431812
- ; Иначе действия с элементами диалогового окна
- .text:004317AF lea ecx, [esp+0CCh+lpString]
- .text:004317B3 push offset aD_1 ; "%d"
- .text:004317B8 push ecx ; int
- .text:004317B9 call sub_4B0144
- .text:004317BE mov edx, [esp+0D4h+lpString]
- .text:004317C2 add esp, 0Ch
- .text:004317C5 mov ecx, esi
- .text:004317C7 push edx ; lpString
- ; ID элемента диалогового окна "Trial Days"
- .text:004317C8 push 45Eh ; nIDDlgItem
- .text:004317CD call sub_4B7BD2
- .text:004317D2 mov ecx, eax
- .text:004317D4 call sub_4B7D49
- .text:004317D9 mov eax, [esp+0C8h+var_B0]
- .text:004317DD lea ecx, [esp+0C8h+lpString]
- .text:004317E1 push eax ; int
- .text:004317E2 push offset aS ; "%s"
- .text:004317E7 push ecx ; int
- .text:004317E8 call sub_4B0144
- .text:004317ED mov edx, [esp+0D4h+lpString]
- .text:004317F1 add esp, 0Ch
- .text:004317F4 mov ecx, esi
- .text:004317F6 push edx ; lpString
- ; ID элемента диалогового окна "Name"
- .text:004317F7 push 460h ; nIDDlgItem
- ; В этой функции вызывается GetDlgItem
- .text:004317FC call sub_4B7BD2
- .text:00431801 mov ecx, eax
- ; В этой функции вызывается SetWindowTextA
- .text:00431803 call sub_4B7D49
- .text:00431808 lea eax, [esp+0C8h+var_88]
- .text:0043180C push eax ; int
- .text:0043180D jmp loc_4318DF
- .text:00431812 ; -------------------------------------------------
- ; Триальная ветка алгоритма
- .text:00431812 loc_431812:
- .text:00431812 lea ecx, [esp+0CCh+Format]
- .text:00431816 lea edx, [esp+0CCh+lpString]
- .text:0043181A push ecx ; Format
- .text:0043181B push edx ; int
- .text:0043181C call sub_4B0144
- .text:00431821 mov eax, [esp+0D4h+lpString]
- .text:00431825 add esp, 0Ch
- .text:00431828 mov ecx, esi
- .text:0043182A push eax ; lpString
- .text:0043182B push 45Eh ; nIDDlgItem
- .text:00431830 call sub_4B7BD2
- .text:00431835 mov ecx, eax
- .text:00431837 call sub_4B7D49
- .text:0043183C mov ecx, [esp+0C8h+var_B0]
- .text:00431840 lea edx, [esp+0C8h+Format]
- .text:00431844 push ecx ; int
- .text:00431845 lea eax, [esp+0CCh+lpString]
- .text:00431849 push edx ; Format
- .text:0043184A push eax ; int
- .text:0043184B call sub_4B0144
- .text:00431850 mov ecx, [esp+0D4h+lpString]
- .text:00431854 add esp, 0Ch
- .text:00431857 push ecx ; lpString
- .text:00431858 push 460h ; nIDDlgItem
- .text:0043185D mov ecx, esi
- .text:0043185F call sub_4B7BD2
- .text:00431864 mov ecx, eax
- .text:00431866 call sub_4B7D49
Code (Assembler) : Убрать нумерацию
- .text:0042F620 mov eax, large fs:0
- .text:0042F626 push 0FFFFFFFFh
- .text:0042F628 push offset unknown_libname_309
- .text:0042F62D push eax
- .text:0042F62E mov large fs:0, esp
- .text:0042F635 push ebx
- .text:0042F636 push esi
- .text:0042F637 push edi
- .text:0042F638 mov eax, [esp+18h+arg_8]
- .text:0042F63C mov [esp+18h+var_4], 0
- .text:0042F644 mov ecx, [eax-8]
- ; Регистрационное имя не должно быть пустым
- .text:0042F647 test ecx, ecx
- .text:0042F649 jz loc_42F70E
- .text:0042F64F mov esi, [esp+18h+arg_4]
- ; Регистрационный код не должен быть пустым
- .text:0042F653 test esi, esi
- .text:0042F655 jz loc_42F70E
- ; Проверка регистрационного кода на значение "10021"
- .text:0042F65B cmp esi, 2725h
- .text:0042F661 jnz short loc_42F68D
- ; Если он равен этому значению, то вернуть EAX = 1, то есть "зарегистрировано"
- .text:0042F663 lea ecx, [esp+18h+arg_8]
- .text:0042F667 mov [esp+18h+var_4], 0FFFFFFFFh
- .text:0042F66F call sub_4B3861
- .text:0042F674 mov eax, 1
- .text:0042F679 mov ecx, [esp+18h+var_C]
- .text:0042F67D mov large fs:0, ecx
- .text:0042F684 pop edi
- .text:0042F685 pop esi
- .text:0042F686 pop ebx
- .text:0042F687 add esp, 0Ch
- .text:0042F68A retn 0Ch
Программа успешно зарегистрирована
Что-то меня тут все-таки смущает. Посмотрим лучше что там находится дальше. Эта ветка алгоритма активируется, когда введено регистрационное имя и код, который не является универсальным.
Code (Assembler) : Убрать нумерацию
- .text:0042F68D loc_42F68D:
- ; Проверить длину введенного регистрационного имени
- .text:0042F68D cmp ecx, 4
- .text:0042F690 jge short loc_42F6A4
- ; Если она меньше 4, то дописать в конец к имени строку "abcd"
- .text:0042F692 push offset aAbcd ; "abcd"
- .text:0042F697 lea ecx, [esp+1Ch+arg_8]
- .text:0042F69B call sub_4B3C3D
- .text:0042F6A0 mov eax, [esp+18h+arg_8]
- .text:0042F6A4 loc_42F6A4:
- ; Длина регистрационного имени
- .text:0042F6A4 mov ecx, [eax-8]
- ; BL = третий символ регистрационного имени
- .text:0042F6A7 mov bl, [eax+2]
- ; DL = первый символ регистрационного имени
- .text:0042F6AA mov dl, [eax]
- ; EAX = последний символ регистрационного имени
- .text:0042F6AC movsx eax, byte ptr [ecx+eax-1]
- ; EDI = третий символ регистрационного имени
- .text:0042F6B1 movsx edi, bl
- ; EDX = первый символ регистрационного имени
- .text:0042F6B4 movsx edx, dl
- .text:0042F6B7 add eax, edi
- .text:0042F6B9 add eax, edx
- .text:0042F6BB imul eax, ecx
- ; Сложить три символа и перемножить их на длину строки
- .text:0042F6BE and eax, 8FFFFFFFh
- .text:0042F6C3 jns short loc_42F6CC
- ; Для отрицательных чисел дополнительная обработка
- .text:0042F6C5 dec eax
- .text:0042F6C6 or eax, 0F0000000h
- .text:0042F6CB inc eax
- .text:0042F6CC loc_42F6CC:
- ; Введенный серийный номер больше 10000000h?
- .text:0042F6CC cmp esi, 10000000h
- .text:0042F6D2 jbe short loc_42F6D9
- ; Да, добавить к проверочному значению 10000000h
- .text:0042F6D4 add eax, 10000000h
- .text:0042F6D9 loc_42F6D9:
- ; ПоXORить проверочное значение с константой 39A13D7h
- .text:0042F6D9 xor eax, 39A13D7h
- .text:0042F6DE xor ecx, ecx
- ; Сравнить введенный серийный номер и проверочное значение
- .text:0042F6E0 cmp esi, eax
- .text:0042F6E2 mov [esp+18h+var_4], 0FFFFFFFFh
- .text:0042F6EA setz cl
- .text:0042F6ED mov esi, ecx
- .text:0042F6EF lea ecx, [esp+18h+arg_8]
- .text:0042F6F3 call sub_4B3861
- .text:0042F6F8 mov eax, esi
- .text:0042F6FA mov ecx, [esp+18h+var_C]
- .text:0042F6FE mov large fs:0, ecx
- .text:0042F705 pop edi
- .text:0042F706 pop esi
- .text:0042F707 pop ebx
- .text:0042F708 add esp, 0Ch
- .text:0042F70B retn 0Ch
Программа успешно зарегистрирована
Если посмотреть по перекрестным ссылкам и другие места, откуда вызывается функция проверки серийного номера, то можно разгадать загадку, почему не сработал план "А". После неудачной проверки вот таким мудреным образом расшифровывается и складывается по отдельным символам строка сообщения "This isnot a valid registration code". Неудивительно, что среди этой кодо-вермишели автор пропустил пробел между двумя словами.
Code (Assembler) : Убрать нумерацию
- .text:0043F5C8 call sub_42F620
- .text:0043F5CD cmp eax, ebx
- .text:0043F5CF jz loc_43F8FB
- .text:0043F5D5 mov al, byte_514B64
- .text:0043F5DA mov cl, byte_514B68
- .text:0043F5E0 mov dl, byte_514B6C
- .text:0043F5E6 xor al, 0AAh
- .text:0043F5E8 xor cl, 55h
- .text:0043F5EB mov [esp+24h], al
- .text:0043F5EF mov al, byte_514B70
- .text:0043F5F4 mov [esp+25h], cl
- .text:0043F5F8 mov cl, byte_514B74
- .text:0043F5FE xor dl, 66h
- .text:0043F601 xor al, 0CCh
- .text:0043F603 xor cl, 77h
- .text:0043F606 mov [esp+26h], dl
- .text:0043F60A mov dl, byte_514B78
- .text:0043F610 mov [esp+27h], al
- .text:0043F614 mov al, byte_514B7C
- .text:0043F619 mov [esp+28h], cl
- .text:0043F61D mov cl, byte_514B80
- .text:0043F623 xor dl, 55h
- .text:0043F626 xor al, 65h
- .text:0043F628 xor cl, 0ACh
- .text:0043F62B mov [esp+29h], dl
- .text:0043F62F mov dl, byte_514B84
- .text:0043F635 mov [esp+2Ah], al
- .text:0043F639 mov al, byte_514B88
- .text:0043F63E mov [esp+2Bh], cl
- .text:0043F642 mov cl, byte_514B90
- .text:0043F648 xor dl, 35h
- .text:0043F64B xor al, 71h
- .text:0043F64D xor cl, 0AAh
- .text:0043F650 mov [esp+2Ch], dl
- .text:0043F654 mov dl, byte_514B94
- .text:0043F65A mov [esp+2Dh], al
- .text:0043F65E mov al, byte_514B98
- .text:0043F663 mov [esp+30h], cl
- .text:0043F667 mov cl, byte_514B9C
- .text:0043F66D xor dl, 55h
- ; и так далее, там такого чудо-кода еще много
- ...
Строка сообщения о модифицированном файле
Спасибо автору за хороший шестнадцатеричный редактор и за интересную защиту. Когда надоедает щелкать однотипные защиты, такие компьютерные ребусы приходятся как нельзя кстати.
Просмотров: 6892 | Комментариев: 7
Метки: исследование защиты, реверсинг
Внимание! Статья опубликована больше года назад, информация могла устареть!
Комментарии
Отзывы посетителей сайта о статье
ManHunter
(22.07.2014 в 00:10):
Здесь программы появляются не потому, что они какие-то суперские и незаменимые, а потому что они платные. А лучше они, или хуже, это все субъективно.
Жека
(22.07.2014 в 00:02):
ManHunter, прога то столетняя, мне тоже интересно, неужели он круче чем FlexHEX?
ссылка
(23.08.2013 в 07:42):
Руслан
(06.05.2013 в 11:41):
Подскажите, этот редактор лучше чем 010 Editor?
ManHunter
(05.05.2013 в 16:49):
Я ошибся, это не модуль, хотя очень похоже. Здесь от DWORD отрезаются несколько битов с 28-го по 30-й, а знаковый 31-й бит остается без изменений, на его основании устанавливается флаг знака. Если число отрицательное, то над ним производятся дополнительные манипуляции.
ivan
(04.05.2013 в 16:17):
Очень интересная статья!
Вот только не могли бы вы пояснить вот этот код?
Вы говорите, что это подсчёт модуля числа, но как он работает мне непонятно. Для чего тут применяются битовые маски.
; Что делает эта инструкция? Имеет ли она отношение к подсчёту модуля
.text:0042F6BE and eax, 8FFFFFFFh
.text:0042F6C3 jns short loc_42F6CC
; Получить модуль числа
.text:0042F6C5 dec eax
.text:0042F6C6 or eax, 0F0000000h
.text:0042F6CB inc eax
Спасибо!
Вот только не могли бы вы пояснить вот этот код?
Вы говорите, что это подсчёт модуля числа, но как он работает мне непонятно. Для чего тут применяются битовые маски.
; Что делает эта инструкция? Имеет ли она отношение к подсчёту модуля
.text:0042F6BE and eax, 8FFFFFFFh
.text:0042F6C3 jns short loc_42F6CC
; Получить модуль числа
.text:0042F6C5 dec eax
.text:0042F6C6 or eax, 0F0000000h
.text:0042F6CB inc eax
Спасибо!
Добавить комментарий
Заполните форму для добавления комментария
Качается пока отсюда -
old-dos.ru/index.php?page=files&mode=files&do=show&id=3987 #file8342