分享
 
 
 

Win32汇编教程十一 进程控制

王朝system·作者佚名  2006-01-08
窄屏简体版  字體: |||超大  

--------------------------------------------------------------------------------

概述

进程控制简单的说相当于在一个程序中执行另一个程序,你可以把它想象成在 Dos 下用 int 21h/4bh 功能来执行另外一个程序,如果单从执行另一个程序的目的来讲,在 Windows 中有不少方法,如使用 ShellExecute 等,但这些 Api 仅仅是“执行”而已,进程控制的意义在于可以创建一个进程,并可以通过进程句柄结束进程,同样你也可以通过进程句柄来跟踪程序,还可以用 ReadProcessMemory 和 WriteProcessMemory 来读写子进程的内存空间。

进程控制要使用的相关 API 有下面这些:

创建进程的函数为CreateProcess,该函数比较复杂,共有十个参数,但有个好消息是使用时大部分可以用 NULL。

BOOL CreateProcess(

LPCTSTR lpApplicationName, // 执行程序文件名

LPTSTR lpCommandLine, // 参数行

LPSECURITY_ATTRIBUTES lpProcessAttributes, // 进程安全参数

LPSECURITY_ATTRIBUTES lpThreadAttributes, // 线程安全参数

BOOL bInheritHandles, // 继承标记

DWORD dwCreationFlags, // 创建标记

LPVOID lpEnvironment, // 环境变量

LPCTSTR lpCurrentDirectory, // 运行该子进程的初始目录

LPSTARTUPINFO lpStartupInfo, // 创建该子进程的相关参数

LPPROCESS_INFORMATION lpProcessInformation // 创建后用于被创建子进程的信息

);

各个参数的说明如下:

lpApplicationName:为执行程序的文件名,你也可以把执行文件名包括在下一个参数 lpCommandLine 中,然后把该参数置为NULL。

lpCommandLine:为参数行,如果无参数可以为NULL,在有参数传递给进程时可以如下设置:lpApplicationName=文件名;lpCommandLine=参数,或者 lpApplicationName=NULL;lpCommandLine=文件名 + 参数。

lpProcessAttributes,lpThreadAttributes:分别描述了创建的进程和线程安全属性,如果使用NULL表示使用默认的安全描述。

bInheritHandles:表示当前进程中的打开的句柄是否能够被创建的子进程所继承。

dwCreationFlags:表示创建标记,通过该标记可以设置进程的创建状态和优先级别。常用的有下面的标记:

CREATE_NEW_CONSOLE:为子进程创建一个新的控制台。

CREATE_SUSPENDED:子进程在创建时为挂起状态。如果指定了这个参数,那么执行 CreateProcess 后进程只是被装入内存,但不是马上开始执行,而是必须等主程序调用 ResumeThread 后才继续执行。

HIGH_PRIORITY_CLASS/NORMAL_PRIORITY_CLASS:高/普通优先级别。

lpEnvironment:表示子进程所使用的环境变量,如果为NULL,则表示与当前进程使用相同的环境变量。

lpCurrentDirectory:表示子进程运行的初始目录。

lpStartupInfo:STARTUPINFO 结构,用于在创建子进程时设置各种属性。

lpProcessInformation:PROCESS_INFORMATION 结构,用来在进程创建后接收相关信息,该结构由系统填写。

调用 CreateProcess 函数有三个参数是必需的,一在 lpApplicationName 或 lpCommandLine 指定文件名,二是 lpStartupInfo 结构,三是 PROCESS_INFORMATION 结构,因为 PROCESS_INFORMATION 结构返回了进程建立后的句柄,以后的一切操作将要用到这些返回的句柄,它是由系统填写的,结构说明如下:

typedef struct _PROCESS_INFORMATION {

HANDLE hProcess; //进程句柄

HANDLE hThread; //进程的主线程句柄

DWORD dwProcessId; //进程ID

DWORD dwThreadId; //进程的主线程ID

} PROCESS_INFORMATION;

另外还有一个关键的结构 STARTUPINFO,该结构定义如下:

typedef struct STARTUPINFO {

DWORD cb; //结构长度

LPTSTR lpReserved; //保留

LPTSTR lpDesktop; //保留

LPTSTR lpTitle; //如果为控制台进程则为显示的标题

DWORD dwX; //窗口位置

DWORD dwY; //窗口位置

DWORD dwXSize; //窗口大小

DWORD dwYSize; //窗口大小

DWORD dwXCountChars; //控制台窗口字符号宽度

DWORD dwYCountChars; //控制台窗口字符号高度

DWORD dwFillAttribute; //控制台窗口填充模式

DWORD dwFlags; //创建标记

WORD wShowWindow; //窗口显示标记,如同ShowWindow中的标记

WORD cbReserved2; //

LPBYTE lpReserved2; //

HANDLE hStdInput; //标准输入句柄

HANDLE hStdOutput; //标准输出句柄

HANDLE hStdError; //标准错误句柄

} STARTUPINFO, *LPSTARTUPINFO;

结构中 dwFlags 指定了其它的一些字段是否有效,如:dwFlags包含 STARTF_USESIZE 表示dwXSize和dwYSize有效,包含STARTF_USEPOSITION表示dwX和dwY有效,等等。如果不是有特殊的要求,我们不用自己去填写这个结构,只需用 GetStartupInfo 让 Windows 为你填写好了,这样,建立一个进程的语句就是:

...

stStartUp STARTUPINFO stProcInfo PROCESS_INFORMATION <?>

stProcInfo PROCESS_INFORMATION <?>

...

invoke GetStartupInfo,addr stStartUp

invoke CreateProcess,NULL,addr szFileName,NULL,NULL,NULL,NORMAL_PRIORITY_CLASS,NULL,NULL,offset stStartUp,offset stProcInfo

...

如果成功的话,eax 将返回非零值,注意返回在 PROCESS_INFORMATION 结构中的 hProcess,以后很多的操作都要用到它。

强制结束一个进程的 API 为 TerminateProcess

BOOL TerminateProcess(

HANDLE hProcess, // 进程句柄

UINT uExitCode // 退出代码

);

你可以使用语句 invoke TerminateProcess,structProcInfo.hProcess,0 来结束进程,要注意的是如果可能的话,尽量不要在程序中强制结束别的进程,因为使用 TerminateProcess 结束的进程,它装载的 dll 不能被正确卸载。这样可能会引起系统资源的无效占用。最好的办法在进程中自己使用 ExitProcess 退出。

查询一个进程状态的 API 为 GetExitCodeProcess。

BOOL GetExitCodeProcess(

HANDLE hProcess, // handle to the process

LPDWORD lpExitCode // address to receive termination status

);

如果进程尚未退出,函数将会返回STILL_ACTIVE。这个 API 是马上返回的。

等待进程执行可以用 WaitForSingleObject

这个 API 并不是单用于进程的等待,其它还可以用在线程等操作,但我们一般用它来等待进程的执行,它的申明是:

DWORD WaitForSingleObject(

HANDLE hHandle, // handle of object to wait for

DWORD dwMilliseconds // time-out interval in milliseconds

);

如果我们要等待进程执行 1 秒钟,可以 invoke WaitForSingleObject,stProcInfo.hProcess,1000 如果要等到进程结束,可以用 WaitForSingleObject,stProcInfo.hProcess,INFINITE ,参数 2 中的 INFINITE 在 Windows.inc 中有定义,意思是无穷等待。

最后,当不再使用进程句柄的时候,不要忘了使用 CloseHandle 关闭 hProcess 和 hThread,否则会浪费系统句柄的资源。

源程序 - 汇编源文件

.386

.model flat, stdcall

option casemap :none ; case sensitive

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

; Include 数据

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

include windows.inc

include user32.inc

include kernel32.inc

include comctl32.inc

include comdlg32.inc

include gdi32.inc

includelib user32.lib

includelib kernel32.lib

includelib comctl32.lib

includelib comdlg32.lib

includelib gdi32.lib

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

; Equ 数据

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

DLG_MAIN equ 3000

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

ID_BROWSE equ 3001

ID_RUN equ 3002

ID_EXIT equ 3003

ID_TEXT equ 3004

F_RUNNING equ 0001h ;进程在运行中

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

; 数据段

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

.data?

stStartUp STARTUPINFO <?>

stProcInfo PROCESS_INFORMATION <?>

stOpenFileName OPENFILENAME <?>

hRunThread dd ?

hInstance dd ?

hWinMain dd ?

hIcon dd ?

szBuffer db 512 dup (?)

dwFlag dd ?

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

.data

szExcute db '执行(&E)',0 ;按钮文字

szKill db '终止(&E)',0

szExcuteError db '启动应用程序错误!',0

szTitleOpen db "Open executable file...",0

szExt db '*.exe',0

szFilter db 'Excutable Files',0,'*.exe;*.com',0

db 0

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

; 代码段

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

.code

if DEBUG

include Debug.asm

endif

include Win.asm

;********************************************************************

; 执行程序用的线程

; 1. 用 CreateProcess 建立进程

; 2. 用 WaitForSingleOject 等待进程结束

;********************************************************************

_RunThread proc uses ebx ecx edx esi edi,dwParam:DWORD

or dwFlag,F_RUNNING

;********************************************************************

; 取消“退出”按钮并把“执行”按钮改为“中止”

;********************************************************************

invoke GetDlgItem,hWinMain,ID_EXIT

invoke EnableWindow,eax,FALSE

invoke SendDlgItemMessage,hWinMain,ID_RUN,WM_SETTEXT,0,offset szKill

;********************************************************************

; 执行文件,如果成功则等待程序结束

;********************************************************************

invoke GetStartupInfo,addr stStartUp

invoke CreateProcess,NULL,addr szBuffer,NULL,NULL,NULL,NORMAL_PRIORITY_CLASS,NULL,NULL,offset stStartUp,offset stProcInfo

.if eax != 0

invoke WaitForSingleObject,stProcInfo.hProcess,INFINITE

invoke CloseHandle,stProcInfo.hProcess

invoke CloseHandle,stProcInfo.hThread

.else

invoke MessageBox,hWinMain,addr szExcuteError,NULL,MB_OK or MB_ICONERROR

.endif

;********************************************************************

; Enable “退出”按钮并把“中止”按钮改为“执行”

;********************************************************************

invoke GetDlgItem,hWinMain,ID_EXIT

invoke EnableWindow,eax,TRUE

invoke SendDlgItemMessage,hWinMain,ID_RUN,WM_SETTEXT,0,offset szExcute

and dwFlag,not F_RUNNING

ret

_RunThread endp

;********************************************************************

; 窗口程序

;********************************************************************

DialogMainProc proc uses ebx edi esi, hWnd:DWORD,wMsg:DWORD,wParam:DWORD,lParam:DWORD

mov eax,wMsg

;********************************************************************

.if eax == WM_INITDIALOG

mov eax,hWnd

mov hWinMain,eax

call _Init

;********************************************************************

.elseif eax == WM_CLOSE

invoke EndDialog,hWinMain,NULL

;********************************************************************

.elseif eax == WM_COMMAND

mov eax,wParam

.if ax == ID_BROWSE

call _BrowseFile

call _CheckText

.elseif ax == ID_TEXT

invoke GetDlgItemText,hWinMain,ID_TEXT,addr szBuffer,512

call _CheckText

.elseif ax == ID_RUN

;********************************************************************

; 如果没有在执行中(dwFlag 没有置位) 则建立线程,在线程中执行程序

; 如果已经在执行中,则用 TerminateProcess 终止执行

;********************************************************************

test dwFlag,F_RUNNING

.if ZERO?

invoke CreateThread,NULL,NULL,offset _RunThread,NULL,NULL,offset hRunThread

.else

invoke TerminateProcess,stProcInfo.hProcess,-1

.endif

.elseif ax == ID_EXIT

invoke EndDialog,hWinMain,NULL

.endif

.else

;********************************************************************

; 注意:对话框的消息处理后,要返回 TRUE,对没有处理的消息

; 要返回 FALSE

;********************************************************************

mov eax,FALSE

ret

.endif

mov eax,TRUE

ret

DialogMainProc endp

;********************************************************************

; 程序入口

;********************************************************************

start:

invoke InitCommonControls

invoke GetModuleHandle,NULL

mov hInstance,eax

invoke DialogBoxParam,hInstance,DLG_MAIN,NULL,offset DialogMainProc,0

invoke ExitProcess,NULL

;********************************************************************

_Init proc

invoke _CenterWindow,hWinMain

invoke SendDlgItemMessage,hWinMain,ID_TEXT,EM_LIMITTEXT,512,NULL

invoke GetDlgItem,hWinMain,ID_RUN

invoke EnableWindow,eax,FALSE

ret

_Init endp

;********************************************************************

; 根据 text control 中有无字符决定是否将“执行”按钮 Disable 掉

;********************************************************************

_CheckText proc

invoke GetDlgItemText,hWinMain,ID_TEXT,addr szBuffer,512

invoke lstrlen,addr szBuffer

.if eax != 0 || (dwFlag & F_RUNNING)

invoke GetDlgItem,hWinMain,ID_RUN

invoke EnableWindow,eax,TRUE

.else

invoke GetDlgItem,hWinMain,ID_RUN

invoke EnableWindow,eax,FALSE

.endif

ret

_CheckText endp

;********************************************************************

_BrowseFile proc

mov stOpenFileName.Flags,OFN_PATHMUSTEXIST or OFN_FILEMUSTEXIST

mov stOpenFileName.lStructSize,SIZEOF stOpenFileName

mov eax,hWinMain

mov stOpenFileName.hwndOwner,eax

mov stOpenFileName.lpstrFilter,offset szFilter ;扩展名

mov stOpenFileName.lpstrFile,offset szBuffer ;文件名缓冲

mov stOpenFileName.nMaxFile,512 ;文件名缓冲长度

mov stOpenFileName.lpstrInitialDir,0

mov stOpenFileName.lpstrTitle,offset szTitleOpen

mov stOpenFileName.lpstrDefExt,offset szExt

invoke GetOpenFileName,offset stOpenFileName

.if eax == FALSE

ret

.endif

invoke SetDlgItemText,hWinMain,ID_TEXT,addr szBuffer

ret

_BrowseFile endp

;********************************************************************

end start

程序的分析和要点

本程序在使用调用 GetOpenFileName 或者自己在文本框中输入执行文件名,然后通过 CreateProcess 建立进程,最后用 WaitForSingleObject 等待进程结束,如果在对话框的处理过程中等待会导致程序在进程返回前无法响应,所以程序中用 CreateThread 建立一个线程来实现这个过程,当子过程返回的时候,线程结束。dwFlag 中的 0 位作为标志位,表示是否子过程在运行中,如果这一位置 1 的话,按下“终止”按钮会用 TerminateProcess 来强制终止子进程。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有