win32api and readprocessmemory problem.. sojo, james, tracer? HELP!
Blitz3D Forums/Blitz3D Programming/win32api and readprocessmemory problem.. sojo, james, tracer? HELP!
| ||
i am currently writing a trainer (or trying to) that will access another program and write to it's memory addresses. at any rate, i have accomplished findind the thread process ID for a program, but i am having trouble reading the memory addresses of the program. for now, i am using the calculator program as a test just to see if i am reading the addresses correctly. i am lost. take a look at the code and see if you can tell what i am trying to accomplish and what i am doing wrong! any help would be appreciated. best, mike [CODE] ; ----------------------------------------------------------------------------- ; 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) ;OpenProcess% (dwDesiredAccess%, Null, dwProcessId%) : "OpenProcess" ;ReadProcessMemory% (hProcess%, lpBaseAddress*, lpBuffer*, nSize%, Null) ;WriteProcessMemory% (hProcess%, lpBaseAddress*, lpBuffer*, nSize%, lpNumberOfBytesWritten%) ; ; ----------------------------------------------------------------------------- ; ----------------------------------------------------------------------------- ; Create or open existing user32.decls file in userlibs folder and place ; these lines in it (uncommented!)... ; ----------------------------------------------------------------------------- ; ;.lib "user32.dll" ; ;FindWindow% (Null, Caption$) : "FindWindowA" ;SetWindowState(hwnd,command):"ShowWindow" ;ShowWindow% (hwnd%, nCmdShow%) : "ShowWindow" ;GetWindowThreadProcessId% (hwnd%, ProcessId%) : "GetWindowThreadProcessId" ; ; ----------------------------------------------------------------------------- ; ----------------------------------------------------------------------------- ;Make sure that the calculator program included with windows is running so that this will identify it ; ----------------------------------------------------------------------------- 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 Const STANDARD_RIGHTS_REQUIRED = $F0000 Const SYNCHRONIZE = $100000 Const PROCESS_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED Or SYNCHRONIZE Or $FFF) ;x = NULL in most instances 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=CreateBank(SizeOf_PE32) PokeInt(Proc32, 0, BankSize(Proc32)) ; dwSize If Process32First (snap, Proc32) ;<--- read first running process Print "Process ID: " + th32ProcessID While Process32Next (snap, Proc32) ;<--- read each running process 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$ ;<--- process name Print "Process ID: " + th32ProcessID If szExeFile$="calc.exe" Then program=th32ProcessID;<--- program = processID of calculator szExeFile$="" Wend EndIf CloseHandle (snap) EndIf Print "Calculator program is thread process " + program + "." ; <--- from here down is where i don't know what i am doing right app=openprocess(PROCESS_ALL_ACCESS,x,program) Print "Value for app is " + app + "." ;<--- just to see what it contains pip=CreateBank(3) ; <-- is bank the way to go here? how big? zap=readprocessmemory(app,$77d43999,pip,4,x) ;<--- Not sure what To put here at all... tip=PeekByte (pip,0) ;<--- just want to see what one address contains. Print "the address $77d43999 contains the number " + tip + "." ; always zero or not what really is at that address ;obviously i am doing something wrong because i can look at address $77d43999 with tsearch and it is not what tip says ;i am not even sure where the addresses for the calculator program begins?? i thought that ;app would point at that or something. anyways, HELP! Input () End ;code below is what we are trying to accomplish, but it is in purebasic format (!?$) ;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) [/CODE] you must have the calculator program (calc.exe) running in the background when you run this. i am not sure how to accesses the addresses that the calc program is residing in memory. that's what i am trying to accomplish. this code requires two .decls (one for user32.dll and one for kernel32.dll) the .decls are included at the top of the code after the ";"'s. just uncomment them and save them in the userlibs directory. I hope someone can help! |
| ||
Her eare some issues I've noticed after looking at it for a minute: 1) Your bank (pip) should be at least 4 bytes, though it wouldn't hurt to be more. 2) You can't rely on the calc process' base address the be the same all the time. You have to get that information somehow, and use that instead of 77d43999. (I'm not sure how ATM.) 3) If you want to pass in NULL, just declare the parameter as % and then pass in 0. (You were doing that, but a little bit strangely.) If you haven't made any headway, I'll take a look after I get a good night's sleep. PS: It's trivial, but you may be interested to know that you can put any number of declarations for any number of libraries in a single .decls file, as long as they're seperated by the appropriate .lib directive. |
| ||
This is the thing with games these days. Moving addresses... The CODE of the game is always in the same spot, but the addresses that the code use to store lifes, etc move around in memory.. What you need to do is find the CODE that decreases lifes or something in a game .. this code will point to a register + <a number> .. the address in the register + the number = the location in memore of the lifes. I tend to go a bit further with this when i make a trainer, i find the code (usually an asm SUB command) and remove it :) the lifes will no longer decrease. There's a tool out there, if it still is out there that can help with this. It's called TSearch.. it basically does the same thing as my own trainer creation tool but a little more 'difficult'. In Tsearch, select the game process (run game first of course), use it's normal value location system to find the value you want to find, say, lifes: Look in the game, say there's 3 lifes left. -Go to TSearch, search for 3, with 2 bytes (doesn't always work but it will not find millions of hits this way) -Go back to the game, loose a life -Go to TSearch, search for 2 -Repeat until you know which address hold the amount of lifes. Add the address to the list on the right. -Now, go to one of the menu's and "enable debugger" -Right click on the address in the list on the right and click on "Autohack" -Go to the game, loose a life. -Go to TSearch, and open the autohack window (same menu as enable debugger i think) -There should be a little machine code command in the list in that window .. click on the little box in front of the command to turn it on.. and voila..lifes will no longer decrease when you die. -Select the machine code command and click on "TMK", and then "Button Script", a small window will appear with a little text in it .. there's the address that you need to NOP (those are the list of 90's you see in the text, 90 = NOP).. WriteProcessMemory to this address (in decimal, not hex, like the text shows) with the 90's and your trainer will kill the CODE to decrease the lifes :) Guess i'll code something. Tracer |
| ||
Ok then, Download the below "trainme.exe" in zip form, run it, and rack up some number on there. Run the BB program below and then try decreasing using the dwn button. 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 Const STANDARD_RIGHTS_REQUIRED = $F0000 Const SYNCHRONIZE = $100000 Const PROCESS_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED Or SYNCHRONIZE Or $FFF) snap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0) If snap Proc32 = CreateBank(SizeOf_PE32) PokeInt(Proc32,0,BankSize(Proc32)) If Process32First(snap,Proc32) 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) If szExeFile$ = "trainme.exe" program = th32ProcessID EndIf szExeFile$="" Wend EndIf CloseHandle (snap) EndIf ; Open Process with full access app = OpenProcess(PROCESS_ALL_ACCESS,x,program) ; Create a little bank buffer = CreateBank(10) ; To READ from memory.. not used in this case, but the below works. ;result = ReadProcessMemory(app,4207112,buffer,2,x) ; Train Me has the command for decreasing the number in the window ; at address 401429 in hex, to make it easy, we'll use dec to ; do our process writing, which is 4199465. ; *NOTE* ; The Hex down below is what it showed when _I_ ran Train Me ; It doesn't mean that it will be that on your computer! ; Keep in mind, CODE is static in memory, DATA is _NOT_ ; The address contains the following: ; 89 1D 08 32 40 00 ; The address where the value is held is: 403208 ; 08 32 40, seem em above? reverse em.. 403208 HEY! whaddaya know :) ; So, ReadProcessMemory CAN be used to find the amount in memory ; even if it changes address! (mind you, in my little Train Me, it's very ; straightforward, it make be VERY different in games. ; So, what to do to stop it from decreasing (but, we want to make sure ; it CAN increase!) ; 4199465 is the address of the command that decreases the number.. so, ; all we have to do is NOP (No OPeration) it out. The command is six ; bytes in length, so we need to put six NOP's in it's place. PokeByte buffer,0,144 ; <- 144 dec = 90 hex = NOP PokeByte buffer,1,144 ; <- 144 dec = 90 hex = NOP PokeByte buffer,2,144 ; <- 144 dec = 90 hex = NOP PokeByte buffer,3,144 ; <- 144 dec = 90 hex = NOP PokeByte buffer,4,144 ; <- 144 dec = 90 hex = NOP PokeByte buffer,5,144 ; <- 144 dec = 90 hex = NOP ; We poked 6 bytes into the bank, each a 144, which is 90 (NOP) in hex. ; Now we write the six bytes to Train Me's memory and remove the ; decreasing command. result = WriteProcessMemory(app,4199465,buffer,6,x) ; Now try to use the "dwn" button! :) ; Note how the up button still works!, this is because we only removed ; the code that decreases the number! The little prog i made to demonstrate (PureBasic): http://www.bannerpacking.com/trainme.zip And it's source code: win = OpenWindow(1,10,10,132,50,#PB_Window_SystemMenu | #PB_Window_MinimizeGadget | #PB_Window_TitleBar | #PB_Window_ScreenCentered,"Train Me") If CreateGadgetList(WindowID(1)) ButtonGadget(1,10,10,24,24,"Up") TextGadget(2,60,15,40,24,"0") ButtonGadget(3,100,10,24,24,"Dn") EndIf num = 0 SetGadgetText(2,Str(num)) Repeat EventID.l = WaitWindowEvent() If EventID = #PB_EventGadget Select EventGadgetID() Case 1 num = num + 1 If num > 200 num = 200 EndIf SetGadgetText(2,Str(num)) Case 3 num = num - 1 If num < 0 num = 0 EndIf SetGadgetText(2,Str(num)) EndSelect EndIf If EventID = #PB_Event_CloseWindow ; If the user has pressed on the close button Quit = 1 EndIf Until Quit = 1 There ya go :) Tracer |
| ||
Oh.. i forgot :).lib "kernel32.dll" CreateToolhelp32Snapshot% (flags, th32processid) Process32First% (snapshot, entry*) Process32Next% (snapshot, entry*) CloseHandle% (object) OpenProcess% (dwDesiredAccess%, bInheritHandle%, dwProcessId%) : "OpenProcess" ReadProcessMemory% (hProcess%, lpBaseAddress%, lpBuffer*, nSize%, lpNumberOfBytesRead%) WriteProcessMemory% (hProcess%, lpBaseAddress%, lpBuffer*, nSize%, lpNumberOfBytesWritten%) Mike, the above is WHY your code didn't work! .. you had "lpBaseAddress" set as a pointer (with the *) .. it's NOT a pointer! Replace the ReadProcessMemory and WriteProcessMemory in your userlib with the ones above! Tracer |
| ||
the above is WHY your code didn't work! .. you had "lpBaseAddress" set as a pointer (with the *) .. In fairness, that may have been my .decls! [EDIT] Wait, no it wasn't... woo-hoo! |
| ||
man that was about the most conclusive explanation i have seen! i can't wait until lunch so i can try it out while i am not working. thanks to everyone (soja, tracer, and others) for helping me with this. i am still trying to work through the api calls. this has been a great learning experience and i appreciate the help. by the way i have been using tsearch and tmk (check my comment lines in the above code where i mention tsearch) for trainers i made in the past, but the tmk only let's you do certain things. i could make more graphical and customized trainers with blitz3d package. thanks again! best, mike |
| ||
just tried it out. works like a charm. thanks! i am going to test it on several programs that i made trainers with tmk for in the past. thanks again! best, mike |
| ||
Make sure you use the autohack feature in TSearch! Otherwise your trainer may not work for long :) Tracer |