前段时间,闲的蛋疼,寻思练练python,就写了一个AWD文件监控脚本。

功能简单,代码简陋,大佬勿喷。

若大家对脚本有改进建议或者bug反馈,可在下方留言。

0x00 脚本功能

  • 备份当前目录下所有文件及目录,储存在./bak目录中
  • 计算当前文件夹下所有文件(包括子目录下的文件)的MD5值,并实时监测,当MD5值发生变化,删除该文件,并从备份文件中将其还原
  • 实时监测新生成的文件,并将新生成的文件修改后缀名,并移动到./bak/drop文件夹内
  • 当原始文件被删除,从备份文件中恢复该文件

0x01 脚本使用

将脚本放到源码文件夹,并在命令行输入

$ python3 ./FileMonitor.py

0x02 脚本代码

# -*- coding: utf-8 -*-
# FileMonitor V1.1
# Author: 7i4n2h3n9
# Team: PolarNight
# Use: python3 ./FileMonitor.py

import os
import sys
import hashlib
import shutil
import random
import string
import time

def generate_random_str(randomlength=16):
    #生成一个指定长度的随机字符串
    #string.digits=0123456789
    #string.ascii_letters=abcdefghigklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
    str_list = [random.choice(string.digits + string.ascii_letters) for i in range(randomlength)]
    random_str = ''.join(str_list)
    return random_str


def get_filelist(dir, Filelist):
    # 遍历文件夹及其子文件夹中的文件,并存储在一个列表中
    # 输入文件夹路径、空文件列表[]
    # 返回 文件列表Filelist,包含文件名(完整路径)
    newDir = dir
    if os.path.isfile(dir):
        Filelist.append(dir)
    elif os.path.isdir(dir):
        for s in os.listdir(dir):
            if s == 'bak':
                pass
#                print('Notice: "bak" is already exist!')
            else:
                newDir=os.path.join(dir,s)
                get_filelist(newDir, Filelist)
        return Filelist

def get_dirlist(dir, Dirlist):
    # 遍历当前目录下所有子目录
    # 输入当前目录路径,空目录列表[]
    # 返回 目录列表Dirlist,包含当前目录下包含的所有目录及子目录
    newDir = dir
    for i in os.listdir(dir):
        newDir = os.path.join(dir,i)
        if os.path.isdir(newDir):
            if newDir == './bak':
                print('Notice: "./bak" is already exist!')
            else:
                Dirlist.append(newDir)
                get_dirlist(newDir, Dirlist)
    return Dirlist

def get_md5(dir_list,File_md5_list):
    # 获取文件MD5值,并和其路径进行拼接
    # 输入文件列表、空MD5列表[]
    # 返回 MD5列表File_md5_list,包含所有文件路径和MD5值:filepath:MD5
    for i in range(len(dir_list)):
        file_name = dir_list[i]
        with open(file_name, 'rb') as fp:
            data = fp.read()

        file_md5 = hashlib.md5(data).hexdigest()
        #print(file_name)
        #print(file_md5)
        File_md5_list.append(str(file_name) + ':' + str(file_md5))

    return File_md5_list

def backupfiles(source_list,bak_list,File_md5_list,Dirlist):
    # 备份所有文件到指定目录
    # 先判断'./bak'目录是否存在,若存在删除'./bak'目录及其目录下所有文件,并重新执行backupfiles()
    # 若'./bak'目录不存在,创建'./bak'目录
    target_dir = './bak/'
    if os.path.isdir(target_dir):
        print('Notice: target_dir is already exist!')
        shutil.rmtree('./bak')
        backupfiles(source_list,bak_list,File_md5_list,Dirlist)

    else:
        os.makedirs(target_dir)
        print('Notice: target_dir created successful!')
        for b in range(len(Dirlist)):
            tmp_dir = './bak' + str(Dirlist[b])[1:]
            os.makedirs(tmp_dir)

    # 创建filename_list列表,截取File_md5_list列表元素,并存储到对应下标的filename_list列表
    filename_list = []
    for j in File_md5_list:
        tmp = j[1:-33]
        filename_list.append(tmp)
#        print(filename_list)

    # 构造备份文件路径,并将文件备份到指定位置
    for i in filename_list:
        source = str(i)
#        print(source)
        target_file_dir = os.path.join(target_dir, source[1:])
#        print(target_file_dir)
        bak_list.append(target_file_dir)
        #备份文件到指定目录
        source_tmp = '.' + str(source)
#        print(source_tmp)
#        print(target_file_dir)
#        os.system('cp ' + str(source_tmp) + ' ' + str(target_file_dir))
#        shutil.copy(source_tmp,target_file_dir)
        if os.path.isdir(source_tmp):
            os.makedirs(target_file_dir)
            print('Notice: create ' + str(target_file_dir) + ' successful!')
        shutil.copy(source_tmp,target_file_dir)

    return bak_list, filename_list

def check_newfiles(old_list, path, filename_tmp):
    # 检测新文件,将新文件后缀重命名并移动到'./drop'目录下
    # 输入原始文件列表,监控目录,(原始文件路径列表,备份文件路径列表)用来恢复文件
    drop_dir = './bak/drop'
    if os.path.isdir(drop_dir):
        pass
    else:
        os.makedirs(drop_dir)

    new_list = get_filelist(path, [])
    for i in new_list:
        if old_list.count(i) == 0:
            tmp_str = generate_random_str()
            tmp_name = str(i) + ".drop" + str(tmp_str)
            os.rename(i,tmp_name)
            shutil.move(tmp_name,drop_dir)

    file_rec(old_list, path, filename_tmp)

def file_list_tmp(filename_list, filename_tmp):
    # 生成原始文件路径
    # 输入原始文件列表
    # 在列表每个元素前加'.'
    for j in filename_list:
        tmp = '.' + str(j)
        filename_tmp.append(tmp)
    return filename_tmp

def file_rec(old_list_1, path, filename_tmp):
    # 检测被删除和被修改的文件,并将其从备份文件中还原
    # 输入原始文件列表,原始目录,原始文件路径,备份文件路径
    new_list_1 = get_filelist(path, [])
    #print(filename_tmp)
    for i in old_list_1:
        if new_list_1.count(i) == 0:
            tmp_idx = filename_tmp.index(i)
            #print('tmp_idx  >>>>>>  ',tmp_idx)
            #print('target_file_dir[tmp_idx]  >>>>>>   ',target_file_dir[tmp_idx])
            tar_file_dir = './bak' + str(i)[1:]
            shutil.copy(tar_file_dir,i)

    new_md5_list = get_md5(new_list_1, [])
    for b in File_md5_list:
        if new_md5_list.count(b) == 0:
            tmp_dir_str = b[:-33]
            tmp_md5_idx = filename_tmp.index(tmp_dir_str)
            #print(target_file_dir[tmp_md5_idx])
            tar_file_dir = './bak' + str(tmp_dir_str)[1:]
            os.remove(tmp_dir_str)
            shutil.copy(tar_file_dir,tmp_dir_str)


if __name__ == '__main__' :
    path = r'./'
    a_list = get_filelist(path, [])
#    print(list)

    dirlist_tmp = get_dirlist(path,[])
#    print(dirlist_tmp)

    File_md5_list = get_md5(a_list,[])
#    print(File_md5_list)

    backup_list,filename_list = backupfiles(a_list,[],File_md5_list,dirlist_tmp)
#    print(target_file_dir)

    filename_tmp = file_list_tmp(filename_list, [])
#    print(filename_tmp)

    while True:
        check_newfiles(a_list, path, filename_tmp)
        time.sleep(2)

0x03 更新日志

FileMonitor v1.1

  • 修复当./bak目录存在时,会将./bak目录和该目录下的文件再次备份的bug