Em um belo dia, diferentes canais do
telegrama começaram a fornecer um
link para o crackmix da LK.
Aqueles que concluíram a tarefa com sucesso serão convidados para uma entrevista! . Depois de uma declaração tão alta, imaginei o quão difícil seria o contrário. Como eu resolvi essa tarefa pode ser lido abaixo do corte (muitas fotos).
Chegando em casa, reli cuidadosamente a tarefa, baixei o arquivo e comecei a ver o que havia dentro. E dentro estava:

Começamos x64dbg, despejo após descompactar, olha o que realmente está dentro:


Pegamos o nome do arquivo nos argumentos da linha de comando -> abrir, ler -> criptografar o primeiro passo -> criptografar o segundo passo -> gravar em um novo arquivo.
É simples, é hora de analisar a criptografia.
Vamos começar com o stage1
No endereço 0x4033f4, existe uma função que chamei de crypt_64bit_up (mais tarde você entenderá o porquê), que é chamada de um loop em algum lugar dentro do stage1

E um resultado de descompilação um pouco torto

No começo, tentei reescrever o mesmo algoritmo em python, o matei por várias horas e resultou em algo assim (o que get_dword e byteswap devem estar claros nos nomes)
def _add(x1, x2): return (x1+x2) & 0xFFFFFFFF def get_buf_val(t, buffer): t_0 = t & 0xFF t_1 = (t >> 8) & 0xFF t_2 = (t >> 16) & 0xFF t_3 = (t >> 24) & 0xFF res = _add(get_dword(buffer, t_0 + 0x312), (get_dword(buffer, t_1 + 0x212) ^ _add(get_dword(buffer, t_2+0x112), get_dword(buffer, t_3+0x12))))
Mas então eu decidi prestar atenção nas constantes 0x12, 0x112, 0x212, 0x312 (sem hexadecimal 18, 274, 536 ... não muito parecido com algo incomum). Tentamos pesquisá-los no Google e encontrar um repositório inteiro (dica: NTR) com a implementação das funções de criptografia e
descriptografia , isso é boa sorte. Tentamos criptografar um arquivo de teste com conteúdo aleatório no programa original, despejá-lo e criptografar o mesmo arquivo com um pequeno script, tudo deve funcionar e os resultados devem ser os mesmos. Depois disso, tentamos descriptografá-lo (decidi não entrar em detalhes e apenas copiar e colar a função de descriptografia da fonte)
def crypt_64bit_down(initials, keybuf): x = initials[0] y = initials[1] for i in range(0x11, 1, -1): z = get_dword(keybuf, i) ^ x x = get_buf_val(z, keybuf) x = y ^ x y = z res_0 = x ^ get_dword(keybuf, 0x01)
Nota importante: a chave no repositório é diferente da chave no programa (o que é bastante lógico). Portanto, depois que a chave é inicializada, eu a despejo em um arquivo, isso é buffer / keybuf
Passamos para a segunda parte
Tudo é muito mais simples aqui: primeiro, uma matriz de caracteres únicos é criada com tamanho 0x55 bytes no intervalo (33, 118) (caracteres imprimíveis) e, em seguida, o valor de 32 bits é compactado em 5 caracteres imprimíveis da matriz criada anteriormente.


Como não há aleatoriedade ao criar a matriz mencionada acima, toda vez que o programa for iniciado, essa matriz será a mesma, despejamos após a inicialização e podemos descompactar stage_2 com uma função simples
def stage2_unpack(packed_data, state):
Fazemos algo assim:
f = open('stage1.state.bin', 'rb') stage1 = f.read() f.close() f = open('stage2.state.bin', 'rb') stage2 = f.read() f.close() f = open('rprotected.dat', 'rb') packed = f.read() f.close() unpacked_from_2 = stage2_unpack(packed, stage2) f = open('unpacked_from_2', 'wb') f.write(unpacked_from_2) f.close() unpacked_from_1 = stage1_unpack(unpacked_from_2, stage1) f = open('unpacked_from_1', 'wb') f.write(unpacked_from_1) f.close()
E nós obtemos o resultado
