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_t、char16_t和char32_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 内存分配规则
-
在windows 10 64位下,内存最小的分配粒度为4kB, systeminfo结构体中,标识了这个变量,为内存分页的大小。
-
在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