githubEdit

Fundamentals

Processes

  • A set of resources used to execute a program.

  • Are isolated from one another.

  • Consists of:

    • A private virtual address space

    • Image of the executable program, contains the initial code to be executed

    • A private table containing the handle of the kernel objects

    • Access token - Security context - the context in which the process is running. Used to check of the process has permission over a resource

    • Threads - one or more threads to execute the program. First thread is created when the process is started.

  • Some properties of process that we can find in task manager:

    • Name: the executable that is run by the process.

    • PID: Process ID, unique identified for the process.

    • Status: Current status of the process:

      • Running: Is consuming data coming from the message queue and processing it.

      • Suspended: The program doesn't look at it's message queue for at least 5 seconds.

    • Users: The owner of the process.

    • Session: 0 is for process run by the system (services and system processes).

    • Memory (active private working set): Amount of private memory that the process is using.

    • Commit Size: The actual amount of private memory allocated for the process.

    • Handle: The number of handle the process currently has.

    • Threads: Number of threads executing the code.

    • Platform: Tells if the process is 64 bit or 32 bit.

Virtual Memory

  • Every process has virtual address space.

  • Process sees a flat linear memory assigned to it, but the virtual memory is mapped to different places in physical memory or on disk (This is taken care by memory manager).

  • Memory is managed in chunks called pages:

    • Default size of 4kb

  • Processes access the memory irrespective of where it resides.

    • Memory managed handles mapping of virtual memory to physical pages

    • Process doesn't need to know the actual physical address of a given address in virtual memory.

Virtual Memory Layout

32 Bit

  • Each process gets a potential User Process Space of 2 gigs that it can use. This is relative as each process gets its own private space.

  • User Process Space: 00000000 to 80000000 - 2GB

  • The other 2 gigs in a 32 bit computer is allocated to System Space where all the kernel, device drivers are loaded. As there is only one kernel, there is only one instance of this space

  • System Space: 8000000 - FFFFFFFF - 2 GB

64 Bit

  • Each process get a potential User Process space of 128 TB. This is relative as each process gets its own private space.

  • User Process Space : 000000000000 - 7FFFFFFFFFFF - 128 TB

  • Another absolute space is used by System Space with is also 128 TB, used by kernel, device drivers etc. As there is only one kernel, there is only instance of this space.

  • System Space: FFF800000000000 - FFFFFFFFFFFFFFF: 128 TB

  • The actual memory size that a register in 64 bit CPU can refer is in exabytes, but is not possible today. Hence most of the address space is left as it is or unmapped.

In 64 bit version of windows 8 and earlier, only 8 TB of user and kernel space was used.

  • Loadable modules, mapped into a process address space

  • Contains:

    • Code

    • Data

    • Resource

  • Can be shared between processes. Process A can point to a certain location in memory in RAM where the DLL is present, and another process B can also point to the same location in memory to access the same DLL. It will very expensive, to copy the DLL for every process.

  • Many DLLs are provided with windows by default.

Threads

  • Entity that is schedule by the kernel to execute code on the processor

  • A thread contains:

    • State of CPU registers

    • Current access mode (user mode or kernel mode)

    • Each user mode has two stacks - One in user space and one in kernel space

    • Thread Local Storage (TLS) - User mode mechanism to store data on per thread basis.

    • Access Token (Optional) - by default, thread use default access token of the user, but sometimes the process needs to impersonate someone.

    • Message queue and Windows (Optional) - Usually a thread is a CPU thread or an IO thread. But if the process creates a windows, the thread handling the window automatically gets a message queue. The thread sends data of everything happening on the window

    • Priority - A number between 0 and 31. Specifies the priority of the thread.

    • State:

      • Running - Thread is currently executing.

      • Ready - Wants to execute code but CPU is busy running other threads.

      • Waiting - Thread doesn't want to execute, as it is waiting for some data or IO processing to complete.

System Architecture

sys_arch1
sys_arch2

Windows Subsystem APIs

Windows API

  • Also called Win32 API

    • Classic C APIs from the initial day of windows NT.

  • Some APIs are COM (Component Object Model)

.NET

  • Managed libraries running on top of the CLR

  • Common language: C#, VB.NET, F#, C++, CLI, Powershell

Windows Runtime (WinRT)

  • New unmanaged API available from Windows 8.

  • Built on top of enhanced version of COM.

Windows API/Win32 API

Getting System Information

  • Output

Handling Errors

GetLastError can be used to get error code encountered in the last function. FormatMessage can be used for format the error message to get the textual description.

Strings

  • Windows uses UTF-16 to represent strings, which is 2 bytes per character.

  • Sometimes also known as Unicode.

  • Windows API also makes use of Unicode strings. For compatibility reasons, ANSI (ASCII) versions of the API call is also available. - Functions ending with "W" represents Unicode version. - Functions ending with "A" represents ANSI version. - Function not having "A" or "W" is really a macro to either A or W version, depending on the machine and compiler. This is usually W for modern systems.

  • Types available: - WCHAR, which a typedef to wchar_t, also knows as wide char, represents UNICODE charachters - 2 Bytes. - PWSTR - Pointer to wide string (Unicode String Pointer), PSTR - Pointer to ASCII characters (ASCII String Pointer) - PCWSTR - Pointer to constant wide string, PCSTR - Pointer to constant ascii string. - Unicode Literal : L"Doctor" - Uses 2 bytes per character.

  • String manipulation: - Classic S functions for string manipulation is unsafe. - Eg: strcpy(ascii) , wcscpy(unicode), strcat etc. - Safe versions: - strcpy_s() - wcscpy_s() - Other safe versions, included in <strsafe.h>: - StringCchCopy - StringCchCat - StringCchPrintf - Have A and W version.

  • Some miscellaneous functions:

Structures

  • Most structures in the windows API are defined like:

  • The long prefix is there for historic reasons. There is no long pointer as such. Pointers have defined size: - 4 bytes for 32 bit processor - 8 bytes for 64 bit processor

  • Some structures have version, and the version depends on the size of the structure. The size of the structure is defined by the first member.

Windows Version

  • Windows Numeric Version: - Windows NT (4.0) - Windows 2000 (5.0) - Windows XP (5.1) - Windows Server 2003, 2003 R2 (5.2) - Windows Vista, Server 2008 (6.0) - Windows 7, Server 2008 (6.1) - Windows 8, Server 2012 (6.2) - Windows 8.1, Server 2012 R2 (6.3) - Windows 10, Server 2016 (10)

  • GetVersionEx() function was used traditionally to get the version information, but is now deprecated.

  • New helper functions defined in versionhelpers.h is used now: - IsWindowsXPSP3OrGreater() - IsWindows10OrGreater() - IsWindowsServer()

  • These functions are implemented with VerifyVersionInfo()

  • It requires manifest file to get correct information

System Information

  • GetNativeSysteminfo() & GetSysteminfo() can be used to query information about the operating system and architecture.

  • GetPerformanceInformation() from psapi.h can be used to get information about processes and threads

Objects & Handles

Kernel Objects

  • Windows is object oriented operating system.

  • Exposes objects like:

    • Process

    • Threads

    • Mutex

    • Semaphores

    • Files

    • Directories

  • Data structure for these objects are present in system space, and is inaccessible in user mode. Kernel mode can access these objects directly.

  • Kernel objects are reference counted. Once all handle to an object is closed, object is destroyed.

  • Users from user mode can only obtain handle to an object.

Handles

  • Process maintains a private handle table.

  • When a process creates an object, it receives a handle to the object, which is an indirect pointer to an object instance.

    • Used as a way to access the underlying object.

    • Can be used to share objects across processes.

  • Process Explorer can be used to see handles opened by a process.

  • Handles are always represented as a multiple of 4.

  • Objects exposed by the Windows API for the user-mode:

    • Process

      • CreateProcess()

      • OpenProcess()

    • Threads

      • CreateThread()

      • OpenThread()

    • Jobs

      • CreateJobObject()

      • OpenJobObject()

    • Files

      • CreateFile()

      • CreateFile2()

    • File Mapping (Section)

      • CreateFileMapping()

      • OpenFileMapping()

    • Token

      • LogonUser()

      • OpenProcessToken()

    • Mutex (Mutant)

      • CreateMutex[Ex]()

      • OpenMutex()

    • Event

      • CreateEvent[Ex]()

      • OpenEvent()

    • Semaphore

      • CreateSemaphore()

      • OpenSemaphore()

    • Timer

      • CreateWritableTimer()

      • OpenWritableTimer()

    • I/O Completion Port

      • CreateIOCompletionPort()

    • Window Station

      • CreateWindowStation()

      • OpenWindowStation()

    • Desktop

      • CreateDesktop()

      • OpenDesktop

  • These functions return a HANDLE to the object created or opened.

  • If the functions fail, it returns NULL or INVALID_HANDLE_VALUE

  • After use, handle should be closed using CloseHandle(), which will delete the handle from the handle table and decrement the reference count of the object by one. (If reference count becomes 0, the object is deleted)

Pseudo Handles

  • A normal handle is always multiple of four. First handle value is 4.

  • Pseudo Handles have special value, and are not closable

    • Handle returned by GetCurrentProcess() returns -1 and is handle to the current process

    • Handle returned by GetCurrentThread() returns -2 and is handle to the current thread

    • Handle returned by GetCurrentProcessToken() returns -4 which is handle to current process's token object.

    • Handle returned by GetCurrentThreadToken() returns -5 which is handle to current thread's token object.

    • Handle returned by GetCurrentThreadEffectiveToken() returns -6 which is handle to current's thread's token if it's impersonating.

    • All tokens have TOKEN_QUERY and TOKEN_QUERY_SOURCE rights only.

  • Use Case: SetPriority() function can be used to set priority of a process, and required handle to a process, so a handle to our own process can be supplied to the function to change the priority of our process.

Sharing Objects

  • Objects created can be shared by other processes.

  • This can be done my:

    • Process handle inheritance: A child process gets access to some handles of the parent process

    • Creating/Opening objects by name.

    • Duplicating a handle: difficult in practice.

1. Object Names

  • Allows object lookup by name.

  • Can be shared easily within process.

  • Not all objects can have name.

  • Named objects are stored in the object manager namespace

  • If the above code runs more than once, the Create*() returns the handle to the same object, but also generates an error with error code 183, which is ERROR_ALREADY_EXISTS

  • Output #1: First Instance

  • Output #2: Second Instance

  • Both these handle with point to the same object.

  • Programs that wants to force a single will create a named object and check for it's existence. If the named object exists, they terminate and move the focus on the original instance.

Object Names & Sessions

  • Each session object should have it's own objects.

  • The object manager creates a session directory with a session ID subdirectory, in which the named objects are created. Session can be:

    • 0: Session 0 is used by services and user-mode drivers

    • 1: Session 1 is used by user programs

  • WinObj from SysInternals can be used to analyze object manager.

  • An object created in session 1 will reside in \Session\1\BaseNamedObjects\mynamedobject

  • Session 0 objects are stored in the root \BaseNamedObjects\

  • If a user wants to access object in session 0, it can be done by prefixing the named object with Global\

  • This to note about standard named objects are they are visible. They can be viewed by sysinternal tools such as Process Explorer. Private Object Namespace can be used to hide objects.

Private Object Namespace

  • This is used to make the objects invisible.

  • Access can be restricted using Integrity levels or SIDs.

  • APIs:

    • CreateBoundaryDescriptor()

    • AddSIDToBoundaryDescriptor()

    • CreatePrivateNamespace()

    • OpenPrivateNamespace()

    • ClosePrivateNamespace()

  • If process is inspected using process explorer, the object will be displayed as \...\mymtx so the namespace of the object is indecipherable/invisible by the inspector. A user mode process can never open handle to this object if they don't know the private namespace name or don't have access to it.

2. Handle Inheritance

  • Way to share objects.

  • Handles can be copied to a new child process.

  • Handles that should be inherited by the child process should be marked INHERITABLE.

  • The CreateProcess() call must specify TRUE for inherit handle parameter.

  • All the inherited handles are duplicated with the the same handles values.

  • After this code, both the program and notepad will have the event handle with the same handle ID pointing to the same resource in memory.

  • The handle ID from the parent process can be copied over the child process by passing the handle value as command line argument to the child process. The child process must now handle the argument to get the handle value and cast it as void pointer to be able to use the event.

3. Duplicating Handles

  • Most generic mechanism to create a copy of a handle.

  • Works for any kind of object

  • The API DuplicateHandle() is used to duplicate a handle in for another process. - Process A creates an object X. - Process A gets a handle to another process B - Process A call duplicate handle API, and passes the handle of process B and the handle of object X to duplicate. - This will duplicate the handle of object X in process B. Process B will now have a handle to X.

  • After this function executes. The handle Myevent will be duplicated over to the notepad process with the same handle access as the caller process.

  • The major issue is notifying the other process that a handle has been duplicated for it. The notification should be done via some inter process communication that the other process can handle.

User & GDI Objects

  • The Object Manager in the executive only manages and responsible for kernel objects.

  • The User and GDI objects are managed by Win32k.sys. These objects are responsible for Userinterface and Graphics Device Interface.

  • The API calls for these objects go through user32.dll and gdi32.dll and not through ntdll.dll as they invoke the sysnter/syscall directly.

  • Handles for User objects are reffered by: - HNWD for Windows - HMENU for Menus - HHOOK for Hooks

  • These objects have no reference counting, and they are private to a window station.

  • But these handles have a much global scope, compared to a normal kernel handle which is private to a process.

  • Handles for GDI objects are referred by: - HDC for device context - HPEN for pen - HBRUSH for brush - HBITMAP for a bitmap

  • These are private to a process but like User objects, they don't have reference counting

Last updated