Repository: Gallopsled/pwntools

Issue:
disasm() doesn't work for context.arch='sparc64'
```
~$ python3
Python 3.8.3 (default, May 14 2020, 11:03:12)
[GCC 9.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from pwn import *
>>> context(arch='sparc')
>>> asm('nop')
b'\x01\x00\x00\x00'
>>> disasm(_)
'   0:   01 00 00 00     nop'
>>>
~$ python3 - DEBUG
Python 3.8.3 (default, May 14 2020, 11:03:12)
[GCC 9.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from pwn import *
>>> context(arch='sparc64')
>>> asm('nop')
[DEBUG] cpp -C -nostdinc -undef -P -I/home/kuba/.local/lib/python3.8/site-packages/pwnlib/data/includes /dev/stdin
[DEBUG] Assembling
    .section .shellcode,"awx"
    .global _start
    .global __start
    _start:
    __start:
    nop
[DEBUG] /usr/bin/sparc64-linux-gnu-as -EB -64 -o /tmp/pwn-asm-wq5065ol/step2 /tmp/pwn-asm-wq5065ol/step1
[DEBUG] /usr/bin/sparc64-linux-gnu-objcopy -j .shellcode -Obinary /tmp/pwn-asm-wq5065ol/step3 /tmp/pwn-asm-wq5065ol/step4
b'\x01\x00\x00\x00'
>>> disasm(_)
[DEBUG] /usr/bin/sparc64-linux-gnu-objcopy -I binary -O elf64-sparc -B sparc64 --set-section-flags .data=code --rename-section .data=.text -w -N * /tmp/pwn-disasm-0m495_e1/step1 /tmp/pwn-disasm-0m495_e1/step2
[ERROR] There was an error running ['/usr/bin/sparc64-linux-gnu-objcopy', '-I', 'binary', '-O', 'elf64-sparc', '-B', 'sparc64', '--set-section-flags', '.data=code', '--rename-section', '.data=.text', '-w', '-N', '*', '/tmp/pwn-disasm-0m495_e1/step1', '/tmp/pwn-disasm-0m495_e1/step2']:
    It had the exitcode 1.
    It had this on stdout:
    /usr/bin/sparc64-linux-gnu-objcopy: architecture sparc64 unknown

[ERROR] An error occurred while disassembling:
    b'\x01\x00\x00\x00'
    Traceback (most recent call last):
      File "/home/kuba/.local/lib/python3.8/site-packages/pwnlib/asm.py", line 785, in disasm
        _run(objcopy + [step1, step2])
      File "/home/kuba/.local/lib/python3.8/site-packages/pwnlib/asm.py", line 382, in _run
        log.error(msg)
      File "/home/kuba/.local/lib/python3.8/site-packages/pwnlib/log.py", line 417, in error
        raise PwnlibException(message % args)
    pwnlib.exception.PwnlibException: There was an error running ['/usr/bin/sparc64-linux-gnu-objcopy', '-I', 'binary', '-O', 'elf64-sparc', '-B', 'sparc64', '--set-section-flags', '.data=code', '--rename-section', '.data=.text', '-w', '-N', '*', '/tmp/pwn-disasm-0m495_e1/step1', '/tmp/pwn-disasm-0m495_e1/step2']:
    It had the exitcode 1.
    It had this on stdout:
    /usr/bin/sparc64-linux-gnu-objcopy: architecture sparc64 unknown

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/kuba/.local/lib/python3.8/site-packages/pwnlib/context/__init__.py", line 1441, in setter
    return function(*a, **kw)
  File "/home/kuba/.local/lib/python3.8/site-packages/pwnlib/asm.py", line 795, in disasm
    log.exception("An error occurred while disassembling:\n%s" % data)
  File "/home/kuba/.local/lib/python3.8/site-packages/pwnlib/asm.py", line 785, in disasm
    _run(objcopy + [step1, step2])
  File "/home/kuba/.local/lib/python3.8/site-packages/pwnlib/asm.py", line 382, in _run
    log.error(msg)
  File "/home/kuba/.local/lib/python3.8/site-packages/pwnlib/log.py", line 417, in error
    raise PwnlibException(message % args)
pwnlib.exception.PwnlibException: There was an error running ['/usr/bin/sparc64-linux-gnu-objcopy', '-I', 'binary', '-O', 'elf64-sparc', '-B', 'sparc64', '--set-section-flags', '.data=code', '--rename-section', '.data=.text', '-w', '-N', '*', '/tmp/pwn-disasm-0m495_e1/step1', '/tmp/pwn-disasm-0m495_e1/step2']:
It had the exitcode 1.
It had this on stdout:
/usr/bin/sparc64-linux-gnu-objcopy: architecture sparc64 unknown


>>> pwnlib.version
'4.1.1'
```


Discussion:
`mips64` and `powerpc64` are also affected.
On Sun, Jun 07, 2020 at 12:14:40PM -0700, Zach Riggle wrote:
> I can't reproduce this.
> 
> ```
> >>> context.clear(arch='sparc64')
> >>> asm('nop')
> '\x01\x00\x00\x00'
> ```
> ```
> >>> context.clear(arch='mips64')
> >>> asm('nop')
> [!] Could not find system include headers for mips64-linux
> '\x00\x00\x00\x00'
> ```
> ```
> >>> context.clear(arch='powerpc64')
> >>> asm('nop')
> '`\x00\x00\x00'
> ```

Please note that the issue happens when calling `disasm`, not `asm`.

@zachriggle Bump. I think you closed this by mistake.
Yep not sure what happened.  If you know why this is failing, a pull request would be nice!
Sorry, I didn't have the time to investigate this properly yet.

Resolving patch:
diff --git a/pwnlib/asm.py b/pwnlib/asm.py
--- a/pwnlib/asm.py
+++ b/pwnlib/asm.py
@@ -167,6 +167,9 @@ def which_binutils(util):
         'i386':   ['x86_64', 'amd64'],
         'i686':   ['x86_64', 'amd64'],
         'amd64':  ['x86_64', 'i386'],
+        'mips64': ['mips'],
+        'powerpc64': ['powerpc'],
+        'sparc64': ['sparc'],
     }.get(arch, [])
 
     # If one of the candidate architectures matches the native
@@ -347,10 +350,13 @@ def _bfdname():
 def _bfdarch():
     arch = context.arch
     convert = {
-    'i386': 'i386',
-    'amd64': 'i386:x86-64',
-    'thumb': 'arm',
-    'ia64': 'ia64-elf64'
+        'amd64':     'i386:x86-64',
+        'i386':      'i386',
+        'ia64':      'ia64-elf64',
+        'mips64':    'mips',
+        'powerpc64': 'powerpc',
+        'sparc64':   'sparc',
+        'thumb':     'arm',
     }
 
     if arch in convert:
@@ -752,6 +758,12 @@ def disasm(data, vma = 0, byte = True, offset = True, instructions = True):
         >>> print(disasm(unhex('656664676665400F18A4000000000051'), byte=0, arch='amd64'))
            0:   gs data16 fs data16 rex nop/reserved BYTE PTR gs:[eax+eax*1+0x0]
            f:   push   rcx
+        >>> print(disasm(unhex('01000000'), arch='sparc64'))
+           0:   01 00 00 00     nop
+        >>> print(disasm(unhex('60000000'), arch='powerpc64'))
+           0:   60 00 00 00     nop
+        >>> print(disasm(unhex('00000000'), arch='mips64'))
+           0:   00000000        nop
     """
     result = ''
 


Test patch: