<< Все статьи по взлому Примеры программ на Макро-ассемблере Обсудить эту статью >>
Автор:bi0w0rM [AHTeam]
Уровень:Для опытных
Инструменты:MSDN или Win32 SDK, MASM32

[ В этой статье :: ]

>> Рассмотрим пример создания загрузчика(loader) для ASProtect
>> Universal Loader для Total Commander(оригинальный код by Nabu)
>> Еще один простой пример


[iNT R0]
Умение программирования есть одно из лучших качеств хорошего крякера, ибо все, что делается руками, можно автоматизировать. Нашел способ распаковать хитрый паковщик/протектор - можно написать распаковщик. Главное вооружиться MSDN или Win32 SDK(поставляется, например, с Delphi или с C++Builder) и уметь кодить на чем-нибудь... отличным от Басика и просто Поцкаля. Мы же будем использовать MASM32(для его скачивания нет лучше сайта, чем www.wasm.ru). Макроассемблер крут и удобен. W32ASM - pure and simple ;) Тем более при компиляции получаются проги ОЧЕНЬ маленького размера, что хорошо крякеру, который что-то релизит в инет. Итак, начнем...

[PART I] ASProtect Loader
Очень много сказано о защите ASProtect, особенно о его распаковке, долгой и мудежной, в большинстве случаев - с подлянами и засадами. Всё новые приемы обнаружения отладчика... Новые его версии уже в win9x хрен снимешь. Да, есть конечно Stripper, но я часто встречал случаи, когда распакованный файл не запускался, хотя версия аспра стриппером поддерживалась. Но очень простой способ прокатывает почти на всех прогах запакованных аспром - это создание загрузчика. Нет, аспр проверяет при запуске целостность кода, но что если патчить память, когда проверка уже произошла и Protection Error 15 не покажется? Вот... И для этого давайте напишим лоадер, который при желании можно заделать под просто лоадер для непакованных прог. Для этого будем использовать функции отладки. Используемые функции и их аргументы:
BOOL CreateProcess(

LPCTSTR lpApplicationName, // имя проги
LPTSTR lpCommandLine, // CommandLine
LPSECURITY_ATTRIBUTES lpProcessAttributes,
LPSECURITY_ATTRIBUTES lpThreadAttributes,
BOOL bInheritHandles,
DWORD dwCreationFlags,
LPVOID lpEnvironment,
LPCTSTR lpCurrentDirectory,
LPSTARTUPINFO lpStartupInfo, //Инфа о стартапе
LPPROCESS_INFORMATION lpProcessInformation //Инфа о процессе
);
В принципе, нужное я обозначил. Если хотите узнать, какие значения может принимать lpProcessAttributes, lpThreadAttributes, dwCreationFlags и другие, то сходите в msdn.com или пошарьте в Win32 SDK, да и вообще в любом справочнике по Win API.
BOOL WriteProcessMemory(

HANDLE hProcess, // Это процесс, созданный по CreateProcess
LPVOID lpBaseAddress, // Виртуальный адрес, по которому надо произвести запись
LPVOID lpBuffer, // Это байты, которые надо записать
DWORD nSize, // Номер байтов для записи
LPDWORD lpNumberOfBytesWritten // Кол-во байтов для записи :)
);
Здесь не должно возникнуть вопросов.
BOOL ReadProcessMemory(

HANDLE hProcess,
LPCVOID lpBaseAddress,
LPVOID lpBuffer,
DWORD nSize,
LPDWORD lpNumberOfBytesRead
);
Да это тоже самое, только здесь не запись в память, а чтение.

Ну вот, теперь запускаем QuickEditor(QEDITOR.EXE в папке MASM32). Пишем туда наш код
======= bEGIN oF mpatch.asm =======

.486
.model flat, stdcall
option casemap :none

include \masm32\include\windows.inc
include \masm32\include\masm32.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
include \masm32\include\shell32.inc

includelib \masm32\lib\masm32.lib
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\shell32.lib

; include - необходимый минимум для нашей проги

.data
App db "DzSoft PHP Editor",0 ; Ну эт я над прогой такой издевался :)
Err1 db "Program not found :(",0 ; Обломов
prog db "DzPhpEd.exe",0 ; Имя проги
bufwr DWORD 90h ; Мне нужно байт 75 поменять на NOP(90)
va DWORD 579C03h ; Это первый адрес, по которому надо произвести запись
va2 DWORD 579C04h ; А это второй

.data?
bufr dw ? ; Байт, в который производится чтение
pinfo PROCESS_INFORMATION <> ; Это Инфа о процессе
sinfo STARTUPINFO <> ; Это инфа о запуске
n DWORD ? ; Кол-во байтов
.code

start: ; Оффицильное начало
invoke CreateProcess,addr prog,NULL,NULL,NULL,FALSE,
CREATE_NEW_CONSOLE OR NORMAL_PRIORITY_CLASS,NULL,NULL,addr sinfo,addr pinfo
; Создаем процесс.. CREATE_NEW_CONSOLE OR NORMAL_PRIORITY_CLASS
; для того, чтобы запускаемая прога не сворачивалась.
.IF eax == 0 ; Если EAX(результат) равен 0(прога не запустилась)
invoke MessageBox,NULL,addr Err1,addr App,MB_OK ; Выдаем сообщение
invoke ExitProcess,0 ; И выходим :)
.ENDIF
.WHILE TRUE ; Это цикл. Вот за такие high-level
; макросы я очень MASM люблю :)
invoke ReadProcessMemory,pinfo.hProcess,va,addr bufr,1,n ; Читаем память
.IF eax != 0 ; Если все ОК
.IF bufr != 00h ; И байт под адресу va(579C03h) не
; равен 00h(прога распакована уже), то....
invoke Sleep,300 ; Слипаем глаза, пока аспр проверяет целостность кода
invoke SuspendThread,addr pinfo.hThread ; Тормозим нашу прогу
invoke WriteProcessMemory,pinfo.hProcess,va,addr bufwr,1,n ; Пишем куда надо NOP
invoke WriteProcessMemory,pinfo.hProcess,va2,addr bufwr,1,n ; И сюда тоже NOP
invoke ResumeThread,addr pinfo.hThread ; Отправляем прогу дальше
invoke CloseHandle,pinfo.hThread ; Сворачиваем мокруху
invoke ExitProcess,0 ; Уходим
.ENDIF
.ENDIF
.ENDW

end start ; Оффициальный конец

======= eND oF mpatch.asm =======
ну че? и все! Теперь Build All и получаем лоадер в 2,5 Кб. Этот размер до того маленький, что даже UPX говорит: "Зачем сжимать? Тут и сжимать нечего!" :). Похожую прогу писал - = ALEX = - , но у него вся эта тема была на делфи с его лишним весом :) тем более я делфу не знаю(и не уютно в ней чувствую себя), знаю только C и ASM(эти языки -- рай для программиста).
Чтоб делать просто лоадер(без всяких там Sleep и цикл м проверкой на распакованность), просто уберите эти строки :). То есть вам надо будет только CreateProcess, SuspendThread, WriteProcessMemory и т.д.

[PART II] Universal Total Commander Loader
Универсальный кряк для крутого файлового менеджера Total Commander. В самой проге применен алгоритм шифровки кода. Если надо - копайтесь, а мы пойдем путем шаровика :) Разработчики хорошо постарались, закриптовав прогу, но допустили погрешнсть - надо сначала показать наг, а потом МейнСкрин(основное окно), а у них НАГ блокиует MainScreen, а поэтому его легко убрать. Берем маленькую прогу WindowMan с y0da.cjb.net и зажав CTRL направляем на наг-скрин Total Commander мышу. Класс зовется TNASTYNAGSCREEN, запомним. Теперь таким же образом смотрим на главное окно, оно зовется TTOTAL_CMD, учтем...

Все, это достаточно, чтоб написать лоадер, который убирает наг автоматически. Подобную прогу уже представлял Nabu. Но там был C, а мы напишем на ассемблере и немного доработаем:
======= bEGiN oF tcmdcrk.asm =======

.486
.model flat, stdcall
option casemap :none

include \masm32\include\windows.inc
include \masm32\include\masm32.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
include \masm32\include\shell32.inc

includelib \masm32\lib\masm32.lib
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\shell32.lib

.data

WND1 HWND ?
WND2 HWND ?
WNDNAME1 db "TNASTYNAGSCREEN",0 ; ага! вот где имя класса нага пригодилось!
WNDNAME2 db "TTOTAL_CMD",0 ; имя класса главного окна
CAPTION db "Total Commander 5.5 - bi0w0rM",0 ; ну ето просто :)
EXENAME db "totalcmd.exe",0 ; Имя проги

.code

start:
INVOKE WinExec, addr EXENAME, SW_SHOWNORMAL ; Запускаем
.WHILE TRUE ; Пусть прога бьется в цикле, когда надо - выйдем по ExitProcess
INVOKE FindWindow,addr WNDNAME2,NULL ; ищем окно TTOTALCMD
MOV WND2,EAX ; Кладем результат в WND2
.IF EAX != 0 ; Если окно нашлос-таки
INVOKE FindWindow,addr WNDNAME1,NULL ; То изем еще одно окно - НАГ
MOV WND1,EAX ; Ложим результат
INVOKE ShowWindow,WND1,SW_HIDE ; Убираем наг НАФИК
INVOKE EnableWindow,WND2,TRUE ; Енейблим главное окно
INVOKE SetForegroundWindow,WND2 ; И делаем его сразу активным
INVOKE SetWindowText,WND2,addr CAPTION ; Ну и небольшой прикол:) который не проходит :((
INVOKE ExitProcess,0 ; Уходим...
.ENDIF
.ENDW

end start

======= eND oF tcmdcrk.asm =======
У Nabu был прикол со Sleep. У нас же лоадер быстрее, так как бьется в цикле, пока не не создастся окно. Если он его находит - убивает наг и енейблит окно. Спасибо тебе, Nabu! Так бы я не решился такого написать!

[ЕЩЕ!]
Еще недавно попросили меня сделать кейген для крякмиса фантома(FaNt0m's Crackme #4). Я разобрался в алгоритме генерации, но что-то лениво очень было писать :) Я решил - опять пойдем другим путем :) в результате - тот же кейген!
В опщем посмотрев в листинге w32dasm я увидел, что сам ключ лежит по адресу 403284. Можно было бы использовать функции отладки, ставить бряки, пробиваясь в цикле... Зачем? можно сделать все проще. Итак, привожу проверку ключа:
===== Начало Листинга =====
:00401205 6800010000 push 00000100
:0040120A 6884304000 push 00403084

* Possible Reference to Dialog: MAINDIALOG, CONTROL_ID:03E8, ""
|
:0040120F 68E8030000 push 000003E8
:00401214 FF7508 push [ebp+08]

* Reference To: USER32.GetDlgItemTextA, Ord:0102h
|
:00401217 E862010000 Call 0040137E
:0040121C 6800010000 push 00000100
:00401221 6884314000 push 00403184

* Possible Reference to Dialog: MAINDIALOG, CONTROL_ID:03E9, ""
|
:00401226 68E9030000 push 000003E9
:0040122B FF7508 push [ebp+08]

* Reference To: USER32.GetDlgItemTextA, Ord:0102h
|
:0040122E E84B010000 Call 0040137E
:00401233 FF7508 push [ebp+08]
:00401236 E8BE000000 call 004012F9
:0040123B 83F800 cmp eax, 00000000
:0040123E 7415 je 00401255
:00401240 6A40 push 00000040

* Possible StringData Ref from Data Obj ->"Check Serial"
|
:00401242 6829304000 push 00403029

* Possible StringData Ref from Data Obj ->"You got it! Congrats! :)"

; ...............
; В процедуре 004012F9 явно происходит проверка, зайдем в нее:

:004012F9 55 push ebp
:004012FA 8BEC mov ebp, esp
:004012FC 56 push esi
:004012FD 57 push edi
:004012FE 8D3584304000 lea esi, dword ptr [00403084]
:00401304 8D3D84324000 lea edi, dword ptr [00403284]
:0040130A 33C0 xor eax, eax
:0040130C 33C9 xor ecx, ecx
:0040130E B31A mov bl, 1A

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00401328(U)
|
:00401310 803E00 cmp byte ptr [esi], 00
:00401313 7415 je 0040132A
:00401315 8A06 mov al, byte ptr [esi]
:00401317 02C1 add al, cl
:00401319 32C1 xor al, cl
:0040131B F6F3 div bl
:0040131D 66C1E808 shr ax, 08
:00401321 0441 add al, 41
:00401323 8807 mov byte ptr [edi], al
:00401325 47 inc edi
:00401326 46 inc esi
:00401327 41 inc ecx
:00401328 EBE6 jmp 00401310

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00401313(C)
|
:0040132A C60700 mov byte ptr [edi], 00
:0040132D 33C0 xor eax, eax
:0040132F 83F900 cmp ecx, 00000000
:00401332 741A je 0040134E
:00401334 6884324000 push 00403284
:00401339 6884314000 push 00403184

* Reference To: KERNEL32.lstrcmpA, Ord:02D6h
|
:0040133E E8A1000000 Call 004013E4 ; Ну уж кда проще - вызов strcmp.
Сравнивает строки на похожесть
:00401343 83F800 cmp eax, 00000000 ; Если не одинаковы, то жопа
:00401346 7404 je 0040134C ; и джамп...
:00401348 33C0 xor eax, eax
:0040134A EB02 jmp 0040134E

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00401346(C)
|
:0040134C 8BC1 mov eax, ecx

* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
|:00401332(C), :0040134A(U)
|
:0040134E 5F pop edi
:0040134F 5E pop esi
:00401350 C9 leave
:00401351 C20400 ret 0004

........................

Перед началом вызова strcmp были записаны два параметра: 00403184 и 00403284. По достоверным данным, которые мне дали SoftICE и OllyDbg - в 00403284 лежит правильный ключ. Что делать теперь? Посмотрим на вызов обламывающего окна:
:00401255 6A30                    push 00000030

* Possible StringData Ref from Data Obj ->"Check Serial"
|
:00401257 6829304000 push 00403029

* Possible StringData Ref from Data Obj ->"Wrong Serial! Keep trying, you'll "
->"get it!"
|
:0040125C 6836304000 push 00403036
:00401261 6A00 push 00000000

* Reference To: USER32.MessageBoxA, Ord:01BBh
|
:00401263 E834010000 Call 0040139C
===== Конец Листинга =====
Короче, вместо push 00403036, мы ставим push 00403284 и тогда вместо появления надписи Wrong Serial нам покажецца наш ключ! :)) Какие байты менять? было 6836304000, а станет 6884324000. Но мы раз кейгенщики, то давайте сделаем, чтобы байты патчились на лету! Вот прога:
======= bEgIN oF loader.asm =======
.486
.model flat, stdcall
option casemap :none

include \masm32\include\windows.inc
include \masm32\include\masm32.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
include \masm32\include\shell32.inc

includelib \masm32\lib\masm32.lib
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\shell32.lib

.data


Exe db "CRACKME4.EXE",0 ; Прога
App db "bi0w0rM'z loader",0 ; Понты :)
Error1 db "Could not create process :((",0 ; Сообщение, если не удалось запустить
Error2 db "Fucking Version :((",0 ; Если это вовсе не наш крякмис,
; а соффсем другая прога

.data?

Sinfo STARTUPINFO <> ; Надо для запуска
Pinfo PROCESS_INFORMATION <> ; Надо для запуска
WByte DWORD ? ; Байт для записи
RByte DWORD ? ; Байт для чтения
Adr DWORD ? ; Адрес для патча
n DWORD ? ; Кол-во байтофф

.code

start:

invoke CreateProcess,addr Exe,NULL,NULL,NULL,FALSE,
NORMAL_PRIORITY_CLASS,NULL,NULL,addr Sinfo,addr Pinfo
CMP EAX,0
JNZ PATCH
INVOKE MessageBox,NULL,addr Error1,addr App,MB_ICONERROR
INVOKE ExitProcess,0

PATCH:

MOV Adr, 0040125Dh
MOV WByte,84h
CALL PATCHER
MOV Adr, 0040125Eh
MOV WByte,32h
CALL PATCHER
MOV Adr, 0040125Fh
MOV WByte,40h
CALL PATCHER

invoke CloseHandle,Pinfo.hThread
INVOKE ExitProcess,0

FUCK:
INVOKE MessageBox,NULL,addr Error2,addr App,MB_ICONERROR

PATCHER PROC
INVOKE ReadProcessMemory,Pinfo.hProcess,Adr,addr RByte,1,n
INVOKE WriteProcessMemory,Pinfo.hProcess,Adr,addr WByte,1,n
RET
PATCHER ENDP

end start

======= eND oF loader.asm =======
Теперь скомпилируем лоадер и запустим его в папке с крякмисом. Введем имя и кей от балды. Во! Появляется мессага с нашим ключом.

Возможно, что в скором времени я напишу подобную статью, только уже об непосредственно отладке, бряках, трейсинге и т.д. Может даже напишем простенький распакоффщик для UPX. Но это будет потом, а пока на этом я прощаюсь.

bi0w0rM[AHT]
bioworm.narod.ru
mailto:bioworm@mail.ru
... на закате 2003
HAPPY NEW YEAR, ALL CRACKERZ AROUND THE WORLD!

<< Все статьи по взлому Обсудить эту статью >>

ALIEN Hack Team - http://ahteam.org
Только для образовательных целей