Users browsing this thread: 4 Guest(s)
Compressed PNG files?
#1
Hi everybody, it's me again.

So I have this mobile game called "Pocket All Star" which is some bootleg RPG featuring most of the Nintendo characters and such. I'm surprised we haven't had sheets posted here already because my god the graphics aren't half bad.

The issue here is,  no image manipulation program will open them at all. I've heard that they're apparently compressed or something. Nobody that I've talked to can decompress them.

So I've attached a folder with a few of the files in hopes someone will be interested enough to decode them.


Attached Files
.zip   Fake PNGS.zip (Size: 304.23 KB / Downloads: 180)
Reply
Thanked by:
#2
Looking at box2-open.png with a hex editor, the first $12 bytes look like this:
89 50 5F A2 0D 0A 0B EF 00 00 11 E8 49 48 55 B7 00 00 11 AE
A standard PNG should look like this:
89 50 4E 47 0D 0A 1A 0A 00 00 00 0D 49 48 44 52 00 00 00 AF

Do you see what's wrong?
Every other word is wrong, every other word is right. I bolded them for you:
__compressed: 89 50 5F A2 0D 0A 0B EF 00 00 11 E8 49 48 55 B7 00 00 11 AE
uncompressed: 89 50 4E 47 0D 0A 1A 0A 00 00 00 0D 49 48 44 52 00 00 00 AF

Very peculiar. That's the only lead I've got right now.

EDIT: If you wish for more help/insight, it's always wise to include as much as files as possible. Excluding obvious false positives like "MUSIC.DAT" or something, you should try uploading _all_ the PNGs and any other suspicious file that might reside in the filesystem.
EDIT: The nibbles of every compressed word's first byte are always the uncompressed one's counterpart ±1!
EDIT: The second nibbles of every compressed word's second byte are always the uncompressed one's counterpart ±5!
Once there was a way to get back homeward
Reply
Thanked by: That Guy Sebi
#3
actually i didnt really know my terms then. every other nibble, add +1 to the numbers/letters in the first half of the data (remember that there is no g and above, so you might wrap to zero) and add +5 to the second half
Reply
Thanked by:
#4
First off sorry, I did look at these earlier but gave up pretty quick. Raccoon Sam is a bit more persistent than me and actually bothers to try find some patterns. With the information he posted I've managed to find out some more stuff though.

I decided to look into this at the bit level, and it seems that for there's some XORing going on. A quick primer on what the heck XORing is:


Bits are ones and zeros, right? For example, 5 in binary is 0101 (for clarity all binary numbers will be green and bold). Why the zero at the start? When representing binary we usually do it in nibbles (chunks of 4 bit) to make them easier to read. As a byte (8 bits i.e. 2 nibbles) 5 is 0000 0101. Pretty simple.

XORing is when you take two numbers, in binary, and do an operation. The operation takes each two corresponding bits, and compares them. If they're the same, the result is a 0. If they're different, the result is a 1.

As an example, let's say we have 1101 (13) and 0101 (5). If we XOR them, we get 1000 (8). Here's how it works:


      15 = 1101
       5 = 0101
15 XOR 5 = 1000


You can see that everywhere there were two different digits we put a 1, and if they were the same we put a 0. Everything matched except the first digit, so the result is 1000 Hopefully that made sense!

(A final note for those interested: XOR is reversible. If A XOR B = C, you can XOR C with A to get B, or B to get A. This means that if we XOR 1000 (8) with 0101 (5), we'll get back to 1101 (13). Very handy, and this is why XORing is a common technique for obfuscation.)


I checked it out, and for the first bytes you guys were onto it. Every first byte is XORed with $11 (17), which is 0001 0001. This means you either add or subtract 1 from each nibble, depending on what's already there.

The second bytes are a bit harder. It seems that every second byte is XORed with $E5 (229), which is 1110 0101, except the last one. However, Sam was looking at the first $14 bytes, not $12. Looking at some PNGs, bytes $12 and $13 seem to differ between them.

I also checked out some of the other fake PNGs. Some were XORed with different values, some in differently sized chunks. Wasn't sure how to find the proper numbers, but I tried some and then I decided to take a look at the file size.

BINGO.

Do you know what the size of box2-open.png is? $11 E5. (Putting spaces to make numbers easier to read.)

That's not even all. The file that had differently sized chunks was cg01_di.png. For each chunk of 4 bytes (long or double word) in this file, the first one was fine, then the next 3 obfuscated. I checked the size, it's $03 35 93. That's 3 bytes worth of data.

Basically, what it seems you do is you take the file's size, express it as 4 bytes, then XOR that with every 4 bytes of the file. $00 00 11 E5 XORed with $89 50 4E 47 is $89 50 5F A2. Perfect.

At this point, I decided to go to the end of the file to see if I could find anything, since that's usually where any info is if it's not at the start. Sure enough, there was the size, plus $800. Not sure why it's $800, but it does look like the last $0C or so bytes of the file should be shaved off.

Phew. So it seems like that's the most of it. I don't think it's as simple as XORing the whole file (I couldn't find any traces of an IEND chunk) but I'll see if I can make a small program to test this out and see what discrepancies pop out.
You may have a fresh start any moment you choose, for this thing that we call "failure" is not the falling down, but the staying down. -Mary Pickford
Reply
Thanked by: shadowman44, Raccoon Sam
#5
Excellent research, puggsoy!!
In the end we figured it out — there are four Big Endian longs at the end of each file and they act as the decryption information. Here's shade.png's, for example (commentated):

0x2017: 00 00 00 00 // always 00 00 00 00
0x201B: 00 00 00 43 // how many bytes to XOR
0x201F: 00 00 28 23 // the XOR value itself (must subtract $800 first)


That's basically it. In this case, XOR the first $43 bytes with the value $00002023.
The files aren't encrypted, only their headers (usually just the first sixty-something bytes).

There are no IEND terminators, so if you really wanted standard-compliant files, the last thing you'd do after decryption was delete the last $C bytes and replace them with 00 00 00 00 49 45 4E 44 AE 42 60 82.


puggsoy is working on a BMS script so until then
Once there was a way to get back homeward
Reply
Thanked by: puggsoy
#6
Bam, here you go!

Code:
# Pocket All-Star .png format
#
# Written by puggsoy (with help from Raccon Sam)
# script for QuickBMS http://quickbms.aluigi.org

endian big

goto -0xC
get ZERO long
get HEADSZ long
get KEY long
math KEY -= 0x800 # not sure why it's 0x800 larger than it needs to be
goto 0

get FILESIZE asize
putvarchr MEMORY_FILE FILESIZE 0
log MEMORY_FILE 0 0

filexor KEY
log MEMORY_FILE 0 HEADSZ

filexor 0
append
set TAILSZ FILESIZE
math TAILSZ -= HEADSZ
log MEMORY_FILE HEADSZ TAILSZ

putvarchr MEMORY_FILE -0xC 0x00000000 long
putvarchr MEMORY_FILE -0x8 0x49454E44 long
putvarchr MEMORY_FILE -0x4 0xAE426082 long

append 1
get SIZE asize MEMORY_FILE
get NAME basename
string NAME += ".png"
log NAME 0 SIZE MEMORY_FILE

Even did what Raccoon Sam suggested and replaced the decryption info with an IEND terminator (since the official specification says it's required and some programs may look for it). Works with all the supplied files so hopefully it does for all of them!
You may have a fresh start any moment you choose, for this thing that we call "failure" is not the falling down, but the staying down. -Mary Pickford
Reply


Forum Jump: