1. 程式人生 > >Dex 檔案格式詳解

Dex 檔案格式詳解

/*
 * 解析 Dex 檔案
 */

#include "dex.h"
#include <sstream>
#include <string>
#include <iostream>

void DexFile::parseAllClass()
{
	for (u4 i = 0; i < dexHeader->classDefsSize; ++i)
	{
		std::cout << parseClassDef(i) << std::endl;
		std::cout << std::endl;
	}
}

DexFile::DexFile(char* file)
{
	// dex 頭
	dexHeader = reinterpret_cast<PDexHeader>(file);
	if (dexHeader == nullptr)
	{
		return;
	}
	else
	{
		// 字串
		if (dexHeader->stringIdsOff != 0)
		{
			stringIds = reinterpret_cast<PDexStringId>((dexHeader->stringIdsOff) + reinterpret_cast<char*>(dexHeader));
		}
		else
		{
			stringIds = nullptr;
		}

		// 型別
		if (dexHeader->typedeIdsOff == 0)
		{
			typeIds = nullptr;
		}
		else
		{
			typeIds = reinterpret_cast<PDexTypeId>((dexHeader->typedeIdsOff) + reinterpret_cast<char*>(dexHeader));
		}

		// 宣告
		if (dexHeader->protoIdsOff == 0)
		{
			protoIds = nullptr;
		}
		else
		{
			protoIds = reinterpret_cast<PDexProtoId>((dexHeader->protoIdsOff) + reinterpret_cast<char*>(dexHeader));
		}

		// 欄位
		if (dexHeader->fieldIdsOff == 0)
		{
			fieldIds = nullptr;
		}
		else
		{
			fieldIds = reinterpret_cast<PDexFieldId>((dexHeader->fieldIdsOff) + reinterpret_cast<char*>(dexHeader));
		}

		// 方法
		if (dexHeader->methodIdsOff == 0)
		{
			methodIds = nullptr;
		}
		else
		{
			methodIds = reinterpret_cast<PDexMethodId>((dexHeader->methodIdsOff) + reinterpret_cast<char*>(dexHeader));
		}

		// 類
		if (dexHeader->classDefsOff == 0)
		{
			classDefs = nullptr;
		}
		else
		{
			classDefs = reinterpret_cast<PDexClassDef>((dexHeader->classDefsOff) + reinterpret_cast<char*>(dexHeader));
		}

		// 資料
		if (dexHeader->dataOff == 0)
		{
			data = nullptr;
		}
		else
		{
			data = reinterpret_cast<PDexData>((dexHeader->dataOff) + reinterpret_cast<char*>(dexHeader));
		}

		// 靜態連結資料區
		if (dexHeader->linkOff == 0)
		{
			linkData = nullptr;
		}
		else
		{
			linkData = reinterpret_cast<PDexLink>((dexHeader->linkOff) + reinterpret_cast<char*>(dexHeader));
		}
	}
	return;
}

/* 
 * 根據索引獲取字串
 *	DexStringId 結構體
 *	typedef struct _DexStringId
 *	{
 *		u4	stringDataOff;			// 指向 MUTF-8 字串的偏移
 *	}DexStringId, *PDexStringId;
 */
std::string DexFile::parseStringId(u4 index)
{
	return std::string(MUTF8ToASCII(reinterpret_cast<char *>(stringIds[index].stringDataOff + reinterpret_cast<char*>(dexHeader))));
}

/*
 * 根據索引獲取型別
 * DexTypeId 結構體
 * typedef struct _DexTypeId
 * {
 *		u4	descriptorIdx;		// 指向 DexStringId 列表的索引
 * }DexTypeId, *PDexTypeId;
 */
std::string DexFile::parseTypeId(u4 index)
{
	return parseStringId(typeIds[index].descriptorIdx);
}


/*
 * 根據索引解析方法宣告
 * DexProtoId 結構體
 * typedef struct _DexProtoId
 * {
 *		u4	shortyIdx;				// 方法宣告字串,指向 DexStringId 列表的索引,方法宣告 = 返回型別+引數列表
 *		u4	returnTypeIdx;			// 方法返回型別字串,指向 DexStringId 列表的索引
 *		u4	parametersOff;			// 方法的引數列表,指向 DexTypeList 結構的偏移
 * }DexProtoId, *PDexProtoId;
 */
std::string DexFile::parseProtoId(u4 index)
{
	// 方法宣告 = 返回型別+引數列表
	std::string funcString = parseStringId(protoIds[index].shortyIdx);

	// 引數
	if (protoIds[index].parametersOff != 0)
	{
		funcString.append(parseDataTypeList(reinterpret_cast<PDexTypeList>((protoIds[index].parametersOff) + reinterpret_cast<char*>(dexHeader))));
	}
	
	// 返回值
	funcString.append(parseTypeId(protoIds[index].returnTypeIdx));

	return funcString;
}


/*
 * 根據索引解析欄位
 * DexFieldId 結構體
 * typedef struct _DexFieldId
 * {
 *		u2	classIdx;			// 類的型別,指向 DexTypeId 列表的索引
 *		u2	typeIdx;			// 欄位的型別,指向 DexTypeId 列表的索引
 *		u4	nameIdx;			// 欄位名,指向 DexStringId 列表的索引
 * }DexFieldId, *PDexFieldId;
 */
std::string DexFile::parseFieldId(u4 index)
{
	std::string  fieldString = parseTypeId(fieldIds[index].classIdx);
	fieldString.append(parseTypeId(fieldIds[index].typeIdx));
	fieldString.append(parseStringId(fieldIds[index].nameIdx));

	return fieldString;
}

/*
 * 根據索引解析方法
 * DexMethodId 結構體
 * typedef struct _DexMethodId
 * {
 *		u2	classIdx;			// 類的型別,指向 DexTypeId 列表的索引
 *		u2	protoIdx;			// 宣告的型別,指向 DexProtoId 列表的索引
 *		u4	nameIdx;			// 方法名,指向 DexStringId 列表的索引
 * }DexMethodId, *PDexMethodId;
 */
std::string DexFile::parseMethodId(u4 index)
{
	std::string methodString = parseTypeId(methodIds[index].classIdx);
	methodString.append(parseProtoId(methodIds[index].protoIdx));
	methodString.append(parseStringId(methodIds[index].nameIdx));

	return methodString;
}



/*
 * 根據索引解析類
 * DexClassDef 結構
 * typedef struct _DexClassDef
 * {
 *		u4	classIdx;				// 類的型別,指向 DexTypeId 列表的索引
 *		u4	accessFlags;			// 類的訪問標誌
 *		u4	superclassIdx;			// 父類型別索引值,指向 DexTypeId 列表的索引,如果沒有父類?
 *		u4	interfacesOff;			// 介面,如果有指向 DexTypeList 結構,否則為0
 *		u4	sourceFileIdx;			// 原始檔名,指向 DexStringId 列表的索引
 *		u4	annotationsOff;			// 註解,指向 DexAnnotationsDirectoryItem,或者為0
 *		u4	classDataOff;			// 指向 DexClassData 結構的偏移,類的資料部分
 *		u4	staticValuesOff;		// 指向 DexEncodeArray 結構的偏移,記錄了類中的靜態資料
 */
std::string DexFile::parseClassDef(u4 index)
{
	std::string classString = "類型別:";
	// 類型別
	classString.append(parseTypeId(classDefs[index].classIdx));
	
	// 類的訪問標誌

	// 父類
	classString.append("\n父類:");
	classString.append(parseTypeId(classDefs[index].superclassIdx));

	// 介面
	if (classDefs[index].interfacesOff != 0)
	{
		classString.append("\n介面:");
		classString.append(parseDataTypeList(reinterpret_cast<PDexTypeList>((classDefs[index].interfacesOff) + reinterpret_cast<char*>(dexHeader))));
	}

	// 原始檔名
	classString.append("\n原始檔名:");
	classString.append(parseStringId(classDefs[index].sourceFileIdx));

	// 註解
	// 暫時不處理

	// 類的資料
	if (classDefs[index].classDataOff != 0)
	{
		classString.append(parseClassData(reinterpret_cast<PDexClassData>((classDefs[index].classDataOff) + reinterpret_cast<char*>(dexHeader))));
	}

	// 類的靜態資料
	if (classDefs[index].staticValuesOff != 0)
	{
		// do something
	}
	return classString;
}


/*
 * DexClassData 結構體
 * typedef struct _DexClassData
 * {
 *		DexClassDataHeader	header;				// 指定欄位與方法的個數
 *		DexField*			staticFields;		// 靜態欄位
 *		DexField*			instanceFields;		// 例項欄位
 *		DexMethod*			directMethods;		// 直接方法
 *		DexMethod*			virtualMethods;		// 虛方法
 * }DexClassData, *PDexClassData;
 *
 * DexClassDataHeader 結構體
 * typedef struct _DexClassDataHeader
 * {
 *		uleb128	staticFieldsSize;		// 靜態欄位個數
 *		uleb128	instanceFieldsSize;		// 例項欄位個數
 *		uleb128	directMethodsSize;		// 直接方法個數
 *		uleb128	virtualMethodsSize;		// 虛方法個數
 * }DexClassDataHeader, *PDexClassDataHeader;
 */
std::string DexFile::parseClassData(PDexClassData classData)
{
	u1* ptr = reinterpret_cast<u1*>(classData);
	std::string str = "";

	u4 staticFieldsSize = uleb128ToInt(&ptr);
	u4 instanceFieldsSize = uleb128ToInt(&ptr);
	u4 directMethodsSize = uleb128ToInt(&ptr);
	u4 virtualMethodsSize = uleb128ToInt(&ptr);

	// 靜態欄位
	if (staticFieldsSize != 0)
	{
		str.append("\n靜態欄位個數:");
		str.append(IntToString(staticFieldsSize));

		// 解析 DexField
		for (u4 i = 0; i < staticFieldsSize; ++i)
		{
			str.append("\n靜態欄位:");
			str.append(parseFieldId(uleb128ToInt(&ptr)));
			str.append("\n訪問標誌:");
			str.append(IntToString(uleb128ToInt(&ptr)));
		}
	}

	// 例項欄位
	if (instanceFieldsSize != 0)
	{
		str.append("\n例項欄位個數:");
		str.append(IntToString(instanceFieldsSize));

		// 解析 DexField
		for (u4 i = 0; i < instanceFieldsSize; ++i)
		{
			str.append("\n例項欄位:");
			str.append(parseFieldId(uleb128ToInt(&ptr)));
			str.append("\n訪問標誌");
			str.append(IntToString(uleb128ToInt(&ptr)));
		}
	}

	// 直接方法
	if (directMethodsSize != 0)
	{
		str.append("\n直接方法個數:");
		str.append(IntToString(directMethodsSize));

		// 解析 DexMethod
		for (u4 i = 0; i < directMethodsSize; ++i)
		{
			str.append("\n直接方法:");
			str.append(parseMethodId(uleb128ToInt(&ptr)));
			str.append("\n訪問標誌:");
			str.append(IntToString(uleb128ToInt(&ptr)));
			str.append("\nDexCode的偏移:");
			str.append(IntToString(uleb128ToInt(&ptr)));
		}
	}

	// 虛方法
	if (virtualMethodsSize != 0)
	{
		str.append("\n虛方法個數:");
		str.append(IntToString(virtualMethodsSize));

		// 解析 DexMethod
		for (u4 i = 0; i < virtualMethodsSize; ++i)
		{
			str.append("\n虛方法:");
			str.append(parseMethodId(uleb128ToInt(&ptr)));
			str.append("\n訪問標誌:");
			str.append(IntToString(uleb128ToInt(&ptr)));
			str.append("\nDexCode的偏移:");
			str.append(IntToString(uleb128ToInt(&ptr)));
		}
	}

	return str;
}


/************************************************
* DexTypeList 結構體
* typedef struct _DexTypeList
* {
*		u4	size;				// 接下來 DexTypeItem 的個數
*		PDexTypeItem	list;	// DexTypeItem 結構
* }DexTypeList, *PDexTypeList;
*
* DexTypeItem 結構體
* typedef struct _DexTypeItem
* {
*		u2	typeIdx;			// 指向 DexTypeId 列表的索引
* }DexTypeItem, *PDexTypeItem;
************************************************/
std::string DexFile::parseDataTypeList(PDexTypeList typeList)
{
	std::string str = "";
	PDexTypeItem ptr = reinterpret_cast<PDexTypeItem>((reinterpret_cast<char*>(typeList)) + sizeof(u4));
	for (u4 i = 0; i < typeList->size; ++i)
	{
		str.append(parseTypeId(ptr[i].typeIdx));
	}

	return str;
}



int DexFile::uleb128ToInt(u1** pStream) 
{
	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) {
					/*
					* Note: We don't check to see if cur is out of
					* range here, meaning we tolerate garbage in the
					* high four-order bits.
					*/
					cur = *(ptr++);
					result |= cur << 28;
				}
			}
		}
	}
	*pStream = ptr;
	return result;
}

int DexFile::sleb128ToInt(u1** pStream) 
{
	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 {
					/*
					* Note: We don't check to see if cur is out of
					* range here, meaning we tolerate garbage in the
					* high four-order bits.
					*/
					cur = *(ptr++);
					result |= cur << 28;
				}
			}
		}
	}
	*pStream = ptr;
	return result;
}


std::string DexFile::IntToString(int num)
{
	std::stringstream strStream;
	std::string	str;
	strStream << num;
	strStream >> str;
	return str;
}