I am trying to generate a method named hello that returns the value 2 using dynamic bytecode generation. This is my current code. To generate the method.
dout.writeShort(Modifier.PUBLIC);//class modifier
dout.writeShort(classConstant("test"));//class name
dout.writeShort(classConstant(Object.class.getName()));//superclass
dout.writeShort(0);//interface count
dout.writeShort(0);//field count
dout.writeShort(1);//method count
dout.writeShort(Modifier.PUBLIC|Modifier.STATIC);//modifiers
dout.writeShort(utfConstant("test"));//name
dout.writeShort(utfConstant(methodDescriptor(int.class, new Class[]{})));//descriptor
dout.writeShort(1);//attribute count
dout.writeShort(utfConstant("Code"));//attribute name
dout.writeInt(34);//attribute length
dout.writeShort(1);//max stack
dout.writeShort(0);//max locals
dout.writeInt(2);//code length
dout.writeByte(0x05);//iconst_2 opcode
dout.writeByte(0xAC);//ireturn opcode
dout.writeShort(0);//exception count
dout.writeShort(0);//attribute count
dout.writeShort(0);//class attributes
The problem is that when i run this code, i get this exception
Exception in thread "main" java.lang.ClassFormatError: Invalid method Code length 0 in class file test
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:791)
at java.lang.ClassLoader.defineClass(ClassLoader.java:634)
at Bytecode.BytecodeTest$BytecodeClassLoader.buildClass(BytecodeTest.java:229)
at Bytecode.BytecodeTest.makeClass(BytecodeTest.java:42)
at Bytecode.BytecodeTest.buildClass(BytecodeTest.java:27)
at Bytecode.BytecodeTest.main(BytecodeTest.java:19)
The weird thing is i am making the code length greater than 0 i am making it 2. I went back through the oracle specification but it still looks right. I have a feeling that i am writing some of the data as the wrong type, but i still cant find a problem.
An undocumented feature of the Hotspot verifier is that for versions <= 45.2, it uses shorter field lengths for some of the fields in the code attribute. That's why changing the version to 49 fixed everything.
If you use Krakatau, it will automatically take care of this, but I haven't seen any other tools that handle this case.
Luckily, the first stable public version of Java was 45.3, so you are unlikely to see legitimate code like this in the wild. But it is a neat trick for foiling reverse engineers.
Well, one thing that strikes me is the attribute length: by my count, it should be 14 (not 34). You also seem to be missing the class attribute count.
It would probably help you to define a couple helper methods for writing attributes, to ensure that you are computing and writing the length correctly, e.g., something like this:
private int writeAttribute(final String attributeName) {
dout.putShort(utfConstant(attributeName));
dout.putInt(0);
return dout.position();
}
private void endAttribute(final int attributeStart) {
dout.putInt(attributeStart- 4, dout.position() - attributeStart);
}
private void writeCode() {
final int codeAttributeStart = writeAttribute("Code");
dout.writeShort(1);//max stack
dout.writeShort(0);//max locals
dout.writeInt(2);//code length
dout.writeByte(0x05);//iconst_2 opcode
dout.writeByte(0xAC);//ireturn opcode
dout.writeShort(0);//exception count
dout.writeShort(0);//attribute count
endAttribute(codeAttributeStart);
}
Also, make sure the classfile minor/major version you're writing out matches the specification you're following--the format does change from time to time :).
Related
I'm using Xtext to generate a parser for my language. But after the java files are generated, i am getting errors :"The code for the static initializer is exceeding the 65535 bytes limit" in my lexer classes.
I found out it's due to one String Array being 13k lines long.
The code is automatically generated so I have no real control about how that array is used.
I tried moving it into a separate class, but the Array itself is too big for the 65k limit.
package com.intercope.analysis1.parser.antlr.internal;
public class ExternalArrays {
static final String[] DFA28_transitionS = {" {
"\11\76\2\75\2\76\1\75\22\76\1\75\1\10\1\73\1\65\3\76\1\74\1\43\1\44\1\61\1\57\1\45\1\60\1\76\1\46\2\70\1\64\2\70\1\66\1\67\3\70\1\76\1\36\1\6\1\5\1\7\2\76\1\3\1\52\1\16\1\20\1\24\1\31\1\37\1\72\1\34\2\72\1\25\1\23\1\22\1\1\1\14\1\72\1\21\1\27\1\32\1\12\1\63\1\41\3\72\3\76\1\71\1\72\1\76\1\4\1\51\1\15\1\17\1\56\1\30\1\40\1\72\1\33\2\72\1\50\1\53\1\72\1\2\1\13\1\72\1\35\1\26\1\47\1\11\1\62\1\42\3\72\1\54\1\76\1\55\uff82\76",
"\1\103\2\uffff\1\101\1\uffff\1\77\1\102\3\uffff\1\100", ...};
}
Since these are values depending on my lexer grammar I cant generate them using a function.
Any suggestions on how I can fix this is appreciated ^^
Edit: An excerpt from the array:
"\1\u0310\1\uffff\1\u0313\7\uffff\1\u0312\1\uffff\1\u030f\2\uffff\1\u0311",
"\1\u0314",
"\1\u0315",
"\1\u0316",
"\1\u0317",
"\1\u0318",
"\1\u0319",
"\12\104\7\uffff\32\104\4\uffff\1\104\1\uffff\32\104",
"\1\u031b",
"\12\104\7\uffff\32\104\4\uffff\1\104\1\uffff\32\104",
"\12\104\7\uffff\32\104\4\uffff\1\104\1\uffff\32\104",
"\1\u031e",
"\1\u031f",
"\1\u0320",
"\1\u0321",
"\1\u0322",
"\12\104\7\uffff\32\104\4\uffff\1\104\1\uffff\32\104",
"\1\u0324",
"\12\104\7\uffff\32\104\4\uffff\1\u0325\1\uffff\32\104",
"\12\104\7\uffff\32\104\4\uffff\1\104\1\uffff\32\104",
"\1\u0328",
"\1\u032c\1\uffff\1\u032b\12\uffff\1\u0329\2\uffff\1\u032a\1\uffff\1\u032d",
"\1\u032e",
"\1\u032f",
"\1\u0330",
"\1\u0331",
"\1\u0332",
"\1\u0333",
"\1\u0334",
"\1\u0335",
"\1\u0336",
I need to add four variables in JMeter and store them in another variable that I will be using for a later request (to be stored in the variable finalScore. I have a BeanShell PreProcessor with the following code:
overallScore = ${__intSum(${score1}, ${score2}, ${score3}, ${score4}, finalScore)};
In executing, I keep getting the following error:
2015/10/16 14:05:05 ERROR - jmeter.JMeter:
Uncaught exception: java.lang.NumberFormatException:
For input string: "${score1}"
Any ideas on what is wrong and how to resolve?
It looks like your ${score1} variable is not defined
You need to remove spaces from __intSum() function, correct syntax is
${__intSum(${score1},${score2},${score3},${score4},finalScore)}
You don't need Beanshell as sum of score1-4 will be stored as ${finalScore}
If you need to have a sum of score1-4 and finalScore - amend your function as:
${__intSum(${score1},${score2},${score3},${score4},${finalScore},overallScore)}
References:
__intSum() user manual chapter
How to Use JMeter Functions - Part III which provides several use cases for __intSum() function
${__intSum(1,5,)} - will return 6
${__intSum(1,5,8)} - will return 14
${__intSum(1,5,8,SUM)} - will return 14 and store it to SUM variable
${__intSum(10,-5)} - will return 5
${__intSum(${A},${B})} - will return an evaluation of A and B variables integer representation sum, which can be handy for Counter value processing.
and extra information on the others.
I am trying bcel to modify a method by inserting invoke before specific instructions.
It seems that my instrumentation would result in a different stackmap table, which can not be auto-generated by the bcel package itself.
So, my instrumented class file contains the old stackmap table, which would cause error with jvm.
I haved tried with removeCodeAttributes, the method of MethodGen, that can remove all the code attributes. It can work in simple cases, a wrapped function, for example. And it can not work in my case now.
public class Insert{
public static void main(String[] args) throws ClassFormatException, IOException{
Insert isrt = new Insert();
String className = "StringBuilder.class";
JavaClass jclzz = new ClassParser(className).parse();
ClassGen cgen = new ClassGen(jclzz);
ConstantPoolGen cpgen = cgen.getConstantPool();
MethodGen mgen = new MethodGen(jclzz.getMethods()[1], className, cpgen);
InstructionFactory ifac = new InstructionFactory(cgen);
InstructionList ilist = mgen.getInstructionList();
for (InstructionHandle ihandle : ilist.getInstructionHandles()){
System.out.println(ihandle.toString());
}
InstructionFinder f = new InstructionFinder(ilist);
InstructionHandle[] insert_pos = (InstructionHandle[])(f.search("invokevirtual").next());
Instruction inserted_inst = ifac.createInvoke("java.lang.System", "currentTimeMillis", Type.LONG, Type.NO_ARGS, Constants.INVOKESTATIC);
System.out.println(inserted_inst.toString());
ilist.insert(insert_pos[0], inserted_inst);
mgen.setMaxStack();
mgen.setMaxLocals();
mgen.removeCodeAttributes();
cgen.replaceMethod(jclzz.getMethods()[1], mgen.getMethod());
ilist.dispose();
//output the file
FileOutputStream fos = new FileOutputStream(className);
cgen.getJavaClass().dump(fos);
fos.close();
}
}
Removing a StackMapTable is not a proper solution for fixing a wrong StackMapTable. The important cite is:
4.7.4. The StackMapTable Attribute
In a class file whose version number is 50.0 or above, if a method's Code attribute does not have a StackMapTable attribute, it has an implicit stack map attribute (§4.10.1). This implicit stack map attribute is equivalent to a StackMapTable attribute with number_of_entries equal to zero.
Since a StackMapTable must have explicit entries for every branch target, such an implicit StackMapTable will work with branch-free methods only. But in these cases, the method usually doesn’t have an explicit StackMapTable anyway, so you wouldn’t have that problem then (unless the method had branches which your instrumentation removed).
Another conclusion is that you can get away with removing the StackMapTable, if you patch the class file version number to a value below 50. Of course, this is only a solution if you don’t need any class file feature introduced in version 50 or newer…
There was a grace period in which JVMs supported a fall-back mode for class files with broken StackMapTables just for scenarios like yours, where the tool support is not up-to-date. (See -XX:+FailoverToOldVerifier or -XX:-UseSplitVerifier) But the grace period is over now and that support has been declined, i.e. Java 8 JVMs do not support the fall-back mode anymore.
If you want to keep up with the Java development and instrument newer class files which might use features of these new versions you have only two choices:
Calculate the correct StackMapTable manually
Use a tool which supports calculating the correct StackMapTable attributes, e.g. ASM, (see java-bytecode-asm) does support it
I'm trying to track down the source of an EOFException in some client/server code, but many of the classes used only have methods which say that they throw an IOException, not specifically an EOFException. Normally I'd just look at the stack trace but I don't have it and can't reproduce it. So, it would be helpful to have a list of every class which has methods which throw EOFException specifically, but I don't know how to find out this information.
Is there a source of information on every (standard) Java class (in SE 7, in my case) which has methods which throw EOFException? I have tried reading the Javadocs on EOFException to no avail.
(I have found, at least, that DataInput does mentionEOFException. But are there any more?)
Afterword: Since it seems the only way to find out is to inspect the source code, here is the result of me searching for "EOFException" in the extracted source code (1.7.0_45).
EDIT: Added results for 7.51, for all source code in the JDK, at the bottom.
In Java 6.17, here are all classes that explicitly throw java.io.EOFException. Specifically, it is the number of times new\s+EOFException was found in each source-code file.
java.io.DataInputStream.java: 8
java.io.ObjectInputStream.java: 6
java.io.RandomAccessFile.java: 8
java.util.zip.GZIPInputStream.java: 2
java.util.zip.InflaterInputStream.java: 1
java.util.zip.ZipFile.java: 1
java.util.zip.ZipInputStream.java: 1
Here is another bit of information: All source-code files containing catch\s*\(\s*EOFException:
java.io.ObjectInputStream.java: 1
java.util.zip.ZipInputStream.java: 1
Note that there are no standard java.* Exception classes that extend EOFException (there are no occurances of
extends\s+([a-z]+\.)*EOFException
anywhere in the java.* source-code).
This is a limited but valuable starting point. As mentioned by others, there may be situations that this misses--when all you have is the source-code to work from, it will be time-consuming to find them. Hopefully this information will set you down the right path.
Here are the results for Java 7.51, for all source-code provided with the JDK:
extends\s+([a-z]+\.)*EOFException
none
catch\s*\(\s*EOFException
com.sun.imageio.plugins.gif.GIFImageReader: 1
com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl: 1
com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl: 4
com.sun.org.apache.xerces.internal.impl.XMLVersionDetector: 1
com.sun.org.apache.xerces.internal.impl.dtd.XMLDTDLoader: 2
java.io.ObjectInputStream: 1
java.util.zip.ZipInputStream: 1
new\s+EOFException
com.sun.corba.se.impl.io.IIOPInputStream: 1
com.sun.imageio.plugins.png.PNGImageReader: 1
com.sun.org.apache.xerces.internal.impl.XMLDTDScannerImpl: 1
com.sun.org.apache.xerces.internal.impl.XMLEntityManager: 1
com.sun.org.apache.xerces.internal.impl.XMLEntityScanner: 1
java.io.DataInputStream: 8
java.io.ObjectInputStream: 6
java.io.RandomAccessFile: 8
java.util.zip.GZIPInputStream: 2
java.util.zip.InflaterInputStream: 1
java.util.zip.ZipFile: 1
java.util.zip.ZipInputStream: 1
javax.imageio.stream.ImageInputStreamImpl: 8
You can find that out only under the assumption that the code creates and immediately throws an EOFException. But the follwoing could also throw an EOFException:
class Foo {
...
public void iAmHarmless(Exception x) { if (x != null) throw x; }
...
}
Or how about the follwoing, to defeat aliteralminds method:
class XYException extends EOFException { ... }
class Foo {
public void surprise() { throw new XYException().super(); }
}
Joking aside - methods from many classes may throw EOFException simply because of inheritance. A grep for "EOFException" gives only the very base classes. But you must consider all subclasses thereof. Example: java.util.jar.JarInputStream
I am getting expected ClassVerifyErrors when attempting to load a class i have generated using ASM. On further inspection i can see that the jvm is correct and that the method is talking about has an invalid MAX_STACK value. THe strange thing is am using the auto calculate the stack and max local options so this should not be a problem...
The method with the invalid option is very simple and yet the result is bad bytecode.
I have written a class with the intended method and compared my asm generated class against what javac produces and the byte codes matchup with the only error being the max stack is 0 which is wrong while javac sets a value of 2.
Id like to avoid having to calculate tha max stack/locals myself.
Max stack and variable calculation can produce the wrong results if bytecode is not valid. You can verify that by running generated code trough the CheckClassAdapter.
For example,
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
// generate code into cw instance...
PrintWriter pw = new PrintWriter(System.out);
CheckClassAdapter.verify(new ClassReader(cw.toByteArray()), true, pw);