2020-04-12

"リバースエンジニアリング" Justin Seitz 著

プログラムを書くのは楽しい。プログラマ35歳定年説が囁かれる中、いくつになっても楽しい。おいらはプログラマではない。でも楽しい...
二十年以上前、組込系 OS を五年間ほど書いていた時期もあるにはあるが、あくまでもハードウェア設計者。当時、リアルタイム処理ではアセンブラ言語が主流だった。C コンパイラの性能がいまいちで、移行にはまだまだ感の残る時代である。とはいえ、CPU の方言を強要される日常を思えば、抽象度の高い高水準言語は憧れであり、コンパイラの癖を探りながら効率的な記述の仕方を試行錯誤したものである。
ちなみに、今では超ロングセラーとなった定番書も、「はじめての C」がいいのよ!... なんて理系女子にささやかれると、純真な好青年で通っていたおいらは赤面したのだった。
その高水準の地位も、コンパイル作業不要のスクリプト言語にもっていかれ、いまや低水準に格下げ。だからといって死滅することはあるまい。プロセッサや DSP の設計者にとって、痒い所に手が届く言語はありがたい存在。それに、人間が編み出した言語システムが、完全で万能ってことはないだろう。用途に適した言語を、好きな言語を、興味のある言語を、場面々々で選べばいいだけのこと。一つの言語に固執するということは、一つの文化に幽閉されているようなものだから...

ところで、システムの開発・設計には、デバッグ環境が欠かせない。おいらの感覚では、プロセッサや DSP の設計・検証に HDL(ハードウェア記述言語)を、数値演算モデルやデータ解析モデルに GNU Octave や Lisp、あるいは C++ を、これらの統合環境にスクリプト言語を用いるのが、一つのパターンとなっている。
そして、スクリプト言語に何を使うかが、いつも悩ましいところで、一昔前は、コマンド系に Unix シェルを、ログ管理に Perl を用いるのが定番であった。未だに、sed や awk を重宝してたりして。
ちなみに、おいらは、Ruby 信奉者だが、いや、だったのだが、仕事場ではなかなか受け入れてくれない。Ruby はもう死んだのか?といった記事も見かけるけど...
近年、Python なら受け入れられるようになったので、納品物に Python を、小物に Ruby をというのがパターン化している。できれば、C++ も避けたいところだけど...
尚、データ群を Excel ファイルで!と要求してくる人種は避けている。CSV や JSON のような形式ではダメらしい。ドキュメントを XML で!という要求もちょくちょく見かけるが、こういうのは頷ける。pdf じゃダメというところも見かけるけど。
いずれにせよ、SM 教の高価なツールを買わせようとするのは、零細業者には御勘弁を!おっと!この手の愚痴がはじまると、かっぱえびせん状態に...

さて、本書の副題に、「Python によるバイナリ解析技法」とある。実は、この題目に惹かれて手にとった。まさにデバッグの視点からスクリプト言語を語ってくれるのだから...
特殊な逆アセンブラを構築するにせよ、独自のデバッガを開発するにせよ、Python が最善の選択肢になるというのである。Python と言えば、大人気と評判のスクリプト言語。スクリプト言語がバイナリ領域にまで入り込んできたら、赤面する機会も失いそうで、ちと寂しい。おいらは、プロセッサの設計者なら、アセンブラレベルから学ぶべきだと考えるネアンデルタール人だが、そんな時代でもなさそうだ。
それにしても、Python の構文って、バージョンが 2.x と3.x で、なんでこうも違うの。おいらは、3.x から始めたので、ほとんど問題にならないが、本書は 2.5 で書かれており、いきなり Print "Hello world!" でこけた。システムを構築する上で、過去のしがらみをどこまで引きずるかは悩ましい。SM 教のような引きずり方をするぐらいなら、あっさり捨てる方がましかも。ということで、Python は最新版を使いましょう...

ここでは、まず、Python と C 言語の構造体や共用体との相性の良さを紹介しながら、ヒープ領域やスタック、あるいはレジスタへのアクセス事例を挙げている。
注目したいのは、二つのデバッガを紹介してくれることだ。デバッグのために実動作と違ったルーチンを通るのは、なるべく避けたい。特にリアルタイムシステムでは。となれば、ハードウェアが介在する領域でプログラムを書く必要がある。デバッグでお馴染みの作業といえば、レジスタやメモリの捕捉、スレッドの列挙、デバッグ用イベントハンドラの実装、ブレークポイントの設置といったところであろうか。そんな要求にも応えてくれそうな。
一つは、PyDbg というピュアなデバッガ。プアなおいらは、これだけでも満腹!こいつには、「プロセススナップショット」というクールな機能が搭載されるという。
二つは、Immunity Debugger というなかなか手強いヤツ。脆弱性の検出やマルウェア解析にも利用できる強力な Python ライブラリを提供しているという。エクスプロイトなコードも書けそうな。
おいらの場合、ソースの存在しないレベルでデバッグする場面はほとんどないが、ソースを見なければ書き手の思惑にも惑わされず、純粋な視点で検証できるかもしれない、と、そんなことも感じさせてくれる。痒いところに手が届くという意味では、スクリプト言語がここまでやれる時代になったのかと忸怩たる思い...

本書は、Windows プログラムを題材にしているところが、ちと抵抗のあるところ。おいらが、Windows プログラムを書くことはほとんどないが、それでも、なかなか興味深い話題を提供してくれる。Win 95 時代に猛勉強した記憶がかすかにあるが、まさかこんなところで Windows プログラムに触れることになろうとは。人生行き当たりばったり... やはり、プログラムを書くのは楽しい...
例えば、 DEP(Data Execution Prevention) を回避する事例に、ちとハマってしまった。DEP は、ヒープやスタックなどメモリ領域でのコードの実行を防止するための Windows に実装されるセキュリティ機能。他にも、善意にも悪意にも利用される DLL インジェクションに、油断のならないコードインジェクション。これらの技法を使えば、実行中のプロセスにコードを挿入することができ、その先にトロイの木馬が見えてくる。
また、プロセスを監視するためのフックを仕掛ける方法も紹介してくれる。そして、この二つの関数の構造体にアクセスするだけでも結構遊べる。
一つは、プロセスを生成するための関数 CreateProcessA()。この関数のフラグをうまく設定することによってデバッグ用プロセスモニタに仕立てるというわけである。

BOOL WINAPI CreateProcessA(
  LPCTSTR lpApplicationName,
  LPTSTR lpCommandLine,
  LPSECURITY_ATTRIBUTES lpProcessAttributes,
  LPSECURITY_ATTRIBUTES lpThreadAttributes,
  BOOL bInheritHandles,
  DWORD dwCreationFlags,
  LPVOID lpEnvironment,
  LPCTSTR lpCurrentDirectory,
  LPSTARTUPINFO lpStartupInfo,
  LPPROCESS_INFORMATION lpProcessInformation
);

二つは、Kernel32.dll からエクスポートされる関数 CreateRemoteThread()。スレッドのセキュリティ属性へのポインタにアクセスできそうな仕組みが見て取れる。

HANDLE WINAPI CreateRemoteThread(
  HANDLE hProcess,
  LPSECURITY_ATTRIBUTES lpThreadAttributes,
  SIZE_T dwStackSize,
  LPTHREAD_START_ROUTINE lpStartAddress,
  LPVOID lpParameter,
  DWORD dwCreationFlags,
  LPDWORD lpThreadId
);

0 コメント:

コメントを投稿