Quais são as strings internas do JavaScript?

147

é difícil resumir esta pergunta no título de uma pergunta

ATUALIZAÇÃO Criei um JSFiddle que constrói uma string ofuscada a partir de sua entrada com base nas letras extraídas desta pergunta: Você pode acessá-la aqui ou uma essência seria mais fácil?

Recentemente, deparei com um pouco de JavaScript ofuscado neste perfil que se parece com isso:

javascript:[[]+1/!1][1^1][1>>1]+({}+[])[1<<1^11>>1]+([]+!!-
[])[1<<1]+[/~/+{}][+!1][-~1<<1]+([]+/-/[(!!1+[])[1>>1]+(!!1
+[])[1<<1^1]+(!1+[])[1|1<<1]+(!!1+[])[1^1]])[1^11<<1]+([,][
~1]+[])[1-~1]+[[]+{}][!1.1%1][11111.1%11.1*111e11|!1]+(/1/+
1/[1<1][1%1])[1^11]+[[],[]+{}][1][+1]+(/<</[1]+[])[1/1.1&1]

Desculpe estragar a surpresa, mas quando isso é avaliado, ele retorna isso:

"I love you" in Chrome
"I lone you" In Firefox
"I lo[e you" in IE10

A maneira como isso funciona, quando dividido, é gerar uma série de mensagens e extrair delas as letras (usando o "I" como exemplo):

[]+1/!1
returns
"Infinity"
then
[[]+1/!1]
creates this array:
["Infinity"]
then
[[]+1/!1][1^1]
Takes the first (1^1 == 0) element of that array
"Infinity"
finally
[[]+1/!1][1^1][1>>1]
Takes the first (1>>1 == 0) char of that string
"I"

Outras cadeias geradas incluem:

({}+[])       -> "[object Object]" (where the space comes from)
([]+!!-[])    -> "false" (used for it's "l")
[/~/+{}][+!1] -> "/~/[object Object]" (this is used for an "o")
(/<</[1]+[])  -> "undefined"

Eu estava interessado em encontrar um substituto para o "n" e "[" e criei o seguinte:

String.fromCharCode(('1'.charCodeAt(0)<<1)+(10<<1))

O que sinto no espírito de usar zeros e zeros, mas viola um dos aspectos mais elegantes do código original, que é a aparência de não ter nada a ver com strings. Alguém mais tem uma idéia de como gerar um "v" que esteja de acordo com o código ofuscado original?

Aqui estão algumas informações extras encontradas depois que muitos programadores talentosos de JavaScript analisaram mais detalhadamente

O Firefox retorna "Eu solto você" Por causa desta linha:

([]+/-/[(!!1+[])[1>>1]+(!!1+[])[1<<1^1]+(!1+[])[1|1<<1]+(!!1+[])[1^1]])[1^11<<1]+

[1^11<<1] apara um caractere específico disso:

([]+/-/[(!!1+[])[1>>1]+(!!1+[])[1<<1^1]+(!1+[])[1|1<<1]+(!!1+[])[1^1]])

O que avalia isso:

"function test() {
    [native code]
}"

Parece que podemos ter o nosso "V" !!!

O Chrome retorna "eu te amo", porque o mesmo código retorna isso:

"function test() { [native code] }"

Antes que a pergunta fosse encerrada para conexão questionável com "um problema de programação real", pensei em adicionar uma solução resumida baseada em @ Supr , @ Cory e @ alpha123 , eis que:

alert([[]+1/!1][1^1][1>>1]+({}+[])[1<<1^11>>1]+(
[]+!!-[])[1<<1]+[/~/+{}][+!1][-~1<<1]+[([]+/-/[(
!!1+[])[1>>1]+(!!1+[])[1<<1^1]+(!1+[])[1|1<<1]+(
!!1+[])[1^1]])[1+(1^(11+1+1)<<1)],([]+/-/[(!!1+[
])[1>>1]+(!!1+[])[1<<1^1]+(!1+[])[1|1<<1]+(!!1+[
])[1^1]])[1^11<<1],([]+/-/[(!!1+[])[1>>1]+(!!1+[
])[1<<1^1]+(!1+[])[1|1<<1]+(!!1+[])[1^1]])[1^(11
+1+1)<<1]][((([]+/-/[(!!1+[])[1>>1]+(!!1+[])[1<<
1^1]+(!1+[])[1|1<<1]+(!!1+[])[1^1]])[(1<<1<<1<<1
)+1<<1]==({}+[])[1^1])*1)+((([]+/-/[(!!1+[])[1>>
1]+(!!1+[])[1<<1^1]+(!1+[])[1|1<<1]+(!!1+[])[1^1
]])[(1^11<<1)-1]==({}+[])[1^1])<<1)]+([,][~1]+[]
)[1-~1]+[[]+{}][!1.1%1][11111.1%11.1*111e11|!1]+
(/1/+1/[1<1][1%1])[1^11]+[[],[]+{}][1][+1]+(/<</
[1]+[])[1/1.1&1])

Dada a complexidade do código e a mensagem que ele produz, é quase como se o mecanismo JavaScript estivesse dizendo o quão especial você se sente :)

Jason Sperske
fonte
9
Diz "amor" no console do Chrome. i.imgur.com/rVyKMoP.png
bfavaretto
2
E se você tira não letras do function test() { [native code] }, então você pode normalizá-lo e extrair a letra desejada
Jason Sperske
4
Baseando o código em uma saída de string não definida por padrões para imprimir uma mensagem usando código ofuscado ... Estou chamando isso de uma maneira muito localizada.
2
@Ian, é verdade. Se as pessoas na minha vida que eu amo realmente se importava comigo eles usariam Chrome :)
Jason Sperske
4
A melhor parte disso é o aviso que meu editor de texto dá: "Uso confuso de '!'"
Jake Johnson

Respostas:

83

Antes de tudo, gostaria de agradecer a Jason e a todos os colaboradores por brincar com esse trecho engraçado. Escrevi esse código apenas por diversão , a fim de enviá-lo para minha esposa em 14 de fevereiro :) Tendo apenas o Chrome instalado no laptop, não tive opções para verificar como ele funciona no Firefox e no IE. Além disso, eu realmente não esperava que a toString()representação dos métodos internos pudesse parecer diferente em outros navegadores.

Agora, passando para o problema real , vamos dar uma olhada precisa no código. Sim, "v"foi o verdadeiro "problema" aqui. Não encontrei outras maneiras de obter essa carta, exceto a análise de [native code]string, que pode ser obtida a partir de qualquer método interno. Como me limitava a não ter seqüências de caracteres e números, exceto o 1usado, eu precisava explorar algum método que tivesse apenas caracteres disponíveis em seu nome.

Caracteres disponíveis podem ser obtidas a partir de palavras-chave existentes e representações de seqüência, ou seja, desde o início, tivemos NaN, null, undefined, Infinity, true, false, e "[object Object]". Alguns deles podem ser facilmente convertidos em strings, por exemplo, 1/!1+[]give "Infinity".

Analisei diferentes métodos internos para matrizes [], objetos {}, expressões regulares /(?:)/, números 1.1, seqüências de caracteres "1"e descobri um belo método de RegExpobjeto chamado test(). Seu nome pode ser montado a partir de todos os caracteres disponíveis, por exemplo, "t"e "e"a partir de true, e "s"de false. Eu criei uma string "test"e resolvi esse método usando a notação de colchetes para regex literal /-/, corretamente identificada nesta linha:

/-/[(!!1+[])[1>>1]+(!!1+[])[1<<1^1]+(!1+[])[1|1<<1]+(!!1+[])[1^1]]

Como já foi discutido, esse trecho de código é avaliado no Chrome como:

function test() { [native code] }

no Firefox como:

function test() {
    [native code]
}

e no IE como:

 function test() {     [native code] }  

(neste último, preste atenção especial ao espaço antes da functionpalavra-chave)

Então, como você vê claramente, meu código estava obtendo o 24º caractere da string apresentada, que era no Chrome "v"(como foi planejado), mas infelizmente no Firefox e IE - "n"e "["respectivamente.

Para obter a mesma saída em todos os navegadores, usei uma abordagem diferente da ilustrada nas outras respostas. Agora a versão modificada se parece com isso:

javascript:[[]+1/!1][1^1][1>>1]+({}+[])[1<<1^11>>1]+([]+!!-
[])[1<<1]+[/~/+{}][+!1][-~1<<1]+/\[[^1]+\]/[([]+![])[1<<1<<
1]+(/|/[(1+{})[1+11>>>1]+[[]+{}][+!1][1]+([]+1/[])[1<<1>>1]
+([1<1]+[])[1+11>>>1+1]+[[!!1]+1][+[]][1-1]+([]+!!/!/)[1|1]
+(/1/[1]+[])[!1%1]+(-{}+{})[-1+1e1-1]+(1+[!!1])[1]+([]+1+{}
)[1<<1]+[!!/!!/+[]][+[]][1&1]]+/=/)[1e1+(1<<1|1)+(([]+/-/[(
!!1+[])[1>>1]+(!!1+[])[1<<1^1]+(!1+[])[1|1<<1]+(!!1+[])[1^1
]])[1^1]==+!1)]+(!![]+{})[1|1<<1]+[1+{}+1][!1+!1][(11>>1)+1
]](([]+/-/[(!!1+[])[1>>1]+(!!1+[])[1<<1^1]+(!1+[])[1|1<<1]+
(!!1+[])[1^1]]))[1&.1][11>>>1]+([,][~1]+[])[1-~1]+[[]+{}][!
1.1%1][11111.1%11.1*111e11|!1]+(/1/+1/[1<1][1%1])[1^11]+[[]
,[]+{}][1<<1>>>1][1||1]+(/[<+>]/[1&1|1]+[1.1])[1/11.1&1.11]

No entanto, para intrigar os leitores, não fornecerei uma solução para isso. Sinceramente, acredito que você entenderá facilmente como funciona ... e alguns podem até surpreender sua amada no modo entre navegadores;)

PS ainda outro ofuscador

Inspirado na idéia de Jason de criar uma ferramenta ofuscante universal, escrevi mais uma. Você pode encontrá-lo em JSBin: http://jsbin.com/amecoq/2 . Ele pode ofuscar qualquer texto que contenha números [0-9], pequenas letras latinas [a-z]e espaços. O comprimento da string é limitado principalmente pela sua RAM (pelo menos o corpo da minha resposta foi ofuscado com sucesso). A saída é suportada pelo Chrome, Firefox e IE.

Dica: a ferramenta usa uma abordagem de ofuscação diferente da apresentada acima.

Visão
fonte
4
"construtor" ... uau, isso é incrível e você manteve o retângulo perfeito com quebras de linha válidas. Você é bom
Jason Sperske
1
Eu criei um Obfuscator que cria uma cadeia de acordo com suas regras de estilo: jsfiddle.net/w9rFF/8
Jason Sperske
@JasonSperske Esse foi um belo truque! Ótimo trabalho! Vou tentar contribuir para isso.
VisioN
26

Por que o native codetrecho da pergunta não está sendo usado? Este fornece um 'v'no Chrome e Firefox:

([]+/-/[(!!1+[])[1>>1]+(!!1+[])[1<<1^1]+(!1+[])[1|1<<1]+(!!1+[])[1^1]])[1^11<<1]>([]+/-/[(!!1+[])[1>>1]+(!!1+[])[1<<1^1]+(!1+[])[1|1<<1]+(!!1+[])[1^1]])[1^(11+1+1)<<1]?([]+/-/[(!!1+[])[1>>1]+(!!1+[])[1<<1^1]+(!1+[])[1|1<<1]+(!!1+[])[1^1]])[1^11<<1]:([]+/-/[(!!1+[])[1>>1]+(!!1+[])[1<<1^1]+(!1+[])[1|1<<1]+(!!1+[])[1^1]])[1^(11+1+1)<<1]

Edite para oferecer suporte ao IE e faça-o sem o operador ternário: Este funciona no Chrome, IE e FF. Constrói uma matriz e usa ==para determinar o navegador.

[([]+/-/[(!!1+[])[1>>1]+(!!1+[])[1<<1^1]+(!1+[])[1|1<<1]+(!!1+[])[1^1]])[1+(1^(11+1+1)<<1)],([]+/-/[(!!1+[])[1>>1]+(!!1+[])[1<<1^1]+(!1+[])[1|1<<1]+(!!1+[])[1^1]])[1^11<<1],([]+/-/[(!!1+[])[1>>1]+(!!1+[])[1<<1^1]+(!1+[])[1|1<<1]+(!!1+[])[1^1]])[1^(11+1+1)<<1]][((([]+/-/[(!!1+[])[1>>1]+(!!1+[])[1<<1^1]+(!1+[])[1|1<<1]+(!!1+[])[1^1]])[(1<<1<<1<<1)+1<<1]==({}+[])[1^1])*1)+((([]+/-/[(!!1+[])[1>>1]+(!!1+[])[1<<1^1]+(!1+[])[1|1<<1]+(!!1+[])[1^1]])[(1^11<<1)-1]==({}+[])[1^1])<<1)]

Legível:

[
    //ie
    ([]+/-/[(!!1+[])[1>>1]+(!!1+[])[1<<1^1]+(!1+[])[1|1<<1]+(!!1+[])[1^1]])[1+(1^(11+1+1)<<1)],
    //ch
    ([]+/-/[(!!1+[])[1>>1]+(!!1+[])[1<<1^1]+(!1+[])[1|1<<1]+(!!1+[])[1^1]])[1^11<<1],
    //ff
    ([]+/-/[(!!1+[])[1>>1]+(!!1+[])[1<<1^1]+(!1+[])[1|1<<1]+(!!1+[])[1^1]])[1^(11+1+1)<<1]
]
[
    //ch?
    ((([]+/-/[(!!1+[])[1>>1]+(!!1+[])[1<<1^1]+(!1+[])[1|1<<1]+(!!1+[])[1^1]])[(1<<1<<1<<1)+1<<1]==({}+[])[1^1])*1)+
    //ff?
    ((([]+/-/[(!!1+[])[1>>1]+(!!1+[])[1<<1^1]+(!1+[])[1|1<<1]+(!!1+[])[1^1]])[(1^11<<1)-1]==({}+[])[1^1])<<1)
]
Supr
fonte
Isso é interessante. Originalmente, foi descartado que a colocação das palavras "código nativo" fosse imprevisível entre o Firefox e o Chrome. Isso resolve isso, mas não funciona no IE10 (onde retorna "i"). Ainda me pergunto se esta opção pode oferecer algumas ideias novas
Jason Sperske
A idéia é simplesmente selecionar ambos ne ve apenas escolher o que for maior: str[23]>str[27]?str[23]:str[27]. Em outras palavras, o operador terciário é o truque. Poderia ser estendido para oferecer suporte ao IE também:([]+/-/[(!!1+[])[1>>1]+(!!1+[])[1<<1^1]+(!1+[])[1|1<<1]+(!!1+[])[1^1]])[1+(1^(11+1+1)<<1)]
Supr
1
Sua resposta foi a primeira (à frente do criador do código original), mas achei que a resposta dele poderia logicamente ser considerada correta. Ainda grande trabalho (e um merecido 13 até votes)
Jason Sperske
1
Nitpick menor: um operador terciário é o terceiro operador mais importante, depois do primário e do secundário. Um operador que usa três operandos é ternário.
amigos estão dizendo sobre eric
1
@ EricLippert, gah, eu até pesquisei no Google para ter certeza de que estava usando o termo certo, mas ainda assim acabei com o errado! Obrigado, corrigido.
Supr
8

Isso é o mais próximo que pude, infelizmente, viola a convenção da ofuscação original ao fazer uma chamada para unescape():

unescape((/%/+[])[1]+(/1/[1]+[])[1%1]+(+!1)+(+!1)+(1e1+(11*(1-~1)<<1)))

Destruir:

(/%/+[])[1]          => "%"
(/1/[1]+[])[1%1]     => "u"
(+!1)                => "0"
(+!1)                => "0"
(1e1+(11*(1-~1)<<1)) => "76"
===========================
unescape("%u0076")   => "v"

Outras idéias:

  1. De alguma forma chegar a unescape("\x76")
  2. De alguma forma, converter 118sem chamarString.fromCharCode()
  3. Obtenha o texto de uma exceção com a palavra "Inválido"

Atualizações:

Comecei a jogar código de golfe e o reduzi, substituindo peças por mais 1s, etc.

Cᴏʀʏ
fonte
Eu também gosto deste. Estou um pouco surpreso ao selecionar uma resposta "correta", já que o seu e o @ alpha123 parecem extremamente ofuscados e ocultam inteligentemente a intenção original.
Jason Sperske
E suporte IE10 sela o acordo (com sinceras desculpas @ alpha123 para a excelente resposta)
Jason Sperske
Você pode substituir isso '%'com a (/%/+[[]+1/!1])[1]remoção de quaisquer aspas. Também adicionei l=unescape;usando letras minúsculas Lpara ocultar a referência unescape. Este tem sido divertido :)
Jason Sperske
@JasonSperske: Ainda mais curto:(/%/+[])[1]
C #
1
Ou você pode nomear sua variável $1;
Cᴏʀʏ
4

Aqui está a parte que gera o n / v:

([]+/-/[(!!1+[])[1>>1]+(!!1+[])[1<<1^1]+(!1+[])[1|1<<1]+(!!1+[])[1^1]])[1^11<<1]

No Firefox, ([]+/-/[(!!1+[])[1>>1]+(!!1+[])[1<<1^1]+(!1+[])[1|1<<1]+(!!1+[])[1^1]])avalia como

"function test() {
    [native code]
}"

enquanto no Chrome é

"function test() { [native code] }"

1^11<<1 é igual a 23. Portanto, devido ao espaço em branco extra do Firefox, isso não é suficiente para chegar ao 'v' e, em vez disso, é 'n'.

E é por isso que você não deve confiar no comportamento da função # toString. ;)

EDIT: Finalmente, encontrei uma versão entre navegadores razoavelmente ofuscada:

[[]+1/!1][1^1][1>>1]+({}+[])[1<<1^11>>1]+([]+!!-[])[1<<1]+[/~/+{}][+!1][-~1<<1]+([]+/-/[(!!1+[])[1>>1]+(!!1+[])[1<<1^1]+(!1+[])[1|1<<1]+(!!1+[])[1^1]])[(1^11<<1)+(parseInt("010")<10?(1+1+1+1):0)]+([,][~1]+[])[1-~1]+[[]+{}][!1.1%1][11111.1%11.1*111e11|!1]+(/1/+1/[1<1][1%1])[1^11]+[[],[]+{}][1][+1]+(/<</[1]+[])[1/1.1&1]

Isso substitui a seção n / v por:

([]+/-/[(!!1+[])[1>>1]+(!!1+[])[1<<1^1]+(!1+[])[1|1<<1]+(!!1+[])[1^1]])[(1^11<<1)+(parseInt("010")<10?(1+1+1+1):0)]

que explora diferenças no parseInt (aparentemente o Firefox analisa números começando com 0 como octal, enquanto o Chrome não) para adicionar 4 no caso do Firefox, obtendo assim 'v' de 'native' nos dois casos (não consigo encontrar outro 'v ': P).
O parseInt parece um pouco fora do lugar, mas é o melhor que posso fazer por enquanto.

Peter C
fonte
1
A questão éDoes anyone else have an idea of how to generate a "v" that is in keeping with the original obfuscated code?
Ian
Obrigado. Agora eu estou tentando descobrir uma maneira de cross-browser para fazer isso ... 'V' é uma carta surpreendentemente incomum ....
Peter C
@Ian - bem, então presumivelmente, [(1 ^ 11 << 1) + 1 + 1 + 1 + 1] faria isso?
enhzflep
@ JanDvorak - Eu não tenho FF no momento. O que ele avalia? Se posso ser tão presunçoso a ponto de perguntar, é isso.
enhzflep
@enhzflep desculpe, eu quis dizer "que não iria funcionar no Chrome, por outro lado"
John Dvorak
4

Para o caso de uso geral , se o uso de caracteres não for uma grande preocupação, posso estar inclinado a trapacear um pouco.

Crie a função "c" que transforma um número 0 .. 25 em um caractere.

c=function(v){for(var i in window){for(var ci in i){if(parseInt(i[ci],(10+11+11)+(1<<1)+(1<<1))==(v+10)){return i[ci]}}}};

Por motivos de desempenho, pré-armazene em cache as letras, se desejar.

l=[];for(var i=0; i<(11+11)+(1<<1)+(1<<1);i++){l[i]=c(i);}

No console do Chrome, a matriz resultante é assim:

> l;
["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "K", "l", "m", "n", "o", "p", "q", "r", "S", "t", "u", "v", "w", "x", "y", "Z"]

Então ... seu v pode ser l[10+10+1].

Como alternativa, uma solução geral como esta:

p=(function(){10%11}+[])[1+11+(1<<1)]; // "%"
u=(function(){club=1}+[])[1+11+(1<<1)]; // "u"
vc=p+u+(0+[])+(0+[])+((111>>1)+11+10+[]); // "%u0076"
unescape(vc);

Ou, para esse problema específico , talvez apenas:

(function(){v=1}+[])[10+(1<<1)]; // "v"
svidgen
fonte
3

Isso fornece av no Chrome:

Object.getOwnPropertyNames(Object)[17][3];

E isso acontece no Firefox:

Object.getOwnPropertyNames(Object)[9][3]

Os dois o extraem Object.prototype.preventExtensions(), então você provavelmente poderia encontrar uma maneira entre navegadores para fazer referência a esse método. (É o único nome de 17 caracteres em Object.Prototype para iniciantes.)

Sinta-se livre para criar uma versão mais ofuscada disso e levar todo o crédito para si mesmo, estou sem tempo;)

Nathan Friedly
fonte
2

No chrome, a expressão é ([]+/-/[(!!1+[])[1>>1]+(!!1+[])[1<<1^1]+(!1+[])[1|1<<1]+(!!1+[])[1^1]])avaliada como "function test() { [native code] }", e é [1^11<<1]avaliada como 23 (operadores bit a bit fazem com que a variável seja truncada em 32 bits)

enhzflep
fonte
A questão éDoes anyone else have an idea of how to generate a "v" that is in keeping with the original obfuscated code?
Ian