进程、线程和模块
2012-04-17 20:22:25| 分类: Windows编程 |字号 订阅
进程包括一个虚拟地址空间及代码、数据、对象等程序运行所需环境和资源的集合。具体而言,在内存空间中包括若干可执行的代码、数据、资源、一系列对系统对象操作的句柄,安全上下文、进程标示符、环境变量等程序执行的环境。同时,进程包括一个或多个执行的线程。
线程是程序的执行流程。在操作系统层面上,线程是需要操作的系统为其分配执行的时间片的基本单元。线程附属于进程,一个线程可以执行进程中的任意代码。一个系统中同一时间只能少量的线程执行(决定于CPU的个数和核数),操作系统会决定当前执行哪一个线程,并进行调度。每一个线程都包含一个上下文(主要是CPU寄存器值)。在进行线程调度时,系统会保存线程上下文。
一个程序由多个模块组成。程序没有运行时,模块以可执行文件的形式存在(如exe、dll等)。程序运行后,所需的模块都加载到进程的虚拟地址空间中,进行初始化的设置后,各模块就开始协同工作。每个模块都肯能包括代码
数据、资源等。
一、基本概念
1.应用程序与进程
(1)可执行文件
exe文件是程序的入口,创建程序必须使用exe文件。dll是动态链接库,一些基础、共用的代码和数据存放在dll中。sys是内核驱动程序。windows平台上可执行文件的格式都是PE格式。
(2)应用程序
应用程序是由一系列具有特定功能的、能完成执行操作的可执行文件、数据的集合,一个应用程序可以包括若干可执行程序、dll、数据文件。
(3)进程
进程提供了程序运行所需要的资源、虚拟内存地址空间、各种数据、可执行的代码、需要使用到的各种内核对象、系统调用接口、优先级与权限配置、工作集、和环境变量等,还包括至少一个执行过程(线程)。
在创建进程时,系统将应用程序的可执行文件加载到内存中,设置相关环境变量后,开始启动执行。
每个进程都有一个PID和句柄,并通过其进行管理和操作。
2.控制台应用程序和图形用户界面应用程序
控制台应用程序称为字符模式应用程序。
图形用户界面应用程序是具有窗口,用户通过操作窗口与控件、程序交互。
二、进程管理
1.创建进程
/* *********************************************************
* 创建进程、获取进程相关信息、获取启动参数
* *********************************************************/
/*头文件*/
#include <Windows.h>
#include <stdio.h>
/* **********************************************************
* DWORD CreateChildProcess(LPSTR szChildProcessCmd)
* 功能:演示创建子进程
* 参数:szChildProcessCmd 启动子进程命令行
* ***********************************************************/
DWORD CreateChildProcess(LPSTR szChildProcessCmd)
{
STARTUPINFO si;
PROCESS_INFORMATION pi;
//将启动信息结构清零
ZeroMemory(&si,sizeof(si));
//设置结构大小,cb属性为结构的大小
si.cb = sizeof(si);
//将进程信息结构清零
ZeroMemory(&pi,sizeof(pi));
//创建子进程,并判断是否成功
if (!CreateProcess(NULL,//使用命令行
szChildProcessCmd,//命令行
NULL,//不继承进程句柄
NULL,//不继承线程句柄
FALSE,//不继承句柄
0,//没有创建标志
NULL,//使用父进程环境变量
NULL,//使用父进程目录作为当前目录
&si,//STARTUPINFO结构
&pi//PROCESS_INFORMATION保存相关信息
)
)
{
//创建失败
printf("CreateProcess failed(%d).\n",GetLastError());
return 1;
}
//在创建成功后父进程可以直接退出,也可等待子进程执行结束
//等待子进程结束
//使用PROCESS_INFORMATION返回相关信息,hProcess为子进程句柄
//父进程也可以不等待子进程完成而直接退出
WaitForSingleObject(pi.hProcess,INFINITE);
//关闭进程句柄和线程句柄
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
return 0;
}
int main()
{
CreateChildProcess("Child.exe abc 123");
}
(1)CreateProcess
CreateProcess(
__in_opt LPCSTR lpApplicationName, //指向启动进程的exe文件
__inout_opt LPSTR lpCommandLine, //启动进程的命令行
__in_opt LPSECURITY_ATTRIBUTES lpProcessAttributes, //进程安全属性
__in_opt LPSECURITY_ATTRIBUTES lpThreadAttributes, //进程句柄是否可被子进程继承
__in BOOL bInheritHandles, //与子进程的句柄为继承关系
__in DWORD dwCreationFlags, //进程的创建标志与优先级控制
__in_opt LPVOID lpEnvironment, //指向新进程的环境变量
__in_opt LPCSTR lpCurrentDirectory, //指向创建后新进程的当前目录
__in LPSTARTUPINFOA lpStartupInfo, //设定启动信息
__out LPPROCESS_INFORMATION lpProcessInformation //返回创建进程信息
);
2.创建子进程
/* ******************************************************************
* 创建进程、获取进程相关信息、获取启动参数
* *****************************************************************/
/*头文件*/
#include <Windows.h>
#include <stdio.h>
/*宏定义*/
#define MyAlloc(size) HeapAlloc(GetProcessHeap(),0,size)
#define MyFree(lpMem) HeapFree(GetProcessHeap(),0,lpMem)
/*结构体定义*/
typedef struct _PROCESS_INFO
{
DWORD dwPid;
HANDLE hProcess;
DWORD dwPrioClass;
DWORD dwHandleCount;
DWORD dwAffinityMask;
SIZE_T dwWorkingSetSizeMax;
SIZE_T dwWorkingSetSizeMin;
LPWSTR szwCommandLine;
STARTUPINFO sti;
}PROCESS_INFO,*LPPROCESS_INFO;
/*全局变量*/
HANDLE hMySelf;
/*函数声明*/
DWORD GetProcessInfo(LPPROCESS_INFO lppi);
/* *************************************************************
* 获取进程信息,在进程中获取命令行参数
* **************************************************************/
int WinMain( __in HINSTANCE hInstance,
__in_opt HINSTANCE hPrevInstance,
__in LPSTR lpCmdLine,
__in int nShowCmd
)
{
PROCESS_INFO pi;
int argc;
WCHAR **argv;
DWORD i;
DWORD dwBufferSize = lstrlen(lpCmdLine) + MAX_PATH + 1024;
LPSTR szShowBuffer = (LPSTR)MyAlloc(dwBufferSize);
hMySelf = hInstance;
//显示直接从WinMain函数参数得到信息
wsprintf(szShowBuffer,"启动参数\n实例句柄:%.8x,命令行参数:%s,显示选项:%.8x",hInstance,lpCmdLine,nShowCmd);
MessageBox(NULL,szShowBuffer,"WinMain函数参数",MB_OK);
//使用自定义的函数获取相关信息
GetProcessInfo(&pi);
//将命令行参数分离
argv = CommandLineToArgvW(pi.szwCommandLine,&argc);
//字符处理,并显示
*szShowBuffer = NULL;
for (i = 0; i < argc; i++)
{
DWORD dwBufferSize = lstrlenW(*argv) + 1;
LPSTR szMBArgv = (LPSTR)MyAlloc(dwBufferSize);
WideCharToMultiByte(CP_ACP,NULL,*argv,-1,szMBArgv,dwBufferSize,NULL,NULL);
argv++;
lstrcat(szShowBuffer,"\n");
lstrcat(szShowBuffer,szMBArgv);
MyFree(szMBArgv);
}
MessageBox(NULL,szShowBuffer,"参数",MB_OK);
MyFree(szShowBuffer);
return 0;
}
DWORD GetProcessInfo(LPPROCESS_INFO lppi)
{
//PID
lppi->dwPid = GetCurrentProcessId();
//句柄
lppi->hProcess = GetCurrentProcess();
//优先级
lppi->dwPrioClass = GetPriorityClass(hMySelf);
//句柄计数
GetProcessAffinityMask(hMySelf,&lppi->dwWorkingSetSizeMin,&lppi->dwWorkingSetSizeMax);
lppi->szwCommandLine = GetCommandLineW();
GetStartupInfo(&lppi->sti);
return 0;
}
执行结果:
3.控制台程序和图形用户界面程序代码上的区别
控制台程序的入口函数是main或wmain,在连接生成可执行文件时,所需要的连接选项为/SUBSYSTEM:CONSOLE 。
GUI程序的入口函数是WinMain,在生成可执行文件时,所需要的连接选项为/SUBSYSTEM:WINDOWS。
三、线程、纤程
1.创建线程、退出线程、获取线程信息
/* **********************************************************************
* 创建线程、退出线程、获取线程信息
* **********************************************************************/
/*头文件*/
#include <Windows.h>
#include <stdio.h>
/*宏定义*/
#define MAX_THREADS 5
/*结构类型*/
typedef struct _THREAD_PARAM{
DWORD i;
DWORD dwRandom;
DWORD dwData;
}THREAD_PARAM,*LPTHREAD_PARAM;
/* *******************************************************************
* 线程函数,将参数打印出
* *******************************************************************/
DWORD WINAPI ThreadProc(LPVOID lpParam)
{
LPTHREAD_PARAM pData;
//参数数据类型
pData = (LPTHREAD_PARAM)lpParam;
//显示参数
printf("TID = %u,\t Parameters = %u, %u, %u\n",GetCurrentThreadId(),pData->i,pData->dwRandom,pData->dwData);
//释放保存参数的内存(在主线程中被分配)
HeapFree(GetProcessHeap(),0,pData);
return 0;
}
void main()
{
LPTHREAD_PARAM pData;
DWORD dwThreadId[MAX_THREADS];
HANDLE hThread[MAX_THREADS];
int i;
//创建MAX_THREADS个线程
for ( i = 0; i< MAX_THREADS; i++)
{
//线程函数参数分配内存
pData = (LPTHREAD_PARAM)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(THREAD_PARAM));
if (pData == NULL)
{
printf("HeapAlloc Error;\n");
ExitProcess(2);
}
//设置参数
pData->i = i;
pData->dwRandom = rand();
pData->dwData = 100;
//创建线程
hThread[i] = CreateThread(
NULL, //默认安全属性
0, //默认堆栈大小
ThreadProc, //线程函数
pData, //参数
0, // 默认创建标志
&dwThreadId[i] //返回TID
);
//判断是否创建成功
if (hThread[i] == NULL)
{
ExitProcess(i);
}
}
getchar();
}
运行结果:
2.挂起、恢复、切换、终止进程
/* **********************************************************************
* 挂起、恢复、切换、终止进程
* *********************************************************************/
/*头文件*/
#include <Windows.h>
#include <stdio.h>
/* **********************************************************************
* 线程函数:间隔循环打印输出
* *********************************************************************/
DWORD WINAPI ThreadProc(LPVOID lpParam)
{
LPDWORD pData;
DWORD i;
//参数数据类型
pData = (LPDWORD)lpParam;
//循环打印输出
for (i ; i < 10; i++)
{
Sleep(100); //每ms打印一次
printf("TID = %u,\t Parameters = %u\t i = %u\n",GetCurrentThreadId(),*pData,i);
}
ExitThread(i);
return 0;
}
void main()
{
DWORD dwData;
DWORD dwThreadId[2];
HANDLE hThread[2];
//创建线程
dwData = 1;
hThread[0] = CreateThread(
NULL,
0,
ThreadProc,
&dwData,
CREATE_SUSPENDED, //挂起新建的进程
&dwThreadId[0]
);
if (hThread[0] == NULL)
{
ExitProcess(0);
}
//创建线程
dwData = 2;
hThread[1] = CreateThread(
NULL,
0,
ThreadProc,
&dwData,
0,
&dwThreadId[1]
);
if (hThread[1] == NULL)
{
ExitProcess(1);
}
//等待200ms,恢复线程执行
Sleep(200);
ResumeThread(hThread[0]);
//挂起线程的执行
SuspendThread(hThread[1]);
//等待300ms,终止线程
Sleep(300);
TerminateThread(hThread[0],0);
ResumeThread(hThread[1]);
//等待所有的线程执行结束
WaitForMultipleObjects(2,hThread,TRUE,INFINITE);
//关闭所有线程句柄
CloseHandle(hThread[0]);
CloseHandle(hThread[1]);
}
3.创建远程线程、将代码注入其他进程中执行
#include <Windows.h>
#include <tlhelp32.h>
#include <stdio.h>
/* *********************************************************************
* BOOL GetProcessIdByName(LPSTR szProcessName,LPDWORD lpPID)
* 功能:通过进程名获取进程PID
* 参数:LPSTR szProcessName 进程名
LPDWORD lpPID 指向保存PID的变量
* 返回:是否成功
* *********************************************************************/
BOOL GetProcessIdByName(LPSTR szProcessName,LPDWORD lpPID)
{
//变量及初始化
STARTUPINFO st;
PROCESS_INFORMATION pi;
PROCESSENTRY32 ps;
HANDLE hSnapshot;
ZeroMemory(&st,sizeof(STARTUPINFO));
ZeroMemory(&pi,sizeof(PROCESS_INFORMATION));
st.cb = sizeof(PROCESSENTRY32);
//遍历进程
hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
if (hSnapshot == INVALID_HANDLE_VALUE)
{
return FALSE;
}
if (!Process32First(hSnapshot,&ps))
{
return FALSE;
}
do
{
//比较进程
if (lstrcmpi(ps.szExeFile,"exeplore11.exe") == 0)
{
//找到了
*lpPID = ps.th32ProcessID;
CloseHandle(hSnapshot);
return TRUE;
}
}
while (Process32Next(hSnapshot,&ps));
}
/* ***********************************************************************
* BOOL EnablePrivilege(LPSTR name)
* 功能:修改进程权限
* **********************************************************************/
BOOL EnablePrivilege(LPSTR name)
{
HANDLE hToken;
BOOL rv;
TOKEN_PRIVILEGES priv = {1,{0,0,SE_PRIVILEGE_ENABLED}};
LookupPrivilegeValue(0,name,&priv.Privileges[0].Luid);
OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES,&hToken);
AdjustTokenPrivileges(hToken,FALSE,&priv,sizeof(priv),0,0);
rv = GetLastError() == ERROR_SUCCESS;
CloseHandle(hToken);
return rv;
}
/* ***********************************************************************
* BOOL LoadRemoteDll(DWORD dwProcessId, LPTSTR lpszLibName)
* 功能:通过创建远程线程给其他进程加载DLL
* 参数:DWORD dwProcessId 目标进程PID
DWORD dwProcessId Dll路径
* 返回值:是否成功
* *************************************************************************/
BOOL LoadRemoteDll(DWORD dwProcessId, LPTSTR lpszLibName)
{
BOOL bResult = FALSE;
HANDLE hProcess = NULL;
HANDLE hThread = NULL;
PSTR pszLibFileRemote = NULL;
DWORD cch;
PTHREAD_START_ROUTINE pfnThreadRtn;
_try
{
//获取想要注入代码的进程句柄
hProcess = OpenProcess(PROCESS_ALL_ACCESS,FALSE,dwProcessId);
if (hProcess == NULL)
{
_leave;
}
//计算DLL路径名需要的字节数
cch = 1 + lstrlen(lpszLibName);
//在远程线程中为路径分配空间
pszLibFileRemote =(PSTR)VirtualAllocEx(hProcess,NULL,cch,MEM_COMMIT,PAGE_READWRITE);
if (pszLibFileRemote == NULL)
{
_leave;
}
//将DLL的路径名复制到远程进程的内存空间
if (!WriteProcessMemory(hProcess,(PVOID)pszLibFileRemote,(PVOID)lpszLibName,cch,NULL))
{
_leave;
}
//获得LoadLibraryA在Kernel32.dll中的真正的地址
pfnThreadRtn = (PTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle(TEXT("Kernel32.dll")),TEXT("LoadLibraryA"));
if (pfnThreadRtn == NULL)
{
_leave;
}
//创建远程线程,并通过远程线程调用用户的DLL文件
hThread =CreateRemoteThread(hProcess,NULL,0,pfnThreadRtn,(PVOID)pszLibFileRemote,0,NULL);
if (hThread == NULL)
{
_leave;
}
//等待远程线程终止
WaitForSingleObject(hThread,INFINITE);
bResult = TRUE;
}
_finally
{
//关闭句柄
if (pszLibFileRemote != NULL)
{
VirtualFreeEx(hProcess,(PVOID)pszLibFileRemote,0,MEM_RELEASE);
}
if (hThread != NULL)
{
CloseHandle(hThread);
}
if (hProcess != NULL)
{
CloseHandle(hProcess);
}
}
return bResult;
}
/* ******************************************************************************
* WinMain
* *****************************************************************************/
int WinMain( __in HINSTANCE hInstance, __in_opt HINSTANCE hPrevInstance, __in LPSTR lpCmdLine, __in int nShowCmd )
{
DWORD dwPID;
//提权,获取SE_DEBUG_NAME权限
//可写在其他进程的内存空间中写入创建线程
if (0 != EnablePrivilege(SE_DEBUG_NAME))
{
return 0;
}
//获取目录进程的PID
if (!GetProcessIdByName("exeplore11.exe",&dwPID))
{
return 0;
}
//通过创建远程线程加载DLL
//将msg.dll放置在系统目录下
if (!LoadRemoteDll(dwPID,"msg.dll"))
{
return 0;
}
return 1;
}
分享到: 阅读(50)| 评论(0)| 转载 (0) |举报
复合 Foundation Kit
相关文章
引用 线程和进程的区别[转]
进程和线程的区别
线程
进程和线程的区别和关系
线程、线程数
评论
点击登录|昵称:
公司简介 - 联系方法 - 招聘信息 - 客户服务 - 隐私政策 - 博客风格 - 手机博客 - VIP博客 - 订阅此博客
网易公司版权所有 ?1997-2012