制作日記

こういうの作った方が、逃げにくいじゃない

1.90でやってること

cnsだけだと厳しいかと思うので
1.90でやってること解説

要はLoadLibraryを叩いてる、その方法を考えてみる

前提条件というか前提知識
DEPを回避する、これ今回の目的
つまり、実行権限の付いていない箇所のコードを実行しない
Ver1.8xとかみたいにdataセクションのコード埋め込んで実行したり
Defオバフロみたいにcns内というか実行権限ついてないヒープ内のコード実行するのはアウト

LoadLibrary関数は引数が1個でライブラリ名を指定する
つまり、スタックの一番上にライブラリ名の先頭アドレスを積んだ状態でLoadLibraryを呼ぶ必要がある

OS等の実行環境に極力依存しない方法
要は、リンクしているライブラリ内の関数を直接呼ぶとかしない
Windowsのdllは全く同じdllなら基本的には全く同じアドレスにマッピングされるから
単一の環境の対象とすれば、もっと手軽に出来る

攻撃の入口はDTCでのスタックオーバーフロー、つまりリターンアドレスの改竄
リンクしているライブラリは呼ばない、winmuge.exe内のみがリターン先の対象
winmugen.exeは0x00400000からマッピングされるから、最上位バイトは必ず0x00=null文字
最上位バイトのnull文字で文字列が終端するため、それ以降はオーバーフローさせられない
改竄可能は範囲は直近のリターンアドレスまでの1024+4バイトのみ
つまり、ここでLoadLibraryの引数をスタックに積むことはできない
ちなみに、dllのアドレス固定(環境依存)で良いならここで引数も積めるから、かなり楽になるはず

引数のライブラリ名は1.8xのコード埋め込み見たいに適当なとこに埋めておけば良いので、割愛

本題
LoadLibraryを叩く方法として思い付くのものを、実行可能か検証していく

1.直接リターンアドレスをLoadLibraryに差し替え
前提条件で否定してるけど、引数をスタックに積めないから無理

2.Defオバフロみたいにスタックポインタが良い感じになったうえでLoadLibraryに飛ぶようなコードを探してそこにリターンする
想定としては、LoadLibrary呼び出し箇所に戻りつつ、引数を積む
LoadLibrary呼び出し箇所はwinmugen.exe内に2か所あるけど、どっちも無理そう
片方は直前に詰んでるし、片方はアドレスゴリゴリ辿ってる
どっちにしろ単体だと無理そう

3.2に加えてスタックの調整とかリターンアドレスの工夫
DTCの出力結果はスタック上にもう1つ保存されてるので、
上手いことリターン先を調整して、そっちの値も使う
懸念はライブラリ名を埋め込む場所、コードはよく0x004Bxxxx辺りに埋めるけど、
あれと同じようにすると0x00=null文字のせいで文字列が終端してしまう、つまりリターンアドレス改竄ができない
よって0x10000000~から変な値を書きこんでも問題ないヒープを探してこないといけない
高位のここら辺必ず使えるとかがあれば解決するが、そういう話は知らない

4.2に加えて関数ポインタを差し替えつつ、上手いこと辿る
で、探してて見つけたのがここ

0049DB25 A178684B00 mov eax, [004B6878h]
0049DB2A 85C0 test eax, eax
0049DB2C 7405 jz 0049DB33h
0049DB2E 53 push ebx
0049DB2F FFD0 call eax
0049DB31 8BD8 mov ebx, eax

* Referenced by an (U)nconditional or (C)onditional Jump or (c)all at Address:
| 0049DB1B(C), 0049DB23(C), 0049DB2C(C)
|
0049DB33 FF742418 push dword ptr [esp+18h]
0049DB37 FF742418 push dword ptr [esp+18h]
0049DB3B FF742418 push dword ptr [esp+18h]
0049DB3F 53 push ebx
0049DB40 FF1570684B00 call dword ptr [004B6870h]

DTCで”%”(0x25)を出力できないからリターン先はもう一つ手前の命令

0049DB23 740E jz 0049DB33h

にリターンしてる、ZFは0だったしjmpはしないと思う

0049DB14 A174684B00 mov eax, [004B6874h]

今更だけど、こっちにリターンしておけば確実だった
0x004B6874は0x004B6878と同じアドレス入れとけば良いし

で、解説

0049DB25 A178684B00 mov eax, [004B6878h]

0x004B6878に入ってるアドレス取ってきて

0049DB2F FFD0 call eax

そこのアドレスのサブルーチン呼び出し


0049DB31 8BD8 mov ebx, eax

戻り値eaxをebxに入れて

0049DB3F 53 push ebx

ebxをスタックに積んで

0049DB40 FF1570684B00 call dword ptr [004B6870h]

0x004B6870に入ってるアドレスのサブルーチン呼び出し

つまり、適当なアドレス引っ張ってくるコードを探して、
そのアドレスを0x004B6878に入れる
文字列を上手いこと埋め込んでおけば、戻り値eaxで取得できる

今回は以下の0x0049D8B8を入れた、0x004B661Cに入ってる値を取り出してる
つまり、適当な場所にライブラリ名(char/_reimu/a.dll)を埋め込んで
その先頭アドレスを0x004B661Cに入れておけばいい

0049D8B8 A11C664B00 mov eax, [004B661Ch]
0049D8BD C7056C684B0001000000 mov dword ptr [004B686Ch], 00000001h

* Referenced by an (U)nconditional or (C)onditional Jump or (c)all at Address:
| 0049D8B6(C)
|
0049D8C7 C3 ret


あとはこいつでLoadLibrary呼べばいいから、

0049DB40 FF1570684B00 call dword ptr [004B6870h]

親捏造でLoadLibraryのアドレスが入っている0x0049F12Cの値を取ってきて
0x004B6870に入れる

これでa.dllのDllMainが呼ばれるから好きにやる
単なるライブラリの動的リンクだから、DEPには引っ掛からない
あと、DllMainから戻ると確実に死ぬから、試合継続したいならDllMainの中で復旧処理が必要

以上、おわり

目新しいことはしてないけど、それをうまく組み合わせた感じ

コメントの投稿

非公開コメント

プロフィール

Author:drab
霊夢改変キャラ
「12 3 ! {V} [_]」
公開中
L霊夢でもl_reimuでも好きなように読んでください

最新記事
最新コメント
月別アーカイブ
カテゴリ
検索フォーム
RSSリンクの表示
リンク