creating trainers and software enhancement programs in blitz

Blitz3D Forums/Blitz3D Programming/creating trainers and software enhancement programs in blitz

Mike Yurgalavage(Posted 2004) [#1]
this topic may have been covered before but i did a few seaches and came up with nothing. basically i would like to be able to make "trainers" or "game enhancers" for my favorite games. stuff like adding lives and tweaking weapons, changing items, etc. this usually can be done by peeks and pokes into the game's .exe. the problem is this:

when i run a blitz program, how to i "grab" the memory addresses of the game program (let's call it game.exe) while it is running? i don't want to edit it as a file on the harddrive, but edit it while it is a program that is running (a separate process running). not sure how to do this-

anyways, it will be impossible to do peeks and pokes to any addresses of the running program (process) game.exe without knowing where it is stored in the computer's ram while it is running. i need to be able to "open" the game.exe process from within my blitz program to get to it's addresses.

blitz would be an easy tool to make this kind of program since the programming language of it would be very easy. i have had blitz for over a year but haven't tried anything like this. the coding would be simple, the thing i don't know how to do is "grabbing" the process of another program (i.e. the game.exe process) and getting the address of where it is running in ram.

thanks for your help in advance-
best,
mike


BlitzSupport(Posted 2004) [#2]
No idea how feasible it is, but you could try the Win32 API commands ReadProcessMemory and WriteProcessMemory. You'd have to do this via Blitz's userlibs and use other Win32 commands such as CreateToolhelp32Snapshot/Process32First/Process32Next to look through the list of processes and get a handle to the correct process. Not really a trivial job, though!


Mike Yurgalavage(Posted 2004) [#3]
thanks james. unfortunately the api calls to createtoolhelp look like they require some declarations that haven't been done by anyone yet for blitz (like the createtoolhelp32snapshot, etc.) it would be cool to make really nice custom trainers or game enhancement or modifying programs with blitz because of it's power and ease of use. however, getting into the windows api stuff really makes it hard. i have the c code below but would have no idea how to convert this into something that i could use in blitz.... if i did i would put it in the code archives and others could use it. anyone want to make a stab at it?

thanks
mike


http://msdn.microsoft.com/library/default.asp?url=/library/en-us/perfmon/base/taking_a_snapshot_and_viewing_processes.asp

--c++ code below-

#include <windows.h>
#include <tlhelp32.h>
#include <stdio.h>

// Forward declarations:
BOOL GetProcessList( );
BOOL ListProcessModules( DWORD dwPID );
BOOL ListProcessThreads( DWORD dwOwnerPID );
void printError( TCHAR* msg );


void main( )
{
GetProcessList( );
}


BOOL GetProcessList( )
{
HANDLE hProcessSnap;
HANDLE hProcess;
PROCESSENTRY32 pe32;
DWORD dwPriorityClass;

// Take a snapshot of all processes in the system.
hProcessSnap = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 );
if( hProcessSnap == INVALID_HANDLE_VALUE )
{
printError( "CreateToolhelp32Snapshot (of processes)" );
return( FALSE );
}

// Set the size of the structure before using it.
pe32.dwSize = sizeof( PROCESSENTRY32 );

// Retrieve information about the first process,
// and exit if unsuccessful
if( !Process32First( hProcessSnap, &pe32 ) )
{
printError( "Process32First" ); // Show cause of failure
CloseHandle( hProcessSnap ); // Must clean up the snapshot object!
return( FALSE );
}

// Now walk the snapshot of processes, and
// display information about each process in turn
do
{
printf( "\n\n=====================================================" );
printf( "\nPROCESS NAME: %s", pe32.szExeFile );
printf( "\n-----------------------------------------------------" );

// Retrieve the priority class.
dwPriorityClass = 0;
hProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, pe32.th32ProcessID );
if( hProcess == NULL )
printError( "OpenProcess" );
else
{
dwPriorityClass = GetPriorityClass( hProcess );
if( !dwPriorityClass )
printError( "GetPriorityClass" );
CloseHandle( hProcess );
}

printf( "\n process ID = 0x%08X", pe32.th32ProcessID );
printf( "\n thread count = %d", pe32.cntThreads );
printf( "\n parent process ID = 0x%08X", pe32.th32ParentProcessID );
printf( "\n Priority Base = %d", pe32.pcPriClassBase );
if( dwPriorityClass )
printf( "\n Priority Class = %d", dwPriorityClass );

// List the modules and threads associated with this process
ListProcessModules( pe32.th32ProcessID );
ListProcessThreads( pe32.th32ProcessID );

} while( Process32Next( hProcessSnap, &pe32 ) );

// Don't forget to clean up the snapshot object!
CloseHandle( hProcessSnap );
return( TRUE );
}


BOOL ListProcessModules( DWORD dwPID )
{
HANDLE hModuleSnap = INVALID_HANDLE_VALUE;
MODULEENTRY32 me32;

// Take a snapshot of all modules in the specified process.
hModuleSnap = CreateToolhelp32Snapshot( TH32CS_SNAPMODULE, dwPID );
if( hModuleSnap == INVALID_HANDLE_VALUE )
{
printError( "CreateToolhelp32Snapshot (of modules)" );
return( FALSE );
}

// Set the size of the structure before using it.
me32.dwSize = sizeof( MODULEENTRY32 );

// Retrieve information about the first module,
// and exit if unsuccessful
if( !Module32First( hModuleSnap, &me32 ) )
{
printError( "Module32First" ); // Show cause of failure
CloseHandle( hModuleSnap ); // Must clean up the snapshot object!
return( FALSE );
}

// Now walk the module list of the process,
// and display information about each module
do
{
printf( "\n\n MODULE NAME: %s", me32.szModule );
printf( "\n executable = %s", me32.szExePath );
printf( "\n process ID = 0x%08X", me32.th32ProcessID );
printf( "\n ref count (g) = 0x%04X", me32.GlblcntUsage );
printf( "\n ref count (p) = 0x%04X", me32.ProccntUsage );
printf( "\n base address = 0x%08X", (DWORD) me32.modBaseAddr );
printf( "\n base size = %d", me32.modBaseSize );

} while( Module32Next( hModuleSnap, &me32 ) );

// Don't forget to clean up the snapshot object.
CloseHandle( hModuleSnap );
return( TRUE );
}

BOOL ListProcessThreads( DWORD dwOwnerPID )
{
HANDLE hThreadSnap = INVALID_HANDLE_VALUE;
THREADENTRY32 te32;

// Take a snapshot of all running threads
hThreadSnap = CreateToolhelp32Snapshot( TH32CS_SNAPTHREAD, 0 );
if( hThreadSnap == INVALID_HANDLE_VALUE )
return( FALSE );

// Fill in the size of the structure before using it.
te32.dwSize = sizeof(THREADENTRY32 );

// Retrieve information about the first thread,
// and exit if unsuccessful
if( !Thread32First( hThreadSnap, &te32 ) )
{
printError( "Thread32First" ); // Show cause of failure
CloseHandle( hThreadSnap ); // Must clean up the snapshot object!
return( FALSE );
}

// Now walk the thread list of the system,
// and display information about each thread
// associated with the specified process
do
{
if( te32.th32OwnerProcessID == dwOwnerPID )
{
printf( "\n\n THREAD ID = 0x%08X", te32.th32ThreadID );
printf( "\n base priority = %d", te32.tpBasePri );
printf( "\n delta priority = %d", te32.tpDeltaPri );
}
} while( Thread32Next(hThreadSnap, &te32 ) );

// Don't forget to clean up the snapshot object.
CloseHandle( hThreadSnap );
return( TRUE );
}

void printError( TCHAR* msg )
{
DWORD eNum;
TCHAR sysMsg[256];
TCHAR* p;

eNum = GetLastError( );
FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, eNum,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
sysMsg, 256, NULL );

// Trim the end of the line and terminate it with a null
p = sysMsg;
while( ( *p > 31 ) || ( *p == 9 ) )
++p;
do { *p-- = 0; } while( ( p >= sysMsg ) &&
( ( *p == '.' ) || ( *p < 33 ) ) );

// Display the message
printf( "\n WARNING: %s failed with error %d (%s)", msg, eNum, sysMsg );
}


Mike Yurgalavage(Posted 2004) [#4]
bump for new people to see and possibly respond/help-

best,
mike


Mike Yurgalavage(Posted 2004) [#5]
bump for new people to see and possibly respond/help-

best,
mike


Tracer(Posted 2004) [#6]
#PROCESS_ALL_ACCESS = #STANDARD_RIGHTS_REQUIRED | #SYNCHRONIZE | $FFF


; Get Process info
hWnd = FindWindow_(Null,"Secret Weapons Over Normandy")

GetWindowThreadProcessId_(hWnd, @pid.l)

app = OpenProcess_(#PROCESS_ALL_ACCESS,Null,pid)

; Buffer For storing stuff, in bytes
pip = AllocateMemory(1,3)

; To read from process
zap = ReadProcessMemory_(app,4987153,pip,3,Null)
tip = PeekL(pip)

; To write to process
zing = PokeL(pip,9474192)
zip = WriteProcessMemory_(app,4987153,pip,3,Null)


Basically a quick 'rip' out of my PureBasic trainer code.. make userlibs for the Win32 API commands used, and it should work much the same way in Blitz+.

If i have time later today, i'll see if can make a bit of B+ code for ya.

(As you can see James, it's pretty damned trivial of a job ;) )

Tracer


BlitzSupport(Posted 2004) [#7]
Well, here's some code to get the list of running process IDs, but there's a slight 'issue' in that I seem to be missing something with the process name (it says 'illegal type conversion'). I think the Process32First/Next functions are overwriting something and it's too late to fiddle too much with it! I briefly tried banks but they end up causing a 'not a valid bank handle' error).

You should find the process in this list IDs match those in Task Manager, at least!

; -----------------------------------------------------------------------------
; Create or open existing kernel32.decls file in userlibs folder and place
; these lines in it (uncommented!)...
; -----------------------------------------------------------------------------
;
; .lib "kernel32.dll"
;
; CreateToolhelp32Snapshot% (flags, th32processid)
; Process32First% (snapshot, entry*)
; Process32Next% (snapshot, entry*)
; CloseHandle% (object)
;
; -----------------------------------------------------------------------------

Const MAX_PATH = 264
Const TH32CS_SNAPHEAPLIST = $1
Const TH32CS_SNAPPROCESS = $2
Const TH32CS_SNAPTHREAD = $4
Const TH32CS_SNAPMODULE = $8
Const TH32CS_SNAPALL = TH32CS_SNAPHEAPLIST Or TH32CS_SNAPPROCESS Or TH32CS_SNAPTHREAD Or TH32CS_SNAPMODULE
Const TH32CS_INHERIT = $80000000
Const INVALID_HANDLE_VALUE = -1
Const SizeOf_PE32 = 296

Type PROCESSENTRY32
    Field dwSize
    Field cntUsage
    Field th32ProcessID
    Field th32DefaultHeapID
    Field th32ModuleID
    Field cntThreads
    Field th32ParentProcessID
    Field pcPriClassBase
    Field dwFlags
    Field szExeFile$ [MAX_PATH]
End Type

snap = CreateToolhelp32Snapshot (TH32CS_SNAPPROCESS, 0)

If snap

	Proc32.PROCESSENTRY32 = New PROCESSENTRY32
    Proc32\dwSize = SizeOf_PE32

    If Process32First (snap, Proc32)

	Print "Process ID: " + Proc32\th32ProcessID

   		While Process32Next (snap, Proc32)
			Print "Process ID: " + Proc32\th32ProcessID
			Print "----> Parent process ID: " + Proc32\th32ParentProcessID
			;Print Proc32\szExeFile ; Illegal type conversion?
	    Wend
            
    EndIf

    CloseHandle (snap)
    
EndIf

Print "Hit ENTER..."
Input ()
End



(As you can see James, it's pretty damned trivial of a job ;) )


Yeah, I really meant the time it takes to look up the functions from MSDN, etc, and create the .decls, etc, and I just didn't have the time!


BlitzSupport(Posted 2004) [#8]
OK, the illegal type error was just me being stupid and not using [x] at the end of the field name, but it still crashes anyway and I'm failing to see why (lame excuse: it's late)... c'mon, Tracer, go to it!


Mike Yurgalavage(Posted 2004) [#9]
you guys (james, tracer) are so very kind to take this on! i appreciate the help. i hope the discussion between the two of you continues until there is a working method of doing this. i'll help in any way i can but like i said, i am a newb with the api calls. i hope one or both of you will keep at it! thanks a million. i think once this works, we should add this to the code archive as a way to access the pointers to program processes.

best,
mike


Mike Yurgalavage(Posted 2004) [#10]
by the way, i noticed something. the list of names of the processes in taskmanager isn't always the same as the window name. sometimes, the window name may change during game play (!) and then a trainer based simply on the window name it is running in would not be helpful. however the name of the process in windows task manager stays constant. so the window name and the process name are two different things. i think the task manager approach would be necessary in those instances where the window name might possibly change during game play or be different each time you load the game. however, for 90% of games (a guess), the window for the .exe is probably static (i.e. the name of it doesn't change) so then tracer's simpler version would apply. i was curious how many api calls are in tracer's code (i am being to lazy to check each statement) and could you quickly generate a .decls file for it (userlib)? i can probably make the trainer using tracer's method for the specific game i have in mind, but being able to select the process using the task manager method would be nice to know since the name of the window could potentially be different when the trainer is engaged. i hope you guys will continue to work on this. thanks a bunch, i know it took a little time to do this for me- these are great forums.

best,
mike


Tracer(Posted 2004) [#11]
I tend to track the process by it's exe name, not the window name, i just used FindWindow to post it as a small bit of source, instead of an entire trainer, which is a lot more code :)

I should have some time to write a B+ version this weekend.

Tracer


Mike Yurgalavage(Posted 2004) [#12]
thanks tracer and james. tracer, i hope that you are able to create the code for this over the weekend. also, it would be nice to have the declarations for the example above (user libs) and the declarations for any code examples you did this weekend. i don't really need a full trainer code, just the code that enables me to get to a particular process (the game .exe) and then to get to it's addresses so that the addresses can be manipulated (peeked and poked). also, i don't have BlitzPlus, just blitz3d so not sure if that is a problem. another problem i might run into would be hotkey detection (even though you are playing the game, the blitz program that is the trainer and is running as a separate process would still respond to certain key presses while you are within the game). sorry for all the trouble but i am learning through this and likely will be better able to use the win32 api myself by learning through all of the examples of others. i'd appreciate further help! thanks-

best,
mike


Mike Yurgalavage(Posted 2004) [#13]
bump for more replies and ideas-
i hope tracer and james are looking at these posts regularly (thanks again guys).

best,
mike


Mike Yurgalavage(Posted 2004) [#14]
bump for more ideas and hope that tracer or james see this.

best,
mike


Wayne(Posted 2004) [#15]
Trainers are not the kind of software I'd like to see the blitz3d people authoring.

If it's for educational purposes I can understand, but all too often is misused.

Try to use good judgement, be professional, and think of others who have to code against this chit.

peace


Kanati(Posted 2004) [#16]
Mike.... The code Tracer posted is complete all by itself. You are going to need to do the legwork yourself to find out what offsets and such you are going to need to poke for whatever game you are trying to "train".

Wayne: As long as it's not hacking an online game (like battlefield 1942 where it's hard to find a game any more that doesn't have cheaters all over the place), then what someone does to their own installs is their business. :)

Kanati


Mike Yurgalavage(Posted 2004) [#17]
kanati,
the code that tracer placed has it's limitations, namely that it classifies the process based on the window name that the game is running in. however, sometimes that window name can change and then your trainer would not be able to access that program. it would be more accurate to select the game.exe by using it's running process name (like in the taskbar). however, james was not able to complete the work on that.

also, i don't have the declarations for tracer's code. i can at least start with that if someone can help me get the declarations right. tracer's code is incomplete and won't compile without the decls file.

i agree that online games are unfair when people are cheating. i am hoping to make trainer(s) for some of the role playing games so that i can select certain items, etc. and blitz would let me display them in 3d, or at least blit them as 2d pics instead of all text.

thanks for the input from each of you and i am still hoping for more input from tracer/james, also.

best,
mike


Mike Yurgalavage(Posted 2004) [#18]
With help from Soja I worked out the final code to get the list of running .exe's (like in a taskbar). I posted it in the code forum also (archives).

; -----------------------------------------------------------------------------
; Create or open existing kernel32.decls file in userlibs folder and place
; these lines in it (uncommented!)...
; -----------------------------------------------------------------------------
;
; .lib "kernel32.dll"
;
; CreateToolhelp32Snapshot% (flags, th32processid)
; Process32First% (snapshot, entry*)
; Process32Next% (snapshot, entry*)
; CloseHandle% (object)
;
; -----------------------------------------------------------------------------

Const MAX_PATH = 264
Const TH32CS_SNAPHEAPLIST = $1
Const TH32CS_SNAPPROCESS = $2
Const TH32CS_SNAPTHREAD = $4
Const TH32CS_SNAPMODULE = $8
Const TH32CS_SNAPALL = TH32CS_SNAPHEAPLIST Or TH32CS_SNAPPROCESS Or TH32CS_SNAPTHREAD Or TH32CS_SNAPMODULE
Const TH32CS_INHERIT = $80000000
Const INVALID_HANDLE_VALUE = -1
Const SizeOf_PE32 = 296

Type PROCESSENTRY32
Field dwSize
Field cntUsage
Field th32ProcessID
Field th32DefaultHeapID
Field th32ModuleID
Field cntThreads
Field th32ParentProcessID
Field pcPriClassBase
Field dwFlags
Field szExeFile$ [MAX_PATH]
End Type


snap = CreateToolhelp32Snapshot (TH32CS_SNAPPROCESS, 0)

If snap
;Print snap
Proc32=CreateBank(SizeOf_PE32)
PokeInt(Proc32, 0, BankSize(Proc32)) ; dwSize


If Process32First (snap, Proc32)
;cntUsage = PeekInt(Proc32, 4) ; Offset at 4th byte -- read 4 bytes (sizeof Int)
;th32ProcessID = PeekInt(Proc32, 8)
;th32DefaultHeapID = PeekInt(Proc32, 12)

Print "Process ID: " + th32ProcessID
Print

While Process32Next (snap, Proc32)
dwSize=PeekInt(Proc32,0)
cntUsage=PeekInt(Proc32,4)
th32ProcessID=PeekInt(Proc32,8)
th32DefaultHeapID=PeekInt(Proc32,12)
th32ModuleID=PeekInt(Proc32,16)
cntThreads=PeekInt(Proc32,20)
th32ParentProcessID=PeekInt(Proc32,24)
pcPriClassBase=PeekInt(Proc32,28)
dwFlags=PeekInt(Proc32,32)
offset = 36
Repeat
char = PeekByte(Proc32, offset)
offset = offset + 1
szExeFile$ = szExeFile$ + Chr$(char)
Until char = 0
szExeFile$=Left$(szExeFile$,Len(szExeFile$)-1)
Print szExeFile$
Print "Process ID: " + th32ProcessID
Print "----> Parent process ID: " + th32ParentProcessID
szExeFile$=""

Input()
Wend
Input()

EndIf

CloseHandle (snap)

EndIf

Print "Hit ENTER..."
Input ()
End