Сегодня мы будум регистрировать хорошо
известную всем почтовую программу TheBat
версии 2.00.6.

Инструменты, которыми мы будем
пользоваться:

Начнем. Для начала посмотрим чем
запакован главный файл программы "thebat.exe",
а еже ли не запакован, то на чем написан.
Сделаем это с помощью того же PEID, загрузим в
PEID "thebat.exe" и в меню программы выберем
"hardcore scan", увидим следующее: "Borland Delphi
6.0 — 7.0". Значит файл все же не запакован и
написан на delphi, скорее всего седьмой версии.

До версии 2.xx Бат защищался с помощью asprotect,
теперь, очевидно, авторы решили не тратить
зря денег и попробовать защитить его самим.
Вероятно это связано с существенным
подорожанием asprotect на рынке защит.

Что ж посмотрим, что получилось у авторов. Т.к.
это делфи приложение, исследовать будем с
помощью DEDE. Запустим DEDE откроем в нем файл
"thebat.exe" и нажмем кнопку "process",
после выполнения этого процесса нам
предложат провести дополнительный анализ
для нахождения нераспознанных процедур,
согласимся с этим  и немного подождем.
После того как DEDE завершит анализ, перейдем
во вкладку "Procedures", там присутствует
много форм, нам же нужна форма ввода
регистрационной информации. Выберем по
имени класса "TRegInputForm" и посмотрим ее
события:

FormCloseQuery 006A0D5C 0015 ; нам
нужно это событие

FormClose 006A0FD0 0010
bOKClick 006A1048 000F
bCencelClick 006A107C 0013
FormCreate 006A10B0 0011
_PROC_006A0E6C 006A0E6C FFFF
_PROC_006A0E6C 006A10D0 FFFF
_PROC_006A0E6C 006A1100 FFFF
_PROC_006A0E6C 006A1108 FFFF
_PROC_006A0E6C 006A117E FFFF

Дизассемблируем событие "FormCloseQuery",
щелкаем по нему правой клавишей мыши и
выбираем "disassemble". Теперь смотрим, что в
там происходит:

006A0D5C 55 push ebp
006A0D5D 8BEC mov ebp, esp
…вырезано…
006A0D79 55 push ebp
006A0D7A 68600E6A00 push $006A0E60

***** TRY
|
006A0D7F 64FF30 push dword ptr fs:[eax]
006A0D82 648920 mov fs:[eax], esp
006A0D85 8B45FC mov eax, [ebp-$04]

* Reference to field TRegInputForm.ModalResult : TModalResult
|
006A0D88 83B84C02000001 cmp dword ptr [eax+$024C], +$01
006A0D8F 0F85B0000000 jnz 006A0E45
006A0D95 8D45B4 lea eax, [ebp-$4C]
006A0D98 50 push eax ; помещаем eax в стек
006A0D99 8D55B0 lea edx, [ebp-$50]
006A0D9C 8B45FC mov eax, [ebp-$04]

* Reference to control TRegInputForm.lPwd : TEdit
|
006A0D9F 8B80FC020000 mov eax, [eax+$02FC] ;


|
006A0DA5 E8EA22E5FF call 004F3094 ;
получает
текст из поля "password", это поле имеет
атрибут visible=off, поэтому мы его не видим,
теперь это строка константа = "bat2"

006A0DAA 8B45B0 mov eax, [ebp-$50] ;
помещается
по адресу eax

006A0DAD 50 push eax ;
помещаем
eax в стек

006A0DAE 8D55AC lea edx, [ebp-$54]
006A0DB1 8B45FC mov eax, [ebp-$04]

* Reference to control TRegInputForm.lSum : TEdit
|
006A0DB4 8B8014030000 mov eax, [eax+$0314] ;

|
006A0DBA E8D522E5FF call 004F3094 ;
получает
текст из поля "Key Checksum"

006A0DBF 8B45AC mov eax, [ebp-$54] ;
помещается
по адресу eax

006A0DC2 50 push eax ;
помещаем
eax в стек

006A0DC3 8D55A8 lea edx, [ebp-$58]
006A0DC6 8B45FC mov eax, [ebp-$04]

* Reference to control TRegInputForm.lKey : TEdit
|
006A0DC9 8B80F8020000 mov eax, [eax+$02F8] ;

|
006A0DCF E8C022E5FF call 004F3094 ;
получает
текст из поля "The Bat! Key"

006A0DD4 8B45A8 mov eax, [ebp-$58] ;
помещается
по адресу eax

006A0DD7 5A pop edx
006A0DD8 59 pop ecx

|
006A0DD9 E81EF8E7FF call 005205FC
006A0DDE 8B45FC mov eax, [ebp-$04]

* Reference to field TRegInputForm.OFFS_0365
|
006A0DE1 8D9065030000 lea edx, [eax+$0365]
006A0DE7 8D45B4 lea eax, [ebp-$4C]
006A0DEA B940000000 mov ecx, $00000040

* Reference to: System.Move(void;void;void;void;Integer);
|
006A0DEF E8101DD6FF call 00402B04 ; System.Move(void;void;void;void;Integer);
006A0DF4 8B45FC mov eax, [ebp-$04]

* Reference to field TRegInputForm.OFFS_031D
|
006A0DF7 8D901D030000 lea edx, [eax+$031D]
006A0DFD 8D45B4 lea eax, [ebp-$4C]

|
006A0E00 E83FE2E7FF call 0051F044 ;
это
важная нам процедура, отметим ее, здесь
собственно и проверяется регистрационная
информация 

006A0E05 8B55FC mov edx, [ebp-$04] ;

* Reference to field TRegInputForm.OFFS_0360
|
006A0E08 898260030000 mov [edx+$0360], eax
006A0E0E 8B45FC mov eax, [ebp-$04]

* Reference to field TRegInputForm.OFFS_0360
|
006A0E11 81B860030000B8F00000 cmp dword ptr [eax+$0360], $0000F0B8 ;
проверка,
равно ли значение по [eax+$0360], $0000F0B8? 

006A0E1B 7428 jz 006A0E45 ;
если
значения равны, прыгает на адрес 006A0E45, иначе
продолжает 

006A0E1D 8B45FC mov eax, [ebp-$04]

|
006A0E20 E873B0E5FF call 004FBE98 ;
сообщение,
о неверной регистрационной информации

006A0E25 8BD0 mov edx, eax

* Reference to pointer to GlobalVar_0086384C
|
006A0E27 A140248600 mov eax, dword ptr [$00862440]

* Reference to field GlobalVar_0086384C.OFFS_00C4
|
006A0E2C 8B80C4000000 mov eax, [eax+$00C4]

* Reference to: TeeLisB.TChartListBox.SetShowActive(TChartListBox;Boolean);
|
006A0E32 E8AD30E0FF call 004A3EE4 ;

здесь выводится сообщение, о неверной
регистрационной информации

006A0E37 8B45FC mov eax, [ebp-$04]

* Reference to : TApplication._PROC_00517B60()
|
006A0E3A E8216DE7FF call 00517B60
006A0E3F 8B45F8 mov eax, [ebp-$08]
006A0E42 C60000 mov byte ptr [eax], $00
006A0E45 33C0 xor eax, eax ; <- прыжок с 006A0E1B
006A0E47 5A pop edx
006A0E48 59 pop ecx
006A0E49 59 pop ecx
006A0E4A 648910 mov fs:[eax], edx

****** FINALLY
|
006A0E4D 68670E6A00 push $006A0E67с ;
помещается
в стек, адрес возврата

006A0E52 8D45A8 lea eax, [ebp-$58]
006A0E55 BA03000000 mov edx, $00000003 ;
помещается
в edx, 3

* Reference to: System.@LStrArrayClr(void;void;Integer);
|
006A0E5A E81140D6FF call 00404E70
006A0E5F C3 ret ;
возвращается
на 006A0E67

* Reference to: System.@HandleFinally;
|
006A0E60 E96B39D6FF jmp 004047D0
006A0E65 EBEB jmp 006A0E52

****** END
|
006A0E67 5B pop ebx ; <- 006A0E67
006A0E68 8BE5 mov esp, ebp
006A0E6A 5D pop ebp
006A0E6B C3 ret

Теперь зайдем в отмеченную нами процедуру
по адресу 0051F044, где проверяется
регистрационная информация.

0051F044 55 push ebp
0051F045 8BEC mov ebp, esp
0051F047 83C4A8 add esp, -$58
0051F04A 8955F8 mov [ebp-$08], edx
0051F04D 8945FC mov [ebp-$04], eax
0051F050 33C0 xor eax, eax ;
очищается
eax

0051F052 8945F4 mov [ebp-$0C], eax
0051F055 8D55A8 lea edx, [ebp-$58]
0051F058 8B45FC mov eax, [ebp-$04]
0051F05B B940000000 mov ecx, $00000040 ;
помещается
в ecx 40h = 64 dec

* Reference to: System.Move(void;void;void;void;Integer);
|
0051F060 E89F3AEEFF call 00402B04 ; System.Move(void;void;void;void;Integer);
0051F065 8D45A8 lea eax, [ebp-$58]
0051F068 E86BFFFFFF call 0051EFD8
0051F06D 8D45A8 lea eax, [ebp-$58]
0051F070 E833FFFFFF call 0051EFA8
0051F075 66C745F2FFFF mov word ptr [ebp-$0E], $FFFF
0051F07B 8D45A8 lea eax, [ebp-$58]
0051F07E 8945EC mov [ebp-$14], eax
0051F081 33C0 xor eax, eax ;
очищается
eax

0051F083 8945E8 mov [ebp-$18], eax
;
начало цикла
0051F086 8B45EC mov eax, [ebp-$14]
0051F089 8B55E8 mov edx, [ebp-$18]
0051F08C 8A0410 mov al, byte ptr [eax+edx]
0051F08F 668B55F2 mov dx, word ptr [ebp-$0E]

* Reference to : TASN1Primitive._PROC_004484DC()
|
0051F093 E84494F2FF call 004484DC
0051F098 668945F2 mov [ebp-$0E], ax
0051F09C FF45E8 inc dword ptr [ebp-$18]
0051F09F 837DE840 cmp dword ptr [ebp-$18], +$40
0051F0A3 75E1 jnz 0051F086 ;
цикл
проверки, после чего значение по [ebp-$0E]
должно быть F0B8 hex

;
конец цикла
0051F0A5 66817DF2B8F0 cmp word ptr [ebp-$0E], $F0B8 ;
если
значения равны — продолжает иначе прыгает
на 005205F2,

0051F0AB 0F8541150000 jnz 005205F2 ;
где
выходит из процедуры и выводит сообщение о
некорректной регистрации

0051F0B1 8B45A8 mov eax, [ebp-$58]
0051F0B4 3D03459C00 cmp eax, $009C4503
0051F0B9 0F8FB70A0000 jnle 0051FB76
0051F0BF 0F8405150000 jz 005205CA
0051F0C5 3DF481CEC2 cmp eax, $C2CE81F4 ;

сравнивает eax с C2CE81F4 hex 

0051F0CA 0F8F57050000 jnle 0051F627
0051F0D0 0F84F4140000 jz 005205CA
0051F0D6 3D98DD60A1 cmp eax, $A160DD98 ;
сравнивает
eax с A160DD98 hex 

0051F0DB 0F8FA6020000 jnle 0051F387
0051F0E1 0F84E3140000 jz 005205CA
0051F0E7 3D396C0092 cmp eax, $92006C39 ;
сравнивает
eax с 92006C39 hex 

0051F0EC 0F8F53010000 jnle 0051F245
0051F0F2 0F84D2140000 jz 005205CA
0051F0F8 3D268EEC8A cmp eax, $8AEC8E26 ;
сравнивает
eax с $AEC8E26 hex 

0051F0FD 0F8FA4000000 jnle 0051F1A7
…вырезано…
0052057F 7F12 jnle 00520593
00520581 7447 jz 005205CA
00520583 2D972F347B sub eax, $7B342F97 ;

вычитается из eax 7B342F97 hex

Не будем вникать в смысл этих проверок, а
просто пропатчим процедуру таким образом,
чтобы по [ebp-$0E] всегда было F0B8 hex и затем
происходил прыжок на адрес 005205D2, что
происходит в случае нормальной регистрации.

00520588 7440 jz 005205CA
0052058A 2D45659000 sub eax, $00906545 ;
вычитается
из eax 00906545 hex

0052058F 7439 jz 005205CA
00520591 EB3F jmp 005205D2
00520593 2DE4C27D7C sub eax, $7C7DC2E4 ;
вычитается
из eax 7C7DC2E4 hex

00520598 7430 jz 005205CA
0052059A 2DCBF5AE00 sub eax, $00AEF5CB ;
вычитается
из eax 00AEF5CB hex

0052059F 7429 jz 005205CA
005205A1 EB2F jmp 005205D2
005205A3 3D7E11C07E cmp eax, $7EC0117E ;
сравнивает
eax с 7EC0117E hex 

005205A8 7F12 jnle 005205BC
005205AA 741E jz 005205CA
005205AC 2DEACC947D sub eax, $7D94CCEA ;
вычитается
из eax 7D94CCEA hex

005205B1 7417 jz 005205CA
005205B3 2D7AE40D00 sub eax, $000DE47A ;
вычитается
из eax 000DE47A hex

005205B8 7410 jz 005205CA
005205BA EB16 jmp 005205D2
005205BC 2D0CB0767F sub eax, $7F76B00C ;
вычитается
из eax 7F76B00C hex

005205C1 7407 jz 005205CA
005205C3 2D62AD3600 sub eax, $0036AD62 ;
вычитается
из eax 0036AD62 hex

005205C8 7508 jnz 005205D2
005205CA 8B45A8 mov eax, [ebp-$58] ;
в
eax помещается значение по адресу [ebp-$58]

005205CD 8945F4 mov [ebp-$0C], eax
005205D0 EB20 jmp 005205F2 ;
005205D2 8B55F8 mov edx, [ebp-$08]
005205D5 8D45A8 lea eax, [ebp-$58]
005205D8 B940000000 mov ecx, $00000040

* Reference to: System.Move(void;void;void;void;Integer);
|
005205DD E82225EEFF call 00402B04 ; System.Move(void;void;void;void;Integer);
005205E2 0FB745F2 movzx eax, word ptr [ebp-$0E]
005205E6 8B55F8 mov edx, [ebp-$08]
005205E9 0FB75209 movzx edx, word ptr [edx+$09]
005205ED 2BC2 sub eax, edx
005205EF 8945F4 mov [ebp-$0C], eax
005205F2 8B45F4 mov eax, [ebp-$0C]
005205F5 8BE5 mov esp, ebp
005205F7 5D pop ebp
005205F8 C3 ret

Т.о. эта процедура проверки правильности
регистрационной информации и вызывается
она всякий раз, когда нужно проверить эти
данные. Вызовем SoftIce, введем "addr thebat" и
поставим точку останова на начало
процедуры проверки 0051F044, для этого введем
"bpx 0051F044". Теперь отпустим SoftIce и
закроем TheBat. Запустим программу и окажемся
в отладчике в начале той самой  процедуры.
Теперь по F10 протрассируем код до адреса
0051FA5, или же поставим не него точку останова
"bpx 0051F0A5" и отпустим SoftIce, в любом случае
мы будем находится по адресу 0051F0A5, где
происходит сравнение значения по адресу
[ebp-$0E] с константой F0B8 hex. Запишем по [ebp-$0E] F0B8
hex, для этого введем в SoftIce команду "e
ebp-0E" и запишем B8F0 (в обратной
последовательности). Теперь введем "e
ebp-58+9" и запишем туда два нуля, т.к. в конце
процедуры от нужного нам числа F0B8 hex,
отнимается значение по адресу "ebp-58+9" и
если оно не равно нулю, число изменится, нам
же надо сохранить это значение по выходу из
процедуры.

005205E9 0FB75209 movzx edx, word ptr [edx+$09]
005205ED 2BC2 sub eax, edx ; F0B8 — 0 = F0B8

После этого отпускаем SoftIce и даем программе
запуститься. При этом пресловутое окно
отсчета времени пользования программой, не
появилось. Смотрим в окно "О программе",
надпись "UNREGISTERED EVALUATION COPY" исчезла,
вместо нее красуется "REGISTERED TO" и
беспорядочный набор символов вместо нашего
имени. Чтобы там стояло наше имя, нам надо
записать его по адресу после "ebp-58+9",
где мы вписывали два нуля. 

Теперь пропатчим thebat.exe, сделаем это с
помощью hex-редактора hiew. Запустим hiew,
откроем thebat.exe, нажмем F4 и выберем режим
дизассемблера, теперь перейдем по адресу
51f0a5, для этого нажмем F5 и введем этот адрес.
Нажмем F3, затем F2 и введем:

mov w, [ebp] [-0E], 0F0B8
lea eax, [ebp] [-58] [+9]
mov w, [eax], 0000
mov w, [eax+2], 31323300
jmp 11F9D2

31323300 — это опкод 123, на кого будет
зарегистрирована программа, можете
изменить это на ваше имя.

Вот собственно и все, теперь приведу,
произведенные в файле изменения:

0011E4A6: 81 C7
0011E4A7: 7D 45
0011E4AB: 0F 8D
0011E4AC: 85 45
0011E4AD: 41 B1
0011E4AE: 15 66
0011E4AF: 00 C7
0011E4B1: 8B 00
0011E4B2: 45 00
0011E4B3: A8 C7
0011E4B4: 3D 40
0011E4B5: 03 02
0011E4B6: 45 31
0011E4B7: 9C 32
0011E4B8: 00 33
0011E4B9: 0F 00
0011E4BA: 8F E9
0011E4BB: B7 13
0011E4BC: 0A 15

В процессе работы с программой нашел еще
одну серьезную недоработку, связанную с
защитой программы, с помощью которой любой
ничего не смыслящий в кракинге человек
может с легкость продолжить пользоваться
Батом после завершения пробного периода, не
переводя часы назад и ничего не меняя в
системных файлах. Как известно, после
завершения пробного периода программа
показывает соответствующее окно с тремя
кнопками: "OK", "EXIT" и "How To Buy",.
Если в одном из наших соединений стоит
опция "автоматически при старте
проверять почту" после нажатии кнопки
"EXIT" программа не выйдет, а предложит
завершить начатый сеанс связи, на что мы
ответим отказом, после чего поставим на
любом из представленных в списке
соединений опцию "Keep This Task". Теперь
сеанс связи будет всегда активен и
программа не завершит работу, а
следовательно мы снова сможем продолжать
ей пользоваться. 

Для нас это, конечно, не суть важно, скорее
это будет полезно самим разработчикам.

ЗЫ: Все написано единственно в учебных
целях, а не абы как…

Оставить мнение

Check Also

Windows 10 против шифровальщиков. Как устроена защита в обновленной Windows 10

Этой осенью Windows 10 обновилась до версии 1709 с кодовым названием Fall Creators Update …