morkt / GARbro

Visual Novels resource browser
MIT License
2.31k stars 245 forks source link

Question: IDA with Decompiler plugin #146

Closed haniwa55 closed 6 years ago

haniwa55 commented 6 years ago

I tried IDA pro 7.0 and Hex Rays Decompiler plugin. I think that it is a very hard work to decrypt decompiled c source programs. I ran Shiinario 2.5 game title with the IDA debugger. However, it exits immediately after execution. Your GARbro has analyzed this game title encryption. The game title I debugged is "Libra of the Vampire Princess (English Version)". GARbro can not Browse "Libra of the Vampire Princess (Japanese Version)". The encryption of WAR 1.7 is different in English / Japanese Version. Therefore I tried the analysis so that GARbro can browse the Japanese version. However, debugging can not be executed and it exits. Do you have any thoughts about this? How did you analyze this game title encryption?

morkt commented 6 years ago

you don't have to run the game to analyze executable (unless executable image is packed/encrypted), usually you could just open it in disassembler and look. now, you've picked rather convoluted engine as an exercise in reverse engineering, but i'll try to help. look at ShiinaRio.EncryptionScheme class fields (i've omitted some irrelevant ones):

        public byte[] CryptKey;
        public uint[] HelperKey;
        public byte[] Region;
        public byte[] DecodeBin;
        public IByteArray       ShiinaImage;
        public IDecryptExtra    ExtraCrypt;

all those fields participate in archive decryption. CryptKey and Region don't change across games, so their values could be taken from other schemes. HelperKey and ShiinaImage arrays are always used in all schemes and vary in every game, DecodeBin and ExtraCrypt sometimes not used, but almost always used in games utilizing v2.50 engine.

ShiinaRio engine is tricky for a beginner because it uses some anti-debugging tricks, for example some of its functions have illegal x86 opcodes embedded in them that prevent IDA decompiler from working (although it can be fixed by patching the first byte of illegal opcodes with NOP instruction).

nevertheless, main decryption routine could be easily located by catching reference to WARC signature (this technique often works with formats that have some signature embedded in them). in IDA, use binary search (Alt+B) and search for "WARC" string (include quotes in search, without quotes IDA expects hex numbers). you should locate 'WARC 1.7' string. now, place cursor on its label and bring cross-references window (X button). the only reference to it should be from an archive read routine (it can't be decompiled without patching).

analyze the code flow from this point and somewhere below will be a call to decryption routine. in GARbro, that's what ShiinaRio.Decoder.DoEncryption method doing, so routine in question should follow similar logic. when you see a function that calls acos and sqrt, that's the one i'm talking about. this routine utilizes contents of ShiinaImage and HelperKey arrays, so they could be extracted from there.

ExtraCrypt part is a bit complicated. find cross-references to decryption subroutine - move cursor to its title and press X. usually it's called from two places - one reading archive index (that's where we came from) and the other reading entries. you need to locate the latter. it's protected from decompilation as well, but you still could follow its logic by comparing it with WarOpener.OpenEntry method from GARbro. routine that performs 'extra' crypt is called twice from there, first time with 0x202 parameter, and the second with 0x204. it's rather short and performs an indirect call to actual decryption subroutine preceded with a couple GetProcAddress calls. this subroutine is unavailable right away, because it's unpacked and put in place at run-time, still, you could obtain its code by following a reference where its address is written (in IDA cross-references dialog places where reference is written are marked with w).

or, you could search for "YPK" string in data segment, it's followed with some zlib-compressed data (starting with 0x78 signature byte), which could be extracted and analyzed separately. its size is stored right before YPK signature if i'm not mistaken. to export data from IDA, place cursor at the beginning of a block, press 'begin selection' (Alt-L), then jump to an end with G button and writing +XXXX as an address, where XXXX is a block size (hex number). then proceed with 'Export data' (Shift-E), 'Export as raw bytes'. resulting file should be decompressed with some utility that is able to handle raw zlib-compressed data (i'm using my own).

alternatively, you'd attach to a running game with debugger and look at this code when it was prepared by the game itself, but with games utilizing anti-debugger measures it's not that simple. although you still should be able to access their memory with such utilities as WinHex, dump it to disk, and then proceed with IDA.

now, if you were able to decompress this block, it could be open in IDA as a binary file with 32-bit code. follow assembler instruction from the very beginning, it should be a jump to 'extra' decryption routine. these routines are reflected in GARbro as ShiinaRio.IDecryptExtra interface implementations. basically, you have to determine, which class implements this particular encryption, or it could be some new, never seen before. [spoiler alert] in "Libra of the Vampire Princess" case it's ShojoMamaCrypt (i name them after the game in which i first saw it). its constructor has two parameters, a 32-bit key and a byte array. number is stored somewhere nearby that YPK block, almost immediately preceding it. byte array is a PNG image that contained within decompressed block - you could find it by analyzing decryption routine code, or just look for PNG/IEND signatures pair.

unfortunately, there's no easy way to add new encryption scheme to GARbro formats database, i do it myself with some private tools. i'll add "Kyuuketsuki no Libra" in the next beta release.

PeratX commented 6 years ago

Wow, that’s amazing. I think such reverse engineering also need the basic cryptography knowledge. I have only used IDA to decompile MC: PE to see how it encode network packets!

haniwa55 commented 6 years ago

Thank you very much for your many kind advice. I understood you do not use a debugger for your analysis. I made the S25 replacement program of WARC 1.7 the other day. I was reading ArcWARC.cs and WarcEncryption.cs program coding. Decoder. KnownSchemes of WARC 1.7 changes with game title. However, all encrypt methods were program coded. I used that encrypt methods. So it was not difficult to made the S25 replacement program of WARC 1.7. Therefore, I chose Shiinario 2.5 game title which GARbro can not browse. I will try the analysis while reading your advice. I think it will be a long time. Please let me question sometime again. So this issue is not closed yet. Thank you very much for your answer despite being so busy.

haniwa55 commented 6 years ago

I think that IDecryptExtra.Seed = 2830397842 from the memory dump of WinHex. IDecryptExtra.DecodeTable searches the binary "89504E" and I know the starting offset. However, I do not know what Length of IDecryptExtra.DecodeTable is calculated by referring. KeyDecryptExtra.EncryptedSize = 0xFF; Therefore it may be a different class from YuruPlusCrypt of English Version. If I know this Length I think that browse testing can be done with existing KeyDecryptBase subclasses. How do I calculate the Length of IDecryptExtra.DecodeTable?

haniwa55 commented 6 years ago

IDecryptExtra.DecodeTable was a PNG image file. I will examine how to find the length of the PNG image file.

haniwa55 commented 6 years ago

I'm sorry. You already taught me how to calculate the length of PNG image file.

just look for PNG/IEND signatures pair.

haniwa55 commented 6 years ago

There was a KeyDecryptExtra.DecryptPre () method in decompiled C source program of memory dumped. Therefore I think sub class of KeyDecryptExtra is ShojoMamaCrypt. I let KeyDecryptBase.DecodeTable loaded length 4547 bytes PNG image. And I changed the value of IDecryptExtra.Seed variously and tried it. They are 32 bit key near the YPK block. 0x3d237400, 0x3148593d, 0x00FFFFFF, 0x25078b18, 0x247c8b57, 0x56555690, 0x90909090 0x00001389, 0x00000019, 0xa8bc12b2, 0x003c0000, 0x0000188d, 0x00002307, 0x00f66964 0x464c5144, 0x474d4246, 0x4cae5a82, 0xf5bdcefc, 0xcfd5fbc9, 0xd2ffeae5, 0xffe8e4fd However, neither key was able to browse the S25 image. There is also the possibility that the method I tried is wrong. Or the Encryption of Japanese Version may be your never seen before.

morkt commented 6 years ago

0xA8BC12B2 seed should work, may be you got some other parameters wrong. what is the length of ShiinaImage array (should be 38224 bytes) and what are values of the HelperKey array (should be { 0xE5E513E2, 0xA5EB39FC, 0x1CEAE3EA, 0x0000E0EA, 0 })?

haniwa55 commented 6 years ago

GARbro can now browse S25 Images of Japanese Version by your answer. It is impossible for me to find ShiinaImage.Length and HelperKeys from decompiled C source program. Analysis without a debugger was a very hard work for me. However, I am glad that I learned lots of things I do not know with IDA & Decompiler plugin. Also this time I understood your analytical techniques and the difficulties of developing GARbro.

I have another question. "The Spirit Master of Retarnia" can not save memory dump with WinHex. "Error #2 Cannot read Primary memory." Do you know how to save memory dump in case of such error?

Thank you very much for your answer despite being so busy.

morkt commented 6 years ago

maybe WinHex should be run as administrator to read process memory. but from what i can tell, this game is built on Unity engine, which is a mix of native C++ and managed C# code, and to analyze the latter you'll need completely different set of tools. for one, ILSpy can decompile managed assemblies.

haniwa55 commented 6 years ago

WinHex was executed with administrator's privilege but memory dump could not be saved. I was checking the decryption of the ".png.utage" image file. The old utage file could be decrypted with the following method, it was written in 2ch BBS.

However, "The Spirit Master of Retarnia" can not be decrypted with this method alone. So I wanted to save a memory dump and check it. I will investigate ILSpy. Please teach your analytical techniques to me again. Thank you very much for your answer despite being so busy.