Análisis de malware

Comprender las declaraciones if en C

noviembre 5, por Srinivas

Las declaraciones «If» en la programación C se utilizan para ejecutar un bloque de declaraciones si una determinada condición es verdadera. Permiten a los programadores controlar la ejecución del código y permiten que las entradas del usuario dirijan las acciones del programa, lo que agrega flexibilidad a los programas. Las declaraciones «If» se utilizan en situaciones de seguridad que requieren credenciales de inicio de sesión. Si las credenciales coinciden con la base de datos de ese usuario, se le concede acceso al usuario. Si las credenciales no coinciden, el usuario es rechazado.

Cuando se trata de ingeniería inversa, las declaraciones «si» se ven con mucha frecuencia al analizar archivos binarios. La mayoría de los programas de malware utilizan declaraciones «si» para tomar decisiones basadas en una condición. Por ejemplo, un autor de malware puede utilizar una declaración «if» para detener la ejecución del binario si se le adjunta un depurador.

¡Conviértete en un ingeniero inverso certificado!

Obtenga capacitación práctica en vivo sobre análisis de malware desde cualquier lugar y conviértase en un analista certificado de ingeniería inversa. Comienza a aprender

Ser capaz de detectar declaraciones «si» en el ensamblaje es una habilidad imprescindible para un ingeniero inverso. En este artículo, discutiremos cómo se pueden detectar declaraciones «si» al invertir un binario.

Identificar declaraciones «si»

Las declaraciones «si» están escritas en una sintaxis simple o anidada.

Declaraciones -if simples

El fragmento de código muestra el uso de una declaración «if» en la programación en C.

#incluir stdio.h

vacío principal()

{

int a = 30;

int b =/p>

si (a b){

printf(«a es mayor que bn»);

}

demás{

printf(«b es mayor que an»);

}

}

Cuando se compila el código y se abre el binario usando un depurador (OllyDbg en este caso), se muestran los siguientes resultados.

EMPUJAR EBP

MOV EBP ESP

Y ESP,FFFFFFFF0

SUBESP,p>

LLAMAR si.004015F0

MOV DWORD PTR SS:[ESP+1C],1E

MOV DWORD PTR SS:[ESP+18],14 ; |

MOV EAX,DWORD PTR SS:[ESP+1C] ; |

CMP EAX,DWORD PTR SS:[ESP+18] ; |

JLE CORTO si.00401546 ; |

MOV DWORD PTR SS:[ESP],if.00404000 ; |ASCII «a es mayor que b»

CALL JMP.msvcrt.puts ; pone

JMP CORTO si.00401552

MOV DWORD PTR SS:[ESP],if.00404014 ; |ASCII «b es mayor que a»

CALL JMP.msvcrt.puts ; pone

NOP

DEJAR

RETENIR

El salto condicional JLE aparece arriba. Está presente para decidir si tomar la sucursal o no. Este salto condicional está precedido por una instrucción CMP. La condición depende del resultado de la instrucción CMP.

El valor hexadecimal 1E se empuja a la pila y luego el valor hexadecimal 14 se empuja a la pila siguiendo las siguientes instrucciones.

MOV DWORD PTR SS:[ESP+1C],1E MOV DWORD PTR SS:[ESP+18],14

Los valores hexadecimales 1E y 14 se traducen en decimales 30 yespectivamente. Estos dos valores se insertan en la pila y las direcciones de la pila hacen referencia a ellos porque se usan con variables locales.

El valor hexadecimal 1E se mueve al registro EAX usando las siguientes instrucciones. El valor almacenado en el registro EAX se utilizará como primer argumento en la instrucción CMP.

MOV EAX,DWORD PTR SS:[ESP+1C]

La siguiente instrucción se ejecuta a continuación para comparar los dos valores.

CMP EAX,DWORD PTR SS:[ESP+18]

El EAX tiene el valor 30 y [ESP+18] se refiere al valor decimalLa instrucción anterior compara el primer operando fuente (valor almacenado en EAX) con el segundo operando fuente (valor al que hace referencia la dirección ESP+18) y establece el indicadores de estado en el registro EFLAGS según los resultados. A continuación se muestra el estado de todos los indicadores después de ejecutar esta instrucción.

A continuación se muestra la siguiente instrucción, que verifica el estado de algunas de las banderas y toma una decisión.

JLE CORTO si.00401546

La instrucción JLE normalmente busca los indicadores O, S y Z. Ninguno de estos indicadores está configurado; por lo tanto, no se realizará el salto condicional y se ejecutará la siguiente instrucción.

A continuación se muestra una descripción general de las instrucciones mostradas hasta ahora.

Las declaraciones «si» suelen tener saltos condicionales, pero no todos los saltos condicionales son declaraciones «si».

«si» anidado

Además de las simples declaraciones «si» que se traducen en saltos condicionales al explorar el desmontaje, existen declaraciones «si» anidadas. A continuación se muestra una declaración «si» anidada donde se inserta una condición «si» dentro de una condición «si».

#incluir stdio.h

vacío principal()

{

int a = 30;

int b =/p>

si (a b){

si(a==30) {

printf(«a es mayor que b y a es igual a 30n»);

}

}

demás{

printf(«b es mayor que an»);

}

}

A continuación se muestra el desensamblaje cuando se compila el código anterior y el binario se abre usando un depurador (OllyDbg en este caso).

EMPUJAR EBP

MOV EBP ESP

Y ESP,FFFFFFFF0

SUBESP,p>

LLAMADA anidada-i.004015F0

MOV DWORD PTR SS:[ESP+1C],1E ; |

MOV DWORD PTR SS:[ESP+18],14 ; |

MOV EAX,DWORD PTR SS:[ESP+1C] ; |

CMP EAX,DWORD PTR SS:[ESP+18] ; |

JLE CORTO anidado-i.0040154D ; |

CMP DWORD PTR SS:[ESP+1C],1E ; |

JNZ SHORT anidado-i.00401559 ; |

MOV DWORD PTR SS:[ESP],nested-i.00404000 ; |ASCII «a es mayor que b y a es igual a 30»

CALL JMP.msvcrt.puts ; pone

JMP CORTO anidado-i.00401559

MOV DWORD PTR SS:[ESP],nested-i.00404027 ; |ASCII «b es mayor que a»

CALL JMP.msvcrt.puts ; pone

NOP

DEJAR

RETENIR

En el código anterior, hay dos saltos condicionales debido a la condición «si» adicional agregada dentro de la declaración «si» existente. Primero se ejecuta un salto condicional (JLE), pero no se realiza el salto en la 10.

Dentro del bloque «si», hay otro salto condicional usando JNZ. Esta instrucción está precedida por una instrucción CMP. La instrucción CMP compara el valor hexadecimal 1E (30 decimal) con el valor al que se hace referencia con [ESP+18]. El valor hexadecimal 18 se traduce al decimal 24. La siguiente muestra la pila antes de que se ejecute la instrucción CMP.

Ambos operandos tienen los mismos valores. Por lo tanto, la instrucción CMP da como resultado la configuración del indicador cero, como se muestra a continuación.

A continuación se muestra la instrucción con el salto condicional después de ejecutar la instrucción CMP.

JNZ CORTO anidado-i.00401559

JNZ da un salto si no se establece la bandera cero. Como la bandera cero está colocada, no se realizará el salto. Se ejecutará la siguiente instrucción e imprimirá «a es mayor que b y a es igual a 30».

Conclusión

Los programas están escritos para ejecutarse secuencialmente, de llamada a función en llamada a función, de la misma manera siempre. Las declaraciones «si» ofrecen más opciones. Permiten que los programas se ramifiquen y realicen saltos condicionales más allá de la secuencia.

Las declaraciones «If» crean un flujo de validación condicional que se utiliza para crear programas de seguridad que pueden controlar la autenticación del usuario.

Fuentes

  1. Referencia del conjunto de instrucciones x86 , c9x.me
  2. Montaje – Condiciones , Tutorialspoint
  3. Michael Sikorski y Andrew Honig, “ Análisis práctico de malware: guía práctica para diseccionar software malicioso ”, No Starch Press, febrero de