探索黑客技术攻防,实战研究与安全创新

导航菜单

编程实现突破Win64内核保护机制

我在之前的文章里说过,要使你的驱动在WIN64系统上加载,有两种方法:1.向微软缴纳高额的“保护费”(即购买驱动签名,虽然说把微软比喻为黑社会不太好,不过这种行径真的很像黑社会);2.破解微软的驱动签名验证机制。如果要在WIN64上进行内核HOOK,那么交保护费都不行,只能破解微软内核保护(PatchGuard)机制。有了这两个门神,不得不说使得WIN64系统十分安全。举个例子,我有个同学他对电脑一窍不通,之前用WINXP时经常中毒要我帮忙重装系统,后来给他安装了WIN7X64后,半年也没有中毒,而且还是在没有安装杀毒软件的情况下。但是对于普通的编程爱好者或者小公司而言,这两个门神会导致开发投入极高,甚至无法开发出安全类的软件,简而言之,就是不能在WIN64平台上吃底层安全这碗饭了。广东地区有句俗语,叫“断人财路犹如杀人父母”,但很明显,这句话的道理是全世界通用的。于是自从VISTAX64出来后,各种对付这两个门神的方法层出不穷,个人认为效果最好的就是fyyre放出的破解工具(disable_pg_ds)了,可惜这个工具不开源。不久之前,我在FASM官方论坛找到了类似这种工具的源代码,今天就把源码的分析心得写成文章分享给大家。顺便再次感叹下,外国人实在太大方了!在此特地感谢这位乐于分享的外国人Feryno!

要实现突破数字签名验证机制和PatchGuard,必须修改两个文件,winload.exe以及ntoskrnl.exe。修改ntoskrnl.exe这个好理解,那么为什么要修改winload.exe呢?因为winload.exe会校验ntoskrnl.exe有没有被修改过,如果发现它被修改过就拒绝加载修改过的ntoskrnl.exe。

首先把WINLOAD.EXE扔到IDA里,看看要修改哪些地方:


.text:00000000004057E8OslInitializeCodeIntegrityprocnear
OslpMain+61Cp
;CODEXREF:
;DATA
.text:00000000004057E8
XREF:.pdata:00000000004B2168o
.text:00000000004057E8
.text:00000000004057E8var_58
.text:00000000004057E8var_50
.text:00000000004057E8var_48
.text:00000000004057E8var_38
.text:00000000004057E8arg_8
.text:00000000004057E8arg_18
.text:00000000004057E8
=qwordptr-58h
=dwordptr-50h
=dwordptr-48h
=qwordptr-38h
=qwordptr10h
=qwordptr20h
.text:00000000004057E8
mov
rax,rsp
rbx
.text:00000000004057EB
push
.text:00000000004057EC
.text:00000000004057ED
.text:00000000004057EE
.text:00000000004057F0
.text:00000000004057F2
.text:00000000004057F6
.text:00000000004057F9
.text:00000000004057FC
.text:0000000000405800
.text:0000000000405807
.text:000000000040580B
.text:000000000040580F
.text:0000000000405812
.text:0000000000405816
BlImgQueryCodeIntegrityBootOptions
push
push
push
push
sub
rbp
rdi
r12
r13
rsp,50h
xor
r13d,r13d
r12d,ecx
r8,[rax+18h]
rcx,BlpApplicationEntry
rdx,[rax+10h]
[rax+20h],r13
rdi,r13
mov
lea
lea
lea
mov
mov
mov
[rax-38h],r13
call


需要修改的是加粗的那行(00000000004057E8):

movrax,rsp

修改为:

moval,1

ret

48h,8Bh,C4h

B0h,01h

C3h

这么做的用途是跳过对BlImgQueryCodeIntegrityBootOptions的调用,据我了解,此函数随后会调用ImgArchPcatLoadBootApplication,接下来还会调用BlImgLoadPEImageEx等函数来判断文件有没有签名以及checksum对不对。所以这是一个难缠的家伙,直接跳过。

接下来是修改ntoskrnl.exe的两个地方,下面是第一个地方:


PAGE:00000001403EAA60SepInitializeCodeIntegrityprocnear
;CODEXREF:SepInitializationPhase1+231p
PAGE:00000001403EAA60
PAGE:00000001403EAA60arg_0
PAGE:00000001403EAA60
PAGE:00000001403EAA60
PAGE:00000001403EAA65
PAGE:00000001403EAA66
PAGE:00000001403EAA6A
PAGE:00000001403EAA6C
PAGE:00000001403EAA72
PAGE:00000001403EAA78
PAGE:00000001403EAA7A
PAGE:00000001403EAA81
PAGE:00000001403EAA84
PAGE:00000001403EAA8B
PAGE:00000001403EAA92
PAGE:00000001403EAA99
=qwordptr8
mov
push
sub
xor
cmp
[rsp+arg_0],rbx
rdi
rsp,20h
ebx,ebx
cs:InitIsWinPEMode,bl
loc_1403EAB0C
jnz
xor
mov
lea
mov
mov
mov
mov
eax,eax
cs:g_CiEnabled,1
edi,[rbx+6]
cs:g_CiCallbacks,rax
cs:qword_14021EE48,rax
cs:qword_14021EE50,rax
rax,cs:qword_1402A8120
PAGE:00000001403EAAA0
PAGE:00000001403EAAA3
PAGE:00000001403EAAA5
PAGE:00000001403EAAAC
PAGE:00000001403EAAAE
PAGE:00000001403EAAB5
cmp
jz
rax,rbx
shortloc_1403EAAF7
[rax+98h],rbx
shortloc_1403EAAEE
rcx,[rax+98h]
cmp
jz
mov
lea
lea
rdx,??_C@_0BJ@KFBEEMJI@DISABLE_INTEGRITY_CHECKS?$AA@NNGAKEGL@
PAGE:00000001403EAABC
PAGE:00000001403EAAC1
PAGE:00000001403EAAC8
call
mov
SepIsOptionPresent
rcx,cs:qword_1402A8120
rdx,??_C@_0M@LNFBLGLD@TESTSIGNING?$AA@NNGAKEGL@
PAGE:00000001403EAACF
PAGE:00000001403EAAD6
PAGE:00000001403EAAD8
PAGE:00000001403EAADB
PAGE:00000001403EAAE0
PAGE:00000001403EAAE2
PAGE:00000001403EAAE9
PAGE:00000001403EAAEB
PAGE:00000001403EAAEE
PAGE:00000001403EAAEEloc_1403EAAEE:
mov
cmp
rcx,[rcx+98h]
eax,ebx
cmovnzedi,ebx
call
cmp
mov
jz
SepIsOptionPresent
eax,ebx
rax,cs:qword_1402A8120
shortloc_1403EAAEE
edi,8
or
;CODEXREF:SepInitializeCodeIntegrity+4Cj
PAGE:00000001403EAAEE
;
SepInitializeCodeIntegrity+89j
PAGE:00000001403EAAEE
cmp
jz
rax,rbx
PAGE:00000001403EAAF1
shortloc_1403EAAF7
rbx,[rax+30h]
PAGE:00000001403EAAF3
lea
PAGE:00000001403EAAF7
PAGE:00000001403EAAF7loc_1403EAAF7:
;CODEXREF:SepInitializeCodeIntegrity+43j
PAGE:00000001403EAAF7
;
SepInitializeCodeIntegrity+91j
PAGE:00000001403EAAF7
PAGE:00000001403EAAFE
PAGE:00000001403EAB01
PAGE:00000001403EAB03
PAGE:00000001403EAB08
PAGE:00000001403EAB0A
PAGE:00000001403EAB0C
;
lea
mov
mov
call
mov
jmp
r8,g_CiCallbacks
rdx,rbx
ecx,edi
CiInitialize
ebx,eax
shortloc_1403EAB12
---------------------------------------------------------------------------
PAGE:00000001403EAB0C
PAGE:00000001403EAB0Cloc_1403EAB0C:
PAGE:00000001403EAB0C
mov
cs:g_CiEnabled,bl
PAGE:00000001403EAB12
PAGE:00000001403EAB12loc_1403EAB12:
;CODEXREF:SepInitializeCodeIntegrity+AAj
PAGE:00000001403EAB12
PAGE:00000001403EAB14
PAGE:00000001403EAB19
PAGE:00000001403EAB1D
PAGE:00000001403EAB1E
mov
mov
add
pop
retn
eax,ebx
rbx,[rsp+28h+arg_0]
rsp,20h
rdi
PAGE:00000001403EAB1ESepInitializeCodeIntegrityendp


需要修改的是加粗的那行(00000001403EAA72):


jnzloc_1403EAB0C
修改为:
0Fh,85h,94h,00h,00h,00h
nop
90h
jmploc_1403EAB0C
E9h,94h,00h,00h,00h


这样做的目的是跳过对是否为WINPE模式的判断,因为如果是WINPE模式的话就不会启动PatchGuard(以下有TDL4的简介作证:


TDL4thereforedisablesthisfeaturebymakingthesystemthinkthatitisbootingintotheWinPEsystemrestoremode–inwhichPatchguardisdisabled–earlyinthebootprocess.


)。

第二个地方:


INIT:0000000140561340sub_140561340procnear
;CODEXREF:KiFilterFiberContext+FFp
INIT:0000000140561340
INIT:0000000140561340
INIT:0000000140561340var_F78
INIT:0000000140561340var_F70
INIT:0000000140561340var_F68
INIT:0000000140561340var_F60
INIT:0000000140561340var_F58
...
;KiFilterFiberContext+187p
=qwordptr-0F78h
=qwordptr-0F70h
=qwordptr-0F68h
=qwordptr-0F60h
=dwordptr-0F58h
...
...
INIT:0000000140561340var_48
INIT:0000000140561340arg_0
INIT:0000000140561340arg_8
INIT:0000000140561340arg_10
INIT:0000000140561340arg_18
INIT:0000000140561340
INIT:0000000140561340
INIT:0000000140561345
INIT:0000000140561349
INIT:000000014056134D
INIT:000000014056134E
=byteptr-48h
=dwordptr8
=dwordptr10h
=dwordptr18h
=qwordptr20h
mov
[rsp+arg_10],r8d
[rsp+arg_8],edx
[rsp+arg_0],ecx
rbx
mov
mov
push
push
rbp
INIT:000000014056134F
INIT:0000000140561350
INIT:0000000140561351
INIT:0000000140561353
INIT:0000000140561355
INIT:0000000140561357
INIT:0000000140561359
INIT:0000000140561360
INIT:0000000140561362
INIT:0000000140561368
INIT:000000014056136A
INIT:000000014056136C
INIT:0000000140561371
INIT:0000000140561371loc_140561371:
;CODEXREF:sub_140561340+28j
INIT:0000000140561371
INIT:0000000140561378
INIT:0000000140561380
INIT:0000000140561383
INIT:0000000140561388
INIT:000000014056138B
INIT:0000000140561391
INIT:0000000140561399
INIT:000000014056139E
INIT:00000001405613A1
...
push
push
push
push
push
push
sub
rsi
rdi
r12
r13
r14
r15
rsp,0F58h
xor
edi,edi
cmp
cs:InitSafeBootMode,edi
shortloc_140561371
al,1
jz
mov
jmp
loc_1405640D9
lea
lea
mov
call
cmp
jz
rbx,FsRtlUninitializeSmallMcb
rdx,[rsp+0F98h+var_E40]
rcx,rbx
RtlPcToFileHeader
rax,rdi
loc_1405640D7
mov
call
cmp
jz
rcx,[rsp+0F98h+var_E40]
RtlImageNtHeader
rax,rdi
loc_1405640D7
...
...
INIT:00000001405640D9loc_1405640D9:
sub_140561340+2Cj
;CODEXREF:
;
INIT:00000001405640D9
sub_140561340+9C36j
INIT:00000001405640D9
INIT:00000001405640E0
INIT:00000001405640E2
INIT:00000001405640E4
INIT:00000001405640E6
INIT:00000001405640E8
INIT:00000001405640E9
INIT:00000001405640EA
INIT:00000001405640EB
INIT:00000001405640EC
INIT:00000001405640EC
add
pop
pop
pop
pop
pop
pop
pop
pop
retn
endp
rsp,0F58h
r15
r14
r13
r12
rdi
rsi
rbp
rbx


需要修改的是加粗的那行(0000000140561368):


jzshortloc_140561371
74h,07h


修改为:


nop
nop
90h
90h


这么修改的目的很明显,去掉这个条件跳转,让关于是否安全模式的判断失效。因为如果是安全模式,也不会启动PatchGuard机制(fyyre在博客里的原话:PatchGuarddoesnotinitializeifwebootintosafemode.)。

经过这三处修改,数字签名校验机制和PatchGuard机制被彻底玩趴下了。但还没有完,修改过的两个文件还要重新计算checksum才行。接下来说说具体编码。由于Feryno是用汇编语言实现这一过程的,所以代码很长(560行),但是内容不多,手法也很普通(读取PE文件到buffer-搜索特征码查找位置-修改刚才提到的位置的字节内容-重新计算checksum-把修改过的buffer输出为文件),所以我估计用高级语言,一两百行就能搞定。核心代码:


;//字节替换部分
patch_bytes:
push
push
rbxrsirdi
rcx
poprsi
cld
lodsb
movzxebx,al
leardi,[file_buf]
lear8,[rdi+rdx]
;loadsizeofbytestofind
;endoffile
align10h
patch_bytes_L0:
push
rsirdi
movecx,ebx
repzcmpsb
poprdirsi
jzpatch_bytes_L4
scasb
;rdi+1in1-byteinstruction
learax,[rdi+rbx*1]
cmprax,r8
jbepatch_bytes_L0
;endoffilereached
jmppatch_bytes_L9
patch_bytes_L4:
;matchingbytesfound,patchthem
addrsi,rbx
lodsb
;loadsizeofbytestobewritten
movzxecx,al
repzmovsb
patch_bytes_L9:
poprdirsirbx
ret
;//重新计算checksum
reconstruct_crc:
;in:ecx=sizeoffile
structIMAGE_DOS_HEADER
e_magicrw1;Magicnumber
e_cblp
e_cp
rw1;Bytesonlastpageoffile
rw1;Pagesinfile
e_crlc
e_cparhdr
e_minalloc
e_maxalloc
e_ss
rw1;Relocations
rw1;Sizeofheaderinparagraphs
rw1;Minimumextraparagraphsneeded
rw1;Maximumextraparagraphsneeded
rw1;Initial(relative)SSvalue
rw1;InitialSPvalue
e_sp
e_csum
e_ip
rw1;Checksum
rw1;InitialIPvalue
e_cs
rw1;Initial(relative)CSvalue
rw1;Fileaddressofrelocationtable
rw1;Overlaynumber
e_lfarlc
e_ovno
e_res
rw4;Reservedwords
e_oemid
e_oeminfo
e_res2
e_lfanew
rw1;OEMidentifier(fore_oeminfo)
rw1;OEMinformation;e_oemidspecific
rw10;Reservedwords
rd1;Fileaddressofnewexeheader
ends
IMAGE_DOS_SIGNATURE
structIMAGE_FILE_HEADER
Machine
=MZ
rw1
rw1
rd1
NumberOfSections
TimeDateStamp
PointerToSymbolTable
NumberOfSymbols
rd
rd
rw
rw
1
1
1
1
SizeOfOptionalHeader
Characteristics
ends
IMAGE_SIZEOF_FILE_HEADER
IMAGE_FILE_MACHINE_AMD64
structIMAGE_DATA_DIRECTORY
VirtualAddress
=
=
sizeof.IMAGE_FILE_HEADER;=20
8664h
;AMD64(K8)
rd
rd
1
1
Size
ends
IMAGE_NUMBEROF_DIRECTORY_ENTRIES=
structIMAGE_OPTIONAL_HEADER64
;Standardfields.
Magic
16
rw
rb
rb
rd
rd
rd
rd
rd
1
1
1
1
1
1
1
1
MajorLinkerVersion
MinorLinkerVersion
SizeOfCode
SizeOfInitializedData
SizeOfUninitializedData
AddressOfEntryPoint
BaseOfCode
;NTadditionalfields.
ImageBase
SectionAlignment
rq1
rd
1
FileAlignment
rd1
MajorOperatingSystemVersionrw1
MinorOperatingSystemVersionrw1
MajorImageVersion
MinorImageVersion
MajorSubsystemVersion
MinorSubsystemVersion
Win32VersionValue
rw1
rw1
rw1
rw1
rd1
rd1
rd1
rd1
rw1
rw1
SizeOfImage
SizeOfHeaders
CheckSum
Subsystem
DllCharacteristics
SizeOfStackReserve
SizeOfStackCommit
SizeOfHeapReserve
SizeOfHeapCommit
LoaderFlags
rq1
rq1
rq1
rq1
rd1
rd1
NumberOfRvaAndSizes
;IMAGE_DATA_DIRECTORY
DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
DataDirectory
IMAGE_DATA_DIRECTORY
rb
(IMAGE_NUMBEROF_DIRECTORY_ENTRIES-1)*(sizeof.IMAGE_DATA_DIRECTORY)
ends
IMAGE_SIZEOF_NT_OPTIONAL64_HEADER=240
IMAGE_NT_OPTIONAL_HDR64_MAGIC
structIMAGE_NT_HEADERS64
=020Bh
Signature
rd1
FileHeader
OptionalHeader
IMAGE_FILE_HEADER
IMAGE_OPTIONAL_HEADER64
ends
IMAGE_NT_SIGNATURE
leardx,[file_buf]
=PE
cmp[rdx+IMAGE_DOS_HEADER.e_magic],IMAGE_DOS_SIGNATURE
jnzreconstruct_crc_L9
moveax,[rdx+IMAGE_DOS_HEADER.e_lfanew]
addrax,rdx
cmp[rax+IMAGE_NT_HEADERS64.Signature],IMAGE_NT_SIGNATURE
jnzreconstruct_crc_L9
cmp
[rax+IMAGE_NT_HEADERS64.FileHeader.Machine],IMAGE_FILE_MACHINE_AMD64
jnzreconstruct_crc_L9
cmp
[rax+IMAGE_NT_HEADERS64.OptionalHeader.Magic],IMAGE_NT_OPTIONAL_HDR64_M
AGIC
jnzreconstruct_crc_L9
;CRC
;eraseoriginalfilecrc
and[rax+IMAGE_NT_HEADERS64.OptionalHeader.CheckSum],0
;ecx=size
;rdx=file_buf
movr10d,ecx
shrecx,1
xorr9d,r9d
xorr8d,r8d
calculate_checksum:
movr9w,[rdx]
addr8d,r9d
movr9w,r8w
shrr8d,16
addr8d,r9d
addrdx,2
loop
calculate_checksum
addr8d,r10d
mov[rax+IMAGE_NT_HEADERS64.OptionalHeader.CheckSum],r8d
;Checksumdone
reconstruct_crc_L9:
ret
;//总体实现:相当于main函数
;//基本流程:read_system_file-patch_bytes-reconstruct_crc-
write_system_file
start:
push
rbx
subrsp,8*(4+2)
learcx,[file0]
call
read_system_file
oreax,eax
movebx,eax
jzexit_failed
movedx,ebx
learcx,[file0ed]
;sizeoffile
;sizeofthewholefile
;pointertopatchingdata
call
patch_bytes
movedx,ebx
learcx,[file3ed]
call
patch_bytes
movedx,ebx
learcx,[file3ed]
call
patch_bytes
movedx,ebx
learcx,[file3ed]
call
patch_bytes
movecx,ebx
;sizeofthewholefile
reconstruct_crc
;sizeofthewholefile
call
movedx,ebx
learcx,[file0n]
call
write_system_file
cmpeax,ebx
jnzexit_delete_file0n
learcx,[file1]
call
read_system_file
oreax,eax
movebx,eax
jnzL0
learcx,[file2]
call
read_system_file
85
oreax,eax
movebx,eax
jzexit_failed
L0:movedx,ebx
learcx,[file1ed]
call
patch_bytes
movedx,ebx
learcx,[file2ed]
call
patch_bytes
movedx,ebx
learcx,[file3ed]
call
patch_bytes
movedx,ebx
learcx,[file3ed]
call
patch_bytes
movedx,ebx
learcx,[file3ed]
call
patch_bytes
movecx,ebx
call
reconstruct_crc
movedx,ebx
learcx,[file1n]
call
write_system_file
cmpeax,ebx
jzexit_success
;jmpexit_delete_file1n_file0n
exit_delete_file1n_file0n:
learcx,[file1n]
call
[DeleteFileA]
exit_delete_file0n:
learcx,[file0n]
call
[DeleteFileA]
exit_failed:
learbx,[msg_failed]
jmpexit_msg
exit_success:
learbx,[msg_success]
exit_msg:
;STD_OUTPUT_HANDLE
;INVALID_HANDLE_VALUE
=-11
=-1
;movrcx,STD_OUTPUT_HANDLE
push
STD_OUTPUT_HANDLE
poprcx
call
push
[GetStdHandle]
rax
poprcx
ifINVALID_HANDLE_VALUE=-1
incrax
else
cmprax,INVALID_HANDLE_VALUE
endif
jzexit
andqword[rsp+8*(4+0)],0
lear9,[rsp+8*(4+1)]
movr8d,msg_size
;leardx,[rbx]
push
rbx
poprdx
lea
rcx,[rcx]
call
xor
add
pop
;alreadyset
[WriteFile]
eax,eax
rsp,8*(4+2)
rbx
exit:
ret


接下来要用到批处理了,光有打过补丁的winload.exe和ntoskrnl.exe还不行,还需要建立新的BCD入口,把PEAUTH服务设为手动,防止在登陆时蓝屏:


@ECHOOFF
ECHO.
ECHOCreatingpatchedcopiesofwinload,ntkrnlmp/ntoskrnl...
ECHO.
patch.exe
ECHO.
ECHOCreatingBCDEntry...
ECHO.
setENTRY_GUID={46595952-454E-4F50-4747-554944FFFFFF}
bcdedit-create%ENTRY_GUID%-dDriverSigning&PatchGuardDisabled
-applicationOSLOADER
bcdedit-set%ENTRY_GUID%devicepartition=%SYSTEMDRIVE%
bcdedit-set%ENTRY_GUID%osdevicepartition=%SYSTEMDRIVE%
bcdedit-set%ENTRY_GUID%systemroot\Windows
bcdedit-set%ENTRY_GUID%path\Windows\system32\freeload.exe
bcdedit-set%ENTRY_GUID%kernelgoodkrnl.exe
bcdedit-set%ENTRY_GUID%recoveryenabled0
bcdedit-set%ENTRY_GUID%nxOptOut
bcdedit-set%ENTRY_GUID%nointegritychecks1
bcdedit-set%ENTRY_GUID%testsigning1
bcdedit-displayorder%ENTRY_GUID%-addlast
bcdedit-timeout5
bcdedit-default%ENTRY_GUID%
ECHO.
ECHOSettingPEAUTHservicetomanual...(avoidBSODatloginscreen)
ECHO.
scconfigpeauthstart=demand
ECHO.
ECHOComplete!
ECHO.
PAUSE


不得不提的是,在代码里似乎有一段跟破解PatchGuard和数字签名无关的内容,作者在帖子里说sowhenyoureboot,Patchguardisnotintialized,driverdigitalsignaturesarenotnecessary,canonicaladdressformoflongmodevirtualmemoryischeckedcorrectly(长模式虚拟内存的规范地址形式被正确检查?就是加粗的这句,我尚未明白它的意义,他还举了“不规范”的地址形式,如:0000800000000000h、FFFF7FFFFFFFFFFFh)。如果有哪位读者明白它的意义,还请不吝赐教。本文代码在WINDOWS7X64和WINDOWS2008R2下测试成功,效果就是选择了相应的内核启动项后可以加载没有任何签名的内核驱动,也可以进行KernelInlineHook而不蓝屏。

本文内容所提及均为本地测试或经过目标授权同意,旨在提供教育和研究信息。作者不鼓励或支持任何形式的非法软件破解行为。