Windows: 架构 & API
营长 Lv3

封面图

图片加载出错啦!

Windows 架构

Windows 系统架构可以被简单的分为四层

  • 应用 - 桌面/命令行应用,直接面向用户
  • Windows API - 一系列包含了应用与系统打交道所需数据类型和函数的库,例如 ntdll.dll, advapi32.dll 以及 user32.dll,在 C 中可通过 #include <windows.h> 导入这些库,有详细的官方文档描述这些接口
  • Windows 原生 API - 封装了系统调用(syscall),没有官方文档且不鼓励使用,但网上有不少破解出的接口信息,且可以被应用直接调用来去做一些 Windows API 做不到的事
  • 内核 - 各种 syscall 的实现以及驱动逻辑图片加载出错啦!

Windows API

数据类型

举例一些常见的数据类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
DWORD dw = 123; // 等价于 unsigned long, 不过注意 long 在 windows 上是 32 比特
SIZE_T s = sizeof(int); // 表示 32/64 位的无符号整型,取系统的位数
PVOID p = NULL; // 等价于 void*

HANDLE handle = CreateFile(...); // 作为内核空间某个对象的引用
HMODULE = GetModuleHandle(...); // 作为某个模块(dll/exe)的引用

LPCSTR lpcString = "Hello, world!" // 等价于 const char*
PCSTR pcString = "Hello, world!" // 等价于 const char*

LPSTR lpString = "Hello, world!" // 等价于 char*
PSTR pString = "Hello, world" // 等价于 char*

LPCWSTR = L"Hello, world!"; // 等价于 const wchar*, 16 位的 Windows 宽字符
PCWSTR = L"Hello, world"; // 等价于 const wchar*

LPWSTR = L"Hello, world!"; // 等价于 wchar*
PWSTR = L"Hello, world"; // 等价于 wchar*

wchar_t wChar = L'A'; // 等价于 wchar
wchar_t* wcString = L"Hello, world!" //等价于 wchar*

PVOID p = malloc(100);
p = (ULONG_PTR)p + 10; // 转换成支持指针运算的类型
  • 命名约定 - 可以发现指针类型会以 P 开头

函数

不少函数会修改某个引用传递的参数作为返回值,因此传入的参数会被分为 InOut 两类,函数执行时的错误码可通过特定的接口获取

1
printf("[!] 错误: %d", GetLastError());

可以通过 Window 系统错误码清单 来去调查原因
不同于 Windows API,原生 API 会直接将错误码以返回值的形式输出

1
2
3
4
NTSTATUS status = NativeSyscall(...);
if (!NT_SUCCESS(status)) {
printf("[!] 错误: 0x%0.8X \n", status);
}

且原生 API 有自己的一套错误码解释

  • 命名约定 - 期待 Ascii 字符串输入的函数会以 A 结尾,例如 CreateFileA,期待 Unicode 字符串输入的则会以 W 结尾,例如 CreateFileW