进程、线程和模块


进程、线程和模块  


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
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值