これは、「Hello world」に警告する小さなJavaScriptコードです。
゚ω゚ノ=/`m´)ノ~┻━┻//*´∇`*/['_'];o=(゚ー゚)=_=3;c=(゚Θ゚)=(゚ー゚)-(゚ー゚);(゚Д゚)=(゚Θ゚)=(o^_^o)/(o^_^o);(゚Д゚)={゚Θ゚:'_',゚ω゚ノ:((゚ω゚ノ==3)+'_')[゚Θ゚],゚ー゚ノ:(゚ω゚ノ+'_')[o^_^o-(゚Θ゚)],゚Д゚ノ:((゚ー゚==3)+'_')[゚ー゚]};(゚Д゚)[゚Θ゚]=((゚ω゚ノ==3)+'_')[c^_^o];(゚Д゚)['c']=((゚Д゚)+'_')[(゚ー゚)+(゚ー゚)-(゚Θ゚)];(゚Д゚)['o']=((゚Д゚)+'_')[゚Θ゚];(゚o゚)=(゚Д゚)['c']+(゚Д゚)['o']+(゚ω゚ノ+'_')[゚Θ゚]+((゚ω゚ノ==3)+'_')[゚ー゚]+((゚Д゚)+'_')[(゚ー゚)+(゚ー゚)]+((゚ー゚==3)+'_')[゚Θ゚]+((゚ー゚==3)+'_')[(゚ー゚)-(゚Θ゚)]+(゚Д゚)['c']+((゚Д゚)+'_')[(゚ー゚)+(゚ー゚)]+(゚Д゚)['o']+((゚ー゚==3)+'_')[゚Θ゚];(゚Д゚)['_']=(o^_^o)[゚o゚][゚o゚];(゚ε゚)=((゚ー゚==3)+'_')[゚Θ゚]+(゚Д゚).゚Д゚ノ+((゚Д゚)+'_')[(゚ー゚)+(゚ー゚)]+((゚ー゚==3)+'_')[o^_^o-゚Θ゚]+((゚ー゚==3)+'_')[゚Θ゚]+(゚ω゚ノ+'_')[゚Θ゚];(゚ー゚)+=(゚Θ゚);(゚Д゚)[゚ε゚]='\\';(゚Д゚).゚Θ゚ノ=(゚Д゚+゚ー゚)[o^_^o-(゚Θ゚)];(o゚ー゚o)=(゚ω゚ノ+'_')[c^_^o];(゚Д゚)[゚o゚]='\"';(゚Д゚)['_']((゚Д゚)['_'](゚ε゚+(゚Д゚)[゚o゚]+(゚Д゚)[゚ε゚]+(゚Θ゚)+(゚ー゚)+(゚Θ゚)+(゚Д゚)[゚ε゚]+(゚Θ゚)+((゚ー゚)+(゚Θ゚))+(゚ー゚)+(゚Д゚)[゚ε゚]+(゚Θ゚)+(゚ー゚)+((゚ー゚)+(゚Θ゚))+(゚Д゚)[゚ε゚]+(゚Θ゚)+((o^_^o)+(o^_^o))+((o^_^o)-(゚Θ゚))+(゚Д゚)[゚ε゚]+(゚Θ゚)+((o^_^o)+(o^_^o))+(゚ー゚)+(゚Д゚)[゚ε゚]+((゚ー゚)+(゚Θ゚))+(c^_^o)+(゚Д゚)[゚ε゚]+(゚ー゚)+((o^_^o)-(゚Θ゚))+(゚Д゚)[゚ε゚]+(゚Θ゚)+(゚Θ゚)+(c^_^o)+(゚Д゚)[゚ε゚]+(゚Θ゚)+(゚ー゚)+((゚ー゚)+(゚Θ゚))+(゚Д゚)[゚ε゚]+(゚Θ゚)+((゚ー゚)+(゚Θ゚))+(゚ー゚)+(゚Д゚)[゚ε゚]+(゚Θ゚)+((゚ー゚)+(゚Θ゚))+(゚ー゚)+(゚Д゚)[゚ε゚]+(゚Θ゚)+((゚ー゚)+(゚Θ゚))+((゚ー゚)+(o^_^o))+(゚Д゚)[゚ε゚]+(゚ー゚)+(c^_^o)+(゚Д゚)[゚ε゚]+(゚Θ゚)+((o^_^o)-(゚Θ゚))+((゚ー゚)+(o^_^o))+(゚Д゚)[゚ε゚]+(゚Θ゚)+((゚ー゚)+(゚Θ゚))+((゚ー゚)+(o^_^o))+(゚Д゚)[゚ε゚]+(゚Θ゚)+((o^_^o)+(o^_^o))+((o^_^o)-(゚Θ゚))+(゚Д゚)[゚ε゚]+(゚Θ゚)+((゚ー゚)+(゚Θ゚))+(゚ー゚)+(゚Д゚)[゚ε゚]+(゚Θ゚)+(゚ー゚)+(゚ー゚)+(゚Д゚)[゚ε゚]+(゚ー゚)+((o^_^o)-(゚Θ゚))+(゚Д゚)[゚ε゚]+((゚ー゚)+(゚Θ゚))+(゚Θ゚)+(゚Д゚)[゚o゚])(゚Θ゚))('_');
見栄えの良いバージョン:
゚ω゚ノ = /`m´)ノ~┻━┻//*´∇`*/['_'];
o = (゚ー゚) = _ = 3;
c = (゚Θ゚) = (゚ー゚) - (゚ー゚);
(゚Д゚) = (゚Θ゚) = (o^_^o)/(o^_^o);
(゚Д゚) = {
゚Θ゚: '_',
゚ω゚ノ: ((゚ω゚ノ==3)+'_')[゚Θ゚],
゚ー゚ノ: (゚ω゚ノ+'_')[o^_^o-(゚Θ゚)],
゚Д゚ノ: ((゚ー゚==3)+'_')[゚ー゚]
};
(゚Д゚)[゚Θ゚] = ((゚ω゚ノ==3)+'_')[c^_^o];
(゚Д゚)['c'] = ((゚Д゚)+'_')[(゚ー゚)+(゚ー゚)-(゚Θ゚)];
(゚Д゚)['o'] = ((゚Д゚)+'_')[゚Θ゚];
(゚o゚)=(゚Д゚)['c'] + (゚Д゚)['o'] + (゚ω゚ノ + '_')[゚Θ゚] + ((゚ω゚ノ==3) + '_')[゚ー゚] + ((゚Д゚) + '_')[(゚ー゚) + (゚ー゚)] + ((゚ー゚==3) + '_')[゚Θ゚] + ((゚ー゚==3) + '_')[(゚ー゚) - (゚Θ゚)] + (゚Д゚)['c'] + ((゚Д゚) + '_')[(゚ー゚) + (゚ー゚)] + (゚Д゚)['o'] + ((゚ー゚==3) + '_')[゚Θ゚];
(゚Д゚)['_'] = (o^_^o)[゚o゚][゚o゚];
(゚ε゚) = ((゚ー゚==3) + '_')[゚Θ゚] + (゚Д゚).゚Д゚ノ + ((゚Д゚) + '_')[(゚ー゚) + (゚ー゚)] + ((゚ー゚==3) + '_')[o^_^o-゚Θ゚] + ((゚ー゚==3) + '_')[゚Θ゚] + (゚ω゚ノ+'_')[゚Θ゚];
(゚ー゚) += (゚Θ゚);
(゚Д゚)[゚ε゚] = '\\';
(゚Д゚).゚Θ゚ノ = (゚Д゚+゚ー゚)[o^_^o-(゚Θ゚)];
(o゚ー゚o) = (゚ω゚ノ+'_')[c^_^o];
(゚Д゚)[゚o゚] = '\"';
(゚Д゚)['_']((゚Д゚)['_'](゚ε゚+(゚Д゚)[゚o゚]+(゚Д゚)[゚ε゚]+(゚Θ゚)+(゚ー゚)+(゚Θ゚)+(゚Д゚)[゚ε゚]+(゚Θ゚)+((゚ー゚)+(゚Θ゚))+(゚ー゚)+(゚Д゚)[゚ε゚]+(゚Θ゚)+(゚ー゚)+((゚ー゚)+(゚Θ゚))+(゚Д゚)[゚ε゚]+(゚Θ゚)+((o^_^o)+(o^_^o))+((o^_^o)-(゚Θ゚))+(゚Д゚)[゚ε゚]+(゚Θ゚)+((o^_^o)+(o^_^o))+(゚ー゚)+(゚Д゚)[゚ε゚]+((゚ー゚)+(゚Θ゚))+(c^_^o)+(゚Д゚)[゚ε゚]+(゚ー゚)+((o^_^o)-(゚Θ゚))+(゚Д゚)[゚ε゚]+(゚Θ゚)+(゚Θ゚)+(c^_^o)+(゚Д゚)[゚ε゚]+(゚Θ゚)+(゚ー゚)+((゚ー゚)+(゚Θ゚))+(゚Д゚)[゚ε゚]+(゚Θ゚)+((゚ー゚)+(゚Θ゚))+(゚ー゚)+(゚Д゚)[゚ε゚]+(゚Θ゚)+((゚ー゚)+(゚Θ゚))+(゚ー゚)+(゚Д゚)[゚ε゚]+(゚Θ゚)+((゚ー゚)+(゚Θ゚))+((゚ー゚)+(o^_^o))+(゚Д゚)[゚ε゚]+(゚ー゚)+(c^_^o)+(゚Д゚)[゚ε゚]+(゚Θ゚)+((o^_^o)-(゚Θ゚))+((゚ー゚)+(o^_^o))+(゚Д゚)[゚ε゚]+(゚Θ゚)+((゚ー゚)+(゚Θ゚))+((゚ー゚)+(o^_^o))+(゚Д゚)[゚ε゚]+(゚Θ゚)+((o^_^o)+(o^_^o))+((o^_^o)-(゚Θ゚))+(゚Д゚)[゚ε゚]+(゚Θ゚)+((゚ー゚)+(゚Θ゚))+(゚ー゚)+(゚Д゚)[゚ε゚]+(゚Θ゚)+(゚ー゚)+(゚ー゚)+(゚Д゚)[゚ε゚]+(゚ー゚)+((o^_^o)-(゚Θ゚))+(゚Д゚)[゚ε゚]+((゚ー゚)+(゚Θ゚))+(゚Θ゚)+(゚Д゚)[゚o゚])(゚Θ゚))('_');
それはここから取得されます:https://codegolf.stackexchange.com/questions/23975/obfuscation-challenge/24041#24041
どのように機能しますか?そのコードにはalert
さえありません。
コードを詳しく調べる前に、JavaScript 1.5以降 identifiers にはASCII文字だけでなくUnicode文字も含めることができることを知っておく必要があります。
この場合、これらの面白いシーケンスの多くは単なる識別子です。これらの識別子をより簡単な識別子で交換し、不要なコメントと括弧を削除すると、コードは次のようになります。
_a = /`m´)ノ~┻━┻/['_'];
o = b = _ = 3;
c = d = b-b;
e = d = o^_^o/o^_^o;
e = {
d: '_',
a: ((a==3)+'_')[d],
h: (a+'_')[o^_^o-d],
i: ((b==3)+'_')[b]
};
e[d] = ((a==3)+'_')[c^_^o];
e['c'] = (e+'_')[b+b-d];
e['o'] = (e+'_')[d];
f = e['c']+e['o']+(a+'_')[d]+((a==3)+'_')[b]+(e+'_')[b+b]+((b==3)+'_')[d]+((b==3)+'_')[b-d]+e['c']+(e+'_')[b+b]+e['o']+((b==3)+'_')[d];
e['_'] = (o^_^o)[f][f];
g = ((b==3)+'_')[d]+e.i+(e+'_')[b+b]+((b==3)+'_')[o^_^o-d]+((b==3)+'_')[d]+(a+'_')[d];
b += d;
e[g] = '\\';
e.j = (e+b)[o^_^o-d];
obo = (a+'_')[c^_^o];
e[f] = '\"';
e['_'](e['_'](g+e[f]+e[g]+d+b+d+e[g]+d+(b+d)+b+e[g]+d+b+(b+d)+e[g]+d+((o^_^o)+(o^_^o))+((o^_^o)-d)+e[g]+d+((o^_^o)+(o^_^o))+b+e[g]+(b+d)+(c^_^o)+e[g]+b+((o^_^o)-d)+e[g]+d+d+(c^_^o)+e[g]+d+b+(b+d)+e[g]+d+(b+d)+b+e[g]+d+(b+d)+b+e[g]+d+(b+d)+(b+(o^_^o))+e[g]+b+(c^_^o)+e[g]+d+((o^_^o)-d)+(b+(o^_^o))+e[g]+d+(b+d)+(b+(o^_^o))+e[g]+d+((o^_^o)+(o^_^o))+((o^_^o)-d)+e[g]+d+(b+d)+b+e[g]+d+b+b+e[g]+b+((o^_^o)-d)+e[g]+(b+d)+d+e[f])(d))('_');
_
これで、一度に各ステートメントを評価できます。
a = /`m´)ノ~┻━┻/['_']
_は_a = undefined
_に評価されますo = b = _ = 3
_は、o
、b
、および__
_整数_3
_を割り当てますc = d = b-b
_はc
およびd
に整数_0
_を割り当てますe = d = o^_^o/o^_^o
_はe
とd
に整数を割り当てます_1
_(_o^_^o
_は3に評価されますXOR 3 XOR 3、3)e = { d: '_', a: ((a==3)+'_')[d], h: (a+'_')[o^_^o-d], i: ((b==3)+'_')[b] }
はe
にオブジェクトを割り当てます_{ d: '_', a: 'a', h: 'd', i: 'e' }
_e[d] = ((a==3)+'_')[c^_^o]
は_e[1]
_文字列_'f'
_を割り当てますe['c'] = (e+'_')[b+b-d]
は_e['c']
_文字列_'c'
_を割り当てますe['o'] = (e+'_')[d]
は_e['o']
_文字列_'o'
_を割り当てますこれはすべてセットアップであり、次の変数が設定されています。
_a = undefined
b = 3
c = 0
d = 1
e = {
1: "f",
a: "a",
c: "c",
d: "_",
h: "d",
i: "e",
o: "o"
}
_
次のステートメントは、何かを構築する最初のステートメントです。
_f = e['c'] + // => "c"
e['o'] + // => "o"
(a+'_')[d] + // => "undefined_"[1] = "n"
((a==3)+'_')[b] + // => "false_"[3] = "s"
(e+'_')[b+b] + // => "object_"[6] = "t"
((b==3)+'_')[d] + // => "true_"[1] = "r"
((b==3)+'_')[b-d] + // => "true_"[2] = "s"
e['c'] + // => "c"
(e+'_')[b+b] + // => "object_"[6] = "t"
e['o'] + // => "o"
((b==3)+'_')[d]; // => "true"[1] = "r"
_
つまり_f = "constructor"
_です。次のステートメントでは、この_"constructor"
_を使用して関数を取得しています。
_e['_'] = (o^_^o)[f][f]
_
これは_(3).constructor.constructor
_と同等であり、 function Function
を生成するため、次のようになります。
_e['_'] = Function
_
このFunction
関数は特別です。パラメーターを介して関数本体のコードを渡すことにより、関数を動的に構築できます。
_f = Function("alert(1)")
// equivalent to
f = function() { alert(1) }
_
次のいくつかのステートメントはスキップして、結果の変数と値を書き込みます。
_a = undefined
b = 4
c = 0
d = 1
e = {
1: "f",
_: Function,
a: "a",
c: "c",
constructor: "\"",
d: "_",
h: "d",
i: "e",
j: "b",
o: "o",
return: "\\"
}
f = "constructor"
obo = "u"
_
最後のステートメントは、最終的な作業を行います。
_e['_'](e['_'](g+e[f]+e[g]+d+b+d+e[g]+d+(b+d)+b+e[g]+d+b+(b+d)+e[g]+d+((o^_^o)+(o^_^o))+((o^_^o)-d)+e[g]+d+((o^_^o)+(o^_^o))+b+e[g]+(b+d)+(c^_^o)+e[g]+b+((o^_^o)-d)+e[g]+d+d+(c^_^o)+e[g]+d+b+(b+d)+e[g]+d+(b+d)+b+e[g]+d+(b+d)+b+e[g]+d+(b+d)+(b+(o^_^o))+e[g]+b+(c^_^o)+e[g]+d+((o^_^o)-d)+(b+(o^_^o))+e[g]+d+(b+d)+(b+(o^_^o))+e[g]+d+((o^_^o)+(o^_^o))+((o^_^o)-d)+e[g]+d+(b+d)+b+e[g]+d+b+b+e[g]+b+((o^_^o)-d)+e[g]+(b+d)+d+e[f])(d))('_');
_
これは次と同等です。
_Function(Function( … )(1))('_')
_
長い式は次の文字列を作成します。
_return"\141\154\145\162\164\50\42\110\145\154\154\157\40\127\157\162\154\144\42\51"
_
エスケープされた文字列は次を評価します:
_alert("Hello World")
_
このreturn
コードはFunction
に渡され、次のような無名関数が作成されます。
_function anonymous() {
return"\141\154\145\162\164\50\42\110\145\154\154\157\40\127\157\162\154\144\42\51";
}
_
これは、次と同等です。
_function anonymous() {
return"alert(\"Hello World\")";
}
_
次に、この関数は_1
_をパラメーターとして実行され、結果の文字列を返します。
_alert("Hello World")
_
次に、これがFunction
に再度渡され、新しい無名関数が作成されます。
_function anonymous() {
alert("Hello World");
}
_
最後に、この関数も_'_'
_をパラメーターとして使用して呼び出されます。
ここにはたくさんのものがあります。変数を囲む括弧は機能しません。
基本的に彼はこの文字列を作成します:
_return"\141\154\145\162\164\50\42\110\145\154\154\157\40\127\157\162\154\144\42\51"
_
のエスケープバージョンです
_return "alert(\"Hello World\")"
_
そして最後にこれを行います:
_Function(Function('return "alert(\\"Hello World\\")"')())()
_
二重Function
は任意のように見えますが、そうではありません。 Function()
は、文字列内のバックスラッシュをエスケープ文字として解釈します。したがって、最初の呼び出しがデコードされ、2番目の呼び出しが実行されます。
_Function("return '\\110\\145\\154\\154\\157'")()
// => "Hello"
_
これは同じコードであり、より適切にフォーマットされており、「通常の」変数名を使用しています。
_var1=/`m´)ノ~┻━┻//*´∇`*/['_'];
three=(threeThenFour)=_=3;
c=(one)=(threeThenFour)-(threeThenFour);
(anObject)=(one)=(three)/(three);
(anObject)={
one:'_',
var1:((var1==3)+'_')[one],
var2ノ:(var1+'_')[three-(one)],
var4ノ:((threeThenFour==3)+'_')[threeThenFour]
};
(anObject)[one]=((var1==3)+'_')[c ^ _ ^ three];
(anObject)['c']=((anObject)+'_')[(threeThenFour)+(threeThenFour)-(one)];
(anObject)['three']=((anObject)+'_')[one];
(theConstructor)=(anObject)['c']+
(anObject)['three']+
(var1+'_')[one]+
((var1==3)+'_')[threeThenFour]+
((anObject)+'_')[(threeThenFour)+(threeThenFour)]+
((threeThenFour==3)+'_')[one]+
((threeThenFour==3)+'_')[(threeThenFour)-(one)]+
(anObject)['c']+
((anObject)+'_')[(threeThenFour)+(threeThenFour)]+
(anObject)['three']+
((threeThenFour==3)+'_')[one];
// theConstructor => "constructor"
(anObject)['_']=(three)[theConstructor][theConstructor];
(theReturn)=((threeThenFour==3)+'_')[one]+
(anObject).var4ノ+
((anObject)+'_')[(threeThenFour)+(threeThenFour)]+
((threeThenFour==3)+'_')[three-one]+
((threeThenFour==3)+'_')[one]+
(var1+'_')[one];
// theReturn => "return"
(threeThenFour)+=(one);
(anObject)[theReturn]='\\';
(anObject).var3ノ=(anObject+threeThenFour)[three-(one)];
(ovar2o)=(var1+'_')[c ^ _ ^ three];
(anObject)[theConstructor]='\"';
// (anObject)['_'] => Function
(anObject)['_'](
(anObject)['_'](theReturn+
(anObject)[theConstructor]+
(anObject)[theReturn]+
(one)+
(threeThenFour)+
(one)+
(anObject)[theReturn]+
(one)+
((threeThenFour)+(one))+
(threeThenFour)+
(anObject)[theReturn]+
(one)+(
threeThenFour)+
((threeThenFour)+(one))+
(anObject)[theReturn]+
(one)+
((three)+(three))+
((three)-(one))+
(anObject)[theReturn]+
(one)+
((three)+(three))+
(threeThenFour)+
(anObject)[theReturn]+
((threeThenFour)+(one))+
(c ^ _ ^ three)+
(anObject)[theReturn]+
(threeThenFour)+((three)-(one))+
(anObject)[theReturn]+
(one)+(one)+
(c ^ _ ^ three)+
(anObject)[theReturn]+
(one)+
(threeThenFour)+
((threeThenFour)+(one))+
(anObject)[theReturn]+
(one)+
((threeThenFour)+(one))+
(threeThenFour)+
(anObject)[theReturn]+
(one)+
((threeThenFour)+(one))+
(threeThenFour)+
(anObject)[theReturn]+
(one)+
((threeThenFour)+(one))+
((threeThenFour)+(three))+
(anObject)[theReturn]+
(threeThenFour)+
(c ^ _ ^ three)+
(anObject)[theReturn]+
(one)+
((three)-(one))+
((threeThenFour)+(three))+
(anObject)[theReturn]+
(one)+
((threeThenFour)+(one))+
((threeThenFour)+(three))+
(anObject)[theReturn]+
(one)+
((three)+(three))+
((three)-(one))+
(anObject)[theReturn]+
(one)+
((threeThenFour)+(one))+
(threeThenFour)+
(anObject)[theReturn]+
(one)+
(threeThenFour)+
(threeThenFour)+
(anObject)[theReturn]+
(threeThenFour)+
((three)-(one))+
(anObject)[theReturn]+
((threeThenFour)+(one))+
(one)+
(anObject)[theConstructor]
)
(one)
)('_');
_
主な手順を説明しましょう。
このコードは、namedという名前のオブジェクトを作成してから、マジックJavaScript 関数コンストラクタ の値を持つプロパティ_'_'
_を追加します。 JavaScriptでは、任意の文字列をFunctionコンストラクターに渡すことにより、コードとして実行できます。
_(゚Д゚)['_']
_には関数コンストラクタがどのように含まれていますか?それは次の行で行われる賢いテクニックです:
_(゚Д゚)['_'] = (o^_^o)[゚o゚][゚o゚];
_
ここでoと_は3に設定されています。したがって、_o^_^o
_は3に戻ります。明らかに_o^_^o
_は同じ値を返すため、作成者はoを使用した可能性がありますが、難読化には優れていると思います:)。したがって、上記の式は_(3)[゚o゚][゚o゚]
_になります。
大括弧内の_゚o゚
_の値は、前のステートメントの連結によって作成されたストリング「コンストラクター」に設定されます。文字列に変換されたJavaScript式から生成される「オブジェクト」、「true」、「false」、「undefined」などの組み込みJavaScript文字列から個々の文字を引き抜くことによって、文字列「コンストラクタ」を構築する非常に巧妙な方法を使用します。どうやら作者はこれらの組み込み文字列から引き抜く文字 "c"を見つけることができなかったので、それを明示的に記述する必要がありました。角括弧内の文字は、ユニコード文字である゚ o ゚であり、丸括弧で使用される単純なoではなく、どちらも非常によく似ています。 _(3)("constructor")
_を実行すると、 Numberコンストラクター関数 が返されます。 NumberコンストラクターのコンストラクターはFunctionコンストラクターです。したがって、_(3)("constructor")("constructor")
_を実行すると、Functionコンストラクタが取得されます。これにより、最終的に任意の文字列を渡して実行できます。
最後の行は、文字列"alert(\"Hello World\")"
を作成し、それをFunctionコンストラクターに渡して実行します。
問題は、実際のアルファベットを入力せずに、その文字列"alert(\"Hello World\")"
を取得する方法ですか?賢い方法は、_\xxx
_を使用することです。ここで、xxxは8進数であり、文字に変換されます。この文字列を取得するために必要な数値は0、1、2、3、4、5、6、7、8です。ただし、実際にはこれらのすべてが必要ではなく、3つの数値0を使用した単純な算術演算によってこれらを生成できます。 、1、4です。たとえば、「アラート」で文字_'a'
_を生成するには、ASCII 10進数97または8進数141、つまり_\141
_が必要です。上記のオブジェクトのいくつかのプロパティに格納されているのは0、1、4だけなので、それらを連結して_'a'
_を生成できます。これにより、すべての文字列が0、1、4のいずれかに格納されている場合でも、任意の文字列を生成できますДオブジェクトのプロパティ。賢いですか。