Categorías
Uncategorized

Reversing de programas en Go

En esta ocasión estaremos viendo diferentes herramientas que nos facilitarán la tarea de realizar reversing a programas en Go

¿Por qué es más complicado realizar reversing a programas en GO?

Son varios los factores que dificultan la tarea a los reversers cuando se trata de realizar reversing a los programas en Go como por ejemplo Los programas en GO están enlazados estáticamente (Statically-Linked) es decir que este tendrá incluidos todas las dependencias necesarias para que este funcione. Esto aumenta el tamaño de los mismos, y si abonado a esto no se tienen los símbolos será aún más complicado entender la relación y funcionamiento de las diferentes funciones y podríamos estar analizando código irrelevante para nuestro análisis (código interno de Go). Cuando realizamos reversing a archivos Go sin símbolos no tenemos información tal como los nombres de las variables y funciones con lo que nos dificulta la tarea de entender el propósito de las diferentes funciones y variables además de perdernos fácilmente en las funciones agregadas por Go.

Otra cosa particular de los programas en Go es que las strings no están null terminated en lugar están colocadas pegadas unas con las otras y cuando una función requiere una string se le pasa el puntero y el tamaño de la misma.

En Go Seguir los argumentos y los valores de retorno es más difícil que en programas por ejemplo de c o c++

Realizando pruebas en Go

En esta parte procederemos a compilar un programa en Go y nos dispondremos a analizar el desensamblado con el objetivo de resaltar las diferencias de los programas en Go con otros lenguajes e ilustrar las dificultades que podemos tener a la hora de analizar los mismos

El código que estaremos analizando es el siguiente

package main

import "fmt"

func main() {
    var a int
    var b int
    var res int

    fmt.Println("Ingrese el primer numero : ")
    fmt.Scan(&a)
    fmt.Println("Ingrese el segundo numero : ")
    fmt.Scan(&b)
    res = suma(a, b)
    fmt.Println("La suma es : ", res)
}

func suma(a, b int) int {
    return a + b
}

Como podemos ver es un sencillo programa que pide dos números e imprime el resultado de la suma de los dos números, procedamos a ver el desensamblado del programa compilado con símbolos

Como vemos en la imagen la función carece del prólogo clásico de las funciones en c o c++ en lugar de eso tiene una comparación y un salto a llamar a runtime_morestack. De esta manera inicializan la mayoría de las funciones en GO en caso de ser necesario allocara más stack en runtime. El código que a nosotros nos concierne es el código escrito por el usuario así que esto lo podemos pasar por alto

Llama a runtime_newobject al parecer para allocar espacio para nuestros dos enteros

Luego llama a fmt_Fprintln pero el paso de argumentos no es tan claro como lo es en otros lenguajes. Coloca en una parte del stack “Ingrese el primer numero”, en ebx tiene os_Stdout en rax tiene File io writer. Pero depurando nos damos cuenta que lo que hace es imprimir “ingrese el primer numero”

Luego llama a fmt_Fscan en rax tiene file io reader, en rbx tiene os_Stdin y en determinada posición del stack coloca var_70 que es uno de nuestras variables enteras creadas con runtime_newobject y si depuramos nos damos cuenta que escribe en var_70 el numero leído con fmt_Fscan

Imprime ingrese el segundo numero

Lee nuestro segundo numero y lo almacena en var_78

Los suma

Y por último imprime el resultado de la suma

Como nos hemos dado cuenta en este ejemplo es que muchas veces seguir las variables, argumentos y valores de retorno en go puede llegar a ser más complicado que en otros lenguajes, pero podemos ayudarnos de la documentación de go la cual es bastante completa y asistirnos de la depuración

Análisis de programas en Go sin símbolos

En esta parte procederemos a compilar el ejemplo anterior pero esta vez sin símbolos y veremos una herramienta que nos ayudara en el análisis de programas Go cuando estos carecen de símbolos.

Abramos el ejemplo en ida

Como podemos ver en la imagen tenemos 1128 funciones y ninguna tiene nombre o alguna pista si es interna de go o creada por el usuario. Si empezamos a realizar el reversing así va a ser demasiado tedioso.

Gracias a AlphaGolang de sentinel labs esto no tiene que ser así. AlphaGolang es una serie de scripts para idapython que te permiten entre otras cosas recuperar la información de los símbolos, veamos esta serie de scripts en acción

  1. Recrear la tabla pcln

La tabla pcln es una tabla que contiene información sobre las funciones del programa incluyendo los nombres. El primer script lo que hace es recrear dicha tabla

Aquí tenemos los segmentos del programa ejemplo antes de ejecutar el primer script

Ejecutamos el primer script

Y este es el resultado el script crea un segmento que contiene la información de esta tabla

2. Descubrimiento de funciones y renombrado

El siguiente script lo que hace es renombrar las funciones del programa

Estas son las funciones antes de ejecutar el segundo script

Y este es el resultado luego de ejecutar el script. Como vemos ha renombrado la gran mayoría de funciones ahorrándonos un gran trabajo sin embargo no todas fueron renombradas

3. El tercer script organiza las funciones en carpetas, pero por una razón la cual desconozco no funciona en mi maquina

4. El cuarto script arreglas las referencias a las strings

5. El quinto y ultimo script comenta en todas las llamadas a newobject el tipo de objeto

Conclusión

La ingeniería inversa de programas en go puede llegar a tener una mayor dificultad que la ingeniería inversa a otros lenguajes, pero existen Scripts y herramientas que hacen que el proceso de reversing sea mas llevadero

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *