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

[iNTR0]
До недавнего времени я не особо любил сидеть в IRC: инет дорого стоит, да и "фигня все эти чаты" думал я. так и думал, пока не подключился к нашей городской интрасети - стоит дешево(2р/час, ночь - free) и народ здесь местный, то есть и друзья реальные. у меня был mIRC 5.12(так, шоб был :)), но на местном ftp-серве я откопал свежую версию этого кульного клиента(6.12), тем более она еще и скрипты поддерживает(что сыграло значительную роль в зафлудивании в привате и нюканьи врагов:)). и защиту Khaled Mardam-Bey улучшил, хотя не намного...

[rIPPiNG]
Давайте поползем в раздел, посвященный регистрации -- Help->Register... Кто знаком с Win32-программированием знает, что из EditBox'а текст достается при помощи вызова API-функции GetDlgItemTextA. В софтайсе я поставил на нее брейкпоинт. bpx getdlgitemtexta. Нажал в мирке на ОК и нифига не вышло :(( Хотя я вспомнил, что достать текст можно еще и через SendDlgItemMessage, вот функция и ее входные параметры:
LONG SendDlgItemMessage(

HWND hDlg, // handle of dialog box
int nIDDlgItem, // identifier of control
UINT Msg, // message to send
WPARAM wParam, // first message parameter
LPARAM lParam // second message parameter
);
Так вот, если посмотреть SDK к винде(поставляется с C++Builder и Delphi), то чтобы достать текст(аналог GetDlgItemTextA), надо в параметр Msg подставить WM_GETTEXT, при этом lParam - адрес строки, куда будет помещен текст, а в wParam максимальное количество символов. Это я все к тому, что надо поставить брейкпоинт на SendDlgItemMessage, делаем bpx SendDlgItemMessage, ОК, F12. и впрямь! попали:
* Reference To: USER32.SendDlgItemMessageA, Ord:0236h
|
:004C2337 8B3D7C465700 mov edi, dword ptr [0057467C]
:004C233D 68E8F45800 push 0058F4E8
:004C2342 68E7030000 push 000003E7
:004C2347 6A0D push 0000000D
:004C2349 6883000000 push 00000083
:004C234E 56 push esi
:004C234F FFD7 call edi
:004C2351 68D0F85800 push 0058F8D0
:004C2356 68E7030000 push 000003E7
:004C235B 6A0D push 0000000D
:004C235D 6884000000 push 00000084
:004C2362 56 push esi
:004C2363 FFD7 call edi
В edi записывается [0057467C](вызов USER32.SendDlgItemMessageA) и edi несколько раз вызывается(то есть вызывается [0057467C] фактически). Вотъ. А мы хоть правильно вообще DOOMаем, может это совсем другие вызовы? Проверим: после вызова call edi проверяем входные параметры, куда должны записаться данные, здесь это 0058F4E8 и 0058F8D0. делаем в софтайсе d 0058F4E8 и смотрим в окно данных: там наше введенное имя. ну раз два вызова стоят вместе, значит в 0058F8D0 лежит наш введенный регномер - так и оказалось. Теперь стираем(или деактивируем) брейкпоинт: bc 00 (или bd 00). и ставим новый, на адрес строки с регномером, то есть: bpm 0058F8D0. F5. Прерываемся на:
:004C1DE2 880C07                  mov byte ptr [edi+eax], cl
:004C1DE5 40 inc eax
:004C1DE6 84C9 test cl, cl
:004C1DE8 75F6 jne 004C1DE0
:004C1DEA 8D942414010000 lea edx, dword ptr [esp+00000114]
:004C1DF1 8D4C2410 lea ecx, dword ptr [esp+10]
:004C1DF5 E886FDFFFF call 004C1B80
:004C1DFA 85C0 test eax, eax
:004C1DFC 7410 je 004C1E0E
:004C1DFE 5F pop edi
:004C1DFF 5E pop esi
:004C1E00 5D pop ebp
:004C1E01 B801000000 mov eax, 00000001
:004C1E06 5B pop ebx
:004C1E07 81C408020000 add esp, 00000208
:004C1E0D C3 ret
Сейчас мы в цикле. Давайте нажмем на F12. Мы попали сюда:
:004C236F E81CFAFFFF              call 004C1D90
:004C2374 85C0 test eax, eax << стоим здесь
:004C2376 0F84BB000000 je 004C2437
мы только что были в некой функции 004C1D90. После выполнения test eax, eax я попробовал модифицировать флаги(команда r -> окажемся вверху экрана софтайса и ищем флаг Z(флаг нуля). Стоя на нем нажимаем Insert, затем Enter). Кто не въехал, как менять, сделайте так: стоя на команде je, пишем eb eip и меняем в окне данных 84 на 85. :)) Только не забудьте потом сменить обратно. Теперь нам сказали спасибо за регистрацию. :)) Следовательно, 004C1D90 - что-то вроде процедуры регистрации, которая устанавливает EAX(ее результат). Кому непонятно, то вот вам пример на C:
int CheckRegistr()
{
... некий код ...
if(!registered)return 0;
else return 1;
}
...
// а где-то вызов ее:

if(CheckRegistr()==1)MessageBox(NULL,"Thanks for registering!!",NULL,MB_OK);
// "==1" можно и не писать :)
Вот так и тут: 004C1D90 - эта самая CheckRegistr(). Только тут ассемблер, результат передается через EAX. Учитывая, как работают команды je и test(см доки по ассемблеру) решаем, что эта процедура должна в EAX возвращать 1! А кстати, вот отрывок, который это делает(снова взят, см выше):
:004C1DF5 E886FDFFFF              call 004C1B80
:004C1DFA 85C0 test eax, eax
:004C1DFC 7410 je 004C1E0E
:004C1DFE 5F pop edi
:004C1DFF 5E pop esi
:004C1E00 5D pop ebp
:004C1E01 B801000000 mov eax, 00000001
:004C1E06 5B pop ebx
:004C1E07 81C408020000 add esp, 00000208
:004C1E0D C3 ret
Ну короче 004C1B80 - еще какая-то процедура проверки, все мудрено. Но вот видим заветные команды: mov eax, 00000001 и ret. То есть процедура возвращает 1. Но этому не бывать, если благодаря процедуре 004C1B80 сработает условный переход je 004C1E0E, перепрыгнув mov eax, 00000001 (очевидно там где-то дальше по коду возвратится 0). Так значит, узнаем смещение команды je 004C1E0E и забиваем ее двумя нопами(потому что команда двубайтовая - 0x74 и 0x10) в HIEW. Теперь по идее везде, где вызвается эта процедура проверки, будет выдаваться, что мы зарегены. Но программа перестала запускаться :( Тогда я попробовал сделать loader на ассемблере, вот его исходный код(компилируется в MASM32):
===================================
.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
App db "mIRC 6.12",0
Err1 db "Program not found :(",0
prog db "MIRC.EXE",0
vastart DWORD 4C1DFCh

.data?
bufr dw ?
pinfo PROCESS_INFORMATION <>
sinfo STARTUPINFO <>
n DWORD ?
.code

start:

JMP STARTUHA

PATCHER PROC RVA:DWORD,WR:DWORD
INVOKE ReadProcessMemory,pinfo.hProcess,RVA,addr bufr,1,n
invoke WriteProcessMemory,pinfo.hProcess,RVA,ADDR WR,1,n
RET
PATCHER ENDP

STARTUHA:
invoke CreateProcess,addr prog,NULL,NULL,NULL,FALSE,
CREATE_NEW_CONSOLE OR NORMAL_PRIORITY_CLASS,NULL,NULL,addr sinfo,addr pinfo
.IF EAX == 0
invoke MessageBox,NULL,addr Err1,addr App,MB_OK
invoke ExitProcess,0
.ENDIF

INVOKE ReadProcessMemory,pinfo.hProcess,vastart,addr bufr,1,n
.IF EAX != 0
.IF bufr == 74h
invoke SuspendThread,addr pinfo.hThread

INVOKE PATCHER,4C1DFCh,90h ; ВОТ! ВОТ главное место программы!
; здесь производится запись в память процесса mIRC
INVOKE PATCHER,4C1DFDh,90h

invoke ResumeThread,addr pinfo.hThread
invoke CloseHandle,pinfo.hThread
invoke ExitProcess,0
RET
.ENDIF
.ENDIF

end start
Лоадер работает, все ОК(только не вздумайте запускать его на уже патченной проге). НО и это не самый лучший вариант. Например, надо передавать mIRC параметры командной строки, тут надо дописывать. И вообще в случае того, что прога не запакована, лучше покопаться, и я решил вскрыть защиту до конца.

Из того, что работал лоадер, следует, что прога проверят на измененность сам свой исполняемый файл, а не шарит по своей памяти. Значит, проге надо узнать, где она находится, имя .exe-шника, короче. Опять пригождается опыт программирования под win32: это можно сделать при помощи вызова апишки GetModuleFileNameA. Ставим на нее бряк. bpx GetModuleFileNameA. Она при старте вызывается несколько раз. И самое интересное происходит при третьем ее вызове - два других это обработка ком. строки и еще что-то. Значит после срабатывания надо нажать два раза на F5, потом F12. Итак, а как вообще стоит поступать в подобных случаях? У меня при себе имеются два экземпляра проги: непатченный(запускается) и патченный(не запускается). Так вот, надо протрейсить вручную код и посмотреть, как ведут себя разные условные переходы. То есть после третьего срабатывания GetModuleFileNameA идем по коду и записываем на листочек адреса всех встретившихся условных переходов и приписываем - сработал или нет. Такую работу следует провести с каждым экземпляром проги. Так вот, там дальше будет порядочных размеров код с огромным циклом с подциклами :) Новичкам не очень сойдет. Нажмем на F12 и увидим, что только что были в процедуре(видимо подпроцедуре проверки целостности):
:004D488F E8CCFDF7FF              call 00454660 << отсюда вернулись
:004D4894 83F802 cmp eax, 00000002 << сравнили результат с 2
:004D4897 741B je 004D48B4
:004D4899 83F803 cmp eax, 00000003
:004D489C 7416 je 004D48B4
:004D489E 33C9 xor ecx, ecx
:004D48A0 E81B920000 call 004DDAC0
:004D48A5 33D2 xor edx, edx
:004D48A7 85C0 test eax, eax
:004D48A9 0F95C2 setne dl
:004D48AC A35CA15900 mov dword ptr [0059A15C], eax
:004D48B1 8BC2 mov eax, edx
:004D48B3 C3 ret

* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
|:004D4888(C), :004D4897(C), :004D489C(C)
|
:004D48B4 33C0 xor eax, eax
:004D48B6 C3 ret
Так вот, если не сработает ни один из je 004D48B4, то прога запустится, а иначе мы прыгнем на xor eax, eax и будет плохо :) Значит вставляем по два nop по адресам 004D4897 и 004D489C и прога заработает. :0)

bi0w0rM[AHTeam]
(c) 9 Mar 2004
SiTE : bioworm.narod.ru
AHTeam: www.ahteam.org

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

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