17

「SteamforLinux」をDebianで動作させようとして、問題が発生しました。libcef(Chromium Embedded Framework)はGLIBC_2.13(Debianテストのeglibcが提供できる)で正常に動作しますが、GLIBC_2.15(eglibcが提供できない)から1つの厄介な小さな追加関数が必要です。

$ readelf -s libcef.so | grep -E "@GLIBC_2\.1[4567]"
1037: 00000000     0 FUNC    GLOBAL DEFAULT  UND __fdelt_chk@GLIBC_2.15 (49)
2733: 00000000     0 FUNC    GLOBAL DEFAULT  UND __fdelt_chk@@GLIBC_2.15

ここでの私の攻撃計画は、LD_PRELOADこれらの機能だけを提供するシムライブラリへの攻撃でした。これはうまくいかないようです。私は本当にインストールを避けたいと思ってGLIBC_2.17います(Debian実験的であるため、Debian sidでさえまだ持っていますGLIBC_2.13)。


これは私が試したことです。

fdelt_chk.c基本的にGNUCライブラリから盗まれます:

#include <sys/select.h>

# define strong_alias(name, aliasname) _strong_alias(name, aliasname)
# define _strong_alias(name, aliasname) \
  extern __typeof (name) aliasname __attribute__ ((alias (#name)));

unsigned long int
__fdelt_chk (unsigned long int d)
{
  if (d >= FD_SETSIZE)
    __chk_fail ();

  return d / __NFDBITS;
}
strong_alias (__fdelt_chk, __fdelt_warn)

私のVersionsスクリプトは次のようになります。

GLIBC_2.15 {
    __fdelt_chk; __fdelt_warn;
};

次に、次のようにライブラリを構築します。

$ gcc -m32 -c -fPIC fdelt_chk.c -o fdelt_chk.o
$ gcc -m32 -shared -nostartfiles -Wl,-s -Wl,--version-script Versions -o fdelt_chk.so fdelt_chk.o

ただし、Steamを実行すると(そもそも動作させるために余分なものがたくさんあります)、ローダーはまだシンボルを見つけることを拒否します:

% LD_LIBRARY_PATH="/home/tinctorius/.local/share/Steam/ubuntu12_32" LD_PRELOAD=./fdelt_chk.so:./steamui.so ./steam 
./steam: /lib/i386-linux-gnu/i686/cmov/libc.so.6: version `GLIBC_2.15' not found (required by /home/tinctorius/.local/share/Steam/ubuntu12_32/libcef.so)    

ただし、バージョンシンボルは、作成した.soばかりのIによっても提供されます。

% readelf -s fdelt_chk.so

Symbol table '.dynsym' contains 8 entries:
   Num:    Value  Size Type    Bind   Vis      Ndx Name
     0: 00000000     0 NOTYPE  LOCAL  DEFAULT  UND 
     1: 00000000     0 FUNC    GLOBAL DEFAULT  UND __chk_fail@GLIBC_2.3.4 (3)
     2: 0000146c     0 NOTYPE  GLOBAL DEFAULT  ABS _edata
     3: 0000146c     0 NOTYPE  GLOBAL DEFAULT  ABS _end
     4: 00000310    44 FUNC    GLOBAL DEFAULT   11 __fdelt_warn@@GLIBC_2.15
     5: 00000310    44 FUNC    GLOBAL DEFAULT   11 __fdelt_chk@@GLIBC_2.15
     6: 00000000     0 OBJECT  GLOBAL DEFAULT  ABS GLIBC_2.15
     7: 0000146c     0 NOTYPE  GLOBAL DEFAULT  ABS __bss_start

この時点で、ローダー(誰?)をだましてシンボルを選択させるために何ができるかわかりません。私は正しい方向に進んでいますか?

4

2 に答える 2

9

Steamではありませんが、私はこれと同じ問題に遭遇しました。私のシステムが持っていた間、私2.15が実行しようとしていたものが欲しかった。不足している機能に対して独自の実装を簡単に提供できる、私たちのような単純なケースの解決策を見つけました。fdelt_chk2.14

私は、機能を実装してそれを実行するというあなたの試みられた解決策から始めましたLD_PRELOADLD_DEBUG=all(osgxによって提案されたように)を使用すると、リンカーがまだ探していることがわかりました。2.15したがって、正しいシンボルを使用するだけでは不十分であり、どこかに他のバージョン管理メカニズムがありました。私はそれに気づきobjdump -preadelf -V両方ともへの参照を示した2.15ので、ELFに関するドキュメントを調べて、バージョン要件に関する情報を見つけました。

したがって、私の新しい目標は、2.15への参照を他の何かへの参照に変換することでした。2.15を参照する構造を、などの下位バージョンを参照する構造で上書きすることは合理的であるように思われました2.1。結局、試行錯誤の末、右Elfxx_Vernaux(es?)を編集するだけ.gnu.version_rで十分であることがわかりましたが、ハッカーには注意が必要だと思います。

この.gnu.version_rセクションは、16バイトElfxx_Verneedと16バイトのリストですElfxx_Vernaux。各Elfxx_Verneedエントリの後には、関連付けられたElfxx_Vernauxesが続きます。私が知る限り、ドキュメントに記載されている場合でも、vn_file実際には関連するElfxx_Vernauxesがいくつあるかがわかりますnumber of associated verneed array entries。しかし、それは私の側の誤解かもしれません。

それで、編集を始めるために、からの情報のいくつかを見てみましょうreadelf -V。気にならない部分を切り取った。

$ readelf -V mybinary
<snip stuff before .gnu.version_r>
Version needs section '.gnu.version_r' contains 5 entries:
 Addr: 0x00000000000021ac  Offset: 0x0021ac  Link: 4 (.dynstr)
<snip libraries that don't refer to GLIBC_2.15>
  0x00c0: Version: 1  File: libc.so.6  Cnt: 10
  0x00d0:   Name: GLIBC_2.3  Flags: none  Version: 19
  0x00e0:   Name: GLIBC_2.7  Flags: none  Version: 16
  0x00f0:   Name: GLIBC_2.2  Flags: none  Version: 15
  0x0100:   Name: GLIBC_2.2.4  Flags: none  Version: 14
  0x0110:   Name: GLIBC_2.1.3  Flags: none  Version: 13
  0x0120:   Name: GLIBC_2.15  Flags: none  Version: 12
  0x0130:   Name: GLIBC_2.4  Flags: none  Version: 10
  0x0140:   Name: GLIBC_2.1  Flags: none  Version: 9
  0x0150:   Name: GLIBC_2.3.4  Flags: none  Version: 4
  0x0160:   Name: GLIBC_2.0  Flags: none  Version: 2

これから、セクションがで始まることがわかります0x21ac。リストされた各ファイルには、サブエントリごとに(のように)Elfxx_Verneedが続きます。構造をダンプしているだけなので、出力の情報の順序は常にファイルの順序と一致すると思います。これが私のセクション全体です。Elfxx_VernauxGLIBC_2.3readelf .gnu.version_r

000021A0                                          01 00 02 00
000021B0   A3 0C 00 00  10 00 00 00  30 00 00 00  11 69 69 0D
000021C0   00 00 11 00  32 0D 00 00  10 00 00 00  10 69 69 0D
000021D0   00 00 0B 00  3C 0D 00 00  00 00 00 00  01 00 02 00
000021E0   BE 0C 00 00  10 00 00 00  30 00 00 00  13 69 69 0D
000021F0   00 00 08 00  46 0D 00 00  10 00 00 00  10 69 69 0D
00002200   00 00 07 00  3C 0D 00 00  00 00 00 00  01 00 02 00
00002210   99 0C 00 00  10 00 00 00  30 00 00 00  11 69 69 0D
00002220   00 00 06 00  32 0D 00 00  10 00 00 00  10 69 69 0D
00002230   00 00 05 00  3C 0D 00 00  00 00 00 00  01 00 02 00
00002240   AE 0C 00 00  10 00 00 00  30 00 00 00  11 69 69 0D
00002250   00 00 12 00  32 0D 00 00  10 00 00 00  10 69 69 0D
00002260   00 00 03 00  3C 0D 00 00  00 00 00 00  01 00 0A 00
00002270   FF 0C 00 00  10 00 00 00  00 00 00 00  13 69 69 0D
00002280   00 00 13 00  46 0D 00 00  10 00 00 00  17 69 69 0D
00002290   00 00 10 00  50 0D 00 00  10 00 00 00  12 69 69 0D
000022A0   00 00 0F 00  5A 0D 00 00  10 00 00 00  74 1A 69 09
000022B0   00 00 0E 00  64 0D 00 00  10 00 00 00  73 1F 69 09
000022C0   00 00 0D 00  70 0D 00 00  10 00 00 00  95 91 96 06
000022D0   00 00 0C 00  7C 0D 00 00  10 00 00 00  14 69 69 0D
000022E0   00 00 0A 00  87 0D 00 00  10 00 00 00  11 69 69 0D
000022F0   00 00 09 00  32 0D 00 00  10 00 00 00  74 19 69 09
00002300   00 00 04 00  91 0D 00 00  10 00 00 00  10 69 69 0D
00002310   00 00 02 00  3C 0D 00 00  00 00 00 00

ここで構造について簡単に説明すると、最初はElfxx_Verneed。です。ドキュメントによると、2つElfxx_Vernauxのesがあり、1つは16バイトのオフセットで、次Elfxx_Verneedは48バイトのオフセットであることがわかります。これらのオフセットは、現在の構造の先頭からのものです。技術的には、関連付けられたElfxx_Vernauxesは現在の後に隣接していないように見えますElfxx_Verneedが、実際には、私が調べたすべてのファイルで隣接していました。

これから、いくつかの異なる方法で必要なファイル(libc.so.6)を見つけることができます。文字列を相互参照するか(これについては説明しません)、Elfxx_Verneedカウントが0A 00(10、readelf上記の出力と一致します)のを見つけるか、最後Elfxx_Verneedの出力であるため最後の文字列を見つけreadelfます。いずれにせよ、私のファイルに適したものはにあります0x226C。その最初Elfxx_Vernauxはで始まり0x227Cます。

(12、上記の出力と一致する)Elfxx_Vernauxのバージョンでを検索します。一致するがであり、構造全体がであることがわかります。オフセットをそのままにするために、最初の12バイトを上書きします。結局のところ、構造を移動するのではなく、データを変更するだけです。0C 00readelfElfxx_Vernaux0x22CC95 91 96 06 00 00 0C 00 7C 0D 00 00 10 00 00 00

上書きするデータを選択するには、Elfxx_Vernaux満足できるバージョンのglibcの別のデータからデータをコピーするだけです。私は、データを使用して、ファイルに2.1あるの1つを選択しました。したがって、これから最初の12バイトを取得し、上記の最初の12バイトを上書きします。これで、16進編集は完了です。0x22EC11 69 69 0D 00 00 09 00 32 0D 00 00 10 00 00 00

もちろん、処理する複数の参照がある場合があります。プログラムには、編集する複数のバイナリがある場合があります。

この時点では、プログラムはまだ実行されません。しかし、そのようなGLIBC_2.15 not foundことを言われる代わりに、行方不明について文句を言うべき__fdelt_chkです。ここLD_PRELOADで、質問で説明されているシムとingを実行します。ただし、実装をとしてバージョン管理する代わりに、2.1516進編集中に選択したバージョンを使用します。この時点で、プログラムが実行されます。

この方法は、不足しているものすべてに実装を提供できるかどうかに依存します。私たちの__fdelt_chkやり方は非常に単純ですが、場合によっては、システムのlibcをアップグレードするよりも、実装を提供する方が難しい場合があることは間違いありません。

于 2013-03-03T04:02:45.227 に答える
8

価値のあることとして、__ fdelt_chk関数は、glibc2.15で追加されたFORTIFY_SOURCE機能に関連しています。これにより、コンパイル時と実行時のバッファオーバーフローのチェックが可能になります。

次のCFLAGSを追加して再コンパイルできた場合、追加のチェックなしで下位互換性のあるバイナリが構築されます。

-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0
于 2014-01-06T15:20:16.953 に答える