ELF Parsing
Python Version
There are multiple ways to parse the Python version from an ELF file that we utilize in Perforator.
Py_Version
Symbol
There is a Py_Version
symbol in the ELF file. This is a global variable that stores 4 bytes of the Python version: the first byte is the major version, the second byte is the minor version, the third byte is the micro version, and the fourth byte is the release level.
Py_GetVersion
Function
Disassemble For CPython versions earlier than 3.11, we can disassemble the Py_GetVersion
function to get the version.
There is this line of code inside the Py_GetVersion
function:
PyOS_snprintf(version, sizeof(version), buildinfo_format, PY_VERSION, Py_GetBuildInfo(), Py_GetCompiler());
Perforator extracts the 4th argument, which is a pointer to a constant global string with the Python version in the .rodata
section.
Then, we can read the version as a string from this address in the binary.
_PyRuntime
Global Variable
There is a _PyRuntime
symbol in the .dynsym
section which can be used to obtain the address of the _PyRuntime
global variable.
PyThreadState_GetCurrent
Disassembling The PyThreadState_GetCurrent
function can be disassembled to get the offset of _PyThreadState_Current
in the Thread Local Image for Python Thread State collection.