DEX文件的签名和校验(翻译)

DEX files, which are the compiled bytecode files that run on the Android OS. Essentially they are like the java bytecode, except they use a modified VM which is called “Dalvik” that was developed for the Android OS.

DEX文件,是运行在android OS编译的字节码文件。 从本质上讲,就像Java字节码一样,除外他们使用一个被称做“dalvik”定制虚拟机,这是为Android OS开发使用。
So long story short – I want to know the structure of these files, and how to edit or patch them. Why? I enjoy reverse engineering things! Anyway there is a wealth of information that I could find on the following sites;
所以,长话短说,我想要知道这些文件的结构,和如何修改或者编辑他们。为什么?我喜欢逆向工程的东西,无论怎样,我在下面的网址找到了丰富的信息。
Shane Isbell’s Weblog :http://www.jroller.com/random7/entry/android_s_dex_class_structure
RetroCode, Dex File Formate : http://www.retrodev.com/android/dexformat.html
 
These site both have great information, though more so on the second link. What intrigued me was that they must have a ‘checksum’ and a ‘SHA-1′ signature. The best information I could find though only eluded to this (RetroCode);​​
这些网址有大量的信息,不过在第二个链接里面有更多的信息。吸引我的是,他们必须有一个校验和跟“SHA-1”的签名,这是我找到的最好的信息,只有这样才能避免RetroCode​
 
[quote]Notes: All non-string fields are stored in little-endian format. It would appear that the checksum and signature fields are assumed to be zero when calculating the checksum and signature.[/quote]​
[引用]注意:所有非字符串字段是存储在低字节里,假设当计算校验和跟签名定为0时,它会出现在检验和跟签名字段[/引用]
 
Well that doesn’t really help me if I’d like to patch a DEX file and then redo the signature and checksum. Especially since we don’t know what exactly is being used to calculate either or what checksum is being used to well, calculate the checksum!
如果我要修改一个DEX文件​,和重做签名跟校验,他们没有真正帮助到我。 特别是因为我们不知道究竟是被用来计算或校验被用来很好,计算校验!
 
Good thing we can extract .jar files and decompile class files, even more so thank goodness google hasn’t used obstufication on any of the classes. An except from “dx\com\android\dx\dex\file\DexFile.class” after being decompiled into DexFile.jar.
好东西我们可以提取.jar和反编译过的类文件 ,更多的要感谢善良的google没有使用obstufication 上的任何类,一个除了从“dx\com\android\dx\dex\file\DexFile.class” 反编译的DexFile.jar文件 

 

 

private static void calcSignature(byte bytes[])
{
MessageDigest md;
try
{
md = MessageDigest.getInstance("SHA-1");
}
catch(NoSuchAlgorithmException ex)
{
throw new RuntimeException(ex);
}
md.update(bytes, 32, bytes.length - 32);
try
{
int amt = md.digest(bytes, 12, 20);
if(amt != 20)
throw new RuntimeException((new StringBuilder()).append("unexpected digest write:").append(amt).append("bytes").toString());
}
catch(DigestException ex)
{
throw new RuntimeException(ex);
}
}

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);
}

 

Ah hah! Now we know how to calculate the signature and the checksum. Essentially is reads in all the bytes of the program, and it disreguards the first 32 bytes and calculates the signature using SHA-1. Then it calculates the checksum disreguarding the first 12 bytes (so it includes the signature). Excellent, lets drop this code into our own program so we can recalculate those values;

现在我们知道如何计算签名跟校验和了。本质上是读取程序所有的字节数,它disreguards 最先的32字节和计算签名使用“SHA-1”,它计算这个校验和disreguarding 最先的12字节(所以它包含签名),好极了~,把它加进我们自己的程序中,我们也可以重新计算这些值了。

/*
*         ReDEX.class
*         Coded: Timothy Strazzere
*
*         10/29/2008
*
*         Pass a .dex file as an argument and it will output the current
*         checksum and signature that is in the file, then it will output
*         the checksum and signature as it calculates them.
*
*/

import java.security.*;
import java.util.zip.Adler32;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

public class ReDEX {

public static void main(String[] args) {
if (args.length == 1) {
try {
File file = new File(args[0]);

byte[] barr = null;
barr = getBytesFromFile(file);

System.out.print(:Original Checksum: ");
for(int i = 8; i<12; i+=4)
System.out.printf("0x%02X%02X%02X%02X ", barr[i+3], barr[i+2], barr[i+1], barr[i]);
System.out.print("\nOriginal Signature: 0x");
for(int i = 12; i<32; i+=4)
System.out.printf"%02X%02X%02X%02X ", barr[i], barr[i+1], barr[i+2], barr[i+3]);

calcSignature(barr);
calcChecksum(barr);
System.out.print("\n\nNew Checksum: ");
for(int i = 8; i<12; i+=4)
System.out.printf("0x%02X%02X%02X%02X ", barr[i+3], barr[i+2], barr[i+1], barr[i]);
System.out.print("\nNew Signature: 0x");
for(int i = 12; i<32; i+=4)
System.out.printf("%02X%02X%02X%02X ", barr[i], barr[i+1], barr[i+2], barr[i+3]);
}
catch (Exception e) {
System.err.println("File input error");
}
}
else
System.out.println("Invalid parameters");
}

public static byte[] getBytesFromFile(File file) throws IOException {
InputStream is = new FileInputStream(file);

// Get the size of the file
long length = file.length();

if (length > Integer.MAX_VALUE) {
// File is too large
}

// Create the byte array to hold the data
byte[] bytes = new byte[(int)length];

// Read in the bytes
int offset = 0;
int numRead = 0;
while (offset < bytes.length && (numRead=is.read(bytes, offset, bytes.length-offset)) >= 0) {
offset += numRead;
}

// Ensure all the bytes have been read in
if (offset < bytes.length) {
throw new IOException("Could not completely read file "+file.getName());
}

// Close the input stream and return bytes
is.close();
return bytes;
}
private static void calcSignature(byte bytes[])
{
MessageDigest md;
try
{
md = MessageDigest.getInstance("SHA-1");
}
catch(NoSuchAlgorithmException ex)
{
throw new RuntimeException(ex);
}
md.update(bytes, 32, bytes.length - 32);
try
{
int amt = md.digest(bytes, 12, 20);
if(amt != 20)
throw new RuntimeException((new StringBuilder()).append("unexpected digest write:").append(amt).append("bytes").toString());
}
catch(DigestException ex)
{
throw new RuntimeException(ex);
}
}

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);
}

Excellent, now I can easily recalculate the signature and the checksum of the dex files. Note that the checksum is actually in little-endian so you need to reverse it when entering it in a hex editor.

好极了,现我我能很容易的重新计算dex文件 校验和跟签名,注意校验和实际是低字节,所以你要扭转时,要用16进制的编辑器。

So, now the Android OS will allow you to install this dex file, after signing it in the correct package (apk). Though as of right now the program still crashes upon launching the file… Hhhmmmmm we’ll have to look into this more I guess.

所以,现在android Os 也能让你安装这个dex file,签名后打包,虽然到目前为止,程序一直崩溃。。。。

 

posted @ 2013-01-11 10:43  eeLee  阅读(1683)  评论(0编辑  收藏  举报