Skip to content

fix_iat crashes with access violation (null deref) on pyscylla 0.11.1, fixed by 0.11.2 #8

Description

@w3K-one

I ran into a reproducible crash in fix_iat while using pyscylla through unlicense (ergrelet/unlicense) to fix imports on a manually dumped 32-bit process.

What happened

pyscylla.fix_iat() crashes the host process with an access violation (0xc0000005) instead of raising a Python exception. This happened consistently with pyscylla 0.11.1 on a specific dump (a WinLicense 3.x protected 32-bit Delphi binary, IAT recovered by unlicense, OEP chosen to point at the real entry point rather than a wrapper).

I attached WinDbg to a crash dump and found the actual fault:

movzx ebx, word ptr [eax+6]

with eax = 0 at the time of the crash, so this is a straightforward null pointer dereference. The call stack shows it happening several frames deep inside the native module, reached from fix_iat's C++ implementation, not from anything in the Python binding layer itself.

Faulting module: pyscylla.cp311-win32.pyd
Fault offset: 0x00019b69

Good news

I rebuilt pyscylla from the current main branch of this repo (which is what's published as 0.11.2 on PyPI) and the same dump no longer crashes. fix_iat completes cleanly and produces a correct import table. So whatever changed between 0.11.1 and 0.11.2 already fixes this, at least for my repro case.

I didn't get to bisecting exactly which commit fixed it before I had to move on, so I can't point at a specific line. Filing this mainly so there's a record of the crash signature and the confirmation that it's fixed in a later version, in case anyone else hits the same offset/symptom on an older pinned version (unlicense's own poetry.lock was still pinned to 0.11.1 when I hit this).

Repro environment

  • 32-bit Python 3.11, Windows
  • pyscylla 0.11.1 (crashes) vs current main / 0.11.2 (does not crash)
  • Called via unlicense's fix_and_dump_pe -> dump_pe -> pyscylla.fix_iat
  • Target binary: a manually unpacked WinLicense 3.x protected 32-bit executable, OEP forced to a real Delphi entry point rather than the packer's detected transition point

I can't share the target binary, but happy to answer questions about the repro setup if useful.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions