Blog. Just Blog

Исследование защиты программы IrfanView

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

IrfanView - один из самых популярных просмотрщиков графики и в особом представлении не нуждается. IrfanView прекрасно работает без какой-либо регистрации, можно даже сказать, что он бесплатный. Регистрационный ключ высылается автором в качестве благодарности за добровольные пожертвования, в остальных случаях программа пишет, что зарегистрирована на "YOU". Отправку пожертвований я оставляю целиком на вашей совести, а сейчас мы просто разберем алгоритм регистрации программы.

Скачиваем дистрибутив, устанавливаем, смотрим что у нас получилось. Файл i_view32.exe упакован UPX, снимаем его им же самим, upx -d i_view32.exe, тут никаких сюрпризов. Дальше в работу традиционно подключается дизассемблер, мы же пока посмотрим на то, как программа регистрируется и как реагирует на ввод неправильных регистрационных данных.

Строка сообщения в ресурсах
Строка сообщения в ресурсах

Строка сообщения о неправильной регистрации находится в ресурсах файла. Ее индекс равен 1238 или 4D6h в шестнадцатеричной системе счисления. Поищем это значение в листинге дизассемблера:
  1. .text:0047FBC1                 lea     edx, [esp+0B1Ch+Str]
  2. .text:0047FBC8                 lea     eax, [esp+0B1Ch+Text]
  3. .text:0047FBCF                 push    edx             ; Str
  4. .text:0047FBD0                 push    eax             ; int
  5. ; Вызвать функцию проверки регистрационных данных
  6. .text:0047FBD1                 call    sub_44B370
  7. .text:0047FBD6                 add     esp, 8
  8. ; Если она вернула EAX=0, то регистрация неправильная
  9. .text:0047FBD9                 test    eax, eax
  10. .text:0047FBDB                 jnz     short loc_47FC04
  11. ; Загрузить строчку из ресурсов и вывести сообщение о неправильной регистрации
  12. .text:0047FBDD                 mov     ecx, hInstance
  13. .text:0047FBE3                 push    eax             ; int
  14. .text:0047FBE4                 push    eax             ; int
  15. .text:0047FBE5                 push    eax             ; int
  16. .text:0047FBE6                 push    eax             ; int
  17. ; Индекс строки из ресурсов
  18. .text:0047FBE7                 push    4D6h            ; uID
  19. .text:0047FBEC                 push    ecx             ; hInstance
  20. .text:0047FBED                 call    sub_46EBC0
  21. .text:0047FBF2                 add     esp, 18h
  22. .text:0047FBF5                 xor     eax, eax
  23. .text:0047FBF7                 pop     edi
  24. .text:0047FBF8                 pop     esi
  25. .text:0047FBF9                 pop     ebp
  26. .text:0047FBFA                 pop     ebx
  27. .text:0047FBFB                 add     esp, 0B0Ch
  28. .text:0047FC01                 retn    10h
  29. .text:0047FC04 ; -----------------------------------------
  30. .text:0047FC04 loc_47FC04:
  31. ; Сохранить регистрационные данные в ini-файле
  32. .text:0047FC04                 mov     esi, ds:WritePrivateProfileStringA
  33. .text:0047FC0A                 lea     edx, [esp+0B1Ch+Data]
  34. .text:0047FC11                 lea     eax, [esp+0B1Ch+Text]
  35. .text:0047FC18                 push    edx             ; lpFileName
  36. .text:0047FC19                 push    eax             ; lpString
  37. .text:0047FC1A                 push    offset aName    ; "Name"
  38. .text:0047FC1F                 push    offset aRegistration ; "Registration"
  39. .text:0047FC24                 call    esi ; WritePrivateProfileStringA
  40. .text:0047FC26                 lea     ecx, [esp+0B1Ch+Data]
  41. .text:0047FC2D                 lea     edx, [esp+0B1Ch+Str]
  42. .text:0047FC34                 push    ecx             ; lpFileName
  43. .text:0047FC35                 push    edx             ; lpString
  44. .text:0047FC36                 push    offset aCode    ; "Code"
  45. .text:0047FC3B                 push    offset aRegistration ; "Registration"
  46. .text:0047FC40                 call    esi ; WritePrivateProfileStringA
  47. .text:0047FC42                 push    0
  48. .text:0047FC44                 push    0
  49. .text:0047FC46                 push    0
  50. .text:0047FC48                 push    0
  51. .text:0047FC4A                 push    4D7h
  52. .text:0047FC4F                 jmp     loc_481294
Код понятен. Сперва вызывается функция проверки, затем или выводится окно с сообщением о неправильной регистрации, или регистрационные данные записываются в ini-файл. Первый вариант решения, как обычно, патч функции проверки, чтобы она всегда возвращала EAX=1. Классический патч по адресу 0044B370 из двух команд MOV EAX,1 / RET и программа с радостью примет любой серийный номер.

Но так придется патчить каждую новую версию программы, что в конце концов надоест. Можно, конечно, сделать универсальный патч и даже inline-патч поверх упаковщика, но стоят ли такие усилия победы над бесплатной программой? Поэтому посмотрим, как проверяется регистрационный номер. Процедура очень простая, несмотря на множество арифметических и логических операций, весь код наглядный и сложности в анализе не представляет. Сперва высчитывается сумма кодов символов регистрационного имени, после чего значение дополнительно преобразуется несколькими операциями и после этого переводится в текстовый вид.
  1. .text:0044B370                 mov     eax, [esp+Str]
  2. .text:0044B374                 sub     esp, 14h
  3. .text:0044B377                 push    ebx
  4. .text:0044B378                 push    ebp
  5. .text:0044B379                 push    esi
  6. .text:0044B37A                 push    edi
  7. .text:0044B37B                 push    eax             ; Str
  8. .text:0044B37C                 xor     ebx, ebx
  9. .text:0044B37E                 call    _atol
  10. .text:0044B383                 mov     esi, [esp+28h+arg_0]
  11. .text:0044B387                 mov     ebp, eax
  12. .text:0044B389                 mov     edi, esi
  13. .text:0044B38B                 or      ecx, 0FFFFFFFFh
  14. .text:0044B38E                 xor     eax, eax
  15. .text:0044B390                 add     esp, 4
  16. .text:0044B393                 xor     edx, edx
  17. .text:0044B395                 repne scasb
  18. .text:0044B397                 not     ecx
  19. .text:0044B399                 dec     ecx
  20. .text:0044B39A                 test    ecx, ecx
  21. .text:0044B39C                 jle     short loc_44B3B5
  22. ; Подсчитать сумму ASCII-кодов всех символов регистрационного имени
  23. .text:0044B39E loc_44B39E:
  24. .text:0044B39E                 movsx   ecx, byte ptr [edx+esi]
  25. .text:0044B3A2                 add     ebx, ecx
  26. .text:0044B3A4                 mov     edi, esi
  27. .text:0044B3A6                 or      ecx, 0FFFFFFFFh
  28. .text:0044B3A9                 xor     eax, eax
  29. .text:0044B3AB                 inc     edx
  30. .text:0044B3AC                 repne scasb
  31. .text:0044B3AE                 not     ecx
  32. .text:0044B3B0                 dec     ecx
  33. .text:0044B3B1                 cmp     edx, ecx
  34. .text:0044B3B3                 jl      short loc_44B39E
  35. .text:0044B3B5 loc_44B3B5:
  36. ; Небольшие преобразования полученного значения
  37. .text:0044B3B5                 mov     eax, 104h
  38. .text:0044B3BA                 push    0Ah             ; Radix
  39. .text:0044B3BC                 sub     eax, ebx
  40. .text:0044B3BE                 cdq
  41. .text:0044B3BF                 xor     eax, edx
  42. .text:0044B3C1                 sub     eax, edx
  43. .text:0044B3C3                 add     eax, 14Ch
  44. .text:0044B3C8                 lea     edx, ds:0[eax*8]
  45. .text:0044B3CF                 sub     edx, eax
  46. .text:0044B3D1                 lea     ecx, [eax+edx*4]
  47. .text:0044B3D4                 lea     edx, [esp+28h+Dest]
  48. .text:0044B3D8                 push    edx             ; Dest
  49. .text:0044B3D9                 lea     esi, [eax+ecx*2]
  50. .text:0044B3DC                 shl     esi, 3
  51. .text:0044B3DF                 push    esi             ; Value
  52. ; Перевести полученное значение в строку (десятичное значение)
  53. .text:0044B3E0                 call    __ltoa
  54. ...
Дальше вычисления могут пойти по двум вариантам, в зависимости от полученного в предыдущем коде значения. Если оно больше 0F423Fh (или 999999 в десятичной системе счисления), то выполняется одна ветка алгоритма, если меньше или равно - другая. Зачем так сделано, будет понятно ниже. В нашем случае для регистрационного имени "ManHunter / PCL" предварительное значение будет "623040". Смотрим дальше.
  1. ; Значение больше 999999?
  2. .text:0044B3E8                 cmp     esi, 0F423Fh
  3. ; Да, переход
  4. .text:0044B3EE                 ja      loc_44B4E3
  5. ; Первая ветка алгоритма
  6. .text:0044B3F4                 mov     cl, byte ptr [esp+24h+var_10]
  7. .text:0044B3F8                 mov     al, byte ptr [esp+24h+var_10+1]
  8. .text:0044B3FC                 mov     dl, [esp+24h+Dest+3]
  9. .text:0044B400                 mov     byte ptr [esp+24h+var_10+2], cl
  10. .text:0044B404                 mov     cl, [esp+24h+Dest+1]
  11. .text:0044B408                 mov     [esp+18h], al
  12. .text:0044B40C                 mov     al, [esp+24h+Dest+2]
  13. .text:0044B410                 mov     byte ptr [esp+24h+var_10+1], dl
  14. .text:0044B414                 mov     [esp+24h+Dest+2], cl
  15. .text:0044B418                 mov     ecx, [esp+24h+var_10]
  16. .text:0044B41C                 and     ecx, 0FFh
  17. .text:0044B422                 mov     [esp+24h+Dest+3], al
  18. .text:0044B426                 mov     eax, ecx
  19. .text:0044B428                 shl     eax, 5
  20. .text:0044B42B                 sub     eax, ecx
  21. .text:0044B42D                 mov     ecx, [esp+18h]
  22. .text:0044B431                 and     ecx, 0FFh
  23. .text:0044B437                 lea     edx, [eax+eax*2]
  24. .text:0044B43A                 lea     eax, [ecx+ecx*4]
  25. .text:0044B43D                 shl     eax, 3
  26. .text:0044B440                 sub     eax, ecx
  27. .text:0044B442                 sub     eax, edx
  28. .text:0044B444                 cdq
  29. .text:0044B445                 mov     ecx, eax
  30. .text:0044B447                 xor     ecx, edx
  31. .text:0044B449                 sub     ecx, edx
  32. .text:0044B44B                 lea     eax, [ecx+ecx*4]
  33. .text:0044B44E                 shl     eax, 3
  34. .text:0044B451                 sub     eax, ecx
  35. .text:0044B453                 mov     ecx, 9
  36. .text:0044B458                 cdq
  37. .text:0044B459                 idiv    ecx
  38. .text:0044B45B                 mov     eax, dword ptr [esp+24h+Dest+3]
  39. .text:0044B45F                 and     eax, 0FFh
  40. .text:0044B464                 add     dl, 30h
  41. .text:0044B467                 mov     byte ptr [esp+24h+var_10+3], dl
  42. .text:0044B46B                 lea     edx, [eax+eax*2]
  43. .text:0044B46E                 shl     edx, 4
  44. .text:0044B471                 sub     edx, eax
  45. .text:0044B473                 mov     eax, [esp+24h+var_10+1]
  46. .text:0044B477                 and     eax, 0FFh
  47. .text:0044B47C                 lea     ecx, [eax+eax*8]
  48. .text:0044B47F                 lea     eax, [eax+ecx*4]
  49. .text:0044B482                 lea     eax, [edx+eax*2]
  50. .text:0044B485                 cdq
  51. .text:0044B486                 xor     eax, edx
  52. .text:0044B488                 sub     eax, edx
  53. .text:0044B48A                 lea     ecx, [eax+eax*8]
  54. .text:0044B48D                 lea     eax, [eax+ecx*4]
  55. .text:0044B490                 mov     ecx, 9
  56. .text:0044B495                 shl     eax, 1
  57. .text:0044B497                 cdq
  58. .text:0044B498                 idiv    ecx
  59. .text:0044B49A                 mov     ecx, dword ptr [esp+24h+Dest]
  60. .text:0044B49E                 and     ecx, 0FFh
  61. .text:0044B4A4                 lea     eax, [ecx+ecx*2]
  62. .text:0044B4A7                 lea     eax, [eax+eax*8]
  63. .text:0044B4AA                 shl     eax, 1
  64. .text:0044B4AC                 sub     eax, ecx
  65. .text:0044B4AE                 add     dl, 30h
  66. .text:0044B4B1                 mov     byte ptr [esp+24h+var_10], dl
  67. .text:0044B4B5                 mov     ecx, dword ptr [esp+24h+Dest+1]
  68. .text:0044B4B9                 and     ecx, 0FFh
  69. .text:0044B4BF                 lea     edx, ds:0[ecx*8]
  70. .text:0044B4C6                 sub     edx, ecx
  71. .text:0044B4C8                 lea     edx, [edx+edx*4]
  72. .text:0044B4CB                 sub     eax, edx
  73. .text:0044B4CD                 cdq
  74. .text:0044B4CE                 mov     ecx, eax
  75. .text:0044B4D0                 xor     ecx, edx
  76. .text:0044B4D2                 sub     ecx, edx
  77. .text:0044B4D4                 lea     eax, [ecx+ecx*2]
  78. .text:0044B4D7                 lea     eax, [eax+eax*8]
  79. .text:0044B4DA                 shl     eax, 1
  80. .text:0044B4DC                 sub     eax, ecx
  81. .text:0044B4DE                 jmp     loc_44B5D8
  82. .text:0044B4E3 ; -----------------------------------------
  83. ; Вторая ветка алгоритма
  84. .text:0044B4E3 loc_44B4E3:
  85. .text:0044B4E3                 mov     al, byte ptr [esp+24h+var_10+1]
  86. .text:0044B4E7                 mov     dl, byte ptr [esp+24h+var_10+2]
  87. .text:0044B4EB                 mov     cl, byte ptr [esp+24h+var_10]
  88. .text:0044B4EF                 mov     byte ptr [esp+24h+var_10+2], al
  89. .text:0044B4F3                 mov     al, [esp+24h+Dest+1]
  90. .text:0044B4F7                 mov     [esp+18h], dl
  91. .text:0044B4FB                 mov     dl, [esp+24h+Dest+2]
  92. .text:0044B4FF                 mov     [esp+24h+Dest+2], al
  93. .text:0044B503                 mov     eax, [esp+24h+var_10+2]
  94. .text:0044B507                 mov     byte ptr [esp+24h+var_10+1], cl
  95. .text:0044B50B                 and     eax, 0FFh
  96. .text:0044B510                 mov     [esp+24h+Dest+3], dl
  97. .text:0044B514                 mov     ecx, eax
  98. .text:0044B516                 shl     ecx, 6
  99. .text:0044B519                 sub     ecx, eax
  100. .text:0044B51B                 mov     eax, [esp+18h]
  101. .text:0044B51F                 and     eax, 0FFh
  102. .text:0044B524                 lea     eax, [eax+eax*8]
  103. .text:0044B527                 shl     eax, 2
  104. .text:0044B52A                 sub     eax, ecx
  105. .text:0044B52C                 mov     ecx, 9
  106. .text:0044B531                 cdq
  107. .text:0044B532                 xor     eax, edx
  108. .text:0044B534                 sub     eax, edx
  109. .text:0044B536                 lea     eax, [eax+eax*8]
  110. .text:0044B539                 shl     eax, 2
  111. .text:0044B53C                 cdq
  112. .text:0044B53D                 idiv    ecx
  113. .text:0044B53F                 add     dl, 30h
  114. .text:0044B542                 mov     byte ptr [esp+24h+var_10+3], dl
  115. .text:0044B546                 mov     eax, [esp+24h+var_10]
  116. .text:0044B54A                 and     eax, 0FFh
  117. .text:0044B54F                 add     eax, 20h
  118. .text:0044B552                 lea     edx, ds:0[eax*8]
  119. .text:0044B559                 sub     edx, eax
  120. .text:0044B55B                 lea     eax, [eax+edx*4]
  121. .text:0044B55E                 lea     ecx, [eax+eax*2]
  122. .text:0044B561                 mov     eax, dword ptr [esp+24h+Dest+3]
  123. .text:0044B565                 and     eax, 0FFh
  124. .text:0044B56A                 lea     edx, [eax+eax*4]
  125. .text:0044B56D                 shl     edx, 3
  126. .text:0044B570                 sub     edx, eax
  127. .text:0044B572                 lea     eax, [ecx+edx*2]
  128. .text:0044B575                 cdq
  129. .text:0044B576                 xor     eax, edx
  130. .text:0044B578                 sub     eax, edx
  131. .text:0044B57A                 lea     ecx, ds:0[eax*8]
  132. .text:0044B581                 sub     ecx, eax
  133. .text:0044B583                 lea     eax, [eax+ecx*4]
  134. .text:0044B586                 mov     ecx, 9
  135. .text:0044B58B                 lea     eax, [eax+eax*2]
  136. .text:0044B58E                 cdq
  137. .text:0044B58F                 idiv    ecx
  138. .text:0044B591                 mov     eax, dword ptr [esp+24h+Dest]
  139. .text:0044B595                 and     eax, 0FFh
  140. .text:0044B59A                 add     dl, 30h
  141. .text:0044B59D                 mov     byte ptr [esp+24h+var_10], dl
  142. .text:0044B5A1                 lea     edx, ds:0[eax*8]
  143. .text:0044B5A8                 sub     edx, eax
  144. .text:0044B5AA                 lea     eax, [eax+edx*4]
  145. .text:0044B5AD                 mov     edx, dword ptr [esp+24h+Dest+1]
  146. .text:0044B5B1                 and     edx, 0FFh
  147. .text:0044B5B7                 mov     ecx, edx
  148. .text:0044B5B9                 shl     ecx, 4
  149. .text:0044B5BC                 add     ecx, edx
  150. .text:0044B5BE                 shl     eax, 1
  151. .text:0044B5C0                 lea     ecx, [ecx+ecx*4]
  152. .text:0044B5C3                 sub     eax, ecx
  153. .text:0044B5C5                 cdq
  154. .text:0044B5C6                 xor     eax, edx
  155. .text:0044B5C8                 sub     eax, edx
  156. .text:0044B5CA                 lea     edx, ds:0[eax*8]
  157. .text:0044B5D1                 sub     edx, eax
  158. .text:0044B5D3                 lea     eax, [eax+edx*4]
  159. .text:0044B5D6                 shl     eax, 1
  160. .text:0044B5D8 loc_44B5D8:
  161. .text:0044B5D8                 cdq
  162. .text:0044B5D9                 mov     ecx, 9
  163. .text:0044B5DE                 mov     [esp+24h+var_B], 0
  164. .text:0044B5E3                 idiv    ecx
  165. .text:0044B5E5                 add     dl, 30h
  166. .text:0044B5E8                 mov     [esp+24h+Dest+1], dl
  167. .text:0044B5EC                 lea     edx, [esp+24h+Dest]
  168. ; Преобразовать строку в десятичное число
  169. .text:0044B5F0                 push    edx             ; Str
  170. .text:0044B5F1                 call    _atol
На основании подсчитанного ранее значения выполняются его преобразования, а строка серийного номера дополняется несколькими символами. Проверка значения нужна для того, чтобы определить, в какие позиции записывать дополнительные символы, после 6-й или после 7-й цифры. Код обеих веток алгоритма линейный и настолько чистый, что его можно копировать в генератор ключей практически без изменений. В основном это двоичная арифметика. Небольшие нюансы есть при манипуляциях с символами, но они также становятся понятны при прохождении кода под отладчиком. Там же в отладчике по адресу 0044B5F0 регистр EDX указывает на правильный серийный номер для введенного имени. Можно на этом и остановиться, получив валидную пару, можно сделать сниффер ключей, а можно выдрать код из проверки и написать свой генератор.

Валидной парой, например, будет регистрационное имя "ManHunter / PCL" и серийный номер "642300400". Попробуем зарегистрировать с их помощью IrfanView. Все проходит на ура, программа принимает серийник и благодарит за регистрацию.

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

Таким образом решен еще один несложный ребус по реверс-инженерии. Мы даже умудрились не нанести никакого вреда индустрии программного обеспечения, так как программа бесплатная. А очередную порцию опыта, надеюсь, вы получили.

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

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

Комментарии

Отзывы посетителей сайта о статье
Станислав (23.04.2015 в 10:14):
Очень полезная программа. Наверное единственная которая корректно работает с принтером, печатая без изменения размеров и искажений.
brute (09.06.2012 в 06:57):
хорошая прога, и.. старые версии бесплатны, как и плагины к ним. В новых версиях плагины триальны, например большие (в пикселях) картинки не конвертятся в JPG..
Zhelezyaka (05.06.2012 в 01:15):
ай-ай-ай, и тётку до трусов раздел, как "не очень хорошо поступили", ей же холодно)))
Super_DJ (04.06.2012 в 23:27):
Соглашусь с ManHunter и не соглашусь с остальными. Человек знаниями делится, а вреда не нанес. Он же её продавать не стал, стало быть, и обвинения беспочвенные.  А за знания большое спасибо.
ManHunter (04.06.2012 в 19:42):
И что мне теперь извиняться перед всеми аффтарами, которые когда-либо попали под мою раздачу? Может все-таки обойдемся без двойных стандартов?
Доброжелатель (04.06.2012 в 19:02):
ManHunter Вы как то не очень хорошо поступили! В ней даже банер с рекламой не весит, а Вы! Обижаете Вы Хороших Програмистов!
ManHunter (04.06.2012 в 12:21):
Нет, пока не довелось
Zhelezyaka (04.06.2012 в 12:21):
нанести вред индустрии - это как-то слишком круто, либо что-то случилось с душевным равновесием...
читал рассказик у Олега Дивова «Мы идем на Кюрасао»?

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

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

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