首页 > 代码库 > Windows核心编程笔记(2)

Windows核心编程笔记(2)

6 进程实例句柄

6.1 每一个EXE或者DLL被加载到内存中后,都会被赋予一个独一无二的句柄(HINSTANCE),该句柄在WinMain函数调用时传入。获取应用程序相关信息(资源、路径)时,有的需要传入HINSTANC有的需要传入HMODULE,实际上HINSTANC与HMODULE完全是一回事,这是16位Windows系统上不同数据类型造成的。
WinMain函数的第一个参数:实例句柄是如何传递进来的呢?查看crtexe.c源码,我们会看到如下代码

	#ifdef WPRFLAG
            mainret = wWinMain(
#else  /* WPRFLAG */
            mainret = WinMain(
#endif  /* WPRFLAG */
                       (HINSTANCE)&__ImageBase,
                       NULL,
                       lpszCommandLine,
                       StartupInfo.dwFlags & STARTF_USESHOWWINDOW
                        ? StartupInfo.wShowWindow
                        : SW_SHOWDEFAULT
                      );
#else  /* _WINMAIN_ */


Crt在这里调用我们的WinMain函数,传入的实例句柄是:__ImageBase的地址,转到其定义位置
extern "C" IMAGE_DOS_HEADER __ImageBase;
实际上实例句柄就是这个PE文件加载到内存后的DOS头的地址,CRT源码都是可见的,在VS安装路径下VC\crt\src\大家可以看下。
6.2 GetModuleHandle(PCTSTR pszModule)的两大注意点:
1、该API只检查主调用进程的地址空间,如果pszModule没有被主进程加载,即使其他进程加载了pszModule也会调用失败,返回NULL;
2、在进程的DLL中调用该函数,返回的HMODULE是该EXE的内存基地址而非该DLL的内存基地址。

7 终止进程

四种方式:
1、主进程入口函数返回(推荐方式、最佳方式);
2、进程中一个线程调用ExitProcess;
3、其他进程调用TerminateProcess;
4、进程中所有线程都自然死亡(几乎不可能发生)。
7.1 主进程入口函数返回,进程终止过程
但主进程WinMain函数返回后,会回到C运行库启动代码,然后正确清理进程使用的所有C运行时资源。释放完这些资源后,C运行时启动代码将显示调用ExitProcess,并将进程的WinMain函数返回值传给它。于是,所有进程中运行的其他进程都会终止。
任何时候都不应该显示调用ExitProcess,否则很有可能导致自定义的C++对象得不到正确的释放。
7.2 TerminateProcess终止进程
1、只有在无法通过其他方法终止进程时,才应使用该函数;
2、被终止的进程无法知道自己将要被终止,终止后虽然进程没有机会自己执行清理工作,但是系统会在进程终止后进行彻底得清理;
3、TerminateProcess函数是异步的,函数返回后并不表示进程已经终止,可以通过WaitForSingleObject来等待判断。
7.3 进程终止运行时,执行的步骤
1、终止进程中遗留的任何线程;
2、释放进程分配的所有用户对象和GDI对象,关闭所有的内核对象,若内核对象引用计数为0则销毁;
3、进程的退出码从STILL_ACTIVE变为传给ExitProcess或者TerminateProcess的参数;
4、进程的内核对象状态变为已触发状态;
5、进程的内核对象引用计数减一,引用计数为0,则销毁内核对象。

8 进程提权

8.1 Windows只允许在进程边界上进行权限提升,一旦进程启动后,再要求更多的权限已经太迟了。一个未提升权限的进程可以生成另一个提升了权限的进程,后者将包含一个COM服务器,这个新进程将保持活跃状态。这样,未提升权限的进程就可以向已提升权限的进程发送IPC(Inter-Process Communication)调用,而不必为了提升权限再开一个新实例然后终止自己。
8.2 手动提权方式

ShellExecuteEx函数,SHELLEXECUTEINFO 结构中lpVerb指定为"runas",同时在lpFile指定一个拥有权限的可执行文件路径。如果用户拒绝提升权限,返回FALSE,GetLastError()返回ERROR_CANCELLED。进程使用提升后的权限运行时,其所创建的所有子进程都会具有相同权限,无需再用ShellExecuteEx提权。


未完待续。

Windows核心编程笔记(2)