Blog. Just Blog

Исследование защиты программы AXE Advanced Hex Editor

Версия для печати Добавить в Избранное Отправить на E-Mail | Категория: Темная сторона Силы | Автор: ManHunter
Скриншот программы AXE Advanced Hex Editor
Скриншот программы AXE Advanced Hex Editor

AXE Advanced Hex Editor - продвинутый шестнадцатеричный редактор с множеством функций, поддержкой скриптового языка, разбором структур, возможностью работать с файлами неограниченного размера и еще целой кучей всяких приятных плюшек. Разработка программы уже давно прекращена, офсайт тоже не отвечает, оплатить лицензию негде (если вы вдруг решили это сделать). Значит мы можем с чистой совестью поковыряться в его бинарных потрошках.

Скачиваем дистрибутив, устанавливаем. Главный исполняемый файл ничем не защищен и не упакован, отправляем его в дизассемблер. А пока посмотрим на систему регистрации и триальности. На ввод неправильных регистрационных данных программа реагирует вот таким безграмотным сообщением:

Сообщение о неправильной регистрации
Сообщение о неправильной регистрации

Попробуем найти эту строчку в исполняемом файле. Ничего не найдено. Ни в ASCII, ни в юникоде, никак. Ладно, план "А" не сработал, переходим к плану "Б". Посмотрим, что у нас находится в ресурсах:

Строки в ресурсах
Строки в ресурсах

Ну прям все как-то слишком идеально выглядит. Есть строчки о правильной регистрации, есть строчки о триальном статусе программы, есть их индексы... Нет только одного - прямых указателей на эти индексы. То есть мы не можем определить, откуда в исполняемом файле идет обращение к этим строкам. Похоже, что автор программы не по наслышке знаком с реверсной инженерией и предусмотрел защиту против новичков и базовых методов взлома. Приходится признать, что план "Б" тоже потерпел неудачу и на очереди план "В". Посмотрим на диалоговое окно "О программе" в ресурсах:

ID элемента диалогового окна
ID элемента диалогового окна

Тут логика простая. Если есть диалоговые окна и известны индексы их элементов, то в исполняемом файле должны быть видны какие-нибудь манипуляции с ними. Конкретно нас интересует установка регистрационного имени в окно "О программе". Для триальной версии это будет строка "Trial", для зарегистрированной, очевидно, должно быть имя пользователя, адрес email или что-то подобное. Индекс этого элемента диалогового окна - 1120 в десятичной или 460h в шестнадцатеричной системе счисления. Поищем в дизассемблере участок кода, где используется это значение и где неподалеку есть функции установки текста в диалоговом окне. Второе вхождение по строке "460h" наводит нас на такой код:
  1. .text:00431794                 push    edi
  2. .text:00431795                 mov     byte ptr [esp+0D0h+var_4], 6
  3. .text:0043179D                 push    ebp
  4. .text:0043179E                 call    ?AfxGetApp@@YGPAVCWinApp@@XZ
  5. .text:004317A3                 mov     ecx, eax
  6. ; Вызвать функцию проверки
  7. .text:004317A5                 call    sub_42F620
  8. ; Если она вернула EAX=0, то переход
  9. .text:004317AA                 cmp     eax, ebx
  10. .text:004317AC                 push    edi             ; int
  11. .text:004317AD                 jz      short loc_431812
  12. ; Иначе действия с элементами диалогового окна
  13. .text:004317AF                 lea     ecx, [esp+0CCh+lpString]
  14. .text:004317B3                 push    offset aD_1     ; "%d"
  15. .text:004317B8                 push    ecx             ; int
  16. .text:004317B9                 call    sub_4B0144
  17. .text:004317BE                 mov     edx, [esp+0D4h+lpString]
  18. .text:004317C2                 add     esp, 0Ch
  19. .text:004317C5                 mov     ecx, esi
  20. .text:004317C7                 push    edx             ; lpString
  21. ; ID элемента диалогового окна "Trial Days"
  22. .text:004317C8                 push    45Eh            ; nIDDlgItem
  23. .text:004317CD                 call    sub_4B7BD2
  24. .text:004317D2                 mov     ecx, eax
  25. .text:004317D4                 call    sub_4B7D49
  26. .text:004317D9                 mov     eax, [esp+0C8h+var_B0]
  27. .text:004317DD                 lea     ecx, [esp+0C8h+lpString]
  28. .text:004317E1                 push    eax             ; int
  29. .text:004317E2                 push    offset aS       ; "%s"
  30. .text:004317E7                 push    ecx             ; int
  31. .text:004317E8                 call    sub_4B0144
  32. .text:004317ED                 mov     edx, [esp+0D4h+lpString]
  33. .text:004317F1                 add     esp, 0Ch
  34. .text:004317F4                 mov     ecx, esi
  35. .text:004317F6                 push    edx             ; lpString
  36. ; ID элемента диалогового окна "Name"
  37. .text:004317F7                 push    460h            ; nIDDlgItem
  38. ; В этой функции вызывается GetDlgItem
  39. .text:004317FC                 call    sub_4B7BD2
  40. .text:00431801                 mov     ecx, eax
  41. ; В этой функции вызывается SetWindowTextA
  42. .text:00431803                 call    sub_4B7D49
  43. .text:00431808                 lea     eax, [esp+0C8h+var_88]
  44. .text:0043180C                 push    eax             ; int
  45. .text:0043180D                 jmp     loc_4318DF
  46. .text:00431812 ; -------------------------------------------------
  47. ; Триальная ветка алгоритма
  48. .text:00431812 loc_431812:
  49. .text:00431812                 lea     ecx, [esp+0CCh+Format]
  50. .text:00431816                 lea     edx, [esp+0CCh+lpString]
  51. .text:0043181A                 push    ecx             ; Format
  52. .text:0043181B                 push    edx             ; int
  53. .text:0043181C                 call    sub_4B0144
  54. .text:00431821                 mov     eax, [esp+0D4h+lpString]
  55. .text:00431825                 add     esp, 0Ch
  56. .text:00431828                 mov     ecx, esi
  57. .text:0043182A                 push    eax             ; lpString
  58. .text:0043182B                 push    45Eh            ; nIDDlgItem
  59. .text:00431830                 call    sub_4B7BD2
  60. .text:00431835                 mov     ecx, eax
  61. .text:00431837                 call    sub_4B7D49
  62. .text:0043183C                 mov     ecx, [esp+0C8h+var_B0]
  63. .text:00431840                 lea     edx, [esp+0C8h+Format]
  64. .text:00431844                 push    ecx             ; int
  65. .text:00431845                 lea     eax, [esp+0CCh+lpString]
  66. .text:00431849                 push    edx             ; Format
  67. .text:0043184A                 push    eax             ; int
  68. .text:0043184B                 call    sub_4B0144
  69. .text:00431850                 mov     ecx, [esp+0D4h+lpString]
  70. .text:00431854                 add     esp, 0Ch
  71. .text:00431857                 push    ecx             ; lpString
  72. .text:00431858                 push    460h            ; nIDDlgItem
  73. .text:0043185D                 mov     ecx, esi
  74. .text:0043185F                 call    sub_4B7BD2
  75. .text:00431864                 mov     ecx, eax
  76. .text:00431866                 call    sub_4B7D49
Вот теперь нам попалась реальная зацепка. По адресу 004317A5 вызывается функция проверки, а по ее результатам в диалоговом окне "О программе" выставляются те или иные значения. Чтобы программа считала себя зарегистрированной, функция проверки должна вернуть в EAX значение отличное от нуля. Переходим к самой функции проверки. Параллельно с анализом в дизассемблере, ее лучше пройти под отладчиком, так будет гораздо нагляднее.
  1. .text:0042F620                 mov     eax, large fs:0
  2. .text:0042F626                 push    0FFFFFFFFh
  3. .text:0042F628                 push    offset unknown_libname_309
  4. .text:0042F62D                 push    eax
  5. .text:0042F62E                 mov     large fs:0, esp
  6. .text:0042F635                 push    ebx
  7. .text:0042F636                 push    esi
  8. .text:0042F637                 push    edi
  9. .text:0042F638                 mov     eax, [esp+18h+arg_8]
  10. .text:0042F63C                 mov     [esp+18h+var_4], 0
  11. .text:0042F644                 mov     ecx, [eax-8]
  12. ; Регистрационное имя не должно быть пустым
  13. .text:0042F647                 test    ecx, ecx
  14. .text:0042F649                 jz      loc_42F70E
  15. .text:0042F64F                 mov     esi, [esp+18h+arg_4]
  16. ; Регистрационный код не должен быть пустым
  17. .text:0042F653                 test    esi, esi
  18. .text:0042F655                 jz      loc_42F70E
  19. ; Проверка регистрационного кода на значение "10021"
  20. .text:0042F65B                 cmp     esi, 2725h
  21. .text:0042F661                 jnz     short loc_42F68D
  22. ; Если он равен этому значению, то вернуть EAX = 1, то есть "зарегистрировано"
  23. .text:0042F663                 lea     ecx, [esp+18h+arg_8]
  24. .text:0042F667                 mov     [esp+18h+var_4], 0FFFFFFFFh
  25. .text:0042F66F                 call    sub_4B3861
  26. .text:0042F674                 mov     eax, 1
  27. .text:0042F679                 mov     ecx, [esp+18h+var_C]
  28. .text:0042F67D                 mov     large fs:0, ecx
  29. .text:0042F684                 pop     edi
  30. .text:0042F685                 pop     esi
  31. .text:0042F686                 pop     ebx
  32. .text:0042F687                 add     esp, 0Ch
  33. .text:0042F68A                 retn    0Ch
Это первая часть проверки. Во-первых мы узнаем, что серийный номер преобразуется в числовое значение. Дальше здесь проверяется, чтобы имя и введенный серийный номер не были пустыми, а после этого введенный серийник сравнивается со значением "10021", и если совпадает, то программа считает себя зарегистрированной. То есть серийник "10021" является универсальным для любого регистрационного имени. После всего ранее увиденного это мне больше напоминает ситуацию когда "ворота поставили, а забор забыли". Тем не менее, программа действительно принимает этот регистрационный код.

Программа успешно зарегистрирована
Программа успешно зарегистрирована

Что-то меня тут все-таки смущает. Посмотрим лучше что там находится дальше. Эта ветка алгоритма активируется, когда введено регистрационное имя и код, который не является универсальным.
  1. .text:0042F68D loc_42F68D:
  2. ; Проверить длину введенного регистрационного имени
  3. .text:0042F68D                 cmp     ecx, 4
  4. .text:0042F690                 jge     short loc_42F6A4
  5. ; Если она меньше 4, то дописать в конец к имени строку "abcd"
  6. .text:0042F692                 push    offset aAbcd    ; "abcd"
  7. .text:0042F697                 lea     ecx, [esp+1Ch+arg_8]
  8. .text:0042F69B                 call    sub_4B3C3D
  9. .text:0042F6A0                 mov     eax, [esp+18h+arg_8]
  10. .text:0042F6A4 loc_42F6A4:
  11. ; Длина регистрационного имени
  12. .text:0042F6A4                 mov     ecx, [eax-8]
  13. ; BL = третий символ регистрационного имени
  14. .text:0042F6A7                 mov     bl, [eax+2]
  15. ; DL = первый символ регистрационного имени
  16. .text:0042F6AA                 mov     dl, [eax]
  17. ; EAX = последний символ регистрационного имени
  18. .text:0042F6AC                 movsx   eax, byte ptr [ecx+eax-1]
  19. ; EDI = третий символ регистрационного имени
  20. .text:0042F6B1                 movsx   edi, bl
  21. ; EDX = первый символ регистрационного имени
  22. .text:0042F6B4                 movsx   edx, dl
  23. .text:0042F6B7                 add     eax, edi
  24. .text:0042F6B9                 add     eax, edx
  25. .text:0042F6BB                 imul    eax, ecx
  26. ; Сложить три символа и перемножить их на длину строки
  27. .text:0042F6BE                 and     eax, 8FFFFFFFh
  28. .text:0042F6C3                 jns     short loc_42F6CC
  29. ; Для отрицательных чисел дополнительная обработка
  30. .text:0042F6C5                 dec     eax
  31. .text:0042F6C6                 or      eax, 0F0000000h
  32. .text:0042F6CB                 inc     eax
  33. .text:0042F6CC loc_42F6CC:
  34. ; Введенный серийный номер больше 10000000h?
  35. .text:0042F6CC                 cmp     esi, 10000000h
  36. .text:0042F6D2                 jbe     short loc_42F6D9
  37. ; Да, добавить к проверочному значению 10000000h
  38. .text:0042F6D4                 add     eax, 10000000h
  39. .text:0042F6D9 loc_42F6D9:
  40. ; ПоXORить проверочное значение с константой 39A13D7h
  41. .text:0042F6D9                 xor     eax, 39A13D7h
  42. .text:0042F6DE                 xor     ecx, ecx
  43. ; Сравнить введенный серийный номер и проверочное значение
  44. .text:0042F6E0                 cmp     esi, eax
  45. .text:0042F6E2                 mov     [esp+18h+var_4], 0FFFFFFFFh
  46. .text:0042F6EA                 setz    cl
  47. .text:0042F6ED                 mov     esi, ecx
  48. .text:0042F6EF                 lea     ecx, [esp+18h+arg_8]
  49. .text:0042F6F3                 call    sub_4B3861
  50. .text:0042F6F8                 mov     eax, esi
  51. .text:0042F6FA                 mov     ecx, [esp+18h+var_C]
  52. .text:0042F6FE                 mov     large fs:0, ecx
  53. .text:0042F705                 pop     edi
  54. .text:0042F706                 pop     esi
  55. .text:0042F707                 pop     ebx
  56. .text:0042F708                 add     esp, 0Ch
  57. .text:0042F70B                 retn    0Ch
Вот теперь это выглядит гораздо правдоподобнее. Мы выяснили формулу вычисления правильного регистрационного кода, ее без труда можно оформить в кейген или сниффер. Так, например, для имени ManHunter / PCL регистрационный код будет 60429527.

Программа успешно зарегистрирована
Программа успешно зарегистрирована

Если посмотреть по перекрестным ссылкам и другие места, откуда вызывается функция проверки серийного номера, то можно разгадать загадку, почему не сработал план "А". После неудачной проверки вот таким мудреным образом расшифровывается и складывается по отдельным символам строка сообщения "This isnot a valid registration code". Неудивительно, что среди этой кодо-вермишели автор пропустил пробел между двумя словами.
  1. .text:0043F5C8                 call    sub_42F620
  2. .text:0043F5CD                 cmp     eax, ebx
  3. .text:0043F5CF                 jz      loc_43F8FB
  4. .text:0043F5D5                 mov     al, byte_514B64
  5. .text:0043F5DA                 mov     cl, byte_514B68
  6. .text:0043F5E0                 mov     dl, byte_514B6C
  7. .text:0043F5E6                 xor     al, 0AAh
  8. .text:0043F5E8                 xor     cl, 55h
  9. .text:0043F5EB                 mov     [esp+24h], al
  10. .text:0043F5EF                 mov     al, byte_514B70
  11. .text:0043F5F4                 mov     [esp+25h], cl
  12. .text:0043F5F8                 mov     cl, byte_514B74
  13. .text:0043F5FE                 xor     dl, 66h
  14. .text:0043F601                 xor     al, 0CCh
  15. .text:0043F603                 xor     cl, 77h
  16. .text:0043F606                 mov     [esp+26h], dl
  17. .text:0043F60A                 mov     dl, byte_514B78
  18. .text:0043F610                 mov     [esp+27h], al
  19. .text:0043F614                 mov     al, byte_514B7C
  20. .text:0043F619                 mov     [esp+28h], cl
  21. .text:0043F61D                 mov     cl, byte_514B80
  22. .text:0043F623                 xor     dl, 55h
  23. .text:0043F626                 xor     al, 65h
  24. .text:0043F628                 xor     cl, 0ACh
  25. .text:0043F62B                 mov     [esp+29h], dl
  26. .text:0043F62F                 mov     dl, byte_514B84
  27. .text:0043F635                 mov     [esp+2Ah], al
  28. .text:0043F639                 mov     al, byte_514B88
  29. .text:0043F63E                 mov     [esp+2Bh], cl
  30. .text:0043F642                 mov     cl, byte_514B90
  31. .text:0043F648                 xor     dl, 35h
  32. .text:0043F64B                 xor     al, 71h
  33. .text:0043F64D                 xor     cl, 0AAh
  34. .text:0043F650                 mov     [esp+2Ch], dl
  35. .text:0043F654                 mov     dl, byte_514B94
  36. .text:0043F65A                 mov     [esp+2Dh], al
  37. .text:0043F65E                 mov     al, byte_514B98
  38. .text:0043F663                 mov     [esp+30h], cl
  39. .text:0043F667                 mov     cl, byte_514B9C
  40. .text:0043F66D                 xor     dl, 55h
  41. ; и так далее, там такого чудо-кода еще много
  42. ...
Кстати, для желающих просто пропатчить функцию проверки регистрации, у автора заготовлена еще вот такая подлянка. Да, программа после патча регистрируется любыми данными, но вот условия срабатывания этой проверки я не нашел. По всей видимости, ожидать ее можно или при каком-нибудь определенном действии, или при неудачном схождении звезд на небе. В любом случае, проверка целостности файла предусмотрена.

Строка сообщения о модифицированном файле
Строка сообщения о модифицированном файле

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

Поделиться ссылкой ВКонтакте Поделиться ссылкой на Facebook Поделиться ссылкой на LiveJournal Поделиться ссылкой в Мой Круг Добавить в Мой мир Добавить на ЛиРу (Liveinternet) Добавить в закладки Memori Добавить в закладки Google
Просмотров: 4997 | Комментариев: 6

Внимание! Статья опубликована больше года назад, информация могла устареть!

Комментарии

Отзывы посетителей сайта о статье
ManHunter (22.07.2014 в 00:10):
Здесь программы появляются не потому, что они какие-то суперские и незаменимые, а потому что они платные. А лучше они, или хуже, это все субъективно.
Жека (22.07.2014 в 00:02):
ManHunter, прога то столетняя, мне тоже интересно, неужели он круче чем FlexHEX?
Руслан (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

Спасибо!

Добавить комментарий

Заполните форму для добавления комментария
Имя*:
Текст комментария (не более 2000 символов)*:

*Все поля обязательны для заполнения.
Комментарии, содержащие рекламу, ненормативную лексику, оскорбления и т.п., а также флуд и сообщения не по теме, будут удаляться. Нарушителям может быть заблокирован доступ к сайту.
Наверх
Powered by PCL's Speckled Band Engine 0.2 RC3
© ManHunter / PCL, 2008-2017
При использовании материалов ссылка на сайт обязательна
Время генерации: 0.09 сек. / MySQL: 2 (0.0053 сек.) / Память: 4.5 Mb
Наверх