22 KiB
Raw Blame History

リバースエンジニアリングツールと基本的な手法

{{#include ../../banners/hacktricks-training.md}}

ImGuiベースのリバースエンジニアリングツール

ソフトウェア:

Wasmデコンパイラ / Watコンパイラ

オンライン:

ソフトウェア:

.NETデコンパイラ

dotPeek

dotPeekは、ライブラリ.dllWindowsメタデータファイル.winmd、および実行可能ファイル.exeを含む複数のフォーマットをデコンパイルおよび検査するデコンパイラです。デコンパイルされた後、アセンブリはVisual Studioプロジェクト.csprojとして保存できます。

ここでの利点は、失われたソースコードをレガシーアセンブリから復元する必要がある場合、このアクションが時間を節約できることです。さらに、dotPeekはデコンパイルされたコード全体を便利にナビゲートできるため、Xamarinアルゴリズム分析に最適なツールの1つです。

.NET Reflector

包括的なアドインモデルと、ツールを正確なニーズに合わせて拡張するAPIを備えた.NET Reflectorは、時間を節約し、開発を簡素化します。このツールが提供する逆コンパイルサービスの豊富さを見てみましょう

  • ライブラリやコンポーネントを通じてデータがどのように流れるかの洞察を提供
  • .NET言語やフレームワークの実装と使用に関する洞察を提供
  • 使用されているAPIや技術からより多くの機能を引き出すために、文書化されていない機能や公開されていない機能を見つける
  • 依存関係や異なるアセンブリを見つける
  • コード、サードパーティコンポーネント、およびライブラリ内のエラーの正確な位置を追跡
  • 作業しているすべての.NETコードのソースをデバッグ

ILSpy & dnSpy

Visual Studio Code用ILSpyプラグイン: どのOSでも使用できますVSCodeから直接インストールできます。gitをダウンロードする必要はありません。拡張機能をクリックし、ILSpyを検索してください)。
デコンパイル修正、および再コンパイルする必要がある場合は、dnSpyまたはそのアクティブにメンテナンスされているフォークであるdnSpyExを使用できます。(右クリック -> メソッドを修正して関数内の何かを変更します)。

DNSpyロギング

DNSpyにファイルに情報をログさせるために、このスニペットを使用できます:

using System.IO;
path = "C:\\inetpub\\temp\\MyTest2.txt";
File.AppendAllText(path, "Password: " + password + "\n");

DNSpy デバッグ

DNSpy を使用してコードをデバッグするには、次の手順が必要です。

まず、デバッグに関連する Assembly attributes を変更します:

From:

[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]

翻訳する内容が提供されていません。翻訳が必要なテキストを提供してください。

[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default |
DebuggableAttribute.DebuggingModes.DisableOptimizations |
DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints |
DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]

そして、コンパイルをクリックします:

次に、_ファイル >> モジュールを保存..._を通じて新しいファイルを保存します

これは必要です。なぜなら、これを行わないと、ランタイム中にいくつかの最適化がコードに適用され、デバッグ中にブレークポイントが決してヒットしないか、いくつかの変数が存在しない可能性があるからです。

次に、.NETアプリケーションがIISによって実行されている場合は、次のコマンドで再起動できます:

iisreset /noforce

その後、デバッグを開始するには、すべてのオープンファイルを閉じ、Debug Tab内で**Attach to Process...**を選択します:

次に、IISサーバーにアタッチするためにw3wp.exeを選択し、attachをクリックします:

プロセスのデバッグを行っているので、実行を停止し、すべてのモジュールをロードする時間です。まず、Debug >> Break All_をクリックし、次にDebug >> Windows >> Modules_をクリックします

Modulesの任意のモジュールをクリックし、Open All Modulesを選択します:

Assembly Explorerの任意のモジュールを右クリックし、Sort Assembliesをクリックします:

Java decompiler

https://github.com/skylot/jadx
https://github.com/java-decompiler/jd-gui/releases

DLLのデバッグ

IDAを使用する

  • rundll32をロードします64ビットはC:\Windows\System32\rundll32.exe、32ビットはC:\Windows\SysWOW64\rundll32.exe
  • Windbgデバッガを選択します
  • "Suspend on library load/unload"を選択します

  • 実行のパラメータを設定し、DLLのパスと呼び出したい関数を指定します:

その後、デバッグを開始すると、各DLLがロードされると実行が停止します。次に、rundll32があなたのDLLをロードすると、実行が停止します。

しかし、ロードされたDLLのコードにどのようにアクセスできますかこの方法では、私はわかりません。

x64dbg/x32dbgを使用する

  • rundll32をロードします64ビットはC:\Windows\System32\rundll32.exe、32ビットはC:\Windows\SysWOW64\rundll32.exe
  • コマンドラインを変更します(File --> Change Command Lineし、DLLのパスと呼び出したい関数を設定します。例えば"C:\Windows\SysWOW64\rundll32.exe" "Z:\shared\Cybercamp\rev2\\14.ridii_2.dll",DLLMain
  • _Options --> Settings_を変更し、DLL Entryを選択します。
  • 次に、実行を開始します。デバッガは各DLLのメインで停止し、ある時点であなたのDLLのDLLエントリで停止します。そこから、ブレークポイントを設定したいポイントを検索します。

実行が何らかの理由でwin64dbgで停止した場合、win64dbgウィンドウの上部どのコードを見ているかを確認できます:

その後、実行が停止したDLLをデバッグすることができます。

GUIアプリ / ビデオゲーム

Cheat Engineは、実行中のゲームのメモリ内に重要な値が保存されている場所を見つけて変更するのに役立つプログラムです。詳細は以下を参照してください:

{{#ref}} cheat-engine.md {{#endref}}

PiNCEは、GNU Project Debugger (GDB)のフロントエンド/リバースエンジニアリングツールで、ゲームに特化しています。ただし、リバースエンジニアリングに関連する任意の作業にも使用できます。

Decompiler Explorerは、いくつかのデコンパイラへのウェブフロントエンドです。このウェブサービスを使用すると、小さな実行可能ファイルに対する異なるデコンパイラの出力を比較できます。

ARM & MIPS

{{#ref}} https://github.com/nongiach/arm_now {{#endref}}

シェルコード

blobrunnerを使用したシェルコードのデバッグ

Blobrunnerは、シェルコードをメモリのスペース内に割り当て、シェルコードが割り当てられたメモリアドレス示し、実行を停止します。
その後、プロセスにデバッガIdaまたはx64dbgをアタッチし、指定されたメモリアドレスにブレークポイントを設定し、実行を再開します。これにより、シェルコードをデバッグできます。

リリースのGitHubページには、コンパイルされたリリースを含むzipファイルがありますhttps://github.com/OALabs/BlobRunner/releases/tag/v0.0.5
以下のリンクにBlobrunnerのわずかに修正されたバージョンがあります。コンパイルするには、Visual Studio CodeでC/C++プロジェクトを作成し、コードをコピー&ペーストしてビルドします。

{{#ref}} blobrunner.md {{#endref}}

jmp2itを使用したシェルコードのデバッグ

jmp2it は、blobrunnerに非常に似ています。シェルコードをメモリのスペース内に割り当て永続ループを開始します。次に、プロセスにデバッガをアタッチし、再生を開始して2-5秒待ち、停止を押します。そうすると、永続ループの中にいることになります。永続ループの次の命令にジャンプすると、それがシェルコードへの呼び出しになります。最終的に、シェルコードを実行していることになります。

コンパイルされたバージョンは、リリースページのjmp2itからダウンロードできます。

Cutterを使用したシェルコードのデバッグ

Cutterは、radareのGUIです。Cutterを使用すると、シェルコードをエミュレートし、動的に検査できます。

Cutterは「ファイルを開く」と「シェルコードを開く」を許可します。私の場合、シェルコードをファイルとして開くと正しくデコンパイルされましたが、シェルコードとして開くとそうではありませんでした

エミュレーションを開始したい場所にbpを設定すると、Cutterはそこから自動的にエミュレーションを開始します

例えば、16進ダンプ内でスタックを見ることができます

シェルコードの難読化解除と実行される関数の取得

scdbgを試してみるべきです。
それは、シェルコードが使用している関数や、シェルコードがメモリ内で自己デコードしているかどうかを教えてくれます。

scdbg.exe -f shellcode # Get info
scdbg.exe -f shellcode -r #show analysis report at end of run
scdbg.exe -f shellcode -i -r #enable interactive hooks (file and network) and show analysis report at end of run
scdbg.exe -f shellcode -d #Dump decoded shellcode
scdbg.exe -f shellcode /findsc #Find offset where starts
scdbg.exe -f shellcode /foff 0x0000004D #Start the executing in that offset

scDbgには、選択したオプションを選んでシェルコードを実行できるグラフィカルランチャーもあります。

Create Dumpオプションは、シェルコードがメモリ内で動的に変更された場合に最終的なシェルコードをダンプします(デコードされたシェルコードをダウンロードするのに便利です)。start offsetは、特定のオフセットでシェルコードを開始するのに役立ちます。Debug Shellオプションは、scDbgターミナルを使用してシェルコードをデバッグするのに便利ですが、Idaやx64dbgを使用できるため、前述のオプションの方がこの目的には適していると思います。

CyberChefを使用した逆アセンブル

シェルコードファイルを入力としてアップロードし、次のレシピを使用して逆コンパイルします: https://gchq.github.io/CyberChef/#recipe=To_Hex('Space',0)Disassemble_x86('32','Full%20x86%20architecture',16,0,true,true)

Movfuscator

この難読化ツールは、すべてのmov命令を修正します(本当にクールです)。実行フローを変更するために割り込みも使用します。どのように機能するかについての詳細情報:

運が良ければ、demovfuscatorがバイナリをデオブfuscateします。いくつかの依存関係があります。

apt-get install libcapstone-dev
apt-get install libz3-dev

And install keystone (apt-get install cmake; mkdir build; cd build; ../make-share.sh; make install)

If you are playing a CTF, this workaround to find the flag could be very useful: https://dustri.org/b/defeating-the-recons-movfuscator-crackme.html

Rust

エントリーポイントを見つけるには、::mainで関数を検索します:

この場合、バイナリはauthenticatorと呼ばれているので、これは興味深いメイン関数であることは明らかです。
呼び出される関数名前を持っているので、インターネットでそれらを検索して入力出力について学びます。

Delphi

Delphiでコンパイルされたバイナリには、https://github.com/crypto2011/IDRを使用できます。

Delphiバイナリをリバースする必要がある場合は、IDAプラグインhttps://github.com/Coldzer0/IDA-For-Delphiを使用することをお勧めします。

ATL+f7を押してIDAにPythonプラグインをインポートPythonプラグインを選択します。

このプラグインは、バイナリを実行し、デバッグの開始時に関数名を動的に解決します。デバッグを開始した後、再度スタートボタン緑のボタンまたはf9を押すと、実際のコードの最初でブレークポイントがヒットします。

グラフィックアプリケーションでボタンを押すと、デバッガーはそのボタンによって実行された関数で停止するため、非常に興味深いです。

Golang

Golangバイナリをリバースする必要がある場合は、IDAプラグインhttps://github.com/sibears/IDAGolangHelperを使用することをお勧めします。

ATL+f7を押してIDAにPythonプラグインをインポートPythonプラグインを選択します。

これにより、関数の名前が解決されます。

Compiled Python

このページでは、ELF/EXE PythonコンパイルバイナリからPythonコードを取得する方法を見つけることができます:

{{#ref}} ../../generic-methodologies-and-resources/basic-forensic-methodology/specific-software-file-type-tricks/.pyc.md {{#endref}}

GBA - Game Body Advance

GBAゲームのバイナリを取得した場合、さまざまなツールを使用してエミュレートおよびデバッグできます:

  • no$gba (デバッグ版をダウンロード) - インターフェースを持つデバッガーを含む
  • mgba - CLIデバッガーを含む
  • gba-ghidra-loader - Ghidraプラグイン
  • GhidraGBA - Ghidraプラグイン

no$gbaの_Options --> Emulation Setup --> Controls_** **では、Game Boy Advanceのボタンを押す方法を確認できます。

押すと、各キーには識別するための値があります:

A = 1
B = 2
SELECT = 4
START = 8
RIGHT = 16
LEFT = 32
UP = 64
DOWN = 128
R = 256
L = 256

この種のプログラムでは、興味深い部分はプログラムがユーザー入力をどのように扱うかです。アドレス0x4000130には、一般的に見られる関数KEYINPUTがあります。

前の画像では、関数がFUN_080015a8から呼び出されているのがわかります(アドレス: 0x080015fa0x080017ac)。

その関数では、いくつかの初期化操作の後(重要ではない):

void FUN_080015a8(void)

{
ushort uVar1;
undefined4 uVar2;
undefined4 uVar3;
ushort uVar4;
int iVar5;
ushort *puVar6;
undefined *local_2c;

DISPCNT = 0x1140;
FUN_08000a74();
FUN_08000ce4(1);
DISPCNT = 0x404;
FUN_08000dd0(&DAT_02009584,0x6000000,&DAT_030000dc);
FUN_08000354(&DAT_030000dc,0x3c);
uVar4 = DAT_030004d8;

このコードが見つかりました:

do {
DAT_030004da = uVar4; //This is the last key pressed
DAT_030004d8 = KEYINPUT | 0xfc00;
puVar6 = &DAT_0200b03c;
uVar4 = DAT_030004d8;
do {
uVar2 = DAT_030004dc;
uVar1 = *puVar6;
if ((uVar1 & DAT_030004da & ~uVar4) != 0) {

最後のifは**uVar4最後のキーにあり、現在のキーではないことを確認しています。現在のキーはuVar1**に保存されています。

if (uVar1 == 4) {
DAT_030000d4 = 0;
uVar3 = FUN_08001c24(DAT_030004dc);
FUN_08001868(uVar2,0,uVar3);
DAT_05000000 = 0x1483;
FUN_08001844(&DAT_0200ba18);
FUN_08001844(&DAT_0200ba20,&DAT_0200ba40);
DAT_030000d8 = 0;
uVar4 = DAT_030004d8;
}
else {
if (uVar1 == 8) {
if (DAT_030000d8 == 0xf3) {
DISPCNT = 0x404;
FUN_08000dd0(&DAT_02008aac,0x6000000,&DAT_030000dc);
FUN_08000354(&DAT_030000dc,0x3c);
uVar4 = DAT_030004d8;
}
}
else {
if (DAT_030000d4 < 8) {
DAT_030000d4 = DAT_030000d4 + 1;
FUN_08000864();
if (uVar1 == 0x10) {
DAT_030000d8 = DAT_030000d8 + 0x3a;

前のコードでは、uVar1押されたボタンの値が格納されている場所)をいくつかの値と比較しています:

  • 最初に、値4SELECTボタン)と比較されています:このチャレンジでは、このボタンは画面をクリアします。
  • 次に、値8STARTボタン)と比較されています:このチャレンジでは、コードがフラグを取得するのに有効かどうかを確認します。
  • この場合、変数**DAT_030000d8**は0xf3と比較され、値が同じであればいくつかのコードが実行されます。
  • 他のケースでは、いくつかのcontDAT_030000d4がチェックされます。これは、コードに入った直後に1を加算するため、contです。
    8未満の場合、DAT_030000d8に値を加算することが行われます基本的には、contが8未満の間、押されたキーの値をこの変数に加算しています

したがって、このチャレンジでは、ボタンの値を知っている必要があり、結果の合計が0xf3になるように8未満の長さの組み合わせを押す必要があります。

このチュートリアルの参考文献: https://exp.codes/Nostalgia/

Game Boy

{{#ref}} https://www.youtube.com/watch?v=VVbRe7wr3G4 {{#endref}}

コース

{{#include ../../banners/hacktricks-training.md}}