jak zmienić wartość w określonym adresie pamięci?

Nov 19 2020

Jestem nowy w programowaniu C. Istnieje przypadek użycia: muszę zmienić wartość w określonym adresie pamięci.

int main(){

    int *p;
    p = 0x111;
    *p = 100;
    return 0; 
}

Nie mogę jednak skompilować powyższego kodu. Pokazuje następujący problem.

test.c:10:7: warning: incompatible integer to pointer conversion assigning to 'int *' from 'int' [-Wint-conversion]
    p = 0x111;
      ^ ~~~~~
1 warning generated.

Próbowałem przesyłać tak jak poniżej:

int main(){

    int *p;
    p = (int *) 0x111;
    *p = 100;
    return 0; 
}

Może się skompilować, jednak po uruchomieniu go widać segmentation fault.

Moje pytanie:

  1. Czy istnieje sposób, w jaki mogę wymusić kompilację i uruchomienie tego kodu? Wiem, że jest problem z dzikim wskaźnikiem. Jednak manipulowanie pamięcią jest powszechnym przypadkiem. Na przykład, kiedy gram w lokalną grę. W jakiś sposób znam konkretny adres w pamięci punktu zdrowia mojego gracza, gdy gra jest uruchomiona, np. Adres = 0x123. Jak po prostu zmienić wartość w 0x123?

  2. Jeśli nie mogę użyć powyższego sposobu do manipulowania wartością w jakimkolwiek określonym adresie pamięci, czy istnieje inny standardowy sposób realizacji mojego przypadku użycia?

PS: Nawiasem mówiąc, znalazłem przykładowy sposób realizacji mojego przypadku użycia.

Możesz odwołać się do kodu źródłowego: https://github.com/haseeb-heaven/GTLibc/

Jak trenerzy gier zmieniają adres w pamięci, który jest dynamiczny?

https://www.youtube.com/watch?v=cRCnN987gd8&ab_channel=HaseebMir

Odpowiedzi

2 eerorika Nov 19 2020 at 15:04

Biorąc pod uwagę poprawny wskaźnik do obiektu w adresie pamięci, pośrednio przez wskaźnik i przypisz wartość:

int health_points = 1337;  // an object in some memory address
int* ptr = &a;             // pointer to the value in that memory address
*ptr = 0;                  // the value is modified

Czy istnieje sposób, w jaki mogę wymusić kompilację i uruchomienie tego kodu?

Twój program jest źle sformułowany. Może istnieć sposób, aby umożliwić kompilatorowi pomyślne skompilowanie go, jeśli kompilator zapewnia odpowiednie rozszerzenie języka, ale zwykle jest złym pomysłem poleganie na takich rozszerzeniach, ponieważ uwięziłoby to w użyciu tego jednego kompilatora.

Zamiast próbować zmusić kompilator do zaakceptowania zepsutego programu, zalecam naprawienie programu.

jak zmienić wartość w określonym adresie pamięci?

Po pierwsze, pamięć w tym adresie musi zostać przydzielona. Implementacja języka zajmuje się przydzielaniem całej pamięci i nie ma standardowego sposobu określenia przydzielonego adresu.

Jednak niektóre implementacje języków mogą określać określone adresy jako dostępne. Jest to typowe w systemach wbudowanych. W takim przypadku możesz przekonwertować wartość całkowitą na wskaźnik za pomocą rzutowania:

std::uintptr_t address = 0x111; // see documentation whether this is a valid address
int* ptr = reinterpret_cast<int*>(address);

Jeśli implementacja języka nie określa, że ​​adres jest dostępny, nie ma gwarancji uzyskania do niego dostępu. W nowoczesnych systemach operacyjnych, które zarządzają pamięcią wirtualną, najlepszym scenariuszem jest segfault.

HaseeBMir Dec 06 2020 at 23:23

Pozwól, że zrozumiesz, w jaki sposób aplikacje odczytują adres innej aplikacji lub użytkownika.

  1. Adres własny.

Adres, który czytasz, znajduje się powyżej adresu bazowego, który jest 0x0040000przeznaczony dla obrazu wykonywalnego, więc powinien wyglądać następująco 0x0040000+ 0x0040gdzie 0x0040jest przesunięcie względem adresu bazowego. A jeśli uzyskujesz dostęp do regionu innego niż .text (tylko do odczytu), musisz najpierw zmienić uprawnienia regionu za pomocą metody VirtualProtect , jak pokazano tutaj

  1. Zewnętrzny adres aplikacji.

Jeśli chcesz odczytać adres z zewnętrznej aplikacji, powiedzmy, że twoja gra to najpierw musisz pobrać uchwyt aplikacji, który jest właśnie identyfikatorem dla twojej aplikacji, a następnie użyć ReadProcessMemory, jak pokazano tutaj, podobnie możesz pisać również używając WriteProcessMemory, jak pokazano tutaj

Po prostu zawsze upewnij się, że nie masz dostępu do .textsekcji innej niż sekcja bez zmiany jej regionu uprawnień, w przeciwnym razie program może się zawiesić.