代码注入相关


无论是进攻还是防御 注入都是非常重要的基本功

记录一下各种注入方式的学习

0x00 注入的本质

  • 先在进程空间里植入代码
  • 拿到线程权限 去执行该代码

本质就是控制进程

参考 逆向工程核心原理第 3 部分 常用的注入方式有

  1. 创建线程
  2. 修改注册表
  3. 消息钩取(Hook)
  4. 直接修改 PE 文件

0x01 注入方式

可分为三类

  • 静态修改

    DLL劫持、导入表注入

  • 全局性注入

    输入法注入、消息钩子注入、注册表注入

  • 线程注入

    APC注入、消息钩子注入(指定)、远程线程注入、挂起进程注入

I. 导入表注入

原理 > 静态添加/修改导入表

先移动所有导入表整体的位置 因为原来的位置空间紧凑 不能添加表

就修改PE头的导入表位置

接着静态手动添加新的导入表

构造INA表 IAT表 以及IMAGE_IMPORT_BY_NAME结构

就OK

导入表内容可以动

INT表可动 IAT表别动

II. 远程线程注入

动态

1. 注入DLL

  • 写入模块名字 常规远程线程调用载入DLL

  • 内存写入模块 修复重定位表 开远程线程执行模块的Entry

    在目标进程中修复IAT表

2. 注入代码

  • 直接将代码写到线程中

  • 通过WriteMemoryProcess写入目标进程

  • 需要参数的话定义一个结构体 传入到目标进程

  • 并启动远程线程进行调用

II. Windows HOOK 注入DLL

Windows 系统给我们提供了一些挂钩函数,使得被hook的进程可以在自己处理接收到的消息之前,先执行我们的消息处理函数,而这个消息处理函数一般会放在 DLL 中,来让目标进程加载,目标进程会映射整个DLL到进程空间,这实际上已经达到了注入代码的效果。

使用 API 函数 SetWindowsHookEx() 把一个应用程序定义的 Hook 子程安装到 Hook 链表中。 函数原型如下:第一个参数是消息编号,第二个参数为 Hook 函数

HHOOK SetWindowsHookExA(
  int       idHook,
  HOOKPROC  lpfn,
  HINSTANCE hmod,
  DWORD     dwThreadId
);

操作如下

extern "C" _declspec(dllexport) void HookStart()
{
//    HHOOK hHook = NULL;
    g_hHook=SetWindowsHookEx(WH_KEYBOARD, HookProc,
        GetModuleHandle("E://Viusal Studio//kanxue//注入技术//SetWindowsHookEx//Inject_dll//Debug//Inject_dll.dll"), 0);
    if (NULL == g_hHook)
    {
        MessageBox(NULL, "安装钩子失败", "提示", MB_OKCANCEL);
    }
}

II. 特洛伊注入

静态

DLL劫持

代替原DLL 转发其函数 同时加入自己的代码

DLL 劫持法 (输入表 DLL 替换法),原理是利用搜索 DLL 路径存在先后顺序 (exe 程序目录 > 系统目录 > 当前目录 > Path), 当较高层存在一个同名的 DLL 文件的时候,就会直接加载较高层的 DLL 文件。常常用于病毒的白加黑。需要注意的是黑 DLL 路径优先级一定要高于原来的 dll 文件,第二,一定要具有源 dll 文件所有的导出函数。

III. 注册表注入

静态

新创建的进程在加载 User32.dll 时,都会自动调用 LoadLibrary 去加载注册表中某个表项键值里写入的 Dll 路径

  • x64下:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows
  • x86下:HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows NT\CurrentVersion\Windows

当某个进程加载 User32.dll 时,这里面列出的所有的 DLL 都将 User32.dll 利用 LoadLibrary 函数加载到该进程空间中。

我们可以把自己的代码放在一个 DLL 中,并加入该键值,这样就可以注入到所有使用 User32.dll 的进程中了。

当 DLL 以 LoadLibrary 的方式加载时,DllMain 会被以 DLL_PROCESS_ATTACH 为原因调用,实际上我们就在 DLL_PROCESS_ATTACH中添加自己的代码就行了

需要关闭UEFI安全启动才能生效

参考链接: https://docs.microsoft.com/zh-cn/windows/win32/dlls/secure-boot-and-appinit-dlls?redirectedfrom=MSDN

IV. APC注入

APC 中文名称为异步过程调用, APC 是一个链状的数据结构,可以让一个线程在其本应该的执行步骤前执行其他代码,每个线程都维护这一个 APC 链。当线程从等待状态苏醒后,会自动检测自己得 APC 队列中是否存在 APC 过程。

所以只需要将目标进程的线程的 APC 队列里面添加 APC 过程,当然为了提高命中率可以向进程的所有线程中添加 APC 过程。然后促使线程从休眠中恢复就可以实现 APC 注入。

首先将 DLL 文件路径写入进程

lpData = VirtualAllocEx(hProcess, lpData, lstrlen(szDllFullPath) + 1, MEM_COMMIT, PAGE_READWRITE);
if (lpData)
{
    bStatus = WriteProcessMemory(hProcess, lpData, szDllFullPath, lstrlen(szDllFullPath) + 1, &stSize);
    if (FALSE == bStatus)
    {
        printf("WriteProcessMemory:%d\n", GetLastError());
        return NULL;
    }
}

然后使用 QueueUserAPC 将 APC 例程添加到 APC 队列中,QueueUserAPC 三个参数分别是 APC 例程,线程句柄,例程参数。所以还需要获取线程句柄

dwRet=QueueUserAPC((PAPCFUNC)LoadLibraryA, hThread, (ULONG_PTR)lpData);
if (NULL == dwRet)           
{
    printf("QueueUserAPC:%d\n", GetLastError());
    return NULL;
}

V. 输入法注入

切换输入法时候,输入法管理器 imm32.dll 就会加载 IME 模块,这样就形成了输入法注入的充要条件。而由于这个 Ime 文件本质上只是个存放在 C:\WINDOWS\system32 目录下的特殊的 DLL 文件,因此我们可以利用这个特性,在 Ime 文件中使用 LoadLibrary () 函数待注入的 DLL 文件。

首先就是编写 ime 文件,至少需要两个导出函数 BOOL ImeClass_Register(HINSTANCE hinstDLL)BOOL WINAPI ImeInquire(LPIMEINFO lpIMEInfo, LPTSTR lpszUIClass, LPCTSTR lpszOption) 这两个是必须要实现的。剩下的导出函数可以选择不去实现。

接着编写注射器。利用 ImmInstallIME 安装 ime 文件,当输入法切换的时候就可以注入 dll 了。


Author: Luluting
Reprint policy: All articles in this blog are used except for special statements CC BY 4.0 reprint policy. If reproduced, please indicate source Luluting !
  TOC