Friday, November 27, 2009

Java Class Unpacker v0.6.0

Java Class Unpacker v0.6.0 released.
Plugin for Total Commander

Changes:
 - fixed: abstract classes and methods
 - added constant pool
 - implemented decompilation of tableswitch and lookupswitch
 - file offsets and hexa bytes in code
 - renamed file to JavaClassUnpacker.wcx

Download: http://cid-511e6cc6d535b08d.skydrive.live.com/self.aspx/JavaClassUnpacker

Cheers,

Lula

Thursday, November 26, 2009

New Total Commander Plugin - Java Class Unpacker v0.5.0

I developed a new plugin for the amazing Total Commander. Using this plugin you can enter to class files as compressed files and see fields and methods as files.
Methods can be viewed using F3, the java bytecode is displayed as text.

I have no site so I uploaded to megaupload, you can download it from:

http://www.megaupload.com/?d=8BW30ZAD

Please feel free to send me bugs, comments or suggestions.

Enjoy!

Friday, November 13, 2009

J2ME: Fixing Cannot find class java/lang/NoClassDefFoundError at preverify

I had a strange error when preverifying a midlet.

     [exec] Error preverifying class temp.TestMidlet
     [exec]     VERIFIER ERROR temp/TestMidlet.()V:
     [exec] Cannot find class java/lang/NoClassDefFoundError


The midlet is ok, Eclipse doesn't display an error. Searching in all the library jars in WTK I found the class NoClassDefFoundError is inside cldcapi11.jar. I modified the cldc jar and nows compiles.

But is not enough for me, I'm not using float or doubles so I want to compile the midlet for CLDC10. So I continued playing and I found the reason: I'm using the field named "class" to obtain the name of a class.

E.g:

To obtain the Class object of class TestMidlet I'm using the following code:

Class clazz = TestMidlet.class;

this is ok for CLDC11 but for CLDC10 is wrong, I must use this.getClass or something similar.

I hope you can find this useful.

Cheers,

Lula

All mobile developer sites

Just for reference, I'm writing here all developer sites useful for mobile frikis:

Java Mobile
http://developers.sun.com/mobility

Sony
http://developer.sonyericsson.com

Motorola
http://developer.motorola.com

Nokia
http://www.nokia.com/developers

Samsung
http://innovator.samsungmobile.com

IPhone
http://developer.apple.com/iphone

Android
http://developer.android.com

Blackberry
http://na.blackberry.com/eng/developers

BREW
http://brew.qualcomm.com/brew/en/developer/overview.html

HTC
http://developer.htc.com

Windows Mobile
http://developer.windowsmobile.com
http://msdn.microsoft.com/en-us/windowsmobile/default.aspx

OpenGL ES
http://www.khronos.org/opengles

Let's go mobile!

Cheers,

Lula

Tuesday, November 10, 2009

Convert Android DEX to Java

I'm playing with a great Android to Java converter named UnDX. You can find it at

http://www.illegalaccess.org/undx

it uses BCEL to convert the files. It's in beta, has some errors.

So, I decided to create my own converter using ASM. The idea is simple:

- Create a DEX reader extending ClassReader. Here call all the Visitor events to generate the java code.
- Use ASM to manipulate the java bytecode.
- Create a DEX ClassWriter. It must be exactly the same for java, but after generating all the bytearrays it must use dx command to create de DEX file.

The idea is simple, I had some tests and it works! I'm generating the java code and I can manipulate it.

I'll tell you later what happens with some big DEX files.

Cheers,

Lula

Thursday, November 5, 2009

How to manipulate bytecode in android

The following was tested successfully in Android SDK 1.1 and 2.0

Step 1: Create an android project in eclipse

Step 2: open the activity class and change the event onCreate with the following

boolean flag = false;

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
TextView tv = new TextView(this);
if(flag){
tv.setText("CONGRATS! YOU CRACKED MY CODE! ;)");
} else{
tv.setText("NOT CRACKED YET... :(");
}
setContentView(tv);
}


Check the new variable named flag, it is our main objective.

Step 3: run the project in the emulator, you will see a screen showing the text "NOT CRACKED YET... :("

Step 4: go to the folder YOUR_PROJECT\bin and remove the signature from the APK file. If you don't know how to do it read my previous entry here

Step 5
  • disassemble the file classes.dex. If you don't know how to do it read my previous entry here.
  • Search the text "onCreate" to find the body of the onCreate method. You will find something like this:

    Virtual methods -
    #0 : (in La/a/Start;)
    name : 'onCreate'
    type : '(Landroid/os/Bundle;)V'
    access : 0x0001 (PUBLIC)
    code -
    registers : 4
    ins : 2
    outs : 2
    insns size : 27 16-bit code units
    0003c4: |[0003c4] a.a.Start.onCreate:(Landroid/os/Bundle;)V
    0003d4: 6f20 0900 3200 |0000: invoke-super {v2, v3}, Landroid/app/Activity;.onCreate:(Landroid/os/Bundle;)V // method@0009
    0003da: 2200 0b00 |0003: new-instance v0, Landroid/widget/TextView; // class@000b
    0003de: 7020 0a00 2000 |0005: invoke-direct {v0, v2}, Landroid/widget/TextView;.:(Landroid/content/Context;)V // method@000a
    0003e4: 5521 0400 |0008: iget-boolean v1, v2, La/a/Start;.flag:Z // field@0004
    0003e8: 3801 0b00 |000a: if-eqz v1, 0015 // +000b
    0003ec: 1a01 0100 |000c: const-string v1, "CONGRATS! YOU CRACKED MY CODE! ;)" // string@0001
    0003f0: 6e20 0b00 1000 |000e: invoke-virtual {v0, v1}, Landroid/widget/TextView;.setText:(Ljava/lang/CharSequence;)V // method@000b
    0003f6: 6e20 0700 0200 |0011: invoke-virtual {v2, v0}, La/a/Start;.setContentView:(Landroid/view/View;)V // method@0007
    0003fc: 0e00 |0014: return-void
    0003fe: 1a01 1300 |0015: const-string v1, "NOT CRACKED YET... :(" // string@0013
    000402: 6e20 0b00 1000 |0017: invoke-virtual {v0, v1}, Landroid/widget/TextView;.setText:(Ljava/lang/CharSequence;)V // method@000b
    000408: 28f7 |001a: goto 0011 // -0009
    catches : (none)
    positions :
    0x0000 line=15
    0x0003 line=16
    0x0008 line=17
    0x000c line=18
    0x0011 line=22
    0x0014 line=23
    0x0015 line=20
    locals :
    0x0008 - 0x001b reg=0 tv Landroid/widget/TextView;
    0x0000 - 0x001b reg=2 this La/a/Start;
    0x0000 - 0x001b reg=3 savedInstanceState Landroid/os/Bundle;


    You need to understand how bytecode works. If you don't have any experience with bytecode manipulation please stop here.

  • I marked in red the line we want to change, because it is a jump that involves the lines of code showing texts. We must invert the jump so the screen will display another text.
  • edit in hexadecimal the file classes.dex and go to the offset 03E8, you will se the hex numbers 38 01 0b 00
    Why? Check the following line:

    0003e8: 3801 0b00 |000a: if-eqz v1, 0015 // +000b

    the first number is the offset in the classes.dex file, the following numbers are the opcode and parameters.
    If you check the opcode numbers HERE you can see the value 0x38 is for the opcode if-eqz, we must change this opcode to if-nez to invert the jump. Checking the opcodes list we see the value for if-nez is 0x39, so change the 38 value at offset 0x3E8 by 39

  • Now you must fix the checksum or you will have errors when installing the app. You can calculate the checksum with the following code:
public class FixDEXChecksum(){

/**
* Calculates the checksum for the .dex file in the
* given array, and modify the array to contain it.
*
* @param bytes non-null; the bytes of the file
*/
private static void calcChecksum(byte[] bytes) {
Adler32 a32 = new Adler32();

a32.update(bytes, 12, bytes.length - 12);

int sum = (int) a32.getValue();

bytes[8] = (byte) sum;
bytes[9] = (byte) (sum >> 8);
bytes[10] = (byte) (sum >> 16);
bytes[11] = (byte) (sum >> 24);
}

public static void main(String[] args) {
try {
File file = new File(args[0]);
FileInputStream fis = new FileInputStream(file);
byte[] data = new byte[fis.available()];
System.out.println("Reading DEX file");
fis.read(data);
System.out.println("Calculating new checksum");
calcChecksum(data);
fis.close();
System.out.println("Making backup");
file.renameTo(new File(args[0]+".bak"));
System.out.println("Writing new DEX file with checksum "+ Integer.toHexString(data[8]) +" "+ Integer.toHexString(data[9]) +" "+ Integer.toHexString(data[10]) +" "+ Integer.toHexString(data[11]));
FileOutputStream fos = new FileOutputStream(new File(args[0]));
fos.write(data);
fos.close();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

}

}
  • Put the new classes.dex inside your unsigned APK
  • Sign the APK file again.
  • Run the program and voila! The text displayed is "CONGRATS! YOU CRACKED MY CODE! ;)"


I know it is a very small program and we know how the code works, but this is useful to see what can be done with bytecode manipulation.

Removing bytecode is not so simple, but you can try replacing the bytecode values in the lines you want to remove by zeros 00, it is the NOP bytecode.

Injecting bytecode is another story, lots of offsets must be modified in the classes.dex file. I will tell you later.

And I will test this in SDK 1.5, 1.6, but another day, i'm tired now :)

Enjoy!

Wednesday, November 4, 2009

How to check the signature in APK files or JAR files

You can use the jarsigner tool from JDK.

JDKFOLDER\bin\jarsigner.exe -verify -verbose -certs myAndroidProgram.apk

or

JDKFOLDER\bin\jarsigner.exe -verify -verbose -certs myJavaProgram.jar

the output will be the list of files with a detail of the signature, as following:

sm 3366 Thu Nov 05 00:57:58 ART 2009 res/drawable/icon.png

X.509, CN=Android Debug, O=Android, C=US
[certificate is valid from 05/11/09 00:01 to 05/11/10 00:01]

sm 640 Thu Nov 05 00:57:58 ART 2009 res/layout/main.xml

X.509, CN=Android Debug, O=Android, C=US
[certificate is valid from 05/11/09 00:01 to 05/11/10 00:01]

sm 1248 Thu Nov 05 00:57:58 ART 2009 AndroidManifest.xml

X.509, CN=Android Debug, O=Android, C=US
[certificate is valid from 05/11/09 00:01 to 05/11/10 00:01]

sm 1012 Thu Nov 05 00:57:58 ART 2009 resources.arsc

X.509, CN=Android Debug, O=Android, C=US
[certificate is valid from 05/11/09 00:01 to 05/11/10 00:01]

sm 1984 Thu Nov 05 00:57:58 ART 2009 classes.dex

X.509, CN=Android Debug, O=Android, C=US
[certificate is valid from 05/11/09 00:01 to 05/11/10 00:01]

401 Thu Nov 05 00:57:58 ART 2009 META-INF/MANIFEST.MF
454 Thu Nov 05 00:57:58 ART 2009 META-INF/CERT.SF
771 Thu Nov 05 00:57:58 ART 2009 META-INF/CERT.RSA

s = signature was verified
m = entry is listed in manifest
k = at least one certificate was found in keystore
i = at least one certificate was found in identity scope

jar verified.


Cheers

Remove signature from APK file and sign it again

The APK file is just a zip file with another extension. To remove the signature just unzip it, remove the folder META-INF and zip it again.

but how to sign it again? You can use your own signature or the debug signature used by Android SDK named debug.keystore

You can copy the debug signature from C:\Documents and Settings\\Local Settings\Application Data\Android\

The data of the signature is the following:

* Keystore name: "debug.keystore"
* Keystore password: "android"
* Key alias: "androiddebugkey"
* Key password: "android"
* CN: "CN=Android Debug,O=Android,C=US"

for more details go to http://developer.android.com/guide/publishing/app-signing.html

Now, how to sign the apk again? Use the jarsigner.exe tool, this tool comes with the JDK.

JDKFOLDER\bin\jarsigner.exe -verbose -storepass android -keystore debug.keystore myprogram.apk androiddebugkey

replace myprogram.apk with your own unsigned apk.

Is this useful? Maybe, if you want to modify the build with reverse engineering or something similar, use your imagination.

voila!

Disassemble dex files

Android SDK comes with the tool dexdump.exe

To disassemble a dex file just use the following command:

dexdump.exe -d -f -h classes.dex >dexdump.txt

The output will be stored in the file dexdump.txt, and the format is dalvik bytecode, not java bytecode.

I will investigate how to modify this file.