This morning The Multimedia Mike told me he’s found yet another undiscovered game video codec used in some games by Imagination Pilots (probably it’s in no way related to the fact the codec has FOURCCs IPMA
and IP20
). Surprisingly there’s a fandom that has REd most of the game formats and made a reasonable assumption that the codec would use LZW in the same way as image resources do.
And it turns out they were right. Frames in both versions of the codec are raw image buffers compressed with LZW. Pixel value 0 is used there for transparency and considering that those animations may use a transparent background as well there’s no difference between frame types at all.
So people who REd the rest of the formats just missed the final step and if they had frame extractor they could simply dump frame data, try to decompress it and see the result. You don’t need to look inside the binary specification for that (I did and it was not that useful even if I could recognize LZW decompression functions there).
The rest of the post I want to dedicate to ranting about Ghidra
failing to decompile it properly.
The problem with the binary specification is that it’s in New Executable format (used for Windows 3.x) which can mix 16- and 32-bit code. And while Ghidra
loads the format just fine it fails to decompile 32-bit part of it properly.
Here’s an example from the beginning of LZW decompression function:
1008:006d 66 c7 45 MOV dword ptr [DI + -0x4],0xc7660200 fc 00 02 66 c7 1008:0075 45 ?? 45h E 1008:0076 f2 ?? F2h 1008:0077 ff ?? FFh 1008:0078 ff ?? FFh 1008:0079 66 c7 45 MOV word ptr [EBP + -0xa],0xffff f6 ff ff
If you look at the actual byte sequence you’ll see it’s three commands using the same pattern 66 c7 45 fX YY YY
which means MOV word ptr [EBP + -off],val
with offset and immediate values being different. Yet the first command gets both immediate value length and destination register wrong. As the result decompiled output looks like this: “Exception while decompiling 1008:0024: Decompiler process died.”
And sadly not enough people care enough to fix that. While looking at other games I’ve discovered that there’s a lot of loaders for console formats and non-IBM PCs. But e.g. Linear Executable loader is neglected and this situation with assembler makes REing mixed 16- and 32-bit code (late DOS and early Windows) quite hard.
I know, I’m a part of the problem for not willing to dive into Java and fix at least something myself, but I also have something better to do (it’s like eating dwarf bread by non-dwarfs—a single look at it makes you realize that you’d rather eat anything else). Maybe if I used it a bit more often I’d get annoyed enough to do something about it but for now I simply sigh and move on.
Nice! Discovered and documented in under 24 hours!