2015-02-20 6 views
11

über das Programm

habe ich ein Programm, das in den Speicher des Spiels schreibt mit experimentiere ich. Der Code funktioniert für mich ganz gut, wenn ich eine normale statische Adresse verwende, aber aus irgendeinem Grund kann ich es nicht tun, sobald ich einen funktionierenden Zeiger gefunden habe. Zum Beispiel finde ich dies in Cheat Engine nach Zeigerabtastregister ein paar Mal: ​​mit Zeigern Gefunden in Cheat Engine in C#

enter image description here

Die Adresse jedes Mal, arbeitet ich das Spiel laden und bearbeiten Sie den Wert. Das Problem ist, dass ich nicht verstehe, wie man es in meinem Programm benutzt. Hier ist meine deklarierten Variablen, die ich in den Werten zu stopfen versucht:

bool UnlimitedAmmo = false; 
string AmmoPointer = "031B7324"; // <--- The address 
int[] AmmoOffset = { 0x2c, 0x1e8, 0x3c8, 0x6d4, 0x508 }; // <--- It's pointers 
int AmmoToFill = 1337; // <--- The Amount of ammo to give 

Ich bin in dieser Variablen vorbei wie folgt:

MyMemory.ReadProcess = MyProcess[0]; 
MyMemory.Open(); 

int PointerAddress = HexToDec(AmmoPointer); 
int[] PointerOffest = AmmoOffset; 
int BytesWritten; 
byte[] ValueToWrite = BitConverter.GetBytes(AmmoToFill); 
string WrittenAddress = MyMemory.PointerWrite((IntPtr)PointerAddress, ValueToWrite, 
    PointerOffest, out BytesWritten); 
MyMemory.CloseHandle(); 

habe ich einmal eine statische Adresse (für ein anderes Spiel) und Mein Code funktionierte gut, sobald ich die Adresse und den Offset einsteckte. Ich bin diesmal ratlos. Jede Hilfe und Erklärungen würden sehr geschätzt werden. Danke im Voraus.

+0

Ich begann ein Kopfgeld auf diese Frage, wie ich derzeit versuche, das gleiche herauszufinden. Nämlich wie man die Adresse von 'THREADSTACK0' in C# bekommt. Ich habe einige Informationen darüber gefunden, wie es in cheatengine erstellt wird, und ich kann die Adresse in cheatengine lesen, aber keine der threadstartaddresses, die ich ziehe C# entspringe, was CE zurückgibt – user1274820

+0

Sehen Sie hier: http://forum.cheatengine.org/ viewtopic.php? p = 5487976 – user1274820

Antwort

3

Ich dachte, ich würde eine Lösung für diese Menschen in der Zukunft veröffentlichen.

Ein Weg, dies umgehen können, wenn Sie in den C nicht dort gespeichert ++ Code tauchen wollen und schreiben in C#, ist einfach dieses Programm auf Github zu verwenden:

https://github.com/makemek/cheatengine-threadstack-finder

Der direkte Download-Link hier ist:

https://github.com/makemek/cheatengine-threadstack-finder/files/685703/threadstack.zip

Sie diese ausführbare Datei eine Prozess-ID übergeben kann und die Thread-Adresse analysieren, die Sie benötigen.

Im Grunde, was ich getan habe, ist mein Prozess führt die exe, leitet die Ausgabe um, und analysiert es.

Dann schließt sich der Prozess und wir tun, was wir brauchen - ich fühle mich irgendwie wie ich betrüge, aber es funktioniert.

Der Ausgang für threadstack.exe sieht in der Regel wie folgt aus:

PID 6540 (0x198c) 
Grabbing handle 
Success 
PID: 6540 Thread ID: 0x1990 
PID: 6540 Thread ID: 0x1b1c 
PID: 6540 Thread ID: 0x1bbc 
TID: 0x1990 = THREADSTACK 0 BASE ADDRESS: 0xbcff8c 
TID: 0x1b1c = THREADSTACK 1 BASE ADDRESS: 0x4d8ff8c 
TID: 0x1bbc = THREADSTACK 2 BASE ADDRESS: 0x518ff8c 

Hier ist der Code ich die Adresse Ich brauche schließlich verwendet zu bekommen: Wenn Sie

[DllImport("kernel32.dll", SetLastError = true)] 
static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, [Out] byte[] lpBuffer, int dwSize, out int lpNumberOfBytesRead); 

//////////////////////////////////////////////////////////////////// 
// These are used to find the StardewValley.Farmer structure  // 
////////////////////////////////////////////////////////////////// 
private IntPtr Thread0Address; 
private IntPtr FarmerStartAddress; 
private static int[] FARMER_OFFSETS = { 0x4, 0x478, 0x218, 0x24C }; 
private static int FARMER_FIRST = 0x264; 
////////////////////////////////////////////////////////////////// 

private async void hookAll() 
{ 
    SVProcess = Process.GetProcessesByName("Stardew Valley")[0]; 
    SVHandle = OpenProcess(ProcessAccessFlags.All, true, SVProcess.Id); 
    SVBaseAddress = SVProcess.MainModule.BaseAddress; 
    Thread0Address = (IntPtr) await getThread0Address(); 
    getFarmerStartAddress(); 
} 
private Task<int> getThread0Address() 
{ 
    var proc = new Process 
    { 
     StartInfo = new ProcessStartInfo 
     { 
      FileName = "threadstack.exe", 
      Arguments = SVProcess.Id + "", 
      UseShellExecute = false, 
      RedirectStandardOutput = true, 
      CreateNoWindow = true 
     } 
    }; 
    proc.Start(); 
    while (!proc.StandardOutput.EndOfStream) 
    { 
     string line = proc.StandardOutput.ReadLine(); 
     if (line.Contains("THREADSTACK 0 BASE ADDRESS: ")) 
     { 
      line = line.Substring(line.LastIndexOf(":") + 2); 
      return Task.FromResult(int.Parse(line.Substring(2), System.Globalization.NumberStyles.HexNumber)); 
     } 
    } 
    return Task.FromResult(0); 
} 
private void getFarmerStartAddress() 
{ 
    IntPtr curAdd = (IntPtr) ReadInt32(Thread0Address - FARMER_FIRST); 
    foreach (int x in FARMER_OFFSETS) 
     curAdd = (IntPtr) ReadInt32(curAdd + x); 
    FarmerStartAddress = (IntPtr) curAdd; 
} 
private int ReadInt32(IntPtr addr) 
{ 
    byte[] results = new byte[4]; 
    int read = 0; 
    ReadProcessMemory(SVHandle, addr, results, results.Length, out read); 
    return BitConverter.ToInt32(results, 0); 
} 

Final

Ich bin daran interessiert, den C++ Code zu aktualisieren, ich glaube der relevante Teil ist hier.

Es sieht eigentlich nicht zu kompliziert - ich glaube, du bist nur die Basisadresse der kernal32.dll Grabbing und die Suche nach der Adresse in dem Thread-Stapel durch zu überprüfen, ob es >= an der Adresse Base oder <= zu die base address + size beim Lesen von jeweils 4 Bytes - ich müsste aber damit spielen.

DWORD GetThreadStartAddress(HANDLE processHandle, HANDLE hThread) { 
    /* rewritten from https://github.com/cheat-engine/cheat-engine/blob/master/Cheat%20Engine/CEFuncProc.pas#L3080 */ 
    DWORD used = 0, ret = 0; 
    DWORD stacktop = 0, result = 0; 

    MODULEINFO mi; 

    GetModuleInformation(processHandle, GetModuleHandle("kernel32.dll"), &mi, sizeof(mi)); 
    stacktop = (DWORD)GetThreadStackTopAddress_x86(processHandle, hThread); 

    /* The stub below has the same result as calling GetThreadStackTopAddress_x86() 
    change line 54 in ntinfo.cpp to return tbi.TebBaseAddress 
    Then use this stub 
    */ 
    //LPCVOID tebBaseAddress = GetThreadStackTopAddress_x86(processHandle, hThread); 
    //if (tebBaseAddress) 
    // ReadProcessMemory(processHandle, (LPCVOID)((DWORD)tebBaseAddress + 4), &stacktop, 4, NULL); 

    CloseHandle(hThread); 

    if (stacktop) { 
     //find the stack entry pointing to the function that calls "ExitXXXXXThread" 
     //Fun thing to note: It's the first entry that points to a address in kernel32 

     DWORD* buf32 = new DWORD[4096]; 

     if (ReadProcessMemory(processHandle, (LPCVOID)(stacktop - 4096), buf32, 4096, NULL)) { 
      for (int i = 4096/4 - 1; i >= 0; --i) { 
       if (buf32[i] >= (DWORD)mi.lpBaseOfDll && buf32[i] <= (DWORD)mi.lpBaseOfDll + mi.SizeOfImage) { 
        result = stacktop - 4096 + i * 4; 
        break; 
       } 

      } 
     } 

     delete buf32; 
    } 

    return result; 
} 

Sie können die Fadenbasisadressen in C# wie diese:

https://stackoverflow.com/a/8737521/1274820

Der Schlüssel ist die NtQueryInformationThread Funktion aufzurufen. Dies ist keine komplett "offizielle" Funktion (möglicherweise in der Vergangenheit undokumentiert?), Aber die Dokumentation schlägt keine Alternative vor, um die Startadresse eines Threads zu erhalten.

Ich habe es in einen .NET-freundlichen Anruf eingewickelt, der eine Thread-ID akzeptiert und die Startadresse als IntPtr zurückgibt. Dieser Code wurde im x86- und x64-Modus getestet, und im letzteren Fall wurde er sowohl auf einem 32-Bit- als auch auf einem 64-Bit-Zielprozess getestet.

Eine Sache, die ich nicht getestet habe, war das mit geringen Privilegien; Ich würde erwarten, dass dieser Code erfordert, dass der Anrufer die SeDebugPrivilege hat.

using System; 
using System.ComponentModel; 
using System.Diagnostics; 
using System.Linq; 
using System.Runtime.InteropServices; 

class Program 
{ 
    static void Main(string[] args) 
    { 
     PrintProcessThreads(Process.GetCurrentProcess().Id); 
     PrintProcessThreads(4156); // some other random process on my system 
     Console.WriteLine("Press Enter to exit."); 
     Console.ReadLine(); 
    } 

    static void PrintProcessThreads(int processId) 
    { 
     Console.WriteLine(string.Format("Process Id: {0:X4}", processId)); 
     var threads = Process.GetProcessById(processId).Threads.OfType<ProcessThread>(); 
     foreach (var pt in threads) 
      Console.WriteLine(" Thread Id: {0:X4}, Start Address: {1:X16}", 
           pt.Id, (ulong) GetThreadStartAddress(pt.Id)); 
    } 

    static IntPtr GetThreadStartAddress(int threadId) 
    { 
     var hThread = OpenThread(ThreadAccess.QueryInformation, false, threadId); 
     if (hThread == IntPtr.Zero) 
      throw new Win32Exception(); 
     var buf = Marshal.AllocHGlobal(IntPtr.Size); 
     try 
     { 
      var result = NtQueryInformationThread(hThread, 
          ThreadInfoClass.ThreadQuerySetWin32StartAddress, 
          buf, IntPtr.Size, IntPtr.Zero); 
      if (result != 0) 
       throw new Win32Exception(string.Format("NtQueryInformationThread failed; NTSTATUS = {0:X8}", result)); 
      return Marshal.ReadIntPtr(buf); 
     } 
     finally 
     { 
      CloseHandle(hThread); 
      Marshal.FreeHGlobal(buf); 
     } 
    } 

    [DllImport("ntdll.dll", SetLastError = true)] 
    static extern int NtQueryInformationThread(
     IntPtr threadHandle, 
     ThreadInfoClass threadInformationClass, 
     IntPtr threadInformation, 
     int threadInformationLength, 
     IntPtr returnLengthPtr); 

    [DllImport("kernel32.dll", SetLastError = true)] 
    static extern IntPtr OpenThread(ThreadAccess dwDesiredAccess, bool bInheritHandle, int dwThreadId); 

    [DllImport("kernel32.dll", SetLastError = true)] 
    static extern bool CloseHandle(IntPtr hObject); 

    [Flags] 
    public enum ThreadAccess : int 
    { 
     Terminate = 0x0001, 
     SuspendResume = 0x0002, 
     GetContext = 0x0008, 
     SetContext = 0x0010, 
     SetInformation = 0x0020, 
     QueryInformation = 0x0040, 
     SetThreadToken = 0x0080, 
     Impersonate = 0x0100, 
     DirectImpersonation = 0x0200 
    } 

    public enum ThreadInfoClass : int 
    { 
     ThreadQuerySetWin32StartAddress = 9 
    } 
} 

Ausgang auf meinem System:

Process Id: 2168 (this is a 64-bit process) 
    Thread Id: 1C80, Start Address: 0000000001090000 
    Thread Id: 210C, Start Address: 000007FEEE8806D4 
    Thread Id: 24BC, Start Address: 000007FEEE80A74C 
    Thread Id: 12F4, Start Address: 0000000076D2AEC0 
Process Id: 103C (this is a 32-bit process) 
    Thread Id: 2510, Start Address: 0000000000FEA253 
    Thread Id: 0A0C, Start Address: 0000000076F341F3 
    Thread Id: 2438, Start Address: 0000000076F36679 
    Thread Id: 2514, Start Address: 0000000000F96CFD 
    Thread Id: 2694, Start Address: 00000000025CCCE6 

abgesehen von dem Zeug in Klammern, da dies erfordert zusätzliche P/Invoke ist.


In Bezug auf SymFromAddress „Modul nicht gefunden“ Fehler, ich wollte nur, dass man erwähnen muss SymInitialize mit fInvadeProcess = true anrufen oder das Modul manuell laden, as documented on MSDN.