こんにちは、徹夜が大好きな? cloudpack津村 です。

春です。

本日は、 [mikalab.info|cloudpack.media]に御アクセス頂き、誠にありがとうございます。

大変申し訳ありませんが、
温泉成分と桜分(声でお仕事なさる方、魔法で戦う方、及び食物・植物等)が足りない為・・・(中略)

シェルスクリプトの改変をチェックする

さて、シェルスクリプトは大変優れたインタプリタ言語である一方、大変困ったことにエディタさえあれば容易に改変できてしまいます。
本来は「シェルスクリプト 難読化」とかやれば良いのでしょうが、難読化してしまうと逆にインタプリタな高級言語の良さがまーーーーーーーったく無くなってしまいます。
(PHPとかだと、最終的に中間言語にさえなれば何食わせても良いという話もありますが。)

サンプル1、改変されてしまってもわからないコード

#!/bin/sh
 
### Init
CMD_ECHO="/bin/echo"
OUTPUT="Hello Sakura World!!!"
 
${CMD_ECHO} $OUTPUT
exit 0

普通のHello Worldです。
単純に「Hello Sakura World!」してるだけなので、 findsed -i 等でOUTPUTの値を一斉に書き換えてしまうと、容易に動作が変更されていまいます。
単純に言うと誤爆です。人間が手で誤爆する事もあります。

では、スクリプトが自身の変更を検知して勝手に適宜な戻り値で強制終了するように変更しましょう。

サンプル2、改変された事を検知して止まるコード

#!/bin/sh
### Init
CMD_ECHO="/bin/echo"
CMD_CAT="/bin/cat"
CMD_GREP="/bin/grep"
CMD_SHASUM="/usr/bin/shasum"
CMD_AWK="/bin/awk"
HASH="ff49f2607b4588e1be215553357dfa8027972637"
 
### Init OutputWords
OUTPUT="Hello Sakura World!!!"
 
### Check Change
CHK_HASH=`${CMD_CAT} "${0}" | ${CMD_GREP} -v "^HASH" | ${CMD_SHASUM} | ${CMD_AWK} -F" " '{print $1}'`
 
if [ "${CHK_HASH}" != "${HASH}" ]; then
 exit 1
fi
 
${CMD_ECHO} $OUTPUT
exit 0

ここでは、変数 HASH と、 'Check Change' 以下の4行のコード、及び依存する CMD変数によって、コードの整合性を確認しています。
HASH(シグネチャ)を作る際、HASH変数は除外します。
これは、ハッシュのハッシュのハッシュのハッシュのハッシュの(中略・ぜーはーぜーはー…)ハッシュを作り続ける為、HASH以外の部分に対してシグネチャを生成します。
単純に grep で除外しているだけなので、「!/bin/sh」の後に「-x」有りなしとか観てもいいかも知れません。

$ ./sakura.sh
Hello Sakura World!!!
$ echo $?
0

改変されていない時、上記のように何事も無くHelloWorldし、正常にプロセスは終了します。

では、コードを改変しましょう。
さくらちゃんの魔法(星の力)から、クロウの魔術(闇の力)に変更する為に、 sed -i でコードを変更します。

$ cp -prv sakura.sh crow.sh
`sakura.sh' -> `crow.sh'
$ sed -i "s/Sakura World/Crow Magic/g" ./crow.sh
$ ./crow.sh
$ echo $?
1

しかし、シグネチャは「Hello Sakura World」のままの為、シグネチャのチェックに失敗し、異常終了します。

こうする事で、ついついリポジトリで管理しないけど、以外と大事なスクリプトを、ちょっとした手間で保護する事が出来ます。

おわりに

やっぱりB Shell系は書かないと忘れますね。
Solaris8で鍛えられたのに、いかんいかん。。。
この手の書物していると、『CMD_hoge=`which hoge`』とかやって、たまにおーちゃくするのですが、暗黙的なパス表記をして環境依存になるよりマシだと思います。(もちろん後で直しますよ?)

尚、cloudpack虎ノ門オフィスから東京タワーが観える事と、本エントリのサンプルコードは、あまり関係ないかもしれません。:P

元記事はこちらです。
自身の改変を検知して止まるシェルスクリプト