strcpy(KrnlInfo->HalName,AnsiString.Buffer);
KrnlInfo->ModuleBase[1]=(DWORD)DataTableEntry->DllBase; if ( NT_SUCCESS(Status) ) {
RtlFreeAnsiString(&AnsiString); //释放空间 }
count++; if(count==2) {
return TRUE; } }
NextEntry = NextEntry->Flink; }
return FALSE;
}
2,在内核驱动中把MS未导出的函数定义成函数指针,然后用户层通过解析PDB文件得到真正的函数地址传进内核驱动,定义如下:
NTSTATUS (WINAPI *PsResumeThread)(IN PETHREAD Thread,OUT PULONG PreviousSuspendCount OPTIONAL);
NTSTATUS (WINAPI *PsTerminateProcess)(IN PEPROCESS Process,IN NTSTATUS Status);
PEPROCESS (WINAPI *PsGetNextProcess) (IN PEPROCESS Process);
PETHREAD (WINAPI *PsGetNextProcessThread) (IN PEPROCESS Process,IN PETHREAD Thread);
VOID (WINAPI *PsQuitNextProcessThread) (IN PETHREAD Thread);
VOID (WINAPI *PsCallImageNotifyRoutines)(IN PUNICODE_STRING FullImageName,IN HANDLE ProcessId, IN PIMAGE_INFO ImageInfo );
NTSTATUS (WINAPI *PsSuspendThread) (IN PETHREAD Thread,OUT PULONG PreviousSuspendCount );
NTSTATUS (WINAPI *MmGetFileNameForAddress) (IN PVOID ProcessVa,OUT PUNICODE_STRING FileName);
NTSTATUS (WINAPI *MmGetFileNameForSection) (IN PVOID SectionObject,OUT POBJECT_NAME_INFORMATION *FileNameInfo);
NTSTATUS (WINAPI * MmCopyVirtualMemory)(IN PEPROCESS FromProcess,IN CONST VOID *FromAddress,IN PEPROCESS ToProcess,OUT PVOID ToAddress,IN SIZE_T BufferSize,IN KPROCESSOR_MODE PreviousMode,OUT PSIZE_T NumberOfBytesCopied);
NTSTATUS (WINAPI *ObDuplicateObject) (IN PEPROCESS SourceProcess,IN HANDLE SourceHandle,IN PEPROCESS TargetProcess OPTIONAL,OUT PHANDLE TargetHandle OPTIONAL,IN ACCESS_MASK DesiredAccess,IN ULONG HandleAttributes,IN ULONG Options,IN KPROCESSOR_MODE PreviousMode );
20
VOID (WINAPI *KeFreezeAllThreads) (VOID); VOID (WINAPI *KeThawAllThreads) (VOID);
VOID (FASTCALL *KiReadyThread)(IN PKTHREAD Thread); VOID (WINAPI * KiSetSwapEvent)();
BOOLEAN (WINAPI *KiSwapProcess) (IN PKPROCESS NewProcess,IN PKPROCESS OldProcess);
int (FASTCALL *KiSwapThread) ();
NTSTATUS (FASTCALL *MiMakeProtectionMask)(unsigned int a1);
NTSTATUS (WINAPI*MiProtectVirtualMemory) (IN PEPROCESS Process,IN PVOID *BaseAddress,IN PULONG RegionSize,IN ULONG NewProtectWin32,IN PULONG LastProtect);
NTSTATUS (WINAPI *PspCreateThread)(OUT PHANDLE ThreadHandle,IN ACCESS_MASK DesiredAccess,IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,IN HANDLE ProcessHandle,IN PEPROCESS ProcessPointer,OUT PCLIENT_ID ClientId OPTIONAL,IN PCONTEXT ThreadContext OPTIONAL,IN PINITIAL_TEB InitialTeb OPTIONAL,IN BOOLEAN CreateSuspended,IN PKSTART_ROUTINE StartRoutine OPTIONAL,IN PVOID StartContext);
void (WINAPI *IopDeallocateApc)(PVOID P, int a2, int a3, int a4, int a5);
NTSTATUS (WINAPI *LpcRequestWaitReplyPortEx) (IN PVOID PortAddress,IN PPORT_MESSAGE RequestMessage,OUT PPORT_MESSAGE ReplyMessage); VOID (FASTCALL *HalRequestSoftwareInterrupt) (KIRQL RequestIrql); VOID (FASTCALL *KiUnlockDispatcherDatabase)(KIRQL irql); VOID (WINAPI *KeContextFromKframes)(IN PKTRAP_FRAME TrapFrame,PKEXCEPTION_FRAME ExceptionFrame,PCONTEXT ContextFrame); VOID (WINAPI *KeContextToKframes) ( PKTRAP_FRAME TrapFrame,PKEXCEPTION_FRAME ExceptionFrame,IN PCONTEXT ContextFrame,IN ULONG ContextFlags,IN KPROCESSOR_MODE PreviousMode); BOOLEAN (WINAPI *KiCheckForAtlThunk) (IN PEXCEPTION_RECORD ExceptionRecord,IN PCONTEXT Context);
BOOLEAN (WINAPI *RtlDispatchException) (IN PEXCEPTION_RECORD ExceptionRecord,IN PCONTEXT ContextRecord);
BOOLEAN (WINAPI *KdIsThisAKdTrap) (IN PEXCEPTION_RECORD ExceptionRecord,IN PCONTEXT ContextRecord,IN KPROCESSOR_MODE PreviousMode);
VOID (WINAPI *KiSegSsToTrapFrame ) (IN PKTRAP_FRAME TrapFrame,IN ULONG SegSs);
VOID (WINAPI *KiEspToTrapFrame)(IN PKTRAP_FRAME TrapFrame,IN ULONG Esp); ULONG (WINAPI *KiCopyInformation) (IN OUT PEXCEPTION_RECORD
21
ExceptionRecord1,IN PEXCEPTION_RECORD ExceptionRecord2); BOOLEAN
(WINAPI *KiDebugRoutine) (
IN PKTRAP_FRAME TrapFrame,
IN PKEXCEPTION_FRAME ExceptionFrame, IN PEXCEPTION_RECORD ExceptionRecord, IN PCONTEXT ContextRecord,
IN KPROCESSOR_MODE PreviousMode, IN BOOLEAN SecondChance );
3,Ring3层程序调用微软提供的SymLoadModule64()函数把这两个内核PDB文件加载到Od进程空间,具体代码如下: //装入PDB文件
DWORD64 HxLoadSym(const char* szSymPath,unsigned long ulBase) {
DWORD dwFileSize=0; HANDLE hFile = NULL;
DWORD64 dw64ModAddress = 0;
hFile = CreateFile(szSymPath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL );
if( INVALID_HANDLE_VALUE == hFile ) {
_tprintf(_T(\when open %s: %d\szSymPath, GetLastError()); return 0; }
if( INVALID_FILE_SIZE == ( dwFileSize = GetFileSize(hFile, NULL)) ) {
_tprintf(_T(\GetLastError()); return 0; }
CloseHandle(hFile);
dw64ModAddress = SymLoadModule64(GetCurrentProcess(),NULL,(PSTR)szSymPath,NULL,ulBase,dwFileSize);
if( dw64ModAddress == 0 ) {
_tprintf(_T(\when SymLoadModule64(): %d \\n\
22
GetLastError()); return 0; }
return dw64ModAddress; }
4,对hal.dll和ntoskrnl.exe分别调用SymEnumSymbols()函数得到内核未导出的函数的地址,SymEnumSymbols()要求一个回调函数,它的类型是BOOL CALLBACK SymEnumSymbolsProc(PSYMBOL_INFO pSymInfo, ULONG SymbolSize, PVOID UserContext );我们可以根据pSymInfo->Name和我们要得到的未导出的函数的名字比较,如果相等,则返回函数地址。具体代码如下:
BOOL HxFindSymBols(DWORD64 pSym,PHX_DYNC_FUNCTION fnList,int nLen) {
g_Nlen=nLen; g_fnList=fnList;
if(!SymEnumSymbols( GetCurrentProcess(), pSym,
NULL, // Null point out that list all symbols SymEnumSymbolsProc, NULL)) {
_tprintf( _T(\when SymEnumSymbols(): %d \\n\GetLastError() ); }
return TRUE; } BOOL CALLBACK SymEnumSymbolsProc(PSYMBOL_INFO pSymInfo, ULONG SymbolSize, PVOID UserContext ) {
DWORD i;
char a[200]={0};
char funcname[60]={0}; if( pSymInfo != 0 ) {
strcpy(funcname,pSymInfo->Name); for(i=0;i if(strcmp(g_fnList[i].FunName,funcname)==0)//比较函数名字是否相等 { g_fnList[i].FunAddr=(DWORD)pSymInfo->Address; break; 23 } } } } return TRUE; 5.4 向Windows系统内核中加入我们自己的系统服务表 Windows系统中有两个系统服务表,一个是KeServiceDescriptorTable,还有一个是KeServiceDescriptorTableShadow,它们的区别就是如果线程是GUI线程,则这个线程最后会从KeServiceDescriptorTableShadow服务表中找系统调用的地址然后去调用,当Ring3层的API调用最终调用sysenter指令进入Ring0时,这条指令会让CPU的指令指针寄存器(EIP)指向KiFastCallEntry(),然后CPU会运行KiFastCallEntry(),kiFastCallEntry()函数会根据系统调用ID从KeServiceDescriptorTable表或者从KeServiceDescriptorTableShadow表找取对应的系统调用函数然后去调用它。下面是用Windbg调试器看的我机器上这两种系统服务表的情况: lkd> dd KeServiceDescriptorTable 8055d700 80505460 00000000 0000011c 805058d4 8055d710 00000000 00000000 00000000 00000000 8055d720 00000000 00000000 00000000 00000000 8055d730 00000000 00000000 00000000 00000000 lkd> dd KeServiceDescriptorTableShadow 8055d6c0 80505460 00000000 0000011c 805058d4 8055d6d0 bf99ce80 00000000 0000029b bf99db90 8055d6e0 00000000 00000000 00000000 00000000 8055d6f0 00000000 00000000 00000000 00000000 系统服务描述表结构定义如下 typedef struct _SERVICE_DESCRIPTOR_TABLE { PVOID *ServiceTable; //指向真正的系统服务地址表 PULONG CounterTable;//系统调用的记录,调用了多少次,在Check版本才有效 ULONG TableSize;//表的大小,Windows总共提供了多少个系统调用 PUCHAR ArgumentTable;//参数大小表,每个系统调用要的参数大小,大小以字节为单位 } SERVICE_DESCRIPTOR_TABLE, *PSERVICE_DESCRIPTOR_TABLE; 所以我们要做的是调用ExAllocatePool在Windows系统的非分页内存中分配空间,然后初始化它们。最后依次改变KeServiceDescriptorTable和KeServiceDescriptorTableShadow系统服务表的ServiceTable成员和 24