1。取得shadow ssdt真实地址
系统只提供了KeServiceDescriptorTable导出
KeServiceDescriptorTableShadow是个未导出结构

定义
Copy code

typedef struct _SYSTEM_SERVICE_TABLE
    {
          PNTPROC  ServiceTable;  // array of entry points
          PDWORD  CounterTable;  // array of usage counters
          DWORD  ServiceLimit;    // number of table entries
          PBYTE    ArgumentTable;  // array of byte counts
    }
    SYSTEM_SERVICE_TABLE,
    *PSYSTEM_SERVICE_TABLE,
    **PPSYSTEM_SERVICE_TABLE;
    //-----------------------------------------------------------------------------------------------------------
    typedef struct _SERVICE_DESCRIPTOR_TABLE
    {
          SYSTEM_SERVICE_TABLE ntoskrnl;  // ntoskrnl.exe ( native api )
        SYSTEM_SERVICE_TABLE win32k;    // win32k.sys (gdi/user support)
          SYSTEM_SERVICE_TABLE Table3;    // not used
          SYSTEM_SERVICE_TABLE Table4;    // not used
    }
    SYSTEM_DESCRIPTOR_TABLE,
    *PSYSTEM_DESCRIPTOR_TABLE,
    **PPSYSTEM_DESCRIPTOR_TABLE;

其实 KeServiceDescriptorTableShadow包含4个子结构,其中第一个就是ntoskrnl.exe ( native api ),和KeServiceDescriptorTable指向一样 我们真正需要获得的是第二个win32k.sys (gdi/user support),第三个和第四个一般不使用

定位方法
1。硬编码
Copy code

//for xp
    if(gKernelVersion==WINXP)
      KeServiceDescriptorTableShadow=KeServiceDescriptorTable-0x40;
    //for 2k
    if(gKernelVersion==WIN2K)
      KeServiceDescriptorTableShadow=KeServiceDescriptorTable+0xE0;

2。搜索KeAddSystemServiceTable
反汇编代码可以看出
Copy code

lkd> u KeAddSystemServiceTable l 40
    nt!KeAddSystemServiceTable:
    805ba589 8bff            mov    edi,edi
    805ba58b 55              push    ebp
    805ba58c 8bec            mov    ebp,esp
    805ba58e 837d1803        cmp    dword ptr [ebp+18h],3
    805ba592 774e            ja      nt!KeAddSystemServiceTable+0x6b (805ba5e2)
    805ba594 8b4518          mov    eax,dword ptr [ebp+18h]
    805ba597 c1e004          shl    eax,4
    805ba59a 83b880a6558000  cmp    dword ptr nt!KeServiceDescriptorTable (8055a680)[eax],0
    805ba5a1 753f            jne    nt!KeAddSystemServiceTable+0x6b (805ba5e2)
    805ba5a3 8d8840a65580    lea    ecx,nt!KeServiceDescriptorTableShadow (8055a640)[eax]
    805ba5a9 833900          cmp    dword ptr [ecx],0
    805ba5ac 7534            jne    nt!KeAddSystemServiceTable+0x6b (805ba5e2)
    805ba5ae 837d1801        cmp    dword ptr [ebp+18h],1
    805ba5b2 8b5508          mov    edx,dword ptr [ebp+8]
    805ba5b5 56              push    esi
    805ba5b6 8b7510          mov    esi,dword ptr [ebp+10h]
    805ba5b9 57              push    edi
    805ba5ba 8b7d14          mov    edi,dword ptr [ebp+14h]
    805ba5bd 8911            mov    dword ptr [ecx],edx
    805ba5bf 8b4d0c          mov    ecx,dword ptr [ebp+0Ch]
    805ba5c2 898844a65580    mov    dword ptr nt!KeServiceDescriptorTableShadow+0x4 (8055a644)[eax],ecx
    805ba5c8 89b048a65580    mov    dword ptr nt!KeServiceDescriptorTableShadow+0x8 (8055a648)[eax],esi
    805ba5ce 89b84ca65580    mov    dword ptr nt!KeServiceDescriptorTableShadow+0xc (8055a64c)[eax],edi
    805ba5d4 0f855a3e0300    jne    nt!KeAddSystemServiceTable+0x4d (805ee434)
    805ba5da 5f              pop    edi
    805ba5db b001            mov    al,1
    805ba5dd 5e              pop    esi
    805ba5de 5d              pop    ebp
    805ba5df c21400          ret    14h
    805ba5e2 32c0            xor    al,al
    805ba5e4 ebf8            jmp    nt!KeAddSystemServiceTable+0x6d (805ba5de)
    805ba5e6 90              nop
    805ba5e7 90              nop
    805ba5e8 90              nop
    805ba5e9 90              nop
    805ba5ea 90              nop

搜索办法很简单
就是找到
805ba5a3 8d8840a65580    lea    ecx,nt!KeServiceDescriptorTableShadow (8055a640)[eax]
的8d88 40a65580    lea    ecx, nt!KeServiceDescriptorTableShadow
代码如下
Copy code

void GetKeServiceDescriptorTableShadow()
    {
        PUCHAR cPtr, pOpcode;
        ULONG Length;
    
        for (cPtr = (PUCHAR)KeAddSystemServiceTable;
            cPtr < (PUCHAR)KeAddSystemServiceTable + PAGE_SIZE;
            cPtr += Length)
        {
            if (!MmIsAddressValid(cPtr)) break;

Length = SizeOfCode(cPtr, &pOpcode);

if (!Length || (Length == 1 && *pOpcode == 0xC3)) break;
        
            if (*(PUSHORT)pOpcode == 0x888D)
            {
                KeServiceDescriptorTableShadow = *(PVOID *)(pOpcode + 2);
                break;
            }
        }
    }

3。从KTHREAD.ServiceTable里面搜索
如果是GUI线程 那么就是指向ServiceDescriptorTableShadow
其实个人更加倾向这个办法 稳定安全可靠,上面那个代码也许会受到以后系统代码变化影响 但是这个肯定不会

Copy code

GetServiceDescriptorTableShadowAddress proc uses esi edi ebx

local dwThreadId:DWORD

xor ebx, ebx                ; = NULL. Assume ServiceDescriptorTableShadow will be not found

mov eax, KeServiceDescriptorTable
        mov esi, [eax]

; Find KTHREAD.ServiceTable field
        ; For non-GUI threads this field == KeServiceDescriptorTable
        ; and it points to ServiceDescriptorTable
        ; For GUI threads
        ; ServiceDescriptorTableShadow

invoke KeGetCurrentThread
        mov edi, 200h-4
        .while edi
            .break .if dword ptr [eax][edi] == esi
            dec edi
        .endw

.if edi != 0
            ; edi = offset to ServiceTable field in KTHREAD structure
            mov dwThreadId, 080h
            .while dwThreadId < 400h
                push eax                    ; reserve DWORD on stack
                invoke PsLookupThreadByThreadId, dwThreadId, esp
                pop ecx                        ; -> ETHREAD/KTHREAD
                .if eax == STATUS_SUCCESS
                    push dword ptr [ecx][edi]
                    fastcall ObfDereferenceObject, ecx
                    pop eax
                    .if eax != esi
                        mov edx, MmSystemRangeStart
                        mov edx, [edx]
                        mov edx, [edx]
                        .if eax > edx        ; some stupid error checking
                            mov ebx, eax
                            invoke DbgPrint, $CTA0("FindShadowTable: Found in thread with ID: %X/n"), dwThreadId
                            .break
                        .endif
                    .endif
                .endif
                add dwThreadId, 4
            .endw
        .endif

mov eax, ebx
        ret

GetServiceDescriptorTableShadowAddress endp

4.mj0011所说的搜索有效内存地址的办法
Copy code

/*
    define structure for the system service table
    */
    struct SYS_SERVICE_TABLE {
    void **ServiceTable;
    unsigned long CounterTable;
    unsigned long ServiceLimit;
    void **ArgumentsTable;
    };

SYSTEM_DESCRIPTOR_TABLE KeServiceDescriptorTableShadow;

/*
    Define KeServiceDescriptorTable based on the SST structure
    */
    extern struct SYS_SERVICE_TABLE *KeServiceDescriptorTable;

/*
    Declare function GetServiceDescriptorShadowTableAddress()
    */
    //struct SYS_SERVICE_TABLE * GetServiceDescriptorShadowTableAddress ();
    /*
    Declare the KeAddSystemServiceTable. This is just a
    handle to the call function, it will be used by the function
    above to obtain the correct address of the KeServiceDescriptorShadowTable
    */
    __declspec(dllimport) KeAddSystemServiceTable (ULONG, ULONG, ULONG, ULONG, ULONG);

struct SYS_SERVICE_TABLE * GetServiceDescriptorShadowTableAddress ()
    {
    // First, obtain a pointer to KeAddSystemServiceTable
    unsigned char *check = (unsigned char*)KeAddSystemServiceTable;
    int i;
      //Initialize an instance of System Service Table, will be used to
    //obtain an address from KeAddSystemServiceTable
    struct SYS_SERVICE_TABLE *rc=0;
    // Make 100 attempts to match a valid address with that of KeServiceDescriptorTable
    for (i=0; i<=99; i++) {
      __try {
      // try to obtain an address from  KeAddSystemServiceTable
      rc = *(struct SYS_SERVICE_TABLE**)check;
      // if this address is NOT valid OR it itself is the address of
      //KeServiceDescriptorTable OR its first entry is NOT equal
      //to the first entry of KeServiceDescriptorTable
      if (!MmIsAddressValid (rc) || (rc == KeServiceDescriptorTable)
        || (memcmp (rc, KeServiceDescriptorTable, sizeof (*rc)) != 0)) {
        // Proceed with the next address
        check++;
        // don't forget to reset the old address
        rc = 0;
      }
      } __except (EXCEPTION_EXECUTE_HANDLER) { rc = 0; }
      // when the loop is completed, check if it produced a valid address
      if (rc)
      // because if it didn't, we failed to find the address of KeServiceDescriptorTableShadow
      break;
    }
    // otherwise, there is a valid address! So return it!
    return rc;
    }

二。函数名定位
这个似乎没有多少好办法,解析pdb可以是可以 但是很麻烦
不过还好的是 同一个版本的系统 调用号一样
所以只需要3套 2k xp 2k3的调用号就可以完成hook
pdb办法
SymInitialize初始化
SymSetSearchPath “srv**symbols*http://msdl.microsoft.com/”
SymLoadModule
SymGetSymFromName
老v曾经发出1个获取shadow地址和函数名称的工具 使用他可以很方便的获取
具体代码可以F5查看
以上读取pdb的方法测试使用的可以的
但是实际使用很麻烦

经过分析 我找到了1个比较好的定位办法
我们以SetWindowsHookExA为例子
Copy code

_text:77D311D1 ; HHOOK __stdcall SetWindowsHookExA(int idHook, HOOKPROC lpfn, HINSTANCE hmod, DWORD dwThreadId)
    _text:77D311D1                public _SetWindowsHookExA@16
    _text:77D311D1 _SetWindowsHookExA@16 proc near
    _text:77D311D1
    _text:77D311D1 idHook          = dword ptr  8
    _text:77D311D1 lpfn            = dword ptr  0Ch
    _text:77D311D1 hModule        = dword ptr  10h
    _text:77D311D1 dwThreadId      = dword ptr  14h
    _text:77D311D1
    _text:77D311D1                mov    edi, edi
    _text:77D311D3                push    ebp
    _text:77D311D4                mov    ebp, esp
    _text:77D311D6                push    2              ; int
    _text:77D311D8                push    [ebp+dwThreadId] ; int
    _text:77D311DB                push    [ebp+hModule]  ; hModule
    _text:77D311DE                push    [ebp+lpfn]      ; int
    _text:77D311E1                push    [ebp+idHook]    ; int
    _text:77D311E4                call    _SetWindowsHookExAW@20 ; SetWindowsHookExAW(x,x,x,x,x)
    _text:77D311E9                pop    ebp
    _text:77D311EA                retn    10h
    _text:77D311EA _SetWindowsHookExA@16 endp

_text:77D2DCFD ; int __stdcall SetWindowsHookExAW(int, int, HMODULE hModule, int, int)
    _text:77D2DCFD _SetWindowsHookExAW@20 proc near        ; CODE XREF: SetWindowsHookExW(x,x,x,x)+13p
    _text:77D2DCFD                                        ; SetWindowsHookExA(x,x,x,x)+13p
    _text:77D2DCFD
    _text:77D2DCFD Filename        = word ptr -20Ch
    _text:77D2DCFD var_4          = dword ptr -4
    _text:77D2DCFD arg_0          = dword ptr  8
    _text:77D2DCFD arg_4          = dword ptr  0Ch
    _text:77D2DCFD hModule        = dword ptr  10h
    _text:77D2DCFD arg_C          = dword ptr  14h
    _text:77D2DCFD arg_10          = dword ptr  18h
    _text:77D2DCFD
    _text:77D2DCFD                mov    edi, edi
    _text:77D2DCFF                push    ebp
    _text:77D2DD00                mov    ebp, esp
    _text:77D2DD02                sub    esp, 20Ch
    _text:77D2DD08                mov    eax, ___security_cookie
    _text:77D2DD0D                push    esi
    _text:77D2DD0E                mov    esi, [ebp+hModule]
    _text:77D2DD11                test    esi, esi
    _text:77D2DD13                push    edi
    _text:77D2DD14                mov    edi, [ebp+arg_4]
    _text:77D2DD17                mov    [ebp+var_4], eax
    _text:77D2DD1A                jz      short loc_77D2DD33
    _text:77D2DD1C                push    104h            ; nSize
    _text:77D2DD21                lea    eax, [ebp+Filename]
    _text:77D2DD27                push    eax            ; lpFilename
    _text:77D2DD28                push    esi            ; hModule
    _text:77D2DD29                call    ds:__imp__GetModuleFileNameW@12 ; GetModuleFileNameW(x,x,x)
    _text:77D2DD2F                test    eax, eax
    _text:77D2DD31                jz      short loc_77D2DD52
    _text:77D2DD33
    _text:77D2DD33 loc_77D2DD33:                          ; CODE XREF: SetWindowsHookExAW(x,x,x,x,x)+1Dj
    _text:77D2DD33                push    [ebp+arg_10]
    _text:77D2DD36                mov    eax, esi
    _text:77D2DD38                push    edi
    _text:77D2DD39                push    [ebp+arg_0]
    _text:77D2DD3C                neg    eax
    _text:77D2DD3E                push    [ebp+arg_C]
    _text:77D2DD41                sbb    eax, eax
    _text:77D2DD43                lea    ecx, [ebp+Filename]
    _text:77D2DD49                and    eax, ecx
    _text:77D2DD4B                push    eax
    _text:77D2DD4C                push    esi
    _text:77D2DD4D                call    __SetWindowsHookEx@24 ; _SetWindowsHookEx(x,x,x,x,x,x)
    _text:77D2DD52
    _text:77D2DD52 loc_77D2DD52:                          ; CODE XREF: SetWindowsHookExAW(x,x,x,x,x)+34j
    _text:77D2DD52                mov    ecx, [ebp+var_4]
    _text:77D2DD55                pop    edi
    _text:77D2DD56                pop    esi
    _text:77D2DD57                call    @__security_check_cookie@4 ; __security_check_cookie(x)
    _text:77D2DD5C                leave
    _text:77D2DD5D                retn    14h
    _text:77D2DD5D _SetWindowsHookExAW@20 endp
    _text:77D2DD5D

_text:77D2DD65 ; __stdcall _SetWindowsHookEx(x, x, x, x, x, x)
    _text:77D2DD65 __SetWindowsHookEx@24 proc near        ; CODE XREF: SetWindowsHookExAW(x,x,x,x,x)+50p
    _text:77D2DD65
    _text:77D2DD65 var_10          = byte ptr -10h
    _text:77D2DD65 var_8          = dword ptr -8
    _text:77D2DD65 var_4          = dword ptr -4
    _text:77D2DD65 arg_0          = dword ptr  8
    _text:77D2DD65 arg_4          = dword ptr  0Ch
    _text:77D2DD65 arg_8          = dword ptr  10h
    _text:77D2DD65 arg_C          = dword ptr  14h
    _text:77D2DD65 arg_10          = dword ptr  18h
    _text:77D2DD65 arg_14          = dword ptr  1Ch
    _text:77D2DD65
    _text:77D2DD65                mov    edi, edi
    _text:77D2DD67                push    ebp
    _text:77D2DD68                mov    ebp, esp
    _text:77D2DD6A                sub    esp, 10h
    _text:77D2DD6D                push    [ebp+arg_4]
    _text:77D2DD70                and    [ebp+var_4], 0
    _text:77D2DD74                lea    eax, [ebp+var_10]
    _text:77D2DD77                push    eax
    _text:77D2DD78                mov    [ebp+var_8], eax
    _text:77D2DD7B                call    ds:__imp__RtlInitUnicodeString@8 ; RtlInitUnicodeString(x,x)
    _text:77D2DD81                push    [ebp+arg_14]
    _text:77D2DD84                push    [ebp+arg_10]
    _text:77D2DD87                push    [ebp+arg_C]
    _text:77D2DD8A                push    [ebp+arg_8]
    _text:77D2DD8D                push    [ebp+var_8]
    _text:77D2DD90                push    [ebp+arg_0]
    _text:77D2DD93                call    _NtUserSetWindowsHookEx@24 ; NtUserSetWindowsHookEx(x,x,x,x,x,x)
    _text:77D2DD98                leave
    _text:77D2DD99                retn    18h
    _text:77D2DD99 __SetWindowsHookEx@24 endp
    _text:77D2DD99

_text:77D2DDA1 ; __stdcall NtUserSetWindowsHookEx(x, x, x, x, x, x)
    _text:77D2DDA1 _NtUserSetWindowsHookEx@24 proc near    ; CODE XREF: _SetWindowsHookEx(x,x,x,x,x,x)+2Ep
    _text:77D2DDA1                mov    eax, 1225h
    _text:77D2DDA6                mov    edx, 7FFE0300h
    _text:77D2DDAB                call    dword ptr [edx]
    _text:77D2DDAD                retn    18h
    _text:77D2DDAD _NtUserSetWindowsHookEx@24 endp

我们看这里 _text:77D2DDA1                mov    eax, 1225h
里面有和ssdt一样的调用号 但是有个问题 NtUserSetWindowsHookEx在user32里面没有导出,我们需要多次搜索才行
Copy code

HHOOK STDCALL    NtUserSetWindowsHookEx (HINSTANCE Mod, PUNICODE_STRING UnsafeModuleName, DWORD ThreadId, int HookId, HOOKPROC HookProc, BOOL Ansi)

这个就是原型 不过搜索起来确实是比较麻烦的,不知道还有无其他好办法了

三。如何hook
似乎这个问题并不大,shadow ssdt和ssdt本质上都是1个地址表,最为简单的方法是把你的函数替换地址表的对应项,具体hook代码甚至可以完全照抄ssdt的,这里只说1下几个偶遇到的小问题
1。win32k.sys不是常在内存的,如果不是GUI线程,shadow ssdt地址无效
解决办法:
1。在driverdispatch中hokk
driverdispatch是位于执行driveriocontrol的线程上下文的
我们使用1个GUI线程去driveriocontrol

2。attachtoprocess
通常 我们使用cerss.exe
Copy code

HANDLE GetCsrPid()
    {
        HANDLE                        Process, hObject;
        HANDLE                        CsrId = (HANDLE)0;
        OBJECT_ATTRIBUTES            obj;
        CLIENT_ID                    cid;
        UCHAR                        Buff[0x100];
        POBJECT_NAME_INFORMATION      ObjName = (PVOID)&Buff;
        PSYSTEM_HANDLE_INFORMATION_EX Handles;
        ULONG                        r;

Handles = GetInfoTable(SystemHandleInformation);

if (!Handles) return CsrId;

for (r = 0; r < Handles->NumberOfHandles; r++)
        {
            if (Handles->Information[r].ObjectTypeNumber == 21) //Port object
            {
                InitializeObjectAttributes(&obj, NULL, OBJ_KERNEL_HANDLE, NULL, NULL);
            
                cid.UniqueProcess = (HANDLE)Handles->Information[r].ProcessId;
                cid.UniqueThread  = 0;

if (NT_SUCCESS(NtOpenProcess(&Process, PROCESS_DUP_HANDLE, &obj, &cid)))
                {
                    if (NT_SUCCESS(ZwDuplicateObject(Process,
                                                    (HANDLE)Handles->Information[r].Handle,
                                                    NtCurrentProcess(),
                                                    &hObject,
                                                      0, 0, DUPLICATE_SAME_ACCESS)))
                    {
                        if (NT_SUCCESS(ZwQueryObject(hObject,
                                                    ObjectNameInformation,
                                                        ObjName,
                                                    0x100, NULL)))
                        {
                            if (ObjName->Name.Buffer &&
                                !wcsncmp(L"//Windows//ApiPort", ObjName->Name.Buffer, 20))
                            {
                                CsrId = (HANDLE)Handles->Information[r].ProcessId;
                            }
                        }

ZwClose(hObject);
                    }

ZwClose(Process);
                }
            }
        }

ExFreePool(Handles);

return CsrId;
    }

然后我们KeAttachProcess
Copy code

ntStatus = PsLookupProcessByProcessId(GetCsrPid(), &EProcess);

if (!NT_SUCCESS( ntStatus ))
      {

DbgPrint("PsLookupProcessByProcessId()/n");
                  return ntStatus;
      }

KeAttachProcess(EProcess);

3.使用MDL映射一块不分页内存,设置成可以写入
不分页内存  ExAllocatePool(NonPagedPool
即为不会被切换到pagefile的内存,是常驻在物理内存的,比较希缺,使用完毕以后记住释放掉
参考regmon的代码
Copy code

PVOID *
    RegmonMapServiceTable(
      SERVICE_HOOK_DESCRIPTOR **ServiceIsHooked
      )
    {
      *ServiceIsHooked = (SERVICE_HOOK_DESCRIPTOR*)
                  ExAllocatePool(NonPagedPool, KeServiceDescriptorTable->TableSize);

if( *ServiceIsHooked )
      {
        RtlZeroMemory(*ServiceIsHooked, KeServiceDescriptorTable->TableSize);

KeServiceTableMdl = MmCreateMdl(0, KeServiceDescriptorTable->ServiceTable, KeServiceDescriptorTable->TableSize << 2);

if( KeServiceTableMdl )
        {
            MmBuildMdlForNonPagedPool(KeServiceTableMdl);

KeServiceTableMdl->MdlFlags |= 1;

return (PVOID*)MmMapLockedPages(KeServiceTableMdl, KernelMode);
        }
      }

return NULL;
    };

看起来shadowssdt何hook本身并没有什么难度
只要正确定位了地址,hook起来和ssdt完全一样
unhook不在重复 完全抄ssdt的代码即可

四。checkhook
hook用的人多了 难免出现重复hook的情况 为了实现和别人的东西和平共处,最好hook之前做个检测
hook的方法是固定的,就那么2种 改地址表 或者inline hook,我们分别来对待
1。修改地址表的hook
  这个对付起来几乎不用特别对待,只是你保存的OldFunc是其他的程序hook函数所在的地址,判断方法很简单,看看这个地址在不在win32k的模块里面,和平共处的办法是你的myfunc里面call别人的hook函数,当然 如果你不想要别人的hook了,直接搜索到原始地址call之也是可行的
另外说1下 在别人的函数里面搜索原始地址 用MmIsAddressValid+ismodulewin32k
可以判断(这个办法好像是在mj文章里面看到的 记不清了)
2。inlinehook
这个比较麻烦了 如果是修改前面5个字节还好,直接替换处理都可以不改变
麻烦是函数中间地方被hook,盲目修改可能直接BSOD了,这个需要1个反汇编引擎来帮助分析代码字节长度,海风大大的hooklib很不错 可以完成这个功能

五,简单说1下restore
Copy code

pWin32k = GetModuleHandle("win32k.sys");
    SdtRVA = &KeServiceDescriptorTable->win32k.ServiceTable - pWin32k ;
    w32kCopy = LoadPeFile("win32k.sys");
    ProcessRelocs(w32kCopy, pWin32k);
    memcpy(&KeServiceDescriptorTable->win32k.ServiceTable, w32kCopy + SdtRVA, SdtSize);

不过 其实可以不用ProcessRelocs处理
因为你可以使用lordpe查看1下 win32k.sys的默认基址就是系统加载的基址
可以不需要ProcessRelocs,不过为了更加方便和通用,这么做也可以的

shadow ssdt学习笔记相关推荐

  1. 在windbg中测试shadow ssdt , win32k!NtUserGetForegroundWindow , hook shadow ssdt

    在windbg中查看shadow ssdt: 0: kd> lm start    end        module name 804d8000 806e3000   nt         ( ...

  2. Windows驱动开发学习笔记(五)—— SSDT HOOK

    Windows驱动开发学习笔记(五)-- SSDT HOOK 系统服务表 系统服务描述符表 实验一:通过代码获取SSDT表地址 通过页表基址修改页属性 方法1:修改页属性 方法2:修改CR0寄存器 实 ...

  3. Windows系统调用学习笔记(四)—— 系统服务表SSDT

    Windows系统调用学习笔记(四)-- 系统服务表&SSDT 要点回顾 系统服务表 实验:分析 KiSystemService 与 KiFastCallEntry 共同代码 SSDT 实验: ...

  4. SATA 学习笔记2 - Shadow Register和FIS的传输

    在上一篇笔记SATA学习笔记1 - Link Layer初认识中,我们简单了解了FIS是如何在不同的layer中进行传输和接收的,在这篇笔记中,我将进一步讲解FIS的相关知识. 在讲FIS前,我们先来 ...

  5. Android开源项目SlidingMenu本学习笔记(两)

    我们已经出台SlidingMenu使用:Android开源项目SlidingMenu本学习笔记(一个),接下来再深入学习下.依据滑出项的Menu切换到相应的页面 文件夹结构: 点击Bluetooth能 ...

  6. 20161102学习笔记

    ctrl+win+左/右,切换虚拟机桌面 win+Tab快速切换任务程序 浏览器的: ctrl+数字或ctrl+PgUp/PgDn或Ctrl+Tab切换浏览器的标签页 Ctrl+w关闭标签页 Ctrl ...

  7. Intel VT学习笔记(六)—— VM-Exit Handler

    Intel VT学习笔记(六)-- VM-Exit Handler Reutrn To DriverEntry VM-Exit Handler External interrupt I/O instr ...

  8. Intel VT学习笔记(四)—— VMCS(下)

    Intel VT学习笔记(四)-- VMCS(下) 要点回顾 VM-Exit Information Guest state fields 代码实现 参考资料 要点回顾 在上一篇中,我们了解了如何设置 ...

  9. Windows驱动开发学习笔记(六)—— Inline HOOK

    Windows驱动开发学习笔记(六)-- Inline HOOK SSDT HOOK Inline Hook 挂钩 执行流程 脱钩 实验一:3环 Inline Hook 实验二:0环 Inline H ...

最新文章

  1. tomcat(4)Tomcat的默认连接器
  2. mysql中group by的排序问题_Mysql之group by 和order by 一起用时的排序问题
  3. 全球股市下跌潮蔓延 多个国家地区拟出手救市
  4. Python 之详解深拷贝和浅拷贝
  5. python 文件和目录操作题库
  6. 查看app包名和启动页Activity的方法
  7. Python实现同义词替换(哈工大pyltp分词)
  8. apkg格式怎么打开_pdf转图片怎么转?分享最简单的PDF转图片方法
  9. 【gfs】google file system 之重点剖析
  10. 深入浅出计算机原理组成--->指令与运算——指令跳转(2)
  11. C++图像处理 -- 图像翻转(镜像)
  12. 萌娃人脸生成器 实践踩坑笔记
  13. python脚本批量修改图片像素大小和重命名
  14. Android的鼠标事件流向
  15. MFC应用程序中添加控制台窗口---debug输出窗口
  16. 国睿驰120gb固态硬盘测试软件,小巧极速 国睿驰精睿系列移动SSD评测
  17. UICollectionView 自定义布局教程: Pinterest
  18. Swift语法基础:19 - Swift的控制转移的语句, Continue, Break, Fallthrough, Labeled Statements...
  19. 【单片机毕业设计】【mcuclub-jj-052】基于单片机的电脑散热底座的设计
  20. C语言矩阵输出acm1523

热门文章

  1. error: goland --build constraints exclude all Go files
  2. 几种常用范数与距离的关系
  3. 【.Net 学习系列】-- EF Core实践(Code First)
  4. Jmeter-获取响应结果中参数出现的次数
  5. linux jdk 安装
  6. PHPExel导出报表--导出类
  7. Sklearn-train_test_split随机划分训练集和测试集
  8. Shell中创建序列和数组(list、array)的方法
  9. libsvm的安装和使用(1)
  10. 测试公众号修改名称_微信公众号开通个人认证,只需三步