记录

二维数组的指针形式

Array[2][3]:

1> *(*(Array + i) + j)

2> *(Array + i * 行长 + j)

详见《C专家编程》

=========================分割线============================

const的后面如果紧随着一个类型说明符,const作用于类型说明符 其他情况下,const作用于它左边紧邻的指针的*号 《C专家编程》P64

=========================分割线============================

互斥对象内部包含有一个线程ID,调用ReleaseMutex时会检查线程ID是否和当前的线程ID相符,不符会返回失败,如果主线程拥有互斥对象,在别的线程中调用ReleaseMutex会失败的,因为线程ID不符,所以互斥对象需要谁拥有谁释放,参考孙鑫VC视频第15课,时间:63:20 <windows核心编程>P255

=========================分割线============================

new 只要你系统的内存还够用,都是在内存里的,不够的话 依标准会抛异常
操作系统如果发现物理内存不够用,会将部分内存调到硬盘上,使用的时候再调回来(换页) virtualalloc 分配的则统统先保存到硬盘上,使用的时候调入内存

<Windows核心编程>P362

=========================分割线============================

使用通用打开对话框打开文件时,会改变当前目录,变为被打开文件的那个目录

=========================分割线============================

关于<Windows核心编程>第19章的P539的死锁问题,根据http://blog.csdn.net/breaksoftware/article/details/8159088所介绍, 线程调用大概是这样的:LdrpInitialize -->LdrpInitializeThread  -->LdrpCallInitRoutine,进而调用DllMain 在LdrpInitialize中进入关键段,也就是书中所说的每个进程的锁,LdrpInitializeThread在关键段中包括着,至于调不调用DisableThreadLibCalls是管不着这个关键段的,也就说调用了它,只不过是不掉用DllMain了,但是任然还是会运行LdrpInitializeThread的,但这个函数被包含在关键段中~当前线程获得这个关键段,然后在DllMain中创建线程,然后根据书中所说,新线程会获得锁,但此时当前线程还在关键段中(因为有WaigForSingleObject),所以新线程还是会被关键段给阻塞等待,死锁依然存在~

=========================分割线============================

休眠挂起睡眠阻塞,似乎是我们一开始学习linux最郁闷的四个概念。

其实简单地解释应该是这样:

阻塞操作是指在执行设备操作的时候若不能获得资源将挂起进程,直到满足该操作的条件后再进行操作。被挂起的进程进入休眠状态,被从调度器的运行队列移走,直到等到的条件被满足。

因为阻塞的进程会进入休眠状态,因此,必须确保有一个地方能够唤醒休眠的进程,唤醒进程的地方最大可能发生在中断里面,因为硬件资源的获得的同时往往伴随着一个终端。

所以,阻塞是一种统称,而挂起是它的具体行为,休眠是一种状态。

至于睡眠,在调度制度里,睡眠是指被放在等待队列里的进程的状态。

 

操作系统中睡眠、阻塞、挂起的区别形象解释 首先这些术语都是对于线程来说的。对线程的控制就好比你控制了一个雇工为你干活。你对雇工的控制是通过编程来实现的。
挂起线程的意思就是你对主动对雇工说:“你睡觉去吧,用着你的时候我主动去叫你,然后接着干活”。
使线程睡眠的意思就是你主动对雇工说:“你睡觉去吧,某时某刻过来报到,然后接着干活”。
线程阻塞的意思就是,你突然发现,你的雇工不知道在什么时候没经过你允许,自己睡觉呢,但是你不能怪雇工,肯定你这个雇主没注意,本来你让雇工扫地,结果扫帚被偷了或被邻居家借去了,你又没让雇工继续干别的活,他就只好睡觉了。至于扫帚回来后,雇工会不会知道,会不会继续干活,你不用担心,雇工一旦发现扫帚回来了,他就会自己去干活的。因为雇工受过良好的培训。这个培训机构就是操作系统

=========================分割线============================

记一下关于SEH全局展开,只有在EXCEPTION_EXECUTE_HANDLER时才进行全局展开,全局展开时,如果异常发生在__try __finally块中,先找到能够处理这个异常的__except,但不执行异常处理代码,然后如果异常过滤值是EXCEPTION_EXECUTE_HANDLER,进行全局展开,首先执行最内层的__finally,然后执行刚刚找到的能够处理这个异常的__except,具体详情查看<Windows核心编程>第24章的全局展开,<Windows核心编程>第24章,P647,全局展开这节的最后一段,<Windows核心编程>第25章25.4节第一段

ps: 如果在__finally的异常处理程序中再次发生异常,将不会执行产生异常的指令后面的指令,如果在__except的异常处理块中发生异常,同样不会执行产生异常的指令后面的指令,而是寻找上一个匹配的__except。如果是异常过滤程序中发生异常,调试时貌似会出现死循环,貌似是如果异常过滤程序发生异常,这个__except会捕获,捕获再进入异常过滤程序,然后再发异常,__except再捕获……

 

 1 void foo()  
 2 {  
 3     __try   
 4     {  
 5         int v = 0;  
 6         int n = 5 / v;  
 7     }  
 8     __finally  
 9     {       // 如果__finally里发生一个异常,则异常指令后的指令将不会执行 
10               // 先执行foo的finally和func的finally的原因就是发生了异常
11               // 需要执行test中的异常处理代码块,跳出了finally的try的代码块
12               // 所以要执行finally 
13         MessageBox(NULL, L"finally2", NULL, 0);           
14     }                                                       
15 }  
16 void func()  
17 {  
18     __try   
19     {  
20         foo();  
21     }  
22     __finally  
23     {  
24         MessageBox(NULL, L"finally1", NULL, 0);  
25     }  
26 }  
27   
28 void test()  
29 {  
30     __try   
31     {  
32         func();  
33     }  
34     __except (EXCEPTION_EXECUTE_HANDLER)  
35     {       // 如果这里产生一个异常,将不会执行产生异常的指令的后面的指令
36               // 继续寻找上一个__except  
37         MessageBox(NULL, L"except2", NULL, 0);  
38     }  
39 }  
40   
41 int _tmain(int argc, _TCHAR* argv[])  
42 {  
43     __try   
44     {  
45         test();  
46     }  
47     __except (EXCEPTION_EXECUTE_HANDLER)  
48     {  
49         MessageBox(NULL, L"except1", NULL, 0);  
50     }  
51     return 0;  
52 }  
53   
54 执行结果:  
55 finally2  
56 finally1  
57 except2  
58 ============================  
59 void foo()  
60 {  
61     __try  
62     {  
63         *(PBYTE)NULL = 0;  
64     }  
65     __except (EXCEPTION_EXECUTE_HANDLER)      
66                // 如果是这样的,应为执行异常处理程序不用跳出finally的try
67                // 所以先执行except后执行finally  
68     {     
69   
70                 MessageBox(NULL, TEXT("except"), NULL, MB_OK);  
71     }  
72 }  
73   
74 void test()  
75 {  
76     __try  
77     {  
78         foo();  
79     }  
80     __finally  
81     {  
82         MessageBox(NULL, TEXT("finally"), NULL, MB_OK);  
83     }  
84 }
View Code

 

=========================分割线============================

TrackPopupMenu函数是同步的,也就是说弹出菜单后,不选择是不会返回的,必须等到菜单弹出后,然后选择了菜单,如果这个菜单的功能也是同步的,必须等到这个菜单处理完,比如弹出一个对话框,等这个对话框关闭了,这个函数才返回.

=========================分割线============================

关于LoadMenu和GetMenu返回的句柄之所以不同,是因为GetMenu返回的是当前窗口已加载的菜单的句柄,而LoadMenu则是新加载一个菜单资源,然后返回其句柄

ps:SetMenu可以把LoadMenu新加载的菜单资源设置为当前菜单

=========================分割线============================

关于CreateFileMapping:

关于使用CreateFileMapping把PE文件映射到进程地址空间中的问题

用CreateFileMapping为一个PE文件创建内存映射并且第三个参数包含SEC_IMAGE标志时,映射后的内存文件会按内存粒度和节中指定的VA对齐~ 此时内存中的布局和磁盘上的通常不一样,因为一般情况下内存对齐粒度比磁盘对齐粒度大~

=========================分割线============================

MEMORY_BASIC_INFORMATION结构一些成员备忘 BaseAddress >> 块(一些具有相同保护属性连续的页面)的起始地址, 将指定地址向下取整到页面大小.(同<Windows内核情景分析P54的区块>) AllocationBase >> 当前内存区域的起始地址, 一个内存区域可以包含多个块, 该区域包含指定地址, 就一个模块而言, 这个地址是模块的基地址. 指定地址为MEM_FREE状态时,此成员为0.(同<Windows内核情景分析P54的区间>) RegionSize >> 当前块的长度

=========================分割线============================

关于MmCreateHyperspaceMapping的一些理解备忘:

在MmCopyMmInfo中, 本进程页目录的HYPERSPACE目录项被赋值为一个物理页号pfn[1], 可以理解为一个页表4kb, 1024个表项. MmCreateHyperspaceMapping将指定的物理页映射到自己的一个空白表项, 然后返回该表项的地址. 返回时Hyperspace基地址 + i * PAGE_SIZE是为了形成地址, Hyperspace是形成页目录号, i * PAGE_SIZE是形成页表号(页表号和页表号之间间隔4096字节, 因为访问偏移超过1页(4kb)才会换页),  下面用MmGetPageTableForProcess中创建指定进程页目录的临时映射为例, 假如, Hyperspace的基地址为0xc0400000, 空白项的索引为1, 返回0xc0401000, 也就PageDir的值, 设PdeOffset为2, 当执行PageDir[PdeOffset](展开为*(0xc0401000 + 8))时, 将地址0xc0401008分为页目录号, 页表号和偏移3部分, 用页目录号从当前进程的页目录中获取Hyperspace的物理地址, 用页表号在Hyperspace中就可以获得MmCreateHyperspaceMapping中保存的目标进程的页目录的PTE(物理地址)了,  然后用偏移加上目标进程页目录的物理地址, 即可获得指定的PDE:

=========================分割线============================

查找窗口的WndProc(如果本地调试时无法查看win32k的符号, .reload下):

参考, ValidateHwnd反汇编, win32子系统之三:ValidateHwnd函数分析

具体原理: (win32k!gSharedInfo(win32k!tagSHAREDINFO)+0x08) * LOWORD(hwnd) + win32k!gSharedInfo+0x04获得一个win32k!_HANDLEENTRY结构指针,该结构的第一个成员phead是结构win32k!tagWND结构的地址, 该结构0x60处为lpWndProc

=========================分割线============================

编译在别的进程中运行的shellcode时要注意的的编译选项:

增量链接: 启用后调用函数会先到一个jmp, 然后再jmp到真实函数

基本运行时检查: 启用会生成ChkEsp

缓冲区安全检查: 启用会在函数头生成安全 cookie相关代码

posted @ 2015-01-29 10:13  Acg!Check  阅读(266)  评论(0)    收藏  举报