Bytecode Reverse Engineering Season 1 Episode 1
Tuesday, June 24, 2008 13:56Alright!!! Let’s get started. This is one of many subjects which always overwhelms me. Why so? Ofcourse, the reasons can not be explained here but then, the reason should be the least of your worries.
Okay, if you know enough about this, then please post your knowledge tips as comments because your comments might help towards my unexplained reasons.
I’ll run this topic as a series for quite a number of posts. You may find similar information on other websites but then, it’s a wild world and I am not intending to infringe any copyrights.
Now to begin with, let’s first understand how to evaluate the performance of java code and protect the java code from tainted objects. We’ll talk about Tainted Object Propagation as we progress in this series of discussions.
I’ll explain this with an example of enum pattern.
We can have enums in Java in two ways.
1) Either we have “public static final” constants declared.
1 2 3 4 5 6 7 8 9 | public class UsingConstants { public static final int CONST_1 = 1234 ; public static final int CONST_2 = 1 ; public static final int CONST_3 = 1 ; private int value ; private UsingConstants(int param) { value = param ; } } |
2) Implement the enum pattern.
1 2 3 4 5 6 7 8 9 10 11 12 13 | public class UsingEnumPattern { public static final UsingEnumPattern CONST_1 = new UsingEnumPattern(1234) ; public static final UsingEnumPattern CONST_2 = new UsingEnumPattern(1) ; public static final UsingEnumPattern CONST_3 = new UsingEnumPattern(1) ; private int value ; private UsingEnumPattern(int param) { value = param ; } public static int getValue() { return value; } } |
To evaluate the performance and understand the details of these two different implementations, have a look at the user code given below:
1 2 3 4 5 6 7 8 9 10 11 12 13 | public class UserCode { public void initializeSomethingUsingConstants(int param) { int i = param; } public void initializeSomethingUsingEnumPattern(UsingEnumPattern param) { UsingEnumPattern i = UsingEnumPattern.CONST_1; int i = UsingEnumPattern.getValue(); } public void callMethods(){ initializeSomethingUsingConstants(1111); // I can pass any integer here initializeSomethingUsingEnumPattern(UsingEnumPattern.CONST_1) // only defined enums can be passed. } } |
Now, We’ll deduce the following two things from this example:
a) The first example, UsingConstants, has defnitely got faster execution time as it has got only few bytecode instructions to execute.
0: aload_0 1: invokespecial #16; //Method java/lang/Object."<init>":()V 4: aload_0 5: iload_1 6: putfield #19; //Field value:I 9: return
where as the second example, UsingEnumPattern has about 16 instructions to execute. 16 to create statics and 6 for initialization.
static {}; 0: new #1; //class com/nds/epg/network/IPConfigErrorCodeA 3: dup 4: sipush 1234 7: invokespecial #14; //Method "<init>":(I)V 10: putstatic #18; //Field CONST_1:LUsingEnumPattern; 13: new #1; //class UsingEnumPattern 16: dup 17: iconst_1 18: invokespecial #14; //Method "<init>":(I)V 21: putstatic #20; //Field CONST_2:LUsingEnumPattern; 24: new #1; //class UsingEnumPattern 27: dup 28: iconst_1 29: invokespecial #14; //Method "<init>":(I)V 32: putstatic #22; //Field CONST_3:LUsingEnumPattern; 35: return 0: aload_0 1: invokespecial #26; //Method java/lang/Object."<init>":()V 4: aload_0 5: iload_1 6: putfield #28; //Field value:I 9: return
and as per user code, constant evaluation will bve faster as it will using the ’sipush’ instruction as compared to ‘getstatic’ instruction in case of enum pattern.
/*
public void initializeSomethingUsingConstants();
0: sipush 1234
3: istore_1
4: return
public void initializeSomethingUsingEnumPattern();
0: getstatic #18; //Field UsingEnumPattern.CONST_1:LUsingEnumPattern;
3: astore_1
4: return
*/So, to summarize, if you are very much worried just about performance then definitely, using constants makes it a perfect sense.
b) Now, lets look at the problem of using constants. get a bit paranoid and think that people are just waiting to break your code. it is easily possible as while using constants, any integer value can be passed to the user method instead of the constant values, which is enough to break your code. Now, to protect this, you’ll have to write conditions for every possible value the program expects and handles the correct error conditions for every incorrect value. Now, won’t this increase your code size resulting in a lot of execution overhead.
Whereas, if you use second example, incorrect values cannot be passed at all and your code will be safe from attackers. and you need not write any extra guard conditions resulting in keeping your code size to minimum.
Alright!! By now, most of you would be thinking that how this post relate to bytecode reverse engineering but then, I just needed a starting point to explain a problem before getting into injecting malicious content in your bytecode to break what you consider secure.
In my next post, i’ll evaluate these bytecodes more and then, later on, we’ll talk about contaminating bytecodes to make the code malfunction. All my posts will consider the aspect of code performance vs. code safety amd I am not sure whether these thoughts of mine will make any sense but I do need a place to vent out. ![]()












