好多天了,都在自己码字,百度,google 查的都烦了。不过为了学习忍了。
再次记上一篇笔记,这些代码很多前辈都写过,写的不好,大家请轻拍
今天笔记说的是,进程遍历 线程遍历,以及 特定模块线程拦截(不知道拦截对不对,我是这么理解的了)
文件保护感觉算不上,大家还是不要看了,本人新手,求轻拿轻放
第一部分:进程、线程遍历
/*********************************************枚举进程线程 通过Eprocess*****************************************/
//函数、结构体声明
typedef struct _SYSTEM_THREAD_INFORMATION {
LARGE_INTEGER KernelTime;
LARGE_INTEGER UserTime;
LARGE_INTEGER CreateTime;
ULONG WaitTime;
PVOID StartAddress;
CLIENT_ID ClientId;
KPRIORITY Priority;//优先级
LONG BasePriority;
ULONG ContextSwitchCount;
ULONG State;
KWAIT_REASON WaitReason;
}SYSTEM_THREAD_INFORMATION, *PSYSTEM_THREAD_INFORMATION;
typedef struct _SYSTEM_PROCESS_INFORMATION {
ULONG NextEntryOffset;
ULONG NumberOfThreads;
LARGE_INTEGER Reserved[3];
LARGE_INTEGER CreateTime;
LARGE_INTEGER UserTime;
LARGE_INTEGER KernelTime;
UNICODE_STRING ImageName;
KPRIORITY BasePriority;
HANDLE ProcessId;
HANDLE InheritedFromProcessId;
ULONG HandleCount;
ULONG Reserved2[2];
ULONG PrivatePageCount;
VM_COUNTERS VirtualMemoryCounters;
IO_COUNTERS IoCounters;
SYSTEM_THREAD_INFORMATION Threads[0];
} SYSTEM_PROCESS_INFORMATION, *PSYSTEM_PROCESS_INFORMATION;
#define SystemProcessInformation 5 //5 号函数
extern "C" NTSYSAPI
NTSTATUS
NTAPI
ZwQuerySystemInformation (
__in ULONG SystemInformationClass,
__out_bcount_opt(SystemInformationLength) PVOID SystemInformation,
__in ULONG SystemInformationLength,
__out_opt PULONG ReturnLength
);
#define SystemModuleInformation 11 //11 号函数
typedef struct _SYSTEM_MODULE_INFORMATION {
ULONG Reserved [2];
PVOID Base;
ULONG Size;
ULONG Flags;
USHORT Index;
USHORT Unknown;
USHORT LoadCount;
USHORT ModuleNameOffset;
CHAR ImageName [256];
} SYSTEM_MODULE_INFORMATION, *PSYSTEM_MODULE_INFORMATION;
typedef struct {
ULONG dwNumberOfModules;
SYSTEM_MODULE_INFORMATION smi[1];
} MODULES, *PMODULES;
char * GetTreadModuleNameByAddress(ULONG threadStartAddress)
{
PMODULES moduleStruct;
DWORD RealSize;
NTSTATUS status;
//先调用一次获取大小
ULONG MaxAddress;
ULONG MinAddress;
char *ModuleName;
status=ZwQuerySystemInformation(SystemModuleInformation,NULL,0,&RealSize);
if(status==STATUS_INFO_LENGTH_MISMATCH)
{
moduleStruct=(PMODULES)ExAllocatePool(NonPagedPool,RealSize);//申请同等大小的内存,存放
status=ZwQuerySystemInformation(SystemModuleInformation,moduleStruct,RealSize,&RealSize);
if(status==STATUS_SUCCESS)
{
//DbgPrint("Module Count: %d \r\n",moduleStruct->dwNumberOfModules);
for (int i=0;i<moduleStruct->dwNumberOfModules;i++)
{
MinAddress = (ULONG) moduleStruct->smi[i].Base;
MaxAddress =(ULONG) ((ULONG) moduleStruct->smi[i].Base + moduleStruct->smi[i].Size);
ModuleName = moduleStruct->smi[i].ImageName ;
//DbgPrint("Module Name: %s Base:%x \r\n",moduleStruct->smi[i].ImageName,moduleStruct->smi[i].Base);
if(threadStartAddress>MinAddress && threadStartAddress <= MaxAddress)
{
goto _End;
}
}
}
_End:
//释放内存
ExFreePool(moduleStruct);
moduleStruct=NULL;
}
return ModuleName;
}
//typedef struct _CLIENT_ID {
// HANDLE UniqueProcess;
// HANDLE UniqueThread;
//} CLIENT_ID;
//typedef CLIENT_ID *PCLIENT_ID;
//增加了模块显示
void EnumProcessListAndThreadByEPRPCESS()
{
PSYSTEM_PROCESS_INFORMATION psysInfo;
PVOID dataBuffer=NULL;
DWORD DwSzie=0;
NTSTATUS status;
ANSI_STRING ProcesNameStr;
UNICODE_STRING ProcessUnName;
status = ZwQuerySystemInformation(SystemProcessInformation,NULL,0,&DwSzie);
if(status==STATUS_INFO_LENGTH_MISMATCH)
{
dataBuffer=ExAllocatePool(NonPagedPool,DwSzie);
status=ZwQuerySystemInformation(SystemProcessInformation,dataBuffer,DwSzie,&DwSzie);
if (NT_SUCCESS(status))
{
psysInfo=(PSYSTEM_PROCESS_INFORMATION)dataBuffer;
while(1)
{
RtlInitUnicodeString(&ProcessUnName,psysInfo->ImageName.Buffer);
RtlUnicodeStringToAnsiString(&ProcesNameStr,&ProcessUnName,TRUE);
DbgPrint("PID: %d ,ProcessName: %ws \r\n",psysInfo->ProcessId,psysInfo->ImageName.Buffer);
if(strcmp(ProcesNameStr.Buffer,"System")==0)
{
DbgPrint("***************************线程信息Start*********************** \r\n");
PEPROCESS CurrentProcess;
PKPROCESS Kprocess;
PETHREAD _thread;
PKTHREAD kThread;
LIST_ENTRY *LCink;
LIST_ENTRY *LNink;
CLIENT_ID *_CLIENT_ID;
DWORD ThreadID=0;
DWORD ThreadStartAddress;
DWORD ThreadTeb;
char *ModuleName;
PsLookupProcessByProcessId(psysInfo->ProcessId,&CurrentProcess);
if(CurrentProcess)
{
Kprocess=(PKPROCESS)CurrentProcess;
LCink=(LIST_ENTRY *)((ULONG)Kprocess+0x50);
LNink=LCink->Flink;
while(LNink!=LCink)
{
_thread=(PETHREAD)((ULONG)LNink-0x1b0);
kThread=(PKTHREAD)_thread;
/*kd> dt _CLIENT_ID
nt!_CLIENT_ID
+0x000 UniqueProcess : Ptr32 Void
+0x004 UniqueThread : Ptr32 Void*/
//ThreadID=*(ULONG *)((*(ULONG *)((ULONG)_thread+0x1EC))+0x4);
_CLIENT_ID=(PCLIENT_ID)((ULONG)_thread+0x1EC);
ThreadID=(DWORD)(_CLIENT_ID->UniqueThread);
ThreadStartAddress=*(ULONG *)((ULONG)_thread+0x224);
ThreadTeb=*(ULONG *)((ULONG)kThread+0x20);
ModuleName = GetTreadModuleNameByAddress(ThreadStartAddress);
DbgPrint("线程ID:%d EPROCESS: %x TEB: %08x ,StartAddress:%08x ModuleName : %s\r\n",ThreadID,_thread,ThreadTeb,ThreadStartAddress,ModuleName);
LNink=LNink->Flink;
}
}
DbgPrint("***************************线程信息End************************* \r\n");
}
//枚举系统进程的线程
if(psysInfo->NextEntryOffset==0)
{
break;
}
psysInfo=(PSYSTEM_PROCESS_INFORMATION)((ULONG)psysInfo+psysInfo->NextEntryOffset);
}
}
}
}
/*********************************************枚举进程线程 通过Eprocess*****************************************/
说明:进程遍历直接通过 ZwQuerySystemInformation 函数的第 5 号功能,来枚举。
ZwQuerySystemInformation 的更多功能,请参考wrk 。
线程遍历采用 PKPROCESS 和 PETHREAD 来遍历。
(我的理解 : PEPROCESS 头部 就是 PKPROCESS ,PETHREAD 头部就是PKTHREAD, wrk 中有定义。 )
PKPROCESS + 0x50 是 LIST_ENTRY 一个链表 ThreadListHead 指向的是 PKTHREAD + 0x1b0 的地方。
遍历时,获取到ThreadListHead 通过遍历链表得到每个线程的PKTHREAD 然后得到线程的具体信息。详细的看代码。
这里加上了 线程模块的显示,不过只是实现了系统进程中线程模块的显示。实现方式,通过线程的开始地址,去比较每个模块的BASE 和 BASE + SIZE 。如果在此区间,就说明线程在此模块中。
模块的遍历使用 ZwQuerySystemInformation 11号功能。
第二部分:HookKiReadyThread 遍历拦截线程
/**********************************Hook KiReadyThread 拦截 线程 激活 Start*******************************************/
ULONG KiReadyThreadHookAddr;
ULONG KiReadyThreadJmpAddr;
//dt _ETHREAD
// nt!_ETHREAD
// +0x000 Tcb : _KTHREAD
// +0x1c0 CreateTime : _LARGE_INTEGER
// +0x1c0 NestedFaultCount : Pos 0, 2 Bits
// +0x1c0 ApcNeeded : Pos 2, 1 Bit
// +0x1c8 ExitTime : _LARGE_INTEGER
// +0x1c8 LpcReplyChain : _LIST_ENTRY
// +0x1c8 KeyedWaitChain : _LIST_ENTRY
// +0x1d0 ExitStatus : Int4B
// +0x1d0 OfsChain : Ptr32 Void
// +0x1d4 PostBlockList : _LIST_ENTRY
// +0x1dc TerminationPort : Ptr32 _TERMINATION_PORT
// +0x1dc ReaperLink : Ptr32 _ETHREAD
// +0x1dc KeyedWaitValue : Ptr32 Void
// +0x1e0 ActiveTimerListLock : Uint4B
// +0x1e4 ActiveTimerListHead : _LIST_ENTRY
// +0x1ec Cid : _CLIENT_ID
// +0x1f4 LpcReplySemaphore : _KSEMAPHORE
// +0x1f4 KeyedWaitSemaphore : _KSEMAPHORE
// +0x208 LpcReplyMessage : Ptr32 Void
// +0x208 LpcWaitingOnPort : Ptr32 Void
// +0x20c ImpersonationInfo : Ptr32 _PS_IMPERSONATION_INFORMATION
// +0x210 IrpList : _LIST_ENTRY
// +0x218 TopLevelIrp : Uint4B
// +0x21c DeviceToVerify : Ptr32 _DEVICE_OBJECT
// +0x220 ThreadsProcess : Ptr32 _EPROCESS
// +0x224 StartAddress : Ptr32 Void
// +0x228 Win32StartAddress : Ptr32 Void
// +0x228 LpcReceivedMessageId : Uint4B
// +0x22c ThreadListEntry : _LIST_ENTRY
ULONG TpModuleStartAddr=0;
ULONG TpModuleSize=0;
BYTE OldKiReadyData[5]={0};
BYTE JmpKiReadyData[5]={0xe9,0,0,0,0};
extern "C" BOOLEAN
PsIsThreadTerminating(
__in PETHREAD Thread
);
//根据KeSetEventBoostPriority 获取 KiReadThread 地址,通过特征码搜索
//KeSetEventBoostPriority 是ntoskrnl导出的函数,KiReadThread未导出
ULONG GetKiReadyThreadAddr()
{
UNICODE_STRING UncodeStr;
RtlInitUnicodeString(&UncodeStr,L"KeSetEventBoostPriority");
//1.先获取 KeSetEventBoostPriority
ULONG KeSetEventBoostPriorityAddr=(ULONG)MmGetSystemRoutineAddress(&UncodeStr);
DbgPrint("KeSetEventBoostPriority Address:%x",KeSetEventBoostPriorityAddr);
//开始搜索特征码:
PCHAR p=(char *)KeSetEventBoostPriorityAddr;
//88566e mov byte ptr [esi+6Eh],dl
//c6466d10 mov byte ptr [esi+6Dh],10h
//884e33 mov byte ptr [esi+33h],cl
//807e6f04 cmp byte ptr [esi+6Fh],4
ULONG KiReadyThreadAddr=0;
for (int i=0;i<400;i++,p++)
{
//DbgPrint("字节:%x",(*p));
if(*(p+1)==0x56 &&
*(p+2)==0x6e &&
*(p+4)==0x46 &&
*(p+5)==0x6d &&
*(p+6)==0x10 &&
*(p+8)==0x4e &&
*(p+9)==0x33 &&
*(p+11)==0x7e &&
*(p+12)==0x6f &&
*(p+13)==0x04)
{
ULONG AbuAddr=(ULONG)(p+34);
KiReadyThreadAddr=AbuAddr+(*((WORD *)(p+35)))+5;//获取的是相对函数的相对偏移(计算hook 是一样的道理)
DbgPrint("KiReadyThread Addr: %x",KiReadyThreadAddr);
break;
}
}
return KiReadyThreadAddr;
}
//过滤函数s
int _stdcall IsPassThread(IN PKTHREAD Thread)
{
PETHREAD Ethread;
ULONG StartAddressThread=0;
ULONG StartOffset=0x224;
if(!MmIsAddressValid(Thread))
{
return 0;
}
if(PsIsThreadTerminating((PETHREAD)Thread))
{
return 0;
}
Ethread=(PETHREAD)Thread;
if(!MmIsAddressValid((PULONG)((ULONG)Ethread+StartOffset)))
{
return 0;
}
StartAddressThread=*((ULONG *)((ULONG)Ethread+StartOffset));
if(TpModuleStartAddr>0 && TpModuleSize>0 )
{
if(StartAddressThread>TpModuleStartAddr && StartAddressThread<=TpModuleStartAddr+TpModuleSize )
{
DbgPrint("TesSafe.sys 线程:开始地址-> %x\r\n",StartAddressThread);
}
}
return 0;
}
__declspec (naked) MyHookKiReadyThreadFun()
{
__asm
{
mov edi,edi
push ebp
mov ebp,esp
pushad
pushfd
push ecx
call IsPassThread
cmp eax,0 //如果不是0就跳,说明是拦截的函数
jnz _PassThread
popfd
popad
jmp KiReadyThreadJmpAddr
_PassThread:
popfd
popad
ret
}
}
VOID
NotifyRoutineTp(
IN PUNICODE_STRING FullImageName,
IN HANDLE ProcessId, // pid into which image is being mapped
IN PIMAGE_INFO ImageInfo
)
{
if(strEnd(FullImageName->Buffer,L"TesSafe.sys"))
{
DbgPrint("TesSafe.sys-> BASE : %x \r\n",ImageInfo->ImageBase);
TpModuleStartAddr=(ULONG)(ImageInfo->ImageBase);
TpModuleSize=(ULONG)(ImageInfo->ImageSize);
}
}
NTSTATUS HookKiReadyThread()
{
KiReadyThreadHookAddr=GetKiReadyThreadAddr();
if(KiReadyThreadHookAddr)
{
//1.先加载系统回调
PsSetLoadImageNotifyRoutine(NotifyRoutineTp);
RtlCopyMemory(OldKiReadyData,(VOID *)KiReadyThreadHookAddr,5);
KiReadyThreadJmpAddr=KiReadyThreadHookAddr+5;
*(ULONG *)(&JmpKiReadyData[1])=(ULONG)MyHookKiReadyThreadFun-KiReadyThreadHookAddr-5;
POFF();
RtlCopyMemory((VOID *)KiReadyThreadHookAddr,JmpKiReadyData,5);
PON();
DbgPrint("KiReadyThread Hook 成功!\r\n");
}else
{
DbgPrint("KiReadyThread Hook 失败!\r\n");
}
return STATUS_SUCCESS;
}
NTSTATUS UnHookKiReadyThread()
{
PsRemoveLoadImageNotifyRoutine(NotifyRoutineTp);
POFF();
RtlCopyMemory((VOID *)KiReadyThreadHookAddr,OldKiReadyData,5);
PON();
DbgPrint("KiReadyThread UnHook 成功!\r\n");
return STATUS_SUCCESS;
}
/**********************************Hook KiReadyThread 拦截 线程 激活 End*******************************************/
说明: 本次实验用的 T某P 当作例子。
先加载一个 系统回调 NotifyRoutineTp 监视一下 sys 的加载。
发现加载了,立刻HOOK KiReadyThread 拦截 线程的激活。
HOOK KiReadyThread:因为KiReadyThread 是未导出的,我的方法是在wrk 中搜索次函数,查看是否在某个导出函数调用了KiReadyThread ,然后通过特征码搜索的方式获取 KiReadyThread 函数首地址,本次使用的是KeSetEventBoostPriority 导出函数。
导出函数获取首地址的方法 MmGetSystemRoutineAddress
搜索的特征码:
//88566e mov byte ptr [esi+6Eh],dl
//c6466d10 mov byte ptr [esi+6Dh],10h
//884e33 mov byte ptr [esi+33h],cl
//807e6f04 cmp byte ptr [esi+6Fh],4
不清楚的话,可以在windbg中看一下。
HOOK 和处理的细节看代码。
第三部分:Hook IoCreateFile 保护文件不被打开
/*************************************文件保护Hook IoCreateFile Start********************************************/
ULONG FunaddrIoCreateFile=0;
ULONG JmpAddrIoCreateFile=0;
BYTE OldDataIoCreateFile[5]={0};
BYTE JmpDataIoCreateFile[5]={0xE9,0,0,0,0};
typedef NTSTATUS
(__stdcall *NewIoCreateFile)(
OUT PHANDLE FileHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes,
OUT PIO_STATUS_BLOCK IoStatusBlock,
IN PLARGE_INTEGER AllocationSize OPTIONAL,
IN ULONG FileAttributes,
IN ULONG ShareAccess,
IN ULONG Disposition,
IN ULONG CreateOptions,
IN PVOID EaBuffer OPTIONAL,
IN ULONG EaLength,
IN CREATE_FILE_TYPE CreateFileType,
IN PVOID ExtraCreateParameters OPTIONAL,
IN ULONG Options
);
NewIoCreateFile _NewIoCreateFile;
__declspec (naked) void IoCreateFileHookFun(...)
{
__asm
{
mov edi,edi
push ebp
mov ebp,esp
jmp JmpAddrIoCreateFile;
}
}
ULONG strEnd(PWCHAR dest,PWCHAR sub)
{
if (dest == NULL && sub == NULL)
return 0;
int ulDest = wcslen(dest);
int ulSub = wcslen(sub);
if (ulSub == 0 || ulSub > ulDest)
return 0;
return !wcscmp(&dest[ulDest - ulSub],sub);
}
NTSTATUS MyIoCreateFile(
OUT PHANDLE FileHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes,
OUT PIO_STATUS_BLOCK IoStatusBlock,
IN PLARGE_INTEGER AllocationSize OPTIONAL,
IN ULONG FileAttributes,
IN ULONG ShareAccess,
IN ULONG Disposition,
IN ULONG CreateOptions,
IN PVOID EaBuffer OPTIONAL,
IN ULONG EaLength,
IN CREATE_FILE_TYPE CreateFileType,
IN PVOID ExtraCreateParameters OPTIONAL,
IN ULONG Options
)
{
NTSTATUS status;
ANSI_STRING FullNameAnsi;
_NewIoCreateFile=(NewIoCreateFile)IoCreateFileHookFun;
status=_NewIoCreateFile(FileHandle,DesiredAccess,ObjectAttributes,IoStatusBlock,AllocationSize,FileAttributes,ShareAccess,Disposition,CreateOptions,EaBuffer,EaLength,CreateFileType,ExtraCreateParameters,Options);
if(MmIsAddressValid(ObjectAttributes))
{
if(MmIsAddressValid(ObjectAttributes->ObjectName) && ObjectAttributes->ObjectName->Buffer!=NULL)
{
RtlUnicodeStringToAnsiString(&FullNameAnsi,ObjectAttributes->ObjectName,TRUE);
if(strstr(FullNameAnsi.Buffer,"myx123123.txt"))
{
DbgPrint("OpenFileName:%Z",&FullNameAnsi);
*(DWORD *)FileHandle=-1;
return STATUS_ACCESS_DENIED;
}
//DbgPrint("OpenFileName:%ws",ObjectAttributes->ObjectName->Buffer);
}
}
return status;
}
NTSTATUS HookIoCreateFile()
{
//获取函数地址
UNICODE_STRING FunName;
RtlInitUnicodeString(&FunName,L"IoCreateFile");
FunaddrIoCreateFile=(ULONG)MmGetSystemRoutineAddress(&FunName);
if(FunaddrIoCreateFile)
{
DbgPrint("IoCreateFile 函数地址:%x ",FunaddrIoCreateFile);
RtlCopyMemory(OldDataIoCreateFile,(PVOID)FunaddrIoCreateFile,5);
JmpAddrIoCreateFile=FunaddrIoCreateFile+5;
*((ULONG *)(&JmpDataIoCreateFile[1]))=(ULONG)MyIoCreateFile-FunaddrIoCreateFile-5;
POFF();
RtlCopyMemory((PVOID)FunaddrIoCreateFile,JmpDataIoCreateFile,5);
PON();
}else
{
DbgPrint("IoCreateFile 函数获取失败!");
return 0;
}
return 1;
}
NTSTATUS UnHookIoCreateFile()
{
POFF();
RtlCopyMemory((PVOID)FunaddrIoCreateFile,OldDataIoCreateFile,5);
PON();
return 1;
}
/*************************************文件保护Hook IoCreateFile End********************************************/
说明:这个就比较简单了,直接过滤一下 要操作的文件名就好了。
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课