Utilizando PySpark para la clasificación de Malware

Adilene Calderón Gómez
MCD-UNISON
Published in
9 min readMay 18, 2022

El siguiente trabajo corresponde al proyecto final del curso optativo Big Data de la maestría en Ciencia de Datos de la Universidad de Sonora, impartida por el Dr. Juan Pablo Soto Barrera.

Autores

Contenido

  • Contexto
  • Descarga y extracción de datos
  • Limpieza de datos
  • Extracción de características y generación de CSV
  • Transformación de CSV a .parquet
  • Generación de datos de entrenamiento y datos de prueba
  • Análisis de datos exploratorio
  • Generación de modelos y optimización de hiperparametros
  • Evaluación y selección de modelo
  • Exportación de modelo
  • Repositorio del modelo
  • Referencias

Contexto

El malware (o software malicioso) es software diseñado para dañar a los usuarios, las organizaciones y los sistemas informáticos y de telecomunicaciones. Más concretamente, el malware puede bloquear la conexión a Internet, corromper un sistema operativo, robar la contraseña y otra información privada de un usuario.

Durante la última década, el Machine Learning ha provocado un cambio radical en muchos sectores, incluido el de la ciberseguridad. Existe la creencia generalizada entre los expertos en ciberseguridad de que las herramientas antimalware potenciadas por Machine learning ayudarán a detectar los ataques de malware modernos y a mejorar los motores de escaneo.

Los n-gramas de bytes se han utilizado previamente como características en una serie de trabajos, y son uno de los tipos de características más comunes utilizados para el análisis estático de malware. Los n-gramas de bytes son especialmente atractivos, ya que no necesitan conocer el formato del archivo, no requieren ningún análisis dinámico y podrían aprender información tanto de las cabeceras como de las secciones de código binario de un ejecutable. El hecho de que el enfoque de los n-gramas no requiera un conocimiento del dominio significa que un sistema de n-gramas de bytes podría utilizarse para otros formatos de archivo, como los PDF.

En este problema utilizaremos el dataset de Microsoft Malware Classification Challenge (BIG 2015), en conjunto con tecnologías tales como Spark y Hadoop, con el fin de realizar la clasificación de Malware en un contexto de Big Data. El dataset de Clasificación de Malware de Microsoft se anunció en 2015 junto con la publicación de un enorme conjunto de datos de casi 0,5 terabytes, compuesto por el desensamblaje y el código de bytes de más de 20 000 muestras de malware.

Este dataset es un conjunto de archivos de malware conocidos que representan una mezcla de 9 familias de malware diferentes. Cada archivo de malware tiene un Id, un valor hash de 20 caracteres que identifica de forma exclusiva el archivo, y una Clase (un número entero que representa uno de los 9 nombres de familia a los que puede pertenecer el malware).

En este proyecto se utilizará PySpark (el cual es una interfaz para Apache Spark en Python) para generar un modelo de Machine Learning el cual permite clasificar a un archivo malicioso en una de las 9 familias de malware presentadas previamente.

Ejecución de código

Todos los archivos descargados y el código ejecutado se realizaron en el Área de Cómputo de Alto Rendimiento (ACARUS), en nodos con las siguientes características:

  • Intel Xeon E5–2698 40 cores max, 3.2 GB RAM por core
  • Amd Opteron 6282SE 64 cores max, 2.0 GB RAM por core

Descarga y extracción de datos

Los datos se descargaron con la API de kaggle, debido a que estos pesan medio terabyte se descargaron comprimidos (todos los archivos .bytes juntos pesan 185 Gb), la extracción se realizó con la librería pyunpack, como se muestra a continuación.

En este proyecto se trabajará solo con los bytecode de los archivos de malware, estos tienen la siguiente estructura:

Pie de foto: Fragmento de un archivo bytecode (AaKdPBWQD37j9prRxFoZ.bytes)

Limpieza de datos

Antes de extraer las características, es necesario la limpieza de los archivos bytecode, debido a que estos tienen la dirección de los bytecode (lo que está señalado en la imagen, también conocido como offset), ya que este es el mismo para todos los archivos. Así como en los métodos de extracción de características, aquí se usó como base el método propuesto por Rohan-Paul-Al , sin embargo, se le realizaron algunas modificaciones para poder correrlo en paralelo la librería MultiProcessing y así corriera de manera más rápida.

Extracción de características y generación de CSV

Extracción de unigramas: Para extraer las características de los archivos bytecode se utilizó el enfoque de la extracción de unigramas. Se intentaron diversas formas (tales como utilizar el método CountVectorizer que viene integrado en PySpark ML), sin embargo, el tamaño de los archivos eran muy grandes y había una gran cantidad de ellos, lo cual hacía que el proceso fuera muy lento (o causaba errores).

Finalmente, la metodología que resultó exitosa fue inspirada en la solución propuesta por Rohan-Paul-Al, pero se modificó ligeramente para adaptarlo a la librería MultiProcessing de Python, el cual, por medio de la paralelización del proceso acelera considerablemente la ejecución del código, como se muestra a continuación:

Extracción del peso de archivo: Otra característica que se contempló fue la extracción del peso del archivo, este extracción de características no es costosa (computacionalmente hablando) y se realizó utilizando como base el método propuesto por Rohan-Paul-Al, adaptándolo a PySpark:

Transformación de CSV a .parquet

Todos los archivos .csv generados a lo largo del proyecto se transformaron a formato parquet, con el fin de eficientar el almacenamiento. Un archivo Parquet es un formato de almacenamiento de datos de forma estructurada, el cual ayuda a optimizar los datos y reducir los tiempos de consulta mientras se consume menos espacio en contraste con un archivo CSV.

Para esto se utilizó la librería Pyarrow, esta proporciona una API de Python para la funcionalidad proporcionada por las bibliotecas Arrow C++, junto con herramientas para la integración de Arrow.

El script que se utilizó para transformar los archivos es el siguiente:

Generación de datos de entrenamiento y datos de prueba

Separar los datos en conjunto de entrenamiento y conjunto de prueba es una parte importante para la evaluación de modelos de aprendizaje. Dado que haremos uso de modelos de clasificación de Machine Learning, es necesario generar datos de entrenamiento y de prueba.

‘’Es importante que el conjunto de datos de prueba tenga un volumen suficiente como para generar resultados estadísticamente significativos, y a la vez, que sea representativo del conjunto de datos global.’’ Cita

Para la clasificación de malware se generaron aleatoriamente los datos de entrenamiento en un 70% y los datos de prueba en un 30% del total. También se definió una semilla 2018 para que al volver a cargar el código se generen los mismos datos aleatorios.

Análisis de datos exploratorio

Vemos las primeras columnas con nombre que son “ID”, “size” y “Class”.

Tenemos 10868 ID distintos.

Veamos las estadísticas básicas de size.

Veamos un boxplot sencillo para la columna “size”.

A continuación un boxplot para la columna “Class”.

¿Podríamos ver algo de las demás columnas? Solamente podemos observar que tienen una mayor dispersión. Aquí es un boxplot de las columnas llamadas 0, 1, 2, 3, 4, 5.

Ahora veamos cómo están distribuidos los malware. Podemos observar en el siguiente histograma que la mayoría de ellos son de clase 1, 2 y 3 mientras que los demás malware no son tan comunes. Es decir, si tienes un malware, habrá un 64% que sea de clase 1, 2 o 3. Aquí también podemos ver que el que más aparece es de clase 3, Kelihos.

Generación de modelos y optimización de hiperparametros

Para obtener el mejor modelo, se probaron los 4 modelos disponibles para clasificación en PySpark, en cada uno de estos se realizó el método Grid Search para la optimización de hiperparámetros y se realizó la validación cruzada para garantizar que los resultados de los modelos son independientes de la partición entre datos de entrenamiento y prueba.

  • Random Forest

Los Bosques Aleatorios (o Random Forest, por su nombre en inglés) es un algoritmo de aprendizaje supervisado que crea múltiples árboles de decisión y los combina para obtener una predicción más precisa y estable. Se realizó con PySpark de la siguiente manera:

Se obtuvieron resultados muy buenos con este algoritmo, y los parámetros óptimos obtenidos con el ParamGrid fueron:

(numTrees=50, numClasses=10, numFeatures=257)

Accuracy = 0.9757002886364886

Test Error = 0.02429971136351139

  • Logistic Regression

Se utilizó el modelo de Regresión Logística para la multi clasificación de los tipos de virus con ayuda de ParamGrid y Cross Validation obteniendo como mejores parámetros regParam=0, elasticNetParam=0 y maxIter=50 y como resultado se obtuvo:

Accuracy = 0.9172370877411326

Test Error = 0.08276292

El código de implementación se realizó de la misma forma que para el modelo de Random Forest utilizando como diferencia la función LogisticRegression().

  • Decision Trees

Un árbol de decisión es un algoritmo de aprendizaje automático supervisado conformado por nodos, donde cada ramificación incluye reglas de clasificación y atributos asociados a cada etiqueta, calculando la categoría a la que pertenece, en este caso, cada malware.

Para este método de la librería Pyspark utilizamos la función DecisionTreeClassifier, con la cual se obtuvo:

Accuracy = 0.9601742377100186

Test Error = 0.03982576228998136

  • Naive bayes

Los clasificadores Naive Bayes son una colección de algoritmos de clasificación basados en el Teorema de Bayes. No es un solo algoritmo sino una familia de algoritmos donde todos comparten un principio común, es decir, cada par de características que se clasifican son independientes entre sí.

El código de implementación se realizó con PySpark utilizando la función NaiveBayes().

Los parámetros óptimos obtenidos con el ParamGrid fueron:

(modelType = multinomial, numClasses = 9, numFeatures = 257)

Se obtuvo lo siguiente:

Test Error = 0.962352

Accuracy = 0.03764779091474798

Selección y exportación de modelo

Se seleccionó el modelo de Random Forest debido a que presentó mejores métricas y se exportó de la siguiente manera:

Al ejecutar este código, se generará un directorio el cual contiene subdirectorios con los metadatos, estimadores y evaluadores, para poder utilizar el modelo en un futuro.

Y listo, ya tenemos un modelo que permite clasificar a los diferentes tipos de Malware en su respectiva familia.

Ideas futuras

Se proponen algunas maneras en las que se puede seguir trabajando en este proyecto, la primera es que además de unigramas se extraigan los diferentes N-gramas N=2–8, ya que hay varios estudios donde se reporta que esto puede mejorar los resultados. Otra es que en lugar de extraer N-gramas, se tome el enfoque de transformar los archivos de malware a imágenes de escala de grises y usar una red neuronal convolucional para clasificarlos.

Repositorio del proyecto

Todo el código y datos (junto con sus diccionarios de datos) que se presentan y se mencionan en el transcurso del artículo se encuentran disponibles en el repositorio del proyecto https://github.com/carlosvelv/big_data_malware.

Agradecimientos

Agradecemos al Área de Cómputo de Alto Rendimiento del Departamento de Matemáticas de la Universidad de Sonora por prestarnos sus servicios para hacer posible este proyecto.

Referencias

--

--