Extraia a Chave XOR: Engenharia Reversa de uma Checagem de Licença em C
O desafio
Este keygen em C lê um número de série, aplica XOR em cada byte com um segredo embutido e compara o resultado a um alvo. Leia o laço de validação, descubra qual string é usada como chave XOR e digite-a exatamente.
O que você vai aprender
- Ler um laço de validação em C e identificar a etapa de XOR byte a byte
- Reconhecer uma string literal embutida usada como chave criptográfica
- Entender por que o XOR é reversível e como recuperar a entrada original
- Explicar por que segredos embutidos em um binário cliente não são secretos
- Distinguir ofuscação de proteção criptográfica real
Habilidades testadas
Pré-requisitos
- Sintaxe básica de C (arrays, laços, ponteiros)
- O que o operador XOR (^) faz
- Bytes e ASCII
Como funciona
Muitas checagens de licença tentam esconder o serial válido atrás de uma transformação. Uma comum é o XOR: cada byte da entrada do usuário recebe XOR com um byte de chave, e o resultado é comparado a uma tabela pré-computada. O XOR é atraente porque é rápido e simétrico, mas essa simetria é exatamente o motivo pelo qual ele falha como proteção - a mesma operação que embaralha os dados também os desembaralha.
Em keygen.c, check_serial declara const char *key = "K3yR3v" e percorre o serial, calculando serial[i] ^ key[i % klen] e comparando cada resultado a expected[i]. Tudo o que a checagem precisa está no binário: a string da chave, a tabela esperada e o algoritmo. Como (serial ^ key) == expected implica serial == expected ^ key, um atacante lê a chave direto no código-fonte e calcula instantaneamente um serial válido - sem precisar de força bruta.
A lição para engenharia reversa é que a resposta está à vista, como uma string literal. O desafio é reconhecer que o operando do XOR no laço é a chave, não a tabela expected (que é o alvo) nem o serial (que é a entrada do atacante). A chave aqui é K3yR3v.
Erros comuns
- Enviar os bytes de expected[]. Essa tabela é o alvo com o qual o resultado do XOR é comparado, não a chave.
- Procurar a chave em main(). A chave é uma variável local em
check_serial;mainapenas lê o argv e imprime o veredito. - Supor que a chave é aleatória ou derivada. Ela é uma string literal simples embutida no código-fonte.
- Confundir o serial com a chave. O serial é a entrada do atacante (argv[1]); a chave é a constante contra a qual ele recebe XOR.
Como se proteger
XOR no lado do cliente é ofuscação, não segurança. Qualquer pessoa com o binário pode ler a chave. Não confie em uma constante escondida para proteger licenciamento ou segredos.
- Valide licenças no lado do servidor, onde o segredo e a checagem nunca chegam ao usuário.
- Se precisar verificar localmente, use tokens assinados (criptografia assimétrica) para que o cliente tenha apenas uma chave pública e não consiga forjar serials válidos.
- Nunca armazene chaves de API ou chaves de assinatura como strings literais em texto puro no código distribuído.
- Trate qualquer coisa compilada em um cliente como totalmente legível por um atacante.