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

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


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

Shareware программа - готовый генератор ключей. Обзор защиты L0pht Crack 4

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

Хорошая подборка видеоуроков, инструментов крэкера, книг и статей - здесь.

Автор: (ry0 <cryo@cydem.org.ua>

Привет! Таймаут окончен, я вернулся.
На этот раз я хотел рассказать вам о защите @stake LC4. Мы разберемся с процедурой генерации правильного серийника, само собой построим генератор, а также рассмотрим, как можно сделать (при помощи небольшого хирургического вмешательства, конечно же) так, чтобы программа, по сути, ломала сама себя (так что и разбираться с алгоритмом генерации не надо!).

Оборудование

 .SoftICE
 .IDA, W32Dasm
 .LordPE
 .hutch's MASM32
 (ничто из перечисленного в рекламе, уверен, не нуждается)
 
 Итак, начнем...
 
Найти необходимую часть кода труда не составит. Ищем в дизасме (W32Dasm) ссылку на строку "You have entered an invalid code" и поднимаемся по jump'ам немного выше:
 :00411BEB 8B4500        mov eax, dword ptr [ebp+00]
 :00411BEE 8D4C2420      lea ecx, dword ptr [esp+20]
 :00411BF2 51            push ecx
 :00411BF3 50            push eax
 :00411BF4 E8B722FFFF    call sub_403EB0 ;генерация с/н
                                  ;на выходе ECX держит адрес правильного ключа
 :00411BF9 8B07          mov eax, dword ptr [edi]
 :00411BFB 8D542428      lea edx, dword ptr [esp+28]
 :00411BFF 52            push edx
 :00411C00 50            push eax
 :00411C01 E8955C0100    call sub_42789B    ;проверка правильности
 :00411C06 83C410        add esp, 00000010
 :00411C09 85C0          test eax, eax
 :00411C0B 7523          jne 00411C30     ;перейти к выдаче сообщения об ошибке
 :00411C0D 8B07          mov eax, dword ptr [edi]
 :00411C0F 50            push eax
 :00411C10 6850134700    push 00471350
 :00411C15 685C134700    push 0047135C
 :00411C1A 8BCE          mov ecx, esi
 :00411C1C 899E3C010000  mov dword ptr [esi+0000013C], ebx
 :00411C22 E89AB20300    call sub_44CEC1
 :00411C27 53            push ebx
 :00411C28 53            push ebx
 :00411C29 6834144700    push 00471434
 :00411C2E EB07          jmp 00411C37
 :00411C30 53            push ebx
 :00411C31 53            push ebx
 :00411C32 6800144700    push 00471400  ;"You have entered an invalid code..."
 :00411C37 E8D3720300    call sub_448F0F
 
Что ж, в принципе, взлом закончен успешно :)
В SoftICE трассируем до адреса 00411BF9, а там "d ecx". Регистрируем и радуемся... Но дело в том, что защита LC4 построена таким образом, что Serial Number генерится все время новый, и после переустановки винды придется ломать прогу заново. Поэтому надо-таки замутить универсальный crack.

Если разбираться с алгоритмом вам совсем не интересно, а патчить не хочется (дабы сохранить .exe в первозданной форме) могу предложить выход: создать загрузчик, который заставит программу саму выдать вам правильный регистрационный ключ. На том и порешили...

Алгоритм таков:
1. Загрузчик запускает и патчит образ lc4.exe в ОЗУ.
2. Юзер вводит ложный Unlock Code и давит OK.
3. L0pht генерит у себя в нутре правильный Unlock Code, и выдает его (благодаря патчу) вместо сообщения об ошибке.
4. Загрузчик завершает работу, оставляя LC4 наедине с собой.

Давайте его реализуем.

Во-первых, мы решили, что правильный с/н будет выводиться вместо строки "You have entered an invalid code...". Она дислоцируется по адресу 00471400h, а смещение строки в файле равно .71400h. Итак, нам нужно будет копировать строку, на которую указывает регистр ECX после выполнения процедуры sub_403EB0 в буффер по адресу 00471400h. Чтобы сообщение выглядело красивее, можно разбавить его чем-то типа "Try again. Your valid Unlock Code is: ". В этом случае строку с настоящим серийником следует прописывать по адресу 00471425h.

Во-вторых, нам нужно добавить некоторое количество байт, образующих собой ту самую процедуру копирования правильного серийника в буффер по адресу 00471400h. Для этого с помощью LordPE нужно найти свободное место. Я решил добавить код в секцию .text начиная с адреса 0045DF00h. Переход к процедуре осуществим с адреса 00411C30h - это начало вызова сообщения об ошибке. Т. о. меняем
 :00411C30  push ebx
 :00411C31  push ebx
 :00411C32  push 00471400
 
 на
 
 :00411C30 jmp 0045DF00h
 :00411C35 nop
 :00411C36 nop
 
 А сама процедура будет выглядеть примерно так:
 
  push esi            ;сохраняем регистры
  push edi            ;мы ведь не хотим вылететь с ошибкой:)
  mov esi, ecx        ;исходная строка
  mov edi, 00471425h  ;буффер
 _label1:             ;а теперь копируем
  lodsb
  stosb
  cmp al, 0
  jnz _label1
  pop edi             ;восстанавливаем регистры
  pop esi
  push ebx            ;восстанавливаем часть кода,
  push ebx            ;которую пропатчили ранее.
  push 00471400h
  jmp 00411C37h       ;и возвращаемся в основную программу.
 
Ну, кажется ничего не забыл. Ниже приведен пример загрузчика в синтаксисе для hutch's MASM32.
 файл RSRC.RC
 ----------------------вырезать------------------------------
 #include "E:\masm32\Templates\Resource.h"  /* укажите свой путь */
 
 DLG_MAIN DIALOGEX 0, 0, 150, 50
 STYLE DS_CENTER | WS_MINIMIZEBOX | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
 CAPTION "LC4 KeyRevealer"
 FONT 8, "Verdana"
 {
    CONTROL "Load 'n' patch LC4", 201, BUTTON, BS_PUSHBUTTON | WS_CHILD |
            WS_VISIBLE | WS_GROUP | WS_TABSTOP, 5, 5, 140, 19 , 0x00020000
    CONTROL "close", 1004, BUTTON, BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE |
            WS_GROUP | WS_TABSTOP, 5, 26, 140, 19 , 0x00020000
 }
 ----------------------вырезать------------------------------
 
 файл lc4pp.asm
 ----------------------вырезать------------------------------
 .586
 .model flat, stdcall
 option casemap:none
 include \masm32\include\windows.inc
 include \masm32\include\user32.inc
 include \masm32\include\kernel32.inc
 include \masm32\include\comdlg32.inc
 includelib \masm32\lib\user32.lib
 includelib \masm32\lib\kernel32.lib
 includelib \masm32\lib\comdlg32.lib
 
 WndProc proto :DWORD, :DWORD, :DWORD, :DWORD
 
 .data
 DlgMainName       BYTE 'DLG_MAIN',0
 OpenFileFilter    BYTE 'L0phtCrack 4 (lc4.exe)',0,'lc4.exe',0,0
 wrongSN           BYTE 'You have entered an invalid code. Please try again.',0
 yourSN	          BYTE 'Try again. Your valid Unlock Code is: ',0
 originalcode      BYTE 53h,53h,68h,00h,14h,47h,00h,0E8h,0D3h,72h,03h,00h
 patch2            BYTE 56h, 57h, 8Bh, 0F1h, 0BFh,  26h,  14h, 47h, 00h, 0ACh,\
                        0AAh, 3Ch, 00h, 75h,  0FAh, 5Fh, 5Eh,  53h,\
                        53h, 68h, 00h,  14h,  47h,  00h, 0E9h, 18h, 3Dh, 0FBh, 0FFh
 patch1            BYTE 0E9h,0CBh,0C2h,04h,00h,90h,90h
 errStr            BYTE 'Patching failed.',0
 errCapt	          BYTE 'Error',0
 of                OPENFILENAME <>
 startupinfo       STARTUPINFO <>
 processinfo       PROCESS_INFORMATION <>
 sa                SECURITY_ATTRIBUTES <>
 sd                SECURITY_DESCRIPTOR <>
 
 .data?
 hInstance         DWORD ?
 dwErrCode         DWORD ?
 hFile             DWORD ?
 OpenFilePath      BYTE  256 dup(?)
 buffer            BYTE  256 dup(?)
 
 .code
 start:
  invoke GetModuleHandle, 0
  mov    hInstance, eax
  invoke DialogBoxParam, hInstance, addr DlgMainName, 0, addr WndProc, 0
  invoke ExitProcess, eax
 
 WndProc proc hWnd:DWORD, uMsg:DWORD, wParam:DWORD, lParam:DWORD
 .IF uMsg == WM_INITDIALOG
      mov    of.lStructSize, SIZEOF OPENFILENAME
      push   hWnd
      pop    of.hWndOwner
      push   hInstance
      pop    of.hInstance
      mov    of.lpstrFile, offset OpenFilePath
      mov    of.nMaxFile, 256
      mov    of.Flags, OFN_FILEMUSTEXIST or OFN_PATHMUSTEXIST or OFN_LONGNAMES or\
                       OFN_EXPLORER or OFN_HIDEREADONLY or OFN_NOCHANGEDIR
 .ELSEIF uMsg == WM_CLOSE
     invoke EndDialog, hWnd, 0
 .ELSEIF uMsg == WM_COMMAND
     mov eax, wParam
     mov edx, eax
     shr edx, 16
     .IF edx == BN_CLICKED
         .IF ax == 201
             mov    of.lpstrFilter, offset OpenFileFilter
             invoke GetOpenFileName, addr of
             .IF eax == TRUE
                 invoke CreateProcess, addr OpenFilePath, 0, 0, 0, 0,
                        NORMAL_PRIORITY_CLASS, 0, 0, addr startupinfo,
                        addr processinfo
                 .IF eax != 0
                   ;ждем, пока LC4 полностью загрузится и будет готов к работе.
                     invoke WaitForInputIdle, processinfo.hProcess, INFINITE
                     lea edi, buffer
                     invoke ReadProcessMemory, processinfo.hProcess, 411C30h,
                            edi, 12, 0
                   ;проверяем частично правильность прочитанных данных
                     cmp dword ptr [edi], 685353h
                     jnz _err
                   ;читаем данные. Должна быть строка "You have entered an inva..."
                     invoke ReadProcessMemory, processinfo.hProcess, 471400h,
                     addr buffer, 56, 0
                     invoke lstrcmp, addr buffer, addr wrongSN
                     cmp eax, 0
                     jnz _err
                   ;пишем строку "Try again. Your valid Unlock Code is: "
                     invoke WriteProcessMemory, processinfo.hProcess, 471400h,
                            addr yourSN, 38, 0
                     cmp eax, 0
                     jz _err
                   ;патчим память - ставим переход на новую процедуру
                     invoke WriteProcessMemory, processinfo.hProcess, 411C30h,
                            addr patch1, 7, 0
                     cmp eax, 0
                     jz _err
                   ;патчим память - записываем новую процедуру
                     invoke WriteProcessMemory, processinfo.hProcess, 45DF00h,
                            addr patch2, 31, 0
                     cmp eax, 0
                     jz _err
                     invoke SendMessage, hWnd, WM_CLOSE, 0, 0
                 .ELSE
                    _err:
                     invoke MessageBox, hWnd, addr errStr, addr errCapt,
                            MB_ICONERROR or MB_OK
                     invoke TerminateProcess, processinfo.hProcess, 0
                     invoke CloseHandle, processinfo.hProcess
                 .ENDIF
             .ENDIF
         .ELSEIF ax == 1004
             invoke SendMessage, hWnd, WM_CLOSE, 0, 0
         .ENDIF
     .ENDIF
 .ELSE
  xor eax, eax
  ret
 .ENDIF
  mov eax, TRUE
  ret
 WndProc endp
 end start
 ----------------------вырезать------------------------------
 
Хорошо, но вам все-таки интересно, что же представляет собой процедура генерации серийника в L0pht'е? Давайте посмотрим... Как отмечалось ранее, за генерацию отвечает процедура sub_403EB0. Углубляемся...
 :00403EB0 83EC0C      sub esp, 0000000C
 :00403EB3 8B442410    mov eax, dword ptr [esp+10]
 :00403EB7 6A08        push 00000008
 :00403EB9 40          inc eax
 :00403EBA 50          push eax
 :00403EBB 8D4C2408    lea ecx, dword ptr [esp+08]
 :00403EBF 51          push ecx
 :00403EC0 E8AB1E0200  call sub_425D70
 :00403EC5 8D54241C    lea edx, dword ptr [esp+1C]
 :00403EC9 52          push edx
 :00403ECA 8D442410    lea eax, dword ptr [esp+10]
 :00403ECE 6888FA4600  push 0046FA88
 :00403ED3 50          push eax
 :00403ED4 C644242000  mov [esp+20], 00
 :00403ED9 E865240200  call sub_426343
 :00403EDE 8B442428    mov eax, dword ptr [esp+28]
 :00403EE2 3552AE376F  xor eax, 6F37AE52
 :00403EE7 8BC8        mov ecx, eax
 :00403EE9 C1E11B      shl ecx, 1B
 :00403EEC C1E805      shr eax, 05
 :00403EEF 03C8        add ecx, eax
 :00403EF1 51          push ecx
 :00403EF2 894C242C    mov dword ptr [esp+2C], ecx
 :00403EF6 8B4C2430    mov ecx, dword ptr [esp+30]
 :00403EFA 6880FA4600  push 0046FA80
 :00403EFF 51          push ecx
 :00403F00 E8EC230200  call sub_4262F1
 :00403F05 33C0        xor eax, eax
 :00403F07 83C430      add esp, 00000030
 :00403F0A C3          ret
 
Посмотрим на процедурку повнимательней. У нас имеется три функции и несколько строк математики. Разберемся сначала с функциями. Сказать особо нечего: sub_425D70 - это API функция strncpy sub_426343 - это API функция sscanf sub_4262F1 - это API функция sprintf Все три расположены в библиотеке msvcrt.dll. И маньяки из @stake, уверен, хотели скрыть этот факт. Извращенцы! Они вырезали функции из .dll'ки и прописали их в коде L0pht'а! Но тем не менее нельзя не признать оригинальности решения. Но не будем удаляться от темы. Вот примерное описание функций. Подробности смотрите в MSDN.
 1.strncpy
 синтаксис:
 push nCount
 push lpOut
 push lpIn
 call strncpy
 Тут все ясно. Функция копирует nCount символов из буффера по адресу lpOut
 в буффер по адресу lpIn.
 
 2.sscanf
 синтаксис:
 ...
 push lpArgument1
 push lpFmt
 push lpOut
 call sscanf
 Функция читает данные из буффера по адресу lpOut, колдует над ними в соответствии
 с заданным форматом (у нас это '%08x') и пишет результат в буффер по адресу
 lpArgument1.
 Количество аргументов может быть различным от одного и более (как в wsprintf). Тип
 аргумента зависит от формата.
 
 3.sprintf
 синтаксис:
 ...
 push lpArgument1
 push lpFmt
 push lpOut
 call sprintf
 Подобно wsprintf форматирует и записывает набор символов из буффера по адресу
 lpOut в другой буффер, адресуемый параметром lpArgument1. Аргументов может быть
 несколько, в зависимости от формата.
 В LC4 эта API функция вызывается с форматом '%04x', а lpOut указывает на место,
 где по завершении процедуры будет лежать правильный Unlock Code.
 
Предельно просто, не так ли? Ниже привожу сырье генератора в синтаксисе для hutch's MASM32.
 файл RSRC.RC
 ----------------------вырезать------------------------------
 #include "E:\masm32\Templates\Resource.h"  /* укажите свой путь */
 DLG_MAIN DIALOGEX 0, 0, 186, 55
 STYLE DS_CENTER | WS_MINIMIZEBOX | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
 CAPTION "LC4 Keygen"
 FONT 8, "VERDANA"
 {
  CONTROL "", 101, EDIT, ES_LEFT | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 61,
          5, 120, 10 , 0x00020000
  CONTROL "", 102, EDIT, ES_LEFT | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 61,
          17, 120, 10 , 0x00020000
  CONTROL "Serial Number:", -1, STATIC, SS_LEFT | SS_CENTERIMAGE | WS_CHILD |
          WS_VISIBLE | WS_GROUP, 5, 5, 54, 10
  CONTROL "Unlock Code:", -1, STATIC, SS_LEFT | SS_CENTERIMAGE | WS_CHILD |
          WS_VISIBLE | WS_GROUP, 5, 17, 54, 10
  CONTROL "Generate", 201, BUTTON, BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE |
          WS_GROUP | WS_TABSTOP, 61, 32, 55, 19 , 0x00020000
  CONTROL "close", 1004, BUTTON, BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE |
          WS_GROUP | WS_TABSTOP, 128, 32, 55, 19 , 0x00020000
 }
 ----------------------вырезать------------------------------
 
 файл lc4kg.asm
 ----------------------вырезать------------------------------
 .586
 .model flat, stdcall
 option casemap:none
 include \masm32\include\windows.inc
 include \masm32\include\user32.inc
 include \masm32\include\kernel32.inc
 includelib \masm32\lib\user32.lib
 includelib \masm32\lib\kernel32.lib
 
 WndProc proto :DWORD, :DWORD, :DWORD, :DWORD
 
 .data
 DlgMainName   BYTE 'DLG_MAIN',0
 scanFormat    BYTE '%08x',0
 printFormat   BYTE '%04x',0
 _sprintf      BYTE 'sprintf',0
 _sscanf       BYTE 'sscanf',0
 szLibrary     BYTE '\msvcrt.dll',0
 szMsgCaption  BYTE '!error',0
 szLibNotFound BYTE 'msvcrt.dll library not found.',13,10,\
                    'Terminating...',0
 .data?
 hInstance     DWORD ?
 szPath        BYTE  256 dup(?)
 hDLL          DWORD ?
 sprintf       DWORD ?
 sscanf        DWORD ?
 
 .code
 start:
  invoke GetModuleHandle, 0
  mov hInstance, eax
 ;--- ПОДГРУЖАЕМ БИБЛИОТЕКУ msvcrt.dll ---
  lea esi, szPath
  invoke GetSystemDirectory, esi, 244
  invoke lstrlen, esi
  add esi, eax
  invoke lstrcpy, esi, addr szLibrary
  invoke LoadLibrary, addr szPath
  .IF eax != 0
      mov hDLL, eax
      invoke DialogBoxParam, hInstance, addr DlgMainName,
             0, addr WndProc, 0
      invoke FreeLibrary, hDLL
  .ELSE
      invoke MessageBox, 0, addr szLibNotFound, addr szMsgCaption,
             MB_ICONERROR or MB_OK
  .ENDIF
  invoke ExitProcess, 0
 
 WndProc proc hWnd:DWORD, uMsg:DWORD, wParam:DWORD, lParam:DWORD
 LOCAL snBuffer[16]:BYTE
 LOCAL ucBuffer[16]:BYTE
 
 .IF uMsg == WM_INITDIALOG
   ;--- ПОЛУЧАЕМ АДРЕСА НУЖНЫХ API ИЗ msvcrt.dll ---
     invoke GetProcAddress, hDLL, addr _sprintf
     mov sprintf, eax
     invoke GetProcAddress, hDLL, addr _sscanf
     mov sscanf, eax
 
 .ELSEIF uMsg == WM_CLOSE
     invoke EndDialog, hWnd, 0
 
 .ELSEIF uMsg == WM_COMMAND
     mov eax, wParam
     mov edx, eax
     shr edx, 16
     .IF edx == BN_CLICKED
         .IF ax == 201
           ;--- ГЕНЕРАЦИЯ СЕРИЙНИКА ---
             lea esi, snBuffer
             invoke GetDlgItemText, hWnd, 101, esi, 16
             add esi, 1
             mov byte ptr [esi+8], 0
             lea edi, ucBuffer
             push edi
             lea eax, scanFormat
             push eax
             push esi
             call sscanf
             mov eax, [edi]
             xor eax, 6F37AE52h
             mov ecx, eax
             shl ecx, 1Bh
             shr eax, 5
             add ecx, eax
             push ecx
             lea edx, printFormat
             push edx
             push edi
             call sprintf
             invoke SetDlgItemText, hWnd, 102, edi
         .ELSEIF ax == 1004
             invoke SendMessage, hWnd, WM_CLOSE, 0, 0
         .ENDIF
     .ENDIF
 .ELSE
      xor eax, eax
      ret
 .ENDIF
  mov eax, TRUE
  ret
 WndProc endp
 end start
 ----------------------вырезать------------------------------
 
Так вот! Порой мне кажется, что создав нечто великолепное, люди так хотят побыстрее на этом заработать, что забывают обо всем другом на свете. Жажда богатства и славы затмевает рассудок, убивает душу. Алчность - путь к нищете. adios.

P.S. Crack 'em all

Дата: август l6, 2OO3
Автор: (ry0
E-mail: cryo#cydem.org.ua
ICQ #: l79S2lSOS

Обсуждение статьи: Shareware программа - готовый генератор ключей. Обзор защиты L0pht Crack 4 >>>


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



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


Вы находитесь на EXELAB.rU
Проект ReactOS