【问题标题】:VirtualAllocEx function in Java JNA mappingJava JNA 映射中的 VirtualAllocEx 函数
【发布时间】:2016-04-11 05:29:17
【问题描述】:

至少一天以来,我一直在尝试解决这个问题,研究所有转换它们的变量类型,查看我在网上找到的 24 个其他示例(甚至其中一个在 JNA github 上为 Kernel32 提供)。我正在尝试使用 JNA 在 java 中绘制 VirtualAllocEx 函数。我对如何做到这一点有一个大致的想法,这是我目前的课程:

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 [链接已删除]。

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

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

还要注意关于这个例子的一些事情:现在已经很晚了,我知道我的程序内部仍然有一些有缺陷的逻辑(比如我传递给 WriteProcessMemory 的项目,我得到一个 487 表示“尝试访问无效地址。 " 但那是因为我无法让 VirtualAllocEx 向我返回一个地址以放入其中,所以我只是传递了任何可用的地址。

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

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

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

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

【问题讨论】:

  • 先在 C 中尝试相同的代码,看看是否可行。
  • @Voo 确实如此,但无论出于何种原因,VirtualAllocEx 仍然无法映射。
  • 问题可能是您已将VirtualAllocEx 的返回类型声明为int,即32 位,而(假设为64 位JRE)实际返回类型为64位指针。
  • @HarryJohnston 这就是我的想法,但我也尝试过指针的返回类型,它只是指针还是有一些特殊的类?

标签: java c++ windows native jna


【解决方案1】:

最有可能的答案是:您没有写入该内存的权限,因此您需要以某种方式提升权限。您是否以管理员身份运行过它?

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

编辑

您还应该调用Native.getLastError() 而不是GetLastError();通常 JNA 会为您执行此操作,但最近出现了一个错误,即在某些情况下无法进行拦截。看看您在更改后是否收到不同的错误。

编辑

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

编辑

PAGE_EXECUTE_READWRITE 的值为零,应为 0x40。

【讨论】:

  • 不可能是权限,除非是系统进程或属于不同用户的进程。此外,权限问题会导致 OpenProcess 失败,而不是 VirtualAllocEx。
  • 您的 PAGE_EXECUTE_READWRITE 的值为零 - 是的,就是这样。好收获!
  • @Franciscocamilo JNA 是一个开源库,用于在 Java 中调用 windows api。谷歌它的链接。
  • @Franciscocamilo 虽然int 可以工作(但仅在32 位窗口上),Pointer 是首选作为返回值。 LPVOID 只是一个指针。
  • @technomage,所以,Pointer 类型作为返回,上面的代码可以在 32 位和 64 位 Windows 中工作吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-06-08
相关资源
最近更新 更多