Blog. Just Blog

Исследование защиты игры Kyodai Mahjongg

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

Kyodai Mahjongg - сборник красивых китайских трехмерных головоломок. Хорошая графика, множество настроек, различные варианты игр, многоязычный интерфейс, поддержка сетевой игры. Я люблю коротать время за разбором маджонгов, но выкладывать за игры деньги - это уже за пределами моего понимания.

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

Триальное окно
Триальное окно

Но это еще не так плохо, как сообщения, которые периодически появляются во время игры. При этом даже сам автор согласен, что эти сообщения мерзкие.

Триальное окно
Триальное окно

Главный исполняемый файл упакован обычным UPX, который без проблем снимается им же самим upx -d kmj.exe, после чего распакованный файл отправляем в дизассемблер. Параллельно посмотрим, как ведет себя игра в случае ввода неправильных данных:

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

Поскольку интерфейс многоязычный, надо искать соответствие в языковых файлах. В файле русского языка обнаружится вот такая запись:

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

То есть строка сообщения на английском является индексом для локализованной строки. Вернемся к дизассемблеру и поищем, где эта строка используется и при каких условиях появляется. Обнаружится следующий код:
  1. CODE:004B7D66                 call    sub_4049F4
  2. CODE:004B7D6B                 mov     eax, ebx
  3. CODE:004B7D6D                 call    sub_4CF8FC
  4. CODE:004B7D72                 mov     eax, ebx
  5. ; Вызвать функцию проверки
  6. CODE:004B7D74                 call    sub_4B9AF0
  7. ; Если она вернула AL=0, то введенный серийник неправильный
  8. CODE:004B7D79                 test    al, al
  9. CODE:004B7D7B                 jz      short loc_4B7DED
  10. ; Сохранить регистрационные данные в реестре
  11. CODE:004B7D7D                 mov     ecx, offset aSoftwareNamida
  12. ; "Software\\Namida"
  13. CODE:004B7D82                 mov     dl, 1
  14. CODE:004B7D84                 mov     eax, off_4332FC
  15. CODE:004B7D89                 call    sub_4343D8
  16. CODE:004B7D8E                 mov     esi, eax
  17. CODE:004B7D90                 mov     eax, [ebx+0A2B98h]
  18. CODE:004B7D96                 push    eax
  19. CODE:004B7D97                 mov     ecx, offset aReguser ; "RegUser"
  20. CODE:004B7D9C                 mov     edx, offset aKyodai_1 ; "Kyodai"
  21. CODE:004B7DA1                 mov     eax, esi
  22. CODE:004B7DA3                 mov     edi, [eax]
  23. CODE:004B7DA5                 call    dword ptr [edi+4]
  24. CODE:004B7DA8                 mov     eax, [ebx+0A2B9Ch]
  25. CODE:004B7DAE                 push    eax
  26. CODE:004B7DAF                 mov     ecx, offset aRegpass ; "RegPass"
  27. CODE:004B7DB4                 mov     edx, offset aKyodai_1 ; "Kyodai"
  28. CODE:004B7DB9                 mov     eax, esi
  29. CODE:004B7DBB                 mov     edi, [eax]
  30. CODE:004B7DBD                 call    dword ptr [edi+4]
  31. CODE:004B7DC0                 mov     eax, esi
  32. CODE:004B7DC2                 call    sub_403BAC
  33. CODE:004B7DC7                 lea     ecx, [ebp+var_C]
  34. CODE:004B7DCA                 mov     edx, offset aThanksAgainYou
  35. ; "Thanks again ! You're now registered."
  36. CODE:004B7DCF                 mov     eax, [ebx+444h]
  37. CODE:004B7DD5                 call    sub_47D9D8
  38. CODE:004B7DDA                 mov     eax, [ebp+var_C]
  39. CODE:004B7DDD                 mov     cx, word_4B7F00
  40. CODE:004B7DE4                 mov     dl, 2
  41. CODE:004B7DE6                 call    sub_4B3148
  42. CODE:004B7DEB                 jmp     short loc_4B7E50
  43. CODE:004B7DED ; --------------------------------------
  44. CODE:004B7DED loc_4B7DED:
  45. CODE:004B7DED                 mov     eax, [ebx+0A2B98h]
  46. CODE:004B7DF3                 call    sub_404C60
  47. CODE:004B7DF8                 cmp     eax, 8
  48. CODE:004B7DFB                 jge     short loc_4B7E23
  49. CODE:004B7DFD                 lea     ecx, [ebp+var_10]
  50. CODE:004B7E00                 mov     edx, offset aTheUserNameMus
  51. ; "The user name must be at least 8 charac"...
  52. CODE:004B7E05                 mov     eax, [ebx+444h]
  53. CODE:004B7E0B                 call    sub_47D9D8
  54. CODE:004B7E10                 mov     eax, [ebp+var_10]
  55. CODE:004B7E13                 mov     cx, word_4B7F00
  56. CODE:004B7E1A                 mov     dl, 2
  57. CODE:004B7E1C                 call    sub_4B3148
  58. CODE:004B7E21                 jmp     short loc_4B7E50
  59. CODE:004B7E23 ; --------------------------------------
  60. CODE:004B7E23 loc_4B7E23:
  61. CODE:004B7E23                 lea     ecx, [ebp+var_14]
  62. CODE:004B7E26                 mov     edx, offset aSorryWrongPass
  63. ; "Sorry, wrong password. Please check out"...
  64. CODE:004B7E2B                 mov     eax, [ebx+444h]
  65. CODE:004B7E31                 call    sub_47D9D8
  66. CODE:004B7E36                 mov     eax, [ebp+var_14]
  67. CODE:004B7E39                 mov     cx, word_4B7F00
  68. CODE:004B7E40                 mov     dl, 2
  69. CODE:004B7E42                 call    sub_4B3148
Все очень наглядно. Выполняется какая-то функция проверки, если она вернула AL=0, то регистрационные данные считаются некорректными. Затем уточняется причина неудачи: регистрационное имя оказалось короче 8 символов, или же введенный серийник не соответствует регистрационному имени. Самый простой способ лечения это прописать пару команд MOV AL,1 и RET в начало функции проверки по адресу 004B9AF0, после чего любые регистрационные данные будут приняты как корректные. Но можно немного заморочиться и посмотреть на функцию проверки поближе.
  1. CODE:004B9B21                 sub     eax, 2
  2. CODE:004B9B24                 jl      short loc_4B9B48
  3. CODE:004B9B26                 inc     eax
  4. CODE:004B9B27                 mov     edx, 2
  5. CODE:004B9B2C loc_4B9B2C:
  6. CODE:004B9B2C                 mov     ecx, [ebx+0A2B98h]
  7. CODE:004B9B32                 mov     cl, [ecx+edx-1]
  8. CODE:004B9B36                 mov     esi, [ebx+0A2B98h]
  9. CODE:004B9B3C                 cmp     cl, [esi]
  10. CODE:004B9B3E                 jz      short loc_4B9B44
  11. CODE:004B9B40                 mov     [ebp+var_1], 0
  12. CODE:004B9B44 loc_4B9B44:
  13. CODE:004B9B44                 inc     edx
  14. CODE:004B9B45                 dec     eax
  15. CODE:004B9B46                 jnz     short loc_4B9B2C
Первая проверка - введенное регистрационное имя не должно состоять из одинаковых символов. Но особого смысла в этом я не вижу, было бы странно регистрировать программу на имя типа "111111".
  1. CODE:004B9BB7                 lea     ecx, [ebp+var_10]
  2. CODE:004B9BBA                 mov     edx, offset aUnregistered_0
  3. ; "UNREGISTERED"
  4. CODE:004B9BBF                 mov     eax, [ebx+444h]
  5. CODE:004B9BC5                 call    sub_47D9D8
  6. CODE:004B9BCA                 mov     edx, [ebp+var_10]
  7. CODE:004B9BCD                 mov     eax, [ebx+0A2B9Ch]
  8. CODE:004B9BD3                 call    sub_404DAC
  9. CODE:004B9BD8                 jz      loc_4BCAE1
  10. CODE:004B9BDE                 mov     eax, [ebx+0A2B98h]
  11. CODE:004B9BE4                 mov     edx, offset aJohnnyXC398
  12. ; "Johnny+X/C3'98!"
  13. CODE:004B9BE9                 call    sub_404DAC
  14. CODE:004B9BEE                 jz      loc_4BCA94
  15. CODE:004B9BF4                 lea     edx, [ebp+var_14]
  16. CODE:004B9BF7                 mov     eax, [ebx+0A2B98h]
  17. CODE:004B9BFD                 call    sub_4089F0
  18. CODE:004B9C02                 mov     eax, [ebp+var_14]
  19. CODE:004B9C05                 mov     edx, offset aCosmoCramer
  20. ; "cosmo cramer"
  21. CODE:004B9C0A                 call    sub_404DAC
  22. CODE:004B9C0F                 jz      loc_4BCA94
  23. CODE:004B9C15                 mov     eax, [ebx+0A2B98h]
  24. CODE:004B9C1B                 mov     edx, offset aRevealsSerialN
  25. ; "Reveals Serial Numbers"
  26. CODE:004B9C20                 call    sub_404DAC
  27. CODE:004B9C25                 jz      loc_4BCA94
  28. CODE:004B9C2B                 mov     eax, [ebx+0A2B98h]
  29. CODE:004B9C31                 mov     edx, offset aCobra1997
  30. ; "Cobra 1997"
  31. ...
  32. ...
  33. ...
А дальше просто аллея славы. Проверяется огромный список имен, ников и сайтов, которые где-то засветились с варезными релизами этой игры.

Список заблокированных имен
Список заблокированных имен

Такое впечатление, что упорная работа автора, о которой он так настойчиво твердит, заключается в отслеживании и блокировке серийников к своему поделию. Едем дальше. Между этими двумя проверками есть следующий код. Если его пройти в отладчике, то все сразу встанет на свои места.
  1. CODE:004B9B6D                 push    eax
  2. CODE:004B9B6E                 xor     ecx, ecx
  3. CODE:004B9B70                 mov     edx, [ebx+0A2B98h]
  4. CODE:004B9B76                 mov     eax, ebx
  5. CODE:004B9B78                 call    sub_4B5FD4
  6. CODE:004B9B7D                 mov     eax, [ebp+var_8]
  7. CODE:004B9B80                 mov     edx, [ebx+0A2B9Ch]
  8. CODE:004B9B86                 call    sub_404DAC
  9. CODE:004B9B8B                 jz      short loc_4B9BB7
  10. CODE:004B9B8D                 lea     eax, [ebp+var_C]
  11. CODE:004B9B90                 push    eax
  12. CODE:004B9B91                 mov     ecx, 2
  13. CODE:004B9B96                 mov     edx, [ebx+0A2B98h]
  14. CODE:004B9B9C                 mov     eax, ebx
  15. ; Сгенерировать правильный серийный номер для введенного имени
  16. CODE:004B9B9E                 call    sub_4B5FD4
  17. CODE:004B9BA3                 mov     eax, [ebp+var_C]
  18. CODE:004B9BA6                 mov     edx, [ebx+0A2B9Ch]
  19. ; Сравнить введенный серийник с правильным
  20. CODE:004B9BAC                 call    sub_404DAC
  21. CODE:004B9BB1                 jnz     loc_4BCAE1
Тут на основании введенного регистрационного имени генерируется контрольный серийник, а затем просто сравнивается с веденным. Вот что получается в регистрах на момент сравнения.

Серийные номера
Серийные номера

Таким образом, регистрационному имени "ManHunter / PCL" соответствует серийный номер "347297675699273". Закрываем отладчик, запускаем игру в обычном режиме, повторяем регистрацию, но уже с найденным серийным номером:

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

Игра еще раз благодарит, после чего переходит в полноценный режим работы. Никакие триальные окна больше не появляются, все работает как надо. Цель достигнута. Теперь автору придется добавить к списку блокировки еще одно имя. Но мы его напрягать лишний раз не будем, а посмотрим на алгоритм генерации правильного серийного номера. Лучше это делать под отладчиком. Загружаем исполняемый файл в отладчик, ставим точку останова по адресу 004B5FD4, запускаем и пытаемся зарегистрировать. Когда точка останова сработает, в пошаговом режиме пройдем функцию генерации серийника.
  1. CODE:004B6039                 mov     edx, [ebp+var_8]
  2. CODE:004B603C                 movzx   eax, byte ptr [edx+eax-1]
  3. CODE:004B6041                 mov     edx, [ebp+var_8]
  4. CODE:004B6044                 movzx   edx, byte ptr [edx]
  5. CODE:004B6047                 add     eax, edx
  6. CODE:004B6049                 mov     ecx, 0Ah
  7. CODE:004B604E                 xor     edx, edx
  8. CODE:004B6050                 div     ecx
  9. CODE:004B6052                 add     edx, 30h
Первая часть. Берутся первый и последний символ регистрационного имени, их коды складываются, результат делится на 10 а к остатку прибавляется код символа "0", таким образом получается цифра от 0 до 9. Это первый символ серийника.
  1. CODE:004B606C                 mov     ebx, 2
  2. CODE:004B6071 loc_4B6071:
  3. CODE:004B6071                 mov     eax, [ebp+var_8]
  4. CODE:004B6074                 movzx   eax, byte ptr [eax+ebx-2]
  5. CODE:004B6079                 mov     edx, [ebp+var_8]
  6. CODE:004B607C                 movzx   edx, byte ptr [edx+ebx-1]
  7. CODE:004B6081                 add     eax, edx
  8. CODE:004B6083                 mov     ecx, 0Ah
  9. CODE:004B6088                 xor     edx, edx
  10. CODE:004B608A                 div     ecx
  11. CODE:004B608C                 add     edx, 30h
  12. CODE:004B608F                 lea     eax, [ebp+var_1C]
  13. CODE:004B6092                 call    sub_404B88
  14. CODE:004B6097                 mov     edx, [ebp+var_1C]
  15. CODE:004B609A                 mov     eax, edi
  16. CODE:004B609C                 call    sub_404C68
  17. CODE:004B60A1                 inc     ebx
  18. CODE:004B60A2                 dec     esi
  19. CODE:004B60A3                 jnz     short loc_4B6071
Дальше в цикле берутся символы регистрационного имени, начиная с первого и до предпоследнего, затем код каждого складывается с кодом следующего по счету символа имени, результат делится на 10 а к остатку прибавляется "0". Так мы получаем оставшиеся цифры правильного серийника, длина которого как раз получается равной длине регистрационного имени. Вот тут, кстати, и становится ясным, зачем делается проверка на все одинаковые символы в регистрационном имени, ведь для такого случая серийник тоже будет полностью состоять из одинаковых цифр.
  1.         ; Keygen для Kyodai Mahjongg
  2.         mov     edi,serial
  3.         mov     esi,name
  4.         mov     ecx,[name_len]
  5.  
  6.         mov     ebx,10
  7.         xor     eax,eax
  8. loc_loop:
  9.         or      eax,eax
  10.         lodsb
  11.         jnz     @1
  12.         add     al,byte[esi+ecx-2]
  13.         dec     esi
  14.         jmp     @2
  15. @1:
  16.         add     al,byte[esi]
  17. @2:
  18.         cdq
  19.         div     ebx
  20.         xchg    eax,edx
  21.         add     al,'0'
  22.         stosb
  23.         loop    loc_loop
  24.         xor     eax,eax
  25.         stosb
Место для патча выяснили, вылавливать правильные серийники под отладчиком научились, алгоритм генерации серийника разобрали. Осталось только нарисовать кейген, но это вы уже сделайте самостоятельно.

Поделиться ссылкой ВКонтакте
Просмотров: 1750 | Комментариев: 6

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

Комментарии

Отзывы посетителей сайта о статье
Алекс (30.11.2024 в 22:08):
ничего не понятно но очень интересно.
спасибо за серийник.
Sonia (11.01.2023 в 08:54):
Серийник из статьи подошел) спасибо за ваш труд, еле нашла рабочий
ManHunter (13.04.2021 в 18:10):
Если речь про классический маджонг, то там фишки должны быть не только одинаковые, но при этом еще и свободные, то есть как минимум с одной из боковых сторон не должно лежать другой фишки.
brute (13.04.2021 в 17:39):
"выиграл" за 40 минут. Там не просто одинаковые фишки надо нажимать, но и в определённой последовательности?
Sergii (13.04.2021 в 08:45):
Прекрасная подача материала! Спасибо. Учусь
voffka (07.04.2021 в 20:16):
Вот это антиквариат. Один из первых моих кейгенов.

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

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

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