Recent Posts

Programming

play_postgres

Play Framework 2.2 and Postgres 9.3.1 java.sql.SQLException: No suitable driver found

Environment

OSX: 10.9
Postgres: 9.3.1
Scala: 2.10.3
PlayFramework: 2.2
Java: 1.7.0_25

build.sbt

...
 
libraryDependencies ++= Seq(
  jdbc,
  anorm,
  cache,
  "org.postgresql" % "postgresql" % "9.2-1003-jdbc4"
)
 
...

application.conf

...
 
db.default.driver=org.postgresql.Driver
db.default.url="jdbc:postgresql://localhost/YOURDATABASENAMEHERE"
 
...

 

Stop/Start your play application and you should be good to go.

twos-compliment_thankstwo

Hacking Java Bytecode for Programmers (Part4) – Krakatau And The Case Of The Integer Overflow

Posted on June 25, 2013

Index

Hacking Java Bytecode for Programmers (Part1) – The Birds and the Bees of Hex Editing
Hacking Java Bytecode for Programmers (Part2) – Lions, and Tigers, and OP Codes, OH MY!
Hacking Java Bytecode for Programmers (Part3) – Yes, disassemble with Javap ALL OVER THE PLACE!
Hacking Java Bytecode for Programmers (Part4) – Krakatau And The Case Of The Integer Overflow

Introduction

A funny thing happened on the way to crafting my next blog post. I met this very talented twenty-one year old student who goes by the handle Storyyeller, on an online forum. He offered to help educate me on how to write bytecode by hand. How freaking pro.

Along the way, Storyyeller mentioned Krakatau. Software that he is actively writing to help with the assembling and disassembling of Java class files. He also sent me a link to a command line application he had written. This application is a puzzle. To solve it, you must hack it. Which gave me the idea that for this article, we are going to reverse engineer Storyyeller’s application. Download the following crackme1.1.jar application now.

As a reminder, please go back and read the other articles if you need to catchup.

CHALLENGE ACCEPTED!

The first thing we will do after downloading the .zip file, is unzip the .zip archive found inside. Then run the program.

thedude$ java -jar crackme1.1.jar 
Please enter a 32bit signed int
thedude$ java -jar crackme1.1.jar 1
Incorrect
thedude$ java -jar crackme1.1.jar -908
Incorrect
thedude$

Storyyeller said, that in order to crack this application, one needs to enter a 32bit integer to get the program to print “Correct”.

Given that rule set, we need to uncompress the .jar file to see what is going on. If you are not aware, a Java .jar file is essentially a zip archive. It is a package/container that holds all the needed binaries and libraries for the application to function, made this way primarily for ease of distribution.

thedude$ unzip crackme1.1.jar
Archive:  crackme1.1.jar
  inflating: META-INF/MANIFEST.MF    
  inflating: Code.class              
  inflating: author.txt              
thedude$

Unzipping the .jar dumps the contents and we can see that there are three files.

  1. The MANIFEST.MF file enclosed in the META-INF directory
  2. The author.txt file
  3. The Code.class binary file

Unlike C, where the main() function is always used to tell the compiler “START THE PROGRAM HERE”, the MANIFEST.MF file found in a .jar archive can be used to specify the program entry point. It can also be used to set the CLASSPATH along with several other parameters. In a large application the information in this file could prove useful, but for us, the .jar contained only a single binary file. Code.class. So it is obvious what binary file we should operate on. (The author.txt file should be self explanatory)

At this point run javap on the Code.class file to see what is dumped.

thedude$ javap -verbose Code.class

The result you will recieve, is rather, well, odd.

xfO9jl

An endless printing of new line characters will be dumped to screen. If we redirect the output to file and wait a while, eventually a  >2GB file will materialize. No bueno.

The initial take away here is that javap can be manipulated. Lets try and figure out how Storyyeller is screwing with our output.

The Hard Way

In order to do this, I ended up writing a script to parse the constant pool of the Code.class file. The two import pieces of information found when parsing the Constant Pool where at index #34 and #35.

Full Output

thedude$ ./dis.py Code.class
Magic			cafebabe
Minor			0
Major			49
ConstantPoolCount	38
 
CONSTANT_Utf8_info { 
	pool_index	hex_offset	byte_offset	tag	length	bytes
	1		0xa		10		01	17	6a
}
CONSTANT_Utf8_info { 
	pool_index	hex_offset	byte_offset	tag	length	bytes
	2		0x1e		30		01	6	64
}
CONSTANT_Utf8_info { 
	pool_index	hex_offset	byte_offset	tag	length	bytes
	3		0x27		39		01	39	28
}
CONSTANT_Utf8_info { 
	pool_index	hex_offset	byte_offset	tag	length	bytes
	4		0x51		81		01	8	69
}
CONSTANT_Utf8_info { 
	pool_index	hex_offset	byte_offset	tag	length	bytes
	5		0x5c		92		01	3	28
}
CONSTANT_Utf8_info { 
	pool_index	hex_offset	byte_offset	tag	length	bytes
	6		0x62		98		01	8	43
}
CONSTANT_Utf8_info { 
	pool_index	hex_offset	byte_offset	tag	length	bytes
	7		0x6d		109		01	9	49
}
CONSTANT_Utf8_info { 
	pool_index	hex_offset	byte_offset	tag	length	bytes
	8		0x79		121		01	31	50
}
CONSTANT_Utf8_info { 
	pool_index	hex_offset	byte_offset	tag	length	bytes
	9		0x9b		155		01	16	6a
}
CONSTANT_Utf8_info { 
	pool_index	hex_offset	byte_offset	tag	length	bytes
	10		0xae		174		01	3	6f
}
CONSTANT_Utf8_info { 
	pool_index	hex_offset	byte_offset	tag	length	bytes
	11		0xb4		180		01	21	4c
}
CONSTANT_Utf8_info { 
	pool_index	hex_offset	byte_offset	tag	length	bytes
	12		0xcc		204		01	19	6a
}
CONSTANT_Utf8_info { 
	pool_index	hex_offset	byte_offset	tag	length	bytes
	13		0xe2		226		01	7	70
}
CONSTANT_Utf8_info { 
	pool_index	hex_offset	byte_offset	tag	length	bytes
	14		0xec		236		01	21	28
}
CONSTANT_Utf8_info { 
	pool_index	hex_offset	byte_offset	tag	length	bytes
	15		0x104		260		01	4	43
}
CONSTANT_Utf8_info { 
	pool_index	hex_offset	byte_offset	tag	length	bytes
	16		0x10b		267		01	4	6d
}
CONSTANT_Utf8_info { 
	pool_index	hex_offset	byte_offset	tag	length	bytes
	17		0x112		274		01	22	28
}
CONSTANT_Class_info {
	pool_index	hex_offset	byte_offset	tag	name_index	
	18		0x12b		299		07	1
}
CONSTANT_Class_info {
	pool_index	hex_offset	byte_offset	tag	name_index	
	19		0x12e		302		07	9
}
CONSTANT_Class_info {
	pool_index	hex_offset	byte_offset	tag	name_index	
	20		0x131		305		07	12
}
CONSTANT_Class_info {
	pool_index	hex_offset	byte_offset	tag	name_index	
	21		0x134		308		07	15
}
CONSTANT_NameAndType_info {
	pool_index	hex_offset	byte_offset	tag	name_index	descriptor_index
	22		0x137		311		0c	0002		0003
}
CONSTANT_NameAndType_info {
	pool_index	hex_offset	byte_offset	tag	name_index	descriptor_index
	23		0x13c		316		0c	0004		0005
}
CONSTANT_NameAndType_info {
	pool_index	hex_offset	byte_offset	tag	name_index	descriptor_index
	24		0x141		321		0c	000a		000b
}
CONSTANT_NameAndType_info {
	pool_index	hex_offset	byte_offset	tag	name_index	descriptor_index
	25		0x146		326		0c	000d		000e
}
CONSTANT_Methodref_info { 
	pool_index	hex_offset	byte_offset	tag	class_index	name_and_type_index
	26		0x14b		331		0a	0012		0016
}
CONSTANT_Methodref_info { 
	pool_index	hex_offset	byte_offset	tag	class_index	name_and_type_index
	27		0x150		336		0a	0012		0017
}
CONSTANT_Methodref_info { 
	pool_index	hex_offset	byte_offset	tag	class_index	name_and_type_index
	28		0x155		341		0a	0014		0019
}
CONSTANT_Fieldref_info {
	pool_index	hex_offset	byte_offset	tag	class_index	name_and_type_index
	29		0x15a		346		09	0013		0018
}
CONSTANT_String_info {
	pool_index	hex_offset	byte_offset	tag	string_index
	30		0x15f		351		08	0006
}
CONSTANT_String_info {
	pool_index	hex_offset	byte_offset	tag	string_index
	31		0x162		354		08	0007
}
CONSTANT_String_info {
	pool_index	hex_offset	byte_offset	tag	string_index
	32		0x165		357		08	0008
}
CONSTANT_Integer_info {
	pool_index	hex_offset	byte_offset	tag	bytes		int_value
	33		0x168		360		03	668f182d	1720653869
}
CONSTANT_Utf8_info { 
	pool_index	hex_offset	byte_offset	tag	length	bytes
	34		0x16d		365		01	65535	0a
}
CONSTANT_Class_info {
	pool_index	hex_offset	byte_offset	tag	name_index	
	35		0x1016f		65903		07	34
}
CONSTANT_NameAndType_info {
	pool_index	hex_offset	byte_offset	tag	name_index	descriptor_index
	36		0x10172		65906		0c	0022		000b
}
CONSTANT_Fieldref_info {
	pool_index	hex_offset	byte_offset	tag	class_index	name_and_type_index
	37		0x10177		65911		09	0023		0024
}
thedude$
CONSTANT_Utf8_info { 
	pool_index	hex_offset	byte_offset	tag	length	bytes
	34		0x16d		365		01	65535	0a
}
CONSTANT_Class_info {
	pool_index	hex_offset	byte_offset	tag	name_index	
	35		0x1016f		65903		07	34
}

We can see that a Utf8 string resides at index #34 in the constant pool. It’s length, in bytes, is 65535. A long string can easily indicate obfuscation. Lets make the string smaller.

Open the Code.class file with Bless and go to offset 0x16d.

0x16dSince we are in the Constant Pool portion of the binary file, 01 is the correct tag for a CONSTANT_Utf8 string.

The two bytes following the tag are the strings length. Converting FF FF to decimal gives us the value 65535. This again helps confirm that we are in the correct location of the file.

Lets find the end of the string by searching for the offset 0x1016f.

UPDATE: People have asked how I knew to go to offset 0x1016f. When I parsed the Contant Pool with my script, the output shows the beginning byte of every member in the Constant Pool. Since I knew where #34 and #35 started, I could just go to the start of #35 (0x1016f) and move back one byte to get to the end of index #34.

0x1016f

Again, still being inside the Constant Pool, we know that 07 is the tag for a CONSTANT_Class. Which if we look at the output from my script, we know to be located at index #35.

CONSTANT_Class_info {
	pool_index	hex_offset	byte_offset	tag	name_index	
	35		0x1016f		65903		07	34
}

What we are going to do, is manually highlight the hex string and replace it with the Hexadecimal notation for a literal “Space” (\s in programmer speak).

highlight

Delete the large, multi-lined (lots of lines fall off the screen) segment of hexadecimal bytes that we have highlighted and replace it with a single hexadecimal value of 20.

replaced

 We are not finished though, we need to then change FF FF to 00 01 to specify a string length of one.

0001

Make sure the file is saved and then run javap over Code.class again.

...output truncated...
    65514: getstatic     #37                // Field " "." ":Ljava/io/PrintStream;
    65517: getstatic     #37                // Field " "." ":Ljava/io/PrintStream;
    65520: getstatic     #37                // Field " "." ":Ljava/io/PrintStream;
    65523: getstatic     #37                // Field " "." ":Ljava/io/PrintStream;
    65526: getstatic     #37                // Field " "." ":Ljava/io/PrintStream;
    65529: getstatic     #37                // Field " "." ":Ljava/io/PrintStream;
    65532: getstatic     #37                // Field " "." ":Ljava/io/PrintStream;
    Exception table:
       from    to  target type
           1    51    42   any
}
thedude$

Eureka! Much more usable output and we really can put together a story of what Storyyeller did.

  • First, he created an insanely long string containing 65535 character bytes.
  • Second, he must have manually manipulated the file by hand to include 65532 getstatic references to that crazy long string.

Storyyeller obviously knew that by creating a .class file in such a way, he woud basically make javap dump over 2GB of individual string characters, essentially DOS’ing javap.

 The Krakatau Way

In the previous section, I created a script and then we manipulated the file by hand using Bless. That is a lot of work! There HAS to be an easier way and luckily there is. We can use Krakatau.

First, delete the Code.class file and then unzip crackme1.1.jar again.

thedude$ rm Code.class
thedude$ unzip crackme1.1.jar
Archive:  crackme1.1.jar
replace META-INF/MANIFEST.MF? [y]es, [n]o, [A]ll, [N]one, [r]ename: A
  inflating: META-INF/MANIFEST.MF    
  inflating: Code.class              
  inflating: author.txt              
thedude$

Then, clone Krakatau from github.

thedude$ git clone https://github.com/Storyyeller/Krakatau.git
Cloning into 'Krakatau'...
remote: Counting objects: 1135, done.
remote: Compressing objects: 100% (415/415), done.
remote: Total 1135 (delta 747), reused 1100 (delta 713)
Receiving objects: 100% (1135/1135), 413.12 KiB | 600 KiB/s, done.
Resolving deltas: 100% (747/747), done.
thedude$

Next, disassemble Code.class using Krakatau.

thedude$ python Krakatau/disassemble.py Code.class 
Krakatau  Copyright (C) 2012-13  Robert Grosse
This program is provided as open source under the GNU General Public License. 
See LICENSE.TXT for more details.
 
processing target Code.class, 1/1 remaining
Class written to /home/thedude/krak/Code.j
9.16616106033  seconds elapsed
thedude$

This will create a Code.j file that uses the same assembly manipulation syntax as the Jasmin assembler.

“Jasmin as an assembler takes ASCII descriptions of JVM Classes, written in a simple assembler-like syntax using the Java Virtual Machine instruction set. It converts them into binary JVM Class files, suitable for loading by a Java runtime system.”

Basically, instead of looking at hexadecimal like we did in the previous section, we will now have a file that will be much easier to manipulate.

Open the Code.j file using a text editor (I use vim) and goto line 21871. You’ll see something like this.

.const [_34] = Utf8 '\n   7:\tastore_0\n   8:\ticonst_0\n   9:\taaload\n   10:\tinvokestatic\t#26; //Method java/lang/Integer.decode:(Ljava/lang/String;)Ljava/lang/Integer;\n   13:\tinvokevirtual\t#27; //Method java/lang/Integer.intValue:()I\n   16:\tbipush\t-27\n   18:\timul\n   19:\tbipush\t39\n   21:\tiadd\n   22:\tldc\t#33; //int 1720653868\n   24:\tif_icmpne\t32\n   27:\tldc\t#30; //String Correct!\n   29:\tgoto\t34\n   32:\tldc\t#31; //String Incorrect\n   34:\tgetstatic\t#29; //Field java/lang/System.out:Ljava/io/PrintStream;\n   37:\tswap\n   38:\tinvokevirtual\t#28; //Method java/io/PrintStream.println:(Ljava/lang/String;)V\n   41:\treturn\n   42:\tpop\n   43:\tldc\t#32; //String Please enter a 32bit signed int\n   45:\tgoto\t34\n   48:\tgetstatic\t#37; //Field www.www:Ljava/io/PrintStream;\n  Exception table:\n   from   to  target type\n     1    51    42   any\n\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\npublic final class Code extends java.io.PrintStream\n  minor version: 0\n  major version: 50\n  Constant pool:\nconst #1 = Asciz\tjava/lang/Integer;\nconst #2 = Asciz\tdecode;\nconst #3 = Asciz\t(Ljava/lang/String;)Ljava/lang/Integer;;\nconst #4 = Asciz\tintValue;\nconst #5 = Asciz\t()I;\nconst #6 = Asciz\tCorrect!;\nconst #7 = Asciz\tIncorrect;\nconst #8 = Asciz\tPlease enter a 32bit signed int;\nconst #9 = Asciz\tjava/lang/System;\nconst #10 = Asciz\tout;\nconst #11 = Asciz\tLjava/io/PrintStream;;\nconst #12 = Asciz\tjava/io/PrintStream;\nconst #13 = Asciz\tprintln;\nconst #14 = Asciz\t(Ljava/lang/String;)V;\nconst #15 = Asciz\tCode;\nconst #16 = Asciz\tmain;\nconst #17 = Asciz\t([Ljava/lang/String;)V;\nconst #18 = class\t#1;\t//  java/lang/Integer\nconst #19 = class\t#9;\t//  java/lang/System\nconst #20 = class\t#12;\t//  java/io/PrintStream\nconst #21 = class\t#15;\t//  Code\nconst #22 = NameAndType\t#2:#3;//  decode:(Ljava/lang/String;)Ljava/lang/Integer;\nconst #23 = NameAndType\t#4:#5;//  intValue:()I\nconst #24 = NameAndType\t#10:#11;//  out:Ljava/io/PrintStream;\nconst #25 = NameAndType\t#13:#14;//  println:(Ljava/lang/String;)V\nconst #26 = Method\t#18.#22;\t//  java/lang/Integer.decode:(Ljava/lang/String;)Ljava/lang/Integer;\nconst #27 = Method\t#18.#23;\t//  java/lang/Integer.intValue:()I\nconst #28 = Method\t#20.#25;\t//  java/io/PrintStream.println:(Ljava/lang/String;)V\nconst #29 = Field\t#19.#24;\t//  java/lang/System.out:Ljava/io/PrintStream;\nconst #30 = String\t#6;\t//  Correct!\nconst #31 = String\t#7;\t//  Incorrect\nconst #32 = String\t#8;\t//  Please enter a 32bit signed int\nconst #33 = int\t1720653869;\nconst #34 = Asciz\twww;\nconst #35 = class\t#34;\t//  www\nconst #36 = NameAndType\t#34:#11;//  www:Ljava/io/PrintStream;\nconst #37 = Field\t#35.#36;\t//  www.www:Ljava/io/PrintStream;\n\n{\npublic static final synchronized void main(java.lang.String[]);\n  Code:\n   Stack=2, Locals=1, Args_size=1\n   0:\taload_0\n   1:\tjsr\t7\n   4:\tgetstatic\t#37; //Field www.www:Ljava/io/PrintStream;\n   7:\tastore_0\n   8:\ticonst_0\n   9:\taaload\n   10:\tinvokestatic\t#26; //Method java/lang/Integer.decode:(Ljava/lang/String;)Ljava/lang/Integer;\n   13:\tinvokevirtual\t#27; //Method java/lang/Integer.intValue:()I\n   16:\tbipush\t58\n   18:\timul\n   19:\tbipush\t-2\n   21:\tiadd\n   22:\tldc\t#33; //int 172065386\n   24:\tif_icmpne\t32\n   27:\tldc\t#30; //String Correct!\n   29:\tgoto\t34\n   32:\tldc\t#31; //String Incorrect\n   34:\tgetstatic\t#29; //Field java/lang/System.out:Ljava/io/PrintStream;\n   37:\tswap\n   38:\tinvokevirtual\t#28; //Method java/io/PrintStream.println:(Ljava/lang/String;)V\n   41:\treturn\n   42:\tpop\n   43:\tldc\t#32; //String Please enter a 32bit signed int\n   45:\tgoto\t34\n   48:\tgetstatic\t#37; //Field www.www:Ljava/io/PrintStream;\n  Exception table:\n   from   to  target type\n     1    51    42   any\n\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\

I highlighted the text inside the single quotes and replaced that big long string with the word Krakatau.

...file truncated...
        getstatic [_37]
        getstatic [_37]
        getstatic [_37]
        getstatic [_37]
        getstatic [_37]
        getstatic [_37]
        getstatic [_37]
        getstatic [_37]
.end method
 
.const [_34] = Utf8 'Krakatau'
.const [_35] = Class [_34]
.const [_37] = Field [_35] [_34] Ljava/io/PrintStream;

Save the file and use Krakatau to assemble Code.j.

thedude$ python Krakatau/assemble.py Code.j
Krakatau  Copyright (C) 2012-13  Robert Grosse
This program is provided as open source under the GNU General Public License. 
See LICENSE.TXT for more details.
 
Processing file Code.j, 1/1 remaining
Class written to /home/thedude/krak/Code.class
thedude$

Now run javap over our newly created Code.class file.

 65448: getstatic     #14                // Field Krakatau.Krakatau:Ljava/io/PrintStream;
    65451: getstatic     #14                // Field Krakatau.Krakatau:Ljava/io/PrintStream;
    65454: getstatic     #14                // Field Krakatau.Krakatau:Ljava/io/PrintStream;
    65457: getstatic     #14                // Field Krakatau.Krakatau:Ljava/io/PrintStream;
    65460: getstatic     #14                // Field Krakatau.Krakatau:Ljava/io/PrintStream;
    65463: getstatic     #14                // Field Krakatau.Krakatau:Ljava/io/PrintStream;
    65466: getstatic     #14                // Field Krakatau.Krakatau:Ljava/io/PrintStream;
    65469: getstatic     #14                // Field Krakatau.Krakatau:Ljava/io/PrintStream;
    65472: getstatic     #14                // Field Krakatau.Krakatau:Ljava/io/PrintStream;
    65475: getstatic     #14                // Field Krakatau.Krakatau:Ljava/io/PrintStream;
    65478: getstatic     #14                // Field Krakatau.Krakatau:Ljava/io/PrintStream;
    65481: getstatic     #14                // Field Krakatau.Krakatau:Ljava/io/PrintStream;
    65484: getstatic     #14                // Field Krakatau.Krakatau:Ljava/io/PrintStream;
    65487: getstatic     #14                // Field Krakatau.Krakatau:Ljava/io/PrintStream;
    65490: getstatic     #14                // Field Krakatau.Krakatau:Ljava/io/PrintStream;
    65493: getstatic     #14                // Field Krakatau.Krakatau:Ljava/io/PrintStream;
    65496: getstatic     #14                // Field Krakatau.Krakatau:Ljava/io/PrintStream;
    65499: getstatic     #14                // Field Krakatau.Krakatau:Ljava/io/PrintStream;
    65502: getstatic     #14                // Field Krakatau.Krakatau:Ljava/io/PrintStream;
    65505: getstatic     #14                // Field Krakatau.Krakatau:Ljava/io/PrintStream;
    65508: getstatic     #14                // Field Krakatau.Krakatau:Ljava/io/PrintStream;
    65511: getstatic     #14                // Field Krakatau.Krakatau:Ljava/io/PrintStream;
    65514: getstatic     #14                // Field Krakatau.Krakatau:Ljava/io/PrintStream;
    65517: getstatic     #14                // Field Krakatau.Krakatau:Ljava/io/PrintStream;
    65520: getstatic     #14                // Field Krakatau.Krakatau:Ljava/io/PrintStream;
    65523: getstatic     #14                // Field Krakatau.Krakatau:Ljava/io/PrintStream;
    65526: getstatic     #14                // Field Krakatau.Krakatau:Ljava/io/PrintStream;
    65529: getstatic     #14                // Field Krakatau.Krakatau:Ljava/io/PrintStream;
    65532: getstatic     #14                // Field Krakatau.Krakatau:Ljava/io/PrintStream;
    Exception table:
       from    to  target type
           1    51    42   any
}
thedude$

YES! That output looks very familiar. Except this time around, it only took a couple minutes to get to this point.

Again, use vim or your favorite text editor to open the Code.j file and remove the L51 label and all the getstatic calls beneath it.

Also, on line 9, since we removed the L51 label, we need to respecify the bounds of the method.

FROM

.catch [0] from L1 to L51 using L42

TO

.catch [0] from L1 to L42 using L42

Your entire Code.j file should now look like this.

.version 49 0
.class super final public Code
.super java/io/PrintStream
 
.method static final synchronized public main : ([Ljava/lang/String;)V
        .limit stack 2
        .limit locals 1
        .catch [0] from L1 to L42 using L42
        aload_0
L1:
        jsr L7
        getstatic [_37]
L7:
        astore_0
        iconst_0
        aaload
        invokestatic java/lang/Integer decode (Ljava/lang/String;)Ljava/lang/Integer;
        invokevirtual java/lang/Integer intValue ()I
        bipush -37
        imul
        bipush 42
        iadd
        ldc 1720653869
        if_icmpne L32
        ldc 'Correct!'
        goto L34
L32:
        ldc 'Incorrect'
L34:
        getstatic java/lang/System out Ljava/io/PrintStream;
        swap
        invokevirtual java/io/PrintStream println (Ljava/lang/String;)V
        return
L42:
        pop
        ldc 'Please enter a 32bit signed int'
        goto L34
        getstatic [_37]
.end method
 
.const [_34] = Utf8 'Krakatau'
.const [_35] = Class [_34]
.const [_37] = Field [_35] [_34] Ljava/io/PrintStream;

Assemble our Code.j file using Krakatau.

thedude$ python Krakatau/assemble.py Code.j
Krakatau  Copyright (C) 2012-13  Robert Grosse
This program is provided as open source under the GNU General Public License. 
See LICENSE.TXT for more details.
 
Processing file Code.j, 1/1 remaining
Class written to /home/thedude/krak/Code.class
thedude$

Run javap over the newly created Code.class file.

thedude$ javap -c Code.class 
public final class Code extends java.io.PrintStream {
  public static final synchronized void main(java.lang.String[]);
    Code:
       0: aload_0       
       1: jsr           7
       4: getstatic     #14                 // Field Krakatau.Krakatau:Ljava/io/PrintStream;
       7: astore_0      
       8: iconst_0      
       9: aaload        
      10: invokestatic  #20                 // Method java/lang/Integer.decode:(Ljava/lang/String;)Ljava/lang/Integer;
      13: invokevirtual #24                 // Method java/lang/Integer.intValue:()I
      16: bipush        -37
      18: imul          
      19: bipush        42
      21: iadd          
      22: ldc           #4                  // int 1720653869
      24: if_icmpne     32
      27: ldc           #2                  // String Correct!
      29: goto          34
      32: ldc           #3                  // String Incorrect
      34: getstatic     #29                 // Field java/lang/System.out:Ljava/io/PrintStream;
      37: swap          
      38: invokevirtual #35                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      41: return        
      42: pop           
      43: ldc           #1                  // String Please enter a 32bit signed int
      45: goto          34
      48: getstatic     #14                 // Field Krakatau.Krakatau:Ljava/io/PrintStream;
    Exception table:
       from    to  target type
           1    42    42   any
}
thedude$

Nice! This output makes much more sense. We can now begin to try and figure out what the required 32bit integer is.

Stepping through the logic

We can easily see that there is a single Main() method.

Expand - Main()

thedude$ javap -c Code.class 
public final class Code extends java.io.PrintStream {
  public static final synchronized void main(java.lang.String[]);    Code:
       0: aload_0       
       1: jsr           7
       4: getstatic     #14                 // Field Krakatau.Krakatau:Ljava/io/PrintStream;
       7: astore_0      
       8: iconst_0      
       9: aaload        
      10: invokestatic  #20                 // Method java/lang/Integer.decode:(Ljava/lang/String;)Ljava/lang/Integer;
      13: invokevirtual #24                 // Method java/lang/Integer.intValue:()I
      16: bipush        -37
      18: imul          
      19: bipush        42
      21: iadd          
      22: ldc           #4                  // int 1720653869
      24: if_icmpne     32
      27: ldc           #2                  // String Correct!
      29: goto          34
      32: ldc           #3                  // String Incorrect
      34: getstatic     #29                 // Field java/lang/System.out:Ljava/io/PrintStream;
      37: swap          
      38: invokevirtual #35                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      41: return        
      42: pop           
      43: ldc           #1                  // String Please enter a 32bit signed int
      45: goto          34
      48: getstatic     #14                 // Field Krakatau.Krakatau:Ljava/io/PrintStream;
    Exception table:
       from    to  target type
           1    42    42   any
}
thedude$

On operation 9, we can see the aaload opcode. Indicating it is loading argument[0] onto the stack.

Expand - aaload

thedude$ javap -c Code.class 
public final class Code extends java.io.PrintStream {
  public static final synchronized void main(java.lang.String[]);
    Code:
       0: aload_0       
       1: jsr           7
       4: getstatic     #14                 // Field Krakatau.Krakatau:Ljava/io/PrintStream;
       7: astore_0      
       8: iconst_0      
       9: aaload              10: invokestatic  #20                 // Method java/lang/Integer.decode:(Ljava/lang/String;)Ljava/lang/Integer;
      13: invokevirtual #24                 // Method java/lang/Integer.intValue:()I
      16: bipush        -37
      18: imul          
      19: bipush        42
      21: iadd          
      22: ldc           #4                  // int 1720653869
      24: if_icmpne     32
      27: ldc           #2                  // String Correct!
      29: goto          34
      32: ldc           #3                  // String Incorrect
      34: getstatic     #29                 // Field java/lang/System.out:Ljava/io/PrintStream;
      37: swap          
      38: invokevirtual #35                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      41: return        
      42: pop           
      43: ldc           #1                  // String Please enter a 32bit signed int
      45: goto          34
      48: getstatic     #14                 // Field Krakatau.Krakatau:Ljava/io/PrintStream;
    Exception table:
       from    to  target type
           1    42    42   any
}
thedude$
Operation 10 is invoking the method Integer.decode on argument[0].

Expand - Integer.decode

thedude$ javap -c Code.class 
public final class Code extends java.io.PrintStream {
  public static final synchronized void main(java.lang.String[]);
    Code:
       0: aload_0       
       1: jsr           7
       4: getstatic     #14                 // Field Krakatau.Krakatau:Ljava/io/PrintStream;
       7: astore_0      
       8: iconst_0      
       9: aaload        
      10: invokestatic  #20                 // Method java/lang/Integer.decode:(Ljava/lang/String;)Ljava/lang/Integer;      13: invokevirtual #24                 // Method java/lang/Integer.intValue:()I
      16: bipush        -37
      18: imul          
      19: bipush        42
      21: iadd          
      22: ldc           #4                  // int 1720653869
      24: if_icmpne     32
      27: ldc           #2                  // String Correct!
      29: goto          34
      32: ldc           #3                  // String Incorrect
      34: getstatic     #29                 // Field java/lang/System.out:Ljava/io/PrintStream;
      37: swap          
      38: invokevirtual #35                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      41: return        
      42: pop           
      43: ldc           #1                  // String Please enter a 32bit signed int
      45: goto          34
      48: getstatic     #14                 // Field Krakatau.Krakatau:Ljava/io/PrintStream;
    Exception table:
       from    to  target type
           1    42    42   any
}
thedude$

Operation 13 is casting the value as an int.

Expand - Integer.intValue

thedude$ javap -c Code.class 
public final class Code extends java.io.PrintStream {
  public static final synchronized void main(java.lang.String[]);
    Code:
       0: aload_0       
       1: jsr           7
       4: getstatic     #14                 // Field Krakatau.Krakatau:Ljava/io/PrintStream;
       7: astore_0      
       8: iconst_0      
       9: aaload        
      10: invokestatic  #20                 // Method java/lang/Integer.decode:(Ljava/lang/String;)Ljava/lang/Integer;
      13: invokevirtual #24                 // Method java/lang/Integer.intValue:()I      16: bipush        -37
      18: imul          
      19: bipush        42
      21: iadd          
      22: ldc           #4                  // int 1720653869
      24: if_icmpne     32
      27: ldc           #2                  // String Correct!
      29: goto          34
      32: ldc           #3                  // String Incorrect
      34: getstatic     #29                 // Field java/lang/System.out:Ljava/io/PrintStream;
      37: swap          
      38: invokevirtual #35                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      41: return        
      42: pop           
      43: ldc           #1                  // String Please enter a 32bit signed int
      45: goto          34
      48: getstatic     #14                 // Field Krakatau.Krakatau:Ljava/io/PrintStream;
    Exception table:
       from    to  target type
           1    42    42   any
}
thedude$

This is where things get interesting. Now that argument[0] is cast as an integer an on the stack, at operation 16, you can see Storyyeller used bipush to push integer -37 onto the operand stack.

Expand - bipush

thedude$ javap -c Code.class 
public final class Code extends java.io.PrintStream {
  public static final synchronized void main(java.lang.String[]);
    Code:
       0: aload_0       
       1: jsr           7
       4: getstatic     #14                 // Field Krakatau.Krakatau:Ljava/io/PrintStream;
       7: astore_0      
       8: iconst_0      
       9: aaload        
      10: invokestatic  #20                 // Method java/lang/Integer.decode:(Ljava/lang/String;)Ljava/lang/Integer;
      13: invokevirtual #24                 // Method java/lang/Integer.intValue:()I
      16: bipush        -37      18: imul          
      19: bipush        42
      21: iadd          
      22: ldc           #4                  // int 1720653869
      24: if_icmpne     32
      27: ldc           #2                  // String Correct!
      29: goto          34
      32: ldc           #3                  // String Incorrect
      34: getstatic     #29                 // Field java/lang/System.out:Ljava/io/PrintStream;
      37: swap          
      38: invokevirtual #35                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      41: return        
      42: pop           
      43: ldc           #1                  // String Please enter a 32bit signed int
      45: goto          34
      48: getstatic     #14                 // Field Krakatau.Krakatau:Ljava/io/PrintStream;
    Exception table:
       from    to  target type
           1    42    42   any
}
thedude$

He then multiplies the integer we supplied with -37 using imul at operation 18.

Expand - imul

thedude$ javap -c Code.class 
public final class Code extends java.io.PrintStream {
  public static final synchronized void main(java.lang.String[]);
    Code:
       0: aload_0       
       1: jsr           7
       4: getstatic     #14                 // Field Krakatau.Krakatau:Ljava/io/PrintStream;
       7: astore_0      
       8: iconst_0      
       9: aaload        
      10: invokestatic  #20                 // Method java/lang/Integer.decode:(Ljava/lang/String;)Ljava/lang/Integer;
      13: invokevirtual #24                 // Method java/lang/Integer.intValue:()I
      16: bipush        -37
      18: imul                19: bipush        42
      21: iadd          
      22: ldc           #4                  // int 1720653869
      24: if_icmpne     32
      27: ldc           #2                  // String Correct!
      29: goto          34
      32: ldc           #3                  // String Incorrect
      34: getstatic     #29                 // Field java/lang/System.out:Ljava/io/PrintStream;
      37: swap          
      38: invokevirtual #35                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      41: return        
      42: pop           
      43: ldc           #1                  // String Please enter a 32bit signed int
      45: goto          34
      48: getstatic     #14                 // Field Krakatau.Krakatau:Ljava/io/PrintStream;
    Exception table:
       from    to  target type
           1    42    42   any
}
thedude$

The result is kept on the stack. Storyyeller then pushes the integer 42 at Operation 19, again using bipush, onto the operand stack.

Expand - bipush

thedude$ javap -c Code.class 
public final class Code extends java.io.PrintStream {
  public static final synchronized void main(java.lang.String[]);
    Code:
       0: aload_0       
       1: jsr           7
       4: getstatic     #14                 // Field Krakatau.Krakatau:Ljava/io/PrintStream;
       7: astore_0      
       8: iconst_0      
       9: aaload        
      10: invokestatic  #20                 // Method java/lang/Integer.decode:(Ljava/lang/String;)Ljava/lang/Integer;
      13: invokevirtual #24                 // Method java/lang/Integer.intValue:()I
      16: bipush        -37
      18: imul          
      19: bipush        42      21: iadd          
      22: ldc           #4                  // int 1720653869
      24: if_icmpne     32
      27: ldc           #2                  // String Correct!
      29: goto          34
      32: ldc           #3                  // String Incorrect
      34: getstatic     #29                 // Field java/lang/System.out:Ljava/io/PrintStream;
      37: swap          
      38: invokevirtual #35                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      41: return        
      42: pop           
      43: ldc           #1                  // String Please enter a 32bit signed int
      45: goto          34
      48: getstatic     #14                 // Field Krakatau.Krakatau:Ljava/io/PrintStream;
    Exception table:
       from    to  target type
           1    42    42   any
}
thedude$
Our result along with integer 42 are added using iadd on operation 21.

Expand - iadd

thedude$ javap -c Code.class 
public final class Code extends java.io.PrintStream {
  public static final synchronized void main(java.lang.String[]);
    Code:
       0: aload_0       
       1: jsr           7
       4: getstatic     #14                 // Field Krakatau.Krakatau:Ljava/io/PrintStream;
       7: astore_0      
       8: iconst_0      
       9: aaload        
      10: invokestatic  #20                 // Method java/lang/Integer.decode:(Ljava/lang/String;)Ljava/lang/Integer;
      13: invokevirtual #24                 // Method java/lang/Integer.intValue:()I
      16: bipush        -37
      18: imul          
      19: bipush        42
      21: iadd                22: ldc           #4                  // int 1720653869
      24: if_icmpne     32
      27: ldc           #2                  // String Correct!
      29: goto          34
      32: ldc           #3                  // String Incorrect
      34: getstatic     #29                 // Field java/lang/System.out:Ljava/io/PrintStream;
      37: swap          
      38: invokevirtual #35                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      41: return        
      42: pop           
      43: ldc           #1                  // String Please enter a 32bit signed int
      45: goto          34
      48: getstatic     #14                 // Field Krakatau.Krakatau:Ljava/io/PrintStream;
    Exception table:
       from    to  target type
           1    42    42   any
}
thedude$

At operation 22 the integer 1720653869 is called onto the stack using ldc and Storyyeller then compares 1720653869 to the result using the if_icmpne at Operation 24.

Expand - ldc

thedude$ javap -c Code.class 
public final class Code extends java.io.PrintStream {
  public static final synchronized void main(java.lang.String[]);
    Code:
       0: aload_0       
       1: jsr           7
       4: getstatic     #14                 // Field Krakatau.Krakatau:Ljava/io/PrintStream;
       7: astore_0      
       8: iconst_0      
       9: aaload        
      10: invokestatic  #20                 // Method java/lang/Integer.decode:(Ljava/lang/String;)Ljava/lang/Integer;
      13: invokevirtual #24                 // Method java/lang/Integer.intValue:()I
      16: bipush        -37
      18: imul          
      19: bipush        42
      21: iadd          
      22: ldc           #4                  // int 1720653869      24: if_icmpne     32
      27: ldc           #2                  // String Correct!
      29: goto          34
      32: ldc           #3                  // String Incorrect
      34: getstatic     #29                 // Field java/lang/System.out:Ljava/io/PrintStream;
      37: swap          
      38: invokevirtual #35                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      41: return        
      42: pop           
      43: ldc           #1                  // String Please enter a 32bit signed int
      45: goto          34
      48: getstatic     #14                 // Field Krakatau.Krakatau:Ljava/io/PrintStream;
    Exception table:
       from    to  target type
           1    42    42   any
}
thedude$

If the mathematical result (using our supplied integer) and 1720653869 are NOT equal, jump to operation 32 and print “Incorrect”

ELSE

Print “Correct!”

Expand - if_icmpne

thedude$ javap -c Code.class 
public final class Code extends java.io.PrintStream {
  public static final synchronized void main(java.lang.String[]);
    Code:
       0: aload_0       
       1: jsr           7
       4: getstatic     #14                 // Field Krakatau.Krakatau:Ljava/io/PrintStream;
       7: astore_0      
       8: iconst_0      
       9: aaload        
      10: invokestatic  #20                 // Method java/lang/Integer.decode:(Ljava/lang/String;)Ljava/lang/Integer;
      13: invokevirtual #24                 // Method java/lang/Integer.intValue:()I
      16: bipush        -37
      18: imul          
      19: bipush        42
      21: iadd          
      22: ldc           #4                  // int 1720653869
      24: if_icmpne     32      27: ldc           #2                  // String Correct!
      29: goto          34
      32: ldc           #3                  // String Incorrect
      34: getstatic     #29                 // Field java/lang/System.out:Ljava/io/PrintStream;
      37: swap          
      38: invokevirtual #35                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      41: return        
      42: pop           
      43: ldc           #1                  // String Please enter a 32bit signed int
      45: goto          34
      48: getstatic     #14                 // Field Krakatau.Krakatau:Ljava/io/PrintStream;
    Exception table:
       from    to  target type
           1    42    42   any
}
thedude$

Use The Mathz Luke

At this point, we could express the value we need to derive with the following equation.

x(-37) – 42 = 1720653869

Obviously we need to solve for x. Which begs the question.

What 32 bit number could we enter into Storyyeller’s application in order for it to eventually equal 1720653869?

Using the following equation, should yield our answer.

(1720653869/-37) – 42 = x

But instead, we find that x is an not an integer and is irreducible.

-1720652315/37 (irreducible)

WTH?

Idea

It is at this point where one should realize that Storyyeller has royally screwed with us. The given problem is not solvable in the traditional sense. Which means that we need to get more creative.

  • We know Storyyeller is trying to have us solve for 1720653869.
  • We know that he is vetting that argument[0] is 32 bit integer.
  • We also know he isn’t validating that the result of x(-37) + 42 is a 32bit integer.

Hopefully his cli application is open to a integer overflow exploit.

Integer Overflow

1100110100011110001100000101101 is the binary representation of 1720653869 but Storyyeller isn’t validating the bitness. What this means, is that we can trick the application into misinterpreting the result of Storyyeller’s initial equation x(-37) + 42 for our favor.

“WAT?” you ask.

I feel you. It really is kind of confusing at first. Have a look at this.

answer      	x           	overflow	binary                               
1720653869.0	-46504157.4865	        	      1100110100011110001100000101101
  • The Answer column is the value Storyyeller is trying to have us solve for
  • The X column is the result returned after x/-37 – 42 is applied
  • The Overflow column is any binary digits that could potentially overflow and fall off
  • The Binary column is the actually binary representation of the number in column X

One way to test our hypothesis, is to continually add 2^31 to our answer as that is the amount of bits in a 32 bit system. Like a clock or safe, we will continue to flip the bits until either we run out of targetable 32bit numbers or we find our answer.

(NOTE: Ordinarily you would use some modular arithmetic to solve this. But I’m going to use a show/do methodolgy to hopefully make more sense on what actually happens under the hood when an integer overflows)

The first time we add 2^31 we get the following.

answer      	x           	overflow	binary                               
1720653869.0	-46504157.4865	        	      1100110100011110001100000101101
3868137517.0	-104544256.081	       1	     11100110100011110001100000101101

Essentially we just added 1 bit to the end of the binary number (dont forget the end is on the left). You can see that the overflow column reminds us that there is 1 overflow bit and that in that space, we have assigned a binary “1”. Again, X is what we are trying to solve for, it needs to be a 32bit integer. -104544256.081 obviously isn’t as we can see it has a remainder.

So lets do it again by adding 2^31.

answer      	x           	overflow	binary                               
1720653869.0	-46504157.4865	        	      1100110100011110001100000101101
3868137517.0	-104544256.081	       1	     11100110100011110001100000101101
6015621165.0	-162584354.676	      10	    101100110100011110001100000101101

Still no luck. Lets use some code to print a bunch of values for us to analyze.

Integer Overflow Code

# We know Storyyeller is evaluating that our input, after multiplication and addition, equals 1720653869
# So the following expression should help articulate trying to solve for x
# x(-37) + 42 = 1720653869
# Love Love Love WolframAlpha
# http://www.wolframalpha.com/input/?i=x%28-37%29+*+42+%3D+1720653869
 
import re
import math
 
def getOverflow(original, derivative):
        needle = str(bin(original))[2:] + "$"
        haystack = str(bin(int(derivative)))[2:]
        overflow = re.sub(needle, '', haystack)
        return overflow
 
def calcAnswer(answer):
        # 2 ^ 31
        bit_offset = 2147483648
        # start the sequence at zero
        answer_sequence = 0
        #bit_ceiling = 2147483648
        #bit_floor = (bit_offset * -1) + 1
        print
        print "%s\t%s\t%s\t%s" % ('answer'.ljust(12),'x'.ljust(12),'overflow'.ljust(8),'binary'.ljust(37))
        while True:
 
                if(answer_sequence == 0):
                        # if 0 assign the answer with no offset
                        answer_sequence = float(answer)
                else:
                        # else add in the offset to flip the binary bit
                        answer_sequence = float(answer_sequence) + float(bit_offset)
 
                x = (answer_sequence - 42) / -37
                overflow = getOverflow(answer,answer_sequence)
                binary = str(bin(int(answer_sequence)))[2:]
                print "%s\t%s\t%s\t%s" % (answer_sequence,x, overflow.rjust(8),binary.rjust(37))
                # must be rational
                # if we wanted more logic, we could add a check to validate bitness 
                # and break if the bitness grew past 32bit.
                if(int(x) == float(x)):
                        print "The solution is %s" % int(x)
                        break
 
        print
calcAnswer(1720653869)

And if we run it.

thedude$ python mathz.py 
answer      	x           	overflow	binary                               
1720653869.0	-46504157.4865	        	      1100110100011110001100000101101
3868137517.0	-104544256.081	       1	     11100110100011110001100000101101
6015621165.0	-162584354.676	      10	    101100110100011110001100000101101
8163104813.0	-220624453.27	      11	    111100110100011110001100000101101
10310588461.0	-278664551.865	     100	   1001100110100011110001100000101101
12458072109.0	-336704650.459	     101	   1011100110100011110001100000101101
14605555757.0	-394744749.054	     110	   1101100110100011110001100000101101
16753039405.0	-452784847.649	     111	   1111100110100011110001100000101101
18900523053.0	-510824946.243	    1000	  10001100110100011110001100000101101
21048006701.0	-568865044.838	    1001	  10011100110100011110001100000101101
23195490349.0	-626905143.432	    1010	  10101100110100011110001100000101101
25342973997.0	-684945242.027	    1011	  10111100110100011110001100000101101
27490457645.0	-742985340.622	    1100	  11001100110100011110001100000101101
29637941293.0	-801025439.216	    1101	  11011100110100011110001100000101101
31785424941.0	-859065537.811	    1110	  11101100110100011110001100000101101
33932908589.0	-917105636.405	    1111	  11111100110100011110001100000101101
36080392237.0	-975145735.0	   10000	 100001100110100011110001100000101101
The solution is -975145735
thedude$

We can see that the script has found a hit on -975145375 which suddenly means that -975145375(-37) + 42 = 1720653869.

“No it doesn’t Jared!” you say.

And you are correct.

-975145735*-37 + 42 = 36080392237

But here is where the overflow comes in.

By design, Storyyeller purposely doesn’t validate the bitness of the result before he evaluates it against 1720653869. He has given us the opportunity to allow the binary bits to overflow. Any extraneous bits that can’t be used in a 32bit system simply are NOT accounted for.

answer      	x           	overflow	binary                               
1720653869.0	-46504157.4865	        	      1100110100011110001100000101101
36080392237.0	-975145735.0	   10000	 100001100110100011110001100000101101

Which means the five bits in the overflow column, 1-0-0-0-0, overflow and drop off.

Basically converting 36080392237 into 1720653869.

Or their binary equivalents.

(10000)1100110100011110001100000101101 into 1100110100011110001100000101101.

Test the answer now against Storyyeller’s application.

thedude$ java -jar crackme1.1.jar -975145735
Correct!
thedude$

Success!!!

Conclusion

You should now know how to further exploit bytecode by hand along with slapping around the constant pool a bit. You should realize that doing such things by hand is insanely tedious. You should understand how to install and utilize Krakatau. And you should be aware and comprehend what Integer Overflow is and hopefully now go and investigate ideas on how to prevent your applications from suffering them.

Thanks again to Storyyeller for not only writing Krakatau but also crafting the crackme. I know it takes a lot of effort and it is much appreciated.

grasshopper_disassemble

Hacking Java Bytecode for Programmers (Part3) – Yes, disassemble with Javap ALL OVER THE PLACE!

Posted on May 28, 2013

Index

Hacking Java Bytecode for Programmers (Part1) – The Birds and the Bees of Hex Editing
Hacking Java Bytecode for Programmers (Part2) – Lions, and Tigers, and OP Codes, OH MY!
Hacking Java Bytecode for Programmers (Part3) – Yes, disassemble with Javap ALL OVER THE PLACE!
Hacking Java Bytecode for Programmers (Part4) – Krakatau And The Case Of The Integer Overflow

Introduction

In Part 2, I showed you at a high level, what Java Opcodes are and I also walked you through how to manipulate Strings inside of the compiled code. I’ve actually used the exact method discussed in that post to bypass some sanity checks in a Java application I was reverse engineering.

As always, refer to the previous posts if you need to catch up.

 Our goal for this blog post will be to get an idea on how to use the disassembler javap to understand compiled code. We will then utilize this knowledge to manipulate the flow control of our program, so that we change the output from “Access Revoked!” to “Access Granted!” by modifying only the compiled source. Simulating privilege escalation. 

Setting Up For Success

For this next example, modify your User.java file to mirror mine.

public class User {
 
        protected boolean authenticated = false;
 
        public void setAuthenticatedTrue() {
                this.authenticated = true;
        }
 
        public static void main(String[] args) {
                User user = new User();
                user.run();
        }
 
        public void run() {
                if (this.authenticated == false) {
                        System.out.println("Access Revoked!");
                }
                else {
                        System.out.println("Access Granted!");
                }
        }
}

Compile the file using javac.

thedude$ javac User.java

Again, lets pretend that we were never given the source file. So for clarity, rename the source file to User.java.del.

thedude$ mv User.java User.java.del
thedude$ ls
User.class  User.java.del

Just like the last scenario, despite the fact that you do not have the source code, you still have the compiled class file that the JVM can execute. Lets run it now.

thedude$ java User 
Access Revoked!
thedude$

Disassemble with Javap, Steph-a-nie

Javap is a disassembler. It analyzes a compiled Class file and dumps out incredibly useful information enabling us to reverse engineer unobfuscated java code fairly easily. The output can be overwhelming for newbs, but don’t worry, we will step through it.

Before we begin, do a quick sanity check on the file to validate that it is binary data.

Using file.

thedude$ file -i User.class
User.class: application/x-java-applet; charset=binary
thedude$

After confirming that it is indeed binary, and with no flags specified, run javap against our User.class file.

thedude$ javap User.class
Compiled from "User.java"
public class User {
  protected boolean authenticated;
  public User();
  public void setAuthenticatedTrue();
  public static void main(java.lang.String[]);
  public void run();
}
thedude$

Well that is cool right? We can see that the binary file contains our public class User. We can also see that the class contains the protected value authenticated along with our public methods. But that still doesn’t do much for us. Lets add some flags to see if we can get even more output.

Try adding the -c flag and run the command again.

thedude$ javap -c User.class 
Compiled from "User.java"
public class User {
  protected boolean authenticated;
 
  public User();
    Code:
       0: aload_0       
       1: invokespecial #1                  // Method java/lang/Object."":()V
       4: aload_0       
       5: iconst_0      
       6: putfield      #2                  // Field authenticated:Z
       9: return        
 
  public void setAuthenticatedTrue();
    Code:
       0: aload_0       
       1: iconst_1      
       2: putfield      #2                  // Field authenticated:Z
       5: return        
 
  public static void main(java.lang.String[]);
    Code:
       0: new           #3                  // class User
       3: dup           
       4: invokespecial #4                  // Method "":()V
       7: astore_1      
       8: aload_1       
       9: invokevirtual #5                  // Method run:()V
      12: return        
 
  public void run();
    Code:
       0: aload_0       
       1: getfield      #2                  // Field authenticated:Z
       4: ifne          18
       7: getstatic     #6                  // Field java/lang/System.out:Ljava/io/PrintStream;
      10: ldc           #7                  // String Access Revoked!
      12: invokevirtual #8                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      15: goto          26
      18: getstatic     #6                  // Field java/lang/System.out:Ljava/io/PrintStream;
      21: ldc           #9                  // String Access Granted!
      23: invokevirtual #8                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      26: return        
}
thedude$

Now that looks much more useful!

I’ve highlighted our initial ClassProtected attribute, and Public methods definitions in yellow to give you a bit of context.

class_protected_public_yellow

Next lets focus on the method blocks which I’ve highlighted in red.

methods_highlighted

You can see that directly inside the block definitions is the instruction listing that makes up the method itself. These are the opcode instructions, that when read top to bottom, let you know exactly what is going on.

Given that our eventual goal is to escalate privledges to our application by printing “Access Granted!”, we need to focus on the run(); method.

  public void run();
    Code:
       0: aload_0       
       1: getfield      #2                  // Field  authenticated:Z
       4: ifne          18
       7: getstatic     #6                  // Field  java/lang/System.out:Ljava/io/PrintStream;
      10: ldc           #7                  // String Access Revoked!
      12: invokevirtual #8                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      15: goto          26
      18: getstatic     #6                  // Field  java/lang/System.out:Ljava/io/PrintStream;
      21: ldc           #9                  // String Access Granted!
      23: invokevirtual #8                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      26: return

There are a total of  five columns to be read and I’ve separated them in blue.

five_columns_of_fierce_blueness

The OffsetMnemonicFieldType, and the ASCII representation.

blue_arrow_doom

MOAR DISASSEMBLE!

Lets break this down a bit more.

At offset 0 we find the aload_0 mnemonic and it has nothing in its field.

  public void run();
    Code:
       0: aload_0              1: getfield      #2                  // Field  authenticated:Z
       4: ifne          18
       7: getstatic     #6                  // Field  java/lang/System.out:Ljava/io/PrintStream;
      10: ldc           #7                  // String Access Revoked!
      12: invokevirtual #8                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      15: goto          26
      18: getstatic     #6                  // Field  java/lang/System.out:Ljava/io/PrintStream;
      21: ldc           #9                  // String Access Granted!
      23: invokevirtual #8                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      26: return

If we check the wikipedia java instruction listing and search for aload_0 we find the following.

The opcode for aload_0 in hexadecimal is 2A and a the decription of the opcode states that it will “load a reference onto the stack from local variable 0″

What is stored at local variable 0? Simple, a reference to this. Basically a pointer to our User object.

Let’s take a look at the next instruction.

At Offset 1 we see that the mnemonic is getfield.

  public void run();
    Code:
       0: aload_0       
       1: getfield      #2                  // Field  authenticated:Z       4: ifne          18
       7: getstatic     #6                  // Field  java/lang/System.out:Ljava/io/PrintStream;
      10: ldc           #7                  // String Access Revoked!
      12: invokevirtual #8                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      15: goto          26
      18: getstatic     #6                  // Field  java/lang/System.out:Ljava/io/PrintStream;
      21: ldc           #9                  // String Access Granted!
      23: invokevirtual #8                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      26: return

Again, we need to refer to our reference and it says that getfield has a bytecode value of B4 and the description states that it will “get a field value of an object objectref, where the field is identified by field reference in the constant pool index (index1 << 8 + index2)”

What the description is trying to communicate, is that getfield will look in its field column, see index #2, and go search the Constant Pool for index #2 for use with the next instruction.

“What is the Constant Pool?” you ask.

Lets talk about that in the next section.

Correlating the Constant Pool

Run javap with the -verbose flag over your User.class.

thedude$ javap -verbose  User.class 
Classfile /home/thedude/hackingjavabytecode/UserA/User.class
  Last modified May 23, 2013; size 688 bytes
  MD5 checksum 3d29c83d00756657d7d14a9b016f51d8
  Compiled from "User.java"
public class User
  SourceFile: "User.java"
  minor version: 0
  major version: 51
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #10.#24        //  java/lang/Object."":()V
   #2 = Fieldref           #3.#25         //  User.authenticated:Z
   #3 = Class              #26            //  User
   #4 = Methodref          #3.#24         //  User."":()V
   #5 = Methodref          #3.#27         //  User.run:()V
   #6 = Fieldref           #28.#29        //  java/lang/System.out:Ljava/io/PrintStream;
   #7 = String             #30            //  Access Revoked!
   #8 = Methodref          #31.#32        //  java/io/PrintStream.println:(Ljava/lang/String;)V
   #9 = String             #33            //  Access Granted!
  #10 = Class              #34            //  java/lang/Object
  #11 = Utf8               authenticated
  #12 = Utf8               Z
  #13 = Utf8               
  #14 = Utf8               ()V
  #15 = Utf8               Code
  #16 = Utf8               LineNumberTable
  #17 = Utf8               setAuthenticatedTrue
  #18 = Utf8               main
  #19 = Utf8               ([Ljava/lang/String;)V
  #20 = Utf8               run
  #21 = Utf8               StackMapTable
  #22 = Utf8               SourceFile
  #23 = Utf8               User.java
  #24 = NameAndType        #13:#14        //  "":()V
  #25 = NameAndType        #11:#12        //  authenticated:Z
  #26 = Utf8               User
  #27 = NameAndType        #20:#14        //  run:()V
  #28 = Class              #35            //  java/lang/System
  #29 = NameAndType        #36:#37        //  out:Ljava/io/PrintStream;
  #30 = Utf8               Access Revoked!
  #31 = Class              #38            //  java/io/PrintStream
  #32 = NameAndType        #39:#40        //  println:(Ljava/lang/String;)V
  #33 = Utf8               Access Granted!
  #34 = Utf8               java/lang/Object
  #35 = Utf8               java/lang/System
  #36 = Utf8               out
  #37 = Utf8               Ljava/io/PrintStream;
  #38 = Utf8               java/io/PrintStream
  #39 = Utf8               println
  #40 = Utf8               (Ljava/lang/String;)V
{
  protected boolean authenticated;
    flags: ACC_PROTECTED
 
  public User();
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=1, args_size=1
         0: aload_0       
         1: invokespecial #1                  // Method java/lang/Object."":()V
         4: aload_0       
         5: iconst_0      
         6: putfield      #2                  // Field authenticated:Z
         9: return        
      LineNumberTable:
        line 1: 0
        line 3: 4
 
  public void setAuthenticatedTrue();
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=1, args_size=1
         0: aload_0       
         1: iconst_1      
         2: putfield      #2                  // Field authenticated:Z
         5: return        
      LineNumberTable:
        line 6: 0
        line 7: 5
 
  public static void main(java.lang.String[]);
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=2, args_size=1
         0: new           #3                  // class User
         3: dup           
         4: invokespecial #4                  // Method "":()V
         7: astore_1      
         8: aload_1       
         9: invokevirtual #5                  // Method run:()V
        12: return        
      LineNumberTable:
        line 10: 0
        line 11: 8
        line 12: 12
 
  public void run();
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=1, args_size=1
         0: aload_0       
         1: getfield      #2                  // Field authenticated:Z
         4: ifne          18
         7: getstatic     #6                  // Field java/lang/System.out:Ljava/io/PrintStream;
        10: ldc           #7                  // String Access Revoked!
        12: invokevirtual #8                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        15: goto          26
        18: getstatic     #6                  // Field java/lang/System.out:Ljava/io/PrintStream;
        21: ldc           #9                  // String Access Granted!
        23: invokevirtual #8                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        26: return        
      LineNumberTable:
        line 15: 0
        line 16: 7
        line 19: 18
        line 21: 26
      StackMapTable: number_of_entries = 2
           frame_type = 18 /* same */
           frame_type = 7 /* same */
 
}
thedude$

Don’t get overwhelmed. Instead of focusing on the entire javap dump, I want you just to concentrate on only this particular part. The Constant Pool.

Constant pool:
   #1 = Methodref          #10.#24        //  java/lang/Object."":()V
   #2 = Fieldref           #3.#25         //  User.authenticated:Z
   #3 = Class              #26            //  User
   #4 = Methodref          #3.#24         //  User."":()V
   #5 = Methodref          #3.#27         //  User.run:()V
   #6 = Fieldref           #28.#29        //  java/lang/System.out:Ljava/io/PrintStream;
   #7 = String             #30            //  Access Revoked!
   #8 = Methodref          #31.#32        //  java/io/PrintStream.println:(Ljava/lang/String;)V
   #9 = String             #33            //  Access Granted!
  #10 = Class              #34            //  java/lang/Object
  #11 = Utf8               authenticated
  #12 = Utf8               Z
  #13 = Utf8               
  #14 = Utf8               ()V
  #15 = Utf8               Code
  #16 = Utf8               LineNumberTable
  #17 = Utf8               setAuthenticatedTrue
  #18 = Utf8               main
  #19 = Utf8               ([Ljava/lang/String;)V
  #20 = Utf8               run
  #21 = Utf8               StackMapTable
  #22 = Utf8               SourceFile
  #23 = Utf8               User.java
  #24 = NameAndType        #13:#14        //  "":()V
  #25 = NameAndType        #11:#12        //  authenticated:Z
  #26 = Utf8               User
  #27 = NameAndType        #20:#14        //  run:()V
  #28 = Class              #35            //  java/lang/System
  #29 = NameAndType        #36:#37        //  out:Ljava/io/PrintStream;
  #30 = Utf8               Access Revoked!
  #31 = Class              #38            //  java/io/PrintStream
  #32 = NameAndType        #39:#40        //  println:(Ljava/lang/String;)V
  #33 = Utf8               Access Granted!
  #34 = Utf8               java/lang/Object
  #35 = Utf8               java/lang/System
  #36 = Utf8               out
  #37 = Utf8               Ljava/io/PrintStream;
  #38 = Utf8               java/io/PrintStream
  #39 = Utf8               println
  #40 = Utf8               (Ljava/lang/String;)V

Upon compliation the Java compiler does some cool stuff. One of the things it creates is an optimized pool of stored values. The application will then reference these values when running the instructions.

Personally, I try to visualize the Constant Pool as a multidimensional array of variables that the JVM can reference.

 
constant_pool = [
  ['#1','Methodref','#10.#24','java/lang/Object."":()V'],
  ['#2','Fieldref','#3.#25','User.authenticated:Z],
  ['#3','Class','#26','User'],
  ['#4','Methodref','#3.#24','User."":()V'],
  ['#5','Methodref','#3.#27','User.run:()V'],
  ['#6','Fieldref','#28.#29','java/lang/System.out:Ljava/io/PrintStream;'],
  ['#7','String','#30','Access Revoked!'],
  ['#8','Methodref','#31.#32','java/io/PrintStream.println:(Ljava/lang/String;)V'],
  ['#9','String','#33','Access Granted!'],
  ['#10','Class','#34','java/lang/Object'],
  ['#11','Utf8','authenticated'],
  ['#12','Utf8','Z'],
  ['#13','Utf8','""'],
  ['#14','Utf8','()V'],
  ['#15','Utf8','Code'],
  ['#16','Utf8','LineNumberTable']
  ['#17','Utf8','setAuthenticatedTrue'],
  ['#18','Utf8','main'],
  ['#19','Utf8','([Ljava/lang/String;)V'],
  ['#20','Utf8','run'],
  ['#21','Utf8','StackMapTable'],
  ['#22','Utf8','SourceFile'],
  ['#23','Utf8','User.java'],
  ['#24','NameAndType','#13:#14','"":()V'],
  ['#25','NameAndType','#11:#12','authenticated:Z'],
  ['#26','Utf8','User'],
  ['#27','NameAndType','#20:#14','run:()V'],
  ['#28','Class','#35','java/lang/System'],
  ['#29','NameAndType','#36:#37','out:Ljava/io/PrintStream;'],
  ['#30','Utf8','Access Revoked!'],
  ['#31','Class','#38','java/io/PrintStream'],
  ['#32','NameAndType','#39:#40','println:(Ljava/lang/String;)V'],
  ['#33','Utf8','Access Granted!'],
  ['#34','Utf8','java/lang/Object'],
  ['#35','Utf8','java/lang/System'],
  ['#36','Utf8','out'],
  ['#37','Utf8','Ljava/io/PrintStream;'],
  ['#38','Utf8','java/io/PrintStream'],
  ['#39','Utf8','println'],
  ['#40','Utf8','(Ljava/lang/String;)V']
]

Please realize this python example of the Constant Pool isn’t functionally accurate. It is not meant to be. It is meant to just share an idea. By allowing this abstract concept to take the shape of an array, it will be way easier for you to visualize how to operate over these values as well as manipulate them.

Now we need to understand how the Contant Pool values correlate to the Opcode instructions in our run(); method.

Tracing Constant Pool Values using Javap Output

Be aware that we are going to feel like a pinball for a bit as we bounce around the references in the Constant Pool.

So where were we? Oh yeah, Offset 1 is getfield.

  public void run();
    Code:
       0: aload_0       
       1: getfield      #2                  // Field  authenticated:Z       4: ifne          18
       7: getstatic     #6                  // Field  java/lang/System.out:Ljava/io/PrintStream;
      10: ldc           #7                  // String Access Revoked!
      12: invokevirtual #8                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      15: goto          26
      18: getstatic     #6                  // Field  java/lang/System.out:Ljava/io/PrintStream;
      21: ldc           #9                  // String Access Granted!
      23: invokevirtual #8                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      26: return

Use this list along with the diagram gif I created, to trace the references between the Opcodes and the Constant Pool.

    1. Index #2 is in fact, itself, a reference to #3.#25. Lets trace index #3 first.
    2. Index #3 references a Class found at index #26.
    3. Index #26 references the Utf8 string User.
    4. Index #25 references a NameAndType (This is the latter half of #3.#25)
    5. Index #11 is the Utf8 string authenticated.
    6. Index #12 is the Utf8 string (operand table also below)

 

bytecode_pointer_referen

Prefix/Suffix Operand Type
i integer
l long
s short
b byte
c character
f float
d double
z boolean
a reference

link

Now, even though we walked through this using that gif, we didn’t really have to. Lets look closely at index #2 again.

   #2 = Fieldref           #3.#25         //  User.authenticated:Z

You can see that right next to #2 written in ASCII, the User class is there with the authenticated attribute. And assigned to the attribute is the Z operand specifying a boolean.

Why did we do this?

Tracing these values down was an incredibly useful exercise in understanding how they are actually stored.

Understanding the Flow

We are almost to the point where we can hack.

At Offset 4 we find the mnemonic ifne.

  public void run();
    Code:
       0: aload_0       
       1: getfield      #2                  // Field  authenticated:Z
       4: ifne          18       7: getstatic     #6                  // Field  java/lang/System.out:Ljava/io/PrintStream;
      10: ldc           #7                  // String Access Revoked!
      12: invokevirtual #8                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      15: goto          26
      18: getstatic     #6                  // Field  java/lang/System.out:Ljava/io/PrintStream;
      21: ldc           #9                  // String Access Granted!
      23: invokevirtual #8                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      26: return

You’ll notice that in the Field next to ifne there is simply the number 18. This is NOT an index as an index would be denoted with a hash symbole #. Instead, this is a branch. Once you are skilled at interpreting the output of Javap, you’d know immediately that there are a total of two code branches in the instruction set. Just by looking at the method.

We will walk through the flow control. Remember, these instructions operate from top to bottom.

Ifne is actually operating on the value in index #2 that the getfield mnemonic is referencing. In plain english.

“If authenticated in index #2 is NOT EQUAL to false, branch the operation to offset 18.”

not_equal_branch_NOT_FALSE

From that point, the JVM would execute the remaining operations at the specified offsets 18,21,23, and 26. But since we wrote the program, we know that the authenticated boolean is indeed false. It will fail the ifne gate and continue on.

not_equal_branch_FALSE

 

Looking at the ASCII display on the right, we can easily identify that we want the ifne to succeed and branch to the instruction set located at offset 18 in order to get the “Access Granted! string to print.

Lets build out the hexadecimal bytecode we will be searching for using Bless.

Below is both the Offset and Bytecode Opcodes up to the fourth offset.

Offset: 0  1  2  3  4
Hex:   2a b4 00 02 9a

We know that at Offset 4, the mnemonic is ifne, and the hex value is 9a.

We also know that ifne is false. Which is the cause for “Access Revoked!” printing to our screen.

What would happen if we replace the ifne opcode for its counter part, the ifeq opcode?

Let’s try it!

Open up the User.class file in Bless and search for the following string (2a b4 00 02 9a).

bless hex series

Replace the opcode 9a (ifne) for the opcode 99 (ifeq) and run javap -c User.class again.

  public void run();
    Code:
       0: aload_0       
       1: getfield      #2                  // Field authenticated:Z
       4: ifeq          18       7: getstatic     #6                  // Field java/lang/System.out:Ljava/io/PrintStream;
      10: ldc           #7                  // String Access Revoked!
      12: invokevirtual #8                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      15: goto          26
      18: getstatic     #6                  // Field java/lang/System.out:Ljava/io/PrintStream;
      21: ldc           #9                  // String Access Granted!
      23: invokevirtual #8                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      26: return

You’ll notice that ifne has been changed to ifeq

Now run your program again.

thedude$ java User 
Access Granted!
thedude$

Success! We have successfully manipulated the flow control.

Conclusion

You should now be able to read and comprehend the Javap output. And you should be able to think through and disrupt the flow control by swapping opcodes at the bytecode level.

If you are finding this series valuable, please leave a comment on where you’d like to go to from here. I’d like to wrap this up and avoid a George R. R. Martin where the series never feels like it is going to end.

In the next post, we are going to look at some reverse engineering tools and techniques. Stay tuned.

Older Posts