[MFC/C++] Class: CBotEngine

07/07/2009 16:28 Adroxxx#1
[MFC/C++] Class: CBotEngine

Hier mal eine recht simple Klasse um das Bot schreiben zu vereinfachen. Natürlich ist es sehr primitiv aber vielleicht hilft es dem ein oder anderen.


#Inhalt:
[-]Klassenbeschreibung
[-]Beispielcode/Benutzung
[-]Nachwort



[-]Klassenbeschreibung

Die Klasse ist in Visual C++ (MFC) geschrieben und Unicode kompatibel.

Zur Zeit hat es nur 6 Funktionen:

SendKey(), um einen Tastendruck zu simulieren mit VKs.
SendText(), um einen ganzen Text zu senden bzw. einen CString.
TargetWindow(), um ein Fensterhandle zu holen.
MemoryRead(), um eine Adresse auszulesen.
sRead(), um aus einer ini Datei Werte zu lesen.
MouseClick(), um einen Mausklick zu simulieren.

Die Funktionen wurden in der Klasse so weit wie möglich vereinfacht, damit man sie leicht benutzten kann. Außerdem sind die Funktionen so programmiert, dass sie im Hintergrund laufen. Sprich wenn der Bot läuft, könnt ihr das Spiele Fenster minimieren und etwas anderes machen.

CBotEngine.h:
PHP Code:
#pragma once

/***************************************************************************
* CBotEngine v 1.0
*    SendKey() Sendet einen Tastendruck. Benutztung mit Virtual Key Codes
*    SendText() Sendet einen Text. Benutzung mit CString
*    TargetWindow() Holt sich den Window Handle
*    MemoryRead() Liest Speicheradresse aus
*    sRead() Liest einen String aus einer INI Datei aus
*    MouseClick() Maus macht einen Klick an einer bestimmten Koordinate
***************************************************************************/
class CBotEngine
{
public:
    
CBotEngine(void);
    ~
CBotEngine(void);


    
void SendKey(unsigned int KEYDWORD DELAY=20);
    
void SendText(CString strText);
    
void TargetWindow(CString strWnd);
    
int MemoryRead(unsigned address);
    
CString sRead(CString strIniNameCString AppNameCString KeyName);
    
void MouseClick(int xPosint yPosDWORD DELAY=100);
    

    
CWnd *pWnd;
    
HWND hWnd;
    
DWORD procID;
}; 
CBotEngine.cpp
PHP Code:
#include "StdAfx.h"
#include "BotEngine.h"
#define BUFSIZE MAX_PATH


CBotEngine::CBotEngine(void)
{
}

CBotEngine::~CBotEngine(void)
{
}

void CBotEngine::SendKey(unsigned int KEYDWORD DELAY)
{

    
LPARAM pmLparam = (::MapVirtualKey(KEY,0)<<16);
    
    
pWnd->PostMessage(WM_KEYDOWN,0,pmLparam);
    
pWnd->PostMessage(WM_CHAR,0,pmLparam);
    
Sleep(DELAY); 
    
pWnd->PostMessage(WM_KEYUP,0,pmLparam);
         
}

void CBotEngine::TargetWindow(CString strWnd)
{
    
    if (
pWnd CWnd::FindWindowExW(NULL,NULL,NULL,strWnd)) {
        
        
hWnd HWND(pWnd->GetSafeHwnd()); 
        
GetWindowThreadProcessId(hWnd,&procID);
        
    }else{
    
AfxMessageBox(_T("Fenster nicht gefunden!"));
    }
    
}

int CBotEngine::MemoryRead(unsigned address)

{
    
int i;
    
DWORD numBytesRead;
    
    
GetWindowThreadProcessId(hWnd,&procID);
    
HANDLE hProc OpenProcess(PROCESS_ALL_ACCESSFALSEprocID);
    
ReadProcessMemory(hProc, (LPCVOID)address, &isizeof(i), &numBytesRead);
    
CloseHandle(hProc);

    return 
i;

    
}

CString CBotEngine::sRead(CString strIniNameCString AppNameCString KeyName)
{

    
    
CString strBuf;
    
TCHAR cDic[BUFSIZE];
    
    
GetCurrentDirectoryW(BUFSIZE,cDic);
    
CString sDic CString(cDic);

    
sDic.Format(_T("%s\\%s"),cDic,strIniName);
    
GetPrivateProfileString(AppName,KeyName,_T(""),strBuf.GetBuffer(254),254,sDic);
    
    return 
strBuf;
}

void CBotEngine::MouseClick(int xPosint yPosDWORD DELAY)
{
    
pWnd->SendMessage(WM_LBUTTONDOWN,MK_LBUTTON,MAKELPARAM(xPos,yPos));
    
Sleep(DELAY);  
    
pWnd->SendMessage(WM_LBUTTONUP,MK_LBUTTON,MAKELPARAM(xPos,yPos));
}



void CBotEngine::SendText(CString strText)
{
    
    
unsigned int *iText;
    
iText = new unsigned int[strText.GetLength()];

    for (
int i =0;<= strText.GetLength();i++)
    {
        
iText[i] = strText[i];
        
pWnd->PostMessage(WM_KEYDOWN,iText[i],0);
        
Sleep(70);
    }



[-]Beispielcode/Benutzung

Ihr müsst als erstes die CBotEngine.h und CBotEngine.cpp in euer Projekt einbinden. Im Anhang hab ich diese nochmal gepackt und dort ist auch eine VKC.h die nochmal die Virutal Key Codes beinhaltet, da (bei mir jedenfalls) in MFC nicht alle Codes definiert sind. Nachdem ihr die Header eingebunden habt, braucht ihr nur euer Objekt erstellen und könnt dann die Funktionen nutzen.

Beispielcode:
Fensterhandle holen und Key Senden, Text Senden

PHP Code:
CBotEngine MyBot/* Objekt wird erstellt */
CString WindowName _T("MeinSpiel"); /* CString Variable mit Namen des Spiels wird erstellt */
CString CustomText _("/giveup"); /* CString Variable mit einem Text wird erstellt */

MyBot.TargetWindow(WindowName); /* CBotFunktion wird aufgerufen und die Variable WindowName übergeben, jetzt haben wir das Handle um an das Fenster senden zu können */

MyBot.SendKey(VK_I); /* Simuliert den Tastendruck, der Taste I und sendet ihn an das Spielefenster. Zum Beispiel um das Inventar zu öffnen */
Sleep(200); /* Damit die nächste Taste nicht zu schnell hintereinander kommt, brauchen wir hier ein Sleep um eine verzögerung rein zu bringen */
MyBot.SendKey(VK_RETURN); /* Drückt die Enter Taste um z.B. den Chat zu öffnen */
Sleep(200);
MyBot.SendText(CustomText); /*Sendet den Inhalt der Variable Custom Text an die Funktion. Das heißt in userem Fall es wird "/giveup" in den Chat eingegeben */
Sleep(200);
MyBot.SendKey(VK_RETURN/* Es wird nochmal Enter gedrückt. Text im Chat wird also abgeschickt */ 


Beispielcode #2:

Werte aus einer INI Datei Lesen.

Sagen wir unsere INI Datei (settings.ini) ist so aufgebaut:
Code:
[SETTINGS]
Sprache=0
AnzahldRunden=40
Verkaufen=1

[MEMORY]
posx=0x41000
posy=0x41004
Können wir das so auslesen:
PHP Code:
CBotEngine rd// Unser Objekt
CString ininame _T("settings.ini"); //Name der Ini datei
CString section[2] = {_T("SETTINGS"),_T("MEMORY")};
CString key[5] = {_T("Sprache"),_T("AnzahldRunden"),_T("Verkaufen"),_T("posx"),_T("posy")};


m_strSprache rd.sRead(ininame,section[1],key[1]);
m_strRunden rd.sRead(ininame,section[1],key[2]);
m_strVerkauf rd.sRead(ininame,section[1],key[3]);
m_strPosx rd.sRead(ininame,section[2],key[1]);
m_strPosy rd.sRead(ininame,section[2],key[2]); 
So könnt ihr mit Arrays auch mehrere INI dateien auslesen. Wenn ihr z.B. eine update.ini und settings.ini habt, macht ihr CString ininame auch als array und packt beide rein und beim auslesen macht ihr ininame halt auch als array.



[-]Nachwort

Die Klasse sollte eigentlich bei allen Spielen Funktionieren. Ich hoffe ich konnte euch damit etwas Arbeit ersparen. Auch wenn diese Klasse nicht das Gelbe vom Ei ist.

Für Verbesserungsvorschläge bin ich offen :)

So far,
Adroxxx
07/11/2009 04:29 backo#2
1. ) delete[] iText in SendText vergessen?
2. ) zu deinem dtor: Rule of three (C++ programming) - Wikipedia, the free encyclopedia
3. ) CBotEngine(void); sowas machte man frueher in c, aber nicht in C++.
4. ) Wieso definierst du den ctor/dtor obwohl du garnix drin machst? ^^


Ansonsten nett, obwohl ich persoenlich kein MFC fan bin. ^^
07/11/2009 11:52 Adroxxx#3
Ja MFC ist Geschmackssache. Ich wurde in der Vergangenheit über Jahre gezwungen MFC zu benutzten, deswegen bin ich auch dabei geblieben. Eigentlich nur aus der Gemüdlichkeit heraus. Wobei eigentlich in dem Source nur CWnd wirklich MFC Spezifisch ist. Kann man also ohne viel Aufwand umschreiben um es auch ohne MFC nutzen zu können.

So ein delete wär wohl nicht schlecht bei SendText. Danke. Hab die Klasse mal so nebenbei geschrieben und eigentlich auch noch nie wirklich verwendet. Nur testweise.

Ja das void kann man weg lassen, muss man aber nicht. Hat soweit ich weiß keinen Einfluss auf die Funktionalität.

ctor und dtor werden bei Visual Studio automatisch mit angelegt wenn man eine Klasse erstellt. Und bin zu faul des weg zu löschen :P ^^

Wie gesagt die Klasse ist nix tolles, bietet aber Leuten die vorher noch nie einen Bot programmiert haben, einen kleinen Einstieg. Ob sie jetzt die Klasse benutzten oder sich nur die Funktionen anschauen und selber nachbauen.
07/11/2009 17:48 backo#4
Quote:
Originally Posted by Adroxxx View Post
Ja MFC ist Geschmackssache. Ich wurde in der Vergangenheit über Jahre gezwungen MFC zu benutzten, deswegen bin ich auch dabei geblieben. Eigentlich nur aus der Gemüdlichkeit heraus. Wobei eigentlich in dem Source nur CWnd wirklich MFC Spezifisch ist. Kann man also ohne viel Aufwand umschreiben um es auch ohne MFC nutzen zu können.

So ein delete wär wohl nicht schlecht bei SendText. Danke. Hab die Klasse mal so nebenbei geschrieben und eigentlich auch noch nie wirklich verwendet. Nur testweise.

Ja das void kann man weg lassen, muss man aber nicht. Hat soweit ich weiß keinen Einfluss auf die Funktionalität.

ctor und dtor werden bei Visual Studio automatisch mit angelegt wenn man eine Klasse erstellt. Und bin zu faul des weg zu löschen :P ^^

Wie gesagt die Klasse ist nix tolles, bietet aber Leuten die vorher noch nie einen Bot programmiert haben, einen kleinen Einstieg. Ob sie jetzt die Klasse benutzten oder sich nur die Funktionen anschauen und selber nachbauen.
Man sieht das du dich am meisten mit MFC beschäftigt hast, sieht man ja da du die Ungarische Notation vorziehst, wie jeder MFC typ ^^. Ansonsten, zum jeden "new" muss ein "delete" kommen, dass gleiche gilt für "new []" & "delete []" Ich denke mal, dass du das allerdingst schon wusstest, wollts nur mal andeuten, für die anderen die sich den thread anguggn. Ein tipp, du könntest dir "visual assist x" runterladen, top plugin für ms vs, viel besser als die intellisense von ms. Nun, muss weg, cu. ;)
07/12/2009 13:09 Adroxxx#5
Danke für den Tipp :) Werde es mir mal laden.
12/01/2009 14:55 darkMedic#6
wird die engine eventuell noch erweitert? :)
12/01/2009 17:18 Adroxxx#7
Quote:
Originally Posted by darkMedic View Post
wird die engine eventuell noch erweitert? :)
Hm ne eigentlich nicht =d Wer lust hat kann sie selbst erweitern. Deswegen auch opensource.

Was fehlt denn deiner Meinung nach noch?
12/07/2009 15:25 darkMedic#8
MemoryWrite währe sicher ganz interessant.
12/07/2009 16:53 Gianotti#9
Quote:
Originally Posted by darkMedic View Post
MemoryWrite währe sicher ganz interessant.
writeprocessmemory o0
12/07/2009 16:54 Adroxxx#10
Naja, kann man die MemoryRead Funktion kopieren und nach Write umschreiben.
Und beim Botschreiben wird ja eher der Speicher gelesen als geschrieben.
12/07/2009 17:25 darkMedic#11
manchmal ist es aber vorteilhafter( vonner Schnelligkeit her) memory zu schreiben, z.b bei nem Angel Bot.
12/13/2009 23:23 Neyoel#12
ich find es gut, eine funktion um eine ini zu schreiben wäre vllt noch sinnvoll da man bei einem bot ja auch einstellungen speichert, ist benutzerfreundlicher wenn man das über eine GUI macht als dass die user selbst in der ini rumpfuschen ^^ aber die funktion kann man ja auch selbst einbauen, die funktion zum lesen ist ja schon da kann man ja fast kopieren xD
12/18/2009 08:24 Arcо#13
Oooh this is simple but fairly enough to teach others how to start creating bots.
Great release. I love it.