Przechwycenie funkcji systemowej

0

Witam.

Chodzi o przechwycenie funkcji systemowej takiej jak ReadFile, żeby moznabyło napisac własną procedurę obsługi (nie wazne jaką, bo i tak potem bedzie sie wywoływało oryginalną).

coś takiego jak w dosie była obsługa przerwań, szło przejąć przerwanie, zapamietac jego adres, wykonać swój kod, a potem wywołać oryginalną funkcje przerwania.

Z góry dzięki za wszelkie informacje.

Pozdrawiam.

0

Nadpisać pierwszy bajt funkcji bajtem 0xCC, zainstalować globalną obsługę wyjątków i obsłużyć EXCEPTION_BREAKPOINT ?

#include <windows.h>
#include <stdio.h>

LONG WINAPI MyHandler(EXCEPTION_POINTERS*);
char cWriteFile;

int main()
{
	// zapamiętaj oryginalny bajt
	ReadProcessMemory(GetCurrentProcess(), WriteFile, &cWriteFile, 1, 0);
	// podmień go
	char bp = '\xCC';
	WriteProcessMemory(GetCurrentProcess(), WriteFile, &bp, 1, 0);
	// i czekaj na wyjątki
	SetUnhandledExceptionFilter(MyHandler);

	DWORD d;
	WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), "\n** WriteFile **\n", 19, &d, 0);
	return 0;
}



LONG WINAPI MyHandler(EXCEPTION_POINTERS* ExceptionInfo)
{
	static bool singlestep = false;
	LONG status = EXCEPTION_CONTINUE_SEARCH;
	// uwaga! printf używa WriteFile

	if (ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_BREAKPOINT)
	{
		// sprawdż czy breakpoint jest postawiony przez nas
		// * użyj linked list zamiast adresów
		if (ExceptionInfo->ExceptionRecord->ExceptionAddress == (LPVOID)WriteFile)
		{
			// usuń breakpoint
			WriteProcessMemory(GetCurrentProcess(), WriteFile, &cWriteFile, 1, 0);
			// ustaw tryb single-step (flaga Trap) aby ponownie zainstalować breakpoint
			// po wykonaniu jednej instrukcji
			ExceptionInfo->ContextRecord->EFlags |= 0x100;
			singlestep = true;
			// cofnij licznik rozkazów na były breakpoint
			ExceptionInfo->ContextRecord->Eip = (DWORD)ExceptionInfo->ExceptionRecord->ExceptionAddress;
			status = EXCEPTION_CONTINUE_EXECUTION;

			// teraz można użyć printf (WriteFile)
			printf("ktos uzyl WriteFile %X\n", (DWORD)WriteFile);
		}
	}
	else if (ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_SINGLE_STEP)
	{
		if (singlestep)
		{
			// tryb single-step sam się wyłącza
			printf(" - ustawiam single step\n");
			singlestep = false;
			// ustaw ponownie breakpoint
			char bp = '\xCC';
			WriteProcessMemory(GetCurrentProcess(), WriteFile, &bp, 1, 0);
			status = EXCEPTION_CONTINUE_EXECUTION;
		}
	}
	return status;
}
0

@sapero
Ale podany kod monitoruje wywołanie WriteFile tylko we własnym kontekście , co to daje ?


http://4programmers.net/Forum/viewtopic.php?id=103704

0

to ze ten kod mozesz wstrzyknac do dowolnego procesu ktory cchesz obserowac.. see watek o dllinjection itp

0

Chyba że tak :-) , jakby się jeszcze nie wywalał to by było ok , jest gdzieś błąd ...

0

Może się wywalić tylko wtedy gdy blok try/catch użyty po SetUnhandledExceptionFilter weźmie na siebie oba użyte tu wyjątki. Stanie się tak gdy Twój compiler doda 'try' po kryjomu, co zazwyczaj robi np. alokując klasę na stosie (vs6).

Możliwe też że masz niepoprawnie zdefiniowane importowane funkcje - symbol WriteFile powinien być zdefiniowany jako dllimport zamiast extern, czyli używając tego symbolu - ukrycie odnosisz się do zawartości __imp__WriteFile w którym jest 'bezpośredni' adres do kernel32.
Proponuję zmianę WriteFile na GetProcAddress, wtedy nie będzie tego wymogu.
Zmień wszystkie tokeny 'WriteFile' na 'fnWriteFile' oprócz wywołania funkcji:

char cWriteFile;
FARPROC fnWriteFile; // dodane

int main()
{
	char bp = '\xCC';
	fnWriteFile = GetProcAddress(GetModuleHandle("kernel32.dll"),"WriteFile"); // dodane
	ReadProcessMemory(GetCurrentProcess(), fnWriteFile/*zmiana*/, &cWriteFile, 1, 0);
0

Mimo wszystko jest jakis problem.
Funkcja WriteFile z main wywołuje int 3 ok .
Nastepuje wywołanie Handlera ok.
Wkonuje sie funkcja printf w Handler ok.
Powrót do main - nie ok .
Następuje Access Violation .

Program wyświetla printf z Handlera "ktos uzyl WriteFile 77E79D8C"
Naruszenie pamięci następuje pod adresem "77E79D8D"
wnioskuję z tego że po powrocie z Handlera wykonanie programu nie trafia "dokładnie"
w funkcję WriteFile lecz o jeden bajt za daleko ...trzeba cofnąc EIP o 1 .
nie wykonuje się poprawnie :
WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), "\n** WriteFile **\n", 19, &d, 0);

No ale nie zawracam gitary , jak złapie natchnienie to coś z tym zrobię .
Pozdro .

0

Ponieważ adres z "ktos uzyl WriteFile 77E79D8C" zgadza się z moim, stwierdzam że mamy identyczne wersje systemu.
WriteFile zaczyna się rozkazem push 18h, co po założeniu pułapki zmienia się w:

int3 ; 1 bajt
sbb [eax+20h],ch ; 3 bajty, w tym tylko pierwszy należy do push

w MyHandler gdy obsługiwany jest "zakazany rozkaz" int3 - przywracam nadpisany pierwszy bajt funkcji i cofam eip na adres gdzie była pułapka (na początek funkcji), gdzie powinno być oryginalne "push".
W moim systemie ExceptionInfo->ExceptionRecord->ExceptionAddress wskazuje dokładnie na adres int3, więc tu ustawiam eip, ale w Twoim widocznie jakaś magiczna jedynka się dodała i program zaczyna w połowie "push" - odejmuje cośtam z adresu 0x00000027 (eax=7 +0x20), tak jakby zmiana eip została zignorowana.

Proponuję następną zmianę:

// case EXCEPTION_BREAKPOINT
ExceptionInfo->ContextRecord->Eip = (DWORD)fnWriteFile;

IP jest ustawiany na z góry znany adres, więc powyższy problem z magiczną jedynką zostaje wyeliminowany.

Dziwne zjawisko, może masz rootkita dowcipnisia [green]

0

Kźwa to jakiś beton [glowa] , nic się nie zmienilo , ale nie ważne .
na razie kończę , wrzucam jeszcze zapytanie czy konieczna jest manipulacja

EXCEPTION_POINTERS* ExceptionInfo <-- Tym , nie widać specjalnie wpływu

jeśli zwracany identyfikator EXCEPTION_CONTINUE_EXECUTION i tak nakazuje wykonanie
kodu od instrukcji która wywołała wyjątek ?

Poza to jeśli u Ciebie ten kod działa to może mój kompilator cos kompilatorokombinuje...

0

Zakładając że WriteFile to adres ZERO:

  1. skaczemy sobie do tej funkcji, ale pierwszy bajt to int 3, który wywołuje exception. EIP zmienia się na następny rozkaz, więc jest równe 1, a kontrola przechodzi do handlera.
  2. w handlerze przywracamy podmieniony bajt więc int 3 jest usunięty a eip zmieniamy na zero, więc po powrocie z handlera funkcja WriteFile zaczyna od początku, ale...
  3. Ustawiamy też flagę Trap (EFlags bit 8) więc funkcja WriteFile po wykonaniu jednej instrukcji spowoduje exception SINGLE_STEP, <ort>wykożystałem</ort> to aby przwrócić chwilowo zablokowany breakpoint.

Dla tych co nie wiedzą: po wyjściu z handlera system robi SetThreadContext(current thread, ExceptionInfo->ContextRecord), więc cokolwiek zmienimy w CONTEXT zostanie zmienione w wątku który spowodował błąd. Na przykład zmieniając ContextRecord->Eip na adres funkcji ReadFile - przekierujemy WriteFile na ReadFile w tym przypadku.
Nie wiem jak u innych z automatycznym resetowaniem flagi Trap, dla stuprocentowej pewności można ją jawnie wyzerować w obsłudze EXCEPTION_SINGLE_STEP:

ExceptionInfo->ContextRecord->EFlags &= ~0x100;

dzejo napisz:

__asm {
	pushf
	or   DWORD PTR[esp],0x100
	popf
	nop
}

pierwsza instrukcja po 'nop' spowoduje EXCEPTION_SINGLE_STEP (najpierw zostanie wykonana)
XP wykrywa że ta flaga jest ustawiona i ją zeruje zanim skoczy do handlera, więc działa to jak guard - jednokrotne exception (przynajmniej ten z SP2 zeruje flagę)

0

Dzięki z super objaśnienie , muszę prześledzić dokładnie sterowanie w programie .
Używam C++ Builder 3 i przeważnie śledzenia w trybie kodu w edytorze bo to wygodne [green] ,
jednak śledzenie programu napisanego w ten sposób jest mocno utrudnione , uruchamia
się tryb Debugera CPU ......

Muszę obejrzeć początek funkcji WriteFile (nie modyfikowanej) u siebie , bo jeśli na początku nie ma tam instrukcji
1-bajtowej ale np 2-bajt (chociaż powinna być 1) to właśnie program powinien działać w taki wykolejony sposób jak działa ,kod z trap się nie wykona i funkcja się wywali na ryja (wykona się jedna instrukcja ale będzie niepoprawna i zostanie wygenerowany wyjątek EA..Violation , tak myślę ) ,ale
z tego co pamiętam z widoku z wszczepionym int3 to jest tam jakaś kaszanka , bo powinno to chyba
wyglądać tak ( bez int3 ) :

push ebp           1bajt funkcji
mov ebp, esp

a po zaszczepieniu :

int 3
mov ebp, esp
                                                                                      Narazie tyle idę orać do roboty
                                                                                      Jeszcze raz dzięki za wyjaśnienia .

Mam jeszcze parę pytań ale , potem...


Teraz jestem na innym kompie (trochę inna wersja systemu ) i początek funkcji WriteFile
wygląda tak :

6A18           push 0x18
683810817C     push 0x7C811038
E82015FFFF     call -0x0000eae0
.........
.........

Dla mnie dziwnie ..., tyle że podmiana 2 bajtów (drugi NOP ) nie poprawiła sytuacji
........
........
=====================================Ciemna NOC-------------------
Doszedłem do fragmentu kodu który działa ,niestety wszelkie
próby jego udoskonalenia powodują nieprawidłowe działanie
programu .
Handlery są po prostu skopane i nie działają zgodnie z opisem .
Nie mogę użyć takich rzeczy :

1)Handler zawsze musi zwracać wartość "EXCEPTION_CONTINUE_SEARCH"
zmiany kontekstu Eip nie mają znaczenia.
2)Użycie "EXCEPTION_CONTINUE_EXECUTION" powoduje nie wykonanie
WriteFile z main .
3)Włączenie trybu step powoduje nie wykonanie WriteFile z main .

Konieczność zwracania "EXCEPTION_CONTINUE_SEARCH" powoduje
wykonanie systemowego Handlera -> UnhandledExceptionFilter
który wyświetla okno o zaistniałym wyjątku , umożliwia to
jednak poprawne wykonanie kodu po powrocie do main .

Czyli coś tam działa ale nie tak jak w księgach piszą , do kitu
to wszystko .</li> </ol>

Jedyny kod działający cokolwiek jaki udało mi się sklecić ,reszta
warjantów poległa (nie działa) :

#include <windows.h>
#include <stdio.h>

LONG WINAPI MyHandler(EXCEPTION_POINTERS*);
char cWriteFile[10];
char bp[] = {'\xCC','\x90'} ;  // używam tylko pierwszego bajtu
FARPROC fnWriteFile;
DWORD d;
const int byteIndex = 1 ;      // pierwszy (jeden bajt)

int main()
{
        // zapamiętaj oryginalny bajt
        fnWriteFile = GetProcAddress(GetModuleHandle("kernel32.dll"),"WriteFile"); // dodane
        if(fnWriteFile== NULL )
        {
          WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), "\n** ErrorModule **\n", 19, &d, 0);
          system("pause");
        }
        ReadProcessMemory(GetCurrentProcess(), fnWriteFile/*zmiana*/, cWriteFile, byteIndex,0);
        WriteProcessMemory(GetCurrentProcess(),fnWriteFile, bp, byteIndex, 0);
        // i czekaj na wyjątki
        SetUnhandledExceptionFilter(MyHandler);

        WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), "\n** WriteFile **\n", 18, &d, 0);
        system("pause") ;
        return 0;
}



LONG WINAPI MyHandler(EXCEPTION_POINTERS* ExceptionInfo)
{
        //static bool singlestep = false;
        DWORD dwExceptionCode ;
        LONG status ; //= EXCEPTION_CONTINUE_SEARCH; ???
        // uwaga! printf używa WriteFile

        dwExceptionCode = ExceptionInfo->ExceptionRecord->ExceptionCode ;

        switch (dwExceptionCode)
        {
          case EXCEPTION_BREAKPOINT:
          if (ExceptionInfo->ExceptionRecord->ExceptionAddress == (LPVOID)fnWriteFile )
          {
            WriteProcessMemory(GetCurrentProcess(),fnWriteFile,cWriteFile, byteIndex, 0);
            printf("EXCEPTION_BREAKPOINT\n");
            printf("ktos uzyl WriteFile %X\n", (DWORD)fnWriteFile);
          }

          break;
          case EXCEPTION_SINGLE_STEP :
                                //???????????????????
          break ;
          default:
          status = EXCEPTION_CONTINUE_SEARCH;

        }
              status = EXCEPTION_CONTINUE_SEARCH ;

        return status;
}

Normalnie Ruina , ktoś coś może na to powie ...np. o co kurna
chodzi ?????
Odnośnie EAccessViolatorów , to występowały z powodu użycia Debugera , po prostu przeszkadzał
w obsłużeniu wyjątku ( int3) menda jedna [rotfl] .
Założenie filtra w Handlerze EXCEPTION_ACCESS_VIOLATION i uruchomienie programu bez Debuga
nie wyłapało niczego szczególnego .

Kod oparty na try i __except działa poprawnie , ale to lokalna obsługa i takiego kodu wcisnąć
się nigdzie nie da ( tzn .da się ale nie ma po co ) :

#include <windows.h>
#include <stdio.h>
#include <conio.h>

LONG ExceptionFltr(EXCEPTION_POINTERS* pEx);

//------------------------------------------------------------------------------
char cWriteFile[10];
char bp[] = {'\xCC','\x90'} ;
FARPROC fnWriteFile;
DWORD d;
const int byteIndex = 2 ;

int main()
{

        fnWriteFile = GetProcAddress(GetModuleHandle("kernel32.dll"),"WriteFile"); // dodane

        if(fnWriteFile== NULL )
        {
          WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), "\n** ErrorModule **\n", 19, &d, 0);
          system("pause");
          return 1 ;
        }

        ReadProcessMemory(GetCurrentProcess(), fnWriteFile, cWriteFile, byteIndex,0);

   while(true)
  {

     try{

        WriteProcessMemory(GetCurrentProcess(),fnWriteFile, bp, byteIndex, 0);

        WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), "\n** WriteFile **\n", 18, &d, 0);

        }
        __except( ExceptionFltr( GetExceptionInformation()) )
        {
        }

        if(27 == getch()){break;}

   }
        return 0;
}

//----------------------------------------------------------------------------------
LONG ExceptionFltr(EXCEPTION_POINTERS* pEx)
{
   LONG status ;
   DWORD dwExceptionCode ;
   dwExceptionCode = pEx->ExceptionRecord->ExceptionCode ;

        switch (dwExceptionCode)
        {
          case EXCEPTION_BREAKPOINT:
          if (pEx->ExceptionRecord->ExceptionAddress == (LPVOID)fnWriteFile )
          {
            WriteProcessMemory(GetCurrentProcess(),fnWriteFile,cWriteFile, byteIndex, 0);
            printf("EXCEPTION_BREAKPOINT\n");
            printf("Ktos uzyl WriteFile %X\n", (DWORD)fnWriteFile);
            status = EXCEPTION_CONTINUE_EXECUTION ;
          }

          break;
          case EXCEPTION_SINGLE_STEP :
          status = EXCEPTION_CONTINUE_EXECUTION ;
                        // Niekonieczne
          break ;
          default:
          status = EXCEPTION_CONTINUE_SEARCH;

        }

   return status ;
}
0

Pierwsze co zrób to sprawdź co robi SetUnhandledExceptionFilter w twoim exe lub obj, czy jest to standardowy import, czy może jakiś klocek borlanda. Jeśli to drugie to lepiej zmień deklarację tej funkcji na dllimport, albo np. użyj tej funkcji dynamicznie pobierając jej adres przez GetProcAddreee(kernel32).

Nawiasem mówiąc - mógłbyś gdzieś wysłać skompilowanego exe (tego co nie działa), są ludzie którzy mają dobre narzędzia do szukania "błędów" i wiedzą jak to robić :)

Apropos try{} - w excpt.h masz zdefiniowaną podstawową funkcję do obsługi wyjątków - jest to _except_handler, a to jeden z prostszych sposobów użycia go
// sprawdź ile razy wyświetli się numer błędu - jeśli raz, to znaczy że zmiana Eip działa (int3 występuje dwukrotnie, ale ponieważ w vs6 nie wie co to jest int3 - wstawiłem dwubajtowe "int 3" które na szczęście skompilowało się jako to jednobajtowe)

#include <excpt.h>
//struct node {node* next; _except_handler; any data here}

int main()
{
	// prawdziwa instalacja try
	__asm {
		push offset _except_handler // nowy handler
		push fs:0 // stary handler
		mov fs:0,esp // dodaj node do 'SEH'
	}

	// jakiś kod z wyjątkami
	printf("robimy exception ");
	_asm int 3 // int3 nie rozpoznawalne?
	_asm int 3
	printf("gotowe!\n");

	// leave
	_asm {
		pop dword ptr fs:0  // usuwa node i przywraca stary handler
		add esp,4 // usuwa adres _except_handler
	}
	return 0;
}


EXCEPTION_DISPOSITION _except_handler(EXCEPTION_RECORD *ExceptionRecord,void * EstablisherFrame,CONTEXT *ContextRecord,void * dispatcherContext)
{
	// default is unhandled
	EXCEPTION_DISPOSITION status = ExceptionContinueSearch;
	printf("%X ", ExceptionRecord->ExceptionCode);
	switch (ExceptionRecord->ExceptionCode)
	{
	case EXCEPTION_BREAKPOINT:
		// poprawne dla 2 * int3 = 0xCC,0xCC
		ContextRecord->Eip = (DWORD)ExceptionRecord->ExceptionAddress + 2; // pomiń oba int3
		status = ExceptionContinueExecution;
	}
	return status;
}

Czym się różni 'try' od SetUnhandledExceptionFilter?
Tym, że 'try' działa tylko dla aktualnego wątku, a SetUnha... w każdym wątku działającym teraz lub w przyszłości zostaje wymuszone zainstalowanie takiego 'try'. Funkcja ta zwraca adres poprzedniego handlera który można przywrócić tą samą funkcją.

0

Zaczyna mi szczęka opadać , z kąd Ty bierzesz ten kod ?
Ciekawe rzeczy [green] .
Spróbuję raczej z dynamicznym ladowaniem SetUnhExxx,
Ostatni kod który podałeś (chociaż mi się bardzo podoba) nie da się skompilować na BCB
( nie męcze już dla czego bo kod jest ok tylko kompilator do d..).

Właściwie to te informacje wystarczą mi na pare dni eksperymentów , myślę że
przepiszę pierwszy kod (pier. w wątku ) który podałeś na MASM32 żeby mieć jasność że nie jest to wina
systemu lub zimnej wody w kranie .
Podpieram się trochę Jeffrey Richter "Programowanie Aplikacji dla Ms Windows" i
wiem jak to "powinno działać" .
Nie chcę niczego poddawać w wątpliwość , wnioskując z postów używasz Vc6 i czy
począwszy od pierwszego postu w tym wątku przykłady które podawałeś chodzą tak "jak w książce pisze" ??? Bo jestem już trochę zamotany między tym co powinno być a co z tego wychodzi :-D .
Jeszcze raz dzięki za podpowiedzi , na razie przeryję trochę kodu co może spowodować Wait() wątku.

0

Wszystkie te przykłady zostały napisane w vc6 i działały zgodnie z planami.
Może nadmienię że wszystkie biblioteki zostały oczyszczone z kodu (libc.lib też) i pozostały w nich tylko importy, więc nawet takie funkcje jak printf, malloc - 'skaczą' bezpośrednio do odpowiedniego dll.
Co do obsługi wyjątków - przeczytaj bloga Matt'a http://www.microsoft.com/msj/0197/exception/exception.aspx

0

Ok , dzięki za potwierdzenie .
Dodam jeszcze że w BCB taki kod :


        // zapamiętaj oryginalny bajt
        ReadProcessMemory(GetCurrentProcess(), WriteFile, &cWriteFile, 1, 0);

Czyli pobranie adresu WriteFile, prowadzi do pobrania adresu do Tablicy jump ( czyli adres jest 40XXXX)
w obrazie pliku .exe i dopiero z tablicy wykonywany jest skok do kernel32 ( no zresztą wiesz o co chodzi ) . Dla tego prosiłem o potwierdzenie , bo nadpisywanie w takim przypadku danych z uzyskanego
adresu mija się ( dosłownie z celem ).To jeszcze mozna darować ,ale SetUnhandledExc.. to chyba nie ?
Oznacza to że BCB i Vc6 jeśli chodzi o kompilacje programów konsolowych (i pewnie nie tylko ) stosujących dziwne techniki ( dziwne :-D API to API ) czasami się różnią (wtopa) i w przypadku BCB
mogą być problemy z kodem podawanym w literaturze i przez programistów drążących tematy
bardziej "od środka" . Faktem staje się to że API oferowane przez BCB nie jest zgodne z opisami
Win32 Reference .Trochę szkoda bo lubię to coś , no ale nie ma rzeczy doskonałych na tym świecie
na razie [green]

(edit)
Fajne :

2. extern "C" __declspec(dllimport) int __stdcall api2();

Co nie zmienia faktu że coś jest skopane , przekierowanie czyli wariant 1) nie powinien prowadzić
np . do odmiennego działania obsługi wyjątków .

0

Każde api można zdefiniować na dwa sposoby:

  1. extern "C" int __stdcall api();
  2. extern "C" __declspec(dllimport) int __stdcall api2();

Pierwsza definicja powiększa kod bo odwołanie do api() skacze do jumpa:

  call _Sleep@4
...
_Sleep@4: jmp [__imp__Sleep@4]

natomiast druga definicja pobiera adres docelowej funkcji z labela __imp__api2@0 i właśnie tej używam w moim vc, gdzie WriteFile zwraca zwyczajny adres funkcji w dll'u

  call [__imp__Sleep@4]

Być może trzeba zmodyfikować kilka #define w headerach :)

0

Tylko wydaje mi się że to trochę ryzykowna sprawa.
w przypadku adresowania funkcji z obrazu pliku exe (przekierowanie) odpowiedzialność
za umieszczenie poprawnych adresów spada na program ładujący exe do pamięci ( system )
i jest to bezpieczne.
W przypadku 2 program po kompilacji zawiera adresy bezpośrednie do .dll , co
oznacz że przeniesienie takiego programu na inną wersję systemu spowoduje
to że program może nie działać ( a raczej nie będzie działać :-/ ).
Chyba że się mylę.

Pozostał bym przy rozwiązaniach dynamicznych :

 fnWriteFile = GetProcAddress(GetModuleHandle("kernel32.dll"),"WriteFile"); // dodane

.....
...
....Jeszcze kombinuję
16,02

0

Rozwiązanie .
Kod działający po Kompilacji Borlandem , zawiera instalację Handlera w asm (Sapero ) ,
Kurcze walnąłem się troszkę i powinno to działać już wcześniej :| .
Teraz działa superowo (Saperowo :-D ) .

#include <windows.h>
#include <excpt.h>
#include <stdio.h>

EXCEPTION_DISPOSITION  _except_handler(EXCEPTION_RECORD *ExceptionRecord,
       void * EstablisherFrame,CONTEXT *ContextRecord,void * dispatcherContext) ;

char cWriteFile[10];
char bp[] = {'\xCC','\x90'} ;  // używam tylko pierwszego bajtu
FARPROC fnWriteFile;
const int byteIndex = 1 ;      // pierwszy (jeden bajt)
DWORD d ;

int main()
{

        fnWriteFile = GetProcAddress(GetModuleHandle("kernel32.dll"),"WriteFile"); // dodane
        if(fnWriteFile == NULL )
        {
          printf("Error->GetProcAddress->WriteFile\n");
          system("pause");
          return 1 ;
        }

//---------Instaluj Handler

         DWORD handler = (DWORD)_except_handler;

        // prawdziwa instalacja try
        __asm {
                push  handler // nowy handler
                push fs:0 // stary handler
                mov fs:0,esp // dodaj node do 'SEH'
        }

// zapamiętaj oryginalny bajt
        ReadProcessMemory(GetCurrentProcess(), fnWriteFile/*zmiana*/, cWriteFile, byteIndex,0);
// zapisz int3
        WriteProcessMemory(GetCurrentProcess(),fnWriteFile, bp, byteIndex, 0);
        // i czekaj na wyjątki

        WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), "\n**WriteFile**z main**\n", 22, &d, 0);

        _asm {
                pop dword ptr fs:0  // usuwa node i przywraca stary handler
                add esp,4 // usuwa adres _except_handler
        }

        system("pause") ;
        return 0;
}


//------------------------------------------------------------------

EXCEPTION_DISPOSITION  _except_handler(EXCEPTION_RECORD *ExceptionRecord,
       void * EstablisherFrame,CONTEXT *ContextRecord,void * dispatcherContext)
{
        DWORD dwExceptionCode ;
        EXCEPTION_DISPOSITION status = ExceptionContinueSearch;
        // uwaga! printf używa WriteFile

        dwExceptionCode = ExceptionRecord->ExceptionCode ;

        switch (dwExceptionCode)
        {
          case EXCEPTION_BREAKPOINT:
          if (ExceptionRecord->ExceptionAddress == (LPVOID)fnWriteFile )
          {
            status = ExceptionContinueExecution;
            WriteProcessMemory(GetCurrentProcess(),fnWriteFile,cWriteFile, byteIndex, 0);

            /*ContextRecord->Eip =
            (DWORD)ExceptionRecord->ExceptionAddress;*/

            printf("EXCEPTION_BREAKPOINT\n");
            printf("ktos uzyl WriteFile %X\n", (DWORD)fnWriteFile);
          }

          break;
          case EXCEPTION_SINGLE_STEP :
                                //???????????????????
          break ;
          default:
          status = ExceptionContinueSearch;

        }

        return status ;  
}

http://www.phearless.org/i3/Exploiting_Stack_Bof_over_SEH.txt .

Wydaje mi się że kod w Borlandzie obsługi SEH za pomocą
SetUnhandledExceptionFilter jest zastępowany przez obsługę
wyjątków C++ (lub jest nim obudowany ?) , wnioskuję tak po problemach ze zwrotem
przez Handler wartości EXCEPTION_CONTINUE_EXECUTION , jest ona traktowana
jako błąd w obsłudze wyjątków C++ .
I to chyba na tyle .
(Pozostaje jeszcze sprawdzenia EXCEPTION_SINGLE_STEP , ale się mi na razie nie chce.)

0

Nie wiem czy to wiesz, ale WriteFile zostanie przechwycone tylko raz jeśli użyjesz swojego pierworodnie działającego kodu. W c++ sporo funkcji istniejących w standardowych dllach jest na siłę wpychanych w kod programu - np. printf, malloc, strlen... i nie wiem czy ktokolwiek wie jako ma to sens, poza zwiększaniem programu i zapotrzebowaniem na pamięć. Przecież wszystkie te funkcje są w crtdll.dll i msvcrt.dll.
Dawno temu to odkryłem i pokasowałem wszelki kod z plików .lib, zmodyfikowałem nagłówki tak, aby zewnętrzne symbole były z przedrostkiem _imp jako że wymusza to linkowanie z dll'ami.

Efekty? Pomijając obrzydliwe działanie popularnego linkera link.exe (pokraczne generowanie objektów i plików exe/dll) można się pochwalić minimalnym rozmiarem skompilowanego programu około 10KB, bez żadnej szkody
W Twoim przypadku musiało być podobnie jak z printf - gdzieś w libc.lib lub "obok" jest kod źle implementujący funkcję SetUnhandledExceptionsFilter.

Wyjaśniam Twoją niepewność co do statycznego adresu api:
w programie masz tablicę funkcji dla każdego importowanego dll. Każda pozycja wygląda mniejwięcej tak:

funkcja: jmp [__imp_funkcja]
__imp_funkcja: dd ?

gdzie znak zapytania to adres danej funkcji wypełniany podczas ładowania programu do pamięci.
Jeśli funkcja jest zdefiniowana jako "extern", to odwołując się do niej program skacze do jump'a, a jeśli funkcja jest zdefiniowana jako "dllimport" to kod odwołuje się bezpośrednio do zawartości zmiennej __imp_funkcja gdzie jest bezpośredni adres danego api (a pierwszy jump nie jest dodawany do programu).
Więc gdy funkcja WriteFile jest zdefiniowana jako __declspec(dllimport), to symbol WriteFile zawiera/zwraca adres do początku właściwej funkcji, a nie adresu jumpa do niej (jest on labelem __imp_WriteFile, ale prefix _imp jest ukryty przed programistą)

Wydaje mi się że kod w Borlandzie[...]
Gdzie link do tego .exe?

0

ale WriteFile zostanie przechwycone tylko raz jeśli użyjesz swojego pierworodnie działającego kodu

Wiem o tym , chodziło mi głównie o to aby ten cholerny Handler załapał tak jak powinien , i udało się ,
resztę pozostawiam ... .
Też mi się wydaje że Fun. SetUnhandled... jest gdzieś skopana .
I dzięki za resztę wyjaśnień odnośnie jmp i całej reszty .

Link do .exe ... nie zamieszczam , sądzę że nie ma co tak bardzo mordować tematu .
Pozdro dzejo .

0

oj ludzie, ludzie... kombinujecie jak konie pod górę:

#include <windows.h>
#include <stdio.h>

void MemWrite (void* dest, void* src, int size=1) 
{ 
  DWORD written;
	WriteProcessMemory (GetCurrentProcess(), dest, src, size, &written); 
};

LONG WINAPI UnhandledExceptionFilter( EXCEPTION_POINTERS* ExceptionInfo);

void* pWriteFile;
static unsigned char int3 = 0xCC;
static unsigned char org_byte;
static unsigned long count;

static char info1 [] = "[PROGRAM] wywolanie WriteFile powodujace breakpointa\n";
static char info2 [] = "[PROGRAM] ...i znow WriteFile...\n";
static char info3 [] = "[PROGRAM] ...i jeszcze raz WriteFile...\n";
static char info4 [] = "[PROGRAM] cos komus to moze przypomina? :>\n";

int main ()
{
  DWORD written;

	pWriteFile = (void*) GetProcAddress (GetModuleHandle("kernel32.dll"), "WriteFile");

	org_byte = *(char*)pWriteFile;

	SetUnhandledExceptionFilter(&UnhandledExceptionFilter);

	printf ("[BPX] Ustawianie breakpointa na WriteFile - adres: %lx\n", pWriteFile);
	MemWrite (pWriteFile, &int3);

	HANDLE StdOut = GetStdHandle(STD_OUTPUT_HANDLE);
	WriteFile (StdOut, &info1, sizeof(info1)-1, &written, 0);
	WriteFile (StdOut, &info2, sizeof(info2)-1, &written, 0);
	WriteFile (StdOut, &info3, sizeof(info3)-1, &written, 0);
	WriteFile (StdOut, &info4, sizeof(info4)-1, &written, 0);

	MemWrite (pWriteFile, &org_byte);
	printf ("[BPX] Usunieto breakpointa na WriteFile - uaktywniony %lu razy\n", count);

	return 0;
};

LONG WINAPI UnhandledExceptionFilter (EXCEPTION_POINTERS* ExceptionInfo)
{
	switch(ExceptionInfo->ExceptionRecord->ExceptionCode)
	{
	case EXCEPTION_BREAKPOINT:
		if (ExceptionInfo->ExceptionRecord->ExceptionAddress != pWriteFile) 
			return 1; // jezeli nie nasz breakpoint - spadamy
		
		ExceptionInfo->ContextRecord->EFlags |= 0x100;	
		MemWrite (pWriteFile, &org_byte);

		printf ("[UEF] Wylapano wywolanie WriteFile z adresem powrotu %lx. Ustawianie Trap Flag\n", 
			*(DWORD*)ExceptionInfo->ContextRecord->Esp);

		return EXCEPTION_CONTINUE_EXECUTION;
	case EXCEPTION_SINGLE_STEP:
		DWORD Eip(ExceptionInfo->ContextRecord->Eip), ddWriteFile ((DWORD)pWriteFile);

		// upewniamy sie co do adresu - wielowatkowosc swoje robi...
		// w sumie to wypadaloby zapisywac i oznaczac bp, ale... to tylko przyklad
		if ((Eip < ddWriteFile) || (Eip > ddWriteFile+15)) 
			return 1; // nie nasz breakpoint...

		printf ("[UEF] Pierwsza instrukcja WriteFile zostala wykonana. Ponowne ustawianie breakpointa.\n");

		MemWrite (pWriteFile, &int3);
		count++;

		return EXCEPTION_CONTINUE_EXECUTION;
	default:	// nie masz error? bye bye...
		return 1;
	};
};

Wynik z konsoli:

[BPX] Ustawianie breakpointa na WriteFile - adres: 7c82f42e
[UEF] Wylapano wywolanie WriteFile z adresem powrotu 40140a. Ustawianie Trap Flag
[UEF] Pierwsza instrukcja WriteFile zostala wykonana. Ponowne ustawianie breakpointa.
[PROGRAM] wywolanie WriteFile powodujace breakpointa
[UEF] Wylapano wywolanie WriteFile z adresem powrotu 401431. Ustawianie Trap Flag
[UEF] Pierwsza instrukcja WriteFile zostala wykonana. Ponowne ustawianie breakpointa.
[PROGRAM] ...i znow WriteFile...
[UEF] Wylapano wywolanie WriteFile z adresem powrotu 401458. Ustawianie Trap Flag
[UEF] Pierwsza instrukcja WriteFile zostala wykonana. Ponowne ustawianie breakpointa.
[PROGRAM] ...i jeszcze raz WriteFile...
[UEF] Wylapano wywolanie WriteFile z adresem powrotu 401482. Ustawianie Trap Flag
[UEF] Pierwsza instrukcja WriteFile zostala wykonana. Ponowne ustawianie breakpointa.
[PROGRAM] cos komus to moze przypomina? :>
[BPX] Usunieto breakpointa na WriteFile - uaktywniony 4 razy

Kompilowane g++, pod Windows Server 2003 sp1 chodzi. Stosowanie SEHa do hooków to moim zdaniem głupota - biblioteki /np. VCL/ i sam system tworzą niejawnie wątki mogące wywoływać daną funkcję. Oczywiście pamiętamy, że SEH jest lokalny, działa w obrębie jednego wątku /i co wtedy z BP?/. Można też użyć rejestrów DR ale też będzie ograniczenie do jednego wątku /ale inne się nie wysypią/. UEF to niezła alternatywa - hook globalny, ale jest coś jeszcze lepszego /niestety tylko na NT/ - VEH. Coś pięknego - taki globalny SEH /łańcuch handlerów/ tylko wygodniejszy :>. Coś o tym pisałem przy okazji ostatniej prowokacji barta.
Małego wyjaśnienia może wymagać:
if ((Eip < ddWriteFile) || (Eip > ddWriteFile+15))
Maksymalny rozmiar instrukcji akceptowany przed dekodery x86 to 15 bajtów - sprawdzamy czy wyjątek wystąpił w oczekiwanym miejscu - przejście do następnej instrukcji /tak mniej więcej ;P - bez dekodera nie można określić dokładnej pozycji 2 instrukcji wcześniej/ . I jedna uwaga do TF - flaga jest resetowana przez procesor po wykonaniu pojedynczej instrukcji. Może po południu jeszcze coś stuknę...

//edit: dodałem brakującego printfa - zamiast 2dw zrobiłem 2dd [rotfl]
ciekawy pomysł: można w 'sprytny' sposób ustalić adres 2 instrukcji danej funkcji poprzez breakpointa sprzętowego obsługiwanego SEH'em - wyłapywany jest wyjątek, ustawiany jest TF i znów SEH :>. bum - mamy adres ;P biorę się za implementację... chyba ;P

/edit2: pomysł może i ciekawy ale... Wygląda na to, że Windows nie pozwala wątkowi na ustawienie rejestru DR7 /w którymkolwiek handlerze - SEH, VEH, UEF ani poprzez SetThreadContext.../, co ciekawe DR0 można ustawić :/ W każdym razie 2k3 nie pozwala na włączenie breakpointów sprzętowych... w sumie to się nie dziwię - można sobie podmapować ntoskrnl.exe, przelecieć exporty i ustalić adres interesującego nas kodu /byłoby przenośne - na każdego NT/, przy pomocy API ustalić adres tego modułu /niby jest stały... ale nie wiem czy we wszystkich NT jest ten sam/ i ustawić HBP. Co by to dało gdyby się dało? Program mógłby zmusić kod ring0 do w sumie wszystkiego ;P Oczywiście to nie jest jedyne ograniczenie :>. Tzn. DR7 można ustawić ale wątek sam sobie nie może - coś musi robić za debugger /przynajmniej tak to na moim 2k3 wygląda/. Ale adres takiej drugiej instrukcji w funkcji takiej jak WriteFile można ustalić na setki sposobów, np. śledzenie poprzez TF. Tu się SEH przyda - mamy wyłączność, a co za tym idzie pewność, że żaden wyjątek nie pojawi się nieprzewidziany.
Zrezygnowałem ze standardowej konwencji struktury ERR wrzucanej po kawałku na stos, na rzecz czego bardziej a'la SetUnhandledExceptionFilter. Powyższy kod rozbudowałem o śledzenie do drugiej instrukcji WriteFile. Wstawki asm dla SEHa w at&t /gcc się kłania/, tak się całość prezentuje:

#include <windows.h>
#include <excpt.h>
#include <stdio.h>

#define ASMV asm volatile
typedef struct ERR; // dla EXCEPTION_HANDLERa
typedef int (__cdecl *EXCEPTION_HANDLER) (EXCEPTION_RECORD*, ERR*, CONTEXT*);
typedef struct ERR
{
	ERR* Next;
	EXCEPTION_HANDLER Handler;
} *PERR;
	
inline PERR SEH_Get () 		// mov eax, [fs:0] ; zwraca aktualny ERR
	{ PERR ptr; ASMV ("movl %%fs:0, %%eax":"=a"(ptr):); return ptr; };
inline PERR SEH_Set (PERR err)  // xchg eax, [fs:] ; podmienia /i zwraca/ handler
	{ PERR ptr; ASMV ("xchgl %%fs:0, %%eax":"=a"(ptr): "a" (err)); return ptr; };

int __cdecl SEH_ExceptionHandler (EXCEPTION_RECORD*, PERR , CONTEXT*);
LONG WINAPI UnhandledExceptionFilter( EXCEPTION_POINTERS* ExceptionInfo);

void MemWrite (void* dest, void* src, int size=1) 
{ 
  DWORD written;
	WriteProcessMemory (GetCurrentProcess(), dest, src, size, &written); 
};

void* pWriteFile;
DWORD SecondInst;
int trigger;

static unsigned char int3 = 0xCC;
static unsigned char org_byte;
static unsigned long count;

static char info1 [] = "[PROGRAM] wywolanie WriteFile powodujace breakpointa\n";
static char info2 [] = "[PROGRAM] ...i znow WriteFile...\n";
static char info3 [] = "[PROGRAM] ...i jeszcze raz WriteFile...\n";
static char info4 [] = "[PROGRAM] cos komus to moze przypomina? :>\n";

int main ()
{
  ERR Error;
  DWORD written;

	pWriteFile = (void*) GetProcAddress (GetModuleHandle("kernel32.dll"), "WriteFile");

	org_byte = *(char*) pWriteFile;

	Error.Next = SEH_Get();
	Error.Handler = &SEH_ExceptionHandler;

	printf ("[BPX] Ustawianie handlera SEH, poprzednia struktura ERR: %lx\n", Error.Next);
	SEH_Set (&Error);

	printf ("[SEH] Rozpoczecie sledzenia do drugiej instrukcji WriteFile\n");
	RaiseException (EXCEPTION_SINGLE_STEP, 0, 0, 0); // handler ustawia sprzetowego breakpointa
	WriteFile (0, 0, 0, 0, 0); // lipne wywolanie w celu określenia pozycji
	printf ("[SEH] Druga instrukcja WriteFile znaleziona - adres: %lx\n", SecondInst);

	SEH_Set (Error.Next); // przywrocenie nastepnego w lanuchu /poprzedniego/ handlera
	printf ("[BPX] Przywrocono poprzedni handler SEH\n");
	
	SetUnhandledExceptionFilter (&UnhandledExceptionFilter);

	printf ("[BPX] Ustawianie breakpointa na WriteFile - adres: %lx\n", pWriteFile);
	MemWrite (pWriteFile, &int3);

	HANDLE StdOut = GetStdHandle(STD_OUTPUT_HANDLE);
	WriteFile (StdOut, &info1, sizeof(info1)-1, &written, 0);
	WriteFile (StdOut, &info2, sizeof(info2)-1, &written, 0);
	WriteFile (StdOut, &info3, sizeof(info3)-1, &written, 0);
	WriteFile (StdOut, &info4, sizeof(info4)-1, &written, 0);

	MemWrite (pWriteFile, &org_byte);
	printf ("[BPX] Usunieto breakpointa na WriteFile - uaktywniony %lu razy\n", count);

	return 0;
};

LONG WINAPI UnhandledExceptionFilter (EXCEPTION_POINTERS* ExceptionInfo)
{
	switch(ExceptionInfo->ExceptionRecord->ExceptionCode)
	{
	case EXCEPTION_BREAKPOINT:
		if (ExceptionInfo->ContextRecord->Eip != (DWORD)pWriteFile) 
			return 1; // jezeli nie nasz breakpoint - spadamy
		
		ExceptionInfo->ContextRecord->EFlags |= 0x100;	
		MemWrite (pWriteFile, &org_byte);

		printf ("[UEF] Wylapano wywolanie WriteFile, adres powrotu: %lx. Ustawianie Trap Flag\n", 
			*(DWORD*)ExceptionInfo->ContextRecord->Esp);

		return EXCEPTION_CONTINUE_EXECUTION;
	case EXCEPTION_SINGLE_STEP:
		DWORD Eip(ExceptionInfo->ContextRecord->Eip), ddWriteFile ((DWORD)pWriteFile);

		if (ExceptionInfo->ContextRecord->Eip != SecondInst)
			return 1; // nie nasz breakpoint...

		printf ("[UEF] Pierwsza instrukcja WriteFile wykonana. Ponowne ustawianie breakpointa.\n");
		MemWrite (pWriteFile, &int3);

		count++;

		return EXCEPTION_CONTINUE_EXECUTION;
	default:	// nie masz error? bye bye...
		return 1;
	};
};

int __cdecl SEH_ExceptionHandler (EXCEPTION_RECORD *ExceptionRecord, PERR ErrorRecord, CONTEXT *ContextRecord)
{
	if (ExceptionRecord->ExceptionCode !=  EXCEPTION_SINGLE_STEP) return 1;

	if(!trigger) // trigger = 1 jesli poprzednio trafiono na EP WriteFile
	{
		trigger = ContextRecord->Eip == (DWORD) pWriteFile;
		ContextRecord->EFlags |= 0x100;
	}
	else
		SecondInst = ContextRecord->Eip;

	return 0;
};

Zaraz ktoś mnie pewenie zamorduje za objętość... hm, debugger to nie jest, ale sprawdza się całkiem nieźle. Jedyny minus to konieczność wywołania monitorowanej funkcji. Trochę tych printfów jest, ale dzieki temu mniej\więcej widać co i kiedy się dzieje /większa szansa, że ktoś więcej to zrozumie/. Do tego wszystkiego można się też dobrać poprzez tablicę importów - monitorowane będą wywołania z konkretnego modułu /jeżeli funkcja nie jest pobierana dynamicznie/. Zmodyfikowanie exportów też się przydać może - ale zadziała tylko dla modułów załadowanych po modyfikacji. Tylko kto nam broni przelecieć IAT wszystkich załadowanych modułów i powstawiać hooka gdzie trzeba? Wcześniej by wypadało exporty 'poprawić'. Problemem będą jednak dynamicznie pobierane adresy, które są zapisywane na potrzeby dalszego działania programu /program się odpala, pobiera adres za pomocą GetProcAddress i zapisuje go w sekcji danych na użytek późniejszych wywołań/. Chociaż... w sumie 2^32 kombinacji ta na tyle dużo, aby szansa na pomyłkę przy przeszukiwaniu całej pamięci była znikoma. W ostateczności też można nadpisać początek funkcji, ale tu bez chociaż podstaw disasemblera się nie obejdzie. Później może napiszę modyfikowanie importów i exportów /dla mnie to banał... już tele razy to 'ręcznie' robiłem, że napisanie automatu będzie miłą odmianą/. W sumie... jak sądzicie, czy aby upewnić się, że dany dword to adres funkcji jest podmalować moduł, w którym się ów dword znajduje i porównać?

p.s. sorry, za taki czas reakcji, ale miałem masę spraw na głowie... do tego padł mi HDD - w sumie podstawową sprawność jeżeli chodzi o programowanie to system odzyskał dopiero wczoraj :/ Cóz, wracam do akcji :>

0

@ deus .
Się kombinuje , co nie :-D .
Wiem że rozmiar wątku jest spory i można się zgubić , problemem jest to że twój kod nie działa
po kompilacji Borland C++ 5.0 i Borland BCB .
To było właśnie powodem dla którego męczyłem ten temat i kombinowałem "jak koń pod górę ".
Czyli nie jak to zrobić , ale dla czego poprawne rozwiązanie nie działa na BCB .( na VC++ działa .)
kod z użyciem funkcji SetUnhandledExceptionFilter nie działa w Borlandzie.

ale ostatni kod zupełnie mi wystarcza z proc:
http://4programmers.net/Forum/355367?f=2#id355367

EXCEPTION_DISPOSITION  _except_handler(EXCEPTION_RECORD *ExceptionRecord,
       void * EstablisherFrame,CONTEXT *ContextRecord,void * dispatcherContext) ;

Przepływ sterowania w programie - resztę której nie dopisałem mogę spróbować odwzorować na Twoim
kodzie - obsługa EXCEPTION_SINGLE_STEP ale bez użycia SetUnhandledExceptionFilter
To było odnosnie podanego kodu pierwszgo .

Kod 2 nie sprawdzałem jeszcze , ale sprawdzę .
na razie wiem tylko tyle że muszę go troszkę
przebudować bo składnia jest nieodpowiednia dla BCB .

Dzięki za odzew i podanie kodu .

                                                                           Pozdro .
</b>
0

heh.. przeczytalem tego watku troche, ten CrashCours Matta Pietreka (czy jakos tak) tez.. z reszta, gosc ma nielada leb i nie pierwszy tak dobrze opisany art jego autorstwa widzialem.

Moje pytanei teraz jest takie:
"wpisujac kod przerwania "CC" (bajt) w miejsce poczatku procedury, napisujemy instrukcje push (jedno bajtowa - przyklad z WriteFile())... teraz zeby ustawic po calej obsludze przerwania kolejna pulapke musimy nadpisac kolejna instrukcie (absrachujac od przykladu WriteFile i uogólniając do dowolnej procedury) skad mam wiedziec jaki rozmiar(jaka jest) ma nastepna instrukcja, jak nadpisze tylko jeden nastepny bajt kolejnej instrukcji a jest ona o rozmiarze > 1b to kolejne obsluga przerwania bedzie przeklamana o ile nie skonczy sie jakims fajowym bledem.

Czy ustawianie flagi co obsluge kodu CC tak by leciec Step By Step bedzie "przeskakiwalo" odpowiednia ilosc bajtow do kolejnych instrukcji czy zawsze jest to przejscie o 1 b"

(wiec teraz zeby uniknac niepotrzebnych uwag:
zarejestrowany na koniec-kropka.com/~c4u .. sporo tych crackmes zrobilem.. wic prosze nie zmywac mnie banalnymi odpowiedziami)

pozdro i wesolych swiat :D

0

Przede wszystkim trace opiera sie o Trap Flag, nie int3. A 0xCC obsługuje się banalnie:

  • zapamiętujesz nadpisywany bajt,
  • zapisujesz int3, wznawiasz wykonywanie, występuje wyjątek, wychwytujesz,
  • podmieniasz bajt na oryginalny i ustawiasz TF, wznawiasz, wykona się jedna instrukcja...
  • przy następnym przebiegu petli debuggera /po złapaniu int1 - single step/ znow break'a wstawiasz.
    Tyle. Rozmiar instrukcji nie ma tutaj znaczenia. Nie zawsze nadpisuje się push - nie wszystki funkcje mają standardowy prolog i epilog.
    Swoja drogą chwalenie się Crackmes4You w tym wypadku wygląda śmiesznie, /sam mam tam tylko jedno CM na sumieniu, prowokacja napisana specjalnie dla mnie/ znajomość podstaw dzialania debuggera to koniecznaść, taka sama jak znajomość assemblera.
    Zresztą, widać że i z asm jesteś na bakier - 0xCC to jednobajtowy opkod int 3 - breakpoint. Trap Flag to zaś 9 bit Flags, powodujący wywołanie int 1 przy kolejnej instrukcji... przeciez do diabła nadpisaną instrukcję musisz wykonać...

p.s. rok temu to pytanie znalazłoby się pewnie na ctrl-d, nie? :-)

0

fakt.. posta napisalem w trakcie przeprowadzki.. i lalo sie troche procentow.. co dodalo troche odwagi :D

a crackmes .. to byla w zasadzie tylko kwestia po to by nie padla odpowiedz "czlowieku.. wiesz co to asembler??"

no i to tylwe..swieta sa.. zmiana pracy.. iwlkie kosze pelne dobrych whiskaczy :D

w zasadzie to Twoj post jest podsumowaniem tego watku.. dzieki za odp. to ze myle CC z int X to kwestia rvbaku praktyki ktora wlasnei staram sie zdobyc lamiac kolejne ciekawe crackme..

co do tego "push" to mial posluzyc tylko jako przyklad instrukcie a nie prawo formujace postac procedur...

w zaszadzie dosc kompletnie odpowiedziales na moje watpliwosci. dziekuje i prosa o wybaczenie.. %%%%% i twoje zdrowie

1 użytkowników online, w tym zalogowanych: 0, gości: 1