Перепечатано с разрешения www.uofg.com.ua




Обсуждение статьи: TeleCount 4.00.02: Evaluation key >>>


Материалы находятся на сайте https://exelab.ru



Оригинальный DVD-ROM: eXeL@B DVD !


Оригинальный DVD-ROM: eXeL@B DVD !
eXeL@B ВИДЕОКУРС !

ВИДЕОКУРС ВЗЛОМ
выпущен 12 ноября!


УЗНАТЬ БОЛЬШЕ >>
Домой | Статьи | RAR-cтатьи | FAQ | Форум | Скачать | Видеокурс
Новичку | Ссылки | Программирование | Интервью | Архив | Связь

TeleCount 4.00.02: Evaluation key

Обсудить статью на форуме

Массу крэкерских инструментов, видеоуроков и статей вы сможете найти на видеокурсе от нашего сайта. Подробнее здесь.
Target: TeleCount 4.00.02
URL:www.telecount.com.
Автор: aSL!

Before starting!

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

Вступление

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


Постановка задачи

Необходимо зарегистрировать TeleCount 4.00.02

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

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

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

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

После недолгого осмотра мы приходим к выводу, что:
  
  • Программа написана с использованием CA-Visual Objects (Что усложняет задачу, но не очень)
  •   
  • Используется для каких-то целей библиотека халявнух функций FUNCky 6.0
  •   
  • 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 полностью взломанным.

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

    Как всегда, мааленькое домашнее задание.

    Первое: Параметры, которые принимаются во внимание при функционировании TeleCount различных типов сильно различаются. Задача: найти к каким типам какие параметры подходят.

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

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


    © 2001 aSL! (asl@aslsoft.com )
    Вы находитесь на EXELAB.rU
    Проект ReactOS