AppToService от Basta Computing - полезная программа, позволяющая запускать любые приложения как сервисы Windows. Но, как и большинство полезных программ, требует денег после испытательного срока. Будем это исправлять. Скачать пациента можно с офсайта, последняя версия на сегодняшний день 3.0. После установки запускаем программу, видим список параметров запуска и нехорошую строчку, предупреждающую, что надо бы заплатить.

Скриншот программы AppToService
Если посмотреть повнимательнее, то там же будет ключ командной строки для регистрации:
/Key:x Unlock AppToService.
Программа написана на C++ и ничем не упакована. Сперва попробуем найти строчку с ключом "Key:" и посмотреть как она обрабатывается. Строка в юникоде, поэтому символы разделены нулевым байтом. Участок кода, где идет обращение к этой строке, будет только один.
.text:00403074 mov edx, offset aKey ; "Key:"
.text:00403079 call sub_402BE0
.text:0040307E add esp, 4
.text:00403081 test eax, eax
; Если параметр в командной строке не равен "Key:", то перейти дальше
.text:00403083 jz short loc_4030E7
.text:00403085 or dword ptr [esp+10h], 2
.text:0040308A call sub_40A54B
.text:0040308F mov eax, [eax+4]
.text:00403092 lea ecx, [esp+46h]
.text:00403096 push ecx
.text:00403097 add eax, 0A4h
.text:0040309C push eax
; Вот это интересная функция, похоже тут проверяется валидность ключа, и
; в зависимости от результатов выполняется прыжок на выход или сообщение об
; успешной регистрации программы
.text:0040309D call sub_4017B0
.text:004030A2 test eax, eax
.text:004030A4 jz loc_403B0D
.text:004030AA call sub_40A54B
.text:004030AF mov eax, [eax+4]
; Установить флажок зарегистрированности
.text:004030B2 mov dword ptr [eax+0C0h], 1
.text:004030BC call sub_40A54B
.text:004030C1 mov eax, [eax+4]
.text:004030C4 lea ecx, [eax+0CCh]
.text:004030CA call sub_402590
; Вывести на экран сообщение об удачной регистрации
.text:004030CF push offset aOk ; "OK\n"
.text:004030D4 mov dword_4402AC, ebx
.text:004030DA call sub_413BCB
.text:004030DF add esp, 4
; И потом пойти куда-то дальше, это нам уже не очень интересно
.text:004030E2 jmp loc_403A95
Посмотрим функцию проверки валидности ключа поподробнее. Кроме всего прочего в ней обнаруживается такой вот интересный кусочек кода:
.text:004019CD sar eax, 1
.text:004019CF lea ecx, [eax+eax+2]
.text:004019D3 push ecx ; cbData
.text:004019D4 push edi ; lpData
.text:004019D5 push 1 ; dwType
.text:004019D7 push 0 ; Reserved
.text:004019D9 push offset aReserved2 ; "Reserved2"
.text:004019DE push esi ; hKey
.text:004019DF call ds:RegSetValueExW
.text:004019E5 push esi ; hKey
.text:004019E6 mov edi, eax
.text:004019E8 call ds:RegCloseKey
.text:004019EE push edi ; dwErrCode
.text:004019EF call ds:SetLastError
То есть устанавливается ключ в реестре, в который записываются данные регистрации. Под отладчиком можно убедиться, что это так и есть, причем запишется только правильный серийный номер. Что ж, раз ключ записывается, значит он должен где-то потом читаться. Находим еще один код, в котором идет обращение к ключу "Reserved2".
.text:004013AE xor eax, esp
.text:004013B0 push eax
.text:004013B1 lea eax, [esp+54h+var_C]
.text:004013B5 mov large fs:0, eax
.text:004013BB mov eax, offset aReserved2 ; "Reserved2"
.text:004013C0 lea esi, [esp+54h+var_48]
.text:004013C4 mov ecx, edi
; Где-то тут читается значение ключа из реестра
.text:004013C6 call sub_401000
.text:004013CB xor ebx, ebx
.text:004013CD mov [esp+54h+var_4], ebx
.text:004013D1 call loc_401160
.text:004013D6 lea eax, [esp+54h+Data]
.text:004013DA push eax
.text:004013DB mov eax, [esp+58h+var_48]
.text:004013DF mov dword ptr [esp+58h+Data], ebx
; Тут вызывается проверка валидности ключа
.text:004013E3 call sub_4074F0
.text:004013E8 add esp, 4
.text:004013EB test eax, eax
; Если проверка не пройдена, то переход
.text:004013ED jz short loc_4013FA
; Тут какая-то дополнительная проверка данных из ключа
.text:004013EF xor eax, eax
.text:004013F1 cmp dword ptr [esp+54h+Data], ebx
; Регистр AL устанавливается в зависимости от результатов проверки.
; 0 - все плохо, 1 - программа зарегистрирована
.text:004013F5 setnl al
.text:004013F8 jmp short loc_4013FC
.text:004013FA loc_4013FA:
; Сюда мы попадаем, если ключ регистрации не найден или он неправильный
.text:004013FA xor eax, eax
.text:004013FC loc_4013FC:
.text:004013FC cmp eax, ebx
; Сохранить куда-то в память флажок "зарегистрировано"
.text:004013FE mov [edi+1Ch], eax
; Переход, если программа не зарегистрирована
.text:00401401 jz short loc_401424
.text:00401403 mov [esp+54h+var_4], 0FFFFFFFFh
.text:0040140B mov eax, [esp+54h+var_48]
.text:0040140F add eax, 0FFFFFFF0h
.text:00401412 lea ecx, [eax+0Ch]
.text:00401415 or edx, 0FFFFFFFFh
.text:00401418 lock xadd [ecx], edx
.text:0040141C dec edx
.text:0040141D test edx, edx
.text:0040141F jmp loc_401589
.text:00401424 loc_401424:
; Программа не зарегистрирована, вычисляется триальный срок и записывается
; в другой ключ реестра - "Reserved0"
.text:00401424 push ebx ; Time
.text:00401425 call __time64
.text:0040142A add esp, 4
.text:0040142D push ebx ; dwDisposition
.text:0040142E mov ebx, edi
.text:00401430 mov [esp+58h+var_3C], eax
.text:00401434 mov [esp+58h+var_38], edx
.text:00401438 call sub_406700
.text:0040143D mov esi, eax
.text:0040143F test esi, esi
.text:00401441 jz short loc_40147A
.text:00401443 push 0 ; lpcbData
.text:00401445 push 0 ; lpData
.text:00401447 push 0 ; lpType
.text:00401449 push 0 ; lpReserved
.text:0040144B push offset aReserved0 ; "Reserved0"
.text:00401450 push esi ; hKey
.text:00401451 call ds:RegQueryValueExW
.text:00401457 push esi ; hKey
.text:00401458 mov ebx, eax
.text:0040145A call ds:RegCloseKey
.text:00401460 push ebx ; dwErrCode
Алгоритм проверки теперь понятен. Заодно выяснили ключ, в котором хранится триальный срок. Если его периодически стирать из реестра, то программа будет работать свои 30 дней вечно. Но мы пойдем другим путем, мы просто пропатчим саму проверку. Удобнее всего патч сделать на этом участке кода:
.text:004013EB test eax, eax
; Заменить JZ на JMP, теперь переход будет выполняться в любом случае
.text:004013ED jz short loc_4013FA ; <-- JMP
.text:004013EF xor eax, eax
.text:004013F1 cmp dword ptr [esp+54h+Data], ebx
.text:004013F5 setnl al
.text:004013F8 jmp short loc_4013FC
.text:004013FA loc_4013FA:
; Сюда будет выполняться переход после патча. В регистре EAX должно быть
; ненулевое значение, тогда программа будет считать, что она зарегистрирована.
; Размер команды XOR EAX,EAX равен 2 байта, проще всего заменить ее на MOV AL,1
.text:004013FA xor eax, eax ; <-- MOV AL,1
Вносим изменения в файл, проверяем. Нехорошая надпись пропала. Для чистоты эксперимента переводим часы на год вперед - все работает как надо.

Программа успешно "зарегистрирована"
Очередной гвоздь в гроб капитализма забит, теперь программа будет работать без всяких ограничений по времени. А на сэкономленные деньги покупаем букет любимой девушке :)