Statifier¶
経緯¶
とあるコマンドをインストールしようと思った・・・・が・・・・・ 駄目っ・・・・・!
パッケージの依存関係がすごい。つまり、1つコマンドを導入するのに、入れたくないパッケージを山のように入れなければならない。。
そのコマンド1つだけ実行したいだけなのに・・・
そこで思いつく悪魔の発想・・・っ!
1バイナリで動くようにすれば、他の環境に楽に持っていける。理論上は出来るはず・・・と思い、調べたら出てきた。
statifierというのを使えば可能であることがわかった。
メンテナンスはあまり活発ではないようだが、x86_64にも対応してくれているっぽい。
その他の案として、参照している動的リンクライブラリを全部洗い出してコピーし、LD_PRELOAD環境変数に突っ込んだ上で実行すればいけるかなぁ。とか、思ったんだけど、試してはいない。
概要¶
結局、なにがしたいかと言うと、
$ cat test.c #include <stdio.h> int main(){ printf("Helloworld"); return 0; } $ gcc test.c $ ldd a.out linux-vdso.so.1 => (0x00007fffc62d0000) libc.so.6 => /lib64/libc.so.6 (0x00007f886214a000) /lib64/ld-linux-x86-64.so.2 (0x00007f8862517000)
この単純なプログラムですら、3つの動的リンクライブラリを必要としている事がわかる。
このライブラリがシステムに存在しないと、プログラムは動かない。
だったら・・・プログラム(a.out)の中に、この3つの動的リンクライブラリを取り込んだらいいじゃない。
という発想。
Install¶
まず、自分はこのソフトのコンパイルのため、コンパイル用の仮想環境を用意した。
statifierを導入するために、依存関係となっている複数パッケージを導入する・・・のは本末転倒である。
コンパイル済みのものだけを目的の環境にコピーしてやればよいではないか。
という訳で、ここから最新版のtar.gzをダウンロードする。
自分が実施した時は、statifier-1.7.4.tar.gz でした。
適当なところに展開しておく。
$ tar xvfz statifier-1.7.4.tar.gz
コンパイル時に必要となるパッケージをインストール。
# yum install glibc.i686 glibc-devel.i686 libgcc.x86_64 libgcc.i686
makeする。
$ cd xvfz statifier-1.7.4 $ bash ./configure $ make
というのが、めんどうな方のために自分がコンパイルしたものをここに置いておく。
statifier-1.7.4_for_x86_64.tar.gz
実行環境について¶
さっそく動作確認してみる。
dateコマンドを静的リンクにしてみよう。
$ ldd /bin/date linux-vdso.so.1 => (0x00007fff3432f000) libc.so.6 => /lib64/libc.so.6 (0x00007f61fcf4f000) /lib64/ld-linux-x86-64.so.2 (0x00007f61fd31c000) $ cd statifier-1.7.4 $ setarch `uname -m` -R src/statifier.sh /bin/date /tmp/date2
これでstaticなdateコマンドが出来たはず。
$ setarch `uname -m` -R /tmp/date2 2016年 6月 5日 日曜日 17:30:56 JST $ ldd /tmp/date2 動的実行ファイルではありません
うん、たぶんうまく動いてるんだと思われる。
超注意:ASLRの怪¶
なんか、おまじないのようなコマンドがくっついているのが、おわかり頂けただろうか・・・
$ setarch `uname -m` -R
実は、これ、LinuxのASLRというセキュリティ機能を一時的に無効にするコマンドになります。
ASLRについては、ググるか、CTF_Pwnをみてね。
なんか、いろいろやってみたけど、動かなくてね~。
どうやら、「静的リンクの実行体に変換する時」と、「実際に動作させる時」にメモリアドレスが同じになってないといけないっぽい。
なので、必ず「setarch uname -m
-R」を頭につけて変換&実行しておくれ。
想定される使い方¶
よっしゃー。これで、1バイナリになって、どの環境でも動くぞイヤッッホォォォオオォオウ!
と、ならないのが世の定め。。
ちょっとLinuxディストリビューションの違うLinuxに持ち込んでみたが動かない。。
まぁ全部試した訳ではないのだけれど、
同じディストリビューションだと動いているっぽい。
たぶん、kernelのバージョンが違ってたりすると、取り込んだlibcでそれを吸収できないとか、そんな感じになっている気がする。
調べてないけど。
そう考えると1バイナリになるGo言語って結構考えられてますね。ファイルサイズが大きくなるだろうから、そこらへんトレードオフなんだろうけど。
なので、自分は同じLinuxディストリビューションで2環境用意して運用している。
- VMでコンパイル用環境を作る(足りない物は、なんでもかんでもyum install。使い捨て)
- 本番環境。できるだけパッケージを入れない。
補足¶
statifier には、こんな記述が
Recent Linux kernels introduced VDSO (Virtual Dynamic Shared Object) and stack randomization. Those things, while valuable features, don't play well with Statifier.
意訳:ASLRとVDSOを使うバイナリは上手く動かないぜ
この statifier を作った方達は、Ermine というソフトを販売しております。
Ermine works in a fashion similar to Statifier, creating self-contained executables from dynamically-linked >applications. But Ermine-packed applications are not snapshots: instead they can be thought of as small virtual machines.
And because of this an Ermine-packed application does not suffer from the problems created by VDSO/stack randomization意訳:Ermineなら問題ないんだぜ
Ermine
http://www.magicermine.com/
15日トライアルもできるらしい。
参考¶
bkブログ - statifier で動的リンクの実行ファイルを擬似的に静的リンクにする
http://0xcc.net/blog/archives/000089.html
ELF Statifierを使って実行形式ファイルをシステム間で移動する
https://osdn.jp/magazine/08/12/02/012255