サンプリングシェル芸

Thu Dec 12 11:43:16 JST 2019 (modified: Sat Dec 14 15:11:53 JST 2019)
views: 2820, keywords:シェル芸, advent calendar この記事は最終更新日が4年以上前のものです。

 難読化シェル芸の手法の一つに、思わぬところから文字を拾って(サンプリングして)コマンドの文字列にするというものがあります。音楽のサンプリングみたいなものです。文字を拾う方法にもいろいろあるので、まとめてみました。

その前に、何に役立つか

 立ちません。何か得した気にならないと気が済まないという、しみったれた考えが気に食わない。

オープニング曲

 これをループでかけながら試すと雰囲気出ます。

コマンドのエラーやヘルプからのサンプリング

 まず最初に紹介するのは、コマンドの出力する文字列からのサンプリングです。例えば次の例は、難読化シェル芸の名付け親のkanataさんの示した方法をアレンジしたもので、「ls --helpの出力からdateコマンドを実行する」というものです。

### Macのlsで試しました ###
   $ __=$(ls --- 2>&1) ; ${__:54:1}${__:51:1}${__:69:1}${__:55:1}
   2019年 12月12日 木曜日 12時30分24秒 JST

 ls ---の出力は次のようなエラーメッセージです。このように、Macのlsでオプションのエラーを起こすと、使えるオプションの一覧が表示されますが、その中にd, a, t, eが含まれています。これを上のように変数(__)に代入し切り出すとdateになります。

### Mac ###
   $ ls ---
   ls: illegal option -- -
   usage: ls [-@ABCFGHLOPRSTUWabcdefghiklmnopqrstuwx1%] [file ...]

 Ubuntuのlsの場合は次のようにdateが実行できます。Ubuntuの場合、bashであらかじめlslというエイリアスが設定されているので、lsの代わりにlを使うとより訳がわかんなくなります。

### Ubuntu 18.04 ###
   $ eval $(grep -oP "'....'(?=;)" <(l --help))
   2019年 12月 12日 木曜日 12:25:11 JST
   ### Ubuntu 19.10 ###
   $ $(grep -oP "[^ ']*(?=\()" <(l --help))
   Thu 12 Dec 2019 12:22:05 PM JST

今の2例の種明かしですが、Ubuntuのls --helpの出力にdateという単語がそのまま含まれているので、そこを切り出して実行しています。簡単ですね。

### Ubuntu 18.04 ###
   $ ls --help | grep date
                                  FORMAT is interpreted like in 'date'; if FORMAT
   ### Ubuntu 19.10 ###
   $ ls --help | grep date
         --time-style=TIME_STYLE  time/date format with -l; see TIME_STYLE below
   FORMAT is interpreted like in date(1).  If FORMAT is FORMAT1<newline>FORMAT2,

 同じテクニックで、dateのmanからtimeコマンドを実行することもできます。

### Ubuntu 18.04 ###
   $ $(man date | grep -m 1 -o ' ....$') sleep 1
   0.00user 0.00system 0:01.00elapsed 0%CPU (0avgtext+0avgdata 2088maxresident)k
   0inputs+0outputs (0major+72minor)pagefaults 0swaps

ファイル名からのサンプリング

 次に、ファイル名からサンプリングしてみます。

### Ubuntu 18.04 ###
   __=(/*/*u?????);${__[-1]:13}
   2019年 12月 12日 木曜日 17:48:03 JST

この例は、bashのファイルグロブでuがついて後ろに5文字で終わるファイル名を表示して、○○updateというファイルをひっかけてdateをサンプリングしています。私の環境では、たまたま末尾に/sbin/unix_updateが来るので、最後のファイル名から末尾の4文字を切り出しています。

$ echo /*/*u?????
   /bin/bunzip2 /bin/busybox /bin/ntfstruncate ... /sbin/unix_update

かなり環境依存ですが、こんな遊びでそんなこと気にしてもどうしようもありません。

乱数からのサンプリング

 乱数からもdateをとってみましょう。/dev/urandomを使うとアルファベットをランダムに出力できます。

### Ubuntu ###
   $ tr -dc a-z < /dev/urandom
   yjqqtpypyogcuihascrrjshudcnhpjycqkjphxdyyzqxrnflrfztnvddwnkbeilvnigaflndpuohvauqquycttnjzdrljhcoqbvnfdzdvbkkjfqlmdyjnjlckvvodxkrfsb ...

ここからdateを見つけて実行すればいいのですが、たぶんdateが揃うのはかなり後のことになりそうです。

 ですので、dateとバレないようにd, a, t, eを含む単語でa-zを置き換えます。(なんでバレたらダメなんだろうという疑問はさておき)

### Ubuntu ###
   $ tr -dc andante < /dev/urandom | fold -b4 | head
   entn
   datt
   natd
   tada
   nnda
   eddn
   tnda
   aaat
   dtna
   dett

そしてこれを無造作にshに突っ込むと、わりと短時間でdateが実行されます。変なコマンドが起動してシステムを壊したりファイルを消したりするかもしれませんので注意が必要です。

### Ubuntu ###
   $ tr -dc andante < /dev/urandom | fold -b4 | sh 2>/dev/null | grep : 
   2019年 12月 12日 木曜日 21:05:02 JST
   2019年 12月 12日 木曜日 21:05:02 JST
   ・・・

Pythonのunicodedataからのサンプリング

 闇豚さん(@yami_buta)のシェル芸で知ったんですが、Pythonにはunicodedataというパッケージがあり、unicodeの情報を見ることができます。

$ python3 -c 'import unicodedata;print(unicodedata.name("൹"))'
   MALAYALAM DATE MARK

上の出力のように、説明文に「DATE」とある文字がたくさんあるので、これをサンプリングするとdateが実行できます。

$ $(python3 -c 'import unicodedata;print(unicodedata.name("൹").split()[1].lower())')
   2019年 12月12日 木曜日 21時20分00秒 JST
   ### 超絶便利Pythonラッパーコマンドopy(呼び方注意)を使う ###
   $ $( echo ൹ | opy '[unicodedata.name(F1).split()[1].lower()]' )
   2019年 12月12日 木曜日 21時21分09秒 JST

余談ですが、上で使った「超絶便利Pythonラッパーコマンドopy(呼び方注意)」は、https://github.com/ryuichiueda/opy にあるのでインストールしてStarをつけましょう。

ウェブからのサンプリング

 最後に、インターーネッツからのスムーズなdateの実行をやってみます。題材のウェブサイトは、終わってしまうと長女から聞かされてショックを受けているラジオ番組「宮川賢のデートの時間でそ?!」のトップページとします。dateだけに。ただ、あんまりみんなでわーっとやると先方から叱られますので、試す場合は別のページを探してください。ていうか長女よ、お前小学生だろ。なに聞いてるんだ。

$ curl https://www.tbsradio.jp/deso/ 2>/dev/null | grep -oP 'new [^(0]{4}' 
   | sed 's/.*/\L&/;s/.* //e'
   2019年 12月 13日 金曜日 09:57:41 JST

 これは特にこのページだからできることではなく、JavaScriptのnew Date()が存在しているページならどれでも可能です。(切り取り方はアレンジする必要があります。)

### ページのHTMLのここから持ってきた ###
   ・・・
           <script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
                   new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
   ・・・

以上。

宣伝

 SoftwareDesignにて連載3年目に入った「シェル芸人の挑戦状」では、もう少し実用的なシェル芸を勉強できます。ぜひぜひぜひぜひ。

 この記事と同じくらいの変態シェル芸を堪能したい場合は、12/28のシェル芸勉強会にぜひご参加ください。特に何もしてなくても叱られないので、初心者の方もどうぞー。みなさん親切です。

今度こそ以上。

ノート   このエントリーをはてなブックマークに追加 
 

やり散らかし一覧

記事いろいろ