- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我是字节码注入(inject)方面的新手。到目前为止,通过详尽的研究和痛苦的反复试验,我能够得到我想要的一切:-)但我似乎已经达到了目前追求的目标的极限。所以,这就是:我的第一个 stackoverflow 问题!
我的目标是通过 Java 代理跟踪方法调用的对象引用。我正在使用 ASM 4.0 库并实现了一个 AdviceAdapter。我重写的 visitMethodInsn() 方法如下所示:
/**
* Visits a method instruction. A method instruction is an instruction that invokes a method.
* The stack before INVOKEINTERFACE, INVOKESPECIAL and INVOKEVIRTUAL instructions is:
* "objectref, [arg1, arg2, ...]"
*
* @param opcode the opcode of the type instruction to be visited. This opcode is either INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC or INVOKEINTERFACE.
* @param owner the internal name of the method's owner class.
* @param name the method's name.
* @param desc the method's descriptor.
*/
@Override
public void visitMethodInsn(int opcode, String owner, String name, String desc) {
if (isExcluded()) {
super.visitMethodInsn(opcode, owner, name, desc);
return;
}
int arraySlot = -1;
boolean isStatic = false;
if (opcode == INVOKEVIRTUAL || opcode == INVOKEINTERFACE) {
arraySlot = saveMethodParameters(owner, desc);
super.visitMethodInsn(opcode, owner, name, desc);
} else if (opcode == INVOKESTATIC) {
isStatic = true;
super.visitMethodInsn(opcode, owner, name, desc);
} else if (opcode == INVOKESPECIAL && !owner.equals("java/lang/Object")) {
//TODO: Causes VerifyError
arraySlot = saveMethodParameters(owner, desc);
super.visitMethodInsn(opcode, owner, name, desc);
} else {
super.visitMethodInsn(opcode, owner, name, desc);
}
if (arraySlot > 0) {
loadLocal(arraySlot);
push(0);
arrayLoad(Type.getType(Object.class));
} else {
super.visitInsn(ACONST_NULL);
}
super.visitMethodInsn(INVOKESTATIC, "net/myjavaagent/MethodLogger",
"writeToLoggerTest", "(Ljava/lang/Object;)V");
}
/**
* Pops the method invocation' arguments and objectref off the stack, saves them into a local array variable and
* then puts them back on the stack again.
*
* @param owner owner class of the method
* @param desc method descriptor
* @return the identifier of the local variable containing the parameters.
*/
private int saveMethodParameters(String owner, String desc) {
JavaTracerAgent.agentErrorLogger.info("Save method parameters: " + owner + " " + desc);
// Preparing the array construction
Type objectType = Type.getType(Object.class);
Type objectArrayType = Type.getType("[Ljava/lang/Object;");
Type[] invokeParamTypes = getMethodParamTypes(owner, desc);
int invokeParamCount = invokeParamTypes.length;
// allocate a slot for the method parameters array
int arrayLocal = newLocal(objectArrayType);
// construct the object array
push(invokeParamCount);
newArray(objectType);
// store array in the local variable
storeLocal(arrayLocal);
// pop the arguments off the stack into the array
// note: the top one is the last parameter !
for (int i = invokeParamCount - 1; i >= 0; i--) {
Type type = invokeParamTypes[i];
JavaTracerAgent.agentErrorLogger.info("Get from stack [" + i + "]:" + type.toString());
if (type != null) {
// convert value to object if needed
box(type);
// load array and swap under value
loadLocal(arrayLocal);
swap(objectArrayType, objectType);
// load index and swap under value
push(i);
swap(Type.INT_TYPE, objectType);
} else {
// this is a static method and index is 0 so we put null into the array
// load array index and then null
loadLocal(arrayLocal);
push(i);
push((Type) null);
}
// store the value in the array as an object
arrayStore(objectType);
}
// now restore the stack and put back the arguments from the array in increasing order
for (int i = 0; i < invokeParamCount; i++) {
Type type = invokeParamTypes[i];
JavaTracerAgent.agentErrorLogger.info("Put to stack [" + i + "]:" + type.toString());
if (type != null) {
// load the array
loadLocal(arrayLocal);
//retrieve the object at index i
push(i);
arrayLoad(objectType);
//unbox if needed
unbox(type);
} else {
// this is a static method so no target instance has to be put on stack
}
}
return arrayLocal;
}
/**
* Returns a type array containing the parameters of a method invocation:
* <ul><li>owner type</li><li>arg1 type</li><li>arg2 type</li><li>...</li><li>argN type</li></ul>
*
* @param owner owner class
* @param desc method descriptor
* @return method parameter types
*/
public Type[] getMethodParamTypes(String owner, String desc) {
Type ownerType = Type.getObjectType(owner);
Type[] argTypes = Type.getArgumentTypes(desc);
int numArgs = argTypes.length;
Type[] result = new Type[numArgs + 1];
result[0] = ownerType;
System.arraycopy(argTypes, 0, result, 1, numArgs);
return result;
}
简而言之,我试图在执行 INVOKESOMETHING 操作之前将堆栈中的所有内容保存到局部变量中。为了能够执行方法操作,我必须将所有内容放回堆栈。之后我假设被调用对象的引用是我本地数组中的第一个条目。
下面是我的一个测试类。这个非常简单:它只是启动另一个线程:
/**
* My test class.
*/
public class ThreadStarter {
public static void main(String args[]) {
Thread thread = new Thread("Hugo") {
@Override
public void run() {
System.out.println("Hello World");
}
};
thread.start();
}
}
关于 INVOKEVIRTUAL、INVOKEINTERFACE 和 INVOKESTATIC,我没有遇到任何问题。一切似乎都很好,日志输出正是我所期望的。但是,INVOKESPECIAL 指令似乎有问题。我在这里遇到了一个丑陋的 VerifyError,所以我想我处理堆栈的方式一定有问题。
Exception in thread "main" java.lang.VerifyError: (class: net/petafuel/qualicore/examples/ThreadStarter, method: main signature: ([Ljava/lang/String;)V) Expecting to find object/array on stack
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:171)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:113)
使用“-noverify”启动测试类会使 VerifyError 消失。一切似乎都很完美,我得到了想要的输出。我可以就这样离开,但实际上整个问题让我很痛苦,让我睡得很不好 ;-)
如果我的理解是正确的,像“new Thread()”这样的语句就变成了
NEW java/lang/Thread
DUP
INVOKESPECIAL <init>
在字节码中。会不会是新创建的对象在调用构造函数之前还未初始化的问题?
我不明白为什么代码可以正常工作,但 JVM 在验证过程中会报错。
即使在检测后查看反编译代码也无济于事:
// Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://www.kpdus.com/jad.html
// Decompiler options: packimports(3)
// Source File Name: ThreadStarter.java
public class ThreadStarter
{
public ThreadStarter()
{
MethodLogger.writeToLoggerTest(null);
}
public static void main(String args[])
{
JVM INSTR new #2 <Class ThreadStarter$1>;
JVM INSTR dup ;
"Hugo";
Object aobj[] = new Object[2];
aobj;
JVM INSTR swap ;
1;
JVM INSTR swap ;
JVM INSTR aastore ;
aobj;
JVM INSTR swap ;
0;
JVM INSTR swap ;
JVM INSTR aastore ;
((_cls1)aobj[0])._cls1((String)aobj[1]);
MethodLogger.writeToLoggerTest(aobj[0]);
Thread thread;
thread;
thread;
Object aobj1[] = new Object[1];
aobj1;
JVM INSTR swap ;
0;
JVM INSTR swap ;
JVM INSTR aastore ;
((Thread)aobj1[0]).start();
MethodLogger.writeToLoggerTest(aobj1[0]);
return;
}
}
一些附加信息:我正在使用 IntelliJ IDEA 10.5.4 进行开发并使用 jdk1.6.0_39。
最后,我希望这里有人可以帮助我获得必要的见解。提前致谢!
最佳答案
我知道有两个原因可能会在 INVOKESPECIAL
被关注时产生这个错误:
您正在尝试对无法验证为未初始化的引用调用构造函数(INVOKESPECIAL
的第一个参数 必须 是未初始化的引用)。
您正试图将未初始化的引用传递到需要初始化引用的地方(作为方法调用、AASTORE 操作等的参数)。
粗略地看一下您的代码表明您可能在方法参数数组中存储了一个未初始化的引用。
关于带有 ASM : VerifyError on code injection at INVOKESPECIAL instructions 的 Java 字节码检测,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16358460/
code
正常吗?
我刚刚开始使用 YARD 来记录我的 Rails 应用程序。我没有指定任何特定的标记处理程序,但我希望 `code` 会转换为 code,但这似乎没有发生。这是正常行为吗?我是否必须添加一些额外的选项
什么是Code-Server 首先程序员朋友们肯定都用过来自微软的VS Code 这款轻量而又高级的编辑器,拥有丰富的插件库,支持各种语言编译运行。而本文介绍的Code-Server就是coder 公
我是一名高中生,今年开始学习汇编。 我目前正在制作 Pacman 克隆作为我的最终项目。 我遇到的唯一问题是我的代码很大,*.exe 文件几乎有 64KB。 所以我的问题是,如果我转向模型介质,我需要
锁定。这个问题及其答案是locked因为这个问题是题外话,但具有历史意义。它目前不接受新的答案或互动。 挑战 按字符计数绘制 Code 39 条码的 ASCII 表示的最短代码。 维基百科关于代码 3
我正在开发 VS 代码的扩展(使用 javascript)。现在我需要安装 VS Code 的路径。 windows有一种方法: var child = require('child_process'
[Windows 10] 我在自定义目录中安装了“Microsoft VS Code(用户设置)”,每当我尝试更新它时,都会显示: 然后这个 Log Info Dec 23 11:42:40.673
我正在尝试更新我的 VS 代码,但收到一条错误消息:由于防病毒软件和/或进程失控,更新可能会失败。 附加了一个来 self 的用户的日志文件,但我不确定要检查什么。我对计算机和编程还是个新手。 最佳答
几天前我安装了 Kali Linux。我正在尝试使用 Code-OSS 而不是 VSCode,因为最新版本的 Kali 没有安装普通版本所需的库。 如果我尝试使用 code-oss . 或 code
我正在从 Atom 迁移到 VS Code,因为这似乎是当今所有酷 child 都在使用的东西。 在 atom 中,我能够如图所示突出显示当前行号(装订线中的蓝色突出显示)。 有没有办法在 VS Co
我试图找到一个明确的 G 代码语法规范,而不是单个 G 代码的含义,我无处不在的规范,我的意思是详细的语法规范,目的是编写解析器。 我编写解析器没有问题,我只是在寻找语法规范,例如。我知道您不必总是为
我想在 VS Code (Windows) 中使用 Fira Code,并且已经按照 instructions 中的说明配置了字体。 。不知何故,字体看起来很模糊。我该如何解决这个问题? "edito
这个问题已经有答案了: How can I navigate back to the last cursor position in Visual Studio Code? (16 个回答) 已关闭
如何选择当前单词,即插入符号所在的位置。 注意:我正在寻找 Visual Studio Code(VS Code)(文本编辑器)的快捷方式,而不是 Visual Studio IDE。 最佳答案 在
我需要在 VS Code 中安装 flutter 但在安装扩展中,我有这个错误 Unable to install 'Dart-Code.flutter'; there is no available
memberData
有什么区别
{@code memberData} 和有什么区别?和 memberData在 JavaDoc 中 最佳答案 有两个主要区别: {@code ...}更简洁:更易于阅读(和输入)。 {@code ..
我有这样一个字符串: Here is my code sample, its not too great: [CODE] [/CODE] I hope you enjoy. 现在我想用 highli
在 VS Code 中,我有一个少于 50 个文件的 Vue 项目,但是在运行开发服务器时 VS Code 抛出 Error: ENOSPC: System limit for number of f
Source Code Pro 如何在 VSC 中使用 ExtraLight ~? 似乎以下不起作用...... 我确定我有字体。 Source Code Pro ExtraLight 最佳答案 编辑
我对 Visual Studio Code 很陌生。我正在尝试调试一个已经存在的应用程序,我已经通过 Git 克隆了它。我的文件都没有被修改。我已经下载了微软扩展“C# for Visual Stud
Visual Code VS Visual Studio Code Insider 我还是不明白这两者有什么区别,难道其中一个是新功能的试用版吗? 最佳答案 Visual Studio Code In
我是一名优秀的程序员,十分优秀!