Prank:Trick 1 背景桌面 と 透明窗口

系列前言

这是一个带来 快乐 的专栏,通过分析的 众多 APT 组织的恶意样本,从中 learn 到了许多恶意的编程技巧,当然这些恶意是相对的,主要看人的主观目的,技术本就是中立的。

运用这些技巧来构建一个 整活 的程序,趁 mate 不注意悄悄安装到 taPC 上,自己则在角落观察 ta 从发现 abnormal,到逐步暴躁的全过程。希望在整活过程中遵循一些底线,不然 friend ship 说翻就翻。
在这里插入图片描述

1.Thought

一开始我是 want 做这样的 Eastwest:

  • 截图当前桌面。
  • 将其设置为桌面背景,并隐藏桌面图标。

这样就会导致,当 mate 点击桌面图标时不会得到任何的相应,当其不知道 整活 存在时会观察其 behavior 将会非常的有意思。想到这里我就开始的动手尝试,通过碰到的问题得到的一下三种解决方案,最终能够使用的就是 桌面背景透明窗口

  1. 桌面背景
win7 win10
  1. 挂起 explorer.exe
    explorer.exe 对于用户的请求没有进行相应时就会产生卡了一样的感觉,这是我在上面的方案不能正常实施之后想到的一个解决办法,但是存在这样的问题 when explorer.exe 未响应时,如果进行操作,系统会自动将 explorer.exe 重启。
  2. 透明窗口
    Windows 10 Black Screen after killing Explorer.exe 的回复中给出了另一种可行的思路:
  • 创建一个窗口,并将其至于最上层
  • 在窗口中加载背景图片

结合这上述思路进行实践,发现了一个重要的特点如果在 WM_PAINT 消息中只调用 BeginPaintEndPaint 能绘制出一幅透明的窗口,如果这个窗口位于顶层则会导致 鼠标无效的假象——图形界面中的任何图标都没有反应。

2.背景桌面(仅win7有效)

完成桌面背景的 Prank 计划需要分为三步:

  1. 截屏桌面
  2. 设置为桌面背景
  3. kill explorer.exe

[1] 截取桌面

  • 由于我们希望截取的画面是桌面,所以其中就不应该包含其他的窗口,故在截取前我们需要通过程序发出 Win + D来显示桌面。Windows API 中提供了 SendInput 来发送键盘消息,这里的消息需要有4个内容,包括WinD 的按下和松开。
    void DesktopBackGround::SimulateWinD() {
        // The INPUT structure is used to store information about a simulated input event  
        INPUT inputs[4] = {}; // We need 4 inputs: down Win, down D, up D, up Win  

        // Press the left Windows key  
        inputs[0].type = INPUT_KEYBOARD;
        inputs[0].ki.wVk = VK_LWIN; // VK_LWIN is the virtual key code for the left Windows key  
        inputs[0].ki.wScan = 0;
        inputs[0].ki.dwFlags = 0; // 0 for key press  
        inputs[0].ki.time = 0;

        // Press the 'D' key  
        inputs[1].type = INPUT_KEYBOARD;
        inputs[1].ki.wVk = 'D'; // 'D' is the virtual key code for the 'D' key  
        inputs[1].ki.wScan = 0;
        inputs[1].ki.dwFlags = 0; // 0 for key press  
        inputs[1].ki.time = 0;

        // Release the 'D' key  
        inputs[2] = inputs[1];
        inputs[2].ki.dwFlags = KEYEVENTF_KEYUP; // KEYEVENTF_KEYUP for key release  

        // Release the left Windows key  
        inputs[3] = inputs[0];
        inputs[3].ki.dwFlags = KEYEVENTF_KEYUP; // KEYEVENTF_KEYUP for key release  

        // Send the input events to the system  
        SendInput(4, inputs, sizeof(INPUT));
    }

[2] 设置为桌面背景。

  • 下面就是截取桌面,并将其存储为一个 .bmp 文件的过程。通过 Windows 提供的 BitBlt 函数来进行相关操作,将文件存入到 strPho 所指向的路径,这里最好是 FullPath,尽管存储时不会有影响,但当使用其作为桌面壁纸的 API 函数需要完整路径。
    // Function to save a DIB as a BMP file  
    bool DesktopBackGround::SaveBitmapToFile(BITMAPINFO* pbi, void* bits, const char* filename) {
        HANDLE fh = CreateFileA(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
        if (fh == INVALID_HANDLE_VALUE) {
            std::cerr << "Failed to create file: " << filename << std::endl;
            return FALSE;
        }

        BITMAPFILEHEADER bfh = { 0 };
        bfh.bfType = 0x4D42; // 'BM'  
        bfh.bfSize = sizeof(BITMAPFILEHEADER) + pbi->bmiHeader.biSize + pbi->bmiHeader.biClrUsed * sizeof(RGBQUAD) + pbi->bmiHeader.biSizeImage;
        bfh.bfOffBits = sizeof(BITMAPFILEHEADER) + pbi->bmiHeader.biSize + pbi->bmiHeader.biClrUsed * sizeof(RGBQUAD);

        DWORD bytesWritten;
        WriteFile(fh, &bfh, sizeof(bfh), &bytesWritten, NULL);
        WriteFile(fh, &pbi->bmiHeader, sizeof(BITMAPINFOHEADER), &bytesWritten, NULL);

        // If there are color table entries, write them  
        if (pbi->bmiHeader.biClrUsed > 0) {
            RGBQUAD* colorTable = reinterpret_cast<RGBQUAD*>((reinterpret_cast<char*>(pbi)) + sizeof(BITMAPINFOHEADER));
            WriteFile(fh, colorTable, pbi->bmiHeader.biClrUsed * sizeof(RGBQUAD), &bytesWritten, NULL);
        }

        // Write the bits  
        WriteFile(fh, bits, pbi->bmiHeader.biSizeImage, &bytesWritten, NULL);

        CloseHandle(fh);
        return TRUE;
    }

	bool DesktopBackGround::SnipDeskTop() {
        //SimulateWinD();
        //Sleep(100);
        HDC hScreen = GetDC(NULL);
        int width = GetSystemMetrics(SM_CXSCREEN);
        int height = GetSystemMetrics(SM_CYSCREEN);

        // Create a device-independent bitmap  
        HDC hMemDC = CreateCompatibleDC(hScreen);
        HBITMAP hBitmap = CreateCompatibleBitmap(hScreen, width, height);
        HGDIOBJ oldObj = SelectObject(hMemDC, hBitmap);

        // Copy the screen to the bitmap  
        BitBlt(hMemDC, 0, 0, width, height, hScreen, 0, 0, SRCCOPY);

        // Get the bitmap info  
        BITMAPINFOHEADER bi = { 0 };
        bi.biSize = sizeof(BITMAPINFOHEADER);
        bi.biWidth = width;
        bi.biHeight = -height; // Negative height indicates top-down DIB  
        bi.biPlanes = 1;
        bi.biBitCount = 24; // Assuming 24-bit color  
        bi.biCompression = BI_RGB;
        bi.biSizeImage = 0; // Calculated automatically by Windows  
        bi.biXPelsPerMeter = 0;
        bi.biYPelsPerMeter = 0;
        bi.biClrUsed = 0;
        bi.biClrImportant = 0;

        BITMAPINFO bmi = { 0 };
        bmi.bmiHeader = bi;

        // Allocate memory for the bitmap bits  
        void* bits = new char[width * height * 3];

        // Get the bits from the bitmap  
        GetDIBits(hMemDC, hBitmap, 0, (UINT)height, bits, &bmi, DIB_RGB_COLORS);

        // Save the bitmap to a file  
        SaveBitmapToFile(&bmi, bits, strPho.c_str());

        // Clean up  
        delete[] bits;
        SelectObject(hMemDC, oldObj);
        DeleteObject(hBitmap);
        DeleteDC(hMemDC);
        ReleaseDC(NULL, hScreen);
		return 1;
	}
  • 有了 .bmp 文件之后,更改桌面图标就很容易了,直接使用 API 函数 SystemParametersInfoA ,将第 0 个参数 uiAction 设置为 SPI_SETDESKWALLPAPER
	bool DesktopBackGround::ChangeDeskTop() {
        if (SystemParametersInfoA(SPI_SETDESKWALLPAPER, 0, (void*)strPho.c_str(), SPIF_UPDATEINIFILE | SPIF_SENDCHANGE) == 0) {
            THREE_COMBO_PRANK(SystemParametersInfoA);
            return 0;
        }
		return 1;
	}

[3] kill explorer.exe
杀死 资源管理器 很简单,只需要使用 CreateProcess 函数来创建一个进程来运行如下命令即可:

taskkill /f /im explorer.exe

3.透明窗口

既然要绘制窗口,则需要遵循 Windows 窗口程序的相应规范,在一个程序中创建窗口的消息处理队列,同时注册一个窗口处理函数来处理不同的消息。

其中最关键的由两部分组成:创建窗口;绘制窗口

  1. 创建窗口,最关键的是选择 窗口属性,在可选窗口 style 中也就是 CreateWindowExA 函数的第 0 个参数需要选择 WS_EX_TOOLWINDOW 来保证窗口 没有边框;选择 WS_EX_TOPMOST 使得窗口位于最顶层。第 3 个参数窗口 style 中选择 WS_POPUPWS_VISIBLE 使得窗口在被创建后会立马显示。
HWND hwnd = CreateWindowExA(
    WS_EX_TOOLWINDOW | WS_EX_TOPMOST,               // Optional window styles.  
    strName.c_str(),                // Window class  
    "Persistent Window",            // Window text  
    WS_POPUP | WS_VISIBLE,          // Window 
    // Size and position  
    CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
    NULL,       // Parent window      
    NULL,       // Menu  
    hInstance,  // Instance handle  
    NULL        // Additional application data  
);
  1. 绘制窗口,这部分的操作很简单,只需要调用 BeginPaintEndPaint 两个函数就能够完成一个透明窗口的绘制。
        case WM_PAINT: {
            BeginPaint(hWnd, &ps);
            EndPaint(hWnd, &ps);
            break;
        }

4.总结

  1. 背景桌面的方式由于系统的升级已经不具有通用性了,只能在 Win7 之前的版本进行使用,当然效果也挺好的。
  2. 挂起 explorer.exe 的方式虽然能够产生效果,但是太短暂了,会触发 explorer.exe 未响应,进而导致进程重启。
  3. 透明窗口,我是更推荐使用这种方式去 整活 的,不仅通用性好,也不会产生任何的破坏。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值