動的リンクの実行ファイルを静的リンクに変換する

なんとか1バイナリにしたいという願望
kanataほぼ8年前に追加

statifierというのを使ってみました。

Statifier

経緯

とあるコマンドをインストールしようと思った・・・・が・・・・・ 駄目っ・・・・・!
パッケージの依存関係がすごい。つまり、1つコマンドを導入するのに、入れたくないパッケージを山のように入れなければならない。。

そのコマンド1つだけ実行したいだけなのに・・・

そこで思いつく悪魔の発想・・・っ!

fig2.png
fig1.png

1バイナリで動くようにすれば、他の環境に楽に持っていける。理論上は出来るはず・・・と思い、調べたら出てきた。

statifierというのを使えば可能であることがわかった。

ELF STATIFIER MAIN PAGE

メンテナンスはあまり活発ではないようだが、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


コメント

クリップボードから画像を追加 (サイズの上限: 100 MB)