diversenok / NtUtilsLibrary

Delphi library for system programming on Windows using Native API
MIT License
110 stars 33 forks source link

Nice work,but poor doc #6

Open tangxiaodao opened 8 months ago

tangxiaodao commented 8 months ago

Nice work,I'd like contribute for it,but poor document

diversenok commented 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.

tangxiaodao commented 7 months ago

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: @.***>

tangxiaodao commented 7 months ago

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: @.***>

diversenok commented 7 months ago

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.

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;
tangxiaodao commented 7 months ago

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;