Obfusc-a-tweet Reloaded
November-December 2015
Abusing Twitter's URL shortener to store and execute ~16kb of JavaScript from a single tweet!
You can read this article explaining how it works.
Or head directly to the packer!
Obfusc-a-tweet: How many JavaScript code can we fit in 140 characters?
November 2013, May 2014, May 2016
The answer is: 190 194 characters!
On 140byt.es, the goal is to write JavaScript functions that fit in a tweet, i.e. in 140 characters.
Until now, these functions were always written in "clear" ASCII characters. But a tweet can contain 140 Unicode characters, including the "astral" ones, encoded on 4 bytes.
So I had the idea to use this encoding (UTF-16) to compress a long JavaScript code, and insert this encoded string in a JavaScript expression able to decode and execute it, while respecting the 140 chars limitation.
Here's the binary representation of an astral UTF-16 character. It is composed of two 16-bit halves (or "surrogates"), in which the first 6 bits are fixed. The last 10 bits (shown as "x" here) can take any value.
110110xx xxxxxxxx 110111xx xxxxxxxx
Here's the binary representation of the string "ABCD" (in ASCII). Each character is encoded in 1 byte.
(In reality, 7 bits are enough to encode an ASCII character, but in modern charsets, the 8th bit is let at 0).
01000001 01000010 01000011 01000100
So the idea is to use only astral UTF-16 characters and store an ASCII character at the end of each surrogate.
Here's the string "ABCD" stored in 2 UTF-16 characters (2 chars in one: that's a compression ratio of 50%!):
11011000 01000001 11011100 01000010 11011000 01000011 11011100 01000100 ==> 𠑂𠱄
|--A---| |--B---| |--C---| |--D---| (ABCD encoded)
Here's an encoder (129 bytes long) that makes this compression:
z=function(b,c,a,f,e){c="";f=String.fromCharCode;for(a=0;190>a;a+=2)c+=f(55296+b[e="charCodeAt"](a))+f(56320+b[e](a+1));return c}
And here is the expression decoding and executing the original JavaScript code (thanks to @subzey for his help):
// replace "𠑂𠱄" with your encoded string
eval(unescape(escape`𠑂𠱄`.replace(/uD./g,'')))
This decoder-executer is only 43 bytes long. So we can execute 194 ((140 - 43) x 2) JS characters in a single tweet.
Demo:
Now there's an app for that: Obfusc-a-tweet !