Skocz do zawartości
  • 👋 Witaj na MPCForum!

    Przeglądasz forum jako gość, co oznacza, że wiele świetnych funkcji jest jeszcze przed Tobą! 😎

    • Pełny dostęp do działów i ukrytych treści
    • Możliwość pisania i odpowiadania w tematach
    • System prywatnych wiadomości
    • Zbieranie reputacji i rozwijanie swojego profilu
    • Członkostwo w jednej z największych społeczności graczy

    👉 Dołączenie zajmie Ci mniej niż minutę – a zyskasz znacznie więcej!

    Zarejestruj się teraz

Pisanie cheatów na przykładzie gry AssaultCube w C#


_sectasy

Rekomendowane odpowiedzi

Opublikowano

Pisanie cheatów na przykładzie gry AssaultCube

                                                                      w języku C#

 

 

Na wstępie chciałbym zaznaczyć, że jest to pierwszy poradnik jakikolwiek napisałem w życiu, aczkolwiek mam nadzięje, że materiały tutaj zawarte okażą się przydatne.  Poniższa treść jest skierowana do osób, które posiadają podstawową wiedzę na temat programowania i nie będę tutaj tłumaczył podstawowych rzeczy.

 

Aby rozpocząć naszą prace na starcie należy się zaopatrzeć w kilka programów:

  1. Cheat Engine.
  2. IDE ( Według uznania, ja korzystam z Visual Studio )

 

Za pomocą programu 'Cheat Engine' będziemy szukać wskazników w pamięci, których potem będziem używać w naszym programie w C#.

 

Czym jest wskaźnik?

 

Wskażnik ang. pointer jest to taki typ danych, który przechowuje adres innej komórki w pamięci.

Najlepiej opisuje wskaznik poniższy obrazek.

 

Pointer

 

Wkazniki mogą mieć kilka poziomów np. wskaznik wskazuje na wskaznik, który wskazuje na wskaznik itd.

Często takie coś nam utrudnia prace podczas pisania.

 

 

 

Na początku musimy wybrać proces w cheat engine.

 

FWRWXZt.png

 

 

Następnie odszukanie pierwszej interesującej nas wartości, ja na początku odszukałem stan życia postaci.

 

Więc aby to zrobić w polu 'value' wpisujemy wartość 100 i klikamy 'first scan'.

W tym momencie waszym oczom ukarze się duża liczba wyników, dlatego też musimy troche zadać obrażeń naszej postaci.

 

VzPuyfI.png

 

 

Na czerwono widzimy, że wartość w pamięci się zmieniła i jest teraz na czerwono, u mnie postać ma 7 punktów życia i adres z taką wartością dodałem też do listy, dla pewności możemy podmienić tę wartość - Jeśli się zmieni mamy pewność, że adres jest prawidłowy.

 

Możemy tak zrobić i poszukać każdej wartości, która będzie potrzebna do naszego cheata, jedna te adresy zmieniają się za każdym razem kiedy uruchomimy gre, dlatego potrzebujemy znalezc wskaznik, który jest statyczny - Jest stały dla konkretnego Buildu gry.

 

 

Szukanie wskaźników

Aby znaleźć wskaznik, musimy sprawdzić jaka instrukcja może wpisywać do tej komórki w pamięci, w tym celu zaznaczmy dynamiczny adres i klikamy f5, Nic na razie nam się nie pokaże ponieważ musimy jeszcze trochę zadać obrażenia naszej postaci.

 

 

M1HPwGJ.png

 

Widzimy, że instrukcją, która ma dostęp do zapisu tej pamięci jest to instrukcja 'mov [edx + 00000F8], eax'

Operacja ta kopiuje wartość z rejestru eax do rejestru edx przy tym dodająć offset 0xF8.

 

offset jest to najprościej mówiąć 'scieżka' do odnalezienia wskaznika do dynamicznej komórki w pamięci. Jednak do tego potrzebujemy adres Entity gracza.

 

Klikająć 'More information' dostaniemy bardziej szczegółowe informacje na temat tego adresu.

 

G0CB17N.png

 

Możemy tutaj przeczytać, że prawdopodobnie wartość wskaznika potrzebna do odnalezienia tego wskaznika jest to '0279A1C0' i w tym przypadku tak też jest.

 

Dlatego też kopiujemy ten adres i w polu 'value' zaznaczmy 'hex'  wklejamy ten adres i klikamy 'first scan'

 

ysO3Mbw.png

 

 

Po zakończeniu procesu skanowania naszą uwagę na pewno przyciągną zielone adresy, są to statyczne adresy (W tym przypadku Entity Gracza), które posłużą nam do odnalezienia wskaznika.

 

h8esuK9.png

 

Jeden z tych zielonych adresów jest to adres, którego szukamy jest nim 'ac_client.exe+10F4F4' dodajemy go do listy poniżej.

Widzymy, że po dodaniu do listy w kolumnie adres pokazuje wartość '0050F4F4' ta wartość będzie nam potrzebna aby wydobyć wskaznik życia.

 

Przechodzimy teraz do 'Memory View' klikamy CTRL+D w polu "Group 1" wpisujemy adres, który wcześniej skopiowaliśmy i klikamy CTRL+N

Naszym oczom ukaże się lista z zielonym kolorem tekstu, to jest właśnie to czego szukaliśmy.

 

Tutaj będziemy szukać, które offsety będziemy pózniej używać w naszym programie.

 

H34GDxD.png

Znalazłem odpowiednie wartości i je nazwałem, następnie dodajemy je do swojej listy i zapisujemy ją.

Wartości po lewej od myślnika są to offsety.

 

 

Wszytkie nasze pobrane wskazniki powinny wyglądać mniej więcej tak:

 

45AcmCX.png

 

 

Dane zebrane, pora na pisanie kodu!

Stwórzmy w Visual Studio nowy projekt 'Windows forms app', Ja nazwe go 'BasicCheat'

następnie musimy utworzyć jakieś gui dla cheat'a. W tym celu należy otworzyć plik Form1.cs i z lewej klikamy 'toolbox' tworzymy nasz interface, ja stworzyłem coś takiego:

 

SwdSoZM.png

 

 

Warto też nadać sobie im odpowiednie nazwy, przez które będziemy się odnosili do nich w kodzie, aby było po prostu łatwiej zapamiętać je.

Po kliknięciu dwa razy na obiekty, które dodaliśmy w designerze środowisko automatycznie utworzy nam odłowania do nich w kodzie.

 

 

Po tych operacjach kod będzie wyglądał tak:

using System;
using System.Windows.Forms;

namespace BasicCheat {
  
    public partial class Form1 : Form {
      
        public Form1() {
            InitializeComponent();
        }

        private void enable_Click(object sender, EventArgs e) {

        }

        private void disable_Click(object sender, EventArgs e) {

        }

        private void exit_Click(object sender, EventArgs e) {

        }

        private void health_CheckedChanged(object sender, EventArgs e) {

        }

        private void checkBox2_CheckedChanged(object sender, EventArgs e) {

        }

        private void ammo_CheckedChanged(object sender, EventArgs e) {

        }

        private void granades_CheckedChanged(object sender, EventArgs e) {

        }
    }
}

Zacznijmy od stworzenia sobie zmiennych, które nam będą potrzebne do interakcji z GUI

Tworzymy je na początku klasy jako jej pola.

 

private bool unlimitedHealth = false;
private bool unlimitedArmour = false;
private bool infiniteGranades = false;
private bool infiniteAmmo = false;

 

Kiedy już je mamy zaczniemy z nimi pracować, zacznijmy od funkcji wyłączenia naszej aplikacji, Musiby obsłużyć wyłączenie przez kliknięcie przyciusku 'Exit' oraz przez zamknięcie X'em. 

// Metoda zamykająca aplikacje, wraz z zabiciem wszystkich jej podprocesów.
private void ApplicationExit() {
  System.Diagnostics.Process.GetCurrentProcess().Kill();
  Application.Exit(); 
}

// Nadpisanie metody wbudowanej, po kliknięciu X'a
protected override void OnFormClosing(FormClosingEventArgs e) {
   ApplicationExit();
}

// Po naciśnięciu przycisku exit
private void exit_Click(object sender, EventArgs e) {
   ApplicationExit();
}

Teraz obsłużmy przyciski enable i disable.

 

 // Po kliknięciu przycisku 'enable';
        private void enable_Click(object sender, EventArgs e){
            processes = Process.GetProcessesByName("ac_client");                // Pobieramy proces o nazwie 'ac_client';
            Thread thread = new Thread(cheatMain);                      // Definicja wątku, w którym będzie uruchomiona
                                                                            // główna funkcja;

            enabled = true;         									// Uruchomienie cheata;


            // Jeśli długość zwróconego przez metode GetProcessesByname() nie równa się 0 - czyli proces istnieje;
            if(processes.Length != 0) {
                thread.Start();           								// Uruchomienie nowego wątku;

                statusValue.Text = "enabled";       					// Zmiana tekstu na 'enabled';
                statusValue.ForeColor = System.Drawing.Color.Green;         // Zmiana koloru tekstu na zielony;
            } else {  // W przeciwnym wypadku
                statusValue.Text = "process not found";  					// Zmien tekst;
                statusValue.ForeColor = System.Drawing.Color.DarkRed; 		// Zmien kolor;

                enabled = false; 								// Wyłącz cheata;
            }
            
        }
 // Po kliknięciu przycisku disable;
private void disable_Click(object sender, EventArgs e){
  if(processes.Length != 0) {
    enabled = false;
    statusValue.Text = "disabled";				
    statusValue.ForeColor = System.Drawing.Color.Red;
  }
}

Przejdzmy do pobrania wartości z checkboxów i odpowienio ich przechowania w zmiennych, które stworzyliśmy wyżej.

 

// Po interakcji z checkboxem
private void health_CheckedChanged(object sender, EventArgs e){
  if(health.Checked){      					// jeśli wciśniety
    unlimitedHealth = true;					// ustaw wartość zmiennej na true;
  } else { 						// Jeśli nie
    unlimitedHealth = false;			// na false;
   }
}

 

 

Robimy to samo dla reszty.

 

private void armour_CheckedChanged(object sender, EventArgs e) {
  if(armour.Checked) {
    unlimitedArmour = true;
  } else {
    unlimitedArmour = false;
  }
}

private void granades_CheckedChanged(object sender, EventArgs e) {
  if(granades.Checked) {
    infiniteGranades = true;
  } else {
    infiniteGranades = false;
  }
}

private void ammo_CheckedChanged(object sender, EventArgs e) {
  if(ammo.Checked) {
    infiniteAmmo = true;
  } else {
    infiniteAmmo = false;
  }
}

Doszliśmy prawie do końca, teraz wszystko co musimy zrobić to stworzyć kolejnych pól(zmiennych) w klasie

oraz dodać bilbioteke w rozszerzeniu dll do naszego projektu. biblioteke pobieramy tutaj.

 

Przechodzimy do okienka po lewej stronie naszego środowiska klikamy prawym na 'References' i add reference z dołu klikamy browser i wybieramy VAMemory.dll z dysku.

 

Aby wszystko poprawnie działało trzeba jeszcze dodać plik manifest do projektu, można to zrobić klikająć new > file i wybieramy manifest

Podmieniamy linijke

<requestedExecutionLevel level="Invoker" uiAccess="false" />

na

<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />

 

Deklaracje zmiennych w naszej klasie powinny wyglądać tak:

 

private Process[] processes = null;         // Obiekt process, który jest potrzebny do sprawdzenia;
// czy proces jest uruchomiony;

private IntPtr processBaseAdress = IntPtr.Zero;                 // Statyczny wskaznik procesu;
private IntPtr playerBaseAddress = IntPtr.Zero;                 // Statyczny wskaznik Etity Gracza;

// Wartości, które się zmienią po wybraniu odpowiednich opcji w gui;
private bool unlimitedHealth = false;
private bool unlimitedArmour = false;
private bool infiniteGranades = false;
private bool infiniteAmmo = false;

// Cheat włączony lub wyłączony
private bool enabled = true;

private int value = 0x3E7; // Wartość, którą  będziemy wpisywać do pamięci, 
// jest to 999 w systemie dziesiętnym;

 

Teraz bierzemy się za metode główna cheat'a w której będziemy edytować wartości w pamięci.

private void cheatMain() {
  VAMemory memory;             // Deklaracja obiektu, który będzie nam potrzebny do edycji pamięci;

  var offsets = new {                             // Anonimowa klasa z offsetami, które pobralismy z 
    health = 0xF8,                                    // Cheat engine. Można je sprawdzić klikając na odpowiedni wskaznik
    armour = 0xFC,

    granades = 0x158,

    AssaultRifleAmmo1 = 0x150,
    SniperRifleAmmo1 = 0x14C,
    PistolAmmo1 = 0x13C,

    AssaultRifleAmmo2 = 0x128,
    SniperRifleAmmo2 = 0x124,
    PistolAmmo2 = 0x114,
  };

  Process cproc = processes[0];                           // pobranie procesu;

  foreach(ProcessModule module in cproc.Modules) {               
    if(module.ModuleName.Contains("ac_client")) {               
    	processBaseAdress = module.BaseAddress;                 // Przypisanie adresu procesu do zmiennej;
    }
  }

  memory = new VAMemory("ac_client");          

  playerBaseAddress = (IntPtr) memory.ReadInt32(processBaseAdress + 0x0010F4F4);          // Pobranie wskaznika do Entity Gracza

  while(enabled) {                        						// Jeśli przycisk enable został wcześniej wciśnięty

    if(unlimitedHealth) {                   						// Jeśli zaznaczono checkbox
      memory.WriteInt32(playerBaseAddress + offsets.health, value);               // Zapisz do pamięci wartość 
    }

    if(unlimitedArmour) {
      memory.WriteInt32(playerBaseAddress + offsets.armour, value);
    }

    if(infiniteAmmo) {
      memory.WriteInt32(playerBaseAddress + offsets.AssaultRifleAmmo1, value);
      memory.WriteInt32(playerBaseAddress + offsets.AssaultRifleAmmo2, value);
      memory.WriteInt32(playerBaseAddress + offsets.SniperRifleAmmo1, value);
      memory.WriteInt32(playerBaseAddress + offsets.SniperRifleAmmo2, value);
      memory.WriteInt32(playerBaseAddress + offsets.PistolAmmo1, value);
      memory.WriteInt32(playerBaseAddress + offsets.PistolAmmo2, value);
    }

    if(infiniteGranades) {
      memory.WriteInt32(playerBaseAddress + offsets.granades, value);
    }

	Thread.Sleep(100);
  }
}

 

 

Dobrneliśmy do końca tego 'poradnika' Mam nadzięję, że przybliżyło to wam mniej więcej jak przebiega proces pisania cheatów do gier.

 

Wszelkie pytania odnośnie kodu itp możecie kierować do mnie w wiadomościach prywatnych jak i pod tym tematem.

 

  •  carbonx zmienił(a) tytuł na Pisanie cheatów na przykładzie gry AssaultCube w C#
  • 1 miesiąc temu...
Opublikowano

"Poradnik" ten nie zawiera żadnych informacji oraz wytłumaczenia jak to działa konkretnie. Czasem mi się zdawało że mylisz wskaźnik z adresem wskazanym lub który zawiera ten adres?? 😖

Przykład zrobiony na martwej grze która siedzi bez zabezpieczeń, zero pokazanych technik jak omijać niektóre zabezpieczenia. Mogłeś pokusić się nawet o zwiększenie szansy na niewykrycie cheata hookując go jako internal w grze i rysować GUI czymś niskiego poziomu.. OpenGL?
Tak samo z programem, powinno to być do zainjectowania jako biblioteka dynamiczna a nie exek, gra może coś takiego wykryć i nawet zassać info o takim programie. Wolałbym przykład na kodzie gry CS:GO, wtedy mielibyśmy jakieś pole do popisu a nie zwykła automatyzacja tego co może zrobić Cheat Engine (nie korzystając z Lua i jego trainerów). Tak samo myślę że w informacji do osób czytających poradnik powinno być że w zmiennych system liczbowy może być dowolny obsługujący język, pisanie heksadecymalnie jeżeli odwołujemy się do mniejszych części adresu np. 0xF8,0xFC więc tutaj system dziesiętny okaże się o wiele bardziej czytelny a taka zamiana nie wpływa na wydajność końcowego kodu po kompilacji.
Jeżeli miałbym ocenić poradnik to 3/10.

Jestem programistą, zaufaj mi :)

Opublikowano
2 godziny temu, nycaffjs napisał:

"Poradnik" ten nie zawiera żadnych informacji oraz wytłumaczenia jak to działa konkretnie. Czasem mi się zdawało że mylisz wskaźnik z adresem wskazanym lub który zawiera ten adres?? 😖

Przykład zrobiony na martwej grze która siedzi bez zabezpieczeń, zero pokazanych technik jak omijać niektóre zabezpieczenia. Mogłeś pokusić się nawet o zwiększenie szansy na niewykrycie cheata hookując go jako internal w grze i rysować GUI czymś niskiego poziomu.. OpenGL?
Tak samo z programem, powinno to być do zainjectowania jako biblioteka dynamiczna a nie exek, gra może coś takiego wykryć i nawet zassać info o takim programie. Wolałbym przykład na kodzie gry CS:GO, wtedy mielibyśmy jakieś pole do popisu a nie zwykła automatyzacja tego co może zrobić Cheat Engine (nie korzystając z Lua i jego trainerów). Tak samo myślę że w informacji do osób czytających poradnik powinno być że w zmiennych system liczbowy może być dowolny obsługujący język, pisanie heksadecymalnie jeżeli odwołujemy się do mniejszych części adresu np. 0xF8,0xFC więc tutaj system dziesiętny okaże się o wiele bardziej czytelny a taka zamiana nie wpływa na wydajność końcowego kodu po kompilacji.
Jeżeli miałbym ocenić poradnik to 3/10.

Nie nazwałbym tego poradnikiem, bardziej artykułem wstępnym do pisania cheatów do róznych gier. Gra nie jest taka martwa, aczkolwiek nie posiada prawie żadnych zabezpieczeń. Zostało to celowo napisane w takiej formie aby zrozumieli to mniej zaawansowani, którzy dopiero swoją przygode z programowaniem zaczynają. Ten artykuł miał na celu przybliżyć jedynie proces. Gdybym miał pisać do takiej gry jak CS:GO artykuł by był zbyt długi, dlatego jako przykład wybrałem Assault Cube.

 

Nie ukrywam, że mogłem gdzieś pomylić nazewnictwo.

Opublikowano

Tylko po co ta gorsza wersja klamer >.< 
Dodatkowo trochę bym ten kod uszczuplił, a zmienne inaczej nazwał bo np.  tu ten kod jest nieczytelny 
 

Cytat

 

AssaultRifleAmmo1 = 0x150,

SniperRifleAmmo1 = 0x14C,

PistolAmmo1 = 0x13C,

AssaultRifleAmmo2 = 0x128,

SniperRifleAmmo2 = 0x124,

PistolAmmo2 = 0x114,

 

Poza tym chyba warto zamiast komentarza zrobić krótką funkcję ;P?

Zarchiwizowany

Ten temat przebywa obecnie w archiwum. Dodawanie nowych odpowiedzi zostało zablokowane.

×
×
  • Dodaj nową pozycję...