因为在多核处理器上,由于有多个逻辑0?1而仏1和提升^01到015?八1^0^¥£都只是 针对当前CPU的,所以无法阻止其他逻辑CPU的线程切换。 对于普通的11001如果只要修改4个字节,如5501^0呢或者搜索目标函数中call指令, 修改之后的4字节来实现跳转,可以用1001^ mov [target],xxx指令来实现多核CPU的安全 H00K。对于多核⑶仏单个逻辑⑶饥司的中断肯定是发生在指令与指令间,但是CPU与CPU之 间的中断未必发生在指令间。由于所有的逻辑CPU都是通过内存总线来访问内存,所以加入 10“前缀可以锁住内存总线来防止数据写入前其他0?诉方问该内存。 但是如果超过4字节,例如我要patch 100多个字节,那该怎么办呢?我们知道,*PATCH内存完成前,只要其他线程不访问该内存就没事。所以,我们可以让其他所有逻辑CPU—直 执行我们的代码(即不发生线程切换),直到口&1吐内存完成。可以通过0?以异步执行过程) 和自旋锁结合来实现CPU的空转。 DPCgfi1JfDISPATH_LEAVE±,所以cpu在执行时,不会发生线程切换,而且cpu又是与处理器相关而不是线程,而自旋锁在获锁期间会一直空转来检测锁,所以完全符合我们的要求。 通过具体代码讲解,获取所有cpu可以通过kequeryactiveprocessors来实现,该函数返回一个ulong的数,每个位对应一cpu,如0XF表示有4个逻辑CPU (二进制是1111b)。 [code] NTSTATUS DriverEntry(PDRIVER_OBJECT driver, PUNICODE_STRING regpath) ULONG currentnumber; KAFFINITY activeprocessors, currentprocessor; KIRQL oldirql; dr i ver->Dr i verUn1oad=UnLoad; KeInitializeSpinLock(&spinlock); //初始化一个自旋锁 oldirql=KeRaiseIrqlToDpcLevel (); //提升至dispath_leave i=0; activeprocessors=KeQueryActiveProcessors (); //获取所有逻辑CPU对应的位图 currentnumber=KeGetCurrentProcessorNumber (); //获取当前CPU编号 for(currentprocessor=1;activeprocessors;currentprocessor<<=l, i++) { //对于其他0?仄我们插入0?0时候执行的例程是脚%肋11^,而对于当前0卩1 插入0?0执打的例程是从7%(^例程。 if((currentprocessor & activeprocessors)) { activeprocessors&=^currentprocessor; if(currentnumber!=i) { if(!NT_SUCCESS(InsertDpcForNumber(MyRoutine, i))) KeLowerIrql(oldirql); return STATUS_SUCCESS; else { if(!NT_SUCCESS(InsertDpcForNumber(MyHook, i))) { KeLowerIrql(oldirql); return STATUS_SUCCESS; KeLowerIrql(oldirql); DbgPrint(^driver is load\n〃); return STATUS_SUCCESS; 上述代码就是枚举cpu,并且分情况插入不同的dpc对象。再来看看InsertDpcForNumber 的代码: [code] NTSTATUS InsertDpcForNumber(PKDEFERRED_ROUTINE comroutine, ULONG number) { dpc[number]=ExAllocatePool(NonPagedPool, sizeof(KDPC)); if (dpc [number]=0) return STATUS_UNSUCCESSFUL; //tl^itWC,仏11^忖&1乜60口0这个函数在初始化0?0对象时候,除了执行例程和参数外其 他都采用默认数据,@以还要调用仏861^&1861?100688(^^^0来设置0?0对象的^1加^62:域,该 域表示本DPC将要插入到哪个逻辑CPU的KPRCB中。即哪个逻辑CPU会投递该DPCo KeInitializeDpc(dpc[number], comroutine, 0); KeSetTargetProcessorDpc(dpc[number], (CCHAR)number); if(FALSE==KeInsertQueueDpc(dpc[number],0, 0)) return STATUS_UNSUCCESSFUL; return STATUS_SUCCESS; } [/code] 上面说到,在枚举CPU插入DPC对象的时候,插入了2种不同的dpc对象,一个dpc的执行例程是1^?0的11^,代码如下: [code] VOID MyRoutine( —in struct _KDPC *Dpc, —in_opt PVOID DeferredContext, —in_opt PVOID SystemArgumentl, —in_opt PVOID SystemArgument2 ) KIRQL oldirql; DbgPrint C%x is goXn^, threadnumber); —asm { lock INC dword ptr [threadnumber]; 将空转cpu个数加一 } while(l) { if(hookstart==TRUE) { KeAcquireSpinLock(&spinlock, &oldirql); KeReleaseSpinLock(&spinlock, oldirql); break; [/code] [code] VOID MyHook(—in struct _KDPC *Dpc, _in_opt PVOID DeferredContext, _in_opt PVOID SystemArgumentl, _in_opt PVOID ) SystemArgument2 { KIRQL oldirql; while(l) / \ if(threadnumber==(i-1)) ; \ KeAcquireSpinLock(&spinlock, &oldirql); DbgPrint("Hook is start\n"); hookstart=TRUE; // pathch 〖61似6^0收收八卩。函数 pushad; pushfd; mov eax, crO; and eax, not 0x10000; |