Friday, May 20, 2022

Windows Objects

Objects in windows are referred as kernel objects. They provide a link or an way to use any objects functionality according with the object itself. There are many types of objects in Window, we can use Sysinternals WinObj in the side menu view you can find "ObjectTypes". This list shows a variety of objects that can be created by us using Windows API. 

  • Objects like: mutex, semaphore, file, process, thread, timer. Can be created by the user-mode using Windows API.
  • Some other objects can be created using WDK, for device driver.
  • And the undocumented used directly by the kernel itself.

All objects can be accessed by it's relative HANDLE. The HANDLE it's private for a process context. It's important to say that HANDLE are basically number IDs for it's reference kernel object structure. So when we open a file we get a HANDLE back, then we use this ID so the kernel can locate this file on "low-levels", hardware managing and etc. 

We always has to CloseHandle after we don't need it anymore this makes a code background (memory and so on) clean and concise with no loose ends. HANDLEs are always 4 bytes long for alignment purposes. Easy and concise memory access. When a HANDLE creation is not successful the the handle it self return NULL(0), except when it's CreateFile that returns INVALID_HANDLE_VALUE(-1).

The function GetLasError is the function to go if any errors occur during the creation or opening of any object probably it will be specified why in the function mentioned.

When you create a program that creates a CreateMutex and tries to open an instance of the same program, you will get a ERROR_ALREADY_EXIST with GetLastError function. The CreateMutex will give you an index, but if you check GetLastError it will give you already exists error.

Handles is a hold of a structure in the kernel space containing all information necessary to access the HANDLE properties. 8 bytes in 32-bits and 16 bytes in 64-bit. Each HANDLE has an AccessMask that contains everything the handle can do. HANDLES has 3 main flags not mot used: Inheritance, Protect from close and Audit on close. AccessMask is a bitmask that is turned on of off by "1" bit in its data. The  AccessMask can be informed at a creation of a Process, for example:


HANDLE hProcess = ::OpenProcess(PROCESS_TERMINATE, FALSE, processId);

The AccessMask is marked by PROCESS_TERMINATE and can be "unified" with the character "|" to append other process access. A process list of access can be viewed here.


::OpenProcess(PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION, FALSE, processId);

 The 3 flags there are used like:

  • Inheritance
    • Used for share handle object between processes. Used when they are needed together to some use.
  • Audit on close
    • Rarely used. Indicates whether an audit entry would be written when the handle get closed.
  • Protect from close
    • Prevents handle from been closed by CloseHandle, returning ERRO_INVALID_HANDLE when tried to be closed. Rarely used and useful.

We can change the flag information by calling  SetHandleInformation.


#define HANDLE_FLAG_INHERIT             0x00000001
#define HANDLE_FLAG_PROTECT_FROM_CLOSE  0x00000002 

::SetHandleInformation(h, HANDLE_FLAG_PROTECT_FROM_CLOSE, HANDLE_FLAG_PROTECT_FROM_CLOSE);

    //To remove it
::SetHandleInformation(h, HANDLE_FLAG_PROTECT_FROM_CLOSE, 0);
We also have the Pseudo Handles, special values that are not closable and always respond with an specific value.

  • GetCurrentProcess()(-1): Return a pseudo handle to current process.
  • GetCurrentThread()(-2): Return pseud handle to current thread.
  • GetCurrentThreadToken()(-5): Return pseudo-handle to then token of the calling thread.
  • GetCurrentThreadEffectiveToken()(-6): Return pseudo handle to the effective token of calling thread (If not token is present in thread, process's is return instead).

Creating Objects 

All objects needs a LP_SECURITY_ATTRIBUTES structure tha tells Windows API which type of access this object will have. 
 

typedef struct _SECURITY_ATTRIBUTES {
    DWORD nLength;
    LPVOID lpSecurityDescriptor;
    BOOL bInheritHandle;
} SECURITY_ATTRIBUTES, *PSECURITY_ATTRIBUTES;
   

The nLenght is a common practice of Windows API to set the structure size in it, so when new version is out the API only will read the stipulated size, then maintaining the old versions compatibility.

The lpSecurityDescriptor is a pointer to a security descriptor this is the core member, that set in the HANDLE structure what it can really do with the open object.

The bInheritHandle is a previous mentioned flag Inheritance, but here we don't need to use SetHandleInformation to set it's value, we can just set it here if it's necessary.

In general when using, for example, CreateMutex:


HANDLE CreateMutex(
    _In_opt_ LPSECURITY_ATTRIBUTES lpMutexAttributes,
    _In_ BOOL bInitialOwner,
    _In_opt_ LPCTSTR lpName
);
   

We just set it to nullptr, and the object assumes it's defaults from the process itself.

Sharing objects

Object name while creating a new object that receive "name" in it's parameters and already exists, the create function will just open the handle to it, the create function would not give any error if everything is right and only will return the object that is already created. As said before we can check this information calling GetLastError will give us the ALREADY_CREATED error. Then the SECURITY_ATTRIBUTES of this attempt to create a new object will NOT affect the already created object.

There are a few ways to share objects through processes:

  • By name
  • By handle inheritance
  • By duplicating handle

When you need to share by name, you just have to create a same type of object, and one that accepts "name" parameter. For example to share a Memory Mapped File. You just has to create in one process and create with the same exact name in another one.


HANDLE hSharedMemory = ::CreateFileMapping(INVALID_HANDLE_VALUE, nullptr, PAGE_READWRITE, 0, 1 << 12, L"ASharedMemory");
   

You just need to use the same line of code, if this object name already exists the API you return a ID that points do the already created object, so making it easy to read from the same space in memory and share the object through processes.

 In this specific case we could use the sequence to write or read from it.


void* buffer = ::MapViewOfFile(hShareMemory, FILE_MAP_WRITE, 0, 0, 0);
::wcscpy_s((PWSTR)buffer, someSize, someData);
void* buffer = ::MapViewOfFile(m_hSharedMem, FILE_MAP_READ, 0, 0, 0);
   

 The last, MAP_READ, we could copy for a local variable or we could just use the buffer in code.

Duplicate handle is also a valid way to share objects. Can be the best option in case the object creation doesn't offers a name parameter. The way to do it is to use the function DuplicateHandle.


BOOL DuplicateHandle(
    _In_ HANDLE hSourceProcessHandle,
    _In_ HANDLE hSourceHandle,
    _In_ HANDLE hTargetProcessHandle,
    _Outptr_ LPHANDLE lpTargetHandle,
    _In_ DWORD dwDesiredAccess,
    _In_ BOOL bInheritHandle,
    _In_ DWORD dwOptions
);
   

hSourceProcessHandle must have the access maks PROCESS_DUP_HANDLE when it was opened in order to the duplication of handles works fine.
dwDesiredAccess This is the mask access to the new handle. In case the DUPLICA_SAME_ACCES is informed in dwOptions, then this parameter is ignored.
dwOptions aside from the one above, we can inform DUPLICATE_CLOSE_SOURCE, this makes the handle on source process to be closed after duplication. I listed just the important parameters only. 

In the same pack of kernel objects we also have some common objects, user objects and GDI objects.

User Objects

 
The user objects can be divided between:
  • Windows - HWND
  • Menus - HMENU
  • Hooks - HHOOK

GDI Objects

 
Graphic Device Interface (GDI) is the classic graphical API in Windows. Even there are more recent ones in use like, Direct2D, GDI is still use. GDI common objects:
  • Device Context - HDC
  • Pen - HPEN
  • Brush - HBRUSH
  • Bitmap - HBITMAP
Important points:
  • Handles are valid only in the process where they were created
  • Cannot be shared between processes
This topic is just a resume and easy access for me to Windows Objects, as I read about it.

Windows Objects

Objects in windows are referred as kernel objects . They provide a link or an way to use any objects functionality according with the object...