For the process.libc property/function, the logic is currently:
def libc():
# <snip>
for lib, address in self.libs().items():
if 'libc.so' in lib or 'libc-' in lib:
e = ELF(lib)
e.address = address
return e
and:
def libs():
# <snip>
# Enumerate all of the libraries actually loaded right now.
maps = {}
for mapping in maps_raw:
path = mapping.path
if os.sep not in path: continue
path = os.path.realpath(path)
if path not in maps:
maps[path]=0
# <snip>
So if there is a libc-anywhere in the mappings path, it will be counted as libc. I happened to be running the binary in a path which contained that string, and the binary sometimes gets returned incorrectly. This happens especially often if the actual libc didn't yet have time to load into the process, and None should be returned.
minimal reproducable script:
from pwn import *
p = process(['./libc-nyanya/junior_formatter'])
print(f'\n\nLIBC: {p.libc}\n\n')
p.close()
Output:
─$ python mvp.py
[+] Starting local process './libc-nyanya/junior_formatter': pid 84213
[*] '/<snip>/libc-nyanya/junior_formatter'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
SHSTK: Enabled
IBT: Enabled
Stripped: No
LIBC: ELF('/<snip>/libc-nyanya/junior_formatter')
[*] Stopped process './libc-nyanya/junior_formatter' (pid 84213)
Proposed solution: Still check for '.so' in the second part of the if, and only check for the filename instead of the whole path.
For the
process.libc
property/function, the logic is currently:and:
So if there is a
libc-
anywhere in the mappings path, it will be counted as libc. I happened to be running the binary in a path which contained that string, and the binary sometimes gets returned incorrectly. This happens especially often if the actuallibc
didn't yet have time to load into the process, andNone
should be returned. minimal reproducable script:Output:
Proposed solution: Still check for '.so' in the second part of the if, and only check for the filename instead of the whole path.