Hacker News new | past | comments | ask | show | jobs | submit login
Pack arbitrary files into PNG and access them using JavaScript (github.com/haxorplatform)
67 points by pierrec on April 4, 2015 | hide | past | favorite | 29 comments



I first learned about this technique from Cody Brocious' post (http://daeken.com/superpacking-js-demos) about his WebGL demo 'Magister' (http://demoseen.com/windowpane/magister.html). That file has a .html extension, but it's also a valid PNG. In his post, he discusses this technique as well as others.

Cody's goal was to compress already minified WebGL code and achieve some pretty impressive results from a ridiculously small file for a demo contest. He also put the JS loader (which is much smaller than the linked decoder) in a custom chunk on the PNG itself. By doing it that way, you can have a PNG that when renamed also contains a web page and/or more Javascript.

It's an interesting technique, for sure, but I've never been able to find a real use for it beyond the compression. With a content-type sniffing vulnerability or something, it could be an interesting way to deliver content to browsers, but otherwise it's really just a curiosity as best I can tell.


This is really clever. Unfortunately, the linked page doesn't seem to have the bootstrap code that has the magic of getting from a PNG to a web page. Is this around somewhere? (I could download the demo PNG and extract it myself, but I'm hoping not to have to do that...)


Right, just rung strings on the demo and you'll see the custom PNG chunk:

``` jawh<img onload=with(document.createElement('canvas'))p=width=4968,(c=getContext('2d')).drawImage(this,e='',0);while(p)e+=String.fromCharCode(c.getImageData(0,0,p,1).data[p-=4]);(t=top).eval(e) src=#> ```


This is pretty great. I also built something similar a while back that would let you post torrents to message boards as images:

https://github.com/mnutt/hid.im/blob/master/public/firefox-e...


I guess this would be useful with Amazon's free unlimited cloud photo storage.


A small (631 bytes) JPEG concatenated with your file of choice (preferably encrypted) accomishes what you're thinking.

But you run the risk of a ToS violating, losing your files and having your account banned.


Only if they leave the photo as a losslessly compressed png. They might convert to a lossy JPEG on upload, which means your data is toast.


Two can play at that game. You can store data in JPEG that can even survive recompression with lower quality. If it's worth it to you to go to all that trouble, that is.


Interesting paper: Bypassing Cloud Providers’ Data Validation to Store Arbitrary Data [1]

>JPG & PNG Steganography Encoder (JPG-PNGStega). The purpose of this encoder is to inject data (hiding it) in JPG and PNG files. It takes a File Format Sample (JPG or PNG) and, for each pixel, it injects 3 bits of data in the LSBs (Least Significant Bit). There are more sophisticated image steganography methods already widely discussed. However, the use of this encoder shows that even basic meth- ods of JPG and PNG steganography are possible in SaaS applications, and the exploitation of such method may bring impacts

http://arxiv.org/ftp/arxiv/papers/1404/1404.2637.pdf


The only use I see for this is for compressing files uploaded to a hosting where you can't enable gzip encoding. I already use static gzip encoding in all my deployments and I got less problems with cross-origin requests from custom-coded binary files than from images.


Most people won't find any real-world use for this, but it's cool/clever enough by itself that it's worth the author's time and effort.


Definitely. In fact it's one of the first things I considered when I started moving the mesh format of my engine from JSON to binary.


I'm not sure what the use case for this is, but you can also add arbitrary data to PNG files by adding a custom chunk. As long as the chunk is marked as ancillary (the first letter of the chunk type is in lower case), it will not affect image decoding.


Contrarily to the appending trick that you mention, this allows you to apply PNG compression to your arbitrary data, and then make use of the browser's decompression capabilities on it.

Though that's still kind of an odd use case, since we have gzip encoding for that.


Any ideas why I would want to do this?


Circumventing censorship; need to move arbitrary data, but only convenient transport is image format.


Imagine if lots of sites added a 1MB image that contained the information that various governments want censored.


Getting around the same-origin policy for GET-ing binary resources?


How would this get you around the same origin policy?


Instead of doing $.get([remoteScript]), you inject img tags that point to prebuilt PNGs on a different server and decode them after they load.

I could be wrong, but doesn't that work?


It doesn't. You can load the img tag, but the browser will not let you access the image itself from javascript, unless you have the proper CORS headers.


Quite right - it will complain that the canvas is "tainted" and won't let you do useful things like calling `getImageData`.


Ah -- useful to know. Thanks for the corrections, folks.


imgur allows any origin


They ask the server to fetch this URL. The client doesn't upload it.


I think the trick originated in demoscene size coding or possibly js5k. By encoding the script as a PNG you let the browser do the decompression and bootstrap it with some tiny piece of javascript.


Nice, how large can the archives become? I guess there is a size limit, which may be different for different browsers.

Also, I wonder how difficult it would be to port a decompression library to asm.js.


Author here!

The need appeared when I was doing my WebGL game engine and wanted to pack/compress mesh, texture, xml and any other stuff that would bloat my loading time with tons of HTTP requests!

Also the browser's native PNG decompression would be faster than any external JS lib for lossless decompression.

I limited it to a 16k x 16k PNG (but I think modern browsers can take more than that), allowing 1GB of data.


> Significantly reduce the number of HTTP requests allowing fast page loads

I wonder how true this holds with HTTP/2.0, where resources are loaded in parallel over a single TCP connection.




Join us for AI Startup School this June 16-17 in San Francisco!

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: