Step into Kernel (VMware 7+WinDbg)

4 de September de 2010 - Fernando Roberto

A primeira impressão, que alguns leitores mais antigos podem estar tendo agora, é a de que eu estou ficando realmente sem tempo de escrever novos posts, e por isso, esse novo post seria apenas uma repetição do post Step into Kernel (WMware+WinDbg). Na verdade estou tão surpreso quanto alguns de vocês. Neste post vou falar sobre um pequeno detalhe que vai fazer diferença na hora de fazer debug de Kernel utilizando uma máquina virtual criada com a nova versão da VMware.

O Sintoma

Neste último final de semana, apesar do feriado, do sol e da imensa vontade de pôr o pé na estrada,  tive que ficar em casa resolvendo algumas tretas pessoais. Uma delas envolvia fazer debug de Kernel numa máquina virtual. Nada de incomum nisso até agora. Afinal de contas, fazer debug de Kernel em máquinas virtuais é arroz com feijão para quem trabalha desenvolvendo drivers.

Criei uma VM nova e instalei o Windows nela, realizei as configurações TARGET e HOST exatamente como descrevo naquele outro post, mas para minha surpresa, por algum motivo o WinDbg não conseguia se conectar ao sistema TARGET, permanecendo sempre com a mesma mensagem “Waiting to reconnect…”. Mesmo usando o Ctrl+Alt+D no WinDbg para ver informações internas do depurador, tudo o que eu tinha na saída do WinDbg era a mensagem exibida abaixo.

 
Microsoft (R) Windows Debugger Version 6.12.0002.633 AMD64
Copyright (c) Microsoft Corporation. All rights reserved.
 
Opened \\.\pipe\com_1
Waiting to reconnect...
>>>> ReadAll(0x800703E3,1,0) fails.
>>>> ReadAll(0x800703E3,1,0) fails.
>>>> ReadAll(0x800703E3,1,0) fails.
>>>> ReadAll(0x800703E3,1,0) fails.
>>>> ReadAll(0x800703E3,1,0) fails.
>>>> ReadAll(0x800703E3,1,0) fails.
SYNCTARGET: Timeout.
>>>> ReadAll(0x800703E3,1,0) fails.
Throttle 0x10 write to 0x1
>>>> ReadAll(0x800703E3,1,0) fails.
>>>> ReadAll(0x800703E3,1,0) fails.
>>>> ReadAll(0x800703E3,1,0) fails.

Depois de verificar todos os passos minuciosamente várias vezes, eu não conseguia entender o que estava acontecendo.

A Causa

Ao criar uma nova porta serial na máquina virtual, a qual seria redirecionada para um named pipe na máquina real, reparei que seu nome estava fora do comum. Apesar de esta ser supostamente a única porta serial do sistema, a interface de edição de configurações da VMware mostrava seu nome como “Serial Port 2” como mostra a figura abaixo.

Desconfiei disso e tentei recriar a porta serial achando que seria um bug na inteface da VMware, mas o mesmo nome apareceu. Então nada melhor que abrir o arquivo de configuração da VM no bom e velho Notepad. Foi então que descobri que apesar de não haver uma porta serial além da que eu estava criando na interface de edição da VMware, no arquivo de configuração de fato haviam duas portas seriais como mostro abaixo.

.encoding = "windows-1252"
config.version = "8"
virtualHW.version = "7"
scsi0.present = "TRUE"
scsi0.virtualDev = "lsisas1068"
memsize = "1024"
mem.hotadd = "TRUE"
scsi0:0.present = "TRUE"
scsi0:0.fileName = "Windows 7 x64.vmdk"
ide1:0.present = "TRUE"
ide1:0.autodetect = "TRUE"
ide1:0.deviceType = "cdrom-raw"
floppy0.startConnected = "FALSE"
floppy0.fileName = ""
floppy0.autodetect = "TRUE"
ethernet0.present = "TRUE"
ethernet0.connectionType = "nat"
ethernet0.virtualDev = "e1000"
ethernet0.wakeOnPcktRcv = "FALSE"
ethernet0.addressType = "generated"
usb.present = "TRUE"
ehci.present = "TRUE"
sound.present = "TRUE"
sound.fileName = "-1"
sound.autodetect = "TRUE"
mks.enable3d = "TRUE"
serial0.present = "TRUE"
serial0.fileType = "thinprint"
pciBridge0.present = "TRUE"
pciBridge4.present = "TRUE"
pciBridge4.virtualDev = "pcieRootPort"
pciBridge4.functions = "8"
pciBridge5.present = "TRUE"
pciBridge5.virtualDev = "pcieRootPort"
pciBridge5.functions = "8"
pciBridge6.present = "TRUE"
pciBridge6.virtualDev = "pcieRootPort"
pciBridge6.functions = "8"
pciBridge7.present = "TRUE"
pciBridge7.virtualDev = "pcieRootPort"
pciBridge7.functions = "8"
vmci0.present = "TRUE"
roamingVM.exitBehavior = "go"
displayName = "Windows 7 x64"
guestOS = "windows7-64"
nvram = "Windows 7 x64.nvram"
virtualHW.productCompatibility = "hosted"
printers.enabled = "TRUE"
extendedConfigFile = "Windows 7 x64.vmxf"
ide1:0.startConnected = "TRUE"
ethernet0.generatedAddress = "00:0c:29:91:aa:62"
tools.syncTime = "FALSE"
uuid.location = "56 4d a8 8a e8 f9 f0 a8-62 de e8 25 40 91 aa 62"
uuid.bios = "56 4d a8 8a e8 f9 f0 a8-62 de e8 25 40 91 aa 62"
cleanShutdown = "FALSE"
replay.supported = "FALSE"
replay.filename = ""
scsi0:0.redo = ""
pciBridge0.pciSlotNumber = "17"
pciBridge4.pciSlotNumber = "21"
pciBridge5.pciSlotNumber = "22"
pciBridge6.pciSlotNumber = "23"
pciBridge7.pciSlotNumber = "24"
scsi0.pciSlotNumber = "160"
usb.pciSlotNumber = "32"
ethernet0.pciSlotNumber = "33"
sound.pciSlotNumber = "34"
ehci.pciSlotNumber = "35"
vmci0.pciSlotNumber = "36"
scsi0.sasWWID = "50 05 05 6a e8 f9 f0 a0"
vmotion.checkpointFBSize = "134217728"
usb:0.present = "TRUE"
usb:1.present = "TRUE"
ethernet0.generatedAddressOffset = "0"
vmci0.id = "1083288162"
usb:1.deviceType = "hub"
usb:0.deviceType = "mouse"
ide1:0.fileName = "auto detect"
unity.wasCapable = "FALSE"
serial1.yieldOnMsrRead = "TRUE"
serial1.fileName = "\\.\pipe\com_1"
serial1.pipe.endPoint = "server"
 

A propriedade “filetype” com o valor “thiprint” na porta serial zero me fez prestar atenção neste novo hardware que fazia parte das configurações da minha máquina virtual e eu nem tinha reparado.

O fato de essa impressora utilizar a porta COM1 da máquina virtual como interface de hardware, fazia com que qualquer nova porta serial utilizasse a COM2, que seria a próxima porta vaga. Agora ficou simples de resolver.

A Solução

Existem duas maneiras de resolver esse pequeno contratempo. A primeira, que minha opinião é mais simples e tosco, é simplesmente remover a impressora antes de adicionar a porta serial que será utilizada como interface de debug. Isso fará com que a primeira porta serial seja realmente utilizada como porta serial. Caso você necessite utilizar a impressora, então adicione e impressora após a adição da porta serial. Isso fará com que a impressora utilize a primeira porta serial disponível, que no caso é a COM2. A janela de configuração de hardware da VMware deve ficar como exibida na figura abaixo.

Reparem que o nome da porta serial não leva mais o número 2 enquanto que na configuração da impressora diz que a porta utilizada é a serial 2.

A segunda solução, como uma alternativa à primeira, é simplesmente configurar o lado TARGET para que ele utilize a porta serial 2. No exemplo da figura abaixo, eu mudo a configuração de um Windows 7 utilizando a ferramenta BcdEdit. Já comentei dessa ferramenta neste post, que fala sobre como fazer debug de Kernel através de portas USB utilizando o Windows Vista.

Depois de tudo resolvido, o depurador agora conecta ao sistema TARGET e agora vem a parte mais fácil; depurar o problema. 😉

Até mais!

12 Responses to “Step into Kernel (VMware 7+WinDbg)”

  1. […] This post was mentioned on Twitter by Wanderley Caloni, Fernando Roberto. Fernando Roberto said: Novo post fala sobre os problemas em conectar o WinDbg no Kernel de uma VM criada pela VMware 7. http://bit.ly/bWHIhS […]

  2. Miranda says:

    Olá, primeiramente gostaria de agradecê-lo por disponibilizar um espaço com tanta informação valiosa
    a respeito de um assunto tão complexo que é o desenvolvimento de drivers.
    Desenvolvi um hardware USB genérico que não utiliza drivers específicos. Ele funciona muito bem com XP, mas em windows Vista e Seven não é reconhecido. O Hardware em questão é uma interface USB-MIDI(utilizada para a comunicação entre instrumentos musicais e computadores) e dando uma googleada parece que não sou o único com este problema. A microsoft disponibilizou hotfixes mas não surtiram efeito. Tentei muitas alternativas mirabolantes e “ad hoc” para o hardware funcionar e sem sucesso!
    Então cheguei na conclusão que não queria (ou queria?): “Tenho que desenvolver um driver!”.
    Já li bastante coisa a respeito e parece que tenho que criar um miniport driver para uma porta MIDI e dele repassar as informações via usb para o dispositivo. Pode me adiantar se isto é a maneira correta?

    Desde já obrigado, pela atenção.

  3. […] already. Also in Device Manager on the VM it mentioned that the COM1 was already in use. Then I hit this article. Now I don’t read Portuguese but the pictures are quite self-explanatory. Apparently when you […]

  4. Gabriel says:

    Ola Fernando,

    Parabens pelos post, sempre aprendo um pouquinho mais aqui no seu blog!!!
    Mais vamo la, me surgiu uma duvida:
    Seria possivel um driver criar um processo de uma aplicacao externa, ou melhor um Driver chamar um .exe de terceiro ?
    A funcao CreateProcess da API do Windows funciona em Drivers ?
    Obrigado

    • Olá Gabriel,

      Infelizmente não é possível (de maneira documentada) disparar a criação de um processo a partir do kernel. A criação de processos depende de chamadas de rotinas que estão definidas na NTDLL.DLL. Tais rotinas não seguem a implementação típica de repassar chamadas de rotinas Zw para rotinas Nt, o código mora de fato na DLL. Por essa razão, um driver não consegue chamá-las.

      Os passos para a criação de um processo são ricamente descritos no capítulo 6 do Windows 2000 Native API Reference. Nessa parte o livro mostra como fazer um fork no Windows.

      Uma coisa que já cheguei a fazer foi simular a presença de chaves no registro usando filtro de Registry. Assim você pode fazer com que o Explorer.exe dispare um executável para você durante o processo de logon. Na verdade eu já fiz algo parecido num post. Dê uma olhada nos fontes de exemplo do post do link abaixo.

      Debug ou falha de segurança?

      Um abraço.

  5. Fabiano says:

    Boa noite Fernando,

    Quando compilo o driver como Checked, e edito ele pelo Notepad consigo enxergar as Strings exatamente igual ao codigo fonte.
    Existe alguma maneira de obfuscar o codigo, ou compactar como se faz com exe’s ???
    E existe alguma API que faça criptografica em low level ????
    um grande abraço e agradecido desde de ja!!!!

  6. Coelho says:

    Olá Fernando,

    Preciso monitorar toda informação que se passa em uma porta Serial. “Googleando” um pouquinho, descobri que é necessário utilizar de Hooking, e gostaria de saber se você tem alguma experiência com Hook em Kernel Mode, especificamente em porta Serial!
    Tem algum ponto de partida ? Algum material ? Estou disposto a desenvolver um Driver para tal função, pois tenho um Driver que funciona belezinha no XP, porem no Vista não…

    Obrigado

    • Olá Coelho,

      Na verdade você precisaria desenvolver um filtro. Um filtro é um hook comportado e documentado. Uma pena não existir um exemplo disso no WDK.
      Bom, utilize o WDK para escrever o filtro. Isso vai lhe fazer ganhar algum tempo.
      Uma documentação básica pode ser encontrada neste livro enquanto uma referência mais completa pode ser encontrada nesse outro livro.

      Have fun!

  7. Boa noite, Fernando.

    Eu sei que tirar uma dúvida minha com você é como usar uma bomba atômica para matar uma formiga. Mas se pudesse apenas me mostrar a direção, ficaria bastante grato.

    Pelo menos comigo, é muito comum utilizar algum hardware que se conectado antes da instalação do driver, o mesmo não funciona.

    Apesar de ser extremamente comum, ligar uma máquina com um novo hardware encaixado e só dentro do SO apontar para um driver, em alguns casos, o SO “comete uma ação sem volta”.

    É o caso de um equipamento USB que estou testando no momento.

    Pensei que não havia mais o drive e o conectei, seguro que através do “VEN_ABCD” e do “DEV_EFGH” seria capaz de encontrar o driver.

    Mas o dispositivo é detectado literalmente como “VID_0000” e “PID_0000”.

    Já tentei, em modo de segurança, apagar todas referências do mesmo no registro. E re-instalar o software. Mas o resultado é sempre o mesmo: “dispositivo desconhecido”.

    Como sabia que o equipamento não estava com defeito, instalei o driver em outra máquina e só depois de instalado, conectei o dispositivo. E desta forma, o dispositivo funciona corretamente e é reconhecido com VID e PIDs distintos.

    Não sou programador de driver. Mas qualquer dica me seria muitíssimo útil.

    Muito obrigado e boa noite!

  8. wellington says:

    Cara, valeu pela informação…

Deixe um comentário