Invierta el controlador de filtro de teclado escrito por usted mismo

  Si no tiene nada que hacer, invierta el impulso que escribió para profundizar su comprensión.
  Aquí la marcha atrás se divide en Debug版, Release版y 加载PDB版. Las características de las tres versiones son: La
  versión Debug no será optimizada por el compilador y es más adecuada para aprender ingeniería inversa.
  La versión Release se lanza al mundo exterior. Muchas estructuras y desmontajes se optimizan y deforman durante la ingeniería inversa. Solo se puede decir que tiene las características del código original.
  Cargar la versión PDB es casi equivalente a leer el código fuente, no hay ningún desafío.

  Por lo tanto, el enfoque del estudio aquí es el propio controlador compilado por la versión de depuración inversa.

Depurar 版

Inserte la descripción de la imagen aquí
  El primer arrastre en DriverEntry reconocido por IDA no es nuestra función DriverEntry real. Es sub_401250.
  Tenga en cuenta que la asignación de la estructura DestinationString en la entrada y la función WdfVersionBind son todas agregadas por el sistema después de la compilación.
  ¿Cuáles son las funciones de inicialización específicas? Puede cargar el PDB y mirarlo. Esto tiene poca importancia.

Inserte la descripción de la imagen aquí
  La función principal de devolución de llamada de registro sub_4012F0 es DriverUnload, y la función de devolución de llamada de registro sub_401210 es MajorFunction.

Inserte la descripción de la imagen aquí
  Se puede ver que esto atraviesa la lista doblemente enlazada, pero es posible que no pueda adivinar que esta es la estructura LDR_DATA_TABLE_ENTRY. Debido a que DriverObject + 0x14 es DriverSection, aquí está la lista vinculada de módulos de controlador.
Inserte la descripción de la imagen aquí
  Cuando una función se envía en la dirección inversa, el tipo de IRP se puede confirmar de acuerdo con el índice de matriz de MajorFunction, y se ubica la función de envío que debe estudiarse cuidadosamente. El primer parámetro de estas funciones de envío es principalmente DriverObject o DeviceObject.
  Después de cargar el PDB, se encuentra que sub401bc0 es __CheckForDebuggerJustMyCode.
Inserte la descripción de la imagen aquí
La estructura DriverObject es muy importante, así que mira hacia adelante y hacia atrás aquí.
El número de elementos de MajorFunction en el código fuente es 0x1B, 0x1B + 1 = 0x1Ch, que es el decimal 28 en la figura. Ocupa 28x4 = 112. Es decir, el valor HEX es 70h, por lo que el tamaño de DriverObject es A8h.
Inserte la descripción de la imagen aquí

typedef struct _IO_STACK_LOCATION {
    
    
    UCHAR MajorFunction;
    UCHAR MinorFunction;
    UCHAR Flags;
UCHAR Control;
Union{
    
    }Parameters;
PDEVICE_OBJECT DeviceObject;
PFILE_OBJECT FileObject;
PIO_COMPLETION_ROUTINE CompletionRoutine;
PVOID Context;
} IO_STACK_LOCATION, *PIO_STACK_LOCATION;

Inserte la descripción de la imagen aquí
  IDA solo tiene la firma de Windows Driver Kit 7/10 de 32 bits, y algunas funciones definidas en Wdm.h no se reconocen, lo que provoca la dificultad de la ingeniería inversa.
Inserte la descripción de la imagen aquí
  La función ReadCompleteRoutine en el código fuente. Desea descifrar esta función y adivinar que a2 es la estructura PIRP es la clave.La clave para lo contrario es adivinar la estructura. La primera es tener experiencia en desarrollo, para que pueda explorar mejor la intención del contexto. En segundo lugar, familiarícese con algunas estructuras de sistema de uso común al escribir código.
Inserte la descripción de la imagen aquí
  IRP + 0X18h es IoStatus. IPR + 0xCh es un puntero AssociatedIrp. El código fuente es un puntero a SystemBuffer.

union {
    
    
        struct _IRP *MasterIrp;
        __volatile LONG IrpCount;
        PVOID SystemBuffer;
} AssociatedIrp;

  No se adivina el desplazamiento de 0x1Ch. Mira la estructura _IO_STATUS_BLOCK.

typedef struct _IO_STATUS_BLOCK {
    
    
    union {
    
    
        NTSTATUS Status;
        PVOID Pointer;
    } DUMMYUNIONNAME;

    ULONG_PTR Information;
} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;

  La dirección de desplazamiento 0x1Ch es 0X18h y luego la dirección de desplazamiento 0x4h, se puede ver que es la estructura IO_STATUS_BLOCK. Para decirlo sin rodeos, siempre que adivine la estructura o el significado de los datos en la estructura, la intención del código se puede ver correctamente.
  Finalmente, se adjunta el código fuente de la función sub_401AB0, que es la función ReadCompleteRoutine:

NTSTATUS ReadCompleteRoutine(PDEVICE_OBJECT pDevObj, PIRP pIrp, PVOID pContext)
{
    
    
	NTSTATUS status = pIrp->IoStatus.Status;
	PKEYBOARD_INPUT_DATA pKeyboardInputData = NULL;
	ULONG ulKeyCount = 0, i = 0;

	if (NT_SUCCESS(status))
	{
    
    
		pKeyboardInputData = (PKEYBOARD_INPUT_DATA)pIrp->AssociatedIrp.SystemBuffer;
		ulKeyCount = (ULONG)pIrp->IoStatus.Information / sizeof(KEYBOARD_INPUT_DATA);

		// 获取按键数据
		for (i = 0; i < ulKeyCount; i++)
		{
    
    
			// Key Press
			if (KEY_MAKE == pKeyboardInputData[i].Flags)
			{
    
    
				// 按键扫描码
				DbgPrint("[Down][0x%X]\n", pKeyboardInputData[i].MakeCode);
			}
			// Key Release
			else if (KEY_BREAK == pKeyboardInputData[i].Flags)
			{
    
    
				// 按键扫描码
				DbgPrint("[Up][0x%X]\n", pKeyboardInputData[i].MakeCode);
			}
			//可以添加上这这一句,然后按键全部被改为了 按下 A
//			pKeyboardInputData[i].MakeCode = 0x1e;
		}
	}

	if (pIrp->PendingReturned)
	{
    
    
		IoMarkIrpPending(pIrp);
	}

	// 减少IRP在队列的数量
	((PDEVICE_EXTENSION)pDevObj->DeviceExtension)->ulIrpInQuene--;

	status = pIrp->IoStatus.Status;
	return status;
}

Supongo que te gusta

Origin blog.csdn.net/qq_43312649/article/details/109222730
Recomendado
Clasificación