Escribir un controlador de computadora portátil para divertirse y obtener ganancias, o Cómo comprometerse con el kernel incluso si no es tan inteligente

Donde todo comenzó


Comencemos con nuestra declaración del problema. Tenemos 1 (una) computadora portátil. Una nueva computadora portátil para jugadores. Con algo de luz de fondo RGB en su teclado. Se ve así:

imagen
Foto tomada de lenovo.com

También hay un programa instalado en esta computadora portátil. Eso es lo que controla nuestra luz de fondo.

Un problema: el programa se ejecuta en Windows y queremos que todo funcione en nuestro Linux favorito. Quiere que los LED parpadeen y que esos bonitos colores parpadeen y aparezcan. Surge una pregunta natural, ¿podemos hacer todo eso sin realizar ingeniería inversa y escribir nuestros propios controladores?

Surge una respuesta natural, no. Abramos IDA y empecemos.



Paso 1 - Excavando el código


Hay tres disparadores que hacen que la luz de fondo brille. En orden de dificultad ascendente:

1. Programa de jugador de gran beneficio llamado Lenovo Nerve Center, que tiene un gran menú de configuración de beneficio solo para esta luz de fondo.

2. Combinación de teclas de acceso rápido Fn + Espacio: posiblemente también administrado por el programa mencionado anteriormente.

3. BIOS. Mientras se carga la computadora portátil, la luz de fondo parpadea en rojo por un breve momento. Tal vez podamos usar eso?

Tuve que probar los 3. Pero hubo algo de éxito solo en el primero, así que hablemos del primero aquí.

Abrimos la carpeta con nuestro programa:

carpeta

¡Aviso aquí! Hay una DLL con un nombre muy interesante: LedSettingsPlugin.dll. ¿Podría ser ...? Vamos a abrirlo en IDA Pro y ver por nosotros mismos.

mitad derecha

Mire la mitad derecha de la pantalla aquí, ¡tanta información de depuración! Vamos a usarlo Algunas cadenas parecen nombres de funciones aquí. Me pregunto por qué ...

nombre de func

Oh, estos son nombres de funciones. Conveniente! Llamemos a algunas cosas por sus propios nombres y luego volvamos a mirar la lista de funciones. Para nombrar cosas en IDA, puede usar la tecla de acceso rápido N, o simplemente hacer clic con el botón derecho en la cosa que desea nombrar.

setledstatusex

Mirando las funciones, vemos algo llamado Y720LedSetHelper :: SetLEDStatusEx. ¡Parece lo que necesitamos! Forma una especie de cadena y luego se la da a algo llamado CHidDevHelper :: HidRequestsByPath. La parte interesante que deberíamos mirar es var_38, cariñosamente resaltada por IDA.

Var_34 también es interesante. Va justo después de var_38: en las tradiciones de ensamblador, las variables se almacenan en orden inverso bajo el RSP. Var_34 en IDA es solo el nombre de la constante - -34h.

A partir de var_38, nuestro programa pone un cero, luego estilo, color, el número tres y el bloque, parte del teclado que ganará este color. (Más adelante, los experimentos mostrarán que el número tres es en realidad el brillo. ¡Agregarle un control hará que nuestro controlador sea aún mejor que el oficial!)

Ahora, profundicemos en HidRequestsByPath e intentemos averiguar qué necesitamos enviar y dónde.

devhelper

Mira, dos funciones. HidD_GetFeature y HidD_SetFeature.

No se rastrean en el archivo ... pero se rastrean muy bien en la documentación oficial de Microsoft, aquí y aquí .

Bueno, podemos darnos palmaditas en la espalda ahora. Este es el fondo de la roca, no hay ningún lugar para cavar más profundo. Linux tiene esas dos funciones: simplemente regresamos y las llamamos con los mismos argumentos. ... verdad?

Paso 2: ¿lanzar el prototipo ...?



No exactamente Volvamos a Linux y abramos lsusb. Encontraremos nuestro teclado allí y le enviaremos algo.

lsusb

Integrated Technology Express, Inc. Es el más interesante aquí. Usemos la popular herramienta / dev / hidraw. Podemos encontrar el apropiado simplemente mirando el / sys / class / hidraw / hidraw * / device / uevent correspondiente.

hidraw

Este Todos los dígitos coinciden, eso significa que / dev / hidraw0 es nuestro dispositivo. Pero intentemos enviar algo ... ¡y no pasa nada! Por qué En este punto, el agotamiento comienza. ¿Quizás no es para simples mortales, esta cosa de ingeniería inversa?

Pero sigamos intentándolo. Si el autor fuera más bueno en esto, habría invertido un poco más el Centro Nervioso y llegaría a una solución ... Pero no tenemos cerebro. Reiniciemos a Windows, hay una idea.

Hay una cosa en Windows: Administrador de dispositivos, lo llaman. Tiene muchas funciones, pero estamos interesados ​​en una. Le permite deshabilitar dispositivos. Simple y autoritario.

¡Así que desactivemos todos los dispositivos hasta que nuestro LED deje de parpadear!

deshabilitar dispositivo

Esto lo hizo. Si echamos un vistazo a su ID de hardware, veremos qué es, ese misterioso dispositivo LED.

nuestro dispositivo

Mira, es él.

dmesg

El dispositivo que ha estado molestando a mi dmesg durante varios años.

[¿Por qué no se mostró en lsusb? ¡No es USB en absoluto, por supuesto! La luz de fondo utiliza un protocolo llamado I2C HID: permite que el fabricante oculte el dispositivo de las manos malvadas de la gente de bricolaje e instale dispositivos HID en el bus del sistema de la computadora.]

Paso lateral 2.5 - hagamos un commit


Esta búsqueda del dispositivo correcto ha sido muy abreviada. En la narración original, tuve que abrir mi configuración casi hasta el núcleo antes de darme cuenta de por qué nada funcionaba. Además, no disfruté este registro de dmesg que se me muestra cada vez que desbloqueo mi computadora. Ya que estamos aquí, ¿por qué no ir y escribir una breve confirmación?

Necesitamos encontrar dos cosas: el lugar donde se manejan los dispositivos I2C HID y el lugar donde se almacenan sus peculiaridades. Aquí No pensemos demasiado y miremos el error: informe incompleto. Hagámoslo completo.

tamaño de entrada incorrecto

Agregue un nuevo capricho, llamémoslo I2C_HID_QUIRK_BAD_INPUT_SIZE o algo así. Para mantener la tematización.

peculiaridad

También agreguemos nuestro dispositivo a la lista de peculiaridades. Lo que hemos hecho hasta ahora:

1. Busqué "i2c hid linux kernel" en un motor de búsqueda. Hizo clic en el cuarto resultado en DuckDuckGo.

2. Escribió tres (!) Palabras en inglés - BAD_INPUT_SIZE

3. Se agregó uno a BIT (4). Resultado - BIT (5).

4. Se agregó un número a hid-ids.h: la identificación de nuestro dispositivo (no se ilustra, pero es similar en dificultad)

Somos programadores, hagamos algo de programación ahora.

Ver la linea:
ret_size = ihid->inbuf[0] | ihid->inbuf[1] << 8;

Y luego se queja de que ret_size no es lo que necesita.

Siempre que nuestro capricho esté activo, hagamos esto pero al revés.

si-condición

Envíe el parche a la lista de correo ... (¡pruébelo de antemano!). Para ser sincero, entrar en esa lista de correo fue más complicado que el parche real. No es simple de ninguna manera.

aplicado

Eso es todo!

Paso 3 - conductor!


En este punto recordé: estaba tratando de escribir un controlador. Decidí que aún no lo comprometeré con el kernel: comenzaron a surgir preguntas, en este punto realmente tienes que pensar un poco. Si alguien que lee esto es bueno en kernel y puede consultarme, me encantaría hablar.

Abramos python. (Solía ​​ser bash, pero cambias de opinión muy rápidamente con ese tipo de lenguaje). Usemos la popular herramienta / dev / hidraw.

/ dev / hidraw0, / dev / hidraw1: ¿cómo funcionan esos archivos? Para E / S simples, puede usarlas como cualquier otra, y parece que simplemente funcionaría. Y GetFeature y SetFeature, bueno, esa es una historia completamente diferente.

StackOverflow (u otra persona, no recuerdo) me dijo que tendría que investigar algo llamado ioctl. Es una forma especial de trabajar con archivos poco comunes como dispositivos HID, terminales y cosas desagradables similares.

Parece simple en la superficie: le das un identificador de archivo abierto (¡no Python-level, OS-level! Lee más sobre los identificadores de OS aquí si quieres saber), algún número y un búfer, y luego lo hace algo con ese búfer y te lo devuelve. No estoy tratando de ser ingenioso aquí, es solo que depende casi por completo de la implementación. Aquí hay un ejemplo: 0xC0114806. Que es eso Eso es SetFeature. Eso también

(6 << 29) | (ord('H') << 8) | (0x06 << 0) | (0x11 << 16).

Los primeros 6 significan que el archivo estará abierto tanto para lectura como para escritura. Solo escribimos, pero los documentos dicen 6 que significa que ponemos 6. Ord ('H') significa HID. A veces representa otras cosas, dependiendo del archivo. Pero ahora está OCULTADO.

0x06 es el comando en sí. El sexto comando de HID es SetFeature, que necesitamos. ¿Y la última parte? El tamaño del búfer.

Todo lo que queda es juntarlo en una llamada ioctl, y obtienes un controlador. Funciona .

Epílogo del autor


Espero que el artículo sea una lectura interesante. Incluso una lectura útil, posiblemente. Algunas partes se omitieron o se acortaron por brevedad: un lector más atento podría notar que el controlador puede leer el estado actual del teclado, y la función set_status tiene una segunda llamada ioctl que ni siquiera se menciona en el texto. El desarrollo de hardware y el kernel de Linux son cosas importantes, y una historia no lo cubrirá todo. Y al final del día, tal vez el artículo no sea sobre esto. Tal vez se trata solo de cómo hacer algo pequeño y bueno, para código abierto o para ti mismo, no es nada difícil. Solo necesita encontrar una semana de noches gratis, algo de té y un deseo de cavar en el código.

Source: https://habr.com/ru/post/484752/


All Articles