program pokerubyhack;
{$APPTYPE CONSOLE}
uses
sysutils,
windows,
messages;
type pcardinal = ^cardinal;
function EnumCb(hnd: hwnd; lParam: cardinal):BOOLEAN;
stdcall;
const bufsize = 256;
var strResult:
string;
begin
setlength(strResult,bufsize);
zeromemory(@strResult[1],bufsize);
//lastHnd := cardinal(hnd);
GetWindowText(hnd,@strResult[1],bufSize);
//if strResult[1] <> #0 then asm int 3 end;
if copy(strResult,1,16) = '
VisualBoyAdvance'
then begin
pcardinal(lParam)^ := hnd;
result := false
end
else result := true;
end;
function findwnd:hwnd;
var lparam: cardinal;
begin
result := 0;
lParam := cardinal( @result );
EnumWindows(@EnumCb,lparam);
end;
procedure haltp(c:integer;s:
string);
begin
writeln(s+#13#10'
press any key to continue');readln;
halt(c);
end;
type
ppokestat = ^pokestat;
pokestat =
packed record
CHP:word;
AHP:word;
ATT:word;
DEF:word;
INI:word;
SPA:word;
SPD:word;
end;
const START_OFFSET = $1560000;
DIST2REC = 6;
pokedef :
array[1..7]
of string[3] =('
CHP','
AHP','
ATT','
DEF','
INI','
SPA','
SPD');
var hnd: hwnd;
pid : dword;
dwread: dword;
hp : thandle;
s:
string;
p, buf, pend,pokedata: pointer;
pokeptr: pointer;
j: integer;
c,d: char;
newstat: pokestat;
pm: pword;
nv: word;
procedure hackStats(pokeNum:byte);
var dwWritten : dword;
begin
writeln(#13#10'
trying to patch pokemon #'+ inttostr(pokenum));
writeprocessmemory(hp,pointer(cardinal(pokedata)+DIST2REC+((pokenum -1) * $64 )),@newstat,sizeof(pokestat),dwWritten);
if dwWritten > 0
then
writeln(format(#13#10'
successful: %d bytes written',[dwWritten]))
else
writeln(#13#10'
an error occured');
end;
begin
writeln('
retnygs pokemon trainer for visual boy advance v 1.0');
writeln('
====================================================');
writeln('
tested with 2006 pokemon ruby 1.2 and VBA Link 1.7.3L'#13#10'
supported cmd line parameters: number of pokemon to patch [1-6]'#13#10'
patch is temporary and will be removed on next level up.'#13#10#13#10);
hnd := findwnd;
if (Hnd <> 0)
then begin
GetWindowThreadProcessId(hnd,@pid);
//Get ProcessID and ignore ThreadID
hp:=openprocess(ProCEsS_aLL_ACCESS,false,pid);
if (hp = 0)
or (pid = 0)
then haltp(1,'
could not find hacker process');
setlength(s,$640000);
buf:=@s[1];
cardinal(p):=START_OFFSET;
// weise startadresse des zu suchenden speicherbereiches zu
readprocessmemory(hP,p,buf,length(s),dwRead);
pokedata :=
nil;
if dwread > 0
then begin
//writeln('could read something'#13#10);
setlength(s,dwread);
cardinal(pend) := cardinal(buf) +dwread;
while cardinal(buf) < cardinal(pend)-$64-(DIST2REC-1)
do begin
inc(pbyte(buf));
// durchsuche speicher nach gewisser bytefolge die typisch ist
if (pcardinal(buf)^ = $0)
and (pbyte(cardinal(buf)+(DIST2REC-1))^ = $FF)
and (pcardinal(cardinal(buf)+$64)^ = $0)
and (pbyte(cardinal(buf)+$64+(DIST2REC-1))^ = $FF)
then
begin
cardinal(pokeptr):= cardinal(buf);
cardinal(pokedata) := START_OFFSET + cardinal(buf) - cardinal(@s[1]);
writeln('
pokemon list found at adress: ' + inttohex(cardinal(pokedata),8));
writeln;
break;
end;
end;
if pokedata <>
nil then begin
writeln('
pokemon #: CHP AHP ATT DEF INI SPA SPD');
writeln('
______________________________________');
for j := 1
to 6
do begin
writeln('
pokemon '+inttostr(j)+'
:'+
format('
%.3d %.3d %.3d %.3d %.3d %.3d %.3d',
[ppokestat(cardinal(pokeptr)+DIST2REC+((j-1)*$64))^.CHP,
ppokestat(cardinal(pokeptr)+DIST2REC+((j-1)*$64))^.AHP,
ppokestat(cardinal(pokeptr)+DIST2REC+((j-1)*$64))^.ATT,
ppokestat(cardinal(pokeptr)+DIST2REC+((j-1)*$64))^.DEF,
ppokestat(cardinal(pokeptr)+DIST2REC+((j-1)*$64))^.INI,
ppokestat(cardinal(pokeptr)+DIST2REC+((j-1)*$64))^.SPA,
ppokestat(cardinal(pokeptr)+DIST2REC+((j-1)*$64))^.SPD
]) );
end;
with ppokestat(@newstat)^
do begin
CHP:=999;
AHP:=999;
ATT:=999;
DEF:=999;
INI:=999;
SPA:=999;
SPD:=999;
end;
if paramcount > 0
then c := paramstr(1)[1]
else begin
writeln(#13#10'
please enter a pokemon number [1-6] that you want to boost or [0] to abort, [A] for all');
readln(c);
end;
case c
of
'
1'..'
6' :
if paramcount > 0
then hackstats(byte(c)-48)
else begin
writeln ('
Automatic hack will set all values to 999'#13#10'
manual hack will allow you to enter the values yourself'#13#10'
type A for automatic or M for manual');
read(d);
if d
in ['
a','
A']
then hackstats(byte(c)-48)
else if d
in ['
m','
M']
then begin
newstat := ppokestat(cardinal(pokeptr)+DIST2REC+(((byte(c)-48)-1)*$64))^;
pm:=@newstat.chp;
for j := 1
to 7
do begin
write('
enter new value for ' + pokedef[j] + '
, current: ' + inttostr(pm^) + '
:');
readln(nv);
pm^ := nv;
inc(pm);
end;
hackstats(byte(c)-48)
end else writeln('
wrong input');
end;
'
0' : writeln('
aborted');
'
A','
a' :
for j := 1
to 6
do hackstats(j);
else haltp(1,'
error - undefined input');
end;
end;
end else writeln('
couldnt read from target process');
closehandle(hp);
haltp(0,#13#10);
end else haltp(1,'
could not find VBA window');
end.