¿Qué tal escribir un controlador para WINDOWS?
Debido a que muchos software antivirus (especialmente el software antivirus no técnico como 360) eliminarán directamente los archivos con el sufijo sys cuando los vean,
ni siquiera llamarán a NtLoadDriver. Para software normal, simplemente describe la solución
. Pero con los programas maliciosos no se puede dar una declaración. Como resultado, muchos autores de malware han tomado el camino contrario y han aprovechado los controladores firmados digitalmente y escritos por grandes empresas para hacer el trabajo sucio.
Algunas personas dicen, ¿cómo se puede utilizar a un buen conductor de una gran empresa para hacer cosas malas? En realidad, esto es fácil de entender.
Muchos software de seguridad o optimización del sistema, e incluso software independiente del sistema, como Thunderbolt, vienen con controladores.
Estos drivers tienen cierto grado de versatilidad. El internauta q_lai_a_qu dijo en su blog: "ComputerZ.sys... está bien
Reverse es el controlador de LU Master. ¡Descubrí que este controlador es completamente funcional y no tiene verificación de llamadas! Puedes leerlo y escriba el registro Msr
, y también puede leer y escribir el puerto con comandos de entrada y salida, así como la longitud completa de datos char/short/long "..Esto es
<. p> personal! Por favor, haga su propia suposición sobre su credibilidad. Aquí hay un ejemplo más creíble: un virus usó una vez 360'sAntiRK.dll para eliminar archivos de software antivirus (busque en Google "360 antirk.dll", encontrará resultados inesperados.
AntiRK.dll no es un controlador, pero se explota ilegalmente). Los virus que pueden descifrar el software antivirus se han considerado infantiles.
De hecho, ¡el uso de ciertos controladores también puede dañar el hardware! He estado investigando el hardware de mi computadora portátil y algunos amigos míos me recomendaron algunos programas: SetFSB, ThrottleStop, NvFlash y WinFlash que pueden modificar la frecuencia externa de la CPU, configurar el multiplicador de la CPU y ajustar el voltaje de la CPU. Son software para modificar el FSB de la CPU, configurar el multiplicador de la CPU (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. En resumen,
Todos son compatibles con NT x86/x64 y sus controladores están correctamente firmados digitalmente (especialmente los dos últimos, que están firmados digitalmente por Nvidia y Asus respectivamente).
Lo más importante es que sus controladores no añaden flores ni conchas, ni tienen llamadores de suma de comprobación.
Si aprovechas estos controladores y haces un poco de ingeniería inversa, puedes crear virus destructivos (lo siguiente es un extracto de mi publicación en el
Foro de programación Crystal de Purple Water):
1.SetFSB puede ajustar el FSB del procesador. Si ajusta directamente el FSB a 600 MHz, la computadora se apagará instantáneamente, lo que puede
dañar la CPU o la placa base;
p>
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 se ajusta a 3 V, quemará directamente la CPU. o incluso la placa base;
3. NvFlash, WinFlash y otro software pueden leer y escribir BIOS directamente (BIOS de tarjeta gráfica y BIOS de placa base), podemos escribir todo
BIOS a cero. ;
4. Si crea un virus, primero escribirá el BIOS de la tarjeta gráfica y el BIOS de la placa base, y luego ajustará el voltaje para quemar la tarjeta gráfica y la CPU
(la placa base pueden dañarse juntos);
Solución
Se puede ver que la persona que llama no está verificada. De hecho, existen grandes peligros ocultos en el conductor. Recientemente, una escuela me encargó crear un software que requería un controlador (el controlador estaría firmado digitalmente). Para evitar que ocurra la tragedia anterior, decidí resolver el problema de cómo evitar que el controlador sea explotado maliciosamente antes de escribirlo oficialmente. Una vez hice esta pregunta en el foro de programación de Amethyst y escuché varias respuestas, pero se puede dividir aproximadamente en tres categorías: la primera es la verificación de mensajes, como la aplicación
Secuencia para El controlador envía un mensaje para verificar si el mensaje es propio; el segundo es empaquetar, como agregar firmas digitales a controladores y aplicaciones
.
El segundo es la protección contra shells, como agregar un shell muy poderoso al controlador y la aplicación, y usar VMP para cifrar la parte de comunicación (similar al método de XueTr que otros han propuesto aplicaciones híbridas, que combinan<); /p>
el primer y segundo enfoque.
Estas tres ideas parecen buenas, pero no creo que sean factibles.
El primero: otros solo necesitan revertir todos los controladores.
El segundo: aunque la protección VMP y la adición de una capa protectora hacen que sea difícil de romper, no hace que sea más fácil de romper. crack se vuelve imposible.
VMP y Shell reducirán la eficiencia de ejecución del programa, lo cual no me gusta mucho. Lo peor de todo es que el software antivirus informará sobre todos los programas con cubiertas protectoras (incluso UPX) y VMP, lo cual no vale la pena. Entonces pensé en la tercera forma: verificar las características
de la persona que llama. Si coincide, se ejecuta la instrucción de función; de lo contrario, no se ejecuta. ¿Cómo calibrar el código de firma de la persona que llama? Mucha gente piensa
que se puede utilizar CRC32 o MD5, pero yo tengo mis propias ideas.
Mi idea es diseñar mi propio algoritmo de verificación con las siguientes reglas: 1. Obtener el EPROCESS de la persona que llama. Obtenerlo a través de la ruta EPROCESS de la persona que llama. al archivo de la persona que llama
3. Obtenga todo el contenido del archivo de la persona que llama y colóquelo en el búfer de bytes
4. Sume y reste todos los elementos en el búfer (fb1 fb2 - fb3). ...) para obtener y1
5. Aísle todos los elementos en el búfer en secuencia (0 XOR fb1 XOR fb2 XOR fb3... Si desea obtener y2, puede usar PsGetCurrentProcess() para comparar. y1 e y2 con los valores calculados. Si son iguales, el código de función se puede ejecutar. Si no son iguales, el código de función no se puede
ejecutar
Utilice PsGetCurrentProcess. () para obtener el EPROCESS de la persona que llama y obtener la ruta del archivo de la persona que llama
La ruta es más problemática. Puede usar mi PsGetCurrentProcess() anterior.
La ruta es más problemática. Puede usar el código que compré de un experto antes (está encapsulado en una función y es fácil de llamar):
// Obtenga la ruta completa del proceso según. EPROCESS
VOID GetFullPathByEprocess (proceso electrónico ULONG, PCHAR ProcessImageName)
{
Objeto ULONG Buffer = NULL
FilePath.Length = 0;
* ProcessImageName = 0;
//Eprocess-gt; secciónobject(offset_SectionObject)
if(MmIsAddressValid((PULONG)(eprocess offset_SectionObject) ))
{
object=(*(PULONG)(eprocess offset_SectionObject));
//KdPrint(("[GetProcessFileName] objeto de sección: 0xx\ n", objeto"));
p>
if(MmIsAddressValid((PULONG)((ULONG)objeto 0x014)))
{
object=*(PULONG)((ULONG) objeto 0x014))
//KdPrint(("[GetProcessFileName] Segmento: 0xx\n", objeto)
if (MmIsAddressValid((PULONG)((ULONG)objeto 0x0)))
{
objeto=*(PULONG)((ULONG_PTR)objeto 0x0);
//KdPrint(("[GetProcessFileName]
ControlAera: 0xx\n", objeto));
if(MmIsAddressValid((PULONG)((ULONG)objeto 0x024)) )
{
objeto=*(PULONG)((ULONG)objeto 0x024);
if (NtBuildNumber gt;= 6000) objeto=((ULONG )objeto amp;
0xffffff8);
//KdPrint(("[GetProcessFileName]
FilePointer: 0xx \n", objeto)); p>
}
else
regresar
}
else
regresar
else
regresar; p>
}
else
regresar
}
else
regresar
else
regresar; p>
}
else
return;
FileObject=(PFILE_OBJECT)objeto;
FilePath.Buffer = ExAllocatePool( paginadoP
ool, 0x200);
FilePath.MaximumLength = 0x200;
//KdPrint(("[GetProcessFileName]
FilePointer: wZ\n", amp; FilePointer-gt;FileName));
ObReferenceObjectByPointer((PVOID)FileObject, 0, NULL, KernelMode);
RtlVolumeDeviceToDosName(FileObject-gt;DeviceObject, amp; DosName);
RtlCopyUnicodeString(amp;FilePath,amp;DosName);
RtlAppendUnicodeStringToString(amp;FilePath,amp;FileObject-gt;FileName);
ObDereferenceObject(FileObject) ;
RtlUnicodeStringToAnsiString(y AnsiString, y 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(amp; AnsiString);
ExFreePool(DosName.Buffer);
ExFreePool(FilePath.Buffer);
}
El código anterior requiere tres códigos físicos, que son NtBuildNumber (número de versión del sistema), el desplazamiento del elemento
SectionObject y el elemento UniqueProcessId en EPROCESS. Mi sistema operativo de prueba es Windows 2003, así que
Lo defino en el código de la siguiente manera:
#define offset_SectionObject 0x124
#define offset_UniqueProcessId 0x94
ULONG NtBuildNumber=3790;
Una vez que tenga la ruta del proceso, verifique el código de la función.
Como el proceso es claro, el código se dará directamente:
VOID CalcChar(PUNICODE_STRING logFileUnicodeString, LONG *XorChar, LONG
*AnSChar)
{< / p>
OBJECT _ATTRIBUTES objectAttributes;
IO_STATUS_BLOCK iostatus;
HANDLE hfile;
NTSTATUS ntStatus;
FILE_STANDARD_ INFORMACIÓN fsi
PUCHAR pBuffer;
ULONG i=0, y1=0, y2=0;
//Inicializar atributos de objeto
Inicializar atributos de objeto ( amp.objectAttributes,
InitializeObjectAttributes(amp.objectAttributes,
InitializeObjectAttributes(amp.objectAttributes(amp.objectAttributes)/0))objectAttributes,
logFileUnicodeString,
OBJ_CASE_INSENSITIVE, //distingue entre mayúsculas y minúsculas
NULL,
NULL);
//crear archivo
ntStatus = ZwCreateFile(amp;hfile,
GENERIC_READ,
amp;objectAttributes,
amp;iostatus,
NULL, p >
FILE_ ATTRIBUTE_NORMAL,
FILE_SHARE_READ,
FILE_OPEN, //crea el archivo incluso si existe
FILE_SYNCHRONOUS_IO_NONALERT,
NULL,
0);
if (!NT_SUCCESS(ntStatus))
{
dprintf("El archivo no está existir ! \n");
return;
}
Leer 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 búfer para leer archivos
pBuffer = (PUCHAR)ExAllocatePool(PaggedPool,
(LONG)fsi.EndOfFile.QuadPart);
PBuffer = (PUCHAR)ExAllocatePool(PaggedPool,
(LONG)fsi.EndOfFile.QuadPart);
else
y2=y2-(LONG)(*(pBuffer i));
}
*AnSChar=y2;
/ Cerrar el identificador del archivo
ZwClose(hfile);
/ Liberar el búfer
ExFreePool(pBuffer);
}
La siguiente función que se llamará. Necesitamos escribir una función VerifyCaller, que debe garantizar dos valores
en el controlador, dos valores característicos de la persona que llama legítima.
Para facilitar el cálculo de estos dos valores propios, escribí una
aplicación cuyo código principal es el siguiente:
Opción explícita
Función privada ReadFile(ByVal strFileName como cadena, ByVal opcional
Función privada ReadFile(ByVal strFileName como cadena, ByVal opcional
lngStartPos como largo = 1, ByVallngFileSize opcional como largo = -1) como Byte()
Atenuar FilNum siempre
FilNum = FreeFile
Abrir strFileName para binario como #FilNum
Si lngFileSize = -1 entonces
ReDim ReadFile(LOF(FilNum) - lngStartPos)
Else
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 siempre que = -1, ByVal opcional sobrescribir como booleano =
True)
En caso de error, Ir a erx
Dim FilNum siempre que
FilNum = FreeFile
Si OverWrite = True y Dir(strFileName) lt;gt "" Entonces
Elimine strFileName
<; p>Finalizar siAbrir strFileName para binario como #FilNum
Si lngStartPos = -1 entonces
Poner #FilNum,LOF(FilNum),LOF(FilNum ), LOF(FilNum).LOF(FilNum) 1, bytData
Else
Poner #FilNum, lngStartPos, bytData
End If
Cerrar #FilNum
erx:
Finalizar función
Subcomando privado1_Click()
Atenuar buff() As Byte, i As Long, y As Long, ub As Long
'text1.text es el nombre del archivo
buff = ReadFile (Text1.Text, 1, -1)
u
b = UBound(buff)
'calc xor char
y = 0
Para i = 0 Para ub
y = y Xor buff(i)
Siguiente
Text2.Text = CLng(y)
DoEvents
'calc add/sub char
y = 0
Para i = 0 Para ub
Si i Mod 2 = 0 Entonces
y = y CLng(buff( i))
Else
y = y - CLng(buff(i))
Finalizar si
Siguiente
Text3.Text = CLng(y)
End Sub
Sub privado Form_Load()
Me.Icon = LoadPicture("") p>
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; p>
LONG xorc, ansc;
cur_ep= PsGetCurrentProcess();
GetFullPathByEprocess((ULONG)cur_ep, cur_pp
// antes el nombre del archivo Agregar \?\\p>
nt_cur_pp=cs("\\\?\\,cur_pp);
DbgPrint("s",nt_cur_pp); p>
RtlInitAnsiString(amp;asCur_pp, nt_cur_pp);
RtlAnsiStringToUnicodeString(amp;usCur_pp, amp;asCur_pp, TRUE);
DbgPrint("wZ", amp;usCur_pp );
CalcChar(amp;usCur_pp, amp;xorc, amp;ansc);
DbgPrint("XorChar: DbgPrint("XorChar: ld; AnSChar: ld", xorc, ansc) ;
// ¡Este es un código de función precalculado por el proceso legal y debe solidificarse en el controlador!
if(xorc==186 amp; amp; ansc==136176)
devuelve 1;
else
devuelve 0;
}
Antes de ejecutar cada función de la función DispatchIoctl, llame a VerifyCaller() para verificar la persona que llama:
switch(uIoControlCode)
{
caso IOCTL_VERIFY:
{
DbgP
rint(" [MyDriver] DispatchIoctl - IOCTL_VERIFY");
if(VerifyCaller()==1)
DbgPrint(" [MyDriver] {IOCTL_VERIFY} ¡Ahora ejecute el código de función! " );
else
DbgPrint("[MyDriver] {IOCTL_VERIFY} ¡Eres una persona que llama ilegalmente!");
status = STATUS_SUCCESS;
descanso;
}
/Omitido a continuación
}
Ejecutar la prueba
3 Primero copie el programa de llamadas legales, el programa de llamadas ilegales (use eXeScope para parchear aleatoriamente el programa de llamadas legales,
por ejemplo, elimine la información de la versión del programa) y el controlador a la máquina virtual
. p>
4. Utilice llamadas legales El programa carga el controlador y lo ejecuta
5. Utilice una llamada ilegal para cargar el controlador y ejecutarlo
6. situaciones en DbgView
Cuando la persona que llama es legal Cuándo:
Cuando la persona que llama es ilegal:
Escrito al final
Al final Al final de este artículo, debo reiterar la verificación de la persona que llama
El código es útil. ¿Por qué? Porque nadie puede parchear a un conductor con una firma digital oficial (una vez que el conductor está parcheado, la firma deja de ser válida, como una mujer cuya virginidad ha sido rota, sin valor. Esta metáfora es aunque vulgar, pero muy
adecuado). Y los conductores sin firmar no valen nada. Incluso si otras personas quieren usarlo, pueden colocar el controlador en
IDA y aparecerá el código.