<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>DriverEntry.com.br</title>
	<atom:link href="http://driverentry.com.br/blog/?feed=rss2" rel="self" type="application/rss+xml" />
	<link>http://driverentry.com.br/blog</link>
	<description>Did you think it&#039;d be easy?</description>
	<lastBuildDate>Wed, 08 Sep 2010 18:04:20 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>Step into Kernel (VMware 7+WinDbg)</title>
		<link>http://driverentry.com.br/blog/?p=943</link>
		<comments>http://driverentry.com.br/blog/?p=943#comments</comments>
		<pubDate>Sat, 04 Sep 2010 23:39:21 +0000</pubDate>
		<dc:creator>Fernando Roberto</dc:creator>
				<category><![CDATA[Debug]]></category>
		<category><![CDATA[Kernel Development]]></category>

		<guid isPermaLink="false">http://driverentry.com.br/blog/?p=943</guid>
		<description><![CDATA[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 [...]]]></description>
			<content:encoded><![CDATA[<p>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 <a href="http://driverentry.com.br/blog/?p=433">Step into Kernel (WMware+WinDbg)</a>. 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.</p>
<h3>O Sintoma</h3>
<p>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.</p>
<p>Criei uma VM nova e instalei o Windows nela, realizei as configurações TARGET e HOST exatamente como descrevo <a href="http://driverentry.com.br/blog/?p=433">naquele outro post</a>, mas para minha surpresa, por algum motivo o WinDbg não conseguia se conectar ao sistema TARGET, permanecendo sempre com a mesma mensagem <em>&#8220;Waiting to reconnect&#8230;&#8221;. </em>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.</p>
<div style="font-family: Consolas; font-size: 9pt; color: black; background: #A4F64C; border: 1px outset; padding: 0 0 0 5px;">
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"> </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">Microsoft (R) Windows Debugger Version 6.12.0002.633 AMD64</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">Copyright (c) Microsoft Corporation. All rights reserved.</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"> </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">Opened \\.\pipe\com_1</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">Waiting to reconnect...</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">&gt;&gt;&gt;&gt; ReadAll(0x800703E3,1,0) fails.</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">&gt;&gt;&gt;&gt; ReadAll(0x800703E3,1,0) fails.</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">&gt;&gt;&gt;&gt; ReadAll(0x800703E3,1,0) fails.</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">&gt;&gt;&gt;&gt; ReadAll(0x800703E3,1,0) fails.</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">&gt;&gt;&gt;&gt; ReadAll(0x800703E3,1,0) fails.</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">&gt;&gt;&gt;&gt; ReadAll(0x800703E3,1,0) fails.</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">SYNCTARGET: Timeout.</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">&gt;&gt;&gt;&gt; ReadAll(0x800703E3,1,0) fails.</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">Throttle 0x10 write to 0x1</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">&gt;&gt;&gt;&gt; ReadAll(0x800703E3,1,0) fails.</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">&gt;&gt;&gt;&gt; ReadAll(0x800703E3,1,0) fails.</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">&gt;&gt;&gt;&gt; ReadAll(0x800703E3,1,0) fails.</pre>
</div>
<p>Depois de verificar todos os passos minuciosamente várias vezes, eu não conseguia entender o que estava acontecendo.</p>
<h3>A Causa</h3>
<p>Ao criar uma nova porta serial na máquina virtual, a qual seria redirecionada para um <em>named pipe</em> 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 &#8220;Serial Port 2&#8243; como mostra a figura abaixo.</p>
<p style="text-align: center;"><img class="aligncenter" src="http://driverentry.com.br/images/VM7Serial2.png" alt="" width="697" height="607" /></p>
<p>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 <em>Notepad</em>. 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.</p>
<div style="font-family: Consolas; font-size: 9pt; color: black; background: #A4F64C; border: 1px outset; padding: 0 0 0 5px;">
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">.encoding = "windows-1252"</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">config.version = "8"</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">virtualHW.version = "7"</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">scsi0.present = "TRUE"</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">scsi0.virtualDev = "lsisas1068"</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">memsize = "1024"</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">mem.hotadd = "TRUE"</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">scsi0:0.present = "TRUE"</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">scsi0:0.fileName = "Windows 7 x64.vmdk"</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">ide1:0.present = "TRUE"</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">ide1:0.autodetect = "TRUE"</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">ide1:0.deviceType = "cdrom-raw"</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">floppy0.startConnected = "FALSE"</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">floppy0.fileName = ""</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">floppy0.autodetect = "TRUE"</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">ethernet0.present = "TRUE"</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">ethernet0.connectionType = "nat"</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">ethernet0.virtualDev = "e1000"</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">ethernet0.wakeOnPcktRcv = "FALSE"</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">ethernet0.addressType = "generated"</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">usb.present = "TRUE"</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">ehci.present = "TRUE"</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">sound.present = "TRUE"</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">sound.fileName = "-1"</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">sound.autodetect = "TRUE"</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">mks.enable3d = "TRUE"</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"><span style="color: #ff0000;">serial0.present = "TRUE"</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"><span style="color: #ff0000;">serial0.fileType = "thinprint"</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">pciBridge0.present = "TRUE"</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">pciBridge4.present = "TRUE"</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">pciBridge4.virtualDev = "pcieRootPort"</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">pciBridge4.functions = "8"</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">pciBridge5.present = "TRUE"</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">pciBridge5.virtualDev = "pcieRootPort"</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">pciBridge5.functions = "8"</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">pciBridge6.present = "TRUE"</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">pciBridge6.virtualDev = "pcieRootPort"</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">pciBridge6.functions = "8"</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">pciBridge7.present = "TRUE"</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">pciBridge7.virtualDev = "pcieRootPort"</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">pciBridge7.functions = "8"</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">vmci0.present = "TRUE"</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">roamingVM.exitBehavior = "go"</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">displayName = "Windows 7 x64"</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">guestOS = "windows7-64"</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">nvram = "Windows 7 x64.nvram"</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">virtualHW.productCompatibility = "hosted"</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">printers.enabled = "TRUE"</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">extendedConfigFile = "Windows 7 x64.vmxf"</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">ide1:0.startConnected = "TRUE"</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">ethernet0.generatedAddress = "00:0c:29:91:aa:62"</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">tools.syncTime = "FALSE"</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">uuid.location = "56 4d a8 8a e8 f9 f0 a8-62 de e8 25 40 91 aa 62"</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">uuid.bios = "56 4d a8 8a e8 f9 f0 a8-62 de e8 25 40 91 aa 62"</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">cleanShutdown = "FALSE"</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">replay.supported = "FALSE"</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">replay.filename = ""</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">scsi0:0.redo = ""</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">pciBridge0.pciSlotNumber = "17"</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">pciBridge4.pciSlotNumber = "21"</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">pciBridge5.pciSlotNumber = "22"</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">pciBridge6.pciSlotNumber = "23"</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">pciBridge7.pciSlotNumber = "24"</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">scsi0.pciSlotNumber = "160"</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">usb.pciSlotNumber = "32"</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">ethernet0.pciSlotNumber = "33"</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">sound.pciSlotNumber = "34"</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">ehci.pciSlotNumber = "35"</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">vmci0.pciSlotNumber = "36"</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">scsi0.sasWWID = "50 05 05 6a e8 f9 f0 a0"</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">vmotion.checkpointFBSize = "134217728"</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">usb:0.present = "TRUE"</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">usb:1.present = "TRUE"</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">ethernet0.generatedAddressOffset = "0"</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">vmci0.id = "1083288162"</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">usb:1.deviceType = "hub"</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">usb:0.deviceType = "mouse"</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">ide1:0.fileName = "auto detect"</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">unity.wasCapable = "FALSE"</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"><span style="color: #ff0000;">serial1.yieldOnMsrRead = "TRUE"</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"><span style="color: #ff0000;">serial1.fileName = "\\.\pipe\com_1"</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"><span style="color: #ff0000;">serial1.pipe.endPoint = "server"</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"> </pre>
</div>
<p>A propriedade <em>&#8220;filetype&#8221;</em> com o valor <em>&#8220;thiprint&#8221;</em> 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.</p>
<p style="text-align: center;"><img class="aligncenter" src="http://driverentry.com.br/images/ThinPrint.png" alt="" width="692" height="605" /></p>
<p>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.</p>
<h3>A Solução</h3>
<p>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.</p>
<p style="text-align: center;"><img class="aligncenter" src="http://driverentry.com.br/images/ThinPrint2.png" alt="" width="694" height="603" /></p>
<p>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.</p>
<p>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 <em>BcdEdit</em>. Já comentei dessa ferramenta <a href="http://driverentry.com.br/blog/?p=325">neste post</a>, que fala sobre como fazer debug de Kernel através de portas USB utilizando o Windows Vista.</p>
<p style="text-align: center;"><img class="aligncenter" src="http://driverentry.com.br/images/SetSerial2Dbg.png" alt="" width="702" height="308" /></p>
<p>Depois de tudo resolvido, o depurador agora conecta ao sistema TARGET e agora vem a parte mais fácil; depurar o problema. <img src='http://driverentry.com.br/wp/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /> </p>
<p>Até mais!</p>
]]></content:encoded>
			<wfw:commentRss>http://driverentry.com.br/blog/?feed=rss2&amp;p=943</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>O que ler para escrever drivers para Windows</title>
		<link>http://driverentry.com.br/blog/?p=825</link>
		<comments>http://driverentry.com.br/blog/?p=825#comments</comments>
		<pubDate>Fri, 27 Aug 2010 19:45:04 +0000</pubDate>
		<dc:creator>Fernando Roberto</dc:creator>
				<category><![CDATA[Kernel Development]]></category>

		<guid isPermaLink="false">http://driverentry.com.br/blog/?p=825</guid>
		<description><![CDATA[Uma pergunta que sempre me fazem é sobre quais livros é necessário se ler para que se possa desenvolver drivers para Windows. Este é um assunto que eu julgava muito óbvio para se ter um post a respeito, mas com o tempo fui percebendo que este assunto não é tão óbvio para os que estão [...]]]></description>
			<content:encoded><![CDATA[<p>Uma pergunta que sempre me fazem é sobre quais livros é necessário se ler para que se possa desenvolver drivers para Windows. Este é um assunto que eu julgava muito óbvio para se ter um post a respeito, mas com o tempo fui percebendo que este assunto não é tão óbvio para os que estão partindo do zero. Para alguns, escrever drivers é algo inalcançável, que por mais que eles leiam ou tentem aprender, nunca será informação suficiente para começar a meter a mão na massa. Para outros, escrever drivers não é algo assim tão complicado, que da mesma forma que ele aprendeu a escrever aplicações com Visual Basic, alguns cliques seriam mais que suficientes para gerar o driver que ele precisa. Na tentativa de dar uma ideia do caminho e das dificuldades a serem enfrentadas nesta nova empreitada, vou listar alguns livros que considero ser um bom caminho a seguir para se escrever drivers.</p>
<h3>Não ensinam isso na faculdade</h3>
<p>Entre as tantas vezes que essa pergunta me foi feita, uma vez me perguntaram se isso é ensinado no curso de Engenharia de Computação, que era o curso que eu fazia na época. Não sei se todos aqui sabem, mas Engenharia de Computação é um curso que fica entre a Ciência da Computação e a Engenharia Eletrônica. Tentando reunir os principais assuntos de ambas as graduações, o curso não dá tanta ênfase em software nem em eletrônica. Apesar de estudar hardware, microprocessadores, linguagem C e sistemas operacionais, não chegamos nem perto do assunto drivers. Sabemos que eles existem e qual sua função, mas nada que chegue nem perto do <a href="http://driverentry.com.br/blog/?p=88">exemplo mais simples desse blog</a>.</p>
<blockquote><p>Pô Fernando, como driver é software, então o curso de Ciência da Computação deve ensinar drivers.</p>
</blockquote>
<p>Na verdade, os assuntos vistos em Ciência da Computação tratam de soluções mais alto nível, com mais detalhes em algoritmos específicos para problemas complexos. O fato é que esse curso fica mais distante do desenvolvimento de software básico. No mestrado isso fica ainda mais raro na área de software.</p>
<h3>Driver é software de baixo nível, mas não exagere</h3>
<p>Tenho um amigo que sempre gostou de estudar tudo nos mínimos detalhes. Tudo bem se a pessoa é um apaixonado por um determinado assunto e quer entendê-lo completamente, mas se o objetivo é escrever drivers, creio que seja melhor estudar apenas o necessário para um início rápido, e depois ir se aprofundando em cada assunto conforme a necessidade. Já vi algumas pessoas dizerem que antes de estudar a linguagem C, gostariam de estudar o completamente a linguagem assembly, ou mesmo começar a estudar o datasheet do processador Intel para ter o completo domínio sobre o assunto. Calma lá gente!</p>
<p><img style="float: right; padding: 0 0 5px 5px;" src="http://driverentry.com.br/images/TreinamentoC.jpg" alt="" width="124" height="180" />Eu aprendi a programar a linguagem C durante meu colegial técnico, eu não conheço as principais referências sobre o assunto, mas o livro que li é simples e, com relação à linguagem C, é abrangente o suficiente para programar. Por isso recomendo o livro <a href="http://www.livrariacultura.com.br/scripts/cultura/resenha/resenha.asp?nitem=3099&amp;sid=1873743612826675171092032&amp;k5=14601B1&amp;uid=">Treinamento em Linguagem C</a>. Você não vai precisar comprar verdadeiras bíblias sobre o assunto, que discutem qual a melhor forma de se compilar um determinado algoritmo.</p>
<p>A grande maioria dos drivers que vi nestes quase 10 anos de experiência em Kernel são escritos em C, e não em C++. A linguagem C é transparente e confiável. Não estou dizendo que não se deve confiar no C++, mas que com o tempo você olha para o código em linguagem C e consegue imaginar como seria o assembly gerado por ele. Isso ajuda bastante quando você precisa depurar sistemas onde os fontes não batem perfeitamente com a versão que você tem, ou mesmo na tentativa de entender situações onde não se tem o fonte. O C++ tem suas armadilhas com sobrecarga de operadores, templates e classes. Olhando para o fonte fica difícil imaginar o que realmente vai acontecer quando aquela linha for executada. Eu mesmo já desenvolvi drivers em C++ e já dei curso numa empresa onde Walter Oney deixou seus fontes de um driver todo em C++. Acho que é uma escolha pessoal, mas o fato é que você não precisa estudar C++ para escrever drivers.</p>
<p>Também já ouvi dizer<em> &#8220;Primeiro vou aprender C++ completamente para depois começar a estudar o Kernel&#8221;</em>. Acho que não preciso dizer que isso é completamente desnecessário. Sem falar que ainda não sei se é humanamente possível aprender C++ completamente.</p>
<h3>Preciso ler Charles Petzold?</h3>
<p><img class="alignright" src="http://driverentry.com.br/images/Winternals5th.jpg" alt="" width="150" height="182" />No curso que ofereço sobre desenvolvimento de drivers, um dos pré-requisitos é API básica do Windows. Quando digo básica, estou me referindo à manipulação de objetos de sistema, tais como arquivos, eventos, threads, processos, memória virtual e coisas do tipo. Não queria adentrar no universo sobre loop de mensagens, <a href="http://en.wikipedia.org/wiki/Microsoft_Foundation_Class_Library">MFC</a>, <a href="http://en.wikipedia.org/wiki/WTL">WTL</a> e inúmeros conceitos de User-Mode que não serão utilizados em Kernel.</p>
<p>Um excelente livro sobre a arquitetura interna do sistema é descrita com muitos detalhes no livro <a href="http://www.amazon.com/gp/product/0735625301/ref=s9_simh_gw_p14_i4?pf_rd_m=ATVPDKIKX0DER&amp;pf_rd_s=center-2&amp;pf_rd_r=0KWKVB5TDT1TB01HWPY3&amp;pf_rd_t=101&amp;pf_rd_p=470938631&amp;pf_rd_i=507846">Windows Internals 5th Edition</a>. O único problema é que o livro tem mais de mil páginas e isso é um verdadeiro pé no freio para quem está empolgadão para sair escrevendo drivers. Uma alternativa viável é a temporária substituição desse livro pelo <a href="http://www.amazon.com/Inside-Windows-NT-Microsoft-Programming/dp/1572316772/ref=sr_1_1?s=books&amp;ie=UTF8&amp;qid=1282862601&amp;sr=1-1">Inside Windows NT 2nd Editon</a>. Um livro tem a metade do tamanho do Windows Internals e que traz os conceitos mais importantes sobre o sistema e que ainda são empregados no Windows 7. Quando você estiver mais a vontade, então poderá ler o Windows Internals, e quem sabe, até tirar <a href="http://www.microsoft.com/learning/en/us/exam.aspx?ID=70-660">uma certificação</a> sobre o assunto.</p>
<h3>Modelo Legacy</h3>
<p><img style="float: right; padding: 0 0 5px 5px;" src="http://www.driverentry.com.br/images/devicedriversml.jpg" alt="" width="128" height="192" />Depois de entender um pouco sobre a arquitetura do Windows, você já poderá começar a estudar o assunto chave. Mas para isso, você deverá escolher que tipo de driver você pretente desenvolver. O modelo mais antigo é o Legacy, que apesar de ter iniciado no Windows NT 3.51, ainda roda sobre o Windows 7. Este modelo não faz interações com o Plug-And-Play Manager, mas ainda é o modelo empregado no desenvolvimento de <em>File Systems</em> até hoje. Todas as regras usadas no modelo Legacy são também utilizadas no modelo WDM. Dessa forma, estudar o modelo Legacy é uma ótima introdução para estudar WDM ou drivers File System. O livro que recomendo para desenvolvimento Legacy é o <a href="http://www.amazon.com/Windows-Device-Development-Classic-Reprints/dp/0976717522/ref=sr_1_2?s=books&amp;ie=UTF8&amp;qid=1282863676&amp;sr=1-2">Windows NT Device Driver Development</a>. Estudar o modelo Legacy dá a oportunidade de o leitor se aprofundar em conceitos básicos e essenciais no desenvolvimento em Kernel Mode. Por ser um modelo mais simples, o cérebro do leitor consegue absorver com mais qualidade questões como: manipulação de IRPs, memória virtual, níveis de execução de um thread, mecânicas de sincronismo, objetos do sistema e por aí vai.</p>
<p>O leitor que estudar o modelo Legacy estará bem mais preparado para lidar como modelo WDM, que possui regras próprias que serão aplicadas utilizando os conceitos já adquiridos no modelo Legacy. O mesmo se pode dizer com relação ao desenvolvimento de drivers de File System. Apesar de os drivers de File System serem desenvolvidos em Legacy, não significa que ao aprender o modelo Legacy, aprende-se File Systems automagicamente. Este também é um assunto que requer um estudo dedicado.</p>
<h3>Windows Driver Model (WDM)</h3>
<p><img style="float: right; padding: 0 0 5px 5px;" src="http://www.driverentry.com.br/images/WDMBook.jpg" alt="" width="144" height="189" />Se o seu modelo alvo é WDM, então um bom livro para começar é o <a href="http://www.amazon.com/Windows-2000-Device-Driver-Book/dp/0130204315/ref=sr_1_1?s=books&amp;ie=UTF8&amp;qid=1282863760&amp;sr=1-1">Windows 2000 Device Driver Book</a>. Isso porque o grande problema dos livros de desenvolvimento de drivers é que muita teoria é necessária para se fazer um driver. No modelo WDM a coisa fica ainda mais carregada. Este não é o melhor livro de WDM que conheço, e já vi comentários em listas de discussão dizendo que este livro é conhecido pelos seus erros. O fato é que ele faz uma apresentação simplificada, e o melhor de tudo é que o autor cria um driver básico no início do livro e depois vai colocando mais conceitos em prática.  Com isso o leitor vai escrever um driver de exemplo antes de morrer louco com tanta teoria.</p>
<p>Depois de ter uma base em WDM, então você já estará pronto para ler um livro de gente grande, e não estou me referindo às revistas de nudez. O livro <a href="http://www.amazon.com/Programming-Microsoft-Windows-Driver-Model/dp/0735618038/ref=sr_1_fkmr0_1?ie=UTF8&amp;qid=1282864266&amp;sr=1-1-fkmr0">Programming the Windows Driver Model 2nd Edition</a> é realmente muito bom. Eu mesmo já o li umas três vezes, mas como eu comentei antes, muitas páginas são necessárias para que o leitor possa começar a ver as coisas como um todo. Toda essa teoria cansa e confunde um leitor que está começando no assunto.</p>
<h3>Drivers de File System</h3>
<p><img style="float: right; padding: 0 0 5px 5px;" src="http://driverentry.com.br/images/FS-Internals-Cover-small.gif" alt="" />Se você é um dos poucos seres vivos desse planeta que precisam   desenvolver ou dar suporte a drivers de File System, então estudar o modelo Legacy foi tranquilo. Alguns me perguntam: <em>&#8220;O que tem de tão complicado em escrever drivers de File System?&#8221;</em> O problema é que além dos conceitos do modelo Legacy, você precisa lidar com os próprios conceitos utilizados na integração dos drivers de File System com outros componentes do sistema. Estou falando dos seus inseparáveis amigos <em>Memory Manager</em> e <em>Cache Manager</em>. Várias estruturas e regras são impostas pelo sistema para que este componente possa cumprir seu papel de forma estável e eficiente. A falta de livros sobre o assunto adiciona alguma adrenalina ao processo de aprendizado. O livro <a href="http://www.amazon.com/Windows-System-Internals-Classic-Reprints/dp/0976717514/ref=sr_1_1?ie=UTF8&amp;s=books&amp;qid=1282919484&amp;sr=8-1">Windows NT File Systems Internals</a> é o único livro que trata do assunto para Windows. Espera-se que a <a href="http://www.osr.com">OSR</a>, empresa que atualmente detém os direitos deste livro, possa lançar uma versão atualizada dele, mas como o público alvo é restrito, talvez não haja incentivo bastante para a concretização disso.</p>
<p>Escrever drivers de File System é complicado e pode-se até imaginar que esse é o tipo de driver mais complicado que existe de se escrever, mas segundo a OSR e outras autoridades no assunto, essa posiçãp de driver mais complexo é ocupada pelos filtros de File System. Isso porque além de ter de conhecer as regras que drivers que File System precisam seguir, os filtros ainda <strong>não</strong> recebem todas as notificações que um o próprio driver recebe. Escrever esse tipo de filtro é estar entre duas caixas pretas que conversam com alta intensidade e intimidade, e ainda agregar valor a esse serviço. Quando fiz <a href="http://driverentry.com.br/blog/?p=442">meu curso de Drivers de File System na OSR</a>, <a href="https://mvp.support.microsoft.com/profile=BE99E7CE-702D-4CA1-B3A4-F5D1EBB55226">Tony Mason</a> disse que as coisas ficam realmente interessantes com a chegada do NTFS transacional.</p>
<p>Diante de tanta dificuldade, a Microsoft criou a classe de drivers chamada MiniFilters, que é uma espécie de Miniport driver para filtros de File System. Infelizmente ainda não existem livros que trate deste assunto. Você vai ter que encarar <a href="http://msdn.microsoft.com/en-us/library/ff540402%28VS.85%29.aspx">esse tópico no site do MSDN</a>. O detalhe aqui é que minifilter drivers são módulos carregados pelo <a href="http://msdn.microsoft.com/en-us/library/ff541591%28VS.85%29.aspx">Filter Manager</a>, que do ponto de vista do sistema, é mais um filtro de File System Legacy. Desta forma, conhecer o modelo Legacy é uma mão na roda na hora de depurar isso tudo.</p>
<h3>Windows Driver Foundation (WDF)</h3>
<p><img style="float: right; padding: 0 0 5px 5px;" src="http://www.driverentry.com.br/images/WDFBook.jpg" alt="" width="148" height="184" />Que o modelo WDM é complexo e trabalhoso, acho que todos concordamos. A fim de evitar tanta complexidade na hora de escrever drivers, a Microsoft criou um novo modelo que se apoia no WDM para implementar todos os comportamentos padrão de um driver por default. Isso significa que você pode escrever um driver de dispositivo e deixar que o framework faça a maior parte do trabalho com relação ao plug-and-play, gerenciamento de energia e inúmeros conceitos que são iguais para a grande maioria dos drivers. Caso você queira um comportamento especial em uma determinada situação, basta registrar a rotina de callback e ser feliz (ou não). O WDF traz dois frameworks, o <strong>Kernel-Mode Driver Framework</strong> (KMDF) e o <strong>User-Mode Driver Framework</strong> (UMDF). Desenvolver drivers em KMDF traz algumas poucas restrições em relação a WDM, mas vale a pena escrever um driver novo em WDF. Drivers em User-Mode trazem maiores restrições, principalmente ao barramento que seu dispositivo está e quão rápido o driver precisa ser. O livro <a href="http://www.amazon.com/Developing-Drivers-Windows-Foundation-Developer/dp/0735623740/ref=sr_1_1?s=books&amp;ie=UTF8&amp;qid=1282927196&amp;sr=1-1">Developing Drivers with the Windows  Driver Foundation</a> ainda é o único que trata deste assunto. Mais uma vez, muita teoria é apresentada até que um exemplo prático apareça. Outra característica interessante sobre este livro é que ambos os frameworks  são apresentados simultaneamente. Assim, você aprende a desenvolver drivers em KMDF e UMDF ao mesmo tempo. Dependendo do leitor, isso deve até dar um barato.</p>
<p>Se o que você quer mesmo é desenvolver driver em User-Mode, então vamos repensar a questão do C++. Como um driver UMDF deve ser implementado em <a href="http://en.wikipedia.org/wiki/Component_Object_Model">COM</a>, alguns recursos do C++ agora são requisitos básico para um desenvolvimento confortável. Mais uma vez vou recomendar um livro da Viviane, o <a href="http://www.livrariacultura.com.br/scripts/cultura/resenha/resenha.asp?nitem=3183666&amp;sid=1873743612618547535934139&amp;k5=3A5DF094&amp;uid=">Treinamento em Liguagem C++</a>, que sob meu ponto de vista é suficiente para escrever drivers com relação à linguagem. Depois você pode se tornar um mestre ninja com <a href="http://en.wikipedia.org/wiki/Boost_C%2B%2B_Libraries">Boost</a>, <a href="http://en.wikipedia.org/wiki/Standard_Template_Library">STL</a> e outras coisas que eu nem imagino.</p>
<p>Depois do C++, uma boa dose de <strong>COM</strong> vai bem. O livro que meu amigo <a href="http://www.1bit.com.br/content.1bit/weblog">Strauss</a> me empresou, que foi direto ao ponto de forma clara e simples é o <a href="http://www.amazon.com/Essential-COM-Don-Box/dp/0201634465/ref=sr_1_1?ie=UTF8&amp;s=books&amp;qid=1282930261&amp;sr=8-1">Essential COM</a> do Don Box.</p>
<p>Toda essa base teórica lhe dará bagagem para que você possa escolher um tipo de driver e se aprofundar nele. Mesmo dentro do assunto Kernel, ainda existem inúmeras especialidades de drivers. Não pense que você poderá aprender este assunto completamente antes de sair desenvolvendo, então escolha logo o seu livro e coloque a mão na massa.</p>
<p>Até mais! <img src='http://driverentry.com.br/wp/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://driverentry.com.br/blog/?feed=rss2&amp;p=825</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Sétimo Encontro de Programadores C/C++</title>
		<link>http://driverentry.com.br/blog/?p=769</link>
		<comments>http://driverentry.com.br/blog/?p=769#comments</comments>
		<pubDate>Wed, 21 Jul 2010 02:11:01 +0000</pubDate>
		<dc:creator>Fernando Roberto</dc:creator>
				<category><![CDATA[Kernel Development]]></category>
		<category><![CDATA[Off Topic]]></category>

		<guid isPermaLink="false">http://driverentry.com.br/blog/?p=769</guid>
		<description><![CDATA[Este post fala sobre minha participação no Sétimo Encontro de Programadores C/C++. São ilustrados os passos das configurações mínimas necessárias para que o participante possa acompanhar o palestrante a fim de seguir os exemplos comentados durante a palestra.]]></description>
			<content:encoded><![CDATA[<p><img style="float: right; margin: 0px 10px;" src="http://www.driverentry.com.br/images/logo_com_c++_160x115.jpg" border="0" alt="" /></p>
<p>Como alguns de vocês já sabem, no próximo dia 14 de agosto acontecerá o <a href="http://www.temporealeventos.com.br/?area=95&amp;tipo=1&amp;id=3360">sétimo encontro de programadores</a> do grupo <a href="http://groups.google.com/group/ccppbrasil">C/C++ Brasil</a>. Mais uma vez, será um grande prazer participar do evento como palestrante e ter a oportunidade de falar um pouco sobre o desenvolvimento de drivers (pra variar). <img src='http://driverentry.com.br/wp/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /> </p>
<p>Minha primeira participação nesse evento foi em sua <a href="http://driverentry.com.br/blog/?p=330">quarta edição</a>, onde fiz um overview sobre arquitetura e desenvolvimento de drivers para Windows. Os slides desta palestra podem ser baixados a partir deste <a href="http://driverentry.com.br/blog/?p=322">post</a>. Apesar de o feedback ter sido muito bom, recebi algumas sugestões sobre mostrar mais código fonte. O desenvolvimento de drivers requer muito conceito, tanto sobre o sistema operacional quanto sobre as  regras impostas pelo I/O Manager e seus inseparáveis amigos. Assim, imaginei que mostrar código fonte sobre estruturas e regras não conhecidas pela maioria dos participantes da palestra soaria como <em>&#8220;Nana neném que a Cuca vem&#8230;&#8221;</em>. Mas não tem jeito, programador gosta mesmo é de código fonte.</p>
<p>Na <a href="http://driverentry.com.br/blog/?p=206">sexta edição</a> foi que tive minha segunda participação. Desta vez foquei nas caraterísticas de funcionamento e utilização da memória virtual por drivers, dei mais ênfase aos nomes das rotinas que drivers utilizam para obter os serviços do Kernel. Pois é, embora tenha melhorado ainda não foi suficiente. O resultado do feedback mais uma vez revelou que faltou exemplos práticos e código fonte pra galera.</p>
<p>Nesta sétima edição vou praticamente escrever, compilar, instalar, executar e depurar um driver de exemplo. Tudo alí na hora. A proposta desta palestra é demostrar como dar os estes primeiros passos para se ter um driver compilado bem alí em seu próprio notebook.</p>
<p>Embora essa informação também esteja na página no evento, seguem os tópicos que serão apresentados por mim:</p>
<ul>
<li>O que é o Windows Driver Kit</li>
<li>Device Drivers e Software Drivers</li>
<li>WDK e os arquivos de um projeto</li>
<li>A rotina DriverEntry e DriverUnload</li>
<li>Hands on: Escrevendo e compilando um driver</li>
<li>Testando drivers em máquinas vituais</li>
<li>Hands on: Instalando o driver exemplo</li>
<li>Depurando o Kernel do Windows</li>
<li>Hands on: Depurando seu driver</li>
<li>A Tela Azul da Morte (BSOD)</li>
<li>Hands on: A primeira Tela Azul a gente nunca esquece</li>
<li>Gerando crash dumps</li>
<li>Hands on: Analisando seu crash dump</li>
<li>Dúvidas, pânico e depressão</li>
</ul>
<p>Parece muito? Pois é, para que isso seja possível no tempo que disponho será necessário que já se tenha o ambiente preparado. Você não vai querer ver uma palestra de uma hora que vai explicar de onde baixar as ferramentas, como instalá-las e como preparar uma máquina virtual que sirva de ambiente de testes para seu novo driver. Se tudo isso for feito no dia do evento, mais uma vez vou ficar devendo o código fonte e provavelmente serei enforcado em praça pública. Eu não sei sobre vocês, mas eu não gostaria que isso acontecesse.</p>
<ul>
</ul>
<h3>Baixando e Instalando o WDK</h3>
<p>O primeiro passo dessa preparação é baixar o kit de desenvolvimento de drivers da Microsoft, o Windows Driver Kit (WDK). Esse kit contém os headers e bibliotecas necessárias para que seu driver possa utilizar as rotinas exportadas pelo Kerne, permitindo a interação do seu driver com o restante do sistema operacional. Além dos headers e bibliotecas, o kit também traz o compilador e depurador de sistema, fazendo desse kit a única ferramenta necessário para que se tenha um driver compilado e depurado.</p>
<p>Ainda não falei dos vários e vários exemplos de drivers que o kit traz, bem como toda a documentação necessária para a utilização das rotinas exportadas pelo Kernel. Essa documentação não serve apenas de referência, mas também como um guia de construção de drivers. Embora a documentação se proponha a servir de guia de construção de drivers, ainda recomendo fortemente a leitura de livros dedicados a essa atividade. Os livros conseguem expor as idéias com mais clareza abordando os assuntos de forma gradativa.</p>
<p>O fato de haver um compilador nesse kit não significa que exista um ambiente de desenvolvimento específico para drivers. O que estou querendo dizer é que não existe uma versão do Visual Studio específica para drivers, ou mesmo um plug-in que fosse instalado no Visual Studio que agregasse tais funcionalidades ao ambiente. No caso mais básico, os fontes poderiam ser editados no bom e velho Notepad. Isso não nos impede de utilizar nosso editor do coração para escrever drivers, como mostra este <a href="http://driverentry.com.br/blog/?p=162">outro post</a>. De fato existem algumas ferramentas com esse propósito como o <a href="http://visualddk.sysprogs.org/">VisualDDK</a>, mas não é nada oficial.</p>
<p>Baixar o WDK é fácil e indolor. E quando digo indolor, estou me referendo também no sentido financeiro da idéia. O primeiro passo é baixar o WDK que está disponível no <a href="http://www.microsoft.com/downloads/details.aspx?displaylang=en&amp;FamilyID=36a2630f-5d56-43b5-b996-7633f2ec14ff">Microsoft Download Center</a>. Seguindo as instruções, você baixará um ISO de aproximadamente 620MB que conterá toda a instalação.</p>
<p>O ISO pode ser queimado em uma mídia de CD, ou você pode simplesmente usar um desses aplicativos que cria uma unidade de disco virtual a partir de um arquivo de imagem. Se você não tem nenhum aplicativo desses à mão, você pode  baixar e instalar gratuitamente o <a href="http://www.osronline.com/article.cfm?article=410">OsrVitrtualCdAndDisk</a> da OSR.</p>
<p>Depois de inserir o CD, execute o aplicativo KitSetup.exe que estará na pasta raíz do CD. Fazendo isso você verá a splash screen do Windows Driver Kit 7.1.0 como exibida abaixo.</p>
<p style="text-align: center;"><img class="aligncenter" src="http://www.driverentry.com.br/images/WDKSetup0.png" alt="" width="576" height="435" /></p>
<p>Em seguida a janela exibida abaixo.</p>
<p style="text-align: center;"><img class="aligncenter" src="http://www.driverentry.com.br/images/WDKSetup1.png" alt="" width="633" height="450" /></p>
<p>Selecione os itens como exibido acima, deixando de selecionar os itens &#8220;Device Simulation Framework&#8221; e &#8220;Windows Device Testing Framework&#8221;. Em seguida clique em OK para ver a próxima janela como exibida na figura abaixo.</p>
<p style="text-align: center;"><img class="aligncenter" src="http://www.driverentry.com.br/images/WDKSetup2.png" alt="" width="560" height="327" /></p>
<p>Pelo menos para a palestra, simplesmente aceite o caminho de instalação sugerido, isso vaip evitar contratempos durante a palestra. Clicando OK nesta janela, apenas aceite os termos da instalação e clique em OK na janela exibida abaixo para finalizar a instalação do WDK.</p>
<p style="text-align: center;"><img class="aligncenter" src="http://www.driverentry.com.br/images/WDKSetup3.png" alt="" width="632" height="449" /></p>
<p>Aguarde a cópia dos arquivos terminar e a instalação se encerrará.</p>
<h3>Dando uma compiladinha, só pra&#8230;</h3>
<p>Depois de instalar o WDK você pode se certificar de que tudo está certo simplesmente compilado um dos exemplos instalados pelo próprio kit. Para fazer isso, abra o prompt de comando de build como demonstrado na figura abaixo.</p>
<p style="text-align: center;"><img class="aligncenter" src="http://www.driverentry.com.br/images/WDKTest1.png" alt="" width="420" height="511" /></p>
<p>Este prompt de comando é diferente do convencional por já estar devidamente configurado com as variáveis de ambiente necessárias para a compilação de drivers para Windows XP. Mais detalhes sobre isso na palestra. Com este prompt de comando, execute os passos indicados na figura a seguir.</p>
<p style="text-align: center;"><img class="aligncenter" src="http://www.driverentry.com.br/images/WDKTest2.png" alt="" width="678" height="484" /></p>
<p>Certifique-se de que o exemplo foi compilado verificando a saída do compilador como destacado na figura acima. Caso você tenha algum problema em seguir estes passos, mande-me um e-mail que a gente sai na porrada e tudo bem.</p>
<h3>Baixando e Instalando o Virtual PC</h3>
<p>Ter o ambiente de desenvolvimento configurado é essencial para o desenvolvimento de drivers, mas de nada adiantaria se você não tiver um ambiente de teste. Não caia na besteira de utilizar sua própria máquina de desenvolvimento como ambiente de teste. Tente pelo menos usar a máquina de desenvolvimento de um estagiário ou sei lá. Pense que você não vai escrever uma aplicação que, na pior das hipóteses, resultará no sonoro PAM. Dependendo do tipo de driver e do tamanho da orelhada que você aprontar, sua máquina pode ficar inutilizada, não iniciar mais ou mesmo ter dados corrompidos.</p>
<p>Depurar um driver de Kernel requer condições especiais. A rigor são necessárias duas máquinas para essa tarefa. Isso mesmo, duas máquinas. O que você está pensando? Que vai poder colocar um break-point em seu driver, interromper sua execução e dar um ALT+TAB para dar uma olhadinha na janela de variáveis locais? Nem pensar amigão. Quando um break-point interrope o sistema operacional, o Windows inteiro para. O mouse não se mexe, a janela não repinta o scheduler não trabalha, nada nada. Por essa razão é que precisamos de uma segunda máquia. Das suas máquinas, uma delas será sua vítima, a máquina na qual rodará seu driver e que será completamente congelada quando necessário. A outra será sua máquina de desenvolvimento. Nela estarão os códigos fontes, os símbolos e o ambiente de depuração. É em sua máquina de desenvolvimento que a janelinha de variáveis locais vai aparecer.</p>
<p>Hoje em dia podemos recorrer à virtualização para economizar tempo e espaço em nossas mesas. Utilizando uma máquina virtual podemos ter o ambiente que precisamos para dar continuidade à palestra e testar o driver que será desenvolvido. Máquinas virtuais ajudam em muitos casos, principalmente nos casos de desenvolvimento de drivers que não lidam com hardware diretamente. Este é o caso de drivers de anti-virus, firewall, file systems, alguns tipos de drivers USB e outros. Por outro lado, se você por exemplo tiver uma placa PCI para fazer <em>port I/O</em>, manipular interrupções ou mesmo fazer DMA, uma VM não vai ajudar muito, mas este é outro caso.</p>
<p>O <a href="http://www.microsoft.com/windows/virtual-pc/default.aspx">Virtual PC</a> é uma ferramenta gratuita da Microsoft e que pode ser baixada a partir deste <a href="http://www.microsoft.com/downloads/details.aspx?displaylang=en&amp;FamilyID=28c97d22-6eb8-4a09-a7f7-f6c7a1f000b5">link</a>. Executando o arquivo baixado, teremos a seguinte janela como listrado na figura abaixo. Apenas clique em <em>Next</em> para a próxima janela.</p>
<p style="text-align: center;"><img class="aligncenter" src="http://www.driverentry.com.br/images/VPCSetup1.png" alt="" width="514" height="390" /></p>
<p>Aceite os termos do produto e clique <em>Next</em> para dar continuidade a instalação.</p>
<p style="text-align: center;"><img class="aligncenter" src="http://www.driverentry.com.br/images/VPCSetup2.png" alt="" width="513" height="391" /></p>
<p>Apenas aceite o diretório de destino sugerido e clique <em>Next</em>.</p>
<p style="text-align: center;"><img class="aligncenter" src="http://www.driverentry.com.br/images/VPCSetup3.png" alt="" width="514" height="390" /></p>
<p>Depois de aguardar a cópia dos arquivos, finalize a instalação.</p>
<h3>Criando uma nova VM</h3>
<p>Este não é um blog especializado em máquinas virtuais, então nem tentem me mandar e-mails com dúvidas cabeludas sobre esse assunto. Entretanto, posso ajudar na criação da máquina virtual que usaremos na palestra. Afinal de contas teremos que destruir alguma coisa, caso contrário ficaria meio sem graça.</p>
<p style="text-align: center;"><img class="aligncenter" src="http://www.driverentry.com.br/images/VPCTest1.png" alt="" width="547" height="470" /></p>
<p>Nesta tela inicial exibida acima, apenas clique <em>Next</em> para continuar com a instalação.</p>
<p style="text-align: center;"><img class="aligncenter" src="http://www.driverentry.com.br/images/VPCTest2.png" alt="" width="533" height="455" /></p>
<p>Aqui selecione a opção de criação de uma nova máquina virtual e depois clique <em>Next</em> para continuar.</p>
<p style="text-align: center;"><img class="aligncenter" src="http://www.driverentry.com.br/images/VPCTest3.png" alt="" width="531" height="454" /></p>
<p>Neste passo você dá o nome da sua máquina virtual. Fique a vontade para colocar o nome que achar mais adequado. Zé, Jão e Toin são algumas opções válidas, mas por simples clareza vou preferir &#8220;Windows XP&#8221; mesmo.</p>
<p style="text-align: center;"><img class="aligncenter" src="http://www.driverentry.com.br/images/VPCTest4.png" alt="" width="531" height="453" /></p>
<p>Neste passo selecionamos o sistema operacional que será instalado nessa nova máquina. Isso serve para que a VM possa instalar as ferramentas certas de integração. Resumindo, selecione Windows XP e clique <em>Next</em> para continuar.</p>
<p style="text-align: center;"><img class="aligncenter" src="http://www.driverentry.com.br/images/VPCTest5.png" alt="" width="530" height="452" /></p>
<p>Apenas aceite a quantidade de memória recomendada pelo Wizard e clique <em>Next</em>.</p>
<p style="text-align: center;"><img class="aligncenter" src="http://www.driverentry.com.br/images/VPCTest6.png" alt="" width="531" height="452" /></p>
<p>Como vamos fazer uma nova instalação do Windows, precisaremos de uma nova HD que será formatada pela instalação do Windows. Selecione a opção indicada na figura acima e clique <em>Next.</em></p>
<p style="text-align: center;"><img class="aligncenter" src="http://www.driverentry.com.br/images/VPCTest7.png" alt="" width="531" height="452" /></p>
<p>Bom, aqui você determina onde o arquivo que representa o disco rígido será criado. Sem muitas firulas apenas aceite o caminho sugerido e clique <em>Next</em> para continuar.</p>
<p style="text-align: center;"><img class="aligncenter" src="http://www.driverentry.com.br/images/VPCTest8.png" alt="" width="529" height="452" /></p>
<p>Finalize a criação da sua nova máquina virtual clicando em <em>Finish</em> e pronto.</p>
<p style="text-align: center;"><img class="aligncenter" src="http://www.driverentry.com.br/images/VPCTest10.png" alt="" width="660" height="476" /></p>
<p><img class="alignright" src="http://www.driverentry.com.br/images/IgrejaSantaIfigenia.png" alt="" width="160" height="241" /></p>
<p>Ufa! Agora sua máquina virtual está pronta para receber um novo sistema operacional.</p>
<p>Deste ponto em diante você pode instalar uma cópia do seu Windows XP. Outras versões do Windows poderiam ser instaladas, mas a fim de evitar diferenças nas configurações de debug durante a palestra, vamos combinar de instalar o Windows XP mesmo.</p>
<p>Caso você não tenha uma cópia do Windows XP para instalar, não há muito que eu possa fazer para te ajudar. O máximo que posso fazer é te dar o seguinte conselho: Vá até a igreja de Santa Ifigênia, que fica na avenida Santa Ifigênia bem no centro de São Paulo, e acenda uma vela para a santa. Aproveitando que você vai estar por lá, dê uma passeada pelo <a href="http://www.portaldasantaifigenia.com.br/">comercio local</a>. Tenho certeza que você receberá uma luz em seu caminho.</p>
<p>Agora vou para por aqui, caso contrário eu não vou ter muito que falar no dia da palestra. Aproveite essa oportunidade para aprender os conceitos básicos (e bota básico nisso) sobre como gerar seu primeiro driver, sua primeira tela azul e por fim fazer seu primeiro crash analysis. Pense que você um dia vai poder contar isso para os seus netos. Embora isso não ajude muito, eles não vão fazer a menor ideia do que você está falando e vão acabar te internando de qualquer maneira.</p>
<p>Espero vê-los por lá. T+!</p>
<p class="download"><a href="http://www.driverentry.com.br/downloads/Palestra-140810.zip">Download dos slides</a></p>
]]></content:encoded>
			<wfw:commentRss>http://driverentry.com.br/blog/?feed=rss2&amp;p=769</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Mapeando Arquivos em Memória</title>
		<link>http://driverentry.com.br/blog/?p=731</link>
		<comments>http://driverentry.com.br/blog/?p=731#comments</comments>
		<pubDate>Sat, 26 Jun 2010 15:13:58 +0000</pubDate>
		<dc:creator>Fernando Roberto</dc:creator>
				<category><![CDATA[Debug]]></category>
		<category><![CDATA[System Programming]]></category>

		<guid isPermaLink="false">http://driverentry.com.br/blog/?p=731</guid>
		<description><![CDATA[Depois de ilustrar algumas das características do Memory Manager sendo um provedor de serviços ao Cache Manager no post anterior, hoje vou demonstrar que meras aplicações User-Mode também podem utilizar tais serviços. Mapeando arquivos em memória a aplicação ganha um intervalo de endereços virtuais que contém o conteúdo do arquivo. O acesso ao conteúdo do [...]]]></description>
			<content:encoded><![CDATA[<p>Depois de ilustrar algumas das características do<strong> Memory Manager</strong> sendo um provedor de serviços ao <strong>Cache Manager</strong> no <a href="http://driverentry.com.br/blog/?p=701">post anterior</a>, hoje vou demonstrar que meras aplicações <em>User-Mode</em> também podem utilizar tais serviços. Mapeando arquivos em memória a aplicação ganha um intervalo de endereços virtuais que contém o conteúdo do arquivo. O acesso ao conteúdo do arquivo se dá simplesmente desreferenciando um ponteiro, sem a necessidade de chamar as funções <a href="http://msdn.microsoft.com/en-us/library/aa365467(VS.85).aspx">ReadFile()</a> ou <a href="http://msdn.microsoft.com/en-us/library/aa365747(VS.85).aspx">WriteFile()</a>.</p>
<p>Quer uma necessidade para isso? Imagine que sua aplicação precise fazer a busca por uma determinada string em um arquivo, digamos &#8220;DriverEntry&#8221;. Em um desevolvimento<em> &#8220;arroz com feijão&#8221;</em>, o handle do arquivo é obtido através da chamada à função <a href="http://msdn.microsoft.com/en-us/library/aa363858(VS.85).aspx">CreateFile()</a>, e um buffer recebe o conteúdo parcial do arquivo, vamos supor 200 bytes. Uma simples função de busca da API poderia fazer tal busca no buffer.</p>
<p style="text-align: center;"><img style="padding: 5px;" src="http://driverentry.com.br/images/StrStr1.png" alt="" width="519" height="132" /></p>
<p>Essa solução seria perfeita se não houvesse a possibilidade de a palavra buscada cair nas extremidades do buffer tal como ilustrado abaixo.</p>
<p style="text-align: center;"><img class="aligncenter" style="padding: 5px;" src="http://driverentry.com.br/images/StrStr2.png" alt="" width="527" height="134" /></p>
<p>Um algoritmo mais espertinho teria que ser utilizado para identificar o prefixo e continuar a busca na próxima leitura do arquivo.</p>
<p>Este é apenas um simples exemplo, mas que ilustra com clareza uma das vantagens de se mapear arquivos. Se houvesse uma simples função que recebesse o path de um arquivo e nos retornasse um ponteiro para o conteúdo dele,  a busca seria bem simples.</p>
<p>Arquivos mapeados em memória também podem facilitar a escrita em seu conteúdo. Escrevendo no ponteiro recebido por tal mapeamento, o Memory Manager vai se encarregar de fazer o I/O necessário para que este novo conteúdo chegue ao disco.</p>
<h3>Uma simples função de mapeamento</h3>
<p>Aqui vou exemplificar o uso das rotinas que mapeiam um arquivo em memória. Os comentários seguem na explicação.</p>
<div style="font-family: Consolas; font-size: 9pt; color: black; background: #A4F64C; border: 1px outset; padding: 0 0 0 5px;">
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"><span style="color: green;">/****</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"><span style="color: green;">***     MapFileToMemory</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"><span style="color: green;">**</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"><span style="color: green;">**      Rotina que recebe o path de um arquivo que será</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"><span style="color: green;">**      mapeado em memória para leitura. Um endereço é</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"><span style="color: green;">**      retornado à rotina chamadora bem como o tamanho</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"><span style="color: green;">**      do arquivo.</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"><span style="color: green;">*/</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"> </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">DWORD MapFileToMemory(LPCTSTR   tzFileName,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">                      LPVOID*   ppMemory,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">                      LPDWORD   pdwSize)</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">{</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">    HANDLE  hFile = NULL,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">            hMapping = NULL;</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">    DWORD   dwError = ERROR_SUCCESS;</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"> </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">    <span style="color: blue;">__try</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    {</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">        <span style="color: blue;">__try</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">        {</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">            <span style="color: green;">//-f--&gt; Zera variáveis de saída.</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">            *pdwSize = NULL;</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">            *ppMemory = NULL;</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"> </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">            <span style="color: green;">//-f--&gt; Aqui abrimos o arquivo a ser mapeado</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">            hFile = CreateFile(tzFileName,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">                               GENERIC_READ,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">                               FILE_SHARE_READ | FILE_SHARE_DELETE,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">                               NULL,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">                               OPEN_EXISTING,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">                               FILE_ATTRIBUTE_NORMAL,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">                               NULL);</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"> </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">            <span style="color: green;">//-f--&gt; Vericamos se o arquivo foi aberto, senão</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">            <span style="color: green;">//      o homem do saco vem e nos leva.</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">            <span style="color: blue;">if</span> (hFile == INVALID_HANDLE_VALUE)</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">                RaiseException(GetLastError(),</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">                               <span style="color: purple;">0</span>,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">                               <span style="color: purple;">0</span>,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">                               NULL);</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"> </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">            <span style="color: green;">//-f--&gt; Embora o tamanho do arquivo não seja necessário</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">            <span style="color: green;">//      nesta função, vamos aproveitar que temos o handle</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">            <span style="color: green;">//      do arquivo em mãos para obter essa informação para</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">            <span style="color: green;">//      a rotina chamadora que vai precisar dela.</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">            *pdwSize = GetFileSize(hFile,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">                                   NULL);</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"> </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">            <span style="color: green;">//-f--&gt; Aqui criamos um mapeamento do arquivo.</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">            <span style="color: green;">//      Em kernel seria o equivalente a se criar uma</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">            <span style="color: green;">//      section do arquivo.</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">            hMapping = CreateFileMapping(hFile,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">                                         NULL,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">                                         PAGE_READONLY,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">                                         <span style="color: purple;">0</span>,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">                                         <span style="color: purple;">0</span>,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">                                         NULL);</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"> </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">            <span style="color: green;">//-f--&gt; Prevenindo o homem do saco.</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">            <span style="color: blue;">if</span> (!hMapping)</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">                RaiseException(GetLastError(),</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">                               <span style="color: purple;">0</span>,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">                               <span style="color: purple;">0</span>,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">                               NULL);</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"> </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">            <span style="color: green;">//-f--&gt; Aqui sim o mapeamento é feito e ganhamos o</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">            <span style="color: green;">//      intervalo de endereços que conterá o conteúdo</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">            <span style="color: green;">//      do arquivo.</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">            *ppMemory = MapViewOfFile(hMapping,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">                                      FILE_MAP_READ,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">                                      <span style="color: purple;">0</span>,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">                                      <span style="color: purple;">0</span>,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">                                      <span style="color: purple;">0</span>);</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"> </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">            <span style="color: green;">//-f--&gt; A mesma treta do saco que já comentei.</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">            <span style="color: blue;">if</span> (!*ppMemory)</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">                RaiseException(GetLastError(),</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">                               <span style="color: purple;">0</span>,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">                               <span style="color: purple;">0</span>,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">                               NULL);</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">        }</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">        <span style="color: blue;">__finally</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">        {</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">            <span style="color: green;">//-f--&gt; Aqui é onde faremos toda a faxina</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">            <span style="color: green;">//      fechando os handles que foram abertos.</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">            <span style="color: blue;">if</span> (hFile)</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">                CloseHandle(hFile);</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"> </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">            <span style="color: blue;">if</span> (hMapping)</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">                CloseHandle(hMapping);</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">        }</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    }</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">    <span style="color: blue;">__except</span>(EXCEPTION_EXECUTE_HANDLER)</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    {</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">        <span style="color: green;">//-f--&gt; Oops! Alguma coisa não saiu como foi ensaiado.</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">        <span style="color: green;">//      Encontre um culpado e faça de conta que não é com você.</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">        dwError = GetExceptionCode();</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    }</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"> </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    <span style="color: blue;">return</span> dwError;</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">}</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"> </pre>
</div>
<p>Este exemplo é realmente bem simples, mas sinta-se à vontade para adicionar parâmetros que tornem essa função mais flexível e complexa.</p>
<blockquote><p>&#8220;Fernando, mesmo que o arquivo tenha sido mapeado com succeso, você fecha o handles do arquivo e do mapeamento. Isso não deveria liberar as refências que este programa tem com o arquivo?&#8221;</p>
</blockquote>
<p>Na verdade, depois de criarmos o mapeamento de arquivo utilizando a rotina <a href="http://msdn.microsoft.com/en-us/library/aa366537(VS.85).aspx">CreateFileMapping()</a> que recebe o handle do arquivo, uma referência extra já foi feita ao arquivo e assim já poderíamos fechar o handle dele se quisessemos. O mesmo acontece com a chamada da rotina <a href="http://msdn.microsoft.com/en-us/library/aa366761(VS.85).aspx">MapViewOfFile()</a>, que recebe o handle do mapeamento, e que por sua vez possui uma referência indireta ao arquivo mapeado. Ou seja, depois de tudo mapeado podemos fechar todos os handles e deixar as referências indiretas tomarem conta disso.</p>
<p>No próximo código fonte veremos um exemplo simples de utilização dessa função.</p>
<div style="font-family: Consolas; font-size: 9pt; color: black; background: #A4F64C; border: 1px outset; padding: 0 0 0 5px;">
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"><span style="color: green;">/****</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"><span style="color: green;">***     _tmain</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"><span style="color: green;">**</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"><span style="color: green;">**      Simples utilização da função de mapeamento de arquivo.</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"><span style="color: green;">**      Só pra não dizer que não fiz tudim tudim...</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"><span style="color: green;">*/</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"> </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"><span style="color: blue;">int</span> _tmain(<span style="color: blue;">int</span> argc, _TCHAR* argv[])</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">{</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">    PBYTE   pBuffer;</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    DWORD   dwError, dwSize, i;</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"> </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    <span style="color: green;">//-f--&gt; Passa o nome do arquivo e obtém o ponteiro</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">    <span style="color: green;">//      com seu conteúdo mapeado. Simples assim...</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    dwError = MapFileToMemory(_T(<span style="color: #a31515;">"C:\\Temp\\Test.txt"</span>),</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">                              (LPVOID*)&amp;pBuffer,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">                              &amp;dwSize);</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"> </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    <span style="color: green;">//-f--&gt; Testar erro nunca é demais.</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">    <span style="color: blue;">if</span> (dwError == ERROR_SUCCESS)</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    {</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">        <span style="color: green;">//-f--&gt; Momentos de suspense antes de tocar o endereço.</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">        printf(<span style="color: #a31515;">"Hit any key to access the buffer at 0x%p...\n"</span>, pBuffer);</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">        _getch();</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"> </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">        <span style="color: green;">//-f--&gt; Imprime cada caractere armzenado no arquivo.</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">        <span style="color: green;">//      "Olha mamãe! Sem o ReadFile()!"</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">        <span style="color: blue;">for</span> (i=<span style="color: purple;">0</span>; i</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">            printf(<span style="color: #a31515;">"%c"</span>, pBuffer[i]);</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"> </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">        <span style="color: green;">//-f--&gt; Aqui o mapeamento é desfeito.</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">        UnmapViewOfFile(pBuffer);</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    }</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"> </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    <span style="color: blue;">return</span> dwError;</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">}</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"> </pre>
</div>
<p>Ao final deste exemplo podemos observar a chamada à rotina <a href="http://msdn.microsoft.com/en-us/library/aa366882(VS.85).aspx">UnmapViewOfFile()</a>, que recebe simplesmente o ponteiro base do mapeamento do arquivo. Com essa chamada, todas as referências internas são desfeitas e o arquivo finalmente é fechado.</p>
<h3>Testando o brinquedo</h3>
<p>Para que possamos fazer um teste besta, crie um arquivo texto utilizando o Notepad.exe.</p>
<p style="text-align: center;"><img class="aligncenter" style="padding: 5px;" src="http://driverentry.com.br/images/TextFileToMap.PNG" alt="" width="621" height="219" /></p>
<p>Rodando a aplicação de teste temos a saída como ilustrada abaixo.</p>
<p style="text-align: center;"><img class="aligncenter" style="padding: 5px;" src="http://driverentry.com.br/images/MapFileOutput2.png" alt="" width="684" height="225" /></p>
<h3>Agora na câmera lenta do replay</h3>
<p>Com o <a href="http://www.microsoft.com/whdc/devtools/debugging/default.mspx">WinDbg</a> podemos observar o exato momento em que a aplicação acessa o intervalo de endereços referente ao conteúdo do arquivo. Para isso vamos colocar um breakpoint na rotina de leitura de arquivo do driver <strong>Ntfs.sys</strong>, desta forma poderemos ver a requisição do Memóry Manager ser atendida. Para que isso aconteça, o arquivo texto não pode estar no cache do sistema, então se você já rodou a aplicação de teste ao menos uma vez, você deverá reiniciar o sistema.</p>
<p>Caso você ainda não tenha utilizado o WinDbg e não sabe como conectá-lo ao sistema, então leia <a href="http://driverentry.com.br/blog/?p=177">este post</a> para um quick start. Depois de conectar o WinDbg ao Kernel do sistema, vá até o diretório onde está a aplicação de teste e a execute, mas ainda não pressione qualquer tecla deixando-a parada como mostra a seguir:</p>
<p style="text-align: center;"><img class="aligncenter" style="padding: 5px;" src="http://driverentry.com.br/images/MapFileOutput1.png" alt="" /></p>
<p>Depois disso pressione Ctrl+Break no WinDbg para que você adquira o controle sobre o sistema depurado, que neste momento vai permanecer congelado.</p>
<p>Para colocar o tal breakpoint na rotina de leitura de arquivo do Ntfs.sys, precisaremos saber onde está essa rotina dentro do driver. Podemos obter essa informação utilizando a extenção <strong>!drvobj</strong> do WinDbg como exibido abaixo.</p>
<div style="font-family: Consolas; font-size: 9pt; color: black; background: #A4F64C; border: 1px outset; padding: 0 0 0 5px;">
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">kd&gt; !drvobj \FileSystem\Ntfs 2</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">Driver object (843fd650) is for:</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"> \FileSystem\Ntfs</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">DriverEntry:   828f5b75    Ntfs!GsDriverEntry</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">DriverStartIo: 00000000    </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">DriverUnload:  00000000    </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">AddDevice:     00000000    </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"> </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">Dispatch routines:</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">[00] IRP_MJ_CREATE                      8289400a    Ntfs!NtfsFsdCreate</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">[01] IRP_MJ_CREATE_NAMED_PIPE           8165a013    nt!IopInvalidDeviceRequest</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">[02] IRP_MJ_CLOSE                       82896fcf    Ntfs!NtfsFsdClose</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"><span style="color: #ff0000;">[03] IRP_MJ_READ                        82818514    Ntfs!NtfsFsdRead</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">[04] IRP_MJ_WRITE                       82815638    Ntfs!NtfsFsdWrite</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">[05] IRP_MJ_QUERY_INFORMATION           82895a88    Ntfs!NtfsFsdDispatchWait</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">[06] IRP_MJ_SET_INFORMATION             8281e950    Ntfs!NtfsFsdSetInformation</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">[07] IRP_MJ_QUERY_EA                    82895a88    Ntfs!NtfsFsdDispatchWait</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">[08] IRP_MJ_SET_EA                      82895a88    Ntfs!NtfsFsdDispatchWait</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">[09] IRP_MJ_FLUSH_BUFFERS               82884349    Ntfs!NtfsFsdFlushBuffers</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">[0a] IRP_MJ_QUERY_VOLUME_INFORMATION    828b5fc6    Ntfs!NtfsFsdDispatch</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">[0b] IRP_MJ_SET_VOLUME_INFORMATION      828b5fc6    Ntfs!NtfsFsdDispatch</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">[0c] IRP_MJ_DIRECTORY_CONTROL           828b5d41    Ntfs!NtfsFsdDirectoryControl</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">[0d] IRP_MJ_FILE_SYSTEM_CONTROL         8289970e    Ntfs!NtfsFsdFileSystemControl</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">[0e] IRP_MJ_DEVICE_CONTROL              82879466    Ntfs!NtfsFsdDeviceControl</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">[0f] IRP_MJ_INTERNAL_DEVICE_CONTROL     8165a013    nt!IopInvalidDeviceRequest</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">[10] IRP_MJ_SHUTDOWN                    8282b36b    Ntfs!NtfsFsdShutdown</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">[11] IRP_MJ_LOCK_CONTROL                82823b7a    Ntfs!NtfsFsdLockControl</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">[12] IRP_MJ_CLEANUP                     828a1d42    Ntfs!NtfsFsdCleanup</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">[13] IRP_MJ_CREATE_MAILSLOT             8165a013    nt!IopInvalidDeviceRequest</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">[14] IRP_MJ_QUERY_SECURITY              828b5fc6    Ntfs!NtfsFsdDispatch</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">[15] IRP_MJ_SET_SECURITY                828b5fc6    Ntfs!NtfsFsdDispatch</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">[16] IRP_MJ_POWER                       8165a013    nt!IopInvalidDeviceRequest</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">[17] IRP_MJ_SYSTEM_CONTROL              8165a013    nt!IopInvalidDeviceRequest</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">[18] IRP_MJ_DEVICE_CHANGE               8165a013    nt!IopInvalidDeviceRequest</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">[19] IRP_MJ_QUERY_QUOTA                 82895a88    Ntfs!NtfsFsdDispatchWait</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">[1a] IRP_MJ_SET_QUOTA                   82895a88    Ntfs!NtfsFsdDispatchWait</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">[1b] IRP_MJ_PNP                         8286137b    Ntfs!NtfsFsdPnp</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"> </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">Fast I/O routines:</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">FastIoCheckIfPossible                   8288187b    Ntfs!NtfsFastIoCheckIfPossible</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">FastIoRead                              82880c38    Ntfs!NtfsCopyReadA</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">FastIoWrite                             82881f53    Ntfs!NtfsCopyWriteA</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">FastIoQueryBasicInfo                    82888c3a    Ntfs!NtfsFastQueryBasicInfo</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">FastIoQueryStandardInfo                 82888aa6    Ntfs!NtfsFastQueryStdInfo</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">FastIoLock                              8287bf41    Ntfs!NtfsFastLock</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">FastIoUnlockSingle                      8287bd75    Ntfs!NtfsFastUnlockSingle</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">FastIoUnlockAll                         828cd7b3    Ntfs!NtfsFastUnlockAll</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">FastIoUnlockAllByKey                    828cd958    Ntfs!NtfsFastUnlockAllByKey</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">ReleaseFileForNtCreateSection           8281e904    Ntfs!NtfsReleaseForCreateSection</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">FastIoQueryNetworkOpenInfo              8287ad84    Ntfs!NtfsFastQueryNetworkOpenInfo</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">AcquireForModWrite                      8280c892    Ntfs!NtfsAcquireFileForModWrite</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">MdlRead                                 828cd0d8    Ntfs!NtfsMdlReadA</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">MdlReadComplete                         81650af6    nt!FsRtlMdlReadCompleteDev</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">PrepareMdlWrite                         828cd31f    Ntfs!NtfsPrepareMdlWriteA</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">MdlWriteComplete                        817f5a9a    nt!FsRtlMdlWriteCompleteDev</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">FastIoQueryOpen                         82874d03    Ntfs!NtfsNetworkOpenCreate</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">AcquireForCcFlush                       8281ab35    Ntfs!NtfsAcquireFileForCcFlush</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">ReleaseForCcFlush                       8281aa9c    Ntfs!NtfsReleaseFileForCcFlush</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"> </pre>
</div>
<p>Como você deve estar imaginando, a rotina de leitura do Ntfs é utilizada com muita frequência, o que faria este breakpoint parar muitas vezes sem ter a menor relação com o nosso teste. Para limitar o escopo do breakpoint, vamos fazer com que ele se aplique somente à thread que fará a solicicação que estamos esperando.</p>
<p>Como já expliquei no <a href="http://driverentry.com.br/blog/?p=701">post anterior</a>, quando o endereço de memória é obtido, o arquivo ainda não foi lido. Quando a aplicação desreferenciar este ponteiro buscando os dados, um <em>page fault</em> será gerado e o Memory Manager vai tomar o controle sobre a thread por meio de um <em>trap</em> de sistema. Essa é a thread que será utilizada para realizar a leitura do arquivo que vai abastecer a página de memória à pedido do Memory Manager. Esta é a razão pela qual nosso programa de teste espera uma tecla ser pressionada antes de acessar o buffer. Isso nos dá a oportunidade de obter a identificação da thread que está aguardando esse evento.</p>
<p>Utilizamos a extenção <strong>!process</strong> para localizar o nosso programa de teste e também listará suas threads, que em nosso caso é uma única.</p>
<div style="font-family: Consolas; font-size: 9pt; color: black; background: #A4F64C; border: 1px outset; padding: 0 0 0 5px;">
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">kd&gt; !process 0 2 MapFile.exe</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">PROCESS 84bf6d90  SessionId: 1  Cid: 0b60    Peb: 7ffdf000  ParentCid: 0b40</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    DirBase: 1f09b4c0  ObjectTable: 8e77ccd0  HandleCount:   5.</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">    Image: MapFile.exe</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"> </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">        THREAD <span style="color: #ff0000;">84f6cb50</span>  Cid 0b60.0b64  Teb: 7ffde000 Win32Thread: 00000000 WAIT: (WrLpcReply) ...</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">            84f6cd64  Semaphore Limit 0x1</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"> </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">kd&gt; bp /1 /t <span style="color: #ff0000;">84f6cb50</span> Ntfs!NtfsFsdRead</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">kd&gt; g</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"> </pre>
</div>
<p>Depois de colocado o breakpoint, podemos liberar a execução do sistema e teclar algo na aplicação de teste. Isso fará com que nosso breakpoint interrompa o sistema bem como pretendíamos. Olhando para a pilha de chamadas que temos no momento, podemos evidenciar a execução do trap que foi gerado pela aplicação de teste. Este <em>trap</em> está sendo atendido pelo Memory Manager.</p>
<div style="font-family: Consolas; font-size: 9pt; color: black; background: #A4F64C; border: 1px outset; padding: 0 0 0 5px;">
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">Breakpoint 0 hit</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">Ntfs!NtfsFsdRead:</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">82818514 6a40</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"> </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">kd&gt; kb</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">ChildEBP <span style="color: #ff0000;">RetAddr</span>  Args to Child</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">8f395b6c 816f00c3 84438020 <span style="color: #ff0000;">84f40290</span> 84f40290 Ntfs!NtfsFsdRead</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">8f395b84 821a3ba7 84437730 84f40290 00000000 nt!IofCallDriver+0x63</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">8f395ba8 821a3d64 8f395bc8 84437730 00000000 fltmgr!FltpLegacyProcessingAfterPreCallbacksCompleted+0x251</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">8f395be0 816f00c3 84437730 84f40290 00000000 fltmgr!FltpDispatch+0xc2</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">8f395bf8 8167bf2e 84f6cb50 8443a18c 8443a158 nt!IofCallDriver+0x63</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">8f395c14 816b8d51 00000043 84f6cb50 8443a198 nt!IoPageRead+0x172</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">8f395cd0 816db03f 00020000 90825810 00000000 nt!MiDispatchFault+0xd18</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">8f395d4c <span style="color: #ff0000;">8168ebf4</span> 00000000 00020000 00000001 <span style="color: #ff0000;">nt!MmAccessFault</span>+0x1fb7</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">8f395d4c 0018d972 00000000 00020000 00000001 <span style="color: #ff0000;">nt!KiTrap0E</span>+0xdc</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">0015fbc0 0018ec36 00000001 00281a28 00281a78 MapFile!wmain+0x72</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">0015fc0c 0018eb0f 0015fc20 77554911 7ffdf000 MapFile!__tmainCRTStartup+0x116</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">0015fc14 77554911 7ffdf000 0015fc60 77ace4b6 MapFile!wmainCRTStartup+0xf</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">0015fc20 77ace4b6 7ffdf000 77a26775 00000000 kernel32!BaseThreadInitThunk+0xe</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">0015fc60 77ace489 0018b532 7ffdf000 00000000 ntdll!__RtlUserThreadStart+0x23</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">0015fc78 00000000 0018b532 7ffdf000 00000000 ntdll!_RtlUserThreadStart+0x1b</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"> </pre>
</div>
<p>Como conhecemos o protótipo que uma rotina de dispatch precisa ter, sabemos que o segundo parâmetro da rotina <em>NtfsFsdRead()</em> é o endereço da <a href="http://driverentry.com.br/blog/?p=454">IRP</a> que o driver recebeu. Utilizando a extensão <strong>!irp</strong> podemos obter detalhes sobre a IRP. Isso nos permite conhecer o <em>FileObject</em> ao qual está destinado essa solicitação.</p>
<div style="font-family: Consolas; font-size: 9pt; color: black; background: #A4F64C; border: 1px outset; padding: 0 0 0 5px;">
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">kd&gt; !irp <span style="color: #ff0000;">84f40290</span> </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">Irp is active with 8 stacks 8 is current (= 0x84f403fc)</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"> Mdl=8443a1d8: No System Buffer: Thread 84f6cb50:  Irp stack trace.  </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">     cmd  flg cl Device   <span style="color: #ff0000;">File</span>     Completion-Context</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"> [  0, 0]   0  0 00000000 00000000 00000000-00000000    </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"> </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">            Args: 00000000 00000000 00000000 00000000</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"> [  0, 0]   0  0 00000000 00000000 00000000-00000000    </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"> </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">            Args: 00000000 00000000 00000000 00000000</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"> [  0, 0]   0  0 00000000 00000000 00000000-00000000    </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"> </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">            Args: 00000000 00000000 00000000 00000000</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"> [  0, 0]   0  0 00000000 00000000 00000000-00000000    </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"> </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">            Args: 00000000 00000000 00000000 00000000</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"> [  0, 0]   0  0 00000000 00000000 00000000-00000000    </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"> </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">            Args: 00000000 00000000 00000000 00000000</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"> [  0, 0]   0  0 00000000 00000000 00000000-00000000    </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"> </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">            Args: 00000000 00000000 00000000 00000000</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"> [  0, 0]   0  0 00000000 00000000 00000000-00000000    </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"> </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">            Args: 00000000 00000000 00000000 00000000</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">&gt;[  3, 0]   0  0 84438020 <span style="color: #ff0000;">84bd0028</span> 00000000-00000000    </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">           \FileSystem\Ntfs</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">            Args: 00001000 00000000 00000000 00000000</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"> </pre>
</div>
<p>Com o endereço do FileObject em mãos, a extensão <strong>!fileobj</strong> nos mostrará mais detalhes sobre esse objeto. Assim podemos verificar que de fato o arquivo a ser lido é o nosso arquivo texto que foi mapeado.</p>
<div style="font-family: Consolas; font-size: 9pt; color: black; background: #A4F64C; border: 1px outset; padding: 0 0 0 5px;">
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">kd&gt; !fileobj <span style="color: #ff0000;">84bd0028</span> </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"> </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"><span style="color: #ff0000;">\Temp\Test.txt</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"> </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">Device Object: 0x84439030   \Driver\volmgr</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">Vpb: 0x84436e28</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">Access: Read SharedRead SharedDelete </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"> </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">Flags:  0x44042</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">    Synchronous IO</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    Cache Supported</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">    Cleanup Complete</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    Handle Created</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"> </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">FsContext: 0x92a4cd80    FsContext2: 0x92a4ced8</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">CurrentByteOffset: 0</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">Cache Data:</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">  Section Object Pointers: 84d24e74</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">  Shared Cache Map: 00000000</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"> </pre>
</div>
<p>Sabendo que estamos no contexto da thread que fez o acesso, podemos dar uma espiadinha no endereço acessado antes do <em>page fault</em> ser atendido. Esse endereço foi exibido na saída da aplicação de teste antes o breakpoint interromper a execução do sistema.</p>
<div style="font-family: Consolas; font-size: 9pt; color: black; background: #A4F64C; border: 1px outset; padding: 0 0 0 5px;">
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">kd&gt; db <span style="color: #ff0000;">0x00020000</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">00020000  ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ??  ????????????????</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">00020010  ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ??  ????????????????</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">00020020  ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ??  ????????????????</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">00020030  ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ??  ????????????????</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">00020040  ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ??  ????????????????</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">00020050  ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ??  ????????????????</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">00020060  ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ??  ????????????????</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">00020070  ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ??  ????????????????</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"> </pre>
</div>
<blockquote><p>&#8220;Fernando, por que aparecem sinais de interrogação? Tudo bem que o conteúdo do arquivo ainda não foi copiado para o buffer da aplicação, mas não deveríamos ver lixo ou mesmo zeros?&#8221;</p>
</blockquote>
<p>Olha, essa sua pergunta foi realmente muito boa, acho que eu mesmo não poderia ter pensado em uma pergunta melhor. Na verdade a resposta para essa pergunta está vinculada àquela reposta tosca do <a href="http://driverentry.com.br/blog/?p=701">post anterior</a>. O que acontece é que um intervalo de endereços foi reservado para conter as páginas de memória com o conteúdo do arquivo. Como nenhum acesso ainda foi feito, o esse endereço virtual ainda não aponta para nenhuma página física de memória. Sem essa página física não se pode determinar seus dados. Podemos verificar isso utilizando a extenção <strong>!vtop</strong> do WinDbg, que faz a tradução de endereços virtuais para endereços físicos.</p>
<div style="font-family: Consolas; font-size: 9pt; color: black; background: #A4F64C; border: 1px outset; padding: 0 0 0 5px;">
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">kd&gt; !vtop 0 <span style="color: #ff0000;">0x00020000</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">X86VtoP: Virt 00020000, pagedir 1f09b4c0</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">X86VtoP: PAE PDPE 1f09b4c0 - 000000001876d801</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">X86VtoP: PAE PDE 1876d000 - 0000000018908867</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">X86VtoP: PAE PTE 18908100 - ffffffff00000420</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">X86VtoP: Virt ffffffff, pagedir 1f09b4c0</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">X86VtoP: PAE PDPE 1f09b4d8 - 00000000187b0801</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">X86VtoP: PAE PDE 187b0ff8 - 0000000000128063</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">X86VtoP: PAE PTE 128ff8 - 0000000000000000</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">X86VtoP: PAE zero PTE</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">Virtual address 20000 translation fails, error <span style="color: #ff0000;">0x8007001E</span>.</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"> </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">kd&gt; !error <span style="color: #ff0000;">0x8007001E</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">Error code: (HRESULT) 0x8007001e (2147942430) - The system cannot read from the specified device.</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"> </pre>
</div>
<p>A tentativa de tradução desse endereço virtual resulta em um erro. Vamos tentar fazer essa tradução novamente depois que o <em>page fault</em> for atendito. Vamos liberar a execução do sistema até o endereço de retorno para a rotina <em>MmAccessFault()</em>. Este endereço foi obtido na pilha de chamadas da thread e foi destacado nos resultados do comando <strong>kd</strong> já ilustrado acima.</p>
<div style="font-family: Consolas; font-size: 9pt; color: black; background: #A4F64C; border: 1px outset; padding: 0 0 0 5px;">
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">kd&gt; ga <span style="color: #ff0000;">8168ebf4</span> </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"> </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">nt!KiTrap0E+0xdc:</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">8168ebf4 85c0            test    eax,eax</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"> </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">kd&gt; !vtop 0 <span style="color: #ff0000;">0x00020000</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">X86VtoP: Virt 00020000, pagedir 1f09b4c0</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">X86VtoP: PAE PDPE 1f09b4c0 - 000000001876d801</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">X86VtoP: PAE PDE 1876d000 - 0000000018908867</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">X86VtoP: PAE PTE 18908100 - 8000000018844025</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">X86VtoP: PAE Mapped phys 18844000</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">Virtual address 20000 translates to physical address 18844000.</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"> </pre>
</div>
<p>Aqui o page fault já foi antendido e o controle será devolvido à aplicação. Neste ponto o Memory Manager realizou as tarefas necessárias para que esse endereço virtual agora pudesse ser traduzido para uma página física. Repetindo a mesma tentativa de tradução que falhou anteriormente, teremos a seguinte saída.</p>
<div style="font-family: Consolas; font-size: 9pt; color: black; background: #A4F64C; border: 1px outset; padding: 0 0 0 5px;">
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">kd&gt; db <span style="color: #ff0000;">0x00020000</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">00020000  54 65 73 74 65 20 64 65-20 6d 61 70 65 61 6d 65  Teste de mapeame</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">00020010  6e 74 6f 20 64 65 20 61-72 71 75 69 76 6f 2e 2e  nto de arquivo..</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">00020020  2e 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">00020030  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">00020040  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">00020050  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">00020060  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">00020070  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................</pre>
</div>
<p>Liberando a execução do sistema, a aplicação fará o acesso ao buffer e teremos a mesma saída exibida anteriormente. Vale lembrar que para repetir essa experiência, é necessário reiniciar o sistema, pois o conteúdo do arquivo texto agora está no <em>cache</em> do sistema. Isso significa que o <em>page fault</em> não ocorrerá novamente até que esta página seja descartada pelo Cache Manager. Tal evento depende de muitos fatores e pode não acontecer até que a máquina desligue.</p>
<p>Enfim, este post além de trazer uma simples função de mapeamento de arquivo, também traz o mesmo blá-blá-blá técnico de sempre. Espero que tenham gostado.<br />
 Até mais! <img src='http://driverentry.com.br/wp/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /> </p>
<p class="download"><a href="http://www.driverentry.com.br/samples/MapFile.zip">MapFile.zip</a></p>
]]></content:encoded>
			<wfw:commentRss>http://driverentry.com.br/blog/?feed=rss2&amp;p=731</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Ponteiro perdido no Kernel pode corromper arquivos?</title>
		<link>http://driverentry.com.br/blog/?p=701</link>
		<comments>http://driverentry.com.br/blog/?p=701#comments</comments>
		<pubDate>Wed, 09 Jun 2010 12:04:16 +0000</pubDate>
		<dc:creator>Fernando Roberto</dc:creator>
				<category><![CDATA[Kernel Development]]></category>

		<guid isPermaLink="false">http://driverentry.com.br/blog/?p=701</guid>
		<description><![CDATA[A nova versão de um driver pode implementar aquela funcionalidade nova que você tanto esperava. Afinal de contas, o time de desenvolvimento de drivers anda sempre muito ocupado, e para conseguir alguma coisa nova é sempre um parto. O único problema é que de vez em outra uma tela azul acontece. Os mais desesperados podem [...]]]></description>
			<content:encoded><![CDATA[<p>A nova versão de um driver pode implementar aquela funcionalidade nova que você tanto esperava. Afinal de contas, o time de desenvolvimento de drivers anda sempre muito ocupado, e para conseguir alguma coisa nova é sempre um parto. O único problema é que de vez em outra uma tela azul acontece. Os mais desesperados podem até querer usar o novo driver a qualquer custo, mesmo que uma telinha azul apareça com uma frequência aceitável. Aí surge a perguntinha:</p>
<blockquote><p>Fernando, existe algum problema se eu for usando esse driver novo até que uma correção para essa tela azul saia?</p>
</blockquote>
<p>O principal problema aqui é que não temos a menor idéia do que está causando a tela azul. Esse tipo de classificação (sem a menor idéia) inclui um ponteiro que pode sair escrevendo onde não se deve. Além de sair atropelando estruturas vitais do sistema operacional, esse ponteiro bomba pode também corromper arquivos. Então, mais uma perguntinha:</p>
<blockquote><p>Mas Fernando, esse driver nem faz manipulação de arquivos. Como é que um ponteiro perdido pode abrir um arquivo e ainda gerar uma escrita em disco para corrompê-lo?</p>
</blockquote>
<p>Na verdade, isso não é assim tão difícil. Você já ouviu falar do Cache Manager?</p>
<h3>Quem é esse tal de Cache Manager?</h3>
<p>Vi uma definição simples de Cache Manager em uma palestra do <a href="http://www.microsoft.com/whdc/driver/filterdrv/IFSPlugfest.mspx">Plugfest</a>. Vamos ver se consigo reproduzí-la aqui. Vocês desenvolvedores provavelmente já fizeram cache do conteúdo de algum arquivo em uma aplicação para não ter que acessar o tal arquivo toda vez que precisar da informação contida nele, certo? Errado? Tá tá, então do começo hoje.</p>
<p><img style="float: right; padding-left: 5px;" src="http://driverentry.com.br/images/SimpleCache.png" alt="" /></p>
<p>Lembra lá no prézinho quando a tia ensinou que se você fizer acesso com frequência a um arquivo, você pode manter uma cópia dele em memória e evitar de fazer tanto I/O para ganhar performance? Nesse caso uma área de memória, também conhecida como cache, é carregada com o conteúdo do arquivo. Depois disso, os vários acessos de leitura ao arquivo são substituídos por leituras no cache. Quando uma escrita acontece, o cache é atualizado e a escrita também vai para o arquivo. Em casos onde a escrita é frequente, o cache é atualizado a cada escrita enquanto o arquivo recebe várias modificações de uma vez em intervalos definidos.</p>
<p>O cache implementado na aplicação perde o sentido se um determinado arquivo é compartilhado por mais de uma aplicação, o conteúdo do cache da aplicação &#8220;A&#8221; tem que ser o mesmo do cache da aplicação &#8220;B&#8221;, caso contrário, as alterações feitas pela aplicação &#8220;A&#8221; não seriam vistas pela aplicação &#8220;B&#8221; e vice versa, sem falar que as atualizações seriam perdidas sem o correto sincronismo que isso exigiria.</p>
<p>Por essa razão é que existe um cache centralizado no sistema. Um módulo no Kernel que mantém páginas de memória contendo o conteúdo dos arquivos recentemente manipulados. Quando um arquivo é aberto, ele é registrado pelo seu respectivo driver de File System no Cache Manager. Mas o Cache Manager não faz tudo sozinho. Na verdade ele faz parte de uma gangue nas &#8220;quebrada&#8221; que garante a otimização de acessos a arquivos no sistema. Para isso o Cache Manager conta com a ajuda de seus fiéis companheiros, o Vitual Memory Manager e os File System Drivers.</p>
<p>Pulando algumas toneladas de detalhes, digamos que quando uma solicitação de leitura chega a um driver de file system, este a encaminha ao Cache Manager, este então vai satisfazer tal operação apenas copiando o conteúdo desejado do arquivo que já estaria em páginas de memória. Copiar os dados da memória é muito mais rápido que fazer todo o ritual para obter os mesmos dados do disco, mas para isso os dados já deveriam estar carregados na memória.</p>
<blockquote><p>Fernando, o Cache Manager coloca todo o arquivo na memória?</p>
</blockquote>
<p>Quer uma resposta tosca? Sim e Não <img src='http://driverentry.com.br/wp/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /> . O Cache Manager na verdade mapeia o arquivo aberto em memória, e para isso ele conta com as características mais básicas de memória virtual discutidas neste <a href="http://driverentry.com.br/blog/?p=302">outro post</a>. Um intervalo de endereços é reservado no sistema, mas tais endereços ainda não se refletem em espaços nos chips de memória, ou seja, existe um endereço de memória, mas seu contetúdo ainda está em disco. O Memory Manager protege esses endereços contra acessos que podem ocorrem a eles. Quando um acesso de leitura é realizado nestes endereços, um <em>page fault</em> ocorre e o Memory Manager então precisa recuperar os dados do arquivo que estão no disco e colocá-os em memória. Para fazer isso o Memory Manager vai criar uma solicitação de leitura no I/O Manager para que uma IRP possa ser entregue ao respectivo driver de file system do arquivo em questão.</p>
<blockquote><p>Pára tudo &#8220;perlamor&#8221; de Deus! Fernando, você disse logo alí em cima que quando uma solicitação de leitura chega ao driver de file system, esta é encaminhada ao Cache Manager que vai copiar os dados já contidos na memória a fim de antender a solicitação. Mas agora você está dizendo que para carregar tais páginas de memória o Cache Manager troca uma idéia com o Memory Manager, que por sua vêz vai criar uma solicitação de leitura para os drivers de file system. Isso não lhe parece um pouco recursivo?</p>
</blockquote>
<p>Eu diria completamente recursivo, mas lembre-se que isso vai ocorrer apenas quando o arquivo ainda não foi lido por nenhum processo, e portanto ainda não está no cache do sistema. Para diferenciar uma solicitação da outra, drivers de file system precisam verificar a flag IRP_NOCACHE nas solicitações que recebem. Quando as solicitações vêm de uma aplicação, estas não carregam a flag IRP_NOCACHE, e desta forma podem ser atendidas pelo Cache Manager, por outro lado quando o Memory Manager precisa suprir as páginas de memória do Cache Manager, tais solicitações precisam ignorar o conteúdo do cache, e por isso carregam a flag IRP_NOCACHE. Paga facilitar o entendimento de toda essa  máquina, observem os passos enumerados de uma leitura de arquivo que ainda não está no cache.</p>
<p style="text-align: center;"><img src="http://driverentry.com.br/images/ReadSequence.png" alt="" width="422" height="412" /></p>
<ol>
<li>Uma aplicação faz uma solicitação de leitura de um arquivo.</li>
<li>I/O Manager cria uma IRP e a encaminha ao seu respectivo driver de file system.</li>
<li>O driver de file system verifica a ausência da flag IRP_NOCACHE e solicita a cópia dos dados desse arquivo do cache para o buffer da aplicação.</li>
<li>O Cache Manager tenta fazer a cópia acessando as páginas que foram mapeadas do arquivo. Com isso um <em>page fault</em> é gerado por esse acesso e é atendido pelo Memory Manager.</li>
<li>O Memory Manager cria uma nova IRP para atender a necessidade de abastecer o Cache Manager. Essa solicitação é encaminhada recursivamente ao driver de file system.</li>
<li>Dessa vez o driver verifica a presença da flag IRP_NOCACHE e então cria as solicitações que serão atendidas pelos drivers de disco ou de rede.</li>
<li>As solicitações de leitura de mídia são atendidas.</li>
<li>As páginas de memória são abastecidas e o <em>page fault</em> é satisteito.</li>
<li>Memory Manager re-executa a tentativa de leitura do Cache Manager que gerou o <em>page fault</em>, mas desta vez a o acesso de leitura será bem sucedido, pois os dados agora estão no endereço de memória mapeado.</li>
<li>O Cache Manager completa a cópia dos dados para o buffer da aplicação.</li>
<li>O driver de file system completa a solicitação de leitura.</li>
<li>Os dados são retornados para a aplicação que fez a solicitação inicial.</li>
</ol>
<p>Atenção agora meninos e meninas: A sequência descrita acima ilustra o caso onde o Cache Manager ainda precisa carregar o arquivo em memória. As próximas tentativas de leituras são satisfeitas diretamente pelo Cache Manager, que não vai gerar um <em>page fault</em>. Não vão me matar de vergonha dizendo por aí que o sistema operacional sempre faz toda a sequência para cada leitura de arquivo.</p>
<p>Mais uma vez as regras básicas de memória virtual são aplicadas aqui para que conforme as páginas de memória vão deixando de ser acessadas com tanta frequência, elas perdem lugar nos chips de memória, e assim, se mais tarde forem acessadas novamente, um novo <em>page fault</em> será gerado.</p>
<p>Interessante ver como esses componentes, o I/O Manager, Cache Manager, Virtual Memory Manager, File System Drivers, sem falar dos filtros que ainda podem existir, todos trabalhando juntos como caixas pretas, cada um com seu papel e sem conhecer o funcionamento interno do outro, interagindo entre si apenas através de suas interfaces públicas. Óbviamente que para a felicidade de alguns e talvêz tristeza de outros, não coloquei todos os detalhes aqui, mas podem ser encontrados no conhecido <a href="http://www.amazon.com/Windows-System-Internals-Classic-Reprints/dp/0976717514/ref=sr_1_1?ie=UTF8&amp;s=books&amp;qid=1276164865&amp;sr=8-1">livro da galinha preta</a>.</p>
<h3>Mas voltando ao assunto&#8230;</h3>
<p>De maneira análoga, as escritas também utilizam essa mesma mecânica que envolve mapeamento de arquivos. O simples fato de escrever no intervalo de endereços que é mantido pelo Cache Manager vai fazer com que tal página seja marcada como modificada, e mais tarde o Memory Manager vai querer atualizar essa página em disco. Dessa forma podemos resumir que solicitações de escrita chegam aos drivers de File System e são encaminhadas ao Cache Manager, que vai simplesmente escrever nas páginas referentes ao conteúdo do arquivo e completar a solicitação. <em>Page faults</em> e threads de sistema vão se encarregar de atualizar o que for preciso no momento mais adequado. O importante a notar aqui é pensarmos no Cache Manager como um simples consumidor dos serviços do Memory Manager, tudo que ele precisa fazer é ler ou escrever em páginas de memória, e é aqui que o título do post começa a fazer sentido.</p>
<p>Nada impede um ponteiro retardado de escrever em páginas de memória que fazem referência ao conteúdo de arquivos. Se isso acontece, o restante do sistema vai se encarregar de atualizar as barbaridades desse ponteiro em disco corrompendo o arquivo. É fácil notar que nem é necessário tantos passos para isso acontecer.</p>
<p style="text-align: center;"><img class="aligncenter" style="padding: 5px;" src="http://driverentry.com.br/images/BuggyWrite.png" alt="" /></p>
<ol>
<li>Um driver inexperiente come aquele pedaço de pizza que ficou esquecido no micro-ondas e fica bem loco. Depois de dar vexame, falar o que não devia, chorar e dizer que te considera pra caramba, o driver escreve em páginas de memória referente a um arquivo de dados. Tipo um daqueles do SQL que eu nem imagino a extensão.</li>
<li>O coitado do Memory Manager faz seu trabalho para garantir o leitinho das crianças como se nada de errado tivesse acontecido.</li>
<li>O driver de file system vai de embalo e consolida a completa falta de noção do driver, que numa hora dessas já está abraçado com o vaso sanitário.</li>
<li>Esse passo não é ilustrado na sequência acima mas pode ser explicado nesse <a href="http://www.apinfo.com/">site</a>.</li>
</ol>
<p>Nessa hora você vai torcer para que seu driver novinho em folha escreva sobre alguma estrutura vital do sistema para que uma tela azul possa conter a atividade desse inconsequente. Por esse motivo é que o sistema está cheio de testes e verificações para garantir que os dados do usuário não sejam perdidos. Melhor ver uma tela azul do que ter consequências muito piores. Lembre-se do sábio Morphy:</p>
<blockquote><p>Nada é tão ruim que não possa ser piorado</p>
</blockquote>
<p><img style="float: right; padding: 0 0 0 5px;" src="http://driverentry.com.br/images/DelayedWrite.png" alt="" />Ainda existem muitas outras características interessantes sobre o Cache Manager que eu gostaria de descrever aqui, como por exemplo a &#8220;Falha de escrita retardada&#8221;, mas esse post já está ficando muito grande.</p>
<p><br class="spacer_" /></p>
<p>Até mais&#8230; <img src='http://driverentry.com.br/wp/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://driverentry.com.br/blog/?feed=rss2&amp;p=701</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Prevenindo Execução de Processos</title>
		<link>http://driverentry.com.br/blog/?p=683</link>
		<comments>http://driverentry.com.br/blog/?p=683#comments</comments>
		<pubDate>Mon, 17 May 2010 04:46:52 +0000</pubDate>
		<dc:creator>Fernando Roberto</dc:creator>
				<category><![CDATA[Kernel Development]]></category>

		<guid isPermaLink="false">http://driverentry.com.br/blog/?p=683</guid>
		<description><![CDATA[Durante esse longo período em que estive distante de novos posts no blog, algumas coisas aconteceram e que mereceram um lugarzinho aqui na em minha listinha de posts a escrever. Uma delas foi a longa discussão que aconteceu na lista do grupo de C/C++. Ela falava sobre quais as passos a serem seguidos para se [...]]]></description>
			<content:encoded><![CDATA[<p><img style="float: right; padding: 0 0 5px 5px;" src="http://www.driverentry.com.br/images/StopIcon.png" alt="" width="150" height="151" />Durante esse longo período em que estive distante de novos posts no blog, algumas coisas aconteceram e que mereceram um lugarzinho aqui na em minha listinha de posts a escrever. <a href="http://groups.google.com/group/ccppbrasil/browse_thread/thread/ace4f9312b8e5668#">Uma delas</a> foi a longa discussão que aconteceu na lista do <a href="http://groups.google.com/group/ccppbrasil">grupo de C/C++</a>. Ela falava sobre quais as passos a serem seguidos para se escrever um driver que faria um pouco de tudo sobre serviços de segurança. Um dos ítens que foi especialmente discutido foi a idéia de se escrever um driver que pudesse impedir que um determinado processo fosse executado. Já vou logo dizendo que não vou me envolver se isso resolve ou não um problema de sergurança. Não estou aqui pra discutir isso, e para ser bem sincero, eu nem quero. Neste post vou demonstrar de uma maneira bem simples como podemos evitar a execução de um processo.</p>
<h3>Rastreando o tempo de vida dos Processos</h3>
<p>Antes de sair colocando os dois pés no peito de um processo para que ele caia, vamos primeiro apenas ver como monitorar seu tempo de vida. Isso é facilmente feito chamando a rotina <a href="http://msdn.microsoft.com/en-us/library/ff559951(VS.85).aspx">PsSetCreateProcessNotifyRoutine()</a> que está disponível desde quando o arco-iris era preto e branco. Embora a documentação diga que está disponível desde o Windows 2000, já conheço essa rotina de outros carnavais e sei que está por aí pelo menos desde o finado Windows NT 3.51. Nossa, estou ficando velho. Mas voltando ao assunto, essa rotina registra uma função de callback que notifica nosso driver sobre o ínico e o término dos processos no sistema. Isso é especialmente útil se um determinado driver quer manter informações relacionadas aos processos, e assim, saber quando um processo foi encerrado é fundamental para liberar os recursos utilizados tais informações.</p>
<div style="font-family: Courier New; font-size: 9pt; color: black; background: #A4F64C; border: 1px outset; padding: 0 0 0 5px;">
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">NTSTATUS PsSetCreateProcessNotifyRoutine(</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">  __in  PCREATE_PROCESS_NOTIFY_ROUTINE NotifyRoutine,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">  __in  BOOLEAN Remove</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">);</pre>
</div>
<p>A função de callback registrada por essa rotina tem a assinatura como exibido abaixo:</p>
<div style="font-family: Courier New; font-size: 9pt; color: black; background: #A4F64C; border: 1px outset; padding: 0 0 0 5px;">
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">VOID</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">(*PCREATE_PROCESS_NOTIFY_ROUTINE) (</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    IN HANDLE  ParentId,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">    IN HANDLE  ProcessId,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    IN BOOLEAN  Create</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">    );</pre>
</div>
<p>Bem simples não? O primeiro parâmetro é o <em>ProcessId</em> do processo pai nessa criação. Isso significa que, se por exemplo você iniciar o Notepad a partir do <em>&#8220;Executar&#8230;&#8221;</em> no menu Iniciar do Windows, teremos o <em>Explorer.exe</em> como processo pai do novo processo <em>Notepad.exe</em>. O segundo parâmetro é o <em>ProcessId</em> do processo sendo iniciado ou encerrado no momento da chamada. Por último e não menos importante, temos a flag que vai indicar se esta é uma notificação de início ou de término de um processo.</p>
<p>Uma coisa importante a notar aqui é sobre o <em>ProcessId </em>do processo pai. Esse parâmetro é confiável nas notificações de inicio de processo, mas nem tanto quando se trata do término. Isso ocorre porque quando um processo está sendo iniciado, seu processo pai ainda está lá, firme e forte, mas quando um processo termina, apesar de o <em>ParentId </em>trazer o mesmo valor da notificação de ínicio de processo, esse dado não tem mais validade. Deixa eu dar um exemplo pra ficar mais fácil.</p>
<ol>
<li>Processo1(32) cria Processo2(57), recebemos chamada: CreateProcessNotifyRoutine(32, 57, TRUE);</li>
<li>Processo1(32) termina.</li>
<li>Processo3(32) é criado e granha Id igual a 32.</li>
<li>Processo2(57) termina e recebemos a chamada: CreateProcessNotifyRoutine(32, 57, FALSE);</li>
</ol>
<p>Na notificação de término do Processo2 que ocorreu no passo 4,  o processo cujo Id é 32 agora é o Processo3, que por sinal, não é realmente o processo pai do processo2. Então ao reunir informações sobre um processo, o faça durante sua inicialização, mantenha estes dados em uma lista e depois as remova quando o processo terminar.</p>
<p>Registrar a função de callback é muito simples, mas o importante mesmo é remover esse registro quando o driver for descarregado. Consegue imaginar o que aconteceria se uma dessas notificações fosse entregue a um driver que não está mais na memória? Bom, eu consigo.</p>
<h3>Obtendo o caminho da imagem de um processo</h3>
<p>É provável que você queira obter mais informações sobre os processos envolvidos nessas notificações, uma dessas informações é o caminho do arquivo que está sendo executado. Pode-se obter essa informação utilizando o Id dos processos que recebemos na notificação de novo processo. Para isso, teremos que utilizar a rotina quase documentada <a href="http://msdn.microsoft.com/en-us/library/ms687420(VS.85).aspx">ZwQueryInformationProcess()</a>. Essa é uma API nativa que existe desde sempre mas que nunca foi documentada oficialmente. Para utilizá-la basta declarar sua assinatura como mostra abaixo.</p>
<div style="font-family: Consolas; font-size: 9pt; color: black; background: #A4F64C; border: 1px outset; padding: 0 0 0 5px;">
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">NTSTATUS</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">ZwQueryInformationProcess(IN HANDLE ProcessHandle,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">                          IN PROCESSINFOCLASS ProcessInformationClass,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">                          OUT PVOID ProcessInformation,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">                          IN ULONG ProcessInformationLength,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">                          OUT PULONG ReturnLength OPTIONAL);</pre>
</div>
<p>Se quiser saber mais sobre APIs nativas não documentadas, <a href="http://www.metasploit.com/users/opcode/syscalls.html">esse link</a> é uma super mão na roda, mas nada como <a href="http://www.amazon.com/gp/product/1578701996/ref=s9_simh_gw_p14_i1?pf_rd_m=ATVPDKIKX0DER&amp;pf_rd_s=center-2&amp;pf_rd_r=0TA5AKHBS2B9MS30G9VR&amp;pf_rd_t=101&amp;pf_rd_p=470938631&amp;pf_rd_i=507846">este livro</a>.</p>
<p>O código abaixo utiliza essa API para obter a imagem de um processo a partir do seu Pid. Reparem que <em>ZwQueryInformationProcess()</em> pede um handle para o processo sobre o qual se quer obter informações. Para se obter esse handle precisaremos primeiro obter a estrutura <strong>EPROCESS</strong> que representa um processo em Kernel-Mode. Faremos isso utilizando a função <a href="http://msdn.microsoft.com/en-us/library/ff551920(VS.85).aspx">PsLookupProcessByProcessId()</a> que nos retornará um ponteiro para essa estrutura.</p>
<div style="font-family: Consolas; font-size: 9pt; color: black; background: #A4F64C; border: 1px outset; padding: 0 0 0 5px;">
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">NTSTATUS PsLookupProcessByProcessId(</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">  __in   HANDLE ProcessId,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">  __out  PEPROCESS *Process</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">);</pre>
</div>
<p>Apesar de opaca, essa estrutura vai nos possibilitar obter o handle para processo representado por ela utilizando agora a função <a href="http://msdn.microsoft.com/en-us/library/ff550985(VS.85).aspx">ObOpenObjectByPointer()</a> do <strong>Object Manager</strong>.</p>
<div style="font-family: Consolas; font-size: 9pt; color: black; background: #A4F64C; border: 1px outset; padding: 0 0 0 5px;">
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">NTSTATUS ObOpenObjectByPointer(</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">  __in      PVOID Object,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">  __in      ULONG HandleAttributes,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">  __in_opt  PACCESS_STATE PassedAccessState,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">  __in      ACCESS_MASK DesiredAccess,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">  __in_opt  POBJECT_TYPE ObjectType,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">  __in      KPROCESSOR_MODE AccessMode,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">  __out     PHANDLE Handle</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">);</pre>
</div>
<p>Acho que tudo vai ficar mais fácil de ser entendido com o fonte abaixo. Afinal, uma linha de código vale mais que mil palavras. A função a seguir obtém a estrutura EPROCESS de um processo, em seguida obtém o handle para ele, com esse handle obtém-se as informações que queremos do processo. Tá, tá, tá&#8230; Segue o fonte, mas não esqueça de ler os comentários.</p>
<div style="font-family: Consolas; font-size: 9pt; color: black; background: #A4F64C; border: 1px outset; padding: 0 0 0 5px;">
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"><span style="color: green;">/****</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"><span style="color: green;">***     GetProcessImageName</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"><span style="color: green;">**</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"><span style="color: green;">**      Retorna um PUNICODE_STRING contendo o caminho</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"><span style="color: green;">**      da imagem utilizada pelo processo cujo Pid foi</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"><span style="color: green;">**      fornecido como parâmetro.</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"><span style="color: green;">*/</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">NTSTATUS</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">GetProcessImageName(HANDLE           hProcessId,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">                    PUNICODE_STRING* ppusImageName)</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">{</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">    NTSTATUS        nts;</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    PUNICODE_STRING pusImageName = NULL;</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">    ULONG           ulSize;</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    HANDLE          hProcess;</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">    PEPROCESS       pEProcess;</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"> </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">    <span style="color: green;">//-f--&gt; Primeiro de tudo, zera a variável de saída.</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    *ppusImageName = NULL;</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"> </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    <span style="color: green;">//-f--&gt; Aqui obtemos a estrutura que representa um processo</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">    <span style="color: green;">//     (EPROCESS) a partir do seu Pid;</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    nts = PsLookupProcessByProcessId(hProcessId,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">                                     &amp;pEProcess);</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    <span style="color: blue;">if</span> (!NT_SUCCESS(nts))</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">        <span style="color: blue;">return</span> nts;</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"> </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">    <span style="color: green;">//-f--&gt; Agora obtemos um handle para este objeto.</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    nts = ObOpenObjectByPointer(pEProcess,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">                                OBJ_KERNEL_HANDLE,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">                                NULL,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">                                <span style="color: purple;">0</span>,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">                                *PsProcessType,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">                                KernelMode,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">                                &amp;hProcess);</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"> </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    <span style="color: green;">//-f--&gt; Independente do handle ter sido ou não obtido,</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">    <span style="color: green;">//      teremos que desfazer a referência que obtivemos</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    <span style="color: green;">//      para o EPROCESS.</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">    ObDereferenceObject(pEProcess);</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    <span style="color: blue;">if</span> (!NT_SUCCESS(nts))</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">        <span style="color: blue;">return</span> nts;</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"> </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">    <span style="color: green;">//-f--&gt; Agora que temos o handle para o processo, podemos</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    <span style="color: green;">//      obter informações a respeito dele, nesse caso,</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">    <span style="color: green;">//      vamos obter o caminho da imagem do processo.</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    nts = ZwQueryInformationProcess(hProcess,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">                                    ProcessImageFileName,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">                                    NULL,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">                                    <span style="color: purple;">0</span>,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">                                    &amp;ulSize);</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"> </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    <span style="color: green;">//-f--&gt; Para obter o tamanho certo, passamos zero na primeira</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">    <span style="color: green;">//      tentativa, isso vai nos retornar um erro e a quantidade</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    <span style="color: green;">//      de bytes necessários para obter essa informação.</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">    <span style="color: blue;">if</span> (nts != STATUS_INFO_LENGTH_MISMATCH)</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">        <span style="color: blue;">return</span> nts;</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"> </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    <span style="color: green;">//-f--&gt; O tamanho retornado inclui o tamanho da estrutura UNICODE_STRING,</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">    <span style="color: green;">//      então tudo é alocado de uma única vez.</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    pusImageName = (PUNICODE_STRING) ExAllocatePoolWithTag(PagedPool,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">                                                           ulSize,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">                                                           TRACER_TAG);</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">    <span style="color: green;">//-f--&gt; Oops! Fecha o Photo Shop e tenta de novo.</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    <span style="color: blue;">if</span> (!pusImageName)</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">        <span style="color: blue;">return</span> STATUS_INSUFFICIENT_RESOURCES;</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"> </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">    <span style="color: green;">//-f--&gt; Agora oferecemos o buffer alocado com o tamanho certo.</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    <span style="color: green;">//      O que pode sair errado? (TUDO!)</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">    nts = ZwQueryInformationProcess(hProcess,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">                                    ProcessImageFileName,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">                                    pusImageName,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">                                    ulSize,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">                                    &amp;ulSize);</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    <span style="color: blue;">if</span> (!NT_SUCCESS(nts))</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">    {</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">        <span style="color: green;">//-f--&gt; Oops! Algo deu errado.</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">        ExFreePoolWithTag(pusImageName,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">                          TRACER_TAG);</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">    }</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    <span style="color: blue;">else</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">    {</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">        <span style="color: green;">//-f--&gt; Tudo bem até aqui. A rotina chamadora fica encarregada</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">        <span style="color: green;">//      de liberar a memória alocado aqui.</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">        *ppusImageName = pusImageName;</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">    }</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"> </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">    <span style="color: blue;">return</span> nts;</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">}</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"> </pre>
</div>
<p>Com essa rotina fica fácil escrever a seguinte função de callback que vai nos mostrar as informações básicas sobre os processos iniciados e terminados.</p>
<div style="font-family: Consolas; font-size: 9pt; color: black; background: #A4F64C; border: 1px outset; padding: 0 0 0 5px;">
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"><span style="color: green;">/****</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"><span style="color: green;">***     OnCreateProcess</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"><span style="color: green;">**</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"><span style="color: green;">**      Função de callback que será registrada caso este</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"><span style="color: green;">**      driver esteja rodando em Windows Vista ou anterior.</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"><span style="color: green;">*/</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">VOID</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">OnCreateProcess(HANDLE  hParentId,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">                HANDLE  hProcessId,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">                BOOLEAN bCreate)</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">{</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">    <span style="color: green;">//-f--&gt; Aqui verificamos se o evento trata de uma criação</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    <span style="color: green;">//      ou término de um processo.</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">    <span style="color: blue;">if</span> (bCreate)</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    {</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">        NTSTATUS        nts;</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">        PUNICODE_STRING pusImageName = NULL;</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"> </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">        <span style="color: green;">//-f--&gt; Obtém o caminho da imagem que foi usada por</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">        <span style="color: green;">//      este processo.</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">        nts = GetProcessImageName(hProcessId,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">                                  &amp;pusImageName);</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"> </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">        <span style="color: blue;">if</span> (NT_SUCCESS(nts))</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">        {</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">            <span style="color: green;">//-f--&gt; Caso o caminho tenha sido obtido com sucesso,</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">            <span style="color: green;">//      registra a notificação de início de processo.</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">            DbgPrint(<span style="color: #a31515;">"[Process Tracer] Action = Starting\n"</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">                     <span style="color: #a31515;">"                 Process Id = 0x%x\n"</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">                     <span style="color: #a31515;">"                 Parent Id = 0x%x\n"</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">                     <span style="color: #a31515;">"                 Image name = %wZ\n\n"</span>,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">                     hProcessId,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">                     hParentId,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">                     pusImageName);</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"> </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">            <span style="color: green;">//-f--&gt; Libera os recursos alocados.</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">            ExFreePool(pusImageName);</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">        }</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    }</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">    <span style="color: blue;">else</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    {</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">        <span style="color: green;">//-f--&gt; Registra o evento de término de processo.</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">        DbgPrint(<span style="color: #a31515;">"[Process Tracer] Action = Finishing\n"</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">                 <span style="color: #a31515;">"                 Process Id = 0x%x\n"</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">                 <span style="color: #a31515;">"                 Parent Id = 0x%x\n\n"</span>,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">                 hProcessId,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">                 hParentId);</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">    }</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">}</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"> </pre>
</div>
<p>Com estas funções trabalhando em um Windows XP, teremos a seguinte saída no depurador.</p>
<div style="font-family: Consolas; font-size: 9pt; color: black; background: #A4F64C; border: 1px outset; padding: 0 0 0 5px;">
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">[Process Tracer] Action = Starting</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">                 Process Id = <span style="color: #ff0000;">0x35c</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">                 Parent Id = <span style="color: #ff0000;">0x694</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">                 Image name = \Device\HarddiskVolume1\WINDOWS\system32\notepad.exe</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"> </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">kd&gt; !process <span style="color: #ff0000;">0x35c</span> 0</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">Searching for Process with Cid == 35c</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">Cid handle table at e1003000 with 380 entries in use</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"> </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">PROCESS 82100020  SessionId: 0  Cid: 035c    Peb: 7ffd7000  ParentCid: 0694</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    DirBase: 08840400  ObjectTable: e10d2400  HandleCount:  41.</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">    Image: <span style="color: #ff0000;">notepad.exe</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"> </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">kd&gt; !process <span style="color: #ff0000;">0x694</span> 0</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">Searching for Process with Cid == 694</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">Cid handle table at e1003000 with 380 entries in use</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"> </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">PROCESS 821cc228  SessionId: 0  Cid: 0694    Peb: 7ffd6000  ParentCid: 0640</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    DirBase: 08840200  ObjectTable: e18df2a0  HandleCount: 365.</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">    Image: <span style="color: #ff0000;">explorer.exe</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"> </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">kd&gt; g</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">[Process Tracer] Action = Finishing</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">                 Process Id = <span style="color: #ff0000;">0x35c</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">                 Parent Id = <span style="color: #ff0000;">0x694</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"> </pre>
</div>
<p>Logo no início eu inicio o processo Notepad a partir do menu <em>&#8220;Executar&#8230;&#8221;</em> como eu comentei logo no início. Depois disso eu utilizo a extensão <strong>!process</strong> do WinDbg para obter informações mínimas sobre os processos envolvidos nesta notificação. Em seguida eu encerro o Notepad dando origem a última mensagem demonstrada acima.</p>
<h3>Uma nova API no Windows Vista SP1</h3>
<p>Tudo bem, isso é muito legal, mas estamos aqui para falar sobre como previnir que um certo processo seja executado. Impedir a execução de processo no Windows Vista virou coisa de criança com a nova rotiva <a href="http://msdn.microsoft.com/en-us/library/ff559953(VS.85).aspx">PsSetCreateProcessNotifyRoutineEx()</a> que tem sua assinatura listada logo abaixo:</p>
<div style="font-family: Courier New; font-size: 9pt; color: black; background: #A4F64C; border: 1px outset; padding: 0 0 0 5px;">
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">NTSTATUS PsSetCreateProcessNotifyRoutineEx(</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">  __in  PCREATE_PROCESS_NOTIFY_ROUTINE_EX NotifyRoutine,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">  __in  BOOLEAN Remove</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">);</pre>
</div>
<p>Essa rotina registra uma função de calback que também notifica seu driver a sobre o início e término dos processos no sistema. O primeiro parâmetro indica a rotina de callback a ser registrada, enquanto que o segundo parâmetro indica se a rotina deve ser registrada ou removida.  Muito semelhante à sua irmã mais velha <em>PsSetCreateProcessNotifyRoutine().</em> A rotina de callback deve ter a seguinte assinatura:</p>
<div style="font-family: Courier New; font-size: 9pt; color: black; background: #A4F64C; border: 1px outset; padding: 0 0 0 5px;">
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">VOID CreateProcessNotifyEx(</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">  __inout   PEPROCESS Process,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">  __in      HANDLE ProcessId,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">  __in_opt  PPS_CREATE_NOTIFY_INFO CreateInfo</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">);</pre>
</div>
<p>Fica fácil perceber que os parâmetros dessa função de callback mudaram bastante. Para saber se o evento se trata da criação ou do término de processo, basta verificar parâmetro <em>CreateInfo</em>. Se esse for não nulo, então se trata de um novo processo sendo executado, caso contrário do seu término. Vamos dar uma olhada nessa estrutura:</p>
<div style="font-family: Courier New; font-size: 9pt; color: black; background: #A4F64C; border: 1px outset; padding: 0 0 0 5px;">
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"><span style="color: blue;">typedef</span> <span style="color: blue;">struct</span> _PS_CREATE_NOTIFY_INFO {</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">  SIZE_T              Size;</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">  <span style="color: blue;">union</span> {</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">    ULONG  Flags;</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    <span style="color: blue;">struct</span> {</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">      ULONG FileOpenNameAvailable  :<span style="color: purple;">1</span>;</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">      ULONG Reserved  :<span style="color: purple;">31</span>;</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">    } ;</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">  } ;</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">  HANDLE              ParentProcessId;</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">  CLIENT_ID           CreatingThreadId;</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">  <span style="color: blue;">struct</span> _FILE_OBJECT *FileObject;</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">  PCUNICODE_STRING    ImageFileName;</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">  PCUNICODE_STRING    CommandLine;</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">  NTSTATUS            CreationStatus;</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">} PS_CREATE_NOTIFY_INFO, *PPS_CREATE_NOTIFY_INFO;</pre>
</div>
<p>Pois é, parace que a vida ficou bem mais fácil para quem quer buscar maiores detalhes sobre os processos envolvidos na notificação. O grande atrativo dessa nova versão é que podemos previnir a criação de um processo apenas modificando o campo <em>CreationStatus</em>. Apenas para exemplificar essa facilidade, eu escrevi a função de callback abaixo. Sempre leia os comentários.</p>
<div style="font-family: Consolas; font-size: 9pt; color: black; background: #A4F64C; border: 1px outset; padding: 0 0 0 5px;">
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"><span style="color: green;">/****</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"><span style="color: green;">***     OnCreateProcessEx</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"><span style="color: green;">**</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"><span style="color: green;">**      Função de callback que será registrada caso este</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"><span style="color: green;">**      driver esteja rodando em Windows Vista SP1 ou superior.</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"><span style="color: green;">*/</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">VOID</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">OnCreateProcessEx(PEPROCESS                 pEProcess,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">                  HANDLE                    hProcessId,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">                  PPS_CREATE_NOTIFY_INFO    pCreateInfo)</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">{</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">    <span style="color: green;">//-f--&gt; Aqui verificamos se o evento trata de uma criação</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    <span style="color: green;">//      ou término de um processo.</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">    <span style="color: blue;">if</span> (pCreateInfo)</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    {</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">        UNICODE_STRING  usBlockingApp;</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"> </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">        <span style="color: green;">//-f--&gt; Como se trata apenas de um exemplo, estou colocando o path</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">        <span style="color: green;">//      do arquivo hard coded aqui, mas lembre-se que referências às</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">        <span style="color: green;">//      imagens de arquivos podem utilizar HarddiskVolume1 ou outras</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">        <span style="color: green;">//      variações que mudam dependendo de muitas coisas.</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">        RtlInitUnicodeString(&amp;usBlockingApp,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">                             L<span style="color: #a31515;">"\\??\\C:\\Windows\\System32\\Notepad.exe"</span>);</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"> </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">        <span style="color: green;">//-f--&gt; Comparando a imagem do processo que acabada de ser criado</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">        <span style="color: green;">//      com o caminho que usei acima.</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">        <span style="color: blue;">if</span> (RtlEqualUnicodeString(&amp;usBlockingApp,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">                                  pCreateInfo-&gt;ImageFileName,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">                                  TRUE))</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">        {</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">            <span style="color: green;">//-f--&gt; Tudo bem, agora é apertar o maluco e chegar apavorando:</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">            <span style="color: green;">//      "Perdeu praybooy!"</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">            DbgPrint(<span style="color: #a31515;">"[Process Tracer] Action = Blocking\n"</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">                     <span style="color: #a31515;">"                 Process Id = 0x%x\n"</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">                     <span style="color: #a31515;">"                 Parent Id = 0x%x\n"</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">                     <span style="color: #a31515;">"                 Image name = %wZ\n\n"</span>,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">                     hProcessId,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">                     pCreateInfo-&gt;ParentProcessId,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">                     pCreateInfo-&gt;ImageFileName);</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"> </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">            <span style="color: green;">//-f--&gt; Muda o status da criação do processo fazendo com que</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">            <span style="color: green;">//      ela não prossiga.</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">            pCreateInfo-&gt;CreationStatus = STATUS_ACCESS_DENIED;</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">        }</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">        <span style="color: blue;">else</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">        {</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">            <span style="color: green;">//-f--&gt; Não é o nosso "homem", deixa o processo inciar normalmente.</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">            DbgPrint(<span style="color: #a31515;">"[Process Tracer] Action = Starting\n"</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">                     <span style="color: #a31515;">"                 Process Id = 0x%x\n"</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">                     <span style="color: #a31515;">"                 Parent Id = 0x%x\n"</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">                     <span style="color: #a31515;">"                 Image name = %wZ\n\n"</span>,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">                     hProcessId,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">                     pCreateInfo-&gt;ParentProcessId,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">                     pCreateInfo-&gt;ImageFileName);</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">        }</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">    }</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    <span style="color: blue;">else</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">    {</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">        <span style="color: green;">//-f--&gt; Aqui apenas registramos a notificação do término de</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">        <span style="color: green;">//      um processo.</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">        DbgPrint(<span style="color: #a31515;">"[Process Tracer] Action = Finishing\n"</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">                 <span style="color: #a31515;">"                 Process Id = 0x%x\n\n"</span>,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">                 hProcessId);</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">    }</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">}</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"> </pre>
</div>
<p>Repare que o caminho para o arquivo que estou impedindo sua criação está <em>hard-coded</em> no fonte de exemplo. Esse caminho pode ter sua sintaxe diferente para o mesmo arquivo dependendo de como o processo é criado ou em qual versão do Windows estamos rodando. Por essa razão, caso queria rodar esse teste na sua casa, verifique se a sintaxe está como utilizei aqui, caso contrário acerte e recompile o exemplo.</p>
<h3>Um driver, duas opções</h3>
<p>Esta nova API está disponível apenas para Windows Vista SP1 e posteriores, mas é provável que você queria ter um driver que seja capaz de ainda rodar em versões anteriores do Windows mesmo que o sistema não tenha suporte a essa rotina. Como você já deve saber, simplesmente chamar a rotina <em>PsSetCreateProcessNotifyRoutineEx()</em> no seu driver vai criar uma dependência estática e seu driver não será capaz de ser carregado em versões mais antigas do Windows.</p>
<p style="text-align: center;"><img class="aligncenter" src="http://www.driverentry.com.br/images/PrTracerFail.png" alt="" width="413" height="464" /></p>
<p style="text-align: left;">Para previnir essa dependência estática tendo um único binário que possa ser carregado tanto em versões mais antigas como nas mais novas, utilizando a versão mais nova dessa rotina, usaremos a função <a href="http://msdn.microsoft.com/en-us/library/ff554563(VS.85).aspx">MmGetSystemRoutineAddress()</a>, que é a irmã Kernel-Mode da bem conhecida <a href="http://msdn.microsoft.com/en-us/library/ms683212(VS.85).aspx">GetProcAddress()</a> em User-Mode. O driver de exemplo disponível para download no final deste post possui essas caracteristicas justamente para demonstrar como isso pode der feito. Obviamente que rodando o driver em Windows XP não teremos o suporte do sistema operacional para interromper um processo, e teremos que recorrer a técnicas alternativas para obter o mesmo resultado.</p>
<p style="text-align: left;">A função <em>DriverEntry</em> para este driver fica da seguinte maneira:</p>
<div style="font-family: Consolas; font-size: 9pt; color: black; background: #A4F64C; border: 1px outset; padding: 0 0 0 5px;">
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"><span style="color: green;">/****</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"><span style="color: green;">***     DriverEntry</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"><span style="color: green;">**</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"><span style="color: green;">**      Ponto de entrada do driver. Se ainda estiver pensando</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"><span style="color: green;">**      é fácil, não se preocupe, você acabará mudando de opinião.</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"><span style="color: green;">*/</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">NTSTATUS</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">DriverEntry(PDRIVER_OBJECT     pDriverObj,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">            PUNICODE_STRING    pusRegistryPath)</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">{</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    UNICODE_STRING  usSystemRoutine;</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">    NTSTATUS        nts;</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"> </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">    <span style="color: green;">//-f--&gt; Registra nossa função de finalização para que</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    <span style="color: green;">//      nosso driver possa ser descarregado.</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">    pDriverObj-&gt;DriverUnload = OnDriverUnload;</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"> </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">    <span style="color: green;">//-f--&gt; Inicia o nome da rotina que tentaremos buscar dinamicamente.</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    RtlInitUnicodeString(&amp;usSystemRoutine,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">                         L<span style="color: #a31515;">"PsSetCreateProcessNotifyRoutineEx"</span>);</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"> </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">    <span style="color: green;">//-f--&gt; Aqui verificamos de o sistema já tem suporte a PsSetCreateProcessNotifyRoutineEx</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    <span style="color: green;">//      Exatamente como a tia ensinou GetProcessAddress() lá no prézinho.</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">    *(PVOID*)&amp;pfPsSetCreateProcessNotifyRoutineEx = MmGetSystemRoutineAddress(&amp;usSystemRoutine);</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"> </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">    <span style="color: blue;">if</span> (pfPsSetCreateProcessNotifyRoutineEx)</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    {</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">        <span style="color: green;">//-f--&gt; Se o estivermos em Windows Vista SP1 ou superior, teremos o endereço</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">        <span style="color: green;">//      desta rotina, e portanto, vamos nos registrar com ela.</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">        nts = pfPsSetCreateProcessNotifyRoutineEx(OnCreateProcessEx,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">                                                  FALSE);</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">    }</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    <span style="color: blue;">else</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">    {</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">        <span style="color: green;">//-f--&gt; Puuts! Estamos rodando em algum 386. Vamos nos registrar com</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">        <span style="color: green;">//      essa rotina da década de 90.</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">        nts = PsSetCreateProcessNotifyRoutine(OnCreateProcess,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">                                              FALSE);</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    }</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"> </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    ASSERT(NT_SUCCESS(nts));</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">    <span style="color: blue;">return</span> nts;</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">}</pre>
</div>
<h3>Testando a PsSetCreateProcessNotifyRoutineEx()</h3>
<p>Até aqui você deve estar dando pulos de alegria imaginando que aquele seu driver de dominar o mundo finalmente vai funcionar com grande facilidade utilzando essa nova API, mas o caso é que essa rotina não é para qualquer um. Isso porque apenas driver digitalmente assinados podem chamar essa rotina nova sem receber o retorno STATUS_ACCESS_DENIED.</p>
<blockquote><p>Mas Fernando, como vou poder testar o seu driver de exemplo? Não tenho certificado nem nada!</p>
</blockquote>
<p>Esta rotina inicialmente verifica de o módulo onde seu driver está definido tem o bit de verificação de integridade setado. Para setar esse bit só de brincadeirinha, adicione a opção /INTEGRITYCHECK nas opções do linker do seu projeto. O arquivo sources do projeto de exemplo está da seguinte forma:</p>
<div style="font-family: Consolas; font-size: 9pt; color: black; background: #A4F64C; border: 1px outset; padding: 0 0 0 5px;">
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">TARGETNAME=ProcessTracer</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">TARGETTYPE=DRIVER</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"> </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">SOURCES=ProcessTracer.cpp</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"> </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">LINKER_FLAGS=/INTEGRITYCHECK</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"> </pre>
</div>
<p>Isso fará com que o sistema verifique a assinatura do seu driver, mas como seu driver não está assinado, você ainda receberá o mesmo erro. Para finalmente ver isso funcionar sem ter mesmo um certificado, você terá que desabilitar e verificacão de integridade de código para drivers no Windows Vista.</p>
<p>Tudo bem, sem pânico. Inicie o Windows Vista e pressione F8 logo que o Boot iniciar, em seguida selecione a opção abaixo no menú que aparecerá como mostra abaixo:</p>
<p style="text-align: center;"><img class="aligncenter" src="http://www.driverentry.com.br/images/DesabilitaAssinaturaDriver.png" alt="" width="640" height="480" /></p>
<p>Com estas duas modificações é possível testar o driver de exemplo e ter uma saída no depurador como a ilustrada abaixo:</p>
<div style="font-family: Consolas; font-size: 9pt; color: black; background: #A4F64C; border: 1px outset; padding: 0 0 0 5px;">
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">[Process Tracer] Action = <span style="color: #ff0000;">Blocking</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">                 Process Id = 0x3a4</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">                 Parent Id = 0xd98</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">                 Image name = \??\C:\Windows\system32\notepad.exe</pre>
</div>
<p>Neste caso, mais uma vez, tentei iniciar o Notepad pelo menú <em>&#8220;Exec</em><em>utar&#8230;&#8221;,</em> mas desta vez a saída que obtive foi a exibida abaixo:</p>
<p style="text-align: center;"><img class="aligncenter" src="http://www.driverentry.com.br/images/PrTracerDenied.png" alt="" width="581" height="147" /></p>
<p>Ufa! Mais um post gigante para a coleção. Espero ter ajudado e até mais!</p>
<p class="download"><a href="http://www.driverentry.com.br/samples/ProcessTracer.zip">ProcessTracer.zip</a></p>
]]></content:encoded>
			<wfw:commentRss>http://driverentry.com.br/blog/?feed=rss2&amp;p=683</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Último post pelo Blogger</title>
		<link>http://driverentry.com.br/blog/?p=629</link>
		<comments>http://driverentry.com.br/blog/?p=629#comments</comments>
		<pubDate>Wed, 28 Apr 2010 23:47:01 +0000</pubDate>
		<dc:creator>Fernando Roberto</dc:creator>
				<category><![CDATA[Off Topic]]></category>

		<guid isPermaLink="false">http://driverentry.com.br/blog/?p=629</guid>
		<description><![CDATA[Olá cambada! Puts, eu já estava com saudade de postar alguma coisa. Pena este ser mais um daqueles chatos posts Off-Topic. O que posso fazer? É o que temos para o momento. Hoje pela manhã recebi um mais um e-mail de aviso do Blogger dizendo que o suporte à publicação via FTP estão com os [...]]]></description>
			<content:encoded><![CDATA[<p><img style="float: right; margin: 0px 10px;" src="http://www.driverentry.com.br/images/BloggerToWP.png" border="0" alt="" /></p>
<p>Olá cambada! Puts, eu já estava com saudade de postar alguma coisa. Pena este ser mais um daqueles chatos posts Off-Topic. O que posso fazer? É o que temos para o momento.</p>
<p>Hoje pela manhã recebi um mais um e-mail de aviso do <a href="http://www.blogger.com">Blogger</a> dizendo que o suporte à publicação via FTP estão com os dias contatos. Como este recurso é utilizado por menos de 5% dos seus usuários, resolveram dar fim à ele. Mas essa não foi a principal razão pela qual eu decidi deixar de postar pelo Blogger para usar o <a href="http://www.wordpress.org">WordPress</a>. Eu já vinha ensaiando essa transição há pelo menos dois anos. A faculdade e outras desculpinhas esfarrapadas não me deixavam pôr essa idéia em prática. Alguns leitores já vinham reclamando da falta de um índice geral e da separação dos posts em categorias, coisas que o WordPress faz com uma mão nas costas.</p>
<p>Como um web designer, eu sou um excelente desenvolvedor de drivers, e eu já tinha ouvido falar que o WordPress usava PHP e MySQL, assuntos os quais eu não tenho a menor intimidade. Inicialmente contei com a ajuda do meu irmão que já possuia um <a href="http://www.kabloc.com.br">blog</a> pelo WordPress, mas assim como eu, ele também tinha faculdade e outras prioridades. Por um tempo eu contratei os serviços de um web designer que colocava em prática as minhas ídéias com relação ao novo layout, mas por fim ele se envolveu com algo maior e fiquei na mão novamente.</p>
<p>A idéia de migrar o blog persistia, mas a preguiça, a falta de tempo e de domínio de HTML e CSS me fizeram ir empurrando esse problema com a barriga. Cheguei até a ler o guia o oficial da famosa série <span style="font-style: italic;">&#8220;Preciso aprender isso de qualquer jeito&#8221;</span>, o livro <a href="http://www.amazon.com/WordPress-Dummies-Computer-Tech/dp/0470149469">&#8220;WordPress for Dummies&#8221;</a>. Pra quem está acostumado a ler livros de assuntos um tanto mais cabeludos, as mais de 380 páginas do livro foram como um passeio no parque. O mais surpreendente pra mim foi descobrir que o WordPress é uma ferramenta que não requer prática nem tampouco habilidade, e isso incluia as habilidades de PHP e MySQL que eu não tenho. Uma ferramenta poderosa, flexível e simples. A parte desagradável dessa história é que tudo que o livro falou sobre HTML e CSS é que ele não falava a respeito.</p>
<p><a href="http://www.amazon.com/WordPress-Dummies-Computer-Tech/dp/0470149469"><img style="float: right; margin: 0px 10px;" src="http://www.driverentry.com.br/images/wordpress-for-dummies.gif" border="0" alt="" /></a></p>
<p>Até aqui excelente. Os 68 posts poderiam ser migrados mas o layout ainda foi o meu carma. Outras tentativas de encontrar alguém disposto a fazer o design pra mim me mostrou que estou no emprego errado. Esse negócio de desenvolver drivers não está com nada. Pra ganhar dinheiro mesmo o negócio é fazer Web Design.</p>
<p>Há uns três meses, quando recebi o primeiro aviso do Blogger sobre o fim do suporte ao FTP foi o momento <span style="font-style: italic;">&#8220;Agora ou nunca&#8221;</span>. Minha faculdade não me servia mais de desculpa e aos poucos fui colocando a mão na massa. Depois de muito trabalho manual de migrar cada post e cada comentário, veio o layout. Graças ao site <a href="http://www.w3schools.com/">W3Schools</a>, às aulas particulares de Photohop do meu irmão e à ajuda de alguns amigos, essa semana consegui publicar o novo blog. Ainda faltam muitas coisas. A página <span style="font-style: italic;">&#8220;About Me&#8221;</span> ainda não tem nada <span style="font-style: italic;">about me</span>. A página de treinamentos, que vai falar sobre os cursos que ofereço ainda fala exatamente isso: <span style="font-style: italic;">&#8220;Essa página vai falar sobre os cursos que ofereço&#8221;</span>. Ainda estou instalando alguns plug-ins que vão ajudar em uma coisa aqui e outra ali. Mas o fato é que há dois dias do prazo final do suporte ao FTP, o novo blog já está no ar.</p>
<p>Esse post foi o último a ser contruído no Blogger com o objetivo principal de avisar àqueles que seguem o RSS original de que o endereço agora mudou. O novo RSS será provido em um novo endereço.</p>
<p>Eu não poderia terminar esse post sem agraceder às pessoas que tiveram a paciência de me aturar com testes e dúvidas sobre HTML, CSS e sei-lá mais o que. Um muito obrigado aos meus amigos <a href="http://www.caloni.com.br">Lesma</a>, <a href="http://twitter.com/thiago_morais">Thiago Oliveira</a>, <a href="http://twitter.com/tgbrito">Thiago Brito</a>, meu irmão <a href="http://www.kabloc.com.br">Kabloc</a>, <a href="http://william.net.br/yap/">Willam</a>, <a href="http://www.oblita.com/">Francisco</a>, à minha esposa Magda que migrou todos os comentários e a todos os outros que não me lembro agora (eu perturbei muita gente).</p>
<p>Se você não conhecia o blog antigo, <a href="http://www.driverentry.com.br/blogger">aqui</a> estão as páginas do velho aposentado.<br />
 Valeu!</p>
]]></content:encoded>
			<wfw:commentRss>http://driverentry.com.br/blog/?feed=rss2&amp;p=629</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>Sexto Encontro de Programadores C/C++</title>
		<link>http://driverentry.com.br/blog/?p=206</link>
		<comments>http://driverentry.com.br/blog/?p=206#comments</comments>
		<pubDate>Fri, 26 Feb 2010 21:42:30 +0000</pubDate>
		<dc:creator>Fernando Roberto</dc:creator>
				<category><![CDATA[Off Topic]]></category>

		<guid isPermaLink="false">http://driverentry.com.br/wp/?p=206</guid>
		<description><![CDATA[Começo de ano é sempre a mesma correria. Depois que a gente começa a se acostumar com a idéia de que o feriadão de Natal e Ano Novo acabaram, logo vem o carnaval e desanda tudo. Aproveitei este início de ano para tirar merecidas férias, já que finalmente meu curso de Engenharia da Computação terminou. [...]]]></description>
			<content:encoded><![CDATA[<p><img style="float: right; margin: 0px 10px;" src="http://www.driverentry.com.br/images/logo_com_c++_160x115.jpg" border="0" alt="" /></p>
<p>Começo de ano é sempre a mesma correria. Depois que a gente começa a se acostumar com a idéia de que o feriadão de Natal e Ano Novo acabaram, logo vem o carnaval e desanda tudo. Aproveitei este início de ano para tirar merecidas férias, já que finalmente meu curso de Engenharia da Computação terminou. Como um belo <span style="font-style: italic;">start</span> para minha reintegração à sociedade, nada melhor que uma viajem ao nordeste brasileiro. Semanas antes desta viajem fiquei sabendo do novo encontro da comunidade de programadores C/C++. Por causa da viagem eu perderia o evento.</p>
<p>Um mês se passou e semana passada vi que o evento foi adiado para o próximo dia <span style="font-weight: bold;">seis de março</span>. Muito boa notícia já que além de poder participar do evento também vou falar um pouquinho. <a href="http://www.driverentry.com.br/blog/2008/03/driverentrycombr-d-as-caras.html">Já participei de outro encontro</a> de programadores e fiquei muito feliz de poder falar para tantas pessoas sobre esse assunto tão misterioso para muitos, que é o desenvolvimento de drivers para Windows.</p>
<p>Sob meu ponto de vista os resultados foram muito bons. A palestra deu uma introdução ao assunto de desenvolvimento de drivers e obviamente os 60 minutos de palestra não foram suficientes para explicar o assunto com detalhes, mas foi interessante mostrar a ponta do <span style="font-style: italic;">iceberg</span> e poder responder a algumas perguntas dos presentes. Eu escrevi um <a href="http://www.driverentry.com.br/blog/2008/06/tirando-o-atraso-p.html">post</a> que comenta sobre o encontro, mas recomendo o <a href="http://www.caloni.com.br/blog/archives/epa-ccpp-4-nossa-comunidade-ganhando-forma">post do meu amigo Lesma</a> que ficou muito bom.</p>
<h3>Lidando com Memória Virtual em Drivers</h3>
<p>Bem, neste novo encontro não vou dar novamente uma introdução ao assunto, mas vou comentar sobre algumas carasterísticas e curiosidades sobre Memória Virtual no desenvolvimento de drivers. Entenda que não vou fazer um resumo do capítulo 9 do Windows Internals, &#8220;Memory Management&#8221; que fala sobre Page Table Entries e Working Sets, mas sim demonstrar que, diferentes de uma aplicação User-Mode, drivers precisam estar cientes dos conceitos fundamentais de memória virtual e paginação, controlando paginação de objetos e atendendo à requisítos de paginação de memória e espaço de endereçamento.</p>
<p>Os tópicos a serem discutidos na palestra serão os seguintes:</p>
<ul>
<li>Overview de Memória Virtual e Paginação.</li>
<li>Operações de I/O e manipulação de Buffers.</li>
<li>Prioridade de thread e acesso à memória.</li>
<li>Pools de alocação, Tags e Quotas.</li>
<li>Evitando Fragmentação.</li>
<li>Drivers no caminho da paginação.</li>
<li>Controlando paginação de funções.</li>
<li>Obtendo endereços reais de memória.</li>
<li>Dispositivos de acesso direto à memória (DMA).</li>
<li>Recursos do Driver Verifier.</li>
<li>Hands on: Operações de memórias por drivers no WinDbg.</li>
<li>Dúvidas.</li>
</ul>
<p>Esta é a <a href="http://ccppbrasil.org/wiki/Grupo:Encontro_VI">página oficial</a> do evento e as <a href="http://www.temporealeventos.com.br/inscricoes/inscricoes.php?area=95&amp;form=367">inscrições</a> estão abertas. Até lá!</p>
<p class="download"><a href="http://www.driverentry.com.br/downloads/Palestra-060310.zip">Download dos slides</a></p>
]]></content:encoded>
			<wfw:commentRss>http://driverentry.com.br/blog/?feed=rss2&amp;p=206</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Escrevendo Filtros</title>
		<link>http://driverentry.com.br/blog/?p=212</link>
		<comments>http://driverentry.com.br/blog/?p=212#comments</comments>
		<pubDate>Wed, 20 Jan 2010 21:48:34 +0000</pubDate>
		<dc:creator>Fernando Roberto</dc:creator>
				<category><![CDATA[Kernel Development]]></category>

		<guid isPermaLink="false">http://driverentry.com.br/wp/?p=212</guid>
		<description><![CDATA[Vamos brincar de algo mais interessante agora. Obviamente ainda vamos dar passos pequenos para não nos perder com tantos detalhes. Hoje falarei sobre filtros de drivers. O IoManager do Windows nos permite adicionar funcionalidade a determinados drivers sem que tenhamos que substituí-lo. Um exemplo clássico seria um driver de criptografia de arquivos. Você não precisa [...]]]></description>
			<content:encoded><![CDATA[<p>Vamos brincar de algo mais interessante agora. Obviamente ainda vamos dar passos pequenos para não nos perder com tantos detalhes. Hoje falarei sobre filtros de drivers. O <span style="font-style: italic;">IoManager</span> do Windows nos permite adicionar funcionalidade a determinados drivers sem que tenhamos que substituí-lo. Um exemplo clássico seria um driver de criptografia de arquivos. Você não precisa escrever um novo driver de <span style="font-style: italic;">file system</span> para que se tenha tal funcionalidade. Você pode simplesmente escrever um filtro que ficaria entre o driver de <span style="font-style: italic;">file system</span> e o restante do sistema.</p>
<p>Na figura abaixo podemos observar o fluxo de <a href="http://www.driverentry.com.br/blog/2007/02/legal-mas-o-que-uma-irp.html">IRPs</a> que vão do <span style="font-style: italic;">IoManager</span> para um certo driver, um filtro é instalado sobre o driver existente e passa a receber as IRPs no lugar do driver original. Com isso o filtro tem a oportunidade de alterar os parâmetros das IRPs recebidas, ou logar a atividade do driver original, ou duplicar solicitações do sistema para esse driver, ou mesmo negar serviço do driver original.</p>
<div style="text-align: center;"><img src="http://www.driverentry.com.br/images/NewFilterDev.png" alt="" /></div>
<p>Numa operação de escrita, um filtro poderia criptografar os dados antes de enviá-los ao driver original, e de maneira similar, numa operação de leitura o filtro poderia decriptografar dados antes de entregá-los ao sistema.</p>
<p>Ainda não vai ser desta vez que construiremos um filtro de criptografia de <span style="font-style: italic;">file system</span>. Filtros de criptografia de arquivos em tempo real estão entre os drivers mais complexos a serem escritos. Vamos escolher um driver mais simples, pra não dizer um bem besta, para aplicar os conceitos básicos demonstrados aqui.</p>
<p>Por falar em driver besta, vamos utilizar o driver <a href="http://www.driverentry.com.br/blog/2009/07/strings-no-kernel.html">deste post</a> que já foi visto aqui. Este driver simplesmente armazena uma lista de strings enviadas por uma aplicação em operações de escrita. Tais strings são retornadas à aplicação em operações de leituras.</p>
<h3>Escrevendo a DriverEntry</h3>
<p>Como vimos neste <a href="http://www.driverentry.com.br/blog/2007/06/nos-queremos-exemplos.html">outro post</a>, uma das das coisas que a função <span style="font-style: italic;">DriverEntry()</span> faz num driver comum é setar as <span style="font-style: italic;">Dispatch Routines</span> que o driver vai atender para certo dispositivo. Para isso deve-se preencher o array de <span style="font-style: italic;">Major Functions</span> que fica na estrutura <a href="http://msdn.microsoft.com/en-us/library/dd852039.aspx">DRIVER_OBJECT</a>.</p>
<div style="font-family: Courier New; font-size: 9pt; color: black; background: #A4F64C; border: 1px outset; padding: 0 0 0 5px;">
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    <span style="color: green;">//-f--> Seta as dispatch routines do driver.</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">    pDriverObj->MajorFunction[IRP_MJ_CREATE] = OnCreate;</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    pDriverObj->MajorFunction[IRP_MJ_CLEANUP] = OnCleanup;</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">    pDriverObj->MajorFunction[IRP_MJ_CLOSE] = OnClose;</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    pDriverObj->MajorFunction[IRP_MJ_READ] = OnRead;</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">    pDriverObj->MajorFunction[IRP_MJ_WRITE] = OnWrite;</pre>
</div>
<p>No caso do nosso filtro de exemplo, queremos apenas monitorar a atividade do driver ao qual estamos atachados, dessa forma teremos sempre que encaminhar quaisquer IRPs recebidas ao driver de baixo. Uma forma simples e comum de fazer isso é setar todas dispath routines para uma única função. Essa função se encarrega de simplesmente logar a solicitação recebida e passá-la a diante.</p>
<p>Se dermos uma olhada na definicão de IRP_MJ_CREATE e seus amigos, veremos o seguinte trecho do arquivo wdm.h.</p>
<div style="font-family: Courier New; font-size: 9pt; color: black; background: #A4F64C; border: 1px outset; padding: 0 0 0 5px;">
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"><span style="color: green;">//</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"><span style="color: green;">// Define the major function codes for IRPs.</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"><span style="color: green;">//</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"> </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"> </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"><span style="color: blue;">#define</span> IRP_MJ_CREATE                   <span style="color: purple;">0x00</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"><span style="color: blue;">#define</span> IRP_MJ_CREATE_NAMED_PIPE        <span style="color: purple;">0x01</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"><span style="color: blue;">#define</span> IRP_MJ_CLOSE                    <span style="color: purple;">0x02</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"><span style="color: blue;">#define</span> IRP_MJ_READ                     <span style="color: purple;">0x03</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"><span style="color: blue;">#define</span> IRP_MJ_WRITE                    <span style="color: purple;">0x04</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"><span style="color: blue;">#define</span> IRP_MJ_QUERY_INFORMATION        <span style="color: purple;">0x05</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"><span style="color: blue;">#define</span> IRP_MJ_SET_INFORMATION          <span style="color: purple;">0x06</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"><span style="color: blue;">#define</span> IRP_MJ_QUERY_EA                 <span style="color: purple;">0x07</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"><span style="color: blue;">#define</span> IRP_MJ_SET_EA                   <span style="color: purple;">0x08</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"><span style="color: blue;">#define</span> IRP_MJ_FLUSH_BUFFERS            <span style="color: purple;">0x09</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"><span style="color: blue;">#define</span> IRP_MJ_QUERY_VOLUME_INFORMATION <span style="color: purple;">0x0a</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"><span style="color: blue;">#define</span> IRP_MJ_SET_VOLUME_INFORMATION   <span style="color: purple;">0x0b</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"><span style="color: blue;">#define</span> IRP_MJ_DIRECTORY_CONTROL        <span style="color: purple;">0x0c</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"><span style="color: blue;">#define</span> IRP_MJ_FILE_SYSTEM_CONTROL      <span style="color: purple;">0x0d</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"><span style="color: blue;">#define</span> IRP_MJ_DEVICE_CONTROL           <span style="color: purple;">0x0e</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"><span style="color: blue;">#define</span> IRP_MJ_INTERNAL_DEVICE_CONTROL  <span style="color: purple;">0x0f</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"><span style="color: blue;">#define</span> IRP_MJ_SHUTDOWN                 <span style="color: purple;">0x10</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"><span style="color: blue;">#define</span> IRP_MJ_LOCK_CONTROL             <span style="color: purple;">0x11</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"><span style="color: blue;">#define</span> IRP_MJ_CLEANUP                  <span style="color: purple;">0x12</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"><span style="color: blue;">#define</span> IRP_MJ_CREATE_MAILSLOT          <span style="color: purple;">0x13</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"><span style="color: blue;">#define</span> IRP_MJ_QUERY_SECURITY           <span style="color: purple;">0x14</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"><span style="color: blue;">#define</span> IRP_MJ_SET_SECURITY             <span style="color: purple;">0x15</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"><span style="color: blue;">#define</span> IRP_MJ_POWER                    <span style="color: purple;">0x16</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"><span style="color: blue;">#define</span> IRP_MJ_SYSTEM_CONTROL           <span style="color: purple;">0x17</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"><span style="color: blue;">#define</span> IRP_MJ_DEVICE_CHANGE            <span style="color: purple;">0x18</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"><span style="color: blue;">#define</span> IRP_MJ_QUERY_QUOTA              <span style="color: purple;">0x19</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"><span style="color: blue;">#define</span> IRP_MJ_SET_QUOTA                <span style="color: purple;">0x1a</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"><span style="color: blue;">#define</span> IRP_MJ_PNP                      <span style="color: purple;">0x1b</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"><span style="color: blue;">#define</span> IRP_MJ_PNP_POWER                IRP_MJ_PNP      <span style="color: green;">// Obsolete....</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"><span style="color: blue;">#define</span> IRP_MJ_MAXIMUM_FUNCTION         <span style="color: purple;">0x1b</span></pre>
</div>
<p>Note que existe uma definição especial, a <span style="font-weight: bold;">IRP_MJ_MAXIMUM_FUNCTION</span>, que indica o índice máximo da tabela de <span style="font-style: italic;">dispatch rotines</span>. Utilizaremos um loop simples para fazer com que todas rotinas em nossa tabela aponte para uma única rotina que daremos o nome de <span style="font-style: italic;">OnForwardDispatch</span>.</p>
<div style="font-family: Courier New; font-size: 9pt; color: black; background: #A4F64C; border: 1px outset; padding: 0 0 0 5px;">
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    <span style="color: green;">//-f--> Seta todas as dispatch routines do driver para</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">    <span style="color: green;">//      uma que encaminhe a IRP para o driver original.</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    <span style="color: blue;">for</span> (i = <span style="color: purple;">0</span>; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">        pDriverObj->MajorFunction[i] = OnForwardDispatch;</pre>
</div>
<p>Veremos a implementação dessa rotina mais tarde. O próximo passo que daremos aqui é localizar o device ao qual vamos nos atachar. Para fazer isso, usaremos a rotina <a href="http://msdn.microsoft.com/en-us/library/ms801459.aspx">IoGetDeviceObjectPointer()</a>. Ela basicamente recebe o nome do device e nos retorna uma referência para ele.</p>
<div style="font-family: Courier New; font-size: 9pt; color: black; background: #A4F64C; border: 1px outset; padding: 0 0 0 5px;">
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">NTSTATUS </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">  IoGetDeviceObjectPointer(</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    IN PUNICODE_STRING  ObjectName,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">    IN ACCESS_MASK  DesiredAccess,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    OUT PFILE_OBJECT  *FileObject,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">    OUT PDEVICE_OBJECT  *DeviceObject</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    );</pre>
</div>
<p>Observe que são dois os parâmetros de saída dessa rotina. Além do ponteiro para o <span style="font-style: italic;">device object</span> ainda recebemos um ponteiro para um <span style="font-style: italic;">file object</span>. Já ví algumas pessoas fazerem confusão com estes dois parâmetros, então vou dar alguma ênfase nisso.</p>
<p>O ponteiro para o <span style="font-style: italic;">file object</span> representa uma conexão criada entre seu driver e o device que você abriu. Como vimos <a href="http://www.driverentry.com.br/blog/2007/08/usando-fileobject-e-fscontext.html">neste post</a>, um <span style="font-style: italic;">file object</span> é criado para respresentar conexões entre aplicações user mode e seu driver. Aplicações usam esse <span style="font-style: italic;">file object</span> através do <span style="font-style: italic;">handle</span> obtido na chamada à rotina <a href="http://msdn.microsoft.com/en-us/library/aa363858(VS.85).aspx">CreateFile()</a>. Aqui temos algo similar, mas apenas o Kernel foi envolvido. Isso significa que se você quizesse, você poderia lançar IRPs para o device solicitando operações como uma aplicação faria, mas não veremos isso hoje, ainda temos um filtro para terminar.</p>
<p>A grande confusão referente a estes dois parâmetros é com relação às referências entre os objetos. <a href="http://msdn.microsoft.com/en-us/library/ms801459.aspx">Na documentação</a> vemos que o chamador desta rotina deverá liberar a referência que ganhou quando o device não for mais utilizado. Fazemos isso simplesmente usando a rotina <a href="http://msdn.microsoft.com/en-us/library/ms802945.aspx">ObDereferenceObject()</a>.</p>
<div style="font-family: Courier New; font-size: 9pt; color: black; background: #A4F64C; border: 1px outset; padding: 0 0 0 5px;">
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">VOID </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">  ObDereferenceObject(</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    IN PVOID  Object</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">    );</pre>
</div>
<blockquote><p><span style="font-weight: bold; font-style: italic;">"Já sei! Como estamos obtendo uma referência para um device object, então devo passar o ponteiro do device object. Certo?"</span></p>
</blockquote>
<p>Er... Na verdade não. O <span style="font-style: italic;">file object</span> é uma referência indireta ao <span style="font-style: italic;">device object</span>. Conforme a figura abaixo, se imaginarmos que os contadores de referência apenas dizem respeito às nossas referências, quando chamarmos <span style="font-style: italic;">ObDereferenceObject()</span> para o <span style="font-style: italic;">file object</span>, seu contador de referência cairia para zero e uma nova chamada para <span style="font-style: italic;">ObDeferenceObject()</span> seria feita indiretamente para o <span style="font-style: italic;">device object</span>, fazendo com que seu contador de referência também caisse para zero destruindo o objeto.</p>
<div style="text-align: center;"><img src="http://www.driverentry.com.br/images/DeviceReferences.png" alt="" /></div>
<p>Depois de obter o ponteiro para o device destino, teremos que criar nosso próprio device, o qual receberá as IRPs no lugar do device original. Para isso ainda usaremos a rotina <a href="http://msdn.microsoft.com/en-us/library/aa490468.aspx">IoCreateDevice()</a> como faziamos com drivers, mas com algumas diferenças.</p>
<p>A primeira diferença é que seu device normalmente não tem nome. É possível criar filtros com nomes, mas isso pode gerar uma falha de segurança. Isso acontece pois quando um nome é consultado no <span style="font-style: italic;">Object Manager</span>, suas regras de segurança são avaliadas. Quando criamos um filtro com nome, criamos a possibilidade de o mesmo objeto ser obtido por um nome diferente e que pode ter regras menos restritivas de segurança. Mas esse é outro assunto.</p>
<p>Quando criamos um device, precisamos informar o tamanho do <span style="font-style: italic;">device extension</span>.</p>
<blockquote><p><span style="font-weight: bold; font-style: italic;">"O que vem a ser um device extension?"</span></p>
</blockquote>
<p><span style="font-style: italic;">Device extension</span> é simplesmente um espaço de memória que está associada ao <span style="font-style: italic;">device object</span>. Tal espaço normalmente mantém informações que dizem respeito ao device. O endereço do device ao qual estamos atachados normalmente fica no <span style="font-style: italic;">device extension</span>. Desta forma, podemos definir que nosso <span style="font-style: italic;">device extension</span> deve conter a seguinte estrutura.</p>
<div style="font-family: Courier New; font-size: 9pt; color: black; background: #A4F64C; border: 1px outset; padding: 0 0 0 5px;">
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"><span style="color: green;">//-f--> Nosso device externsion conterá apenas o endereço</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"><span style="color: green;">//      do device ao qual estamos atachados.</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"><span style="color: blue;">typedef</span> <span style="color: blue;">struct</span> _DEVICE_EXTENSION</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">{</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    PDEVICE_OBJECT  pNextDeviceObj;</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"> </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">} DEVICE_EXTENSION, *PDEVICE_EXTENSION;</pre>
</div>
<p>Depois de criar nosso <span style="font-style: italic;">device object</span>, configuramos o método de I/O copiando os bits <span style="font-weight: bold;">DO_BUFFERED_IO</span> e <span style="font-weight: bold;">DO_DIRECT_IO</span>. Se você não se lembra destes bits, dê uma olhada <a href="http://www.driverentry.com.br/blog/2008/10/buffered-direct-ou-neither.html">neste post</a>. O filtro deve propagar a escolha do driver original e o driver tem o compromisso de não mudar método durante seu tempo de vida.</p>
<p>Agora estamos prontos para nos atachar ao device escolhido, e faremos isso utilizando a rotina <a href="http://msdn.microsoft.com/en-us/library/ms795450.aspx">IoAttachDeviceToDeviceStackSafe()</a> para fazer nosso device entrar na pilha de dispositivos.</p>
<div style="font-family: Courier New; font-size: 9pt; color: black; background: #A4F64C; border: 1px outset; padding: 0 0 0 5px;">
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">NTSTATUS</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">  IoAttachDeviceToDeviceStackSafe(</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    IN PDEVICE_OBJECT  SourceDevice,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">    IN PDEVICE_OBJECT  TargetDevice,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    IN OUT PDEVICE_OBJECT  *AttachedToDeviceObject </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">    );</pre>
</div>
<p>Com esta chamada obteremos o ponteiro do device ao qual estaremos atachados, esse device será o próximo device que receberá a IRP depois que você a passar a diante.</p>
<blockquote><p><span style="font-weight: bold; font-style: italic;">"Mas Fernando, nós já não temos o ponteiro do device de destino?"</span></p>
</blockquote>
<p>Muito bem, quando você obtém o ponteiro para um device, você teoricamente não sabe se existem filtros já atachados sobre ele. O ponteiro que você recebe nesta rotina pode não ser o ponteiro para o device de destino. Na figura abaixo podemos entender como essa relação acontece.</p>
<div style="text-align: center;"><img src="http://www.driverentry.com.br/images/NextDevice.png" alt="" /></div>
<blockquote><p><span style="font-weight: bold; font-style: italic;">"Fernando, existe uma versão unsafe desta rotina?"</span></p>
</blockquote>
<p>Na verdade existe, a <a href="http://msdn.microsoft.com/en-us/library/aa490466.aspx">IoAttachDeviceToDeviceStack()</a>.</p>
<div style="font-family: Courier New; font-size: 9pt; color: black; background: #A4F64C; border: 1px outset; padding: 0 0 0 5px;">
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">PDEVICE_OBJECT </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">  IoAttachDeviceToDeviceStack(</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    IN PDEVICE_OBJECT  SourceDevice,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">    IN PDEVICE_OBJECT  TargetDevice</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    );</pre>
</div>
<p>Ela é considerada unsafe por causa de uma pequena janela de tempo que pode causar um race condition. Repare que a diferença entre estas rotinas é a forma de obter o endereço do próximo device. Na versão original, este endereço é obtido pelo retorno na função. Se colocarmos essa função para rodar em câmera lenta veremos os seguintes passos.</p>
<p><br class="spacer_" /></p>
<ol>
<li>Seu device é atachado à pilha de dispositivos.</li>
<li>O endereço do próximo device é retornado pela função.</li>
<li>Seu driver recebe este endereço no retorno da função e atualiza o device extension.</li>
<li>IRPs começam a chegar e seu driver às encaminham para o próximo device da lista.</li>
</ol>
<p><br class="spacer_" /></p>
<p>Tudo parece lindo e até dá a impressão de que tudo vai funcionar muito bem em qualquer situação, mas desenvolvedor de driver é um bixo treinado para buscar race conditions. Dê mais uma olhada na sequência, mas agora em câmera super lenta. Com essa câmera super lenta agora podemos observar os passos que podem ocorrer entre os passos 2 e 3.</p>
<p><br class="spacer_" /></p>
<ol>
<li>Seu device é atachado à lista de dispositivos.</li>
<li>O endereço do próximo device é retornado pela função.
<ol>
<li>Sua thread é interrompida e uma IRP lançada por uma aplicação que roda em paralelo começa sua viagem por essa pilha de dispositivos.</li>
<li>Seu device, que já está atachado, recebe a IRP e tenta encaminhá-la ao device de baixo.</li>
<li>Oops! Nosso <span style="font-style: italic;">device extension</span> ainda não foi atualizado com tal endereço.</li>
<li>Seu driver se lembra de quando era uma criança e de tudo o que vivera até ali.</li>
<li>Ele decide entrar de vez naquela dança e enviar a IRP para um device cujo ponteiro ainda é NULL causando um BSOD.</li>
</ol>
</li>
<li>"Jeremias, eu sou homem. Coisa que você não é e não atiro pelas costas não..."</li>
</ol>
<p><br class="spacer_" /></p>
<p>Enfim, entenda que mesmo que você utilize o retorno da rotina <span style="font-style: italic;">IoAttachDeviceToDeviceStack(</span>) diretamente para atualizar seu device extension, ainda assim existe uma janela de tempo em que seu device estará atachado, mas que o valor ainda não foi atualizado no device extension. Isso porque o valor de retorno de uma rotina vem por um registrador. Pegar o valor desse registrador e atualizar uma variável ainda dá chances para o azar.</p>
<div style="font-family: Courier New; font-size: 9pt; color: black; background: #A4F64C; border: 1px outset; padding: 0 0 0 5px;">
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    <span style="color: green;">//-f--> ----==== NÃO COPIE ISSO ====----</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">    <span style="color: green;">//      Aqui ainda temos uma janela de tempo entre o device ser</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    <span style="color: green;">//      atachado e o valor de pNextDeviceObj ser atualizado.</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">    pDeviceExt->pNextDeviceObj = IoAttachDeviceToDeviceStack(pMyDeviceObj,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">                                                             pTargetDeviceObj);</pre>
</div>
<p>A rotina <span style="font-style: italic;">IoAttachDeviceToDeviceStackSafe(</span>) faz o sistema interromper o fluxo de IRPs nesta pilha até que a variável apontada pelo ponteiro de saída seja atualizado. Por essa razão, o endereço passado nesta rotina deve ser o endereço final da variável onde este valor será armazenado, que em nosso caso é <span style="font-style: italic;">pDeviceExt->pNextDeviceObj</span> sem passar por variáveis intermediárias.</p>
<p><img style="float: right; margin: 0px 10px;" src="http://www.driverentry.com.br/images/homer_doh.png" border="0" alt="" /></p>
<p>Esses detalhes são importantes e farão você entender que usar a versão safe desta rotina não é garantia de que tudo dará certo. Imagine que usando a versão safe você receba o endereço do próximo device em uma variável local e depois atualize seu device extension. Esse é um daqueles típicos casos que é necessário substituir aquele componente que fica entre o teclado e a cadeira.</p>
<p>Acha preciosismo? Tente ler o capítulo 5 do livro <a href="http://www.amazon.com/Programming-Microsoft-Windows-Driver-Model/dp/0735618038/ref=sr_1_1?ie=UTF8&amp;s=books&amp;qid=1264044523&amp;sr=1-1">"Programming the Microsoft Windows Driver Model"</a> onde Walter Oney fala sobre como lidar com cancelamento de IRPs.</p>
<p>Depois de atacharmos nosso device já podemos liberar a referência obtida por <span style="font-style: italic;">IoGetDeviceObjectPointer()</span> utilizando a rotina <span style="font-style: italic;">ObDereferenceObject()</span>, já que a rotina <span style="font-style: italic;">IoAttachDeviceToDeviceStackSafe()</span> já garantiu a referência até que essa ligação seja desfeita.</p>
<p>Muito bem. Pra quem não conseguiu entender quase nada do que eu disse, segue o código fonte da implementação da nossa <span style="font-style: italic;">DriverEntry()</span> de exemplo. Sabe como é cabeça de programador, as vezes um <span style="font-style: italic;">if</span> vale mais que mil páginas de explicação.</p>
<div style="font-family: Courier New; font-size: 9pt; color: black; background: #A4F64C; border: 1px outset; padding: 0 0 0 5px;">
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"><span style="color: green;">/****</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"><span style="color: green;">***     DriverEntry</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"><span style="color: green;">**</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"><span style="color: green;">**      Ponto de entrada do driver.</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"><span style="color: green;">**      Bem vindo ao inferno.</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"><span style="color: green;">*/</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"><span style="color: blue;">extern</span> <span style="color: #a31515;">"C"</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">NTSTATUS</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">DriverEntry(IN PDRIVER_OBJECT  pDriverObj,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">            IN PUNICODE_STRING pusRegistryPath)</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">{</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">    NTSTATUS            nts;</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    PDEVICE_OBJECT      pMyDeviceObj;</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">    <span style="color: blue;">int</span>                 i;</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    UNICODE_STRING      usDeviceName;</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">    PDEVICE_OBJECT      pTargetDeviceObj;</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    PFILE_OBJECT        pFileObj;</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">    PDEVICE_EXTENSION   pDeviceExt;</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"> </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">    <span style="color: green;">//-f--> Seta a rotina de descarga do driver.</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    pDriverObj->DriverUnload = OnDriverUnload;</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"> </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    <span style="color: green;">//-f--> Seta todas as dispatch routines do driver para</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">    <span style="color: green;">//      uma que encaminhe a IRP para o driver original.</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    <span style="color: blue;">for</span> (i = <span style="color: purple;">0</span>; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">        pDriverObj->MajorFunction[i] = OnForwardDispatch;</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"> </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">    <span style="color: green;">//-f--> Inicializamos a string com o nome do device ao</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    <span style="color: green;">//      qual queremos nos atachar.</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">    RtlInitUnicodeString(&amp;usDeviceName,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">                         L<span style="color: #a31515;">"\\Device\\StringList"</span>);</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"> </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    <span style="color: green;">//-f--> Obtemos o ponteito do device de destino</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">    nts = IoGetDeviceObjectPointer(&amp;usDeviceName,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">                                   FILE_READ_DATA,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">                                   &amp;pFileObj,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">                                   &amp;pTargetDeviceObj);</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">    <span style="color: blue;">if</span> (!NT_SUCCESS(nts))</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">        <span style="color: blue;">return</span> nts;</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"> </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    <span style="color: green;">//-f--> Criamos nosso device object</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">    nts = IoCreateDevice(pDriverObj,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">                         <span style="color: blue;">sizeof</span>(DEVICE_EXTENSION),</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">                         NULL,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">                         pTargetDeviceObj->DeviceType,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">                         pTargetDeviceObj->Characteristics,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">                         FALSE,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">                         &amp;pMyDeviceObj);</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    <span style="color: blue;">if</span> (!NT_SUCCESS(nts))</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">    {</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">        <span style="color: green;">//-f--> Oops!</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">        ObDereferenceObject(pFileObj);</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">        <span style="color: blue;">return</span> nts;</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">    }</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"> </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">    <span style="color: green;">//-f--> Obtem nosso DEVICE_EXTENSION</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    pDeviceExt = (PDEVICE_EXTENSION)pMyDeviceObj->DeviceExtension;</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"> </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    <span style="color: green;">//-f--> Utiliza o mesmo método de IO do driver original</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">    pMyDeviceObj->Flags |= pTargetDeviceObj->Flags &amp; (DO_BUFFERED_IO | DO_DIRECT_IO);</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"> </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">    <span style="color: green;">//-f--> Aqui nosso driver entra na pilha de dispositivos</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    nts = IoAttachDeviceToDeviceStackSafe(pMyDeviceObj,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">                                          pTargetDeviceObj,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">                                          &amp;pDeviceExt->pNextDeviceObj);</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">    <span style="color: blue;">if</span> (!NT_SUCCESS(nts))</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    {</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">        <span style="color: green;">//-f--> Oops!</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">        IoDeleteDevice(pMyDeviceObj);</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">        <span style="color: green;">//-f--> Aqui não está faltando um return.</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    }</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"> </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    <span style="color: green;">//-f--> Independente de estarmos atachados ou não, devemos liberar</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">    <span style="color: green;">//      a referência obtida do device de destino.</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    ObDereferenceObject(pFileObj);</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">    <span style="color: blue;">return</span> nts;</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">}</pre>
</div>
<h3>Escrevendo a OnDriverUnload</h3>
<p>Aqui é onde a festa acaba, antes de o nosso driver ser descarregado pelo sistema, teremos que remover nosso device da pilha de dispositivos e destruí-lo. (Risadas maléficas)</p>
<p>O código aqui é simples e não requer explicações se você for capaz de ler os comentários contidos nele.</p>
<div style="font-family: Courier New; font-size: 9pt; color: black; background: #A4F64C; border: 1px outset; padding: 0 0 0 5px;">
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"><span style="color: green;">/****</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"><span style="color: green;">***     OnDriverUnload</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"><span style="color: green;">**</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"><span style="color: green;">**      Rotina de descarga do driver.</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"><span style="color: green;">*/</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">VOID</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">OnDriverUnload(IN PDRIVER_OBJECT  pDriverObj)</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">{</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    PDEVICE_OBJECT      pMyDeviceObj;</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">    PDEVICE_EXTENSION   pDeviceExt;</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"> </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">    <span style="color: green;">//-f--> Nosso device está na lista de devices criados por este driver</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    <span style="color: green;">//      então vamos obtê-lo simples assim:</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">    pMyDeviceObj = pDriverObj->DeviceObject;</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"> </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">    <span style="color: green;">//-f--> Aqui obtêmos o device extension.</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    pDeviceExt = (PDEVICE_EXTENSION)pMyDeviceObj->DeviceExtension;</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"> </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    <span style="color: green;">//-f--> Aqui removemos nosso device da pilha passando o endereço do</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">    <span style="color: green;">//      próximo device para a rotina abaixo.</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    IoDetachDevice(pDeviceExt->pNextDeviceObj);</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"> </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    <span style="color: green;">//-f--> Agora podemos destruir nosso device (risadas maléficas)</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">    IoDeleteDevice(pMyDeviceObj);</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">}</pre>
</div>
<blockquote><p><span style="font-weight: bold; font-style: italic;">"Fernando, nosso driver é forçado a se descarregar quando o driver original é descarregado?"</span></p>
</blockquote>
<p>Essa é a filosofia do <span style="font-weight: bold;">WDM</span>, drivers são carregados automáticamente quandos seus dispositivos são detectados e descarregados quando seus dispositivos são desativados ou removidos. Os filtros seguem as mesmas regras e são carregados/descarregados basendo-se nestes eventos.</p>
<p>Mas não é isso o que acontece aqui. Os drivers de exemplo que uso neste blog são do modelo <span style="font-weight: bold;">Legacy</span>, e não WDM. No modelo Legacy, drivers são iniciados seguindo sua ordem de carga no registry, e não tem nada a ver com a detecção do seu dispositivo. Os filtros precisam iniciar depois dos drivers originais, e isso também é controlado pela sua ordem de carga. <a href="http://www.driverentry.com.br/blog/2009/12/drivers-de-boot-no-windows.html">Este post</a> fala sobre a ordem de carga dos legacy drivers.</p>
<blockquote><p><span style="font-weight: bold; font-style: italic;">"Tá! Falou, falou e não respondeu minha pergunta. O que acontece se eu solicitar a descarga do driver original enquanto houver um filtro atachado sobre ele?"</span></p>
</blockquote>
<p>A descarga dos drivers que formam uma pilha deve ocorrer de forma inversa à sua carga. Neste caso o filtro deve ser descarregado antes do driver original, desempilhando os devices de cima para baixo. Caso o driver original receba uma solicitação de descarga enquanto ainda hoverem referências a seus devices, seja por um filtro ou por uma aplicação, a descarga é adiada até que suas referências sejam desfeitas. Até lá, a tentativa de obter novas referências para um device que recebeu a solicitação de descarga serão negadas.</p>
<h3>Escrevendo Dispatch Routines</h3>
<p>As <span style="font-style: italic;">dispatch routines</span> de um filtro também são diferentes das <span style="font-style: italic;">dispatch routine</span>s de um driver. Apensar de elas poderem completar uma IRP chamando <a href="http://msdn.microsoft.com/en-us/library/aa490590.aspx">IoCompleteRequest()</a>, elas normalmente repassam a socilitação adiante utilizando a rotina <a href="http://msdn.microsoft.com/en-us/library/aa490633.aspx">IoCallDriver()</a>. Vou falar mais sobre o comportamento das <span style="font-style: italic;">dispatch routines</span> de um filtro em posts futuros. Neste filtro de exemplo vamos apenas logar a atividade e repassar a solicitação ao próximo driver.</p>
<p>Quando falamos em repassar uma solicitação estamos na verdade falando de repassar IRPs. A leitura deste <a href="http://www.driverentry.com.br/blog/2007/02/legal-mas-o-que-uma-irp.html">outro post</a> é essencial para o que vamos fazer na implementação de nossas <span style="font-style: italic;">dispatch routines</span>.</p>
<p>Para acabar esse post ainda nessa vida, segue código da implementação de nossa <span style="font-style: italic;">dispatch routine</span>. Depois de ler o post sobre IRPs que acabei de recomendar, ler os comentários deste código devem ser suficientes para entender tudo o que foi feito aqui, ou não.</p>
<div style="font-family: Courier New; font-size: 9pt; color: black; background: #A4F64C; border: 1px outset; padding: 0 0 0 5px;">
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"><span style="color: green;">/****</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"><span style="color: green;">***     OnForwardDispatch</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"><span style="color: green;">**</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"><span style="color: green;">**      Nossa dispatch routine simplesmente loga a IRP</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"><span style="color: green;">**      recebida e repassa a solicitação adiante.</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"><span style="color: green;">**</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"><span style="color: green;">*/</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">NTSTATUS</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">OnForwardDispatch(IN PDEVICE_OBJECT    pDeviceObj,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">                  IN PIRP              pIrp)</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">{</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">    PDEVICE_EXTENSION   pDeviceExt;</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    PIO_STACK_LOCATION  pStack;</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"> </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    <span style="color: green;">//-f--> Obtém ponteiro para o device extesion</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">    pDeviceExt = (PDEVICE_EXTENSION)pDeviceObj->DeviceExtension;</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;"> </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">    <span style="color: green;">//-f--> Obtém stack location corrente</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    pStack = IoGetCurrentIrpStackLocation(pIrp);</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"> </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    <span style="color: green;">//-f--> Manda o nome na major routine da IRP</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">    ASSERT(pStack->MajorFunction <= IRP_MJ_MAXIMUM_FUNCTION);</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    DbgPrint(<span style="color: #a31515;">"[StringFilter] : %s\n"</span>, g_szMajorNames[pStack->MajorFunction]);</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"> </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    <span style="color: green;">//-f--> Como não estamos modificando nada na stack location,</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">    <span style="color: green;">//      vamos deixá-la para que o próximo device a use.</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    IoSkipCurrentIrpStackLocation(pIrp);</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;"> </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">    <span style="color: green;">//-f--> Encaminha a IRP para o próximo device.</span></pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">    <span style="color: blue;">return</span> IoCallDriver(pDeviceExt->pNextDeviceObj,</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">                        pIrp);</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">}</pre>
</div>
<p>Caso não tenham entendido nada, não esqueçam de me mandar um e-mail expondo suas dúvidas (sem ofenças pessoais). Isso me ajudará a entender suas dificuldades e a melhorar minhas explicações.</p>
<h3>Testando o Filtro</h3>
<p>Essa é a parte fácil do post. Para testar o filtro teremos primeiro que compilar, instalar e iniciar o driver <a href="http://www.driverentry.com.br/blog/2009/07/strings-no-kernel.html">deste post</a>. Se você ainda não sabe como fazer isso, este <a href="http://www.driverentry.com.br/blog/2006/09/getting-started.html">outro post</a> pode te dar um ponto de partida. Depois disso, compile, instale e inicie o filtro.</p>
<p>Depois de instalados, podemos utilizar a aplicação de teste para exercitar o driver. Poderemos acompanhar a atividade do filtro observando suas mensagens de debug que podem ser vistas no depurador de Kernel ou simplemente usando <a href="http://www.osronline.com/article.cfm?article=99">esta aplicação</a>, que dispensa o uso de um depurador para ver as mensagens de debug de um driver.</p>
<div style="text-align: center;"><img src="http://www.driverentry.com.br/images/Filtering.png" alt="" /></div>
<blockquote><p><span style="font-weight: bold; font-style: italic;">"Fernando, fiz um teste aqui e ví que ao iniciar o filtro ele loga um evento de <span style="font-style: italic;">IRP_MJ_CLOSE</span> mesmo antes de iniciar a aplicação de teste. O que eu fiz de errado?"</span></p>
</blockquote>
<div style="text-align: center;"><img src="http://www.driverentry.com.br/images/LogClose.png" alt="" /></div>
<p>Não há nada de errado. Isso acontece por causa da sequência de passos seguidos na rotina <span style="font-style: italic;">DriverEntry()</span> do filtro. Inicialmente o driver chama a rotina <span style="font-style: italic;">IoGetDeviceObjectPointer()</span>, isso faz com que o <span style="font-style: italic;">IoManager</span> envie uma solicitação de <span style="font-style: italic;">IRP_MJ_CREATE</span> para o driver original. Depois disso nos atachamos à pilha de dispositivos e por fim chamamos a rotina <span style="font-style: italic;">ObDereferenceObject()</span> que vai finalizar a única referência do <span style="font-style: italic;">file object</span> que recebemos, enviando uma solicitação de <span style="font-style: italic;">IRP_MJ_CLOSE</span> para o driver de baixo. Como já estamos atachados a ele, então somos capazes de ver nossa própria atividade sobre o driver original. Isso pode ser observado pela pilha de chamadas que teremos se houver um <span style="font-style: italic;">breakpoint</span> em nossa <span style="font-style: italic;">dispatch routine</span> quando liberarmos a referência do <span style="font-style: italic;">file object</span> ao final da <span style="font-style: italic;">DriverEntry()</span>.</p>
<div style="font-family: Courier New; font-size: 9pt; color: black; background: #A4F64C; border: 1px outset; padding: 0 0 0 5px;">
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">kd> k</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">ChildEBP RetAddr  </pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA; color: red;">f8af9bcc 804ee129 StringFilter!OnForwardDispatch</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">f8af9bdc 80578f6a nt!IopfCallDriver+0x31</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">f8af9c14 805b0b18 nt!IopDeleteFile+0x132</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">f8af9c30 80522bd1 nt!ObpRemoveObjectRoutine+0xe0</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">f8af9c54 f8c80663 nt!ObfDereferenceObject+0x5f</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF; color: red;">f8af9c7c 805767ff StringFilter!DriverEntry+0xf3</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">f8af9d4c 8057690f nt!IopLoadDriver+0x66d</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">f8af9d74 80534c12 nt!IopLoadUnloadDriver+0x45</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">f8af9dac 805c61ee nt!ExpWorkerThread+0x100</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FFFFFF;">f8af9ddc 80541de2 nt!PspSystemThreadStartup+0x34</pre>
<pre style="margin: 0px; padding: 0 0 0 5px; background: #FAFAFA;">00000000 00000000 nt!KiThreadStartup+0x16</pre>
</div>
<p>Como de costume, o fonte do filtro que foi implementado neste post está disponível para download. Nosso filtro não faz quase nada, mas já servirá de base para posts futuros que darão mais funcionalidade a ele explicando como tais funcionalidades são implementadas.</p>
<p>Até mais!</p>
<p class="download"><a href="http://www.driverentry.com.br/samples/StringFilter.zip">StringFilter.zip</a></p>
]]></content:encoded>
			<wfw:commentRss>http://driverentry.com.br/blog/?feed=rss2&amp;p=212</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Drivers de Boot no Windows</title>
		<link>http://driverentry.com.br/blog/?p=217</link>
		<comments>http://driverentry.com.br/blog/?p=217#comments</comments>
		<pubDate>Thu, 17 Dec 2009 13:37:40 +0000</pubDate>
		<dc:creator>Fernando Roberto</dc:creator>
				<category><![CDATA[Kernel Development]]></category>

		<guid isPermaLink="false">http://driverentry.com.br/wp/?p=217</guid>
		<description><![CDATA[Tenho acompanhado o trabalho do meu amigo Lesma, que em seu blog tem descrito como o processo de boot transforma um apanhado de bytes no disco rígido em um sistema operacional vivo. Pegando carona nesse tema, vou aproveitar para comentar sobre a ordem de carga dos drivers durante este processo. Com isso posso tentar responder [...]]]></description>
			<content:encoded><![CDATA[<p><img style="float: right; margin: 0px 10px;" src="http://www.driverentry.com.br/images/StartingWidows.png" border="0" alt="" /></p>
<p>Tenho acompanhado o trabalho do meu amigo Lesma, que em <a href="http://www.caloni.com.br">seu blog</a> tem descrito como o processo de boot transforma um apanhado de bytes no disco rígido em um sistema operacional vivo. Pegando carona nesse tema, vou aproveitar para comentar sobre a ordem de carga dos drivers durante este processo. Com isso posso tentar responder uma pergunta frequente dos leitores: <span style="font-style: italic;"><span style="font-weight: bold;">&#8220;Como fazer para que meu driver seja o primeiro a ser carregado?&#8221;</span></span>. Talvez este post possa clarear um pouco as coisas neste sentido, ou não.</p>
<h3>Eu primeiro! Eu primeiro!</h3>
<p>Um ponto importante a ser considerado no modelo <span style="font-weight: bold;">Legacy</span> quando escrevemos um driver é o referente ao momento no qual seu driver é carregado. Isso é configurado no valor <span style="font-style: italic;">&#8220;Start&#8221;</span> na chave do driver no registro. Quatro valores configuram o momento da carga do seu driver, sendo eles:</p>
<ul>
<li>Boot (0) &#8211; Drivers são carregados durante o boot, antes mesmo sistema operacional estar completamente pronto para execução.</li>
<li>System (1) &#8211; Drivers são carregados depois dos drivers de boot, quando o Kernel já está completamente funcional.</li>
<li>Automatic (2) &#8211; Neste grupo os drivers são carregados quando os subsistemas forem carregados. Basicamente junto com os serviços de <span style="font-style: italic;">User Mode</span>.</li>
<li>Manual (3) &#8211; Nenhuma carga automática é realizada aqui, o driver é carregado somente quando alguém, ou algum componente, solicita sua carga.</li>
<li>Disabled (4)- Mesmo que o driver seja solicitado, sua carga é negada.</li>
</ul>
<p><br class="spacer_" /></p>
<p><span style="font-weight: bold;"><span style="font-style: italic;">&#8220;Bom, então para meu driver ser o primeiro a ser carregado ele precisa ser iniciado como boot e pronto?&#8221;</span></span></p>
<p>Na verdade seu driver vai disputar um lugar na fila de drivers que querem ser iniciados no boot. Vários drivers estão configurados para ser iniciados nesse momento e o seu será apenas mais um. Mesmo entre os drivers de boot, uma ordem de carga precisa ser seguida para que certos drivers possam contar com os serviços de outros drivers. Por esse motivo, drivers se separam em grupos. Um grupo de cada vez vai sendo iniciado até que todos os drivers de boot passem por esse processo.</p>
<p>Drivers identificam seu grupo pelo valor <span style="font-style: italic;">&#8220;Group&#8221;</span> encontrado em sua chave de registro. Esta chave deve conter o nome do grupo ao qual o driver pertence. Os nomes de todos os grupos podem ser encontrados na chave <span style="font-weight: bold;">HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\ServiceGroupOrder</span>. Nela existe um valor do tipo <span style="font-style: italic;">REG_MULTI_SZ</span> chamado <span style="font-style: italic;">&#8220;List&#8221;</span> que contém a lista de todos os grupos existentes dispostos em sua ordem de carga.</p>
<div style="text-align: center;"><img src="http://www.driverentry.com.br/images/ServiceGroupOrder.png" alt="" /></div>
<p><br class="spacer_" /></p>
<p><span style="font-weight: bold;"><span style="font-style: italic;">&#8220;Tudo bem, meu driver está configurado para ser iniciado em Boot e está configurado para iniciar com o primeiro grupo de drivers. Pronto agora?&#8221;</span></span></p>
<p>Quase. Quando falamos em iniciar grupos de drivers, já fica sub-entendido que mais de um driver será carregado. A ordem que tais drivers são carregados dentro de cada grupo também pode ser determinada.</p>
<p>A chave <span style="font-weight: bold;">KHEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\GroupOrderList</span> mantém uma série de valores, cada um com o nome de um grupo. O valor é do tipo <span style="font-style: italic;">REG_BINARY</span> e sua interpretação é um array de conjuntos de quatro bytes. O primeiro conjunto indica quantas tags estão contidas naquele buffer binário. Os demais conjuntos são as representações numéricas de cada tag. Dessa forma, a interpretação do buffer exibido na figura abaixo nos dá a informação de que temos seis tags, sendo elas: 1, 2, 3, 4, 5 e 6.</p>
<div style="text-align: center;"><img src="http://www.driverentry.com.br/images/GroupOrderList.png" alt="" /></div>
<p><br class="spacer_" /></p>
<p><span style="font-weight: bold;"><span style="font-style: italic;">&#8220;Mas o que é uma tag?&#8221;</span></span></p>
<p>Uma tag é a identificação numérica de um driver dentro de um determinado grupo. Um driver se identifica pelo valor <span style="font-style: italic;">&#8220;Tag&#8221;</span> que podemos encontrar na chave do driver no registro.</p>
<p>Apesar de o exemplo nos mostrar uma ordem crescente de tags, o valor da tag não determina a ordem de carga dos drivers. A ordem é determinada por sua posição dentro do buffer binário.</p>
<p>Ficou com nojinho de mexer em buffers binários? Você pode utilizar o <a href="http://www.osronline.com/article.cfm?article=157">OSR Driver Loader</a> que configura tudo isso pra você quando utilizado para instalar um driver.</p>
<div style="text-align: center;"><img src="http://www.driverentry.com.br/images/DrvReinitLdr.png" alt="" /></div>
<p><br class="spacer_" /></p>
<p>Colocar sua tag como primeiro na lista de tags classifica sua ordem de carga dentro de um determinado grupo, mas ainda não é fator determinante para ter seu driver carregado antes de todos os drivers do universo. Um novo grupo sempre pode ser criado e ter sua ordem de carga configurada para antes do seu grupo.</p>
<p>Todas essas regras sobre grupos, tags e afins não fazem sentido nos drivers gerenciados pelo <span style="font-weight: bold;">Plug-And-Play (Pnp) Manager</span>, já que a carga de tais drivers é solicitada quando o dispositivo ao qual seu driver está relacionado é detectado pelo driver de barramento.</p>
<p><span style="font-weight: bold;"><span style="font-style: italic;">&#8220;Aff! Fernando, pega leve e tenta explicar isso de novo.&#8221;</span></span></p>
<p>Tudo bem, vamos lá. Quando você instala um driver Pnp, você o associa a um determinado dispositivo. Apenas como exemplo, digamos que esse dispositivo seja um conversor USB/Serial. Seu driver será carregado automagicamente quando seu dispositivo for detectado e será descarregado quando o dispositivo for removido.</p>
<p>Para que ele seja detectado, outros dispositivos precisam ser detectados antes, tais como controladora PCI, controladora USB e hub USB. Essa lista de dependência cria a <a href="http://msdn.microsoft.com/en-us/library/ms794302.aspx">pilha de dispositivos USB</a>.</p>
<p>A controladora PCI, ao ser detectada, tem seu driver carregado e este enumera seus dispositivos filhos, já que PCI é um barramento. Para cada disposivito detectado, esse driver utiliza o barramento para detectar a identidade de cada dispositivo e cria um <span style="font-weight: bold;">Phisical Device Object</span> (PDO) para cada um deles. O Pnp Manager carrega o driver de cada dispositivo atachado a esse barramento. Esse driver criará o <span style="font-weight: bold;">Functional Device Object</span> (FDO) do dispositivo, dando funcionalidade a ele.</p>
<p>Um desses dispositivos é a controladora do barramento USB. Seguindo o ritual, o driver de barramento USB enumera seus dispositivos filhos, criando novos PDOs. Assim, os hubs USB são detectados e seu driver será carregado. Este driver criará um novo FDO para cada hub. O driver de hub USB vai enumerar seus dispositivos filhos e é nesse momento que seu dispositivo é detectado. O driver que você escreveu será carregado e o Pnp Manager irá chamar sua rotina <a href="http://msdn.microsoft.com/en-us/library/ms795509.aspx">AddDevice</a>, que receberá o PDO que o driver de hub criou referente ao seu dispositivo.</p>
<p>Ufa! Tudo bem, tenham calma. O assunto Plug-And-Play não é o foco deste post e já está na minha lista de posts futuros.</p>
<p>Toda essa atividade que age recursivamente serve para montar a <a href="http://msdn.microsoft.com/en-us/library/aa489660.aspx">árvore de dispositivos do sistema</a>. Sabendo que esta árvore é formada pelos nossos drivers e seus devices, fica explícito aqui que no fundo <a href="http://www.youtube.com/watch?v=JqIeVYIUKxk">&#8220;As árveres somos nozes&#8221;</a>. A figura abaixo dá uma idéia de como a árvore de dispositivos é organizada.</p>
<div style="text-align: center;"><img src="http://www.driverentry.com.br/images/DeviceTree.png" alt="" /></div>
<p><br class="spacer_" /></p>
<p>Ainda falando sobre ordem de carga de drivers, não faria sentido ter seu driver carregado antes de todos os outros drivers, já que os componentes básicos para a comunicação com seu dispositivo ainda não foram carregados, e por isso, não possuem funcionalidade nenhuma. Além do mais, ter seu driver carregado muito cedo lhe trará problemas em lidar com outros componentes do sistema que ainda não estarão prontos para atender seu pedido. Mais detalhes <a href="http://www.driverentry.com.br/blog/2007/06/comear-de-novo.html">neste post</a>.</p>
<h3>Depurando no Boot</h3>
<p>Outro assunto curioso e que pode gerar alguma confusão é o referente ao debug de drivers que são carregados no boot. Apesar de a conexão de Debug usar o meio <a href="http://www.driverentry.com.br/blog/2006/12/step-into-kernel-serial.html">serial</a>, <a href="http://www.driverentry.com.br/blog/2008/07/step-into-kernel-firewire.html">firewire</a> ou mesmo <a href="http://www.driverentry.com.br/blog/2008/03/step-into-kernel-vista-usb2.html">USB</a>, os drivers referentes a estes meios não precisam estar carregados para que você possa realizar o debug do sistema. Em outras palavras, o driver de porta serial não é utilizado para fazer debug do sistema quando se usa o meio serial. Isso seria um problema se pensarmos que alguns drivers são carregados e inciados antes do driver de porta serial. Como estes drivers seriam depurados?</p>
<p>O fato é que o algoritmo que lida com os meios de depuração do sistema são definidos no próprio Kernel (mais precisamente no módulo ntoskrnl.exe e seus irmãos). Este módulo lida diretamente com o hardware responsável pelo meio utilizado. Essa é também a explicação para outra pergunta frequente: <span style="font-style: italic;"><span style="font-weight: bold;">&#8220;Meu computador não tem porta serial. Posso usar um conversor USB/Serial do lado Target para fazer debug do sistema?&#8221;</span></span>. Como acabamos de ver, um conversor USB/Serial depende de toda uma pilha de dispositivos para que a porta serial esteja disponível. Tal funcionalidade não está implementada no algoritmo de debug do sistema, e como comentei <a href="http://www.driverentry.com.br/blog/2006/10/serial-killers.html">neste outro post</a>, sistemas mais novos implementam novas funcionalidades de debug no Kernel.</p>
<p>Mesmo que seu driver seja de boot, ele ainda pode ser depurado. <a href="http://www.driverentry.com.br/blog/2007/07/bug-em-meu-driver-de-boot-j-posso.html">Este outro post</a> mostra ainda como fazer mapeamento de um driver de boot pelo WinDbg. Não sabe do que estou falando? É sobre ter seu driver substituído por uma nova versão automaticamente no lado target quando este for carregado. Vale a pena dar uma olhada.</p>
<p>Have fun!</p>
]]></content:encoded>
			<wfw:commentRss>http://driverentry.com.br/blog/?feed=rss2&amp;p=217</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
	</channel>
</rss>
