4KJO (4K Java Optimiser) version 3 released

Version 3 of my very very dodgy tool which tries to find the best sequence of obsfucators and optimisers has been released.

http://www.cuteandcuddlypet.com.au/moogie/4KJOv3.zip

http://unlimited.woogley.net/hosted/moogie/4KJOv3.zip

To use:

  1. unzip into a directory
  2. type java -jar \4KJO.jar

This will give you the command line options. More help is available when using the -gui option.

Improvements since last version:

  • should now be 1.5/1.6 complient
  • now using proguard 4.1
  • jshrink now works with the tool. (well mostly… jshrink does not seem able to correctly process alrealy obfucated/optimised jars and thus is only able to be uses as a first step… this is handeled automatically)
  • added Marvin Obsfucator
  • added Retroguard Obsfucator
  • removed JavaGuard as it seems unable to process java 1.5+
  • changed default configuration.
  • now using kzip instead of java’s zip for intermediate steps

These changes should theoretically improve the compression ratio as compared to the previous version.

Please let me know if it works has errors etc.

Cheers

the default configuration performs 5! permutations so it may take a little while, however once peformed you can use the output config file and skip these permutations.

When your entry has grown/ changed significantly it might be wise to run the default configuration again to see whether a different comibnation now give the best compresion.

Alternatively to speed it up you can make your own config file using the GUI and simply select a smaller number of optimisers to permuate combinations when finding the best solution.

Sounds nice, I’ll give it a try :slight_smile:

Good stuff! I’ll make sure to try it out over the next few days! :slight_smile:

Well, I tried it on z4rch and it reduced the jar size from 4091 to 3634 bytes BUT - it broke the code, all the ships vanished! :frowning:

lol! i suggest creating a script for each optimiser individually to see if you can identify which optimiser is being too aggressive. once/if you have identified it then create a script which is based on the default script minus the offending optimiser :slight_smile:

Is the ship data directly injected into the byte code? i believe all optimisers remove the such data. I do have a undocumented -data option which does inject the data back into the optimised jar.

I used your already compressed jar to test 4KJO.

It seems the JOGA does not like your class at all and gives an error when optimising (that is handled by the tool) however the JODE optimiser seems to be the culprit and aggressively optimises some portions of your code completely away! I unchecked it from the list of optimisers and was able to save 108 bytes (from 4091 to 3983)

here is the config i used:


<config>
	<classOptimiser>
		<findBestOptimiser>false</findBestOptimiser>
		<usePack200ForEach>false</usePack200ForEach>
		<usePack200atEnd>true</usePack200atEnd>
		<useDummyCompressedSize>true</useDummyCompressedSize>
		<optimisers>
			<count>2</count>
			<orderPosition0>PROGUARD OPTIMIZER</orderPosition0>
			<orderPosition1>JARG OPTIMIZER</orderPosition1>
		</optimisers>
	</classOptimiser>
	<jarCompressor>
		<useKzipOnly>false</useKzipOnly>
		<useBWJDeflateOnly>true</useBWJDeflateOnly>
		<BWJflateFindBestSplitSize>false</BWJflateFindBestSplitSize>
		<KzipFindBestSplitSize>false</KzipFindBestSplitSize>
		<useDefOptAfterEach>false</useDefOptAfterEach>
		<useDefOptAtEnd>true</useDefOptAtEnd>
		<kzipIterations>30</kzipIterations>
		<kzipSplits>30</kzipSplits>
		<BWJflateBlockSize>512</BWJflateBlockSize>
	</jarCompressor>
</config>

You might get better compression when using the original un-optimised jar as input.

Thanks moogie! That works fine - trouble is now I’ll have to look at my code again and see what I can do with the 110 bytes!!

hehe cant help you there… maybe have wave effects?

Hi Moogie,

Just thought I’d give your optimiser a try for my Kart game (else I probably don’t have enough space to finish it, doh!)… but the link below doesn’t seem to work any more.

Cheers, Tim.

ah,sorry about that. we cancelled that web host… I have uploaded it to the public ftp related to java 4k entries hosted by Woogley. If he objects then i will have to host by the atrocity which is free file hosting :slight_smile:

Here is the new link: http://unlimited.woogley.net/hosted/moogie/4KJOv3.zip

Hi Moogie,

I gave the optimiser a quick go. It has a couple of problems ATM. I’m afraid I haven’t spent more than about 10 mins on it so far to try to fix them…

  1. There are a lot of errors from the optimisers. Looks like most of them don’t like the class file. I’m compiling with Java 6, but with -target 1.5 -source 1.5 (at least I think I’m using those options… I should check really :slight_smile: )
  2. I need to inject a bitmap back into the class file before the compression stage. You mention above that you have an undocumented -data option to do this? Could you explain how please.

Cheers, Tim.

Well, if the optimisers generate exceptions, they are skipped… so you will still have a valid output JAR at the end. With some classes, one of the optimisers might be a little too aggressive and actually optimise sections of your code away. In that case the only real option is to remove the offending optimiser from the list of of optimisers using the -gui command line option.

there is a -addData option which will inject the contents of the file directly into the final best optimised class just before the JAR creation step.

I assume you have code in your class which reads in the class itself as input and searches for a unique byte string which indicates the start of the your embedded data? If not then you must do so as it is indeterminable to know what byte offset your data will start at.

Have a look at this thread ( http://www.java-gaming.org/forums/index.php?topic=17869.0 ) to see how I read in the data.

I’ve just come across another way to insert binary data into the class file. Just define a string and use octal escapes for the characters. For example:

“\000\001\002\003”

represents the bytes 0 to 3. Then you can just do getBytes() on the String and get a byte array of the contents. Optimizers won’t strip this String from the class file. There’s a caveat however: String.getBytes() uses the platform encoding to turn the string into bytes. The platform encoding of (effectively) all platforms is ascii-safe, so you can use values 0 to 127 (inclusive).

OK, thanks.

Sounds like just the thing. I’ll try to find some time to have a go at this tonight.

Yes, I already have code to do this… thanks.

I just realised that I had another question… the manifest file seems to disappear from the final .jar. Is this what you’d expect?

Cheers, Tim.

Also be aware that Java uses a modified UTF8 format, one difference being that the char ‘\000’ is encoded using 2 bytes rather than 1.
This coupled with the additional code necessary for converting these 7bit bytes into a more conventional form means that storing binary data as a seperate Attribute within the class file is generally more efficient.

Interesting, and good to know. So far no problems here though (and this machine is set to use UTF-8)…

Yes, this is pretty much expected as it is optimising for deployment as a Webstartable JAR… simply load the JAR in a zip utility such as winRAR or 7zip and add your manifest if you want to make it a self executing JAR.

I have found that adding a manifest does eat up much of the bytes gained from the optimisation.

OK, once I added that -addData thing, and added the manifest file back in, it did the job…

Before: 3,999 bytes. (proguard, kzip /b 128)
After: 3,864 bytes. (jode, kzip 30 / 128)

Saved 135 bytes… thanks moogie!

Cheers, Tim.

no problems :slight_smile:

I just wish i had time this year to enter myself :frowning: