趣味js-只用1和特殊字符生成字符串

2018-02-09 12:40:41来源:http://www.hongweipeng.com/index.php/archives/1477/作者:栖迟於一丘人点击

分享
前言


今天逛justjavac
老哥的博客(http://justjavac.com/about.html
)看到了类似下面的代码


(+([]+(11^(1<<1))+((1+1)<<(1+1))+(11>>>1)+(1^1)+((11>>1)+(1<<1))+(-~1)+(-~1+1)+(1^1)+(1^1)))[(!!1+[])[1^1]+([]+{}+[])[1]+(([]+{})[([]+{})[11-1>>1]+[[],[]+{}+[]][[]+1][1]+(/^/[1]+[])[1|1>>1|1]+[{},11^1,!{}+[]][1+1][1<<1^1]+(11/!{}+{})[~1+(11^1)+~1]+[!!{}+{}][[]&111][1&1]+(/^/[111]+[])[11^11]+[{},[{}]+{},1][1+[]][11-~1+11>>1]+(!!1+{})[1&1>>1]+([]+{1:1}+[])[1|1]+[[]+!!1][111>>>111][1<<1>>1]]+[])[([]+![111])[1|1<<1|1]+[/=/,[]+[][11]][1|[]][1>>1]+([{}]+{})[1+!![1]]+[1,!1+/~/][1%11][1^1<<1]+(!!1+[])[1^1]+[!!/-/+/-/][11%11][+!!1]](11^1<<1,-~11>>1)](~1-~(11^1)<<1<<1)


输出:gahing


实现的原理是什么?


原理


了解 js 隐式类型转换(不懂可以参考这里
)的都知道



我们可以通过执行!1+[]
得到"false"


具体原理是 false+object 操作会先去调用object的valueOf()方法 发现其值=this


继续调用toString()方法得到"", 结果即false+"" = "false"(又去做了隐式转换)



故我们通过数组下标就可以拿到想要的字符f,a,l,s,e


类似的方法我们还能够拿到


!1+[] = "false"
!!1+[] = "true"
1/[]+[] = "Infinity"
[]/[]+[] = "NaN"
[]+{} = "[object Object]"
[]+/^/[1] = "undefined" /* /^/是正则 */
[]+/:@$/ = "/:@$" /*特殊字符放其中获取*/

然后你会发现,26个字母还是有好多不在上面的,并不能通过每次去上面拿字符然后再做拼接



但是!!constructor
这个字符串里面的字符都可以通过上面的拿到


"constructor" = ([]+{})[11-1>>1]+[[],[]+{}+[]][[]+1][1]+(/^/[1]+[])[1|1>>1|1]+[{},11^1,!{}+[]][1+1][1<<1^1]+(11/!{}+{})[~1+(11^1)+~1]+[!!{}+{}][[]&111][1&1]+(/^/[111]+[])[11^11]+[{},[{}]+{},1][1+[]][11-~1+11>>1]+(!!1+{})[1&1>>1]+([]+{1:1}+[])[1|1]+[[]+!!1][111>>>111][1<<1>>1]


constructor
有什么作用呢,先思考下...



好吧其实作用就是""['constructor']+[]
可以拿到"function String() { [native code] }"



于是,我拿到了String
字符串,再通过其他地方又可拿到to
,于是toString
方法就get了


最后实现的原理其实是toString,即:



(985072300).toString(36)



36=~1-~(11^1)<<1<<1


前面的数字串是字符串的36进制(0~9a-z)表示,比如 gahing 的36进制表示是985072300


进制转换:

36进制可以预先通过下面的方法获得


parseInt("gahing",36)
=>985072300
(985072300).toString(36)
=>"gahing"
number转换为1和字符组合构成

举个例子就懂了


[]+1+2+3 = "123"
(+([]+1+2+3)) = 123

我们设置0~9的组合串为如下:


0:(1^1)
1:(1|1)
2:(-~1)
3:(-~1|1)
4:(-~1<<1)
5:(11>>1)
6:((11+1)>>1)
7:(11>>1|-~1)
8:(11^(-~1|1))
9:(11^(1<<1))
实现
//$1="constructor"
let $1= ([]+{})[11-1>>1]+[[],[]+{}+[]][[]+1][1]+(/^/[1]+[])[1|1>>1|1]+[{},11^1,!{}+[]][1+1][1<<1^1]+(11/!{}+{})[~1+(11^1)+~1]+[!!{}+{}][[]&111][1&1]+(/^/[111]+[])[11^11]+[{},[{}]+{},1][1+[]][11-~1+11>>1]+(!!1+{})[1&1>>1]+([]+{1:1}+[])[1|1]+[[]+!!1][111>>>111][1<<1>>1]
//$11="function String() { [native code] }"
let $11 = (([]+{})[$1]+[])
//$111="substr"
let $111 = ([]+![111])[1|1<<1|1]+[/=/,[]+[][11]][1|[]][1>>1]+([{}]+{})[1+!![1]]+[1,!1+/~/][1%11][1^1<<1]+(!!1+[])[1^1]+[!!/-/+/-/][11%11][+!!1]
//$$="String"
let $$ = $11[$111](11^1<<1,-~11>>1) //substr(9,6)
//$$1="toString"
let $$1=(!!1+[])[1^1]+([]+{}+[])[1]+$$
//结果:(985072300)['toString'](36)
(+([]+(11^(1<<1))+((1+1)<<(1+1))+(11>>>1)+(1^1)+((11>>1)+(1<<1))+(-~1)+(-~1+1)+(1^1)
+(1^1)))[$$1](~1-~(11^1)<<1<<1)
存在的问题及其改进方法
长字符串


当字符串有多种类型时(比如下面会提到的中文)需要考虑分段,多次toString(36)
最后拼接起来。



由于toString
方法获得不易,让$='toString'


大写字母、中文字符、非常见字符

个别大写字母可以通过以下式子去拿到


$1='constructor'
A: [][$1]+[]="function Array() { [native code] }"
B: (!!1)[$1]+[]="function Boolean() { [native code] }"
I: 1/[]+[] = "Infinity"
N: []/[]+[] = "NaN"
O: []+{}="[object Object]"
当然,我们可以用黑科技去获取。


String类有个方法fromCodePoint
(不用fromCharCode
因为其不能识别32位字符)



通过传入Unicode
值即可得到对应的字符,String类可以通过构造函数''['constructor']
拿到。



例:''['constructor']['fromCodePoint'](23433) //输出'安'



23433
是安
的unicode码,可以通过'安'.codePointAt(0)
获得



故我们可以事先得到fromCodePoint
的36位编码。用一个临时变量保存,会经常用到


letfcp = 74719523963420330000 // 'fromCodePoint'的36位编码
let $$ =(fcp)['toString'](36) //'fromCodePoint'
$1='constructor'
''[$1][$$](23433) // 输出'安'

这样,所有的字符都可以得到了。


一般来说:

1.先让连续的数字小写字符串用toString(36)


2.可以直接拿到的英文字符,特殊字符,直接去获取



3.最后再用fromCodePoint
方法


这样生成的串就比较短了


未完待续..


最新文章

123

最新摄影

微信扫一扫

第七城市微信公众平台