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, botów: 0