mirror of
https://github.com/ufrisk/MemProcFS.git
synced 2026-05-07 22:06:17 +08:00
444 lines
13 KiB
Java
444 lines
13 KiB
Java
package vmm.internal;
|
|
|
|
import java.nio.charset.StandardCharsets;
|
|
|
|
import com.sun.jna.*;
|
|
import com.sun.jna.ptr.*;
|
|
|
|
import leechcore.*;
|
|
import leechcore.entry.*;
|
|
import vmm.internal.LeechCoreNative.LC_BAR_REQUEST;
|
|
|
|
/**
|
|
* JNA native code wrapper for LeechCore.
|
|
* @see https://github.com/ufrisk/MemProcFS
|
|
* @author Ulf Frisk - pcileech@frizk.net
|
|
*/
|
|
public class LeechCoreImpl implements ILeechCore
|
|
{
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// INITIALIZATION FUNCTIONALITY BELOW:
|
|
//-----------------------------------------------------------------------------
|
|
private Pointer hLC = null;
|
|
private String lcNativeLibraryPath = null;
|
|
|
|
/*
|
|
* Do not allow direct class instantiation from outside.
|
|
*/
|
|
private LeechCoreImpl()
|
|
{
|
|
}
|
|
|
|
private LeechCoreImpl(String lcNativeLibraryPath, String strDevice, String strRemote, int flagsVerbose, long paMax)
|
|
{
|
|
byte[] bDevice = strDevice.getBytes(StandardCharsets.UTF_8);
|
|
byte[] bRemote = strRemote.getBytes(StandardCharsets.UTF_8);
|
|
LeechCoreNative.LC_CONFIG lcConfig = new LeechCoreNative.LC_CONFIG();
|
|
lcConfig.dwVersion = LeechCoreNative.LC_CONFIG_VERSION;
|
|
System.arraycopy(bDevice, 0, lcConfig.szDevice, 0, Math.min(lcConfig.szDevice.length - 1, bDevice.length));
|
|
System.arraycopy(bRemote, 0, lcConfig.szRemote, 0, Math.min(lcConfig.szRemote.length - 1, bRemote.length));
|
|
lcConfig.dwPrintfVerbosity = flagsVerbose;
|
|
lcConfig.paMax = paMax;
|
|
System.setProperty("jna.library.path", lcNativeLibraryPath);
|
|
hLC = LeechCoreNative.INSTANCE.LcCreate(lcConfig);
|
|
if(hLC == null) { throw new LeechCoreException("LeechCore Init: failed in native code."); }
|
|
this.lcNativeLibraryPath = lcNativeLibraryPath;
|
|
}
|
|
|
|
public static ILeechCore Initialize(vmm.IVmm vmmInstance)
|
|
{
|
|
if((vmmInstance == null) || !vmmInstance.isValid()) {
|
|
return null;
|
|
}
|
|
long lcHandle = vmmInstance.getConfig(vmm.IVmm.OPT_CORE_LEECHCORE_HANDLE);
|
|
String strDevice = "existing://0x" + Long.toHexString(lcHandle);
|
|
String lcNativeLibraryPath = vmmInstance.getNativeLibraryPath();
|
|
return new LeechCoreImpl(lcNativeLibraryPath, strDevice, "", 0, 0);
|
|
}
|
|
|
|
public static ILeechCore Initialize(String lcNativeLibraryPath, String strDevice)
|
|
{
|
|
return new LeechCoreImpl(lcNativeLibraryPath, strDevice, "", 0, 0);
|
|
}
|
|
|
|
public static ILeechCore Initialize(String lcNativeLibraryPath, String strDevice, String strRemote, int flagsVerbose, long paMax)
|
|
{
|
|
return new LeechCoreImpl(lcNativeLibraryPath, strDevice, strRemote, flagsVerbose, paMax);
|
|
}
|
|
|
|
public boolean isValid() {
|
|
return hLC != null;
|
|
}
|
|
|
|
public String getNativeLibraryPath() {
|
|
return lcNativeLibraryPath;
|
|
}
|
|
|
|
public void close()
|
|
{
|
|
LeechCoreNative.INSTANCE.LcClose(hLC);
|
|
hLC = null;
|
|
}
|
|
|
|
/*
|
|
* Always close native implementation upon finalization.
|
|
*/
|
|
@Override
|
|
public void finalize()
|
|
{
|
|
try {
|
|
this.close();
|
|
} catch (Exception e) {}
|
|
}
|
|
|
|
/*
|
|
* Custom toString() method.
|
|
*/
|
|
@Override
|
|
public String toString()
|
|
{
|
|
return (hLC != null) ? "LeechCore" : "LeechCoreNotValid";
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// CONFIGURATION SETTINGS BELOW:
|
|
//-----------------------------------------------------------------------------
|
|
|
|
@Override
|
|
public long getOption(long fOption)
|
|
{
|
|
LongByReference pqw = new LongByReference();
|
|
boolean f = LeechCoreNative.INSTANCE.LcGetOption(hLC, fOption, pqw);
|
|
if(!f) { throw new LeechCoreException("LeechCore.LcGetOption(): failed."); }
|
|
return pqw.getValue();
|
|
}
|
|
|
|
@Override
|
|
public void setOption(long fOption, long qw)
|
|
{
|
|
boolean f = LeechCoreNative.INSTANCE.LcSetOption(hLC, fOption, qw);
|
|
if(!f) { throw new LeechCoreException("LeechCore.LcSetOption(): failed."); }
|
|
}
|
|
|
|
@Override
|
|
public byte[] memRead(long pa, int size)
|
|
{
|
|
byte[] pbResult = new byte[size];
|
|
boolean f = LeechCoreNative.INSTANCE.LcRead(hLC, pa, size, pbResult);
|
|
if(!f) { throw new LeechCoreException("LeechCore.LcRead(): failed."); }
|
|
return pbResult;
|
|
}
|
|
|
|
@Override
|
|
public void memWrite(long pa, byte[] data)
|
|
{
|
|
boolean f = LeechCoreNative.INSTANCE.LcWrite(hLC, pa, data.length, data);
|
|
if(!f) { throw new LeechCoreException("LeechCore.LcWrite(): failed."); }
|
|
}
|
|
|
|
@Override
|
|
public String getMemMap()
|
|
{
|
|
return new String(command(ILeechCore.LC_CMD_MEMMAP_GET, null), StandardCharsets.UTF_8);
|
|
}
|
|
|
|
@Override
|
|
public void setMemMap(String strMemMap)
|
|
{
|
|
byte[] bMemMap = strMemMap.getBytes(StandardCharsets.UTF_8);
|
|
command(ILeechCore.LC_CMD_MEMMAP_SET, bMemMap);
|
|
}
|
|
|
|
@Override
|
|
public byte[] command(long fCommand, byte[] data)
|
|
{
|
|
PointerByReference ppbDataOut = new PointerByReference();
|
|
IntByReference pcbDataOut = new IntByReference();
|
|
int dataInLen = 0;
|
|
Pointer dataInPtr = null;
|
|
if((data != null) && (data.length > 0)) {
|
|
dataInLen = data.length;
|
|
dataInPtr = new Memory(dataInLen);
|
|
dataInPtr.write(0, data, 0, dataInLen);
|
|
}
|
|
boolean f = LeechCoreNative.INSTANCE.LcCommand(hLC, fCommand, dataInLen, dataInPtr, ppbDataOut, pcbDataOut);
|
|
if(!f) { throw new LeechCoreException("LeechCore.LcCommand(): failed."); }
|
|
int cbDataOut = pcbDataOut.getValue();
|
|
if(0 == cbDataOut) { return null; }
|
|
Pointer pbDataOut = ppbDataOut.getValue();
|
|
if(0 == Pointer.nativeValue(pbDataOut)) { return null; }
|
|
byte[] dataOut = pbDataOut.getByteArray(0, cbDataOut);
|
|
LeechCoreNative.INSTANCE.LcMemFree(pbDataOut);
|
|
return dataOut;
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// LEECHCORE INTERNAL TLP FUNCTIONALITY BELOW:
|
|
//-----------------------------------------------------------------------------
|
|
|
|
@Override
|
|
public void writePCIeTLP(byte[] tlp)
|
|
{
|
|
if((tlp != null) && (tlp.length > 0) || ((tlp.length % 4) == 0)) {
|
|
command(ILeechCore.LC_CMD_FPGA_TLP_WRITE_SINGLE, tlp);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public ILeechCoreTlpContext setPCIeTlpCallback(ILeechCoreTlpCallback callback)
|
|
{
|
|
return LeechCoreTlpContextImpl.initializeLeechCoreTlpContextImpl(this, callback);
|
|
}
|
|
|
|
private class LeechCoreTlpContextImpl implements ILeechCoreTlpContext
|
|
{
|
|
private LeechCoreImpl lc;
|
|
private Integer key;
|
|
private Pointer keyPointer;
|
|
private ILeechCoreTlpCallback cbUser;
|
|
private LeechCoreNative.CALLBACK_TLP cbNative;
|
|
|
|
static LeechCoreTlpContextImpl initializeLeechCoreTlpContextImpl(LeechCoreImpl lc, ILeechCoreTlpCallback cbUser)
|
|
{
|
|
LeechCoreTlpContextImpl ctx = lc.new LeechCoreTlpContextImpl();
|
|
ctx.cbNative = new LeechCoreNative.CALLBACK_TLP() {
|
|
@Override
|
|
public void invoke(int ctxNative, int cbTlp, Pointer pbTlp, int cbInfo, String szInfo) {
|
|
try {
|
|
byte[] tlp = pbTlp.getByteArray(0, cbTlp);
|
|
Integer key = Integer.valueOf(ctxNative);
|
|
LeechCoreTlpContextImpl ctx = (LeechCoreTlpContextImpl)JnaObjectMap.getInstance().get(key);
|
|
ctx.cbUser.LeechCoreTlpCallback(ctx.lc, tlp, szInfo);
|
|
} catch (Exception e) {}
|
|
}
|
|
};
|
|
ctx.lc = lc;
|
|
ctx.cbUser = cbUser;
|
|
ctx.key = JnaObjectMap.getInstance().put(ctx);
|
|
ctx.keyPointer = new Pointer(ctx.key.longValue());
|
|
if(!LeechCoreNative.INSTANCE.LcSetOption(lc.hLC, LC_OPT_FPGA_TLP_READ_CB_WITHINFO, 1)) {
|
|
ctx.close();
|
|
return null;
|
|
}
|
|
if(!LeechCoreNative.INSTANCE.LcCommand(lc.hLC, LC_CMD_FPGA_TLP_CONTEXT, 0, ctx.keyPointer, null, null)) {
|
|
ctx.close();
|
|
return null;
|
|
}
|
|
if(!LeechCoreNativeEx.INSTANCE.LcCommand(lc.hLC, LC_CMD_FPGA_TLP_FUNCTION_CALLBACK, 0, ctx.cbNative, null, null)) {
|
|
ctx.close();
|
|
return null;
|
|
}
|
|
return ctx;
|
|
}
|
|
|
|
@Override
|
|
public void close()
|
|
{
|
|
if((lc == null) || (key == null)) {
|
|
return;
|
|
}
|
|
PointerByReference pptr = new PointerByReference();
|
|
if(!LeechCoreNative.INSTANCE.LcCommand(lc.hLC, LC_CMD_FPGA_TLP_CONTEXT_RD, 0, null, pptr, null)) {
|
|
return;
|
|
}
|
|
if(Pointer.nativeValue(pptr.getPointer()) != key.longValue()) {
|
|
return;
|
|
}
|
|
LeechCoreNative.INSTANCE.LcCommand(lc.hLC, LC_CMD_FPGA_TLP_FUNCTION_CALLBACK, 0, null, null, null);
|
|
LeechCoreNative.INSTANCE.LcCommand(lc.hLC, LC_CMD_FPGA_TLP_CONTEXT, 0, null, null, null);
|
|
JnaObjectMap.getInstance().remove(key);
|
|
keyPointer = null;
|
|
cbNative = null;
|
|
cbUser = null;
|
|
key = null;
|
|
lc = null;
|
|
}
|
|
|
|
/*
|
|
* Always close native implementation upon finalization.
|
|
*/
|
|
@Override
|
|
public void finalize()
|
|
{
|
|
try {
|
|
close();
|
|
} catch (Exception e) {}
|
|
}
|
|
|
|
@Override
|
|
public String toString()
|
|
{
|
|
return "LeechCoreTlpContext";
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// LEECHCORE INTERNAL BAR FUNCTIONALITY BELOW:
|
|
//-----------------------------------------------------------------------------
|
|
|
|
@Override
|
|
public LeechCoreBar[] getBarInfo()
|
|
{
|
|
IntByReference pcbDataOut = new IntByReference();
|
|
PointerByReference ppbDataOut = new PointerByReference();
|
|
boolean f = LeechCoreNative.INSTANCE.LcCommand(hLC, ILeechCore.LC_CMD_FPGA_BAR_INFO, 0, null, ppbDataOut, pcbDataOut);
|
|
if(!f) { throw new LeechCoreException("LeechCore.LcCommand(): failed."); }
|
|
Pointer pbDataOut = ppbDataOut.getValue();
|
|
if(0 == Pointer.nativeValue(pbDataOut)) { return null; }
|
|
LeechCoreNative.LC_BAR_6 nativeBars = new LeechCoreNative.LC_BAR_6(pbDataOut);
|
|
LeechCoreBar lcBars[] = new LeechCoreBar[6];
|
|
// process result:
|
|
for(LeechCoreNative.LC_BAR n : nativeBars.bars) {
|
|
LeechCoreBar e = new LeechCoreBar();
|
|
e.fValid = n.fValid;
|
|
e.f64Bit = n.f64Bit;
|
|
e.fPrefetchable = n.fPrefetchable;
|
|
e.iBar = n.iBar;
|
|
e.pa = n.pa;
|
|
e.cb = n.cb;
|
|
lcBars[e.iBar] = e;
|
|
}
|
|
LeechCoreNative.INSTANCE.LcMemFree(pbDataOut);
|
|
return lcBars;
|
|
}
|
|
|
|
@Override
|
|
public ILeechCoreBarContext setPCIeBarCallback(ILeechCoreBarCallback callback)
|
|
{
|
|
return LeechCoreBarContextImpl.initializeLeechCoreBarContextImpl(this, callback);
|
|
}
|
|
|
|
private class LeechCoreBarReplyImpl implements ILeechCoreBarReply
|
|
{
|
|
private LC_BAR_REQUEST n;
|
|
|
|
@Override
|
|
public void reply(byte[] data) {
|
|
if(!n.fRead) {
|
|
throw new LeechCoreException("LeechCore.replyBarRead(): only possible to reply to read requests.");
|
|
}
|
|
if(data == null) {
|
|
n.cbData = 0;
|
|
n.fReadReply = true;
|
|
return;
|
|
}
|
|
if(n.cbData != data.length) {
|
|
throw new LeechCoreException("LeechCore.replyBarRead(): data length of reply mis-matches requested data length.");
|
|
}
|
|
n.fReadReply = true;
|
|
System.arraycopy(data, 0, n.pbData, 0, n.cbData);
|
|
}
|
|
}
|
|
|
|
private class LeechCoreBarContextImpl implements ILeechCoreBarContext
|
|
{
|
|
private LeechCoreImpl lc;
|
|
private Integer key;
|
|
private Pointer keyPointer;
|
|
private ILeechCoreBarCallback cbUser;
|
|
private LeechCoreNative.CALLBACK_BAR cbNative;
|
|
|
|
static LeechCoreBarContextImpl initializeLeechCoreBarContextImpl(LeechCoreImpl lc, ILeechCoreBarCallback cbUser)
|
|
{
|
|
LeechCoreBarContextImpl ctx = lc.new LeechCoreBarContextImpl();
|
|
ctx.cbNative = new LeechCoreNative.CALLBACK_BAR() {
|
|
@Override
|
|
public void invoke(LC_BAR_REQUEST n) {
|
|
try {
|
|
LeechCoreNative.LC_BAR nbar = new LeechCoreNative.LC_BAR(n.pBar);
|
|
LeechCoreBar bar = new LeechCoreBar();
|
|
bar.fValid = nbar.fValid;
|
|
bar.f64Bit = nbar.f64Bit;
|
|
bar.fPrefetchable = nbar.fPrefetchable;
|
|
bar.iBar = nbar.iBar;
|
|
bar.pa = nbar.pa;
|
|
bar.cb = nbar.cb;
|
|
LeechCoreBarReplyImpl reply = lc.new LeechCoreBarReplyImpl();
|
|
reply.n = n;
|
|
LeechCoreBarRequest req = new LeechCoreBarRequest();
|
|
req.reply = reply;
|
|
req.bar = bar;
|
|
req.bTag = n.bTag;
|
|
req.bFirstBE = n.bFirstBE;
|
|
req.bLastBE = n.bLastBE;
|
|
req.is64Bit = n.f64;
|
|
req.isRead = n.fRead;
|
|
req.isWrite = n.fWrite;
|
|
req.cbData = n.cbData;
|
|
req.oData = n.oData;
|
|
if(req.isWrite) {
|
|
req.pbDataWrite = new byte[req.cbData];
|
|
System.arraycopy(n.pbData, 0, req.pbDataWrite, 0, req.cbData);
|
|
}
|
|
// call into user-defined function:
|
|
// user may optionally call back to reply.reply() which updated native data.
|
|
Integer key = Integer.valueOf((int)Pointer.nativeValue(n.ctx));
|
|
LeechCoreBarContextImpl ctx = (LeechCoreBarContextImpl)JnaObjectMap.getInstance().get(key);
|
|
ctx.cbUser.LeechCoreBarCallback(req);
|
|
} catch (Exception e) {}
|
|
}
|
|
};
|
|
ctx.lc = lc;
|
|
ctx.cbUser = cbUser;
|
|
ctx.key = JnaObjectMap.getInstance().put(ctx);
|
|
ctx.keyPointer = new Pointer(ctx.key.longValue());
|
|
if(!LeechCoreNative.INSTANCE.LcCommand(lc.hLC, LC_CMD_FPGA_BAR_CONTEXT, 0, ctx.keyPointer, null, null)) {
|
|
ctx.close();
|
|
return null;
|
|
}
|
|
if(!LeechCoreNativeEx.INSTANCE.LcCommand(lc.hLC, LC_CMD_FPGA_BAR_FUNCTION_CALLBACK, 0, ctx.cbNative, null, null)) {
|
|
ctx.close();
|
|
return null;
|
|
}
|
|
return ctx;
|
|
}
|
|
|
|
@Override
|
|
public void close()
|
|
{
|
|
if((lc == null) || (key == null)) {
|
|
return;
|
|
}
|
|
PointerByReference pptr = new PointerByReference();
|
|
if(!LeechCoreNative.INSTANCE.LcCommand(lc.hLC, LC_CMD_FPGA_BAR_CONTEXT_RD, 0, null, pptr, null)) {
|
|
return;
|
|
}
|
|
if(Pointer.nativeValue(pptr.getPointer()) != key.longValue()) {
|
|
return;
|
|
}
|
|
LeechCoreNative.INSTANCE.LcCommand(lc.hLC, LC_CMD_FPGA_BAR_FUNCTION_CALLBACK, 0, null, null, null);
|
|
LeechCoreNative.INSTANCE.LcCommand(lc.hLC, LC_CMD_FPGA_BAR_CONTEXT, 0, null, null, null);
|
|
JnaObjectMap.getInstance().remove(key);
|
|
keyPointer = null;
|
|
cbNative = null;
|
|
cbUser = null;
|
|
key = null;
|
|
lc = null;
|
|
}
|
|
|
|
/*
|
|
* Always close native implementation upon finalization.
|
|
*/
|
|
@Override
|
|
public void finalize()
|
|
{
|
|
try {
|
|
close();
|
|
} catch (Exception e) {}
|
|
}
|
|
|
|
@Override
|
|
public String toString()
|
|
{
|
|
return "LeechCoreBarContext";
|
|
}
|
|
}
|
|
}
|