概述:windows操作系统 ntdll.dll 学习笔记
ntdll是Windows操作系统核心的一个dll,里边集成了大多数 windows api 所需要的接口。学习 ntdll 有助于我们快速了解 windows API。
[toc]
0x01、认识 ntdll
使用三方工具可以看到,ntdll的导出函数有两千多个,从基本的输入输出到内存操作都覆盖。本文主要记录在工作学习中使用到的相关导出接口,用多少写多少。
0x02、关键内存函数
NtAllocateVirtualMemory
分配虚拟内存,是 VirtualAlloc 的底层实现。
NTSTATUS NtAllocateVirtualMemory(
HANDLE ProcessHandle, // 进程句柄,-1表示当前进程
PVOID *BaseAddress, // 期望的基地址(输入/输出)
ULONG_PTR ZeroBits, // 地址对齐限制
PSIZE_T RegionSize, // 分配大小(输入/输出)
ULONG AllocationType, // 分配类型:MEM_COMMIT | MEM_RESERVE
ULONG Protect // 内存保护属性:PAGE_READWRITE等
);示例:
PVOID pBase = NULL;
SIZE_T size = 0x1000;
NTSTATUS status = NtAllocateVirtualMemory(
(HANDLE)-1,
&pBase,
0,
&size,
MEM_COMMIT | MEM_RESERVE,
PAGE_EXECUTE_READWRITE
);NtFreeVirtualMemory
释放虚拟内存,是 VirtualFree 的底层实现。
NTSTATUS NtFreeVirtualMemory(
HANDLE ProcessHandle,
PVOID *BaseAddress,
PSIZE_T RegionSize,
ULONG FreeType // MEM_DECOMMIT | MEM_RELEASE
);NtProtectVirtualMemory
修改内存保护属性,是 VirtualProtect 的底层实现。
NTSTATUS NtProtectVirtualMemory(
HANDLE ProcessHandle,
PVOID *BaseAddress,
PSIZE_T NumberOfBytesToProtect,
ULONG NewAccessProtection,
PULONG OldAccessProtection
);NtReadVirtualMemory / NtWriteVirtualMemory
读写进程内存,是 ReadProcessMemory / WriteProcessMemory 的底层实现。
NTSTATUS NtReadVirtualMemory(
HANDLE ProcessHandle,
PVOID BaseAddress,
PVOID Buffer,
SIZE_T NumberOfBytesToRead,
PSIZE_T NumberOfBytesReaded
);
NTSTATUS NtWriteVirtualMemory(
HANDLE ProcessHandle,
PVOID BaseAddress,
PVOID Buffer,
SIZE_T NumberOfBytesToWrite,
PSIZE_T NumberOfBytesWritten
);NtQueryVirtualMemory
查询内存信息,是 VirtualQuery 的底层实现。
NTSTATUS NtQueryVirtualMemory(
HANDLE ProcessHandle,
PVOID BaseAddress,
MEMORY_INFORMATION_CLASS MemoryInformationClass,
PVOID MemoryInformation,
SIZE_T MemoryInformationLength,
PSIZE_T ReturnLength
);0x03、模块与函数查找
LdrLoadDll
加载 DLL,是 LoadLibrary 的底层实现。
NTSTATUS LdrLoadDll(
PWSTR DllPath, // DLL搜索路径
PULONG DllCharacteristics, // 特征标志
PUNICODE_STRING DllName, // DLL名称
PVOID *DllHandle // 返回模块句柄
);LdrGetProcedureAddress
获取导出函数地址,是 GetProcAddress 的底层实现。
NTSTATUS LdrGetProcedureAddress(
PVOID DllHandle, // 模块句柄
ANSI_STRING *ProcedureName, // 函数名(可选)
ULONG ProcedureNumber, // 函数序号(可选)
PVOID *ProcedureAddress // 返回函数地址
);示例:
HMODULE hNtdll = GetModuleHandleA("ntdll.dll");
FARPROC pFunc = GetProcAddress(hNtdll, "NtAllocateVirtualMemory");
// 或使用 LdrGetProcedureAddress
UNICODE_STRING ustrDllName;
RtlInitUnicodeString(&ustrDllName, L"ntdll.dll");
PVOID hModule = NULL;
LdrLoadDll(NULL, NULL, &ustrDllName, &hModule);
ANSI_STRING asFuncName;
RtlInitAnsiString(&asFuncName, "NtAllocateVirtualMemory");
PVOID pFuncAddr = NULL;
LdrGetProcedureAddress(hModule, &asFuncName, 0, &pFuncAddr);LdrGetDllHandle
获取已加载 DLL 的句柄,不增加引用计数。
NTSTATUS LdrGetDllHandle(
PWSTR DllPath,
PULONG DllCharacteristics,
PUNICODE_STRING DllName,
PVOID *DllHandle
);0x04、线程函数
NtCreateThread
创建线程,是 CreateThread 的底层实现。
NTSTATUS NtCreateThread(
PHANDLE ThreadHandle, // 返回线程句柄
ACCESS_MASK DesiredAccess, // 访问权限
POBJECT_ATTRIBUTES ObjectAttributes,
HANDLE ProcessHandle, // 目标进程句柄
PCLIENT_ID ClientId, // 返回线程ID
PCONTEXT ThreadContext, // 线程上下文
PVOID InitialTeb, // 初始TEB
BOOLEAN CreateSuspended // 是否挂起创建
);NtCreateThreadEx
扩展版的线程创建函数,支持更多参数。
NTSTATUS NtCreateThreadEx(
PHANDLE ThreadHandle,
ACCESS_MASK DesiredAccess,
POBJECT_ATTRIBUTES ObjectAttributes,
HANDLE ProcessHandle,
LPTHREAD_START_ROUTINE StartRoutine,
PVOID Argument,
ULONG CreateFlags, // 标志位
ULONG_PTR ZeroBits,
SIZE_T StackSize,
SIZE_T MaximumStackSize,
PPSS_ATTRIBUTE_LIST AttributeList
);NtTerminateThread
终止线程。
NTSTATUS NtTerminateThread(
HANDLE ThreadHandle,
NTSTATUS ExitStatus
);NtQueueApcThread
向线程队列添加 APC(异步过程调用)。
NTSTATUS NtQueueApcThread(
HANDLE ThreadHandle,
PVOID ApcRoutine,
PVOID ApcArgument1,
PVOID ApcArgument2,
PVOID ApcArgument3
);0x05、进入内核函数
Nt函数与Zw函数
ntdll 中每个系统调用都有两个导出:Nt* 和 Zw*。在用户模式下,它们指向相同的系统服务存根;在内核模式下,行为有所不同:
- Nt系列:原系统服务入口,会进行参数验证
- Zw系列:内核模式下的”干净”调用路径,假设参数已验证
// 用户模式下,两者等价
NtCreateFile == ZwCreateFile // 都通过 syscall 进入内核系统调用机制
ntdll 中的系统调用通过 syscall(x64)或 sysenter(x86)指令进入内核:
x64 系统调用存根示例:
ntdll!NtCreateFile:
00007FF9`12340000 4C8BD1 mov r10, rcx
00007FF9`12340003 B855000000 mov eax, 55h ; 系统服务号
00007FF9`12340008 0F05 syscall
00007FF9`1234000A C3 retKiFastSystemCall / KiIntSystemCall
早期的系统调用入口(32位系统):
// Windows XP/2003 等旧系统
__declspec(naked) void KiFastSystemCall() {
__asm {
mov edx, esp
sysenter
}
}关键系统调用号(System Service Number)
系统调用号因 Windows 版本而异,可通过 NtQuerySystemInformation 获取:
| 函数 | Win10 19041 | Win11 22000 |
|---|---|---|
| NtCreateFile | 0x55 | 0x57 |
| NtReadFile | 0x06 | 0x06 |
| NtWriteFile | 0x08 | 0x08 |
| NtAllocateVirtualMemory | 0x18 | 0x18 |
动态获取系统调用号:
// 从 ntdll 的导出函数中解析 syscall 号
ULONG GetSyscallNumber(PCHAR FuncName) {
HMODULE hNtdll = GetModuleHandleA("ntdll.dll");
PUCHAR pFunc = (PUCHAR)GetProcAddress(hNtdll, FuncName);
// x64: mov eax, 0xXX
if (pFunc[0] == 0x4C && pFunc[1] == 0x8B && pFunc[2] == 0xD1) {
// mov r10, rcx
if (pFunc[3] == 0xB8) {
return *(ULONG*)(pFunc + 4);
}
}
return 0;
}0x06、进程函数
NtCreateProcess
创建进程。
NTSTATUS NtCreateProcess(
PHANDLE ProcessHandle,
ACCESS_MASK DesiredAccess,
POBJECT_ATTRIBUTES ObjectAttributes,
HANDLE ParentProcess,
BOOLEAN InheritObjectTable,
HANDLE SectionHandle,
HANDLE DebugPort,
HANDLE ExceptionPort
);NtTerminateProcess
终止进程。
NTSTATUS NtTerminateProcess(
HANDLE ProcessHandle,
NTSTATUS ExitStatus
);NtOpenProcess
打开进程获取句柄。
NTSTATUS NtOpenProcess(
PHANDLE ProcessHandle,
ACCESS_MASK DesiredAccess,
POBJECT_ATTRIBUTES ObjectAttributes,
PCLIENT_ID ClientId // 进程ID
);0x07、其他常用函数
RtlInitUnicodeString / RtlInitAnsiString
初始化字符串结构。
VOID RtlInitUnicodeString(
PUNICODE_STRING DestinationString,
PCWSTR SourceString
);
VOID RtlInitAnsiString(
PANSI_STRING DestinationString,
PCSTR SourceString
);NtQuerySystemInformation
查询系统信息,功能强大。
NTSTATUS NtQuerySystemInformation(
SYSTEM_INFORMATION_CLASS SystemInformationClass,
PVOID SystemInformation,
ULONG SystemInformationLength,
PULONG ReturnLength
);常用信息类:
SystemProcessInformation- 进程列表SystemModuleInformation- 内核模块列表SystemHandleInformation- 系统句柄列表
NtQueryInformationProcess
查询进程信息。
NTSTATUS NtQueryInformationProcess(
HANDLE ProcessHandle,
PROCESSINFOCLASS ProcessInformationClass,
PVOID ProcessInformation,
ULONG ProcessInformationLength,
PULONG ReturnLength
);0x08、参考链接
2024年8月1日09:27:57 更新
除了导出接口,也应该了解到系统调用表