Fernando Mercês Posted September 30, 2018 at 04:35 AM Share Posted September 30, 2018 at 04:35 AM Não é exatamente um desafio, mas este pequeno programa foi usado para exemplificar o assunto de strings ofuscadas na aula 23 do CERO e queria postá-lo aqui. O lance é entender por que a string não aparece na análise estática. Bem básico, mas é a proposta do CERO mesmo. ? cade.exe Quote Link to comment Share on other sites More sharing options...
Hakuoo Posted January 16, 2021 at 06:08 PM Share Posted January 16, 2021 at 06:08 PM Em 30/09/2018 em 05:35, Fernando Mercês disse: Não é exatamente um desafio, mas este pequeno programa foi usado para exemplificar o assunto de strings ofuscadas na aula 23 do CERO e queria postá-lo aqui. O lance é entender por que a string não aparece na análise estática. Bem básico, mas é a proposta do CERO mesmo. ? cade.exe Olá criador do desafio, Vamos a nossa analise: 1º Parte Quando encontramos o EntryPoint a parte que mais chama a atenção é a seguinte: mov dword ptr [esp+1Ch], 6A645B63h ; Char 1 mov dword ptr [esp+20h], 645F585Bh ; Char 2 mov dword ptr [esp+24h], 575F6857h ; Char 3 mov dword ptr [esp+28h], 63655924h ; Char 4 mov dword ptr [esp+2Ch], 685824h ; Char 5 Nesse caso temos alguns valores sendo movidos para algumas posições da memória indicadas por ESP +offset, e colados lá, isso é caracteristica de um array, ou da instrução strcpy. 2º Vamos organizar isso e tentar encaixar na instrução do strcpy, ficará da seguinte forma: int main(int argc, char** argv) { char buffer[20]; /* mov dword ptr [esp+1Ch], 6A645B63h ; Char 1 mov dword ptr [esp+20h], 645F585Bh ; Char 2 mov dword ptr [esp+24h], 575F6857h ; Char 3 mov dword ptr [esp+28h], 63655924h ; Char 4 mov dword ptr [esp+2Ch], 685824h ; Char 5 ESP[0] = 6A645B63h; ESP[1] = 645F585Bh; ESP[2] = 575F6857h; ESP[3] = 63655924h; ESP[4] = 685824h; Simplificando: strcpy(ESP, "c[dj[X_dWh_W$Yec$Xh") */ strcpy(buffer, "c[dj[X_dWh_W$Yec$Xh"); } Interessante temos um buffer sendo alimentado por uma string aparentemente ofuscada e convertida do hexadecimal para o ASCII. 3º Vamos entender mais um pouco de como é feito essa chamada lea eax, [esp+1Ch] ; copia o endereço de uma posição para EAX mov [esp], eax ; move o conteúdo do endereço pego para ESP call DecriptStr ; chama uma call para um função mov [esp], eax ; retorno da call ! Todas calls costumam retornam em EAX nosso peseudocódigo ficará da seguinte forma: DecriptStr([ESP]); Legal, temos um ponteiro de um char sendo movido para uma função ? sim. Veja a reescrita disso com as informações que já temos: int main(int argc, char** argv) { // Nova adição, para receber o retorno de EAX const char* escrever; char buffer[20]; /* mov dword ptr [esp+1Ch], 6A645B63h ; Char 1 mov dword ptr [esp+20h], 645F585Bh ; Char 2 mov dword ptr [esp+24h], 575F6857h ; Char 3 mov dword ptr [esp+28h], 63655924h ; Char 4 mov dword ptr [esp+2Ch], 685824h ; Char 5 ESP[0] = 6A645B63h; ESP[1] = 645F585Bh; ESP[2] = 575F6857h; ESP[3] = 63655924h; ESP[4] = 685824h; Simplificando: strcpy(ESP, "c[dj[X_dWh_W$Yec$Xh") */ strcpy(buffer, "c[dj[X_dWh_W$Yec$Xh"); // nova adição escrever = DecriptStr(buffer); // Simplificamos os detalhes, então a call é efetuada o retorno volta em EAX e volta a "referência" para um endereço. } 4º Nosso código está ficando bacana, vamos prestar mais atenção nos próximos detalhes abaixo disso: call _puts ; Chama a função puts para escrever nosso retorno mov eax, 0 ; Lembra da dica de retorno da função ? sim, nosso main também é uma subcall e ele vai retornar 0 Pseudocode: puts(escrever); return 0; 5º Vamos reescrever isso agora no código que já entendemos. int main(int argc, char** argv) { const char* escrever; char buffer[20]; /* mov dword ptr [esp+1Ch], 6A645B63h ; Char 1 mov dword ptr [esp+20h], 645F585Bh ; Char 2 mov dword ptr [esp+24h], 575F6857h ; Char 3 mov dword ptr [esp+28h], 63655924h ; Char 4 mov dword ptr [esp+2Ch], 685824h ; Char 5 ESP[0] = 6A645B63h; ESP[1] = 645F585Bh; ESP[2] = 575F6857h; ESP[3] = 63655924h; ESP[4] = 685824h; Simplificando: strcpy(ESP, "c[dj[X_dWh_W$Yec$Xh") */ strcpy(buffer, "c[dj[X_dWh_W$Yec$Xh"); escrever = DecriptStr(buffer); puts(escrever); return 0; } Dando continuidade com nossa reconstrução e agilizando o processo, analisei a função de DecriptStr e ficou da seguinte forma: char* DecriptStr(char *stringOfuscada){ char *armazenaLocal; armazenaLocal = stringOfuscada; while(*stringOfuscada) *stringOfuscada++ += 10; return armazenaLocal; } Esse é o algoritmo usado para ocultar as strings do Debugger, basicamente, é relativamente simples esconder alguma string do debbuger, por esse fato devemos também ficar atento no que acontece no algoritmo do mesmo verificar se temos argumentos suspeitos sendo passados. Conclusão: Esse tipo de algoritmo é muito comum em malwares como o bom e velho XOR, porem são muito utilizados em diversos software que você encontrar durante sua analise, fique atento a isso ! E para o fim temos o resultado: Obrigado pela sua Leitura, e espero que isso tenha sido útil para alguém ! Saudações a todos. CADE_Algoritimo.zip 1 Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.