Skip to content
KitploitKITPLOIT
FerramentasExploitsBlog
Log in
Enviar
FerramentasExploitsBlog
Enviar

Ferramentas de Hacking, PenTest e Cibersegurança para o seu Arsenal de Segurança!

Kitploit é um diretório de ferramentas de hacking, cibersegurança e pentesting. Descubra as últimas atualizações de projetos para encontrar vulnerabilidades, analisar sistemas, automatizar testes e fortalecer sua segurança.

··Feeds·Contato·Privacidade·© 2026 Kitploit

Diretório de Ferramentas

Categorias

Ver todas as categorias
Loading categories
Mergen — Desofuscação via otimização com uso de LLVM IR e análise de assembly. | Kitploit
Ferramentas/GitHubGitHub/nac-l/mergen
Análise EstáticaAnálise Dinâmica (Sandboxing)Engenharia ReversaAnálise de BináriosExploração de Binários
GitHubnac-l/mergen

Mergen

Desofuscação via otimização com uso de LLVM IR e análise de assembly.

Ver Repositório
8789448há 4 mesesRevisado pelo Kitploit

Mais Populares

Ver todos →

Descubra as ferramentas mais usadas pela nossa comunidade.

Explore todas as ferramentas

Navegue pela nossa coleção de ferramentas

Ver todas as ferramentas →
Compartilhar

Visão Geral do Projeto:

Mergen é uma ferramenta projetada para converter código Assembly em Representação Intermediária (IR) do LLVM. Esta ferramenta foi criada para:

  • A deofuscação ou desvirtualização de código binário ofuscado
  • A melhoria do processo de engenharia reversa, tornando-o mais eficiente e eficaz, especialmente para sistemas de software complexos.

Guia para construir & executar

Para construir e executar o projeto, consulte docs/BUILDING.md.

Portão de regressão da base de reescrita

O trabalho de reescrita deve manter o portão de regressão da base verde. O portão compila amostras PE focadas, executa lifter e verifica as saídas IR geradas.

  • Documento do fluxo de trabalho: docs/REWRITE_BASELINE.md
  • Portão de um comando: scripts\\rewrite\\run.cmd

Objetivos Principais:

  • Deofuscação

  • Desvirtualização

  • Otimização

Como funciona?

Nós executamos simbolicamente (ou elevamos simbolicamente) o alvo, a ideia aqui não é elevar instruções individuais, mas sim elevar uma função inteira. Não esperamos que uma única instrução ou um único bloco básico se comporte da mesma forma toda vez, em vez disso, os tratamos como se pudessem ser e são para propósitos diferentes a cada vez. Tentamos manter o IR gerado o mais simples e otimizável possível. Também temos necessidades diferentes de um compilador comum. Usamos análise para avaliar o fluxo de controle. Não podemos depender do LLVM para toda a nossa análise, porque eles são criados para objetivos diferentes e podem não ser ideais para o nosso caso de uso.

image

Exemplos

Este é o exemplo prático para ilustrar como o Mergen resolve contra programas virtualizados.

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

Exemplo #1 (VMProtect)

Este é o nosso programa alvo

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

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

image

image

Configurações do VMProtect, tudo está desligado, virtualizamos a função na configuração ultra. (Versões testadas 3.4.0-3.6.0 3.8.1)

image

image

Aqui, executamos o mergen. O primeiro argumento é o nome do arquivo e o segundo argumento é o endereço da função. Veja como é simples de executar. E podemos compilar a saída para explorá-la usando nosso decompilador favorito.

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) }

Após compilar:

image

image

Agora você pode notar que os registradores estão um pouco diferentes. Isso ocorre porque não seguimos as convenções de chamada; se seguíssemos as convenções de chamada, a assinatura da função seria assim:

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

Portanto, apenas ajustamos a assinatura da função para parecer normal. Se você tiver mais dúvidas sobre esta parte, sugiro pesquisar sobre convenções de chamada e ABI.

Exemplo #2 (Branches/Jumptables)

Então, vamos supor que temos este código. As VMs pegarão o código abaixo e o transformarão em um salto indireto, o que é um pouco mais incômodo para o engenheiro reverso.

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;

Nós sempre tentamos analisar valores e mantê-los rastreados. Isso nos permite entender o fluxo de controle. Para branches do tipo jumptable A saída otimizada seria um simples

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
}

Saída não otimizada. (DCE aplicado para legibilidade)

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
Baixar ferramenta