VirtualProtect - podmiana adresu powrotnego

0

Witam, pisze nowy temat bo w starym było troszkę nieporozumień i nie było by sensem tego dalej prowadzić i w dodatku było mało odzewów. Podejrzewam, że troszkę użytkownicy nie zrozumieli i dlatego.. Ten temat jest uściśleniem tego co chciałbym uzyskać. Mianowicie. Piszę swoistego hacka do gry, która w momencie gdy wywoła pewną funkcję np. "onLostHealth" hack miałby wykryć jej wywołanie i zamiast domyślnego adresu powrotnego wskazywała by na moją funkcję, w której znajdowały by się różne instrukcje chociażby najzwyklejszy tekstu typu "Straciłeś kilka punktów życia". Oczywiście funkcja "onLostHealth" obowiązkowo musiałaby wykonać własne instrukcje, a dopiero moje. W innym przypadku gra by się posypała informując, że program przestał działać... Wiem, że jest możliwe wykonać coś takiego za pomocą funkcji VirtualProtect. Jak wiadomo do takiej sytuacji jest potrzebne DLL-Injecting, ja oczywiście już to zrobiłem. Pozostaje tylko skonstruowanie funkcji. Byłbym wielce wdzięczny, jak by ktoś pomógł skonstruować taką funkcję.

Przykład do zrozumienia:

void onLostHealth()
{
      scoreExperience -= 5
      respect -= 0.01
      //jakieś tam przykładowe instrukcje tej funkcji z gry, które obowiązkowo muszą się wykonać (nie możemy w nie ingerować bo program się sypnie)
}
 
void hackFunction()
{
      cout << "Straciłeś kilka punktów życia\n";
}

Efektem końcowym miało by być wykonanie się bezawaryjnie onLostHealth, której na końcu adresem powrotnym miałby być hackFunction().

0

Mielismy bardzo podobne zadanie do tego tylko zwiazane z przerwaniami i w asm ;p Ogolnie w teorii caly myk polegal na przejeciu funkcji oryginalnej podmianie adresu skoku do tej funkcji na nasza nowa funkcje a nastepnie wywolanie oryginalnej funkcji przy koncu wykonywania naszej funkcji. Pokazalbym Ci jak to wyglada w asmie ale raczej Ci sie nie przyda. W tym przypadku prawdopodobnie trzeba zalozyc hook na dana funkcje. Nie wiem czy bez wstawek asm sie to uda.

0

Jeżeli bys mógł to bardzo bym prosił. Przedstaw mi to na jakimś przykładzie, jeżeli asm w c++ to nie ma jakoś tam wielkiego problemu. Dzieki:)

0

Moge Ci pokazac kawalki kodu ale nie wiem czy Ci pomoga z uwagi na to ze ze jest to czysty asm. Jedynie pokaza ci jak to dziala.

 ; variables	
	adres_klawiatura	DD		? 				; adres oryginalnej procedury przerwania dla klawiatury (32 bity)
	adres_zegar			DD		?				; adres oryginalnej procedury przerwania dla zegara (32 bity)
	opcja				DB		?				; zmienna przechowujaca numer wybranej opcji przez uzytkownika
	regulacja			DW		0FFFFh			; aby pokazac dzialania, wartosc musi sie zmieniac od duzej do malej wartosci, odwrotnie proporcjonalnie do tego
												; czy wybieramy zwiekszenie, czy zmniejszenie czestotliwosci
												; przyjeta maksymalna wartosc mozliwa
	licznik 			db      10
	zmniejsz_zegar		db      0				; zmienna a'la bool informujaca czy zmniejszamy juz priorytet czy moze jeszcze troche :)
.STACK
	DB	100h DUP (?)	; 100 bajtow powinno wystarczyc na stos
	

Mamy zmienne ktore beda przechowywac odpowiednie adresy procedur

pobierzWektorPrzerwania MACRO przerwanie, zmienna		; pobieranie adresu procedury obslugi przerwania  (dla klawiatury numer_przerw = 09h)
	mov	ah, 35h											; dla pobierania wektora zawsze używamy przerwania 35h	    
	mov	al, przerwanie									; numer przerwania, dla ktorego zostanie pobrany adres procedury obslugi
	int	21h
	mov	WORD PTR zmienna, bx						    ; mlodsze slowo adresu postaci ES:BX ( adres procedury obslugi przerwania ma 32bity )
	mov	WORD PTR zmienna+2, es				 			; starsze slowo adresu postaci ES:BX ( adres procedury obslugi przerwania ma 32bity )
ENDM

ustawWektorPrzerwania MACRO przerwanie, nowa_procedura		
	push ds												; odkladamy na stos segment danych
	mov	dx, OFFSET nowa_procedura						; bierzemy offset nowej procedury obslugi przerwania
	mov	ax, cs											; zmieniamy rejetr danych na cs [ponizej wyjasnienie]
	mov	ds, ax											; poniewaz nie mozna bezposrednio przeniesc miedzy rejestrami segmentowymi, uzywamy pomostu -> ax
	mov	ah, 25h											; Dzieki temu mamy adres wektora przerwania ustawiony na DS:DX
	mov	al, przerwanie	
	int	21h
	pop	ds												; zdejmujemy ze stosu segment danych
ENDM
 

Makra wywolujace odpowiednie przerwania biosu w celu przejecia procedur. W twoim wypadku wydaje sie ze trzeba za pomoca olly czy ida ustawic pulapke na funkcje i znalezc jej adres. Tutaj operujemy na tablicy wektorow przerwan ktora jest zawarta na poczatku PAO.

przerwij_klawiatura PROC FAR  	
; nowa procedura obslugi przerwania klawiatury
	sti				; ustawiamy IF=1, procesor potem sam wyzeruje :-)
	push	ax
	push	bx
	push	cx
	push	ds

	mov	ax, @DATA    		; ustawiamy wlasciwy segment danych (DS)
	mov	ds, ax
		
	WyswietlZnak 'd'		; poczatek obslugi przerwania klawiatury
	WyswietlZnak '+'
	call duzyLoop			; wywolujemy duzego loopa :D
		
	WyswietlZnak '+'
	WyswietlZnak 'b'		; koniec obslugi przerwania
		
	pushf					; przed wywolaniem oryginalnej procedury przerwania, musimy zachowac flagi
	call adres_wektora_k ; oryginalny wektor obslugi przerwania
		
	pop	ds
	pop	cx
	pop	bx
	pop	ax					; zdjecie ze strosu zawartosci rejestrow ax, bx, .. itd
	iret					; iret zdejmuje takze rejestr flagowy
ENDP 

Przykladowa przejeta funkcja robimy swoje i pod koniec wywolujemy oryginalna funkcje.

Przy c bedzie to inaczej troche wygladalo, bo nie masz chyba tablicy adresow funkcji zebranej w pamieci procesu. Tutaj jest jedynie sama idea przejecia jakiejs funkcji.

0

Hmm to mi nie zbyt pomoże, nie znam się na tym i nie potrafię przełożyć tego na c/c++. Adresy jestem w stanie pobrać za pomocą IDY, ale mi przedstaw na przykładowych adresach funkcji. Potrafiłbyś zrobić tą funkcję dodająca instrukcje w wysokopoziomowcu? Będe wielce wdzieczny :)

0

Po 1 adresem powrotnym nie moze byc twoja funkcja hook, adresem powrotnym MA BYC ADRES wywolujacy ta funkcje, nie mozesz tego modyfikowac, zastanow sie tak na logike, po wywolaniu funkcji, program musi wrocic do miejsca, z ktorego zostlala wywolana funkcja renderujaca (w tym przypadku), jak podmienisz adres powrotny to program sie posypie bo uszkodzisz stos.

Inne metody? Ja bym to po prostu w asm naklepal bo to sa banalne rzeczy do zrobienia, zwlaszcza, jak znasz wszystkie szczegoly programu, adres funkcji i prototyp funkcji (np. dzieki deadlistingowi w IDA), powiem Ci jak ja bym to zrobil

  1. analiza funkcji onlosthealth()
  2. znalezienie konca funkcji
  3. znalezienie sekwencji wyjsciowej np.
    pop esi edi ebx
    leave
    ret imm16
    int 3
    int 3
    int 3
  1. teraz ja bym zrobil tak patcha na koncowce funkcji
    ;push [ebp+oryginalny_parametr3]  ; opcjonalnie przekaz orygnialne parametry
    ;push [ebp+oryginalny_parametr2]
    ;push [ebp+oryginalny_parametr1]
    mov eax,MOJA_FUNKCJA_HACK       ; 
    call eax
    pop esi edi ebx
    leave
    ret imm16

zwykle po koncu funkcji masz paddingi, jakies int3 albo nopy, wiec miejsce dla 1 call-a do twojej funkcji hack by sie znalazlo, jak by bylo malo miejsca to zostaje wrzucenie

    jmp MOJ_HACK_STUB
    pop esi edi ebx
    leave
    ret imm16

...
MOJ_HACK_STUB: ; w twojej pamieci

;push [ebp+oryginalny_parametr3]  ; opcjonalnie przekaz orygnialne parametry
;push [ebp+oryginalny_parametr2]
;push [ebp+oryginalny_parametr1]
mov eax,MOJA_FUNKCJA_HACK       ; 
call eax
pop esi edi ebx                            ; oryginalne instrukcje koncowki funkcji
leave
ret imm16

Jakbym sie uparl juz na to C++ to bym sobie to jako libke zrobil w asm, w ogole nie rozumiem dlaczego takie rzeczy ludzie robia w C++, bo to tylko utrudnia sprawe, operacje na niskim poziomie sie powinno robic na niskim poziomie :)

Innym rozwiazaniem jest po prostu hook na funkcje i wywolanie oryginalnej funkcji w hooku

DWORD hookedFunkcja()
{
dwReturn = oryginalnaFunkcja();

mojStuff;

return hookedFunkcja;

}

0

Aha, no dzięki za wyjasnienie z tym adresem powrotnym. Z tego co patrze na twoje wyjaśnienia to wynika, że musiałbym ingerować w plik wykonywalny i zedytować kod assemblerowy za pomocą edytora do tego przeznaczonego. Ja niestety nie chcę tak, chciałbym go zostawić nienaruszonego, dopiero w momencie (lub ewentualnie później - nieważne) zainicjowania wspólnej przestrzeni adresowyj (dll-injecting) dołożyć wywołanie funkcji Fake do funkcji Prototypa (tak jakby jedna wspólna funkcja można by powiedzieć).

Jakbym sie uparl juz na to C++ to bym sobie to jako libke zrobil w asm, w ogole nie rozumiem dlaczego takie rzeczy ludzie robia w C++, bo to tylko utrudnia sprawe, operacje na niskim poziomie sie powinno robic na niskim poziomie :)

Tak jak wyżej wspomniałem, wolę pozostawić plik nienaruszony, a w związku z tym chcę dokonać tego za pomocą c++ i ewentualnie wstawką asma (jeżeli zajdzie taka potrzeba). Bo gdybym modyfikował plik wykonywalny i tam zalozyl hooka na potrzebna mi funkcję, to zaraz kod związany z całym Hackiem napisanym w c++ musiałbym modyfikować na asma i resztę rzeczy dokańczać w asmie, trochę nie fajnie.. Byłoby super, przewspaniale i nie wiem jak jeszcze, gdybyś mi taką funkcję hook'ującą w c++ napisał. Będę niezmiernie wdzięczny jeśli to zrobisz. Trochę to brzmi jakbym leciał na lenia i pasożyta, ale naprawdę nie wiem jak się za to zabrać w c++ a ty jesteś akurat głębiej w temacie. Więc jakbyś wykonał mi taką funkcję to byłoby przesuper.

0

Takie cuś co swego czasu napisał kolega :)
Może się przyda:
http://adwi32.blogspot.com/2011/11/klasa-do-hookingu.html

0

Takie cuś co swego czasu napisał kolega :)
Może się przyda:
http://adwi32.blogspot.com/2011/11/klasa-do-hookingu.html

Podmiana pierwszych 7 bajtów. Czyli podmiana funkcji (tudzież przekazanie argumentów), a nie przyłączenie funkcji Fake do funkcji Prototypa. Nie rozwiązuje to nadal mojego zapotrzebowania. Mniej jednak dzięki ; )

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