# O boot no Windows: Kernel

2009-12-04 tag_coding ^

Finalmente chegamos em um ponto onde podemos usar o WinDbg.

Podemos espetar o depurador e fazê-lo parar assim que conectado. Se estiver rodando antes do próprio sistema operacional, teremos um sistema sem processos e sem threads, pois ele irá parar assim que o executivo puder enviar o sinal de início pela porta serial, após carregar na memória os módulos básicos.

windbg -k com:pipe,port=\\.\pipe\com_1 <strong><font color="#000000">-b</font></strong>

Microsoft (R) Windows Debugger Version 6.11.0001.404 AMD64

Copyright (c) Microsoft Corporation. All rights reserved.

Opened \\.\pipe\com_1

Waiting to reconnect...

Connected to Windows XP 2600 x86 compatible target at (Tue Sep 8 22:33:27.267 2009 (GMT-3)), ptr64 FALSE

Kernel Debugger connection established. (Initial Breakpoint requested)

Symbol search path is: *** Invalid ***

****************************************************************************

* Symbol loading may be unreliable without a symbol search path. *

* Use .symfix to have the debugger choose a symbol path. *

* After setting your symbol path, use .reload to refresh symbol locations. *

****************************************************************************

Executable search path is:

*********************************************************************

* Symbols can not be loaded because symbol path is not initialized. *

* *

* The Symbol Path can be set by: *

* using the _NT_SYMBOL_PATH environment variable. *

* using the -y <symbol_path> argument when starting the debugger. *

* using .sympath and .sympath+ *

*********************************************************************

*** ERROR: Symbol file could not be found. Defaulted to export symbols for ntkrnlpa.exe -

Windows XP Kernel Version 2600 UP Free x86 compatible

Built by: 2600.xpsp_sp2_rtm.040803-2158

Machine Name:

Kernel base = 0x804d7000 PsLoadedModuleList = 0x805531a0

System Uptime: not available

Break instruction exception - code 80000003 (first chance)

*******************************************************************************

* *

* You are seeing this message because you pressed either *

* CTRL+C (if you run kd.exe) or, *

* CTRL+BREAK (if you run WinDBG), *

* on your debugger machine's keyboard. *

* *

* THIS IS NOT A BUG OR A SYSTEM CRASH *

* *

* If you did not intend to break into the debugger, press the "g" key, then *

* press the "Enter" key now. This message might immediately reappear. If it *

* does, press "g" and "Enter" again. *

* *

*******************************************************************************

*** ERROR: Symbol file could not be found. Defaulted to export symbols for ntkrnlpa.exe -

nt!DbgBreakPointWithStatus+0x4:

80526da8 cc int 3

kd> lm

start end module name

804d7000 806ce300 nt (export symbols) ntkrnlpa.exe

806cf000 806ef380 hal (deferred)

f96f0000 f970a580 Mup (deferred)

f970b000 f9737a80 NDIS (deferred)

f9738000 f97c4480 Ntfs (deferred)

f97c5000 f97db780 KSecDD (deferred)

f97dc000 f97edf00 sr (deferred)

f97ee000 f980c780 fltMgr (deferred)

f980d000 f9824800 SCSIPORT (deferred)

f9825000 f983c480 atapi (deferred)

f983d000 f985bb80 ftdisk (deferred)

f985c000 f986cd80 pci (deferred)

f986d000 f989b000 ACPI (deferred)

f999c000 f99a4d80 isapnp (deferred)

f99ac000 f99b6500 MountMgr (deferred)

f99bc000 f99c9000 VolSnap (deferred)

f99cc000 f99d4e00 disk (deferred)

f99dc000 f99e8200 CLASSPNP (deferred)

f99ec000 f99f6580 agp440 (deferred)

f9c1c000 f9c22200 PCIIDEX (deferred)

f9c24000 f9c28900 PartMgr (deferred)

f9dac000 f9daf000 BOOTVID (deferred)

f9db0000 f9db2480 compbatt (deferred)

f9db4000 f9db7700 BATTC (deferred)

f9db8000 f9dbab00 vmscsi (deferred)

f9e9c000 f9e9db80 kdcom (deferred)

f9e9e000 f9e9f100 WMILIB (deferred)

f9ea0000 f9ea1600 intelide (deferred)

kd> .sympath

Symbol search path is: <empty>

Expanded Symbol search path is: <empty>

kd> .symfix

kd> .sympath

Symbol search path is: srv*

Expanded Symbol search path is: cache*C:\Tools\DbgTools\sym;SRV*http://msdl.microsoft.com/download/symbols

kd> !process 0 0

**** NT ACTIVE PROCESS DUMP ****

NT symbols are incorrect, please fix symbols

kd> .reload

Connected to Windows XP 2600 x86 compatible target at (Tue Sep 8 22:34:41.661 2009 (GMT-3)), ptr64 FALSE

Loading Kernel Symbols

...........................

Loading User Symbols

kd> !process 0 0

**** NT ACTIVE PROCESS DUMP ****

NULL value in PsActiveProcess List<font color="#ff0000"> <strong><font color="#000000"> <-- Nenhum processo por aqui</font></strong></font>

kd> !thread0 0

No export thread0 found

kd> !thread 0 0

00000000: Unable to get thread content<font color="#000000">s</font><font color="#000000"> <strong> <-- Nenhuma thread também!</strong></font>

kd> r

eax=00000001 ebx=80087000 ecx=80548c74 edx=80548c44 esi=80087000 edi=00000000

eip=80526da8 esp=80548c60 ebp=80548de8 iopl=0 nv up ei pl nz na po nc

cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00000202

nt!RtlpBreakWithStatusInstruction:

80526da8 cc int 3

kd> k

ChildEBP RetAddr

80548c5c 80682baa nt!RtlpBreakWithStatusInstruction

80548de8 8068fd48 nt!ExpInitializeExecutive+0x350

80548e3c 8068d99b nt!KiInitializeKernel+0x3b2

00000000 00000000 nt!KiSystemStartup+0x2bf

kd> kv

ChildEBP RetAddr Args to Child

80548c5c 80682baa 00000001 80551920 00000000 nt!RtlpBreakWithStatusInstruction (FPO: 1,0,0)

80548de8 8068fd48 00000000 80087000 8003fc00 nt!ExpInitializeExecutive+0x350 (FPO: 2,93,4)

80548e3c 8068d99b 80551b80 80551920 80549100 nt!KiInitializeKernel+0x3b2 (FPO: Non-Fpo)

00000000 00000000 00000000 00000000 00000000 nt!KiSystemStartup+0x2bf

Todos os módulos carregados antes dessa fase são os drivers que tiveram seu Start definido em zero no registro. Todos os programadores que desenvolvem esses drivers gostariam de um dia poder usar o WinDbg. Mas não podem. Quem inicia a comunicação serial com o depurador é o kernel, que só recebe o controle do ntldr depois que os drivers básicos foram carregados.

Brincadeira. É claro que esses programadores usam o WinDbg, usam até demais. Mas só a partir desse ponto. Se algum problema evitar que o sistema chegue nessa fase, o desenvolvedor terá que usar métodos alternativos de depuração, como teste de mesa (risos incontroláveis).

De qualquer forma, estamos aí. Agora podemos depurar a criação de qualquer thread, qualquer processo, o carregamento de qualquer módulo, e a chamada a qualquer função do kernel.

Para depurar a criação de qualquer thread: coloque um breakpoint na função **PsCreateSystemThread**.

kd> bp PsCreateSystemThread

kd> bl

0 e 805c732e 0001 (0001) nt!PsCreateSystemThread

kd> g

Breakpoint 0 hit

nt!PsCreateSystemThread:

805c732e 8bff mov edi,edi

kd> k

ChildEBP RetAddr

805499a8 8069c17e nt!PsCreateSystemThread

80549a4c 8069c419 nt!PspInitPhase0+0x3f0

<strong>80549a58 8068509c nt!PsInitSystem+0x33</strong>

80549be8 80691f28 nt!ExpInitializeExecutive+0x742

80549c3c 8068fa9f nt!KiInitializeKernel+0x3b2

00000000 00000000 nt!KiSystemStartup+0x2bf

Para depurar a criação de qualquer processo: coloque um breakpoint na função **PspCreateProcess**, logo no começo. Será possível capturar a criação do processo System, o processo onde roda a primeira thread do kernel, que inicializa o resto dos componentes.

kd> bp PspCreateProcess

kd> bl

0 e 805c6a8c 0001 (0001) nt!PspCreateProcess

kd> g

Breakpoint 0 hit

nt!PspCreateProcess:

805c6a8c 681c010000 push 11Ch

kd> k

ChildEBP RetAddr

805499a0 8069c0dc nt!PspCreateProcess

<strong>80549a4c 8069c419 nt!PspInitPhase0+0x34e</strong>

80549a58 8068509c nt!PsInitSystem+0x33

80549be8 80691f28 nt!ExpInitializeExecutive+0x742

80549c3c 8068fa9f nt!KiInitializeKernel+0x3b2

00000000 00000000 nt!KiSystemStartup+0x2bf

E não é lindo ver que, após a chamada ao Process Manager o processo REALMENTE foi criado e está na lista de processos?

kd> !process 0 0

**** NT ACTIVE PROCESS DUMP ****

TYPE mismatch for process object at 8055a0d0

kd> gu

nt!PspInitPhase0+0x34e:

8069c0dc 85c0 test eax,eax

kd> !process 0 0

**** NT ACTIVE PROCESS DUMP ****

PROCESS 81bcc830 SessionId: none Cid: 0004 Peb: 00000000 ParentCid: 0000

DirBase: 00319000 ObjectTable: e1000cc0 HandleCount: 1.

<strong> Image: System Process</strong>

É nesse momento que percebemos que um processo, uma thread, um qualquer-coisa dentro do kernel não é nada mais nada menos que **um item em uma lista**. Quase tudo no kernel será um item numa lista com um monte de ponteiros referenciando outras estruturas. É isso que mantém a lógica e a coerência no sistema inteiro. Tudo isso é basicamente software, construído como castelos no ar.

O próximo processo a ser criado, logo após carregar todos os drivers, é o nosso amigo SMSS, o Gerenciador de Sessão, o primeiro pedacinho do iceberg que desponta no oceano. É ele que irá iniciar toda a "parte user-mode do kernel".

<blockquote>_Nota: Apesar de parecer contraditório, algumas partes do kernel são de fato implementadas em user mode. Os motivos podem variar, mas geralmente são maior segurança (código que não precisa rodar em um ring privilegiado) e desempenho (código que não precisa de muita prioridade)._</blockquote>

Breakpoint 0 hit

nt!PspCreateProcess:

805c6a8c 681c010000 push 11Ch

kd> kv

ChildEBP RetAddr Args to Child

f9dc365c 805c73e1 f9dc3858 001f0fff f9dc37c0 nt!PspCreateProcess (FPO: Non-Fpo)

f9dc36b0 805c745d f9dc3858 001f0fff f9dc37c0 nt!NtCreateProcessEx+0x77 (FPO: Non-Fpo)

f9dc36dc 8053d638 f9dc3858 001f0fff f9dc37c0 nt!NtCreateProcess+0x3d (FPO: Non-Fpo)

f9dc36dc 804fe155 f9dc3858 001f0fff f9dc37c0 nt!KiFastCallEntry+0xf8 (FPO: 0,0 TrapFrame @ f9dc3704)

f9dc3774 8069caa3 f9dc3858 001f0fff f9dc37c0 nt!ZwCreateProcess+0x11 (FPO: 8,0,0)

f9dc3818 80686681 <strong>f9dc38b0</strong> 00000040 00040000 nt!RtlCreateUserProcess+0x125 (FPO: Non-Fpo)

f9dc3dac 805c6160 80087000 00000000 00000000 nt!Phase1Initialization+0x1059 (FPO: Non-Fpo)

f9dc3ddc 80541dd2 80685628 80087000 00000000 nt!PspSystemThreadStartup+0x34 (FPO: Non-Fpo)

00000000 00000000 00000000 00000000 00000000 nt!KiThreadStartup+0x16

kd> !ustr <strong>f9dc38b0</strong>

<strong>String(58,520) at f9dc38b0: \SystemRoot\System32\smss.exe</strong>

kd> gu

kd> !process 0 0

**** NT ACTIVE PROCESS DUMP ****

PROCESS 81bcc830 SessionId: none Cid: 0004 Peb: 00000000 ParentCid: 0000

DirBase: 00319000 ObjectTable: e1000cc0 HandleCount: 52.

Image: System

PROCESS 81a2a430 SessionId: none Cid: 0218 Peb: 7ffd6000 ParentCid: 0004

DirBase: 08500020 ObjectTable: e1584818 HandleCount: 0.

<strong> Image: smss.exe</strong>

Como podemos ver, isso é muito divertido e muito extenso. Poderíamos ir para qualquer lado da evolução do boot. Talvez em artigos futuros daremos uma olhada no processo de logon de um usuário, o que nos obrigaria a ter uma leve noção de como o Windows autentica e autoriza as pessoas. ou talvez daremos uma passadinha no sistema de escalonamento de threads do kernel, um assunto pra lá de complicado e esotérico.

<blockquote>_Nota: Eu pessoalmente recomendo acompanhar o processo de boot descrito por Russinovich e depurar passo-a-passo um boot de verdade. Serão horas e mais horas de puro conhecimento empírico catalogado em seu cérebro-depurador._</blockquote>

Então até lá. Com licença que eu preciso ver a criação do System mais uma vez.

.reboot


# Aprendendo um terceiro idioma

2009-12-11 ^

Inspirado pelo texto de Chad Fowler que explica como o aprendizado de um segundo idioma mudou sua vida (sua língua-mãe é o inglês americano), resolvi descrever brevemente o que foi o momento da minha vida que decidi que iria tentar aprender Russo. Lógico, sem todo o folclore e a experiência de vida do autor do original.

Primeiro, meus motivos primários:

  • Estava escutando Tatu;
  • Costumava conversar pelo ICQ com uma amiga de Moscou (em inglês, apesar dela falar mais três ou quatro idiomas; e ela só tinha 19 anos!);
  • Estava querendo aproveitar parte do meu cérebro que fica inerte a maior parte do tempo porque meu emprego basicamente só mexe com coisas (quase) lógicas, como programação;
  • Achava uma língua bem bonita e exótica;
  • Gosto de jogar xadrez (o que isso tem a ver?).

Bom, no início comecei aprendendo o alfabeto. Alguns podem dizer que não há nenhum segredo no cirílico, e de fato não há. Porém, uma coisa é saber interpretar mais ou menos aquelas letrinhas derivadas do grego; outra completamente diferente é saber escrever em letra de base e em letra de mão todos os 33 caracteres, e ainda saber de cor o leiaute do teclado russo. Isso leva um pouco de tempo, e é bem divertido!

A partir daí passei cerca de seis meses apenas treinando a escrita e leitura do cirílico, aprendendo a diferença de som dependendo do contexto, um caderno a tiracolo no meio do ônibus, do trem e do metrô escrevendo infinitas linhas incompreensível provavelmente por 99% das pessoas que cruzavam meu caminho e olhavam curiosas.

Depois, o idioma em si. Nessa fase resolvi apelar para um curso disponível no mosteiro S. Bento ministrado por uma russa autência, de S. Petersburgo. Ela não falava muito bem português, o que para mim era um "plus".

Passei mais seis meses de curso com ela e com alguns textos que ia baixando da internet. Depois do curso comprei um curso em áudio e texto que fui acompanhando morosamente pelo resto dos dois anos que passei me aventurando pelo idioma.

No meio do caminho um amigo meu achou o podcast Spoonful of Russian, o que foi uma diversão só, especialmente pelo conhecimento cultural e musical do povo russo. Minha amiga também me enviou alguns CDs de bandas russas famosas, e fiquei especialmente encantando com Ivan Kupala, que até hoje escuto. Se trata de uma banda que pegou músicas do folclore russo e adaptou para os tempos atuais, mas cantado ainda por velhinhas e velhinhos que aparentemente parecem ter saído de uma aldeia dos Montes Urais.

O cinema e a BBC russa também representaram um instrumento de aprimoramento do listening do dia-a-dia. Uma coisa é escutar um russo falando devagar durante uma aula de declinação do futuro por aspecto. Outra coisa é ver alguém usando isso enquanto atravessa a rua conversando com um amigo no meio do barulho da cidade grande, ou uma mulher que mais parece uma metralhadora disparando 500 notícias de uma vez no podcast de um jornal da internet.

Infelizmente, essa fase esmaeceu. Agora estou muito interessado em finanças e isso fez com que o russo ficasse cada vez mais para trás. Se me pedir hoje para falar algo em russo vou conseguir apenas balbuciar as mais "comunzinhas", pois esqueci todo o resto. Foi perda de tempo? Claro que não! Foi uma experiência que mostra que podemos aprender qualquer coisa a qualquer hora, independente do quão estranho ou bizarro isso seja.


# Devaneio nerd rápido sobre aniversários

2009-12-14 ^

Hoje não é aniversário do blogue. É meu. Há exatos (sic) trinta anos nascia eu, essa pessoa que vos fala. Legal, não?

Beeeem legal. Tão legal quanto saber que o núcleo de um átomo representa 99,9% de sua masssa ou que uma borboleta bate duzentas mil vezes a asa por hora (só chutando, eu não sei realmente).

Ou saber, talvez, que o homem deciciu contar sua idade terrena através do número de vezes que esse planetinha gira em órbita de sua estrela. É o tipo de curiosidade mais que suficiente para comentar em sua quinquagésima festa de aniversário durante a rodinha do tédio (aquela em que você não tem  nada pra comentar porque já é a quinquagésima festinha do ano e as pessoas já estão cansadas de se verem).

Dr. House: Ah, my birthday. Normally I'd put on a festive hat and celebrate the fact that the Earth has circled the Sun one more time; I really didn't think it was going to make it this year, but darn it if it wasn't the little planet that could all over again. (1.06 The Socratic Method)

Do ponto de vista estatístico (sempre ela!), então, nem se fala. Na região onde eu moro vivem dez milhões de pessoas. Em uma conta de padaria, trinta mil fazem aniversário junto comigo. Na mesma hora, talvez umas mil. Bom, mas existem sessentas minutos em uma hora! Dessa forma, eu tenho a chance de ter nascido no mesmo minuto junto de cerca de vinte rebentos. Ah, e os segundos!?!? É verdade. Sou obrigado a torcer o nariz para o "fato" que tenho mais de 50% de chance de ser a única pessoa na região de São Paulo a ter nascido no mesmo segundo. Que especial! Bom, no mundo inteiro, é óbvio que não tenho nem um milissegundo pra mim, o que torna a data tão insignificativa quanto um alerta do orkut sobre a mesma.

* Se aplicarmos a mesma lógica matemática à morte e aos nascimentos chegaremos à inevitável (e óbvia) equação que a vida de um indivíduo para a nossa espécie hoje em dia vale menos que sua aposentadoria. Até porque, dessa imensa maioria de pessoas que nascem e morrem, a maioria é pobre e não tem condições de contribuir com uma boa parcela de gastos para o bem de nossa economia. A maioria é burra também, e pode contribuir menos ainda pelo valor agregado de nossa riqueza.

* Me foi contado que aniversários são eventos para celebrar a vida, principalmente do aniversariante. Ótimo! Isso quer dizer que a vida de cada um vale menos de 0,3% do ano inteiro, já que reservamos apenas um dia em 360 para confirmar que ainda estamos respirando.

Bom, esse artigo já devanou demais. E como meu objetivo nem foi chegar a uma conclusão, termino por aqui. Ah, para dar mais corda pra pensar: feliz natal!

PS: Mensagens de feliz aniversário serão devidamente descartadas. Ah, e feliz ano-novo pra você, também.


# Devaneio nerd rápido sobre profecias

2009-12-30 ^

Para quem já analisou os dados de uma tela azul sabe que, quando o Windows acha um culpado (vulgo driver) a data de sua compilação é exibida em um formato conhecido como **DateStamp** ou **TimeStamp**. Nesse formato o que temos é um número hexadecimal que segue o formato de tempo do Unix, que no caso é o número de segundos desde o dia primeiro de Janeiro de 1970. Isso, por curiosidade, nos dá uma margem de 140 anos antes dos número se repetirem se usarmos 32 bits nessa contagem.

O comando .formats do WinDbg nos consegue trazer desse número a hora exata em que determinado componente foi compilado. Se, por exemplo, um driver faltoso apresentou um DateStamp igual a 49EE9758, podemos concluir que ele foi compilado no dia 22 de abril de 2009, uma linda quarta-feira.

0:000> <font color="#0000ff">.formats 49EE9758</font>

Evaluate expression:

Hex: 00000000`49ee9758

Decimal: 1240373080

Octal: 0000000000011173513530

Binary: 00000000 00000000 00000000 00000000 01001001 11101110 10010111 01011000

Chars: ....I..X

<strong><font color="#0000ff"> Time: Wed Apr 22 01:04:40 2009</font></strong>

Float: low 1.95454e+006 high 0

Double: 6.12826e-315

Quando fazemos algo muitas vezes seguidas temos o hábito inconsciente de observar certas idiossincrasias dos dados que sempre vem e vão. No caso dos Date Stamps, sempre me veio o fato deles iniciarem com 4 e estarem prestes a "virar o contador" para 5.

Isso aos poucos - entre uma tela azul e outra - me deixou curioso a respeito de quando seria o dia fatídico em que teríamos o DateStamp 50000000, um número cabalístico em nosso sistema decimal. E, imaginem só:

0:000> <font color="#0000ff">.formats 50000000</font>

Evaluate expression:

Hex: 00000000`50000000

Decimal: 1342177280

Octal: 0000000000012000000000

Binary: 00000000 00000000 00000000 00000000 01010000 00000000 00000000 00000000

Chars: ....P...

<font color="#0000ff"> Time: Fri Jul 13 08:01:20 2012</font>

Float: low 8.58993e+009 high 0

Double: 6.63124e-315

Pois é, meus amigos. O DateStamp para a virada do contador Unix se fará numa manhã de sexta. Para ser preciso, uma sexta-feira 13.

Curioso, não? Mais curioso que isso, só sabendo que o ano que isso vai ocorrer é o igualmente fatídico 2012. Felizmente antes de dezembro.


<< >>