Java JNA 映射中的 VirtualAllocEx 函数

VirtualAllocEx function in Java JNA mapping

我已经尝试解决这个问题至少一天了,研究了所有将它们转换过来的变量类型,查看了我在网上找到的 24 个其他示例(甚至其中一个在 JNA github 适用于 Kernel32)。我正在尝试使用 JNA 在 java 中映射 VirtualAllocEx 函数。我对如何执行此操作有一个大致的了解,这是我目前的 class:

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.util.Arrays;

import com.sun.jna.Memory;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.platform.win32.BaseTSD.SIZE_T;
import com.sun.jna.platform.win32.Tlhelp32;
import com.sun.jna.platform.win32.WinDef;
import com.sun.jna.platform.win32.WinNT;
import com.sun.jna.platform.win32.WinNT.HANDLE;
import com.sun.jna.ptr.IntByReference;
import com.sun.jna.win32.StdCallLibrary;
import com.sun.jna.win32.W32APIOptions;

public class HelloWorld 
{

    public interface Kernel32 extends StdCallLibrary 
    {
        public static final Kernel32 INSTANCE = (Kernel32)Native.loadLibrary("kernel32", Kernel32.class, W32APIOptions.UNICODE_OPTIONS);


        public static final int PROCESS_CREATE_THREAD = 0x0002;
        public static final int PAGE_EXECUTE_READWRITE = 0;
        public static int PROCESS_QUERY_INFORMATION = 0x0400;
        public static int PROCESS_VM_OPERATION = 0x0008;
        public static int PROCESS_VM_WRITE = 0x0020;
        public static int PROCESS_VM_READ = 0x0010;
        public static int PAGE_READWRITE = 0x04;
        public static int MEM_RESERVE = 0x2000;
        public static int MEM_COMMIT = 0x1000;

        //public Pointer VirtualAllocEx(int ProcessToAllocateRamIn, int AddresToStartAt, int DesiredSizeToAllocate, int AllocationType, int  ProtectType);
        int VirtualAllocEx(HANDLE hProcess, Pointer lpAddress, SIZE_T dwSize, int flAllocationType, int flProtect); 
        //public int VirtualAllocEx(HANDLE hProcess,IntByReference lpAddress,int dwSize,int flAllocationType,int flProtect);
        //public IntByReference VirtualAllocEx(HANDLE hProcess, Pointer lpAddress, SIZE_T dwSize, int flAllocationType, int flProtect);
        public WinNT.HANDLE CreateToolhelp32Snapshot(WinDef.DWORD var1, WinDef.DWORD var2);
        public boolean Process32First(WinNT.HANDLE var1, Tlhelp32.PROCESSENTRY32 var2);
        public boolean Process32Next(WinNT.HANDLE var1, Tlhelp32.PROCESSENTRY32 var2);
        public WinNT.HANDLE OpenProcess(int var1, boolean var2, int var3);
        public boolean CloseHandle(WinNT.HANDLE var1);
        public boolean WriteProcessMemory(WinNT.HANDLE var1, Pointer var2, Pointer var3, int var4, IntByReference var5);
        public int GetLastError();
    }

    public static void main(String[] args) throws Exception 
    {
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream(new File("C:\WINDOWS\system32\cmd.exe")));
        byte[] buffer = new byte[1000000];
        int read = bis.read(buffer);
        bis.close();
        byte[] nwBuff = Arrays.copyOfRange(buffer, 0, read);

        Tlhelp32.PROCESSENTRY32.ByReference processEntry = new Tlhelp32.PROCESSENTRY32.ByReference();  

        WinNT.HANDLE snapshot = Kernel32.INSTANCE.CreateToolhelp32Snapshot(Tlhelp32.TH32CS_SNAPPROCESS, new WinDef.DWORD(0));
        try  {
            while (Kernel32.INSTANCE.Process32Next(snapshot, processEntry)) {
                System.out.println(processEntry.th32ProcessID + "\t" + Native.toString(processEntry.szExeFile));
            }
        }
        finally {
            Kernel32.INSTANCE.CloseHandle(snapshot);
        }
        HANDLE process = Kernel32.INSTANCE.OpenProcess(Kernel32.PROCESS_VM_OPERATION|Kernel32.PROCESS_VM_WRITE|Kernel32.PROCESS_VM_READ|Kernel32.PROCESS_CREATE_THREAD|Kernel32.PROCESS_QUERY_INFORMATION, false, 3756);
        System.out.println((process != null));
        writeMemory(process, nwBuff);
    }

    public static void writeMemory(HANDLE process, byte[] data)
    {
        int size = data.length;
        Memory toWrite = new Memory(size);

        for(int i = 0; i < size; i++)
            toWrite.setByte(i, data[i]);

        System.out.println("Memory size: "+size+"\t"+toWrite.size());

        SIZE_T a = new SIZE_T();
        a.setValue(toWrite.size());
        int x = Kernel32.INSTANCE.VirtualAllocEx(process, Pointer.NULL, a, Kernel32.MEM_RESERVE|Kernel32.MEM_COMMIT, Kernel32.PAGE_EXECUTE_READWRITE);
        int c = Kernel32.INSTANCE.GetLastError();
        System.out.println(x+"\t"+c);
        Pointer pros = process.getPointer();
        Pointer buffer = toWrite.getPointer(0);
        IntByReference z = new IntByReference();
        boolean b = Kernel32.INSTANCE.WriteProcessMemory(process, pros, buffer, size, z);
        c = Kernel32.INSTANCE.GetLastError();
        System.out.println(b+"\t"+c+"\t"+z.getValue());
    }
}

所以你可以忽略打印行(对我来说是调试信息)和我创建的所有随机未使用或不必要的变量。所以我的第一个问题:我是否正确构建了 Kernel32 接口? (它工作得很好,但是;我已经看到很多其他示例只是扩展了其他库等等……)。第二个问题:我发布这个的原因......我无法让 VirtualAllocEx 工作。我从 MSDN 中查找了方法定义并自己转换了类型,并查看了我在网上找到的其他 23 个示例: Example directly from JNA repo [链接已删除]。

如你所见,我还注释掉了一些我尝试过的其他函数 headers(我有很多,但我删除了我试图映射到的其他函数,以便稍微清理一下位。)

基本上我在这里想要完成的是打印所有 运行ning 进程(工作得很好......),然后获取 firefox 的 pid(作为测试......)[我硬编码pid right now] 并打开进程,然后将 cmd.exe 注入(或其他相关的 shellcode)以 运行 该代码。 (我也有将执行 CreateRemoteThread 的代码,并且应该用于生成 cmd.exe。)但是为了这个例子,我只是保持简短,因为 VirtualAllocEx 不会工作......(我什至需要在 运行ning 进程中分配内存以使其工作?)。

还要注意这个例子的一些事情:现在已经很晚了,我知道我在程序中仍然有一些有缺陷的逻辑(比如我传递给 WriteProcessMemory 的项目,我得到了 487 "Attempt to access invalid address."但那是因为我无法让 VirtualAllocEx return 给我一个地址,所以我只是把它传递给了任何可用的东西。

此时我愿意接受关于如何继续的任何建议或我可能尚未访问的任何链接,以便让我更好地了解我做错了什么。

编辑:忘记提及程序的输出:

[All processes [cut out for space]]
true
Memory size: 232448 232448
0   87
false   487 0

这就是它的输出。 VirtualAllocEx 函数调用后的错误代码 87,因为我无法正确调用 Write 调用后的 487,因为我还没有来自 VirtualAllocEx 的有效地址。谢谢!

最有可能的答案:您没有写入该内存的权限,因此您需要以某种方式提升权限。你 运行 作为管理员吗?

至于扩展库与从头编写自己的库,并不重要,但请参考 JNA 如何为 W32 API 库执行库初始化(即使用 StdCallLibrary 并使用 W32APIOptions.DEFAULT_OPTIONS).

编辑

您还应该调用 Native.getLastError() 而不是 GetLastError();通常 JNA 会为你做这件事,但最近有一个错误,在某些情况下拦截不会发生。查看更改后是否出现其他错误。

编辑

VirtualAllocEx 应该返回 Pointer,而不是 int。不过,这可能不会影响错误代码 87 (INVALID_PARAMETER)。

编辑

您的 PAGE_EXECUTE_READWRITE 值为零,应该是 0x40。