gpt4 book ai didi

java - 如何在 64 位应用程序中以 32 位模式使用 BridJ?

转载 作者:太空宇宙 更新时间:2023-11-04 10:33:47 25 4
gpt4 key购买 nike

我正在尝试以某种方式使用 BridJ,但不确定它是否受支持:

我有一个 64 位应用程序。我通过调试器接口(interface)获取包含 32 位应用程序内存的字节数组。

我想使用 BridJ 将此字节数组的内容解析为 C 数据类型。我通过使用 Pointer.pointerToBytes().as(my_struct.class).get() 来完成此操作。该技术适用于 32 位应用程序。但在 64 位应用程序中则不然,因为 BridJ 使用主机应用程序的字大小(64 位),而我想使用字节数组的字大小(32 位)。

这可以吗?是否可以以某种方式手动切换 BridJ 的字大小,以便 BridJ 使用 32 位字,即使它在 64 位应用程序中运行?

我正在尝试做的事情的更长示例

byte[] objData = debugger.readMemory(remoteStructAddr, BridJ.sizeOf(c_struct.class));
// pointerToBytes only works as expected when objData has the same
// word size as the host system
c_struct s = Pointer.pointerToBytes(objData).as(c_struct.class).get();
int structMem = s.member();

// offsetOfField only works as expected when objData has the same
// word size as the host system
byte[] namePtr = debugger.readMemory(removePtr + StructObject.offsetOfField(new c_struct(), "name"), 4);
String name = debugger.readString(namePtr);

更多详细信息

  • 我使用JNAerator生成 BridJ 类
  • 我尝试使用 JNAerator -arch 标志,但它似乎没有达到我想要的效果。
  • 我不将 native 库与 BridJ 一起使用,我只是使用 BridJ 读取通过调试器 API 获取的字节数组。

最佳答案

我通过编写自己的代码来解决这个问题,用于将具有 C 结构的字节数组读取到 Java 对象中。此代码是针对 32 位输入编写的,无论主机应用程序使用的字大小如何。

示例:

some_struct s = Bridj32.readObject(some_struct.class, 
new byte[] { 0x01, 0x23, 0x45, 0x67 });

Bridj32 类包含此方法的实现。它采用用 BridJ 注释(FieldStructPtr 等)和带有数据的字节数组作为输入类。给出包含输入数组数据的已解析 Java 对象作为输出。

Bridj32 最棘手的部分是它实现了 C 结构打包算法。

Bridj32的代码:

import static java.util.stream.Collectors.toMap;

import java.lang.reflect.Method;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.NoSuchElementException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Stream;

import org.bridj.BridJ;
import org.bridj.Pointer;
import org.bridj.SizeT;
import org.bridj.StructIO;
import org.bridj.StructObject;
import org.bridj.ann.Array;
import org.bridj.ann.Bits;
import org.bridj.ann.Field;
import org.bridj.ann.Ptr;
import org.bridj.ann.Struct;

import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.common.primitives.Primitives;

/**
* Code for using {@link BridJ} in 32 bit mode, even in a 64 bit application.
* Reads byte arrays into objects, gets offset of fields and gets the size of structs.
* <p>
* Assumes little-endian byte order for all input.
* <p>
* Input struct types must be annotated with BridJ annotations, as if they where generated
* with Jnaerator.
*/
public class Bridj32 {
private static final Map<Class<?>, StructDescription> structCache = new ConcurrentHashMap<>();

private static class StructDescription {
public final int byteSize;
public final int largestMemberSize;
public final List<MemberDescription> members;
@SuppressWarnings("unused")
public final Class<? extends StructObject> structClass;

public StructDescription(Class<? extends StructObject> structClass) {
this.structClass = structClass;

Map<Integer, Method> memMap = structFieldMethods(structClass)
.collect(toMap(m -> m.getAnnotation(Field.class).value(), e -> e));

Struct structAnn = structClass.getAnnotation(Struct.class);
if (structAnn != null && structAnn.pack() > 1) {
throw new UnsupportedOperationException("Packed structs are not supported. Struct: " + structClass);
}

ImmutableList.Builder<MemberDescription> mems = ImmutableList.builder();

int offset = 0;
int maxLargestMem = 0;

for (Entry<Integer, Method> e : memMap.entrySet()) {
Method memberMethod = e.getValue();

int alignSize = alignSize(memberMethod);
maxLargestMem = Math.max(maxLargestMem, alignSize);
int size = calcByteSize(memberMethod);
offset += alignPadSize(offset, alignSize);

mems.add(new MemberDescription(memberMethod, e.getKey(), offset, size));

offset += size;
}

largestMemberSize = maxLargestMem;

members = mems.build();
byteSize = offset;
}

public MemberDescription findMember(String memName) {
for (MemberDescription desc : members) {
if (desc.method.getName().equals(memName)) {
return desc;
}
}
throw new NoSuchElementException(memName);
}

}

static int alignPadSize(int size, int alignment) {
int p = size % alignment;
if (p == 0) return 0;
else return alignment - p;
}

private static class MemberDescription {
Method method;
int index;
int byteOffset;
@SuppressWarnings("unused")
int byteSize;

public MemberDescription(Method method, int index, int byteOffset, int byteSize) {
this.method = method;
this.index = index;
this.byteOffset = byteOffset;
this.byteSize = byteSize;
}

public Class<?> getType() {
return method.getReturnType();
}
}


/**
* @return The size of the C struct that corresponds to the input class
* argument. This size includes trailing padding in the struct.
*/
public static int paddedSizeOf(Class<?> cls) {
StructDescription desc = getStructDescription(cls);
return desc.byteSize + alignPadSize(desc.byteSize, desc.largestMemberSize);
}

private static Stream<Method> structFieldMethods(Class<? extends StructObject> structClass) {
return Arrays.stream(structClass.getMethods())
.filter(m -> m.getAnnotation(Field.class) != null)
.filter(m -> m.getParameterCount() == 0);
}

private static StructDescription getStructDescription(Class<?> cls) {
StructDescription result = structCache.get(cls);
if (result == null) {
@SuppressWarnings("unchecked")
Class<? extends StructObject> structCls = (Class<? extends StructObject>) cls;
result = new StructDescription(structCls);
structCache.put(cls, result);
}
return result;
}

@SuppressWarnings("unused")
private static int nrFields(Class<? extends StructObject> structClass) {
int maxFieldNr = -1;
for (Method f : structClass.getMethods()) {
Field fieldAnn = f.getAnnotation(Field.class);
if (fieldAnn != null) {
maxFieldNr = Math.max(maxFieldNr, fieldAnn.value());
}
}
return maxFieldNr + 1;
}

/**
* @return The size of the C struct that corresponds to the input class
* argument. This size does not include trailing padding
* in the struct.
*/
public static int sizeOf(Class<? extends StructObject> structClass) {
return getStructDescription(structClass).byteSize;
}

private static int calcByteSize(Method memMeth) {
Array arrayAnn = memMeth.getAnnotation(Array.class);
int mult = arrayAnn == null
? 1 : (int) Arrays.stream(arrayAnn.value()).reduce(1, (a, b) -> a * b);

int sizeSingle = calcByteSizeSingle(memMeth);

return mult * sizeSingle;
}

private static int alignSize(Method memMeth) {
if (StructObject.class.isAssignableFrom(memMeth.getReturnType())) {
return getStructDescription(memMeth.getReturnType()).largestMemberSize;
} else {
return primitiveByteSize(memMeth);
}
}

private static int primitiveByteSize(Method memMeth) {
Class<?> cls = Primitives.wrap(memMeth.getReturnType());

if (memMeth.getAnnotation(Ptr.class) != null) return 4;

if (memMeth.getAnnotation(Bits.class) != null) {
throw new UnsupportedOperationException("Bit fields are not supported. Method: " + memMeth);
}

if (cls == Boolean.class) return 1;
if (cls == Byte.class ) return 1;
if (cls == Short.class ) return 2;
if (cls == Integer.class) return 4;
if (cls == Long.class ) return 8;
if (cls == Float.class ) return 4;
if (cls == Double.class ) return 8;

if (cls == String.class ) return 4;

if (cls == Pointer.class) return 4;
if (cls == SizeT.class ) return 4;

throw new IllegalArgumentException("Unknown type: " + cls);
}

private static int calcByteSizeSingle(Method memMeth) {
Class<?> cls = memMeth.getReturnType();
if (StructObject.class.isAssignableFrom(cls)) {
return paddedSizeOf(cls);
} else {
return primitiveByteSize(memMeth);
}
}

/**
* Reads one object (and all its members) from the bytes array.
*/
public static <T extends StructObject> T readObject(Class<T> structClass, byte[] bytes) {
ByteBuffer buff = ByteBuffer.wrap(bytes, 0, bytes.length).order(ByteOrder.LITTLE_ENDIAN);
return readObject(structClass, buff, 0);
}

private static <T extends StructObject> T readObject(Class<T> structClass, ByteBuffer buff, int offset) {
StructDescription desc = getStructDescription(structClass);
Preconditions.checkArgument(buff.capacity() - offset >= desc.byteSize);
StructIO io = StructIO.getInstance(structClass);

T struct;
try {
struct = structClass.getConstructor().newInstance();
} catch (ReflectiveOperationException exc) {
throw new RuntimeException(exc);
}

for (MemberDescription memDesc : desc.members) {
setField(memDesc, struct, io, buff, offset);
}

return struct;
}

public static int offsetOfField(Class<? extends StructObject> structClass, String memName) {
return getStructDescription(structClass).findMember(memName).byteOffset;
}

private static void setField(MemberDescription desc, StructObject struct, StructIO io, ByteBuffer bytes, int structOffset) {
Class<?> cls = Primitives.wrap(desc.getType());
int offset = desc.byteOffset + structOffset;
int ix = desc.index;

if (cls == Boolean.class) io.setBooleanField(struct, ix, bytes.get(offset) != 0);
else if (cls == Byte.class ) io.setByteField (struct, ix, bytes.get(offset));
else if (cls == Short.class ) io.setShortField (struct, ix, bytes.getShort(offset));
else if (cls == Integer.class) io.setIntField (struct, ix, bytes.getInt(offset));
else if (cls == Long.class ) io.setLongField (struct, ix, bytes.getLong(offset));
else if (cls == Float.class ) io.setFloatField (struct, ix, bytes.getFloat(offset));
else if (cls == Double.class ) io.setDoubleField (struct, ix, bytes.getDouble(offset));

else if (cls == String.class) throw new UnsupportedOperationException();

else if (SizeT.class.isAssignableFrom(cls)) {
io.setSizeTField(struct, offset, Integer.toUnsignedLong(bytes.getInt(offset)));
} else if (Pointer.class.isAssignableFrom(cls)) {
@SuppressWarnings("deprecation")
Pointer<?> p = Pointer.pointerToAddress(Integer.toUnsignedLong(bytes.getInt(offset)));
io.setPointerField(struct, ix, p);
} else if (StructObject.class.isAssignableFrom(cls)) {
@SuppressWarnings("unchecked")
StructObject o = readObject((Class<? extends StructObject>) cls, bytes, offset);
io.setNativeObjectField(struct, ix, o);
}
}

/**
* Reads all objects of type objCls form arrData and returns them. The number of objects
* depend on the binary size of objCls objects.
* <p>
* If the size of arrData is not evenly devisible by the size of objCls
*
*/
public static <T extends StructObject> List<T> readAllObjects(Class<T> objCls, byte[] arrData) {
int strideSize = paddedSizeOf(objCls);
List<T> result = new ArrayList<>();
ByteBuffer buff = ByteBuffer.wrap(arrData).order(ByteOrder.LITTLE_ENDIAN);

for (int offset = 0; offset < arrData.length; offset += strideSize) {
result.add(readObject(objCls, buff, offset));
}
return result;
}
}

关于java - 如何在 64 位应用程序中以 32 位模式使用 BridJ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49706267/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com