In regular QBasic, we had
PEEK and
POKE. In QB64, those functions are kept mostly for legacy and will overflow on modern variables. On the Wiki, there was code written in 2011 by Michael Calkins to give
PEEK and
POKE functionality back to QB64 without such issues (here:
https://www.qb64.org/wiki/PEEK_and_POKE_Library). It works
ok but not great. It crashes quite often when trying to
POKE the memory of a different process. So, in my endeavor to make trainers in QB64, I decided it was high-time someone made a good alternative to
PEEK and
POKE that allows you to change the memory of a
different process/application. So, we have
Peeping Tom. A library made using WinAPI's
OpenProcess,
ReadProcessMemory, and
WriteProcessMemory functions. With this you can
peekbyte,
peekint,
peeklong,
peekint64,
peekstring,
pokebyte,
pokeint,
pokelong,
pokeint64, and
pokestring for
ANY process that has read/writeable memory in the locations you are attempting to access.
A screenshot showing the library editing values in the exe compiled from the source:
And the source code (tested in 32 and 64 bit):
CONST PROCESS_VM_READ
= &H0010 CONST PROCESS_QUERY_INFORMATION
= &H0400 CONST PROCESS_VM_WRITE
= &H0020 CONST PROCESS_VM_OPERATION
= &H0008 CONST STANDARD_RIGHTS_REQUIRED
= &H000F0000 CONST SYNCHRONIZE
= &H00100000 CONST PROCESS_ALL_ACCESS
= STANDARD_RIGHTS_REQUIRED
OR SYNCHRONIZE
OR &HFFFF
CONST TH32CS_INHERIT
= &H80000000 CONST TH32CS_SNAPHEAPLIST
= &H00000001 CONST TH32CS_SNAPMODULE
= &H00000008 CONST TH32CS_SNAPMODULE32
= &H00000010 CONST TH32CS_SNAPPROCESS
= &H00000002 CONST TH32CS_SNAPTHREAD
= &H00000004 CONST TH32CS_SNAPALL
= TH32CS_SNAPHEAPLIST
OR TH32CS_SNAPMODULE
OR TH32CS_SNAPPROCESS
OR TH32CS_SNAPTHREAD
_TITLE "Peeping Tom: A Powerful PEEK/POKE"
test
= "This is a test" + CHR$(0)
testint = 320
testlong = &HFF
testint64 = 922337
a
= pokeint
(exe
, _OFFSET(testint
), 312)
a
= pokelong
(exe
, _OFFSET(testlong
), &HFE)
a
= pokeint64
(exe
, _OFFSET(testint64
), 922345)
a
= pokestring
(exe
, _OFFSET(test
), "This is NOT a test" + CHR$(0))
DIM pe32
AS PROCESSENTRY32
hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)
hProcess
= OpenProcess
(PROCESS_VM_READ
OR PROCESS_QUERY_INFORMATION
OR PROCESS_VM_WRITE
OR PROCESS_VM_OPERATION
, FALSE
, pe32.th32ProcessID
) memo
= ReadProcessMemory
(hProcess
, address
, _OFFSET(result
), 1, 0) closeh = CloseHandle(hProcessSnap)
closeh = CloseHandle(hProcess)
peekbyte = result
DIM pe32
AS PROCESSENTRY32
hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)
hProcess
= OpenProcess
(PROCESS_VM_READ
OR PROCESS_QUERY_INFORMATION
OR PROCESS_VM_WRITE
OR PROCESS_VM_OPERATION
, FALSE
, pe32.th32ProcessID
) memo
= ReadProcessMemory
(hProcess
, address
, _OFFSET(result
), 2, 0) closeh = CloseHandle(hProcessSnap)
closeh = CloseHandle(hProcess)
peekint = result
DIM pe32
AS PROCESSENTRY32
hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)
hProcess
= OpenProcess
(PROCESS_VM_READ
OR PROCESS_QUERY_INFORMATION
OR PROCESS_VM_WRITE
OR PROCESS_VM_OPERATION
, FALSE
, pe32.th32ProcessID
) memo
= ReadProcessMemory
(hProcess
, address
, _OFFSET(result
), 4, 0) closeh = CloseHandle(hProcessSnap)
closeh = CloseHandle(hProcess)
peeklong = result
DIM pe32
AS PROCESSENTRY32
hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)
hProcess
= OpenProcess
(PROCESS_VM_READ
OR PROCESS_QUERY_INFORMATION
OR PROCESS_VM_WRITE
OR PROCESS_VM_OPERATION
, FALSE
, pe32.th32ProcessID
) memo
= ReadProcessMemory
(hProcess
, address
, _OFFSET(result
), 8, 0) closeh = CloseHandle(hProcessSnap)
closeh = CloseHandle(hProcess)
peekint64 = result
DIM pe32
AS PROCESSENTRY32
hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)
hProcess
= OpenProcess
(PROCESS_VM_READ
OR PROCESS_QUERY_INFORMATION
OR PROCESS_VM_WRITE
OR PROCESS_VM_OPERATION
, FALSE
, pe32.th32ProcessID
) result
= SPACE$(PointerLen
(address
)) memo
= ReadProcessMemory
(hProcess
, address
, _OFFSET(result
), LEN(result
), 0) closeh = CloseHandle(hProcessSnap)
closeh = CloseHandle(hProcess)
peekstring = result
DIM pe32
AS PROCESSENTRY32
hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)
hProcess
= OpenProcess
(PROCESS_VM_READ
OR PROCESS_QUERY_INFORMATION
OR PROCESS_VM_WRITE
OR PROCESS_VM_OPERATION
, FALSE
, pe32.th32ProcessID
) memo
= WriteProcessMemory
(hProcess
, address
, _OFFSET(value
), 1, 0) closeh = CloseHandle(hProcessSnap)
closeh = CloseHandle(hProcess)
pokebyte = memo
DIM pe32
AS PROCESSENTRY32
hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)
hProcess
= OpenProcess
(PROCESS_VM_READ
OR PROCESS_QUERY_INFORMATION
OR PROCESS_VM_WRITE
OR PROCESS_VM_OPERATION
, FALSE
, pe32.th32ProcessID
) memo
= WriteProcessMemory
(hProcess
, address
, _OFFSET(value
), 2, 0) closeh = CloseHandle(hProcessSnap)
closeh = CloseHandle(hProcess)
pokeint = memo
DIM pe32
AS PROCESSENTRY32
hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)
hProcess
= OpenProcess
(PROCESS_VM_READ
OR PROCESS_QUERY_INFORMATION
OR PROCESS_VM_WRITE
OR PROCESS_VM_OPERATION
, FALSE
, pe32.th32ProcessID
) memo
= WriteProcessMemory
(hProcess
, address
, _OFFSET(value
), 4, 0) closeh = CloseHandle(hProcessSnap)
closeh = CloseHandle(hProcess)
pokelong = memo
DIM pe32
AS PROCESSENTRY32
hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)
hProcess
= OpenProcess
(PROCESS_VM_READ
OR PROCESS_QUERY_INFORMATION
OR PROCESS_VM_WRITE
OR PROCESS_VM_OPERATION
, FALSE
, pe32.th32ProcessID
) memo
= WriteProcessMemory
(hProcess
, address
, _OFFSET(value
), 8, 0) closeh = CloseHandle(hProcessSnap)
closeh = CloseHandle(hProcess)
pokeint64 = memo
DIM pe32
AS PROCESSENTRY32
hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)
hProcess
= OpenProcess
(PROCESS_VM_READ
OR PROCESS_QUERY_INFORMATION
OR PROCESS_VM_WRITE
OR PROCESS_VM_OPERATION
, FALSE
, pe32.th32ProcessID
) memo
= WriteProcessMemory
(hProcess
, address
, _OFFSET(value
), LEN(value
), 0) closeh = CloseHandle(hProcessSnap)
closeh = CloseHandle(hProcess)
pokestring = memo
PointerLen = strlen(value)
Feel free to change it up as you see fit. Note: You will have to know where the address of the data you want to change is located. I
do have a function that searches out strings and can be modified to search for numbers (and is not included here)
BUT you
DO NOT want to try it that way as you will
MOST CERTAINLY WRITE TO THE WRONG ADDRESS since there are multiple places where a value could be the same as the one you are searching for. After I make my tutorial on creating game trainers you will see that you should use Cheat Engine
https://www.cheatengine.org/ to locate the BASE addresses you are wanting to change. Base addresses remain constant between launches of a program with several offsets in place to arrive at the variable address that
does change between launches. Be
VERY CAREFUL modifying memory in programs. Don't go all will-nilly changing things for the heck of it. Take care in what you do.