# O boot no Windows: NTLDR

Caloni, 2009-11-26 computer [up] [copy]

Minhas análises estão demorando muito para ser feitas. Talvez seja a hora de revelar o pouco que sei (e pesquisei) sobre o próximo processo de boot do Windows: o NTLDR.

O nosso amigo NT Loader pode ser entendido através da leitura do já citado **Windows Internals** ou através de uma outra leitura que estou fazendo atualmente e que pouquíssimos amigos blogueiros irão se lembrar: o livro da galinha preta; formalmente conhecido como **Windows Nt File System Internals**.

Para os sabichões de plantão, inclusive os que me criticaram (?) no meu último texto humorístico sobre como Java é podre, eu sei que o bicho da capa não é uma galinha, mas um urubu. A troca de urubu por galinha vem do requisito básico para você fazer trabalhos esotéricos, como macumba e desenvolvimento de drivers: uma galinha preta na encruzilhada. Alguns usam um papel dentro da boca de um sapo, mas vai do gosto de cada um. =)

E, para os que leram o livro, devem entender que para explicar sobre o funcionamento do sistema de arquivos do Windows, parte intrínseca do funcionamento do próprio kernel, foi necessário ao autor explicar várias partes do kernel, inclusive **sua inicialização**; e é nessa parte que podemos aprender algo mais sobre o NT Loader.

Podemos aprender, por exemplo, que ele é carregado **logo depois do NT Detect**, que é o executável que dá uma olhada no hardware e ajusta a configuração do boot de acordo com o ambiente encontrado. Após esse ajuste, o nosso amigo NT Loader faz algumas coisas pra lá de interessantes.

O NTLDR é um executável "híbrido" que possui tanto código em modo real quanto código em modo protegido. Com isso podemos supor que é ele o responsável por entrar em modo protegido, uma tarefa que exige alguns conhecimentos da arquitetura.

Além disso, como o próprio nome diz, ele tecnicamente "sobe" o sistema operacional, pois provê a comunicação entre o hardware (processador e periféricos da máquina) e o software (kernel e drivers de boot). O hardware é o que está espetado na máquina e o kernel é o arquivo **ntoskrnl.exe**; para a comunicação entre eles existe uma camada de abstração, o **hal.dll**.

Esses dois arquivos, juntos dos drivers de boot, são carregados pelo NTLDR.

Depois de todo aquele trabalhão do setor de boot para analisar o sistema de arquivos, achar o NTLDR, carregá-lo na memória e executá-lo, o controle passa para o nosso amigo híbrido, ainda em modo real. Ele então abre a partição de boot e procura pelo arquivo boot.ini (estamos falando de um boot antes de bcdedit, mas o funcionamento seria aproximado). Como o driver do sistema de arquivos ainda não subiu, isso quer dizer que o NTLDR usa o próprio código embutido para interpretar uma FAT, NTFS ou outros sistemas suportados (um dos motivos por que não é possível instalar o Windows em um ReiserFS).

Nesse ponto o nosso amigo loader faz o que todo mundo já fez na infância (não fez?): trocar o modo de tela fazendo uma chamada para a BIOS para modo texto 80x50 em 16 cores. Ah, ele também faz algo que eu adorava fazer (você não?): encher a memória de vídeo de pixels pretos para limpar a tela!

Como ele leu a lista de kernels bootáveis, é isso que ele exibe naquela famosa tela que qualquer um que depura o kernel vê:

Escolheu seu boot, é a partir daí que ele acha o executável do kernel: **ntoskrnl.exe**. Ele deve estar na pasta system32 (em ambientes 32 bits). Também é nesse momento que é carregada a HAL (hal.dll) e isola-se o hardware do software a partir daí. As DLLs que esses dois componentes dependem são identificadas e carregadas na memória.

Agora é hora de abrir o registro. Quer dizer, parte dele. Dentro da pasta system32/config deve estar a hive SYSTEM, que é onde ficam os drivers que devem ser carregados a partir daí em vários níveis. Inicialmente são carregados os que possuem o valor **Start igual a zero**, como o driver Atapi (controlador de disco):

A partir daí vários componentes do kernel serão carregados progressivamente. Só que a partir do momento que é chamada a rotina interna **KiInitializeKernel** o NTLDR não tem mais nada pra fazer: o kernel, em sua forma básica e primitiva, está carregado.

   
   windbg notepad
   $$>a<<a href="http://www.caloni.com.br/carregando-dlls-arbitrarias-pelo-windbg-parte-2">scripts\loadlibrary.txt</a> <strong>ntoskrnl.exe</strong>
   
   0:000> lm m nt*
   start    end        module name
   00400000 00629000   ntoskrnl   (pdb symbols)          c:\tools\symbols\ntkrnlmp.pdb\46DFBE2D3E484140A0909F7519B1700A2\ntkrnlmp.pdb
   7c900000 7c9b6000   ntdll      (pdb symbols)          c:\tools\symbols\ntdll.pdb\6992F4DAF4B144068D78669D6CB5D2072\ntdll.pdb
   0:000> x ntoskrnl!KiInit*
   005ef332 ntoskrnl!KiInitializePcr = <no type information>
   005eefc0 ntoskrnl!KiInitQueuedSpinLocks = <no type information>
   005ef1de ntoskrnl!KiInitSystem = <no type information>
   00439ded ntoskrnl!KiInitializeTSS = <no type information>
   <strong>005eadd2 ntoskrnl!KiInitializeKernel = <no type information></strong>
   0043aefb ntoskrnl!KiInitializeAbios = <no type information>
   005e4add ntoskrnl!KiInitMachineDependent = <no type information>
   0058faa4 ntoskrnl!KiInitializePAT = <no type information>
   005dde52 ntoskrnl!KiInitializeTSS2 = <no type information>
   004105e5 ntoskrnl!KiInitializeUserApc = <no type information>
   00415619 ntoskrnl!KiInitializeContextThread = <no type information>
   0043afdb ntoskrnl!KiInitializeAbiosGdtEntry = <no type information>
   005dde01 ntoskrnl!KiInitializeMachineType = <no type information>
   005e51f7 ntoskrnl!KiInitializeMTRR = <no type information>
   
   0:000> u ntoskrnl!KiInitializeKernel
   ntoskrnl!KiInitializeKernel:
   005eadd2 6a28            push    28h
   005eadd4 68c0784300      push    offset ntoskrnl!KiDebugRegisterContextOffsets+0x3c (004378c0)
   005eadd9 e8a510e2ff      call    ntoskrnl!_SEH_prolog (0040be83)
   005eadde e8b531ffff      call    ntoskrnl!KiSetProcessorType (005ddf98)
   005eade3 e8cfffffff      call    ntoskrnl!KiSetCR0Bits (005eadb7)
   005eade8 e8d334ffff      call    ntoskrnl!KiIsNpxPresent (005de2c0)
   005eaded 8845e7          mov     byte ptr [ebp-19h],al
   005eadf0 64a11c000000    mov     eax,dword ptr fs:[0000001Ch]

Veremos nos próximos capítulos como podemos nos aproveitar do ntoskrnl.exe para poder depurar o código a partir daí. Até lá.

pouquíssimos amigos blogueiros irão se lembrar: o livro da galinha preta: http://www.amazon.com/Windows-File-System-Internals-Developers/dp/1565922492

último texto humorístico sobre como Java é podre, eu sei que o bicho da capa não é uma galinha, mas um urubu. A troca de urubu por galinha vem do requisito básico para você fazer trabalhos esotéricos, como macumba e desenvolvimento de drivers: uma galinha preta na encruzilhada. Alguns usam um papel dentro da boca de um sapo: http://www.driverentry.com.br/blog/2006/10/serial-killers.html


[2009-09] [2009-12]