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


Материалы находятся на сайте http://cracklab.narod.ru/doc/






Hosted by uCoz