Repository: Gallopsled/pwntools

Issue:
`ROP` doesn't work when ELF path is bytestring
```py
from pwn import ELF, ROP

e = ELF(b"/bin/whoami")
ROP(e)
```

`elf.path` gets passed down to ROPgadget, then argparse, which performs `arg_string[0] in self.prefix_chars`, causing this error:
```
  File "/tmp/poc.py", line 4, in <module>
    ROP(e)
  File ".../pwnlib/rop/rop.py", line 598, in __init__
    self.__load()
  File ".../pwnlib/rop/rop.py", line 1290, in __load
    args = ropgadget.args.Args().getArgs()
  File ".../ropgadget/args.py", line 25, in __init__
    self.__parse(arguments, custom_arguments_provided)
  File ".../ropgadget/args.py", line 101, in __parse
    self.__args = parser.parse_args(arguments)
  File "/usr/lib/python3.10/argparse.py", line 1826, in parse_args
    args, argv = self.parse_known_args(args, namespace)
  File "/usr/lib/python3.10/argparse.py", line 1859, in parse_known_args
    namespace, args = self._parse_known_args(args, namespace)
  File "/usr/lib/python3.10/argparse.py", line 1903, in _parse_known_args
    option_tuple = self._parse_optional(arg_string)
  File "/usr/lib/python3.10/argparse.py", line 2194, in _parse_optional
    if not arg_string[0] in self.prefix_chars:
TypeError: 'in <string>' requires string as left operand, not int

```

For context, this was discovered with this code:
```py
e = ELF(path)
libc = ELF(e.runpath + b'./libc.so.6')
r = ROP(libc)
```
As `runpath` is a bytestring, the quickest way to get a valid path was to append a bytestring, leading to this confusing error.

I was able to reproduce this on Docker.
`ROP` doesn't work when ELF path is bytestring
```py
from pwn import ELF, ROP

e = ELF(b"/bin/whoami")
ROP(e)
```

`elf.path` gets passed down to ROPgadget, then argparse, which performs `arg_string[0] in self.prefix_chars`, causing this error:
```
  File "/tmp/poc.py", line 4, in <module>
    ROP(e)
  File ".../pwnlib/rop/rop.py", line 598, in __init__
    self.__load()
  File ".../pwnlib/rop/rop.py", line 1290, in __load
    args = ropgadget.args.Args().getArgs()
  File ".../ropgadget/args.py", line 25, in __init__
    self.__parse(arguments, custom_arguments_provided)
  File ".../ropgadget/args.py", line 101, in __parse
    self.__args = parser.parse_args(arguments)
  File "/usr/lib/python3.10/argparse.py", line 1826, in parse_args
    args, argv = self.parse_known_args(args, namespace)
  File "/usr/lib/python3.10/argparse.py", line 1859, in parse_known_args
    namespace, args = self._parse_known_args(args, namespace)
  File "/usr/lib/python3.10/argparse.py", line 1903, in _parse_known_args
    option_tuple = self._parse_optional(arg_string)
  File "/usr/lib/python3.10/argparse.py", line 2194, in _parse_optional
    if not arg_string[0] in self.prefix_chars:
TypeError: 'in <string>' requires string as left operand, not int

```

For context, this was discovered with this code:
```py
e = ELF(path)
libc = ELF(e.runpath + b'./libc.so.6')
r = ROP(libc)
```
As `runpath` is a bytestring, the quickest way to get a valid path was to append a bytestring, leading to this confusing error.

I was able to reproduce this on Docker.


Discussion:

Resolving patch:
diff --git a/pwnlib/elf/elf.py b/pwnlib/elf/elf.py
--- a/pwnlib/elf/elf.py
+++ b/pwnlib/elf/elf.py
@@ -225,7 +225,7 @@ def __init__(self, path, checksec=True):
         super(ELF,self).__init__(self.mmap)
 
         #: :class:`str`: Path to the file
-        self.path = os.path.abspath(path)
+        self.path = packing._need_text(os.path.abspath(path))
 
         #: :class:`str`: Architecture of the file (e.g. ``'i386'``, ``'arm'``).
         #:


Test patch: