使用 Javassist 获取 class 中已声明字段的索引以用于字节码
Get index of declared field in class using Javassist for use in bytecode
我想使用字节码检测来访问我已添加到 class 的整数数组字段。为此,我需要 class 文件中字段的索引,但找不到它。
为了更详细地解释,而不是(期望是声明的局部整数,我从局部变量 table 中获取其索引):
desired = Server.rand.nextInt(4);
我想做:
desired = _MyField[Server.rand.nextInt(_MyField.length)];
在 JASM 中是:
// field reference to later access an index in the array
aload <local variable index of "this"> (push reference of class)
getfield <fieldindex> (pop reference, push field reference to stack)
// rand is a public static field in class Server
getstatic java.util.Random com.wurmonline.server.Server.rand
// field reference to pass to arraylength and the Random.nextInt(int) call
aload <local variable index of "this">
getfield <fieldindex> (push reference of array)
arraylength (pop reference, push array.length value)
invokevirtual int java.util.Random.nextInt(int) (pop length for rng, push index)
iaload (pop index, push integer value from array index)
istore <index of local variable "desired"> (pop value, store in variable)
字段是使用 Javassist 添加的,如果 sb 是包含字段初始化程序的 StringBuilder(例如 "new int[] { n, n, n, n, n };"):
ctClass.addField(
new CtField(
HookManager.getInstance().getClassPool().get("[I"),
"_OtherServerMissions",
ctClass),
sb.toString());
使用 DirtyJOE 查看 class 文件,DirtyJOE 是一种字节码编辑器,适用于 Java8/Major class 文件版本 52,我找不到字段的索引值。我似乎也找不到使用 CtField 或适用的 AttributeInfo 的。
for (CtField ctField : ctClass.getDeclaredFields())
所以我想知道从哪里获取字段索引。
我希望对于熟悉此事的可怜人来说,解释足够清楚。
有时它确实有助于以一种向其他人解释的方式写出问题。
传递给 GETFIELD 操作码的 FIELDINDEX 是对 class 常量池的引用。您必须将 FieldrefInfo 添加到 class' 常量池。 addFieldrefInfo()的return值是它在常量池中的索引
ConstPool constPool = ctClass.getClassFile().getConstPool();
[...]
sb = new StringBuilder();
sb.append("new int[] { ");
for (int i : _OtherServerMissions)
sb.append(String.format("%d,", i));
sb.deleteCharAt(sb.lastIndexOf(","));
sb.append(" };");
ctClass.addField(
new CtField(
HookManager.getInstance().getClassPool().get("[I"),
"_OtherServerMissions",
ctClass),
sb.toString());
int otherFieldIndex = constPool.addFieldrefInfo(constPool.getThisClassInfo(), "_OtherServerMissions", "[I");
logger.log(Level.INFO, "Added OtherFieldIndex as " + otherFieldIndex);
您还必须确定 "this" 的索引,以便在使用 GETFIELD 之前将 class 实例(如果适用)的引用推送到堆栈上。
int thisIndex = -1;
LocalVariableAttribute lva = (LocalVariableAttribute)generateMission
.getMethodInfo()
.getCodeAttribute()
.getAttribute(LocalVariableAttribute.tag);
for (int i = 0; thisIndex < 0 && i < lva.tableLength(); i++) {
if (lva.variableName(i).equals("this"))
thisIndex = lva.index(i);
}
如果它不在局部变量table中,我现在不知道如何添加它。或者一般如何准确地添加到局部变量 table 。如果您知道,请随时发表评论(如果您有足够的代表点数,呃...)。
固定问题现在包含与此处列出的值一起使用的正确 java 汇编代码。
我想使用字节码检测来访问我已添加到 class 的整数数组字段。为此,我需要 class 文件中字段的索引,但找不到它。
为了更详细地解释,而不是(期望是声明的局部整数,我从局部变量 table 中获取其索引):
desired = Server.rand.nextInt(4);
我想做:
desired = _MyField[Server.rand.nextInt(_MyField.length)];
在 JASM 中是:
// field reference to later access an index in the array
aload <local variable index of "this"> (push reference of class)
getfield <fieldindex> (pop reference, push field reference to stack)
// rand is a public static field in class Server
getstatic java.util.Random com.wurmonline.server.Server.rand
// field reference to pass to arraylength and the Random.nextInt(int) call
aload <local variable index of "this">
getfield <fieldindex> (push reference of array)
arraylength (pop reference, push array.length value)
invokevirtual int java.util.Random.nextInt(int) (pop length for rng, push index)
iaload (pop index, push integer value from array index)
istore <index of local variable "desired"> (pop value, store in variable)
字段是使用 Javassist 添加的,如果 sb 是包含字段初始化程序的 StringBuilder(例如 "new int[] { n, n, n, n, n };"):
ctClass.addField(
new CtField(
HookManager.getInstance().getClassPool().get("[I"),
"_OtherServerMissions",
ctClass),
sb.toString());
使用 DirtyJOE 查看 class 文件,DirtyJOE 是一种字节码编辑器,适用于 Java8/Major class 文件版本 52,我找不到字段的索引值。我似乎也找不到使用 CtField 或适用的 AttributeInfo 的。
for (CtField ctField : ctClass.getDeclaredFields())
所以我想知道从哪里获取字段索引。
我希望对于熟悉此事的可怜人来说,解释足够清楚。
有时它确实有助于以一种向其他人解释的方式写出问题。
传递给 GETFIELD 操作码的 FIELDINDEX 是对 class 常量池的引用。您必须将 FieldrefInfo 添加到 class' 常量池。 addFieldrefInfo()的return值是它在常量池中的索引
ConstPool constPool = ctClass.getClassFile().getConstPool();
[...]
sb = new StringBuilder();
sb.append("new int[] { ");
for (int i : _OtherServerMissions)
sb.append(String.format("%d,", i));
sb.deleteCharAt(sb.lastIndexOf(","));
sb.append(" };");
ctClass.addField(
new CtField(
HookManager.getInstance().getClassPool().get("[I"),
"_OtherServerMissions",
ctClass),
sb.toString());
int otherFieldIndex = constPool.addFieldrefInfo(constPool.getThisClassInfo(), "_OtherServerMissions", "[I");
logger.log(Level.INFO, "Added OtherFieldIndex as " + otherFieldIndex);
您还必须确定 "this" 的索引,以便在使用 GETFIELD 之前将 class 实例(如果适用)的引用推送到堆栈上。
int thisIndex = -1;
LocalVariableAttribute lva = (LocalVariableAttribute)generateMission
.getMethodInfo()
.getCodeAttribute()
.getAttribute(LocalVariableAttribute.tag);
for (int i = 0; thisIndex < 0 && i < lva.tableLength(); i++) {
if (lva.variableName(i).equals("this"))
thisIndex = lva.index(i);
}
如果它不在局部变量table中,我现在不知道如何添加它。或者一般如何准确地添加到局部变量 table 。如果您知道,请随时发表评论(如果您有足够的代表点数,呃...)。
固定问题现在包含与此处列出的值一起使用的正确 java 汇编代码。