C# 恶搞小程序 (基于C#的电脑桌面冻结 极速(everything方式)搜索文件及操作文件隐藏、只读等)

题目:基于C#的电脑桌面冻结和极速搜索文件及操作文件隐藏、只读等

前言:大家好,我是杰夫,是一名程序员届的小学生,精通面向搜索引擎的编程,专业过硬,一直在Debugging。

-------------------------分割线----------------------

摘要:

(本程序为纯娱乐目的制作,非电脑病毒,非黑客技术。)

本程序内容包含如下内容:

1️⃣桌面截图,并将截图全屏投射到电脑屏幕达到“冻结”桌面的目的。

2️⃣获取用户管理员权限。

3️⃣使用与Everything同样的方式搜索用户文件。

4️⃣对搜索到的文件进行隐藏、只读、系统以及恢复的操作。

正文:

首先使用vs2019建立一个winform工程,只需要一个form。将form1的BackColor属性设置为ButtonShadow(减少冻结桌面后仍有一些范围还是通透的可能性),FormBorderStyle属性设置为None。添加一个pictureBox用来投射桌面图片,并将此控件铺满窗体,BackColor属性设置为Transparent,Anchor为上下左右全选。

一、桌面截图并全屏投射到电脑屏幕

1.程序启动后首先执行“显示桌面”操作,使桌面上打开的窗体全部最小化,只留下桌面壁纸和图标。

            Type shellType = Type.GetTypeFromProgID("Shell.Application");
            object shellObject = System.Activator.CreateInstance(shellType);
            shellType.InvokeMember("ToggleDesktop", System.Reflection.BindingFlags.InvokeMethod, null, shellObject, null);
            System.Threading.Thread.Sleep(300);//线程休眠

2.在Form1_Load时执行截取屏幕内容指令

public static void GetScreen()
        {
            //截取屏幕内容   
            Size screen = new Size(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height);
            Bitmap memoryImage = new Bitmap(screen.Width, screen.Height);
            Graphics memoryGraphics = Graphics.FromImage(memoryImage);
            memoryGraphics.CopyFromScreen(0, 0, 0, 0, screen, CopyPixelOperation.MergeCopy);
            //储存截图
            memoryImage.Save(@"screen.bmp", ImageFormat.Bmp);
            MemoryStream data = new MemoryStream();
            memoryImage.Save(data, ImageFormat.Bmp);
        }

然后

pictureBox1.Image = Image.FromFile(@"screen.bmp");//将获取的屏幕截图投射到控件

this.WindowState = FormWindowState.Maximized;    //最大化窗体 
this.TopMost = true;//置顶当前窗体

3.在此时我预览了一下程序,在投射桌面截图的时候电脑屏幕会闪一下,发现是在投射截图之前窗体进行初始化的残影。这就有点有失作品的水准,显然专业过硬的我是不会允许这样一点小瑕疵存在的。所以:

需求:无感化图片替换桌面的过程

解决方案:将窗体透明度改为0,在执行完图片替换之后再将透明度改成1。

代码:

this.Opacity = 0;// 初始化窗口的透明度为0%

this.Opacity = 1;//设置窗体透明度为100%

*扩展:

我这里用的方式是初始化窗体的透明度是0%,再通过定时器,每过0.1秒将透明度加0.1,彻底无感化桌面的变化,让用户根本察觉不到ta的桌面正在被一张图片给替换。

代码:

void timer1_Tick(object sender, EventArgs e)
        {
            if (Opacity < 1)//如果窗体的透明度小于最大透明度1的话慢慢往上加
            {
                Opacity += 0.1;
            }
            else//当透明度加到1的时候将时钟的点电池卸下来(时钟停止工作)
            {
                timer1.Enabled = false;

            }
        }

二、程序获取管理员权限

由于读取用户文件需要管理员权限,需要设置一下:

1、 在Visual Studio 中--解决方案资源管理器--右键项目名称--属性,找到“安全性”选项,

2、勾选“启用ClickOnce安全设置”,

3、这时,在项目下面会多出一个“app.manifest”的文件,选中它,并找到代码段<requestedExecutionLevel level="asInvoker" uiAccess="false" />,将其改为:<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />,

4、改正后,不要急于重新编译生成,再次打开“属性--安全性”界面,

将“启用ClickOnce安全设置”前面的勾去掉后再编译运行。 不然程序会报错无法运行。

5、最后,保存修改,重新编译运行程序。

打开程序时,会提示“用户账户控制”来获取管理员权限运行,点击“是”则获取了管理员权限。

三:使用与Everything的方式搜索用户文件。

原理:

        Everything获取磁盘上的文件靠的是读取NTFS文件系统的USN日志。因此,使用NTFS的磁盘都可以通过读取USN日志的方式来实现文件的快速查找。

    USN日志称为更改日志。每个NTFS磁盘分区都有一个USN日志用于记录该磁盘上的文件更改情况,更改日志中的每条记录都包含USN(即记录编号)、文件的名称,文件引用号,父文件引用号等信息。但并不记录具体的更改操作,因此体积相对于主文件表来说要小很多。

    我们可以通过调用 system32文件夹下动态链接库中的API编程接口,来读取USN日志的内容,并对其内容进行解析,从中得到文件名和文件路径,进而实现快速查找磁盘上任意文件的功能。

USN日志的结构:

    public struct USN_RECORD
    {
        public int RecordLength;
        public short MajorVersion;
        public short MinorVersion;
        public long FileReferenceNumber;
        public long ParentFileReferenceNumber;
        public long Usn;
        public long TimeStamp;
        public int Reason;
        public int SourceInfo;
        public int SecurityId;
        public FileAttributes FileAttributes;
        public short FileNameLength;
        public short FileNameOffset;
    }

RecordLength:  记录长度,单位字节。
MajorVersion; MinorVersion   主次版本号。版本不同,USN日志的格式也会有差异。
FileReferenceNumber   文件引用号 ,可以看作文件的ID
ParentFileReferenceNumber   父文件引用号,父目录的ID
Usn   更新日志号,递增,不规律
FileNameLength   文件名长度
FileNameOffset   相对于该记录起始位置,文件名起始位置的偏移量

需要通过文件名长度和文件名偏移量,来读出文件名,根据父文件引用号,找到父文件名,并拼接出文件的完整路径。这些操作都在内存中,且会用到指针,所以速度是很快的。

如何读取到USN日志:

    通过一个叫做DeviceIoControl的系统函数来读取USN日志,从它的名字可以猜出,这是一个非常强大的函数.

BOOL DeviceIoControl(
    HANDLE       hDevice,
    DWORD        dwIoControlCode,
    LPVOID       lpInBuffer,
    DWORD        nInBufferSize,
    LPVOID       lpOutBuffer,
    DWORD        nOutBufferSize,
    LPDWORD      lpBytesReturned,
    LPOVERLAPPED lpOverlapped
);

第一个参数是一个句柄指针,它指向你要操作的Device对象。
第二个参数是控制码,它是一个常量,决定了这个函数的作用,当读取USN日志时,该值为:0x900b3;
lpInBuffer 代表输入条件,它是一个指向特定结构体的指针。这个结构体的格式根据你的用法而定,也就是第二个参数dwIoControlCode。
nInBufferSize     lpInBuffer的大小
lpOutBuffer     是一个指向输出缓存区的指针,用于接收返回的数据
nOutBufferSize     输出缓冲区的大小
lpBytesReturned     返回的数据字节数

    从USN日志中读取到的内容保存在了lpOutBuffer所指向的字节数组中,该数组的前八个字节代表着下一条USN日志号(因为接收缓存区大小限制,USN日志并不一定能一次读取完成。下一条USN日志号是将要读取到的那条记录号)。输出缓冲区里可能会包含多条记录,它们并没有明确的长度,边界。因此必须按照上面提到的结构规则对其进行解析。
    需要注意,我们需要通过lpBytesReturned :返回的数据字节数,来判断USN日志是否读取完成。而且在解析接收缓冲区的时候,同样需要用到。

    下面这段代码讲的就是上面这个过程,事实上仅仅需要读取出文件名并获取文件路径的话,使用C#只需要一百来行代码。

在C#编程中,我们并不需要考虑指针和内存分配,但是C#仍然给我们提供了丰富的操作非托管资源的方法。我们可以使用unsafe代码,也可以使用更高级的Inptr和Marshal类。

do
    {           
        if (WinApi.DeviceIoControl(
            rootHandle,
            WinApi.FSCTL_ENUM_USN_DATA,
            mftPtr, 
            Marshal.SizeOf(mftData),
            receiveBuffer, 
            receiveBufferSize,
            out retBytes, 
            IntPtr.Zero))
        {
          cb = retBytes;
            IntPtr recPtr = new IntPtr(receiveBuffer.ToInt64() + 8);
            while (retBytes > 64)
            {                   
                record = (WinApi.USN_RECORD)Marshal.PtrToStructure(recPtr,typeof(WinApi.USN_RECORD));
                FileName =Marshal.PtrToStringUni(new IntPtr(recPtr.ToInt64() + record.FileNameOffset), record.FileNameLength / 2);
                bool IsFile = !record.FileAttributes.HasFlag(FileAttributes.Directory);
                FSNodes.Add(record.FileReferenceNumber, new FSNode(record.FileReferenceNumber, record.ParentFileReferenceNumber, FileName, IsFile));
                recPtr = new IntPtr(recPtr.ToInt64() + record.RecordLength);
                retBytes-=record.RecordLength;
            }
            Marshal.WriteInt64(mftPtr, Marshal.ReadInt64(receiveBuffer, 0));
        }
        else
        {
            break;
        }                

    } while (cb > 8);     

导入WindowsAPI到项目中, CreateFile函数用于获取磁盘句柄:

    其实不能说是导入,因为动态链接库是程序运行时才加载的,这里只是一个声明.程序会从system32,bin文件夹下等查找该dll . 能够在c#中使用其他语言编写的链接库, 得益于.NET遵循的CTS通用类型系统,它制定了中间语言所能转化的基本数据类型。

[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr CreateFile(
    string lpFileName, 
    uint dwDesiredAccess, 
    int dwShareMode, 
    IntPtr lpSecurityAttributes, 
    int dwCreationDisposition, 
    int dwFlagsAndAttributes, 
    IntPtr hTemplateFile);

[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool DeviceIoControl(
    IntPtr hDevice, 
    uint dwIoControlCode, 
    IntPtr lpInBuffer, 
    int nInBufferSize, 
    IntPtr lpOutBuffer, 
    int nOutBufferSize, 
    out int lpBytesReturned, 
    IntPtr lpOverlapped);

最后,将解析到的日志条目保存到Dictionary或是List。通过父文件引用号,找到父文件名,把父文件名和自己的名字串起来,一直串下去,就可以得到文件路径了。

具体实施:

               sw.Start();
                //读取USN日志
                Task.Factory.StartNew((Action)delegate ()
                {
                    Mypanel mypanel = flpCatagoryView.Controls[0] as Mypanel;
                    var completeNames = ftp.InitCollectionFromDisks();
                    foreach (string name in completeNames)
                    {
                        this.Invoke((Action)delegate ()
                        {
                            label1.Text = name + "  ";
                            mypanel.FileNumber = DataSource.Files.Count.ToString();
                        });
                    }
                    sw.Stop();
                    this.Invoke((Action)delegate ()
                    {
                        if (DataSource.Files.Count == 0)
                            MessageBox.Show("请以管理员身份执行该程序(鼠标右键选项).");
                        
                        mypanel.FileNumber = DataSource.Files.Count.ToString();
                    });

                    this.dataGridView1.Invoke((Action)delegate ()
                    {
                        string inputstring = ".doc";//给出的搜索关键词 可以自定义 这里是寻找word文档
                        List<string> extensions = new List<string>(5);
                        extensions.Add("*");
                        DataSource.TemporaryList1 = ftp.SearchMatchFileMethod("", inputstring, extensions).AsParallel().ToList<FileModel>(); 
                        dataGridView1.Visible = true;
                        dataGridView1.Rows.Add();//将文件信息添加进dataGridView
                        label1.Text = "查询完成!共" + DataSource.TemporaryList1.Count + "个WORD文档" + " 正在执行删除操作...";//现在不用隐藏了直接将自己的真实身份真实目的告知用户。
                    });
                }

四、对文件进行隐藏、只读、系统以及恢复的操作。

File.SetAttributes(FilePath, FileAttributes.Normal);//设置文件属性,FileAttributes为枚举类

同时具有system和hidden属性的文件会在系统中彻底隐形,这也是病毒常用的伎俩。文件去掉全部属性后(四种基本属性),将自动标记为normal。

那我们就可以将搜索到的文件的属性在原有的基础上加上system和hidden两个属性。

File.SetAttributes(filePath, File.GetAttributes(filePath) | FileAttributes.Hidden | FileAttributes.System);//文件属性增加隐藏和系统两个属性。

具体实施:

try
                        {
                            String filePath = "";
                            if (DataSource.TemporaryList1.Count > 0)
                            {
                                for (int i = 1; i <= DataSource.TemporaryList1.Count; i++)
                                {
                                    filePath = dataGridView1.Rows[i-1].Cells[1].Value.ToString();
                                    //File.SetAttributes(filePath, File.GetAttributes(filePath) & FileAttributes.Normal);//恢复正常
                                    File.SetAttributes(filePath, File.GetAttributes(filePath) | FileAttributes.Hidden | FileAttributes.System);//文件增加隐藏属性。
                                    
                                }
                            }
                           
                            this.Invoke((Action)delegate ()
                            {
                                label1.Text = filePath;
                            });
                        }
                        catch { }
                        
                        dataGridView1.Rows.Clear();
                        
                        label1.Text = "全部删除成功!";//本着绝对娱乐的态度,文件并不会直接删除,只是被隐藏起来了

恢复隐藏的文件:

File.SetAttributes(filePath, File.GetAttributes(filePath) & FileAttributes.Normal);//恢复正常

-----------------------------------------分割线---------------------------------------------------------

效果:

其中加了一下花里胡哨的元素

资料来源:

1.C# 桌面截图_C#_自动化测试工具研究专栏-CSDN博客  https://blog.csdn.net/vbic0673/article/details/6100579?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522158529432819725256714174%2522%252C%2522scm%2522%253A%252220140713.130056874..%2522%257D&request_id=158529432819725256714174&biz_id=0&utm_source=distribute.pc_search_result.none-task

2.C#获取管理员权限_C#_沙师弟专栏-CSDN博客  https://blog.csdn.net/u014597198/article/details/76614937?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522158529438519725211905442%2522%252C%2522scm%2522%253A%252220140713.130056874..%2522%257D&request_id=158529438519725211905442&biz_id=0&utm_source=distribute.pc_search_result.none-task

3.everything快速搜索的原理及C#实现_C#_chenweicode的博客-CSDN博客  https://blog.csdn.net/chenweicode/article/details/81986279?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task

4.Everything原理探究以及C#实现_C#_qq_40404477的博客-CSDN博客  https://blog.csdn.net/qq_40404477/article/details/97028056?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522158398045419195162533608%2522%252C%2522scm%2522%253A%252220140713.130056874..%2522%257D&request_id=158398045419195162533608&biz_id=0&utm_source=distribute.pc_search_result.none-task

5.在C#中快速查询文件_C#_menghuangxiao的专栏-CSDN博客  https://blog.csdn.net/menghuangxiao/article/details/78661362?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task

6.去除文件只读属性、判断文件夹及文件的隐藏属性_运维_weixin_30338481的博客-CSDN博客  https://blog.csdn.net/weixin_30338481/article/details/99170978?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522158493065919724835847630%2522%252C%2522scm%2522%253A%252220140713.130056874..%2522%257D&request_id=158493065919724835847630&biz_id=0&utm_source=distribute.pc_search_result.none-task

7.C# 去除文件和文件夹的只读属性 - hanmos - 博客园  https://www.cnblogs.com/hanmos/archive/2011/01/28/1946974.html

8.C#文件相关操作_宝宝_新浪博客  http://blog.sina.com.cn/s/blog_4a4634e20100a5u2.html

  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值