Inject a function into a Java .class file using Ha

2019-03-27 11:22发布

I have written a Java bytecode parser using Haskell, and it works just fine. However the next step has me completely stumped.

My Haskell program needs to modify the .class file so that, when executed, the Java program prints:

"Entering [method name here]" before executing a method, and

"Exiting [method name here]" after executing a method.

All I know is that we will need to append the constant pool and method table with calls to System.out.println, but I feel I'm still missing something.

  • What is the best way to approach this problem?
  • How do you know how to call System.out.println in bytecode?
  • How do you store the string with the name of the method, to later be called as an argument of System.out.println?

4条回答
小情绪 Triste *
2楼-- · 2019-03-27 11:35

Just grab your Java bytecode listing and pop open a simple compiled class with a function call to just System.out.println() and take a peek. Do this for whatever methods you need. The best way to find this out is to do some investigation with some simple code files and reverse engineer as you go along. You'll have to translate the message you want into unicode and pass that into your function. Don't forget about that part as well. There are various programs that will help you on your quest to conquer the bytecode.

查看更多
萌系小妹纸
3楼-- · 2019-03-27 11:39

Well, this is what the various byte code engineering libraries give you. ASM, BCEL, etc. The specifics of your homework is an aspect, and AspectJ does precisely that.

Sounds like the homework is to write a Haskell byte code engineering exercise, so you will need to mod the class file yourself. Suggestion above by @biziclop is correct. Do a before and after on a class file, note the delta, and do the same yourself from Haskell.

[ps: of course, the above "short-cut" :P is if you don't feel like reading the JVM Spec (as noted in comment to your q) and figuring out how to do it as if you would if writing a Java compiler. You basically call a method by using one of the various byte codes for invoke -- here an interface method call --before which you need to have the receiver e.g. static field out of class System and the method name on the stack. Details in the spec.]

查看更多
Ridiculous、
4楼-- · 2019-03-27 11:48

Probably the easiest approach is to write a Java class that has a single method with a System.out.println() code in it, compile it with javac and observe the results.

Once you are familiar with it, proceed step by step.

  1. Add a System.out.println() call somewhere in the java file that you want to instrument. This takes care of the constant pool. Write the Haskell code that finds the relevant constants and injects the bytecode.
  2. Remove the "crutch" call from the java file and implement the constant pool manipulation in Haskell.
查看更多
SAY GOODBYE
5楼-- · 2019-03-27 11:49

I think the best way to approach this problem is to use the Javassist library (Java Programming Assistant). Javassist.bytecode class has some functions that might be useful.

查看更多
登录 后发表回答