Windows Application Programming Interfaces (Win32 API) Most of us, if not all, are users of the Microsoft® Windows®. I’m very sure all of us have heard the popular jargon API. An Application Program Interface (API) is a set of functions that the Operating System (OS) makes available to applications for communicating with the OS, hardware and other applications. Win32, DirectX, WinSock, Image Color Management (ICM), CryptoAPI, Graphics Device Interface (GDI), etc, are popular Windows APIs. The Win32 is a very large set of functions that make up the official low-level programming interface for Windows applications. DirectX is a set of low-level APIs that provides Windows programs with high-performance hardware-accelerated multimedia support. ICM is another API that helps to ensure that colors will be accurately and consistently represented on all of our publishing devices of the system. CryptoAPI provides a set of functions that allow applications to encrypt or digitally sign data in a flexible manner while providing protection for the user's sensitive private key data. GDI is a library of APIs for graphics output devices. The Win32 API: Win32 API, though very powerful and high on performance, is not particularly user friendly. Their usage requires a lot of knowledge about internal data structures and many other issues. Hence, we can see many higher-level interfaces brought out by Microsoft. One such is the Microsoft Functional Classes (MFC), a great collection of inherited C++ objects that interacts with Windows. These upper layers are much more convenient to use, but they incur a lot of performance penalty, an issue that has always haunted Windows systems. The WIN32 API is divided into mainly three categories: Kernel, USER and GDI. The Fig.1 shows the relation between the Win32 interface DLLs, NTDLL.DLL and the Windows Kernel Component. Kernel APIs (BASE APIs) are implemented in the KERNEL32.DLL module and include all non-GUI related services of Windows OS such as file i/o, memory management, object management, process and thread management to name a few. KERNEL32.DLL at times calls low-level native APIs from NTDLL.DLL to implement many of services. GDI APIs are implemented in GDI32.DLL and include low-level graphics services. E.g. drawing a line, displaying a bitmap etc. The GDI APIs are implemented in the kernel, in the WIN32K.SYS module. GDI APIs make system calls into WIN32K.SYS, because most of the tasks are recursive and combinational in nature, revolving around GDI objects used for drawing objects such as brushes, pens, etc. These objects are not managed by Kernel Object Manager. USER APIs are implemented in the USER32.DLL module and include all higher-level GUI related services such as Windows management, menus, dialog boxes, common controls,
[email protected]
interface controls, etc. All GUI objects are drawn by USER using GDI calls. USER APIs revolve around user-related objects and hence the name of the API. Again these objects are not managed by the kernel.
KERNEL32.DLL BASE API Client Component
NTDLL.DLL Native API Interface
Application Modules
USER32.DLL The USER API Client Component
GDI32.DLL GDI API Client Component
User Mode Kernel Mode
NTOSKRNL.EXE The Windows Kernel
WIN32K.SYS The Win32 Kernel
Fig 1. The Win32 Interface DLLs and Their relation to the Kernel Components The NATIVE API: The Native API is the actual interface to the Windows NT system. The WIN32 APIs is just a layer above the native API. The native API has nothing to do with GUI and hence does not include any graphics related services. But the application programs are never supposed to call the native APIs. Perhaps that is why, they aren’t documented by Microsoft. Applications are expected to call only WIN32 APIs for interacting with the system. Technically, the native API is a set of functions exported from both NTDLL.DLL (user mode) and NTOSKRNL.EXE (Kernel Mode). They start with two prefixes either Nt or Zw. E.g. They may be NtCreateFile or ZwCreateFile. You might just wonder what Zw stands for. I’m rally sorry; I have no idea what so ever. In their user-mode implementation both groups are the same. I mean there is a single implementation and both point to the same code. But in the kernel mode, they are different: the Nt
[email protected]
versions are the actual implementations, while Zw versions are given to be going through system-call mechanism. Dynamically Linked Libraries (DLL): The idea behind DLLs is that a program can be divided into more than one executable file, where each file is responsible for one feature of whole program. The overall memory consumption for each program as well as for the whole system drastically reduces as OS can detect whether an executable is loaded in memory or not and map its address accordingly. The DLLs are different from the build-time static libraries such as the #includes of our C programs. The #include files are not linked in runtime but are an indistinguishable part of the program binary. The DLL may be loaded and linked to a Windows program by two methods. 1. Static Linking: The executable contains a reference to another executable within an Import Address Table (IAT). While compiling the compiler would not know where the imported functions may be found and it is simply illogical to hardcode the imported functions address. That would simply make our program non-relocatable. This is where the double indirect CALL statement we learnt in 8086 comes to our rescue. Imported functions are implemented using The Import Directory and IAT. The Import Directory is used in runtime to resolve the function’s name with a matching name in the target executable and IAT stores the actual address of target function. When the loader loads such an executable, it loads all modules that are used by the current module and resolves all references by making entries in the IAT. E. g: CALL DWORD PTR [IAT_PTR]: This x86 statement calls a function pointed by the location pointed by IAT_PTR. 2. Runtime Linking: An executable may itself load another executable itself and call a function from it. This implies that the host executable must be able to locate the exact executable and find the right function by searching the header of the target executable. This is more flexible, but is very difficult to implement from a programmer’s point of view. References: [1]. “The Windows Interface Guidelines”, Microsoft Publication [2]. “Microsoft Win32 API Overview”, MSDN Library 6.0a [3]. Eldad Eilam, “REVERSING: Secrets of Reverse Engineering”, Wiley Publishing Inc. 2005
[email protected]