Traduzindo para C essa função, teriamos algo assim:
int ispresent(){int pval;if(ptrace(PTRACE_TRACEME,0,1,0)==0xffffffff)
printf("Não vai nem me pagar uma cerveja\n");
pval =1;else
pval =0;return pval;}
PTRACE_TRACEME - Indicate that this process is to be traced by its parent RETURN VALUE - On error, all requests return -1, and errno is set appropriately
Quando utilizamos a função ptrace() com o request PTRACE_TRACEME, os valores de pid_t pid, void *addr e void *data são ignorados, portanto os valores utilizados na função poderiam ser qualquer um ?
2- algoritmo, nadaaqui() - Onde a mágica acontece ?️♂️
Tentando ser o mais sucinto possível, o programa armazena em um float o valor 720300.0 e divide esse valor (incial) e o resultado subsequente por cada "numero" enviado pelo usuário.
A atribuição de key pode ter sido feita de diversas formas no código original, no exemplo acima utilizei -48 por conta dos caracteres que são enviados no userInput.
Um observação importante é que o programa só aceita números 0-9, portanto como o que é enviado é um char teriamos de acordo com a tabela ASCII:
Acredito que na implementação original o autor utilizou isdigit() (ctype.h) para fazer essa verificação.
0x000006bc<+93>: call 0x470<__ctype_b_loc@plt>
De qualquer forma, se enviarmos 0 como char ele seria 48 em decimal, então 48-48 = 0. No código, val = val / (long double)0;
Caso enviassemos 1 como char, seria 49, então 49-48 = 1. No código, val = val / (long double)1;
Deu para entender a idéia.
3- main()
Como tinha comentado, o código é bem simples e main() executa algumas funções.
1- Verifica se o programa está sendo debugado (Pode deixar que eu pago a breja :D)
2- Verifica se a sequência digitada contém caracteres inválidos (Somente números são permitidos).
3- Verifica se o resultado de nadaaqui() == 1.0, sendo assim, a chave é validada ou não.
Compilado com a flag: -lm (obrigatória por conta do roundf())
Algumas considerações sobre o keygen:
Para ganhos de performance, utilizei um seed de nanoseconds para o rand() gerar números aleatórios entre 2 e 7 e utilizar como userInput, visto que divisões por 0 daria inf e por ´1 daria o mesmo número. As divisões por 8 e 9 nunca resultariam em um resultado sem dízima portando inválidos. Com certeza existe uma outra forma de fazer esse cálculo mas não atrapalhou no resultado final.
Mais um Crackme
em Desafios e CTF
Postado · Editado por ipax
Opa, muito interessante a iniciativa, obrigado por ter compartilhado ?
Como já tem um tempinho que postou e ninguém respondeu, tirei uns minutinhos agora pela manha para analisar e resolver.
O crackme é bem simples e consiste de 2 funções principais (anti-debug e o algoritmo em si).
1- anti-debug, ispresent() com a função ptrace().
Traduzindo para C essa função, teriamos algo assim:
PTRACE_TRACEME - Indicate that this process is to be traced by its parent
RETURN VALUE - On error, all requests return -1, and errno is set appropriately
Quando utilizamos a função ptrace() com o request PTRACE_TRACEME, os valores de pid_t pid, void *addr e void *data são ignorados, portanto os valores utilizados na função poderiam ser qualquer um ?
2- algoritmo, nadaaqui() - Onde a mágica acontece ?️♂️
Tentando ser o mais sucinto possível, o programa armazena em um float o valor 720300.0 e divide esse valor (incial) e o resultado subsequente por cada "numero" enviado pelo usuário.
Em C seria mais ou menos assim:
A atribuição de key pode ter sido feita de diversas formas no código original, no exemplo acima utilizei -48 por conta dos caracteres que são enviados no userInput.
Um observação importante é que o programa só aceita números 0-9, portanto como o que é enviado é um char teriamos de acordo com a tabela ASCII:
Acredito que na implementação original o autor utilizou isdigit() (ctype.h) para fazer essa verificação.
De qualquer forma, se enviarmos 0 como char ele seria 48 em decimal, então 48-48 = 0. No código, val = val / (long double)0;
Caso enviassemos 1 como char, seria 49, então 49-48 = 1. No código, val = val / (long double)1;
Deu para entender a idéia.
3- main()
Como tinha comentado, o código é bem simples e main() executa algumas funções.
1- Verifica se o programa está sendo debugado (Pode deixar que eu pago a breja :D)
2- Verifica se a sequência digitada contém caracteres inválidos (Somente números são permitidos).
3- Verifica se o resultado de nadaaqui() == 1.0, sendo assim, a chave é validada ou não.
Com isso essa lógica em mente, escrevi o keygen ?:
Compilado com a flag: -lm (obrigatória por conta do roundf())
Algumas considerações sobre o keygen:
Para ganhos de performance, utilizei um seed de nanoseconds para o rand() gerar números aleatórios entre 2 e 7 e utilizar como userInput, visto que divisões por 0 daria inf e por ´1 daria o mesmo número. As divisões por 8 e 9 nunca resultariam em um resultado sem dízima portando inválidos. Com certeza existe uma outra forma de fazer esse cálculo mas não atrapalhou no resultado final.
ipax@core:~/crackme$ ./mbin-hehe-keygen
Key: 523257777
ipax@core:~/crackme$ ./hehe 523257777
Isso aí!! A chave é válida!
?♂️
Como uma brincadeira extra, tentei gerar uma lista das combinações ou keys possíveis e cheguei ao número de 5338.
Muito divertido e como falei, obrigado por compartilhar.
Envie mais! ?