Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

can't read from mapped peripheral memory range #131

Open
Squirre17 opened this issue Dec 27, 2024 · 2 comments
Open

can't read from mapped peripheral memory range #131

Squirre17 opened this issue Dec 27, 2024 · 2 comments

Comments

@Squirre17
Copy link

import os
import subprocess

from avatar2 import *
from avatar2.peripherals import AvatarPeripheral
import struct


filename = 'a.out'
GDB_PORT = 1234          

# This is a bare minimum elf-file, gracefully compiled from 
# https://github.com/abraithwaite/teensy
tiny_elf = (b'\x7f\x45\x4c\x46\x02\x01\x01\x00\xb3\x2a\x31\xc0\xff\xc0\xcd\x80'
            b'\x02\x00\x3e\x00\x01\x00\x00\x00\x08\x00\x40\x00\x00\x00\x00\x00'
            b'\x40\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
            b'\x00\x00\x00\x00\x40\x00\x38\x00\x01\x00\x00\x00\x00\x00\x00\x00'
            b'\x01\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
            b'\x00\x00\x40\x00\x00\x00\x00\x00\x00\x00\x40\x00\x00\x00\x00\x00'
            b'\x78\x00\x00\x00\x00\x00\x00\x00\x78\x00\x00\x00\x00\x00\x00\x00'
            b'\x00\x00\x20\x00\x00\x00\x00\x00')
            
            

# Hello world shellcode
shellcode = (b'\x68\x72\x6c\x64\x21\x48\xb8\x48\x65\x6c\x6c\x6f\x20\x57\x6f\x50'
             b'\x48\x89\xef\x48\x89\xe6\x6a\x0c\x5a\x6a\x01\x58\x0f\x05')
          

class HelloWorldPeripheral(AvatarPeripheral):
    def hw_read(self, offset, size):
        # Read from hello_world and cycle the buffer
        ret = self.hello_world[:size]
        self.hello_world = self.hello_world[size:] + self.hello_world[:size]
        
        # Convert the return value to an integer (py2/py3-compatible)
        s2fmt = {1: 'B', 2: 'H', 4: 'I', 8: 'Q'}
        ret = struct.unpack('<' + s2fmt[size], ret)[0]

        return ret

    def nop_write(self, offset, size, value):
        print("[+] nop_write")
        return True    

    def __init__(self, name, address, size, **kwargs):
        AvatarPeripheral.__init__(self, name, address, size)
        self.hello_world = b'Hello World'
        self.read_handler[0:size] = self.hw_read 
        self.write_handler[0:size] = self.nop_write


# Save our executable to disk
with open(filename, 'wb') as f:
    f.write(tiny_elf)
os.chmod(filename, 0o744)

# Create the avatar instance and specify the architecture for this analysis
avatar = Avatar(arch=archs.x86.X86_64)

# Create the endpoint: a gdbserver connected to our tiny ELF file
gdbserver = subprocess.Popen('gdbserver --once 127.0.0.1:%d a.out' % GDB_PORT, shell=True)

# Create the corresponding target, using the GDBTarget backend
target: GDBTarget = avatar.add_target(GDBTarget, gdb_port=GDB_PORT)

# Add a dummy memory range with the custom peripheral
hello_world_address = 0x40004c00
mem_range: MemoryRange = avatar.add_memory_range(hello_world_address, 0x100, name='hello_world',
                                    emulate=HelloWorldPeripheral, permissions='rw-')

# Emulate multiple reads to demonstrate cycling through the message
for i in range(12):
    print(target.read_memory(hello_world_address, size=1).decode(), end="")

print("")

# # Initialize the target. 
# # This usually connects the target to the endpoint
# target.init()

# # Now it is possible to interact with the target.
# # For example, we can insert our shellcode at the current point of execution
# target.write_memory(target.read_register('pc'), len(shellcode),
#                     shellcode, raw=True)

# # We can now resume the execution in our target
# # You should see hello world printed on your screen! :)
# target.cont()



# Clean up!
os.remove(filename)
avatar.shutdown()

this is a minimum poc modified from example code. but exception raised:

Traceback (most recent call last):
  File "/home/zjh/workspace/avatar2-examples/example3.py", line 73, in <module>
    print(target.read_memory(hello_world_address, size=1).decode(), end="")
  File "/home/zjh/.pyenv/versions/3.9.2/lib/python3.9/site-packages/avatar2/watchmen.py", line 78, in watchtrigger
    ret = func(self, *args, **kwargs)
  File "/home/zjh/.pyenv/versions/3.9.2/lib/python3.9/site-packages/avatar2/targets/target.py", line 29, in check
    raise Exception(
Exception: read_memory() requested but memory is undefined.

replace target.read_memory with target.write_memory, then the log of emulated peripheral's write_handler triggered normally.

[+] nop_write
[+] nop_write
[+] nop_write
[+] nop_write
[+] nop_write
[+] nop_write
[+] nop_write
[+] nop_write
[+] nop_write
[+] nop_write
[+] nop_write
[+] nop_write
@mariusmue
Copy link
Member

Hi, thanks for your interest in avatar2.

Unfortunately, what you are trying to attempt is not possible. Normal ELF files don't have a notion of peripherals, which is why we have not implemented such a functionality.

Peripherals are rather for emulated hardware platforms, which is why this feature is available to other targets, such as QEMU or PANDA. That being said, I guess one could implement pyperipheral-equivalent functionality via shared memory maps or userfaultfd - but I am unsure what would be the use-case for it.

@Squirre17
Copy link
Author

Hi, thanks for your interest in avatar2.

Unfortunately, what you are trying to attempt is not possible. Normal ELF files don't have a notion of peripherals, which is why we have not implemented such a functionality.

Peripherals are rather for emulated hardware platforms, which is why this feature is available to other targets, such as QEMU or PANDA. That being said, I guess one could implement pyperipheral-equivalent functionality via shared memory maps or userfaultfd - but I am unsure what would be the use-case for it.

What should I do if i want to use peripheral feature? use QEMUtarget to launch a raw binary rather than ELF and add a peripheral in specific address?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants