Skip to content
KitploitKITPLOIT
工具博客
提交
工具博客
提交

黑客、渗透测试和网络安全工具,武装您的安全武器库!

Kitploit 是一个黑客、网络安全和渗透测试工具的目录。发现最新的项目更新,查找漏洞、分析系统、自动化测试并加强你的安全。

··订阅源·联系·隐私·© 2026 Kitploit

工具目录

分类

查看所有分类
Loading categories
NativeDump — 使用纯NTAPI函数手工制作Minidump文件来转储lsass(不使用MiniDumpWriteDump!!!) | Kitploit
工具/GitHubGitHub/ricardojoserf/nativedump
内存取证后渗透利用红队
GitHubricardojoserf/nativedump

NativeDump

使用纯NTAPI函数手工制作Minidump文件来转储lsass(不使用MiniDumpWriteDump!!!)

查看仓库网站
7451044天前Kitploit 审核通过

最受欢迎

查看全部 →

发现我们社区最常用的工具。

探索所有工具

浏览我们的工具集合

查看所有工具 →
分享

NativeDump

NativeDump 允许仅使用 NTAPI 转储 lsass 进程,生成一个仅包含 Mimikatz 或 Pypykatz 等工具解析所需流(SystemInfo、ModuleList 和 Memory64List 流)的 Minidump 文件。

方案图

  • NTOpenProcessToken 和 NtAdjustPrivilegeToken 用于获取“SeDebugPrivilege”权限
  • RtlGetVersion 用于获取操作系统版本详细信息(主版本号、次版本号和内部版本号)。这对于 SystemInfo 流是必需的
  • NtQueryInformationProcess 和 NtReadVirtualMemory 用于获取 lsasrv.dll 的地址。这是 ModuleList 流唯一需要的模块
  • NtOpenProcess 用于获取 lsass 进程的句柄
  • NtQueryVirtualMemory 和 NtReadVirtualMemory 用于遍历内存区域并转储所有可能的区域。同时填充 Memory64List 流

该程序有一个可选参数用于输出文件,默认文件名为“proc_<PID>.dmp”:

root@kitploit:~
NativeDump.exe [DUMP_FILE]

POC

该工具已在最新版本的 Windows 上经过常见安全解决方案(Microsoft Defender for Endpoints、CrowdStrike...)的测试,运行良好,但隐蔽性取决于你选择的“风味”:使用不常见的语言并自定义二进制文件可获得最佳效果!但是,如果启用了 PPL 或 PEB 结构不可读,则无法运行。更新:现在可以在不读取 PEB 的情况下执行程序,请查看 peb-unreadable 分支 :)

此技术的一些优点包括:

  • 不使用众所周知的 dbghelp!MinidumpWriteDump 函数
  • 仅使用 Ntdll.dll 中的函数,因此可以通过重新映射库来绕过 API 钩子
  • Minidump 文件不必写入磁盘,你可以将其字节(编码或加密)传输到远程机器

你可以找到不同“风味”(或语言)的项目:

  • main - .NET 基本实现(此分支)

  • python-flavour - Python 实现,包含 3 种 ntdll.dll 覆盖方法 + 外泄到远程机器

  • golang-flavour - Golang 实现,包含 3 种 ntdll.dll 覆盖方法 + 外泄到远程机器

  • c-flavour - C/C++ 实现,包含 3 种 ntdll.dll 覆盖方法

  • bof-flavour - BOF 文件,包含 3 种 ntdll.dll 覆盖方法

  • rust-flavour - Rust 实现,作者 @safedv

  • crystal-flavour - Crystal 实现,具有 ntdll.dll 覆盖能力

  • nim-flavour - Nim 实现,具有 ntdll.dll 覆盖能力

其他有趣的 .NET 分支:

  • remote - 外泄到远程机器 + 3 种 ntdll.dll 覆盖方法 + 动态函数解析 + 字符串 AES 加密 + XOR 编码 Minidump 内容

  • all-modules - 获取所有模块的信息(不仅仅是 lsasrv.dll)

  • peb-unreadable - 不读取 lsass PEB 结构的实现 + 3 种 ntdll.dll 覆盖方法



技术详解:创建最小的 Minidump 文件

在阅读了 Minidump 未文档化的结构后,其结构可以总结为:

  • 头部:包含签名(“MDMP”)、流目录的位置和流的数量等信息
  • 流目录:每个流对应一条条目,包含类型、总大小和在文件中的位置
  • 流:每个流包含与进程相关的不同信息,并且有自己的格式
  • 区域:来自进程中每个可读内存区域的实际字节

结构

我创建了一个解析工具,可能会有所帮助:MinidumpParser。我们将专注于创建一个有效的文件,仅包含头部、流目录以及 Mimikatz/Pypykatz 解析 Minidump 文件所需的仅三个流:SystemInfo、ModuleList 和 Memory64List 流所需的值。


A. 头部

头部是一个 32 字节的结构,在 C# 中可以定义为:

root@kitploit:~
public struct MinidumpHeader
{
    public uint Signature;
    public ushort Version;
    public ushort ImplementationVersion;
    public ushort NumberOfStreams;
    public uint StreamDirectoryRva;
    public uint CheckSum;
    public IntPtr TimeDateStamp;
}

所需的值是:

  • Signature:固定值 0x504d44d(“MDMP” 字符串)
  • Version:固定值 0xa793(Microsoft 常量 MINIDUMP_VERSION)
  • NumberOfStreams:固定值 3,文件所需的三个流
  • StreamDirectoryRVA:固定值 0x20 或 32 字节,即头部的大小

B. 流目录

流目录中的每个条目是一个 12 字节的结构,因此有 3 个条目时大小为 36 字节。C# 中条目的结构定义为:

root@kitploit:~
public struct MinidumpStreamDirectoryEntry
{
    public uint StreamType;
    public uint Size;
    public uint Location;
}

字段“StreamType”表示流的类型(整数或 ID),一些最相关的如下:


C. SystemInformation 流

第一个流是 SystemInformation 流,ID 为 7。大小为 56 字节,位于偏移量 68(0x44),即流目录之后。其 C# 定义为:

root@kitploit:~
public struct SystemInformationStream
{
    public ushort ProcessorArchitecture;
    public ushort ProcessorLevel;
    public ushort ProcessorRevision;
    public byte NumberOfProcessors;
    public byte ProductType;
    public uint MajorVersion;
    public uint MinorVersion;
    public uint BuildNumber;
    public uint PlatformId;
    public uint UnknownField1;
    public uint UnknownField2;
    public IntPtr ProcessorFeatures;
    public IntPtr ProcessorFeatures2;
    public uint UnknownField3;
    public ushort UnknownField14;
    public byte UnknownField15;
}

所需的值是:

  • ProcessorArchitecture:64 位 Windows 系统为 9,32 位系统为 0
  • Major version、Minor version 和 BuildNumber:硬编码或通过 kernel32!GetVersionEx 或 ntdll!RtlGetVersion 获取(我们将使用后者)

D. ModuleList 流

第二个流是 ModuleList 流,ID 为 4。位于 SystemInformation 流之后偏移量 124(0x7C)处,大小也是固定的,为 112 字节,因为它只包含一个模块的条目,这是解析正确所需的唯一模块:“lsasrv.dll”。

该流的典型结构是一个 4 字节的值(包含条目数量),后面跟着每个模块的 108 字节条目:

root@kitploit:~
public struct ModuleListStream
{
    public uint NumberOfModules;
    public ModuleInfo[] Modules;
}

由于只有一个模块,它简化为:

root@kitploit:~
public struct ModuleListStream
{
    public uint NumberOfModules;
    public IntPtr BaseAddress;
    public uint Size;
    public uint UnknownField1;
    public uint Timestamp;
    public uint PointerName;
    public IntPtr UnknownField2;
    public IntPtr UnknownField3;
    public IntPtr UnknownField4;
    public IntPtr UnknownField5;
    public IntPtr UnknownField6;
    public IntPtr UnknownField7;
    public IntPtr UnknownField8;
    public IntPtr UnknownField9;
    public IntPtr UnknownField10;
    public IntPtr UnknownField11;
}

所需的值是:

  • NumberOfStreams:固定值 1
  • BaseAddress:使用 psapi!GetModuleBaseName 或 ntdll!NtQueryInformationProcess 与 ntdll!NtReadVirtualMemory 的组合(我们将使用后者)
  • Size:通过从 BaseAddress 开始累加所有内存区域的大小,直到遇到大小为 4096 字节(0x1000)的区域(其他库的 .text 节)获得
  • PointerToName:指向“C:\Windows\System32\lsasrv.dll”字符串的 Unicode 字符串结构,位于流本身之后偏移量 236(0xEC)处

E. Memory64List 流

第三个流是 Memory64List 流,ID 为 9。位于 ModuleList 流和 Unicode 字符串之后偏移量 298(0x12A)处,其大小取决于模块数量。

root@kitploit:~
public struct Memory64ListStream
{
    public ulong NumberOfEntries; 
    public uint MemoryRegionsBaseAddress;
    public Memory64Info[] MemoryInfoEntries;
}

每个模块条目是一个 16 字节的结构:

root@kitploit:~
public struct Memory64Info
{
    public IntPtr Address;
    public IntPtr Size;
}

所需的值是:

  • NumberOfEntries:内存区域的数量,遍历内存区域后获得
  • MemoryRegionsBaseAddress:内存区域字节的起始位置,通过累加所有 16 字节内存条目的大小后计算得出
  • Address 和 Size:遍历每个有效区域时获得

F. 遍历内存区域

遍历 lsass.exe 进程的内存区域有一些先决条件,这些条件仅使用 NTAPI 即可解决:

  1. 获取“SeDebugPrivilege”权限。我们不使用典型的 Advapi!OpenProcessToken、Advapi!LookupPrivilegeValue 和 Advapi!AdjustTokenPrivilege,而是使用 ntdll!NtOpenProcessToken、ntdll!NtAdjustPrivilegesToken 以及 Luid 的硬编码值 20(该值在所有最新 Windows 版本中是固定的)
  2. 获取进程 ID。例如,使用 ntdll!NtGetNextProcess 遍历所有进程,使用 ntdll!NtQueryInformationProcess 获取 PEB 地址,然后使用 ntdll!NtReadVirtualMemory 读取 ProcessParameters 中的 ImagePathName 字段。为了避免使 PoC 过于复杂,我们将使用 .NET 的 Process.GetProcessesByName(<PROCESS_NAME>)
  3. 打开进程句柄。使用 ntdll!OpenProcess 并设置权限 PROCESS_QUERY_INFORMATION (0x0400) 以检索进程信息,以及 PROCESS_VM_READ (0x0010) 以读取内存字节

有了这些,就可以通过调用以下函数遍历进程内存:

  • ntdll!NtQueryVirtualMemory:返回一个 MEMORY_BASIC_INFORMATION 结构,其中包含每个内存区域的保护类型、状态、基址和大小
    • 如果内存保护不是 PAGE_NOACCESS (0x01) 且内存状态为 MEM_COMMIT (0x1000),表示该区域可访问且已提交,则基址和大小填充 Memory64List 流的一个条目,字节可以添加到文件中
    • 如果基址等于 lsasrv.dll 的基址,则用于计算 lsasrv.dll 在内存中的大小
  • ntdll!NtReadVirtualMemory:将该区域的字节添加到 Memory64List 流之后的 Minidump 文件中

G. 创建 Minidump 文件

经过前面的步骤,我们已经拥有创建 Minidump 文件所需的一切。我们可以在本地创建一个文件,或者将字节发送到远程机器,并且可以在此之前对字节进行编码或加密。其中一些可能性已在 delegates 分支 中编码实现,该分支中本地创建的文件可以使用 XOR 编码;以及 remote 分支,该分支中文件可以在发送到远程机器之前使用 XOR 编码。



TrickDump

对于避免创建 Minidump 文件的替代方法,请查看 TrickDump:它生成三个 JSON 文件和一个 ZIP 存档,Minidump 在攻击者的机器上重建。这有助于规避那些监控 Minidump 创建或外泄的安全解决方案。

下载工具
ID流类型
0x00UnusedStream
0x01ReservedStream0
0x02ReservedStream1
0x03ThreadListStream
0x04ModuleListStream
0x05MemoryListStream
0x06ExceptionStream
0x07SystemInfoStream
0x08ThreadExListStream
0x09Memory64ListStream
0x0ACommentStreamA
0x0BCommentStreamW
0x0CHandleDataStream
0x0DFunctionTableStream
0x0EUnloadedModuleListStream
0x0FMiscInfoStream
0x10MemoryInfoListStream
0x11ThreadInfoListStream
0x12HandleOperationListStream
0x13TokenStream
0x16HandleOperationListStream