challenges.re - RE 02#

O Challenges.re é um site com uma compilação de exercícios de Reverse Engineering. Estou escrevendo este documento apenas para meu próprio uso, para praticar meus conhecimentos em programação assembly e engenharia reversa. Se você pretende resolver esses exercícios por conta própria algum dia, por favor, não leia minha solução, tente resolver sozinho. Minha resposta pode estar errada, então não confie em mim, confie no processo.

Pergunta#

Reverse Engineering challenge #2. Tags: . O que esse código faz?

Código Assembly#

Para esclarecer minhas dúvidas sobre este exercício, decidi comentar cada linha com uma descrição mais detalhada.

mov    eax,DWORD PTR [esp+0x4] ; MOVE o valor do endereço ESP+0x4 para EAX                               	
bswap  eax ; 					 Troca a posição dos bytes de um valor, por exemplo: 0x123456 => 0x563412   
mov    edx,eax ; 				 Mover o valor de EAX para EDX                                              
and    eax,0xf0f0f0f ;  		 Faça uma comparação AND com 0x0F0F0F0F e armazene em EAX.                  
and    edx,0xf0f0f0f0 ; 		 Faça uma comparação AND com 0xF0F0F0F0 e armazene no EDX.                  
shr    edx,0x4 ; 				 Desloca o binário de EDX 4 bits para a direita (divida por 16).            
shl    eax,0x4 ; 				 Desloca o binário de EAX 4 bits para a esquerda (multiplique por 2⁴)       
or     eax,edx ; 				 Faça uma comparação OR e armazene em EAX.                                  
mov    edx,eax ; 				 Mover o valor EAX para EDX                                                 
and    eax,0x33333333 ; 		 Faça uma comparação AND e armazene em EAX.                                 
and    edx,0xcccccccc ; 		 Faça uma comparação AND e armazene no EDX.                                 
shr    edx,0x2 ; 				 Desloca o binário de EDX 2 bits para a direita (divida por 4).             
shl    eax,0x2 ; 				 Desloca o binário de EAX 2 bits para a esquerda (multiplique por 2²).      
or     eax,edx ; 				 Faça uma comparação OR e armazene em EAX.                                  
mov    edx,eax ; 				 Mover o valor EAX para EDX                                             
and    eax,0x55555555 ; 		 Faça uma comparação AND e armazene em EAX.                                 
and    edx,0xaaaaaaaa ; 		 Faça uma comparação AND e armazene no EDX.                                 
add    eax,eax ;  				 Adicione EAX com EAX (EAX += EAX || EAX*=2)                                
shr    edx,1 ; 					 Desloque o bit binário de EDX 1 para a direita (divida por 2).             
or     eax,edx ;				 Faça uma comparação OR e armazene em EAX.                                  
ret ;							 Operação de retorno                                                        

Usei o valor 0x123456 como exemplo, pois assim fica mais claro para mim.

Para explicar o que este código faz, vou acompanhar os valores em EAX e EDX e ver como eles mudam. Podemos observar:

; EAX: ; EDX: ;
; function f does a thing 
; And return
mov    eax,DWORD PTR [esp+0x4] 	; MOVE o valor do endereço ESP+0x4 para EAX                               
; EAX: 0x1234; EDX: 0x0;                                                                                               
bswap  eax 						; Troca a posição dos bytes de um valor, por exemplo: 0x123456 => 0x563412
; EAX: 0x3412; EDX: 0x0;                                                                                               
mov    edx,eax 					; Mover o valor de EAX para EDX                                           
; EAX: 0x3412; EDX: 0x3412;                                                                                            
and    eax,0xf0f0f0f 			; Faça uma comparação AND com 0x0F0F0F0F e armazene em EAX.               
; EAX: 0x402; EDX: 0x3412;                                                                                             
and    edx,0xf0f0f0f0 			; Faça uma comparação AND com 0xF0F0F0F0 e armazene no EDX.               
; EAX: 0x402; EDX: 0x3010;                                                                                             
shr    edx,0x4 					; Desloca o binário de EDX 4 bits para a direita (divida por 16).         
; EAX: 0x402; EDX: 0x301;                                                                                              
shl    eax,0x4 					; Desloca o binário de EAX 4 bits para a esquerda (multiplique por 2⁴)    
; EAX: 0x4020; EDX: 0x301;                                                                                             
or     eax,edx 					; Faça uma comparação OR e armazene em EAX.                               
; EAX: 0x4321; EDX: 0x301;                                                                                             
mov    edx,eax 					; Mover o valor EAX para EDX                                              
; EAX: 0x4321; EDX: 0x4321;                                                                                            
and    eax,0x33333333 			; Faça uma comparação AND e armazene em EAX.                              
; EAX: 0x321; EDX: 0x4321;                                                                                             
and    edx,0xcccccccc 			; Faça uma comparação AND e armazene no EDX.                              
; EAX: 0x321; EDX: 0x4000;                                                                                             
shr    edx,0x2 					; Desloca o binário de EDX 2 bits para a direita (divida por 4).          
; EAX: 0x321; EDX: 0x1000;                                                                                             
shl    eax,0x2 					; Desloca o binário de EAX 2 bits para a esquerda (multiplique por 2²).   
; EAX: 0xC84; EDX: 0x1000;                                                                                             
or     eax,edx 					; Faça uma comparação OR e armazene em EAX.                               
; EAX: 0x1C84; EDX: 0x1000;                                                                                            
mov    edx,eax 					; Mover o valor EAX para EDX                                              
; EAX: 0x1C84; EDX: 0x1C84;                                                                                            
and    eax,0x55555555			; Faça uma comparação AND e armazene em EAX.                              
; EAX: 0x1404; EDX: 0x1C84;                                                                                            
and    edx,0xaaaaaaaa 			; Faça uma comparação AND e armazene no EDX.                              
; EAX: 0x1404; EDX: 0x880;                                                                                             
add    eax,eax 					; Adicione EAX com EAX (EAX += EAX || EAX*=2)                             
; EAX: 0x2808; EDX: 0x880;                                                                                             
shr    edx,1 					; Desloque o bit binário de EDX 1 para a direita (divida por 2).          
; EAX: 0x2808; EDX: 0x440;                                                                                             
or     eax,edx 					; Faça uma comparação OR e armazene em EAX.                               
; EAX: 0x2C48; EDX: 0x440;                                                                                             
ret								; Operação de retorno                                                     

Se separarmos as funções deste programa, podemos dividi-lo em duas partes: uma para “inverter” e outra para “embaralhar”:

; EAX: ; EDX: ;
; function f does a thing 
; And return
inverter_os_bytes:
	mov    eax,DWORD PTR [esp+0x4]
	; EAX: 0x1234; EDX: 0x0;
	bswap  eax 
	; EAX: 0x3412; EDX: 0x0;
	mov    edx,eax
	; EAX: 0x3412; EDX: 0x3412;
	and    eax,0xf0f0f0f
	; EAX: 0x402; EDX: 0x3412;
	and    edx,0xf0f0f0f0
	; EAX: 0x402; EDX: 0x3010;
	shr    edx,0x4
	; EAX: 0x402; EDX: 0x301;
	shl    eax,0x4
	; EAX: 0x4020; EDX: 0x301;
	or     eax,edx
	; EAX: 0x4321; EDX: 0x301;

embaralhar:
	mov    edx,eax
	; EAX: 0x4321; EDX: 0x4321;
	and    eax,0x33333333
	; EAX: 0x321; EDX: 0x4321;
	and    edx,0xcccccccc
	; EAX: 0x321; EDX: 0x4000;
	shr    edx,0x2
	; EAX: 0x321; EDX: 0x1000;
	shl    eax,0x2
	; EAX: 0xC84; EDX: 0x1000;
	or     eax,edx
	; EAX: 0x1C84; EDX: 0x1000;
	mov    edx,eax
	; EAX: 0x1C84; EDX: 0x1C84;
	and    eax,0x55555555
	; EAX: 0x1404; EDX: 0x1C84;
	and    edx,0xaaaaaaaa
	; EAX: 0x1404; EDX: 0x880;
	add    eax,eax
	; EAX: 0x2808; EDX: 0x880;
	shr    edx,1
	; EAX: 0x2808; EDX: 0x440;
	or     eax,edx
	; EAX: 0x2C48; EDX: 0x440;
	ret

O que este código faz:#

Esta função recebe uma mensagem do ESP (Stack Pointer) + 0x4, inverte os bytes e realiza uma operação AND com os bits pares e ímpares. Isso embaralha a mensagem.

Mas, ao inserir a mensagem embaralhada na função, ela será reembaralhada para a mensagem original. Semelhante a um XOR.

Exemplo:

input: 0x1234 => output: 0x2C48
input: 0x2C48 => output: 0x1234