
本文来完成一个安卓下可执行文件格式的解析器,对有意向学习安卓软件安全,如Dex混淆、加固、病毒分析等的朋友可以起到一个抛砖引玉的作用。
01 准备一个Dex文件
在完成一个安卓可执行文件格式解析器前,首先需要准备一个Dex文件来进行分析。什么是Dex文件呢?它是安卓平台上的可执行文件。在安卓平台上,应用程序都以Java语言作为开发语言,但是它并没有使用JVM(Java虚拟机)作为运行环境来执行,安卓的设计者为它重新设计了一套虚拟机被称为Dalvik。Dalvik有别于JVM,首先它编译后不再使用.class作为扩展名,而是使用.dex为扩展名。由于虚拟机不同,生成的文件不同,因此,它也有一套属于自己的字节码。
在使用传统的Java编程时,需要安装JDK。对于安卓系统下应用的开发除了需要安装JDK以外,还需要其自身的PSDK,即安卓系统的平台开发包。对于Java语言而言,其编译生成文件的扩展名为.class,而对于安卓开发环境生成的可执行文件一般是.apk。APK文件并不是一个独立的文件,它是由多个文件打包而成的。在APK文件中,除了编译后的可执行文件以外,还包含了配置文件、资源文件等。APK中包含的可执行文件.dex文件就是这里要介绍的内容。

下面来说一下获得Dex文件的方法。
1. 从APK中提取Dex文件
APK文件是一个打包过的文件,其中包含了安卓程序运行所需要的配置文件、资源文件和Dex可执行文件等。看到这里,大家可以从网上下载一个APK文件,或者通过安卓的集成开发环境编译生成一个APK文件。将得到的APK文件的扩展名由.APK修改为.RAR(或者.ZIP也可以),这样就可通过解压缩工具(比如WinRar)打开,打开该.RAR文件后可以看到APK中打包的相关文件,如图1所示。
public class HelloWorld {
public static void main(String[] args){
System.out.println(“Hello World!”);
}
}
讯享网
讯享网
d:\TestDex>javac -source 1.6 -target 1.6 HelloWorld.java
d:\TestDex>java HelloWorld
讯享网
dx –dex –output=HelloWorld.dex HelloWorld.class
struct DexFile {
/* 直接映射的”opt”头部 /
const DexOptHeader
pOptHeader;
/* 基础 DEX 中直接映射的结构体和数组的指针 /
const DexHeader
pHeader;
const DexStringId* pStringIds;
const DexTypeId* pTypeIds;
const DexFieldId* pFieldIds;
const DexMethodId* pMethodIds;
const DexProtoId* pProtoIds;
const DexClassDef* pClassDefs;
const DexLink* pLinkData;
/*
* 这些不映射到”auxillary”部分,不包含在该文件中
*
/
const DexClassLookup
pClassLookup;
const void* pRegisterMapPool; // RegisterMapClassPool
/* 指向 DEX 文件开头的指针 /
const u1
baseAddr;
/* 跟踪辅助结构的内存开销 /
int overhead; /
其他与 DEX 相关联的数据结构 /
//void
auxData;
};
讯享网
struct DexFile {
/* 基础 DEX 中直接映射的结构体和数组的指针 /
const DexHeader
pHeader;
const DexStringId* pStringIds;
const DexTypeId* pTypeIds;
const DexFieldId* pFieldIds;
const DexMethodId* pMethodIds;
const DexProtoId* pProtoIds;
const DexClassDef* pClassDefs;
const DexLink* pLinkData;
};
/*
* Direct-mapped “map_item”.
/
struct DexMapItem { u2 type; u2 unused; u4 size; u4 offset;};
讯享网
#include “vm/Common.h”
/
* 以下类型匹配 VM 规范中的定义
/
typedef uint8_t u1;typedef uint16_t u2;typedef uint32_t u4;typedef uint64_t u8;typedef int8_t s1;typedef int16_t s2;typedef int32_t s4;typedef int64_t s8;
讯享网
/
* 读取无符号的 LEB128 值,更新指向已读取值未尾的指针,该函数第 5 种编码类型中的非零高阶位
*/
DEX_INLINE int readSignedLeb128(const u1 pStream) {
const u1* ptr = pStream;
int result =
(ptr++);
if (result <= 0x7f) {
result = (result << 25) >> 25;
} else {
int cur = *(ptr++);
result = (result & 0x7f) | ((cur & 0x7f) << 7);
if (cur <= 0x7f) {
result = (result << 18) >> 18;
} else {
cur = (ptr++);
result |= (cur & 0x7f) << 14; if (cur <= 0x7f) { result = (result << 11) >> 11; } else { cur =
(ptr++);
result |= (cur & 0x7f) << 21;
if (cur <= 0x7f) {
result = (result << 4) >> 4;
} else {
/*
* 注意,不检查 cur 是否越界,这意味着可接受高 4 阶位中的垃圾
/
cur =
(ptr++);
result |= cur << 28;
}
}
}
}
*pStream = ptr;
return result;
}
DEX_INLINE int readUnsignedLeb128(const u1 pStream) {
const u1* ptr = pStream;
int result =
(ptr++);
if (result > 0x7f) {
int cur = (ptr++);
result = (result & 0x7f) | ((cur & 0x7f) << 7); if (cur > 0x7f) { cur =
(ptr++);
result |= (cur & 0x7f) << 14;
if (cur > 0x7f) {
cur = (ptr++);
result |= (cur & 0x7f) << 21; if (cur > 0x7f) { /
* 注意,不检查 cur 是否越界,这意味着可接受高 4 阶位中的垃圾
/
cur =
(ptr++);
result |= cur << 28;
}
}
}
}
pStream = ptr;
return result;}
讯享网
/
* Direct-mapped “header_item” struct.
/
struct DexHeader { u1 magic[8]; u4 checksum; u1 signature[kSHA1DigestLen]; u4 fileSize; u4 headerSize; u4 endianTag; u4 linkSize; u4 linkOff; u4 mapOff; u4 stringIdsSize; u4 stringIdsOff; u4 typeIdsSize; u4 typeIdsOff; u4 protoIdsSize; u4 protoIdsOff; u4 fieldIdsSize; u4 fieldIdsOff; u4 methodIdsSize; u4 methodIdsOff; u4 classDefsSize; u4 classDefsOff; u4 dataSize; u4 dataOff;};
/
DEX file magic number /
#define DEX_MAGIC “dex\n”/
* 旧的仍然识别的版本(对应于 Android API 级别 13 或更早的版本)
/
#define DEX_MAGIC_VERS_API_13 “035\0”
讯享网
/
* 直接映射的”map_list”
/
struct DexMapList { u4 size; /
列表中的条目 /
DexMapItem list[1]; /
条目 /
};
/
* 直接定义的”map_item”.
/
struct DexMapItem { u2 type; u2 unused; u4 size; u4 offset;};
讯享网
/
map item type codes /
enum { kDexTypeHeaderItem = 0x0000, kDexTypeStringIdItem = 0x0001, kDexTypeTypeIdItem = 0x0002, kDexTypeProtoIdItem = 0x0003, kDexTypeFieldIdItem = 0x0004, kDexTypeMethodIdItem = 0x0005, kDexTypeClassDefItem = 0x0006, kDexTypeMapList = 0x1000, kDexTypeTypeList = 0x1001, kDexTypeAnnotationSetRefList = 0x1002, kDexTypeAnnotationSetItem = 0x1003, kDexTypeClassDataItem = 0x2000, kDexTypeCodeItem = 0x2001, kDexTypeStringDataItem = 0x2002, kDexTypeDebugInfoItem = 0x2003, kDexTypeAnnotationItem = 0x2004, kDexTypeEncodedArrayItem = 0x2005, kDexTypeAnnotationsDirectoryItem = 0x2006,};
/
* Direct-mapped “string_id_item”.
/
struct DexStringId { u4 stringDataOff;};
讯享网
Struct DexStringItem { uleb128 size; ubyte data;};
/
* Direct-mapped “type_id_item”.
/
struct DexTypeId { u4 descriptorIdx;};
讯享网
/
* 直接映射的”proto_id_item”
/
struct DexProtoId { u4 shortyIdx; u4 returnTypeIdx; u4 parametersOff;};
/
* 直接映射的”type_list”
/
struct DexTypeList { u4 size; DexTypeItem list[1];};
讯享网
/
* 直接映射的”type_item”
/
struct DexTypeItem { u2 typeIdx;};
void (Ljava/lang/String) { return void;}
讯享网
/
* Direct-mapped “field_id_item”.
/
struct DexFieldId { u2 classIdx; u2 typeIdx; u4 nameIdx;};
/
* Direct-mapped “method_id_item”.
/
struct DexMethodId { u2 classIdx; u2 protoIdx; u4 nameIdx;};
讯享网
/
* 直接映射的”class_def_item”
/
struct DexClassDef { u4 classIdx; u4 accessFlags; u4 superclassIdx; u4 interfacesOff; u4 sourceFileIdx; u4 annotationsOff; u4 classDataOff; u4 staticValuesOff;};
/
* 访问标记和 mask,标准的标记和 mask 都小于或等于 0x4000
*
* 注意 ClassFlags 枚举中 vm/oo/Object.h 里相关的声明 ClassFlags
/
enum { ACC_PUBLIC = 0x00000001, ACC_PRIVATE = 0x00000002, ACC_PROTECTED = 0x00000004, ACC_STATIC = 0x00000008, ACC_FINAL = 0x00000010, ACC_SYNCHRONIZED = 0x00000020, ACC_SUPER = 0x00000020, ACC_VOLATILE = 0x00000040, ACC_BRIDGE = 0x00000040, ACC_TRANSIENT = 0x00000080, ACC_VARARGS = 0x00000080, ACC_NATIVE = 0x00000100, ACC_INTERFACE = 0x00000200, ACC_ABSTRACT = 0x00000400, ACC_STRICT = 0x00000800, ACC_SYNTHETIC = 0x00001000, ACC_ANNOTATION = 0x00002000, ACC_ENUM = 0x00004000, ACC_CONSTRUCTOR = 0x00010000, ACC_DECLARED_SYNCHRONIZED = 0x00020000, ACC_CLASS_MASK = (ACC_PUBLIC | ACC_FINAL | ACC_INTERFACE | ACC_ABSTRACT | ACC_SYNTHETIC | ACC_ANNOTATION | ACC_ENUM), ACC_INNER_CLASS_MASK = (ACC_CLASS_MASK | ACC_PRIVATE | ACC_PROTECTED | ACC_STATIC), ACC_FIELD_MASK = (ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED | ACC_STATIC | ACC_FINAL | ACC_VOLATILE | ACC_TRANSIENT | ACC_SYNTHETIC | ACC_ENUM), ACC_METHOD_MASK = (ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED | ACC_STATIC | ACC_FINAL | ACC_SYNCHRONIZED | ACC_BRIDGE | ACC_VARARGS | ACC_NATIVE | ACC_ABSTRACT | ACC_STRICT | ACC_SYNTHETIC | ACC_CONSTRUCTOR | ACC_DECLARED_SYNCHRONIZED),};
讯享网
/
* Direct-mapped “annotations_directory_item”.
/
struct DexAnnotationsDirectoryItem { u4 classAnnotationsOff; u4 fieldsSize; u4 methodsSize; u4 parametersSize; /
后面是 DexFieldAnnotationsItem[fieldsSize] /
/
后面是 DexMethodAnnotationsItem[methodsSize] /
/
后面是 DexParameterAnnotationsItem[parametersSize] /
};
/
class_data_item 的扩展形式,注意,如果特定项不存在
* (如没有静态字段),那么
* is set to NULL. /
struct DexClassData { DexClassDataHeader header; DexField
staticFields;
DexField* instanceFields;
DexMethod* directMethods;
DexMethod* virtualMethods;
};
讯享网
/* class_data_item header 的扩展形式 /
struct DexClassDataHeader { u4 staticFieldsSize; u4 instanceFieldsSize; u4 directMethodsSize; u4 virtualMethodsSize;};
/
不经验证就读取 class_data_item 的头部,这会更新指向已读取数据未尾的指针
*/
DEX_INLINE void dexReadClassDataHeader(const u1 pData,
DexClassDataHeader pHeader) {
pHeader->staticFieldsSize = readUnsignedLeb128(pData); pHeader->instanceFieldsSize = readUnsignedLeb128(pData); pHeader->directMethodsSize = readUnsignedLeb128(pData); pHeader->virtualMethodsSize = readUnsignedLeb128(pData);}
讯享网
/
expanded form of encoded_field /
struct DexField { u4 fieldIdx; u4 accessFlags;};
/
expanded form of encoded_method /
struct DexMethod { u4 methodIdx; u4 accessFlags; u4 codeOff;};
讯享网
/
* Direct-mapped “code_item”.
*
* 当抛出异常时使用”catches”表,当显示异常栈跟踪或调试信息时,显示”debugInfo”,偏移量是零
* 表示没有条目
/
struct DexCode { u2 registersSize; u2 insSize; u2 outsSize; u2 triesSize; u4 debugInfoOff; u4 insnsSize; u2 insns[1]; /
后面是可选的 u2 padding /
/
后面是 try_item[triesSize] /
/
后面是 uleb128 handlersSize /
/
后面是 catch_handler_item[handlersSize] /
};
/
* 直接映射的”encoded_array”
*
* 注意,该结构是按字节对齐的
*/
struct DexEncodedArray {
u1 array[1];
};

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/140235.html