Windows核心编程【4】小结

Windows核心编程【20】小结 第20章 DLL高级技术 一、DLL模块的显示载入和符号链接 在任何时候,进程中的一个线程可以调用下面两个函数来将一个DLL映射到进程的地址空间中: HMODULE LoadLibrary(PCTSTR pszDLLPathName); HMODULE LoadLibraryEx(PCTSTR pszDLLPathName, HANDLE hFile, DWORD dwFlags) 阅读详情

第四章进程
 
一、基本知识

1、  进程的定义,一个正在运行的程序的一个实例。由两部分组成,内核对象(系统保存进程统计信息的地方,用来管理进程)和地址空间(进程的所有执行体、数据段、堆栈等)。

2、  Windows有2大类应用程序。CUI(控制台用户界面)和GUI(图形用户界面),划分界限模糊。其中,关联到了VS集成环境链接器的各种开关。

3、  启动函数在进行一系列初始化(获取新进程的完整命令行的指针、环境变量指针、初始化C/C++运行库的全局变量、C运行库内存分配函数malloc和calloc及其他低级I/O历程使用的堆、调用全局和静态C++类对象的构造函数)后进入入口函数。

4、  进程实例句柄,独一无二。HMODULE和HINSTANCE是一回事吧,16位Windows除外。相关的函数就有HMOUDULEGetModuleHandle(PCTSTR pszModule),参数为NULL则是主调进程的(在DLL中调用的话,既是调用DLL的进程)可执行文件的基地址(HINSTANCE)。

5、  进程的命令行,一个新进程在创建时,都会接收一个命令行。WinMain的pszCmdline相关(忽略了执行体文件的名称的)。GetCommandLine返回的是同一块命令行内存,一般用来只读。好习惯的话,应该创建个缓冲区来。

6、  进程的环境变量,每个进程都有这么个与之关联的环境块,是在进程地址空间内分配的一个内存块。可通过GetEnvironmentStrings函数来获取完整的环境块。格式就不多说了。释放环境变量应该用BOOL FreeEnvironmentStrings(PTSTR pszEnvironmentBlock)函数。(这样就可以不管它’\0’位置怎样了)        CUI程序还有专用的访问方法,通过main入口函数所接收的TCHAR* env[]参数来实现。env是一个字符串指针数组,每个指针都指向一个不同的环境变量(定义采用常规的“名称=值”的格式),NULL指针表示数组尾。

7、  用户登录Windows时,系统会创建shell进程。通过检查注册表中的两个项来获得初始的环境字符串。第一个项包含应用于系统的所有环境变量的列表:HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SessionManager\Environment第二个项包含应用于当前登录用户的所有环境变量的列表:HKEY_CURRENT_USER\Environment。

8、  通过修改注册表修改环境变量后,用户需要注销并重新登录才能生效。或者给其它主窗口发送WM_SETTINGCHANGE消息。SendMessage(HWND_BROADCAST, WM_SETTINGCHANGE, 0, (LPARAM)TEXT("Environment"))。

9、  子进程会继承父进程的环境变量,但会受到父进程的控制(访问权限)。不过,子进程的环境块和父进程的环境块不共享一块内存。既是子进程的环境变量改变不影响父进程。

10、             环境变量的其它相关操作:GetEnvironmentVariable,ExandEnvironmentStrings,SetEnvironmentVariable。

11、             进程的错误模式,SetErrorMode函数。

12、             进程当前所在的驱动器和目录,文件路径查找使用。该信息以进程为单位进行维护(GetCurrentDirectory、SetCurrentDirectory)。可以提供多个驱动器的当前目录。GetFullPathName获取当前完整目录。

13、             系统版本,暂时过滤……

 

二、CreatProcess函数

1、  一个线程调用CreatProcess时,系统将创建一个进程的内核对象,初始化计数器为1。然后为新进程创建一个虚拟地址空间,并将执行体文件(和所有必要DLL)的代码及数据加载到进程的地址空间。

2、  CreatProcess在进程完全初始化之前就返回TRUE了,这意味着操作系统的加载器尚未定位到所有必要的DLL。如果说有DLL找不到或者无法初始化,那么这个进程就会终止。

CreatProcess函数的原型如下:
BOOL WINAPI CreateProcess(

__in_opt     LPCTSTRlpApplicationName,

__inout_opt  LPTSTRlpCommandLine,

__in_opt     LPSECURITY_ATTRIBUTESlpProcessAttributes,

__in_opt     LPSECURITY_ATTRIBUTESlpThreadAttributes,

__in         BOOLbInheritHandles,

__in         DWORDdwCreationFlags,

__in_opt     LPVOIDlpEnvironment,

__in_opt     LPCTSTRlpCurrentDirectory,

__in         LPSTARTUPINFOlpStartupInfo,

__out        LPPROCESS_INFORMATIONlpProcessInformation

);

3、  参数lpApplicationName和lpCommandLine分别代表新进程所要使用的执行体文件名称,以及要传给新进程的命令行字符串。lpCommandLine是个LPSTR变量,也就是意味着需要一个非“常量字符串”。因为在CreatProcess内部会暂时地改变命令行字符串,所以不能为只读。否则会出错。所以需要先把常量字符串拷贝到一个临时缓冲区里。

4、  如果lpApplicationName参数为NULL的时候,可以使用lpCommandLine参数来指定一个完整的命令行,供CreateProcess创建新进程。CreateProcess解析lpCommandLine字符串时,会检查字符串中的第一个标记,如果是执行体文件的名称(无扩展名默认为exe),则为按照以下顺序搜索。a、主调用进程.exe文件所在的目录;b、住调用进程的当前目录;c、Windows系统目录,既是GetSystemDirectory返回的System32子文件夹;d、Windows目录;e、PATH环境变量中列出的目录。当然,如果命令行包含一个完整的路径的时候,就只会用该完整路径来查找执行体了。

5、  lpProcessAttributes、lpThreadAttributes和bInheritHandles参数,与新进程的内核对象操作权限有关。创建新的进程,系统必须创建一个进程内核对象和一个线程内核对象(用于进程的主线程)。一般设置前两个参数为NULL的话,系统会为这两个内核对象(进程内核对象和线程内核对象)指定默认的安全描述符。

6、  dwCreationFlags参数,标志了影响新进程创建方式的标志。多个标志可以用按位OR运算符来组合。同时,还允许指定一个优先级类。不过,书上说这样做没有多大必要,而且对于大多数应用程序,都不应该这样做,说是系统会为新进程分配一个默认的优先级类。

7、  lpEnvironment参数,指向一个内存块,该内存块包含新进程要使用的环境变量字符串。大多数时候为NULL,导致子进程继承父进程使用的环境变量。

8、  lpCurrentDirectory参数,允许父进程设置子进程的当前驱动和目录。如果为NULL,则子进程的工作目录与父进程的一样。该参数必须执行一个用0来终止的字符串,同时必须在路径中指定一个盘符(驱动器号)。

9、  lpStartupInfo参数,指向STARTUPINFO结构。然后就该学习这个结构了。Windows在创建新进程的时候使用这个结构的成员。大多数应用程序都希望生成的应用程序只是使用默认值。最起码要将此结构中的所有成员初始化为0,并将bd城花园设为此结构的大小(STARTUPINFO si = { sizeof(si) };)。如果没有把结构的内容清零,则成员将包含主调用线程的堆栈上的垃圾数据,可能会造成破坏。然后把就要结合刚刚的dwCreationFlags的标志了,既是是否允许使用STARTUPINFO的某些成员。

10、             关于STARTUPINFOEX的另外一个字段lpAttributeList,还需要再继续看看。

11、             lpProcessInformation参数,指向一个PROCESS_INFORMATION结构。就是用来保存新创建的进程的基本信息的结构吧。有hProcess、hThread、dwProcessId、dwThreadId。需要注意的都是ID的时效性,既是ID是随机分配的,一般不要使用ID,用内核对象或者窗口句柄等。

 

三、终止进程

1、  四种方式终止:a、主线程的入口函数返回(强烈推荐);b、进程中的一个线程调用ExitProcess函数(要避免这个方式);c、另一个进程中的线程调用TerminateProcess函数(要避免这种方式);d、进程中的所有线程都“自然死亡”(很难发生)。

2、  主线程的入口函数返回,可以保证主线程的所有资源都被正确清理。a、该线程创建的任何C++对象都将由这些对象的析构函数正确销毁;b、操作系统将正确释放线程堆栈使用的内存;c、系统将进程的退出代码(在进程内核对象中维护)设为我们的入口函数的返回值;d、系统会递减进程内核对象的使用计数。

3、  ExitProcess函数,进程中的其它任何线程都会随进程一起终止。Windows Platfrom SDK文档支出,一个进程在其所有线程都终止之后才会终止。从操作系统的角度出发,这种说法是正确的。但是C/C++运行时的启动代码确保了下面这一点:一旦你的应用程序的主线程从它的入口函数返回,那么不管当前在进程中是否正在运行其他线程,都会调用Exitprocess来终止进程。不过,如果在入口函数中调用ExitThread,而不是调用ExitProcess或者简单返回,应用程序的主线程将停止执行,但只要进程中还有其他线程正在运行,进程就不会终止。ExitProcess会造成进程“当场死亡”,C++对象不会被正确析构。

4、  TerminateProcess函数,任何线程都可以调用其来终止另一个进程或者它自己的进程。应该在无法通过其它方法来强制进程退出时使用。在这种情况下,进程无法将它再内存中的任何信息转存到磁盘上。因为没有被终止的通知。不过,操作系统会在进程终止之后彻底进行清理,确保不会泄露任何操作系统资源。但TerminateProcess是异步的,返回的时候不一定马上被杀死了,需要配合类似WaitForSingleObject(该进程对象变为signaled)的函数。

5、  GetExitProcess函数,可以用来获取已经死亡的一个进程的退出代码,需要句柄,既是在该进程死亡前,需要获得其句柄。任何时候都可以调用这个函数,如果进程没有终止,则是STILLZ_ACTIVE标志,如果终止了,则返回实际的而退出代码。

 

四、子进程

1、  单任务同步机制,共享数据方式(用于进程通信),内存映射文件是最方便的方式。

2、  运行分离的子进程,一旦进程创建并开始执行,父进程就不再与新进程通信,或者不用等他完成工作之后才继续自己的工作。Windows资源管理器就是这样工作的。方法:创建成功后关闭新的进程以及其主线程的句柄。

 

五、UAC(用户账号控制)

1、  安全令牌,每当有代码视图一个受保护的安全资源时,操作系统就会要求出示这个安全令牌。

2、  经过筛选的令牌,只授予标志用户的权限。权限受限的进程无法访问需要更高权限才能访问的安全资源。

3、  可以要求操作系统提升权限,但只能再进程边界上提升。默认情况下,一个进程启动时,它会与当前登录用户的筛选令牌关联起来。要为进程授予更多的权限,需要指示Windows做这样一件事情:在进程启动之前,友好地征求最终用户提权的同意。作为最终用户,可以通过以管理员身份运行来提权。

4、  系统程序,征求对话框是蓝色横幅;有签名的程序,征求对话框是灰色的横幅;没有签名的程序,对话框则是橙色的横幅。

5、  普通用户登录的话,就需要一个over-the-shoulder登录,既是需要输入管理员信息。

6、  Windows只运行在进程边界上进行提权。一旦进程启动,再要求更多的权限就已经迟了。不过,一个未提权的进程可以生成另一个提升了权限的进程,后者将包含一个COM服务器。

7、  自动提升进程的权限,应用程序的执行体中嵌入了一种特定的资源(RT_MAIFEST),系统就会检查<trustInfo>区域,并解析其内容。其中有level属性,可以用来设置需要的权限。更改后,需要注销登录。

8、  手动提升进程的权限,需要调用ShellExecuteExitProcess函数(BOOLShellExecuteEx(LPSHELLEXECUTEINFO pExecInfo);)。而SHELLEXECUTEINFO结构中唯一有趣的字段是lpVerb和lpFile。前者必须被设为“runas”,后者必须包含使用提升后的权限来启动的一个执行体文件的路径。如果用户拒绝提权,将返回FALSE,可以通过GetLastError来使用ERROR_CANCELLED值判断。当一个进程使用提升权后的权限启动时,它每次用CreatProcess来生成另一个进程时,子进程都会获得和它的父进程一样的提升后的权限。

9、  假如一个应用程序使用一个筛选后的令牌来运行的,那么一旦视图调用CreatProcess来生成一个要求提权的执行体,这个调用就会失败,GetLastError会返回ERROR_ELEVATION_REQUIRED。

10、             何为当前权限上下文,两个问题:如何判断应用程序是否以管理员身份运行;如何判断它是以提升的权限来启动的,还是正在使用筛选的令牌运行。函数GetProcessElevation(P106)能返回提升类型和一个指出是否正在以管理员身份运行的布尔值。

Windows核心编程【10】小结 第十章 同步设备I/O与异步设备I/O 1、本章介绍的技术可以用来设计高性能、伸缩性好、响应性好,而且健壮的应用。一个伸缩性好的应用程序在处理大量并发操作时和处理少数并发操作时同样高效。 2、在Windows应用程序中,线程是最好的工具,可以用来对工作进行划分。 3、通过I/O完成端口,可以让线程在读取设备和写入设备的时候不必等待设备的响应,从而显著地提高吞吐量。 4、I/O完成端口最初被 阅读详情

相关推荐

论文超详细精读|万字:2s-AGCN

1. 提出了一种新的双流自适应图卷积网络(2S-AGCN)用于基于骨架的动作识别。**模型中的图的拓扑既可以统一地学习,也可以通过BP算法以端到端的方式单独学习。** 2. 提出了一种同时对**一阶和二阶信息(骨架的长度与方向)建模的双流框架**,在识别精度上有了显著的提高。 它将骨架数据的图结构参数化,并嵌入到网络中,与模型共同学习和更新。 3. 文章主要创新点有两个,一个是双流网络,另外一个是自适应。

IanYue的博客 6341

管理员权限运行程序ShellExecuteex等待进程执行结束

不过,如果你确实需要以编程方式降低权限级别(尽管这通常不是一个推荐的做法,因为它可能导致权限不足的问题),你可能需要创建一个辅助进程,该进程以较低的权限级别运行,并通过某种形式的进程间通信(如命名管道、套接字或共享内存)与你的主应用程序通信。这通常意味着你需要以标准用户身份登录到 Windows,或者确保你的应用程序的快捷方式或启动配置没有设置为“以管理员身份运行”。相反,你应该设计你的应用程序以便它可以在标准用户权限下运行,或者提供适当的用户界面来提示用户以管理员身份运行特定的操作(如果确实需要)。

1151

cefshap(C#)定义浏览器的右键菜单

菜单效果:复制(自),搜索文本,打开链接,复制链接,刷新,检查,关于 public class MenuHandler : IContextMenuHandler { //public event Action<string> PopupRequest; void IContextMenuHandler.OnBeforeContextMenu(IWebBrowser browserControl, IBrows

无线智能模块 可视DIY智能专家 1658

C++设置系统时间的几种方式 Windows 11 C++设置系统时间需要管理员权限。判断是否为管理员并切换Run as administrator SYSTEMTIME时间+8小时变为本地时间同步

Windows 11中,使用C++设置系统时间需要管理员权限。设置系统时间涉及修改操作系统的关键参数,为了防止未经授权的修改,Windows要求进行这些操作的用户拥有管理员权限。在C++中,设置系统时间可以通过调用Windows API函数来实现。然而,在调用这个函数之前,必须确保程序以管理员身份运行,否则会失败并返回权限不足的错误。

chenhao0568的专栏 2245

Windows创建进程时指定父进程

通常情况下,在进程特别多的情况下使用ProcMon抓行为的时候都只是简单的看一下该进程的进程树,不会去注意系统进程创建的进程,这里就有了一个想法,可不可以在创建的时候指定父进程,之后在网上找了份代码,也没改直接拿来测试下,发现在提权之后是可以指定父进程为session 0的进程 #include<windows.h> #include<stdio.h> BOOL ...

被遗弃的庸才博客 2040

创建进程时指定其父进程

记录一下,以免忘记。 uses Windows, PsAPI, SysUtils; const SE_SECURITY_NAME = 'SeSecurityPrivilege'; PROC_THREAD_ATTRIBUTE_PARENT_PROCESS = $00020000; EXTENDED_STARTUPINFO_PRESENT

dbyoung的Delphi专栏 4747

创建进程置新进程的父进程为指定进程 附 一个提权函数 一个进程名寻进程ID函数

#include #include #include #include BOOL EnablePrivilege( LPCTSTR name ) {//提升进程权限 BOOL bRet=FALSE; //获得指定的权限值 TOKEN_PRIVILEGES priv = { 1, { 0, 0, SE_PRIVILEGE_ENABLED } }; BOOL bLookup = LookupPrivilegeValue( NULL, name,

whitehack的专栏 5405

学习《windows核心编程小结

这三周里基本上每天都有4~6小时学习windows核心编程这本上书,就这个系列学习过程,小结一下情况。因为之前的工作内容有多线程相关内容,并且那个时候参考《windows多线程程序设计》已经作了系统的学习,这里就没提那方面的内容;内存映射文件在以前解析数据文件的时候使用过,虽然没有进行过系统学习,翻看了一下应该不是太大的问题;动态连接库已经经过系统的学习,PE文件结构也比较清楚了。至于堆的内容,需

行者无疆的专栏 1862

Windows核心编程【9】小结

第九章 用内核对象进行线程同步 1、在用户模式下进行线程同步的最大好处就是速度非常快。如果关心应用程序的兴宁,那么应该先看看用户模式下的同步机制能否适用。 2、但是用户模式下的同步机制存在一些局限性。例如,对Interlocked系列函数只能对一个值进行操作,它们从来不会把线程切换到等待状态。我们可以用关键段来把线程切换到等待状态,但是它们只能用来对同一个进程中的线程进行同步。此外,在

BetaBin 2804

Windows核心编程【22】小结

第22章 DLL注入和API拦截 在Windows中,每个进程都有自己私有的地址空间。独立的地址空间对开发人员和用户都是非常有利的。对开发人员来说,系统更有可能捕获错误的内存读/写。对用户来说,OS变得更加健壮,因为一个应用程序的错误不会导致其他应用程序或OS崩溃。 APP需要跨越进程边界来访问另一个进程的地址空间的情况如下: 1、想要从另一个进程创建的窗口派生子类窗口。

BetaBin 1938

Windows核心编程【6】小结

第六章 线程基础 1、每个进程至少都有一个线程。 2、线程的两个组件:一个是线程的内核对象,操作系统用它管理线程;另一个是线程堆栈,用于维护线程执行时所需的所有函数参数和局部变量。 3、进程是有惰性的,它从来不执行任何东西,只是一个线程的容器。 4、线程只有一个内核对象和一个堆栈,几乎不涉及记录活动,不需要占用多少内存。 一、何时创建线程 1、线程描述了进程内部的一个执行路

BetaBin 1631

Windows核心编程【2】小结

第二章 字符和字符串处理 一、字符编码 1、常规C、C++语言学习中习惯单字节(8个bits,256个字符)ANSI字符编码。 2、双字节字符集(double-byte character,DBCS),一个字符串中的每个字符都由1个或2个字节组成。以日本汉字为例,如果第一个字符在0x81到0x9f之间,或者在0xe0到0xfc之间,就必须检查下一个字节,才能判断出一个完整的汉字。这样

BetaBin 1331

Windows核心编程【1】小结

第一章 错误处理 1、调用Windows函数时,它会先验证你传给它的参数,然后再开始执行任务。如果传入的参数无效,或者由于其他原因导致操作无法执行,则函数的返回值将支出函数在某个方面失败了。 2、每种错误都有三种表示:一个消息ID(一个可在源代码中使用的宏,用于与GetLastError的返回值进行比较)、消息文本(描述错误的英文文本)和一个编号(应该避免使用此编号,尽量使用消

BetaBin 1340

window核心编程小结

1.C r e a t e T h r e a d函数是用来创建线程的Wi n d o w s函数。不过,如果你正在编写C / C + +代码,决不应该调用C r e a t e T h r e a d。相反,应该使用Visual C++运行期库函数_ b e g i n t h r e a d e x.原因比较简单,操作系统并不知道每种语言对堆栈空间的管理,调用CPP的_ b e g i n t

游戏人生的专栏 3613

windows中使用Createprocess创建进程和创建注册表

Createprocess CreateProcess用来创建一个新的进程和它的主线程,这个新进程运行指定的可执行文件(相当于打开一个已经存在的父进程) 语法 创建进程 //基本语法 //注意如果第一第二个参数都不为空的话,那创建进程会以第一个为准,而第二个只会当前命令行参数 BOOL CreateProcess( LPCTSTR lpApplicationName, ...

qq_35426012的博客 870

VC++ 利用 ShellExecuteEx 函数运行进程,并等待该进程退出返回。

returnCode 为运行进程退出返回的错误代码,通常进程返回:0。filePath 为运行的EXE(可执行文件)路径。arguments 为运行使用的CLI命令行接口参数。runas 为是否以管理员身份运行。

liulilittle的博客 328

windows学习进程创建过程 3

Windows程序当中,每一个进程对象都有4G的虚拟内存。当一个可执行文件在内存中被创建进程时,设定用户空间为2G,内存分布如下: 共享的内核分区是由所有的进程对象共同享用的。 进程的创建过程:当用户双击运行一个可执行文件对象的时候,操作系统就会通过调用explorer.exe进程对象来为当前的可执行程序创建一个新的进程对象。Explorer.exe进程对象将会调用CreateProcess()函数对象来实现进程对象的创建操作。 (1)映射exe文件:当双击运行一个可执行文件时,开辟一块用户独享的.

青之羽 327

[笔记]Windows核心编程《番外篇》几种常见的执行命令行方法

文章目录C++ 控制台执行Windows命令行WinExecCreateProcessSystemShellExecute区别 C++ 控制台执行Windows命令行 WinExec CreateProcess System ShellExecute 区别 c++ system()和WinExec()的区别 https://blog.csdn.net/qq_26591517/article/details/80513985 winExec是不同步的进程调用,就是调用起来了就返回了,不会等调用起来的程序结束

二次元怪兽的博客 3297

windows核心编程--4、线程和线程同步

一、前言     该系列前几篇:         windows核心编程–1、使用vs2019编写第一个win32项目         windows核心编程–2、windows的画笔画刷以及一些简单的应用         windows核心编程–3、有关进程的三个函数 二、相关工具     IDE:Visual Studio 2019 三、相关概念     1、在win32程序中,我们创建一个线程主要是使用CreateThread函数,该函数一共有6个参数,第一个参数lpThreadAttribute

windy_ll的博客 342

基于52单片机土壤干湿度检测自动浇花系统(包含原理图源程序论文等)

基于52单片机土壤干湿度检测自动浇花系统,包含原理图源程序论文等文件

上一篇: AVL树实现类——二叉链表实现
下一篇: ClamAV学习【1】——ClamAV流程
BetaBin
博客等级 码龄15年 155粉丝 121原创
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值