summaryrefslogtreecommitdiff
path: root/hypodermic/main.py
blob: 3cbb047807953e67dbe09801ab59661fa2f75fe0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# Copyright (C) 2017 Jakob Kreuze, All Rights Reserved.
#
# This file is part of Hypodermic.
#
# Hypodermic is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation, either version 3 of the License, or (at your
# option) any later version.
#
# Hypodermic is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
# Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with Hypodermic. If not, see <http://www.gnu.org/licenses/>.

"""Command-line interface to Hypodermic."""

import argparse
import sys
import textwrap

from hypodermic.process import Process


class CustomHelp(argparse.HelpFormatter):
    """Modifications to argparse's default HelpFormatter."""
    def _fill_text(self, text, width, indent):
        filled = []
        for line in text.splitlines(keepends=True):
            filled.append(indent + line)
        return "".join(filled)

    def _split_lines(self, text, width):
        return text.splitlines()

    def add_usage(self, usage, actions, groups, prefix=None):
        prefix = prefix or "Usage: "
        both = super(CustomHelp, self)
        return both.add_usage(usage, actions, groups, prefix)


def _alert(quiet: bool):
    def alert(*args):
        if not quiet:
            print(*args)
    return alert


def main():
    parser = argparse.ArgumentParser(
        add_help=False,
        formatter_class=CustomHelp,
        usage="%(prog)s [-a pid] [-c path] [options]",
        description="Don't share needles, brah!"
    )
    parser._positionals.title = "Positional Arguments"
    parser._optionals.title = "Optional Arguments"

    parser.add_argument(
        "target",
        help="The target shared object to inject."
    )
    parser.add_argument(
        "-q",
        "--quiet",
        help="Suppress everything but critical output"
    )

    doc = parser.add_argument_group("Documentation")
    doc.add_argument(
        "-h",
        "--help",
        action="help",
        help="Display this help page and exit."
    )
    doc.add_argument(
        "-V",
        "--version",
        action="version",
        version="What version?",
        help="Display the currently installed version and exit."
    )

    proc = parser.add_argument_group("Process Manipulation")
    meth = proc.add_mutually_exclusive_group()
    proc.add_argument(
        "-a",
        "--attach",
        metavar="PID",
        help="The pid of a process to attach to."
    )
    proc.add_argument(
        "-c",
        "--create",
        metavar="BIN",
        help="The path of a binary to execute and attach to."
    )

    args = parser.parse_args()
    alert = _alert(args.quiet)

    if args.attach is None and args.create is None:
        print("No action specified. Quitting!")
        sys.exit(1)

    if args.create:
        alert("Creating process at path '{}'...".format(args.create))
        p = Process(path=args.create)
    else:
        alert("Attaching to process with pid {}...".format(args.attach))
        p = Process(pid=args.attach)
    print(p.dlopen("/usr/lib/libyggdrasil.so"))
    p.continue_until_haulted()