Advent Calendarで書いてもよかったかもしれませんが、どちらかと言うと逆かなーとか思ったのでこちらで。 aaencodeと言えば、はせがわさんが作ったjavascript向けの
サーバ上のjavascriptファイルを可視状態で編集してもクライアントからは難読化されて見えるという代物。実装としてはapacheのOutputフィルタモジュールとなります。
aaencodeは実装としては結構簡単な作りなのでソース全体を公開します。
/**
* mod_aaencode -- apache filter module encoding to japanese style emoticons.
*
* AUTHOR:
* Yasuhiro Matsumoto <mattn.jp@gmail.com> a.k.a mattn
*
* ORIGINAL IDEA:
* Yosuke HASEGAWA, http://utf-8.jp/
*
* COMPILING:
*
* for Windows:
* apxs2 -i -a -c -Wc,-O2 mod_aaencode.c \
* libapr-1.lib libaprutil-1.lib libhttpd.lib
*
* for UNIX:
* apxs2 -i -a -c -Wc,-O2 mod_aaencode.c -lapr-1 -laprutil-1
*
* INSTALLATION:
* add following line into your '.htaccess'.
*
* AddOutputFilter AAENCODE .js
*/
#include "httpd.h"
#include "http_config.h"
#include "http_protocol.h"
#include "http_log.h"
#include "ap_config.h"
#define PUT(f, bb, s) \
APR_BRIGADE_INSERT_TAIL(bb, \
apr_bucket_immortal_create(s, strlen(s), f->c->bucket_alloc))
#define CTOI(c) ( \
(c >= '0' && c <= '9') ? (c - '0') : \
(c >= 'a' && c <= 'f') ? (c - 'a' + 10) : \
(c >= 'A' && c <= 'F') ? (c - 'A' + 10) : -1)
static char
utf8len_tab[256] = {
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,6,6,1,1,
};
static char
utf8len_tab_zero[256] = {
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,6,6,0,0,
};
static int
utf_ptr2len(unsigned char* p) {
int len;
int i;
if (*p == 0)
return 0;
len = utf8len_tab[*p];
for (i = 1; i < len; ++i)
if ((p[i] & 0xc0) != 0x80)
return 1;
return len;
}
static int
utf_ptr2char(unsigned char* p) {
int len;
if (p[0] < 0x80) /* be quick for ASCII */
return p[0];
len = utf8len_tab_zero[p[0]];
if (len > 1 && (p[1] & 0xc0) == 0x80) {
if (len == 2)
return ((p[0] & 0x1f) << 6) + (p[1] & 0x3f);
if ((p[2] & 0xc0) == 0x80) {
if (len == 3)
return ((p[0] & 0x0f) << 12) + ((p[1] & 0x3f) << 6)
+ (p[2] & 0x3f);
if ((p[3] & 0xc0) == 0x80) {
if (len == 4)
return ((p[0] & 0x07) << 18) + ((p[1] & 0x3f) << 12)
+ ((p[2] & 0x3f) << 6) + (p[3] & 0x3f);
if ((p[4] & 0xc0) == 0x80) {
if (len == 5)
return ((p[0] & 0x03) << 24) + ((p[1] & 0x3f) << 18)
+ ((p[2] & 0x3f) << 12) + ((p[3] & 0x3f) << 6)
+ (p[4] & 0x3f);
if ((p[5] & 0xc0) == 0x80 && len == 6)
return ((p[0] & 0x01) << 30) + ((p[1] & 0x3f) << 24)
+ ((p[2] & 0x3f) << 18) + ((p[3] & 0x3f) << 12)
+ ((p[4] & 0x3f) << 6) + (p[5] & 0x3f);
}
}
}
}
/* Illegal value, just return the first byte */
return p[0];
}
static apr_status_t
aaencode_output_filter(ap_filter_t* f, apr_bucket_brigade* bb) {
const char* aa[] = {
"(c^_^o)", // (c^_^o)
"(\xef\xbe\x9f\xce\x98\xef\xbe\x9f)", // (゚Θ゚)
"((o^_^o) - (\xef\xbe\x9f\xce\x98\xef\xbe\x9f))", // ((o^_^o) - (゚Θ゚))
"(o^_^o)", // (o^_^o)
"(\xef\xbe\x9f\xef\xbd\xb0\xef\xbe\x9f)", // (゚ー゚)
"((\xef\xbe\x9f\xef\xbd\xb0\xef\xbe\x9f) + (\xef\xbe\x9f\xce\x98\xef\xbe\x9f))", // ((゚ー゚) + (゚Θ゚))
"((o^_^o) +(o^_^o))", // ((o^_^o) +(o^_^o))
"((\xef\xbe\x9f\xef\xbd\xb0\xef\xbe\x9f) + (o^_^o))", // ((゚ー゚) + (o^_^o))
"((\xef\xbe\x9f\xef\xbd\xb0\xef\xbe\x9f) + (\xef\xbe\x9f\xef\xbd\xb0\xef\xbe\x9f))", // ((゚ー゚) + (゚ー゚))
"((\xef\xbe\x9f\xef\xbd\xb0\xef\xbe\x9f) + (\xef\xbe\x9f\xef\xbd\xb0\xef\xbe\x9f) + (\xef\xbe\x9f\xce\x98\xef\xbe\x9f))", // ((゚ー゚) + (゚ー゚) + (゚Θ゚))
"(\xef\xbe\x9f\xd0\x94\xef\xbe\x9f) .\xef\xbe\x9f\xcf\x89\xef\xbe\x9f\xef\xbe\x89", // (゚Д゚) .゚ω゚ノ
"(\xef\xbe\x9f\xd0\x94\xef\xbe\x9f) .\xef\xbe\x9f\xce\x98\xef\xbe\x9f\xef\xbe\x89", // (゚Д゚) .゚Θ゚ノ
"(\xef\xbe\x9f\xd0\x94\xef\xbe\x9f) ['c']", // (゚Д゚) ['c']
"(\xef\xbe\x9f\xd0\x94\xef\xbe\x9f) .\xef\xbe\x9f\xef\xbd\xb0\xef\xbe\x9f\xef\xbe\x89", // (゚Д゚) .゚ー゚ノ
"(\xef\xbe\x9f\xd0\x94\xef\xbe\x9f) .\xef\xbe\x9f\xd0\x94\xef\xbe\x9f\xef\xbe\x89", // (゚Д゚) .゚Д゚ノ
"(\xef\xbe\x9f\xd0\x94\xef\xbe\x9f) [\xef\xbe\x9f\xce\x98\xef\xbe\x9f]", // (゚Д゚) [゚Θ゚]
};
const char* head =
"\xef\xbe\x9f\xcf\x89\xef\xbe\x9f\xef\xbe\x89= /\xef\xbd\x80\xef\xbd\x8d\xc2\xb4\xef\xbc\x89\xef\xbe\x89 ~\xe2\x94\xbb\xe2\x94\x81\xe2\x94\xbb //*\xc2\xb4\xe2\x88\x87\xef\xbd\x80*/ ['_']; o=(\xef\xbe\x9f\xef\xbd\xb0\xef\xbe\x9f) =_=3; " // ゚ω゚ノ= /`m´)ノ ~┻━┻ //*´∇`*/ ['_']; o=(゚ー゚) =_=3;
"c=(\xef\xbe\x9f\xce\x98\xef\xbe\x9f) =(\xef\xbe\x9f\xef\xbd\xb0\xef\xbe\x9f)-(\xef\xbe\x9f\xef\xbd\xb0\xef\xbe\x9f); (\xef\xbe\x9f\xd0\x94\xef\xbe\x9f) =(\xef\xbe\x9f\xce\x98\xef\xbe\x9f)= (o^_^o)/ (o^_^o);" // c=(゚Θ゚) =(゚ー゚)-(゚ー゚); (゚Д゚) =(゚Θ゚)= (o^_^o)/ (o^_^o);
"(\xef\xbe\x9f\xd0\x94\xef\xbe\x9f)={\xef\xbe\x9f\xce\x98\xef\xbe\x9f: '_' ,\xef\xbe\x9f\xcf\x89\xef\xbe\x9f\xef\xbe\x89 : ((\xef\xbe\x9f\xcf\x89\xef\xbe\x9f\xef\xbe\x89==3) +'_') [\xef\xbe\x9f\xce\x98\xef\xbe\x9f] " // (゚Д゚)={゚Θ゚: '_' ,゚ω゚ノ : ((゚ω゚ノ==3) +'_') [゚Θ゚]
",\xef\xbe\x9f\xef\xbd\xb0\xef\xbe\x9f\xef\xbe\x89 :(\xef\xbe\x9f\xcf\x89\xef\xbe\x9f\xef\xbe\x89+ '_')[o^_^o -(\xef\xbe\x9f\xce\x98\xef\xbe\x9f)] " // ,゚ー゚ノ :(゚ω゚ノ+ '_')[o^_^o -(゚Θ゚)]
",\xef\xbe\x9f\xd0\x94\xef\xbe\x9f\xef\xbe\x89:((\xef\xbe\x9f\xef\xbd\xb0\xef\xbe\x9f==3) +'_')[\xef\xbe\x9f\xef\xbd\xb0\xef\xbe\x9f] }; (\xef\xbe\x9f\xd0\x94\xef\xbe\x9f) [\xef\xbe\x9f\xce\x98\xef\xbe\x9f] =((\xef\xbe\x9f\xcf\x89\xef\xbe\x9f\xef\xbe\x89==3) +'_') [c^_^o];" // ,゚Д゚ノ:((゚ー゚==3) +'_')[゚ー゚] }; (゚Д゚) [゚Θ゚] =((゚ω゚ノ==3) +'_') [c^_^o];
"(\xef\xbe\x9f\xd0\x94\xef\xbe\x9f) ['c'] = ((\xef\xbe\x9f\xd0\x94\xef\xbe\x9f)+'_') [ (\xef\xbe\x9f\xef\xbd\xb0\xef\xbe\x9f)+(\xef\xbe\x9f\xef\xbd\xb0\xef\xbe\x9f)-(\xef\xbe\x9f\xce\x98\xef\xbe\x9f) ];" // (゚Д゚) ['c'] = ((゚Д゚)+'_') [ (゚ー゚)+(゚ー゚)-(゚Θ゚) ];
"(\xef\xbe\x9f\xd0\x94\xef\xbe\x9f) ['o'] = ((\xef\xbe\x9f\xd0\x94\xef\xbe\x9f)+'_') [\xef\xbe\x9f\xce\x98\xef\xbe\x9f];" // (゚Д゚) ['o'] = ((゚Д゚)+'_') [゚Θ゚];
"(\xef\xbe\x9fo\xef\xbe\x9f)=(\xef\xbe\x9f\xd0\x94\xef\xbe\x9f) ['c']+(\xef\xbe\x9f\xd0\x94\xef\xbe\x9f) ['o']+(\xef\xbe\x9f\xcf\x89\xef\xbe\x9f\xef\xbe\x89 +'_')[\xef\xbe\x9f\xce\x98\xef\xbe\x9f]+ ((\xef\xbe\x9f\xcf\x89\xef\xbe\x9f\xef\xbe\x89==3) +'_') [\xef\xbe\x9f\xef\xbd\xb0\xef\xbe\x9f] + " // (゚o゚)=(゚Д゚) ['c']+(゚Д゚) ['o']+(゚ω゚ノ +'_')[゚Θ゚]+ ((゚ω゚ノ==3) +'_') [゚ー゚] +
"((\xef\xbe\x9f\xd0\x94\xef\xbe\x9f) +'_') [(\xef\xbe\x9f\xef\xbd\xb0\xef\xbe\x9f)+(\xef\xbe\x9f\xef\xbd\xb0\xef\xbe\x9f)]+ ((\xef\xbe\x9f\xef\xbd\xb0\xef\xbe\x9f==3) +'_') [\xef\xbe\x9f\xce\x98\xef\xbe\x9f]+" // ((゚Д゚) +'_') [(゚ー゚)+(゚ー゚)]+ ((゚ー゚==3) +'_') [゚Θ゚]+
"((\xef\xbe\x9f\xef\xbd\xb0\xef\xbe\x9f==3) +'_') [(\xef\xbe\x9f\xef\xbd\xb0\xef\xbe\x9f) - (\xef\xbe\x9f\xce\x98\xef\xbe\x9f)]+(\xef\xbe\x9f\xd0\x94\xef\xbe\x9f) ['c']+" // ((゚ー゚==3) +'_') [(゚ー゚) - (゚Θ゚)]+(゚Д゚) ['c']+
"((\xef\xbe\x9f\xd0\x94\xef\xbe\x9f)+'_') [(\xef\xbe\x9f\xef\xbd\xb0\xef\xbe\x9f)+(\xef\xbe\x9f\xef\xbd\xb0\xef\xbe\x9f)]+ (\xef\xbe\x9f\xd0\x94\xef\xbe\x9f) ['o']+" // ((゚Д゚)+'_') [(゚ー゚)+(゚ー゚)]+ (゚Д゚) ['o']+
"((\xef\xbe\x9f\xef\xbd\xb0\xef\xbe\x9f==3) +'_') [\xef\xbe\x9f\xce\x98\xef\xbe\x9f];(\xef\xbe\x9f\xd0\x94\xef\xbe\x9f) ['_'] =(o^_^o) [\xef\xbe\x9fo\xef\xbe\x9f] [\xef\xbe\x9fo\xef\xbe\x9f];" // ((゚ー゚==3) +'_') [゚Θ゚];(゚Д゚) ['_'] =(o^_^o) [゚o゚] [゚o゚];
"(\xef\xbe\x9f\xce\xb5\xef\xbe\x9f)=((\xef\xbe\x9f\xef\xbd\xb0\xef\xbe\x9f==3) +'_') [\xef\xbe\x9f\xce\x98\xef\xbe\x9f]+ (\xef\xbe\x9f\xd0\x94\xef\xbe\x9f) .\xef\xbe\x9f\xd0\x94\xef\xbe\x9f\xef\xbe\x89+" // (゚ε゚)=((゚ー゚==3) +'_') [゚Θ゚]+ (゚Д゚) .゚Д゚ノ+
"((\xef\xbe\x9f\xd0\x94\xef\xbe\x9f)+'_') [(\xef\xbe\x9f\xef\xbd\xb0\xef\xbe\x9f) + (\xef\xbe\x9f\xef\xbd\xb0\xef\xbe\x9f)]+((\xef\xbe\x9f\xef\xbd\xb0\xef\xbe\x9f==3) +'_') [o^_^o -\xef\xbe\x9f\xce\x98\xef\xbe\x9f]+" // ((゚Д゚)+'_') [(゚ー゚) + (゚ー゚)]+((゚ー゚==3) +'_') [o^_^o -゚Θ゚]+
"((\xef\xbe\x9f\xef\xbd\xb0\xef\xbe\x9f==3) +'_') [\xef\xbe\x9f\xce\x98\xef\xbe\x9f]+ (\xef\xbe\x9f\xcf\x89\xef\xbe\x9f\xef\xbe\x89 +'_') [\xef\xbe\x9f\xce\x98\xef\xbe\x9f]; " // ((゚ー゚==3) +'_') [゚Θ゚]+ (゚ω゚ノ +'_') [゚Θ゚];
"(\xef\xbe\x9f\xef\xbd\xb0\xef\xbe\x9f)+=(\xef\xbe\x9f\xce\x98\xef\xbe\x9f); (\xef\xbe\x9f\xd0\x94\xef\xbe\x9f)[\xef\xbe\x9f\xce\xb5\xef\xbe\x9f]='\\\\'; " // (゚ー゚)+=(゚Θ゚); (゚Д゚)[゚ε゚]='\\';
"(\xef\xbe\x9f\xd0\x94\xef\xbe\x9f).\xef\xbe\x9f\xce\x98\xef\xbe\x9f\xef\xbe\x89=(\xef\xbe\x9f\xd0\x94\xef\xbe\x9f+ \xef\xbe\x9f\xef\xbd\xb0\xef\xbe\x9f)[o^_^o -(\xef\xbe\x9f\xce\x98\xef\xbe\x9f)];" // (゚Д゚).゚Θ゚ノ=(゚Д゚+ ゚ー゚)[o^_^o -(゚Θ゚)];
"(o\xef\xbe\x9f\xef\xbd\xb0\xef\xbe\x9fo)=(\xef\xbe\x9f\xcf\x89\xef\xbe\x9f\xef\xbe\x89 +'_')[c^_^o];" // (o゚ー゚o)=(゚ω゚ノ +'_')[c^_^o]; TODO
"(\xef\xbe\x9f\xd0\x94\xef\xbe\x9f) [\xef\xbe\x9fo\xef\xbe\x9f]='\\\"';" // (゚Д゚) [゚o゚]='\"';
"(\xef\xbe\x9f\xd0\x94\xef\xbe\x9f) ['_'] ( (\xef\xbe\x9f\xd0\x94\xef\xbe\x9f) ['_'] (\xef\xbe\x9f\xce\xb5\xef\xbe\x9f+" // (゚Д゚) ['_'] ( (゚Д゚) ['_'] (゚ε゚+
"(\xef\xbe\x9f\xd0\x94\xef\xbe\x9f)[\xef\xbe\x9fo\xef\xbe\x9f]+ "; // (゚Д゚)[゚o゚]+
apr_status_t err;
apr_size_t buf_len = 0;
unsigned char* ptr;
unsigned char* buf = 0;
unsigned char s[16];
err = apr_brigade_pflatten(bb, (char**)&buf, &buf_len, f->r->pool);
if (err) return err;
apr_brigade_cleanup(bb);
PUT(f, bb, head);
ptr = buf;
while(ptr - buf <= buf_len) {
unsigned int i, l = utf_ptr2len(ptr);
unsigned int c = utf_ptr2char(ptr);
if (l == 0 || c == 0) break;
PUT(f, bb, "(\xef\xbe\x9f\xd0\x94\xef\xbe\x9f)[\xef\xbe\x9f\xce\xb5\xef\xbe\x9f]+"); // (゚Д゚)[゚ε゚]+
if (c <= 127) {
sprintf(s, "%o", c);
for (i = 0; i < strlen(s); i++) {
PUT(f, bb, aa[CTOI(s[i])]);
PUT(f, bb, "+ ");
}
} else {
PUT(f, bb, "(o\xef\xbe\x9f\xef\xbd\xb0\xef\xbe\x9fo)+ "); // (o゚ー゚o)+
sprintf(s, "%04x", c);
for (i = 0; i < strlen(s); i++) {
PUT(f, bb, aa[CTOI(s[i])]);
PUT(f, bb, "+ ");
}
}
ptr += l;
}
PUT(f, bb, "(\xef\xbe\x9f\xd0\x94\xef\xbe\x9f)[\xef\xbe\x9fo\xef\xbe\x9f]) (\xef\xbe\x9f\xce\x98\xef\xbe\x9f)) ('_');"); // (゚Д゚)[゚o゚]) (゚Θ゚)) ('_');
APR_BRIGADE_INSERT_TAIL(bb, apr_bucket_eos_create(f->c->bucket_alloc));
//ap_remove_output_filter(f);
return ap_pass_brigade(f->next, bb);
}
static void
aaencode_insert_output_filter(request_rec* r) {
ap_add_output_filter("AAENCODE", NULL, r, r->connection);
}
static void
aaencode_register_hooks(apr_pool_t *p) {
ap_register_output_filter("AAENCODE", aaencode_output_filter, NULL, AP_FTYPE_CONTENT_SET);
}
module AP_MODULE_DECLARE_DATA aaencode_module = {
STANDARD20_MODULE_STUFF,
NULL,
NULL,
NULL,
NULL,
NULL,
aaencode_register_hooks
};
一応リポジトリのリンクも貼っておきますね。
mattn/mod_aaencode - GitHubコンパイルは
apache filter module encoding to japanese style emoticons.
https://github.com/mattn/mod_aaencode
apxs2 -i -a -c -Wc,-O2 mod_aaencode.c -lapr-1 -laprutil-1
Windowsなら
apxs2 -i -a -c -Wc,-O2 mod_aaencode.c libapr-1.lib libaprutil-1.lib libhttpd.lib
でインストールまでやってくれます。apacheを再起動すれば準備完了。使い方は .htaccess に
AddOutputFilter AAENCODE .js
と書くだけ。これで例えば
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8" />
<script type="text/javascript" src="hello.js"></script>
</head>
<body>
はろーわーるど
</body>
</html>
こんなソースがあって、「ほほーん。jsのソースはhello.jsか」と解析する人がいたとします。で、ブラウザのURL欄に直接 hello.js を足して中身を閲覧しようとする訳です。だがしかし!
となる想定。
えっ!?
見た方はビックリするか、はたまた和むか...
ちなみにjqueryを食わすと結果が11メガバイトになったり、30秒近くレスポンスが返ってこないのはもちろん仕様です!
ただ最近、aadecodeなんで物を作った人がいて、こちらもそろそろ難読化レベルが下がってきているので、そろそろ新しい難読化技術を公開して欲しいですね!はせがわさん