Golangバイナリの反転を促進するか、IDAでスクリプトを記述する理由

Golangは素晴らしい言語です。 強力なタイピング、ガベージコレクション、cgoを介したC関数の呼び出し、リフレクト、ちゃん-おとぎ話! 明らかに、そう思うだけでなく、 goは人気があります。つまり、多くのプログラマーが使用していることを意味します。つまり、誰かがバイナリをリバースする必要がある可能性が高いことを意味します。



準備する



開始するには、windows / amd64の下で新鮮なgolang 1.8を使用してください。 バイナリには、自分の工芸品の 1つを使用します。 go build



コンパイルしgo build



。 ファイルサイズ-7256576バイト、DWARFが配置されています。 それはしません。 ほとんどの場合、リリースされると、不要なものはすべてバイナリから切り取られます。 stripのような標準ユーティリティはgoではうまく機能しませんgo build -ldflags "-w -s"



バイナリをトリミングするための一般的なオプションの1つであるgo build -ldflags "-w -s"



を見つけます。 これらのフラグの機能を見ると、 -wが DWARFを削除し、 -sがシンボルテーブルとデバッグ情報を削除していることがわかります。 コンパイルし、ファイルサイズを調べます-4894720、まあ、小さいと約束した人はないようです。



機能を探しています



バイナリをidaで開き、検出された機能のために、エントリポイントのみであるため、悲しいです。 少し掘り下げてみると、idaが次のようになっていることがわかります。



 lea rax, qword_452018+128h jmp rax
      
      





アドレスに行き、関数を宣言し、分析を実行します-215個の関数が見つかりました。







この精神で続けると、解析に時間がかかります。 考える時間です。 標準ライブラリからのリフレクトにより、関数を名前で呼び出すことができることを思い出してください。つまり、関数の名前をよく、または少なくともそれらのハッシュをどこかに保存する必要があり、アイデアを提供することができます。



必要な構造体へのポインターにGo build ID: "e07bfb8669c13efb74574c0ad220c5f2cfae5cd4"



することを期待して、ファイルの先頭にスキップしますが、 Go build ID: "e07bfb8669c13efb74574c0ad220c5f2cfae5cd4"



という行を満たします。 golangソースは私たちが利用できるので食べますが、この行について言及しています。 リンカコードに行があります



 ctxt.Syms.Lookup("go.buildid", 0)
      
      





これは、いくつかのgo.buildid文字テーブルの検索について説明しています 。 バイナリでこの行を見つけると仮定して、見つけます。



これらの構造を探しました






線のすぐ上に401000hという数字があります。これは、線へのポインタです。 以下に関数の定義を示し、上に-値の1つがポインターのように見えるペアの配列を示します。 これらのポインタが指す場所をチェックし、見逃さないようにします-関数上。



ポインターに変換された配列の部分






上記の内容を確認するには、デバッグ情報を残してコードをコンパイルします。 idaで開き、この配列がpclntabと呼ばれることを確認します。この配列はfunc(ctxt * Link)pclntab()関数を使用してリンカーに設定されます。



関数名が格納されているpclntabテーブルに関する情報があり、buildidを介してこのテーブルにアクセスする方法があります。 コードを書きます:



関数に名前を付けるコード
 def go_find_pclntab(): pos = idaapi.get_segm_by_name(".text").endEA textstart = idaapi.get_segm_by_name(".text").startEA while True: # hex    "go.buildid"     , #     gobuilddefpos = FindBinary( pos, SEARCH_UP, "67 45 23 01 " + "00 "*20 + "67 6f 2e 62 75 69 6c 64 69 64") if gobuilddefpos < 100 or gobuilddefpos > pos: #  ,    # buildid pclntab entry   :( break #   buildid entry  if Dword(gobuilddefpos-0x10) == textstart: #         pclntab #     pclntab return gobuilddefpos + 24 - Dword(gobuilddefpos-0x8) pos = gobuilddefpos return None def go_pclntab_travel(pclntab): nfunc = Dword(pclntab+8) #       pclntab for i in xrange(nfunc): entry = pclntab + 0x10 + i * 0x10 sym = Qword(entry) info = Qword(entry + 8) + pclntab symnameoff = Dword(info + 8) + pclntab symname = GetString(symnameoff) #   go_pclntab_handle_function(sym, symname, info)
      
      







開始して結果を確認します。



ケフ



ほとんどすべての5728関数には名前があります



名前には、パッケージへのフルパスが含まれます。



タイプを探しています



関数名の後に私が興味を持った2番目のことは、型の識別です。 まず、構造に動的メモリがどのように割り当てられるかに興味があります。これはすぐにnewobject関数につながり、 runtime._typeへのポインタが渡されます



Runtime._type構造
 type _type struct { size uintptr ptrdata uintptr // size of memory prefix holding all pointers hash uint32 tflag tflag align uint8 fieldalign uint8 kind uint8 alg *typeAlg // gcdata stores the GC type data for the garbage collector. // If the KindGCProg bit is set in kind, gcdata is a GC program. // Otherwise it is a ptrmask bitmap. See mbitmap.go for details. gcdata *byte str nameOff ptrToThis typeOff }
      
      







気づいた? ヒント: str nameOff



フィールド。 ヒント:strは文字列です。 ヒント:nameOff-> name-> name-> type structure name-> type name。 型構造には型名が含まれています! それだけが何らかの親類です。 strは、モジュールセクションの型の先頭からのオフセットであり 、モジュール構造のmoduledataから取得できるポインターであることがわかります。 そのため、タイプを見つけるために、moduledataを見つける必要があります。 簡単にするために、常に1つのモジュールがあると仮定します。 関数runtime.resolveNameOffでは 、最初のモジュールが変数firstmoduledataにあることがわかります。これは、バイナリで見つける必要があります。 上記のスクリプトですべての関数のアドレスと名前を既に収集しているので、これに遠ざかる必要はなく、同じ関数resolveNameOffを調べることができます。 認識のための型を見つけるだけです。これは、newobject関数へのすべての呼び出しを取得し、パラメーターから型へのポインターを取得したためです。



 lea rbx, _type_p_elliptic_p256Point_6dad60 ; *elliptic.p256Point mov [rsp+0A8h+var_A8], rbx call runtime_newobject ;         
      
      





まとめ



このバイナリの解析を続行できますが、すでに目標を達成しており、golangバイナリの探索は非常に簡単であり、IDAのスクリプトを使用すると作業が大幅に容易になることが示されています。



ソースコード: github.com/mogaika/golang_ida_scripts



コードは「概念実証」に基づいて記述されており、欠陥が含まれている場合があります。すべてのクレームは、ここまたはgithubのプライベートメッセージで表現できます。



テキストは「すべての善」の権利に基づいて書かれており、テキストの品質に関する主張はプライベートメッセージで期待されています。



All Articles