第三章 远程线程注入(附源码)

前言

远程线程注入是指一个进程在另一个进程中创建线程的技术。

函数介绍

OpenProcess函数

打开一个已存在的进程对象,并返回进程的句柄。

语法
HANDLE OpenProcess(
  [in] DWORD dwDesiredAccess,
  [in] BOOL  bInheritHandle,
  [in] DWORD dwProcessId
);
参数

[in] dwDesiredAccess

对进程对象的访问。参数可以是一个或多个进程访问权限。

[in] bInheritHandle

如果此值为TRUE,则此进程创建的进程将继承句柄。否则,进程不会继承这个句柄。

[in] dwProcessId

要打开的本地进程的标识符。

返回值

如果函数成功,则返回值是指定进程的打开句柄。

如果函数失败,则返回值为NULL

VirtualAllocEx函数

在指定进程的虚拟地址空间保留、提交或更改内存状态。

语法
LPVOID VirtualAllocEx(
  [in]           HANDLE hProcess,
  [in, optional] LPVOID lpAddress,
  [in]           SIZE_T dwSize,
  [in]           DWORD  flAllocationType,
  [in]           DWORD  flProtect
);
参数

[in] hProcess

进程的句柄。

[in, optional] lpAddress

要分配的页面区域指定所需起始地址的指针。

[in] dwSize

要分配的内存区域的大小,以字节为单位。

[in] flAllocationType

内存分配的类型。

[in] flProtect

要分配的页面区域的内存保护。

返回值

如果函数成功,则返回值是页面分配区域的基地址。

如果函数失败,则返回值为零。

WriteProcessMemory函数

写入进程的内存区域。

语法
BOOL WriteProcessMemory(
  [in]  HANDLE  hProcess,
  [in]  LPVOID  lpBaseAddress,
  [in]  LPCVOID lpBuffer,
  [in]  SIZE_T  nSize,
  [out] SIZE_T  *lpNumberOfBytesWritten
);
参数

[in] hProcess

要修改的进程内存的句柄。

[in] lpBaseAddress

指向指定进程中写入数据的基地址的指针。

[in] lpBuffer

要写入指定进程地址空间的数据的缓冲区的指针。

[in] nSize

要写入指定进程的字节数。

[out] lpNumberOfBytesWritten

一个指向接收传输到指定进程的字节数的变量的指针。该参数是可选的。

返回值

如果函数成功,则返回值非零。

如果函数失败,则返回值为0。

GetProcAddress函数

检索指定的DLL中的输出库函数地址。

语法
FARPROC GetProcAddress(
  [in] HMODULE hModule,
  [in] LPCSTR  lpProcName
);
参数

[in] hModule

包含函数或变量的DLL模块的句柄。

[in] lpProcName

函数或变量名称,或函数的序数值。

返回值

如果函数成功,则返回值是导出函数或变量的地址。

如果函数失败,则返回值为NULL

CreateRemoteThread函数

它能够创建一个在其它进程地址空间中运行的线程(也称:创建远程线程)。

语法
HANDLE CreateRemoteThread(
  [in]  HANDLE                 hProcess,
  [in]  LPSECURITY_ATTRIBUTES  lpThreadAttributes,
  [in]  SIZE_T                 dwStackSize,
  [in]  LPTHREAD_START_ROUTINE lpStartAddress,
  [in]  LPVOID                 lpParameter,
  [in]  DWORD                  dwCreationFlags,
  [out] LPDWORD                lpThreadId
);
参数

[in] hProcess

要在其中创建线程的进程的句柄。

[in] lpThreadAttributes

指向SECURITY_ATTRIBUTES结构的指针,该结构为新线程指定安全描述符并确定子进程是否可以继承返回的句柄。

如果lpThreadAttributesNULL,则线程获得一个默认的安全描述符并且句柄不能被继承。

[in] dwStackSize

堆栈的初始大小,以字节为单位。

[in] lpStartAddress

远程进程中线程的起始地址。

[in] lpParameter

指向要传递给线程函数的变量的指针。

[in] dwCreationFlags

控制线程创建的标志。

[out] lpThreadId

指向接收线程标识符的变量的指针。

返回值

如果函数成功,则返回值是新线程的句柄。

如果函数失败,则返回值为NULL

示例

程序代码

RemoteThreadInject第一个参数为要被注入的PID,第二个参数为要注入的DLL文件。

// 远程线程注入.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>
#include <Windows.h>



//远程线程注入
bool RemoteThreadInject(int Pid, const char* Path)
{
    //1.使用PID打开进程获取权限
    HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, NULL, Pid);
    
    //2.申请内存,写入DLL路径
    LPVOID pBuf = VirtualAllocEx(hProcess, NULL, strlen(Path) + 1, MEM_COMMIT, PAGE_READWRITE);
    
    //3.写入内存
    if (!WriteProcessMemory(hProcess, pBuf, Path, strlen(Path) + 1, NULL))
    {
        printf("写入内存失败!\n");
        return false;
    }


    //4.创建远程线程,让对方调用LoadLibrary
    HMODULE hModule = LoadLibrary("kernel32.dll");
    LPTHREAD_START_ROUTINE pfnStartAddress = (LPTHREAD_START_ROUTINE)GetProcAddress(hModule, "LoadLibraryA");
    if (!pfnStartAddress)
    {
        printf("获取LoadLibraryA失败!\n");
        return false;
    }
    else
    {
        printf("获取LoadLibraryA成功!\n");
    }
    HANDLE hRemoteThread = CreateRemoteThread(hProcess, NULL, NULL,
        pfnStartAddress, pBuf, NULL, NULL);
    if (NULL == hRemoteThread)
    {
        printf("目标进程中创建线程失败!\n");
        CloseHandle(hProcess);
        return FALSE;
    }
    else
    {
        printf("目标进程中创建线程成功!\n");
    }
    
    //5.等待线程结束返回,释放资源
	WaitForSingleObject(hRemoteThread, 2000);
    CloseHandle(hRemoteThread);
    VirtualFreeEx(hProcess, pBuf, 0, MEM_FREE);
}


int main()
{
    const char* dllpath = "D:\\testDll.dll";
    RemoteThreadInject(15220, dllpath);
    printf("执行结束");
    return 0;
}

DLL代码

// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "pch.h"

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
//        Sleep(1000000);
        MessageBox(NULL, L"TIPS", L"TEST", NULL);
        break;
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}

测试

要被注入的进程“calc.exePID为1012;

注入DLL文件为“C:\Users\Administrator\Desktop\messagebox.dll”:

执行程序生成EXE

image-20211127225921958

使用ProcessExplorer查看进程:

image-20211127230245486

原理学习

之所以被称为远程线程注入,是因为使用CreateRemoteThead函数在其他进程中创建一个线程。

kernel32.dlluser32.dll总是被映射到进程的内存首选地址;所有使用这两个DLL的进程中,这两个DLL的内存地址是相同的。我们在本进程中获取到的kernel32.dllLoadLibrary函数的地址,和目标进程中是一样的。

在目标进程中使用CreateRemoteThead在目标进程中创建新的线程;使用LoadLibrary函数调用DLL

对系统进程进行尝试注入,由于系统存在SESSION 0隔离,不能成功注入到系统进程。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值