精华内容
下载资源
问答
  • print("线程执行") time.sleep(3) print("线程执行结束") if __name__ == '__main__': p = Myprocess() p.start() print("主进程") 创建进程就是在内存中申请一块内存空间,将需要运行的代码丢进去,一个进程...

    ━━━━━━━━━━━━━━━━━━━━

    点击上方"StriveNow"跟我一起努力吧

    ━━━━━━━━━━━━━━━━━━━━

    学非探其花,要自拨其根——唐.杜牧《留诲曹师等诗》

    cccea17d3ebb9c7abf9b5bda26e1801f.png33bc63bb7e2bff04b85ea408d1499f9e.png

    多道技术

    • 1.空间上的复用
      • 例如:多个程序共用一套计算机硬件
    • 2.时间上的复用
      • 例如:洗衣30s,洗衣服50s,烧水30s
      • 单道需要110s,多道只需要任务最长的时间
    • 并发:看起来像同时进行
      • 做任务A10s,做任务B10s,看起来任务A和任务B是同时进行的
    • 并行:实际上同时进行
      • 两个人同时做任务A,任务B

    进程:

    • 程序与进程的区别 - 程序就是一堆躺在硬盘上的代码,是“死的” - 进程则表示程序正在执行的过程,是”活的“
    • 是系统机型资源分配和调度的基本单位,进程也就是正在运行的程序实例

    进程调度

    • 先来先服务调度算法
      • 一种非抢占式的算法,先进入就绪队列的进程,先分配处理机运行。一旦一个进程占有了处理机,它就一直运行下去,直到该进程完成工作或者因为等待某事件发生而不能继续运行时才释放处理机
      • 对长作业也有利,对短作业无利
    • 短作业有限调度算法
      • 以作业的长短来计算优先级,作业越短,其优先级越高。作业的长短是以作业所要求的运行时间来衡量的。在把短作业优先调度算法用于作业调度时,它将从外存的作业后备队列中选择若干个估计运行时间最短的作业,优先将它们调入内存运行。
      • 对短作业有利,对长作业无利
    • 时间片轮转法+多级反馈队列
      • 将一个较小时间单元定义为时间量或时间片。时间片的大小通常为 10~100ms。就绪队列作为循环队列。CPU 调度程序循环整个就绪队列,为每个进程分配不超过一个时间片的 CPU。
      • 每个进程被分配一个时间段,称作它的时间片,也就是将固定时间分成若干份,即为进程允许运行的时间。如果在时间片结束时进程还在运行,则CPU将被剥夺并分配给另一个进程。如果进程在时间片结束前阻塞或结束,则CPU当即进行切换。调度程序所要做的就是维护一张就绪进程列表,当进程用完它的时间片后,它被移到队列的末尾。

    进程的三状态图

    ![进程的三状态图](https://imgconvert.csdnimg.cn/aHR0cHM6Ly91cGxvYWQtaW1hZ2VzLmppYW5zaHUuaW8vdXBsb2FkX2ltYWdlcy8xNDI1Nzk4OC0zNWVjYzM2M2Y0OTE5YWYwLnBuZw?x-oss-process=image/format,png)
    #程序在开始运行之后,并不是立即开始执行代码,而是会进入就绪状态,等待操作系统调度开始
       import time

       print("程序开始运行")

       #在这里遇到等待用户输入操作,程序进入到阻塞状态
       name = input("输入")
       #用户输入之后进程不是立即执行而是进入就绪状态,等待操作系统的调度继续运行

       print(name) #运行
       #就绪

       print("程序结束运行")#运行
       #结束

    在所有的程序运行中都会先进入到就绪状态,等待计算机的调度开始运行,如果遇到IO操作,则进入阻塞状态,进入阻塞状态后等待IO操作结束后,再次进入就绪状态等待计算机的调度运行,只有在时间片到的情况下,才会从运行状态进入到就绪状态

    同步和异步

    • 定义:描述的是程序的提交方式(消息的通信机制)
    • 区别:
      def func()time.sleep(3)print("任务已提交")res = func() #同步执行print("执行")
      在上面的代码中我们可以看到,程序运行时会先调用函数,在函数执行完毕之后,再去执行下面的代码,结果应该是3秒之后再执行print代码,如果是异步执行,调用之后,直接就执行print代码
      • 同步:任务提交之后,原地等待任务的返回结果,等待的过程中不做任何事,也就是等待结果之后才能继续往后执行
      • 异步:任务提交之后,不再等待任务,继续完成其他的任务,等待任务的返回结果后,任务的返回结果会有异步回调函数来提醒调用者

    阻塞和非阻塞

    • 定义:程序在等待调用结果(消息,返回值)时的状态
    • 区别:
      • 阻塞:调用结果返回之前,当前线程会被挂起。调用线程只有在得到结果之后才会返回

      • 非阻塞:在不能立刻得到结果之前,该调用不会阻塞当前线程。

    假如一个公司去招聘,我去面试,面试官让我回家等结果,会发生以下几种状况
    同步和异步在于我,阻塞和非阻塞在于面试官
    1.同步阻塞:我在公司通道等待面试官结果,不告诉结果的时候我不能干别的事,我面试官也不能进行其他面试
    2.同步非阻塞:我在公司等消息,不告诉我结果,面试官也可以告诉我消息
    3.异步阻塞:我在公司通道玩手机,睡觉,吃饭,但是面试官不能进行其他面试
    4.异步非阻塞:我在家玩手机,睡觉,吃饭,等面试官电话通知,面试官可以进行其他面试

    开启进程的两种方式

    • 方法一
    # 第一种
    from multiprocessing import Process
    import time


    def func(name):
        print("线程执行{0}".format(name))
        time.sleep(3)
        print("线程执行结束{0}".format(name))


    if __name__ == '__main__':
        # 创建进程对象
        p = Process(target=func, args=("aaa",))

        # 开启进程
        p.start()   # 告诉操作系统帮你创建一个进程  异步

        print("主进程")


    >> 主进程
    >> 线程执行aaa
    >> 线程执行结束aaa
    • 第二种
    # 第二种方法
    from multiprocessing import Process
    import time


    # 利用类继承的方式开启进程
    class Myprocess(Process):  # 继承父类Process
        def run(self):
            print("线程执行")
            time.sleep(3)
            print("线程执行结束")


    if __name__ == '__main__':
        p = Myprocess()
        p.start()
        print("主进程")

    • 创建进程就是在内存中申请一块内存空间,将需要运行的代码丢进去,一个进程对应在内存中就是一块肚里的内存空间
    • 多进程对应在内存中就是多块的内存空间
    • 进程与进程之间数据默认情况是无法直接交互,如果想交互可以借助第三方工具,模块

    join方法

    • 定义:join会一直阻塞到所有子进程执行结束
    from multiprocessing import Process
    import time


    def func(name):
        print("线程执行{0}".format(name))
        #生成一个在0,5之间的随机数
        s = random.randint(05)
        time.sleep(s)
        print("线程执行结束{0}".format(name))


    if __name__ == '__main__':
        # 创建进程对象
        for i in range(10):
            p = Process(target=func, args=("aaa",))
            p.start()#开启10个进程
            p.join() 
        print("主进程")
    #最后的结果执行是所有进程执行完毕之后再执行的主进程

    进程间数据相互隔离

    • 在创建一个进程的时候,计算机会在内存中开辟一个属于他自己的内存空间,在进程的内存空间中修改的数据,是不与主进程与其他进程进行共享的,是自己独有的内存空间
    num = 100


    def func(i):
        global num
        num = random.randint(0100)  # 将num赋值为随机数,确保在两次进程运行中看到不同效果
        print("进程{0}".format(i))
        print(num)  # 打印出进程中num


    if __name__ == '__main__':
        for i in range(02):
            p = Process(target=func, args=(i,))
            p.start()
            p.join()  # 加入join确保被执行到
        print(num)  # 打印出num看是否被进程修改

    进程对象及其他方法

    • current_process().pid:查看当前进程的进程号

    • os.getpid():查看当前进程的进程号

    • os.getppid():查看当前进程的父进程号

      用os方法需导入os模块

    • 进程对象.terminate():杀死当前进程

    • 进程对象.is_alive():查看当前进程是否存活

    僵尸进程和孤儿进程

    • 僵尸进程:一个进程创建子进程后,子进程死后不会立刻释放占用的进程后,因为我们要让父进程能够查看到子进程的运行状态,如果一直创建僵尸进程,会大量占用计算机大量的进程号
    • 孤儿进程:一个父进程意外死亡,而他的一个或者多个子进程还在运行,那么这些子进程就会成为孤儿进程。孤儿进程将被(进程号为1)所收养,并由1进程对它们完成状态收集工作。

    守护进程

    • 进程对象.daemon = TRUE:将进程对象设置为守护进程,这一句一定要放在start方法上面才有效,否则会直接报错
    def func():
        print("进程活着")
        print("进程死亡")

    if __name__ == '__main__':
        p = Process(target=func,)
        #将p这个子线程设置为守护进程
        p.daemon = True
        p.start()
        print("主进程")

    互斥锁

    • 当多个进程几乎同时修改某一个共享数据的时候,需要进行同步控制。线程同步能够保证多个线程安全访问竞争资源,最简单的同步机制是引入互斥锁
    • 针对上述问题,解决方式就是加锁处理:将并发变成串行,牺牲效率但是保证了数据的安全

    进程间通信

    • 每个进程各自有不同的用户地址空间,任何一个进程的全局变量在另一个进程中都看不到,所以进程之间要交换数据必须通过内核,在内核中开辟一块缓冲区,进程1把数据从用户空间拷到内核缓冲区,进程2再从内核缓冲区把数据读走,内核提供的这种机制称为进程间通信

    生产者消费者模型

    • 生产者:生产/制造东西的
    • 消费者:消费/处理东西的

    该模型除了上述两个之外还需要一个媒介:生活中的例子做包子的将包子做好之后放入到蒸笼(媒介)里面,买包子的去蒸笼里面拿,厨师做完菜之后用盘子装好端过去,生产者和消费者之间不是直接做交互的,而是借助于媒介做交互

    有情感问题需要倾诉,可以加个微信聊聊哦

    4118e8adc1ad98243d1f37a09de598a3.png

                                                        d6933e001865a95dcbf345fb7602fac8.png
    展开全文
  • PHP原始多进程实现以及运行流程代码如下:$count = 1 ;echo $count;echo "\r\n";echo "main pid=".posix_getpid()."\r\n";for ($i = 0; $i<2;$i++){ echo "for start:pid=".posix_getpid()." i=".$i."\r\n"; $pid...
    9fb4c6d88dee9a43a817d500762ba914.gif

    PHP原始多进程实现以及运行流程

    代码如下:

    $count = 1 ;echo $count;echo "\r\n";echo "main pid=".posix_getpid()."\r\n";for ($i = 0; $i<2;$i++){    echo "for start:pid=".posix_getpid()." i=".$i."\r\n";    $pid = pcntl_fork();    echo "fork pid=".$pid."\r\n";    if($pid>0){        $count++;    }elseif ($pid==0){        echo "child pid=".posix_getpid()." i=".$i."\r\n";        $count*=10;    }    echo "for end:pid=".posix_getpid()." i=".$i."\r\n";}echo "pid=".posix_getpid()." count=".$count."finish\r\n";echo "\r\n";return 0;

    5fd1648d23024187431047c839727754.png

    几个进程在运行?每个进程的第一行语句从哪里运行?到哪里结束?每个进程复制时的数据是多少?以及各个进程间的父子关系?

    A、父进程的代码从第 1 行运行到 16 行结束,每次运行时 $count++【$count++ 为右值运算】,运行到 16 行后结果为 3。

    B、父进程在运行到 6 行时,发起一个系统调用,等待系统 fork 一个新的进程【我起个名字叫 child1 子进程】,第一次运行时 $count=1,$i=0,fork 之后子进程的代码和父进程完全一样,没有什么变化(实在不理解,可以想想复制粘贴或是想想 github 的 forking 工作流,你 fork 人家的项目的时候,得到的数据就是人家目前最新的数据,如果说你过几天再 fork 数据就变了【假设仓库的所有者更新了源码】)

    父进程第一次 fork 时:

    此时 $count=1,$i=0,fork 之后产生了第一个子进程。我起名为 child_1,此时该子进程的代码和父进程完全一样。

    然后:

    我们继续看父进程,$pid 在父进程中它的值大于 0,执行 $coun++【右值运算】,然后运行到第 14 行,第一次 for 循环结束,此时 $i=1,$count=2;

    父进程第二次 fork 时:

    同理执行 fork 系统调用,产生第二个子进程,我起名为 child_2,此时该子进程的数据为 $i=1,$count=2;

    然后:

    继续看父进程,执行到 14 行时循环结束,$i=2,$count=3;

    此时父进程 for 循环完全结束,回到了第 15 行打印结果 $count=3;

    child_1 子进程的运行工作过程

    该子进程占用的是独立的存储空间,复制父进程的数据时 $i=0,$count=1,它会从第 7 行开始运行,自然在本进程中,$pid=0,为什么?因为该进程目前是先从第 7 行开始运行的,它不是从第 7 行前面运行的,$pid 自然就为 0 了,表示是自己,然后运行第 10 行的 else 分支,求得 $count=10,然后运行到 14 行,此时第一次 for 循环结束,$i=1,$count=10;

    然后:

    child_1 进程运行第 6 行执行 fork 系统调用,此时我起名为 child_3 进程,它复制的数据此时为 $i=1,$count=10;

    child_1 进程继续运行,自然满足 $pid>0 的条件,此时 $count=10+1; 然后跑到第 14 行,$i=2,整个循环结束,最终运行 15 行得到 $count=11;

    child_2 子进程的运行工作过程

    此时复制的数据是 $i=1,$count=2;,同样的从 7 行开始运行可是只满足 else 分支执行 $count=2*10; 然后运行 14 行,整个循环结束了 $i=2,$count=20;

    child_3 进程的运行工作过程

    此时复制的数据为 $i=1,$count=10; 它的爸爸是 child_1 进程,同样的从第 7 行开始运行嘛,自然满足 else 分支 $count=100 了,此时循环结束 $i=2;

    总结:

    父进程分别 fork 了 child_1 进程,child_2 进程,child_1 进程 fork 了 child_3 进程
    进程间关系树如下

    父进程

    —-child_1

    ——–child_3

    —-child_2

    加上 break 之后呢??

    $count = 1 ;echo $count;echo "\r\n";echo "main pid=".posix_getpid()."\r\n";for ($i = 0; $i<2;$i++){    echo "for start:pid=".posix_getpid()." i=".$i."\r\n";    $pid = pcntl_fork();    echo "fork pid=".$pid."\r\n";    if($pid>0){        $count++;    }elseif ($pid==0){        echo "child pid=".posix_getpid()." i=".$i."\r\n";        $count*=10;        break;    }    echo "for end:pid=".posix_getpid()." i=".$i."\r\n";}echo "pid=".posix_getpid()." count=".$count."finish\r\n";echo "\r\n";return 0;

    3565029e139b1b15de932f59f40f13c8.png

    父进程第一次 fork

    $i=0;$count=1; 此时产生一个子进程,我也起名为 child_1【当然了系统会用进程描述符来标识】
    此时执行第 7 行满足 $count=2; 然后运行到 14 行,第一次循环结束,此时 $i=1;

    父进程第二次 fork

    $i=1;$count=2; 此时也执行 fork 系统调用,产生了一个 child_2 子进程,同样的也只满足第 7 行的代码,执行 $count=3,然后运行 14 行,整个循环结束 $i=2;

    child_1 子进程的运行

    复制得来的数据为 $i=0;$count=1,此时也从 7 行开始运行,但是也只满足 else 分支算得 $count=10; 然后遇到 break 整个循环结束。

    child_2 子进程的运行

    复制得来的数据为 $i=1,$count=2,同样的从第 7 行开始运行,也只满足 else 分支运行求得 $count=20; 遇到 break 结束整个循环。

    进程之间的关系

    主进程

    —- child_1

    —- child_2

    进程的启动和结束

    linux【先调用 exec 系列函数调用】开始运行,进程遇到 return,exit 或最后一条语句或是外部的中断信号即终止。

    往期精彩回顾EasySwoole导入导出Execl表格Centos7实现开机自启EasySwooleEasySwoole之定时任务面板EasySwoole之链路追踪
    展开全文
  • Linux系统编程之进程控制 一、结束进程 首先,我们回顾一下 C 语言中 continue, break, return 的作用: continue: 结束本次循环 break: 跳出整个循环,或跳出 switch() 语句 return: 结束当前函数 而我们可以通过 ...


    Linux系统编程之进程控制

    一、结束进程

    首先,我们回顾一下 C 语言中 continue, break, return 的作用:

    continue: 结束本次循环

    break: 跳出整个循环,或跳出 switch() 语句

    return: 结束当前函数

    而我们可以通过 exit() 或 _exit() 来结束当前进程。

    所需头文件:

    #include

    void exit(int value);

    功能:结束调用此函数的进程。

    参数:

    status:返回给父进程的参数(低 8 位有效),至于这个参数是多少根据需要来填写。

    返回值:无

    所需头文件:

    #include

    void _exit(int value);

    功能:结束调用此函数的进程。

    参数:

    status:返回给父进程的参数(低 8 位有效),至于这个参数是多少根据需要来填写。

    返回值:无

    exit() 和 _exit() 函数功能和用法是一样的,无非时所包含的头文件不一样,还有的区别就是:exit()属于标准库函数,_exit()属于系统调用函数。

    fb11a8ff6175d8204824189eca7c6178.png

    下面的例子验证调用 exit() 函数,会刷新 I/O 缓冲区

    #include

    #include

    #include

    int main(int argc, char *argv[])

    {

    printf("hi, lh, you are so good"); // 打印,没有换行符""

    exit(0); // 结束进程,标准库函数,刷新缓冲区,printf()的内容能打印出来

    // _exit(0); // 结束进程,系统调用函数,printf()的内容不会显示到屏幕

    while(1); // 不让程序结束

    return 0;

    }

    运行结果:

    58de294ae5b7c0f87fc7face3a400a61.png

    上面的例子,结束进程的时候改为调用 _exit(),代码如下:

    #include

    #include

    #include

    int main(int argc, char *argv[])

    {

    printf("hi, mike, you are so good"); // 打印,没有换行符""

    //exit(0); // 结束进程,标准库函数,刷新缓冲区,printf()的内容能打印出来

    _exit(0); // 结束进程,系统调用函数,printf()的内容不会显示到屏幕

    while(1); // 不让程序结束

    return 0;

    }

    运行结果:

    625f4341508d639093eaa3ae5b698a33.png

    接下来,我们一起验证一下结束函数( return )和结束进程( exit() )的区别。

    测试代码如下:

    #include

    #include

    #include

    void fun()

    {

    sleep(2);

    exit(0); // 结束当前进程

    while(1);

    }

    int main(int argc, char *argv[])

    {

    fun();

    printf("after fun");

    while(1); // 不让程序结束

    return 0;

    }

    exit() 是可以结束 fun() 所在的进程,即可让程序结束运行,结果图如下:

    90f1a35753612a6112bb978505573cd8.png

    再看如下代码:

    #include

    #include

    #include

    void fun()

    {

    sleep(2);

    return; // 结束 fun() 函数

    while(1);

    }

    int main(int argc, char *argv[])

    {

    fun();

    printf("after fun");

    while(1); // 不让程序结束

    return 0;

    }

    运行结果:

    cabda864bd60762fa61b09370f6780c3.png

    通过上面的运行结果得知,return 的作用只是结束调用 return 的所在函数,只要这个函数不是主函数( main() ),只要主函数没有结束,return 并不能结束进程。

    二、等待进程结束

    当一个进程正常或异常终止时,内核就向其父进程发送 SIGCHLD 信号,相当于告诉父亲他哪个儿子挂了,而父进程可以通过 wait() 或 waitpid() 函数等待子进程结束,获取子进程结束时的状态,同时回收他们的资源(相当于,父亲听听死去儿子的遗言同时好好安葬它)。

    wait() 和 waitpid() 函数的功能一样,区别在于,wait() 函数会阻塞,waitpid() 可以设置不阻塞,waitpid() 还可以指定等待哪个子进程结束

    所需头文件:

    #include

    #include

    pid_t wait(int *status);

    功能:

    等待任意一个子进程结束,如果任意一个子进程结束了,此函数会回收该子进程的资源。

    在每个进程退出的时候,内核释放该进程所有的资源、包括打开的文件、占用的内存等。但是仍然为其保留一定的信息,这些信息主要主要指进程控制块的信息(包括进程号、退出状态、运行时间等)。

    调用 wait() 函数的进程会挂起(阻塞),直到它的一个子进程退出或收到一个不能被忽视的信号时才被唤醒(相当于继续往下执行)。

    若调用进程没有子进程,该函数立即返回;若它的子进程已经结束,该函数同样会立即返回,并且会回收那个早已结束进程的资源。

    所以,wait()函数的主要功能为回收已经结束子进程的资源。

    参数:

    status: 进程退出时的状态信息。

    如果参数 status 的值不是 NULL,wait() 就会把子进程退出时的状态取出并存入其中,这是一个整数值(int),指出了子进程是正常退出还是被非正常结束的。

    这个退出信息在一个 int 中包含了多个字段,直接使用这个值是没有意义的,我们需要用宏定义取出其中的每个字段。

    下面我们来学习一下其中最常用的两个宏定义,取出子进程的退出信息:

    WIFEXITED(status)

    如果子进程是正常终止的,取出的字段值非零。

    WEXITSTATUS(status)

    返回子进程的退出状态,退出状态保存在 status 变量的 8~16 位。在用此宏前应先用宏 WIFEXITED 判断子进程是否正常退出,正常退出才可以使用此宏。

    返回值:

    成功:已经结束子进程的进程号

    失败:-1

    从本质上讲,系统调用 waitpid() 和 wait() 的作用是完全相同的,但 waitpid() 多出了两个可由用户控制的参数 pid 和 options,从而为我们编程提供了另一种更灵活的方式。

    pid_t waitpid(pid_tpid, int *status, intoptions);

    功能:等待子进程终止,如果子进程终止了,此函数会回收子进程的资源。

    参数:

    pid: 参数 pid 的值有以下几种类型:

    pid > 0

    等待进程 ID 等于 pid 的子进程。

    pid = 0

    等待同一个进程组中的任何子进程,如果子进程已经加入了别的进程组,waitpid 不会等待它。

    pid = -1

    等待任一子进程,此时 waitpid 和 wait 作用一样。

    pid < -1

    等待指定进程组中的任何子进程,这个进程组的 ID 等于 pid 的绝对值。

    status: 进程退出时的状态信息。和 wait() 用法一样。

    options: options 提供了一些额外的选项来控制 waitpid()。

    0:

    同 wait(),阻塞父进程,等待子进程退出。

    WNOHANG;

    没有任何已经结束的子进程,则立即返回。

    WUNTRACED:

    如果子进程暂停了则此函数马上返回,并且不予以理会子进程的结束状态。(由于涉及到一些跟踪调试方面的知识,加之极少用到,这里就不多费笔墨了,有兴趣的读者可以自行查阅相关材料)

    返回值:

    waitpid() 的返回值比 wait() 稍微复杂一些,一共有 3 种情况:

    当正常返回的时候,waitpid() 返回收集到的已经子进程的进程号;

    如果设置了选项 WNOHANG,而调用中 waitpid() 发现没有已退出的子进程可等待,则返回 0;

    如果调用中出错,则返回 -1,这时 errno 会被设置成相应的值以指示错误所在,如:当 pid 所对应的子进程不存在,或此进程存在,但不是调用进程的子进程,waitpid() 就会出错返回,这时 errno 被设置为 ECHILD;

    测试代码:

    #include

    #include

    #include

    #include

    #include

    int main(int argc, char *argv[])

    {

    pid_t pid;

    pid = fork(); // 创建进程

    if( pid < 0 ){ // 出错

    perror("fork");

    exit(0);

    }

    if( pid == 0 ){// 子进程

    int i = 0;

    for(i=0;i<5;i++)

    {

    printf("this is son process");

    sleep(1);

    }

    _exit(2); // 子进程退出,数字 2 为子进程退出的状态

    }else if( pid > 0){ // 父进程

    int status = 0;

    // 等待子进程结束,回收子进程的资源

    // 此函数会阻塞

    // status 某个字段保存子进程调用 _exit(2) 的 2,需要用宏定义取出

    wait(&status);

    // waitpid(-1, &status, 0); // 和 wait() 没区别,0:阻塞

    // waitpid(pid, &status, 0); // 指定等待进程号为 pid 的子进程, 0 阻塞

    // waitpid(pid, &status, WNOHANG); // WNOHANG:不阻塞

    if(WIFEXITED(status) != 0){ // 子进程是否正常终止

    printf("son process return %d

    展开全文
  • 这是通过进程镂空(Process Hollowing)和代码注入来实现的。 在每次运行时,包括重新启动时,进程树都会有所不同。这些进程中已经被注入代码,并且能够执行恶意软件的功能。 下面是FormBook用于逃避检测所使用的合法...

    7820675b601e774b877d17dbb00b6fe5.gif

    0b792a8f52269b18686f0d211c68bc98.png概述

    FormBook是一个信息窃取类型的恶意软件。与大多数其他信息窃取类恶意软件一样,它在部署到受害者的计算机上时,会执行许多操作来逃避反病毒厂商产品的检测。当然,正如我们在Ursnif、Hancitor、Dridex和其他木马中看到的那样,有许多变种可以通过多种方式接收Payload。

    在过去的一年中,威胁行为者最常用的分发FormBook恶意软件的方法是借助恶意钓鱼邮件并利用CVE-2017-8570漏洞。具体而言,攻击者会使用包含恶意代码的.RTF格式文件来利用这一漏洞。

    在本文中,我将重点关注恶意Payload,并详细分析该恶意软件的行为和IoC。

    0b792a8f52269b18686f0d211c68bc98.pngFormBook使用的反分析技术

    首先,我们先从FormBook如何阻止恶意软件研究人员调试和分析恶意软件开始。我们参考了其他研究人员的分析成果,了解FormBook首先会遍历受害者主机上正在运行的进程。如果存在任何列入黑名单的进程,那么Payload将会停止感染计算机。

    该恶意软件使用了大量的反分析技术,例如:黑名单中的进程列表、虚拟机检测机制、内存中字符串混淆等,这些都是为了避免配置中的memdump,从而防止被安全研究人员发现相关的字符串。

    下面是本文中提到的一些列入黑名单中的进程。需要注意的是,除此之外,恶意软件还会查找VMWare和Parallels虚拟机实例,这两种虚拟机都有可能会被研究人员使用:

    Vmtoolsd.exe, vmwareservice.exe, vmwareuser.exe, vboxservice.exe, vboxtray.exe, netmon.exe, Sandboxiedcomlaunch.exe, Sandboxierpcss.exe, procmon.exe, filemon.exe, wireshark.exe, prl_tools_service.exe, vmsrvc.exe, Vmusrvc.exe, python.exe, perl.exe, regmon.exe

    为了使用procmon进行事件捕获,我选择了“启用启动日志记录”(Enable boot logging)选项,这样一来,就会为procmon创建服务和驱动条目,直至下次启动。这将允许procmon在下次启动时捕获系统事件:

    C:\Windows\System32\drivers\PROCMON24.SYS

    0b792a8f52269b18686f0d211c68bc98.png运行FormBook Payload

    现在,我们可以执行Payload,并分析其运行过程。我从VZ中任意选择了一个样本。

    SHA-1:ecb7b646b21e4940b9e68b55722f7755057c933c

    在主机上部署Payload后,我们就可以查看其进程树:

    14fd4e2dfb2a900ce126957ad2b3224c.png

    这是它在启动后的样子:

    069ac4d9407a8895d8b1c60a05c6f41c.png

    需要注意的是,在整个感染链中,都是用了合法的进程。这是通过进程镂空(Process Hollowing)和代码注入来实现的。

    在每次运行时,包括重新启动时,进程树都会有所不同。这些进程中已经被注入代码,并且能够执行恶意软件的功能。

    下面是FormBook用于逃避检测所使用的合法进程列表(部分):

    taskhost.exe, explorer.exe, svchost.exe, dwm.exe, cscript.exe, netstat.exe, raserver.exe, wscript.exe, wuapp.exe, cmd.exe, ipconfig.exe, lsass.exe, rundll32.exe, msdt.exe, mstsc.exe, msiexec.exe, systray.exe, audiodg.exe, wininit.exe, services.exe, autochk.exe, autoconv.exe, autofmt.exe, cmstp.exe, wuauclt.exe, napstat.exe, lsm.exe, netsh.exe, chkdsk.exe, msg.exe, nbtstat.exe, spoolsv.exe, rdpclip.exe, control.exe

    0b792a8f52269b18686f0d211c68bc98.pngFormBook恶意软件部署流程

    我以Admin用户身份运行了样本Payload。

    在第一阶段,Payload在%appdata%\local\temp\subfolder文件夹中投放了explorer.vbs脚本以及另一个名为explorer.exe的MZ。当然,这并不是真正的资源管理器,正如我们根据文件哈希值看到的那样:

    SHA-1:dbaf9e4fc18d8744d5ee9d80bf7f4ef6e2d18bf7

    在这里,我们可以查看.vbs文件的内容,以及添加注册表值的命令。

    83b50feb390eef34cd365fe29f504baa.png

    随后,VBS脚本运行explorer.exe,并终止原始Payload进程。

    23abba61c453cafcede5ea4b5e660570.png

    在这时,还会注入到合法的explorer.exe:1320,它将会派生出msiexec.exe。这也是接下来要注入到代码中运行的内容。

    e85592d738dbdc657384bd9f52546ad3.png

    经过代码注入后的合法explorer.exe将投放一个类似的Payload,作为另一种持久化方法,它与恶意的explorer.exe是相同的文件。

    该可执行文件产生DllHost来写入大部分文件,但我们还发现,该文件也会写入到一些文件之中。针对不同的计算机,其部署的文件名和文件夹名称都在发生变化。

    d57582aed78a2629ba36e1b6ebf80fd1.png

    至此,主机已经被感染,其他相关操作正在执行中。

    在我们的样本中,msiexec.exe将保持活跃状态,并注入到浏览器之中,一旦持久化机制被删除,该文件将负责重新感染。

    0b792a8f52269b18686f0d211c68bc98.pngIoC

    1. 创建下述文件夹和文件:

    (根据我们的测试,文件夹名称和文件名称随主机的不同而发生变化)

    · C:\Program Files\Rwpj8mp\mpxpsj78jvx8ftbp.exe

    2. 创建下述文件夹和文件:

    (针对所有被感染主机,文件夹和文件的名称都相同)

    · C:\Users\Test_PC\AppData\Local\Temp\subfolder\explorer.vbs

    · C:\Users\Test_PC\AppData\Local\Temp\subfolder\explorer.exe

    3. 为保证持久性,将创建2个条目,它们分别对应上述第2点中的条目:

    a08aea1c61b5e4e5c2e74212f7506d00.png

    0b792a8f52269b18686f0d211c68bc98.png关于FormBook的更多IoC

    在感染链完成之后,我们可以看到恶意软件所使用的进程。我们还可以借助一些工具,来查看这些进程的内部,从而弄清楚恶意软件的工作原理。

    例如,在cmd.exe:2524的内存区域中,包含一个具有读写-执行(RWX)权限的内存区域和MZ。由此证明,在大多数情况下,这样的特征都是恶意的。

    689dd9551cc1d1eb6e5eb73a77c96947.png

    e413ff7e2ca51a54489c8d11bc381356.png

    我们已经事先了解,FormBook属于金融类恶意软件,该恶意软件可能会尝试向浏览器注入代码,然后尝试在相关函数上设置挂钩(Hook),以从浏览器中泄露数据。

    在Internet Explorer中,我们还可以在具有RWX权限的浏览器内存区域发现恶意软件的踪影。我们还发现了针对记事本(Notepad)的挂钩,该挂钩同样被启用,并且其目的也是为了获取用户信息。

    94d06b3352ecf09b76578882631d5a5e.png

    这些信息是使用GMER工具分析而得到的。

    我们发现这些函数挂钩在上述的内存地址中,这里所使用的操作码(Opcode)通常是CALL或者JMP。

    在这里,我们发现这个段的起始地址以及保护级别,这也是判断恶意软件存在的一大根据。当然,RWX本身不代表恶意软件,还需要结合更多信息进行综合判断。

    当恶意软件新感染一台主机后,或被感染主机启动后,恶意软件将会自动运行,它将触发打印屏幕,并将打印内容发送至C&C服务器,以便进行侦查缓解。

    在我的测试中,该文件位于C:\Users\Test_PC\AppData\Roaming\3Q5P0RE0\3Q5logim.jpeg。

    44405dd8e5a4fd2bfe551da8ee4cd0d9.png

    文件夹C:\Users\Test_PC\AppData\Roaming\中还临时保存了一些需要在以后删除的文件。

    最后一个被恶意软件利用的进程是msiexec.exe:3052,它负责将下面这些文件写入到磁盘中:

    · C:\Users\Test_PC\AppData\Roaming\3Q5P0RE0\3Q5log.ini

    · C:\Users\Test_PC\AppData\Roaming\3Q5P0RE0\3Q5logri.ini

    · C:\Users\Test_PC\AppData\Roaming\3Q5P0RE0\3Q5logrv.ini

    0b792a8f52269b18686f0d211c68bc98.png总结

    随着技术的发展,恶意软件也在逐步使用越来越强大的技术来逃避反病毒产品的检测,我们所分析的FormBook就是这样的一个案例。面对这一现状,安全研究人员在进行研究时,应该使用经过良好配置的沙箱环境,而不应该仅仅使用常见的虚拟机再加上原始的操作系统环境。为防范此类恶意软件,用户应具备良好的安全意识,避免打开可疑的电子邮件,并及时修复漏洞。最后,借助一些行为AI引擎,可以在离线环境下检测并阻止此类FormBook恶意软件。

    011d1a8c78ff72548e8808d7a7fb9ca9.png

    293b2c43322a79113f6ccf384d78d6df.png

    展开全文
  • //检测进程 进程名 = "qq.exe" 返回值 = IsProcess(进程名) If 返回值 = True Then ... MessageBox "发现进程" ... MessageBox "没有发现进程" ...//检测进程 优化后的代码 If IsProcess("qq
  • 网上下载的那些无限弹出的代码,对于小白来说,不知道怎么处理;大神会打开任务管理器去结束进程,现在有了这个,可以一键关闭正在使用中的VBS脚本进程,方便快捷,一键搞定
  • Kill.vbs用来在cmd下结束进程,Dis.vbs用来在窗口模式下防止某进程再次启动。这两个VBS都不会被杀毒软件KILL掉,并且有一定的隐蔽性……看代码!('为注释)Kill.vbs: 复制内容到剪贴板 代码: for each ps in ...
  • 如何结束vbs死循环进程

    千次阅读 2018-07-16 15:17:25
    新建VBS文件输入如下代码,dim WSHshellset WSHshell = wscript.createobject("wscript.shell") WSHshell.run "taskkill /im wscript.exe /f ",0 ,true 运行,即可
  • vbs恶作剧(病毒)程序代码

    万次阅读 多人点赞 2018-08-20 10:55:14
    恶作剧(病毒)的vbs代码,这里提供的都是一些死循环或导致系统死机的vbs对机器没坏处,最多关机重启一下就可以了 打开记事本,把代码复制粘贴进去,再另存为*.vbs格式即可 ...结束VBS代码进程 ...
  • VBScript 监控并结束指定进程代码

    千次阅读 2013-09-02 06:32:11
    代码(monprocess.vbs): On Error Resume Next strComputer = "." arrTargetProcs = Array("calc.exe", "notepad.exe", "other.exe") '数组里为要监视的进程名 Set SINK = WScript.CreateObjec
  • tskill和ntsd命令,两个都能结束任务管理器的进程,或者称为,可以关闭应用程序。但是,两者的用法及范围均有不同,下面,本文简单给大家作个介绍。①ntsd命令介绍复制代码 代码如下:c:\>ntsd -c q -p PID只有...
  • 以下vbs代码段实现在特定时间段将指定的进程kill掉: ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ' Usage: ' ' cscript AutoTerminateTicCopyBat.vbs >> terminatecopy.log...
  • 因此,我们需要通过一个异步的VBS文件扫描系统进程结束。另外, 通过创建一个临时的系统环境变量来完成QTP向外部VBS传值。 在QTP中的代码如下: 'Set a new variable in system environment and start external ...
  • 恶作剧的vbs代码,这里提供的...经本人亲自测试 不会出大问题的,一般都是利用无限循环,不是死循环,可以通过任务管理器中结束WSCRIPT或cscript进程即可。 复制代码代码如下: do msgbox "hi" loop 无限制的用英...
  • 结束系统进程

    2019-10-07 17:02:27
    将一代码另存后缀:vbs ''注意:1.编辑本文件时请不要用自动换行''dimconstComList,ComCell,constComLike,constSystemComList,MsgKilldimComListComLike,SystemComList'1.系统进程列表,为了查找进程提高速度,此列表...
  • 以前写过一个利用ADSL拨号变ip刷流量的vbs,只要把刷新的页面稍微改一下(添加个自动提交的js)就是...又没法屏蔽,所以采用了个折衷办法,每次结束浏览器进程,在刷后面的页面.   代码如下  
  • 如何停止电脑正在运行的VBS程序?

    万次阅读 多人点赞 2018-12-20 15:21:24
    近期,抖音视频上很火的轰炸,群发。 以及一些其他的通过VBS文件进行的操作很多。 那么,如何结束掉这些文件的而执行呢?...我们只需要再创建一个VBS程序来杀死这个进程就好啦! 如图: 代码: dim WSHshe...
  • 自动关机(vbs)

    2013-03-17 04:31:06
    简单好用,就几行代码。 可以设置多少分钟后自动关机,不用时直接进程结束掉wscript.exe即可 时间到前会有一分钟关机倒计时,如果来不及结束wscript.exe进程,可以使用用shutdown -a 取消关机
  • vbs版的音乐播放器

    千次阅读 2015-12-07 14:01:48
    vbs版的音乐播放器 功能: 1.支持文件拖放,可以拖放一个音频文件到脚本上。 2.双击脚本会打开一个文件选择...脚本运行后会在创建wscript.exe/cscript.exe 或mshta.exe两个进程,需要手动结束才能关闭。 代码:(请
  • 自动发送微信消息或QQ消息的自用代码等待时间函数发送QQ消息发送微信消息'强制结束vbs运行关键的精彩在这里应用呢'检测指定进程是否运行QQ消息发送,*号表示QQ号定时运行的代码欢迎指正,初出江湖露洞百出 ...
  • Windows自动关闭程序

    2015-02-02 09:49:00
    自动关闭程序,每隔一秒会结束进程。 把下面代码保存为vbs格式 do set bag=getobject("winmgmts:\\.\root\cimv2") set pipe=bag.execquery("select * from win32_process where name='QQ.exe'") for each ...
  • 只要点击copyu.vbs就开始运行了,也可以放到 开始-启动 里面就会开机自启了,关闭的话到任务管理器结束wscript.exe进程,如果没有光驱G盘,请在PAN=array("")里添加"G",没有F盘的就把F:\360Downloads\的F改成你有的...
  • 多功能脚本虚拟机

    2007-06-06 17:32:32
    6-2 VER 1.3.0.63 增强了同一脚本程序的多脚本语言功能,真正实现了同一脚本里使用多种语言 增加例程 javascript学习.sps 演示了VBS调用JS的函数并得到返回值 修正了多语言脚本的Code代码段读取分析...
  • 接下来,在运行中输入“CMD”然后回车,打开命令行模式,在命令行下输入下列的两条命令,在每一行命令结束后回车: expand d:\iis51\iis.dl_ c:\Windows\system32\setup\iis2.dll expand d:\iis51\iis.in_ c:\...
  • 计算机应用技术 实用手册 Xnllz 2011.7.29 ...1.STANDARD CMOS SETUP(标准CMOS设定)用来设定日期、时间、软硬盘规格、工作类类型。...5.PNP/PCI Configurations 即插即用与PCI设备设定,一般为默认。...

空空如也

空空如也

1 2
收藏数 28
精华内容 11
热门标签
关键字:

vbs结束进程代码