Skip to content

Conversation

@ivonastojanovic
Copy link

@ivonastojanovic ivonastojanovic commented Mar 26, 2025

This PR introduces the following changes for Windows:

  • Locate PyRuntime address

  • Read memory from the target process

  • Write to the target process

@ivonastojanovic ivonastojanovic changed the title External debugger windows support External debugger Windows support Mar 27, 2025
@ivonastojanovic ivonastojanovic marked this pull request as ready for review March 27, 2025 13:42
return 0;
HANDLE hProcSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, handle->pid);
if (hProcSnap == INVALID_HANDLE_VALUE) {
PyErr_SetString(PyExc_PermissionError, "Unable to create module snapshot. Check permissions or PID.");
Copy link
Collaborator

@godlygeek godlygeek Mar 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should test what happens when attaching from a 32-bit process to a 64-bit one, and vice versa.

It seems that creating a snapshot of a 64-bit process from a 32-bit one will fail:

If the specified process is a 64-bit process and the caller is a 32-bit process, this function fails and the last error code is ERROR_PARTIAL_COPY (299).

And I think that our snapshot of a 32-bit process from a 64-bit one will contain no modules, and so our Module32FirstW call will immediately return false, because we're not setting TH32CS_SNAPMODULE32. If that is the behavior, I think that's fine, but we should manually test it to confirm (we won't be able to have automated tests for this case, but we should be able to test it manually).

I don't care if attaching to a remote process of a different bittedness actually works, I just want to make sure that it doesn't accidentally write to the wrong spot and corrupt memory.

return NULL;
}

IMAGE_SECTION_HEADER* pSection_header = (IMAGE_SECTION_HEADER*)(mapView + pDOSHeader->e_lfanew + sizeof(IMAGE_NT_HEADERS));
Copy link
Collaborator

@godlygeek godlygeek Mar 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See the comment below about attaching to a 32-bit process from a 64-bit one or vice versa. If we did allow that, I think sizeof(IMAGE_NT_HEADERS) would be wrong, since that is defined to be either IMAGE_NT_HEADERS32 or IMAGE_NT_HEADERS64 at compile time.

As long as we only allow attaching 32-bit to 32-bit or 64-bit to 64-bit, this seems fine, but if we decide to allow sending commands from a 64-bit process to a 32-bit one, this would look at the wrong offset, I think.

ivonastojanovic and others added 5 commits March 28, 2025 18:14
The PyRuntime section can be found in either the main executable (python.exe) or the Python DLL (pythonXY.dll, where X and Y represent the major and minor version numbers). Scan the modules of the process to locate the PyRuntime address in one of these modules.
Ensure that the caller and target processes have matching architectures
before proceeding. Attaching to a 64-bit process from a 32-bit process
will fail when using CreateToolhelp32Snapshot, and attempting to attach
to a 32-bit process from a 64-bit process may cause issues during PE
file parsing. To avoid potential errors abort the operation if the
architectures differ.
This reverts commit 746ecfc.

That commit isn't correct. It conflates the return from `IsWow64Process`
(whether the process is running under 32-bit emulation on a 64-bit
process) with whether the process is 64-bit. A 32-bit process on 32-bit
Windows would have `IsWow64Process` set our `isWow64` flag to `FALSE`,
and we'd then incorrectly return `TRUE` from `is_process64Bit`.
@godlygeek godlygeek merged commit 6076548 into pablogsal:main Mar 28, 2025
19 of 35 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants