diff --git a/samples/alpc_client_serveur.py b/samples/alpc_client_serveur.py new file mode 100644 index 0000000..857595d --- /dev/null +++ b/samples/alpc_client_serveur.py @@ -0,0 +1,40 @@ +import multiprocessing + +import windows.alpc +from windows.generated_def import LPC_CONNECTION_REQUEST, LPC_REQUEST + +PORT_NAME = r"\RPC Control\YOLOPORT" + +def alpc_server(): + server = windows.alpc.AlpcServer(PORT_NAME) + print("[SERV] PORT CREATED") + attrs, msg = server.wait_data() + print("[SERV] Message type = {0:#x}".format(msg.u2.s2.Type)) + print("[SERV] Received data: <{0}>".format(msg.data)) + if msg.u2.s2.Type & LPC_CONNECTION_REQUEST: + print("[SERV] Connection request") + msg.data = "WOKAY" + server.accept_connection(msg) + attrs, msg = server.wait_data() + print("[SERV] Received message") + print("[SERV] Message type = {0:#x}".format(msg.u2.s2.Type)) + if msg.u2.s2.Type & LPC_REQUEST: + print("[SERV] ALPC request: <{0}>".format(msg.data)) + server.reply(msg, "REQUEST '{0}' DONE".format(msg.data)) + + +def alpc_client(): + client = windows.alpc.AlpcClient() + connect_response = client.connect_to_port(PORT_NAME, "COUCOU") + print("[CLIENT] Connected: {0}".format(connect_response.data)) + print("[CLIENT] Send Message ") + attr, response = client.send_receive("POUET") + print("[CLIENT] Server response: <{0}>".format(response.data)) + + +if __name__ == "__main__": + proc = multiprocessing.Process(target=alpc_server, args=()) + proc.start() + import time; time.sleep(0.5) + alpc_client() + print("BYE") \ No newline at end of file diff --git a/samples/wincli.py b/samples/wincli.py new file mode 100644 index 0000000..361aa0a --- /dev/null +++ b/samples/wincli.py @@ -0,0 +1,219 @@ +import argparse +import os.path +import windows +import windows.generated_def as gdef + +def find_processes_from_kwargs(pid=None, name=None, **kwargs): + if pid is None and name is None: + return windows.system.processes + if pid is not None: + return [p for p in windows.system.processes if p.pid == pid] + return [p for p in windows.system.processes if p.name.lower() == name.lower()] + +def find_one_process_from_kwargs(pid=None, name=None, **kwargs): + if pid is not None: + targets = [p for p in windows.system.processes if p.pid == pid] + if not len(targets): + raise ValueError("Could not find process with pid <{0}>".format(pid)) + assert len(targets) == 1 + return targets[0] + + targets = [p for p in windows.system.processes if p.name.lower() == name.lower()] + if not len(targets): + raise ValueError("Could not find a process with name <{0}>".format(name)) + # Ask to choose a process + if len(targets) == 1: + return targets[0] + print("Multiple process with name {0}, please choose:".format(name)) + for i, proc in enumerate(targets): + print(" {0}) {1}".format(i, proc)) + choice = raw_input("Number > ") + try: + return targets[choice] + except IndexError: + raise + + +def proc_command_list(**kwargs): + print("Listing processes") + for proc in find_processes_from_kwargs(**kwargs): + print (proc) + +def proc_command_shell(**kwargs): + target = find_one_process_from_kwargs(**kwargs) + pfw_path = os.path.dirname(windows.__path__[0]) + print("Using PythonForWindows at <{0}>".format(pfw_path)) + try: + target.execute_python("import sys; sys.path.append(r'{0}')".format(pfw_path)) + target.execute_python("import windows; windows.utils.pop_shell()") + except Exception as e: + print("Error while injecting python code: <{0!r}>".format(e)) + raise + +def proc_command_kill(**kwargs): + target = find_one_process_from_kwargs(**kwargs) + print(target.exit(0)) + print(target) + +def proc_command_killall(**kwargs): + targets = find_processes_from_kwargs(**kwargs) + for target in targets: + target.exit(0) + print(target) + + +PAGE_PROTECTIONS = [ +gdef.PAGE_NOACCESS, +gdef.PAGE_READONLY, +gdef.PAGE_READWRITE, +gdef.PAGE_WRITECOPY, +gdef.PAGE_EXECUTE, +gdef.PAGE_EXECUTE_READ, +gdef.PAGE_EXECUTE_READWRITE, +gdef.PAGE_EXECUTE_WRITECOPY, +gdef.PAGE_GUARD, +gdef.PAGE_NOCACHE, +gdef.PAGE_WRITECOMBINE, +] +PAGE_PROTECTIONS_MAPPER = {x:x for x in PAGE_PROTECTIONS} + +MEMORY_STATE = [gdef.MEM_COMMIT, +gdef.MEM_RESERVE, +gdef.MEM_DECOMMIT , +gdef.MEM_RELEASE, +gdef.MEM_FREE, +gdef.MEM_PRIVATE, +gdef.MEM_MAPPED, +gdef.MEM_RESET, +gdef.MEM_TOP_DOWN , +gdef.MEM_WRITE_WATCH, +gdef.MEM_PHYSICAL, +gdef.MEM_ROTATE, +gdef.MEM_LARGE_PAGES, +gdef.MEM_4MB_PAGES] +MEMORY_STATE_MAPPER = {x:x for x in MEMORY_STATE} + +def proc_command_addr(**kwargs): + target = find_one_process_from_kwargs(**kwargs) + print(target) + for addr in kwargs["addresses"]: + print("== Address <{0:#x}> ==".format(addr, target)) + data = target.query_memory(addr) + + print("* BaseAddress = {0:#x}".format(data.BaseAddress)) + print("* RegionSize = {0:#x}".format(data.RegionSize)) + print("* State = {0}".format(MEMORY_STATE_MAPPER.get(data.RegionSize, data.RegionSize))) + print("* Protect = {0}".format(PAGE_PROTECTIONS_MAPPER.get(data.Protect, data.Protect))) + print('* MappedFile = "{0}"'.format(target.get_mapped_filename(addr))) + + x = work_set = target.query_working_setex([addr]) + attrs = x[0].VirtualAttributes + if attrs.valid: + print('* Shared = {0}'.format(bool(attrs.shared))) + + # Module + for mod in target.peb.modules: + if mod.baseaddr <= addr < mod.baseaddr + mod.SizeOfImage: + break + else: + print("Not in a module") + return + print("Part of {0}".format(mod)) + print(" * {0} + {1:#x}".format(mod.name, addr - mod.baseaddr)) + + exports = mod.pe.exports + res = (0xfffffff, "NOTFOUND") + for name, exportaddr in exports.items(): + if isinstance(name, (int, long)): + continue + if exportaddr > addr: + continue + dist = addr - exportaddr + res = min((dist, name), res) + if dist == 0: + break + if res[1] != "NOTFOUND": + print(" * {0}!{1}+{2:#x}".format(mod.name, res[1], dist)) + +# Services + +def find_services_from_kwargs(name=None, **kwargs): + if name is None: + return windows.system.services + return [p for p in windows.system.services if p.name.lower() == name.lower()] + + +def find_one_service_from_kwargs(name=None, **kwargs): + targets = [s for s in windows.system.services if s.name.lower() == name.lower()] + if not len(targets): + raise ValueError("Could not find a service with name <{0}>".format(name)) + # Ask to choose a process + if len(targets) == 1: + return targets[0] + print("Multiple services with name {0}, please choose:".format(name)) + for i, serv in enumerate(targets): + print(" {0}) {1}".format(i, serv)) + choice = raw_input("Number > ") + try: + return targets[choice] + except IndexError: + raise + +def serv_command_list(**kwargs): + print("Listing services") + for serv in find_services_from_kwargs(**kwargs): + print (serv) + +def serv_command_start(**kwargs): + serv = find_one_service_from_kwargs(**kwargs) + serv.start() + serv = find_one_service_from_kwargs(**kwargs) + print(serv) + +parser = argparse.ArgumentParser(prog=__file__) +subparsers = parser.add_subparsers(description='valid subcommands',) + +# Processes commandes +proc_parser = subparsers.add_parser('proc') +proc_parser.set_defaults(func=proc_command_list) + +group = proc_parser.add_mutually_exclusive_group() +group.add_argument('--pid', type=int, help='The pid of the process') +group.add_argument('--name', help='The name of the process') + +proc_subparsers = proc_parser.add_subparsers(description='valid subcommands',) + +proc_list_parser_ = proc_subparsers.add_parser('list') +proc_list_parser_.set_defaults(func=proc_command_list) + +proc_inject_parser = proc_subparsers.add_parser('shell') +proc_inject_parser.set_defaults(func=proc_command_shell) + +proc_inject_parser = proc_subparsers.add_parser('kill') +proc_inject_parser.set_defaults(func=proc_command_kill) + +proc_inject_parser = proc_subparsers.add_parser('killall') +proc_inject_parser.set_defaults(func=proc_command_killall) + +proc_addr_parser = proc_subparsers.add_parser('addr') +proc_addr_parser.set_defaults(func=proc_command_addr) +proc_addr_parser.add_argument('addresses', type=lambda x: int(x, 0), nargs="+", help='The addresses to explore') + +# Services commandes +serv_parser = subparsers.add_parser('serv') +serv_parser.set_defaults(func=proc_command_list) + +group = serv_parser.add_mutually_exclusive_group() +group.add_argument('--name', help='The name of the service') + +serv_subparsers = serv_parser.add_subparsers(description='valid subcommands',) + +serv_list_parser_ = serv_subparsers.add_parser('list') +serv_list_parser_.set_defaults(func=serv_command_list) + +serv_list_parser_ = serv_subparsers.add_parser('start') +serv_list_parser_.set_defaults(func=serv_command_start) + +if __name__ == "__main__": + res = parser.parse_args() + res.func(**res.__dict__) \ No newline at end of file diff --git a/windows/rpc/__init__.py b/windows/rpc/__init__.py index a4ee3a1..3e0e1e9 100644 --- a/windows/rpc/__init__.py +++ b/windows/rpc/__init__.py @@ -1,3 +1,3 @@ -from client import RPC_SYNTAX_IDENTIFIER, RPCClient import ndr -from epmapper import find_alpc_endpoint_and_connect, construct_alpc_tower \ No newline at end of file +from client import RPC_SYNTAX_IDENTIFIER, RPCClient +from epmapper import find_alpc_endpoint_and_connect, endpoint_map_alpc, construct_alpc_tower \ No newline at end of file diff --git a/windows/rpc/client.py b/windows/rpc/client.py index ae425eb..5360185 100644 --- a/windows/rpc/client.py +++ b/windows/rpc/client.py @@ -41,7 +41,9 @@ KNOW_RESPONSE_TYPE = { KNOWN_RPC_ERROR_CODE = { 1783 : "RPC_X_BAD_STUB_DATA", - 1717 : "RPC_S_UNKNOWN_IF" + 1717 : "RPC_S_UNKNOWN_IF", + 1745 : "RPC_S_PROCNUM_OUT_OF_RANGE" + } NOT_USED = 0xBAADF00D diff --git a/windows/rpc/ndr.py b/windows/rpc/ndr.py index 55a579a..cb7ffc6 100644 --- a/windows/rpc/ndr.py +++ b/windows/rpc/ndr.py @@ -34,7 +34,7 @@ class NdrUniquePTR(object): def pack(self, data): subpack = self.subcls.pack(data) if subpack is None: - return dword_pad(0) + return pack_dword(0) return pack_dword(0x02020202) + subpack def pack_in_struct(self, data, id): @@ -75,6 +75,11 @@ class NdrWString(object): result += data return dword_pad(result) + # @classmethod + # def unpack(self, stream): + # maxcount, offset, count = stream.partial_unpack("<3I") + # return maxcount, offset, count + class NdrLong(object): @classmethod def pack(cls, data): diff --git a/windows/winobject/sid.py b/windows/winobject/sid.py new file mode 100644 index 0000000..06b5e5e --- /dev/null +++ b/windows/winobject/sid.py @@ -0,0 +1,19 @@ +from windows.generated_def import PSID +from windows import winproxy + +class EPSID(PSID): + def __repr__(self): + return ''.format(str(self), id(self)) + + def __str__(self): + sid_str = LPCSTR() + winproxy.ConvertSidToStringSidA(self, sid_str) + result = sid_str.value + winproxy.LocalFree(sid_str) + return result + + @classmethod + def from_string(cls, sidstr): + self = cls() + winproxy.ConvertStringSidToSidA(sidstr, self) + return self \ No newline at end of file