From 44fa4e29e70743a98d67a800feed596f4909fd12 Mon Sep 17 00:00:00 2001 From: cforgeron Date: Sun, 31 Jan 2016 15:09:20 -0400 Subject: [PATCH] - Added detect for Python 2/3 so the correct iteritems()/iter is called. - Renamed 'id' variable use (which is a built-in) to my_id. - Small formatting changes to make it more PEP compliant. --- bindings/python/sample_network_auditing.py | 150 +++++++++++++-------- 1 file changed, 92 insertions(+), 58 deletions(-) diff --git a/bindings/python/sample_network_auditing.py b/bindings/python/sample_network_auditing.py index 66e575ce..ccd279cd 100755 --- a/bindings/python/sample_network_auditing.py +++ b/bindings/python/sample_network_auditing.py @@ -7,7 +7,14 @@ from unicorn import * from unicorn.x86_const import * import struct import uuid -import random + +# Python 2/3 Compat without installing six +DEAD_PYTHON = False +import sys + +if sys.version_info[0] < 3: + DEAD_PYTHON = True + print("Python 2.x is dead. Start thinking about migrating to 3.x. https://wiki.python.org/moin/Python2orPython3") SIZE_REG = 4 SOCKETCALL_MAX_ARGS = 3 @@ -51,10 +58,11 @@ X86_REVERSE_TCP_2 = b"\x31\xc0\x31\xdb\x31\xc9\x31\xd2\xb0\x66\xb3\x01\x51\x6a\x # memory address where emulation starts ADDRESS = 0x1000000 + # supported classes class IdGenerator: def __init__(self): - self.__next_id = 3 # exclude sdtin, stdout, stderr + self.__next_id = 3 # exclude sdtin, stdout, stderr def next(self): next_id = self.__next_id @@ -63,6 +71,7 @@ class IdGenerator: return next_id + class LogChain: def __init__(self): self.__chains = {} @@ -72,11 +81,11 @@ class LogChain: self.__chains = {} self.__linking_fds = {} - def create_chain(self, id): - if not self.__chains.has_key(id): - self.__chains[id] = [] + def create_chain(self, my_id): + if not my_id in self.__chains: + self.__chains[my_id] = [] else: - print("LogChain: id %d existed" % id) + print("LogChain: id %d existed" % my_id) def add_log(self, id, msg): fd = self.get_original_fd(id) @@ -87,20 +96,25 @@ class LogChain: print("LogChain: id %d doesn't exist" % id) def link_fd(self, from_fd, to_fd): - if not self.__linking_fds.has_key(to_fd): + if not to_fd in self.__linking_fds: self.__linking_fds[to_fd] = [] self.__linking_fds[to_fd].append(from_fd) def get_original_fd(self, fd): - if self.__chains.has_key(fd): + if fd in self.__chains: return fd - for orig_fd, links in self.__linking_fds.iteritems(): - if fd in links: - return orig_fd + if DEAD_PYTHON: + for orig_fd, links in self.__linking_fds.iteritems(): + if fd in links: + return orig_fd + else: + for orig_fd, links in self.__linking_fds.items(): + if fd in links: + return orig_fd - return None + return None def print_report(self): print(""" @@ -108,10 +122,16 @@ class LogChain: | START REPORT | ---------------- """) - for id, logs in self.__chains.iteritems(): - print("---- START FD(%d) ----" % id) - print("\n".join(logs)) - print("---- END FD(%d) ----" % id) + if DEAD_PYTHON: + for my_id, logs in self.__chains.iteritems(): + print("---- START FD(%d) ----" % my_id) + print("\n".join(logs)) + print("---- END FD(%d) ----" % my_id) + else: + for my_id, logs in self.__chains.items(): + print("---- START FD(%d) ----" % my_id) + print("\n".join(logs)) + print("---- END FD(%d) ----" % my_id) print(""" -------------- @@ -119,10 +139,9 @@ class LogChain: -------------- """) + # end supported classes -id_gen = IdGenerator() -fd_chains = LogChain() # utilities def bin_to_ipv4(ip): @@ -132,6 +151,7 @@ def bin_to_ipv4(ip): (ip & 0xff00) >> 8, (ip & 0xff)) + def read_string(uc, addr): ret = "" @@ -140,36 +160,43 @@ def read_string(uc, addr): while c != 0x0: ret += chr(c) - c = uc.mem_read(addr+read_bytes, 1)[0] + c = uc.mem_read(addr + read_bytes, 1)[0] read_bytes += 1 return ret + def parse_sock_address(sock_addr): sin_family, = struct.unpack("HI", sock_addr[2:8]) + + if sin_family == 2: # AF_INET + port, host = struct.unpack(">HI", sock_addr[2:8]) return "%s:%d" % (bin_to_ipv4(host), port) - elif sin_family == 6: # AF_INET6 + elif sin_family == 6: # AF_INET6 return "" + def print_sockcall(msg): print(">>> SOCKCALL %s" % msg) + + # end utilities # callback for tracing instructions def hook_code(uc, address, size, user_data): - print(">>> Tracing instruction at 0x%x, instruction size = 0x%x" %(address, size)) + print(">>> Tracing instruction at 0x%x, instruction size = 0x%x" % (address, size)) # read this instruction code from memory tmp = uc.mem_read(address, size) - print(">>> Instruction code at [0x%x] =" %(address), end="") + print(">>> Instruction code at [0x%x] =" % (address), end="") for i in tmp: - print(" %x" %i, end="") + print(" %x" % i, end="") print("") + # callback for tracing Linux interrupt def hook_intr(uc, intno, user_data): + global id_gen + # only handle Linux syscall if intno != 0x80: return @@ -182,17 +209,17 @@ def hook_intr(uc, intno, user_data): # print(">>> INTERRUPT %d" % eax) - if eax == 1: # sys_exit + if eax == 1: # sys_exit print(">>> SYS_EXIT") uc.emu_stop() - elif eax == 3: # sys_read + elif eax == 3: # sys_read fd = ebx buf = ecx count = edx dummy_content = str(uuid.uuid1())[:32] if len(dummy_content) > count: - dummy_content = dummy_content[:count] + dummy_content = dummy_content[:count] uc.mem_write(buf, dummy_content) @@ -200,7 +227,7 @@ def hook_intr(uc, intno, user_data): fd_chains.add_log(fd, msg) print(">>> %s" % msg) - elif eax == 4: # sys_write + elif eax == 4: # sys_write fd = ebx buf = ecx count = edx @@ -211,13 +238,13 @@ def hook_intr(uc, intno, user_data): print(">>> %s" % msg) fd_chains.add_log(fd, msg) - elif eax == 5: # sys_open + elif eax == 5: # sys_open filename_addr = ebx flags = ecx mode = edx filename = read_string(uc, filename_addr) - dummy_fd = id_gen.next() + dummy_fd = id_gen.next() uc.reg_write(UC_X86_REG_EAX, dummy_fd) msg = "open file (filename=%s flags=%d mode=%d) with fd(%d)" % (filename, flags, mode, dummy_fd) @@ -225,42 +252,42 @@ def hook_intr(uc, intno, user_data): fd_chains.create_chain(dummy_fd) fd_chains.add_log(dummy_fd, msg) print(">>> %s" % msg) - elif eax == 11: # sys_execv + elif eax == 11: # sys_execv # print(">>> ebx=0x%x, ecx=0x%x, edx=0x%x" % (ebx, ecx, edx)) filename = read_string(uc, ebx) print(">>> SYS_EXECV filename=%s" % filename) - elif eax == 63: # sys_dup2 + elif eax == 63: # sys_dup2 fd_chains.link_fd(ecx, ebx) print(">>> SYS_DUP2 oldfd=%d newfd=%d" % (ebx, ecx)) - elif eax == 102: # sys_socketcall + elif eax == 102: # sys_socketcall # ref: http://www.skyfree.org/linux/kernel_network/socket.html call = uc.reg_read(UC_X86_REG_EBX) args = uc.reg_read(UC_X86_REG_ECX) SOCKETCALL_NUM_ARGS = { - 1: 3, # sys_socket - 2: 3, # sys_bind - 3: 3, # sys_connect - 4: 2, # sys_listen - 5: 3, # sys_accept - 9: 4, # sys_send + 1: 3, # sys_socket + 2: 3, # sys_bind + 3: 3, # sys_connect + 4: 2, # sys_listen + 5: 3, # sys_accept + 9: 4, # sys_send 11: 4, # sys_receive - 13: 2 # sys_shutdown + 13: 2 # sys_shutdown } - buf = uc.mem_read(args, SOCKETCALL_NUM_ARGS[call]*SIZE_REG) - args = struct.unpack("<" + "I"*SOCKETCALL_NUM_ARGS[call], buf) + buf = uc.mem_read(args, SOCKETCALL_NUM_ARGS[call] * SIZE_REG) + args = struct.unpack("<" + "I" * SOCKETCALL_NUM_ARGS[call], buf) # int sys_socketcall(int call, unsigned long *args) - if call == 1: # sys_socket + if call == 1: # sys_socket # err = sys_socket(a0,a1,a[2]) # int sys_socket(int family, int type, int protocol) family = args[0] sock_type = args[1] protocol = args[2] - dummy_fd = id_gen.next() + dummy_fd = id_gen.next() uc.reg_write(UC_X86_REG_EAX, dummy_fd) if family == 2: # AF_INET @@ -269,10 +296,10 @@ def hook_intr(uc, intno, user_data): fd_chains.create_chain(dummy_fd) fd_chains.add_log(dummy_fd, msg) print_sockcall(msg) - elif family == 3: # AF_INET6 + elif family == 3: # AF_INET6 pass - elif call == 2: # sys_bind + elif call == 2: # sys_bind fd = args[0] umyaddr = args[1] addrlen = args[2] @@ -283,19 +310,19 @@ def hook_intr(uc, intno, user_data): fd_chains.add_log(fd, msg) print_sockcall(msg) - elif call == 3: # sys_connect + elif call == 3: # sys_connect # err = sys_connect(a0, (struct sockaddr *)a1, a[2]) # int sys_connect(int fd, struct sockaddr *uservaddr, int addrlen) fd = args[0] uservaddr = args[1] addrlen = args[2] - sock_addr = uc.mem_read(uservaddr, addrlen) + sock_addr = uc.mem_read(uservaddr, addrlen) msg = "fd(%d) connect to %s" % (fd, parse_sock_address(sock_addr)) fd_chains.add_log(fd, msg) print_sockcall(msg) - elif call == 4: # sys_listen + elif call == 4: # sys_listen fd = args[0] backlog = args[1] @@ -303,7 +330,7 @@ def hook_intr(uc, intno, user_data): fd_chains.add_log(fd, msg) print_sockcall(msg) - elif call == 5: # sys_accept + elif call == 5: # sys_accept fd = args[0] upeer_sockaddr = args[1] upeer_addrlen = args[2] @@ -321,7 +348,7 @@ def hook_intr(uc, intno, user_data): fd_chains.add_log(fd, msg) print_sockcall(msg) - elif call == 9: # sys_send + elif call == 9: # sys_send fd = args[0] buff = args[1] length = args[2] @@ -332,7 +359,7 @@ def hook_intr(uc, intno, user_data): fd_chains.add_log(fd, msg) print_sockcall(msg) - elif call == 11: # sys_receive + elif call == 11: # sys_receive fd = args[0] ubuf = args[1] size = args[2] @@ -342,7 +369,7 @@ def hook_intr(uc, intno, user_data): fd_chains.add_log(fd, msg) print_sockcall(msg) - elif call == 13: # sys_shutdown + elif call == 13: # sys_shutdown fd = args[0] how = args[1] @@ -350,8 +377,11 @@ def hook_intr(uc, intno, user_data): fd_chains.add_log(fd, msg) print_sockcall(msg) + # Test X86 32 bit def test_i386(code): + global fd_chains + fd_chains.clean() print("Emulate i386 code") try: @@ -366,7 +396,7 @@ def test_i386(code): # initialize stack mu.reg_write(UC_X86_REG_ESP, ADDRESS + 0x200000) - + # tracing all instructions with customized callback # mu.hook_add(UC_HOOK_CODE, hook_code) @@ -384,9 +414,13 @@ def test_i386(code): fd_chains.print_report() + +# Globals +fd_chains = LogChain() +id_gen = IdGenerator() + if __name__ == '__main__': - test_i386(X86_SEND_ETCPASSWD) + test_i386(X86_SEND_ETCPASSWD) test_i386(X86_BIND_TCP) test_i386(X86_REVERSE_TCP) test_i386(X86_REVERSE_TCP_2) -