Skip to content
KitploitKITPLOIT
ツールエクスプロイトブログ
Log in
提出
ツールエクスプロイトブログ
提出

ハッキング、侵入テスト、サイバーセキュリティツールをあなたのセキュリティアーセナルに!

Kitploitはハッキング、サイバーセキュリティ、ペネトレーションテストのツールディレクトリです。最新のプロジェクトアップデートを見つけて、脆弱性の発見、システム分析、テストの自動化、セキュリティの強化を行いましょう。

··フィード·お問い合わせ·プライバシー·© 2026 Kitploit

ツールディレクトリ

カテゴリ

すべてのカテゴリを見る
Loading categories
Mergen — LLVM IRとアセンブリ解析を用いた最適化による難読化解除。 | Kitploit
ツール/GitHubGitHub/nac-l/mergen
静的分析動的分析 (サンドボックス)リバースエンジニアリングバイナリ解析バイナリエクスプロイト
GitHubnac-l/mergen

Mergen

LLVM IRとアセンブリ解析を用いた最適化による難読化解除。

リポジトリを見る
87894484ヶ月前Kitploit レビュー済み

人気

すべて見る →

コミュニティで最も使われているツールを見つけましょう。

すべてのツールを探索

ツールコレクションを閲覧

すべてのツールを見る →
共有

Project Overview:

Mergenは、アセンブリコードをLLVM中間表現(IR)に変換するために設計されたツールです。 このツールは以下を目的としています:

  • 難読化されたバイナリコードの難読化解除または仮想化解除
  • リバースエンジニアリングプロセスの強化、特に複雑なソフトウェアシステムにおいて効率的かつ効果的にするため。

Guide to build & run

プロジェクトのビルドと実行方法については、docs/BUILDING.mdを参照してください。

Rewrite baseline gate

書き換え作業は、ベースライン回帰ゲートをグリーンのまま維持する必要があります。ゲートは対象のPEサンプルをビルドし、lifterを実行し、リフトされたIR出力を検証します。

  • Workflow doc: docs/REWRITE_BASELINE.md
  • One-command gate: scripts\\rewrite\\run.cmd

Core Objectives:

  • Deobfuscation

  • Devirtualization

  • Optimization

How does it work?

我々はターゲットをシンボリックに実行(またはシンボリックリフト)します。ここでの考え方は、個々の命令をリフトするのではなく、関数全体をリフトすることです。各命令や基本ブロックが毎回同じように動作するとは期待せず、毎回異なる目的のために存在しうるものとして扱います。生成されるIRを可能な限りシンプルで最適化可能に保つよう努めます。また、通常のコンパイラとは異なるニーズがあります。分析を用いて制御フローを評価します。LLVMの分析だけに依存することはできません。なぜなら、LLVMは異なる目的のために作られており、我々のユースケースには最適でない可能性があるからです。

image

Examples

これは、Mergenが仮想化されたプログラムに対してどのように対処するかを示す実用的な例です。

  1. VMProtect
  2. Branches/Jumptables
  3. Themida 3.1.6.0 LION64 (Red)

Example #1 (VMProtect)

This is our target program

struct test {
    int a;
    int b;
    int c;
};

int maths(test a, int b, int c) {
        return a.a  + b - c;
}

image

image

VMProtect settings, everything is turned off, we virtualize the function on ultra setting. (Tested versions 3.4.0-3.6.0 3.8.1)

image

image

Here, we run mergen. First argument is the name of the file and the second argument is the address of the function. Look how simple it is to run. And we can compile the output so we can explore it using our favorite decompiler.

image

; ModuleID = 'my_lifting_module'
source_filename = "my_lifting_module"

; Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read)
define i64 @main(i64 %rax, i64 %rcx, i64 %rdx, i64 %rbx, i64 %0, i64 %rbp, i64 %rsi, i64 %rdi, i64 %r8, i64 %r9, i64 %r10, i64 %r11, i64 %r12, i64 %r13, i64 %r14, i64 %r15, ptr nocapture readonly %memory) local_unnamed_addr #0 {
entry:
  %stackmemory = alloca i128, i128 13758960, align 8
  %1 = trunc i64 %r8 to i32
  %2 = trunc i64 %rdx to i32
  %GEPLoadxd-5369456437- = getelementptr i8, ptr %memory, i64 %rcx
  %3 = load i32, ptr %GEPLoadxd-5369456437-, align 4
  %adc-temp-5370242400- = sub i32 %2, %1
  %realnot-5369532059- = add i32 %adc-temp-5370242400-, %3
  %stackmemory10243.sroa.55.1375304.insert.ext10255 = zext i32 %realnot-5369532059- to i64
  ret i64 %stackmemory10243.sroa.55.1375304.insert.ext10255
}

attributes #0 = { mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read) }

After compiling:

image

image

Now you might notice the registers are a little bit off. This is because of we dont follow the calling conventions, if we were to follow the calling conventions, function signature would look like this:

define i64 @main(i64 %rcx, i64 %rdx, i64 %rdx, i64 %r8, i64 %r9 ...)

So, we just adjust the function signature to look normally. If you have more questions about this part, I suggest you research calling conventions and ABI.

Example #2 (Branches/Jumptables)

So, lets say we have this code. VM's will take the below code then turn it to an indirect jump, its slightly more unconvenient for the reverser.

int maths(int a, int b, int c) {
    if (a > b)
        return a + b + c;
    else
        return a - b - c;
}
next_handler = xxx;
if ( a-b > 0 )
  next_handler = yyy;
jump next_handler;

We try to always analyze values and keep track of them. This allows us to understand control flow. For jumptable-like branches Optimized output would be a simple

define i64 @main(i64 %rax, i64 %rcx, i64 %rdx, i64 %rbx, i64 %rsp, i64 %rbp, i64 %rsi, i64 %rdi, i64 %r8, i64 %r9, i64 %r10, i64 %r11, i64 %r12, i64 %r13, i64 %r14, i64 %r15, ptr nocapture readnone %TEB, ptr nocapture readnone %memory) local_unnamed_addr #0 {
fake_ret:
  %0 = lshr i64 %rcx, 62
  %common.ret.op = and i64 %0, 2
  ret i64 %common.ret.op
}

Unoptimized output. (DCE'd for readability)

source_filename = "my_lifting_module"

define i64 @main(i64 %rax, i64 %rcx, i64 %rdx, i64 %rbx, i64 %rsp, i64 %rbp, i64 %rsi, i64 %rdi, i64 %r8, i64 %r9, i64 %r10, i64 %r11, i64 %r12, i64 %r13, i64 %r14, i64 %r15, ptr %TEB, ptr %memory) {
  %lsb = and i64 %rcx, 255
  %pf1 = mul i64 %lsb, 72340172838076673
  %pf2 = and i64 %pf1, -9205322385119247871
  %pf3 = urem i64 %pf2, 511
  %pf4 = and i64 %pf3, 1
  %pf5 = icmp eq i64 0, %pf4
  %0 = zext i1 %pf5 to i64
  %createrflag2 = shl i64 %0, 2
  %creatingrflag = or i64 2, %createrflag2
  %zeroflag = icmp eq i64 %rcx, 0
  %1 = zext i1 %zeroflag to i64
  %createrflag21 = shl i64 %1, 6
  %creatingrflag2 = or i64 %creatingrflag, %createrflag21
  %signflag = icmp slt i64 %rcx, 0
  %2 = zext i1 %signflag to i64
  %createrflag23 = shl i64 %2, 7
  %creatingrflag4 = or i64 %creatingrflag2, %createrflag23
  %GEPSTORE-5368713221- = getelementptr i8, ptr %memory, i64 1376032
  store i64 %creatingrflag4, ptr %GEPSTORE-5368713221-, align 4
  %realand-5368713229- = and i64 %creatingrflag4, 128
  %shr-lshr-5368713233- = lshr i64 %realand-5368713229-, 7
  %3 = mul i64 %shr-lshr-5368713233-, 4
  %bvalue_indexvalue = add i64 5368713249, %3
  %4 = icmp eq i64 %bvalue_indexvalue, 5368713253
  %lolb- = select i1 %4, i64 5368713264, i64 5368713257
  %GEPSTORE-5368713248- = getelementptr i8, ptr %memory, i64 1376032
  store i64 %lolb-, ptr %GEPSTORE-5368713248-, align 4
  br i1 %4, label %real_ret, label %real_ret41

real_ret:                                         ; preds = %fake_ret
  %inc-5368713273- = add i64 %shr-lshr-5368713233-, 1
  ret i64 %inc-5368713273-

real_ret41:                                       ; preds = %fake_ret
  ret i64 %shr-lshr-5368713233-
}

Notice this part

  %realand-5368713229- = and i64 %creatingrflag4, 128
  %shr-lshr-5368713233- = lshr i64 %realand-5368713229-, 7

フラグを取得し、7番目のビットである符号フラグを取得し、その符号フラグを使用してアドレスを計算します。分析により、アドレスは2つの値5368713257または5368713264のいずれかであると判断し、それを比較に変換します。アドレスが5368713257の場合は一方の分岐を取り、もう一方の場合は別の分岐を取ります。このとき、条件を適切な値でマークすることも重要です。後でまったく同じ値で別のジャンプを計算する必要があるかもしれないからです。

間接ジャンプを解決できるものの、可能な位置が2つを超えるジャンプはサポートされていません。これは、それらの分析がまだ実装されていないためです。これにより、VMスタイルのブランチは解決できますが、実際のジャンプテーブルには問題があります。

Example #3 (Themida 3.1.6.0 LION64 (Red))

Our target program:

ツールをダウンロード