Example #1
0
void CNANDContentLoader::GetKeyFromTicket(u8* pTicket, u8* pTicketKey)
{
	u8 CommonKey[16] = {0xeb,0xe4,0x2a,0x22,0x5e,0x85,0x93,0xe4,0x48,0xd9,0xc5,0x45,0x73,0x81,0xaa,0xf7};
	u8 IV[16];
	memset(IV, 0, sizeof IV);
	memcpy(IV, pTicket + 0x01dc, 8);
	AESDecode(CommonKey, IV, pTicket + 0x01bf, 16, pTicketKey);
}
Example #2
0
std::vector<u8> CNANDContentLoader::GetKeyFromTicket(const std::vector<u8>& ticket)
{
	const u8 common_key[16] = {0xeb,0xe4,0x2a,0x22,0x5e,0x85,0x93,0xe4,0x48,0xd9,0xc5,0x45,0x73,0x81,0xaa,0xf7};
	u8 iv[16] = {};

	std::copy(&ticket[0x01DC], &ticket[0x01DC + 8], iv);
	return AESDecode(common_key, iv, &ticket[0x01BF], 16);
}
Example #3
0
void CNANDContentLoader::InitializeContentEntries(const std::vector<u8>& tmd,
                                                  const std::vector<u8>& decrypted_title_key,
                                                  const std::vector<u8>& data_app)
{
  m_Content.resize(m_NumEntries);

  std::array<u8, 16> iv;
  u32 data_app_offset = 0;

  for (u32 i = 0; i < m_NumEntries; i++)
  {
    const u32 entry_offset = 0x24 * i;

    SNANDContent& content = m_Content[i];
    content.m_ContentID = Common::swap32(&tmd[entry_offset + 0x01E4]);
    content.m_Index = Common::swap16(&tmd[entry_offset + 0x01E8]);
    content.m_Type = Common::swap16(&tmd[entry_offset + 0x01EA]);
    content.m_Size = static_cast<u32>(Common::swap64(&tmd[entry_offset + 0x01EC]));

    const auto header_begin = std::next(tmd.begin(), entry_offset + 0x01E4);
    const auto header_end = std::next(header_begin, ArraySize(content.m_Header));
    std::copy(header_begin, header_end, content.m_Header);

    const auto hash_begin = std::next(tmd.begin(), entry_offset + 0x01F4);
    const auto hash_end = std::next(hash_begin, ArraySize(content.m_SHA1Hash));
    std::copy(hash_begin, hash_end, content.m_SHA1Hash);

    if (m_IsWAD)
    {
      u32 rounded_size = Common::AlignUp(content.m_Size, 0x40);

      iv.fill(0);
      std::copy(&tmd[entry_offset + 0x01E8], &tmd[entry_offset + 0x01E8 + 2], iv.begin());

      content.m_Data = std::make_unique<CNANDContentDataBuffer>(AESDecode(
          decrypted_title_key.data(), iv.data(), &data_app[data_app_offset], rounded_size));

      data_app_offset += rounded_size;
      continue;
    }

    std::string filename;
    if (content.m_Type & 0x8000)  // shared app
      filename = CSharedContent::AccessInstance().GetFilenameFromSHA1(content.m_SHA1Hash);
    else
      filename = StringFromFormat("%s/%08x.app", m_Path.c_str(), content.m_ContentID);

    content.m_Data = std::make_unique<CNANDContentDataFile>(filename);

    // Be graceful about incorrect TMDs.
    if (File::Exists(filename))
      content.m_Size = static_cast<u32>(File::GetSize(filename));
  }
}
Example #4
0
void CNANDContentLoader::InitializeContentEntries(const std::vector<u8>& tmd, const std::vector<u8>& decrypted_title_key, const std::vector<u8>& data_app)
{
	m_Content.resize(m_numEntries);

	std::array<u8, 16> iv;
	u32 data_app_offset = 0;

	for (u32 i = 0; i < m_numEntries; i++)
	{
		const u32 entry_offset = 0x24 * i;

		SNANDContent& content = m_Content[i];
		content.m_ContentID = Common::swap32(&tmd[entry_offset + 0x01E4]);
		content.m_Index     = Common::swap16(&tmd[entry_offset + 0x01E8]);
		content.m_Type      = Common::swap16(&tmd[entry_offset + 0x01EA]);
		content.m_Size      = static_cast<u32>(Common::swap64(&tmd[entry_offset + 0x01EC]));
		std::copy(&tmd[entry_offset + 0x01E4], &tmd[entry_offset + 0x01E4 + 36], content.m_Header);
		std::copy(&tmd[entry_offset + 0x01F4], &tmd[entry_offset + 0x01F4 + 20], content.m_SHA1Hash);

		if (m_isWAD)
		{
			u32 rounded_size = ROUND_UP(content.m_Size, 0x40);

			iv.fill(0);
			std::copy(&tmd[entry_offset + 0x01E8], &tmd[entry_offset + 0x01E8 + 2], iv.begin());

			content.m_data = AESDecode(decrypted_title_key.data(), iv.data(), &data_app[data_app_offset], rounded_size);

			data_app_offset += rounded_size;
			continue;
		}

		if (content.m_Type & 0x8000)  // shared app
			content.m_Filename = CSharedContent::AccessInstance().GetFilenameFromSHA1(content.m_SHA1Hash);
		else
			content.m_Filename = StringFromFormat("%s/%08x.app", m_Path.c_str(), content.m_ContentID);

		// Be graceful about incorrect TMDs.
		if (File::Exists(content.m_Filename))
			content.m_Size = static_cast<u32>(File::GetSize(content.m_Filename));
	}
}
Example #5
0
bool CNANDContentLoader::Initialize(const std::string& _rName)
{
	if (_rName.empty())
		return false;
	m_Path = _rName;
	WiiWAD Wad(_rName);
	u8* pDataApp = nullptr;
	u8* pTMD = nullptr;
	u8 DecryptTitleKey[16];
	u8 IV[16];
	if (Wad.IsValid())
	{
		m_isWAD = true;
		m_TIKSize = Wad.GetTicketSize();
		m_TIK = new u8[m_TIKSize];
		memcpy(m_TIK, Wad.GetTicket(), m_TIKSize);
		GetKeyFromTicket(m_TIK, DecryptTitleKey);
		u32 pTMDSize = Wad.GetTMDSize();
		pTMD = new u8[pTMDSize];
		memcpy(pTMD, Wad.GetTMD(), pTMDSize);
		pDataApp = Wad.GetDataApp();
	}
	else
	{
		std::string TMDFileName(m_Path);

		if ('/' == *TMDFileName.rbegin())
			TMDFileName += "title.tmd";
		else
			m_Path = TMDFileName.substr(0, TMDFileName.find("title.tmd"));

		File::IOFile pTMDFile(TMDFileName, "rb");
		if (!pTMDFile)
		{
			WARN_LOG(DISCIO, "CreateFromDirectory: error opening %s",
					 TMDFileName.c_str());
			return false;
		}
		u32 pTMDSize = (u32)File::GetSize(TMDFileName);
		pTMD = new u8[pTMDSize];
		pTMDFile.ReadBytes(pTMD, (size_t)pTMDSize);
		pTMDFile.Close();
	}

	memcpy(m_TMDView, pTMD + 0x180, TMD_VIEW_SIZE);
	memcpy(m_TMDHeader, pTMD, TMD_HEADER_SIZE);


	m_TitleVersion = Common::swap16(pTMD + 0x01dc);
	m_numEntries = Common::swap16(pTMD + 0x01de);
	m_BootIndex = Common::swap16(pTMD + 0x01e0);
	m_TitleID = Common::swap64(pTMD + 0x018c);
	m_IosVersion = Common::swap16(pTMD + 0x018a);
	m_Country = *(u8*)&m_TitleID;
	if (m_Country == 2) // SYSMENU
		m_Country = GetSysMenuRegion(m_TitleVersion);

	m_Content.resize(m_numEntries);


	for (u32 i=0; i<m_numEntries; i++)
	{
		SNANDContent& rContent = m_Content[i];

		rContent.m_ContentID = Common::swap32(pTMD + 0x01e4 + 0x24*i);
		rContent.m_Index = Common::swap16(pTMD + 0x01e8 + 0x24*i);
		rContent.m_Type = Common::swap16(pTMD + 0x01ea + 0x24*i);
		rContent.m_Size= (u32)Common::swap64(pTMD + 0x01ec + 0x24*i);
		memcpy(rContent.m_SHA1Hash, pTMD + 0x01f4 + 0x24*i, 20);
		memcpy(rContent.m_Header, pTMD + 0x01e4 + 0x24*i, 36);

		if (m_isWAD)
		{
			u32 RoundedSize = ROUND_UP(rContent.m_Size, 0x40);
			rContent.m_pData = new u8[RoundedSize];

			memset(IV, 0, sizeof IV);
			memcpy(IV, pTMD + 0x01e8 + 0x24*i, 2);
			AESDecode(DecryptTitleKey, IV, pDataApp, RoundedSize, rContent.m_pData);

			pDataApp += RoundedSize;
			continue;
		}

		rContent.m_pData = nullptr;

		if (rContent.m_Type & 0x8000)  // shared app
		{
			rContent.m_Filename = CSharedContent::AccessInstance().GetFilenameFromSHA1(rContent.m_SHA1Hash);
		}
		else
		{
			rContent.m_Filename = StringFromFormat("%s/%08x.app", m_Path.c_str(), rContent.m_ContentID);
		}

		// Be graceful about incorrect tmds.
		if (File::Exists(rContent.m_Filename))
		{
			rContent.m_Size = (u32) File::GetSize(rContent.m_Filename);
		}
	}

	delete [] pTMD;
	return true;
}
Example #6
0
/*
	解析文件,输出文件名
	返回:-1---打开错误,-2---文件不合法
		>0----文件解析成功
*/
JNIEXPORT jint JNICALL Java_com_example_android_bluetoothlegatt_MyNative_update_1fileParse
		(JNIEnv *env, jobject, jbyteArray file_name) {

	char *fileName = (char *) env->GetByteArrayElements(file_name,0 );

	FILE *fp;
	char buf[1024], *buf_temp, tempBuf[100];
	int versionStr_flag;
	int fileNum, fileSize, imageOffset;
	int i, j;
	char *pTempStr;
	unsigned long crc;
	tR11_UPDATEFILE_HEADER imageHeader[FILE_NUM_MAX];
	tR11_UPDATEFILE_HEADER *pHeader;
	U8 headerBuf[1024];

	fp = fopen(fileName, "rb");
//	for (int i = 0; i < 32; i++)
//	{
//		LOGI("string %X", headerBuf[i], 1024);//去字符串s%
//	}
	if (fp == NULL) {
		/* 文件打开错误 */
		LOGI("文件打开错误");
		return -1;
	}
	fread(&headerBuf[0], 1024, 1, fp);
//	for (int i = 0; i < 32; i++)
//	{
//		LOGI("string %X", headerBuf[i], 1024);//去字符串s%
//	}
	//fread(&imageHeader[0], FILE_NUM_MAX*sizeof(tR11_UPDATEFILE_HEADER), 1, fp);
	{
		/* 信息头AES解密 */
#include "aes.h"
		extern int AESDecode (BYTE *pUserKey, int keyLen, const char* srcString, int srcLen, char** dstString, int* dstLen);
#define USER_KEY_LEN	16
		const BYTE userKey[USER_KEY_LEN]=
				{
						0xEA, 0x45, 0x11, 0xEB, 0x02, 0xCE, 0x56, 0xAE,
						0xDE, 0x52, 0xEE, 0x42, 0xFC, 0x32, 0x7D, 0xCA
				};
		int ret;
		char *pcDecodeDst = NULL;
		int dstLen = 0;
		ret = AESDecode((BYTE *)userKey, USER_KEY_LEN, (const char *)headerBuf, 1024, &pcDecodeDst, &dstLen);
		if (ret == 0)
		{
			memcpy(&imageHeader[0], pcDecodeDst, FILE_NUM_MAX*sizeof(tR11_UPDATEFILE_HEADER));
		}
//		for (int i = 0; i < 48; i++)
//		{
//			LOGI("string %X",(jbyte) pcDecodeDst[i]);//去字符串s%
//		}
		free(pcDecodeDst);
	}

	fileNum = 0;
	for (i=0; i<FILE_NUM_MAX; i++)
	{
		pHeader = &imageHeader[i];
		/* 1. 判断标识 */
//		for (int j = 0; j < 16; j++)
//		{
//			LOGI("string %X", pHeader->idStr[j]);//去字符串s%
//		}
		int result = memcmp(& pHeader->idStr[0], R11_IMAGE_ID_STR, R11_IMAGE_ID_STR_LEN);
		if ( result != 0)
		{
			/* 标识错误,不再继续查找 */
//			for (int j = 0; j < 16; j++)
//			{
//				LOGI("string %X", pHeader->idStr[j]);//去字符串s%
//			}
//			for (int j = 0; j < 16; j++)
//			{
//				LOGI("string %X", imageHeader[i].idStr[j]);//去字符串s%
//			}
			LOGI("标识错误,不再继续查找 ,返回存在的头文件数量");
			break;
		}

		/* 2. 判断版本号字符 */
		versionStr_flag = 0;
		pTempStr = &pHeader->versionStr[0];
		for (j=0; j<9; j++)
		{
			if (pTempStr[j] != '.' &&
				(pTempStr[j] < '0' || pTempStr[j] > '9'))
			{
				/* 版本号字符错误 */
				LOGI("版本号字符错误 ");
				versionStr_flag = -1;
				break;
			}
		}
		if (versionStr_flag == -1)
		{
			/* 版本号字符错误,不再继续查找 */
			LOGI("版本号字符错误,不再继续查找 ");
			break;
		}
		/* 3. 判断硬件信息 */
		if (pHeader->hwInfo == 0)
		{
			/* 硬件信息错误 */
			LOGI("硬件信息错误 ");
			break;
		}

		/* 4. 判断升级数据大小 */
		if (pHeader->imageSize < R11_IMAGE_SIZE_MIN || pHeader->imageSize > R11_IMAGE_SIZE_MAX)
		{
			/* 升级数据大小错误,不再继续查找 */
			LOGI("升级数据大小错误,不再继续查找 ");
			break;
		}

		memcpy(&r11_updateImage[fileNum].header, pHeader, sizeof(tR11_UPDATEFILE_HEADER));
		buf_temp = &r11_updateImage[fileNum].data[0];
		fseek(fp, pHeader->imageOffset, SEEK_SET);
		fread(buf_temp, pHeader->imageSize, 1, fp);

		fileNum++;
	}
	fclose(fp);

	if (fileNum == 0)
	{
		/* 没有找到合法的image信息,文件错误 */
		LOGI("没有找到合法的image信息,文件错误 ");
		return -2;
	}

	validImageNum = fileNum;
	env->ReleaseByteArrayElements(file_name, (jbyte*)fileName, 1);
	return fileNum;
}