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
- 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