0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

IDA Proで復号キーの抽出を試みる [静的解析編]

Posted at

こんばんは!

皆さん、お久しぶりです!
私は無事、希望していた高校に合格し、やっと落ち着いてきたところです。
そして今日から夏休み。これから1ヶ月、勉強しつつこちらでも遊んでいけたらと思っています。


最近の興味:リバースエンジニアリング

最近、リバースエンジニアリングにハマっています。
具体的には、IDA ProGhidraなどを使って、静的解析をちょくちょく試しています。

中学2年生の頃にもGhidraを少し触ってみたことがあったのですが、当時は「何をどこからどう勉強すればいいのか」が全く分からず、結局放置してしまいました。

でも今は、AIの発達もあり、無料でも相当優秀なAI教師が身近にいますよね。
そのおかげで、最近またGhidraなどに触れて解析を再開してみると、パズルのように問題が解けていく感覚があり、とても楽しく感じるようになりました。


将来やってみたいこと

この経験を通じて、将来やってみたい仕事が明確になってきました。
それは――リバースエンジニアリングの仕事です。

とはいえ、リバースエンジニアリングにも色々な役職がありますよね。

  • ゼロデイ脆弱性の発見
  • マルウェア・ランサムウェアの挙動解析
  • バイナリ解析全般

私は、そのすべてに興味があります。
ですから、高校3年間で2,000〜3,000時間の学習時間を確保し、しっかりスキルを身につけたいと考えています。


将来の目標

以下が、私の今考えているキャリアプランです:

  1. GMO Flatt SecurityまたはGMOサイバーセキュリティ byイエラエに就職
     → 実務を通じて技術力を磨く

  2. 英語の勉強と並行してスキルを高め、FFRIセキュリティに転職
     → より高度なマルウェア解析技術とゼロデイ発見スキルを習得

  3. 最終的に、CrowdStrikeフルリモートで就職
     → 世界レベルの環境でリバースエンジニアとして働く

もちろん、こんなに上手くいくとは限りませんが(笑)、
目指す価値のある夢だと思っています。


本題!

今回の記事では、IDA Proについてを取り扱っています。

具体的には、exeファイルデコンパイルディスアセンブルについてを解説します!

基本的なつかいかた

IDA Proはインストールされている体で話をします。私は毎回ida.exeを開くのは面倒なので、レジストリ登録して右クリックで簡単に開けるようにしてます。んで、IDA Proで逆アセンブル処理などが終わったら、Produce File>Create C Fileに行って、疑似C言語ファイルを保存します。大体C言語で大まかな動作フローが分かったらそれでいいです。後、まだ何なのかよくわからない関数などが出てきたらmapファイルなども保存して見てください。私の今回の目的は、とあるexeファイルから、暗号化されたファイルを復号化するためのキーを特定することです。私の場合は、自己展開型のexeファイルだったため、tempフォルダを覗いて、完全コピーしました。私はまだ使ったことはないのですが、x64dbgなどの動的解析ツールを使って、CreateFileやWriteFileとかのAPI呼び出しにブレークポイントを設定して監視するという方法もあります。そういうのが難しいならProcess Monitorを使ってどこにファイルを作成したかなどを知ることができます。

逆コンパイル結果の解析

まずは、元のexeファイルのメタデータを確認します。確認方法はプロパティ>詳細に行けば分かります。大きな手掛かりがありました。元のファイル名が載っていました。ここでの明言は避けますが(ほとんどは利用規約的にリバースエンジニアリングは禁止されているので)、この元のファイル名が後に重要な手掛かりになります。そして、言語の部分がニュートラル言語となっていました。これは、言語の設定をしていなかったときに設定されます。これは、RustやGoなどのマルウェア、ほかには自己展開型(以降SFXと呼ぶ)の実行ファイルに良く見られます。今回の線では、SFXの実行ファイルだと仮説を立てて進めてみます。

では次に、WindowsのAPIであるCreateFileや、WriteFileCreateDirectorytempなどを検索してみます。見事にヒットしました。sfxと見て間違いなさそうです。

exeファイルの疑似C言語ファイルを見てみます。そのコードのごく一部に、このような記述がありました。

xxx-xxx-1.x.x.exe.c
  v5 = sub_14000AAA0(&NewDirectory, L"{TEMP}\\onefile_{PID}_{TIME}", 4096);
  v6 = sub_14000A4B0("NUITKA_ONEFILE_PARENT");

これは、NUITKAという、PyInstallerと良く混同するコンパイラのことです。PyInstallerはpythonのエンジンを使ったままそれをexeに包み込んで使用するラッパーで、nuitkaはpythonコードをC/C++のネイティブコードに変換して、一切pythonエンジンを使わずexeで動作するsfx型のコンパイラのことです。このコードを見る限り、このtempフォルダの最初がonefileというディレクトリにプログラムの中身があるようです。

逆アセンブル結果の解析

一応exeのアセンブリ見てはみたんですがmovとか低レベルすぎてちんぷんかんぷんでした。ですが、AIに取り込んでみると、一部動作ロジックの推測はできました。いやぁ自分も早くx86アーキテクチャのアセンブリ習得したいところですね(笑) 先にアセンブリを見るのではなく、まずは逆コンパイルをして、そのコードを確認してから、大雑把に全体を見て、最適化難読化によって読み取れない部分があるならそこをアセンブリで細かく確認すると良さそうです。でも、C言語とは違って、関数変数も何なくてメモリアドレスレジスタ名処理を追う必要があるため、可読性が死ぬほど低いのととにかく量が多いのでやる気が失せてしまいますね(笑)

Tempに保存されたファイルの解析

Tempに保存されていたファイルから復号キーが保存されているであろうファイルを探ります。さっき発見したメタデータに含まれていた元のファイル名と良く似た、こちらもまたメタデータがニュートラル言語になっているdllファイルを見つけました。おそらくこのdllファイルに復号キーが保存されているのでしょう。

dllファイルのディスアセンブル

次はdllファイルのディスアセンブルを行いたいと思います。行った後の結果がこちらです。

decryptやcrypto、aesとかで検索をかけたら、このようなものがヒットしました。

assembly
.data:000000018045E320		                dq offset aCryptoCipherRa ; "Crypto.Cipher._raw_aes"

Crypto.Cipher._raw_aesでgoogleに検索かけてみると、pycryptodomeというpythonのライブラリがヒットしました。AES暗号の復号化をするうえで重要な関数だそうです。ここのアドレスからクロスリファレンスを参照てみます。が、何もヒットしません。もしかすると直接このアドレスから関数を呼び出しているのではなく、このアドレスが沢山保存されているテーブルから間接的にアクセスしている可能性があります。ということで、即値検索を行っていきます。

即値検索

IDA Proでは、Alt+Iで即値検索のウィンドウが開きます。さっきのポインタのアドレスをここに入力します。さっきの例だと18045E320です。ida側にhex形式だと指定しなければならないため、このアドレスの先頭に、0xを追加します。

Address
0x18045E320

これでsearchしてみます。残念ながらヒットしませんでした。推測が間違っているようです。もしかするとアドレスの動的計算をしている可能性があります。その線で考えていきましょう。

解析手法の変更

今までは、アドレスから直接関数を参照しているものを見つけようとしていました。(クロスリファレンス)
でも、この動的計算によってキーの保存されたアドレスが参照されていると話は変わってきます。このキーが参照される瞬間を捉える必要があります。そこで今使えるのが、
PyBytes_FromStringAndSizeです。
これは何なのかというと、このNuiktaによってC言語に変換されたプログラムを、Pythonで受け渡しができるような形式に変換するためのPythonのAPIです。具体例を言うと、C言語で書かれたAESの復号処理を行うプログラムを、そのままPythonに渡して動かそうとしても言語が違うため処理不能です。でも、このPython/C APIを使うことによって、C言語のプログラムをPythonで動かせる形に変換してくれるのです。このAPIの一部の関数が、先ほどのPyBytes_FromStringAndSizeです。だから、このAESの復号処理をするときにこのAPIは必ず使われます。よって、この関数を特定し、これを参照しているアドレスを発見出来たら、それが復号キーの保存されている可能性が高いのです。では具体的な手順に移ります。

Python APIの関数特定

まずは、IDA Proで先ほどのdllを開いた状態で、Shift+F3をFunctionsタブを開きます。そこでCtrl+Fを押して、さっきのAPI関数、PyBytes_FromStringAndSizeでフィルターをかけて検索してみます。ヒットしませんでした。ここでももしかすると動的リンクで関数呼び出しをしているのかもしれません。簡単に言うと、
dllのインポートテーブルからPython本体(Python310.dll)にアドレスを参照してもらって、そこからcallしている可能性があります。
そのため、関数リスト(Functions)には検索をしてもヒットしませんでした。では、どうすればいいのか.
それは、Importsから検索をしてみることです。そうすることで、このインポートテーブルにある目的のPython310.dllにアドレスを参照するものを見つけることができます。

ImportsからAPIの関数検索

Importsタブの方からPyObject_GetAttrStringを検索してみます。この関数はさっきのものとは違い、AESで復号化をするとき、指定した名前のメソッドを取り出すために使われる関数です。具体例でいうと、AES.newというのをC言語で処理できるように変換するようなものです。Nuitkaでコンパイルされたプログラムなら確実と言っていいほど使われてます。すると、400件ほど沢山ヒットしました。成功です。でも400件は多すぎますね(笑)
絞り込む方法があるのかまでは知らないので、骨が折れますが、一つひとつ確認していきましょう。

呼び出し元の検証

ここまで済んだらあとは脳筋で見ていくだけです。 まずはヒットしたものをクリックしてコードにジャンプします。そうすると、大抵はこういう感じになっているはずです。

assembly
.text:0000000180009AFB                 lea     rdx, aSpecFromModule ; "_spec_from_module"
.text:0000000180009B02                 mov     rcx, rax
.text:0000000180009B05                 call    cs:PyObject_GetAttrString

しっかりとPyObject_GetAttrStringがcallされているのを確認できますね。
そして、ここで重要なのがこのcallされている命令の、直前にある引数です。この例でいうとrcxが第一引数、rdxが第二引数です。私の場合、このaSpecFromModuleの部分が、aNewのものを探します。理由を詳しく解説するとだいぶ長くなるので割愛しますが、簡単に説明すると、このNewというのは、Cryptodomeを使うとAES.newという形で、復号オブジェクトを生成するときに使われる、絶対に変わることのない関数名です。なぜこれを調べるのかというと、ここには私の探している、復号キーや、初期化ベクトルなどが絶対に入っているキーワードだからです。他にもdecryptとかだったら復号処理を行うときに使われるキーワードの可能性があるため、それで検索してみてもいいかもしれません。でも、今回は一番確実かと思われるNewで探しています。でももちろん、newという単語は一般的に良く知られていて、使われている単語なのでほかの無関係の関数とかもヒットするかもしれません。現に10個ほどヒットしました。
別に、他のものを解析するときも同じような考え方でいいです。たとえばネットワーク通信している箇所を見つけたい場合は、pythonだったらsocketライブラリを使うだろうな、と仮説を立てて、socketconnectなどで検索をかけてみます。それでsocketライブラリ特有の関数とかが使われていることが判明したら仮説は正解です。後はそのsokcetライブラリ特有のキーワードを調べて、自分の欲しい処理に含まれているキーワードを検索していったら辿り着きます。今回の場合は復号処理が行われているであろうと思い、decryptcryptoaesと検索をしてみたら
Crypto.Cipher._raw_aesというものがヒットしたので、これをWeb検索してみたらCryptodomeのライブラリの関数だったと判明しました。あとはこのCryptodomeで復号処理をする前準備(AESオブジェクトの作成)のときに使われるAES.newの、newという単語を選びました。AESで検索をかけると別の関数でも沢山使われていて今調べているものとは全く違うものまで大量にヒットするからです。でも、このAESは、何のライブラリを使っているかを調べるときにはだいぶ有効なので、使い分けが大切です。だから、このAESオブジェクトの作成の時に使われるAES.newnewだったらほかの関数がヒットしたりということは起こりません。それとちなみに補足を言うと、変数名とか(今の解析している対象物だとdecryption_keyivなど)から直接探そうとすると、ほっとんど無理です。何故かというとこういうのはコンパイルして、変数の名前が完全に変わってしまうからです。それをデコンパイラとかディスアセンブラがいいように解釈して、v3とか、v57みたいな具合で変数を設定しているので、何か特別なことがない限りここからの特定はだいぶ厳しいです。実際に、もしもdecryption_keyという形の変数を探そうとした場合、途方もない労力と時間がかかります。汚染解析と言って、とにかく他の関数とかロジックを全て一つずつ調べて、このdecryption_keyの中身だろうなと予想して、発見する方法です。C言語のデコンパイル結果でこのようなものをたまに見ますよね。

C
v1 = v2

これが汚染解析の一部です。v1をv2に代入するみたいに書かれてますよね。こうやって広がっていくので汚染解析と呼ばれています。このようなプログラムを全て網羅して、全体を見て解析する必要があります。正攻法である前方解析と比べると100倍労力と時間がかかります。

ちょっと長く言いすぎてしまいました。ってことで、次のステップに移りましょう。
ということで、分かりましたね?第二引数であるrdxの後の文字列は、aNewでないといけないということが。理由は先ほどのとおりです。大事だから詳しく書きました。リバースエンジニアリングをするうえで、仮説を立てることはとっても大切なことです。(AIからそのことを学びました)
これができないとほとんどリバースエンジニアリングはできないでしょう。目的のものを探し出すためには、その目的のもののちょっと特殊なキーワードを頭に入れておかないと、静的解析をするのは困難です。動的解析の話は別ですよ?まあそれでもこの考えはどっちの解析手法でも同じですが。ある程度身に付けておかないと自分で解析するのは難しくなります。

ということで、話を整理するためもう一度、ImportsでPyObject_GetAttrStringを検索してみると、一つヒットしました。クリックしてコードにジャンプしてみます。.idataセクションに辿り着きました。ここで、PyObject_GetAttrStringにカーソルを置いた状態でXキーを押してクロスリファレンスを確認します。約400個のアドレスで呼び出されているようです。AIに生成してもらった検索ツールを使って、このクロスリファレンスに出てきたアドレスの周囲10アドレス以内にnewというキーワードがあるのかを調べてもらいました。結論から言うとヒットしませんでした。これも失敗。次の方法に移ります。

PyBytes_FromStringAndSizeの調査

説明だけして実際に調査はしていませんでした。こりゃ失敬失敬。ということで、実際に調査してみます。
Importsタブで、PyBytes_FromStringAndSizeを検索してみます。ヒットしませんでした。これもダメか、と思いつつ、入力されたテキストを消していくと、一つだけヒットしました。それが、
PyBytes_FromStringです。これはさっきの関数とほぼ同等のものです。そして、ジャンプしてクロスリファレンスを参照してみました。二件、.rdata.pdataにヒットしました。.rdataに行ってみてみました。すると、こんなアセンブリになっていました。

.text:000000018040D584                 mov     [rsp+10C8h+var_58], rax
.text:000000018040D58C                 mov     rbp, rdx
.text:000000018040D58F                 mov     [rsp+10C8h+var_1088], r9b
.text:000000018040D594                 mov     r15, rcx
.text:000000018040D597                 mov     edx, 2Eh ; '.'  ; Ch
.text:000000018040D59C                 mov     rcx, rbp        ; Str
.text:000000018040D59F                 mov     r13, r8
.text:000000018040D5A2                 call    strrchr
.text:000000018040D5A7                 mov     r14, rax
.text:000000018040D5AA                 mov     r12, rbp
.text:000000018040D5AD                 test    rax, rax
.text:000000018040D5B0                 jz      short loc_18040D5B6
.text:000000018040D5B2                 lea     r12, [rax+1]
.text:000000018040D5B6
.text:000000018040D5B6 loc_18040D5B6:                          ; CODE XREF: sub_18040D560+50↑j
.text:000000018040D5B6                 xor     esi, esi
.text:000000018040D5B8                 mov     rcx, r12
.text:000000018040D5BB                 test    r14, r14
.text:000000018040D5BE                 mov     eax, esi
.text:000000018040D5C0                 cmovnz  rax, rbp
.text:000000018040D5C4                 mov     [rsp+10C8h+var_1080], rax
.text:000000018040D5C9                 call    cs:PyBytes_FromString

これは私の期待しているものではありませんでした。私は、

lea rcx, [キーが格納されたアドレス]
call cs:PyBytes_FromString

こんなふうになっていて、このキーが格納されたアドレスに直接復号キーが入っているものかと思っていました。でも、この例では、rcxに、r12というレジスタが入っています。これは何を意味するのかというと、第一引数がr12という名前の、rcxとは違う中身がずっと保持される不揮発性のレジスタのことです。アセンブリを追っていくと、PyBytes_FromStringに渡すアドレスをr12から受け取っていて、そのr12はどこからやってきたのかと調べていくと、lea r12, [rax+1] ここではr12に入っている中身が、rax+1にあるアドレスのものに書き換えられていることが分かります。このraxはどこからきたのかを調べると、

mov     r12, rbp

このようにrbpの中身がr12にコピーされているということがわかります。rbpはどこからやってきたんでしょう。

call    strrchr

これを見ると、strrchrという関数がcallされていることが分かります。web検索をしてみると、C言語の関数だそうです。どういうものかというと、 文字strの中から文字cがあるかどうか探索する。
対象の文字が見つかった場合、最後に現れた文字cのポインタを返す。
というものです。簡単に言うと、文字列を後ろから検索して、対象の文字が最後に出てきた場所のアドレスを返す関数です。
この対象の文字が何なのかを調べるためにこのstrrchrがcallされる前の命令を見てみます。

mov     edx, 2Eh ; '.'  ; Ch

これを見てみると、edx(第二引数)に2Ehというものを入れているようです。2Ehはasciiコード表では、「.」だそうです。これを見てください。

.text:000000018040D59C mov rcx, rbp ; Str

strrchrのrcx(第一引数)にはrbpの値をセットしていることが分かります。このrbpは何なんでしょうか?

.text:000000018040D58C mov rbp, rdx

この関数の最初のところで、第二引数として渡されたrdxを、rbpにコピーしているようです。

よって、これはファイル名から拡張子を取得するためのコードだと分かります。これは私の探し求めているものではありませんでした。これは失敗ということで、手段を変えてみます。そもそも何故これは失敗してしまったのでしょうか?目的のものがヒットしなかったということは、実行時に動的にアドレス解決を行っている可能性が非常に高いです。x64dbgを使ってブレークポイントを置いたら一番効率的に復号キーを取得することができると思いますが、今回は静的解析だけで復号キーを特定したいため、この手段は封印します。というかそもそもまだx64dbgを使ったことがないので、今はとりあえずIDA Proだけを使って本気で解析してみます。静的解析のスキルも上がるし悪いことでも何でもありません。これは一種の手段です。
ちなみにこれから調べていく関数で動的解析が必須になってしまう場面がやってきます(笑)

GetProcAddressの監視

さっきのようにインポートテーブルから検索してもヒットしないのはなぜかというと、さっきも説明した通り動的にアドレス解決を行っている可能性が高いです。もう一つの可能性は、そもそもその関数は使われていないという仮説です。でも、今回のような場合ではこの関数は確実に使っているものと推測できます。(PyBytes_FromStringはC言語をPythonで処理するときに必ず必要な関数だから)
なので、インポートテーブルなしに外部の関数のアドレスを取得する代表的な方法が、このGetProcAddressというものです。これを使えば動的にアドレス解決を行うことができます。ということで、GetProcAddressというWindowsのAPIをImportsタブから探してみます。これは、kernel32からヒットするはずです。無事ヒットしました。
次に、それをクリックしてクロスリファレンスを確認します。すると、10個くらいヒットしました。一つ一つ確認していくと、このようなアセンブリがありました。

Assembly
.text:000000018040D814                 lea     rdx, [rsp+10C8h+ProcName] ; lpProcName
.text:000000018040D81C                 mov     rcx, r12        ; hModule
.text:000000018040D81F                 call    cs:GetProcAddress

見た感じ、動的解析するしかなさそうです(笑)
普通の人はここでx64dbgでブレークポイントを置いて使うんですが、私の場合は、x64dbgが実行できない環境にいる前提で話を進めます。まあ別にここでx64dbgを使えば、復号キーのありかはわかります。でも、今回は動的解析はできないので、他の調べ方を模索してみます。

解析方法の洗い出し

私は超重要な根本のことを忘れていました。AES-256のキーは必ず、32バイトであることを。初期化ベクトルも同様16バイトであることを。私が何を言いたいのかというと、PyBytes_FromStringAndSizeのような関数を呼び出すときには必ず、このバイト数を引数として渡す必要があります。話は簡単です。ただ、16や32のような数字を関数で引数としてロードされている箇所をアセンブリで検索するような簡単なことです。ということで、やっていきます。

バイト列からの探索

IDA ProのSearch > Sequence of bytesで、検索を行っていきます。普通にアセンブリでテキスト検索するのでも、まあ駄目なわけではないんですが、若干の無関係なもの(ノイズ)が出てくるため、バイト列から検索するのが最も正確なのでそれをお勧めします。

mov edx, 20h

を探します。この20hは16進数表記になっていて、10進数に変換すると32です。さっきのAES-256のキーは必ず32バイトと言いましたね。これを使うことによってedxレジスタに32という数字が入ってきたということです。ただ、このままだとバイト列検索ができないため、バイトシーケンスの型に直して検索をかけます。

BA 20 00 00 00

こうすることで検索ができるようになります。そうすると、二件ヒットしました。

Address	Function	Instruction
.text:0000000180167244	sub_1801666F0	mov     edx, 20h ; ' '
.text:00000001803DEE44	sub_1803DED20	mov     edx, 20h ; ' '

この二つのコードにそれぞれジャンプしてみます。
そうすると、このようなものが現れました。

.text:0000000180167244                 mov     edx, 20h ; ' '
.text:0000000180167249                 jmp     loc_1801675A1

ビンゴです。この命令が終わった後のコードフローを確認してみると、jmp loc_1801675A1 というジャンプ先があります。実際に飛んでみてください。すると、

.text:000000018016754D                 mov     [rsp+0F0h+var_C0], rcx ; __int64
.text:0000000180167552                 mov     [rsp+0F0h+var_C8], rcx ; __int64
.text:0000000180167557                 mov     [rsp+0F0h+var_D0], rcx ; __int64
.text:000000018016755C                 lea     rcx, sub_180165A30 ; int
.text:0000000180167563                 call    sub_1803DDDB0
.text:0000000180167568                 mov     rdx, cs:qword_180473708
.text:000000018016756F                 mov     r8, rax
.text:0000000180167572                 mov     rcx, r14
.text:0000000180167575                 mov     rbx, rax
.text:0000000180167578                 call    cs:PyObject_SetItem
.text:000000018016757E                 sub     qword ptr [rbx], 1
.text:0000000180167582                 mov     dword ptr [rbp+57h+arg_8], eax
.text:0000000180167585                 jnz     short loc_180167594
.text:0000000180167587                 mov     rdx, [rbx+8]
.text:000000018016758B                 mov     rcx, rbx
.text:000000018016758E                 call    qword ptr [rdx+30h]
.text:0000000180167591                 mov     eax, dword ptr [rbp+57h+arg_8]
.text:0000000180167594
.text:0000000180167594 loc_180167594:                          ; CODE XREF: sub_1801666F0+E95↑j
.text:0000000180167594                 test    eax, eax
.text:0000000180167596                 jz      loc_180167647
.text:000000018016759C                 mov     edx, 6Eh ; 'n'
.text:00000001801675A1
.text:00000001801675A1 loc_1801675A1:                          ; CODE XREF: sub_1801666F0+B59↑j
.text:00000001801675A1                                         ; sub_1801666F0+BE7↑j ...
.text:00000001801675A1                 mov     rax, [rdi+58h]
.text:00000001801675A5                 mov     rbx, [rdi+68h]
.text:00000001801675A9                 mov     qword ptr [rbp+57h+var_70], rax
.text:00000001801675AD                 mov     rax, [rdi+60h]
.text:00000001801675B1                 mov     qword ptr [rbp+57h+var_70+8], rax
.text:00000001801675B5                 xor     eax, eax
.text:00000001801675B7                 mov     [rdi+58h], rax
.text:00000001801675BB                 mov     [rdi+60h], rax
.text:00000001801675BF                 mov     [rdi+68h], rax
.text:00000001801675C3                 mov     [rbp+57h+var_60], rbx
.text:00000001801675C7                 test    rbx, rbx
.text:00000001801675CA                 jnz     short loc_1801675F3
.text:00000001801675CC                 mov     rcx, r12
.text:00000001801675CF                 call    sub_180411220
.text:00000001801675D4                 mov     rcx, [rbp+57h+var_60]
.text:00000001801675D8                 mov     rbx, rax
.text:00000001801675DB                 test    rcx, rcx

のようなアセンブリがありました。この中でとっても重要なものはこの二つです。

.text:00000001801675CC mov rcx, r12

.text:00000001801675CF call sub_180411220

何故これが重要なのかというと、復号キーが入っているRCXレジスタに、r12の内容をコピーするという処理と、この呼び出されたsub_180411220という関数は、さっきの復元キーがセットされたRCXレジスタと、その前にEDXにセットされたバイトの長さを使って次の処理をしようとしているのです。そして、このr12の内容を調べるため、これよりも上の方にあるアセンブリを見てみます。

.text:000000018016719E                 mov     r12, rax
.text:00000001801671A1                 mov     rax, [rdi+18h]
.text:00000001801671A5                 mov     [rdi+18h], r12
.text:00000001801671A9                 test    rax, rax
.text:00000001801671AC                 jz      short loc_1801671B3
.text:00000001801671AE                 mov     [r12+18h], rax

このようなアセンブリを発見しました。r12レジスタにraxレジスタに入ってるものをコピーしているようです。これが、このsub_180411220で使われるrcxレジスタの中身です。

結論

結論から言うと、静的解析では「ここまでが限界」です。私は今までバカほど時間を費やして静的解析をしてきましたが、raxは何なのかを調べようとするには、動的解析を使うしかほかなる方法はもうありません。GetProcAddressによってアドレスが動的解決されているのです。そのため、実際にブレークポイントを置いて解析するしか方法はありません。また近日中に動的解析編をやるかもしれません(笑)
本当に不定期なので気が乗ったらやります!ご清聴ありがとうございました!!

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?