Skip to main content

Python library to automate gdb debugging

Project description

Patchelfy

Patchelfy is a library to inject new code into an ELF without breaking it. It can be used when you can't attach to the process to alter part of the execution or simply log informations while reversing it.

The code has to be written in assembly and some methods are offered to add calls to any libc function or to access specific addresses in the binary.

Log

The simplest use for this library is to log data during the execution.

You can write as many shellcodes as you want on the same address, but you just have to keep in mind that they will be called from the last to the fist you set and the memory will be restored between each of them.

from patchelfy import Patchelf
p = Patchelf("./binary")
# Warning the \n must be escaped
p.log(0x1651, "the function returned %ld\\n", ["rax"])
p.log(0x1651, "I'm at address: 0x%lx\\n", [0x1651])
p.log(0x1651, "This is a log\\n", [])
#p.save("./binary_patched")
# If left empty the name for the new binary will be <name>_patched
p.save()

output:

$ ./binary_patched
This is a log
I'm at address: 0x1651
the function returned 0x7f41f656a000

Access variables on stack

To access variables on the stack, or in another stackframe, you can load them into a register with pre. Remember to save the original value and restore it after.

from patchelfy import Patchelf
p = Patchelf("./binary")

shellcode = """
push rbp
push rbx
mov rbp, qword ptr [rbp]
mov ebx, dword ptr [rbp - 0x4]
"""

p.log(0x154c, "[process: %d] returned %ld\\n", ["rbx", "rax"], pre=shellcode, post="pop rbx\npop rbp")
p.save()

Place shellcodes

You can insert your own shellcodes inside the binary and reffer to functions in the binary by their relative address

from patchelfy import Patchelf
p = Patchelf("./binary")

# Skip a portion of code
shellcode = """
jmp 0x1537
"""

p.place_shellcode(0x1526, shellcode)
p.save()

Calling a function

If you have to call a function in your shellcode you can use the wrapper Patchelf.shellcode_call to save all registers and parse your arguments. If the function you want to call is in the libc you can get a relative address to it with Patchelf.setup_libc to build your shellcode.

from patchelfy import Patchelf
p = Patchelf("./binary")

system_address = p.setup_libc("memcpy")
ptable = list(range(0x100))
shellcode = p.shellcode_call(system_address, [0x205153, ptable, 0x100])
p.place_shellcode(0x1526, shellcode)
p.save()

Edge cases

To place your shellcode we overwrite 6 bytes of the binary. It is not a problem except if the program has to jump right in that area. Try not to place it there, but if you REALY have to you can use restoring_shellcode that restore the memory once executed. Unfortunately there is nothing I can do if you jump into that area before running your shellcode.

from patchelfy import Patchelf
p = Patchelf("./binary")

# overwrite return value with True
shellcode = """
xor rax, rax
inc rax
"""

p.restoring_shellcode(0x15a3, shellcode)
# If you are in a loop and want your shellcode to be executed each time you need a point to set again your shellcode. This will be developed in a future version
#p.restoring_shellcode(0x15a3, shellcode, loop = 0x15bb)
p.save()

If you need it for a log, use the argument p.log(..., restoring=True)

Installation

stable

pip3 install patchelfy

Limitations

  • Can not yet patch a section that will be unpacked at runtime. I will look into a setup to handle it.
  • Setup_libc requires the binary to be relro or at least the last function in the got table to be loaded when called. You can inject a restoring_shellcode on entry to the last function of the plt or disable ASLR, load the absolute address in a register and call that register.
  • You can only write 2MB of shellcode... Do you really have a case where it isn't enough ?

Project details


Release history Release notifications | RSS feed

This version

0.1

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

patchelfy-0.1.tar.gz (18.7 kB view details)

Uploaded Source

Built Distribution

patchelfy-0.1-py3-none-any.whl (21.3 kB view details)

Uploaded Python 3

File details

Details for the file patchelfy-0.1.tar.gz.

File metadata

  • Download URL: patchelfy-0.1.tar.gz
  • Upload date:
  • Size: 18.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.2 CPython/3.10.6

File hashes

Hashes for patchelfy-0.1.tar.gz
Algorithm Hash digest
SHA256 a11525a209849c126cdd36ab49dfe5e14fc7b8fff3c75ed16172d5bf00de7df5
MD5 a76ac2b0243a7d4a6c790d0a0622be41
BLAKE2b-256 642fc7069e60ad5b341ea348570e94a5db001f177d6da175d59b671a96f65f8c

See more details on using hashes here.

File details

Details for the file patchelfy-0.1-py3-none-any.whl.

File metadata

  • Download URL: patchelfy-0.1-py3-none-any.whl
  • Upload date:
  • Size: 21.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.2 CPython/3.10.6

File hashes

Hashes for patchelfy-0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 25c3f94214470d44994a8d48410a58ac406cb3f16f4f3335655c6b241e8c1511
MD5 78c2e8c8862f8b3050b78bf63c32ef76
BLAKE2b-256 9d6d531a5c19e8d5494a348e85e40ebc237da549a747e245be8d4e5c46070a04

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page