我们在使用Inline Hook技术时,如果你的系统环境是多核时就可能会出现一些情况导致系统蓝屏,如果要了解这个原因,我们就需要了解多核同步。
临界区
并发与同步
在了解临界区之前我们需要补充一些前置知识,以此作为铺垫再进行学习。我们需要了解并发与同步的概念:并发是指多个线程同时执行,在单核的情况下并不是真正的同时执行而是分时执行,多核的情况下就可以在某一个时刻同时多个线程执行。同步则是保证在并发执行的环境中各个线程可以有序的执行,无论是单核或多核的环境。
单行指令同步
如下所示代码,有一个全局变量dwVal,在线程中执行的代码是对dwVal的自增:
DWORD dwVal =
0
;
// 全局变量
// 线程执行的代码
dwVal++;
以C++的角度来看,上面的代码dwVal的自增只有一行指令,所以多个线程去调用不会存在问题,但实际并不是这样的,因为程序的执行是以汇编指令出发的,自增的汇编代码如下:
mov eax, [
0x12345678
]
add eax,
1
mov [
0x12345678
], eax
所以我们试想一下当A线程去执行自增代码时,走到了ADD指令,这时候发生了线程的切换,B线程执行完自增代码,此时dwVal的值就是1,线程在切换回A,A线程将值填过去,dwVal的值仍然是1,但从代码实现的本意上来看,自增执行了两次那dwVal的值就应该是2。
既然单行代码会存在问题,那么我们尝试将其变成单行汇编指令是否就可以避免这个问题呢?如下汇编所示:
INC DWORD PTR DS:[
0x12345678
]
这条汇编指令只有一行,即使出现线程切换也不会造成上述的情况,但也不能完全避免。因为在单核的情况下是分时执行,所以这条指令是没问题的,但是在多核的情况下可以在某一个时刻同时多个线程执行,因此也会出现不同线程同时执行这条指令的情况,也会产生上述的问题。
我们想要真正的解决这类问题,就需要使用LOCK指令,如下所示:
LOCK INC DWORD PTR DS:[
0x12345678
]
从LOCK指令字面意思来看,我们就知道它是一个锁,它锁的不是CPU而是内存,可以锁定当前指令执行时线程所访问的内存。如上所示代码执行时,会对0x12345678地址处的值进行修改,在LOCK指令的限制下,其它线程是不能访问