美文网首页
wifijammer源码分析一

wifijammer源码分析一

作者: lifesmily | 来源:发表于2017-05-02 21:18 被阅读136次

    处于学习别人代码风格阶段,github参考学习程序
    程序开头会有

    #!/usr/bin/python
    # -*- coding: utf-8 -*-
    

    一是用来指定脚本语言为 Python,二是用来指定文件编码为utf-8.

    1、Python logging 模块使用

    最好学习资料还是官方文档

    (1)输出等级

    logging是一个实用的辅助工具,可以分等级地打印调试信息或错误信息。分为五个等级:

    Paste_Image.png
    默认是warning等级。设置等级后只有大于等于该等级的信息会打印出。不指定文件则打印在终端上。可以通过以下方式指定输出文件和输出等级:
    logging.basicConfig(filename='example.log',level=logging.DEBUG)
    也可以在命令行通过 --log=INFO/DEBUG/ERROR等
    (2)格式化显示

    可以根据自己的需要改变显示信息的格式,如:

    logging.warning('%s before you %s', 'Look', 'leap!')

    import logging
    logging.basicConfig(format='%(levelname)s:%(message)s', level=logging.DEBUG)
    logging.debug('This message should appear on the console')
    logging.info('So should this')
    logging.warning('And this, too')
    

    打印出:

    DEBUG:This message should appear on the console
    INFO:So should this
    WARNING:And this, too

    即可以通过basicConfig改变输出格式,默认为

    WARNING:root:Look before you leap!

    关于时间

    import logging
    logging.basicConfig(format='%(asctime)s %(message)s')
    logging.warning('is when this event was logged.')
    

    打印出:

    2017-04-29 19:47:17,128 is when this event happened

    也可以改变默认的时间显示格式(some problem):

    logging.basicConfig(format='%(asctime)s %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p')
    
    (3)深入学习

    https://docs.python.org/2/howto/logging-cookbook.html#logging-cookbook
    程序示例:

    import logging
    
    logging.basicConfig(level=logging.DEBUG,
                    format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',
                    datefmt='%a, %d %b %Y %H:%M:%S',
                    filename='myapp.log',
                    filemode='w')
    
    #################################################################################################
    #定义一个StreamHandler,将INFO级别或更高的日志信息打印到标准错误,并将其添加到当前的日志处理对象#
    console = logging.StreamHandler()
    console.setLevel(logging.INFO)
    formatter = logging.Formatter('%(name)-12s: %(levelname)-8s %(message)s')
    console.setFormatter(formatter)
    logging.getLogger('').addHandler(console)
    #################################################################################################
    
    logging.debug('This is debug message')
    logging.info('This is info message')
    logging.warning('This is warning message')
    

    当没有指定filename时,默认为标准错误输出,如上程序中的StreamHandler。

    2、scapy工具使用

    scapy是一个强大的第三方库,用于网络嗅探。能够伪造或者解码大量的网络协议数据包,能够发送、捕捉、匹配请求和回复包等等。它可以很容易地处理一些典型操作,比如端口扫描,tracerouting,探测,单元 测试,攻击或网络发现(可替代hping,NMAP,arpspoof,ARP-SK,arping,tcpdump,tethereal,P0F等)。 最重要的他还有很多更优秀的特性——发送无效数据帧、注入修改的802.11数据帧、在WEP上解码加密通道(VOIP)、ARP缓存攻击(VLAN) 等,这也是其他工具无法处理完成的。

    有以下两种使用方式:

    执行sudo scapy命令进入交互式数据包处理,或在Python代码中使用from scapy.all import *引入scapy

    慢慢学习别人,造轮子

    3、threading模块实现多线程

    threading对thread(多线程底层支持模块,一般不建议使用)进行了封装,将一些线程的操作对象化
    参考 http://www.cszhi.com/20130528/python-threading.html

    import threading
     
    def thread_fun(num):
        for n in range(0, int(num)):
            print " I come from %s, num: %s" %( threading.currentThread().getName(), n)
     
    def main(thread_num):
        thread_list = list();
        # 先创建线程对象
        for i in range(0, thread_num):
            thread_name = "thread_%s" %i
            thread_list.append(threading.Thread(target = thread_fun, name = thread_name, args = (20,)))
     
        # 启动所有线程
        for thread in thread_list:
            thread.start()
     
        # 主线程中等待所有子线程退出
        for thread in thread_list:
            thread.join()
     
    if __name__ == "__main__":
        main(3)
    

    列表的广义化,列表可以是函数、类的集合。可以理解为存放的是地址。通过threading.Thread函数创建一个线程,指定target-回调函数,线程名以及参数等。
    thread.join()函数会依次检测线程池中的线程是否结束,没有结束就阻塞直到线程结束,结束后会跳转执行下一个线程的join函数。Python的join函数还可以设置超时时间,Thread.join([timeout])。

    上述是通过自定义创建函数,并通过Thread运行,也可以继承Thread类进行简化编程。

    import threading
     
    class MyThread(threading.Thread):
        def __init__(self):
            threading.Thread.__init__(self);
     
        def run(self):
            print "I am %s" %self.name
     
    if __name__ == "__main__":
        for thread in range(0, 5):
            t = MyThread()
            t.start()
    

    通过自定义run函数重写Thread中的run函数。

    扩展:
    (1)setdaemon函数

    Python中得thread的一些机制和C/C++不同:在C/C++中,主线程结束后,其子线程会默认被主线程kill掉。而在python中,主线程结束后,会默认等待子线程结束后,主线程才退出。
    setDaemon:主线程A启动了子线程B,调用b.setDaemaon(True),则主线程结束时,会把子线程B也杀死,与C/C++中得默认效果是一样的。

    #! /usr/bin/env python
    
    import threading
    import time
    
    class myThread(threading.Thread):
       def __init__(self, threadname):
         threading.Thread.__init__(self, name=threadname)
         self.st = 2
    
       def run(self):
         time.sleep(self.st)
         print self.getName()
       def setSt(self, t):
         self.st = t
    
    def fun1():
       t1.start()
       print "fun1 done"
    
    def fun2():
       t2.start()
       print "fun2 done"
    
    t1=myThread("t1")
    t2=myThread("t2")
    t2.setSt(10);
    # t2.setDaemon(True)
    fun1()
    fun2()
    print "now u will see me"
    

    当 t2.setDaemon(True)没有生效时,打印出

    fun1 done
    fun2 done
    now u will see me
    t1
    t2
    

    生效后,打印出

    fun1 done
    fun2 done
    now u will see me
    t1
    

    t2.setDaemon(True)表示主进程结束后立即结束子进程,不管子进程有没有运行完成。

    (2)互斥锁

    多个线程访问同一资源,由于先后顺序不确定,产生“线程不安全”,引入互斥锁,使无序变有序。

    import threading
    import time
     
    counter = 0
    mutex = threading.Lock()
     
    class MyThread(threading.Thread):
        def __init__(self):
            threading.Thread.__init__(self)
     
        def run(self):
            global counter, mutex
            time.sleep(1);
            if mutex.acquire():
                counter += 1
                print "I am %s, set counter:%s" % (self.name, counter)
                mutex.release()
     
    if __name__ == "__main__":
        for i in range(0, 100):
            my_thread = MyThread()
            my_thread.start()
    

    当一个线程调用Lock对象的acquire()方法获得锁时,这把锁就进入“locked”状态。因为每次只有一个线程1可以获得锁,所以如果此时另一个线程2试图获得这个锁,该线程2就会变为“block“同步阻塞状态。直到拥有锁的线程1调用锁的release()方法释放锁之后,该锁进入“unlocked”状态。线程调度程序从处于同步阻塞状态的线程中选择一个来获得锁,并使得该线程进入运行(running)状态。

    (3)避免死锁
    (4)进程间通信
    (5)管道pipe

    4、subprocess 模块

    官网参考资料
    subprocess允许开启一个新的进程,并与之通信。
    subprocess用来代替以下模块:

    • os.system
    • os.spawn*
    • os.popen*
    • popen2.*
    • commands.*
    (1)subprocess.call(args, *, stdin=None, stdout=None, stderr=None, shell=False)

    运行参数中的命令,并返回 returncode,如:
    subprocess.call(['ls','-al']) 在官方文档中有以下注意

    Note :Do not use stdout=PIPE or stderr=PIPE with this function as that can deadlock based on the child process output volume. Use Popen
    with the communicate() method when you need pipes.

    值得注意shell=False这个参数,根据官网shell=False比shell=True更安全,假设运行以下

     cmd = "cat test.txt; rm test.txt"  
    subprocess.call(cmd, shell=True)
    

    shell=True参数会让subprocess.call接受字符串类型的变量作为命令,并调用shell去执行这个字符串,第一个测试中的分号被认为是shell命令中的分隔符,执行了cat和rm两个命令。
    当shell=False时,subprocess.call只接受数组变量作为命令,并将数组的第一个元素作为命令,剩下的全部作为该命令的参数,因此第二个测试只执行了cat命令,并试着打开了作为参数的”text.txt;”,”rm” , “text.txt”三个文件。

    (2)subprocess.check_call (*popenargs , **kwargs )

    执行上面的call命令,并检查返回值,如果子进程返回非0,则会抛出CalledProcessError异常,这个异常会有个returncode
    属性,记录子进程的返回值。

    (2)subprocess.check_output(args, *, stdin=None, stderr=None, shell=False, universal_newlines=False)

    和上个函数类似,主要不同在于将所有输出保存为字符串,而不直接打印到标准输出。

    >>> import subprocess
    >>> str = subprocess.check_output(['echo','hello world'])
    >>> str
    'hello world\n'
    >>> 
    
    (3) class subprocess.Popen(args, bufsize=0, executable=None, stdin=None, stdout=None, stderr=None, preexec_fn=None, close_fds=False, shell=False, cwd=None, env=None, universal_newlines=False, startupinfo=None, creationflags=0)

    是该模块中最为重要的方法之一,创建一个新进程,类似于unix系统下的 os.execvp()
    ,windows下的 CreateProcess() 。

    >>> import shlex, subprocess
    >>> command_line = raw_input()
    /bin/vikings -input eggs.txt -output "spam spam.txt" -cmd "echo '$MONEY'"
    >>> args = shlex.split(command_line)
    >>> print args
    ['/bin/vikings', '-input', 'eggs.txt', '-output', 'spam spam.txt', '-cmd', "echo '$MONEY'"]
    >>> p = subprocess.Popen(args) # Success!
    

    shelex是一个简单的词典分析模块 ,shlex.split()
    可以被用于序列化复杂的命令参数,比如:

    >>> shlex.split('ls ps top grep pkill')
    ['ls', 'ps', 'top', 'grep', 'pkill']
    
    args参数:

    可以是一个字符串,可以是一个包含程序参数的列表。要执行的程序一般就是这个列表的第一项,或者是字符串本身。
    subprocess.Popen(["cat","test.txt"])
    subprocess.Popen("cat test.txt")
    这两个之中,后者将不会工作。因为如果是一个字符串的话,必须是程序的路径才可以。
    但是下面的可以工作 subprocess.Popen("cat test.txt", shell=True)
    这是因为它相当于 subprocess.Popen(["/bin/sh", "-c", "cat test.txt"])
    在*nix下,当shell=False(默认)时,Popen使用os.execvp()来执行子程序。args一般要是一个【列表】。如果args是个字符串的
    话,会被当做是可执行文件的路径,这样就不能传入任何参数了。

    executable参数 :

    很少用到,用来指定要执行的程序,一般程序可以用args参数指定。

    preexec_fn参数:

    如果把preexec_fn设置为一个可调用的对象(比如函数),就会在子进程被执行前被调用。(仅限*nix)

    close_fds参数:

    如果把close_fds设置成True,*nix下会在开子进程前把除了0、1、2以外的文件描述符都先关闭。在 Windows下也不会继承其他文件描述符。

    shell参数:

    如果把shell设置成True,指定的命令会在shell里解释执行。

    cwd参数:

    如果cwd不是None,则会把cwd做为子程序的当前目录。注意,并不会把该目录做为可执行文件的搜索目录,所以不要把程序文件所在
    目录设置为cwd 。

    env参数:

    如果env不是None,则子程序的环境变量由env的值来设置,而不是默认那样继承父进程的环境变量。注意,即使你只在env里定义了
    某一个环境变量的值,也会阻止子程序得到其他的父进程的环境变量
    后面几个很少用到。

    Popen类的method
    Popen.poll()

    Check if child process has terminated. Set and return returncode attribute.

    Popen.wait()

    Wait for child process to terminate. Set and return returncode attribute.

    Popen.communicate(input=None)

    Interact with process: Send data to stdin. Read data from stdout and stderr, until end-of-file is reached. Wait for process to terminate. The optional input argument should be a string to be sent to the child process, or None, if no data should be sent to the child.

    Popen.send_signal(signal)
    Popen.terminate()

    停止一个子进程,在linux下发送SIGTERM信号给子进程

    Popen.kill()

    杀死一个子进程,在linux下发送SIGKILL给子进程。

    常用的一些属性
    • Popen.returncode
    • Popen.pid
    • Popen.stderr
    • Popen.stdout
    • Popen.stdin
      对于Popen.stdin,如果stdin是PIPE,则这个属性返回的是为子进程提供输入的文件对象。
      同理,If the stdout argument was PIPE
      , Popen.stdout is a file object that provides output from the child process. Otherwise, it is None
      示例:
      output= dmesg | grep hda
      等价于
    p1 = Popen(["dmesg"], stdout=PIPE)
    p2 = Popen(["grep", "hda"], stdin=p1.stdout, stdout=PIPE)
    p1.stdout.close()  # Allow p1 to receive a SIGPIPE if p2 exits.
    output = p2.communicate()[0]
    

    注意以下几点:
    communicate函数返回一个元祖 (stdoutdata, stderrdata)
    当Popen函数中stdout=PIPE时,表示输出到一个管道中,要获取该管道,Popen.stdout会返回该句柄,可以通过读文件方法读出该管道中数据。

    pipe = os.popen("cmd", 'r', bufsize)
    ==>
    pipe = Popen("cmd", shell=True, bufsize=bufsize, stdout=PIPE).stdout
    

    相关文章

      网友评论

          本文标题:wifijammer源码分析一

          本文链接:https://www.haomeiwen.com/subject/kpoctxtx.html