Escrevemos um driver para um laptop para diversão e lucro, ou como se comprometer com o kernel, mesmo que você seja um tolo

Como tudo começou


Vamos começar colocando o problema. Dado: um laptop. Novo laptop, jogos. Com luz de fundo RGB. Aqui está um laptop como este:

imagem
Imagem retirada de lenovo.com

Há também um programa para este laptop. O programa apenas controla essa luz de fundo.

O único problema é o programa para Windows, mas quero que tudo funcione no seu Linux favorito. E lâmpadas para brilhar, e assim cores bonitas tremeluziam. Sim, é assim que se faz, para que, sem engenharia reversa e sem escrever seus drivers? A resposta simples veio rapidamente - de jeito nenhum. Bem, vamos escrever um driver.

Etapa 1 - investigando o código


Temos três lugares a partir dos quais você pode ver como a luz de fundo pisca. Em ordem crescente de dificuldade:

1. Um programa de jogos grande e otimizado, o Lenovo Nerve Center - no qual há uma função para configurar toda essa luz de fundo.

2. A combinação das teclas de atalho Fn + Space é possível. é processado pelo mesmo programa.

3. BIOS. Enquanto o laptop está carregando, a luz de fundo também pisca - mas apenas em vermelho e apenas por um segundo.

Olhando para o futuro, direi que tive que tentar os três, mas progredi com algum sucesso apenas no primeiro. Nós falaremos sobre ela.

Bem, abra a pasta do programa:

pasta

Notamos imediatamente que existe uma DLL com um nome interessante - LedSettingsPlugin.dll. É o nosso ...? Vamos abrir no IDA Pro e dar uma olhada.

metade direita

Preste atenção na metade direita da tela. Há muita informação deixada pelos programadores - nós a usaremos. Vemos que, por algum motivo, existem muitas linhas semelhantes aos nomes dos métodos. Porque

nome da função

E estes são os nomes dos métodos. Quão conveniente! Digamos o que podemos com nossos próprios nomes e vejamos a lista de funções novamente. Para nomear na IDA, você pode usar a tecla de atalho N ou apenas clicar com o botão direito do mouse no que queremos chamar.

setledstatusex

Examinamos as funções ... Y720LedSetHelper :: SetLEDStatusEx. Parece que precisamos! Percebemos que algo como uma string é formado aqui e depois passado para um determinado CHidDevHelper :: HidRequestsByPath. Especificamente interessado em var_38, todas as metamorfoses que a IDA gentilmente designou para nós.

Var_34 também é interessante para nós. Isso ocorre logo após var_38 - na tradição da montagem, as variáveis ​​são armazenadas em ordem inversa no RSP. Var_34 aqui é apenas o nome da constante - -34h.

Entendemos que a partir de var_38 o programa coloca zero, então o estilo, cor, número três e o bloco são a parte do teclado à qual essa cor será aplicada. (Olhando para o futuro, direi que três é o valor do brilho aqui. Após torná-lo gerenciável, deixamos o motorista ainda mais frio que o original!)

Vamos entrar no HidRequestsByPath e finalmente descobrir como vai.

devhelper

Vemos duas funções, HidD_GetFeature e HidD_SetFeature. Ambos no arquivo não são rastreados ... Mas eles são muito bem rastreados na documentação oficial da Microsoft - aqui e aqui .

Você pode se felicitar por isso - chegamos lá. Este é o fundo, não há necessidade de ir mais fundo. No Linux, existem essas funções - você só precisa chamá-las com os mesmos argumentos, e tudo deve dar certo ... é verdade?

Etapa 2 - lançar o protótipo ...?


Na verdade não. Vamos começar simples e executar o lsusb. Então, encontramos o teclado e enviamos algo para ele.

lsusb

Integrated Technology Express, Inc. parece o mais interessante aqui. Usaremos a famosa ferramenta / dev / hidraw. Nós encontramos o caminho certo ... Isso é feito através de uma pesquisa simples nos arquivos / sys / class / hidraw / hidraw * / device / uevent.

hidraw

Aqui está um. Os números são os mesmos - isso significa que este dispositivo é hidraw0. Mas estamos tentando enviar dados e nada acontece! Algum tipo de bobagem. Nesse estágio, as mãos começam a cair ... Talvez, não para meros mortais, seja essa engenharia reversa?

Mas vamos continuar. Vamos tentar. Se o autor entendesse tudo isso, ele reverteria a busca por nosso motorista no mesmo Centro Nervoso ... Mas não temos cérebro. Vamos voltar ao Windows, há uma ideia.

Existe uma coisa dessas no Windows - Gerenciador de dispositivos. Ele permite que você faça muito - estamos interessados ​​no fato de permitir cortar dispositivos. Simples e intransigente.

Vamos cortar os dispositivos um de cada vez até que o estado das lâmpadas pare de mudar.

desativar dispositivo

Este foi cortado. Portanto, se você olhar para o ID do hardware, veremos qual é o nome dele e o que ele come.

nosso dispositivo

Nós olhamos - é ele.

dmesg

Um dispositivo que venho inundando há vários anos no dmesg.

[Por que ele não apareceu em LSUSB? E nem USB. Ele usa o protocolo I2C HID, que permite ocultar dispositivos das mãos inquisitivas dos artesãos para instalar dispositivos HID no barramento do próprio computador.]

Digressão lírica - vamos nos comprometer


Em busca do dispositivo correto, peguei minha instalação quase no kernel. Além disso, não gostei muito do que mostrei esta folha de dmesg antes de cada bloqueio. Como estou aqui, por que não escrever um pequeno commit? As mãos coçam de qualquer maneira.

O que precisamos ver é onde os dispositivos estão no I2C HID e onde escrever quais esquisitices são inerentes a eles. Aqui. Sem mais delongas, vamos ouvir o erro - comprimento incorreto da entrada. Vamos corrigir isso.

tamanho de entrada ruim

Adicione uma nova peculiaridade, vamos chamá-la de I2C_HID_QUIRK_BAD_INPUT_SIZE. Por analogia com os existentes.

peculiaridade

Adicione nosso dispositivo à lista de quirkut. O que fizemos até agora:

1. Pesquise na Internet “i2c hid linux kernel”. Clicou na quarta resposta ao DuckDuckGo.

2. Escreveu três (!) Palavras em inglês - BAD_INPUT_SIZE

3. Adicionado um ao BIT (4). Descobriu-se o BIT (5).

4. Adicionamos um número em hid-ids.h - o ID do nosso dispositivo (não mostrado na ilustração, mas também existe aproximadamente).

Vamos programar agora.

Vemos a linha - `ret_size = ihid-> inbuf [0] | ihid-> inbuf [1] << 8; `

E depois reclama que ret_size não é igual ao que deseja.

Se o estranho estiver envolvido, faça a mesma coisa, exatamente o oposto.

if-condition

Enviamos o patch para a lista de discussão, sem esquecer de testar ... (para ser sincero, bastava mais para adicionar ao boletim do cérebro. Não é fácil.)

aplicado

E é isso.

Etapa 3 - o motorista!


Então me lembrei - oh sim, você ainda precisa escrever um driver. Decidi não entregá-lo ao kernel ainda (as perguntas começaram a ser levantadas lá, eu realmente tinha que pensar. Se algum cidadão de Habrovsk pode me ajudar a aconselhar, escreva para mim - ficarei feliz!)

Abra o python. (No início, o bash era, mas mudei de idéia muito rapidamente.) Usaremos a conhecida ferramenta / dev / hidraw.

/ dev / hidraw0, / dev / hidraw1 - como esses arquivos funcionam? Para E / S simples, elas podem ser usadas como qualquer arquivo normal e funcionarão. Mas GetFeature e SetFeature precisam mexer com ...

O StackOverflow (ou alguém que ainda não me lembro) sugeriu que ele precisava de algum ioctl. Este é um método especial para trabalhar com arquivos incomuns, como dispositivos HID, terminais e similares.

Ioctl funciona assim. Você fornece a ele um descritor de arquivo aberto (que está interessado no que é, há um link para a Wikipedia ), algum número e um buffer - após o que ele faz algo com esse buffer e o devolve. Eu não vou exagerar, apenas muitas coisas dependem da implementação. Deixe-me dar um exemplo: 0xC0114806, ou já familiar para nós SetFeature. É

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

Os 6 primeiros aqui significam que o arquivo será aberto para escrita e leitura. Por que a leitura não é muito clara - mas está escrita para isso, provavelmente deveria. Ord ('H') aqui - abreviado HID. Talvez outras coisas signifiquem, dependendo do arquivo. Nesse caso, o HID.
0x06 - o próprio time. A sexta equipe da HID é a SetFeature. A última parte é o comprimento do buffer.

Resta apenas chamar ioctl com esses valores - e a saída é o driver. Ele está trabalhando

Posfácio


Espero que tenha sido interessante ler. Mesmo útil, talvez. Alguns foram omitidos ou abreviados - talvez o leitor perspicaz descubra a leitura do estado no driver, e algum segundo SetFeature, que não foi mencionado no texto. O desenvolvimento de drivers e o kernel do Linux são grandes coisas, e eles não podem ser completamente dominados em uma bicicleta. O artigo provavelmente não é sobre isso, mas sobre o fato de que fazer algo pequeno e agradável, de código aberto ou para você, não é nada difícil. Você só precisa encontrar uma semana de noites com chá e um desejo de se aprofundar no código.

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


All Articles