月初的时候,接受到某公司的面试,不过大多数题目都是根据我项目来问的,所以仅供参考。
下面只是一部分题目。
1. 如何判断用户层的地址是否有效?内核层的呢?
使用ProbeForRead
在wdk中我们可以看到它是这样的。
1 | void ProbeForRead( |
可以看到,他首先是对Alignment进行了判断,也就是指定用户模式缓冲区开头所需的对齐方式一定是1、2、4、8、16,否则的话直接退出了。
接着就判断Length长度是否为0,不为0的话判断一下这个Address地址是否按照Alignment指定字节数对齐,如果没有对齐的话,则会抛出异常。
msdn上是这么说的:
如果地址范围的开头未与Alignment指定的字节边界对齐,则ProbeForRead会引发STATUS_DATATYPE_MISALIGNMENT异常
接着判断一下这个地址是否在用户态范围内。
msdn上是这么说的:
如果指定的内存范围不在用户模式地址范围内,ProbeForRead会引发STATUS_ACCESS_VIOLATION异常。
因此我们使用这个ProbeForRead的时候需要在try/except内,方便接收异常。
在msdn上还有这样的一段话:
不要在内核模式地址上使用此例程;它将引发异常。
如果Irp-> RequestorMode = KernelMode,则Irp-> AssociatedIrp.SystemBuffer和Irp-> UserBuffer字段不包含用户模式地址,并且调用ProbeForRead以探查由任一字段指向的缓冲区将引发异常。
因此它并不能检测内核层的地址是否有效。
而内核层的话,我们应该使用这个MmIsAddressValid
。
实际上它又调用了MiIsAddressValid (VirtualAddress, FALSE);
MiIsAddressValid 如下:
1 | { |
也就是检查了是否在物理寻址范围内和利用了分页机制去查询。
msdn上提到:
如果在给定的虚拟地址上进行读取或写入操作不会发生页面错误,则MmIsAddressValid返回TRUE。
但是也提到了这一点:
即使MmIsAddressValid返回TRUE,访问该地址也可能导致页面错误,除非内存已被锁定或该地址是有效的非页面缓冲池地址。
对于这一点,我也没找到方法,引用看雪上qihoocom的一句话
没有100% OK的方法。
不过调用这个函数的话就不需要使用try/except来接收异常了
2. tf标志位的作用是什么
当软件断点被命中的时候,这个程序的控制就交到用户手上了。而程序还没执行指令,所以我们设置tf标志位后,程序会在那一瞬间单步步入一下。并且将这个控制权立即返回给用户。
3. 附加进程的那个api有没有研究过
DebugActiveProcess
这里有一篇文章说的挺好的,可以参考一下这个。
https://www.cnblogs.com/zibility/p/5683280.html
4. 内存释放的原理
参考https://www.cnblogs.com/kex1n/archive/2011/01/26/2286427.html
使用SetProcessWorkingSetSize。
msdn上说
使用这个函数来设置应用程序最小和最大的运行空间,只会保留需要的内存。当应用程序被闲置或系统内存太低时,操作系统会自动调用这个机制来设置应用程序的内存。应用程序也可以使用 VirtualLock 来锁住一定范围的内存不被系统释放。
当你加大运行空间给应用程序,你能够得到的物理内存取决于系统,这会造成其他应用程序降低性能或系统总体降低性能,这也可能导致请求物理内存的操作失败,例如:建立 进程,线程,内核池,就必须小心的使用该函数。
事实上,这并不会提高什么性能,也不会真的节省内存。只是暂时的将应用程序占用的内存移至虚拟内存,一旦应用程序被级货或者有操作请求,这些内存会被重新占用。如果你用着方法来设置程序占用的内存,反而可能会降低系统性能,因为这个系统需要频繁的进行内存和硬盘间的页面交换。
5. 栈在应用层和内核层最大大小
Windows:
应用栈:默认1M,编译指令/stack可改设其他值
内核栈:系统根据CPU架构而定,x86系统上为12KB,x64系统上为24KB,安腾系统上为32KB
6. pae模式下最大范围 存在意义
最大支持64G
32位的虚拟地址(线性地址)则没有变,所以一般的应用软件可以继续使用地址为32位的指令;如果用平面内存模式的话,这些软件的地址空间也被限制为4GiB。操作系统用页表将这4GiB的地址空间映射到大小为64GiB的实体内存,而这个映射对各个进程一般是不一样的。这样一来,即使不能为单单一个程序所用,那些增加了的物理内存仍然可以发挥作用。