This project has moved. For the latest updates, please go here.

Error Handling

How to translate NTSTATUS error codes to message string

All function calls must check:
    if(!NT_SUCCESS(ntStatus))
      throw NtError(ntStatus);


Exception class:
class NtError:public std::exception
{
  std::string m_str;

public:
  NtError(DWORD status)
  {
    m_str = DisplayError(status);
  }

  const char* what() const throw()
  {
    return m_str.c_str();
  }

  std::string to_string(const std::wstring wstr )
  {
    typedef std::vector<std::string::value_type> mbstr_buf;
    mbstr_buf	buf( wstr.size() * ( sizeof( std::wstring::value_type) / 
      sizeof( std::string::value_type)) );
    wcstombs( 	&buf[0], 	wstr.c_str(), 	wstr.size()); 
    return std::string( &buf[0] );
  }

  std::string DisplayError(DWORD NTStatusMessage)
  {
    wchar_t* lpMessageBuffer;
    HMODULE Hand = LoadLibrary(L"NTDLL.DLL");

    FormatMessage( 
      FORMAT_MESSAGE_ALLOCATE_BUFFER | 
      FORMAT_MESSAGE_FROM_SYSTEM | 
      FORMAT_MESSAGE_FROM_HMODULE,
      Hand, 
      NTStatusMessage,  
      MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
      (LPTSTR) &lpMessageBuffer,  
      0,  
      NULL );

    std::wstring s = (wchar_t*)lpMessageBuffer;

    // Free the buffer allocated by the system.
    LocalFree( lpMessageBuffer ); 
    FreeLibrary(Hand);

    return to_string(s);
  }

};

Defines

#define FILE_SUPERSEDE                  0
#define FILE_OPEN                       1
#define FILE_CREATE                     2
#define FILE_OPEN_IF                    3
#define FILE_OVERWRITE                  4
#define FILE_OVERWRITE_IF               5
#define FILE_MAXIMUM_DISPOSITION        5

#define FILE_SYNCHRONOUS_IO_NONALERT    0x00000020

#define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0)
#define NT_INFORMATION(Status) ((ULONG)(Status) >> 30 == 1)
#define NT_WARNING(Status) ((ULONG)(Status) >> 30 == 2)
#define NT_ERROR(Status) ((ULONG)(Status) >> 30 == 3)

Function definition

typedef void (WINAPI * PIO_APC_ROUTINE)(PVOID,PIO_STATUS_BLOCK,ULONG);

typedef void (WINAPI *pRtlInitUnicodeString)(PUNICODE_STRING,PCWSTR);
typedef NTSTATUS (WINAPI *pNtCreateFile)(PHANDLE,ACCESS_MASK,POBJECT_ATTRIBUTES,PIO_STATUS_BLOCK,PLARGE_INTEGER,ULONG,ULONG,ULONG,ULONG,PVOID,ULONG);
typedef NTSTATUS (WINAPI *pNtClose)(HANDLE);
typedef NTSTATUS (WINAPI *pNtOpenFile)(PHANDLE,ACCESS_MASK,POBJECT_ATTRIBUTES,PIO_STATUS_BLOCK,ULONG,ULONG);
typedef NTSTATUS (WINAPI *pNtReadFile)(HANDLE,HANDLE,PIO_APC_ROUTINE,PVOID,PIO_STATUS_BLOCK,PVOID,ULONG,PLARGE_INTEGER,PULONG);
typedef NTSTATUS (WINAPI *pNtWriteFile)(HANDLE,HANDLE,PIO_APC_ROUTINE,PVOID,PIO_STATUS_BLOCK,const void*,ULONG,PLARGE_INTEGER,PULONG);

Structures definition

typedef LONG NTSTATUS;

typedef struct _LSA_UNICODE_STRING {
  USHORT Length;
  USHORT MaximumLength;
  PWSTR Buffer;
} LSA_UNICODE_STRING, 
*PLSA_UNICODE_STRING, 
UNICODE_STRING, 
*PUNICODE_STRING;

typedef struct _OBJECT_ATTRIBUTES {
  ULONG  Length;
  HANDLE  RootDirectory;
  PUNICODE_STRING  ObjectName;
  ULONG  Attributes;
  PVOID  SecurityDescriptor;
  PVOID  SecurityQualityOfService;
} OBJECT_ATTRIBUTES, *POBJECT_ATTRIBUTES;
typedef CONST OBJECT_ATTRIBUTES *PCOBJECT_ATTRIBUTES;

typedef struct _IO_STATUS_BLOCK {
  union {
    NTSTATUS Status;
    PVOID Pointer;
  };
  ULONG_PTR Information;
} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;

Initilizers

#define InitializeObjectAttributes(p,n,a,r,s) \
  do { \
  (p)->Length = sizeof(OBJECT_ATTRIBUTES); \
  (p)->RootDirectory = r; \
  (p)->Attributes = a; \
  (p)->ObjectName = n; \
  (p)->SecurityDescriptor = s; \
  (p)->SecurityQualityOfService = NULL; \
  } while (0)

NtOpenFile parametrs

    NTSTATUS    ntStatus = STATUS_SUCCESS;
    UNICODE_STRING   szPath  = {0};
    OBJECT_ATTRIBUTES   Attr  = {0};
    IO_STATUS_BLOCK   IoStatusBlock = {0};
    HANDLE     hBeep  = 0;

    RtlInitUnicodeString(&szPath, L"\\??\\PhysicalDrive0");
    InitializeObjectAttributes(&Attr, &szPath, 0, NULL, NULL);

    DWORD dwDesiredAccess = GENERIC_WRITE;
    
    ntStatus = NtOpenFile(&hBeep, dwDesiredAccess | SYNCHRONIZE, &Attr, &IoStatusBlock, 0, FILE_SYNCHRONOUS_IO_NONALERT);

DD for Windows project

Low level access example (DD project)

C#

using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.ComponentModel;
using Microsoft.Win32.SafeHandles;

namespace usbburn
{
  public class NtDll
  {
    public class NtStatusException : Exception
    {
      const uint FORMAT_MESSAGE_ALLOCATE_BUFFER = 0x00000100;
      const uint FORMAT_MESSAGE_IGNORE_INSERTS = 0x00000200;
      const uint FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000;
      const uint FORMAT_MESSAGE_FROM_HMODULE = 0x00000800;

      const uint LANG_NEUTRAL = 0x00;
      const uint SUBLANG_DEFAULT = 0x01;

      [DllImport("kernel32.dll")]
      static extern IntPtr LoadLibrary(string lpFileName);

      // the version, the sample is built upon:
      [DllImport("Kernel32.dll", SetLastError = true)]
      static extern uint FormatMessage(uint dwFlags, IntPtr lpSource,
         int dwMessageId, uint dwLanguageId, ref IntPtr lpBuffer,
         uint nSize, IntPtr pArguments);

      [DllImport("kernel32.dll", SetLastError = true)]
      static extern IntPtr LocalFree(IntPtr hMem);

      [DllImport("kernel32.dll", SetLastError = true)]
      static extern bool FreeLibrary(IntPtr hModule);

      static uint MAKELANGID(uint p, uint s)
      {
        return (uint)((((UInt16)(s)) << 10) | (UInt16)(p));
      }

      public NtStatusException(int err)
        : base(DisplayError(err))
      {
      }

      static string DisplayError(int NTStatusMessage)
      {
        IntPtr lpMessageBuffer = IntPtr.Zero;
        IntPtr Hand = LoadLibrary("NTDLL.DLL");

        uint dwChars = FormatMessage(
          FORMAT_MESSAGE_ALLOCATE_BUFFER |
          FORMAT_MESSAGE_FROM_SYSTEM |
          FORMAT_MESSAGE_FROM_HMODULE,
          Hand,
          NTStatusMessage,
          MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
          ref lpMessageBuffer,
          0,
          IntPtr.Zero);

        if (dwChars == 0)
          Marshal.ThrowExceptionForHR(Marshal.GetLastWin32Error());

        string sRet = Marshal.PtrToStringAnsi(lpMessageBuffer);

        // Free the buffer allocated by the system.
        LocalFree(lpMessageBuffer);
        FreeLibrary(Hand);

        return sRet;
      }
    }

    public const uint FILE_SYNCHRONOUS_IO_NONALERT = 0x00000020;

    public const uint SYNCHRONIZE = 0x00100000;

    public const uint GENERIC_READ = 0x80000000;
    public const uint GENERIC_WRITE = 0x40000000;

    public static bool NT_SUCCESS(int Status)
    {
      return (Status) >= 0;
    }

    /// <summary>
    /// Don't forget call FreeObjectAttributes, CLR specific!!!
    /// </summary>
    /// <param name="oa"></param>
    /// <param name="n"></param>
    /// <param name="a"></param>
    /// <param name="r"></param>
    /// <param name="s"></param>
    public static void InitializeObjectAttributes(ref OBJECT_ATTRIBUTES oa, UNICODE_STRING n, UInt32 a, UInt32 r, IntPtr s)
    {
      oa.Length = Marshal.SizeOf(typeof(OBJECT_ATTRIBUTES));
      oa.RootDirectory = r;
      oa.ObjectName = Marshal.AllocHGlobal(Marshal.SizeOf(oa.ObjectName));
      Marshal.StructureToPtr(n, oa.ObjectName, false);
      oa.Attributes = a;
      oa.SecurityDescriptor = s;
      oa.SecurityQualityOfService = IntPtr.Zero;
    }

    public static void FreeObjectAttributes(ref OBJECT_ATTRIBUTES oa)
    {
      if(oa.ObjectName!=IntPtr.Zero)
        Marshal.FreeHGlobal(oa.ObjectName);
    }

    [DllImport("ntdll.dll",
    SetLastError = true,
    CharSet = CharSet.Unicode,
    CallingConvention = CallingConvention.Winapi)]
    public static extern int NtOpenFile(
        ref IntPtr FileHandle,
        uint DesiredAccess,
        ref OBJECT_ATTRIBUTES ObjectAttributes,
        ref IO_STATUS_BLOCK IoStatusBlock,
        uint ShareAccess,
        uint OpenOptions);

    [DllImport("ntdll.dll", CharSet = CharSet.Unicode)]
    public static extern void RtlInitUnicodeString(
      ref UNICODE_STRING DestinationString,
      string SourceString);

    [DllImport("ntdll.dll", CharSet = CharSet.Unicode)]
    public static extern int NtClose(
      IntPtr Handle
      );

    [DllImport("kernel32.dll", SetLastError=true)]
    public static extern bool ReadFile(IntPtr hFile, byte[] lpBuffer,
       int nNumberOfBytesToRead, ref int lpNumberOfBytesRead, IntPtr lpOverlapped);

    [DllImport("kernel32.dll", SetLastError = true)]
    public static extern Boolean WriteFile(IntPtr fFile, Byte[] lpBuffer, int nNumberOfBytesToWrite,
            ref int lpNumberOfBytesWritten, IntPtr lpOverlapped);

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
    public struct IO_STATUS_BLOCK
    {
      public uint Status;
      public uint Information;
    }

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
    public struct UNICODE_STRING
    {
      public ushort Length;
      public ushort MaximumLength;
      public string Buffer;
    }

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
    public struct OBJECT_ATTRIBUTES
    {
      public int Length;
      public uint RootDirectory;
      public IntPtr ObjectName;
      public uint Attributes;
      public IntPtr SecurityDescriptor;        // Points to type SECURITY_DESCRIPTOR
      public IntPtr SecurityQualityOfService;  // Points to type SECURITY_QUALITY_OF_SERVICE
    }
  }
}


How it work:

using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.ComponentModel;
using Microsoft.Win32.SafeHandles;
using System.IO;

namespace usbburn
{
  class LowLevelIO : NtDll, IDisposable
  {
    IntPtr m_handle = IntPtr.Zero;

    public LowLevelIO(string device,FileAccess fa)
    {
      IO_STATUS_BLOCK st = new IO_STATUS_BLOCK();
      UNICODE_STRING path = new UNICODE_STRING();
      OBJECT_ATTRIBUTES oa = new OBJECT_ATTRIBUTES();

      try
      {
        RtlInitUnicodeString(ref path, device);

        InitializeObjectAttributes(ref oa, path, 0, 0, IntPtr.Zero);

        uint flags = 0;
        switch (fa)
        {
          case FileAccess.Read:
            flags = GENERIC_READ;
            break;
          case FileAccess.Write:
            flags = GENERIC_WRITE;
            break;
          case FileAccess.ReadWrite:
            flags = GENERIC_WRITE | GENERIC_READ;
            break;
          default:
            throw new ArgumentException();
        }

        int i = NtOpenFile(ref m_handle, flags | SYNCHRONIZE, ref oa, ref st, 0, FILE_SYNCHRONOUS_IO_NONALERT);

        if (!NT_SUCCESS(i))
          throw new NtStatusException(i);
      }
      finally
      {
        FreeObjectAttributes(ref oa);
      }
    }

    public void Dispose()
    {
      if (m_handle != IntPtr.Zero)
      {
        NtClose(m_handle);
        m_handle = IntPtr.Zero;
      }
    }

    public byte[] Read(int size)
    {
      byte[] buf = new byte[size];
      int read = 0;

      bool s=ReadFile(m_handle,buf,buf.Length,ref read,IntPtr.Zero);

      if (!s)
        Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());

      return buf;
    }

    public void Write(byte[] buf)
    {
      int write = 0;

      bool s = WriteFile(m_handle, buf, buf.Length, ref write, IntPtr.Zero);

      if (!s)
        Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
    }

    ~LowLevelIO()
    {
      Dispose();
    }
  }
}

Last edited Feb 4, 2008 at 3:19 AM by axet, version 5

Comments

No comments yet.