Símbolos e módulos sintéticos (WinDbg / DbgEng)

Esta publicação se concentrará em módulos sintéticos e símbolos do mecanismo de depuração do Windows (mecanismo de depuração). Ou seja, sobre entidades que podem ser adicionadas artificialmente ao depurador para colorir endereços de memória.



Módulos sintéticos


Em geral, um módulo como parte de um mecanismo de depurador é uma certa área contínua da memória virtual: o endereço base do módulo (endereço do primeiro byte do arquivo projetado) e seu tamanho. Para cada tipo de depuração (análise ao vivo da depuração / despejo, modo do usuário / modo do kernel, etc.), o depurador possui seu próprio mecanismo para ler e manter atualizada a lista de módulos carregados. A maneira mais fácil de forçar a atualização da lista de módulos carregados é o comando .reload com a opção / s .


Se falamos, por exemplo, sobre a depuração ao vivo do processo no modo de usuário, a lista de módulos carregados é construída de acordo com três listas principais do carregador : uma lista de ordem de carregamento do módulo (InLoadOrderModuleList), uma lista de módulos na memória (InMemoryOrderModuleList) e uma lista de prioridades de inicialização (InInitializationOrderModuleList). Por um lado, não é ( quase ) nada que nos impede de pegar dados arbitrários (de um arquivo PE em disco, por exemplo) e marcá-los na memória para execução com nossas próprias mãos. Por outro lado, há muito tempo são conhecidas técnicas para remover DLL carregada com meios regulares das três listas de carregadores acima (ocultando o módulo).


Nos dois casos, ao depurar essa situação, será útil marcar a área do módulo oculto. Para isso, módulos sintéticos são adequados. Como um experimento prático, você pode simplesmente fazer o WinDbg soltar o módulo carregado de sua lista interna com o mesmo comando .reload, mas com a opção / u .


Além disso, na qualidade das listagens listadas, usarei a depuração usual do processo no modo de usuário (notepad.exe). Primeiro, lembre-se do endereço base do módulo ntdll (0x07ffa8a160000) e calcule seu tamanho (0x01e1000):


0:007> lm m ntdll Browse full module list start end module name 00007ffa`8a160000 00007ffa`8a341000 ntdll 0:007> ? 00007ffa`8a341000-00007ffa`8a160000 Evaluate expression: 1970176 = 00000000`001e1000 

Considere uma lista da função RtlFreeSid simples do módulo ntdll, que chama a função RtlFreeHeap deste módulo, lembrando simultaneamente os endereços dos caracteres RtlFreeSid e RtlFreeHeap (0x7ffa8a1cbc20 e 0x7ffa8a176df0):


 0:007> uf ntdll!RtlFreeSid ntdll!RtlFreeSid: 00007ffa`8a1cbc20 4053 push rbx 00007ffa`8a1cbc22 4883ec20 sub rsp,20h 00007ffa`8a1cbc26 488bd9 mov rbx,rcx 00007ffa`8a1cbc29 33d2 xor edx,edx 00007ffa`8a1cbc2b 65488b0c2560000000 mov rcx,qword ptr gs:[60h] 00007ffa`8a1cbc34 4c8bc3 mov r8,rbx 00007ffa`8a1cbc37 488b4930 mov rcx,qword ptr [rcx+30h] 00007ffa`8a1cbc3b e8b0b1faff call ntdll!RtlFreeHeap (00007ffa`8a176df0) 00007ffa`8a1cbc40 33c9 xor ecx,ecx 00007ffa`8a1cbc42 85c0 test eax,eax 00007ffa`8a1cbc44 480f45d9 cmovne rbx,rcx 00007ffa`8a1cbc48 488bc3 mov rax,rbx 00007ffa`8a1cbc4b 4883c420 add rsp,20h 00007ffa`8a1cbc4f 5b pop rbx 00007ffa`8a1cbc50 c3 ret 

Além disso, de acordo com a listagem, é fácil calcular o tamanho da função ntdll! RtlFreeSid:


 0:007> ? 00007ffa`8a1cbc51 - 0x07ffa8a1cbc20 Evaluate expression: 49 = 00000000`00000031 

E o tamanho da função ntdll! RtlFreeHeap não é importante para o nosso experimento, portanto, para simplificar, você pode considerar igual a um byte.


Agora simule ocultando o módulo ntdll:


 0:007> .reload /u ntdll Unloaded ntdll 

O campo deste trabalho com o endereço da função ntdll! RtlFreeSid no depurador não é tão informativo (e você já pode acessar o início da função apenas pelo endereço virtual):


 0:007> uf 00007ffa`8a1cbc20 00007ffa`8a1cbc20 4053 push rbx 00007ffa`8a1cbc22 4883ec20 sub rsp,20h 00007ffa`8a1cbc26 488bd9 mov rbx,rcx 00007ffa`8a1cbc29 33d2 xor edx,edx 00007ffa`8a1cbc2b 65488b0c2560000000 mov rcx,qword ptr gs:[60h] 00007ffa`8a1cbc34 4c8bc3 mov r8,rbx 00007ffa`8a1cbc37 488b4930 mov rcx,qword ptr [rcx+30h] 00007ffa`8a1cbc3b e8b0b1faff call 00007ffa`8a176df0 00007ffa`8a1cbc40 33c9 xor ecx,ecx 00007ffa`8a1cbc42 85c0 test eax,eax 00007ffa`8a1cbc44 480f45d9 cmovne rbx,rcx 00007ffa`8a1cbc48 488bc3 mov rax,rbx 00007ffa`8a1cbc4b 4883c420 add rsp,20h 00007ffa`8a1cbc4f 5b pop rbx 00007ffa`8a1cbc50 c3 ret 

Para adicionar um módulo sintético, você precisa chamar a interface do programa IDebugSymbols3 :: AddSyntheticModule . Simplesmente não existem comandos internos que permitam que esta chamada seja feita (tanto quanto eu sei). Mikhail I. Izmestev sugeriu que existe um mecanismo semelhante - o mesmo .reload , mas com os parâmetros de nome, endereço e tamanho: "Módulo = Endereço, Tamanho" (e, possivelmente, é implementado em módulos sintéticos).


.reload ntdll = 00007ff8`470e1000,001e1000
 0:007> .reload ntdll=00007ff8`470e1000,001e1000 *** WARNING: Unable to verify timestamp for ntdll *** ERROR: Module load completed but symbols could not be loaded for ntdll 0:007> uf 00007ff8`4714bc20 ntdll+0x6ac20: 00007ff8`4714bc20 4053 push rbx 00007ff8`4714bc22 4883ec20 sub rsp,20h 00007ff8`4714bc26 488bd9 mov rbx,rcx 00007ff8`4714bc29 33d2 xor edx,edx 00007ff8`4714bc2b 65488b0c2560000000 mov rcx,qword ptr gs:[60h] 00007ff8`4714bc34 4c8bc3 mov r8,rbx 00007ff8`4714bc37 488b4930 mov rcx,qword ptr [rcx+30h] 00007ff8`4714bc3b e8b0b1faff call ntdll+0x15df0 (00007ff8`470f6df0) 00007ff8`4714bc40 33c9 xor ecx,ecx 00007ff8`4714bc42 85c0 test eax,eax 00007ff8`4714bc44 480f45d9 cmovne rbx,rcx 00007ff8`4714bc48 488bc3 mov rax,rbx 00007ff8`4714bc4b 4883c420 add rsp,20h 00007ff8`4714bc4f 5b pop rbx 00007ff8`4714bc50 c3 ret 

Bem, vamos usar a extensão do depurador, e aqui o pykd virá em socorro . Na versão mais recente (no momento da redação), 0.3.4.3 , foram adicionadas funções para gerenciar módulos sintéticos: addSyntheticModule (...) (que é necessário no nosso caso) e removeSyntheticModule (...).


Usando o endereço base e o tamanho do módulo que foram salvos anteriormente, adicionamos informações sobre o módulo ntdll oculto ao depurador (em caso de erro, uma exceção será lançada; portanto, a execução silenciosa é um sinal de sucesso, os avisos de impressão podem ser ignorados):


 0:007> !py Python 2.7.15 (v2.7.15:ca079a3ea3, Apr 30 2018, 16:30:26) [MSC v.1500 64 bit (AMD64)] on win32 Type "help", "copyright", "credits" or "license" for more information. (InteractiveConsole) >>> addSyntheticModule(0x07ffa8a160000, 0x01e1000, 'ntdll') *** WARNING: Unable to verify timestamp for ntdll >>> exit() 

Agora a lista do desmontador tornou-se um pouco mais informativa:


 0:007> uf 00007ffa`8a1cbc20 ntdll+0x6bc20: 00007ffa`8a1cbc20 4053 push rbx 00007ffa`8a1cbc22 4883ec20 sub rsp,20h 00007ffa`8a1cbc26 488bd9 mov rbx,rcx 00007ffa`8a1cbc29 33d2 xor edx,edx 00007ffa`8a1cbc2b 65488b0c2560000000 mov rcx,qword ptr gs:[60h] 00007ffa`8a1cbc34 4c8bc3 mov r8,rbx 00007ffa`8a1cbc37 488b4930 mov rcx,qword ptr [rcx+30h] 00007ffa`8a1cbc3b e8b0b1faff call ntdll+0x16df0 (00007ffa`8a176df0) 00007ffa`8a1cbc40 33c9 xor ecx,ecx 00007ffa`8a1cbc42 85c0 test eax,eax 00007ffa`8a1cbc44 480f45d9 cmovne rbx,rcx 00007ffa`8a1cbc48 488bc3 mov rax,rbx 00007ffa`8a1cbc4b 4883c420 add rsp,20h 00007ffa`8a1cbc4f 5b pop rbx 00007ffa`8a1cbc50 c3 ret 

Mais precisamente, vemos que a função dentro do módulo ntdll chama outra função dentro do mesmo módulo.


Símbolos sintéticos


A listagem, depois de adicionar um módulo sintético, tornou-se mais informativa, mas ainda não tão eloqüente quanto o original. Faltam caracteres (no nosso caso, os nomes das funções RtlFreeSid e RtlFreeHeap). Para corrigir isso, é necessária uma chamada novamente, mas com uma interface de programa diferente - IDebugSymbols3 :: AddSyntheticSymbol . Pykd novamente pronto para nos ajudar com isso:


 0:007> !py Python 2.7.15 (v2.7.15:ca079a3ea3, Apr 30 2018, 16:30:26) [MSC v.1500 64 bit (AMD64)] on win32 Type "help", "copyright", "credits" or "license" for more information. (InteractiveConsole) >>> addSyntheticSymbol(0x07ffa8a1cbc20, 0x31, 'RtlFreeSid') <pykd.syntheticSymbol object at 0x0000014D47699518> >>> addSyntheticSymbol(0x07ffa8a176df0, 1, 'RtlFreeHeap') <pykd.syntheticSymbol object at 0x0000014D476994A8> >>> exit() 

O resultado é muito semelhante ao que estava ao usar os símbolos do arquivo ntdll pdb:


 0:007> uf 00007ffa`8a1cbc20 ntdll!RtlFreeSid: 00007ffa`8a1cbc20 4053 push rbx 00007ffa`8a1cbc22 4883ec20 sub rsp,20h 00007ffa`8a1cbc26 488bd9 mov rbx,rcx 00007ffa`8a1cbc29 33d2 xor edx,edx 00007ffa`8a1cbc2b 65488b0c2560000000 mov rcx,qword ptr gs:[60h] 00007ffa`8a1cbc34 4c8bc3 mov r8,rbx 00007ffa`8a1cbc37 488b4930 mov rcx,qword ptr [rcx+30h] 00007ffa`8a1cbc3b e8b0b1faff call ntdll!RtlFreeHeap (00007ffa`8a176df0) 00007ffa`8a1cbc40 33c9 xor ecx,ecx 00007ffa`8a1cbc42 85c0 test eax,eax 00007ffa`8a1cbc44 480f45d9 cmovne rbx,rcx 00007ffa`8a1cbc48 488bc3 mov rax,rbx 00007ffa`8a1cbc4b 4883c420 add rsp,20h 00007ffa`8a1cbc4f 5b pop rbx 00007ffa`8a1cbc50 c3 ret 

Características de entidades sintéticas


Vale ressaltar que a criação de símbolos sintéticos é permitida em quaisquer módulos existentes, e não apenas nos sintéticos. Ou seja, você pode adicionar símbolos aos módulos com arquivos pdb acessíveis e aos módulos para os quais não temos arquivos com informações de depuração. Mas você não pode criar caracteres fora dos módulos. Ou seja, para marcar um endereço de memória arbitrário fora dos limites dos módulos existentes, você deve primeiro criar um módulo sintético envolvente e, em seguida (se necessário, porque o nome do módulo pode ser suficiente para colorir ), criar um símbolo sintético nele.


Também vale ressaltar que módulos e símbolos sintéticos podem ser removidos com um movimento descuidado da mão:


  • recarregar os símbolos de depuração do módulo exclui todos os símbolos sintéticos deste módulo;
  • recarregar todos os módulos removerá todos os módulos sintéticos.

! synexts


Embora o uso do pykd seja conveniente na grande maioria dos casos (principalmente considerando a presença de um bootstarpper ), às vezes você pode entrar em uma situação em que precisará gastar um esforço considerável para usar o pykd. Por exemplo, uma vez eu precisei depurar da máquina host'ovy na qual o Windows XP funcionava. Como se viu, o pykd não suporta o XP há algum tempo, e eu precisava de caracteres e módulos sintéticos. Pareceu-me que, para esta tarefa, é mais fácil montar uma pequena extensão separada que resolverá uma gama estreita de tarefas necessárias do que restaurar o suporte completo do XP ao pykd. Como resultado, um projeto separado ! Synexts foi criado.


Essa é uma extensão simples que possui duas exportações disponíveis para o usuário:


  • ! synexts.addsymbol - cria um símbolo sintético em qualquer módulo existente;
  • ! synexts.addmodule - cria um módulo sintético na lista interna do mecanismo de depuração.

Para demonstrar, simulamos ocultando o módulo ntdll novamente:


 0:007> .reload /u ntdll Unloaded ntdll 0:007> uf 00007ffa`8a1cbc20 00007ffa`8a1cbc20 4053 push rbx 00007ffa`8a1cbc22 4883ec20 sub rsp,20h 00007ffa`8a1cbc26 488bd9 mov rbx,rcx 00007ffa`8a1cbc29 33d2 xor edx,edx 00007ffa`8a1cbc2b 65488b0c2560000000 mov rcx,qword ptr gs:[60h] 00007ffa`8a1cbc34 4c8bc3 mov r8,rbx 00007ffa`8a1cbc37 488b4930 mov rcx,qword ptr [rcx+30h] 00007ffa`8a1cbc3b e8b0b1faff call 00007ffa`8a176df0 00007ffa`8a1cbc40 33c9 xor ecx,ecx 00007ffa`8a1cbc42 85c0 test eax,eax 00007ffa`8a1cbc44 480f45d9 cmovne rbx,rcx 00007ffa`8a1cbc48 488bc3 mov rax,rbx 00007ffa`8a1cbc4b 4883c420 add rsp,20h 00007ffa`8a1cbc4f 5b pop rbx 00007ffa`8a1cbc50 c3 ret 

Novamente, restauramos o conhecimento do módulo e dos símbolos na forma de entidades sintéticas, mas já usando a extensão! Synexts:


 0:007> !synexts.addmodule ntdll C:\Windows\System32\ntdll.dll 00007ffa`8a160000 0x01e1000 *** WARNING: Unable to verify timestamp for C:\Windows\System32\ntdll.dll Synthetic module successfully added 0:007> !synexts.addsymbol RtlFreeSid 00007ffa`8a1cbc20 31 Synthetic symbol successfully added 0:007> !synexts.addsymbol RtlFreeHeap 00007ffa`8a176df0 1 Synthetic symbol successfully added 

Supõe-se que você já tenha copiado a biblioteca synexts.dll compilada (correspondente à profundidade de bits usada pelo WinDbg) para o diretório winext do depurador:


 0:007> .chain Extension DLL search Path: C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\WINXP;C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\winext;C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\winext\arcade;C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\pri;C:\Program Files (x86)\Windows Kits\10\Debuggers\x64;<…> Extension DLL chain: pykd.pyd: image 0.3.4.3, API 1.0.0, built Thu Jan 10 19:56:25 2019 [path: C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\winext\pykd.pyd] synexts: API 1.0.0, built Fri Jan 18 17:38:17 2019 [path: C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\winext\synexts.dll] <…> 

E, novamente, vemos o resultado da adição de caracteres sintéticos ao módulo sintético:


 0:007> uf 00007ffa`8a1cbc20 ntdll!RtlFreeSid: 00007ffa`8a1cbc20 4053 push rbx 00007ffa`8a1cbc22 4883ec20 sub rsp,20h 00007ffa`8a1cbc26 488bd9 mov rbx,rcx 00007ffa`8a1cbc29 33d2 xor edx,edx 00007ffa`8a1cbc2b 65488b0c2560000000 mov rcx,qword ptr gs:[60h] 00007ffa`8a1cbc34 4c8bc3 mov r8,rbx 00007ffa`8a1cbc37 488b4930 mov rcx,qword ptr [rcx+30h] 00007ffa`8a1cbc3b e8b0b1faff call ntdll!RtlFreeHeap (00007ffa`8a176df0) 00007ffa`8a1cbc40 33c9 xor ecx,ecx 00007ffa`8a1cbc42 85c0 test eax,eax 00007ffa`8a1cbc44 480f45d9 cmovne rbx,rcx 00007ffa`8a1cbc48 488bc3 mov rax,rbx 00007ffa`8a1cbc4b 4883c420 add rsp,20h 00007ffa`8a1cbc4f 5b pop rbx 00007ffa`8a1cbc50 c3 ret 

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


All Articles