Windows编程知识点汇总

113 阅读5分钟

unicode字符集和utf编码

unicode是一个字符集,只规定了每个符号的二进制值,当然也有确定的编码码值,但是符号具体如何存储并没有规定。

utf是unicode的存储实现,utf全称为unicode transformation format,即unicode转换格式。

utf-8是一种针对unicode的可变长度字符编码,使用1至4个字节为每个字符编码。

utf-16是用16bit编码来表达unicode,一个字符占2个字节

windows中的unicode默认是utf-16le存储方式

BOM字节顺序标记

byte-order mark,字节顺序标记,它是插入到以UTF-8、UTF16或UTF-32编码Unicode文件开头的特殊标记,用来识别Unicode文件的编码类型。

  • UTF-8:EF BB BF
  • UTF-16LE(小端):FF FE
  • UTF-16BE(大端):FE FF

windows字符数据类型

CHAR -> char
PSTR -> char *
WCHAR -> wchar_t
PWSTR -> wchar_t *
TCHAR -> 一个宏,当前是什么字符集,编译出来就是什么字符集
PTSTR -> TCHAR * 
  • wchar_t 类型是实现定义的宽字符类型。 在 Microsoft 编译器中,它表示一个 16 位宽字符,用于存储编码为 UTF-16LE 的 Unicode(Windows 操作系统上的本机字符类型)
  • char8_tchar16_tchar32_t 类型分别表示 8 位、16 位和 32 位宽字符
  • 编码为 UTF-8 的 Unicode 可以存储在 char8_t 类型中。编码为 UTF-16 的 Unicode 可以存储在 char16_t 类型中,而编码为 UTF-32 的 Unicode 可以存储在 char32_t类型中。
  • TEXT宏

对于如下语句

TCHAR * ptch = TEXT("aha~") ;

如果编译器使用unicode字符集,则TEXT相当于将"aha~"转成L"aha~";如果使用普通ascii字符集,则没有效果,还是普通的"aha~"

即可以通过TEXT宏将字符串转成TCHAR *类型,需要在vs中设置项目属性关闭强类型

  • 字符串前加L是告诉编译器将字符串转成unicode字符串,每个字符占两个字节。

windows进程和线程

windows中系统通过句柄管理进程,每个进程的句柄存储在内核空间中的一个全局句柄表中。并且每个进程也有一个句柄表,但是这个句柄表是进程私有的。

句柄表:由操作系统内核维护的一个二维表格。全局句柄表中的句柄ID就是操作系统的进程列表中的PID。

进程执行的加载过程

  • 1.映射EXE
  • 2.创建内核对象EPROCESS
  • 3.映射系统DLL(ntdll.dll)
  • 4.创建线程内核对象ETHREAD
  • 5.系统启动线程、映射DLL(ntdll.LdrInitalizeThunk)、线程开始执行

创建进程用CreateProcess

进程和线程关系

进程是一个程序正在运行的一个实例,它提供了一块存储代码的空间,在进程被创建时,系统也会给进程创建一个主线程(primary thread),主线程负责执行代码,一个进程没有线程是无法运行的

一个进程可以拥有多个线程,但是永远是先拥有主线程,通过主线程创建其他线程。

每个进程都至少有一个线程负责运行代码,否则进程将进入睡眠状态,或被系统销毁。

当主线程运行完毕,进程也将会被销毁。

一个进程在运行后,通过线程执行,一个进程必须拥有一个线程

线程操作函数

  • 暂停线程:SuspendThread(hThread)

任何线程都可以调用该函数来暂停另一个线程的运行(只要拥有线程的句柄)。线程可以自行暂停运行,但是不能自行恢复运行。

  • 恢复线程:ResumeThread(hThread)

CreateThread

HANDLE WINAPI CreateThread(
      _In_opt_  LPSECURITY_ATTRIBUTES  lpThreadAttributes,   
      _In_      SIZE_T                 dwStackSize,
      _In_      LPTHREAD_START_ROUTINE lpStartAddress,
      _In_opt_  LPVOID                 lpParameter,
      _In_      DWORD                  dwCreationFlags,
      _Out_opt_ LPDWORD                lpThreadId
    );

第一个参数 lpThreadAttributes 表示线程内核对象的安全属性,一般传入NULL表示使用默认设置。

第二个参数 dwStackSize 表示线程栈空间大小。传入0表示使用默认大小(1MB)。

第三个参数 lpStartAddress 表示新线程所执行的线程函数地址,多个线程可以使用同一个函数地址。

第四个参数 lpParameter 是传给线程函数的参数。

第五个参数 dwCreationFlags 指定额外的标志来控制线程的创建,为0表示线程创建之后立即就可以进行调度,如果为CREATE_SUSPENDED则表示线程创建后暂停运行,这样它就无法调度,直到调用ResumeThread()。

第六个参数 lpThreadId 将返回线程的ID号,传入NULL表示不需要返回该线程ID号。

WaitForSingleObject

等待子线程结束

WaitForSingleObject(
    _In_ HANDLE hHandle,
    _In_ DWORD dwMilliseconds //等待时间 如果为INFINITE 则一直等待
    );

Windows网络编程

用到的函数

  • WSAStartup
  • socket
  • connect
  • send
  • recv
  • closesocket
  • WSACleanup

示例见项目https://github.com/isBigChen/BadCode

  • BadCodeSocketServer=>BadCodeSocketServer.cpp
  • BadCodeSocketClient=>BadCodeSocketClient.cpp

Windows 内存分配规则

  1. 在windows 10 64位下,内存最小的分配粒度为4kB, systeminfo结构体中,标识了这个变量,为内存分页的大小。

  2. 在windows中,所有VirtualAllocEx分配的内存,会向上取整到AllocationGranularity的值,windows10下为64kb,比如:

    我们在0x40000000的基址分配了4kB的MEM_COMMIT | MEM_RESERVE的内存,那么整块0x40010000 (64kB)区域将不能被重新分配。

unhook

Windows10之后的版本增加了windows parallel加载的特性,简单点说就是win10之前的系统dll加载都是同步加载的,windows10以后引入异步加载。

在加载所有dll之前系统会做一些列判断,判断是采用同步还是异步加载。

在这过程种,windows会保存NtOpenFile(), NtCreateSection(), ZwQueryAttributeFile(), ZwOpenSection(), ZwMapViewOfFile()这几个函数的存根,保存位置在ntdll的.text节中。

这样就是说,这几个函数就算被hook,我们也可以获取到syscall number。并且有了这个函数,我们可以重新把内存种的ntdll换成干净的ntdll,实现了unhook的操作。

https://xz.aliyun.com/t/11532