Red de conocimiento informático - Conocimiento del nombre de dominio - Cómo destruir el hardware de una computadora

Cómo destruir el hardware de una computadora

Para una persona que escribe programas con frecuencia, escribir controladores no es una tarea difícil. Debido a que hay muchos códigos ya preparados en Internet, si desea implementar una determinada función, simplemente use Ctrl+C y Ctrl+V para resolver el problema. Pero si el controlador se puede cargar en el kernel después de escribirlo es otra cuestión. Para ser precisos, si puede existir en el disco duro de otra persona es otra cuestión.

Debido a que muchos software antivirus (especialmente los no técnicos como 360) eliminan archivos con el sufijo sys cuando los ven.

Ni siquiera hay posibilidad de llamar a NtLoadDriver. Para software general, basta con dar una declaración explicando la solución

. Pero no se puede hacer ninguna declaración sobre los programas maliciosos. Por lo tanto, muchos autores de malware encuentran otra forma de hacer cosas malas mediante el uso de controladores firmados digitalmente y escritos por grandes empresas.

Algunas personas preguntan: ¿cómo se pueden utilizar los factores que las grandes empresas hacen bien para hacer cosas malas? De hecho, esto es algo muy fácil de entender.

Muchos software de seguridad o optimización del sistema, e incluso software no relacionado con el sistema (como Thunder), vienen con controladores.

Estos drivers tienen cierto grado de versatilidad. El internauta q_lai_a_qu dijo en su blog: "ComputerZ.sys... está bien

Descubrí que era el controlador de Master Lu. ¡Descubrí que este controlador tiene funciones completas y no tiene verificación de llamadas! Ambos pueden leer y escriba Msr

Registro, también puede usar instrucciones de entrada y salida para leer y escribir puertos, ¡y la longitud de datos char/short/long estará completa! Esta es

una declaración personal, por favor haga su propio juicio sobre la credibilidad. Aquí hay un ejemplo más creíble: un virus usó AntiRK.dll de 360 ​​para eliminar archivos de software antivirus (busque en Google "360 antirk.dll", se sorprenderá)

Aunque AntiRK. .dll no es un controlador, se ha utilizado ilegalmente). Los virus que destruyen el software antivirus ya se consideran infantiles.

De hecho, ¡algunos controladores también pueden destruir el hardware! Recientemente estuve jugueteando con el hardware de mi computadora portátil y los internautas del "Friends Club" me recomendaron varios programas: SetFSB, ThrottleStop, NvFlash y WinFlash. Son software para modificar el FSB de la CPU, configurar el multiplicador de la CPU (que puede ajustar el voltaje de la CPU), leer y escribir el BIOS de la tarjeta gráfica y leer y escribir el BIOS de la placa base. Para resumir sus características en una palabra,

Todos soportan NT x86/x64, y sus controladores tienen firmas digitales formales (especialmente los dos últimos, que tienen las firmas digitales de NVIDIA y ASUS respectivamente).

Lo más importante es que sus controladores no están empaquetados ni verificados.

Si usas estos controladores y agregas un poco de conocimiento inverso, puedes crear virus destructivos (lo siguiente es). extraído de mi publicación en Zishui

Foro de programación Jing):

1.SetFSB puede ajustar el FSB del procesador. Si configura directamente el ajuste FSB a 600 MHz, la computadora lo hará instantáneamente. pantalla negra, que puede

dañar la CPU o la placa base;

2. ThrottleStop puede ajustar el multiplicador de la CPU (si la CPU no bloquea el multiplicador), si ajusta directamente el multiplicador a 31,

la computadora se apagará instantáneamente, lo que puede dañar la CPU o la placa base; ThrottleStop también puede ajustar el voltaje del núcleo de la CPU si

el voltaje del núcleo de la CPU es. ajustado a 3V puede quemar directamente la CPU o incluso la placa base

3. NvFlash, WinFlash y otro software pueden leer y escribir BIOS (BIOS de tarjeta gráfica y BIOS de placa base), podemos escribir todo el BIOS a cero. ;

4. Si crea un virus, primero escriba el BIOS de la tarjeta gráfica y la BIOS de la placa base defectuosos, y luego queme la tarjeta gráfica y la CPU ajustando el voltaje

(puede dañar el placa base juntas);

Solución

Se puede ver que el controlador sin verificar a la persona que llama es realmente dañino.

Recientemente, la universidad me encargó la creación de un software que requiere un controlador (el controlador estará firmado digitalmente). Para evitar que ocurra la tragedia anterior, decidí descubrir cómo evitar que mi propio controlador se use maliciosamente antes de escribirlo oficialmente. Ya hice esta pregunta en el Foro de programación de Amethyst.

Las respuestas de los internautas fueron variadas, pero se pueden dividir aproximadamente en tres categorías: la primera categoría es la verificación de información, como aplicaciones

El programa envía un mensaje al controlador para verificar que es "uno de los nuestros"; el segundo tipo es la protección contra bombardeos, como agregar un shell muy fuerte y difícil de eliminar al controlador y a la aplicación, y usar. Cifrado VMP Parte de comunicación (similar al enfoque de XueTr), otros han propuesto aplicaciones híbridas que combinan las prácticas de la primera y segunda categoría.

Estas tres ideas parecen buenas, pero creo que son inapropiadas. El primero: otros solo necesitan aplicar ingeniería inversa a todos los controladores. El segundo: aunque la protección VMP y la cubierta protectora hacen que sea difícil descifrar, no lo hace imposible. Además

VMP y el shell protector pueden reducir la eficiencia de la ejecución del programa, lo cual no me gusta mucho. Lo más repugnante es que el software antivirus informará sobre los virus a los programas que han sido empaquetados (incluso UPX) y VMP, lo que no vale la pena perder. Entonces se me ocurrió la tercera idea: verificar las características

de la persona que llama. Si coincide, se ejecutará la declaración de función; de lo contrario, no se ejecutará. ¿Cómo verificar la firma de la persona que llama? Mucha gente piensa en utilizar CRC32 o MD5. No es imposible usarlos, pero todavía tengo mis propias ideas.

Mi idea es diseñar un algoritmo de verificación por mí mismo. Sus reglas son las siguientes:

1. Obtener el EPROCESS de la persona que llama

2. Pasar la persona que llama. EPROCESS obtiene la ruta del archivo de la persona que llama.

3. Obtiene todo el contenido del archivo de la persona que llama y lo coloca en la matriz de bytes.

4. Agrega todos los elementos en la secuencia de resta (fb1 + fb2 - fb3). ...) para obtener y1

5. XOR todos los elementos del beneficio en secuencia (0 XOR fb1 XOR fb2 XOR fb3...) para obtener y2

Compara y1 y y2 con los valores calculados si son iguales, se ejecutará el código de función. Si no son iguales, no se ejecutará el código de función.

Ejecutar el código de función

<. p>Obtener el EPROCESS de la persona que llama puede usar PsGetCurrentProcess() directamente. Obtener la ruta del archivo de la persona que llama

es problemático. Puede usar el código que compré de un experto antes (ya encapsulado como una función para facilitar la llamada). :

//Obtenga la ruta completa del proceso basada en EPROCESS

VOID GetFullPathByEprocess( ULONG eprocess, PCHAR ProcessImageName )

{

Objeto ULONG;

PFILE_OBJECT FileObject;

UNICODE_STRING FilePath;

UNICODE_STRING DosName;

STRING AnsiString;

FileObject = NULL;

FilePath.Buffer = NULL;

FilePath.Length = 0;

*ProcessImageName = 0;

//Eprocess->sectionobject(offset_SectionObject)

if(MmIsAddressValid((PULONG)(eprocess+offset_SectionObject)))

{

object=(*( PULONG)(eprocess+offset_SectionObject));

//KdPrint(("[GetProcessFileName] objeto de sección :0x%x\n",objeto));

if(MmIsAddressValid(( PULONG)((ULONG)objeto+0x014 )))

{

objeto=*(PULONG)((ULONG)objeto+0x014);

/ /KdPrint(("[GetProcessFileName] Segmento:0x%x\n",objeto));

if(MmIsAddressValid((PULONG)((ULONG)objeto+0x0)))

{

object=*(PULONG)((ULONG_PTR)object+0x0);

//KdPrint(("[GetProcessFileName]

ControlAera : 0x%x\n",objeto) );

if(MmIsAddressValid((PULONG)((ULONG)objeto+0x024)))

{

objeto=*(PULONG)((ULONG )objeto+0x024);

si

(NtBuildNumber >= 6000) object=((ULONG)object &

0xfffffff8);

//KdPrint(("[GetProcessFileName]

FilePointer :0x %x\n",objeto));

}

else

return ;

}

más

regresar ;

}

más

regresar ;

}

else

return ;

FileObject=(PFILE_OBJECT)objeto;

FilePath.Buffer = ExAllocatePool(PaggedPool,0x200);

FilePath .MaximumLength = 0x200;

//KdPrint(("[GetProcessFileName]

FilePointer :%wZ\n",&FilePointer->FileName));

ObReferenceObjectByPointer((PVOID)FileObject,0,NULL,KernelMode);

RtlVolumeDeviceToDosName(FileObject-> DeviceObject, &DosName);

RtlCopyUnicodeString(&FilePath, &DosName);

RtlAppendUnicodeStringToString(&FilePath, &FileObject->FileName);

ObDereferenceObject(FileObject);

RtlUnicodeStringToAnsiString(&AnsiString, &FilePath, TRUE);

if ( AnsiString .Length >= 216 )

{

memcpy(ProcessImageName, AnsiString.Buffer, 0x100u);

*(ProcessImageName + 215) = 0;

}

else

{

memcpy(ProcessImageName, AnsiString.Buffer, AnsiString.Length);

ProcessImageName [AnsiString.Length] = 0;

}

RtlFreeAnsiString(&AnsiString);

ExFreePool(DosName.Buffer);

ExFreePool (FilePath.Buffer);

}

El código anterior requiere tres códigos físicos, a saber, NtBuildNumber (número de versión del sistema),

elementoSectionObject en EPROCESS y el desplazamiento del elemento UniqueProcessId. El sistema operativo que probé fue Windows 2003.

Entonces

Lo definí de la siguiente manera en el código:

#define offset_SectionObject 0x124

#define offset_UniqueProcessId 0x94

ULONG NtBuildNumber=3790 ;

Después de obtener la ruta del proceso, verifique la firma.

Como el proceso se ha explicado claramente, el código se proporciona directamente:

VOID CalcChar(PUNICODE_STRING logFileUnicodeString, LONG *XorChar, LONG

*AnSChar)

{

OBJECT_ATTRIBUTES objectAttributes;

IO_STATUS_BLOCK iostatus;

HANDLE hfile;

NTSTATUS ntStatus;

FILE_STANDARD_INFORMATION fsi;

PUCHAR pBuffer;

ULONG i=0,y1=0,y2=0;

//Inicializar atributos de objeto

Inicializar atributos de objeto( &objectAttributes ,

logFileUnicodeString,

OBJ_CASE_INSENSITIVE,//sensible a mayúsculas y minúsculas

NULL,

NULL);

//Crear archivo

ntStatus = ZwCreateFile(&hfile,

GENERIC_READ,

&objectAttributes,

&iostatus,

NULL,

FILE_ATTRIBUTE_NORMAL,

FILE_SHARE_READ,

FILE_OPEN, //Crear incluso si el archivo existe

FILE_SYNCHRONOUS_IO_NONALERT,

p>

NULL,

0);

if (!NT_SUCCESS(ntStatus))

{

dprintf( " ¡El archivo no existe!\n");

return;

}

//Leer la longitud del archivo

ntStatus = ZwQueryInformationFile(hfile,

&iostatus,

&fsi,

sizeof(FILE_STANDARD_INFORMATION),

FileStandardInformation);

dprintf("El programa quiere leer %d bytes\n",fsi.EndOfFile.QuadPart);

//Asignar un buffer para el archivo leído

pBuffer = (PUCHAR )ExAllocatePool(PaggedPool,

(LONG)fsi.EndOfFile.QuadPart);

//Leer archivo

ZwReadFile(hfile,NULL,

NULL,NULL,

&iostatus,

pBuffer,

(LONG)fsi.EndOfFile.QuadPart,

NULL, NULL);

dprintf("El programa realmente leyó %d bytes\n",iostatus.Information);

//Cálculo XOR

for(i =0;i

tatus.Information;i++)

y1=y1^(LONG)(*(pBuffer+i));

*XorChar=y1;

// Cálculos de suma y resta

for(i=0;i

{

if(i%2==0)

p>

y2=y2+(LARGO)(*(pBuffer+i));

else

y2=y2-(LARGO)(*(pBuffer+ i)) ;

}

*AnSChar=y2;

//Cerrar el identificador del archivo

ZwClose(hfile);

//Libera el buffer

ExFreePool(pBuffer);

}

Será llamado a continuación. Necesitamos escribir una función VerifyCaller. En esta función, hay dos valores que deben solidificarse en el controlador, que son los dos valores característicos de la persona que llama legalmente.

Para facilitar el cálculo de estos dos valores característicos, escribí especialmente una aplicación. El código principal es el siguiente:

Opción explícita

Función privada ReadFile(ByVal strFileName As String, Opcional ByVal

lngStartPos Mientras = 1, Opcional ByVallngFileSize Mientras = -1) Como Byte()

Dim FilNum Mientras

FilNum = FreeFile

Abrir strFileName para binario como #FilNum

Si lngFileSize = -1 entonces

ReDim ReadFile(LOF(FilNum) - lngStartPos)

De lo contrario

ReDim ReadFile(lngFileSize - 1)

Finalizar si

Obtener #FilNum, lngStartPos, ReadFile

Cerrar #FilNum

Función final

Función privada WriteFile(ByVal strFileName como cadena, bytData() como byte,

ByVal lngStartPos opcional mientras = -1, ByVal sobreescritura opcional como booleano =

Verdadero)

En caso de error, Ir a erx

Atenuar FilNum mientras

FilNum = FreeFile

Si se sobrescribe = True y Dir(strFileName) <> "" Entonces

Eliminar strFileName

Finalizar si

Abrir strFileName para binario como #FilNum

Si lngStartPos = -1 Entonces

Pon #FilNum, LOF(FilNum) + 1, bytData

De lo contrario

Pon #FilNum, lngStartPos, bytData

Finalizar si

Cerrar #FilNum

erx:

Finalizar función

Subcomando privado1_Click()

Dim buff() As Byte, i As Long, y As Long, ub As Long

'text1.text es el nombre del archivo

buff = ReadFile (Text1. Texto, 1, -1)

ub = UBound(buff)

'calc xor char

y = 0

Para i = 0 A ub

y = y Xor buff(i)

Siguiente

Text2.Text = CLng(y)

DoEvents

'calc add/sub char

y = 0

Para i = 0 Para u

b

Si i Mod 2 = 0 Entonces

y = y + CLng(buff(i))

De lo contrario

y = y - CLng(buff(i))

Fin si

Siguiente

Texto3.Text = CLng(y)

Fin Sub

Private Sub Form_Load()

Me.Icon = LoadPicture("")

End Sub

El código VerifyCaller en el controlador es el siguiente:

LONG VerifyCaller(void)

{

PEPROCESS cur_ep;

char cur_pp[260];

char *nt_cur_pp;

ANSI_STRING asCur_pp;

UNICODE_STRING usCur_pp;

LONG xorc, ansc;

cur_ep=PsGetCurrentProcess ();

GetFullPathByEprocess((ULONG)cur_ep, cur_pp);

//Agrega \?\ delante del nombre del archivo

nt_cur_pp=cs( "\\? \\",cur_pp);

DbgPrint("%s",nt_cur_pp);

RtlInitAnsiString(&asCur_pp, nt_cur_pp);

RtlAnsiStringToUnicodeString (&usCur_pp, &asCur_pp , TRUE);

DbgPrint("%wZ",&usCur_pp);

CalcChar(&usCur_pp, &xorc, &ansc);

DbgPrint( "XorChar: % ld; AnSChar: %ld",xorc,ansc);

// ¡Esta es la firma de un programa legal calculado de antemano y debe solidificarse en el controlador!

if(xorc==186 && ansc==136176)

devuelve 1;

si no

devuelve 0;

}

Antes de ejecutar cada función de la función DispatchIoctl, se llama a VerifyCaller() para verificar la persona que llama:

switch(uIoControlCode)

{

caso IOCTL_VERIFY:

{

DbgPrint("[MyDriver] DispatchIoctl - IOCTL_VERIFY");

if(VerifyCaller() ==1)

DbgPrint("[MyDriver] {IOCTL_VERIFY} ¡Código de función ejecutado ahora!");

else

DbgPrint("[MyDriver] { IOCTL_VERIFY} ¡Eres una persona que llama ilegalmente!");

status = STATUS_SUCCESS;

break;

}

//abajo Omitir

}

Ejecute la prueba

3. Primero, separe la persona que llama legal y la ilegal.

La persona que llama (use eXeScope para parchear a la persona que llama legalmente,

por ejemplo, elimine la información de la versión del programa) y el controlador se copian en la máquina virtual

4. persona que llama para cargar el controlador y ejecutarlo

5. Utilice una persona que llama ilegal para cargar el controlador y ejecutarlo

6 Compare la salida de los dos anteriores en DbgView

.

La persona que llama es legal Cuando:

Cuando la persona que llama es ilegal:

Escrito al final

Después de escribir este artículo, debo reiterar nuevamente: sólo cuando el conductor lleva una firma digital formal. Sólo cuando es de valor verificar el código de la persona que llama. ¿Por qué dices eso? Porque otros no pueden parchear a un conductor con una firma digital formal (una vez que el conductor es parcheado, la firma deja de ser válida, al igual que una mujer cuya virginidad se ha perdido y no tiene valor. Aunque esta metáfora es vulgar, es muy

p>

apropiado). Un conductor sin firma no tiene valor de uso. Incluso si otros quieren usarlo, simplemente coloque el controlador en IDA y aparecerá todo el código.