Escrever um driver de laptop para diversão e lucro ou Como se comprometer com o kernel, mesmo que você não seja tão inteligente

Onde tudo começou


Vamos começar com a nossa declaração do problema. Temos 1 (um) laptop. Um novo laptop para jogadores. Com alguma luz de fundo RGB no teclado. É assim:

imagem
Foto tirada no lenovo.com

Há também um programa instalado neste laptop. É isso que controla nossa luz de fundo.

Um problema - o programa é executado no Windows e queremos que tudo funcione no nosso Linux favorito. Quer que os LEDs pisquem e que cores bonitas pisquem e apagem, e assim por diante. Uma questão natural surge: podemos fazer tudo isso sem fazer engenharia reversa e escrever nossos próprios drivers?

Uma resposta natural surge, não. Vamos abrir a IDA e começar a quebrar.



Etapa 1 - Digitando o código


Existem três gatilhos que fazem a luz de fundo brilhar. Em ordem de dificuldade crescente:

1. Um programa de jogadores com grandes buffs chamado Lenovo Nerve Center, que possui um menu de configuração de grandes buffs apenas para essa luz de fundo.

2. Combinação de teclas de atalho Fn + Space - possivelmente gerenciada pelo programa acima mencionado também.

3. BIOS. Enquanto o laptop está carregando, a luz de fundo pisca em vermelho por um breve momento. Talvez possamos usar isso?

Eu tive que tentar todos os 3. Mas houve algum sucesso apenas ao longo do primeiro, então vamos falar sobre o primeiro aqui.

Abrimos a pasta com o nosso programa:

pasta

Observe aqui! Há uma DLL com um nome muito interessante - LedSettingsPlugin.dll. Poderia ser ...? Vamos abri-lo no IDA Pro e ver por nós mesmos.

metade direita

Veja a metade direita da tela aqui - tantas informações de depuração! Vamos usá-lo. Algumas strings parecem nomes de função aqui. Eu me pergunto por que ...

nome da função

Oh, esses são nomes de funções. Conveniente! Vamos chamar algumas coisas com seus próprios nomes e depois ver a lista de funções novamente. Para nomear itens na IDA, você pode usar a tecla de atalho N ou clicar com o botão direito do mouse na coisa que deseja nomear.

setledstatusex

Observando as funções, vemos algo chamado Y720LedSetHelper :: SetLEDStatusEx. Parece que precisamos! Ele forma algum tipo de string e, em seguida, o atribui a algo chamado CHidDevHelper :: HidRequestsByPath. A parte interessante que devemos examinar é var_38, destacada com carinho pela IDA.

Var_34 também é interessante. Isso acontece logo após var_38 - nas tradições assembler, as variáveis ​​são armazenadas em ordem inversa no RSP. Var_34 no IDA é apenas o nome da constante - -34h.

A partir de var_38, nosso programa coloca zero, depois estilo, cor, o número três e o bloco - parte do teclado que ganhará essa cor. (Mais tarde, os experimentos mostrarão que o número três é realmente o brilho. Adicionar um controle sobre isso tornará nosso motorista ainda melhor do que o oficial!)

Agora, vamos nos aprofundar no HidRequestsByPath e tentar descobrir o que precisamos enviar e para onde.

devhelper

Olha, duas funções. HidD_GetFeature e HidD_SetFeature.

Eles não são rastreados no arquivo ... mas são muito bem rastreados na documentação oficial da Microsoft - aqui e aqui .

Bem, podemos dar um tapinha nas costas agora. Este é o fundo do poço, não há onde cavar mais fundo. O Linux tem essas duas funções - nós apenas retornamos e as chamamos com os mesmos argumentos. ... certo?

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



Não exatamente. Vamos voltar ao Linux e abrir o lsusb. Encontraremos nosso teclado lá e enviaremos algo para ele.

lsusb

Integrated Technology Express, Inc. é o mais interessante aqui. Vamos usar a ferramenta popular / dev / hidraw. Podemos encontrar o correto apenas olhando para o / sys / class / hidraw / hidraw * / device / uevent correspondente.

hidraw

Este aqui. Todos os dígitos correspondem - o que significa / dev / hidraw0 é o nosso dispositivo. Mas vamos tentar enviar algo ... e nada acontece! Porque Nesse ponto, o burnout entra em ação. Talvez não seja por meros mortais, essa coisa de engenharia reversa?

Mas vamos continuar tentando. Se o autor fosse mais bom nisso, ele teria revertido o Nerve Center um pouco mais e teria uma solução ... Mas não temos cérebro. Vamos reiniciar no Windows, há uma ideia.

Existe essa coisa no Windows - o Gerenciador de dispositivos, como eles chamam. Tem muitas funções - mas estamos interessados ​​em uma. Permite desativar dispositivos. Simples e autoritário.

Então, vamos desativar todos os dispositivos até que nosso LED pare de piscar!

desativar dispositivo

Isso foi feito. Se espiarmos o seu ID de hardware - veremos o que é, esse misterioso dispositivo de LED.

nosso dispositivo

Olha - é ele.

dmesg

O dispositivo que incomoda meu dmesg há vários anos.

[Por que não foi mostrado em LSUSB? Não é USB, é claro! A luz de fundo usa um protocolo chamado I2C HID - permite que o fabricante esconda o dispositivo das mãos de pessoas mal-intencionadas de DIY e instale gadgets HID no barramento do sistema do próprio computador.]

Sidestep 2.5 - vamos fazer um commit


Essa busca pelo dispositivo correto foi fortemente abreviada. Na versão original, eu tive que abrir minha configuração quase até o kernel antes de perceber por que nada funcionava. Além disso, eu não gostei desse log do dmesg aparecendo para mim toda vez que desbloqueio o computador. Já que estamos aqui - por que não escrever um pequeno commit?

Precisamos encontrar duas coisas - o local onde os dispositivos I2C HID são manipulados e o local onde suas peculiaridades são armazenadas. Aqui. Não vamos pensar muito e analisar o erro: relatório incompleto. Vamos completar.

tamanho de entrada ruim

Adicione uma nova peculiaridade, vamos chamá-la de I2C_HID_QUIRK_BAD_INPUT_SIZE ou algo assim. Para manter o tema.

peculiaridade

Também vamos adicionar nosso dispositivo à lista de peculiaridades. O que fizemos até agora:

1. Procurei "i2c hid linux kernel" em um mecanismo de pesquisa. Clicou no quarto resultado no DuckDuckGo.

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

3. Adicionado um ao BIT (4). Resultado - BIT (5).

4. Adicionado um número ao hid-ids.h - o ID do nosso dispositivo (não ilustrado, mas com dificuldade semelhante)

Somos programadores, vamos fazer uma programação agora.

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

E depois reclama que ret_size não é o que quer.

Sempre que nossa peculiaridade estiver ativa, vamos fazer isso apenas ao contrário.

if-condition

Envie o patch para a lista de discussão ... (teste antes!). Para ser sincero, entrar nessa lista de discussão foi mais complicado que o patch atual. Não é simples de forma alguma.

aplicado

É isso aí!

Etapa 3 - motorista!


Nesse ponto, lembrei - eu estava tentando escrever um driver. Decidi que não vou comprometer isso com o kernel ainda - as perguntas começaram a surgir; nesse momento, você realmente precisa pensar em algumas. Se alguém lendo isso é bom no kernel e pode me consultar, ficaria feliz em falar.

Vamos abrir o python. (Costumava ser festança, mas você muda de idéia muito rapidamente com esse tipo de linguagem). Vamos usar a ferramenta popular / dev / hidraw.

/ dev / hidraw0, / dev / hidraw1 - como esses arquivos funcionam? Para E / S simples, você pode usá-las como qualquer outra, e parece que isso funcionaria. E GetFeature e SetFeature - bem, essa é uma história completamente diferente.

O StackOverflow (ou qualquer outra pessoa, não me lembro) me disse que eu teria que procurar algo chamado ioctl. É uma maneira especial de trabalhar com arquivos incomuns, como dispositivos HID, terminais e coisas nojentas semelhantes.

Parece simples na superfície - você fornece um identificador de arquivo aberto (não no nível Python, no SO! Leia mais sobre identificadores do SO aqui, se quiser saber.) algo com esse buffer e devolva para você. Eu não estou tentando ser inteligente aqui, é apenas que é quase totalmente dependente da implementação. Aqui está um exemplo: 0xC0114806. O que é isso? Isso é SetFeature. Isso também

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

Os 6 primeiros significam que o arquivo será aberto tanto para leitura quanto para gravação. Nós escrevemos apenas, mas os documentos disseram 6, o que significa que colocamos 6. Ord ('H') significa HID. Às vezes, representa outras coisas, dependendo do arquivo. Mas agora está escondido.

0x06 é o próprio comando. O sexto comando do HID é o SetFeature, do qual precisamos. E a última parte? O tamanho do buffer.

Tudo o que resta é juntá-lo em uma chamada ioctl e você recebe um motorista. Isso funciona. .

Posfácio do autor


Espero que o artigo tenha sido uma leitura interessante. Até uma leitura útil, possivelmente. Algumas partes foram omitidas ou encurtadas por questões de concisão - um leitor mais atento pode perceber que o driver pode ler o estado atual do teclado e a função set_status possui uma segunda chamada ioctl que nem foi mencionada no texto. O desenvolvimento de hardware e o kernel Linux são grandes coisas, e um conto não cobre tudo. E no final do dia, talvez o artigo não seja sobre isso. Talvez seja apenas sobre como fazer algo pequeno e bom, para código aberto ou para si mesmo, não seja nada difícil. Você só precisa encontrar o valor de uma semana de noites gratuitas, um pouco de chá e um desejo de procurar por códigos.

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


All Articles