728x90

자바에서 특정 윈도우 응용프로그램의 메모리 값을 읽어오는 방법이 궁금해서 구글링을 해보니 해당 예제가 나와서 메모 해둠.

언젠가는 쓸일이 있을 것 같으므로 ...

 

https://stackoverflow.com/questions/18849609/how-to-manipulate-memory-from-java-with-jna-on-windows

 

How to manipulate memory from Java with JNA on Windows

How do I manipulate memory from Java? I know that Java runs in it's own JVM, so it can't access process memory directly. I heard about JNA which can be used to get interfaces between the Operating

stackoverflow.com

 

아래내용은 해당 링크의 번역 입니다.

 

JNA 라이브러리를 사용해야 합니다. 두 개의 Jar 파일(jna.jar 및 jna-platform.jar)을 다운로드합니다 .

이 라이브러리를 사용하는 방법을 설명하는 pastebin에 대한 자습서를 찾았습니다 . 그러나 다음을 이해하기 위해 읽을 필요는 없습니다.

Windows 게임 "Solitaire"의 주소와 해당 값을 조작하려고 한다고 가정해 보겠습니다.


알고, 당신이 무엇을

  1. 주소와 해당 값을 조작하려는 경우 수행할 작업을 알고 있어야 합니다!
    주소에 저장된 값의 크기를 알아야 합니다. 4Byte인지, 8Byte인지 등등.
  2. 도구를 사용하여 동적 및 기본 주소를 얻는 방법을 알아두십시오. 나는 CheatEngine을 사용합니다 .
  3. 기본 주소와 동적 주소의 차이점을 알아두세요.
    • 동적 주소는 애플리케이션(솔리테어)을 다시 시작할 때마다 변경됩니다.
      여기에는 필요한 값이 포함되지만 매번 주소를 다시 찾아야 합니다. 따라서 먼저 배워야 할 것은 기본 주소를 얻는 방법입니다.
      CheatEngine Tutorial을 통해 플레이하면서 이를 배우십시오.
    • 기본 주소는 정적 주소입니다. 이러한 주소는 주로 다음과 같은 방식으로 다른 주소를 가리킵니다. [[base-adres + offset] + offset] -> value. 따라서 필요한 것은 기본 주소와 동적 주소를 얻기 위해 주소에 추가해야 하는 오프셋을 아는 것입니다.

이제 알아야 할 사항을 알았으므로 Solitaire에서 CheatEngine으로 몇 가지 조사를 수행합니다.


동적 주소를 찾았고 기본 주소를 검색했습니까? 좋습니다. 결과를 공유해 보겠습니다.

점수에 대한 기본 주소: 0x10002AFA8
동적 주소에 도달하기 위한 오프셋: 0x50(첫 번째) 및 0x14(두 번째)

모든 것이 맞습니까? 좋은! 계속해서 실제로 코드를 작성해 보겠습니다.


새 프로젝트 만들기

새 프로젝트에서 해당 라이브러리를 가져와야 합니다. Eclipse를 사용하지만 다른 IDE에서도 작동해야 합니다.

User32 인터페이스

User32 인터페이스를 설정해 준 Todd Fast에게 감사드립니다 . 완전하지는 않지만 여기에 필요한 것은 충분합니다.

이 인터페이스를 사용하여 Windows에서 user32.dll의 일부 기능에 액세스할 수 있습니다. 다음 기능이 필요합니다 FindWindowA.GetWindowThreadProcessID

참고: Eclipse에서 구현되지 않은 메서드를 추가해야 한다고 표시되면 무시하고 코드를 실행하십시오.

Kernel32 인터페이스

Kernel32 인터페이스 에 대해 Deject3d에게 감사드립니다 . 조금 수정했습니다.

이 인터페이스에는 메모리를 읽고 쓰는 데 사용하는 메서드가 포함되어 있습니다. WriteProcessMemory그리고 ReadProcessMemory. 프로세스를 여는 방법도 포함되어 있습니다.OpenProcess

실제 조작

이제 몇 가지 도우미 메서드와 JVM의 액세스 지점으로 기본 기능을 포함할 새 클래스를 만듭니다.

public class SolitaireHack {

    public static void main(String... args)
    {

    }
}

오프셋 및 기본 주소와 같이 이미 알고 있는 항목을 입력해 보겠습니다.

public class SolitaireHack {

    final static long baseAddress = 0x10002AFA8L;
    final static int[] offsets = new int[]{0x50,0x14};

    public static void main(String... args)
    {

    }
}

다음으로 인터페이스를 사용하여 Windows 특정 메서드에 액세스합니다.

import com.sun.jna.Native;

public class SolitaireHack {

    final static long baseAddress = 0x10002AFA8L;
    final static int[] offsets = new int[]{0x50,0x14};

    static Kernel32 kernel32 = (Kernel32) Native.loadLibrary("kernel32",Kernel32.class);
    static User32 user32 = (User32) Native.loadLibrary("user32", User32.class);

    public static void main(String... args)
    {

    }
}

마지막으로 프로세스에 대한 읽기 및 쓰기 권한을 얻기 위해 필요한 몇 가지 권한 상수를 만듭니다.

import com.sun.jna.Native;

public class SolitaireHack {

    final static long baseAddress = 0x10002AFA8L;
    final static int[] offsets = new int[]{0x50,0x14};

    static Kernel32 kernel32 = (Kernel32) Native.loadLibrary("kernel32",Kernel32.class);
    static User32 user32 = (User32) Native.loadLibrary("user32", User32.class);

    public static int PROCESS_VM_READ= 0x0010;
    public static int PROCESS_VM_WRITE = 0x0020;
    public static int PROCESS_VM_OPERATION = 0x0008;

    public static void main(String... args)
    {

    }
}

메모리를 조작할 수 있는 프로세스를 얻으려면 창을 가져와야 합니다. 이 창을 사용하여 프로세스 ID를 얻을 수 있습니다 . 이 ID로 프로세스를 열 수 있습니다.

public static void main(String... args)
{
    int pid = getProcessId("Solitaire");
    Pointer process = openProcess(PROCESS_VM_READ|PROCESS_VM_WRITE|PROCESS_VM_OPERATION, pid);
}

public static int getProcessId(String window) {
     IntByReference pid = new IntByReference(0);
     user32.GetWindowThreadProcessId(user32.FindWindowA(null, window), pid);

     return pid.getValue();
}

public static Pointer openProcess(int permissions, int pid) {
     Pointer process = kernel32.OpenProcess(permissions, true, pid);
     return process;
}

메서드 에서 getProcessId우리는 창의 제목인 매개변수를 사용하여 창 핸들을 찾습니다. ( FindWindowA) 이 창 핸들은 프로세스 ID를 가져오는 데 사용됩니다. IntByReference는 프로세스 ID가 저장되는 포인터의 JNA 버전입니다.

프로세스 ID를 얻으면 이를 사용하여 openProcess. 이 메서드는 프로세스를 열기 위한 권한과 pid를 가져오고 프로세스에 대한 포인터를 반환합니다. 프로세스에서 읽으려면 PROCESS_VM_READ 권한이 필요하고 프로세스에서 쓰려면 PROCESS_VM_WRITE 및 PROCESS_VM_OPERATION 권한이 필요합니다.

다음으로 가져와야 할 것은 실제 주소입니다. 동적 주소입니다. 따라서 다른 방법이 필요합니다.

public static void main(String... args)
{
    int pid = getProcessId("Solitaire");
    Pointer process = openProcess(PROCESS_VM_READ|PROCESS_VM_WRITE|PROCESS_VM_OPERATION, pid);

    long dynAddress = findDynAddress(process,offsets,baseAddress);
}

public static long findDynAddress(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;
}

이 방법에는 프로세스, 오프셋 및 기본 주소가 필요합니다. 객체 에 일부 임시 데이터를 저장합니다 Memory. 이것이 정확히 말하는 것입니다. 기억. 기본 주소에서 읽고 메모리에 새 주소를 가져와 오프셋을 추가합니다. 이것은 모든 오프셋에 대해 수행되며 결국 동적 주소가 될 마지막 주소를 반환합니다.

이제 점수를 읽고 출력하려고 합니다. 우리는 점수가 저장된 동적 주소를 가지고 있고 그것을 읽어야 합니다. 점수는 4Byte 값입니다. 정수는 4바이트 데이터 유형입니다. 따라서 Integer를 사용하여 읽을 수 있습니다.

public static void main(String... args)
{
    int pid = getProcessId("Solitaire");
    Pointer process = openProcess(PROCESS_VM_READ|PROCESS_VM_WRITE|PROCESS_VM_OPERATION, pid);

    long dynAddress = findDynAddress(process,offsets,baseAddress);

    Memory scoreMem = readMemory(process,dynAddress,4);
    int score = scoreMem.getInt(0);
    System.out.println(score);
}

public static Memory readMemory(Pointer process, long address, int bytesToRead) {
    IntByReference read = new IntByReference(0);
    Memory output = new Memory(bytesToRead);

    kernel32.ReadProcessMemory(process, address, output, bytesToRead, read);
    return output;
}

우리는 kernel32 메서드에 대한 래퍼를 작성했습니다 readProcessMemory. 우리는 4Byte를 읽어야 한다는 것을 알고 있으므로 bytesToRead는 4가 됩니다. 메서드에서 개체 Memory가 생성되고 반환되며 크기는 byteToRead이고 주소에 포함된 데이터를 저장합니다. 메서드 를 사용하면 .getInt(0)오프셋 0에서 메모리의 정수 값을 읽을 수 있습니다.

솔리테어로 약간 플레이하고 점수를 얻으십시오. 그런 다음 코드를 실행하고 값을 읽습니다. 그것이 당신의 점수인지 확인하십시오.

마지막 단계는 점수를 조작하는 것입니다. 우리는 최고가 되고 싶습니다. 따라서 메모리에 4Byte 데이터를 써야 합니다.

byte[] newScore = new byte[]{0x22,0x22,0x22,0x22};

이것은 우리의 새로운 점수가 될 것입니다. newScore[0]가장 낮은 바이트가 되고 newScore[3]가장 높은 바이트가 됩니다. 따라서 점수를 값 20으로 변경하려면 다음과 byte[]같이 하십시오.
byte[] newScore = new byte[]{0x14,0x00,0x00,0x00};

메모리에 적어 봅시다.

public static void main(String... args)
{
    int pid = getProcessId("Solitaire");
    Pointer process = openProcess(PROCESS_VM_READ|PROCESS_VM_WRITE|PROCESS_VM_OPERATION, pid);

    long dynAddress = findDynAddress(process,offsets,baseAddress);

    Memory scoreMem = readMemory(process,dynAddress,4);
    int score = scoreMem.getInt(0);
    System.out.println(score);

    byte[] newScore = new byte[]{0x22,0x22,0x22,0x22};
    writeMemory(process, dynAddress, newScore);
}

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);
}

우리의 방법을 사용하면 호출된 데이터를 주소에 writeMemory씁니다 . byte[]새 객체를 생성 Memory하고 크기를 배열의 길이로 설정합니다. 올바른 오프셋으로 개체 에 데이터를 쓰고 Memory주소에 개체를 씁니다.

이제 572662306의 환상적인 점수를 얻었을 것입니다.

정확히 모르는 경우 일부 kernel32 또는 user32 메서드가 수행하는 작업은 MSDN을 참조하거나 자유롭게 문의하십시오.

알려진 문제:

Solitaire의 프로세스 ID를 얻지 못한 경우 작업 관리자에서 확인하고 수동으로 pid를 작성하십시오. 독일 Solitär는 작동하지 않습니다. 이름의 ä 때문인 것 같습니다.

이 튜토리얼이 마음에 드셨기를 바랍니다. 대부분의 부분은 다른 튜토리얼에서 가져온 것이지만 여기에 모두 정리되어 있으므로 누군가 시작점이 필요한 경우 도움이 될 것입니다.

Deject3d와 Todd Fast의 도움에 다시 한 번 감사드립니다. 문제가 있는 경우 저에게 말씀해 주시면 도와드리겠습니다. 빠진 것이 있으면 언제든지 알려 주시거나 직접 추가해 주세요.

감사합니다. 좋은 하루 되세요.


SolitaireHack 클래스의 전체 코드를 살펴보겠습니다.

import com.sun.jna.Memory;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.ptr.IntByReference;

public class SolitaireHack {

    final static long baseAddress = 0x10002AFA8L;
    final static int[] offsets = new int[]{0x50,0x14};

    static Kernel32 kernel32 = (Kernel32) Native.loadLibrary("kernel32",Kernel32.class);
    static User32 user32 = (User32) Native.loadLibrary("user32", User32.class);

    public static int PROCESS_VM_READ= 0x0010;
    public static int PROCESS_VM_WRITE = 0x0020;
    public static int PROCESS_VM_OPERATION = 0x0008;

    public static void main(String... args)
    {
        int pid = getProcessId("Solitaire");
        Pointer process = openProcess(PROCESS_VM_READ|PROCESS_VM_WRITE|PROCESS_VM_OPERATION, pid);

        long dynAddress = findDynAddress(process,offsets,baseAddress);

        Memory scoreMem = readMemory(process,dynAddress,4);
        int score = scoreMem.getInt(0);
        System.out.println(score);

        byte[] newScore = new byte[]{0x22,0x22,0x22,0x22};
        writeMemory(process, dynAddress, newScore);
    }

    public static int getProcessId(String window) {
         IntByReference pid = new IntByReference(0);
         user32.GetWindowThreadProcessId(user32.FindWindowA(null, window), pid);

         return pid.getValue();
    }

    public static Pointer openProcess(int permissions, int pid) {
         Pointer process = kernel32.OpenProcess(permissions, true, pid);
         return process;
    }

    public static long findDynAddress(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;
    }

    public static Memory readMemory(Pointer process, long address, int bytesToRead) {
        IntByReference read = new IntByReference(0);
        Memory output = new Memory(bytesToRead);

        kernel32.ReadProcessMemory(process, address, output, bytesToRead, read);
        return output;
    }

    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);
    }
}

 

해당게시글의 링크의 내용

이 라이브러리를 사용하는 방법을 설명하는 pastebin에 대한 자습서를

 

this topic assumes that:1) you are semi proficient at game hacking/memory edit - Pastebin.com

Pastebin.com is the number one paste tool since 2002. Pastebin is a website where you can store text online for a set period of time.

pastebin.com

this topic assumes that:
1) you are semi proficient at game hacking/memory editing/programming
2) you've already downloaded the JNA.jar and related files and know how to set it up.

I haven't found a solid example/explanation of how to do this, so i'll try my best;

warning: this is not purely java by any means. as far as I know, java can't interact with anything in the OS as it runs in a virtual machine. i have no idea how the hell this JNA thing works, but oh well.

In this example, you will be learning how to cheat at the game "3d pinball" that comes with windows by using  JNA.jar to interface with the native windows functions for editing memory.

Now, I'm pretty clueless as to how the JNA actually works, and I pieced this together myself from pretty much nothing. It's still mostly magic to me, but I'll give you everything you need to get at least an example working.

First of all, you need an interface for each native windows function you want to use. Here's my code for Kernel32.dll. It is far from complete, but plenty for this example. Kernel32 contains the necessary crap for memory editing. I hope you knew that.

[code]
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();
}
[/code]


User32 also contains a few very important functions - GetWindowThreadProcessID and FindWindowA. Here's some code I luckily lifted off of google. I think it's the entire User32 class rewritten as java. Thanks, Mr. Todd Fast. now, this is way more than we need, but it could be nice to have someday.

[code]
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.Structure;
import com.sun.jna.examples.win32.W32API;
import com.sun.jna.examples.win32.GDI32.RECT;
import com.sun.jna.ptr.ByteByReference;
import com.sun.jna.ptr.IntByReference;

/** 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 W32API {

    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);
}
[/code]

Good. copy and paste both of those into your java project.

Now, make the class that will be containing the actual code for cheating. I named my class Cheater.

[code]
public class Cheater
{
    public static void main(String[] args)
    {

    }
}
[/code]

Amazing. now what?

First, imports. lots of them.

[code]
import java.util.Arrays;
import com.sun.jna.Memory;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.ptr.IntByReference;
import com.sun.jna.*;

public class Cheater
{
    public static void main(String[] args)
    {

    }
}
[/code]

Okay, cool. we've got imports. Can we start memory editing yet? no. not even close. you now need to load the native libraries using the JNA.

here's how.

[code]
import java.util.Arrays;
import com.sun.jna.Memory;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.ptr.IntByReference;
import com.sun.jna.*;

public class Cheater
{
    static Kernel32 kernel32 = (Kernel32) Native.loadLibrary("kernel32", Kernel32.class);
    static User32     user32 = (User32)   Native.loadLibrary("user32"  , User32.class);
    
    public static void main(String[] args)
    {

        }
}
[/code]

cool spacing, eh? yeah, whatever. you should be focusing.

So, now that we have the interface's to the native functions all set up, we can start hackin', right?! still not close.

Pretend you're memory editing in C++ or visual basic or whatever else - what do you need to do first before you can read/write memory to a process? you need the process ID. so how the hell do we get the process ID? just like in C++ - we use GetWindowThreadProcessId() !

so, GetWindowThreadProcessID() is located in user32.dll - so let's peek at our interface.

[code]
...
     int GetWindowThreadProcessId(Pointer hWnd, IntByReference lpdwProcessId);
...
[/code]

great, the function is in our interface. that means we can use it. but... how do we do that? what the hell is a Pointer in java terms? how do we get the hWnd?! IntByReference?! wtf?!

yeah, this is why this is hard to do. we're basically translating C++ into java.

anyways, the first parameter for GetWindowThreadProcessId() is a hWnd. how do we get that in C++? with FindWindowA() of course!

let's see now... yep, FindWindowA() is definitely in our user32 interface-

[code]
     Pointer FindWindowA(String winClass, String title);
[/code]

luckily, it takes Strings (phew). us java users know how those work (i hope).

so let's piece together some code, shall we?

why not make a getProcessId() method in our cheater class just to make things easier to read and use.

[code]
    public static int getProcessId(String window)
    {
        IntByReference pid = new IntByReference(0);
        user32.GetWindowThreadProcessId(user32.FindWindowA(null,window), pid);
        
        return pid.getValue();
    }
[/code]

perfect. this will return the integer process ID of the window we ask for - but as you can probably tell, I skipped ahead of myself a bit.

the first thing you notice is 

[code]
IntByReference pid = new IntByReference(0);
[/code]

an IntByReference comes from our import "import com.sun.jna.ptr.IntByReference;" It is just used as a pointer, basically. the variable "pid" is where GetWindowThreadProcessId will put the processes PID. we can't use just regular java ints because of what the MSDN documentation says:


[code]

DWORD WINAPI GetWindowThreadProcessId(
  __in       HWND hWnd,
  __out_opt  LPDWORD lpdwProcessId
);
[/code]
[url]http://msdn.microsoft.com/en-us/library/ms633522(VS.85).aspx[/url]
"LPDWORD
- A pointer to a variable that receives the process identifier."

since it has to be a pointer, we're forced to use IntByReference. You should be able to figure out how they work just by looking at the code above.

"pid.getValue()" just turns the pointer back into a regular java int. easy enough.

-------------------------

Alright, great. We can now get the process ID of a given process. here's how it should look:

[code]
import java.util.Arrays;
import com.sun.jna.Memory;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.ptr.IntByReference;
import com.sun.jna.*;

public class Cheater
{
    static Kernel32 kernel32 = (Kernel32) Native.loadLibrary("kernel32", Kernel32.class);
    static User32     user32 = (User32)   Native.loadLibrary("user32"  , User32.class);
    
    public static void main(String[] args)
    {
        int pid = getProcessId("3D Pinball for Windows - Space Cadet");
    }
    
    public static int getProcessId(String window)
    {
        IntByReference pid = new IntByReference(0);
        user32.GetWindowThreadProcessId(user32.FindWindowA(null,window), pid);
        
        return pid.getValue();
    }
[/code]

great, we're getting somewhere. But what comes next? if this were C++, we would need to open the process so that we can start getting down and dirty. that's right, now we get to rewrite OpenProcess().

let's check it out in the Kernel32 interface;

[code]
    /*
    HANDLE WINAPI OpenProcess(
      __in  DWORD dwDesiredAccess,
      __in  BOOL bInheritHandle,
      __in  DWORD dwProcessId
    );
     */
    Pointer OpenProcess(int desiredAccess, boolean inherit, int pid);
[/code]

this should be relatively straightforward to any experienced people - the MSDN documentation ([url]http://msdn.microsoft.com/en-us/library/ms684320(VS.85).aspx[/url]) tells us the parameters.

so, it takes a DWORD (also known as double word (which is also known as int. 4 bytes. i'm sure you knew that.)) to know what access we're trying to open the process with. check out some of the possible values here- [url]http://msdn.microsoft.com/en-us/library/ms684880(v=VS.85).aspx[/url]

then we can see that it takes a boolean. the boolean isn't so important. we like it when it is true.

finally, it takes in the processID. we got that earlier! yay!

so let's write another method in our Cheater class to, once again, make things easier on ourself.

[code]
    public static Pointer openProcess(int permissions, int pid)
    {
        Pointer process = kernel32.OpenProcess(permissions,true, pid);
        return process;
    }
[/code]

that was simple enough. the most difficult part of getting all of this to work is re-coding the C++ datatypes as java datatypes. I don't even remember how I figured out how it should return a Pointer. luckily for us, it gets even more difficult later. (since java has no unsigned data types)

so let's see how things are shaping up so far;

[code]
import java.util.Arrays;
import com.sun.jna.Memory;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.ptr.IntByReference;
import com.sun.jna.*;

public class Cheater
{
    static Kernel32 kernel32 = (Kernel32) Native.loadLibrary("kernel32", Kernel32.class);
    static User32     user32 = (User32)   Native.loadLibrary("user32"  , User32.class);
    
    public static void main(String[] args)
    {
        int pid = getProcessId("3D Pinball for Windows - Space Cadet");
        Pointer readprocess = openProcess(0x0010, pid);
    }
    
    public static int getProcessId(String window)
    {
        IntByReference pid = new IntByReference(0);
        user32.GetWindowThreadProcessId(user32.FindWindowA(null,window), pid);
        
        return pid.getValue();
    }
    
    public static Pointer openProcess(int permissions, int pid)
    {
        Pointer process = kernel32.OpenProcess(permissions,true, pid);
        return process;
    }
[/code]

if you're confused as to why "Pointer readprocess = openProcess(0x0010, pid);" has 0x0010, go back to this link: [url]http://msdn.microsoft.com/en-us/library/ms684880(v=VS.85).aspx[/url]

[quote]
PROCESS_VM_READ (0x0010)	Required to read memory in a process using ReadProcessMemory.
[/quote]

right-o.

so now let's have some fun. let's make java print out our current score!

for that, we now need to recreate ReadProcessMemory(). I gave you the interface for it in the Kernel32 class:

[code]
    /*
    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);
[/code]

so let's go through those paremeters.

Pointer hProcess - check (our variable "readprocess")

int inBaseAddress - check (the memory address we want to start reading from. if you need help with this step, check out some tutorials on finding memory addresses using a memory searcher/editor such as Memory Hacking Software ([url]http://memoryhacking.com/)[/url])

Pointer outbutBuffer - ok, what the hell is this? let's check the trusty MSDN:

[quote]
lpBuffer [out]
A pointer to a buffer that receives the contents from the address space of the specified process.
[/quote]

so basically, it's where the memory that we read is going to be stored. i'll show you how this works in a second.

int nSize - this is just how much memory we should be reading from the process (in bytes) remember, an integer value is 4 bytes. most of the time you're going to be reading 4 bytes if you want to read a number.

IntByReference outNumberOfBytesRead - the MSDN tells us that this will hold the number of bytes that actually gets read. it will be the same as nSize most of the time.

-------

alright, so let's piece this this together by making another method in our Cheater class.

[code]
    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;
    }
[/code]

let's break this down:

we know what an IntByReference is for, but what is a "Memory" ? Memory is just a class that the JNA uses to hold memory. go figure. the constructor it takes is how much memory it should hold (in bytes)

hopefully the rest is fully understandable. if not, feel free to ask about it.


so this is how the Cheater class should look so far:

[code]
import java.util.Arrays;
import com.sun.jna.Memory;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.ptr.IntByReference;
import com.sun.jna.*;

public class Cheater
{
    static Kernel32 kernel32 = (Kernel32) Native.loadLibrary("kernel32", Kernel32.class);
    static User32     user32 = (User32)   Native.loadLibrary("user32"  , User32.class);
    
    public static void main(String[] args)
    {
        int pid = getProcessId("3D Pinball for Windows - Space Cadet");
        Pointer readprocess = openProcess(0x0010, pid);
        int size = 4;
        Memory read = readMemory(readprocess,0x00AB0C62,size);
    }

    public static int getProcessId(String window)
    {
        IntByReference pid = new IntByReference(0);
        user32.GetWindowThreadProcessId(user32.FindWindowA(null,window), pid);
        
        return pid.getValue();
    }
    
    public static Pointer openProcess(int permissions, int pid)
    {
        Pointer process = kernel32.OpenProcess(permissions,true, pid);
        return process;
    }

    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;
    }
}
[/code]

"int size = 4;"
this is the size in bytes of what we want to read. since the score is held in an integer and an integer is 4 bytes, we definitely want to read 4 bytes.

"Memory read = readMemory(readprocess,0x00AB0C62,size);"
0x00AB0C62 is the memory address that holds the score for pinball.

now you see that we're using the Memory class again to hold.. well, memory.

so how do we get the value out of the Memory class? simple. we read 4 bytes. 4 bytes is an integer. the Memory class has a method for this.

read.getInt(0) (0 is the offset. we don't want an offset)

so.. great. now we can read memory with java!

let's see how it all comes together.

[code]
import java.util.Arrays;
import com.sun.jna.Memory;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.ptr.IntByReference;
import com.sun.jna.*;

public class Cheater
{
    static Kernel32 kernel32 = (Kernel32) Native.loadLibrary("kernel32", Kernel32.class);
    static User32     user32 = (User32)   Native.loadLibrary("user32"  , User32.class);
    
    public static void main(String[] args)
    {
        int pid = getProcessId("3D Pinball for Windows - Space Cadet"); // get our process ID
        Pointer readprocess = openProcess(0x0010, pid); // open the process ID with read priviledges.
        
        int size = 4; // we want to read 4 bytes
        Memory read = readMemory(readprocess,0x00AB0C62,size); // read 4 bytes of memory starting at the address 0x00AB0C62.

        System.out.println(read.getInt(0)); // print out the value!
    }
    
    public static int getProcessId(String window)
    {
        IntByReference pid = new IntByReference(0);
        user32.GetWindowThreadProcessId(user32.FindWindowA(null,window), pid);
        
        return pid.getValue();
    }
    
    public static Pointer openProcess(int permissions, int pid)
    {
        Pointer process = kernel32.OpenProcess(permissions,true, pid);
        return process;
    }
    
    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;
    }
}
[/code]

congratulations, you now have the framework for reading process memory with java.

i'm not going to jerk your chain around and make you guess on how to write memory with java. it's pretty much the same process:

[code]
    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);
        return written.getValue();
    }
[/code]


Enjoy!

- Deject3d

User32 인터페이스를

 

User32 Interface - Pastebin.com

Pastebin.com is the number one paste tool since 2002. Pastebin is a website where you can store text online for a set period of time.

pastebin.com

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;

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);  
}

ernel32 인터페이스

 

Kernel32 Interface - Pastebin.com

Pastebin.com is the number one paste tool since 2002. Pastebin is a website where you can store text online for a set period of time.

pastebin.com

import com.sun.jna.Pointer;
import com.sun.jna.ptr.IntByReference;
import com.sun.jna.win32.StdCallLibrary;

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, long 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, long 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();  
}

https://drive.google.com/file/d/1GLxYKfl6gG53cNyVwLpTlMTdIPjY2-NH/view?usp=share_link 

 

Google Drive: 로그인

이메일 또는 휴대전화

accounts.google.com

 

728x90

'Programming > JAVA' 카테고리의 다른 글

Json String to VO  (0) 2023.04.01
이클립스 화면설계 플러그인  (0) 2023.04.01
WEB 크롤링 - Selenium  (0) 2023.03.29
WIN10 ipconfig wsl ip tunneling  (0) 2023.03.29

+ Recent posts