Open tangxiaodao opened 8 months ago
Hi! Thanks for the interest in the project. What kind of documentation are you looking for?
Most of the library's functionality assumes certain understanding of system mechanisms and familiarity with the underlying low-level API. The goal of this project is to simplify calling functions from ntdll.dll
and other system libraries by providing wrappers that integrate them into Delphi. Documenting what these (underlying) system functions do is out of the scope of this project. I know, some of the things might be undocumented and meaningful only to security researchers that reverse engineer Windows. If your goal is understanding the system mechanisms, I can recommend the Windows Internals book; if you want to learn the details about the underlying APIs, NtDoc (which I'm slowly expanding) might have some useful information. Otherwise, just googling the functions that my wrappers call might help.
When it comes to documenting the added functionality of this library, you can find comments inside the interface section of each NtUtils.*.pas
file. These files group wrappers for a subset of APIs based on a common topic and each exposed function has a short description. For instance, if you know what registry syscalls exist/do on Windows, you should find functions from NtUtils.Registry.pas
pretty self-explanetory.
I can work on better discoverability of the available functionality, though. I was planning to add a table to the readme that summarizes which system mechanisms each library module covers. However, you would still need to check the comments in the interface section of the corresponding module for the complete overview of the exposed functionality.
Hi,diversenok.
Thank you for your reply.
What I mean is, some explanatory documents for this source code. For example, whether the header files for Ntdll and Undoc Ntdll have been defined, or is it just a wrapper for the Ntdll function. Has PEB, SYSTEM PROCESS, etc. been defined? Does it provide access to SSDT arrays, and does it provide access to APINAME through SSDT.
------------------ 原始邮件 ------------------ 发件人: "diversenok/NtUtilsLibrary" @.>; 发送时间: 2024年3月20日(星期三) 上午6:15 @.>; @.**@.>; 主题: Re: [diversenok/NtUtilsLibrary] Nice work,but poor doc (Issue #6)
Hi! Thanks for the interest in the project. What kind of documentation are you looking for?
Most of the library's functionality assumes certain understanding of system mechanisms and familiarity with the underlying low-level API. The goal of this project is to simplify calling functions from ntdll.dll and other system libraries by providing wrappers that integrate them into Delphi. Documenting what these (underlying) system functions do is out of the scope of this project. I know, some of the things might be undocumented and meaningful only to security researchers that reverse engineer Windows. If your goal is understanding the system mechanisms, I can recommend the Windows Internals book; if you want to learn the details about the underlying APIs, NtDoc (which I'm slowly expanding) might have some useful information. Otherwise, just googling the functions that my wrappers call might help.
When it comes to documenting the added functionality of this library, you can find comments inside the interface section of each NtUtils.*.pas file. These files group wrappers for a subset of APIs based on a common topic and each exposed function has a short description. For instance, if you know what registry syscalls exist/do on Windows, you should find functions from NtUtils.Registry.pas pretty self-explanetory.
I can work on better discoverability of the available functionality, though. I was planning to add a table to the readme that summarizes which system mechanisms each library module covers. However, you would still need to check the comments in the interface section of the corresponding module for the complete overview of the exposed functionality.
— Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you authored the thread.Message ID: @.***>
for example://GetSSDT mov eax,0x11E1 lea edx,dword ptr ss:[esp+4] int 0x2E ret 0x0C .............
Would you provide such usage examples and tutorial,etc
------------------ 原始邮件 ------------------ 发件人: "diversenok/NtUtilsLibrary" @.>; 发送时间: 2024年3月20日(星期三) 上午6:15 @.>; @.**@.>; 主题: Re: [diversenok/NtUtilsLibrary] Nice work,but poor doc (Issue #6)
Hi! Thanks for the interest in the project. What kind of documentation are you looking for?
Most of the library's functionality assumes certain understanding of system mechanisms and familiarity with the underlying low-level API. The goal of this project is to simplify calling functions from ntdll.dll and other system libraries by providing wrappers that integrate them into Delphi. Documenting what these (underlying) system functions do is out of the scope of this project. I know, some of the things might be undocumented and meaningful only to security researchers that reverse engineer Windows. If your goal is understanding the system mechanisms, I can recommend the Windows Internals book; if you want to learn the details about the underlying APIs, NtDoc (which I'm slowly expanding) might have some useful information. Otherwise, just googling the functions that my wrappers call might help.
When it comes to documenting the added functionality of this library, you can find comments inside the interface section of each NtUtils.*.pas file. These files group wrappers for a subset of APIs based on a common topic and each exposed function has a short description. For instance, if you know what registry syscalls exist/do on Windows, you should find functions from NtUtils.Registry.pas pretty self-explanetory.
I can work on better discoverability of the available functionality, though. I was planning to add a table to the readme that summarizes which system mechanisms each library module covers. However, you would still need to check the comments in the interface section of the corresponding module for the complete overview of the exposed functionality.
— Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you authored the thread.Message ID: @.***>
For example, whether the header files for Ntdll and Undoc Ntdll have been defined, or is it just a wrapper for the Ntdll function.
You can find definitions in the Headers directory. Most filenames resemble the names of related Windows SDK/WDK and PHNT headers. It's possible to include and use them directly, without relying on any wrappers.
Has PEB, SYSTEM PROCESS, etc. been defined? Does it provide access to SSDT arrays, and does it provide access to APINAME through SSDT.
PEB
(as well as TEB
, and KUSER_SHARED_DATA
) are available in the Ntapi.ntpebteb.pas
header. There also RtlGetCurrentPeb
and NtCurrentTeb
for accessing them.SYSTEM_PROCESS_INFORMATION
and related structures for enumerating processes? Then it's in Ntapi.ntexapi.pas
, but I would recommend using more Delphi-friendly wrappers from NtUtils.Processes.Snapshots.pas
as they do all parsing for you.NtUtils.ImageHlp.Syscalls.pas
that allows retrieving syscall numbers from ntdll.dll
or win32u.dll
. If the goal is to bypass user-mode hooks by issuing syscalls, NtUtils.AntiHooking.pas
offers this functionality transparently to the rest of the code. You specify which ntdll imports to unhook and it automatically redirects related library calls into clean syscall stubs. Internally, it uses IAT hooks and a second instance of ntdll mapped from KnownDlls. Here is an example of how someone might use it:uses
Ntapi.WinNt, Ntapi.ntpsapi, NtUtils, NtUtils.AntiHooking, NtUtils.Threads;
function UnhookAndInjectAPC(
[in] TID: TThreadId;
[in] Payload: Pointer;
[in, opt] PayloadParameter: Pointer = nil
): TNtxStatus;
var
hxThread: IHandle;
begin
// Dynamically replace our imports of ntdll.NtOpenThread and
// ntdll.NtQueueApcThreadEx with clean syscall stubs
Result := RtlxEnforceExternalImportAntiHooking([
@NtOpenThread,
@NtQueueApcThreadEx
]);
if not Result.IsSuccess then
Exit;
// Open the target thread (now issues a syscall instad of
// calling ntdll.NtOpenThread)
Result := NtxOpenThread(hxThread, TID, THREAD_SET_CONTEXT);
if not Result.IsSuccess then
Exit;
// Inject an APC that executes the payload on the thread
// (now issues a syscall instead of calling ntdll.NtQueueApcThreadEx)
Result := NtxQueueApcThreadEx(hxThread.Handle, Payload, PayloadParameter);
// Here the compiler automatically inserts code for closing the thread handle
end;
Thank for your reply.
I'll find something from your code and test it.
About SYSTEM_PROCESS ,defined as follow:
_SYSTEM_PROCESS = record
NextEntryDelta:ULONG;// Netx Struct Offset,0 = Struct End
ThreadCount:ULONG;
Reserved : array [0..5] of ULONG;
CreateTime:LARGE_INTEGER;
UserTime:LARGE_INTEGER;
KernelTime:LARGE_INTEGER;
ImageName: UNICODE_STRING;
BasePriority:KPRIORITY;
ProcessId :ULONG;
InheritedFromProcessId:ULONG;
HandleCount:ULONG;
Reserved2:array[0..1]of ULONG;
VmCounters : VM_COUNTERS;
IoCounters : IO_COUNTERS;
Threads : array [0..0] of SYSTEM_THREADS;
end;
SYSTEM_PROCESS = _SYSTEM_PROCESS;
PSYSTEM_PROCESS = ^SYSTEM_PROCESS;
My EnumKernelSSDT code as follow(Uncompleted && Untest):
procedure EnumKernelSSDT_ID;stdcall;
var
modIndex:Integer;// 1=ntdll.dll 2=user32.dll 3=gdi32.dll
tempFile:string;
modFile:string;
modData:THandle;
dataPointer:Pointer;
r3handle:PDWORD;
modHandle:Integer;
optHeader:IMAGE_OPTIONAL_HEADER;
sectionHeader:array of IMAGE_SECTION_HEADER_E;
funcExportArr:array of FuncExportTable;
temp : NTFuncID;
opcodeArr : ByteArray; //API Entry First X number Bytes OpCodes
mpointer : Integer;
count : Integer;
tempAddr : DWORD;
tempAddrJmp : DWORD;
tempAddrJmpX:DWORD;
tempAddrJmpXX:DWORD;
tempPath : array [0..MAX_PATH-1] of AnsiChar;
hFile : THandle;
fileSize : Integer;
i: Integer;
begin
if g_NTSSDT_Id = nil then
begin
g_NTSSDT_Id := TList.Create;
end;
for modIndex := 1 to 3 do
begin
case modIndex of
1: modFile := 'ntdll.dll';
2: modFile := 'use32.dll';
3: modFile := 'gdi32.dll';
end;
temp.dllIndex := modIndex;
modHandle := Module_GetModuleHandle(modFile);
GetTempPath(MAX_PATH,tempPath);
GetTempFileNameA(tempPath,'*',0,PChar(tempFile));
GetSystemDirectory(tempPath,MAX_PATH);
modFile := StrPas(tempPath) + '\' + modFile;
CopyFile(PChar(modFile),PChar(tempFile),False);
hFile := FileOpen(tempFile,fmOpenRead);
fileSize := GetFileSize(hFile,nil);
FileRead(hFile,modData,fileSize);
DeleteFile(tempFile);
if (GetModuleImage(modData,optHeader,False) and (optHeader.Magic = $10B)) then
begin
r3handle := VirtualAllocEx(
THandle(-1),
nil,
optHeader.SizeOfImage,
4096 or 8192,
64);
Mem_WriteMem_(
r3handle^,
modData,
optHeader.SizeOfHeaders);
for i := 0 to GetModuleSection(modData,sectionHeader,nil) - 1 do//Copy all sectionData from Dll
begin
Mem_WriteMem_(
ADD__(r3handle^,sectionHeader[i].VirtualAddress),
ADD__(modData,sectionHeader[i].PointerToRawData),
sectionHeader[i].SizeOfRawData);
end;
RetifyReloc(r3handle^,modHandle);
for i := 0 to GetModuleExport(r3handle^,funcExportArr) - 1 do
begin
if modIndex = 1 then//一级
begin
if LeftStr(funcExportArr[i].ApiName,2) <> 'Zw' then//Jmp if not Zw prefix
Continue;
end;
Mem_ReadBytes_(funcExportArr[i].ApiEntry,opcodeArr,32);
if (opcodeArr[0] = 184) or (opcodeArr[0] = 255) then //
begin
temp.APIName := funcExportArr[i].ApiName;
temp.RETN_XX := 0;
temp.SSDT_ID := ReadInteger(opcodeArr,1);
if (g_WindowsVersoin.dwMajorVersion = 5) and (g_WindowsVersoin.dwMinorVersion = 0) then//' Windows 2000
begin
if (opcodeArr[9] = 205) and (opcodeArr[10] = 46) then // INT 2E
begin
if opcodeArr[11] = 194 then// C2=194 C3=195
begin
temp.RETN_XX := ReadWord(opcodeArr,12);
g_NTSSDT_Id.Add(@temp);
Continue;
end;
if opcodeArr[11] = 195 then
begin
g_NTSSDT_Id.Add(@temp);
Continue;
end;
if opcodeArr[11] = 233 then
begin
mpointer := ADD__(mpointer,16);
mpointer := ADD__(mpointer,ReadWord(opcodeArr,12));
Mem_ReadBytes_(mpointer,opcodeArr,32);//C2 0C00 RETN 0C JMP to Here
if opcodeArr[0] = 194 then//C2=194 C3=195
begin
temp.RETN_XX := ReadWord(opcodeArr,1);
g_NTSSDT_Id.Add(@temp);
Continue;
end;
if opcodeArr[0] = 195 then
begin
g_NTSSDT_Id.Add(@temp);
Continue;
end;
end;
end;
end;
if g_WindowsVersoin.isWin64 then
begin
end;
if opcodeArr[5] = 232 then//' WIN8.32
begin
mpointer := ReadInteger(opcodeArr,6);
if (mpointer > 0) and (mpointer < 10) then //11+API Pointer + 2 = 15(sysenter)
begin
mpointer := ADD__(mpointer,13);
if 15 = opcodeArr[mpointer] then
begin
if opcodeArr[10] = 194 then
begin
temp.RETN_XX := ReadWord(opcodeArr,11);
g_NTSSDT_Id.Add(@temp);
Continue;
end;
if opcodeArr[10] = 195 then
begin
g_NTSSDT_Id.Add(@temp);
Continue;
end;
end;
end;
end;
if (opcodeArr[5] = 186) and (opcodeArr[10] = 255) then//XP.SP2 2003 Vista Win7
begin
if (opcodeArr[11] = 18) or (opcodeArr[11] = 210) then
begin
if opcodeArr[12] = 194 then// C2=194 C3=195
begin
temp.RETN_XX := ReadWord(opcodeArr,13);
g_NTSSDT_Id.Add(@temp);
Continue;
end;
end;
if opcodeArr[12] = 195 then
begin
g_NTSSDT_Id.Add(@temp);
Continue;
end;
end;
end;
end;
if g_WindowsVersoin.isWin64 then
begin
temp.ECX := 0;
if (g_WindowsVersoin.dwMajorVersion = 10) and (g_WindowsVersoin.dwMinorVersion = 0) then
begin
if (opcodeArr[5] = 186) and (opcodeArr[10] = 255) and (opcodeArr[11] = 210) then//Win10.x64
begin
if opcodeArr[12] = 194 then//temp.ECX = 0
begin
temp.RETN_XX := ReadWord(opcodeArr,13);
g_NTSSDT_Id.Add(@temp);
Continue;
end;
if opcodeArr[12] = 195 then
begin
g_NTSSDT_Id.Add(@temp);
Continue;
end;
end;
if (opcodeArr[5] = 186) and (opcodeArr[10] <> 255) and (opcodeArr[11] <> 210) then//Win10.x64
begin
if funcExportArr[i].ApiName = 'ZwQueryInformationProcess' then
begin
if (opcodeArr[24] = 194) or (opcodeArr[28] = 194) then// temp.ECX = 0
begin
if (opcodeArr[24] = 194) then
temp.RETN_XX := ReadWord(opcodeArr,25);
if opcodeArr[28] = 194 then
temp.RETN_XX := ReadWord(opcodeArr,29);
g_NTSSDT_Id.Add(@temp);
Continue;
end;
if (opcodeArr[24] = 195) or (opcodeArr[28] = 195) then
begin
g_NTSSDT_Id.Add(@temp);
Continue;
end;
end;
end;
if opcodeArr[0] = 255 then
begin
Mem_ReadInteger_(funcExportArr[i].ApiEntry + 2,tempAddrJmp);
Mem_ReadInteger_(tempAddrJmpX,tempAddrJmpXX);
Mem_ReadBytes_(tempAddrJmpXX,opcodeArr,32);
temp.SSDT_ID := ReadInteger(opcodeArr,1);
if opcodeArr[12] = 194 then//temp.ECX = 0
begin
temp.RETN_XX := ReadWord(opcodeArr,13);
g_NTSSDT_Id.Add(@temp);
Continue;
end;
if opcodeArr[12] = 195 then
begin
g_NTSSDT_Id.Add(@temp);
Continue;
end;
end;
end;
if (opcodeArr[5] = 100) and (opcodeArr[6] = 255) and (opcodeArr[8] = 192) then//Win8.x64
begin
if opcodeArr[12] = 194 then
begin
temp.RETN_XX := ReadWord(opcodeArr,13);
g_NTSSDT_Id.Add(@temp);
Continue;
end;
if opcodeArr[12] = 195 then
begin
g_NTSSDT_Id.Add(@temp);
Continue;
end;
end;
if (opcodeArr[5] = 51) and (opcodeArr[7] = 141) and (opcodeArr[11] = 100) then// xor ecx, ecx
begin
if (opcodeArr[18] = 195) or (opcodeArr[21] = 195) then
begin
g_NTSSDT_Id.Add(@temp);
Continue;
end;
if opcodeArr[18] = 194 then
begin
temp.RETN_XX := ReadWord(opcodeArr,19);
g_NTSSDT_Id.Add(@temp);
Continue;
end;
if opcodeArr[21] = 194 then
begin
temp.RETN_XX := ReadWord(opcodeArr,22);
g_NTSSDT_Id.Add(@temp);
Continue;
end;
end;
if (opcodeArr[5] = 141) and (opcodeArr[9] = 51) and (opcodeArr[11] = 100) then//xor ecx, ecx Unknown
begin
if (opcodeArr[18] = 195) or (opcodeArr[21] = 195) then
begin
g_NTSSDT_Id.Add(@temp);
Continue;
end;
if opcodeArr[18] = 194 then
begin
temp.RETN_XX := ReadWord(opcodeArr,19);
g_NTSSDT_Id.Add(@temp);
Continue;
end;
if opcodeArr[21] = 194 then
begin
temp.RETN_XX := ReadWord(opcodeArr,22);
g_NTSSDT_Id.Add(@temp);
Continue;
end;
end;
if (opcodeArr[5] = 185) and (opcodeArr[10] = 141) and (opcodeArr[14] = 100) then//mov ecx,xxxxx
begin
temp.ECX := ReadInteger(opcodeArr,6);
if (opcodeArr[21] = 195) or (opcodeArr[24] = 195) then
begin
g_NTSSDT_Id.Add(@temp);
Continue;
end;
if opcodeArr[21] = 194 then
begin
temp.RETN_XX := ReadWord(opcodeArr,22);
g_NTSSDT_Id.Add(@temp);
Continue;
end;
if opcodeArr[24] = 194 then
begin
temp.RETN_XX := ReadWord(opcodeArr,25);
g_NTSSDT_Id.Add(@temp);
Continue;
end;
temp.ECX := 0;
end;
if (opcodeArr[5] = 141) and (opcodeArr[9] = 185) and (opcodeArr[14] = 100) then//' mov ecx, xxxxxxxx
begin
temp.ECX := ReadInteger(opcodeArr,10);
if (opcodeArr[21] = 195) or (opcodeArr[24] = 195) then
begin
g_NTSSDT_Id.Add(@temp);
Continue;
end;
if opcodeArr[22] = 194 then
begin
temp.RETN_XX := ReadWord(opcodeArr,22);
g_NTSSDT_Id.Add(@temp);
Continue;
end;
if opcodeArr[24] = 194 then
begin
temp.RETN_XX := ReadWord(opcodeArr,25);
g_NTSSDT_Id.Add(@temp);
Continue;
end;
end;
end;
end;
end;
end;
Nice work,I'd like contribute for it,but poor document