Skip to content
KitploitKITPLOIT
FerramentasBlog
Enviar
FerramentasBlog
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
87894há 3 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

root@kitploit:~
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

root@kitploit:~
; 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:

root@kitploit:~
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.

root@kitploit:~
int maths(int a, int b, int c) {
    if (a > b)
        return a + b + c;
    else
        return a - b - c;
}
root@kitploit:~
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

root@kitploit:~
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)

root@kitploit:~
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-
}

Observe esta parte

root@kitploit:~
  %realand-5368713229- = and i64 %creatingrflag4, 128
  %shr-lshr-5368713233- = lshr i64 %realand-5368713229-, 7

Obtemos os flags, depois obtemos o 7º bit, que é o Flag de Sinal (Sign Flag), e usamos o Flag de Sinal para calcular um endereço. Através da análise, determinamos que o endereço pode ser um de dois valores, 5368713257 ou 5368713264, e então transformamos isso em uma comparação. Se o endereço for 5368713257, pegue um ramo, se for o outro, pegue o outro. Ao fazer isso, também é importante marcar a condição com o valor apropriado, porque mais tarde, podemos precisar calcular outro salto com o mesmo valor exato.

Mesmo que resolvamos os saltos indiretos, saltos com mais de 2 locais possíveis não são suportados. Isso ocorre porque a análise para eles ainda não foi implementada. Isso nos permite resolver branches do tipo VM, mas temos problemas com jumptables reais.

Exemplo #3 (Themida 3.1.6.0 LION64 (Red))

Nosso programa alvo:

image

Configurações do Themida (só nos importamos com VMs no momento):

image

image

image

Após a VM:

image

Executando o Mergen:

image

Código de saída: clique aqui Então, por que nosso resultado não é tão bem-sucedido quanto elevar um binário protegido por VMP?

O Themida escreve ativamente na seção .themida. Ao contrário da pilha, não podemos desconsiderar essas escritas, porque esses valores podem ser lidos por outras coisas posteriormente.

Mas temos uma solução temporária para isso. Remover todos os stores na seção .themida. Como nosso programa não escreve na memória, apenas comentei todos os stores. Agora ficamos com isto:

root@kitploit:~
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 writeonly %memory) local_unnamed_addr #0 {
  %trunc = trunc i64 %r8 to i32
  %trunc1 = trunc i64 %rdx to i32
  %trunc2 = trunc i64 %rcx to i32
  %realadd-5369771371- = add i32 %trunc1, %trunc2
  %realadd-5369582686- = add i32 %realadd-5369771371-, %trunc
  %trunc457139 = zext i32 %realadd-5369582686- to i64
  ret i64 %trunc457139
}

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

Desafios técnicos

  • Loops
  • Código automodificante (especialmente com modificação condicional)
  • Estar em um universo onde passes de "outlining" e "unrolling" não existem.

Como entrar em contato

Junte-se ao nosso Servidor Discord Mergen para trocar ideias ou apenas conversar em geral.

Baixar ferramenta