sergio-echigo/malware_analysis_cp1

GitHub: sergio-echigo/malware_analysis_cp1

Stars: 0 | Forks: 0

# Análise inicial do programa A princípio, logo após a execução do programa, pôde-se perceber que ele se baseia na entrada de valores válidos para o nome de usuário e para a senha, "username" e "password", respectivamente. Logo de cara deve-se dar entrada ao nome de usuário e a senha, no entanto, percebe-se que desde que o nome de usuário esteja incorreto, a execução do programa é finalizada. Portanto, o primeiro passo para se obter as credenciais válidas é obtendo algum nome de usuário válido. A primeira coisa a ser feita foi buscar referências textuais (strings) que condiziam com a mensagem de erro referente ao nome de usuário inválido, que é "Pay attention to the username." ![Incorrect username](https://static.pigsec.cn/wp-content/uploads/repos/2026/06/ed6b1e8d36005547.png) Além dessa referência encontrada, é importante notar que outras referências textuais existem e que estas condizem com a lógica até agora encontrada, que é a entrada dos dados, a validação do nome de usuário, a finalização ou continuação do programa — a depender da validade do nome de usuário —, a validação da senha e a mensagem de sucesso ou de erro conforme os dados encontrados. ![Input and output code.](https://static.pigsec.cn/wp-content/uploads/repos/2026/06/853001f6a5005547.png) ![Input code](https://static.pigsec.cn/wp-content/uploads/repos/2026/06/15535999fe005548.png) ## Validação do nome de usuário Após uma série de *breakpoints* criados e uma longa depuração do código em assembly, pôde-se mapear as seguintes instruções, que se referem à saída e a entrada de dados do programa: ![Username validation](https://static.pigsec.cn/wp-content/uploads/repos/2026/06/6279248041005549.png) Na imagem é possível observar uma série de comentários que foram adicionados para facilitar o entendimento do código, além da adição de *labels* para o entendimento de algumas funções — como **OutputFunction** e **InputFunction**. Ademais percebe-se uma condição um tanto quanto especial, que faz com que a mensagem referente a um nome de usuário inválido seja mostrada na tela, que é a seguinte: je 2tdcg.cp01.thestartpoint.351301 A condição *je* executa um *jump* para determinado endereço desde que a *flag* **ZF** seja 1. No geral, *jumps* condicionais são executados logo após a execução de instruções de comparação de determinados valores, que é o que ocorre durante a seguinte instrução: cmp dword ptr ss:[ebp-30],B A instrução acima realiza uma comparação entre dois argumentos — mais especificamente, uma subtração — e atribui valor 1 para a *flag* **ZF** caso o resultado da comparação seja zero. Portanto, aqui pode-se determinar que os valores comparados devem ser iguais e dessa forma, o nome de usuário estará sendo validado corretamente. No entanto, o que significa o primeiro operando? ;dword significa double word, equivalente a 32 bits (quatro bytes). ;ptr significa que é um endereço na memória. ;ss:[ebp-30] significa um endereço da stack. Procurando por referências dele, a única coisa que se encontra é que, antes de todo esse esquema de saída e entrada de valores começar, é atribuído um valor de zero a ele. Observando mais a fundo, assim como é mostrado no vídeo abaixo, percebe-se que o valor no endereço de memória indicado é sempre igual ao comprimento do nome de usuário. https://youtu.be/L2MYrhpcdyU Sendo assim, conclui-se que o nome de usuário deve ter um comprimento de **B** — onze, em decimal. A prova real vem a seguir: https://youtu.be/IFVBfQHiyf8 Agora, deve-se buscar uma senha válida. ## Validação da senha Mais uma vez é possível encontrar diversos saltos condicionais, logo após a execução de inúmeras outras instruções que felizmente não redirecionam a execução do programa para mais nenhum lugar — se isso ocorresse, e durante esses outros lugares existissem mais redirecionamentos, o código ficaria um tanto quanto complicado de se seguir, ou pelo menos é o que se pensa de antemão. Enfim, tais saltos condicionais são responsáveis por fazer com que a aplicação indique que a senha entregue é inválida. Dessa forma, deve-se analisar cada um deles para que se possa validar corretamente a senha dada. ### Condição 1 A primeira instrução que poderia modificar o valor da *flag* **ZF** e fazer com que o salto condicional ocorresse — ou não — é a seguinte: test eax, eax Essa instrução realiza uma operação *bitwise* **AND** entre dois valores. A operação **AND** pode ser vista como uma comparação de cada bit de determinado valor; para cada bit, se os dois têm valor igual a 1, o resultado da operação é 1; caso contrário, se pelo menos um dos valores for zero, o resultado é zero. Durante a instrução **test**, o valor zero é atribuído para a *flag* **ZF** quando o resultado da operação é diferente de zero. Portanto, pode-se descrever a seguinte "tabela-verdade": | eax & eax | ZF | | :-------: | :-: | | 0 | 1 | | ~0 | 0 | Por isso, deve-se fazer com que o valor de **eax** seja diferente de zero, o que já acontece por padrão, afinal, o valor de **eax** nesse ponto de execução da aplicação está sendo igual ao comprimento do valor da senha. Por isso essa condição não influencia de forma alguma a validação da senha — a não ser que de alguma forma algum valor vazio fosse *inputado*. ![First condition.](https://static.pigsec.cn/wp-content/uploads/repos/2026/06/2cb916204e005549.png) ### Condição 2 A próxima condição encontrada é idêntica a de cima, exceto pelo valor de **eax**, que é calculado de forma um pouco mais complicada. Fazendo uma análise profunda do que está acontecendo no código, percebe-se que, a depender dos dados que se coloque, o valor zero é atribuído a **eax**, e então, durante a instrução `test eax, eax`, a *flag* **ZF** possui valor zero, o que faz com que a senha seja dada como inválida. O seguinte trecho do código em **assembly** demonstra a atribuição implícita de valor para o registrador **eax**: ![Second condition.](https://static.pigsec.cn/wp-content/uploads/repos/2026/06/3a6b6af64e005551.png) É exatamente durante a execução da instrução `call ` que o valor de **eax** muda para determinados valores de entrada para o nome de usuário e para a senha. Com um pouco de pesquisa, nota-se que essa instrução chama uma função nativa de **C/C++**, que é a `memchr`. Essa função é responsável por retornar um ponteiro para o endereço de memória no qual um determinado caractere é encontrado numa *string*, ou também, um endereço de memória. A seguinte definição é encontrada na linguagem **C**, por exemplo: void *memchr(const void *str, int c, size_t n) Brevemente nota-se que os seguintes parâmetros estão presentes: o endereço de memória `str` para se buscar o caractere `c`, limitando-se a `n` caracteres desde o início do endereço de memória `str`. Novamente analisando o código em **assembly**, percebe-se que três valores bem específicos são adicionados ao topo da *stack*, respectivamente: - Um inteiro; - Um inteiro positivo, que, no entanto, sempre representa um caractere válido em **ASCII**; - Uma *string*. Associando tais valores, *debugando* o código e fazendo o entendimento dele, percebe-se que esses valores se referem ao comprimento da senha, o caractere a se buscar, e a *string* (senha) em si. Mais uma vez *debugando* o código, pode-se perceber que essa repetição ocorre num máximo de três vezes, testando valores bem específicos, que são: o terceiro, quinto e último caracteres do nome de usuário, e a senha em si. Portanto, pôde-se determinar que esses caracteres devem estar presentes na senha, pois caso contrário, **eax** tem seu valor zerado e a senha é determinada como inválida. O seguinte mapeamento de dados adicionados a *stack* auxiliam na análise desse comportamento: ==== REPRESENTAÇÃO 1 ==== Username: 01234567890 Password: 234567890 0x9 0x32 ('2') 0093F778 ("234567890") Portanto, EAX=0093F778 ("234567890") E, ESP=0093F73C 0x9 0x34 ('4') 0093F778 ("234567890") Portanto, EAX=0093F77A ("4567890") E, ESP=0093F73C 0x9 0x30 ('0') 0093F778 ("234567890") Portanto, EAX=0093F780 E, ESP=0093F73C ==== REPRESENTAÇÃO 2 ==== Username: 01234567890 Password: VITOR 0x5 0x32 ('2') ("VITOR") Portanto, EAX=0 Aqui Desde que se faça isso, a senha ainda é considerada válida e o código avança. Alguns *jumps* condicionais são ignorados, e logo a próxima condição para a validação da senha é encontrada. ### Condição 3 Apesar das duas condições anteriores levarem a saltos condicionais que iriam indicar uma senha inválida, esta terceira é responsável justamente por fazer com que a senha seja validada como correta. E a seguinte linha do código demonstra isso: cmova eax,esi cmp byte ptr ds:[eax+3],2D je 2tdcg.cp01.thestartpoint.1E13A7 Considerando que o valor do registrador **esi** é a senha, nota-se que o novo valor de **eax** agora é a própria senha. Finalmente, se compara o quarto caractere da senha — o que indica que pelo menos quatro caracteres são requeridos para a senha — com o hexadecimal **0x2D**, que representa, na tabela **ASCII**, o caractere **-**. Portanto, o quarto caractere deve ser um hífen. A seguinte imagem demonstra a validação dos dados indicados: ![Fourth valid character.](https://static.pigsec.cn/wp-content/uploads/repos/2026/06/dfdfaa144f005551.png) E com isso, pode-se pegar um nome de usuário e senha válidos. Contudo, analisando o restante do código em **assembly**, percebe-se que há, também, outra condição para a geração de uma senha válida: que o nono caractere seja igual a um hífen, assim como a possibilidade do terceiro ser. A seguinte imagem também demonstra isso: ![Ninth valid character.](https://static.pigsec.cn/wp-content/uploads/repos/2026/06/b060514f91005552.png) ## Conclusão Dito tudo isso, pode-se descrever as seguintes condições para a escolha de um nome de usuário e senha válidos: - O nome de usuário **deve** possuir exatamente onze caracteres. - A senha **deve** conter o terceiro, quinto e último caracteres do nome de usuário. - O quarto caractere ou o nono caractere da senha deve ser um hífen. Alguns dados válidos são: - 01234567890,240- - VITOR_VITOR,TRpAAAAA- - rm988248901,ma933801- ![Valid credentials.](https://static.pigsec.cn/wp-content/uploads/repos/2026/06/86f3f9e654005553.png) RM98824