This discussion is archived
1 Reply Latest reply: Sep 17, 2013 10:16 AM by 1d09cae7-2ad1-4e9f-b00f-60d6a8878a55 RSS

Java - Write And Read From memory Like CheatEngine ( Writing not working?)

AndreLopes Newbie
Currently Being Moderated

Hello Oracle Forum

I came here some time ago to ask about javaFX , i solved all my issues and im right now waiting for javaFx tot ake over swing and hmm, im working on learning LIBGDX to create games in java.

 

However, im in need to create an app to change values of memory to fix a bug in an old program that i have, and the only way until now is using cheatEngine, So i decided to take a tutorial and learn how to do that in java.

Well, im able to read from the memory but the write isnt working somehow... Im posting the code here, if anyone can give me a hint, i would thank and a lot, because theres a community that really needs this app to automate the fix without using cheat engine.

 

 

package MainStart;
import com.br.HM.User32;
import com.br.kernel.Kernel32;
import com.sun.jna.Memory;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.ptr.IntByReference;
public class Cheater {
    static Kernel32 kernel32 = (Kernel32) Native.loadLibrary("kernel32", Kernel32.class);
    static User32 user32 = (User32) Native.loadLibrary("user32", User32.class);
    static int readRight = 0x0010;
    static int writeRight = 0x0020;
    //static int PROCESS_VM_OPERATION = 0x0008;
    public static void main(String[] args) {
        //Read Memory
        //MineSweeper = Campo Minado
        int pid = getProcessId("Campo Minado"); // get our process ID
        System.out.println("Pid = " + pid);
        Pointer readprocess = openProcess(readRight, pid); // open the process ID with read priviledges.
        Pointer writeprocess = openProcess(writeRight, pid);
        int size = 4; // we want to read 4 bytes
        int address = 0x004053C8;
        //Read Memory
        Memory read = readMemory(readprocess, address, size); // read 4 bytes of memory starting at the address 0x00AB0C62.
        System.out.println(read.getInt(0)); // print out the value!       
        //Write Memory
        int writeMemory = writeMemory(writeprocess, address, new short[0x22222222]);
        System.out.println("WriteMemory :" + writeMemory);
        
        Memory readM = readMemory(readprocess, address, size);
        System.out.println(readM.getInt(0));
    }
    public static int writeMemory(Pointer process, int address, short[] data) {
        IntByReference written = new IntByReference(0);
        Memory toWrite = new Memory(data.length);
        for (long i = 0; i < data.length; i++) {
            toWrite.setShort(0, data[new Integer(Long.toString(i))]);
        }
        boolean b = kernel32.WriteProcessMemory(process, address, toWrite, data.length, written);
        System.out.println("kernel32.WriteProcessMemory : " + b); // Retorna false
        return written.getValue();
    }
    public static Pointer openProcess(int permissions, int pid) {
        Pointer process = kernel32.OpenProcess(permissions, true, pid);
        return process;
    }
    public static int getProcessId(String window) {
        IntByReference pid = new IntByReference(0);
        user32.GetWindowThreadProcessId(user32.FindWindowA(null, window), pid);
        return pid.getValue();
    }
    public static Memory readMemory(Pointer process, int address, int bytesToRead) {
        IntByReference read = new IntByReference(0);
        Memory output = new Memory(bytesToRead);
        kernel32.ReadProcessMemory(process, address, output, bytesToRead, read);
        return output;
    }
}

 

 

package com.br.HM;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.Structure;
import com.sun.jna.platform.win32.WinDef.RECT;
import com.sun.jna.ptr.ByteByReference;
import com.sun.jna.ptr.IntByReference;
import com.sun.jna.win32.StdCallLibrary.StdCallCallback;
import com.sun.jna.win32.W32APIOptions;
/**
 * Provides access to the w32 user32 library. Incomplete implementation to
 * support demos.
 *
 * @author Todd Fast, todd.fast@sun.com
 * @author twall@users.sf.net
 */
public interface User32 extends W32APIOptions {
    User32 INSTANCE = (User32) Native.loadLibrary("user32", User32.class, DEFAULT_OPTIONS);
    Pointer GetDC(Pointer hWnd);
    int ReleaseDC(Pointer hWnd, Pointer hDC);
    int FLASHW_STOP = 0;
    int FLASHW_CAPTION = 1;
    int FLASHW_TRAY = 2;
    int FLASHW_ALL = (FLASHW_CAPTION | FLASHW_TRAY);
    int FLASHW_TIMER = 4;
    int FLASHW_TIMERNOFG = 12;
    public static class FLASHWINFO extends Structure {
        public int cbSize;
        public Pointer hWnd;
        public int dwFlags;
        public int uCount;
        public int dwTimeout;
    }
    int IMAGE_BITMAP = 0;
    int IMAGE_ICON = 1;
    int IMAGE_CURSOR = 2;
    int IMAGE_ENHMETAFILE = 3;
    int LR_DEFAULTCOLOR = 0x0000;
    int LR_MONOCHROME = 0x0001;
    int LR_COLOR = 0x0002;
    int LR_COPYRETURNORG = 0x0004;
    int LR_COPYDELETEORG = 0x0008;
    int LR_LOADFROMFILE = 0x0010;
    int LR_LOADTRANSPARENT = 0x0020;
    int LR_DEFAULTSIZE = 0x0040;
    int LR_VGACOLOR = 0x0080;
    int LR_LOADMAP3DCOLORS = 0x1000;
    int LR_CREATEDIBSECTION = 0x2000;
    int LR_COPYFROMRESOURCE = 0x4000;
    int LR_SHARED = 0x8000;
    Pointer FindWindowA(String winClass, String title);
    int GetClassName(Pointer hWnd, byte[] lpClassName, int nMaxCount);
    public static class GUITHREADINFO extends Structure {
        public int cbSize = size();
        public int flags;
        Pointer hwndActive;
        Pointer hwndFocus;
        Pointer hwndCapture;
        Pointer hwndMenuOwner;
        Pointer hwndMoveSize;
        Pointer hwndCaret;
        RECT rcCaret;
    }
    boolean GetGUIThreadInfo(int idThread, GUITHREADINFO lpgui);
    public static class WINDOWINFO extends Structure {
        public int cbSize = size();
        public RECT rcWindow;
        public RECT rcClient;
        public int dwStyle;
        public int dwExStyle;
        public int dwWindowStatus;
        public int cxWindowBorders;
        public int cyWindowBorders;
        public short atomWindowType;
        public short wCreatorVersion;
    }
    boolean GetWindowInfo(Pointer hWnd, WINDOWINFO pwi);
    boolean GetWindowRect(Pointer hWnd, RECT rect);
    int GetWindowText(Pointer hWnd, byte[] lpString, int nMaxCount);
    int GetWindowTextLength(Pointer hWnd);
    int GetWindowModuleFileName(Pointer hWnd, byte[] lpszFileName, int cchFileNameMax);
    int GetWindowThreadProcessId(Pointer hWnd, IntByReference lpdwProcessId);
    interface WNDENUMPROC extends StdCallCallback {
        /**
         * Return whether to continue enumeration.
         */
        boolean callback(Pointer hWnd, Pointer data);
    }
    boolean EnumWindows(WNDENUMPROC lpEnumFunc, Pointer data);
    boolean EnumThreadWindows(int dwThreadId, WNDENUMPROC lpEnumFunc, Pointer data);
    boolean FlashWindowEx(FLASHWINFO info);
    Pointer LoadIcon(Pointer hInstance, String iconName);
    Pointer LoadImage(Pointer hinst, // handle to instance
            String name, // image to load
            int type, // image type
            int xDesired, // desired width
            int yDesired, // desired height
            int load // load options
            );
    boolean DestroyIcon(Pointer hicon);
    int GWL_EXSTYLE = -20;
    int GWL_STYLE = -16;
    int GWL_WNDPROC = -4;
    int GWL_HINSTANCE = -6;
    int GWL_ID = -12;
    int GWL_USERDATA = -21;
    int DWL_DLGPROC = 4;
    int DWL_MSGRESULT = 0;
    int DWL_USER = 8;
    int WS_EX_COMPOSITED = 0x20000000;
    int WS_EX_LAYERED = 0x80000;
    int WS_EX_TRANSPARENT = 32;
    int GetWindowLong(Pointer hWnd, int nIndex);
    int SetWindowLong(Pointer hWnd, int nIndex, int dwNewLong);
    int LWA_COLORKEY = 1;
    int LWA_ALPHA = 2;
    int ULW_COLORKEY = 1;
    int ULW_ALPHA = 2;
    int ULW_OPAQUE = 4;
    boolean SetLayeredWindowAttributes(Pointer hwnd, int crKey,
            byte bAlpha, int dwFlags);
    boolean GetLayeredWindowAttributes(Pointer hwnd,
            IntByReference pcrKey,
            ByteByReference pbAlpha,
            IntByReference pdwFlags);
    /**
     * Defines the x- and y-coordinates of a point.
     */
    public static class POINT extends Structure {
        public int x, y;
    }
    /**
     * Specifies the width and height of a rectangle.
     */
    public static class SIZE extends Structure {
        public int cx, cy;
    }
    int AC_SRC_OVER = 0x00;
    int AC_SRC_ALPHA = 0x01;
    int AC_SRC_NO_PREMULT_ALPHA = 0x01;
    int AC_SRC_NO_ALPHA = 0x02;
    public static class BLENDFUNCTION extends Structure {
        public byte BlendOp = AC_SRC_OVER; // only valid value
        public byte BlendFlags = 0; // only valid value
        public byte SourceConstantAlpha;
        public byte AlphaFormat;
    }
    boolean UpdateLayeredWindow(Pointer hwnd, Pointer hdcDst,
            POINT pptDst, SIZE psize,
            Pointer hdcSrc, POINT pptSrc, int crKey,
            BLENDFUNCTION pblend, int dwFlags);
    int SetWindowRgn(Pointer hWnd, Pointer hRgn, boolean bRedraw);
    int VK_SHIFT = 16;
    int VK_LSHIFT = 0xA0;
    int VK_RSHIFT = 0xA1;
    int VK_CONTROL = 17;
    int VK_LCONTROL = 0xA2;
    int VK_RCONTROL = 0xA3;
    int VK_MENU = 18;
    int VK_LMENU = 0xA4;
    int VK_RMENU = 0xA5;
    boolean GetKeyboardState(byte[] state);
    short GetAsyncKeyState(int vKey);
}

 

 

 

package com.br.kernel;
import com.sun.jna.*;
import com.sun.jna.win32.StdCallLibrary;
import com.sun.jna.ptr.IntByReference;
// by deject3d
public interface Kernel32 extends StdCallLibrary
{
    // description from msdn
    //BOOL WINAPI WriteProcessMemory(
    //__in   HANDLE hProcess,
    //__in   LPVOID lpBaseAddress,
    //__in   LPCVOID lpBuffer,
    //__in   SIZE_T nSize,
    //__out  SIZE_T *lpNumberOfBytesWritten
    //);
    boolean WriteProcessMemory(Pointer p, int address, Pointer buffer, int size, IntByReference written);
   
   
    //BOOL WINAPI ReadProcessMemory(
    //          __in   HANDLE hProcess,
    //          __in   LPCVOID lpBaseAddress,
    //          __out  LPVOID lpBuffer,
    //          __in   SIZE_T nSize,
    //          __out  SIZE_T *lpNumberOfBytesRead
    //        );
    boolean ReadProcessMemory(Pointer hProcess, int inBaseAddress, Pointer outputBuffer, int nSize, IntByReference outNumberOfBytesRead);
   
   
    //HANDLE WINAPI OpenProcess(
    //  __in  DWORD dwDesiredAccess,
    //  __in  BOOL bInheritHandle,
    //  __in  DWORD dwProcessId
    //);
    Pointer OpenProcess(int desired, boolean inherit, int pid);
   
    /* derp */
    int GetLastError();
}

 

 

 

http://pastebin.com/Vq8wfy39

  • 1. Re: Java - Write And Read From memory Like CheatEngine ( Writing not working?)
    1d09cae7-2ad1-4e9f-b00f-60d6a8878a55 Newbie
    Currently Being Moderated

    Hello there,

     

    this tutorial was exactly what I needed, so thank you.

     

    Your problem seems to be in this line:

     

     int writeMemory = writeMemory(writeprocess, address, new short[0x22222222]);  
    
    
    
    
    
    

     

    The problem is, you're creating a new short array with the length of 0x22222222. Which not only results in an java.lang.OutOfMemoryError: Java heap space

    but also, if it would work, would create an empty array with the length of 0x22222222.

     

    I think you want to write 0x22222222 as value in your address.

     

    Correctly stored the code you'd need to write would be:

    short[] sarray = new short[]{(short) 0x22222222};
    
    
    
    
    
    

    But because the value is too long for the short, the value stored in your array would be the number 8738.

     

    I think, what you want to do is to store the number 572662306, which would be the hex value, stored in an int variable.

     

     

    So first of all you need to strip down your hex-value to shorts:

     

    Short in Java uses 16 Bit = 2 Byte. 0x22222222 -> 0x2222 for your high byte and 0x2222 for your low byte

    So your array would be

    short[] sarray = new short[]{0x2222,0x2222};//notice, that sarray[0] is the lowbyte and sarray[1] the high byte, if you want to store 20 it would be new short[]{20,0} or if you use hex new short[]{0x14,0x00}
    
    
    
    
    
    

     

    The next part is your writeToMemory Method. If I'm right, the method in the tutorial is a little bit wrong. The right version should be this:

     

    public static int writeMemory(Pointer process, int address, short[] data) {
      IntByReference written = new IntByReference(0);
      int size = data.length*Short.SIZE/8;
      Memory toWrite = new Memory(size);
      for (int i = 0; i < data.length; i++) {
      toWrite.setShort(i*Short.SIZE/8,
      data[i]);
      }
      boolean b = kernel32.WriteProcessMemory(process, address, toWrite,
      size, written);
      return written.getValue();
      }
    
    
    
    

    You need to calculate your offset right. And the size of your memory. Maybe you could write this method not with shorts, but with integers. But this should work.

     

    If you pass your new array to this function, it should write 0x22222222 to your adress. If you read out your toWrite value with toWrite.getInt(0) you get the right value.

     

    And there is one more thing. In order to write data to a process, you need to grant two access rights:

    A handle to the process memory to be modified. The handle must have PROCESS_VM_WRITE and PROCESS_VM_OPERATION access to the process.

     

    You have to grant the right to write data: PROCESS_VM_WRITE: 0x0020 and PROCESS_VM_OPERATION: 0x0008

     

    So your writeProcess needs to get initialized this way:

     

    Pointer writeprocess = openProcess(0x0020|0x0008,pid);
    
    
    
    

     

    I hope this works for you. Let me know.

     

    Greetings

     

    Edit:

     

    Because every data you write will be 1 byte to whatever count of byte I think the best way is to use the following method to write data to the memory:

     

    public static void writeMemory(Pointer process, long address, byte[] data)
      {
      int size = data.length;
      Memory toWrite = new Memory(size);
      for(int i = 0; i < size; i++)
      {
      toWrite.setByte(i, data[i]);
      }
      boolean b = kernel32.WriteProcessMemory(process, address, toWrite, size, null);
      }
    
    

     

    You can see some changes. First I changed all address values from int to long, because some addresses are out of range. And with all, i mean all. Not only in writeMemory, but also in readMemory and in your kernel32 Class.

    Second I don't use the IntByReference anymore..

     

    To use this method you need to store your data the following way if you would write 4 Byte data:

     

    byte[] values = new byte[]{0x14,0x00,0x00,0x00};
    
    

     

    This value would be the number 20. Index 0 will be the lowest byte and index 3 will be the highest byte.

     

    And one more thing I wrote is an method which you can use to calculate your address if you have a baseAddress.

     

    If you restart your program/game your old addresses won't point at the same values of your game. With some research (I use CheatEngine) you can get the baseaddress. This one will alway be the same.

     

    To get from your baseaddress to the dynamic adress you use offsets.

     

    public static long findDynAddy(Pointer process, int[] offsets, long baseAddress)
      {
      long pointer = baseAddress;
      int size = 4;
      Memory pTemp = new Memory(size);
      long pointerAddress = 0;
      for(int i = 0; i < offsets.length; i++)
      {
      if(i == 0)
      {
      kernel32.ReadProcessMemory(process, pointer, pTemp, size, null);
      }
      pointerAddress = ((pTemp.getInt(0)+offsets[i]));
      if(i != offsets.length-1)
      kernel32.ReadProcessMemory(process, pointerAddress, pTemp, size, null);
      }
      return pointerAddress;
      }
    
    

     

    This methods gets a process, an array of offsets (hex-values) and your baseadress and returns the dynamic address.

     

    For Solitaire the following code would give you the address to the score:

     

    long baseAddr = 0x10002AFA8L;
      int[] offsets = new int[]{0x50,0x14};
      long addr = findDynAddy(process, offsets, baseAddr);
    
    

     

    If somebody wants to get the whole code (user32, kernel32 and the cheater) just pm me and I will give you a link.

Legend

  • Correct Answers - 10 points
  • Helpful Answers - 5 points