Created
September 24, 2011 17:38
-
-
Save ezterry/1239615 to your computer and use it in GitHub Desktop.
A python library to provide some insight into the internals of the dex/odex files; just a start to allow checking of the checksums and sha signatures, may grow to have additional functions
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python | |
import struct | |
import zlib | |
import hashlib | |
class dexOptHeader: | |
def __init__(self,fp,dexFile): | |
"""Load the header data structure | |
sets attributes: | |
magic,dexOffset,Length,depsOffset,depsLength, | |
optOffset,optLength,flags,checksum | |
This operation reads from the dex file""" | |
(self.magic, | |
self.dexOffset, | |
self.dexLength, | |
self.depsOffset, | |
self.depsLength, | |
self.optOffset, | |
self.optLength, | |
self.flags, | |
self.checksum) = struct.unpack("<8s8l",fp.read(40)) | |
self.dexFile=dexFile | |
self._fp=fp | |
self.odex=True | |
if self.magic[4:] == '035\x00': | |
#we have a classes.dex file | |
self.dexOffset=0 | |
self.dexLength=self.flags | |
self.depsOffset=0 | |
self.depsLength=0 | |
self.optLength=0 | |
self.optOffset=0 | |
self.flags=0 | |
self.odex=False | |
def calculateChecksum(self): | |
"""Calculate the actual adler32 checksum from the file""" | |
assert(self.odex) | |
self._fp.seek(self.depsOffset) | |
data = self._fp.read(self.optOffset+self.optLength-self.depsOffset) | |
true_checksum=zlib.adler32(data) | |
return true_checksum; | |
def verifyChecksum(self): | |
"""Verify if the file data matches the checksum | |
Note: this will read from the dexfile""" | |
assert(self.odex) | |
true_checksum=self.calculateChecksum() | |
return true_checksum == self.checksum | |
class dexHeader: | |
def __init__(self,fp,dexFile): | |
self._fp=fp | |
self.dexFile = dexFile | |
dexOptHdr=self.dexFile.getDexOptHeader() | |
fp.seek(dexOptHdr.dexOffset) | |
(self.magic, | |
self.checksum, | |
self.signature, | |
self.fileSize, | |
self.headerSize, | |
self.endianTag, | |
self.linkSize, | |
self.linkOff, | |
self.mapOff, | |
self.stringIdsSize, | |
self.stringIdsOff, | |
self.typeIdsSize, | |
self.typeIdsOff, | |
self.protoIdsSize, | |
self.protoIdsOff, | |
self.fieldIdsSize, | |
self.fieldIdsOff, | |
self.methodIdsSize, | |
self.methodIdsOff, | |
self.classDefsSize, | |
self.classDefsOff, | |
self.dataSize, | |
self.dataOff) = struct.unpack("<8sl20s20l",fp.read(112)) | |
def calculateChecksum(self): | |
"""Calculate the actual check sum from the file""" | |
skip_nonsum = 8 + 4 #skip 8b magic + 4b checksum | |
dexOptHdr=self.dexFile.getDexOptHeader() | |
self._fp.seek(dexOptHdr.dexOffset + skip_nonsum) | |
data=self._fp.read(self.fileSize - skip_nonsum) | |
true_checksum=zlib.adler32(data) | |
return true_checksum | |
def verifyChecksum(self): | |
"""Verify if the file data matches the checksum | |
Note: this will read from the dexfile""" | |
true_checksum=self.calculateChecksum() | |
return true_checksum == self.checksum | |
def calculateSignature(self): | |
"""Calculate the SHA signature from the file""" | |
skip_nonsum = 8 + 4 + 20 #skip 8b magic + 4b checksum + sha1 | |
dexOptHdr=self.dexFile.getDexOptHeader() | |
self._fp.seek(dexOptHdr.dexOffset + skip_nonsum) | |
data=self._fp.read(self.fileSize - skip_nonsum) | |
sha1=hashlib.new('sha1') | |
sha1.update(data) | |
return sha1.digest() | |
def verifySignature(self): | |
"""Verify the sha1 signature""" | |
true_sig = calculateSignature(self) | |
return true_sig == self.signature | |
class dexFile: | |
def __init__(self,fp): | |
self._fp=fp | |
self.dexOptHeader=None | |
self.dexHeader=None | |
self.odexDeps=None | |
def getDexOptHeader(self): | |
"""Get the dexopt header object, either the existing instance | |
or load a new instance""" | |
if(self.dexOptHeader is not None): | |
return self.dexOptHeader | |
self._fp.seek(0) | |
self.dexOptHeader=dexOptHeader(self._fp,self) | |
return self.dexOptHeader | |
def getDexHeader(self): | |
"""Get the dex header object, either the existing instance or | |
load a new instace""" | |
if(self.dexHeader is not None): | |
return self.dexHeader | |
self.dexHeader=dexHeader(self._fp,self) | |
return self.dexHeader |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment