song_5007 发表于 2015-5-16 23:49:52

东方深秘录解包工具源代码【需对应修改】

出于我并不是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;
}

song_5007 发表于 2015-5-16 23:54:55

{:16_458:}本来是自己写了一段代码的,结果一看正式版的封包比起web版又改了,又回到了古老的模式,,,我干脆就又用th135pak的代码做基础改了。。。

丧病的黄昏体验版里对RSApublicKey的加密在正式版里居然没了。。

漆黑之翼 发表于 2015-5-17 12:20:47

要找文件名的话,还不如过一遍脚本里面的字符串来得快

nyfair 发表于 2015-5-17 18:22:28

文件名我直接扒内存找了

nyfair 发表于 2015-5-17 18:22:35

文件名我直接扒内存找了

notebook 发表于 2015-5-28 22:46:01

哇,大触!技术群里新来的那位特地在群里问起您了……

古明地黒子 发表于 2015-5-28 23:32:35

为何不直接丢到GitHub呢
页: [1]
查看完整版本: 东方深秘录解包工具源代码【需对应修改】