diff options
Diffstat (limited to 'public/posts/2022-04-09/phperkaigi-2022-tokens/index.html')
| -rw-r--r-- | public/posts/2022-04-09/phperkaigi-2022-tokens/index.html | 76 |
1 files changed, 23 insertions, 53 deletions
diff --git a/public/posts/2022-04-09/phperkaigi-2022-tokens/index.html b/public/posts/2022-04-09/phperkaigi-2022-tokens/index.html index d16739b..bbeacb2 100644 --- a/public/posts/2022-04-09/phperkaigi-2022-tokens/index.html +++ b/public/posts/2022-04-09/phperkaigi-2022-tokens/index.html @@ -66,8 +66,7 @@ ソースコードはこちら。実行には PHP 8.1 以上が必要なので注意。 </p> - <pre class="highlight" language="php" linenumbering="unnumbered"> - <code><?php + <pre class="highlight" language="php" linenumbering="unnumbered"><code><?php declare(strict_types=0O1); @@ -135,8 +134,7 @@ $👉, $👍, $👍, $📝, $👉, $👎, $📝, $👈, $📝, - ]);</code> - </pre> + ]);</code></pre> <p> この問題は、単に適切なバージョンの PHP で動かせばトークンが得られる。 @@ -165,8 +163,7 @@ なお、brainf*ck プログラムを普通の書き方で書くと、次のようになる。 </p> - <pre class="monospaced highlight"> - <code>+ + + + + + + + + + + <pre class="monospaced highlight"><code>+ + + + + + + + + + [ > + + + > + + + + + @@ -187,8 +184,7 @@ < . > + + . > - . -< .</code> - </pre> +< .</code></pre> <p> 実行結果はこちら:<a href="https://ideone.com/22VWmb">https://ideone.com/22VWmb</a> @@ -271,9 +267,7 @@ ソースコードのライセンスを示したこの部分だが、 </p> - <pre class="highlight" language="php" linenumbering="unnumbered"> - <code>https://creativecommons.org/publicdomain/zero/1.0/</code> - </pre> + <pre class="highlight" language="php" linenumbering="unnumbered"><code>https://creativecommons.org/publicdomain/zero/1.0/</code></pre> <p> 完全に合法な PHP のコードである。<code>https:</code>部分はラベル、<code>//</code>以降は行コメントになっている。 @@ -286,13 +280,11 @@ ソースコード中に、ほとんど数値リテラルが書かれていないことにお気づきだろうか。 PHP では、型変換を利用することで任意の整数を作り出すことができる。 </p> - <pre class="highlight" language="php" linenumbering="unnumbered"> - <code>assert(0 === +!![]); + <pre class="highlight" language="php" linenumbering="unnumbered"><code>assert(0 === +!![]); assert(1 === +![]); assert(2 === ![]+![]); assert(3 === ![]+![]+![]); -assert(10 === +(![].+!![]));</code> - </pre> +assert(10 === +(![].+!![]));</code></pre> <p> <code>[]</code>に<code>!</code>を適用すると<code>true</code>が返ってくる。それに<code>+</code>を適用すると、<code>bool</code>から<code>int</code>ヘの型変換が走り、<code>1</code>が生成される。<code>10</code>はさらにトリッキーだ。まず<code>1</code>と<code>0</code>を作り、<code>.</code>で文字列として結合する (<code>'10'</code>)。これに<code>+</code>を適用すると、<code>string</code>から<code>int</code>への型変換が走り、<code>10</code>が生まれる (コード量に頓着しないなら、<code>1</code>を 10 個足し合わせてももちろん 10 が作れる)。 @@ -333,8 +325,7 @@ assert(10 === +(![].+!![]));</code> ソースコードはこちら。実行には PHP 8.0 以上が必要なので注意。 </p> - <pre class="highlight" language="php" linenumbering="unnumbered"> - <code><?php + <pre class="highlight" language="php" linenumbering="unnumbered"><code><?php /********************************************************* * This program displays a PHPer token. * @@ -367,8 +358,7 @@ assert(10 === +(![].+!![]));</code> $x = str_replace(search: ['0', '1'], replace: [' ', '#'], subject: $x); $x = implode("\n", str_split($x, length: 5)); echo "{$x}\n\n"; - }</code> - </pre> + }</code></pre> <p> さて、この問題はさきほどのように単純に実行しただけでは、謎のブロックが表示されるだけでトークンは得られない。 トークンを得るためには、ソースコードを読み、定数<code>N</code>を特定する必要がある。 @@ -384,43 +374,33 @@ assert(10 === +(![].+!![]));</code> まずはソースコードを読んでいく。 </p> - <pre class="highlight" language="php" linenumbering="unnumbered"> - <code>$token = [ + <pre class="highlight" language="php" linenumbering="unnumbered"><code>$token = [ // 略 - ];</code> - </pre> + ];</code></pre> <p> 数値からなる<code>$token</code>があり、各要素をループしている。 </p> - <pre class="highlight" language="php" linenumbering="unnumbered"> - <code> $x = $x ^ N;</code> - </pre> + <pre class="highlight" language="php" linenumbering="unnumbered"><code> $x = $x ^ N;</code></pre> <p> まずは排他的論理和 (xor) を取り、 </p> - <pre class="highlight" language="php" linenumbering="unnumbered"> - <code> $x = sprintf('%025b', $x);</code> - </pre> + <pre class="highlight" language="php" linenumbering="unnumbered"><code> $x = sprintf('%025b', $x);</code></pre> <p> 二進数に変換して、 </p> - <pre class="highlight" language="php" linenumbering="unnumbered"> - <code> $x = str_replace(search: ['0', '1'], replace: [' ', '#'], subject: $x);</code> - </pre> + <pre class="highlight" language="php" linenumbering="unnumbered"><code> $x = str_replace(search: ['0', '1'], replace: [' ', '#'], subject: $x);</code></pre> <p> 0 を空白に、1 を<code>#</code>にし、 </p> - <pre class="highlight" language="php" linenumbering="unnumbered"> - <code> $x = implode("\n", str_split($x, length: 5));</code> - </pre> + <pre class="highlight" language="php" linenumbering="unnumbered"><code> $x = implode("\n", str_split($x, length: 5));</code></pre> <p> 5文字ごとに区切ったあと、改行で結合している。 @@ -474,16 +454,13 @@ assert(10 === +(![].+!![]));</code> <code>N</code>は高々 </p> - <pre class="highlight" language="php" linenumbering="unnumbered"> - <code>assert(0 <= N && N <= 0b11111_11111_11111_11111_11111);</code> - </pre> + <pre class="highlight" language="php" linenumbering="unnumbered"><code>assert(0 <= N && N <= 0b11111_11111_11111_11111_11111);</code></pre> <p> なのでブルートフォースしてもよいが、ここではブルートフォースしない方法を紹介する。 </p> - <pre class="highlight" language="php" linenumbering="unnumbered"> - <code><?php + <pre class="highlight" language="php" linenumbering="unnumbered"><code><?php $x = 0x14B499C; @@ -498,15 +475,13 @@ assert(10 === +(![].+!![]));</code> "#####\n" . " # # \n" . "#####\n" . - " # # ");</code> - </pre> + " # # ");</code></pre> <p> この一連の変換に対する逆変換を考えると、次のようになる。 </p> - <pre class="highlight" language="php" linenumbering="unnumbered"> - <code><?php + <pre class="highlight" language="php" linenumbering="unnumbered"><code><?php $x = " # # \n" . @@ -521,8 +496,7 @@ $x = bindec($x); $n = $x ^ 0x14B499C; -echo "N = $n\n";</code> - </pre> +echo "N = $n\n";</code></pre> <p> これを実行すると、<code>N</code>が得られる。 @@ -536,8 +510,7 @@ echo "N = $n\n";</code> ソースコードはこちら。 </p> - <pre class="highlight" language="php" linenumbering="unnumbered"> - <code><?php + <pre class="highlight" language="php" linenumbering="unnumbered"><code><?php // License: https://creativecommons.org/publicdomain/zero/1.0/ // This is a quine-like program to generate a PHPer token. @@ -565,16 +538,13 @@ echo "N = $n\n";</code> $t = null.false; for ($i = 0; $i <= intdiv(__LINE__-035,6); ++$i) if (!isset($xs[$i])) break; else $t .= implode("\n", str_split(str_replace(['0','1'], [' ','##'], sprintf(chr(37) . '025b', $xs[$i])), 012)) . "\n\n"; $ws = array_map(fn($w) => implode(', ', $w), array_chunk(array_map(fn($x) => sprintf('0x' . chr(37) . '07X', $x), $xs), 10)); - printf($s, $t, str_rot13("<<<'D'\n{$s}\nD"), implode(",\n", $ws));</code> - </pre> + printf($s, $t, str_rot13("<<<'D'\n{$s}\nD"), implode(",\n", $ws));</code></pre> <p> コメントにもあるとおり、次のようにして実行すれば答えがでてくる。 </p> - <pre class="highlight" language="shell-session" linenumbering="unnumbered"> - <code>$ php toquine.php | php | php | php | ...</code> - </pre> + <pre class="highlight" language="shell-session" linenumbering="unnumbered"><code>$ php toquine.php | php | php | php | ...</code></pre> <p> 実際にはもう少しパイプで繋げなければならない。 |
