Win32(一)

一、字符

1.字符編碼

(1)原始的ASCII表: 0—7F(0—127)

(2)擴展的ASCII表: 0—FF(0—255) GB2312或GB2312-80 <用2個字節編碼一個漢字>

(3)Unicode編碼:

編碼範圍:0—0x10FFFF

存在問題:只規定了符號的二進制代碼,沒有規定代碼如何存儲

(4)如何存儲Unicode:UTF-16/UTF-8是Unicode的實現方式

UTF-16:以16位無符號整數爲單位,以2個字節對齊 

UTF-8:  變長編碼,以1/2/3/4字節爲單位

Unicode編碼(16進制) UTF-8字節流(二進制)
000000-00007F 0xxxxxxx
000080-0007FF 110xxxxx  0xxxxxxx
000800-00FFFF 1110xxxx  10xxxxxx  10xxxxxx
010000-10FFFF 11110xxx  10xxxxxx  10xxxxxx  10xxxxxx

BOM(Byte Order Mark):表明文件的存儲格式,位於文件開頭

UTF-8                     

EF BB BF

UTF-16LE(小端)

FF FE

UTF-16BE(大端) FE FF
字符:"A中"
UTF-16: 41 00 2D 4E (小端存儲)
        01000001 00000000 00101101 01001110
UTF-8:  41 E4 B8 AD
        01000001 1110(0100) 10(111000) 10(101101)

(0100) (111000) (101101) = 01001110 00101101 = 4E 2D

2.C語言的寬字符

(1)字符串在內存中的值

char szStr[] = "中國";
D6 D0 B9 FA 00                 //拓展的ASCII,5字節
wchar_t swzStr[] = L"中國";    //以UTF-16存儲
2D 4E FD 56 00 00              //Unicode編碼,6字節

(2)在控制檯打印寬字符

#include<locale.h>
setlocale(LC_ALL,"");    //使用控制檯默認的編碼
wchar_t swzStr[] = L"中國";
wprintf(L"%S\n",x1);

(3)字符串長度

char szStr[] = "abcde";
wchar_t swzStr[] = L"abcde";   
strlen(szStr);           //獲取字符長度,不包含00,返回5
wcslen(swzStr);          //獲取字符長度,不包含00 00,返回5
//分別用於ASCII字符串和Unicode的字符串,不同的字符串要使用對應的函數,如果強制轉型使用錯誤的函數成功編譯,不能得到正確的結果

(4)常用函數

char       wchar_t            //多字節字符類型    寬字符類型
printf     wprintf            //打印到控制檯函數
strlen     wcslen             //獲取長度
strcpy     wcscpy             //字符串複製
strcat     wcscat             //字符串拼接
strcmp     wcscmp             //字符串比較
strstr     wcsstr             //字符串查找

3.API中的寬字符

(1)概念(幾個重要的DLL)

Kernel32.dll 最核心的功能模塊,如:內存管理、進程/線程處理
User32.dll Windows用戶界面相關應用程序接口,如:創建窗口、發送消息
GDI32.dll 全稱Graphical Device Interface(圖形設備接口),包含:用於畫圖和顯示文本的函數

(2)在Win32中使用字符串

MessageBox()函數

LPCTSTR  =  LPCSTR  =  CONST CHAR*  =  const char*

字符類型:
CHAR szStr[] = "中國";            //ASCII
WCHAR swzStr[] = L"中國";         //Unicode
TCHAR stzStr[] = TEXT("中國");    //TCHAR是一個宏,根據項目默認使用的字符自動轉換字符編碼
字符串指針:
PSTR pszStr[] = "中國";           //char*
PWSTR pwszStr[] = L"中國";        //wchat_t*
PTSTR ptszStr[] = TEXT("中國");   //PTSTR是一個宏,有利於跨平臺
//建議使用TCHAR和PTSTR

二、多線程

1.進程的創建過程

(1)概念:進程爲程序提供所需的資源(代碼/數據),線程使用資源;

(2)進程內存空間的地址劃分

分區 x86 32位Windows
空指針賦值區 0x00000000 - 0x0000FFFF(從未使用)
用戶模式區 0x00010000 - 0x7FFEFFFF
64KB禁入區 0x7FFF0000 - 0x7FFFFFFF
內核 0x80000000 - 0xFFFFFFFF(所有進程共用內核高2GB的內存空間)

(3)進程的創建過程:任何進程都是由別的進程創建的,進程創建時總會創建一個線程,CreateProcess()

1.映射EXE文件 (A.exe)
2.創建內核對象EPROCESS,每個進程都有自己的EPROCESS對象
3.映射系統DLL(ntdll.dll)
4.創建系統內核對象ETHREAD
5.系統啓動線程:
          //將A進程要執行的DLL換成B進程的,最終執行的是B
          映射DLL(ntdll.LdrlnitializeThunk)
          線程開始執行

2.創建進程的函數

BOOL CreateProcess
(
LPCTSTR lpApplicationName,   //對象名稱,完整的路徑名
LPTSTR lpCommandLine,        //命令行參數,可以不使用爲NULL
LPSECURITY_ATTRIBUTES lpProcessAttributes,  //創建的進程是否允許被繼承
LPSECURITY_ATTRIBUTES lpThreadAttributes,   //同時創建的線程是否允許被繼承
BOOL bInheritHandles,                       //是否要繼承父進程的句柄表
DWORD dwCreationFlags,       //CREATE_SUSPENDED
LPVOID lpEnvironment,         //環境塊
LPCTSTR lpCurrentDirectory,   //當前進程的工作目錄
LPSTARTUPINFO lpStartupInfo,             //新窗口如何顯示,STARTUPINFO結構存儲啓動狀態,IN參數
LPPROCESS_INFORMATION lpProcessInformation   //PROCESS_INFORMATION結構,OUT參數
);

(1)命令行

使用cd命令打開瀏覽器
使用cd命令打開瀏覽器

(2)由父進程爲子進程填充STARTUPINFO結構

由OD生成
由explore生成
#include "stdio.h"
#include <windows.h>

void AntiDebug()
{
	STARTUPINFO si;    //每個進程創建都有這個結構體,值由父進程填充
	GetStartupInfo(&si);   //獲取啓動進程的信息
	printf("%x %x %x %x %x %x %x %x\n", si.dwX, si.dwY, si.dwXCountChars,
		si.dwYCountChars, si.dwFillAttribute, si.dwXSize, si.dwYSize,si.dwFlags);
}
BOOL CreateChildProcess(PTCHAR szChildProcessName, PTCHAR szCommandLine)
{
	STARTUPINFO si;
	PROCESS_INFORMATION pi;
	ZeroMemory(&pi, sizeof(si));  //把結構體初始值至0
	ZeroMemory(&pi, sizeof(pi));
	si.cb = sizeof(si);               //此成員必須初始化

	//創建子進程,返回成功與失敗
	if (!CreateProcess(szChildProcessName,  //對象名稱
		szCommandLine,    //命令行
		NULL,         //不繼承進程句柄
		NULL,         //不繼承線程句柄
		FALSE,        //不繼承句柄,子進程由獨立的句柄表;若爲True,子進程可獲取父進程可繼承的句柄表
		0,            //沒有創建標誌,dwFlags
		NULL,         //使用父進程環境變量
		NULL,         //使用父進程目錄作爲當前目錄,可以自己設置目錄
		&si,
		&pi))
	{
		printf("創建子進程失敗:%d \n", GetLastError()); return FALSE;
	}
	//釋放句柄
	CloseHandle(pi.hProcess); CloseHandle(pi.hThread); return TRUE;
}

int main(int argc, char* argv[])
{
	TCHAR szApplicationName[] = TEXT("E://360瀏覽器//360se6//Application//360se.exe");
	TCHAR szCmdLine[] = TEXT(" 61.135.169.121");   //注意空格
	CreateChildProcess(szApplicationName, szCmdLine);
	//printf("%s - %s \n", argv[0], argv[1]);
	//AntiDebug();
	getchar();
	return 0;
}

3.句柄表

(1)內核對象:進程、線程、文件、互斥體、事件等在內核有一個對應的結構體,結構體由內核負責管理,稱爲內核對象;

(2)管理內核對象:句柄表是每個進程私有的一張表,句柄值在本進程內纔有意義;內核對象可用CloseHandle關閉;                                                                SuspendThread();      ResumeThread();  

(3)多進程共享一個內核對象(方式一)

  • 內核對象A使用計數爲2;CloseHandle只是將內核對象的使用計數減1,並不是關閉;當使用計數爲0,內核對象會被關閉;
  • 結束一個線程句柄不會結束相關聯的線程,要關閉線程,既要結束線程,也要使使用計數爲0;只要線程不結束,進程就不會結束;

(4)句柄是否可以被繼承(共享內核方式二)

  • 創建的內核對象中一定包含安全描述符(SECURITY_ATTRIBUTES結構);
  • 句柄表表項:當前對象繼承標誌、索引、內核結構體地址;
  • 下圖,父進程中2、4項可被子進程繼承,子進程獲取父進程句柄表,其中子進程可直接使用父進程的句柄值;

4.進程相關API

(1)ID與句柄

  • 全局句柄表(操作系統所有):包含所有正在運行中的進程和線程;
  • 進程ID/線程ID:全局句柄表的一個索引;
  • 進程句柄:進程句柄表的索引;

(2)以掛起的形式創建進程:CREATE_SUSPENDED參數

//進程創建過程發生改變
1.映射EXE文件 (A.exe)
2.創建內核對象EPROCESS,每個進程都有自己的EPROCESS對象
3.映射系統DLL(ntdll.dll)
4.創建系統內核對象ETHREAD
5.進程以掛起的方式創建:
      。。。進程進入等待狀態      //可在此注入自己的代碼
5.恢復以後再繼續執行:
          映射DLL(ntdll.LdrlnitializeThunk)
          線程開始執行

(3)模塊目錄、工作目錄

GetModuleFileName();      //獲取當前模塊(運行的exe)所在的路徑
GetCurrentDirectory();    //獲取當前工作路徑,工作路徑由父進程填充

(4)其他進程相關API

獲取進程PID:GetCurrentProcessId
獲取進程句柄:GetCurrentProcess
獲取命令行:GetCommandLine
獲取啓動信息:GetStartupInfo
遍歷進程ID:EnumProcess
進程快照:CreateToolhelp32Snapshot   //獲取系統當前全部進程,進程擁有的模塊

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章