// 03 iniciante inverter jump condicional

Inverter
Jump

A lógica está certa. O portão está virado. Um byte resolve tudo.

Sistema de ativação. Código de 8 dígitos. Você não tem o código. E não precisa ter.

No desafio #02 você aprendeu a mentir dentro da função. Desta vez, a função está certa — ela valida direito. O problema está em quem interpreta o resultado.

~/cracklab/03-inverter-jump
$ ./challenge
=========================================
SISTEMA DE ATIVACAO v1.0
=========================================
Insira o codigo de ativacao (8 digitos): 12345678
[X] Codigo invalido. Tente novamente.
// conceitos necessários
JE — jump if equal
Opcode 74. Pula para outro endereço quando ZF=1 (resultado anterior foi zero). Usado após test eax, eax quando função retorna 0.
JNE — jump if not equal
Opcode 75. Pula quando ZF=0 (resultado foi diferente de zero). Exatamente o oposto do je — diferem por apenas 1 bit.
zero flag (ZF)
test eax, eax faz AND lógico de eax com si mesmo. Se eax=0, seta ZF=1. Os jumps condicionais leem esse flag pra decidir se pulam.

Abre o disassembly do main.
Procura o call validate_code.
O que vem logo depois? Se o resultado é 0 (inválido), o programa pula pra onde?
E se você fizesse ele pular pro lado errado?

// solução passo a passo
01
Localiza o ponto de decisão no main
bash
objdump -d ./challenge | grep -A 10 "call.*validate_code"
Você vai ver:
asm
4012bc:  e8 f5 fe ff ff   call  4011b6 <validate_code>
4012c1:  85 c0            test  %eax, %eax         ; eax = retorno (0 ou 1)
4012c3:  74 2f            je    4012f4             ; se 0 (inválido) → pula pro erro
4012c5:  ...                                          ; senão → conteúdo válido

O je em 0x4012c3 é o portão.
Se validate_code retorna 0, ZF=1, e je pula pro bloco de erro.
Se retorna 1, não pula — cai no bloco de sucesso.

A função está correta. Só o portão está do lado errado.

02
A inversão — um byte
74 = je (pula se zero) → 75 = jne (pula se não-zero). Diferem por exatamente 1 bit.
// o que a troca de um byte faz
validate_code("12345678") → retorna 0 (código inválido)

antes (je):
  test eax, eax   → ZF = 1
  74 2f           → je → ZF=1, PULA → erro

depois (jne):
  test eax, eax   → ZF = 1
  75 2f           → jne → ZF=1, NÃO PULA → sucesso ✓
03
Confirma o byte e aplica o patch
bash
# confirma o byte atual
objdump -d ./challenge | grep "4012c3"
# esperado: 4012c3:  74 2f   je  4012f4
radare2
r2 -w ./challenge
s 0x4012c3
wx 75           ; só o opcode — offset 2f não muda
q
Alternativa sem radare2 — com dd direto:
bash — sem radare2
# patch com printf + dd (funciona sem nenhuma ferramenta extra)
printf '\x75' | dd of=./challenge bs=1 seek=$((0x4012c3)) conv=notrunc 2>/dev/null
04
Verifica e roda
bash
# verifica: deve mostrar jne agora
objdump -d ./challenge | grep "4012c3"
# 4012c3:  75 2f   jne  4012f4
~/cracklab/03-inverter-jump $ ./challenge
Insira o codigo de ativacao (8 digitos): 00000000
[OK] Codigo valido. Sistema ativado.
// cola rápida — jumps condicionais
instruçãoopcodepula quandopar oposto
je74ZF=1 (igual / zero)jne (75)
jne75ZF=0 (diferente / não-zero)je (74)
jl7CSF≠OF (menor, signed)jge (7D)
jge7DSF=OF (maior ou igual)jl (7C)
jle7EZF=1 ou SF≠OFjg (7F)
jg7FZF=0 e SF=OFjle (7E)

Cada par de opostos difere por 1 bit no opcode. 7475 é literalmente um toggle de bit.

// variações pra explorar
métodoondeo que faz
je → jne0x4012c3 — mainUm byte. Portão invertido. A solução mais limpa.
patch em validate_code0x401245 — funçãoTroca sete por setne: retorna 1 pra qualquer coisa que não seja o código correto.
NOP no exit0x401326 — main5 NOPs no call de exit(1). Funciona mas output mostra erro. Feio.

Qual dessas três abordagens (je→jne, patch na função, NOP no exit) deixaria menos rastro numa análise forense do binário?