Home Derinlemesine Windows API (0x01)
Post
Cancel

Derinlemesine Windows API (0x01)

Windows DLL ve Header İlişkisi

Windows aslında arkaplanda çok düzenli bir mekanizmaya sahip bir işletim sistemidir. Bu düzen kullanıcının girdiği herhangi bir input’tan bilgisayarın output’una kadar geçerlidir.

Mesela yeni bir text dosyası oluşturmak istediğinizde, arkaplanda dosya oluşturmaya yarayan windows api fonksiyonu (CreateFile) call edilir. Daha sonra bu fonksiyon başka bir dll’e forward edilir ve syscall/sysenter yapılarak kernel diyarına geçiş yapılır. Gerisi ise kernel ile çalışan driver ve manager’lara kalmış işlemlerdir (burada yapılan işlemleri görebilmek için windbg kullanılabilir).

Peki biz dosya oluşturmayı sağlayan winapi fonksiyonunu direkt olarak call etsek nasıl olur? CreateFile fonksiyonu kernel32.dll modülüne ait bir fonksiyon olarak geçer. Bu fonksiyonu kullanmak istediğimizde ise dll’i değil, fonksiyonun tanımlandığı header’ı (Windows.h) include etmemiz gerekiyor.

Windows.h Windows API’sindeki tüm fonksiyonlar, programcılar tarafından kullanılan tüm yaygın makrolar ve Windows tarafından kullanılan veri türleri için bildirimler içeren header dosyasıdır.

CreateFile_function_preview.png

CreateFile fonksiyonunun kullanımına baktığımızda ise aslında filapi.h header’ında olduğunu görüyoruz. Demekki buradan şöyle bişey çıkarabiliriz:

Dll_Headers_Connexion.png

Well Known DLLs

  • kernel32.dll: Low level NTDLL wrappers.

  • user32.dll: User interface primitives used by graphical programs with menus, toolboxes, prompts, windows ..

  • shell.dll

  • gdi32.dll: Basic drawing primitives.

  • ole32.dll

  • MSVCRT.DLL: Implementation of the C standard library stdlib.

  • advapi.dll: Contains functions for system-related tasks such as registry and registry handling.

  • WS_32.DLL: Winsock2 library contains a socket implementation.

  • Ntdll.dll: Interface to Kernel. Not used by Windows programs directly.

  • Wininet.dll: Provides high level network APIs, for instance, HttpOpenRequest, FtpGetFile …

Main Headers

  • windows.h: Basic header file of Windows API
  • WinError.h: Error codes and strings
  • tchar.h: Provides the macro _T(…) and TEXT(…) for Unicode/ANSI string encoding handling.
  • wchar.h: Wide Character - UTF16 or wchar
  • global.h
  • ntfsb.h
  • Winsock2.h: Network sockets
  • Winbase.h: Windows types definitions
  • WinUser.h: Windows Messages
  • ShellAPI.h: Shell API
  • ShFolder.h: Folder definitions
  • Commdlg.h: Commom Controls (COM based)
  • Dlgs.h: Dialog definitions
  • IUnknown.h: COM header
  • conio.h: Console Input/Output functions - it is heritage grom MSDOS.

WinAPI Data Types

Windows API’lerle programlama yapmadan önce kendi syntax’ini ve veri tiplerini anlamakta fayda var. WinAPI C/C++ tabanında yazıldığına rağmen ben bunun ayrı bir dil olduğunu hayal ederim (sizin düşünmenize gerek yok). Çünkü windows kendi içinde çok fazla veri tipine sahip ve sadece kendi veri tiplerini kullanarak programlamaya izin veriyor. Örneğin integer veri tipini kabul etmez, dword veri tipini kabul eder. Halbuki ikisi de aynı şey (nerdeyse). Yazının ilerisinde ne demek istediğimi daha iyi anlayacaksınız.

Function Prefix Types

İlk önce API fonksiyonlarının parametrelerinde, başlangıçlarında yazan iki-üç harflik ek’lere bakalım istiyorum. Örnek olarak CreateProcess fonksiyonunu inceleyelim:

1
2
3
4
5
6
7
8
9
10
11
12
BOOL CreateProcessA(
  [in, optional]      LPCSTR                lpApplicationName,
  [in, out, optional] LPSTR                 lpCommandLine,
  [in, optional]      LPSECURITY_ATTRIBUTES lpProcessAttributes,
  [in, optional]      LPSECURITY_ATTRIBUTES lpThreadAttributes,
  [in]                BOOL                  bInheritHandles,
  [in]                DWORD                 dwCreationFlags,
  [in, optional]      LPVOID                lpEnvironment,
  [in, optional]      LPCSTR                lpCurrentDirectory,
  [in]                LPSTARTUPINFOA        lpStartupInfo,
  [out]               LPPROCESS_INFORMATION lpProcessInformation
);

Parametre önlerinde (sağdakiler) duran lp, b, dw eklerini gördünüz mü? Bunlar parametrenin alabileceği veri tiplerini temsil eder. Ve dikkat ettiyseniz tanımlanan veri tipleriyle (ortadakiler) benzerlikleri var. Bunu gereksiz veya küçük bir bilgi gibi görebilirsiniz ama bu işlerde bilginiz pek yoksa en çok hata alacağınız kısım veri tipleri olacaktır.

Aşağıda tüm preprefix’leri ve anlamlarını beliten tabloyu görebilirsiniz:

PrefixTypeDescriptionVariable Name Example
bBYTE or BOOLbooleanBOOL bFlag; BOOL bIsOnFocus
ccharCharacter - 1 bytechar cLetter
wWORDword 
dwDWORDdouble word 
iintintegerint iNumberOfNodes
u32unsigned [int]unsigned integerunsigned u32Nodes
f or fpfloatfloat point - single precisionfInterestRate
ddoublefloat point - double precisiondRateOfReturn
n short int 
szchar* or const char*Pointer to null terminated char array.char* szButtonLabel
HHANDLEHandleHANDLE hModule; HMODULE hInstance;
p-Pointerdouble* pdwMyPointer;
lp-Long Pointerint* lpiPointer;
fn-Function pointer 
lpsz Long Pointer 
LP Long Pointer 
I-Interface (C++ interface class)class IDrawable …
S-Struct declarationstruct SContext { … }
C-Class declarationclass CUserData{ … }
m_-Private member variable name of some classm_pszFileName
s_-Static member of a classstatic int s_iObjectCount

Aklınızda bulunsun; windows api’lerin bu şekilde değişken isimlendirmesine macar notasyonu (hungarian notataion) deniyor.

Genel Data Types

Windows API fonksiyonlara girdi olabilecek veri tipleri, return edilebilecek veri tipleri vs. tüm api fonksiyonları bu data tiplerini kullanır.

Data TypeDefinitionDescription
BOOLtypedef int BOOLBoolean variable true (non zero) or false (zero or 0)
BYTEtypedef unsigned char BYTEA byte, 8 bits.
CCHARtypedef char CHARAn 8-bit Windows (ANSI) character.
DWORDtypedef unsigned long DWORDA 32-bit unsigned integer. The range is 0 through 4294967295 decimal.
DWORDLONGtypedef unsigned __int64 DWORDLONG64 bits usigned int.
DWORD32typedef unsigned int DWORD32A 32-bit unsigned integer.
DWORD64typedef unsigned __int64 DWORD64A 64-bit unsigned integer.
FLOATtypedef float FLOATA floating-point variable.
INT8typedef signed char INT8An 8-bit signed integer.
INT16typedef signed short INT16A 16-bit signed integer.
INT32typedef signed int INT32A 32-bit signed integer. The range is -2147483648 through 2147483647 decimal.
INT64typedef signed __int64 INT64A 64-bit signed integer.
LPBOOLtypedef BOOL far *LPBOOL;A pointer to a BOOL.
LPBYTEtypedef BYTE far *LPBYTEA pointer to a BYTE.
LPCSTR, PCSTRtypedef __nullterminated CONST CHAR *LPCSTRpointer to a constant null-terminated string of 8-bit Windows (ANSI) characters.
LPCVOIDtypedef CONST void *LPCVOID;A pointer to a constant of any type.
LPCWSTR, PCWSTRtypedef CONST WCHAR *LPCWSTR;A pointer to a constant null-terminated string of 16-bit Unicode characters.
LPDWORDtypedef DWORD *LPDWORDA pointer to a DWORD.
LPSTRtypedef CHAR *LPSTR;A pointer to a null-terminated string of 8-bit Windows (ANSI) characters.
LPTSTR An LPWSTR if UNICODE is defined, an LPSTR otherwise.
LPWSTRtypedef WCHAR *LPWSTR;A pointer to a null-terminated string of 16-bit Unicode characters.
PCHARtypedef CHAR *PCHAR;A pointer to a CHAR.
CHARANSI Char or char 
WCHARWide character 16 bits UTF16 
TCHAR-A WCHAR if UNICODE is defined, a CHAR otherwise.
UCHARtypedef unsigned char UCHAR;An unsigned CHAR.
WPARAMtypedef UINT_PTR WPARAM;A message parameter.

Diğer önemli data tipleri aşağıdaki gibidir.

Data TypeDescription
HANDLE32 bits integer used as a handle
HDCHandle to device context
HWND32-bit unsigned integer used as handle to a window
LONG 
LPARAM 
LPSTR 
LPVOIDGeneric pointer similar to void*
LRESULT 
UINTUnsigned integer
WCHAR16-bit Unicode character or Wide-Character
WPARAM 
HINSTANCE 

Source Code Annotation Language (SAL)

Windows API’lerle çalışırken hangi parametrelerin değer döndürmek için kullanıldığını veya yalnızca girdi olarak kullanıldığını anlamak zor olabilir. Burada Windows’un kullandığı SAL yazım biçimi, hangi fonksiyon parametrelerinin input, readonly ve hangi parametrelerin output olduğunu _In_ veya _out_ gibi prefix’lerle bildirmeyi sağlar.

Aşağıda bu prefix’lerin ne anlam ifade ettiğini görebilirsiniz.

SAL AnnotatioDescription
_In_Input parameter - read only argument no modified inside the by the function. Generally has the const qualifier such as const char*.
In_OutOptional input parameter, can be ignored by passing a null pointer.
_Out_Output paramenter - Argument is written by the called function. It is generally a pointer.
Out_optOptional output parameter. Can be ignored by setting it to null pointer.
_Inout_Data is passed to the function and pontentially modified.
_Outptr_Output to caller. The value returned by written to the parameter is pointer.
Outptr_optOptional output pointer to caller, can be ignored by passing NULL pointer.

Yine CreateProcess fonksiyonu ile devam edersek örneği aşağıdaki gibidir:

1
2
3
4
5
6
7
8
9
10
11
12
BOOL WINAPI CreateProcess(
  _In_opt_    LPCTSTR               lpApplicationName,      // const char*
  _Inout_opt_ LPTSTR                lpCommandLine,          // char*
  _In_opt_    LPSECURITY_ATTRIBUTES lpProcessAttributes,
  _In_opt_    LPSECURITY_ATTRIBUTES lpThreadAttributes,     // 
  _In_        BOOL                  bInheritHandles,
  _In_        DWORD                 dwCreationFlags,
  _In_opt_    LPVOID                lpEnvironment,
  _In_opt_    LPCTSTR               lpCurrentDirectory,
  _In_        LPSTARTUPINFO         lpStartupInfo,
  _Out_       LPPROCESS_INFORMATION lpProcessInformation
);

Eğer kendimiz de SAL formatında bir fonksiyon yazmak istersek sal.h header’ını include etmemiz gerekiyor. Çünkü standart C/C++ dili arasında bu yazım biçimi yoktur. Ayrıca bu yazım biçimi yalnızca MSVC - Microsoft Visual C++ compiler üzerinde çalışır.

Eğer _opt_ prefix’i varsa NULL olarak o parametreyi geçebilirsiniz, fakat bu prefix yoksa parametreye input vermek zorunludur.

SAL yazım biçiminin kullanarak programla örneğini aşağıda görebilirsiniz:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <sal.h>     // Microsft's Source Code Annotation Language 
#include <iostream>

// Computes elementwise product of two vectors 
void vector_element_product(
      _In_ size_t size,
      _In_ const double xs[],
      _In_ const double ys[],
      _Out_      double zs[]
      ){
      for(int i = 0; i < size; i++){
          zs[i] = xs[i] * ys[i];
      }
}

void showArray(size_t size, double xs[]){
  std::cout << "(" << size << ")[ ";
  for(int i = 0; i < size; i++){
    std::cout << xs[i] << " ";
  }
  std::cout << "] ";
}

int main(){
  double xs [] = {4, 5, 6, 10};
  double ys [] = {4, 10, 5, 25};
  double zs [4];
  vector_element_product(4, xs, ys, zs);
  std::cout << "xs = "; showArray(4, xs); std::cout << "\n";
  std::cout << "ys = "; showArray(4, ys); std::cout << "\n";
  std::cout << "zs = "; showArray(4, zs); std::cout << "\n";

}

WinAPI’de Karakter Encoding

TypeDefinition
LPSTRchar*
LPCSTRconst char*
LPWSTRwchar_t*
LPCWSTRconst wchar_t*
LPTSTRTCHAR*
LPCTSTRconst TCHAR*

Environment Variables

Kaynakça ve Referanslar

  1. Windows API index - Win32 apps | Microsoft Learn

  2. Windows Data Types (BaseTsd.h) - Win32 apps | Microsoft Learn

  3. Understanding SAL | Microsoft Learn

This post is licensed under CC BY 4.0 by the author.