Quantcast
Channel: Python extension for WinDbg
Viewing all articles
Browse latest Browse all 1625

Commented Unassigned: from_address crashes when accessing structure members [14118]

$
0
0
Hi,

First I'm starting a kernel-mode debugging and entering a process context, while the ntdll.dll is loaded at an address 00007fff`aa2b0000, which is shown below. The dd command verifies that this is indeed a PE file.

```
0: kd> lmi
00007fff`aa2b0000 00007fff`aa481000 ntdll (pdb symbols) ntdll.dll

0: kd> dd 00007fff`aa2b0000
00007fff`aa2b0000 00905a4d 00000003 00000004 0000ffff
00007fff`aa2b0010 000000b8 00000000 00000040 00000000
00007fff`aa2b0020 00000000 00000000 00000000 00000000
00007fff`aa2b0030 00000000 00000000 00000000 000000d8
00007fff`aa2b0040 0eba1f0e cd09b400 4c01b821 685421cd
00007fff`aa2b0050 70207369 72676f72 63206d61 6f6e6e61
00007fff`aa2b0060 65622074 6e757220 206e6920 20534f44
00007fff`aa2b0070 65646f6d 0a0d0d2e 00000024 00000000

```

The current installed version of Python after loading pykd extension:

```
0: kd> .load pykd
0: kd> !info

pykd bootstrapper version: 2.0.0.5

Installed python:

Version: Status: Image:
------------------------------------------------------------------------------
* 2.7 x86-64 Loaded C:\Windows\system32\python27.dll
3.5 x86-64 Loaded C:\Program Files\Python 3.5\python35.dll
```

Then I'm using ctypes by first creating the IMAGE_DOS_HEADER structure, then casting an address (where ntdll.dll is loaded) to an actual object, which works fine. However, when accessing the structure member the pykd crashes as presented below.

```
>>> import ctypes
>>> class IMAGE_DOS_HEADER(ctypes.Structure):
... _fields_ = [
... ("e_magic", ctypes.c_ushort),
... ("e_cblp", ctypes.c_ushort),
... ("e_cp", ctypes.c_ushort),
... ("e_crlc", ctypes.c_ushort),
... ("e_cparhdr", ctypes.c_ushort),
... ("e_minalloc", ctypes.c_ushort),
... ("e_maxalloc", ctypes.c_ushort),
... ("e_ss", ctypes.c_ushort),
... ("e_sp", ctypes.c_ushort),
... ("e_csum", ctypes.c_ushort),
... ("e_ip", ctypes.c_ushort),
... ("e_cs", ctypes.c_ushort),
... ("e_lfarlc", ctypes.c_ushort),
... ("e_ovno", ctypes.c_ushort),
... ("e_res", ctypes.c_ushort * 4),
... ("e_oemid", ctypes.c_ushort),
... ("e_oeminfo", ctypes.c_ushort),
... ("e_res2", ctypes.c_ushort * 10),
... ("e_lfanew", ctypes.c_ushort),
... ]
...
...
>>> dos = IMAGE_DOS_HEADER.from_address(0x00007fffaa2b0000)
>>> dos
<__main__.IMAGE_DOS_HEADER object at 0x00000000078B6B48>
>>> dos.e_lfanew
c0000005 Exception in C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\winext\pykd.py debugger extension.
PC: 00000000`1d1ac910 VA: 00007fff`aa2b003c R/W: 0 Parameter: 00000000`00000000
```

Does anybody know if there are any fixes regarding this issue, are you aware of this issue?
Comments: ** Comment from web user: evelyette **

Let me present how from_address can be used just fine. First start python.exe, then attach WinDbg to the process as presented below.

![Image](https://snag.gy/PTYGJ3.jpg)

Then issue __lmi__ command to get base addresses:

> 0:001> lmi
start end module name
00000000`1d000000 00000000`1d00a000 python (deferred)
00000000`1e000000 00000000`1e264000 python27 (deferred)
00000000`56bb0000 00000000`56c53000 MSVCR90 (deferred)
00000000`73720000 00000000`73728000 wow64cpu (deferred)
00000000`73730000 00000000`7378c000 wow64win (deferred)
00000000`73790000 00000000`737cf000 wow64 (deferred)
00000000`74b50000 00000000`74b5c000 CRYPTBASE (deferred)
00000000`74b60000 00000000`74bc0000 SspiCli (deferred)
00000000`74bc0000 00000000`74c61000 ADVAPI32 (deferred)
00000000`74ca0000 00000000`74cb9000 SECHOST (deferred)
00000000`75260000 00000000`752c0000 IMM32 (deferred)
00000000`755a0000 00000000`756a0000 USER32 (deferred)
00000000`756a0000 00000000`7576c000 MSCTF (deferred)
00000000`757b0000 00000000`758a0000 RPCRT4 (deferred)
00000000`75a50000 00000000`75a97000 KERNELBASE (deferred)
00000000`75b40000 00000000`75b4a000 LPK (deferred)
00000000`75b90000 00000000`75be7000 SHLWAPI (deferred)
00000000`75c10000 00000000`75d20000 KERNEL32 (deferred)
00000000`76030000 00000000`760c0000 GDI32 (deferred)
00000000`760d0000 00000000`7616d000 USP10 (deferred)
00000000`76170000 00000000`76dbb000 SHELL32 (deferred)
00000000`76dc0000 00000000`76e6c000 msvcrt (deferred)
00000000`77090000 00000000`7723a000 ntdll (pdb symbols) C:\Windows\SYSTEM32\ntdll.dll
00000000`77270000 00000000`773f0000 ntdll_77270000 (deferred)

Then continue the process with __g__ in order to let python.exe continue and import ctypes, define IMAGE_DOS_HEADER and form an object from the address where ntdll.dll was loaded.

```
>>> import ctypes
>>> class IMAGE_DOS_HEADER(ctypes.Structure):
... _fields_ = [
... ("e_magic", ctypes.c_ushort),
... ("e_cblp", ctypes.c_ushort),
... ("e_cp", ctypes.c_ushort),
... ("e_crlc", ctypes.c_ushort),
... ("e_cparhdr", ctypes.c_ushort),
... ("e_minalloc", ctypes.c_ushort),
... ("e_maxalloc", ctypes.c_ushort),
... ("e_ss", ctypes.c_ushort),
... ("e_sp", ctypes.c_ushort),
... ("e_csum", ctypes.c_ushort),
... ("e_ip", ctypes.c_ushort),
... ("e_cs", ctypes.c_ushort),
... ("e_lfarlc", ctypes.c_ushort),
... ("e_ovno", ctypes.c_ushort),
... ("e_res", ctypes.c_ushort * 4),
... ("e_oemid", ctypes.c_ushort),
... ("e_oeminfo", ctypes.c_ushort),
... ("e_res2", ctypes.c_ushort * 10),
... ("e_lfanew", ctypes.c_ushort),
... ]
...
...
>>> dos = IMAGE_DOS_HEADER.from_address(0x77090000)
>>> dos
<__main__.IMAGE_DOS_HEADER object at 0x02155080>
>>> dos.e_lfanew
224
>>>
```

As you can see, the __e_lfanew__ was printed as expected, so no issues there. The reason why I do not want to use __typedVar__ is the fact that it relies on the current symbols managed by WinDbg. If the symbols are not present, WinDbg will download them at runtime, import them into WinDbg from where pykd can use them. However, if WinDbg doesn't have access to the PDB symbols due to symbols not being present (PDBs are sometimes not published immediately by Microsoft, which means this won't work), or if the WinDbg's sympath is configured incorrectly (I know, the user is to blame here, but bare with me).

Other than that, from_buffer should work the same as from_address, since ctypes provides the following functions to get object instances. Although there is some confusion about the actual usecase, since the from_buffer/from_buffer_copy return a __ctypes instance__, while from_address returns a __ctypes type instance__.

* __from_buffer__: This method returns a __ctypes instance__ that shares the buffer of the source object.
* __from_buffer_copy__: This method creates a __ctypes instance__, copying the buffer from the source object buffer which must be readable.
* __from_address__: This method returns a __ctypes type instance__ using the memory specified by address which must be an integer.

Can you elaborate what is the exact difference between the __ctypes instance__ and__ctypes type instance__, which seems to be important here. Also, why does the ctypes example I present even work then, if from_address is not supposed to be used like that?


Viewing all articles
Browse latest Browse all 1625

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>