2016年12月28日水曜日

D言語の演算子評価順序


Twitterでこんな記事を見た。
paiza開発日誌 - ツイッターで出題した未定義問題のお詫びと調査と解説について

最近のpaiza割りと酷くて、C言語の環境依存系の問題バカスカ出してる印象がある。
(ポインタの長さ系の問題とか、sizeof(char*)==4が正解みたいなアレ)
まぁそれは置いといて、では我らがD言語さんは、言語仕様で演算子の評価順序が定義されているのか確認してみた。

公式の文書(Expressions)によれば、

Order Of Evaluation

Binary expressions and function arguments are evaluated in strictly left-to-right order. This is similar to Java but different to C and C++, where the evaluation order is unspecified. Thus, the following code is valid and well defined. 
というわけで、左から右へ評価される と定義されているらしい。
では実際にコードを書いて、生成されたバイナリを見てみよう。

こんなコードを書く。
そんで、次にバイナリを読む。



もっとわかりやすくしてみる。


お分かりいただけただろうか。
とにかく左から順に計算していく。
ただし、インクリメントは後置と前置では全く違うのでこのあたりを考慮してやる必要がある。

では、Paizaの問題をD言語で評価するとどうなるか。

int i=0;
i = i++ + i++;
機械語を読むとこう評価されている模様。(後置のインクリメントは1度だけ実行)
i = 1+(0 + 0);
というわけで、Javaだけじゃなくて、D言語も対象言語に入るよ~
Paizaさん、D言語ちゃんも仲間に入れてあげて!

2016年12月23日金曜日

fsbでELFファイルを引っこ抜いてみる

fsbでできることをとりあえず書いていく
まとめではないので、いつかはまとめたい。

SharifCTFのpwnで学んだことが一つあるのでそれについて。
Sharif CTF pwn 150点の問題の概要
「fsbが有って、それを使ってELFを引っこ抜いてpwnする!以上だ!」
みたいな感じだった(だった気がする、細かいことは気にしない)

個人的には、スタックのリークとアドレスの上書き(GOT Overwrite等)くらいかなと思ってたけど、ELFの引っこ抜きは盲点だった。
ってわけで、やってみる。

ELFファイルが実行されるときは、大体仮想アドレス上の0x400000に固定されて走る
ELFファイルもココに全部マッピングされる。

つまり、fsbで0x00400000から0x00410000くらいまでをリークすればELFファイル
を復元できる
(厳密には完全に復元できるわけじゃなく特定のセクション、今回は.textのみ復元できる)
.textが復元できれば、プログラムの構造がだいたいどんなふうに成っているか分かるし
pwnしやすくなる。

と言うわけでやっていきましょう。

2016年12月13日火曜日

Binary ninjaで遊んでみる

Binary ninja買いました 今のレートだと1万2000円位じゃないでしょうか(ざっくり)

端的にいうと、Binary ninjaはいいぞ。

2016年10月1日土曜日

D言語でOpenSSLをstatic linkする方法

訳あってOpenSSLのDLLがない環境でも動くものが必要になった。
そこで、D言語でOpenSSLを使った暗号化ラッパーライブラリを作って静的リンクさせたかったので書く。

dubビルドスクリプト(json)
これが今回一番大事で、これちゃんと作れないとx64版ビルドしかできない。
x86版が作れない。
ほんとうに大事。

dubに何も引数指定しない場合:x86版がビルドされる
dubに--arch=x86_64を指定した場合:x64版がビルドされる
  • sourceFiles-x86_64ディレクティブ
    • x64版のstatic linkライブラリを指定する
    • dub --arch=x86_64 を指定した場合のみここが走る
  • sourceFiles-x86ディレクティブ
    • x86版のstatic linkライブラリを指定する
  • sourceFilesディレクティブ
    • どのような場合でもOpenSSLが使うインポートライブラリをリンクする
  • dflags-x86ディレクティブ
    • x86版をビルドする場合に、 -m32mscoff オプションを付ける
    • これを付けることで、MSCOFF形式のライブラリ/オブジェクトファイルに対応してくれる
    • ていうかMS謹製のlink.exeが今のところ立ち上がる。(検証済み)
    • デフォルトだとOMF形式しかリンカが認識しないためその処置
    • なんでMSCOFFとOMFで2つも規格あるんだよどっちかに統一してくれ


MSCOFFとOMFには割りと因縁があり、7年前C言語の勉強始めた頃に、VisualStudioでビルドされたライブラリをBorland C Compilerについてるリンカでリンクしようとしたら怒られまくって心折れた記憶が復活したよね。
今回はなんとか倒した。(他の人に色々聞いた、優しい世界)

原因は、x64ビルドだとVisualStudio付属のlink.exeが立ち上がってビルドされるから問題ないけど、x86だとDigital Mars製のOptlinkが立ち上がってビルドする。このOptlinkはデフォルトだと読まれるライブラリをOMFと仮定して処理しようとする。
つまりデフォルトでは、MSCOFF形式のライブラリだとエラーを吐く。クソかよ。


メイン関数
特に説明はない。
ハッシュ値の生成とランダム値の生成をやってるだけ

標準ライブラリのハッシュクラスを更に使いやすく(Pythonっぽく)ラッピングしたクラステンプレート
これ一つで文字列・ファイル・バイト列からSHA1でもSHA224でもSHA256でもMD5などD言語が対応しているハッシュなら生成できる (MD5の使いみちとしたら衝突攻撃の検証とかかな?)

OpenSSLリンクチェック用のランダム値生成関数


というわけで、なんとか静的リンクさせることができた。
あと、D言語のテンプレートクラスと標準ライブラリの豊富さに無限の可能性を感じた。
終わり。

2016年9月2日金曜日

D言語のコンパイル時に決定する静的な文字列の扱い

ここにOSによって、SEGVするコードがある。
その理由を突き詰めてみる。

なお、元ネタ。


OS(というかバイナリの形式、Windowsの場合はPE、Linuxの場合はELF)によって
配置されるセグメントが違うから、SEGVが起こると考えられる。
実際どこに置かれるか、逆アセンブルして見てみる。

Linux版バイナリははWindows Subsystem for Linuxのbash(x86-64)でビルド
Windows版バイナリはWindows 10 Professional(x86-64)でビルド

Linux
c:\D_Codes\test>bash
segfo@SEGFODESKTOP:/mnt/c/D_Codes/test$ uname -a
Linux SEGFODESKTOP 3.4.0+ #1 PREEMPT Thu Aug 1 17:06:05 CST 2013 x86_64 x86_64 x86_64 GNU/Linux 

Windows
c:\D_Codes\test>ver
Microsoft Windows [Version 10.0.14393]

dmdのバージョンは以下のとおり

Linux
segfo@SEGFODESKTOP:/mnt/c/D_Codes/test$ dmd --version
DMD64 D Compiler v2.071.1                                                           
Copyright (c) 1999-2015 by Digital Mars written by Walter Bright
segfo@SEGFODESKTOP:/mnt/c/D_Codes/test$ exit

Windows
c:\D_Codes\test>dmd --version
DMD32 D Compiler v2.071.1                 
Copyright (c) 1999-2015 by Digital Mars written by Walter Bright


なお、コンパイルは以下のコマンドで行った。(共通)
※WSLでは現状32bitバイナリが実行できないため64bitバイナリを生成する。

dmd -m64 SEGV_OS_Dependent.d

実行結果は以下のとおり。

Linux版バイナリ
segfo@SEGFODESKTOP:/mnt/c/D_Codes/test$ ./test                                                           
Segmentation fault (コアダンプ)

Windows版バイナリ
c:\D_Codes\test>test                                                                                     
hAgehoge 

Linux版はSEGV
Windows版は最後まで実行できた。

この違いは何か、バイナリレベルで見てみる。
今回は、x64バイナリ、IDA Freeでは見られないので
Linuxはgdb、Windowsはx64Dbgで書き換えられる部分のメモリの属性を見る。

まずはLinux版

RBX0x7ffffe14c7f0 --> 0x7ffffe14c810 --> 0x0
RCX0x468491 --> 0x65676f6865676f ('ogehoge')   
RDX: 0x1  
[---------------------code------------------------------]
   0x438c12 <_Dmain+50>:        call   0x4390d0 <_D3app7__arrayZ>
   0x438c17 <_Dmain+55>:        inc    rcx
   0x438c1a <_Dmain+58>:        mov    QWORD PTR [rbp-0x10],rcx
=> 0x438c1e <_Dmain+62>:        mov    BYTE PTR [rcx],0x41
[-------------------------------------------------------]
Legend: codedatarodata, value
Stopped reason: SIGSEGV
0x0000000000438c1e in D main () at source/app.d:5                                                                                     
5               ubyte[] sb=cast(ubyte[])s;       

おもむろに、gdbを立ち上げて、runするだけ。

codeペインのこの行は
=> 0x438c1e <_Dmain+62>:        mov    BYTE PTR [rcx],0x41                        

D言語のソースの7行目を指している。
(gdbの画面では5行目がでているが、恐らくバグ)
なお、
Legend: codedatarodata, value 
で、rodata(読み取り専用セグメント)に代入していることがわかる。

vmmapで確認する

gdb-peda$ vmmap                                              
Start       End        Perm  Name
0x00400000  0x00481000 r-x-  /mnt/c/D_Codes/test/SEGV_OS_Dependent
0x00680000  0x00681000 r---  /mnt/c/D_Codes/test/SEGV_OS_Dependent
0x00681000  0x0068c000 rw--  /mnt/c/D_Codes/test/SEGV_OS_Dependent 

RCXの値は、
RCX0x468491 --> 0x65676f6865676f ('ogehoge') 

(cast(ubyte[])"hogehoge")[1] の2文字目の o を指しているポインタであることがわかる。
値は0x468491

vmmapでは、このメモリ領域のパーミッションは、r-x-となっている。
だからSEGVが発生する。

ではWindowsではどうか。

00007FF7229D1039の命令が7行目の命令。
RCXの値は 00007FF722A1EA41

00007FF722A1EA41のメモリ領域は、-RW-- となっており、読み書き自由。


以上のことから、コンパイル先のバイナリやOS?によってDコンパイラはデータを配置するセグメントを変えていると思われる。

Windowsの場合は、明示的にstringをimmutableにしてもキャストしたら実行できてしまった。
このことから、コンパイル時に確定している文字列は暗黙的にimmutable(またはconst)の扱いとなると考えられる。


D言語でも吸収できない闇を垣間見てしまった気がする。
おわり。

2016年8月4日木曜日

Windows subsystem for Linuxを試してみた。

WindowsでUbuntu bash使えるようになってたので
いろいろ動かしてみた。

動いたもの
Pythonライブラリ:pwntools / binjitsu
Python
gdb/gcc
gdb-peda

動かなかったもの
ping(icmpソケットが開けない的な理由)

で、gdb-pedaの動作確認をしていた時の事。
とてもエモい感じだったのでメモ。



a.outの.textのベースアドレスがWindowsっぽく、0x00400000から始まってるのと
各.textセクションのパーミッションが、r-x-のはずがrwx-になっていて非常にエモい。
多分、命令をエミュレート(Windows syscallに動的変換?)する時に書き込んだりしてるのかもね。


それだけ。

2016年7月10日日曜日

D言語でPEファイルヘッダをパースしてみた

今日もD言語やっていこうかと。

と言うわけで、作るもののネタが無いのでPEファイルのヘッダを解析してみる。
アルゴリズム的には、構造体作って、構造体にそのまま取り込んで、表示するだけなので
構造体をコピペすれば完成する代物。

ちょっとだけエイリアスを宣言してやる必要があるけど、やることはそれだけ。
とりあえず、x86バイナリと、x64バイナリに対応できればいいかなって感じ。

ちゃんと解析できてるかどうかの確認はIDA Freeあたりで試す。

D言語の std.File.rawReadは配列しか渡せないので、構造体をC言語みたいにポインタで渡すとか言う直感的な方法でなくて、戸惑ったけど、書き方が微妙に違うだけでほぼ同じだった。
D言語はいいぞ。ランタイムあたりが厄介者だけど、それはどうにかすればいい。

dmd -m32 PEHeaderAnalyzer.d
PEHeaderAnalyzer.exe PEHeaderAnalyzer.exe

実行結果こんな感じ
Machine: i386
applicationBits: 32
Subsystem: Windows CUI
ImageBase: 0x400000
BaseOfCode: 0x2000
SizeOFCode: 183296
AddressOfEntryPoint: 2565c
Absolute entry point: 42565c
SizeOfImage: 274432
IDAで答え合わせ。

※ 画像クリックで拡大可能

Machine: i386 と
ImageBase: 0x400000 はIDAでみると、問題なさそう。

BaseOfCode: 0x2000 も取り出せてる



エントリーポイントのアドレス(Absolute entry point) = ImageBase + AddressOfEntryPoint
ImageBase: 0x400000
AddressOfEntryPoint: 2565c
Absolute entry point: 42565c
合ってるっぽい。



かんたんでよい、きょうはここまで。

2016年7月9日土曜日

D言語ローレイヤ入門

D言語(ローレイヤ)入門していきます。

ぼく「D言語の最小ランタイムほしいよ~」
ぼく「uefi-dとか使ってみたけど構造体宣言できないし色々ダメ」
ぼく「UEFI AppをDでつくりたい、あわよくば・・・OSカーネルも」

というつぶやきをしたらプロから返事が帰ってきた。
Twitterつよい。


というわけで、minimal.zipを落として makeしてみた

minimal-d/object.d:1248: `_deh_beg' に対する定義されていない参照です
minimal-d/object.d:1249: `_deh_end' に対する定義されていない参照です
無いってさ!
ちなみに、object.dの1248行目と1249行目はこんな感じ。

        extern __gshared
        {
            /* Symbols created by the compiler and inserted into the object file
             * that 'bracket' the __deh_eh segment
             */
            void* _deh_beg;
            void* _deh_end;
        }

※object.d:すべてのクラスや構造体のベースになるクラスが入ったファイル。これがないとD言語の機能はもちろん、C言語で普通にできてた構造体の宣言すらできない(RTTI:実行時型情報が必須な言語の宿命(TypeInfo_Struct等が宣言されてないとリンカエラー))ので、大事。


見たとおり外部に宣言してある_deh_begと_deh_endを参照する ってな感じになってるし
もちろんコンパイラはそんなシンボルを生成してくれないしで、きっとD言語の仕様が微妙に変わったのかもしれない。

リンカスクリプトでEHテーブルセクションを定義した時にシンボルも定義すれば良いんだけど、それをやらなくてもできる方法があるので今回はそっちでやる。
ちなみに、EHテーブルセクション(セグメント)については、ここに書いてあった。
http://www.kmonos.net/alang/d/abi.html

例外ハンドラがたくさん書いてあるところ(GOTみたいな関数テーブル)っていう感じ。

先ず、CompilerDSOData構造体と_d_dso_registryって関数をみてみると
CompilerDSOData構造体には、_deh_beg、_deh_endの2つが居るけど
でもその構造体を引数にとってる、_d_dso_registry関数はそれらメンバに対して何も操作してない。
でも、引数をとってるからには、何かが入ってるはずなので、下のソースみたいに
もともと有った外部参照するところをコメントアウトする。
次に、普通にコメントアウトした変数と同名の変数の実体を宣言する。
さらに、宣言した変数に引数からもらった CompilerDSOData構造体の同名の変数の値を代入する。

これでリンカエラーは出なくなる。

じゃあ本当に直した部分は動くの?動きそうなの?
と言う疑問が湧いてきたので、一旦これでmakeコマンド叩いてみて、バイナリを生成して逆アセンブルしてみる。

動きそう、動かなそうの判断は、意図したデータ(EHテーブルセクションの開始位置と終了位置)
が入ってるか入ってないかで判断する。

各メモリアドレスの詳細


一応メモリアドレスがちゃんと有効なセクションを指してるのと、
構造体の順番と同じようにスタックにレイアウトされてるから問題なさそう。

C言語っぽい擬似コード




てわけで、きょうはこんなところで。