Accessing DLL pointers through Java - java

I am using Java (JNA) to access DLL code. Here is the DLL I am using:
U32 ReadMemU32(U32 Addr, U32 NumItems, U32* pData, U8* pStatus);
Here is my sample code:
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.ptr.*;
import com.sun.jna.*;
import java.lang.*;
import java.util.*;
import com.sun.jna.*;
import java.lang.*;
public class DLL1 {
#UserFunction(Description="DLL1 Java wrapper", Name = "DLL1")
public static String DLL1(
#UserFunction.Arg(Name = "Address", Description = "Register Address")
String Address
) throws Exception {
byte Status[] = new byte[1];
PointerByReference Data = new PointerByReference ();
long Addr = Long.parseLong(Address.substring(2, Address.length()));
DllInterface.INSTANCE.ReadMemU32(Addr, 1, Data, Status);
System.out.println("Data = " + Data);
System.out.println("Data.getValue() = " + Data.getValue());
return null;
}
// C++ function definition and tell which DLL to fetch
public interface DllInterface extends Library {
DllInterface INSTANCE = (DllInterface) Native.loadLibrary("<dll name>", DllInterface.class);
long ReadMemU32(long Addr, long NumItems, PointerByReference pData, byte[] pStatus);
}
}
The result I am getting is:
Data = allocated#0xe25ac90 (8 bytes)(com.sun.jna.ptr.PointerByReference#e25ac90)
Data.getValue() = native#0xaaaaaaaa
The result (0xaaaaaaaa) does not match with what I expect it to be.
I am new to Java and I am not sure if PointerByReference is the correct thing to use for U32* pData. Please advice.

Looking at the type definition for the function, I would make an educated guess and say that pData is the array pointer to which the function writes the read memory. You can use int[] directly here. Since the status is returned as an out parameter via pointer, you can use a ByteByReference.
In Java, long refers to a 64-bit integer, equivalent to C++'s long long. Since the type is U32, it's probably safe to guess that it refers to a 32-bit integer. This would be an int. You can check JNA's type mappings here.
Notice also that since the function accepts a 32-bit integer for the address, you cannot pass 64-bit addresses to the function.
I would guess that one proper mapping for this function would be:
int ReadMemU32(
int address,
int numItems,
int[] pData,
ByteByReference status
);
If your function truly only needs to read one 32-bit integer from memory, you can change pData's type to IntByReference and use it in the same way as the status parameter's ByteByReference.
Since the function returns an integer, I would guess that it returns the amount of bytes read. If so, it's important to check that this value matches with what you're expecting. Check what the library's documentation says about the return value and error states.
Try this:
import java.lang.*;
import java.util.*;
import com.sun.jna.*;
import com.sun.jna.ptr.*;
public class DLL1 {
#UserFunction(Description="DLL1 Java wrapper", Name = "DLL1")
public static String DLL1(
#UserFunction.Arg(Name = "Address", Description = "Register Address")
String Address
) throws Exception {
String addressWithoutPrefix = Address.substring(2)
int parsedAddress = Integer.parseInt(addressWithoutPrefix, 16)
int bytesToRead = 1;
int[] buffer = new int[bytesToRead];
ByteByReference status = new ByteByReference(0);
int BytesRead = DllInterface.INSTANCE.ReadMemU32(
parsedAddress,
bytesToRead,
buffer,
status
);
System.out.println("Status = " + status.getValue());
System.out.println("Bytes read = " + bytesRead);
System.out.println("Data = " + Arrays.toString(buffer));
return null;
}
// C++ function definition and tell which DLL to fetch
public interface DllInterface extends Library {
DllInterface INSTANCE = (DllInterface) Native.loadLibrary("<dll name>", DllInterface.class);
int ReadMemU32(
int address,
int numItems,
int[] pData,
ByteByReference status
);
}
}

Related

Build webassembly sorting functions from C++ and Java source code

I have a problem that I was going to work on arrays in WebAssembly and I wanted to use Java and C ++, and trying to do this, I ran into the following problems and I would like to ask for help:
Java: I'm using JWebAssembly
And we have a class that works on tables
import de.inetsoftware.jwebassembly.api.annotation.Export;
public class Add {
#Export
public static int[] add( int a[], int b ) {
for(int i = 0;i<b-1;i++){
a[i] += b ;
}
return a;
}
}
we convert it to wasm
import de.inetsoftware.jwebassembly.JWebAssembly;
import java.io.File;
import java.net.URL;
public class Wasm {
public static void main(String[] args) {
File wasmFile = new File("testTable.wasm");
JWebAssembly wasm = new JWebAssembly();
Class clazz = Add.class;
URL url = clazz.getResource(
'/' +
clazz.getName().replace('.', '/') +
".class");
wasm.addFile(url);
String txt = wasm.compileToText();
System.out.println(txt);
wasm.compileToBinary(wasmFile);
}
}
and such an error comes out
Exception in thread "main" de.inetsoftware.jwebassembly.WasmException: Unimplemented Java byte code operation: 42 at Add.java:11
https://en.wikipedia.org/wiki/List_of_Java_bytecode_instructions
And I don't understand why because in this guy's presentation https://www.youtube.com/watch?v=93z9SaLQVVw (40 min+) you can see that it works and compiles
Now C++
I use emscripten, I wanted to do a bubble sort but for the sake of simplicity an example showing the problem
#include <emscripten.h>
using namespace std;
EMSCRIPTEN_KEEPALIVE
int* mainFunction(int table[], int length)
{
int* outTable = new int[length];
for(int i = 0;i<length; i++){
outTable[i] = table[i];
}
return table;
}
By running it with this command test.cpp -s WASM=1 -o test.html
after compiling it, files appear to me from which I extract the appropriate data and in javascript I set and import everything
let wasmExports = null;
let asmLibraryArg = {
abort: () => {},
emscripten_resize_heap: () => {},
};
let info = {
env: asmLibraryArg,
wasi_snapshot_preview1: asmLibraryArg,
};
async function loadWasm() {
let response = await fetch("test.wasm");
let bytes = await response.arrayBuffer();
let wasmObj = await WebAssembly.instantiate(bytes, info);
wasmExports = wasmObj.instance.exports;
}
loadWasm();
and later in the code I use
console.log(wasmExports);
console.log(wasmExports._Z12mainFunctionPii(table, table.length));
results
and when I throw in some array of integers it only throws me the number 0 and I have no idea how to get out of it. Or maybe someone knows another language in which it is possible to compile for wasm and then run it on the website?

How to read the text of a locally open MS Word document using Java or Java Native Access

I have a problem statement of reading the text of locally open MSWord document. What I understand, using the following approach, given the path of the document, I can perform any operation in the document .
https://github.com/java-native-access/jna/blob/master/contrib/msoffice/src/com/sun/jna/platform/win32/COM/util/office/Wordautomation_KB_313193_Mod.java
But in my case I have a Handle (WinDef.HWND) to the locally opened word object . And I am not able to get the local path from it. I have given the code which I am trying out and I am not able to achieve what I looking for . Please give the any pointer how I can achieve solution of the above .
Please note that the following gives the path of WINWORD.EXE . And
System.out.println("File Path: "+desktop.getFilePath());
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.platform.DesktopWindow;
import com.sun.jna.platform.FileUtils;
import com.sun.jna.platform.WindowUtils;
import com.sun.jna.platform.WindowUtils.NativeWindowUtils;
import com.sun.jna.platform.win32.WinDef;
import com.sun.jna.platform.win32.Kernel32Util;
import com.sun.jna.platform.win32.WinUser;
import com.sun.jna.win32.StdCallLibrary;
import java.util.List;
public class NativeWordpadExtractor {
public static void main(String ar[]){
executeNativeCommands();
}
public static void executeNativeCommands(){
NativeExtractor.User32 user32 = NativeExtractor.User32.INSTANCE;
user32.EnumWindows(new WinUser.WNDENUMPROC() {
int count = 0;
#Override
public boolean callback(WinDef.HWND hWnd, Pointer arg1) {
byte[] windowText = new byte[512];
user32.GetWindowTextA(hWnd, windowText, 512);
String wText = Native.toString(windowText);
// get rid of this if block if you want all windows regardless of whether
// or not they have text
if (wText.isEmpty()) {
return true;
}
if("SampleTextForScreenScrapping_Word - WordPad".equals(wText)){
System.out.println("Got the 'Wordpad'" + hWnd + ", class " + hWnd.getClass() +"getPointer"+ hWnd.getPointer()+ " Text: " + wText);
//WinDef.HWND notePadHwnd = user32.FindWindowA("Wordpad",null );
byte[] fileText = new byte[1024];
System.out.println("fileText : " + WindowUtils.getWindowTitle(hWnd));
List<DesktopWindow> desktops=WindowUtils.getAllWindows(true);
// Approach 1) For getting a handle to the Desktop object . I am not able to achieve result with this.
for(DesktopWindow desktop:desktops){
System.out.println("File Path: "+desktop.getFilePath());
System.out.println("Title : "+desktop.getTitle());
}
System.out.println("fileText : " + WindowUtils.getAllWindows(true));
// Approach 2) For getting a handle to the native object .
// This is also not working
WinDef.HWND editHwnd = user32.FindWindowExA(hWnd, null, null, null);
byte[] lParamStr = new byte[512];
WinDef.LRESULT resultBool = user32.SendMessageA(editHwnd, NativeExtractor.User32.WM_GETTEXT, 512, lParamStr);
System.out.println("The content of the file is : " + Native.toString(lParamStr));
return false;
}
System.out.println("Found window with text " + hWnd + ", total " + ++count + " Text: " + wText);
return true;
}
}, null);
}
interface User32 extends StdCallLibrary {
NativeExtractor.User32 INSTANCE = (NativeExtractor.User32) Native.loadLibrary("user32", NativeExtractor.User32.class);
int WM_SETTEXT = 0x000c;
int WM_GETTEXT = 0x000D;
int GetWindowTextA(WinDef.HWND hWnd, byte[] lpString, int nMaxCount);
boolean EnumWindows(WinUser.WNDENUMPROC lpEnumFunc, Pointer arg);
WinDef.HWND FindWindowA(String lpClassName, String lpWindowName);
WinDef.HWND FindWindowExA(WinDef.HWND hwndParent, WinDef.HWND hwndChildAfter, String lpClassName, String lpWindowName);
WinDef.LRESULT SendMessageA(WinDef.HWND paramHWND, int paramInt, WinDef.WPARAM paramWPARAM, WinDef.LPARAM paramLPARAM);
WinDef.LRESULT SendMessageA(WinDef.HWND editHwnd, int wmGettext, long l, byte[] lParamStr);
int GetClassNameA(WinDef.HWND hWnd, byte[] lpString, int maxCount);
}
}
I'm not quite sure you can achieve what you want, but I'll do what I can to answer your questions to get you closer to the goal.
There are two ways to get the file information: one more generic with Java/JNA and the the other requiring you to peer inside the process memory space. I'll address the first one.
Rather than dealing with a window handle, let's get the Process ID, which is easier to use later. That's relatively straightforward:
IntByReference pidPtr = new IntByReference();
com.sun.jna.platform.win32.User32.INSTANCE.GetWindowThreadProcessId(hWnd, pidPtr);
int pid = pidPtr.getValue();
(Of note, you should probably have your own User32 interface extend the one above so you can just use the one class and not have to fully qualify the JNA version like I did.)
Now, armed with the PID, there are a few options to try to get the path.
If you're lucky and the user opened the file directly (rather than using File>Open), you can recover the commandline they used, and it will likely have the path. You can retrieve this from the WMI class Win32_Process. Full code you can find in my project OSHI in the WindowsOperatingSystem class or you can try using Runtime.getRuntime().exec() to use the commandline WMI version: wmic path Win32_Process where ProcessID=1234 get CommandLine, capturing the result in a BufferedReader (or see OSHI's ExecutingCommand class for an implementation.)
If the command line check is unsuccessful you can search for which file handles are open by that process. The easiest way to do that is to download the Handle utility (but all your users would have to do this) and then just execute the command line handle -p 1234. This will list open files held by that process.
If you can't rely on your users downloading Handle, you can try to implement the same code yourself. This is an undocumented API using NtQuerySystemInformation. See the JNA project Issue 657 for sample code which will iterate all of an operating system's handles, allowing you to look at the files. Given that you already know the PID you can shortcut the iteration after SYSTEM_HANDLE sh = info.Handles[i]; by skipping the remainder of the code unless sh.ProcessID matches your pid. As stated in that issue, the code listed is mostly unsupported and dangerous. There is no guarantee it will work in future versions of Windows.
Finally, you can see what you can do with process memory. Armed with the PID, you could open the Process to get a handle:
HANDLE pHandle = Kernel32.INSTANCE.OpenProcess(WinNT.PROCESS_QUERY_INFORMATION, false, pid);
Then you could enumerate its modules with EnumProcessModules; for each module use GetModuleInformation to retrieve a MODULEINFO structure. This gives you a pointer to memory that you can explore to your heart's content. Of course, accurately knowing at what offsets to find what information requires the API for the executable you're exploring (Word, WordPad, etc., and the appropriate version.) And you need admin rights. This exploration is left as an exercise for the reader.

JNA, Mapping and pointers references

I need to use DLL inside my Java application. DLL is exporting some set of functions, authors called it "Direct DLL API". I'm trying to define in java equivalent of following function declaration:
int XcCompress( HXCEEDCMP hComp, const BYTE* pcSource, DWORD dwSourceSize, BYTE** ppcCompressed, DWORD* pdwCompressedSize, BOOL bEndOfData );
Inside my interface that extends Library I declared it as follows:
int XcCompress(WString hComp, Pointer pcSource, int dwSourceSize, Pointer[] ppcCompressed, IntByReference pdwCompressedSize, boolean bEndOfData);
Problem is everytime I get an error:
Exception in thread "main" java.lang.Error: Invalid memory access
So basically I'm stuck at this point.
HXCEEDCMP hComp - is suppose to store handler to the function, and works fine as WString for init DLL / destroying DLL functions so I kept it like this.
The header reference "creature" is:
typedef HXCEEDCMP ( XCD_WINAPI *LPFNXCCREATEXCEEDCOMPRESSIONW )( const WCHAR* );
const BYTE* pcSource - is the source data for compression, inside my code I instantiate it this way:
private static Pointer setByteArrayPointer(String dataToCompress) {
Pointer pointer = new Memory(1024);
pointer.write(0, dataToCompress.getBytes(), 0,
dataToCompress.getBytes().length);
return pointer;
}
DWORD dwSourceSize - for this im getting reserved Memory size in this way:
String testData = "ABCDABCDABCDAAD";
Pointer source = setByteArrayPointer(testData);
(int) ((Memory)source).size()
BYTE** ppcCompressed - function should populate ppcCompressed reference after work is done. I assume I made a mistake there, by doing it in this way:
Pointer[] compressed = {new Pointer(1024), new Pointer(1024)};
DWORD* pdwCompressedSize - returned by function size of compressed data. I map it in this way:
IntByReference intByReference = new IntByReference();
Not sure if it is good idea aswell..
BOOL bEndOfData - i need to set it to true.
So finally my method call, which returns an error looks like this:
xceedApiDll.XcCompress(handle, source, (int) ((Memory)source).size(), compressed, intByReference, true);
Any help will be appreciated. Thank you.
I think i solved the issue (thanks for comments guys). Maybe for someone using this library it will be useful:
In the end the main problem was with handler declaration and the ppcCompressed value.
I used the following solution which works fine for me:
Method declarations inside java interface:
int XcCompress(Pointer hComp, byte[] pcSource, int dwSourceSize, PointerByReference ppcCompressed, IntByReference pdwCompressedSize, int bEndOfData);
int XcUncompress(Pointer hComp, byte[] pcSource, int dwSourceSize, PointerByReference ppcUncompressed, IntByReference pdwUncompressedSize, int bEndOfdata);
Usage:
private static final XceedFunctions XCEED_DLL_API;
static {
XCEED_DLL_API = Native.load("XceedZipX64", XceedFunctions.class);
}
private static final String TEST_DATA = "abcabcddd";
//Data pointers
private static Pointer compHandle;
private static byte[] baSource = TEST_DATA.getBytes();
private static PointerByReference pbrCompressed = new PointerByReference();
private static PointerByReference pbrUncompressed = new PointerByReference();
private static IntByReference ibrCompressedSize = new IntByReference();
private static IntByReference ibrUncompressedSize = new IntByReference();
public static void main(String[] args) {
try {
boolean isSuccessfulInit = XCEED_DLL_API.XceedZipInitDLL();
if(isSuccessfulInit) {
compHandle = XCEED_DLL_API.XcCreateXceedCompressionW(new WString("YOUR_LICENCE_KEY_HERE"));
int compressionResult = XCEED_DLL_API.XcCompress(compHandle, baSource, baSource.length, pbrCompressed, ibrCompressedSize, 1);
byte[] compressed = getDataFromPbr(pbrCompressed, ibrCompressedSize);
System.out.println("Compression result: " + compressionResult + " Data: " + new String(compressed));
int decompressionResult = XCEED_DLL_API.XcUncompress(compHandle, compressed, compressed.length, pbrUncompressed, ibrUncompressedSize, 1);
byte[] uncompressed = getDataFromPbr(pbrUncompressed, ibrUncompressedSize);
System.out.println("Decompression result: " + decompressionResult + " Data: " + new String(uncompressed));
}
} finally {
System.out.println("Free memory and shutdown");
if(compHandle != null) {
XCEED_DLL_API.XcDestroyXceedCompression(compHandle);
}
XCEED_DLL_API.XceedZipShutdownDLL();
}
}
private static byte[] getDataFromPbr(PointerByReference pbr, IntByReference ibr) {
return pbr.getValue().getByteArray(0, ibr.getValue());
}
Example output:
Compression result: 0 Data: KLJNLJNII yK
Decompression result: 0 Data: abcabcddd
Free memory and shutdown

ByteBuffer Missing Data When decoded As string

I'm reading and writing to a ByteBuffer
import org.assertj.core.api.Assertions;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder;
public class Solution{
public static void main(String[] args) throws Exception{
final CharsetEncoder messageEncoder = Charset.forName("ISO-8859-1").newEncoder();
String message = "TRANSACTION IGNORED";
String carrierName= "CARR00AB";
int messageLength = message.length()+carrierName.length()+8;
System.out.println(" --------Fill data---------");
ByteBuffer messageBuffer = ByteBuffer.allocate(4096);
messageBuffer.order(ByteOrder.BIG_ENDIAN);
messageBuffer.putInt(messageLength);
messageBuffer.put(messageEncoder.encode(CharBuffer.wrap(carrierName)));
messageBuffer.put(messageEncoder.encode(CharBuffer.wrap(message)));
messageBuffer.put((byte) 0x2b);
messageBuffer.flip();
System.out.println("------------Extract Data Approach 1--------");
CharsetDecoder messageDecoder = Charset.forName("ISO-8859-1").newDecoder();
int lengthField = messageBuffer.getInt();
System.out.println("lengthField="+lengthField);
int responseLength = lengthField - 12;
System.out.println("responseLength="+responseLength);
String messageDecoded= messageDecoder.decode(messageBuffer).toString();
System.out.println("messageDecoded="+messageDecoded);
String decodedCarrier = messageDecoded.substring(0, carrierName.length());
System.out.println("decodedCarrier="+ decodedCarrier);
String decodedBody = messageDecoded.substring(carrierName.length(), messageDecoded.length() - 1);
System.out.println("decodedBody="+decodedBody);
Assertions.assertThat(messageLength).isEqualTo(lengthField);
Assertions.assertThat(decodedBody).isEqualTo(message);
Assertions.assertThat(decodedBody).isEqualTo(message);
ByteBuffer messageBuffer2 = ByteBuffer.allocate(4096);
messageBuffer2.order(ByteOrder.BIG_ENDIAN);
messageBuffer2.putInt(messageLength);
messageBuffer2.put(messageEncoder.encode(CharBuffer.wrap(carrierName)));
messageBuffer2.put(messageEncoder.encode(CharBuffer.wrap(message)));
messageBuffer2.put((byte) 0x2b);
messageBuffer2.flip();
System.out.println("---------Extract Data Approach 2--------");
byte [] data = new byte[messageBuffer2.limit()];
messageBuffer2.get(data);
String dataString =new String(data, "ISO-8859-1");
System.out.println(dataString);
}
}
It works fine but then I thought to refactor it, Please see approach 2 in above code
byte [] data = new byte[messageBuffer.limit()];
messageBuffer.get(data);
String dataString =new String(data, "ISO-8859-1");
System.out.println(dataString);
Output= #CARR00ABTRANSACTION IGNORED+
Could you guys help me with explanation
why the integer is got missing in second approach while decoding ???
Is there any way to extract the integer in second approach??
Okay so you are trying to read an int from the Buffer which takes up 4 bits and then trying to get the whole data after reading 4 bits
What I have done is call messageBuffer2.clear(); after reading the int to resolve this issue. here is the full code
System.out.println(messageBuffer2.getInt());
byte[] data = new byte[messageBuffer2.limit()];
messageBuffer2.clear();
messageBuffer2.get(data);
String dataString = new String(data, StandardCharsets.ISO_8859_1);
System.out.println(dataString);
Output is:
35
#CARR0033TRANSACTION IGNORED+
Edit: So basically when you are calling clear it resets various variables and it also resets the position it's getting from and thats how it fixes it.

InvalidProtocolBufferException when sending data from Python to Java

I'd like to encode a protopuf in python and send it via redis to a java application where I decode it.
Atm I can print the data in the java app and the values are correct. But everytime I receive data I get the following exception:
InvalidProtocolBufferException: Protocol message end-group tag did not match expected tag
I tried it also with Jedis but the data was wrong there. Also tried to send it without the bytearray cast from python but I get the same error here.
Does anyone have an idea concerning this issue?
Code on python side:
tele_bytes = array("B")
// tele_bytes data comes from serial interface
tele_bytes[1] = ser.read()
tele_bytes[2] = ser.read()
raw_data = ''.join(chr(x) for x in [
tele_bytes[1],
tele_bytes[2]
])
gw_id = '12345678'
reading = Reading_raw_data_pb2.ReadingRaw()
reading.timestamp = int(time())
reading.gw_id = gw_id
reading.raw_data = raw_data
reading_string = reading.SerializeToString()
r_server.lpush("testID", bytearray(reading_string))
Code on Java Side:
import com.google.protobuf.InvalidProtocolBufferException;
import redis.clients.jedis.BinaryJedis;
import protos.Reading4Java;
import java.io.IOException;
import java.util.List;
public class SimpleSubByte {
public static Reading4Java.ReadingRaw trRaw = null;
public static void main(String[] args) {
BinaryJedis binaryJedis = new BinaryJedis("test.id.local");
while (true) {
List<byte[]> byteArray = binaryJedis.brpop(0, "testID".getBytes());
for (byte[] e : byteArray) {
// System.out.println(e);
try {
trRaw = Reading4Java.ReadingRaw.parseFrom(e);
} catch (InvalidProtocolBufferException e1) {
e1.printStackTrace();
}
System.out.println(trRaw);
}
}
}
}
Protobuf file python:
package ttm
message ReadingRaw {
required string gw_id = 1; // gateway id (e. g. mac address)
required bytes raw_data = 2; // raw data from serial interface
optional int64 timestamp = 3; // timestamp of data reading from sensor device
}
Protobuf File for java:
package protos;
option java_outer_classname = "TireReading4Java";
message TireReadingRaw {
required string gw_id = 1; // gateway id (e. g. mac address)
required bytes raw_data = 2;
optional int64 timestamp = 3;
}

Categories

Resources