驱动内存加载[理论]

07 驱动内存加载

驱动加载介绍

内存驱动加载不需要签名

双击一个PE程序的时候发生了什么

1.通过explorer.exe(资源管理器)定位到双击的文件

2.资源管理器通过CreatProcess创建进程

3.创建进程的时候开辟一块空间

此时在R3(PEB)和R0(填充基址)需要的地方挂上R3的物理页

4.通过文件路径载入PE

5.接下来是修复和解析

  1. 解析PE头,将对应的数据目录存放到内存相关的偏移地址
  2. 修复重定位,有可能出现随机基址,或者指定的地址被占用,这样的话基址就被修改了,所以要修复重定位
  3. 修复IAT(系统相关函数)导入表,比如在win7、win10都有一个函数,但是函数地址不一样
  4. 修复TLS(线程)
  5. 修复延迟导入表,再一次去用才修复的
  6. 修复SEH异常
  7. 获取入口点
  8. call 入口点

上面的这些驱动加载的时候都有,唯一不同的是驱动加载的时候没有修复和解析中的45也就是修复TLS,和修复异常导入表,不过在驱动中多修复一个cookie

实验(COOKIE不对的情况)

这里为了做演示将Driver Settings -> Target OS Version改成Win10

然后在win7虚拟机里面执行会蓝屏

接下来分析一下

可以在IP这里看到这里有个security_init_cookie出问题了

从调用栈这里也可以看到

先是DriverEntry驱动入口点,然后执行了一个__security_init_cookie+0x1b的操作,然后就发生错误(RtlFailFast)

但是很显然这个__security_init_cookie不是我们自己写的,所以接下来用ida看一下

然后我们进去看一下这个call的cookie做了什么操作

代码很简单,可以直接看下面的说明

; void __cdecl __security_init_cookie()
___security_init_cookie proc near       ; CODE XREF: DriverEntry+5↑p
mov     eax, ___security_cookie         ; 获取当前的security_cookie值保存到eax中
test    eax, eax                        ; 将eax值与运算,判断eax是否是0
jz      short loc_404028                ; 如果是是0,崩溃

cmp     eax, 0BB40E64Eh                 ; 将eax值与0BB40E64Eh比较
jz      short loc_404028                ; 相等崩溃

not     eax                             ; 将eax取反
mov     dword_403004, eax               ; dword_403004 = eax
retn                                    ; 返回

; ---------------------------------------------------------------------------

loc_404028:                             ; CODE XREF: ___security_init_cookie+7↑j
                                        ; ___security_init_cookie+E↑j
push    6
pop     ecx
int     29h                             ; Win8: RtlFailFast(ecx)

___security_init_cookie endp

也可以看一下伪c代码,基本一样

接下来我们把Driver Settings -> Target OS Version改成Win7,再编译一样,放到ida看一下

; void __cdecl __security_init_cookie()
___security_init_cookie proc near       ; CODE XREF: DriverEntry+5↑p
mov     edi, edi
push    ebp
mov     ebp, esp
push    ecx
push    ecx
mov     eax, ___security_cookie         ; 将当前的cookie值保存到eax
mov     ecx, 0BB40E64Eh                 ; ecx = 0BB40E64Eh
test    eax, eax                        ; 比较eax是否是0
jz      short loc_404029                ; 如果真,跳到loc_404029

cmp     eax, ecx                        ; 比较eax和ecx
jnz     short loc_40403E                ; 如果真,跳到loc_40403E


loc_404029:                             ; CODE XREF: ___security_init_cookie+13↑j
rdtsc                                   ; 获取CPU运行至今的时间周期,eax保存低位,edx保存高位
xor     eax, offset ___security_cookie  ; 将eax值与cookie异或,因为能够跳到这里的cookie都是0,所以eax不变
mov     ___security_cookie, eax         ; cookie = eax
jnz     short loc_40403E                ; eax值取反

mov     eax, ecx                        ; eax = ecx = 0BB40E64Eh
mov     ___security_cookie, eax         ; cookie = eax


loc_40403E:                             ; CODE XREF: ___security_init_cookie+17↑j
                                        ; ___security_init_cookie+25↑j
not     eax                             ; eax值取反
mov     dword_403004, eax               ; dword_403004 = eax
leave
retn

___security_init_cookie endp

可以很明显的看出来Win7有自我修复的步骤,一旦cookie不存在或者是特定值都会进行自我修复

这也是为什么在Win7下可以不修复cookie但是在win10高版本下必须要修复cookie,因为win10的这个蓝屏机制就是通过检查cookie来防止内存加载

修复方式

但是这个SecurityCookie是在IMAGE_LOAD_CONFIG_DIRECTORY结构体中的(不知道为什么Windbg找不到这个结构体)

这个结构体分32位和64位,具体可以看微软文档

从中可以很明显的看到这个Cookie

IMAGE_LOAD_CONFIG_DIRECTORY结构体

typedef struct _IMAGE_LOAD_CONFIG_DIRECTORY32 {
  DWORD                            Size;
  DWORD                            TimeDateStamp;
  WORD                             MajorVersion;
  WORD                             MinorVersion;
  DWORD                            GlobalFlagsClear;
  DWORD                            GlobalFlagsSet;
  DWORD                            CriticalSectionDefaultTimeout;
  DWORD                            DeCommitFreeBlockThreshold;
  DWORD                            DeCommitTotalFreeThreshold;
  DWORD                            LockPrefixTable;
  DWORD                            MaximumAllocationSize;
  DWORD                            VirtualMemoryThreshold;
  DWORD                            ProcessHeapFlags;
  DWORD                            ProcessAffinityMask;
  WORD                             CSDVersion;
  WORD                             DependentLoadFlags;
  DWORD                            EditList;
  DWORD                            SecurityCookie;
  DWORD                            SEHandlerTable;
  DWORD                            SEHandlerCount;
  DWORD                            GuardCFCheckFunctionPointer;
  DWORD                            GuardCFDispatchFunctionPointer;
  DWORD                            GuardCFFunctionTable;
  DWORD                            GuardCFFunctionCount;
  DWORD                            GuardFlags;
  IMAGE_LOAD_CONFIG_CODE_INTEGRITY CodeIntegrity;
  DWORD                            GuardAddressTakenIatEntryTable;
  DWORD                            GuardAddressTakenIatEntryCount;
  DWORD                            GuardLongJumpTargetTable;
  DWORD                            GuardLongJumpTargetCount;
  DWORD                            DynamicValueRelocTable;
  DWORD                            CHPEMetadataPointer;
  DWORD                            GuardRFFailureRoutine;
  DWORD                            GuardRFFailureRoutineFunctionPointer;
  DWORD                            DynamicValueRelocTableOffset;
  WORD                             DynamicValueRelocTableSection;
  WORD                             Reserved2;
  DWORD                            GuardRFVerifyStackPointerFunctionPointer;
  DWORD                            HotPatchTableOffset;
  DWORD                            Reserved3;
  DWORD                            EnclaveConfigurationPointer;
  DWORD                            VolatileMetadataPointer;
  DWORD                            GuardEHContinuationTable;
  DWORD                            GuardEHContinuationCount;
  DWORD                            GuardXFGCheckFunctionPointer;
  DWORD                            GuardXFGDispatchFunctionPointer;
  DWORD                            GuardXFGTableDispatchFunctionPointer;
  DWORD                            CastGuardOsDeterminedFailureMode;
  DWORD                            GuardMemcpyFunctionPointer;
} IMAGE_LOAD_CONFIG_DIRECTORY32, *PIMAGE_LOAD_CONFIG_DIRECTORY32;

很显然,既然结构体里面有,我们就能改

32位程序内存加载

其中签名目录记录了程序的签名信息,可以通过这个目录得到程序的签名

其中异常目录在x86下一直是空的,x64下才有值,因为x86不使用资源目录保存异常

posted @ 2024-05-18 17:21  MuRKuo  阅读(176)  评论(0编辑  收藏  举报