link もっと前
   2020年 7月 10日 -
      2020年 7月 1日  
link もっと後

link 未来から過去へ表示(*)
link 過去から未来へ表示

日々

link permalink

link 編集する

ELF バイナリで SEGV その 2 - 64 バイト

昨日(2020年 7月 4日の日記参照)は SEGV する ELF バイナリサイズを 92 バイトまで削ることができました。

その後、色々弄っていて見つけたのですが、プログラムヘッダの type を NULL にしておけば、ファイルサイズやオフセットがめちゃくちゃでも execve は文句を言わないっぽいみたいです。

ELF ヘッダの e_ident の後半 8バイトは 0(前半を書き換えると ELF と認識されなくなります)なので、この部分をプログラムヘッダだよ、と指定すれば type NULL に解釈されます。

これで 64 バイト、つまり ELF ヘッダしかない実行ファイルができました。何の役にも立たないですけどね……。

SEGV するバイナリ、64バイト版
$ ls -la a.out

-rwxrwxr-x+ 1 katsuhiro katsuhiro 64 Jul  3 06:39 a.out


SEGV する 64 バイトバイナリ、ELF ヘッダ


SEGV する 64 バイトバイナリ、プログラムヘッダ

これ以上 1 バイトでも削ると ELF ヘッダの長さを下回るため、ELF バイナリとして成立しません。よって 64 バイトが最短だと思いますが、私が気づいていない裏技があるかもしれません。

SEGV する 64 バイトバイナリの検証

このファイルを実行してみると、システムコール execve がエラーを返さないで進むので、ELF ファイルとして認識してもらえているようです。

SEGV する 64 バイトバイナリ、実行
$ strace ./a.out

execve("./a.out", ["./a.out"], 0x7ffedf7dfa90 /* 47 vars */) = 0
--- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=0x400000001} ---
+++ killed by SIGSEGV +++
Segmentation fault
SEGV する 64 バイトバイナリ、readelf
$ readelf -a a.out
ELF Header:
  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 
  Class:                             ELF64
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              EXEC (Executable file)
  Machine:                           Advanced Micro Devices X86-64
  Version:                           0x1
  Entry point address:               0x400000001
  Start of program headers:          8 (bytes into file)
  Start of section headers:          0 (bytes into file)
  Flags:                             0x0
  Size of this header:               64 (bytes)
  Size of program headers:           56 (bytes)
  Number of program headers:         1
  Size of section headers:           0 (bytes)
  Number of section headers:         0
  Section header string table index: 0
There are no sections in this file.
There are no sections to group in this file.
Program Headers:
  Type           Offset             VirtAddr           PhysAddr
                 FileSiz            MemSiz              Flags  Align
  NULL           0x00000001003e0002 0x0000000400000001 0x0000000000000008
                 0x0000000000000000 0x0038004000000000         0x1
There is no dynamic section in this file.
There are no relocations in this file.
The decoding of unwind sections for machine type Advanced Micro Devices X86-64 is not curr
ently supported.
Dynamic symbol information is not available for displaying symbols.
No version information found in this file.

一応 readelf でも読めますが、プログラムヘッダのオフセットやアドレスはめちゃくちゃです。

[編集者: すずき]
[更新: 2020年 7月 5日 21:07]

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



link permalink

link 編集する

ELF バイナリで SEGV その 1 - 92 バイト

昨日(2020年 7月 3日の日記参照)試したところによると、C 言語は 0 文字で SEGV するプログラムを書けました。

では、出力されたバイナリだと最短はいくつでしょうか?とりあえずベースとして C 言語の 0 文字 SEGV プログラムの出力を見ます。

0 文字で SEGV のバイナリサイズ
$ gcc -nostdlib a.c

/usr/bin/ld: warning: cannot find entry symbol _start; defaulting to 0000000000001000

$ ls -la a.out

-rwxr-xr-x 1 katsuhiro katsuhiro 9528 Jul  3 04:11 a.out

なんと 9KB もあります。readelf で見るとダイナミックリンカー関連のシンボルが含まれているようなので、static オプションを付けてダイナミックリンカー関連のシンボルを消します。

0 文字で SEGV のバイナリサイズ、static 版
$ echo -n  > a.c && gcc -nostdlib -static a.c

/usr/bin/ld: warning: cannot find entry symbol _start; defaulting to 0000000000401000

$ ls -la a.out

-rwxr-xr-x 1 katsuhiro katsuhiro 968 Jul  3 04:12 a.out

$ strace ./a.out

execve("./a.out", ["./a.out"], 0x7ffc92c2b390 /* 46 vars */) = 0
--- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=0x401000} ---
+++ killed by SIGSEGV +++
Segmentation fault

ログが大量に出るはずの strace も、わずか 1行しかログが出ません。何もしないバイナリにも関わらず a.out のサイズは 1KB 近くあります。

ツールでバイナリを削る

お手軽なバイナリのダイエットとして、実行に不要なセクションを strip します。

SEGV するバイナリ、strip する
$ strip -R ".note.gnu.build-id" -R ".comment" a.out

$ ls -la a.out
-rwxr-xr-x 1 katsuhiro katsuhiro 376 Jul  3 04:18 a.out

それでも 376 バイト。まだでかいですね。

手でバイナリを削る

この 376 バイトのファイルを元にして、バイナリを手で削ります。加工の方針としては、

  • ELF ヘッダ(64バイト)とプログラムヘッダ(56バイト)を一部重ねる(-28バイト)
  • 不要なプログラムヘッダ 2つを消す(-56 x 2バイト)
  • セクションヘッダを消す(-64 x 2バイト)
  • .shstrtab セクションを消す(-16バイト)
  • ELF ヘッダの辻褄を合わせる

結果 92 バイトになりました。

SEGV するバイナリ、手で削る
$ ls -la a.out

-rwxrwxr-x+ 1 katsuhiro katsuhiro 92 Jul  3 05:43 a.out


SEGV する 92 バイトバイナリ、ELF ヘッダ


SEGV する 92 バイトバイナリ、プログラムヘッダ

もっとアグレッシブに ELF ヘッダとプログラムヘッダを重ねれば、64 バイトにできるかもしれません。

SEGV する 92 バイトバイナリの検証

このファイルを実行してみると、システムコール execve がエラーを返さないで進むので、ELF ファイルとして認識してもらえているようです。

SEGV する 92 バイトバイナリ、実行
$ strace ./a.out

execve("./a.out", ["./a.out"], 0x7fff2b4f74a0 /* 47 vars */) = 0
--- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=0x400000001} ---
+++ killed by SIGSEGV +++
Segmentation fault
SEGV する 92 バイトバイナリ、readelf
$ readelf -a a.out

ELF Header:
  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
  Class:                             ELF64
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              EXEC (Executable file)
  Machine:                           Advanced Micro Devices X86-64
  Version:                           0x1
  Entry point address:               0x400000001
  Start of program headers:          36 (bytes into file)
  Start of section headers:          0 (bytes into file)
  Flags:                             0x0
  Size of this header:               64 (bytes)
  Size of program headers:           56 (bytes)
  Number of program headers:         1
  Size of section headers:           0 (bytes)
  Number of section headers:         0
  Section header string table index: 0
There are no sections in this file.
There are no sections to group in this file.
Program Headers:
  Type           Offset             VirtAddr           PhysAddr
                 FileSiz            MemSiz              Flags  Align
  NULL           0x0000000000000000 0x0000000100380040 0x0000000000000000
                 0x0000000000000000 0x0000000000000000         0x1000
There is no dynamic section in this file.
There are no relocations in this file.
The decoding of unwind sections for machine type Advanced Micro Devices X86-64 is not currently supported.
Dynamic symbol information is not available for displaying symbols.
No version information found in this file.

一応 readelf でも読めますし、そこそこ真っ当なファイルをキープできていると思います。

[編集者: すずき]
[更新: 2020年 7月 5日 21:06]

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



link permalink

link 編集する

C 言語で SEGV

SEGV を出すのが Twitter で流行しているみたいなので、少し考えてみました。Twitter で見かけたのは、*a;main(){*a=0;}(16文字)です。最適化オプションにもよりますが、異常なアドレスへの mov か、未定義命令 ud2 が出力されて SEGV します。

16文字で SEGV
$ echo -n '*a;main(){*a=0;}' > a.c && gcc a.c

a.c:1:1: warning: data definition has no type or storage class
    1 | *a;main(){*a=0;}
      | ^
a.c:1:2: warning: type defaults to 'int' in declaration of 'a' [-Wimplicit-int]
    1 | *a;main(){*a=0;}
      |  ^
a.c:1:4: warning: return type defaults to 'int' [-Wimplicit-int]
    1 | *a;main(){*a=0;}
      |    ^~~~

$ ./a.out

Segmentation fault

ただ SEGV するだけで良ければ、main のアドレスを .text ではないアドレスにすれば良いので、main;(5 文字)でも、達成できます。

5文字で SEGV
$ echo -n 'main;' > a.c && gcc a.c

a.c:1:1: warning: data definition has no type or storage class
    1 | main;
      | ^~~~
a.c:1:1: warning: type defaults to 'int' in declaration of 'main' [-Wimplicit-int]

$ ./a.out

Segmentation fault

この例は main を関数ではなく変数として定義し、main を bss セクションに配置します。最近の Linux ならばデータが置かれているセグメントは実行禁止にするはずなので、main が指すデータが何であろうと、ジャンプした瞬間に SEGV します。

趣旨とは外れますが SEGV を避けて正常終了させたければ、

SEGV したくない場合
$ echo -n 'main=0xc3;' > a.c && gcc -z execstack a.c

a.c:1:1: warning: data definition has no type or storage class
    1 | main=0xc3;
      | ^~~~
a.c:1:1: warning: type defaults to 'int' in declaration of 'main' [-Wimplicit-int]

$ ./main3.out

(SEGV しない)

変数 main が指す位置に retq 命令(0xc3)を置いて、-z execstack オプションでデータ領域を実行可能にしています。attribute で .text 領域に置いても実行できますが、そんなことするくらいなら main() 関数を書いた方が短いです。

これが最短か?

変化球を使ってよければ 0 文字で SEGV できます。nostdlib オプションを使います。

0 文字で SEGV
$ echo -n > a.c && gcc -nostdlib a.c

/usr/bin/ld: warning: cannot find entry symbol _start; defaulting to 0000000000001000

$ ./a.out

Segmentation fault

GNU ld(他のリンカーでも同じだと思いますけど)は ELF のエントリアドレスに _start というシンボルのアドレスを使います。通常は crt.o など、リンク時に自動的に追加されるオブジェクトが _start を定義しますが、nostdlib オプションにより crt.o がリンクされなくなって、_start は未定義になります。

すると ld は _start を適当なアドレスに設定(上記の例では 0x1000 に)します。当然 _start が指すアドレスにコードはありませんから、実行するとクラッシュします。

[編集者: すずき]
[更新: 2020年 7月 5日 18:58]

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



link permalink

link 編集する

Steam の秘密の実績を暴く方法

Steam の買い物カートの中身一覧を見る方法を探していたんですが、全くわかりませんでした。だいぶ彷徨いましたが、未だトップ画面からカートを見る方法はわからないままです。Steam は本当に UI がひどい。Amazon を見習ってくれ……。

その際に副産物として、秘密の実績を確認する方法を見つけたのでメモしておきます。

  • Steam のウインドウ
  • ユーザー名のタブ
  • プロフィール
  • 最近プレイした全てのゲーム
  • すべてのゲーム

と辿ると自分が所持しているゲームの一覧が出ますから、実績を見たいゲームの

  • データを表示
  • グローバル実績

と辿ると全ての実績が表示されます。


個人のプレイデータでは秘密の実績と表示される


グローバルプレイデータでは秘密の実績も全て表示される

秘密の実績の意味とは一体……??

[編集者: すずき]
[更新: 2020年 7月 2日 03:27]

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



link permalink

link 編集する

STATIONflow ランク 100

STATIONflow のランクが 100 になりました。何か実績と紐づいているかなと思いましたが、特に何も起きませんでした。しょんぼり。


ランク 100

普通のマップだと重いし、時間も掛かりすぎてやってられないので、専用の軽量マップを作ってひたすら待ちました。それでも相当時間が掛かります。普通に遊ぶ分にはランク 50 で十分ですね。

わかったこと

STATIONflow でランク 100 にする途中でいくつかわかったことがありました。

集客レベル
途中で出入口と乗り場の集客レベルがカンストし、変化もやることもなくなります。実績解除に必要なランク 50 以降はほぼ無意味です。
集客レベルの上がる余地は最大 132(※)なので、ランク 100 まで上がり続けるかと思いきや、ランク 1 上がるごとに集客レベルが 2〜4 くらい上がるので、だいたいランク 60 くらいでカンストします。
評価収入
ランクとは無関係で、出入口と乗り場の集客レベルの合計に依存するようです。出入口と乗り場を最大数作り、集客レベルを全て最大にして、ランク A+ を取ったときが 540,000 でした。おそらくこれが最大値です。

ランク 100 まで行ってもまだ取れない実績が残っていて(ラッキーセブン、トウキョウ)、なかなか気が遠くなるゲームです。

(※)出入口が 6 x 9 = 54、乗り場が 6 x 2 = 12、集客レベルは 2段階上がるため (54 + 12) x 2 = 132 です。

実績の typo

STATIONflow の実績に typo がありました。


8000?九千?

漢字だけ間違ってます。惜しい……!

[編集者: すずき]
[更新: 2020年 7月 1日 22:20]

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



link もっと前
   2020年 7月 10日 -
      2020年 7月 1日  
link もっと後

管理用メニュー

link 記事を新規作成

合計:  counter total
本日:  counter today

link About www.katsuster.net
RDF ファイル RSS 1.0
QR コード QR コード

最終更新: 7/5 21:07

カレンダー

<2020>
<<<07>>>
---1234
567891011
12131415161718
19202122232425
262728293031-

最近のコメント 5件

  • link 20年06月29日
    すずき 「うちのマシンは基本速度が取得できてないん...」
    (更新:07/01 11:18)
  • link 20年06月29日
    hdk 「Athlon 5350 (2.05GHz...」
    (更新:06/30 23:55)
  • link 20年05月02日
    すずき 「ちょっと調べたところ、コアが焼けると騒ぎ...」
    (更新:05/08 15:43)
  • link 20年05月02日
    すずき 「結構、怖い制御に見えますね&hellip...」
    (更新:05/08 15:23)
  • link 20年05月02日
    hdk 「デスクトップ用のNVIDIA Quadr...」
    (更新:05/07 20:30)

最近の記事 3件

link もっとみる
  • link 20年07月05日
    すずき 「[ELF バイナリで SEGV その 2 - 64 バイト] 昨日...」
    (更新:07/05 21:07)
  • link 20年07月04日
    すずき 「[ELF バイナリで SEGV その 1 - 92 バイト] 昨日...」
    (更新:07/05 21:06)
  • link 20年07月03日
    すずき 「[C 言語で SEGV] SEGV を出すのが Twitter で...」
    (更新:07/05 18:58)

こんてんつ

open/close wiki
open/close Java API

過去の日記

open/close 2002年
open/close 2003年
open/close 2004年
open/close 2005年
open/close 2006年
open/close 2007年
open/close 2008年
open/close 2009年
open/close 2010年
open/close 2011年
open/close 2012年
open/close 2013年
open/close 2014年
open/close 2015年
open/close 2016年
open/close 2017年
open/close 2018年
open/close 2019年
open/close 2020年
open/close 過去日記について

その他の情報

open/close アクセス統計
open/close サーバ一覧
open/close サイトの情報