RCE.SU - реверсинг, кодинг, выделенные сервера, ICQ, proxy

TeleCount 4.00.02: Part 1. Evaluation key.

[Исследование]

Subject: Reversing.
Target: TeleCount 4.00.02.
URL:www.telecount.com.
Author: aSL!
Date: 04.08.2001

Before starting!
Все ниже изложенное предназначено только для образовательных целей.

I. Вступление

Здравствуйте мои маленькие любители прекрасного! :)

Сегодня я представлю две статьи про одну и ту же программу на пример того, как НЕ надо делать защиты :) Причем защита будет ПОЛНОСТЬЮ реверсирована.

II. Постановка задачи
  1. Необходимо зарегистрировать TeleCount 4.00.02
III. Исследование

Необходимые инструменты:

  1. W32Dasm 8.9x
  2. TRW 1.2x
  3. HIEW 6.x
  4. Delphi 4.0

Итак, приступим...

После недолгого осмотра мы приходим к выводу, что:

  1. Программа написана с использованием CA-Visual Objects (Что усложняет задачу, но не очень)
  2. Используется для каких-то целей библиотека халявнух функций FUNCky 6.0
  3. TC.EXE используется как wrapper для запуска _tc.exe

Итак, запускаем. И что же мы видим??? "License wizard". Хмм.. Интересно. А затем - "Please enter your evaluation key...". Ну что же... Ключа у меня нет, на мой запрос компания не ответила. Будем ломать...

Нетрудно догадаться, что все функции защиты выполняет tcsecure.dll. Нам же лучше. Ищем, где она вызывается... Я нашел вот такой код:

* Possible StringData Ref from Data Obj ->"TCSECURE.DLL"
|
 
:0044812A B8EC7B4900
:0044812F 50
:00448130 B8A0020000
:00448135 50
mov eax, 00497BEC
push eax
mov eax, 000002A0
push eax
* Reference To: ISARUN.PrepCreateInstance, Ord:0000h
|
 
:00448136 E8CD250400
:0044813B 0BC0
:0044813D 0F851B000000
Call 0048A708
or eax, eax
jne 0044815E

И чуть дальше, уже после джампа:

* Reference To: CAVORT20.Send, Ord:023Eh
|
 
:004481D0 E86B1E0400
:004481D5 81C408000000
Call 0048A040
add esp, 00000008
* Reference To: CAVORT20._P2Logic, Ord:03EFh
|
 
:004481DB E8581E0400
:004481E0 0BC0
:004481E2 7505
:004481E4 E91B000000
Call 0048A038
or eax, eax
jne 004481E9
jmp 00448204

После вызова Send() мы вываливаемся аккурат в tcsecure.dll в License:PerformLicenseVerification. Хмм... Оччень интересные у них экспорты :))) Особенность CA-Visual Objects, однако...

Итак, смотрим tcsecure.dll. Вспоминаем, что мы видели при попытке ввести Evaluation Key. "Invalid Evaluation Key!". Ищем в String Reference'ах. Нашли? А теперь смотрим чуть выше:

:010316B9 FF5354
:010316BC 0BC0
:010316BE 0F8538000000
call [ebx+54]
or eax, eax
jne 010316FC
* Reference To: CAVORT20.uiLineNum_RT, Ord:0561h
|
 
:010316C4 8B1DF8760D01
:010316CA C70324000000
mov ebx, dword ptr [010D76F8]
mov dword ptr [ebx], 00000024
* Possible StringData Ref from Data Obj ->"Invalid evaluation license key."

Патчим or eax,eax \ jne 010316FC на mov al,1 \ jmp 010316FC.
Дальше... "The evaluation license key is invalid". Ищем...

:01021011 FF5354
:01021014 0BC0
:01021016 0F8556010000
call [ebx+54]
or eax, eax
jne 01021172

Патч аналогичен.
Запускаем... И что же? Expired... Почему? Объясню позже. А сейчас достаточно пропатчить все это дело...

:01031BE7 8B4618
:01031BEA 0BC0
:01031BEC 7505
:01031BEE E91C020000
mov eax, dword ptr [esi+18]
or eax, eax
jne 01031BF3
jmp 01031E0F

Меняем or eax,eax \ jne 01031BF3 на xor eax,eax \ nop \ nop. Хмм... Не помогает. Ага. Это переход если у нас версия с ключом. Ну что же... Смотрим выше...

Следует отметить, что у этой версии есть Debug, и отладочные строки то и дело проглядываю (заметно облегчая слом). Итак смотрим чуть выше... Что это?

* Reference To: CAVORT20.Today, Ord:0298h
|
 
:01031B2A E8F90D0700
:01031B2F 8945DC
:01031B32 8B7508
:01031B35 8B4610
:01031B38 2B45DC
:01031B3B 7105
Call 010A2928
mov dword ptr [ebp-24], eax
mov esi, dword ptr [ebp+08]
mov eax, dword ptr [esi+10]
sub eax, dword ptr [ebp-24]
jno 01031B42

Очевидно, что это получение текущей даты. После джампа идет какой-то блок выбора. Очевидно, он и выполняет вычисление expiration date. Ну что же. Посмотрим на "комментарий" (Ну вы поняли, про что это я). - "We appear...". Понятно как патчить? Поясняю:

:01031B42 3DB9000000
:01031B47 7E05
:01031B49 E90A000000
cmp eax, 000000B9
jle 01031B4E
jmp 01031B58
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:01031B47(C)
|
:01031B4E B801000000
:01031B53 E905000000
mov eax, 00000001
jmp 01031B5D
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:01031B49(U)
|
:01031B58 B800000000 mov eax, 00000000
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:01031B53(U)
|
:01031B5D 0BC0
:01031B5F 7505
:01031B61 E966000000
or eax, eax
jne 01031B66
jmp 01031BCC

Нам надо, чтобы сработал переход на 01031B66, А для этого необходим ненулевой eax. Как это получить? Нужно, чтобы сработал jmp по адресу 01031B53, а для этого, очевидно, надо, чтобы сработал jmp по адресу. 01031B47. Патчим его - 7E на EB.

Все! Запустилось! Посмотрим в About...
Evaluation expires 13.09.2093
Unlimited Voice Ports
1,691,250,000 Voice Minutes
33,825 Billing Customers
(Я вводил номер из всех 1). Это не есть хорошо. Очевидно, что наш номер каким-то образом повлиял на вводимые ограничения. Теперь предстоит поискать, где записывается наша информация о том, что мы ввели. Поиск в реестре не дал должных результатов. В .ini тоже. Я пригляделся... И что же? В каталоге с TeleCount'ом появился новый файл - tc.spv. Я его удалил и снова появилось - "Evaluation...". Да, кстати, TeleCount делает его backup в катологе с форточками под именем vtspvftc.sys. Это так.. Удалять надо обоих.

Итак, теперь нам надо реверсировать защиту keyfile'а. Ищем его в referenca'х. Нашли? Хорошо. Два раза? Еще лучше... Это очевидно. Нам надо его не только считывать, но и создавать в первый раз. Легко догадаться, что нам нужен тот, что по адресу 102E4DE. Скроллируем вниз, читаем комментарии. Что же это?:

* Reference To: TCSECURE.StrDecompress
:
0102E668 E8CF0E0000
:0102E66D 81C404000000
:0102E673 8945F8
|
call 0102F53C
add esp, 00000004
mov dword ptr [ebp-08], eax
* Reference To: CAVORT20.uiLineNum_RT, Ord:0561h

:0102E676 8B1DF8760D01
:0102E67C C7031D000000
|
mov ebx, dword ptr [010D76F8]
mov dword ptr [ebx], 0000001D
* Possible StringData Ref from Data Obj ->"TeleCountSecurityLicenseProfile"
:
0102E682 B810D70A01
:0102E687 50
:0102E688 8B45F8
:0102E68B 50
|
mov eax, 010AD710
push eax
mov eax, dword ptr [ebp-08]
push eax
* Reference To: TCSECURE.Decrypt

:0102E68C E8730F0000
:0102E691 81C408000000
:0102E697 8945F8
|
call 0102F604
add esp, 00000008
mov dword ptr [ebp-08], eax

Запускаем TRW. Непосредственно убеждаемся, что на вход StrDecompress подается содержимое нашего tc.spv, А ее выход подается на Decrypt, а "TeleCountSecurityLicenseProfile", очевидно, ключ. После Decrypt смотрим на выход.... Ого! Какие-то парметры, да еще и текстовые. Интересно... Залазим в StrDecompress...

Мда... Оказывается, используется функция MemDecompress из FUNCky 6. Для особо любопытных скажу, что там используется inflate by Mark Adler, etc. Зачем вызывается два раза? Первый раз из запакованных данных вытаскивается длина их после распаковки, затем уже выделяется память и распаковывается. Опять запускаем TRW, чтобы выяснить параметры вызова.
Итак:

  1. Параметры первого вызова:
    Первый - исходные данные, второй - их длина. Третий и четвертый - 0. Пятый - адрес памяти, куда записать распакованную длину.
    Выход: по адресу, указанному в пятом параметре возвращается длина.
  2. Параметры второго вызова:
    Первый - исходные данные, второй - их длина. Третий - адрес буфера, куда поместить распакованные данные, Четвертый - длина распакованных данных (результат после первого вызова). Пятый - адрес, куда записать, сколько байт распаковано.

Все! Можно напрямую вызывать функцию MemDecompress из FUNCky60.dll. Теперь залазим в Decrypt... Опять вызывается функция из FUNCky 6 -- _decrypt. Читаем документацию... И что же? Оказывается это простой побайтный xor, только у каждого байта ключа предварительно включается старший бит. Все!

Теперь рассмотрим тот вызов, где создается tc.spv. Аналогично с точностью до наоборот: MemCompress и _encrypt из FUNCky 6. Про _encrypt мы уже все знаем - xor - он и в Африке xor, при исследовании при помощи TRW параметров функции MemCompress выяснилось следующее:
Первый - адрес памяти, "что упаковывать", второй - длина, третий - буфер, куда складывать сжатую информация, четвертый - 0x138h (Хоть убейте, не знаю зачем), пятый - буфер, куда записывается кол-во байт после упаковки. И все! Я написал маленькую программку на Делфях, показывающую полный процес записи\восстановления tc.spv: (Сорри за отсутствие форматирования, имхо, и так понятно).

program test;
Uses SysUtils,WIndows;
{$APPTYPE CONSOLE}

var
f,f1,f2:file of byte;
i:integer;
b,b1:byte;
len:dword;
p,p1,p2:pointer;
pass:string='TeleCountSecurityLicenseProfile';

procedure FDecompress (adr1,adr2,adr3,adr4,adr5:DWORD);stdcall;external 'funcky60.dll' name 'MemDecompress';
procedure FCompress (adr1,adr2,adr3,adr4,adr5:DWORD);stdcall;external 'funcky60.dll' name 'MemCompress';

begin
for i:=1 to length(pass) do pass[i]:=chr(ord(pass[i]) or $80);
if paramstr(1)='-in' then begin
AssignFile(f,'tc.spv');
AssignFile(f1,'tc.in.spv');
ReWrite(f1);
ReSet(f);
GetMem(p,FileSize(f));
GetMem(p1,FileSize(f));
GetMem(p2,FileSize(f));
BlockRead(f,p^,FileSize(f));
FDecompress(DWORD(p),FileSize(f),0,0,DWORD(p2));
len:=DWORD(p2^);
FDecompress(DWORD(p),FileSize(f),DWORD(p2),len,DWORD(p1));
for i:=1 to len do begin
b:=Byte(pointer(Integer(p2)+i-1)^);
b1:=i mod 31;
if b1=0 then b1:=31;
b:=b xor ord(pass[b1]);
Byte(pointer(Integer(p2)+i-1)^):=b;
end;
BlockWrite(f1,p2^,len);
CloseFile(f);
CloseFile(f1);
end
else if paramstr(1)='-out' then begin
AssignFile(f1,'tc.in.spv');
AssignFile(f2,'tc.out.spv');
ReSet(f1);
ReWrite(f2);
GetMem(p,FileSize(f1)+1024);
GetMem(p1,FileSize(f1)+1024);
GetMem(p2,FileSize(f1)+1024);
BlockRead(f1,p2^,FileSize(f1));
len:=FileSize(f1);
for i:=1 to len do begin
b:=Byte(pointer(Integer(p2)+i-1)^);
b1:=i mod 31;
if b1=0 then b1:=31;
b:=b xor ord(pass[b1]);
Byte(pointer(Integer(p2)+i-1)^):=b;
end;
FCompress(DWORD(p2),len,DWORD(p),$138,DWORD(p1));
BlockWrite(f2,p^,DWORD(p1^));
CloseFile(f1);
CloseFile(f2);
end;
end.

Ну что же. Скармливаем ей tc.spv и получаем такое на выходе:
001=33858
002=1
003=33858
004=33825
005=CA,TF,FM,AR
006=0050
007=3382533825
008=1
009=1
010=65535
011=0
012=0
013=33825
014=33825
015=25508096
Хммм. Что же это значит? Очевидно, различные параметры, которые определяют функционирование программы. Да, сразу скажу, что параметр 015 - CRC всего файла, я это не знал и в первый раз проковырялся пол-часа, пока узнал, где грабли. Патчится в следующем месте (догадайтесь, почему):

:0102F355 3DB3030000
:0102F35A 0F8578000000
cmp eax, 000003B3
jne 0102F3D8

Теперь мы можем самостоятельно изменять параметры и модифицировать keyfile. Итак, методом научного тыка выяснились все параметры в KeyFile (я приведу их в виду схемы):

  1. 001=Start of Expiration Period
  2. 002=IsEval
  3. 003=Evaluation Length
  4. 004=Type of application:
    1- TeleCount *NOT For Resale*
    2- TeleCount Lite
    3- TeleCount Enterprise
    4- TeleCount IP
    5- TeleCount IP Enterprise
    6- TeleCount Enterprise Billing
    7- CommStats
    8- CommStars Enterprise
  5. 005=Different addons (toll fraud, etc.)
  6. 006=Version
  7. 007=Serial number
  8. 008=Number of extensions (0=Unlimited)
  9. 009=Number of truncks (0=Unlimited)
  10. 010=Number of voice ports (65535=Unlimited)
  11. 011=Number of data ports (65535=Unlimited)
  12. 012=Number of data servers (65535=Unlimited)
  13. 013=Number of voice minutes (0=Unlimited)
  14. 014=Number of billing customers (1=Unlimited)
  15. 015=CRC

Все! Можно считать TeleCount полностью взломанным.

IV. Подводим итоги:

Как всегда, мааленькое домашнее задание.
Первое: Параметры, которые принимаются во внимание при функционировании TeleCount различных типов сильно различаются. Задача: найти к каким типам какие параметры подходят.
И второе: Написать процедуру вычисления CRC у keyfile'а, чтобы не патчить.

В принципе, все. Сказать по поводу evaluation версии мне больше нечего. Но осталась нераскрытой именно не evaluation версия. Ее реверсингу (а там защита основана на Sentine Super Pro ключе) будет посвящена вторая статья.

Вот собственно и все! :)

Endnote:
© 2001 aSL! (asl@aslsoft.com )
This essay can be freely distributed/ published/ printed etc... as long as no modifications are made in any way.
Greets to: Everyone in UOFG www.uofg.com.ua


<= Вернуться к статьям

Rambler's Top100