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

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

Строка сообщения в ресурсах
Строка сообщения о неправильной регистрации находится в ресурсах файла. Ее индекс равен 1238 или 4D6h в шестнадцатеричной системе счисления. Поищем это значение в листинге дизассемблера:
Code (Assembler) : Убрать нумерацию
- .text:0047FBC1 lea edx, [esp+0B1Ch+Str]
- .text:0047FBC8 lea eax, [esp+0B1Ch+Text]
- .text:0047FBCF push edx ; Str
- .text:0047FBD0 push eax ; int
- ; Вызвать функцию проверки регистрационных данных
- .text:0047FBD1 call sub_44B370
- .text:0047FBD6 add esp, 8
- ; Если она вернула EAX=0, то регистрация неправильная
- .text:0047FBD9 test eax, eax
- .text:0047FBDB jnz short loc_47FC04
- ; Загрузить строчку из ресурсов и вывести сообщение о неправильной регистрации
- .text:0047FBDD mov ecx, hInstance
- .text:0047FBE3 push eax ; int
- .text:0047FBE4 push eax ; int
- .text:0047FBE5 push eax ; int
- .text:0047FBE6 push eax ; int
- ; Индекс строки из ресурсов
- .text:0047FBE7 push 4D6h ; uID
- .text:0047FBEC push ecx ; hInstance
- .text:0047FBED call sub_46EBC0
- .text:0047FBF2 add esp, 18h
- .text:0047FBF5 xor eax, eax
- .text:0047FBF7 pop edi
- .text:0047FBF8 pop esi
- .text:0047FBF9 pop ebp
- .text:0047FBFA pop ebx
- .text:0047FBFB add esp, 0B0Ch
- .text:0047FC01 retn 10h
- .text:0047FC04 ; -----------------------------------------
- .text:0047FC04 loc_47FC04:
- ; Сохранить регистрационные данные в ini-файле
- .text:0047FC04 mov esi, ds:WritePrivateProfileStringA
- .text:0047FC0A lea edx, [esp+0B1Ch+Data]
- .text:0047FC11 lea eax, [esp+0B1Ch+Text]
- .text:0047FC18 push edx ; lpFileName
- .text:0047FC19 push eax ; lpString
- .text:0047FC1A push offset aName ; "Name"
- .text:0047FC1F push offset aRegistration ; "Registration"
- .text:0047FC24 call esi ; WritePrivateProfileStringA
- .text:0047FC26 lea ecx, [esp+0B1Ch+Data]
- .text:0047FC2D lea edx, [esp+0B1Ch+Str]
- .text:0047FC34 push ecx ; lpFileName
- .text:0047FC35 push edx ; lpString
- .text:0047FC36 push offset aCode ; "Code"
- .text:0047FC3B push offset aRegistration ; "Registration"
- .text:0047FC40 call esi ; WritePrivateProfileStringA
- .text:0047FC42 push 0
- .text:0047FC44 push 0
- .text:0047FC46 push 0
- .text:0047FC48 push 0
- .text:0047FC4A push 4D7h
- .text:0047FC4F jmp loc_481294
Но так придется патчить каждую новую версию программы, что в конце концов надоест. Можно, конечно, сделать универсальный патч и даже inline-патч поверх упаковщика, но стоят ли такие усилия победы над бесплатной программой? Поэтому посмотрим, как проверяется регистрационный номер. Процедура очень простая, несмотря на множество арифметических и логических операций, весь код наглядный и сложности в анализе не представляет. Сперва высчитывается сумма кодов символов регистрационного имени, после чего значение дополнительно преобразуется несколькими операциями и после этого переводится в текстовый вид.
Code (Assembler) : Убрать нумерацию
- .text:0044B370 mov eax, [esp+Str]
- .text:0044B374 sub esp, 14h
- .text:0044B377 push ebx
- .text:0044B378 push ebp
- .text:0044B379 push esi
- .text:0044B37A push edi
- .text:0044B37B push eax ; Str
- .text:0044B37C xor ebx, ebx
- .text:0044B37E call _atol
- .text:0044B383 mov esi, [esp+28h+arg_0]
- .text:0044B387 mov ebp, eax
- .text:0044B389 mov edi, esi
- .text:0044B38B or ecx, 0FFFFFFFFh
- .text:0044B38E xor eax, eax
- .text:0044B390 add esp, 4
- .text:0044B393 xor edx, edx
- .text:0044B395 repne scasb
- .text:0044B397 not ecx
- .text:0044B399 dec ecx
- .text:0044B39A test ecx, ecx
- .text:0044B39C jle short loc_44B3B5
- ; Подсчитать сумму ASCII-кодов всех символов регистрационного имени
- .text:0044B39E loc_44B39E:
- .text:0044B39E movsx ecx, byte ptr [edx+esi]
- .text:0044B3A2 add ebx, ecx
- .text:0044B3A4 mov edi, esi
- .text:0044B3A6 or ecx, 0FFFFFFFFh
- .text:0044B3A9 xor eax, eax
- .text:0044B3AB inc edx
- .text:0044B3AC repne scasb
- .text:0044B3AE not ecx
- .text:0044B3B0 dec ecx
- .text:0044B3B1 cmp edx, ecx
- .text:0044B3B3 jl short loc_44B39E
- .text:0044B3B5 loc_44B3B5:
- ; Небольшие преобразования полученного значения
- .text:0044B3B5 mov eax, 104h
- .text:0044B3BA push 0Ah ; Radix
- .text:0044B3BC sub eax, ebx
- .text:0044B3BE cdq
- .text:0044B3BF xor eax, edx
- .text:0044B3C1 sub eax, edx
- .text:0044B3C3 add eax, 14Ch
- .text:0044B3C8 lea edx, ds:0[eax*8]
- .text:0044B3CF sub edx, eax
- .text:0044B3D1 lea ecx, [eax+edx*4]
- .text:0044B3D4 lea edx, [esp+28h+Dest]
- .text:0044B3D8 push edx ; Dest
- .text:0044B3D9 lea esi, [eax+ecx*2]
- .text:0044B3DC shl esi, 3
- .text:0044B3DF push esi ; Value
- ; Перевести полученное значение в строку (десятичное значение)
- .text:0044B3E0 call __ltoa
- ...
Code (Assembler) : Убрать нумерацию
- ; Значение больше 999999?
- .text:0044B3E8 cmp esi, 0F423Fh
- ; Да, переход
- .text:0044B3EE ja loc_44B4E3
- ; Первая ветка алгоритма
- .text:0044B3F4 mov cl, byte ptr [esp+24h+var_10]
- .text:0044B3F8 mov al, byte ptr [esp+24h+var_10+1]
- .text:0044B3FC mov dl, [esp+24h+Dest+3]
- .text:0044B400 mov byte ptr [esp+24h+var_10+2], cl
- .text:0044B404 mov cl, [esp+24h+Dest+1]
- .text:0044B408 mov [esp+18h], al
- .text:0044B40C mov al, [esp+24h+Dest+2]
- .text:0044B410 mov byte ptr [esp+24h+var_10+1], dl
- .text:0044B414 mov [esp+24h+Dest+2], cl
- .text:0044B418 mov ecx, [esp+24h+var_10]
- .text:0044B41C and ecx, 0FFh
- .text:0044B422 mov [esp+24h+Dest+3], al
- .text:0044B426 mov eax, ecx
- .text:0044B428 shl eax, 5
- .text:0044B42B sub eax, ecx
- .text:0044B42D mov ecx, [esp+18h]
- .text:0044B431 and ecx, 0FFh
- .text:0044B437 lea edx, [eax+eax*2]
- .text:0044B43A lea eax, [ecx+ecx*4]
- .text:0044B43D shl eax, 3
- .text:0044B440 sub eax, ecx
- .text:0044B442 sub eax, edx
- .text:0044B444 cdq
- .text:0044B445 mov ecx, eax
- .text:0044B447 xor ecx, edx
- .text:0044B449 sub ecx, edx
- .text:0044B44B lea eax, [ecx+ecx*4]
- .text:0044B44E shl eax, 3
- .text:0044B451 sub eax, ecx
- .text:0044B453 mov ecx, 9
- .text:0044B458 cdq
- .text:0044B459 idiv ecx
- .text:0044B45B mov eax, dword ptr [esp+24h+Dest+3]
- .text:0044B45F and eax, 0FFh
- .text:0044B464 add dl, 30h
- .text:0044B467 mov byte ptr [esp+24h+var_10+3], dl
- .text:0044B46B lea edx, [eax+eax*2]
- .text:0044B46E shl edx, 4
- .text:0044B471 sub edx, eax
- .text:0044B473 mov eax, [esp+24h+var_10+1]
- .text:0044B477 and eax, 0FFh
- .text:0044B47C lea ecx, [eax+eax*8]
- .text:0044B47F lea eax, [eax+ecx*4]
- .text:0044B482 lea eax, [edx+eax*2]
- .text:0044B485 cdq
- .text:0044B486 xor eax, edx
- .text:0044B488 sub eax, edx
- .text:0044B48A lea ecx, [eax+eax*8]
- .text:0044B48D lea eax, [eax+ecx*4]
- .text:0044B490 mov ecx, 9
- .text:0044B495 shl eax, 1
- .text:0044B497 cdq
- .text:0044B498 idiv ecx
- .text:0044B49A mov ecx, dword ptr [esp+24h+Dest]
- .text:0044B49E and ecx, 0FFh
- .text:0044B4A4 lea eax, [ecx+ecx*2]
- .text:0044B4A7 lea eax, [eax+eax*8]
- .text:0044B4AA shl eax, 1
- .text:0044B4AC sub eax, ecx
- .text:0044B4AE add dl, 30h
- .text:0044B4B1 mov byte ptr [esp+24h+var_10], dl
- .text:0044B4B5 mov ecx, dword ptr [esp+24h+Dest+1]
- .text:0044B4B9 and ecx, 0FFh
- .text:0044B4BF lea edx, ds:0[ecx*8]
- .text:0044B4C6 sub edx, ecx
- .text:0044B4C8 lea edx, [edx+edx*4]
- .text:0044B4CB sub eax, edx
- .text:0044B4CD cdq
- .text:0044B4CE mov ecx, eax
- .text:0044B4D0 xor ecx, edx
- .text:0044B4D2 sub ecx, edx
- .text:0044B4D4 lea eax, [ecx+ecx*2]
- .text:0044B4D7 lea eax, [eax+eax*8]
- .text:0044B4DA shl eax, 1
- .text:0044B4DC sub eax, ecx
- .text:0044B4DE jmp loc_44B5D8
- .text:0044B4E3 ; -----------------------------------------
- ; Вторая ветка алгоритма
- .text:0044B4E3 loc_44B4E3:
- .text:0044B4E3 mov al, byte ptr [esp+24h+var_10+1]
- .text:0044B4E7 mov dl, byte ptr [esp+24h+var_10+2]
- .text:0044B4EB mov cl, byte ptr [esp+24h+var_10]
- .text:0044B4EF mov byte ptr [esp+24h+var_10+2], al
- .text:0044B4F3 mov al, [esp+24h+Dest+1]
- .text:0044B4F7 mov [esp+18h], dl
- .text:0044B4FB mov dl, [esp+24h+Dest+2]
- .text:0044B4FF mov [esp+24h+Dest+2], al
- .text:0044B503 mov eax, [esp+24h+var_10+2]
- .text:0044B507 mov byte ptr [esp+24h+var_10+1], cl
- .text:0044B50B and eax, 0FFh
- .text:0044B510 mov [esp+24h+Dest+3], dl
- .text:0044B514 mov ecx, eax
- .text:0044B516 shl ecx, 6
- .text:0044B519 sub ecx, eax
- .text:0044B51B mov eax, [esp+18h]
- .text:0044B51F and eax, 0FFh
- .text:0044B524 lea eax, [eax+eax*8]
- .text:0044B527 shl eax, 2
- .text:0044B52A sub eax, ecx
- .text:0044B52C mov ecx, 9
- .text:0044B531 cdq
- .text:0044B532 xor eax, edx
- .text:0044B534 sub eax, edx
- .text:0044B536 lea eax, [eax+eax*8]
- .text:0044B539 shl eax, 2
- .text:0044B53C cdq
- .text:0044B53D idiv ecx
- .text:0044B53F add dl, 30h
- .text:0044B542 mov byte ptr [esp+24h+var_10+3], dl
- .text:0044B546 mov eax, [esp+24h+var_10]
- .text:0044B54A and eax, 0FFh
- .text:0044B54F add eax, 20h
- .text:0044B552 lea edx, ds:0[eax*8]
- .text:0044B559 sub edx, eax
- .text:0044B55B lea eax, [eax+edx*4]
- .text:0044B55E lea ecx, [eax+eax*2]
- .text:0044B561 mov eax, dword ptr [esp+24h+Dest+3]
- .text:0044B565 and eax, 0FFh
- .text:0044B56A lea edx, [eax+eax*4]
- .text:0044B56D shl edx, 3
- .text:0044B570 sub edx, eax
- .text:0044B572 lea eax, [ecx+edx*2]
- .text:0044B575 cdq
- .text:0044B576 xor eax, edx
- .text:0044B578 sub eax, edx
- .text:0044B57A lea ecx, ds:0[eax*8]
- .text:0044B581 sub ecx, eax
- .text:0044B583 lea eax, [eax+ecx*4]
- .text:0044B586 mov ecx, 9
- .text:0044B58B lea eax, [eax+eax*2]
- .text:0044B58E cdq
- .text:0044B58F idiv ecx
- .text:0044B591 mov eax, dword ptr [esp+24h+Dest]
- .text:0044B595 and eax, 0FFh
- .text:0044B59A add dl, 30h
- .text:0044B59D mov byte ptr [esp+24h+var_10], dl
- .text:0044B5A1 lea edx, ds:0[eax*8]
- .text:0044B5A8 sub edx, eax
- .text:0044B5AA lea eax, [eax+edx*4]
- .text:0044B5AD mov edx, dword ptr [esp+24h+Dest+1]
- .text:0044B5B1 and edx, 0FFh
- .text:0044B5B7 mov ecx, edx
- .text:0044B5B9 shl ecx, 4
- .text:0044B5BC add ecx, edx
- .text:0044B5BE shl eax, 1
- .text:0044B5C0 lea ecx, [ecx+ecx*4]
- .text:0044B5C3 sub eax, ecx
- .text:0044B5C5 cdq
- .text:0044B5C6 xor eax, edx
- .text:0044B5C8 sub eax, edx
- .text:0044B5CA lea edx, ds:0[eax*8]
- .text:0044B5D1 sub edx, eax
- .text:0044B5D3 lea eax, [eax+edx*4]
- .text:0044B5D6 shl eax, 1
- .text:0044B5D8 loc_44B5D8:
- .text:0044B5D8 cdq
- .text:0044B5D9 mov ecx, 9
- .text:0044B5DE mov [esp+24h+var_B], 0
- .text:0044B5E3 idiv ecx
- .text:0044B5E5 add dl, 30h
- .text:0044B5E8 mov [esp+24h+Dest+1], dl
- .text:0044B5EC lea edx, [esp+24h+Dest]
- ; Преобразовать строку в десятичное число
- .text:0044B5F0 push edx ; Str
- .text:0044B5F1 call _atol
Валидной парой, например, будет регистрационное имя "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):
нанести вред индустрии - это как-то слишком круто, либо что-то случилось с душевным равновесием...
читал рассказик у Олега Дивова «Мы идем на Кюрасао»?
читал рассказик у Олега Дивова «Мы идем на Кюрасао»?

Добавить комментарий
Заполните форму для добавления комментария
