hiro氏作の難読化シェル芸の解読
===
###### tags: `シェル芸`
hiro氏の放った難読化シェル芸。脅威の圧縮・難読率にTLが震撼した。
最初は[jsfuck](https://github.com/aemkei/jsfuck)でも実行したのかと思ったがきちんとしたbashのコマンドだった。
https://twitter.com/minyoruminyon/status/1152161173158055936
```bash
\;\$\'\\$[$$&&$$]$[$[]$[$$&&$$]$[]>>$[$$&&$$]]$[$[]$[$$&&$$]$[]>>$[$$&&$$]]\\$[$$&&$$]$[$[]$[$$&&$$]$[]>>$[$$&&$$]]$[$$&&$$]\\$[$$&&$$]$[$[]$[$$&&$$]$[]$[]]\\$[$$&&$$]$[$[]$[$$&&$$]$[]>>$[$$&&$$]]$[$[$$&&$$]$[]>>$[$$&&$$]]\'\;>&$;. $ #シェル芸 #難daコレ
```
パット見、呪文にしか見えない。
しかしながら、一つ一つ紐解いていくと、Bashの様々な機能を活用した高度なシェルであることがわかった。
解読結果をここにまとめる。
# 記号で表現された整数値
まず、このシェルの中に頻出する以下のシェルは数値を表現している。
| シェル | 値 |
| ----------- | -------- |
| `$[]` | 0 |
| `$[$$&&$$]` | 1 |
このことを踏まえて、前述の式を10進数の数値に置換すると次のようになる。
```bash
\;\$\'\\1$[010>>1]$[010>>1]\\1$[010>>1]1\\1$[0100]\\1$[010>>1]$[10>>1]\'\;>&$;. $ #シェル芸 #難daコレ
```
なんとなく数値計算をしていることが見えてきた。
この中から一つ計算式を取り出してみる。
# ビット演算
`$[010>>1]`という式はBashの算術演算を行っている。
Bashの算術演算は`$(( 1 + 1 ))`というふうに書くのが一般的だが
`$[ 1 + 1]`でも同様の演算ができる。
で、`$[010>>1]`の計算内容だが、010は8進数の10で、それを1右シフトしている。
010を2進数3桁に変換すると次のようになる。
| | 2桁目 | 1桁目 |
| --- | ---- | ----- |
|8進数| 1 | 0 |
|2進数| 001 | 000 |
これを1右シフトすると4になる。
| | 2桁目 | 1桁目 |
| --- | ---- | ----- |
|2進数| 001 | 000 |
|2進数(右シフト後)| 000 | 100 |
よって`$[010>>1]`は4になる。
ちなみに、Bashでは0で始まる数値を8進数とみなすようだが
Zshでは0で始まっても10進数として扱うのでZsh環境で同じコマンドを実行しても同じ結果にならない。
初めそれに気づかなくてハマった。
`$[10>>1]`は10進数10の右シフト。
以下のように商を次の計算に使用してを繰り返し、
余りを逆順に取得すると10進数から2進数を導ける。
$$
10 \div 2 = 5 \cdots 0
$$
$$
5 \div 2 = 2 \cdots 1
$$
$$
2 \div 2 = 1 \cdots 0
$$
$$
1 \div 2 = 0 \cdots 1
$$
10進数10は1010である。
これを右シフトすると0101。10進数では5になる。
以上の計算を踏まえて、前述のシェルを更に変換すると次のようになる。
```bash
\;\$\'\\144\\141\\164\\145\'\;>&$;. $ #シェル芸 #難daコレ
```
# ASCIIコード
もう大体見えてきたが、これはASCIIコードの数値を計算していた模様。
[ASCIIコード - Wikipedia](https://ja.wikipedia.org/wiki/ASCII)
ASCIIコード表を見比べると、これは d a t e になる。
つまり、おなじみ難読化dateシェル芸であることがわかる。
Bashではコードポイントを文字に変換する機能がある(名前がわからない)。
以下のように、前述のシェルを実行すると、きちんとdateになることがわかる。
```bash
$ echo $'\144\141\164\145'
date
$ $'\144\141\164\145'
2019年 7月 19日 金曜日 22:56:58 JST
```
シェルの先頭にエスケープした$とシングルクォートがあることがからも
最終的にはこのようなシェルのコマンド列に持っていきたいことがわかる。
# リダイレクトの難読化とコマンド実行
末尾に`>&$;. $`というものがあるがこれはファイルへのリダイレクトである。
```bash
>&$;. $ #シェル芸 #難daコレ
```
そしてリダイレクト先は`$`これは`$`というファイルに出力している。
難読化のためにあえて`$`を採用したと思われる。
そして`. $`でファイルを現在のシェルに読み込んで実行している。
このリダイレクト部分を除外して出力を確認してみる。
```bash
\;\$\'\\144\\141\\164\\145\'\;
```
> ;$'\144\141\164\145';: コマンドが見つかりません
つまり、この文字列が`.`によって実行されたことになる。
しかしながら、ターミナル上でコマンドを実行した場合だとまだ不十分。
今回の難読化されたシェルをファイルに書いて`bash nandoku.sh`という具合に実行してみる。
```bash
$ bash nandoku.sh
$: 行 1: nandoku.sh:: コマンドが見つかりません
2019年 7月 19日 金曜日 23:09:34 JST
$ cat $
nandoku.sh: 行 3: ;$'\144\141\164\145';: コマンドが見つかりません
```
$ファイルの先頭にスクリプト名が含まれている。
この文字列を、後続の難読化したdateコマンド列と分けるために、
今回の難読化シェルの先頭にエスケープしたセミコロンが存在したわけである。
dateの後ろのセミコロンも同様で、シェルを分けるためにつけてあるようだ。
解読は以上です。