东方深秘录解包工具源代码【需对应修改】
出于我并不是th135pak的作者,我没法直接发所有源文件以下提及的函数需要在Riatre大神的th135pak中对应修改才能使用。
本来以为黄昏在正式版当中封入了文件名,,,,结果并没有。。。
我跑了个彩虹表,,,能有3、4千文件名,,,,实在跑不动了。。。。。
以下代码请在有限范围内任意使用。。。
话说我要不要挂一份去github。。。
const unsigned char PUBLIC_KEY_N = {
0xC6, 0x43, 0xE0, 0x9D, 0x35, 0x5E, 0x98, 0x1D, 0xBE, 0x63, 0x6D, 0x3A, 0x5F, 0x84, 0x0F, 0x49,
0xB8, 0xE8, 0x53, 0xF5, 0x42, 0x06, 0x37, 0x3B, 0x36, 0x25, 0xCB, 0x65, 0xCE, 0xDD, 0x68, 0x8C,
0xF7, 0x5D, 0x72, 0x0A, 0xC0, 0x47, 0xBD, 0xFA, 0x3B, 0x10, 0x4C, 0xD2, 0x2C, 0xFE, 0x72, 0x03,
0x10, 0x4D, 0xD8, 0x85, 0x15, 0x35, 0x55, 0xA3, 0x5A, 0xAF, 0xC3, 0x4A, 0x3B, 0xF3, 0xE2, 0x37
};
int Decrypt6432(const unsigned char* src,unsigned char* dst,size_t dstLen)
{
if(keyInitialized == -1) InitRSAKeyPair(0);
if(dstLen > 0x20) return -1;
unsigned char tmp = {0};
DecryptBlock(src,tmp);
unsigned char*lp = tmp + 2;
while (*lp++ == 0xff);
memcpy(dst, lp, dstLen);
return 0;
}
int DecodeFile(unsigned char* src, unsigned char* dst, size_t Len, byte* __key)
{
memcpy(dst, src, Len);
unsigned char* currentlp = dst;
DWORD uk1 = *(DWORD*)__key, uk2 = *(DWORD*)__key;
byte key = { 0 };
memcpy(key, __key, 16);
memcpy(key+16, __key, 4);
if (!strncmp((char*)(currentlp), "TFWA", 4) || !strncmp((char*)(currentlp), "TFBM", 4) || !strncmp((char*)(currentlp), "OggS", 4) || !strncmp((char*)(currentlp+2), "RI", 2))
{
uk2 = *(DWORD*)currentlp;
currentlp += 4;
uk2 >>= 8;
uk2 += (*currentlp)*0x1000000;
*currentlp^= *(key + 4);
*currentlp ^= *(currentlp-4);
currentlp++;
}
if (Len & 1)
{
DWORD tmpKey = uk2 >> 8;
tmpKey += (*currentlp) * 0x1000000;
unsigned long current = (currentlp - dst) & 0xf;
(*(byte*)currentlp) ^= *(byte*)(key + current);
(*(byte*)currentlp) ^= LOBYTE( uk2);
uk2 = tmpKey;
currentlp ++;
}else
if (Len & 2)
{
DWORD tmpKey = HIWORD(uk2) + LOWORD((*(DWORD*)currentlp)) * 0x10000;
unsigned long current = (currentlp - dst) & 0xf;
(*(WORD*)currentlp) ^= *(WORD*)(key + current);
(*(WORD*)currentlp) ^= LOWORD(uk2);
currentlp += 2;
uk2 = tmpKey;
}
if (currentlp < dst + Len)
{
do
{
DWORD tmp = *(DWORD*)currentlp;
unsigned long current = (currentlp - dst) & 0xf;
(*(DWORD*)currentlp) ^= *(DWORD*)(key + current);
(*(DWORD*)currentlp) ^= uk2;
uk2 = tmp;
currentlp += 4;
} while (currentlp < dst + Len);
}
return 0;
}
DWORD SpecialFNVHash(char *begin, char *end, DWORD initHash = 0x811C9DC5u)
{
DWORD hash;
byte ch;
int inMBCS = 0;
for (hash = initHash; begin != end; hash = (hash^ch) * 0x1000193)
{
ch = *begin++;
if (ch == '/') ch = '\\';
if (!inMBCS && ch>=128)
inMBCS = 2;
if(!inMBCS)
{
ch = tolower(ch);// bad ass style but WORKS PERFECTLY!
}
else inMBCS--;
}
return hash;
}
int ExtractAll(const wchar_t* ArchiveFileName,const wchar_t* OutputFolder)
{
HANDLE hFile = CreateFile(ArchiveFileName,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_FLAG_RANDOM_ACCESS,NULL);
HANDLE hInMapping = CreateFileMapping(hFile,NULL,PAGE_READONLY,0,GetFileSize(hFile,NULL),NULL);
BYTE* pPackage = (BYTE*)MapViewOfFile(hInMapping,FILE_MAP_READ,0,0,0);
if(hFile == INVALID_HANDLE_VALUE || hInMapping == INVALID_HANDLE_VALUE || !pPackage)
return 0;
DWORD Magic = *(DWORD*)pPackage;
if(Magic != 'KPFT')
return 0;
DWORD cur = 0x5;
DWORD DirCount = 0;
Decrypt6432(pPackage + cur, (BYTE*)&DirCount, sizeof(DWORD));
cur += KEY_BYTESIZE;
std::unordered_map<DWORD, std::pair<char*, char*> > hashToName;
if (DirCount)
{
DIRLIST* DirList = new DIRLIST;
ZeroMemory(DirList, DirCount*sizeof(DIRLIST));
for (int i = 0; i < DirCount; i++)
{
Decrypt6432(pPackage + cur, (BYTE*)&DirList, sizeof(DWORD) * 2);
cur += KEY_BYTESIZE;
}
FNHEADER fnh;
ZeroMemory(&fnh, sizeof(FNHEADER));
Decrypt6432(pPackage + cur, (BYTE*)&fnh, sizeof(FNHEADER));
cur += KEY_BYTESIZE;
BYTE* CompFN = new BYTE;
for (int i = 0; i < fnh.BlockCnt; i++)
{
Decrypt6432(pPackage + cur, CompFN + i*KEY_BYTESIZE / 2);
cur += KEY_BYTESIZE;
}
char* FNList = new char;
DWORD realOrigSize = fnh.OrigSize;
ZeroMemory(FNList, fnh.OrigSize);
uncompress((BYTE*)FNList, &realOrigSize, CompFN, fnh.CompSize);
delete[] CompFN;
HANDLE hTemp = CreateFile(L"fnlist.txt",GENERIC_READ|GENERIC_WRITE,0,NULL,CREATE_ALWAYS,FILE_FLAG_RANDOM_ACCESS,NULL);
WriteFile(hTemp,FNList,fnh.OrigSize,&realOrigSize,NULL);
CloseHandle(hTemp);
assert(fnh.OrigSize == realOrigSize);
DWORD fnPos = 0;
for (int i = 0; i < DirCount; i++)
{
for (int j = 0; j < DirList.FileCount; j++)
{
int tlen = strlen(FNList + fnPos);
DWORD NameHash = -SpecialFNVHash(FNList + fnPos, FNList + fnPos + tlen, DirList.PathHash);
hashToName = std::make_pair(DirList.Path, FNList + fnPos);
fnPos += tlen + 1;
}
}
}
DWORD FileCount = 0;
Decrypt6432(pPackage + cur, (BYTE*)&FileCount, sizeof(DWORD));
cur += KEY_BYTESIZE;
unordered_map<DWORD, FileLST> fileList;
vector<DWORD> hashList;
for (int i = 0; i < FileCount; i++)
{
QWORD fileDes = {0};
Decrypt6432(pPackage + cur, (BYTE*)&fileDes, sizeof(QWORD));
cur += KEY_BYTESIZE;
QWORD hashDes = { 0 };
Decrypt6432(pPackage + cur, (BYTE*)&hashDes, sizeof(QWORD));
cur += KEY_BYTESIZE;
DQWORD XorKeys = { 0 };
Decrypt6432(pPackage + cur, (BYTE*)&XorKeys, sizeof(DQWORD));
cur += KEY_BYTESIZE;
fileDes.HIDWORD ^= XorKeys.HIQWORD.HIDWORD;//FileSize
fileDes.LODWORD ^= XorKeys.HIQWORD.LODWORD;//FileOffset;
//fileDes.LODWORD += FileBegin;
hashDes.HIDWORD ^= XorKeys.LOQWORD.HIDWORD;
hashDes.LODWORD ^= XorKeys.LOQWORD.LODWORD;
DWORD hash = hashDes.HIDWORD;
hashList.push_back(hash);
fileList.size = fileDes.HIDWORD;
fileList.offset = fileDes.LODWORD;
fileList.unKey = hashDes.LODWORD;
memcpy(fileList.xorKey, &XorKeys, 16);
for (unsigned int i = 0; i<4; i++)
{
((DWORD*)fileList.xorKey) = -((DWORD*)fileList.xorKey);
}
}
DWORD FileBegin = cur;
for (unsigned int i = 0; i < hashList.size(); i++)
{
DWORD cHash = hashList;
byte* loadDst = (byte*)calloc(1, fileList.size + 4);
DecodeFile(pPackage + fileList.offset + FileBegin, loadDst, fileList.size, fileList.xorKey);
WCHAR path = { 0 };
if (dirHashToName.find(cHash)==dirHashToName.end())
{
char* extend = NULL;
if (!strncmp((char*)loadDst, "TFCS", 4))//人家说函数返回值不要是布尔,果然很难理解= =
{
extend = ".csv";
}
else if (!strncmp((char*)loadDst, "OggS", 4))
{
extend = ".ogg";
}
else if (!strncmp((char*)(loadDst + 2), "RIQS", 4))
{
extend = ".nut";
}
else if (!strncmp((char*)(loadDst + 2), "xml", 3))
{
extend = ".xml";
}
else if (!strncmp((char*)(loadDst), "ACT", 3))
{
extend = ".act";
}
else if (!strncmp((char*)(loadDst), "#===", 4))
{
extend = ".pl";
}
else if (!strncmp((char*)(loadDst), "DDS", 3))
{
extend = ".dds";
}
else if (!strncmp((char*)(loadDst), "OTTO", 4))
{
extend = ".otf";
}
else if (!strncmp((char*)(loadDst), "TFBM", 4))
{
extend = ".bmp";
}
else if (!strncmp((char*)(loadDst), "TFWA", 4))
{
extend = ".wav";
}
else if (!strncmp((char*)(loadDst), "IBMB", 4))
{
extend = ".bmb";
}
else if (!strncmp((char*)(loadDst), "TFPA", 4))
{
extend = ".bmp";
}
else
{
extend = ".null";
}
swprintf(path, L"%s%x%s", OutputFolder, cHash, extend);
}
else
{
swprintf(path, L"%s%s", OutputFolder, dirHashToName.data());
}
CreateDirectoryForPath(path);
DWORD rb = 0;
HANDLE Hload = CreateFile(path, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, 0, OPEN_ALWAYS, 0, 0);
WriteFile(Hload, loadDst, fileList.size, &rb, NULL);
CloseHandle(Hload);
free(loadDst);
cout << ".";
}
UnmapViewOfFile(pPackage);
CloseHandle(hInMapping);
CloseHandle(hFile);
return 1;
} {:16_458:}本来是自己写了一段代码的,结果一看正式版的封包比起web版又改了,又回到了古老的模式,,,我干脆就又用th135pak的代码做基础改了。。。
丧病的黄昏体验版里对RSApublicKey的加密在正式版里居然没了。。 要找文件名的话,还不如过一遍脚本里面的字符串来得快 文件名我直接扒内存找了 文件名我直接扒内存找了 哇,大触!技术群里新来的那位特地在群里问起您了…… 为何不直接丢到GitHub呢
页:
[1]