驱动开发:内核中实现Dump进程转储
多数ARK反内核工具中都存在驱动级别的内存转存功能,该功能可以将应用层中运行进程的内存镜像转存到特定目录下,内存转存功能在应对加壳程序的分析尤为重要,当进程在内存中解码后,我们可以很容易的将内存镜像导出,从而更好的对样本进行分析,当然某些加密壳可能无效但绝大多数情况下是可以被转存的。
在上一篇文章《驱动开发:内核R3与R0内存映射拷贝》
介绍了一种方式SafeCopyMemory_R3_to_R0
可以将应用层进程的内存空间映射到内核中,要实现内存转储功能我们还是需要使用这个映射函数,只是需要在此函数上增加一些功能而已。
在实现转存之前,需要得到两个东西,进程内模块基地址
以及模块长度
这两个参数是必不可少的,至于内核中如何得到指定进程的模块数据,在很早之前的文章《驱动开发:内核中枚举进线程与模块》
中有详细的参考方法,这里就在此基础之上实现一个简单的进程模块遍历功能。
如下代码中使用的就是枚举
进程PEB
结构得到更多参数的具体实现,如果不懂得可以研读《驱动开发:内核通过PEB得到进程参数》
这篇文章此处不再赘述。
#include <ntddk.h>
#include <windef.h>// 声明结构体
typedef struct _KAPC_STATE
{LIST_ENTRY ApcListHead[2];PKPROCESS Process;UCHAR KernelApcInProgress;UCHAR KernelApcPending;UCHAR UserApcPending;
} KAPC_STATE, *PKAPC_STATE;typedef struct _LDR_DATA_TABLE_ENTRY
{LIST_ENTRY64 InLoadOrderLinks;LIST_ENTRY64 InMemoryOrderLinks;LIST_ENTRY64 InInitializationOrderLinks;PVOID DllBase;PVOID EntryPoint;ULONG SizeOfImage;UNICODE_STRING FullDllName;UNICODE_STRING BaseDllName;ULONG Flags;USHORT LoadCount;USHORT TlsIndex;PVOID SectionPointer;ULONG CheckSum;PVOID LoadedImports;PVOID EntryPointActivationContext;PVOID PatchInformation;LIST_ENTRY64 ForwarderLinks;LIST_ENTRY64 ServiceTagLinks;LIST_ENTRY64 StaticLinks;PVOID ContextInformation;ULONG64 OriginalBase;LARGE_INTEGER LoadTime;
} LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;// 偏移地址
ULONG64 LdrInPebOffset = 0x018; //peb.ldr
ULONG64 ModListInPebOffset = 0x010; //peb.ldr.InLoadOrderModuleList// 声明API
NTKERNELAPI UCHAR* PsGetProcessImageFileName(IN PEPROCESS Process);
NTKERNELAPI PPEB PsGetProcessPeb(PEPROCESS Process);
NTKERNELAPI HANDLE PsGetProcessInheritedFromUniqueProcessId(IN PEPROCESS Process);// 根据进程ID返回进程EPROCESS,失败返回NULL
PEPROCESS LookupProcess(HANDLE Pid)
{PEPROCESS eprocess = NULL;if (NT_SUCCESS(PsLookupProcessByProcessId(Pid, &eprocess)))return eprocess;elsereturn NULL;
}// 枚举指定进程的模块
// By: LyShark.com
VOID EnumModule(PEPROCESS Process)
{SIZE_T Peb = 0;SIZE_T Ldr = 0;PLIST_ENTRY ModListHead = 0;PLIST_ENTRY Module = 0;ANSI_STRING AnsiString;KAPC_STATE ks;// EPROCESS地址无效则退出if (!MmIsAddressValid(Process))return;// 获取PEB地址Peb = (SIZE_T)PsGetProcessPeb(Process);// PEB地址无效则退出if (!Peb)return;// 依附进程KeStackAttachProcess(Process, &ks);__try{// 获得LDR地址Ldr = Peb + (SIZE_T)LdrInPebOffset;// 测试是否可读,不可读则抛出异常退出ProbeForRead((CONST PVOID)Ldr, 8, 8);// 获得链表头ModListHead = (PLIST_ENTRY)(*(PULONG64)Ldr + ModListInPebOffset);// 再次测试可读性ProbeForRead((CONST PVOID)ModListHead, 8, 8);// 获得第一个模块的信息Module = ModListHead->Flink;while (ModListHead != Module){//打印信息:基址、大小、DLL路径DbgPrint("模块基址 = %p | 大小 = %ld | 模块名 = %wZ | 完整路径= %wZ \n",(PVOID)(((PLDR_DATA_TABLE_ENTRY)Module)->DllBase),(ULONG)(((PLDR_DATA_TABLE_ENTRY)Module)->SizeOfImage),&(((PLDR_DATA_TABLE_ENTRY)Module)->BaseDllName),&(((PLDR_DATA_TABLE_ENTRY)Module)->FullDllName));Module = Module->Flink;// 测试下一个模块信息的可读性ProbeForRead((CONST PVOID)Module, 80, 8);}}__except (EXCEPTION_EXECUTE_HANDLER){ ; }// 取消依附进程KeUnstackDetachProcess(&ks);
}VOID DriverUnload(IN PDRIVER_OBJECT DriverObject)
{}NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)
{DbgPrint("hello lyshark.com \n");ULONG i = 0;PEPROCESS eproc = NULL;for (i = 4; i<100000000; i = i + 4){eproc = LookupProcess((HANDLE)i);if (eproc != NULL){ObDereferenceObject(eproc);if (strstr(PsGetProcessImageFileName(eproc), "lyshark.exe") != NULL){EnumModule(eproc);}}}DriverObject->DriverUnload = DriverUnload;return STATUS_SUCCESS;
}
如上我们指定获取应用层lyshark.exe
进程的模块信息,并可得到以下输出效果:
上篇文章中的代码就不再啰嗦了,这里只给出内存转存的核心代码,如下代码:
- RtlInitUnicodeString 用于初始化转存后的名字字符串
- ZwCreateFile 内核中创建文件到应用层
- ZwWriteFile 将文件写出到文件
- ZwClose 最后是关闭文件并释放堆空间
很简单只是利用了SafeCopyMemory_R3_to_R0
将进程内存读取到缓冲区内,并将缓冲区写出到C盘目录下。
// 进程内存拷贝函数
// By: LyShark.com
NTSTATUS ProcessDumps(PEPROCESS pEprocess, ULONG_PTR nBase, ULONG nSize)
{BOOLEAN bAttach = FALSE;KAPC_STATE ks = { 0 };PVOID pBuffer = NULL;NTSTATUS status = STATUS_UNSUCCESSFUL;if (nSize == 0 || pEprocess == NULL){return status;}pBuffer = ExAllocatePoolWithTag(PagedPool, nSize, 'lysh');if (!pBuffer){return status;}memset(pBuffer, 0, nSize);if (pEprocess != IoGetCurrentProcess()){KeStackAttachProcess(pEprocess, &ks);bAttach = TRUE;}status = SafeCopyMemory_R3_to_R0(nBase, (ULONG_PTR)pBuffer, nSize);if (bAttach){KeUnstackDetachProcess(&ks);bAttach = FALSE;}OBJECT_ATTRIBUTES object;IO_STATUS_BLOCK io;HANDLE hFile;UNICODE_STRING log;// 导出文件名称RtlInitUnicodeString(&log, L"\\??\\C:\\lyshark_dumps.exe");InitializeObjectAttributes(&object, &log, OBJ_CASE_INSENSITIVE, NULL, NULL);status = ZwCreateFile(&hFile,GENERIC_WRITE,&object,&io,NULL,FILE_ATTRIBUTE_NORMAL,FILE_SHARE_WRITE,FILE_OPEN_IF,FILE_SYNCHRONOUS_IO_NONALERT,NULL,0);if (!NT_SUCCESS(status)){DbgPrint("打开文件错误 \n");return STATUS_SUCCESS;}ZwWriteFile(hFile, NULL, NULL, NULL, &io, pBuffer, nSize, NULL, NULL);DbgPrint("写出字节数: %d \n", io.Information);DbgPrint("[*] LyShark.exe 已转存");ZwClose(hFile);if (pBuffer){ExFreePoolWithTag(pBuffer, 'lysh');pBuffer = NULL;}return status;
}VOID UnDriver(PDRIVER_OBJECT driver)
{DbgPrint(("Uninstall Driver Is OK \n"));
}// lyshark.com
NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{DbgPrint("hello lyshark.com \n");NTSTATUS ntStatus;PEPROCESS pCurProcess = NULL;__try{ntStatus = PsLookupProcessByProcessId((HANDLE)272, &pCurProcess);if (NT_SUCCESS(ntStatus)){// 设置基地址以及长度ntStatus = ProcessDumps(pCurProcess, 0x140000000, 1024);ObDereferenceObject(pCurProcess);}}__except (1){ntStatus = GetExceptionCode();}Driver->DriverUnload = UnDriver;return STATUS_SUCCESS;
}
转存后效果如下所示:
至于导出的进程无法运行只是没有修复而已(后期会讲),可以打开看看是没错的。
驱动开发:内核中实现Dump进程转储相关推荐
- Linux驱动开发—内核I2C驱动详解
Linux驱动开发--内核I2C驱动 I2C驱动文件结构 I2C数据传输过程 i2c_transfer i2c_msg I2C通讯常用的接口函数(老版本) 快速读写接口函数:(连续读写) 常用的读操作 ...
- A40i使用笔记:编译驱动到内核中调用(ubuntu和A40i平台)
一.前言 最近因个人需求和工作需求,准备入坑linux驱动篇,学习了几节课程,简单了解了linux驱动流程,本章前期现介绍开发linux驱动必备的工具,否则后续学习很困难 二.环境 notepadqq ...
- X64驱动:内核中的文件回调
无论在用户层还是内核层,操作文件的流程基本一致,除了在API函数上的区别(用户层调用用户层API,内核层调用内核API)以外其他基本一致,先讲解一下文件系统执行的流程. 以NTFS文件系统为例:假设我 ...
- 《Linux操作系统 - 驱动开发》第9章 进程上下文、中断上下文及原子上下文
谈论进程上下文 .中断上下文.原子上下文之前,有必要讨论下两个概念: a – 上下文 上下文是从英文context翻译过来,指的是一种环境.相对于进程而言,就是进程执行时的环境: 具体来说就是各个变量 ...
- windows内核中杀任意进程,可杀360!
废话不多说 先上代码. static void DProKill(HANDLE pid){ PEPROCESS pe = DProPid2Eprocess(pid); if (NULL == pe) ...
- Windows驱动开发 - 内核模式下的字符串操作
1 ASCII字符串和宽字符串 char型,记录ansi字符集.每个字符一个字节.以0标志结束.在KdPrint中用%s输出. 宽字符型,wchar_t,描述unicode字符集的字符串,每个字符两个 ...
- Linux 驱动开发 三十五:Linux 内核时钟管理
参考: linux时间管理,时钟中断,系统节拍_u010936265的博客-CSDN博客_系统节拍时钟中断 Linux内核时钟系统和定时器实现_anonymalias的专栏-CSDN博客_linux内 ...
- linux摄像头内核驱动开发,FS_S5PC100平台上Linux Camera驱动开发详解(一)
说明: 理解摄像头驱动需要四个前提: 1)摄像头基本的工作原理和S5PC100集成的Camera控制器的工作原理 2)platform_device和platform_driver工作原理 3)Lin ...
- 【Linux 内核】进程管理 ( 进程特殊形式 | 内核线程 | 用户线程 | C 标准库与 Linux 内核中进程相关概念 | Linux 查看进程命令及输出字段解析 )
文章目录 一.进程特殊形式 ( 内核线程 | 用户线程 ) 二.C 标准库与 Linux 内核中进程相关概念 三.Linux 查看进程命令及输出字段解析 一.进程特殊形式 ( 内核线程 | 用户线程 ...
最新文章
- java中byte, iso-8859-1, UTF-8,乱码的根源
- 在别人那看到的很不错的ext.net的基本讲解
- 【转载】阿里云ECS服务器监控资源使用情况
- hive shell/sql 命令行
- 从源码的角度再看 React JS 中的 setState
- 微信为什么没有公众号导航
- Leetcode每日一题:38.Count and Say(外观数列)
- OpenGL加载纹理glGenTextures——内存优化(OpenGL内存泄漏)
- 拓端tecdat|R语言中回归模型预测的不同类型置信区间应用比较分析
- mysql迁移升级_MYSQL迁移或者升级的故障解决大全
- FPGROWTH算法
- 博弈论之:威胁与承诺
- 服务器安全证书过期怎么办,安全证书过期怎么办 网站安全证书失效处理【解决方法】...
- RNA剪接体 Spliceosome | 冷冻电镜 | 结构生物学
- 使用JavaScript获取当前时间方法(AM、PM)
- 2017.02.18 这一周的面试
- java作业 实现模拟保皇开始的发牌环节
- 地方两会前瞻布局 谋定·经信研究-李刚:各地元宇宙虚实融合
- zstuoj (浙理工) 孙壕请一盘青岛大虾呗
- 二进制推广者电子计算机,31-戏说计算机与二进制那点事儿
热门文章
- 职业选择心理测试软件,职业选择的心理测试题
- Java我的世界forge安装失败,我的世界forge安装失败install怎么办_MCforge安装失败install解决方法...
- 设计模式之Java语言模拟肯德基点餐收银系统
- FTPClient.listFiles
- Wannacry勒索蠕虫对企业安全有哪些影响?企业安全又将如何捍卫?看安普诺CEO怎么说
- [附源码]计算机毕业设计JAVA宠物商城
- IT治理、IT控制与IT审计之间的关系
- HP网络打印机--如何添加打印机
- 乐视在美国为新项目众筹,成功后将生产混合动力滑板车
- IDEA工具(阿里巴巴)代码规范检查插件