多数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进程转储相关推荐

  1. Linux驱动开发—内核I2C驱动详解

    Linux驱动开发--内核I2C驱动 I2C驱动文件结构 I2C数据传输过程 i2c_transfer i2c_msg I2C通讯常用的接口函数(老版本) 快速读写接口函数:(连续读写) 常用的读操作 ...

  2. A40i使用笔记:编译驱动到内核中调用(ubuntu和A40i平台)

    一.前言 最近因个人需求和工作需求,准备入坑linux驱动篇,学习了几节课程,简单了解了linux驱动流程,本章前期现介绍开发linux驱动必备的工具,否则后续学习很困难 二.环境 notepadqq ...

  3. X64驱动:内核中的文件回调

    无论在用户层还是内核层,操作文件的流程基本一致,除了在API函数上的区别(用户层调用用户层API,内核层调用内核API)以外其他基本一致,先讲解一下文件系统执行的流程. 以NTFS文件系统为例:假设我 ...

  4. 《Linux操作系统 - 驱动开发》第9章 进程上下文、中断上下文及原子上下文

    谈论进程上下文 .中断上下文.原子上下文之前,有必要讨论下两个概念: a – 上下文 上下文是从英文context翻译过来,指的是一种环境.相对于进程而言,就是进程执行时的环境: 具体来说就是各个变量 ...

  5. windows内核中杀任意进程,可杀360!

    废话不多说 先上代码. static void DProKill(HANDLE pid){ PEPROCESS pe = DProPid2Eprocess(pid); if (NULL == pe) ...

  6. Windows驱动开发 - 内核模式下的字符串操作

    1 ASCII字符串和宽字符串 char型,记录ansi字符集.每个字符一个字节.以0标志结束.在KdPrint中用%s输出. 宽字符型,wchar_t,描述unicode字符集的字符串,每个字符两个 ...

  7. Linux 驱动开发 三十五:Linux 内核时钟管理

    参考: linux时间管理,时钟中断,系统节拍_u010936265的博客-CSDN博客_系统节拍时钟中断 Linux内核时钟系统和定时器实现_anonymalias的专栏-CSDN博客_linux内 ...

  8. linux摄像头内核驱动开发,FS_S5PC100平台上Linux Camera驱动开发详解(一)

    说明: 理解摄像头驱动需要四个前提: 1)摄像头基本的工作原理和S5PC100集成的Camera控制器的工作原理 2)platform_device和platform_driver工作原理 3)Lin ...

  9. 【Linux 内核】进程管理 ( 进程特殊形式 | 内核线程 | 用户线程 | C 标准库与 Linux 内核中进程相关概念 | Linux 查看进程命令及输出字段解析 )

    文章目录 一.进程特殊形式 ( 内核线程 | 用户线程 ) 二.C 标准库与 Linux 内核中进程相关概念 三.Linux 查看进程命令及输出字段解析 一.进程特殊形式 ( 内核线程 | 用户线程 ...

最新文章

  1. java中byte, iso-8859-1, UTF-8,乱码的根源
  2. 在别人那看到的很不错的ext.net的基本讲解
  3. 【转载】阿里云ECS服务器监控资源使用情况
  4. hive shell/sql 命令行
  5. 从源码的角度再看 React JS 中的 setState
  6. 微信为什么没有公众号导航
  7. Leetcode每日一题:38.Count and Say(外观数列)
  8. OpenGL加载纹理glGenTextures——内存优化(OpenGL内存泄漏)
  9. 拓端tecdat|R语言中回归模型预测的不同类型置信区间应用比较分析
  10. mysql迁移升级_MYSQL迁移或者升级的故障解决大全
  11. FPGROWTH算法
  12. 博弈论之:威胁与承诺
  13. 服务器安全证书过期怎么办,安全证书过期怎么办 网站安全证书失效处理【解决方法】...
  14. RNA剪接体 Spliceosome | 冷冻电镜 | 结构生物学
  15. 使用JavaScript获取当前时间方法(AM、PM)
  16. 2017.02.18 这一周的面试
  17. java作业 实现模拟保皇开始的发牌环节
  18. 地方两会前瞻布局 谋定·经信研究-李刚:各地元宇宙虚实融合
  19. zstuoj (浙理工) 孙壕请一盘青岛大虾呗
  20. 二进制推广者电子计算机,31-戏说计算机与二进制那点事儿

热门文章

  1. 职业选择心理测试软件,职业选择的心理测试题
  2. Java我的世界forge安装失败,我的世界forge安装失败install怎么办_MCforge安装失败install解决方法...
  3. 设计模式之Java语言模拟肯德基点餐收银系统
  4. FTPClient.listFiles
  5. Wannacry勒索蠕虫对企业安全有哪些影响?企业安全又将如何捍卫?看安普诺CEO怎么说
  6. [附源码]计算机毕业设计JAVA宠物商城
  7. IT治理、IT控制与IT审计之间的关系
  8. HP网络打印机--如何添加打印机
  9. 乐视在美国为新项目众筹,成功后将生产混合动力滑板车
  10. IDEA工具(阿里巴巴)代码规范检查插件