python的反编译pyc、pyo

    如果慢不是python的最大缺点,源码保护或许是。

    python源码通常写作xxx.py,其对应二进制文件为pyc,python可运行调用两者达到相同的效果。pyc文件更多信息可以百度,不多说了。

    反编译pyc工具不少,列几个。


    首先是Uncompyle2

    https://github.com/wibiti/uncompyle2

    这货可以解密python2.7的pyc,用过,非常不错。但对别的版本就无奈了。

    据说可解2.7 to 3.5


    然后Easy Python Decompiler

    https://sourceforge.net/projects/easypythondecompiler/files/bin/

    解开了2.6的,没有试别的。

    据说可解1.0-3.3,只有windows版本,exe格式。

    其实是基于其他两个的解包工具,写了个gui,打包了而已。


    别的没用过,仅列表

    unpyclib
    Decompyle++ (pycdc) https://github.com/zrax/pycdc 1.5 to 3.5

    decompyle http://sourceforge.net/projects/decompyle/ 1.5 up to 2.3


    参考文献

    http://stackoverflow.com/questions/5287253/is-it-possible-to-decompile-a-compiled-pyc-file-into-a-py...


    最后,解密的zproxy v1.1

    # Embedded file name: zproxy.py
    import socket, logging
    import select, errno
    import os
    import sys
    import traceback
    import gzip
    import Queue
    import threading
    import time
    import thread
    import cgi
    import json
    import imp
    import re
    import ssl
    from cgi import parse_qs
    from StringIO import StringIO
    from os.path import join, getsize
    logger = logging.getLogger('network-server')

    def getTraceStackMsg():
        tb = sys.exc_info()[2]
        msg = ''
        for i in traceback.format_tb(tb):
            msg += i

        return msg


    def InitLog():
        logger.setLevel(logging.DEBUG)
        fh = logging.FileHandler('network-server.log')
        fh.setLevel(logging.DEBUG)
        ch = logging.StreamHandler()
        ch.setLevel(logging.ERROR)
        formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
        ch.setFormatter(formatter)
        fh.setFormatter(formatter)
        logger.addHandler(fh)
        logger.addHandler(ch)


    def clearfdpro(epoll_fd, params, fd):
        try:
            fd_check = int(fd)
        except Exception as e:
            print 'fd error'
            sys.exit(1)

        try:
            epoll_fd.unregister(fd)
        except Exception as e:
            pass

        try:
            param = params[fd]
            try:
                addr = param['addr']
                if 'next' in param:
                    print '\xe5\x85\xb3\xe9\x97\xadSock, %s:%s' % (addr[0], addr[1])
            except Exception as e:
                pass

            param['connections'].shutdown(socket.SHUT_RDWR)
            param['connections'].close()
            f = param.get('f', None)
            if f != None:
                f.close()
            rc = param.get('rc', None)
            if rc != None:
                rc.close()
            if 'read_cache_name' in param:
                os.remove(param['read_cache_name'])
        except Exception as e:
            pass

        try:
            del params[fd]
        except Exception as e:
            pass

        return


    def clearfd(epoll_fd, params, fd):
        try:
            param = params[fd]
            if 'nextfd' in param:
                nextfd = param['nextfd']
                next_param = params[nextfd]
                del param['nextfd']
                del next_param['nextfd']
                if 'next' not in param:
                    clearfdpro(epoll_fd, params, nextfd)
                elif 'writedata' not in next_param or len(next_param['writedata']) == 0:
                    clearfdpro(epoll_fd, params, nextfd)
                else:
                    next_param['sendandclose'] = 'true'
            clearfdpro(epoll_fd, params, fd)
        except Exception as e:
            pass


    def FindHostPort(datas):
        host_s = -1
        host_e = -1
        host_str = None
        host = ''
        port = ''
        mhost = ''
        if not datas.startswith('CONNECT'):
            host_s = datas.find('zyx~')
            mhost_s = datas.find('Host:')
            mhost_e = datas.find('\r\n', mhost_s)
            if mhost_s > 0 and mhost_e > 0:
                mhost_str = datas[mhost_s + 5:mhost_e].strip()
            if host_s < 0:
                host_s = datas.find('xxx~')
            if host_s > 0:
                host_e = datas.find('\r\n', host_s)
            if host_s > 0 and host_e > 0:
                host_str = datas[host_s + 4:host_e].strip()
                add_list = host_str.split(':')
                if len(add_list) == 2:
                    host = add_list[0]
                    port = add_list[1]
                else:
                    host = add_list[0]
                    port = 80
                first_seg = datas.find('\r\n')
                first_line = datas[0:first_seg]
                first_line = first_line.replace(' http://%s' % mhost_str, ' http://%s' % host_str)
                datas = datas.replace('Host: %s' % mhost_str, 'Host: %s' % host_str)
                datas = datas.replace('zyx~ %s\r\n' % host_str, '')
                datas = first_line + datas[first_seg:]
        else:
            first_seg = datas.find('\r\n')
            head_e = datas.find('\r\n\r\n')
            host_s = datas.find('zyx~')
            mhost_s = datas.find('Host:')
            mhost_e = datas.find('\r\n', mhost_s)
            if mhost_s > 0 and mhost_e > 0:
                mhost_str = datas[mhost_s + 5:mhost_e].strip()
            if host_s < 0:
                host_s = datas.find('xxx:')
            if host_s > 0:
                host_e = datas.find('\r\n', host_s)
            if host_s > 0 and host_e > 0:
                host_str = datas[host_s + 4:host_e].strip()
            if first_seg > 0 and head_e > 0:
                first_line = datas[0:first_seg]
                first_line = first_line.replace('CONNECT %s' % mhost_str, 'CONNECT %s' % host_str)
                com, host_str, http_version = re.split('\\s+', first_line)
                add_list = host_str.split(':')
                if len(add_list) == 2:
                    host = add_list[0]
                    port = add_list[1]
                else:
                    host = add_list[0]
                    port = 443
                host_s = 1
                host_e = 1
        return (host_str,
        host_s,
        host_e,
        host,
        port,
        datas)


    def connect_pro(params, param, epoll_fd, datas, fd, cur_time, host, port):
        try:
            nextfd = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
            nextfd.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
            nextfd.settimeout(5)
            try:
                nextfd.connect((host, int(port)))
            except Exception as e:
                print 'ZProxy\xe8\xbd\xac\xe5\x8f\x91\xe5\xa4\xb1\xe8\xb4\xa5---%s:%s' % (host, port)

            nextfd.setblocking(0)
            next_fileno = nextfd.fileno()
            print 'Zproxy\xe8\xbd\xac\xe5\x8f\x91\xe6\x88\x90\xe5\x8a\x9f---%s:%s' % (host, port)
            if next_fileno in params:
                sys.exit(1)
            if not datas.startswith('CONNECT'):
                next_param = {'addr': [host, port],
                'writelen': 0,
                'connections': nextfd,
                'time': cur_time,
                'nextfd': fd}
                param['nextfd'] = next_fileno
                next_param['writedata'] = datas
                next_param['writelen'] = 0
                next_param['next'] = 'true'
                param['read_len'] = 0
                param['readdata'] = ''
                params[next_fileno] = next_param
                epoll_fd.register(next_fileno, select.EPOLLIN | select.EPOLLOUT | select.EPOLLERR | select.EPOLLHUP)
                epoll_fd.modify(fd, select.EPOLLIN | select.EPOLLERR | select.EPOLLHUP)
            else:
                next_param = {'addr': [host, port],
                'writelen': 0,
                'connections': nextfd,
                'time': cur_time,
                'nextfd': fd}
                param['nextfd'] = next_fileno
                next_param['next'] = 'true'
                params[next_fileno] = next_param
                epoll_fd.register(next_fileno, select.EPOLLIN | select.EPOLLERR | select.EPOLLHUP)
                param['read_len'] = 0
                param['readdata'] = ''
                param['writedata'] = 'HTTP/1.1 200 Connection Established\r\nConnection: close\r\n\r\n'
                param['writelen'] = 0
                param['reuse'] = 'true'
                epoll_fd.modify(fd, select.EPOLLIN | select.EPOLLOUT | select.EPOLLERR | select.EPOLLHUP)
        except socket.error as msg:
            clearfd(epoll_fd, params, fd)


    def process_datas(process_status, params, param, epoll_fd, datas, read_len, fd, cur_time):
        if process_status == 'close':
            clearfd(epoll_fd, params, fd)
        else:
            need_connect = False
            host_str = None
            host_s = -1
            host_e = -1
            if 'reuse' in param and 'next' not in param:
                if not datas.startswith('CONNECT') and not datas.startswith('GET') and not datas.startswith('POST') and not datas.startswith('PUT'):
                    del param['reuse']
                else:
                    host_str, host_s, host_e, host, port, datas = FindHostPort(datas)
                    host_s = int(host_s)
                    host_e = int(host_e)
                    next_fileno = param['nextfd']
                    next_param = params[next_fileno]
                    addr = next_param['addr']
                    if host_s > 0 and host_e > 0:
                        if host != addr[0] or str(port) != str(addr[1]):
                            print '%s,%s neq %s,%s' % (host,
                            port,
                            addr[0],
                            addr[1])
                            need_connect = True
                            del param['nextfd']
                            del next_param['nextfd']
                            clearfd(epoll_fd, params, next_fileno)
                        del param['reuse']
                    else:
                        param['read_len'] = read_len
                        param['readdata'] = datas
                        return
            if need_connect or 'nextfd' not in param:
                if host_str == None or not host_s > 0 or not host_e > 0:
                    host_str, host_s, host_e, host, port, datas = FindHostPort(datas)
                    host_s = int(host_s)
                    host_e = int(host_e)
                if host_s > 0 and host_e > 0:
                    if not datas.startswith('CONNECT'):
                        epoll_fd.modify(fd, select.EPOLLERR | select.EPOLLHUP)
                    thread.start_new_thread(connect_pro, (params,
                    param,
                    epoll_fd,
                    datas,
                    fd,
                    cur_time,
                    host,
                    port))
                else:
                    param['read_len'] = read_len
                    param['readdata'] = datas
            else:
                next_fileno = param['nextfd']
                next_param = params[next_fileno]
                if 'next' in param:
                    next_param['reuse'] = 'true'
                write_data = next_param.get('writedata', '')
                write_data += datas
                next_param['writedata'] = write_data
                param['read_len'] = 0
                param['readdata'] = ''
                epoll_fd.modify(next_fileno, select.EPOLLIN | select.EPOLLOUT | select.EPOLLERR | select.EPOLLHUP)
            if process_status == 'close_after_process':
                clearfd(epoll_fd, params, fd)
        return


    def run_main(listen_fd):
        try:
            epoll_fd = select.epoll()
            epoll_fd.register(listen_fd.fileno(), select.EPOLLIN | select.EPOLLERR | select.EPOLLHUP)
        except select.error as msg:
            logger.error(msg)

        params = {}
        last_min_time = -1
        while True:
            epoll_list = epoll_fd.poll()
            cur_time = time.time()
            for fd, events in epoll_list:
                if fd == listen_fd.fileno():
                    while True:
                        try:
                            conn, addr = listen_fd.accept()
                            conn.setblocking(0)
                            epoll_fd.register(conn.fileno(), select.EPOLLIN | select.EPOLLERR | select.EPOLLHUP)
                            conn.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
                            params[conn.fileno()] = {'addr': addr,
                            'writelen': 0,
                            'connections': conn,
                            'time': cur_time}
                        except socket.error as msg:
                            break

                elif select.EPOLLIN & events:
                    param = params.get(fd, None)
                    if param == None:
                        continue
                    param['time'] = cur_time
                    datas = param.get('readdata', '')
                    cur_sock = params[fd]['connections']
                    read_len = param.get('read_len', 0)
                    process_status = 'close'
                    while True:
                        try:
                            data = cur_sock.recv(102400)
                            if not data:
                                if datas == '':
                                    break
                                else:
                                    raise Exception('close after process')
                            else:
                                datas += data
                                read_len += len(data)
                        except socket.error as msg:
                            if msg.errno == errno.EAGAIN:
                                process_status = 'process'
                                break
                            else:
                                break
                        except Exception as e:
                            process_status = 'close_after_process'
                            break

                    process_datas(process_status, params, param, epoll_fd, datas, read_len, fd, cur_time)
                elif select.EPOLLHUP & events or select.EPOLLERR & events:
                    clearfd(epoll_fd, params, fd)
                    logger.error('sock: %s error' % fd)
                elif select.EPOLLOUT & events:
                    param = params.get(fd, None)
                    if param == None:
                        continue
                    param['time'] = cur_time
                    sendLen = param.get('writelen', 0)
                    writedata = param.get('writedata', '')
                    total_write_len = len(writedata)
                    cur_sock = param['connections']
                    f = param.get('f', None)
                    totalsenlen = param.get('totalsenlen', None)
                    if writedata == '':
                        clearfd(epoll_fd, params, fd)
                        continue
                    while True:
                        try:
                            sendLen += cur_sock.send(writedata[sendLen:])
                            if sendLen == total_write_len:
                                if f != None and totalsenlen != None:
                                    readmorelen = 102400
                                    if readmorelen > totalsenlen:
                                        readmorelen = totalsenlen
                                    morefiledata = ''
                                    if readmorelen > 0:
                                        morefiledata = f.read(readmorelen)
                                    if morefiledata != '':
                                        writedata = morefiledata
                                        sendLen = 0
                                        total_write_len = len(writedata)
                                        totalsenlen -= total_write_len
                                        param['writedata'] = writedata
                                        param['totalsenlen'] = totalsenlen
                                        continue
                                    else:
                                        f.close()
                                        del param['f']
                                        del param['totalsenlen']
                                if 'sendandclose' not in param:
                                    param['writedata'] = ''
                                    param['writelen'] = 0
                                    epoll_fd.modify(fd, select.EPOLLIN | select.EPOLLERR | select.EPOLLHUP)
                                else:
                                    clearfd(epoll_fd, params, fd)
                                break
                        except socket.error as msg:
                            if msg.errno == errno.EAGAIN:
                                param['writelen'] = sendLen
                                break
                            clearfd(epoll_fd, params, fd)
                            break

                else:
                    continue

            if cur_time - last_min_time > 20:
                last_min_time = cur_time
                objs = params.items()
                for key_fd, value in objs:
                    fd_time = value.get('time', 0)
                    del_time = cur_time - fd_time
                    if del_time > 20:
                        clearfd(epoll_fd, params, key_fd)
                    elif fd_time < last_min_time:
                        last_min_time = fd_time

        return


    if __name__ == '__main__':
        reload(sys)
        sys.setdefaultencoding('utf8')
        InitLog()
        if len(sys.argv) < 2:
            port = 8888
        else:
            port = int(sys.argv[1])
        print '\xe5\x90\xaf\xe5\x8a\xa8ZProxy\xe6\x88\x90\xe5\x8a\x9f,\xe7\xab\xaf\xe5\x8f\xa3%s' % port
        print '\xe5\xbd\x93\xe5\x89\x8d\xe7\x89\x88\xe6\x9c\xac V0.11'
        try:
            listen_fd = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
        except socket.error as msg:
            logger.error('create socket failed')

        try:
            listen_fd.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        except socket.error as msg:
            logger.error('setsocketopt SO_REUSEADDR failed')

        try:
            listen_fd.bind(('', port))
        except socket.error as msg:
            logger.error('bind failed')

        try:
            listen_fd.listen(10240)
            listen_fd.setblocking(0)
        except socket.error as msg:
            logger.error(msg)

        child_num = 19
        c = 0
        while c < child_num:
            c = c + 1
            newpid = os.fork()
            if newpid == 0:
                run_main(listen_fd)

        run_main(listen_fd)


    zproxy v1.2

    # Embedded file name: zproxy.py
    import socket
    import select, errno
    import os
    import sys
    import traceback
    import gzip
    import Queue
    import threading
    import time
    import thread
    import cgi
    import json
    import imp
    import re
    import ssl
    from cgi import parse_qs
    from StringIO import StringIO
    from os.path import join, getsize

    def clearfdpro(epoll_fd, params, fd):
        try:
            fd_check = int(fd)
        except Exception as e:
            print 'fd error'
            sys.exit(1)

        try:
            epoll_fd.unregister(fd)
        except Exception as e:
            pass

        try:
            param = params[fd]
            try:
                addr = param['addr']
            except Exception as e:
                pass

            param['connections'].shutdown(socket.SHUT_RDWR)
            param['connections'].close()
            f = param.get('f', None)
            if f != None:
                f.close()
            rc = param.get('rc', None)
            if rc != None:
                rc.close()
            if 'read_cache_name' in param:
                os.remove(param['read_cache_name'])
        except Exception as e:
            pass

        try:
            del params[fd]
        except Exception as e:
            pass

        return


    def clearfd(epoll_fd, params, fd):
        try:
            param = params[fd]
            if 'nextfd' in param:
                nextfd = param['nextfd']
                next_param = params[nextfd]
                del param['nextfd']
                del next_param['nextfd']
                if 'next' not in param:
                    clearfdpro(epoll_fd, params, nextfd)
                elif 'writedata' not in next_param or len(next_param['writedata']) == 0:
                    clearfdpro(epoll_fd, params, nextfd)
                else:
                    next_param['sendandclose'] = 'true'
            clearfdpro(epoll_fd, params, fd)
        except Exception as e:
            pass


    def FindHostPort(datas):
        host_s = -1
        host_e = -1
        host_str = None
        host = ''
        port = ''
        mhost = ''
        mhost_str = None
        mhost_s = -1
        mhost_e = -1
        if not datas.startswith('CONNECT'):
            host_s = datas.find('zyx~')
            mhost_s = datas.find('Host:')
            mhost_e = datas.find('\r\n', mhost_s)
            if mhost_s > 0 and mhost_e > 0:
                mhost_str = datas[mhost_s + 5:mhost_e].strip()
            if host_s < 0:
                host_s = datas.find('xxx~')
            if host_s > 0:
                host_e = datas.find('\r\n', host_s)
            if host_s > 0 and host_e > 0:
                host_str = datas[host_s + 4:host_e].strip()
                add_list = host_str.split(':')
                if len(add_list) == 2:
                    host = add_list[0]
                    port = add_list[1]
                else:
                    host = add_list[0]
                    port = 80
                first_seg = datas.find('\r\n')
                first_line = datas[0:first_seg]
                first_line = first_line.replace(' http://%s' % mhost_str, ' http://%s' % host_str)
                datas = datas.replace('Host: %s' % mhost_str, 'Host: %s' % host_str)
                datas = datas.replace('zyx~ %s\r\n' % host_str, '')
                datas = first_line + datas[first_seg:]
        else:
            first_seg = datas.find('\r\n')
            head_e = datas.find('\r\n\r\n')
            host_s = datas.find('zyx~')
            mhost_s = datas.find('Host:')
            mhost_e = datas.find('\r\n', mhost_s)
            if mhost_s > 0 and mhost_e > 0:
                mhost_str = datas[mhost_s + 5:mhost_e].strip()
            if host_s < 0:
                host_s = datas.find('xxx:')
            if host_s > 0:
                host_e = datas.find('\r\n', host_s)
            if host_s > 0 and host_e > 0:
                host_str = datas[host_s + 4:host_e].strip()
            if first_seg > 0 and head_e > 0:
                first_line = datas[0:first_seg]
                first_line = first_line.replace('CONNECT %s' % mhost_str, 'CONNECT %s' % host_str)
                com, host_str, http_version = re.split('\\s+', first_line)
                add_list = host_str.split(':')
                if len(add_list) == 2:
                    host = add_list[0]
                    port = add_list[1]
                else:
                    host = add_list[0]
                    port = 443
                host_s = 1
                host_e = 1
        return (host_str,
        host_s,
        host_e,
        host,
        port,
        datas)


    def connect_pro(params, param, epoll_fd, datas, fd, cur_time, host, port):
        try:
            nextfd = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
            nextfd.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
            nextfd.settimeout(5)
            try:
                nextfd.connect((host, int(port)))
            except Exception as e:
                print 'ZProxy\xe8\xbd\xac\xe5\x8f\x91\xe5\xa4\xb1\xe8\xb4\xa5--%s:%s' % (host, port)

            nextfd.setblocking(0)
            next_fileno = nextfd.fileno()
            print 'ZProxy\xe8\xbd\xac\xe5\x8f\x91\xe6\x88\x90\xe5\x8a\x9f--%s:%s' % (host, port)
            if next_fileno in params:
                sys.exit(1)
            if not datas.startswith('CONNECT'):
                next_param = {'addr': [host, port],
                'writelen': 0,
                'connections': nextfd,
                'time': cur_time,
                'nextfd': fd}
                param['nextfd'] = next_fileno
                next_param['writedata'] = datas
                next_param['writelen'] = 0
                next_param['next'] = 'true'
                param['read_len'] = 0
                param['readdata'] = ''
                params[next_fileno] = next_param
                epoll_fd.register(next_fileno, select.EPOLLIN | select.EPOLLOUT | select.EPOLLERR | select.EPOLLHUP)
                epoll_fd.modify(fd, select.EPOLLIN | select.EPOLLERR | select.EPOLLHUP)
            else:
                next_param = {'addr': [host, port],
                'writelen': 0,
                'connections': nextfd,
                'time': cur_time,
                'nextfd': fd}
                param['nextfd'] = next_fileno
                next_param['next'] = 'true'
                params[next_fileno] = next_param
                epoll_fd.register(next_fileno, select.EPOLLIN | select.EPOLLERR | select.EPOLLHUP)
                param['read_len'] = 0
                param['readdata'] = ''
                param['writedata'] = 'HTTP/1.1 200 Connection Established\r\nConnection: close\r\n\r\n'
                param['writelen'] = 0
                param['reuse'] = 'true'
                epoll_fd.modify(fd, select.EPOLLIN | select.EPOLLOUT | select.EPOLLERR | select.EPOLLHUP)
        except socket.error as msg:
            clearfd(epoll_fd, params, fd)


    def process_datas(process_status, params, param, epoll_fd, datas, read_len, fd, cur_time):
        if process_status == 'close':
            clearfd(epoll_fd, params, fd)
        else:
            need_connect = False
            host_str = None
            host_s = -1
            host_e = -1
            if 'reuse' in param and 'next' not in param:
                if not datas.startswith('CONNECT') and not datas.startswith('GET') and not datas.startswith('POST') and not datas.startswith('PUT'):
                    del param['reuse']
                else:
                    host_str, host_s, host_e, host, port, datas = FindHostPort(datas)
                    host_s = int(host_s)
                    host_e = int(host_e)
                    next_fileno = param['nextfd']
                    next_param = params[next_fileno]
                    addr = next_param['addr']
                    if host_s > 0 and host_e > 0:
                        if host != addr[0] or str(port) != str(addr[1]):
                            print '%s,%s neq %s,%s' % (host,
                            port,
                            addr[0],
                            addr[1])
                            need_connect = True
                            del param['nextfd']
                            del next_param['nextfd']
                            clearfd(epoll_fd, params, next_fileno)
                        del param['reuse']
                    else:
                        param['read_len'] = read_len
                        param['readdata'] = datas
                        return
            if need_connect or 'nextfd' not in param:
                if host_str == None or not host_s > 0 or not host_e > 0:
                    host_str, host_s, host_e, host, port, datas = FindHostPort(datas)
                    host_s = int(host_s)
                    host_e = int(host_e)
                if host_s > 0 and host_e > 0:
                    if not datas.startswith('CONNECT'):
                        epoll_fd.modify(fd, select.EPOLLERR | select.EPOLLHUP)
                    thread.start_new_thread(connect_pro, (params,
                    param,
                    epoll_fd,
                    datas,
                    fd,
                    cur_time,
                    host,
                    port))
                else:
                    param['read_len'] = read_len
                    param['readdata'] = datas
            else:
                next_fileno = param['nextfd']
                next_param = params[next_fileno]
                if 'next' in param:
                    next_param['reuse'] = 'true'
                write_data = next_param.get('writedata', '')
                write_data += datas
                next_param['writedata'] = write_data
                param['read_len'] = 0
                param['readdata'] = ''
                epoll_fd.modify(next_fileno, select.EPOLLIN | select.EPOLLOUT | select.EPOLLERR | select.EPOLLHUP)
            if process_status == 'close_after_process':
                clearfd(epoll_fd, params, fd)
        return


    def run_main(listen_fd):
        try:
            epoll_fd = select.epoll()
            epoll_fd.register(listen_fd.fileno(), select.EPOLLIN | select.EPOLLERR | select.EPOLLHUP)
        except select.error as msg:
            print '\xe5\x87\xba\xe7\x8e\xb0\xe9\x94\x99\xe8\xaf\xaf'

        params = {}
        last_min_time = -1
        while True:
            epoll_list = epoll_fd.poll()
            cur_time = time.time()
            for fd, events in epoll_list:
                if fd == listen_fd.fileno():
                    while True:
                        try:
                            conn, addr = listen_fd.accept()
                            conn.setblocking(0)
                            epoll_fd.register(conn.fileno(), select.EPOLLIN | select.EPOLLERR | select.EPOLLHUP)
                            conn.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
                            params[conn.fileno()] = {'addr': addr,
                            'writelen': 0,
                            'connections': conn,
                            'time': cur_time}
                        except socket.error as msg:
                            break

                elif select.EPOLLIN & events:
                    param = params.get(fd, None)
                    if param == None:
                        continue
                    param['time'] = cur_time
                    datas = param.get('readdata', '')
                    cur_sock = params[fd]['connections']
                    read_len = param.get('read_len', 0)
                    process_status = 'close'
                    while True:
                        try:
                            data = cur_sock.recv(102400)
                            if not data:
                                if datas == '':
                                    break
                                else:
                                    raise Exception('close after process')
                            else:
                                datas += data
                                read_len += len(data)
                        except socket.error as msg:
                            if msg.errno == errno.EAGAIN:
                                process_status = 'process'
                                break
                            else:
                                break
                        except Exception as e:
                            process_status = 'close_after_process'
                            break

                    process_datas(process_status, params, param, epoll_fd, datas, read_len, fd, cur_time)
                elif select.EPOLLHUP & events or select.EPOLLERR & events:
                    clearfd(epoll_fd, params, fd)
                elif select.EPOLLOUT & events:
                    param = params.get(fd, None)
                    if param == None:
                        continue
                    param['time'] = cur_time
                    sendLen = param.get('writelen', 0)
                    writedata = param.get('writedata', '')
                    total_write_len = len(writedata)
                    cur_sock = param['connections']
                    f = param.get('f', None)
                    totalsenlen = param.get('totalsenlen', None)
                    if writedata == '':
                        clearfd(epoll_fd, params, fd)
                        continue
                    while True:
                        try:
                            sendLen += cur_sock.send(writedata[sendLen:])
                            if sendLen == total_write_len:
                                if f != None and totalsenlen != None:
                                    readmorelen = 102400
                                    if readmorelen > totalsenlen:
                                        readmorelen = totalsenlen
                                    morefiledata = ''
                                    if readmorelen > 0:
                                        morefiledata = f.read(readmorelen)
                                    if morefiledata != '':
                                        writedata = morefiledata
                                        sendLen = 0
                                        total_write_len = len(writedata)
                                        totalsenlen -= total_write_len
                                        param['writedata'] = writedata
                                        param['totalsenlen'] = totalsenlen
                                        continue
                                    else:
                                        f.close()
                                        del param['f']
                                        del param['totalsenlen']
                                if 'sendandclose' not in param:
                                    param['writedata'] = ''
                                    param['writelen'] = 0
                                    epoll_fd.modify(fd, select.EPOLLIN | select.EPOLLERR | select.EPOLLHUP)
                                else:
                                    clearfd(epoll_fd, params, fd)
                                break
                        except socket.error as msg:
                            if msg.errno == errno.EAGAIN:
                                param['writelen'] = sendLen
                                break
                            clearfd(epoll_fd, params, fd)
                            break

                else:
                    continue

            if cur_time - last_min_time > 20:
                last_min_time = cur_time
                objs = params.items()
                for key_fd, value in objs:
                    fd_time = value.get('time', 0)
                    del_time = cur_time - fd_time
                    if del_time > 20:
                        clearfd(epoll_fd, params, key_fd)
                    elif fd_time < last_min_time:
                        last_min_time = fd_time

        return


    if __name__ == '__main__':
        reload(sys)
        sys.setdefaultencoding('utf8')
        if len(sys.argv) < 2:
            port = 80
        else:
            port = int(sys.argv[1])
        print '\xe5\x90\xaf\xe5\x8a\xa8ZProxy\xe6\x88\x90\xe5\x8a\x9f,\xe7\x9b\x91\xe5\x90\xac\xe7\xab\xaf\xe5\x8f\xa3%s' % port
        print '\xe5\xbd\x93\xe5\x89\x8d\xe7\x89\x88\xe6\x9c\xac V0.12'
        try:
            listen_fd = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
        except socket.error as msg:
            print '\xe5\xa5\x97\xe6\x8e\xa5\xe5\xad\x97\xe5\x88\x9b\xe5\xbb\xba\xe5\xa4\xb1\xe8\xb4\xa5'

        try:
            listen_fd.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        except socket.error as msg:
            print '\xe5\xa5\x97\xe6\x8e\xa5\xe5\xad\x97\xe5\x88\x9b\xe5\xbb\xba\xe5\xa4\xb1\xe8\xb4\xa5'

        try:
            listen_fd.bind(('', port))
        except socket.error as msg:
            print '\xe7\xab\xaf\xe5\x8f\xa3\xe7\xbb\x91\xe5\xae\x9a\xe5\xa4\xb1\xe8\xb4\xa5'

        try:
            listen_fd.listen(10240)
            listen_fd.setblocking(0)
        except socket.error as msg:
            print '\xe5\xa5\x97\xe6\x8e\xa5\xe5\xad\x97\xe5\x88\x9b\xe5\xbb\xba\xe5\xa4\xb1\xe8\xb4\xa5'

        child_num = 19
        c = 0
        while c < child_num:
            c = c + 1
            newpid = os.fork()
            if newpid == 0:
                run_main(listen_fd)

        run_main(listen_fd)


标签: python 逆向