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

Esta publicación se centrará en los módulos sintéticos y los símbolos del motor de depuración de Windows (motor de depuración). Es decir, sobre entidades que pueden agregarse artificialmente al depurador para colorear direcciones de memoria.



Módulos sintéticos


En general, un módulo como parte de un motor de depuración es una cierta área continua de memoria virtual: la dirección base del módulo (dirección del primer byte del archivo proyectado) y su tamaño. Para cada tipo de depuración (depuración en vivo / análisis de volcado, modo de usuario / modo kernel, etc.), el depurador tiene su propio mecanismo para leer y mantener actualizada la lista de módulos cargados. La forma más fácil de forzar la actualización de la lista de módulos cargados es el comando .reload con la opción / s .


Si hablamos, por ejemplo, de la depuración en vivo del proceso en modo usuario, la lista de módulos cargados se construye de acuerdo con tres listas principales del cargador : una lista de orden de carga de módulos (InLoadOrderModuleList), una lista de módulos en memoria (InMemoryOrderModuleList) y una lista de prioridad de inicialización (InInitializationOrderModuleList). Por un lado, no hay ( casi ) nada que nos impida tomar datos arbitrarios (de un archivo PE en el disco, por ejemplo) y marcarlos en la memoria para su ejecución con nuestras propias manos. Por otro lado, las técnicas para eliminar DLL cargadas con medios regulares de las tres listas de cargadores anteriores (ocultar el módulo) se conocen desde hace mucho tiempo.


En ambos casos, al depurar esta situación, será útil marcar el área del módulo oculto. Para esto, los módulos sintéticos son adecuados. Como experimento práctico, simplemente puede hacer que WinDbg suelte el módulo cargado de su lista interna con el mismo comando .reload, pero con la opción / u .


Además, en la calidad de los listados enumerados, utilizaré la depuración habitual del proceso del modo de usuario (notepad.exe). Primero, recuerde la dirección base del módulo ntdll (0x07ffa8a160000) y calcule su tamaño (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 una lista de la función RtlFreeSid simple del módulo ntdll, que llama a la función RtlFreeHeap de este módulo, recordando simultáneamente las direcciones de los caracteres RtlFreeSid y RtlFreeHeap (0x7ffa8a1cbc20 y 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 

Además, de acuerdo con la lista, es fácil calcular el tamaño de la función ntdll! RtlFreeSid:


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

Y el tamaño de la función ntdll! RtlFreeHeap no es importante para nuestro experimento, por lo que, por simplicidad, puede tomarlo igual a un byte.


Ahora simule ocultar el módulo ntdll:


 0:007> .reload /u ntdll Unloaded ntdll 

El campo de este trabajo con la dirección de la función ntdll! RtlFreeSid en el depurador no es tan informativo (y ya puede acceder al comienzo de la función solo por la dirección 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 agregar un módulo sintético, debe llamar a la interfaz del programa IDebugSymbols3 :: AddSyntheticModule . Simplemente no hay comandos integrados que permitan realizar esta llamada (que yo sepa). Mikhail I. Izmestev sugirió que existe un mecanismo similar: el mismo .reload , pero con el nombre, la dirección y los parámetros de tamaño: "Módulo = Dirección, Tamaño" (y, posiblemente, se implementa en 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 

Bueno, usaremos la extensión del depurador, y aquí Pykd vendrá al rescate . En la última versión (en el momento de la redacción) 0.3.4.3 , se agregaron funciones para administrar módulos sintéticos: addSyntheticModule (...) (que es necesario en nuestro caso) y removeSyntheticModule (...).


Usando la dirección base y el tamaño del módulo que se guardó previamente, agregamos información sobre el módulo ntdll oculto al depurador (en caso de error, se generará una excepción, por lo tanto, la ejecución silenciosa es una señal de éxito, las advertencias de impresión pueden ignorarse):


 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() 

Ahora la lista de desensambladores se ha vuelto un poco más 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 

Más precisamente, vemos que la función dentro del módulo ntdll llama a otra función dentro del mismo módulo.


Símbolos sintéticos


El listado, después de agregar un módulo sintético, se ha vuelto más informativo, pero aún no tan elocuente como el original. Carece de caracteres (en nuestro caso, los nombres de las funciones RtlFreeSid y RtlFreeHeap). Para solucionar esto, se requiere una llamada nuevamente, pero de una interfaz de programa diferente: IDebugSymbols3 :: AddSyntheticSymbol . Pykd otra vez listo para ayudarnos con esto:


 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() 

El resultado es muy similar al que se usaba al usar los símbolos del archivo 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 las entidades sintéticas.


Vale la pena señalar que la creación de símbolos sintéticos está permitida en cualquier módulo existente, y no solo en los sintéticos. Es decir, puede agregar símbolos tanto a módulos con archivos pdb accesibles como a módulos para los que no tenemos archivos con información de depuración. Pero no puedes crear personajes fuera de los módulos. Es decir, para marcar una dirección de memoria arbitraria fuera de los límites de los módulos existentes, primero debe crear un módulo sintético envolvente y luego (si es necesario, porque el nombre del módulo puede ser suficiente para colorear ) crear un símbolo sintético en él.


También vale la pena mencionar que los módulos y símbolos sintéticos se pueden quitar con un movimiento descuidado de la mano:


  • recargar los símbolos de depuración del módulo elimina todos los símbolos sintéticos de este módulo;
  • La recarga de todos los módulos eliminará todos los módulos sintéticos.

! synexts


Aunque el uso de pykd es conveniente en la gran mayoría de los casos (especialmente teniendo en cuenta la presencia de un bootstarpper ), a veces puede entrar en una situación en la que tendrá que gastar un esfuerzo considerable para usar pykd. Por ejemplo, una vez necesitaba depurar desde la máquina host'ovy en la que trabajaba Windows XP. Al final resultó que, pykd no ha sido compatible con XP durante bastante tiempo, y necesitaba caracteres y módulos sintéticos. Me pareció que para esta tarea es más fácil ensamblar una pequeña extensión separada que resolverá un rango estrecho de tareas necesarias que restaurar el soporte completo de XP para pykd. Como resultado, se creó un proyecto separado ! Synexts .


Esta es una extensión simple que tiene dos exportaciones disponibles para el usuario:


  • ! synexts.addsymbol: crea un símbolo sintético en cualquier módulo existente;
  • ! synexts.addmodule: crea un módulo sintético en la lista interna del motor de depuración.

Para demostrarlo, simulamos ocultar nuevamente el módulo ntdll:


 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 

Nuevamente, restauramos el conocimiento del módulo y los símbolos en forma de entidades sintéticas, pero ya utilizamos la extensión! 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 

Se supone que ya ha copiado la biblioteca compilada synexts.dll (correspondiente a la profundidad de bits utilizada por WinDbg) en el directorio winext del 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] <…> 

Y nuevamente vemos el resultado de agregar caracteres sintéticos al 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/es436644/


All Articles