WinAPI use in C#

05/19/2008 18:22 Term!nX#1
Hi,

in Anlehnung an die Topics hier habe ich mich dazu aufgerafft, nen Annotrainer zu schreiben (siehe Attachment).

In der Listview werden halt aktive Annoprozesse angezeigt, die man dann anwählen kann um dann mit dem Cheat button Geld zu cheaten. Jedes item in der Listview hat im item.Tag das jeweilige Prozessobject, somit auch die ID.

Allerdings komme ich mit den eigentlichen Funktionen OpenProcess, ReadProcessMemory und WirteProcessMemory in C# noch nicht klar. Zwar bekomme ich das irgendwie hin, aber ich würde es gerne richtig verstehen und nicht nur die compilerfehler behandeln.

Imports:
Code:
        [DllImport("kernel32.dll")]
        static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress,
           byte[] lpBuffer, UIntPtr nSize, out IntPtr lpNumberOfBytesWritten);
        
        [DllImport("kernel32.dll")]
        static extern IntPtr OpenProcess(UInt32 dwDesiredAccess, Boolean bInheritHandle, UInt32 dwProcessId);
Code:
IntPtr phdl = OpenProcess(0x10, false, (uint)po.Id);
Das Handle, is sogar != null.

Zwar weiss ich, dass man die für C# "unbekannten" Datenformate wie zB DWORD irgendwie in ein IntPtr Objekt umwandelt, aber was da genau passiert und was es bedeutet weiss ich nicht. Und das wüsste ich gern :)

Grüße
05/19/2008 19:41 Term!nX#2
Mir grad erst aufgefallen, komischerweise dp, obwohl ich nur edit gemacht habe ..
05/19/2008 22:05 sirru#3
Ich finde den Startpost seehr unpräzise.
Bitte mehr Quellcode, am besten das ganze Projekt und dazu noch ne konkrete Frage.
Hier meine allgemeine Antwort für deine allgemeine Frage: [Only registered and activated users can see links. Click Here To Register...]
(Google c# dword erster Treffer :x)
05/20/2008 12:37 Term!nX#4
Joa es geht nur darum, wie ich die unterschiedlichen Datentypen behandle.
In C++ war es DWORD PROCESS_VM_READ zB, oder HANDLE processhndl. Hier mal der Code in C++:

Code:
#include <iostream>
#include <stdlib.h>
#include <windows.h>

using namespace std;

class Trainer {
    public:
        Trainer();
        ~Trainer();
        int Pressed(int vkey);
        void SetMoneyValue();
        void GetHandles();
        void SetMoney();
        
    private:
        int ValueAddToMoney;
        HWND hWnd;
        HANDLE hProcess;
        DWORD dwProcessId;
        unsigned lpBaseAdress
        int buffer;
        DWORD rw; 
};

Trainer::Trainer()
{
    lpBaseAdress = 0x560264; //Hier Speicheradresse für Gold eingeben
    rw = 0;
}

Trainer::~Trainer()
{
    CloseHandle(hProcess);
}

void Trainer::SetMoneyValue()
{
    cout << "Wieviel Gold hinzufügen?n";
    cin >> ValueAddToMoney;
}

void Trainer::GetHandles()
{
  hWnd = FindWindowA(NULL, "Anno 1602");
  
  if (hWnd == 0) {
    cerr << "Fenster nicht gefunden. Prozess offen? Exit in 3 Sekunden.";
    Sleep(3000);
    exit(1);
  }
  
  GetWindowThreadProcessId(hWnd, &dwProcessId);

  hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId);
  
  if (hProcess == 0)
  {
  DWORD error = GetLastError();

  cout << "n Errorcode: " << error << "n";
  cout << "Handle konnte nicht initialisiert werden. Exit in 3 Sekunden.n";
  Sleep(3000);
  exit(1);
  }
}  

void Trainer::SetMoney()
{ 
  ReadProcessMemory(hProcess, (LPCVOID)lpBaseAdress, &buffer, sizeof(int), &rw);
  
  WriteProcessMemory(hProcess, (LPVOID)lpBaseAdress, &(buffer = buffer + ValueAddToMoney), sizeof(int), &rw);
}    
                  
int Trainer::Pressed(int vkey)
{
    //return GetAsyncKeyState(vkey);
}

int main(int argc, char *argv[])
{
  Trainer Anno;
  
  Anno.SetMoneyValue();
  Anno.GetHandles();
  
  while (true)
  {
      Sleep(50);
      if (Anno.Pressed(0x79)!= 0)
      {
          Anno.SetMoney();
      }    
  }  
  
  system("PAUSE");	
  return 0;
}
Jetzt steht da als 1 Argument der ReadProcessMemory Funktion: DWORD dwProcessId. DWORD gibts aber in C# nicht, also mache ich aus DWORD irgendwie IntPtr. Darum gehts im Endeffekt, wie ich der Funktion die DWORD, HANDLE und HWND Argumente liefere, ohne diese Datentypen in C# wirklich verfügbar zu haben.
05/20/2008 20:35 Term!nX#5
Code:
            IntPtr phdl = OpenProcess(0x10, false, (uint)po.Id);
            if (phdl == null)
                MessageBox.Show("Prozesshandle konnte nicht erstellt werden! Prozess aktiv?", "Fehler!");
            uint size = 4;
            // uint vNumberOfBytesRead = 0;
            byte[] vBuffer = new byte[size];
            uint adress = 0x560264;
            uint size2 = sizeof(int);
            IntPtr rw;
            bool read;
            read = ReadProcessMemory(phdl, (IntPtr)adress, vBuffer, (UIntPtr)size2, out rw);
            if (!read)
                MessageBox.Show("ReadMem fehlgeschlagen.");
            bool write;
            vBuffer = BitConverter.
            write = WriteProcessMemory(phdl, (IntPtr)adress, vBuffer, (UIntPtr)size2, out rw);
            if (!write)
                MessageBox.Show("write fehlgeschlagen.");
So. ReadMemory klappt, gibt auch den richtigen Wert an. Jetzt weiss ich bei write memory nicht, wie ich den Wert des Buffers jetzt verändere, damit ich letzlich den Wert an der Speicherstelle verändern kann. Im Moment ist write immer false (vBuffer = BitConverter. ist absichtlich stehen gelassen und nicht der Fehler :))
05/20/2008 23:23 sirru#6
Wort = 1Byte
Dword = Doppelwort = 2Byte
Zumindest habe ich das mal so gelernt, du solltest einfach immer den Datentyp wählen in den die Zahl die von der WinAPI kommt rein passt.
Hättest dir vielleicht mal den Link den ich gepostet habe anschauen sollen, da ist genau so ein Beispiel aufgeführt:
Quote:
Arbeiten mit Strukturen

Ich wollte schon öfter den Akkustatus meines Laptops ermitteln. Win32 bietet Energieverwaltungsfunktionen für das Abrufen dieser Informationen.
Eine Suche im MSDN führt schnell zu der GetSystemPowerStatus()-Funktion.

BOOL GetSystemPowerStatus(
LPSYSTEM_POWER_STATUS lpSystemPowerStatus
);

Diese Funktion verarbeitet einen Zeiger auf eine Struktur. Darauf sind wir bisher noch nicht eingegangen. Für das Arbeiten mit Strukturen müssen wir eine Struktur in C# definieren. Wir beginnen mit der nicht verwalteten Definition:

typedef struct _SYSTEM_POWER_STATUS {
BYTE ACLineStatus;
BYTE BatteryFlag;
BYTE BatteryLifePercent;
BYTE Reserved1;
DWORD BatteryLifeTime;
DWORD BatteryFullLifeTime;
} SYSTEM_POWER_STATUS, *LPSYSTEM_POWER_STATUS;

Anschließend schreiben wir eine C#-Version, indem wir die C-Typen durch ihre C#-Entsprechungen ersetzen.

struct SystemPowerStatus
{
byte ACLineStatus;
byte batteryFlag;
byte batteryLifePercent;
byte reserved1;
int batteryLifeTime;
int batteryFullLifeTime;
}

Nun können wir einfach den C#-Prototyp schreiben:

[DllImport("kernel32.dll")]
public static extern bool GetSystemPowerStatus(
ref SystemPowerStatus systemPowerStatus);
IntP(oin)tr sind übrig eigentlich für was anderes gedacht:
[Only registered and activated users can see links. Click Here To Register...]

Da ich wieder selbst recherchieren müsste um den Quellcode nachzuvollziehen gucke ich mir das morgen mal an und schreibe dir vielleicht was dazu.
05/22/2008 16:37 x]vIrus[x#7
Quote:
Originally Posted by sirru View Post
Wort = 1Byte
Dword = Doppelwort = 2Byte
Zumindest habe ich das mal so gelernt, du solltest einfach immer den Datentyp wählen in den die Zahl die von der WinAPI kommt rein passt.
Hättest dir vielleicht mal den Link den ich gepostet habe anschauen sollen, da ist genau so ein Beispiel aufgeführt:
IntP(oin)tr sind übrig eigentlich für was anderes gedacht:
[Only registered and activated users can see links. Click Here To Register...]

Da ich wieder selbst recherchieren müsste um den Quellcode nachzuvollziehen gucke ich mir das morgen mal an und schreibe dir vielleicht was dazu.
word = 16bit = 2 byte
dword = 32bit = 4byte = in c# nimmt man dafür unsigned int, (uint)

ein handle ist einfach ein IntPtr
05/22/2008 16:45 Term!nX#8
Danke, dass hilft mir schon weiter :) hab leider keine Zeit mir die Seiten vernünftig durchzulesen. Mal sehen, danke!
05/22/2008 20:09 mondesser#9
Quote:
Originally Posted by x]vIrus[x View Post
dword = 32bit = 4byte = in c# nimmt man dafür unsigned int, (uint)
Ich hätte dafür spontan einen Int32 genommen in c#.
Oder kann ein dword nicht negativ sein?
05/24/2008 04:01 sirru#10
Kommt ganz drauf an nehm ich an.
Der Unterschied zwischen Int und Uint besteht ja darin, dass beim normalen Integer das MSB als Vorzeichenbit verwendet wird und die Zahl deswegen um ein Bit kleiner ist.
Trotzdem sind sowohl int als auch unit beides 32 (ja ich glaube der viri hat Recht, ich war mir selber nicht ganz sicher) Bit Zahlen.
06/08/2008 14:43 Term!nX#11
Öhm wenn ich ein bytearray habe.. Wie kann man das jetzt bearbeiten? Unter anderem möchte ich den Wert in int konvertieren, habe dazu das gemacht:

Code:
                int[] ints = new int[bytes.Length];
                for (int i = 0; i < bytes.Length; i++)
                {
                    ints[i] = bytes[i];
                }
                int val = 0;
                for (int k = 0; k < ints.Length; k++)
                {
                    val += ints[k];
                    MessageBox.Show(ints[k].ToString());
                }
                MessageBox.Show(val.ToString(), "Value:");
Aber val ist nicht richtig. Denn irgendwie muss ich das bytearray ja verändern, um einen neuen Wert zu schreiben.

In cpp macht man einfach &(buffer = buffer + x)
06/08/2008 17:43 mondesser#12
Quote:
Originally Posted by Term!nX View Post
Öhm wenn ich ein bytearray habe.. Wie kann man das jetzt bearbeiten? Unter anderem möchte ich den Wert in int konvertieren, habe dazu das gemacht:

Aber val ist nicht richtig. Denn irgendwie muss ich das bytearray ja verändern, um einen neuen Wert zu schreiben.

In cpp macht man einfach &(buffer = buffer + x)


Schau dir mal die Klasse [Only registered and activated users can see links. Click Here To Register...] an.
Die stellt genau das zur Verfügung, was du suchst.
06/08/2008 19:14 Term!nX#13
Fein :) Danke.
06/09/2008 01:15 Bot_interesierter#14
Die Größe des words hängt auch von der Prozessor Architektur ab, man kann also nicht sagen ein word entsprich 16bits, oder ein dword entschricht 32bits.
06/09/2008 02:14 -Anthrax-#15
Nein, ein DWORD ist unter x64 auch nur 32 Bit groß. Allerdings passen die nun verwendeten 64 Bit-Adressen nicht mehr in ein DWORD. Im MSDN-Artikel ist das alles wunderbar erklärt

c-p von [Only registered and activated users can see links. Click Here To Register...] ^^