第三十個CreateToolhelp32Snapshot給當前進程拍一個照
HANDLE hProcessSnap=::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
//記住這種格式就行了,返回的句柄,存儲有進程信息,可以用Process32Firs函數找出來。
第三十一個Process32First根據CreateToolhelp32Snapshot函數返回的句柄獲取進程信息
結合Process32Next函數使用,有點像文件尋找函數。
看完整例子:顯示系統進程名,以及進程ID號
#include<windows.h>
#include<tlhelp32.h>//聲明快照函數的頭文件
#include<stdio.h>
int main()
{
PROCESSENTRY32 pe32;//進程的信息將會存儲在這個結構裏
//在使用這個結構之前,先設置它的大小
pe32.dwSize=sizeof(pe32);
//給系統內的所有進程拍一個快照
HANDLE hProcessSnap=::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
BOOL bMore=::Process32First(hProcessSnap,&pe32);//第一次查找
while(bMore)
{
printf("進程名稱:%s/n",pe32.szExeFile);//szExeFile是進程名
printf("進程ID號:%u/n/n",pe32.th32ProcessID);//th32ProcessID是進程ID號
bMore=::Process32Next(hProcessSnap,&pe32);//尋找下個進程,函數返回0,則沒有進程可尋
}
return 0;
}
第三十二個OpenProcess根據進程ID號獲得進程句柄,句柄通過函數返回
函數定義:HANDLE OpenProcess( DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwProcessId);
第一個參數不要管它,填PROCESS_ALL_ACCESS,第二個參數也一樣,填FALSE,那最後一個參數就是進程ID號。
第三十三個TerminateProcess結束一個進程(需進程句柄做參數)
該函數只有兩個參數,第一個是進程句柄,第二個填0就行了。
現在給個例子:假設當前有一個進程名爲abc.exe的進程正在運行,編一個程序結束它。
#include<windows.h>
#include<tlhelp32.h>//聲明快照函數的頭文件
int main(int argc,char *argv[])
{
PROCESSENTRY32 pe32;
//在使用這個結構之前,先設置它的大小
pe32.dwSize=sizeof(pe32);
//給系統內的所有進程拍一個快照
HANDLE hProcessSnap=::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
//遍歷進程快照,輪流顯示每個進程的信息
BOOL bMore=::Process32First(hProcessSnap,&pe32);
while(bMore)
{
if(strcmp("abc.exe",pe32.szExeFile)==0)//如果找到進程名爲abc.exe
{
HANDLE hProcess=OpenProcess(PROCESS_ALL_ACCESS,FALSE,pe32.th32ProcessID);//獲取句柄
::TerminateProcess(hProcess,0);//結束它
}
bMore=::Process32Next(hProcessSnap,&pe32);//尋找下一個
}
return 0;
}
上面的這個例子,只能結束普通權限進程,如果爲系統進程的話,則沒有用,結束不了。在後面的提升權限函數,會有例子說明如何結束系統進程。
第三十四個CreatePen創建一個畫筆(返回畫筆句柄)
函數定義:BOOL CreatePen(int nPenStyle, int nWidth, COLORREF crColor);
第一個參數,表示是什麼類型的線,取值有以下:
如創建一個畫筆:HPEN pen=CreatePen(PS_SOLID,3,RGB(255,78,99));
PS_SOLID 畫筆畫出的是實線 PS_DASH 畫筆畫出的是虛線(nWidth必須是1) PS_DOT 畫筆畫出的是點線(nWidth必須是1)
PS_DASHDOT 畫筆畫出的是點劃線(nWidth必須是1) PS_DASHDOTDOT 畫筆畫出的是點-點-劃線(nWidth必須是1)
第二個參數是畫筆的寬度,第三個參數是畫筆的顏色,COLORREF類型可以RGB來獲得如RGB(233,128,88);分別是紅綠藍。
第三十五個CreateSolidBrush創建一個畫刷
只有一個COLORREF類型的參數
HBRUSH brush=CreateSolidBrush(RGB(22,182,111));
第三十六個SelectObject把GDI對象選入相應的DC中
像畫筆(句柄HPEN),畫刷(HBURSH),位圖(HBITMAP)等都是GID對象。因爲畫圖函數,如畫圓,畫矩形,畫直線,它們所畫出圖形,默認屬性都是不變的,如線的寬度。那麼想要改變畫出來時線的寬度,比如我想畫出來的圖形它的線條寬度爲5(像素),那麼就要創建一個寬度爲5的畫筆,然後再通過SelectObject函數,給這個畫筆選入,就可以了.
接下舉個例子:SelectObject應用
#include "stdafx.h"
#include<windows.h>
LRESULT CALLBACK WinSunProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
static HPEN pen=CreatePen(PS_SOLID,3,RGB(255,78,99));//創建畫筆
static HBRUSH brush=CreateSolidBrush(RGB(22,182,111));//創建畫刷
if(uMsg==WM_PAINT)//窗口需要重畫的時候
{
HDC hDC;
PAINTSTRUCT ps;
hDC=BeginPaint(hwnd,&ps); //BeginPaint只能在響應WM_PAINT,不能用GetDC獲取設備上下文
SelectObject(hDC,pen);//選入畫筆
SelectObject(hDC,brush);//選入畫刷
Rectangle(hDC,100,100,200,200);
EndPaint(hwnd,&ps);
}
else if(uMsg==WM_CLOSE)//用戶關閉了窗口
DestroyWindow(hwnd);//銷燬窗口,併發送WM_DESTROY消息
else if(uMsg==WM_DESTROY)//如果窗口被銷燬
PostQuitMessage(0);//讓進程退出
return DefWindowProc(hwnd,uMsg,wParam,lParam); //未處理的消息通過DefWindowProc函數交給系統處理
}
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
WNDCLASS wndcls; //定義一個存儲窗口信息WNDCLASS變量
wndcls.cbClsExtra=0; //默認爲0
wndcls.cbWndExtra=0; //默認爲0
wndcls.hbrBackground=(HBRUSH)GetStockObject(GRAY_BRUSH); //背景畫刷
wndcls.hCursor=LoadCursor(NULL,IDC_ARROW); //光標
wndcls.hIcon=LoadIcon(NULL,IDI_ERROR); //窗口圖標
wndcls.hInstance=hInstance; //應用程序實例句柄由WinMain函數傳進來
wndcls.lpfnWndProc=WinSunProc; //窗口消息處理函數
wndcls.lpszClassName="windowclass"; //窗口類名
wndcls.lpszMenuName=NULL; //窗口菜單名,沒有菜單,爲NULL
wndcls.style=CS_HREDRAW | CS_VREDRAW;//窗口類型,CS_HREDRAW和CS_VERDRAW 表明
//當窗口水平方向垂直方向的寬度變化時重繪整個窗口
RegisterClass(&wndcls); //把窗口信息提交給系統,註冊窗口類
HWND hwnd; //用以存儲CreateWindow函數所創建的窗口句柄
hwnd=CreateWindow("windowclass","first windows",
WS_OVERLAPPEDWINDOW,0,0,600,400,NULL,NULL,hInstance,NULL);//創建窗口
ShowWindow(hwnd,SW_SHOWNORMAL);//窗口創建完了,顯示它
UpdateWindow(hwnd); //更新窗口,讓窗口毫無延遲的顯示
MSG msg;//消息結構類型
while(GetMessage(&msg,NULL,0,0))//獲取消息
{
//TranslateMessage(&msg); //此函數用於把鍵盤消息(WM_KEYDOWN,WM_KEYUP)轉換成字符消息WM_CHAR
DispatchMessage(&msg); //這個函數調用窗口過程處理函數,並把MSG裏的信息處理後傳給過程函數的四個參數
}
return 0;
}
第三十七個 ReadProcessMemory根據進程句柄讀取相應的一段內存(讀其它進程裏的內存)
函數定義:BOOL ReadProcessMemory(HANDLE hProcess,PVOID pvAddressRemote,PVOID pvBufferLocal,DWORD dwSize,
PDWORD pdwNumBytesRead);總共四個參數
第一個參數hProcess是遠程進程句柄,被讀取者 。第二個pvAddressRemote是遠程進程中內存地址。 從具體何處讀取
pvBufferLocal是本地進程中內存地址. 函數將讀取的內容寫入此處 ,dwSize是要讀取的字節數。要讀取多少
pdwNumBytesRead是實際讀取的內容(函數執行後,實際讀了多少字節,將存儲在該變量裏)
遠程進程的內存地址是什麼意思呢,比如我現在定義一個變量a,int a;就是了,大家知道int型是佔四個字節的,也就是說如果a變量所佔的內存起始地址是0x1234,那麼變量a就佔用0x1234,0x1235,0x1236,0x1237這四個字節,這四個字節的內容決定了a變量的值。
好了知道了這個,我們就來舉個例子,讀取另一個進程裏一個變量的值:需設計兩個程序,一個用於讀(Read)一個用於被讀(BeRead);
那麼要如何獲得另一個進程中一個變量的地址呢?這裏我們用一個簡單的方法,讓另一個進程自己去獲取,然後輸出地址值。
被讀的程序代碼如下:假設該進程名爲:BeRead.exe
#include<stdio.h>
int main()
{
int a=10;//要讀取的變量。
printf("%x/n",&a);//輸出這個變量的起始地址,假設輸出爲12ff7c
while(1)
{
Sleep(1000);
}
return 0;
}
必須先讓這個程序運行,然後根據輸出的地址值,才能在下面的程序填入地址值。
讀取的程序代碼如下:
#include<windows.h>
#include<stdio.h>
#include<tlhelp32.h>
int main()
{
//先要獲取進程句柄,如何獲取,參照TerminateProcess函數,結束一個進程
HANDLE ReProcess;
PROCESSENTRY32 pe32;
pe32.dwSize=sizeof(pe32);
HANDLE hProcessSnap=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
BOOL bMore=::Process32First(hProcessSnap,&pe32);
while(bMore)
{
if(strcmp(pe32.szExeFile,"BeRead.exe")==0)//如果是BeRead.exe
{
ReProcess=::OpenProcess(PROCESS_ALL_ACCESS,FALSE,pe32.th32ProcessID);//獲取該進程句柄
break;
}
bMore=Process32Next(hProcessSnap,&pe32);
}
int *ReAddress=(int *)0x12ff7c;//要讀取的內存的地址值
int *p=new int;
unsigned long size;
ReadProcessMemory(ReProcess,ReAddress,p,4,&size);//讀取BeRead進程的內存
printf("%d/n",*p);//輸出讀取來的值
return 0;
}
第三十八個WriteProcessMemory根據進程句柄寫入相應的一段內存(寫入其它進程裏的內存)
這個函數裏的參數跟ReadProcessMemory函數參數意思一樣,只不過一個是寫,一個是讀。
下面直接舉個例子,形式跟讀內存函數的例子一樣。
被寫的程序代碼如下:假設該進程名爲:BeWrite.exe
#include<stdio.h>
int main()
{
int a=10;
printf("%x/n",&a);//假設輸出爲12ff7c
while(1)
{
printf("%d/n",a);//每隔一秒輸出,查看值有沒有改變
Sleep(1000);
}
return 0;
}
寫入的代碼如下:
#include<windows.h>
#include<stdio.h>
#include<tlhelp32.h>
int main()
{
HANDLE ReProcess;
PROCESSENTRY32 pe32;
pe32.dwSize=sizeof(pe32);
HANDLE hProcessSnap=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
BOOL bMore=::Process32First(hProcessSnap,&pe32);
while(bMore)
{
if(strcmp(pe32.szExeFile,"BeWrite.exe")==0)
{
ReProcess=::OpenProcess(PROCESS_ALL_ACCESS,FALSE,pe32.th32ProcessID);
break;
}
bMore=Process32Next(hProcessSnap,&pe32);
}
int *ReAddress=(int *)0x12ff7c;
int *p=new int;
*p=300;
unsigned long size;
WriteProcessMemory(ReProcess,ReAddress,p,4,&size);
return 0;
}
第三十九個CreateThread創建一個線程(多線程)
線程是什麼意思呢,代碼是由線程來執行的,一個程序默認只有一個線程(主線程),打個比方,線程就好比一個人,而不同功能的代碼或函數就好是一件件不同的事情,如洗碗,洗衣服,擦地。一個人要把這幾種事情做完,可以有好幾種方案,第一種就是,洗完碗,就去洗衣服,衣服洗完了,再去擦地。第二種就是:洗一分鐘碗,再去洗一分鐘衣服,再去擦一分鐘,然後又去洗一分鐘衣服.......直到做完。好了,現在你可以再創造一個人幫你做事,創造這個人後,你就叫他洗衣服,而你就洗碗,這樣兩件事就可以同時被做了。而這裏的創造一個人指的就是CreateThread函數。
函數定義:HANDLE CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes,DWORD dwStackSize,LPTHREAD_START_ROUTINE lpStartAddress,LPVOID lpParameter,DWORD dwCreationFlags,LPDWORD lpThreadId);
該函數有六個參數,第一個參數不用管它,填NULL,第二個參數dwStackSize用於新線程的初始堆棧大小,默認爲0,第三個lpStartAddress填函數名(指標),但這個函數必須是這種固定格式的DWORD _stdcall ThreadProc(LPVOID lpParameter),新的線程將會執行這個函數裏面的代碼,直到函數結束,線程死亡。第四個lpParameter是一自定義參數,用戶可以通過這個參數,傳遞需要的類型,這個參數與線程函數的參數相對應。第五個dwCreationFlags填0表示立即執行,如果是CREATE_SUSPENDED表示掛起,直到用ResumeThread函數喚醒。第六個lpThreadId填NULL就行了。
現舉個例子,兩個線程同時每隔一秒輸出一個數字,也就是一秒會有兩數字輸出。
#include<windows.h>
#include<stdio.h>
DWORD _stdcall ThreadProc(LPVOID lpParameter)//線程執行函數
{
int si=100;
while(si>0)
{
printf("子線程輸出數字:%d/n",si--);
Sleep(1000);
}
return 0;
}
int main()
{
int mi=0;
CreateThread(NULL,0,ThreadProc,NULL,0,NULL);//創建一個線程,去執行ThreadProc函數
while(mi<100)
{
printf("主線程輸出數字:%d/n",mi++);
Sleep(1000);
}
return 0;
}
第四十個GetCurrentProcessId獲得當前進程ID
DWORD currentPID;
currentPID=::GetCurrentProcessId();//返回進程ID號
cout<<currentPID<<endl;