@@ -94,6 +94,30 @@ The following is an example implementation::
94
94
return base_address + section_offset
95
95
96
96
97
+ On Linux systems, there are two main approaches to read memory from another
98
+ process. The first is through the ``/proc `` filesystem, specifically by reading from
99
+ ``/proc/[pid]/mem `` which provides direct access to the process's memory. This
100
+ requires appropriate permissions - either being the same user as the target
101
+ process or having root access. The second approach is using the
102
+ ``process_vm_readv() `` system call which provides a more efficient way to copy
103
+ memory between processes. While ptrace's ``PTRACE_PEEKTEXT `` operation can also be
104
+ used to read memory, it is significantly slower as it only reads one word at a
105
+ time and requires multiple context switches between the tracer and tracee
106
+ processes.
107
+
108
+ For parsing ELF sections, the process involves reading and interpreting the ELF
109
+ file format structures from the binary file on disk. The ELF header contains a
110
+ pointer to the section header table. Each section header contains metadata about
111
+ a section including its name (stored in a separate string table), offset, and
112
+ size. To find a specific section like .PyRuntime, you need to walk through these
113
+ headers and match the section name. The section header then provdes the offset
114
+ where that section exists in the file, which can be used to calculate its
115
+ runtime address when the binary is loaded into memory.
116
+
117
+ You can read more about the ELF file format in the `ELF specification
118
+ <https://en.wikipedia.org/wiki/Executable_and_Linkable_Format> `_.
119
+
120
+
97
121
.. rubric :: macOS (Mach-O)
98
122
99
123
To find the ``PyRuntime `` structure on macOS:
@@ -134,6 +158,29 @@ The following is an example implementation::
134
158
# Step 5: Compute the PyRuntime address in memory
135
159
return base_address + section_offset
136
160
161
+ On macOS, accessing another process's memory requires using Mach-O specific APIs
162
+ and file formats. The first step is obtaining a ``task_port `` handle via
163
+ ``task_for_pid() ``, which provides access to the target process's memory space.
164
+ This handle enables memory operations through APIs like
165
+ ``mach_vm_read_overwrite() ``.
166
+
167
+ The process memory can be examined using ``mach_vm_region() `` to scan through the
168
+ virtual memory space, while ``proc_regionfilename() `` helps identify which binary
169
+ files are loaded at each memory region. When the Python binary or library is
170
+ found, its Mach-O headers need to be parsed to locate the ``PyRuntime `` structure.
171
+
172
+ The Mach-O format organizes code and data into segments and sections. The
173
+ ``PyRuntime `` structure lives in a section named ``__PyRuntime `` within the
174
+ ``__DATA `` segment. The actual runtime address calculation involves finding the
175
+ ``__TEXT `` segment which serves as the binary's base address, then locating the
176
+ ``__DATA `` segment containing our target section. The final address is computed by
177
+ combining the base address with the appropriate section offsets from the Mach-O
178
+ headers.
179
+
180
+ Note that accessing another process's memory on macOS typically requires
181
+ elevated privileges - either root access or special security entitlements
182
+ granted to the debugging process.
183
+
137
184
138
185
.. rubric :: Windows (PE)
139
186
@@ -180,6 +227,27 @@ The following is an example implementation::
180
227
return base_address + section_rva
181
228
182
229
230
+ On Windows, accessing another process's memory requires using the Windows API
231
+ functions like ``CreateToolhelp32Snapshot() `` and ``Module32First()/Module32Next() ``
232
+ to enumerate loaded modules. The ``OpenProcess() `` function provides a handle to
233
+ access the target process's memory space, enabling memory operations through
234
+ ``ReadProcessMemory() ``.
235
+
236
+ The process memory can be examined by enumerating loaded modules to find the
237
+ Python binary or DLL. When found, its PE headers need to be parsed to locate the
238
+ ``PyRuntime `` structure.
239
+
240
+ The PE format organizes code and data into sections. The ``PyRuntime `` structure
241
+ lives in a section named "PyRuntim" (truncated from "PyRuntime" due to PE's
242
+ 8-character name limit). The actual runtime address calculation involves finding
243
+ the module's base address from the module entry, then locating our target
244
+ section in the PE headers. The final address is computed by combining the base
245
+ address with the section's virtual address from the PE section headers.
246
+
247
+ Note that accessing another process's memory on Windows typically requires
248
+ appropriate privileges - either administrative access or the ``SeDebugPrivilege ``
249
+ privilege granted to the debugging process.
250
+
183
251
184
252
Reading _Py_DebugOffsets
185
253
========================
0 commit comments