I don't know if it's right. It's supposed to help you.
Compressed resource format of a game
Two structures are involved :
Code: Select all
struct st_NpkHeader
{
int _magic;// [_offset + 0]
int _count;// [_offset + 4] size(count * 28)
int _unknonw2;
int _unknonw3;
int _bUseTrunkCompressType;
int _offset;
};
20170118163246801.png
Code: Select all
struct st_NpkTrunk
{
int _trunkHash;
int _dataOffset;
int _compressSize;
int _realSize;
int _unknown1;
int _unknonw2;
int _compressType;
};
20170118163253963.png
Full code:
Code: Select all
// UnNpk.cpp : Define the entry point for the console application.
//
#include "./liblz4/lz4.h"
#include "./zlib/zlib.h"
#include "stdafx.h"
#include <string>
#include <io.h>
#include <direct.h>
struct st_NpkHeader
{
int _magic;// [_offset + 0]
int _count;// [_offset + 4] size(count * 28)
int _unknonw2;
int _unknonw3;
int _bUseTrunkCompressType;
int _offset;
};
struct st_NpkTrunk
{
int _trunkHash;
int _dataOffset;
int _compressSize;
int _realSize;
int _unknown1;
int _unknonw2;
int _compressType;
};
std::string GetNpkFileName(char *pData, unsigned int maxLen)
{
std::string name;
for (int i = 0; i < maxLen; ++i)
{
if ((pData[i] >= 'a' && pData[i] <= 'z')
|| (pData[i] >= 'A' && pData[i] <= 'Z') )
{
name += pData[i];
}
}
return name;
}
int _tmain(int argc, _TCHAR* argv[])
{
if (argc < 2)
{
printf("%s npkFile\n", argv[0]);
return 0;
}
FILE *fp = fopen(argv[1], "rb");
if (!fp)
{
return 0;
}
unsigned int nFileLen = 0;
fseek(fp,0,SEEK_END); //Navigate to the end of the file
nFileLen = ftell(fp); //file length
fseek(fp,0,SEEK_SET);
st_NpkHeader npkHeader;
fread(&npkHeader, sizeof(npkHeader), 1, fp);
if (npkHeader._magic != 0x4b50584e)
{
printf("not npk file\n");
return 0;
}
fseek(fp,0,SEEK_SET);
st_NpkTrunk* pNpkTrunkList = new st_NpkTrunk[npkHeader._count];
std::string strDir = "./Dump";
if (_access(strDir.c_str(), 0) != 0)
{
_mkdir(strDir.c_str());
}
fseek(fp, npkHeader._offset,SEEK_SET);
int nRSize = fread(pNpkTrunkList, sizeof(st_NpkTrunk), npkHeader._count, fp);
for (int i = 0; i < nRSize; ++i)
{
fseek(fp, pNpkTrunkList[i]._dataOffset, SEEK_SET);
char *pSrc = new char[pNpkTrunkList[i]._compressSize];
fread(pSrc, pNpkTrunkList[i]._compressSize, 1, fp);
char *pDst = new char[pNpkTrunkList[i]._realSize];
if (pNpkTrunkList[i]._compressType == 2)
{
LZ4_decompress_safe(pSrc, pDst, pNpkTrunkList[i]._compressSize, pNpkTrunkList[i]._realSize);
}
else if (pNpkTrunkList[i]._compressType == 1)
{
int realSize = pNpkTrunkList[i]._realSize;
int nRet = uncompress((Bytef *)pDst, (uLongf*)&realSize, (Bytef *)pSrc, pNpkTrunkList[i]._compressSize);
}
else
{
memcpy(pDst, pSrc, pNpkTrunkList[i]._realSize);
}
char fileName[126];
std::string format = GetNpkFileName(pDst, 5);
sprintf_s<126>(fileName, "%s/%x.%s", strDir.c_str(), pNpkTrunkList[i]._trunkHash, format.c_str());
FILE *fp2 = fopen(fileName, "wb");
fwrite(pDst, pNpkTrunkList[i]._realSize, 1, fp2);
fclose(fp2);
delete[] pSrc;
delete[] pDst;
}
return 0;
}
I wish you success in decryption:)