НЕКОТОРЫЕ СТРУКТУРЫ И ПСЕВДОКОД =============================== Золотой красотой сумрака И солнцем, стоящем низко в нашем небе Охотящимися тенями деревьев И могилами, загипнотизирован я. (с) by Anathema В основном этот текст - склейка моих черновиков, чужих и моих хэдеров. Мне лень приводить это все в порядок... ;) 00. ETHREAD, EPROCESS и сопровождающие их структуры. 01. Псевдокод функций ядра, работающих с рабочим набором. (NT40) 02. Псевдокод для функции MmInitMachineDependents(). (NT40) 03. Псевдокод для функции MmAccessFault. (NT40) 04. Вытеснение страниц в файлы откачки. Псевдокод. (NT40) 05. Создание процесса. Псевдокод. (NT40) 06. Псевдокод KeAttachProcess/KeDetachProcess. (NT40) 07. Псевдокод ExMapHandleToPointer (NT5.0) 08. Псевдокод функций, работающих с объектом "секция" (NT50) 09. Некоторые системные сервисы. 00.ETHREAD, EPROCESS и сопровождающие их структуры ================================================== При исследовании ядра, практически не возможно обойтись без знания основных структур, представляющих в системе поток и процесс. Ниже описаны эти и некоторые другие сопутствующие недокументированные структуры для NT4.0 и NT5.0. /***************************NT4.0 and NT5.0**********************************/ typedef struct APC_STATE_POINTER //size : 0x8 { PKAPC_STATE SavedApcState; //0x00 PKAPC_STATE ApcState; //0x04 }APC_STATE_POINTER; /***************************************************************************/ typedef struct _KAPC_STATE //Size: 0x18 { LIST_ENTRY ApcListHead[2]; //0x00 EPROCESS* Process; //0x10 BYTE KernelApcInProgress; //0x14 BYTE KernelApcPending; //0x15 BYTE UserApcPending; //0x16 BYTE Reserved; //0x17 }KAPC_STATE, *PKAPC_STATE; /***************************************************************************/ typedef enum _THREADSTATE { ThreadStateInitialized, ThreadStateReady, ThreadStateRunning, ThreadStateStandby, ThreadStateTerminated, ThreadStateWaiting, ThreadStateTransition, ThreadStateExecutive, ThreadStateFreePage, ThreadStatePageIn, ThreadStatePoolAllocation, ThreadStateDelayExecution, ThreadStateSuspended, ThreadStateUserRequest, ThreadStateEventPairHigh, ThreadStateEventPairLow, ThreadStateLpcReceive, ThreadStateLpcReply, ThreadStateVirtualMemory, ThreadStatePageOut, ThreadStateSpare1, ThreadStateSpare2, ThreadStateSpare3, ThreadStateSpare4, ThreadStateSpare5, ThreadStateSpare6, ThreadStateSpare7, ThreadStateUnknown } THREADSTATE; /***************************************************************************/ typedef struct _ServiceDescriptor{ DWORD* ServiceTable; /*указатель на таблицу адресов сервисов*/ DWORD Reserved; /* назначение не известно, всегда 0. Похоже - для выравнивания.*/ DWORD ServiceLimit; /* Число сервисов в таблице */ BYTE* KiArgumentTable; /* указатель на размер массива параметров в стеке для сервисов */ /* фактически равен 4*количество параметров) */ }ServiceDescriptor; // ServiceDescriptor ServiceTable[4]; /***************************************************************************/ typedef struct _KPROCESS{ // for NT4.0 and NT5.0 DISPATCHER_HEADER Header; //0 LIST_ENTRY ProfileListHead; //0x10 uint32 DirectoryTableBase; //0x18 uint32 HyperspaceBase; //0x1c KGDTENTRY LdtDescriptor; //0x20 KIDTENTRY Int21Descriptor; //0x28 uint16 IopmOffset; //0x30 byte Iopl; //0x32 byte VdmFlag; //0x33 uint32 ActiveProcessors; //0x34 uint32 KernelTime; //0x38 uint32 UserTime; //0x3c LIST_ENTRY ReadyListHead; //0x40 LIST_ENTRY SwapListEntry; //0x48 LIST_ENTRY ThreadListHead; //0x50 uint32 ProcessLock; //0x58 uint32 Affinity; //0x5c uint16 StackCount; //0x60 char BasePriority; //0x62 char ThreadQuantum; //0x63 byte AutoAlignment; //0x64 byte State; //0x65 union ready,idle,transition byte ThreadSeed; //0x66 byte DisableBoost; //0x67 byte PowerState; //0x68 byte DisableQuantum; //0x69 byte Spare[2]; //0x6a }KPROCESS, *PKPROCESS; /***************************************************************************/ typedef struct _KAPC_STATE{ // NT4.0 and NT5.0 LIST_ENTRY ApcListHead[2]; KPROCESS *Process; byte KernelApcInProgress; byte KernelApcPending; byte UserApcPending; byte Padding; } KAPC_STATE; /***************************************************************************/ typedef struct _KWAIT_BLOCK { // NT4.0 and NT5.0 LIST_ENTRY WaitListEntry; KTHREAD *Thread; void *Object; KWAIT_BLOCK *NextWaitBlock; uint16 WaitKey; uint16 WaitType; }KWAIT_BLOCK; /***************************************************************************/ typedef struct _KTHREAD{ // for NT4.0 and 5.0 DISPATCHER_HEADER Header; //0x00 LIST_ENTRY MutantListHead; //0x10 void *InitialStack; //0x18 void *StackLimit; //0x1c void *Teb; //0x20 void *TlsArray; //0x24 void *KernelStack; //0x28 byte DebugActive; //0x2c byte State; //0x2d byte Alerted[2]; //0x2e byte Iopl; //0x30 byte NpxState; //0x31 char Saturation; //0x32 char Priority; //0x33 KAPC_STATE ApcState; //0x34 uint32 ContextSwitches; //0x4c int32 WaitStatus; //0x50 byte WaitIrql; //0x54 char WaitMode; //0x55 byte WaitNext; //0x56 byte WaitReason; //0x57 KWAIT_BLOCK *WaitBlockList; //0x58 LIST_ENTRY WaitListEntry; //0x5c uint32 WaitTime; //0x64 char BasePriority; //0x68 byte DecrementCount; //0x69 char PriorityDecrement; //0x6a char Quantum; //0x6b KWAIT_BLOCK WaitBlock[4]; //0x6c void *LegoData; //0xcc uint32 KernelApcDisable; //0xd0 uint32 UserAffinity; //0xd4 byte SystemAffinityActive; //0xd8 byte PowerState; //0xd9 byte NpxIrql; //0xda byte Pad[1]; //0xdb ServiceDescriptor *ServiceTable; //0xdc KQUEUE *Queue; //0xe0 uint32 ApcQueueLock; //0xe4 KTIMER Timer; //0xe8 LIST_ENTRY QueueListEntry; //0x110 uint32 Affinity; //0x118 byte Preempted; //0x11c byte ProcessReadyQueue; //0x11d byte KernelStackResident; //0x11e byte NextProcessor; //0x11f void *CallbackStack; //0x120 void *Win32Thread; //0x124 KTRAP_FRAME *TrapFrame; //0x128 KAPC_STATE *ApcStatePointer[2]; //0x12c char PreviousMode; //0x134 byte EnableStackSwap; //0x135 byte LargeStack; //0x136 byte ResourceIndex; //0x137 uint32 KernelTime; //0x138 uint32 UserTime; //0x13c KAPC_STATE SavedApcState; //0x140 byte Alertable; //0x158 byte ApcStateIndex; //0x159 byte ApcQueueable; //0x15a byte AutoAlignment; //0x15b void *StackBase; //0x15c KAPC SuspendApc; //0x160 KSEMAPHORE SuspendSemaphore; //0x190 LIST_ENTRY ThreadListEntry; //0x1a4 char FreezeCount; //0x1ac char SuspendCount; //01ad byte IdealProcessor; //0x1ae byte DisableBoost; //0x1af }KTHREAD, *PKTHREAD; /***************************************************************************/ typedef struct _ETHRAED{ KTHREAD Tcb; //0x00 LARGE_INTEGER CreateTime; //0x1b0 Union { LARGE_INTEGER ExitTime; //0x1b8 LIST_ENTRY LpcReplyChain; } int32 ExitStatus; //0x1c0 LIST_ENTRY PostBlockList; //0x1c4 LIST_ENTRY TerminationPortList; //0x1cc uint32 ActiveTimerListLock; //0x1d4 LIST_ENTRY ActiveTimerListHead; //0x1d8 CLIENT_ID Cid; //0x1e0 KSEMAPHORE LpcReplySemaphore; //0x1e8 void *LpcReplyMessage; //0x1fc uint32 LpcReplyMessageId; //0x200 uint32 PerformanceCountLow; //0x204 PS_IMPERSONATION_INFORMATION *ImpersonationInfo; //0x208 LIST_ENTRY IrpList; //0x20c uint32 TopLevelIrp; //0x214 DEVICE_OBJECT *DeviceToVerify; //0x218 uint32 ReadClusterSize; //0x21c byte ForwardClusterOnly; //0x220 byte DisablePageFaultClustering; //0x221 byte DeadThread; //0x222 byte HideFromDebugger; //0x223 uint32 HasTerminated; //0x224 uint32 GrantedAccess; //0x228 EPROCESS *ThreadsProcess; //0x22c void *StartAddress; //0x230 void *Win32StartAddress; //0x234 byte LpcExitThreadCalled; //0x238 byte HardErrorsAreDisabled; //0x239 byte LpcReceivedMsgIdValid; //0x23a byte ActiveImpersonationInfo; //0x23b int32 PerformanceCountHigh; //0x23c LIST_ENTRY ThreadListEntry; //0x240 }ETHREAD, *PETHREAD; /***************************NT4.0 ONLY**********************************/ typedef _QUOTA_BLOCK{ // only for nt4.0 ??? KSPIN_LOCK QuotaLock; DWORD RefCounter; DWORD PeakNonPagedPoolUsage; DWORD PeakPagedPoolUsage; DWORD NonPagedpoolUsage; DWORD PagedPoolUsage; DWORD NonPagedPoolLimit; DWORD PagedPoolLimit; DWORD PeakPagefileUsage; DWORD PagefileUsage; DWORD PageFileLimit; }QUOTA_BLOCK,*PQUOTA_BLOCK; /***************************************************************************/ typedef struct _PEB { // Size: 0x1D8 /*000*/ UCHAR InheritedAddressSpace; /*001*/ UCHAR ReadImageFileExecOptions; /*002*/ UCHAR BeingDebugged; /*003*/ UCHAR SpareBool; // Allocation size /*004*/ HANDLE Mutant; /*008*/ HINSTANCE ImageBaseAddress; // Instance /*00C*/ VOID *Ldr; // Module list? /*010*/ VOID *ProcessParameters; /*014*/ ULONG SubSystemData; /*018*/ HANDLE ProcessHeap; /*01C*/ KSPIN_LOCK FastPebLock; /*020*/ ULONG FastPebLockRoutine; /*024*/ ULONG FastPebUnlockRoutine; /*028*/ ULONG EnvironmentUpdateCount; /*02C*/ ULONG KernelCallbackTable; /*030*/ LARGE_INTEGER SystemReserved; /*038*/ ULONG FreeList; /*03C*/ ULONG TlsExpansionCounter; /*040*/ ULONG TlsBitmap; /*044*/ LARGE_INTEGER TlsBitmapBits; /*04C*/ ULONG ReadOnlySharedMemoryBase; /*050*/ ULONG ReadOnlySharedMemoryHeap; /*054*/ ULONG ReadOnlyStaticServerData; /*058*/ ULONG AnsiCodePageData; /*05C*/ ULONG OemCodePageData; /*060*/ ULONG UnicodeCaseTableData; /*064*/ ULONG NumberOfProcessors; /*068*/ LARGE_INTEGER NtGlobalFlag; // Address of a local copy /*070*/ LARGE_INTEGER CriticalSectionTimeout; /*078*/ ULONG HeapSegmentReserve; /*07C*/ ULONG HeapSegmentCommit; /*080*/ ULONG HeapDeCommitTotalFreeThreshold; /*084*/ ULONG HeapDeCommitFreeBlockThreshold; /*088*/ ULONG NumberOfHeaps; /*08C*/ ULONG MaximumNumberOfHeaps; /*090*/ ULONG ProcessHeaps; /*094*/ ULONG GdiSharedHandleTable; /*098*/ ULONG ProcessStarterHelper; /*09C*/ ULONG GdiDCAttributeList; /*0A0*/ KSPIN_LOCK LoaderLock; /*0A4*/ ULONG OSMajorVersion; /*0A8*/ ULONG OSMinorVersion; /*0AC*/ USHORT OSBuildNumber; /*0AE*/ USHORT OSCSDVersion; /*0B0*/ ULONG OSPlatformId; /*0B4*/ ULONG ImageSubsystem; /*0B8*/ ULONG ImageSubsystemMajorVersion; /*0BC*/ ULONG ImageSubsystemMinorVersion; /*0C0*/ ULONG ImageProcessAffinityMask; /*0C4*/ ULONG GdiHandleBuffer[0x22]; /*14C*/ ULONG PostProcessInitRoutine; /*150*/ ULONG TlsExpansionBitmap; /*154*/ UCHAR TlsExpansionBitmapBits[0x80]; /*1D4*/ ULONG SessionId; } PEB, *PPEB; /***************************************************************************/ // +++ // User-Mode Thread Environment Block (UTEB) // Selector 0x3B: DPL=3, Base=0x7FFDE00 (1st thread), Lim=0x00000FFF // Base is updated at every thread switch. // Loaded into FS in User Mode // --- typedef struct _TEB { // Size: 0xF88 /*000*/ NT_TIB NtTib; /*01C*/ VOID *EnvironmentPointer; /*020*/ CLIENT_ID ClientId; /*028*/ HANDLE ActiveRpcHandle; /*02C*/ VOID *ThreadLocalStoragePointer; /*030*/ PEB *ProcessEnvironmentBlock; // PEB /*034*/ ULONG LastErrorValue; /*038*/ ULONG CountOfOwnedCriticalSections; /*03C*/ ULONG CsrClientThread; /*040*/ ULONG Win32ThreadInfo; /*044*/ UCHAR Win32ClientInfo[0x7C]; /*0C0*/ ULONG WOW32Reserved; /*0C4*/ ULONG CurrentLocale; /*0C8*/ ULONG FpSoftwareStatusRegister; /*0CC*/ UCHAR SystemReserved1[0xD8]; /*1A4*/ ULONG Spare1; /*1A8*/ ULONG ExceptionCode; /*1AC*/ UCHAR SpareBytes1[0x28]; /*1D4*/ UCHAR SystemReserved2[0x28]; /*1FC*/ UCHAR GdiTebBatch[0x4E0]; /*6DC*/ ULONG gdiRgn; /*6E0*/ ULONG gdiPen; /*6E4*/ ULONG gdiBrush; /*6E8*/ CLIENT_ID RealClientId; /*6F0*/ ULONG GdiCachedProcessHandle; /*6F4*/ ULONG GdiClientPID; /*6F8*/ ULONG GdiClientTID; /*6FC*/ ULONG GdiThreadLocalInfo; /*700*/ UCHAR UserReserved[0x14]; /*714*/ UCHAR glDispatchTable[0x460]; /*B74*/ UCHAR glReserved1[0x68]; /*BDC*/ ULONG glReserved2; /*BE0*/ ULONG glSectionInfo; /*BE4*/ ULONG glSection; /*BE8*/ ULONG glTable; /*BEC*/ ULONG glCurrentRC; /*BF0*/ ULONG glContext; /*BF4*/ ULONG LastStatusValue; /*BF8*/ LARGE_INTEGER StaticUnicodeString; /*C00*/ UCHAR StaticUnicodeBuffer[0x20C]; /*E0C*/ ULONG DeallocationStack; /*E10*/ UCHAR TlsSlots[0x100]; /*F10*/ LARGE_INTEGER TlsLinks; /*F18*/ ULONG Vdm; /*F1C*/ ULONG ReservedForNtRpc; /*F20*/ LARGE_INTEGER DbgSsReserved; /*F28*/ ULONG HardErrorsAreDisabled; /*F2C*/ UCHAR Instrumentation[0x40]; /*F6C*/ ULONG WinSockData; /*F70*/ ULONG GdiBatchCount; /*F74*/ ULONG Spare2; /*F78*/ ULONG Spare3; /*F7C*/ ULONG Spare4; /*F80*/ ULONG ReservedForOle; /*F84*/ ULONG WaitingOnLoaderLock; } TEB, *PTEB; /***************************************************************************/ typedef struct _EPROCESS // for NT4.0 { KPROCESS Pcb; //0 NTSTATUS ExitStatus; //68 ! KEVENT LockEvent; //6c ! ULONG LockCount; //7c TIME CreateTime; //80 ! TIME ExitTime; //88 ! PVOID LockOwner; //90 ! ULONG UniqueProcessId; //94 ! LIST_ENTRY ActiveProcessLinks;//98 // see PsActiveProcessHead ULONG QuotaPeakNonPagedPoolUsage; //a0 ! ULONG QuotaPeakPagedPoolUsage; //a4 ! ULONG QuotaNonPagedPoolUsage; //a8 ! ULONG QuotaPagedPoolUsage; //ac ! ULONG PagefileUsage; //b0 in pages ULONG CommitCharge; //b4 ULONG PeakPagefileUsage; //b8 in pages ULONG PeakVirtualUsage; //bc LARGE_INTEGER VirtualSize; //c0 VM Vm; // c8 Actually 48 bytes PVOID LastProtoPteFault; //f8 PVOID DebugPort; //fc ! PVOID ExceptionPort; //100 ! PVOID ObjectTable; //104 ! PVOID Token; //108 ! KMUTEX WorkingSetLock; //10c ! PVOID WorkingSetPage; //12c UCHAR ProcessOutswapEnabled; //130 UCHAR ProcessOutswapped; //131 UCHAR AddressSpaceInitialized;//132 UCHAR AddressSpaceDeleted; //133 KMUTEX AddressCreationLock; //134 KSPIN_LOCK CreateAddressSpaceLock; //154 KTHREAD ForkInProgress; //158 WORD VmOperation; //15c BOOLEAN ForkWasSuccessful; //15e UCHAR MmAgressiveWsTrimMask; // 15f db AggresivlyTrimWorkingSet| //(MmSystemSize!=0)<<1 (see image characteristics) PKEVENT VmOperationEvent; //160 PVOID PageDirectoryPte; //164 DWORD LastFaultCount; //168 DWORD ModifiedPageCount; //16c PVOID VadRoot; //170 PVOID VadHint; //174 PVOID CloneRoot; //178 ULONG NumberOfPrivatePages; //17c ULONG NumberOfLockedPages; //180 WORD Seed ; //184 ! ? Инициализируется случайным числом UCHAR ExitProcessCalled; //186 UCHAR CreateProcessReported; //187 HANDLE SectionHandle; //188 PPEB Peb; //18c ! PVOID SectionBaseAddress; //190 PQUOTA_BLOCK QuotaBlock; //194 ! NTSTATUS LastThreadExitStatus; //198 DWORD WorkingSetWatch; //19c // DWORD Win32WindowStation; //1a0 ULONG InheritedFromUniqueProcessId; //1a4 ! ACCESS_MASK GrantedAccess; //1a8 ! ULONG DefaultHardErrorProcessing; //1ac ! PVOID LdtInformation; //1b0 ULONG VadFreeHint; //1b4 PVOID VdmObjects; //1b8 KMUTANT ProcessMutant; //1bc CHAR ImageFileName[16]; //1dc LARGE_INTEGER VmTrimFaultValue; //1ec UCHAR SetTimerResolution; //1f0 UCHAR PriorityClass; //1f1 union { struct { UCHAR SubSystemMinorVersion; //1f2 UCHAR SubSystemMajorVersion; //1f3 }; USHORT SubSystemVersion; //1f2 }; DWORD Win32Process; //1f4 } EPROCESS, *PEPROCESS; /***************************************************************************/ typedef struct _VM{ /* C8*/ LARGE_INTEGER UpdateTime; //0 /* D0*/ DWORD Pages; //8 called so, by S-Ice authors /* D4*/ DWORD PageFaultCount //0c faults; // in fact number of MiLocateAndReserveWsle calls /* D8*/ DWORD PeakWorkingSetSize; //10 all /* DC*/ DWORD WorkingSetSize; //14 in /* E0*/ DWORD MinimumWorkingSet; //18 pages, not in /* E4*/ DWORD MaximumWorkingSet; //1c bytes /* E8*/ PWS_LIST WorkingSetList; //20 data table /* EC*/ LIST_ENTRY WorkingSetExpansion; //24 expansion /* F4*/ BYTE fl0; // Operation??? //2c BYTE fl1; // always 2??? //2d BYTE fl2; // reserved??? always 0 //2e BYTE fl3; // //2f }VM *PVM; /***************************************************************************/ typedef struct _WS_LIST{ DWORD Quota; //0 ??? i'm not shure.... DWORD FirstFreeWsle // 4 start of indexed list of free items DWORD FirstDynamic; // 8 Num of working set wsle entries in the start //FirstDynamic DWORD LastWsleIndex; // c above - only empty items DWORD NextSlot; //10 in fact always == FirstDynamic // NextSlot PWSLE Wsle; //14 pointer to table with Wsle DWORD Reserved1; //18 ??? DWORD NumOfWsleItems; //1c Num of items in Wsle table // (last initialized) DWORD NumOfWsleInserted; //20 of Wsle items inserted (WsleInsert/ WsleRemove) PWSHASH_ITEM HashPtr; //24 pinter to hash, now we can get index of // Wsle item by address. Present only if // NumOfWsleItems>0x180 DWORD HashSize //28 hash size DWORD Reserved2 //2c ??? }WS_LIST *PWS_LIST; typedef struct _WSLE{ // элемент таблицы рабочего набора DWORD PageAddress; }WSLE *PWSLE; // PageAddress представляет собой виртуальный адрес страницы рабочего набора // Младшие 12 бит используются как атрибуты (виртуальный адрес страницы // всегда кратен 4K) #define WSLE_DONOTPUTINHASH 0x400 // не помещать в хэш #define WSLE_PRESENT 0x1 // не пустой элемент #define WSLE_INTERNALUSE 0x2 // фрэйм используется менеджером памяти // Свободный WSLE со сброшенным битом WSLE_PRESENT представляет собой // индекс на следующий свободный WSLE. Таким образом свободные WSLE // организованы в список. Последний свободный WSLE ссылается на -1 #define EMPTY_WSLE (next_emty_wsle_index) (next_emty_wsle_index<<4) #define LAST_EMPTY_WSLE 0xfffffff0 typedef struct _WSHASH_ITEM{ DWORD PageAddress; //Value DWORD WsleIndex; //index in Wsle table }WSHASH_ITEM *PWSHASH_ITEM; /***************************************************************************/ typedef struct _ACCESS_TOKEN{ // only for NT4.0??? char SourceName[8]; // 0 Источник token'a LUID SourceIdentifier; // 8 LUID TokenId; // 10 LUID AuthenticationId;// 18 LARGE_INTEGER ExpirationTime; // 20 LUID ModifiedId; // 28 меняется при изминении token'a DWORD NumberOfUserAndGroupSids;//30 DWORD NumberOfPrivileges //34 DWORD VariableSize; //38 DWORD DynamicCharged; //3c DWORD DynamicAvailable; //40 DWORD NumberOfOwnerSid //44 PVOID SidDB; //48 PSID PrimaryGroup; //4c PLUID_AND_ATTRIBUTES TokenPrivileges; //50 DWORD Unknown1; //54 PACL DefaultDacl; //58 TOKEN_TYPE TokenType; //5c Первичный или // олицетворение SECURITY_IMPERSONATION_LEVEL ImpLevel; //60 Олицетворение BYTE UnknownFlag; //64 BYTE TokenInUse; BYTE Pad[2]; PVOID ProxyData; //68 PVOID AuditData; //6c DWORD Tail[ANYSIZE_ARRAY]; //70 }ACCESS_TOKEN,*PACCESS_TOKEN; /***************************NT5.0 ONLY**********************************/ typedef struct _MMSUPPORT{ LARGE_INTEGER LastTrimTime; //0xd0 uint32 LastTrimFaultCount; //0xd8 uint32 PageFaultCount; //0xdc uint32 PeakWorkingSetSize; //0xe0 uint32 WorkingSetSize; //0xe4 uint32 MinimumWorkingSetSize;//0xe8 uint32 MaximumWorkingSetSize;//0xec PVOID VmWorkingSetList;//0xf0 LIST_ENTRY WorkingSetExpansionLinks; //0xf4 byte AllowWorkingSetAdjustment; //0xfc byte AddressSpaceBeingDeleted; //0xfd byte ForegroundSwitchCount; //0xfe byte MemoryPriority; //0xff uint32 LongFlags; //0x100 /* bits0-0 SessionSpace bits1-1 BeingTrimmed bits2-2 ProcessInSession bits3-3 SessionLeader bits4-4 TrimHard bits5-5 WorkingSetHard bits6-6 WriteWatch bits7-31 Filler */ uint32 Claim; //0x104 uint32 NextEstimationSlot; //0x108 uint32 NextAgingSlot; //0x10c uint32 EstimatedAvailable; //0x110 uint32 GrowthSinceLastEstimate; //0x114 } MMSUPPORT; /***************************************************************************/ typedef struct _EPROCESS{ // for NT5.0 ONLY!!! KPROCESS Pcb; //0x00 int32 ExitStatus; //0x6c KEVENT LockEvent; // 0x70 LARGE_INTEGER ExitTime; //0x90 KTHREAD *LockOwner; //0x98 void *UniqueProcessId; //0x9c LIST_ENTRY ActiveProcessLinks; //0xa0 uint32 QuotaPeakPoolUsage[2]; //0xa8 uint32 QuotaPoolUsage[2]; //0xb0 uint32 PagefileUsage; //0xb8 uint32 CommitCharge; //0xbc uint32 PeakPagefileUsage; //0xc0 uint32 PeakVirtualSize; //0xc4 uint32 VirtualSize; //0xc8 MMSUPPORT Vm; //0xcc LIST_ENTRY SessionProcessLinks; //0x118 void *DebugPort; //0x120 void *ExceptionPort; //0x124 PVOID *ObjectTable; //0x128 void *Token; //0x12c FAST_MUTEX WorkingSetLock; //0x130 uint32 WorkingSetPage; //0z150 byte ProcessOutswapEnabled; //0x154 byte ProcessOutswapped; //0x155 byte AddressSpaceInitialized; //0x156 byte AddressSpaceDeleted; //0x157 FAST_MUTEX AddressCreationLock; //0x158 uint32 HyperSpaceLock; //0x178 ETHREAD *ForkInProgress; //0x17c uint16 VmOperation; //0x180 byte ForkWasSuccessful; //0x182 byte MmAgressiveWsTrimMask; //0x183 KEVENT *VmOperationEvent; //0x184 void *PaeTop; //0x188 uint32 LastFaultCount; //0x18c uint32 ModifiedPageCount; //0x190 void *VadRoot; //0x194 void *VadHint; //0x198 void *CloneRoot; //0x19c uint32 NumberOfPrivatePages; //0x1a0 uint32 NumberOfLockedPages; //0x1a4 uint16 NextPageColor; //0x1a8 byte ExitProcessCalled; //0x1aa byte CreateProcessReported; //0x1ab void *SectionHandle; //0x1ac PVOID *Peb; //0x1b0 void *SectionBaseAddress; //0x1b4 EPROCESS_QUOTA_BLOCK *QuotaBlock; //0x1b8 int32 LastThreadExitStatus; //0x1bc PAGEFAULT_HISTORY *WorkingSetWatch; //0x1c0 void *Win32WindowStation; //0x1c4 void *InheritedFromUniqueProcessId; //0x1c8 uint32 GrantedAccess; //0x1cc uint32 DefaultHardErrorProcessing; //0x1d0 void *LdtInformation; //0x1d4 void *VadFreeHint; //0x1d8 void *VdmObjects; //0x1dc void *DeviceMap; //0x1e0 uint32 SessionId; //0x1e4 LIST_ENTRY PhysicalVadList; //0x1e8 HARDWARE_PTE_X86 PageDirectoryPte; //0x1f0 /* bits0-0 Valid bits1-1 Write bits2-2 Owner bits3-3 WriteThrough bits4-4 CacheDisable bits5-5 Accessed bits6-6 Dirty bits7-7 LargePage bits8-8 Global bits9-9 CopyOnWrite bits10-10 Prototype bits11-11 reserved bits12-31 PageFrameNumber uint64 Filler */ uint32 PaePageDirectoryPage; //0x1f8 byte ImageFileName[16]; //0x1fc uint32 VmTrimFaultValue; //0x20c byte SetTimerResolution; //0x210 byte PriorityClass; //0x211 uint16 SubSystemVersion; //0x212 void *Win32Process ; //0x214 void *Job; //0x218 uint32 JobStatus; //0x21c struct _LIST_ENTRY JobLinks; //0x220 void *LockedPagesList; //0x228 void *SecurityPort; //0x22c void *Wow64Process; //0x230 LARGE_INTEGER ReadOperationCount; //0x238 LARGE_INTEGER WriteOperationCount; //0x240 LARGE_INTEGER OtherOperationCount; //0x248 LARGE_INTEGER ReadTransferCount; //0x250 LARGE_INTEGER WriteTransferCount; //0x258 LARGE_INTEGER OtherTransferCount; //0x260 uint32 CommitChargeLimit; //0x268 uint32 CommitChargePeak; //0x26c LIST_ENTRY ThreadListHead; //0x270 RTL_BITMAP *VadPhysicalPagesBitMap; //0x278 uint32 VadPhysicalPages; //0x27c uint32 AweLock; //0x280 }EPROCESS, *PEPROCESS; /***************************************************************************/ 01.Псевдокод функций ядра, работающих с рабочим набором. (NT4.0) ================================================================ /**************************************************************************/ /* Изменить квоты для WorkingSet/экспортируемая не документируемая */ /**************************************************************************/ MmAdjustWorkingSetSize(MinimumWorkingSet,MaximumWorkingSet,Vm) // Не документирована, но экспортируется. // Изменить размер Working Set { Status=0; // 0 return status if(!Vm)VM=pCurProcess->Vm; // if no VM, current process's VM if(!MinimumWorkingSet)MinimumWorkingSet=VM->MinimumWorkingSet; if(!MaximumWorkingSet)MaximumWorkingSet=VM->MaximumWorkingSet; if(MinimumWorkingSet==-1&&MaximumWorkingSet==-1)// clear WorkingSet if so {MiEmptyWorkingSet(VM);return;} MinimumWorkingSet>>=12; // in pages MaximumWorkingSet>>=12; // in pages if(MaximumWorkingSetWorkingSetLock); } // check for parameters range if(MmMaximumWorkingSetSizeMinimumWorkingSet) {MinimumWorkingSet=MmMinimumWorkingSetSize; Status=STATUS_WORKING_SET_LIMIT_RANGE;} WorkingSetList=VM->WorkingSetList; FirstDynamic=WorkingSetList->FirstDynamic; if((FirstDynamic+8)>=MaximumWorkingSet) { Status=STATUS_BAD_WORKING_SET_LIMIT; goto ret; } Wsle=WorkingSetList->Wsle; OldIrql2=KeRaiseIrqlToDpcLevel(); Delta=(MinimumWorkingSet-VM->MinimumWorkingSet); // got increase delta if(Delta>0) // we are need some physical pages to increase minimum working set { if(MmResidentAvailablePages>=Delta) // enouth resident pages { if(Delta>>10+20)>MmAvailablePages){ KeLowerIrql(OldIrql2); Status=STATUS_INSUFFICIENT_RESOURCES; goto ret; } } else { // no resident pages KeLowerIrql(OldIrql2); Status=STATUS_INSUFFICIENT_RESOURCES; goto ret; } } // now, we are known, that we have enouth pages MmResidentAvailablePages-=Delta; KeLowerIrql(OldIrql2); if(!VM->fl0)MmAllowWorkingSetExpansion(); if(WorkingSetList->NumOfWsleItems>=MaximumWorkingSet) {//if(1) если в таблице больше мест, чем нужно if(VM->WorkingSetSize>MaximumWorkingSet)//Maximum must be decrease { //if(2) if((FirstDynamic+8)>=MaximumWorkingSet){ Status=STATUS_BAD_WORKING_SET_LIMIT; goto ret; } //if(2) LastIndex=WorkingSetList->LastWsleIndex; while(LastIndex>MaximumWorkingSet) // remove delta { TmpPte=*(Wsle+LastIndex*4)>>10+0xc0000000; if(*(Wsle+LastIndex*4)&1){ // if valid entry if(!MiFreeWsle(ws_c,VM,TmpPte))break; } LastIndex--; } WorkingSetList->LastWsleIndex=LastIndex; // MaximumWsle if(WorkingSetList->NextSlot>=LastIndex) WorkingSetList->NextSlot=FirstDynamic; //NumOfValidWsleItems i=FirstDynamic; while(VM->WorkingSetSize>MaximumWorkingSet) { TmpPte=*(Wsle+i*4)>>10+0xc0000000; if(*(Wsle+i*4)&1)MiFreeWsle(i,VM,TmpPte); i++; if(i>LastIndex){ Counter++; if(Counter>2){Status=0xc000004c;break;} i=FirstDynamic; } } if(Counter<=2)WorkingSetList->Quota=MaximumWorkingSet; } //if(2) }//if(1) else { // если в таблице меньше места, чем нужно while(WorkingSetList->NumOfWsleItemsNumOfWsleItems-1; break;} } } // less2 AboveMin=VM->WorkingSetSize-MinimumWorkingSet; OldAboveMin=VM->WorkingSetSize-VM->MinimumWorkingSet; OldIrql2=KeRaiseIrqlToDpcLevel(); if(OldAboveMin>0)MmPagesAboveWsMinimum-=OldAboveMin; if(AboveMin>0)MmPagesAboveWsMinimum+=AboveMin; KeLowerIrql(OldIrql2); if(Counter<=2){ VM->MinimumWorkingSet=MinimumWorkingSet; VM->MaximumWorkingSet=MaximumWorkingSet; if(WorkingSetList->Quota<=MinimumWorkingSet) WorkingSetList->Quota=MinimumWorkingSet; } if(WorkingSetList->HashPtr)goto ret; if(VM->MaximumWorkingSet<=0x180)goto ret; MoGrowWsleHash(VM,0); ret: ; if(Vm){ MmSystemLockOwner=0; ExReleaseResourceLite(MmSystemWsLock); KeLowerIrql(OldIrql); } else ExReleaseFastMutex(CurProcess->WorkingSetLock); MmUnlockPagableImageSection(ExPageLockHandle); return Status; } /**************************************************************************/ /* Инициализировать рабочий набор */ /**************************************************************************/ MiInitializeWorkingSetList(pProcess) // инициализация Working Set { *MmWorkingSet=*(MmWorkingSetList+0xc)=pProcess->MinimumWorkingSet; *(MmWorkingSetList+Reserved2)=0; MmWorkingSetList->HashPtr=0; MmWorkingSetList->HashSize=0; MmWorkingSetList->Wlse=MmWsle; *MmWsle=0xc0300000|0x403; // @MmWsle эта область для каждого нового процесса // ремэппится (принадлежит hyper-space) // TmpPte=(0xc0300403&0xfffff3ff)>>0xa+0xc0000000; // TmpPte=0xc0300c00 (кат // страниц) // TmpPfn=(*TmpPte>>12)*0x18+MmPfnDatabase; *TmpPfn=pProcess; // Фрэйм, соотв. PD содержит в flink, ук. на процесс *(MmWsle+4)=0xc0301000|0x403; // // 0xc0301000 - начало hyper space TmpPte=(0xc0301000>>10)+0xc0000000; // TmpPte=0xc0300c04 TmpPfn=(*TmpPte>>12)*0x18+MmPfnDatabase; *TmpPfn=1; *(MmWlse+8)=MmWorkingSetList|0x403; TmpPte=MmWorkingSetList>>10+0xc0000000; TmpPfn=(*TmpPte>>12)*0x18+MmPfnDatabase; *TmpPfn=2; Num=(C0503000-MmWsle)>>2; // num of WsleItems of first wsle? pMaximumWorkingSet=&(pProcess->MaximumWorkingSet); Count=3; TmpPtr=MmWsle+8; if(Num<=*pMaximumWorkingSet) // растягиваем таблицу для макс. WorkingSet { WorkingSetAfter=MmWorkingSetList+0x1000; // to the next pt TmpPte=MmWsle>>0xa+0xc0000000; // start pte for MmWsle // same, that for MmWorkingSetList Seed=&(pProcess->Seed); OldIrql=KeRaiseIrqlToDpcLevel(); while(1) { TmpPte+=4; //to the next pte MiEnsureAvailablePageOrWait(0,0); TmpPtr+=4; Color=*((WORD*)Seed); *(WORD*)Seed=Color+1; RemovedFrame=MiRemoveZeroPage(Color&MmSecondaryColorMask); *TmpPte=0x80; MiInitializePfn(RemovedFrame,TmpPte,1);// build page Mask=MiDetermineUserGlobalPteMask(TmpPte); Num+=0x400; // идем по 1024 wsle items Mask=Mask|(RemovedFrame<<12)|2|0x40; *TmpPte=Mask; *TmpPtr=WorkingSetAfter|0x403; // to the next WorkingSetAfter+=0x1000; TmpPfn=MmPfnDatabase+0x18*(*TmpPte)<<12; *TmpPfn=Count++; if(*pMaximumWorkingSetWorkingSetSize=Count; // in pages that used for wsle entries *(MmWorkingSetList+FirstFreeWsle)=MmWorkingSetList->FirstDynamic=*\ (MmWorkingSetList+0x10)=Count; Count++; Tmp=Count<<4; while(1){ // заполнить пустые wsle списком свободных item'ов TmpPtr+=4; Count++; *TmpPtr=Tmp; Tmp+=0x10; if(Count>Num)break; } MmWorkingSetList->NumOfWsleItems=Num-1; *TmpPtr=0xfffffff0; // -1, last item if(*pMaximumWorkingSet>0x180)//384 { MiGrowWsleHash(&(pProcess->VM),0); } return; } /**************************************************************************/ /* Строим хэш */ /**************************************************************************/ MiGrowWsleHash(VM) // построение хэша { WorkingSetList=VM->WorkingSetList; Wsle=WorkingSetList->Wlse; Hash=WorkingSetList->HashPtr; ptr=(MiMaximumWorkingSet*4+Wsle)&0xfffff000+0x1000; if(!Hash) { Delta=((WorkingSetList->NumOfWsleInserted<<4)+0x100f)&0xfffff000; HashSize=WorkingSetList->HashSize; WorkingSetList->HashSize=0; if(HashSize*8>Delta)Delta=HashSize*8; } else { if(VM->WorkingSetSizeNumOfWsleItems+5) Delta=0x4000; else Delta=0x1000; HashSize=WorkingSetList->HashSize; } TmpPte=((WorkingSetList->HashSize)*8+ptr)>>0xa+0xc0000000; count=Delta; for(;count;count-=0x1000,TmpPte+=4;) { if(*TmpPte&1)continue; // already present! OldIrql=KeRaiseIrqlToDpcLevel(); Frame=MiRemoveZeroPage(MmSecondaryColorMask&MmSystemPageColor++); *TmpPte=0x80; MiInitializePfn(Frame,TmpPte,1); Mask=MiDetermineUserGlobalPteMask(TmpPte); PteVal=Frame<<0xc|Mask|2|0x40; *TmpPte=PteVal; KeLowerIrql(OldIrql); TmpPfn=MmPfnDatabase+Frame*0x18; *TmpPfn=CurThread; Result=MiLocateAndReserveWsle(VM); MiUpdateWsle(&Result,TmpPte<<0xa,WorkingSetList,TmpPfn); if(WorkingSetList->FirstDynamic<=Result) { FirstDynamic=WorkingSetList->FirstDynamic; if(WorkingSetList->FirstDynamic!=Result) MiSwapWslEntries(Result,FirstDynamic,VM); WorkingSetList->FirstDynamic=WorkingSetList->NextSlot=\ WorkingSetList->FirstDynamic+1; *(Wsle+FirstDynamic*4)|=2; } } WorkingSetList->HashSize+=Delta>>3; WorkingSetList->HashPtr=ptr; if(HashSize)memset(ptr,0,HashSize<<3); Cntr=WorkingSetList->NumOfWsleInserted; Divider=WorkingSetList->HashSize-1; WslePtr=Wsle; i=0; for(;Cntr;WslePtr+=4,i++) { if(*WslePtr&1==0||*WslePtr&0x400)continue; Val=*WslePtr; HashIndex=(Val>>0xa)%Divider; Cntr--; if(ptr+HashIndex*8) { while(1){// look for empty hash item HashIndex++; if(WorkingSetList->HashSize<=HashIndex)HashIndex=0; if(*(ptr+HashIndex*8)==0)break; } } *(ptr+HashIndex*8)=Val&0xfffff000; *(ptr+HashIndex*8+4)=i; } return; } /**************************************************************************/ /* Освободить элемент таблицы Wsle */ /**************************************************************************/ MiFreeWsle(Num,VM,Pte) // с упрощениями { Wsle=VM->WorkingSetList->Wsle; TmpPfn=*Pte>>12*0x18+MmPfnDatabase; KeRaiseIrqlToDpcLevel(&OldIrql); if(TmpPfn->ShareCounter>1&&(!TmpPfn->Flags&0x8)){ KeLowerIrql(OldIrql); return 0; } MiEliminateWorkingSetEntry(Num,Pte,TmpPfn,Wsle); KeLowerIrql(OldIrql); MiRemoveWsle(Num,VM->WorkingSetList); *(Wsle+Num*4)=VM->WorkingSetList->FirstFreeWsle<<4; VM->WorkingSetList->FirstFreeWsle=Num; if(VM->MinimumWorkingSetSizeWorkingSetSize)MmPagesAboveWsMinimum--; VM->WorkingSetSize--; return 1; } /**************************************************************************/ /* Низкий уровень = используется др функцией */ /**************************************************************************/ MiEliminateWorkingSetEntry(Num,Pte,Frame,Wsle) { NewPteValue=*Pte; PageBaseAddr=NewPteValue>>12; if(Frame->Flags&8){ // shared if(*(Wsle+Num*4)&0x200){ TmpPte=Frame->Pte; NewPteValue=((TmpPte+0x1f000000)&0xffffff00|0x100<<2)| (TmpPte&0x1fc>>1); HighestUserPte=MmHighestUserAddress>>10+0xc0000000; if(HighestUserPte=0xc0303000)) { NewPteValue=NewPteValue^((MmPteGlobal<<8)&0x100); } } else { WsleItem=*(Wsle+Num*4); NewPteValue=WsleItem&0x1f0|0xfffff800<<1; } NewPteValue|=0x400; //d bit if(!(Pte>>10+0xc0000000)&1) { MiCheckPdeForPagedPool(Pte); } MiDecrementShareCount2(*(Pte>>10+0xc0000000)>>12); } // shared else { // not shared NewPteValue=NewPteValue|0x800&0xfffffffe&0xfffffbff^ (Frame->ContFrame&0x3e0); } OldPteValue=*Pte; WsleItem=*(Wsle+Num*4); *Pte=NewPteValue; invlpg((void*)WsleItem); if((!Frame->Flags&1)&&OldPteValue&0x40){ Frame->Flags|=1; if((!Frame->Trans&0x400)&&(!Frame->Flags&4)){ MiReleasePageFileSpace(Frame->Trans); FrameTrans&=0xfff; } } MiDecrementShareCount2(PageBaseAddr); } /**************************************************************************/ /* Убрать вход в таблицe Wsle */ /**************************************************************************/ MiRemoveWsle(Num,WorkingSetList) { Wsle=WorkingSetList->Wsle; TmpPtr=Wsle+4*Num; Val=*TmpPtr&0xfffff000; *TmpPtr&=0xfffffffe; if(*TmpPtr&0x400)return; WorkingSetList->NumOfWsleInserted--; if(!WorkingSetList->HashPtr)return; Mod=(*TmpPtr>>10)%(WorkingSetList->HashSize-1); if(WorkingSetList->HashPtr+Mod*4==Val){WorkingSetList->HashPtr+Mod*4=0;return;} do{ Mod++; if(WorkingSetList->HashSize>Mod)continue; Mod=0; if(Flag=0)Flag=1; else // KeBugCheckEx(0x1a,0x41784.... }while(WorkingSetList->HashPtr+Mod*4!=Val); } return; } /**************************************************************************/ /* Внести VM в expansion список */ /**************************************************************************/ MmAllowWorkingSetExpansion() { OldIrql=KeRaiseIrqlToDpcLevel(); VM=CurProcess->VM; if(!VM->fl0){ VM->fl0=1; VM->WorkingSetExpansion.Flink=MmWorkingSetExpansionHead.Flink; VM->WorkingSetExpansion.Blink=MmWorkingSetExpansionHead.Blink; MmWorkingSetExpansionHead.Blink->Flink=&VM->WorkingSetExpansion; MmWorkingSetExpansionHead.Blink=&VM->WorkingSetExpansion; } KeLowerIrql(OldIrql); } /**************************************************************************/ /* Расширить таблицу Wsle на одну страницу */ /**************************************************************************/ MiAddWorkingSetPage(VM) { WorkingSetList=VM->WorkingSetList; Wsle=WorkingSetList->Wsle; Num=WorkingSetList->NumOfWsleItems; TmpPtr=Wsle+Num*4; TmpPte=TmpPtr>>0xa+0xc0000004; // pte of next Wsle portion PageAddr=TmpPte<<0xa; NewNum=(PageAddr+0x1000-Wsle)>>2; OldIrql=KeRaiseIrqlToDpcLevel(); if(MmAvailablePages<0x14) { WorkingSetList->Quota=NumOfWsleItems; KeLowerIrql(OldIrql); return 0; } Frame=MiRemoveZeroPage((MmSystemPageColor++&MmSecondaryColorMask)); *TmpPte=0x80; MiInitializePfn(Frame,TmpPte,1); KeLowerIrql(OldIrql); Mask=MiDetermineUserGlobalPteMask(TmpPte); PteVal=Frame<<0xc|Mask|2|0x40; *TmpPte=PteVal; Mum=WorkingSetList->NumOfWsleItems+1; TmpPtr=Wsle+(Num-1)*4; if(NewNum>Num) { EmptyVal=(Num+1)<<4; IncNum=NewNum-Num; while(IncNum--) { TmpPtr+=4; *TmpPtr=EmptyVal; EmptyVal+=0x10; } } *TmpPtr=WorkingSetList->FirstFreeWsle<<4; WorkingSetList->FirstFreeWsle=Num; WorkingSetList->NumOfWsleItems=NewNum-1; WorkingSetList->Quota++; TpmPfn=(*TmpPte>>12)*0x18+MmPfnDatabase; *TmpPfn->0=CurThread; VM->WorkingSetSize++; TmpWsle=WorkingSetList->FirstFreeWsle; WorkingSetList->FirstFreeWsle=*(Wsle+TmpWsle*4)>>4; if(VM->MinimumWorkingSetWorkingSetSize)MmPagesAboveWsMinimum++; if(WorkingSetList->LastWsleIndexLastWsleIndex=TmpWsle; MiUpdateWsle(&TmpWsle,PageAddr,WorkingSetList,TmpPfn); j=WorkingSetLis->FirstDynamic; if(j<=TmpWsle) { if(jFirstDynamic=WorkingSetList->NextSlot=\ WorkingSetList->FirstDynamic+1; *(Wsle+j*4)|=2; } if(WorkingSetList->HashPtr)return 1; if(MmAvailablePages<=0x14)return 1; VM->fl0=0x14; //AddWorkingSetPage return 1; } /**************************************************************************/ /* Поменять элементы таблицы Wsle */ /**************************************************************************/ MiSwapWslEntries(i,k,VM) { WorkingSetList=VM->WorkingSetList; Wsle=WorkingSetList->Wsle; TmpI=Wsle+4*i; k_val=*(Wsle+4*k); i_val=*TmpI; if(!k_val&1){ MiRemoveWsleFromFreeList(k,Wsle,WorkingSetList); *(Wsle+k*4)=i_val; if(i_val&0x400){ TmpPte=i_val>>0xa+0xc0000000; TmpPfn=*TmpPte>>12+MmPfnDatabase; TmpPfn->0=k; } else { if(WorkingSetList->HashPtr){ index=MiLookupWsleHashIndex(i_val,WorkingSetList); *(WorkingSetList->HashPtr+index*8+4)=k; } } *TmpI=WorkingSetList->FirstFreeWsle<<4; WorkingSetList->FirstFreeWsle=i; return; } *TmpI=k_val; if(k_val&0x400){ TmpPte=k_val>>0xa+0xc0000000; TmpPfn=*TmpPte>>12+MmPfnDatabase; TmpPfn->0=i; } else { if(WorkingSetList->HashPtr){ index=MiLookupWsleHashIndex(k_val,WorkingSetList); *(WorkingSetList->HashPtr+index*8+4)=i; } } if(i_val&0x400){ TmpPte=i_val>>0xa+0xc0000000; TmpPfn=*TmpPte>>12+MmPfnDatabase; TmpPfn->0=k; } else { if(WorkingSetList->HashPtr){ index=MiLookupWsleHashIndex(i_val,WorkingSetList); *(WorkingSetList->HashPtr+index*8+4)=k; } } return; } /**************************************************************************/ /* Искать в хэше */ /**************************************************************************/ MiLookupWsleHashIndex(Value,WorkingSetList) { Val=value&0xfffff000; TmpPtr=WorkingSetList->HashPtr; Mod=(Val>>0xa)%(WorkingSetList->HashSize-1); if(*(TmpPtr+Mod*8)==Val)return Mod; while(*(TmpPtr+Mod*8)!=Val)){ Mod++; if(WorkingSetList->HashSize>Mod)continue; Mod=0; if(fl)KeBugCheckEx(0x1a,0x41884,Val,Value,WorkingSetList); fl=1; } return Mod; } /**************************************************************************/ /* Добавить страницу к WorkingSet (высок уровень) */ /**************************************************************************/ MiUpdateWsle(DWORD* Number,PageAddr,WorkingSetList,TmpPfn) // с упрощениями { Wsle=WorkingSetList->Wsle; inum=*Number; TmpPtr=Wsle+inum*4; *TmpPtr=PageAddr&0xfffff000|1; if(TmpPfn->0==CurThread){ TmpPfn->0=i; *TmpPtr|=0x400; return; } Num=*TmpPfn; if(WorkingSetList->HashPtr==0 && WorkingSetList->NumOfWsleItems>Num && WorkingSetList->FirstDynamicFirstFreeWsle==Num){ WorkingSetList->FirstFreeWsle=inum; i=*TmpPtr; *TmpPtr=*(Wsle+4*Num); *(Wsle+4*Num)=i; inum=Num; } else if(!*(Wsle+(Num-1)*4)&1){ if(*(Wsle+(Num-1)*4)>>4==Num)Tmp=Num-1; } else if(!*(Wsle+(Num+1)*4)&1){ if(*(Wsle+(Num+1)*4)>>4==Num)Tmp=Num+1; } if(Tmp){ i=*(Wsle+4*inum); *(Wsle+Tmp*4)=inum<<4; *(Wsle+inum*4)=*(Wsle+Num*4); *(Wsle+Num*4)=i; inum=Num; } }// if val else if(Val&0x400){ MiSwapWslEntries(Num,inum,CurPorcess->VM); inum=Num; } *Number=inum; if(WorkingSetList->LastWsleIndexLastWsleIndex=inum; } // hash MiInsertWsle(inum,WorkingSetList); // ecx, edx return; } /**************************************************************************/ /* Вставить элемент в wsle */ /**************************************************************************/ MiInserWsle(inum,WorkingSetList) { i=inum; Wsle=WorkingSetList->Wsle; WorkingSetList->NumOfWsleInserted++; Num=WorkingSetList->NumOfWsleInserted; HashPtr=WorkingSetList->HashPtr; HashSize=WorkingSetList->HashSize; if(!HashPtr)return; Val=Wsle+i*4; Mod=Val>>0xa%(HashSize-1); Tmp=HashSize>>4+Num+0xa; if(Tmp>HashSize){//if(2) // не пора ли почистить некоторые элементы из хэша? VM=CurProcess->VM; Tmp=(0xbee5c-MiMaximumWorkingSet)&0x3ffffc00>>1-0x400; if(Tmp>HashSize&&VM->fl0==0)VM->fl0=0x14; if((HashSize>>4+Num)>HashSize) {//if(3) KeQueryTickCount(&TickCount); TmpRnd=TickCount&0xf+Mod; if(HashSize<=TmpRnd)TmpRnd=TickCount&0xf; while(1){//while if(*(HashPtr+TmpRnd*8)){//if(4) Num=HashPtr+TmpRnd*8+4; TmpPte=*(Wsle+Num*4)>>0xa+0xc0000000; if(MiFreeWsle(Num,VM,TmpPte))break; }//if(4) TmpRnd++; if(HashSize<=TmpRnd)TmpRnd=0; }//while }//if(3) }//if(2) if(*(HashPtr+Mod*8)) { while(1){ Mod++; if(HashSize<=Mod)Mod=0; if(!*(HashPtr+Mod*8))break; } } *(HashPtr+Mod*8)=*(Wsle+i*4); *(HashPtr+Mod*8+4)=i; return; } /******************************************************************************/ /* Найти свободный wsle вход в Wsle/обычно косвенно вызывается при стр. ошибке*/ /******************************************************************************/ DWORD MiLocateAndReserveWsle(VM) { WorkingSetList=VM->WorkingSetList; Wsle=WorkingSetList->Wsle; VM->PageFaultCount++; MmInfoCounters.PageFaults++; // 0 disp while(1) { if(VM->MinimumWorkingSet>VM->WorkingSet){ i=0; inc=1; break; } if(VM->fl0!=6){ if((WorkingSetList->Quota)>(VM->WorkingSetSize)) { i=10; inc=1; break; } if(VM->MaximumWorkingSet>(VM->WorkingSetSize)) { if((VM->PageFaultCount-VM->Pages)fl3==2)i-=0xfa; } else i=MmWsAdjustTreshold; inc=MmWorkingSetSizeIncrement; break; } if((VM->PageFaultCount-VM->Pages)<(VM->WorkingSetSize>>3)) { i=MmMoreThanEnouthFreePages+0xc8; if(VM->fl3==2)i-=0xfa; } else i+=MmWsExpandTreshold; inc=MmWorkingSetSizeExpansion; if(VM->WorkingSetSize>MiMaximumWorkingSet){i=-1;inc=1;} break; } MiTrimWorkingSet(0x14,VM,1); KeQuerySystemTime(&TimerCount); VM->fl0=1; VM->UpdateTime=TimerCount; VM->Pages=VM->PageFaultCount; WorkingSetList->Quota=VM->WorkingSetSize; if(VM->MinimumWorkingSet>VM->WorkingSetSize)WorkingSetList->Quota=VM->MinimumWorkingSet; } if(!VM->fl1&&i&&(MmAvailablePages<=i||(!VM->WorkingSetExpansion.Flink)){ i=Count=WorkingSetList->NextSlot; k=0; do{ // диапазоны этого цикла // от [0x10] до 0xc , от 0x8 до 0x10 i++; if(i>=WorkingSetList->LastWsleIndex)i=WorkingSetList->FirstDynamic; val=*(Wsle+i*4); if(!val&1)continue; TmpPte=val>>0xa+0xc0000000; if(!*TmpPte&0x20||(k>0x11&&i!=count)) if(MiFreeWsle(i,VM,TmpPte){ WorkingSetList->NextSlot=i; break;} *TmpPte&=0xffffffdf; k++; }while(i!=count); } VM->WorkingSetSize++; if(VM->WorkingSetSize>WorkingSetList->Quota) { WorkingSetList->Quota+=inc; VM->Pages=VM->PageFaultCount; if(WorkingSetList->NumOfWsleItemsQuota)MiAddWorkingSetPage(VM); } TmpWsle=WorkingSetList->FirstFreeWsle; WorkingSetList->FirstFreeWsle=*(Wsle+TmpWsle*4)>>4; if(VM->WorkingSetSize>VM->MinimumWorkingSet)MmPagesAboveWsMinimum++; if(VM->PeakWorkingSetSize<=VM->WorkingSetSize)VM->PeakWorkingSetSize=VM->WorkingSetSize; if(WorkingSetList->LastWsleIndexLastWsleIndex=TmpWsle; return TmpWsle; } /**************************************************************************/ /* Урезать WorkingSet */ /**************************************************************************/ MiTrimWorkingSet(NumToDel,VM,aggresive_fl) { n=NumToDel; WorkingSetList=VM->WorkingSetList; Wsle=WorkingSetList->Wsle; last_i=WorkingSetList->LastWsleIndex; CurIndex=WorkingSetList->NextSlot; par3=(aggresive_fl==0)?0xfd:0+5; i=0; for(i=0;i!=par3&&n;i++,CurIndex=WorkingSetList->FirstDynamic){ for(;n;CurIndex++){ if(CurIndex>last_i)break; if(!*(Wsle+CurIndex*4)&1)continue; TmpPte=*(Wsle+CurIndex*4)>>0xa+0xc0000000; if(*TmpPte&0x20){*TmpPte&=0xffffffdf;continue;} if(MiFreeWsle(CurIndex,VM,TmpPte))n--; } } WorkingSetList->NextSlot =CurIndex; if(VM->WorkingSetSize==WorkingSetList->FirstDynamic)return Num-n; if(WorkingSetList->Quota+0x40f>=WorkingSetList->LastWsleIndex)return Num-n; if((VM->MaximumWorkingSet+0x40f)>=WorkingSetList->LastWsleIndex)return Num-n; MiRemoveWorkingSetPages(WorkingSetList,VM); return Num-n; } //................. /**************************************************************************/ /* Убить страницы WorkingSet */ /**************************************************************************/ MiRemoveWorkingSetPages(WorkingSetList,VM) { HashPtr=WorkingSetList->HashPtr; if(HashPtr){ // есть ли хэш. Tmp=((WorkingSetList->NumOfWsleInserted<<4+0xfff)&0xfffff000)>>3; if(VM->WorkingSetSize<0xc8)Tmp=0; if(WorkingSetSize->HashSize>Tmp){ // урезать хэш? if(Tmp&&(VM->fl0!=0))VM->fl0=0x14; TmpPtr=Tmp*8+HashPtr; WorkingSetList->HashSize=Tmp; WorkingSetList->HashPtr=0; OldIrql=KeRaiseIrqlToDpcLevel(); TmpPte=TmpPtr>>0xa+0xc0000000; while(*TmpPte&1){ MiDeletePte(TmpPte,TmpPte<<0xa,0,CurProcess,0,&PtesList); CurProcess->NumberOfPrivatePages++; TmpPte+=4; } MiFlushPteList(&PteList,0,ZeroPte); KeLowerIrql(OldIrql); } } Wsle=WorkingSetList->Wsle; if(VM->WorkingSetSize==WorkingSetList->FirstDynamic){ k=WorkingSetList->FirstDynamic; TmpPtr=Wsle+WorkingSetList->k*4; goto jmp1; } i=WorkingSetList->FirstDynamic; k=WorkingSetList->LastWsleIndex; TmpPtr1=Wsle+i*4; TmpPtr=Wsle+k*4; fl=0; if(TmpPtr>TmpPtr1) // перераспределить элементы таблицы // (дефрагментация WorkingSet) { while(TmpPtr>TmpPtr1){ if(*TmpPtr1&1){TmpPtr1+=4;i++;continue;}// ищем сл. свободное место if(!*TmpPtr&1){TmpPtr-=4;k--;continue;} //ищем сл. занятое место *TmpPtr1=*TmpPtr; // транспортировка fl=1; if(*TmpPtr&0x400){// нет в хэше, можем переставить номера фрэймов руками TmpPte=*TmpPtr>>0xa+0xc0000000; TmpPfn=MmPfnDatabase+0x18*((*TmpPte)>>0xc); TmpPfn->0=i; } else { MiRemoveWsle(k,WorkingSetList); MiInsertWsle(i,WorkingSetList); } k--; *TmpPtr=0; TmpPtr-=4; TmpPtr1+=4; i++; } } if(!fl)return; jmp1: ; if(*TmpPtr&1)TmpPtr+=4;k++; WorkingSetList->FirstFreeWsle=k; WorkingSetList->LastWsleIndex=k-1; TmpPtr1=TmpPtr; if(WorkingSetList->NumOfWsleItems>k)// заполнить список пустых мест { Val=k<<4; while(1){ Val+=0x10; k++; *TmpPtr=Val; TmpPtr+=4; if(k>=WorkingSetList->NumOfWsleItems)break; } } n=WorkingSetList->NumOfWsleItems; TmpPte=(Wsle+n*4)>>0xa+0xc0000000; TmpPtr=Wsle+VM->MinimumWorkingSet*4; if(TmpPtr1>0xa)+0xc0000000; while(TmpPte2NumberOfPrivatePages++; } MiFlushPteList(&PtesList,0,ZeroPte); KeLowerIrql(OldIrql); Ptr=TmpPtr1&0xfffff000+0xffc; *(Ptr)=0xfffffff0; WorkingSetList->NextSlot=WorkingSet->FirstDynamic; WorkingSet->NumOfWsleItems=(Ptr-Wsle)>>2; if(WorkingSetList->QuotaNumOfWsleItems)WorkingSetList->Quota=WorkingSet->NumOfWsleItems; return; } /**************************************************************************/ /* Добавить страницу к WorkingSet */ /**************************************************************************/ MiAddValidPageToWorkingSet(PageAddr,Pfn,Flags) { if(PageAddr<=MmHighestUserAddress||(PageAddr>=0xc0000000&&PageAddr<0xc07fffff)) { VM=&CurProcess->VM; Wsle=MmWsle; } else { Wsle=MmSystemCacheWsle; VM=&MmSystemCacheWs; } Num=MiLocateAndReserveWsle(VM); MiUpdateWsle(&Num,PageAddr,VM->WorkingSetList,Pfn); *(Wsle+Num*4)|=Flags; } /**************************************************************************/ MiCheckPdeForPagedPool(adr) { SysPte=MmSystemRangeStart>>10+0xc0000000; if(adr0xc03fffff){ if(adr>20+0xc0300000; ret=0; } else {// adr lies in system pte ret=1; Pde=adr>>10+0xc0000000; } if(*Pde&1)return ret; *Pde=*(MmSystemPagePtes+Pde&0xffc); return ret; } /**************************************************************************/ 02.Псевдокод для функции MmInitMachineDependents(). (NT4.0) =========================================================== Несколько слов. В этой функции сосредоточены машино-зависимые действия менеджера памяти при инициализации подсистемы памяти, работает эта функция в основном со структурами, которые были описаны выше. Многие вещи стали для меня понятны, после разбора этой совсем не маленькой рутины. Конечно, что бы не совсем не захламлять код детализацией - кое-где делались упрощения. Не описаны переменные, но легко догадаться о их типах из названий и контекста. Так же явно не производится инициализация. Указатели, если не оговорено, имеют тип BYTE*. Тип по умолчанию - DWORD. Кое-где вместо имен полей, проставлены их смещения. Например, такая строчка псевдокода: TmpPfn=(MmPfnDatabase+0x18*PfnOfModifPage); На C будет выглядеть так: TmpPfn=MmPfnDatabase[PfnOfModifPage]; Или TmpPfn=(PfnDatabaseEntry*)((char*)MmPfnDatabase+0x18*PfnOfModifPage); Функция получает в качестве параметра номер фазы. Я отдельно привожу псевдокод для двух фаз. Немного о LoaderBlock --------------------- На стадии инициализации, ядром используется информация, полученная загрузчиком. Что бы понять, что делает MmInitMachineDependents(), надо кое что описать... LoaderBlock: .... +0x8 -> +--- +---- |0 dd -> |Next 4 | 8 dd Flag {3-LoaderBad,2|5} c dd BasePage 10 dd PageCount +0x44 -> Switches .... По смещению 0x8 в LoaderBlock находится указатель на список, который описывает память, обнаруженную загрузчиком. Каждый элемент списка содержит указатель на следующий блок, номер базовой страницы, счетчик страниц, который описывает данный блок, флаги и неизвестные мне поля, которые не понадобились. Значения флагов до конца не понятно, главное, что область может быть отмечена как "плохая", область "ядра" и нормальная. Именно флаг "плохая" область используется в опции BURNMEMORY.(* см. ExBurnMemory) Псевдокод MmInitMachineDependents(0)для фазы 0 =============================================== PDWORD ptr=0; DWORD DirectoryPageBase; //KeFeatureBits - описание бит. //=========================== // 7 6 5 4 3 2 1 0 //Бит Что означает Значение //7 - XmpXchng комманда 0x80 //1 - stamp counter 0x2 //3 - CMOV 0x8 //0&2 - VME 0x5 //6 - MTRR 0x40 //8 - unknown (higher than pentium) 0x100 //5&2 - pse 0x24 //4&2 - PGE 0x14 if(KeFeaturesBits&0x10){ //PGE MmPteGlobal=1; ValidKernelPte|=0x100; } DirectoryPageBase=*((dword*)c0300c00)>>12; // Directory frame CurProcess->Pde=DirectoryPageBase; // memset(c0300000,0,0x400); // clear DT PLOADERFRAME pLoaderPageFrames=pLoaderBlock->pLoaderFrames; // disp=8 // got frames from loader PLOADERFRAME pLoaderPageFrame=pLoaderPageFrames;// got first frame pointer /********Got Lowest Highest frames and Largest Blocks***************/ if(pLoaderPageFrames-pLoaderBlock!=8) { for(;pLoaderPageFrame=pLoaderPageFrame->Next;pLoaderPageFrames-pLoaderBlock!=8) // For all frames from loader { FramesFlag=pLoaderPageFrames->Flag; if(FrameFlag==6||FrameFlag==0x16)continue; // skip this frames MmNumberOfPhysicalPage+=pLoaderPageFrame->PageCount; if(MmLowestPhysicalPage>pLoaderPageFrame->BasePage) MmLowestPhysicalPage=pLoaderPageFrame->BasePage; if(MmHighestPhysicalPageBasePage+pLoaderPageFrame->PageCount) MmHighestPhysicalPage=pLoaderPageFrame->BasePage+pLoaderPageFrame->PageCount-1; if(FrameFlag==2||FrameFlag==4||FrameFlag==5||FrameFlag==8) { if(pLoaderPageFrame->PageCount>MaxPageCount) { MaxPageCount=pLoaderPageFrame->PageCount; pLoaderMaxPageFrames=pLoaderPageFrame; // search for max block } if(pLoaderPageFrame->BasePage<0x1000&&PagesToCellPageCount) // 0x1000-16Mb // looking for largest block in low 16MB { if(PagesToCell<(0x1000-PageBase)) { PagesToCell=(PageCount<0x1000-PageBase)?PageCount:0x1000-PageBase; pLargestBlockInLow16Mb=pLoaderPageFrame; } } } }//for }// if // now we have MaxPagesCount,pLoaderMaxPageFrames,pLargestBlockInLow16Mb // and PagesToCell /************************************************************************/ LargestLowBasePage=pLargestBlockInLow16Mb->BasePage; LargestLowPageCounter=pLargestBlockInLow16Mb->PageCounter; LargestBasePage=pLoaderMaxPageFrames->PageBase; LargestCounter=pLoaderMaxPageFrames->PageCounter; if(MmNumberOfPhysicalPages<0x44c)//if less than 4 MB KeBugCheckEx(0x7d,MmNumberOfPhysicalPages,MmLowestPhysicalPage,MmHighestPhysicalpage,0); /************************************************************************/ /////////////////////// ifautodetect, no info in reestr // MmSizeOfNonPagedPoolInBytes = 0 // MmMinimumNonPagedPoolSize = 0x40000 ; 256Kb // MmMinAdditionNonPagedPoolPerMb = 0x8000 ; 32Kb // MmMaxAdditionNonPagedPoolPerMb = 0x64000 ; 400k // MmMaximumNonPagedPoolInBytes = 0 // MmDefaultMaximumNonPagedPool = 0x100000 ; 1 Mb // MmSecondaryColors = 0 // MmNonPagedPoolEnd = 0xFFBE0000 // MmNonPagedPoolStart = 0 /***********Got NP pool size and start***********************************/ if(MmNumberOfPhysicalPages*56<(MmSizeOfNonPagedPoolInBytes>>12)) MmSizeOfNonPagedPoolInBytes=0; if(MmSizeOfNonPagedPoolInBytes>8)* // in MB MmMinAdditionNonPagedPoolPerMb+ MmMinimumNonPagedPoolSize; } if(MmSizeOfNonPagedPoolInBytes>0x8000000(128mb)) MmSizeOfNonPagedPoolInBytes=128Mb MmSizeOfNonPagedPoolInBytes&=0xfffff000; //Page aligned if(MmMaximumNonPagedPoolInBytes==0){ MmMaximumNonPagedPoolInBytes=((NumberOfPhysPages-0x400)>>8)* //in Mb MmMaxAdditionNonPagedPoolPerMb + (MmHigestPhysicalPage*0x18)&0xfffff000+ MmDefaultMaximumNonPagedPool; } if(MmMaximumNonPagedPoolInBytes < MmHigestPhysicalPage*0x18&0xfffff000 + MmSizeOfNonPagedPoolInBytes+0x10000) MmMaximumNonPagedPoolInBytes=MmHigestPhysicalPage*0x18&0xfffff000+ //PfnDB size MmSizeOfNonPagedPoolInBytes+ //NPPool 0x10000; //Fixed if(MmMaximumNonPagedPoolInBytes>0x8000000) // 128Mb MmMaximumNonPagedPoolInBytes=0x8000000; PfnDatabaseSizeInPages=(MmSecondaryColors<<4+(MmHighestPhysicalPage+1)*0x18)>>12+1; MmMaximumNonPagedPoolInBytes+=PfnDatabaseSizeInPages<<12; // Hmm... Done twice?? MmNonPagedPoolStart=(MmNonPagedPoolEnd-MmMaximumNonPagedPoolInBytes) &0xfffff000; //Page Aligned MmPageAlignedPoolBase=MmNonPagedPoolStart; MmNonPagedSystemStart=((0xffffffff-MmNumberOfSystemPtes)<<0xc + MmPageAlignedPoolBase)&0xffc00000; // high 10 bits if(MmNonPagedSystemStart<0xeb000000){ MmNonPagedSystemStart=0xeb000000; MmNumberOfSystemPtes=(MmPageAlignedPoolBase+0x15000000)>>0xc-1; } StartPde=(MmNonPagedSystemStart&0xffcfffff)>>0x14+0xc0300000; //Start PDE of non-paged address space EndPde=((MmNonPagedPoolEnd-1)&0xffcfffff)>>0x14+0xc0300000; //End PDE of non-paged address space if(EndPde>=StartPde){ // if so, jump to the second buffer // one pde describes 1024*4Kb = 4Mb // so, if we have more than 4Mb of NPPool // get largest block pLargestAreaInLow16Mb=BasePageLowLargest<<0xc; PagesToCell-=((EndPde-StartPde)+4)>>2; BasePageLowLargest+=((EndPde-StartPde)+4)>>2; } /***********************Fill np pool page tables with 0******************/ do{ ValidKernelPde_U=(ValidKernelPde_U&0xfff|pLargestAreaInLow16Mb; *StartPde=ValidKernelPde_U; pLargestAreaInLow16Mb+=0x1000; // next page StartPde+=4; memset(StartPde<<0xa,0,0x400); //fill corresponding page table with zeros // (pagetable of np pool.) }while(StartPde<=EndPde); /**********************If PSE enabled manipulations**********************/ // map all (almost) physical memory (<=512mb)... if(MmVirtualBias==0 && KeFeatureBits&0x20 && //PSE - we have >P5 processor // with 4mb pages feature MmNumberPfPhysicalPages>0x1f00 )// 31 MB { HighestPagePde=0xc03009fc; //PT represents from 9fc00000 to 9fffffff if(MmHighestPhysicalPage<0x20000) //512Mb { // if so, all physical pages // directly mapped from 0x80000000 to 0x9fffffff HighestPagePde=((MmHighestPhysicalPage+0x80000) // + 2Gb &0xffc00)>>8+0xc0300000; } ValidKernelPde_U=ValidKernelPde; SystemPte=0xc0200000; // System Page Tables SystemPhysAddresses=0; SystemPde=0xc0300800; // System PDEs while(;SystemPde<=HighestPagePde;SystemPte+=0x1000,SystemPde+=4;){ // for all system Pde's and Pte's pd_fl=0; if(!*SystemPde&1) { // if not present ValidKernelPde_U=ValidKernelPde_U&0xfff|(BasePageLowLargest<<0xc); BasePageLowLargest++; PagesToCell--; if(!PagesToCell){//change buffer if needed BasePageLowLargest=pLoaderMaxPageFrames->BasePage; PagesToCell=pLoaderMaxPageFrames->PageCount; } *SystemPde=ValidKernelPde_U; pd_fl=1; //we did it! } Count=0x400; while(Count--) // for all pte's { if(pd_fl||(!*SystemPte&1)){ *SystemPte=ValidKernelPte|SystemPhysAddresses; } SystemPte+=4; SystemPhysAddresses+=0x1000; } }//while PSE_Flag=1; //PSE feature needed }//if NonPagedPoolStart=MmNonPagedPoolStart; NonPagedPoolSize=MmNonPagedPoolSizeInBytes; NonPagedPoolPTStart=(MmNonPagedPoolStart&fffff3ff)>>10+c0000000;//NonPagedPool start Page Table NonPagedPoolPTEnd=(MmSizeOfNonPagedPoolInBytes+MmNonPagedPoolStart-1)&0xfffff3ff>>10+c0000000; if(PSE_Flag) // if PSE feature enabled (>P5) { //PSE feature if(NonPagedPoolSize>(PagesToCell<<12)) MmSizeOfNonPagedPoolInBytes=PagesToCell<<12; NonPagedPoolStart=MmNonPagedPoolStart+MmSizeOfNonPagedPoolInBytes; MmNonPagedPoolStart=(BasePageLowLargest|fff80000)<<0xc; // NonPagedPoolStart is PhysicalAddr+0x80... BasePageLowLargest+=MmSizeOfNonPagedPoolInBytes>>0xc; PagesToCell-=MmSizeOfNonPagedPoolInBytes>>0xc; if(!PagesToCell) // switch to the next buffer { BasePageLowLargest=pLoaderMaxPageFrames->BasePage; PagesToCell=pLoaderMaxPageFrames->PageCount; } MmSubsectionBase=MmNonPagedPoolStart; if(BasePageLowLargest<0x8000) //low 128 Mb { MmSubsectionBase=0x80000000; //2Gb MmSubsectionTopPage=0x8000;// 128Mb } MmNonPagedPoolExpansionStart=NonPagedPoolStart +NonPagedPoolSize -MmSizeOfNonPagedPoolInBytes; } else { //PSE_flag=0 // just fill all pde's if(NonPagedPoolPTStart<=NonPagedPoolPTEnd) //(MmSizeOfNonPagedPoolInBytes+_ecx-1)&0xfffff3ff>>10+c0000000) { for(;NonPagedPoolPTStart<=NonPagedPoolPTEnd;NonPagedPoolPTStart+=4;) { ValidKernelPde_U=ValidKernelPde_U&0xfff|(BasePageLowLargest<<0xc); BasePageLowLargest++; PagesToCell--; if(!PagesToCell) { BasePageLowLargest=pLoaderMaxPageFrames->BasePage; PagesToCell=pLoaderMaxPageFrames->PageCount; } *NonPagedPoolPTStart=ValidKernelPde_U; }//for }/if MmNonPagedPoolExpansionStart=MmSizeOfNonPagedPoolInBytes+NonPagedPoolStart; }//else MmPageAlignedPoolBase=MmNonPagedPoolStart; MmMaximumNonPagedPoolInBytes+=MmSizeOfNonPagedPoolInBytes-NonPagedPoolSize; MiInitializeNonPagedPool(MmNonPagedPoolStart); MmMaximumNonPagedPoolInBytes+=-(MmSizeOfNonPagedPoolInBytes-NonPagedPoolSize); MmSecondaryColors>>=0xc; if(!MmSecondaryColors||(MmSecondaryColors&(MmSecondaryColors-1))||MmSecondaryColors<2||MmSecondaryColors>0x400) MmSecondaryColors=0x40; // in reality always 0x40 MmSecondaryColorMask=MmSecondaryColors-1; //0x3f TopPages=pLoaderMaxPageFrames->BasePage+pLoaderMaxPageFrames->PageCount; FreeRoom=TopPages-BasePageLowLargest; // free room of block, that not used yet if(PSE_Flag&&FreeRoom>=PfnDatabaseSizeInPages&&TopPages<0x2000) //0x2000 == 32M { // if PSE feature is on, so - MmPfn will be in 0x8000...(512Mb) block flg3=1; MmPfnDatabase=(TopPages-PfnDatabaseSizeInPages)|0xfff80000<<0xc; memset(MmPfnDatabase,0,PfnDatabaseSizeInPages<<0xc); pLoaderMaxPageFrames->PageCount-=PfnDatabaseSizeInPages; if(MmTotalFreeSystemPtes.Pool1>0x8000) { MiReserveSystemPtes(MmTotalFreeSystemPtes.Pool1-0x8000,1,0,0,1); } } else{ // it's harder, if PSE is off :( TmpPte=MiReserveSystemPtes(PfnDatabaseSizeInPages,1,0,0,1); MmPfnDatabase=TmpPte<<10; if(pLoaderPageFrames-pLoaderBlock!=8) { pLoaderPageFrame=pLoaderPageFrames; for(;pLoaderPageFrame=pLoaderPageFrame->Next;pLoaderPageFrames-pLoaderBlock!=8) // for all blocks { if(pLoaderPageFrame->Flag==6||pLoaderPageFrame->Flag==0x16)continue; PfnEntryHighPte=((pLoaderPageFrame->PageCount+pLoaderPageFrame->BasePage)* 0x18+MmPfnDatabase-1)>>0xa+0xc0000000; PfnEntryPte=(pLoaderPageFrame->BasePage*0x18+MmPfnDatabase)>>0xa+0xc0000000; if(PfnEntryPte<=PfnEntryHighPte) { for(PfnEntryPte<=PfnEntryHighPte;PfnEntryPte+=4;) { if(*PfnEntryPte&1)continue; ValidKernelPde_U=BasePageLowLargest<<0xc|ValidKernelPde_U&0xfff; BasePageLowLargest++; PagesToCell--; if(!PagesToCell) { BasePageLowLargest=pLoaderMaxPageFrames->BasePage; PagesToCell=pLoaderMaxPageFrames->PageCount; } *PfnEntryPte=ValidKernelPde_U; memset(PfnEntryPte<<0xa,0,0x400); } } } //for }// } //else MmFreePagesByColor.Start(0)=MmHighestPhysicalPage*0x18+MmPfnDatabase+0x18; MmFreePagesByColor.End(4)=MmHighestPhysicalPage*0x18+MmPfnDatabase+0x18+MmSecondaryColors<<3; if(FreePagesByColor>0xa0000000) { FreePagesByColorStartPte=MmFreePgaesByColor.Start>>0xa+c0000000 FreePagesByColorEndPte=(MmSecondaryColors<<3+MmFreePagesByColor.End-1)>>a+0c0000000; if(FreePagesByColorStartPte<=FreePagesByColorEndPte){ for(;FreePagesByColorStartPte<=FreePagesByColorEndPte;FreePagesByColorStartPte+=4) { if(*FreePagesByColorStartPte&1)continue; ValidKernelPde_U=BasePageLowLargest<<0xc|ValidKernelPde_U&0xfff; BasePageLowLargest++; PagesToCell--; if(!PagesToCell) { BasePageLowLargest=pLoaderMaxPageFrames->BasePage; PagesToCell=pLoaderMaxPageFrames->PageCount; } *FreePagesByColorStartPte=ValidKernelPde_U; memset(FreePagesByColorStartPte<>12; NPPoolSizeInPages=MmSizeOfNonPagedPoolInBytes>>12; pPfn=MmPfnDatabase+NPPoolStartPhysPage*0x18;// pPfn на фрэйм начала pool'a NPPoolStartPageAligned=NPPoolStartPhysPage<<12; while(NPPoolSizeInPages--)// для всех страниц pool'a { pTmpPde=0xc0300000+(CurPhysPage+0x80000)&0xffc00>>8; // pde на таблицу страниц, в которой определен pte описывающий // эту физическую страницу CurPhysPage++; pPfn->Frame(14)=*pTmpPde>>12;// фрэйм содержащий pte на эту страницу pPfn->Pte=NPPoolStartPageAligned; NPPoolStartPageAligned+=0x1000; pPfn->ShareCounter++; pPfn->RefCounter=1; pPfn->Flags=pPfn->Flags&0xfeff|0x600&0xff8f; } } PPDE pPde=0xc0300000; // указатель на 0 pde DWORD Num=0x400; DWORD i=0; // The last step, fill pfn while(num--) //0x400 (1024) раз. Для всех pde { if(MmVirtualBias!=0&&(pPde>=0xc0300800&&pPde<0xc0300810)) { pPde+=4; i+=0x400000; continue; } if((*pPde&0x1==0)|(*pPde&0x80)){// отсутствующий Pde или таблицы в 4m i+=0x400000; pPde+=4; continue; } Frame=*pPde>>12; // фрэйм таблицы страниц pPfn=(PFN)(Frame*0x18+(char*)MmPfnDatabase); // указатель на фрэйм таблицы страниц pPfn->Pte=pPde; // pde в данном случае играет роль pde pPfn->RefCounter=1; pPfn->ShareCounter++; pPfn->Flags=pPfn->Flags&0xfe00|0x600&0xff8f; pPfn->ContFrame=*pTmpPde>>12; pPte=0xc0000000+(i&0xfffff3ff)>>10;// 0й pte в таблице соотв pde Mask=MiDetermineUserGlobalPteMask(pPte); *pPde|=Mask&0xffffffdf; k=0x400; for(;k>0;k--,i+=0x1000,pPte+=4)// для всех pte { if(!((*pPte)&1))continue; // не присутствует Mask=MiDetermineUserGlobalPteMask(pPte); *pPte|=Mask&0xffffffdf; pPfn->ShareCount++; if((*pPte>>12)>MmHighestPhysicalPage)continue; if(i<0xa0000000)continue; // pte отображает адреса // до 0xa0000000 if(i<(MmVirtualBias+0x80000000)|| (i>=(MmVirtualBias+0x81000000)) { pPfn2=MmPfnDatabase+(*pPte>>12)*0x18; // указатель на фрэйм соотв текущему pte if(!MmIsAddressValid(pPfn2)continue; if(!MmIsAddressValid(pPfn2+0x17)continue; pPfn2->ContFrame=Frame;// фрэйм табл страниц pPfn2->Pte=pPte; pPfn2->ShareCounter++; pPfn2->RefCounter=1; pPfn2->Flags=pPfn2->Flags&0xfeff|0x600&0xff8f; } } pPde+=4; } //... поднять IRQL на DPC KeFlushCurrentTb(); //... спустить IRQL pPfn=MmLowestPhysicalPage*0x18+MmPfnDatabase; if((MmLowestPhysicalPage==0)&&pPfn->RefCounter==0) { pPfn->ContFrame=DirectoryPageBase; pPfn->Pte=0xc0300ffc; pPfn->ShareCounter++; pPfn->RefCounter=0xfff0 pPfn->Flags=pPfn->Flags&0xfeff|0x600&0xff8f; } TopOfLowBlock=pLargestBlockInLow16m->PageCount+pLargestBlockInLow16m->BasePage; if(TopOfLowBlock>=BasePageLowLargest) { pLargestBlockInLow16m->PageCount=pLargestBlockInLow16m->PageCount-BasePageLowLargest +BasePageLowLargestOrig; pLargestBlockInLow16m->BasePage=BasePageLowLargest; } else { pLargestBlockInLow16m->PageCount=0; pLoaderMaxPageFrames->PageCount+=MaxBase-BasePageLowLargest; pLoaderMaxPageFrames->BasePage=BasePageLowLargest; } // for all pages, from loader info, that are free if(pLoaderPageFrames-pLoaderBlock!=8) { pLoaderPageFrame=pLoaderPageFrames; for(;pLoaderPageFrame=pLoaderPageFrame->Next;pLoaderPageFrames-pLoaderBlock!=8) { // for all blocks Count=pLoaderPageFrame->PageCount; Base=pLoaderPageFrame->BasePage; Flag=pLoaderPageFrame->Flag; switch(Flag) { default: case 0: // kernel blocks? case 1: TmpPfn=Base*0x18+MmPfnDatabase; TmpPte=(MmVirtualBias+(Base+0x80000)<<0xc)>>a+0xc0000000; Base8=(Base+0x80000)<<0xc); if(!Count)break; for(;Count!=0;TmpPte+=4,Count--,Base8+=0x1000,TmpPfn+=0x18) { TmpPde=((MmVirtualBias+Base8)&0xffcfffff>>)0x14+0xc0300000; if(!TmpPfn->RefCounter) { TmpPfn->ContFrame=DirectoryPageBase; if(!Flag)TmpPfn->14=*TmpPde>>0xc; TmpPfn->Pte=TmpPte; TmpPfn->Share++; TmpPfn->Ref=1; TmpPfn->Flags=Attr|0x00000600 .... } } break; case 2: // free case 4: case 5: case 8: if(MaxCount2RefCounter)continue; TmpPfn->Pte=BaseMul4; MiInsertPageInList(MmPageLocationList->MmFreePageListHead,Base); } break; case 3: // bad if(!Count)break; for(;count;Count--,Base++)MiInsertPageInList(MmPageLocationList->MmBadPageListHead,Base); case 0x16: case 6: }//switch }//for }// if if(!Flg3){ LowestPagePte=*((MmLowestPhysicalPage*0x18+MmPfnDatabase)&0xfffff3ff>>0xa+0xc0000000); ((LowestPagePte>>12)*0x18+MmPfnDatabase)->Flags|=ReadInProgress; HighestPagePte=&((MmHighestPhysicalPage*0x18+MmPfnDatabase)&0xfffff3ff>>0xa+0xc0000000); ((HighestPagePte>>12)*0x18+MmPfnDatabase)->Flags|=WriteInProgress; MmSubsectionPoolEnd=MmPfnDatabase; } else { // MmPfn is in 0x800... - 0x9ff.. TmpPfn=MmPfnDatabase&0x1ffff000>>0xc*0x18+MmPfnDatabase; TmpPte=MmPfnDatabase&0x1ffff000>>0xa; // where is + 0xc0... ??? // i don't know... for(;PfnDatabaseSizeInPages;PfnDatabaseSizeInPages--,TmpPte+=4) { TmpPfn->Pte=TmpPte; TmpPfn->Flags&=0x8f TmpPfn->Share++; } HighestPagePfn=MmHighestPhysicalPage*0x18+MmPfnDatabase; do { // remove pages from pfn, that are not used TmpPfn=HighestPagePfn; if(TmpPfn&0xfff){ // not page aligned TmpPfn&=0xfffff000; // nearest page ebx18=HighestPagePfn+0x18; } else { TmpPfn-=0x1000; ebx18=HighestPagePfn; } if(TmpPfn>0xc*0x18+MmPfnDatabase TmpPfn->Pte=TmpPfn&1ffff000>>10; TmpPfn->Attr&=0xffffff8f; MiInsertPageInList(MmPageLocationList.MmFreePageListHead,TmpPfn&1ffff000>>12); } } while(HighestPagePfn>MmPfnDatabase)//do }//else /************************Now, succeed pool****************/ TmpPte=MmNonPagedMustSucceed&0xfffff3ff>>0xa+0xc0000000; if(MmSizeOfNonPagedMustSucceed>0) { MustSucceedPages=(MmSizeOfNonPagedMustSucceed+0xfff)>>0xc; while(1) { TmpPfn=*TmpPte>>12+MmPfnDatabase; TmpPfn->Attr|=2; // Read in Progress TmpPfn->Attr|=4; // and write in progress TmpPte+=4; MustSucceedPages--; if(!MustSucceedPages)break; } } pLargestBlockInLow16m->Count=PageCountLowLargest; pLargestBlockInLow16m->BasePage=BasePageLowLargest; pMaxBlock->Count=MaxCounter; pMaxBlock->BasePage=MaxBase; KeInitializeSpinLock(MmSystemSpaceLock); KeInitializeSpinLock(MmPfnLock); NonPagedPteStart=NonPagedPoolStart>>10+c0000000; MmNumberOfSystemPtes=(NonPagedPteStart-MmNonPagedSystemStart>>0xa+0xc0000000)/4-1; MmInitializeSystemPtes(MmNonPagedSystemStart>>0xa+0xc0000000,MmNumberOfSystemPtes,0); LastPoolPages=(SizeInBytes-MmSizeOfNonPagedPoolInBytes)>>0xc; if(LastPoolPages){ ValidKernelPde_U=ValidKernelPte; Counter=MaxCount2; //max block #2 Frame=MaxBase2-1; TmpPde=NonPagedPteStart; while(1){ if(Counter){MiUnlinkFreeOrZeroedPage(++Frame); else {Frame=MiRemoveAnyPage(MmSecondaryColorMask& MmSystemPageColor); MmSystemPageColor++; } TmpPfn=MmPfnDatabase+Frame*0x18; TmpPfn->Ref=1; TmpPfn->Share=1; TmpPfn->Pte=TmpPde; TmpPfn->Trans=0x80; TmpPfn->ContFrame=*(TmpPde>>10+0xc0000000)>>12; TmpPfn->Attr=Attr&feff|0x600; ValidKernelPde_U=ValidKernelPde_U&0xfff|Frame<<12; *TmpPde=ValidKernelPde_U; TmpPde+=4; LastPages--; if(!LastPages==0)break; } TmpPfn->Flags|=4; *NonPagedPteStart >>12*0x18+MmPfnDatabase->Flags|=2; Old=MmAllocatedNonPagedPool; MiFreePoolPages(NonPagedPoolStart); MmAllocatedNonPagedPool=Old; } InitializePool(0,0); res=MiRemoveAnyPage(0); ValidKernelPde_U=MmValidKernelPde; ValidKernelPde_U=res<<12|ValidKernelPde_U; *c0300c04h=ValidKernelPde_U; // hyperspace pde //irql->2 KeFlushCurrentTb(); //<< memset(c0301000,0,0x400); // hyperspace pte MmFirstReservedMappingPte=0xc0301000; MmLastReservedMappingPte=0xc03013fc; MmWorkingSetList=0xc0502000; MmWsle=0xc0502690; TmpPfn=DirectoryPageBase*0x18+MmPfnDatabase; TmpPfn->Ref=0; TmpPfn->Share=0; res=MiRemoveAnyPage(0); CurProcess->WorkinSetPage=res; *c0300c08=res<<12|ValidKernelPde_U&0xfff; // Working Set Page KeFlushCurrentTb(); memset(0xc0302000,0,0x400); CurProcess->MinimumWorkingSet=MmSystemProcessWorkingSetMin; CurProcess->MaximumWorkingSet=MmSystemWorkingSetMax; MmInitializeProcessAddressSpace(CurProcess,0,0); *c0300c08=ZeroPte; if(!MmFreePagesByColor&0xfff && MmSecondaryColors&0x0fffffff<0x100) { OldFreeP=MmFreePagesByColor.List0; MmFreePagesByColor.List0=ExAllocatePoolWithTag(2,MmSecondaryColors*4,' mM'); MmFreePagesByColor.List1=MmSecondaryColors*8+MmFreePagesByColor.List0; memmove(MmFreePagesByColor.List0,OldFreeP,MmSecondaryColors*16); if(OldFreeP>0xa0000000) { OldPteFrame=*(OldFreeP>>10+0xc0000000)>>c; *(OldFreeP>>10+0xc0000000)=ZeroKernelPte; } else { OldFramePte=*OldFreeP>>10; } TmpPfn=MmPfnDatabase+0x18*OldFramePte; TmpPfn->ShareCounter=0; TmpPfn->RefCounter=1; TmpPfn->Pte=-1; MiDecrementReferenceCount(OldFramePte); } TmpPfn=MmPfnDatabase+0xf00; //a0 TmpPfn2=MmPfnDatabase+0x17e8; //ff while(1){ if(!TmpPfn->Share && !TmpPfn->Ref !TmpPfn->Pte) { TmpPfn->Ref=1; TmpPfn->Pte=0x7fffffff; TmpPfn->Attr -... 8f..6 & eff } TmpPfn+=0x18; if(TmpPfn2 0x1f00) { // поднять irql на dpc ValidKernelPde_U=ValidKernelPde&0xf7f|0x80; TmpPde=0xc0300800; while(1) { if(*TmpPde&1) { TmpPfn=PfnDatabase+0x18*(*TmpPde>>12); TmpPfn->Share=0;TmpPfn->Ref=1; TmpPfn->Attr=Attr&0xfaff|0x0200; TmpPfn->Pte=-1; MmDecrementReferenceCount((*TmpPde>>12)); *TmpPde=ValidKernelPde_U; invlpg *(TmpPde<=0xc0300a00)breakl } // опустить MmKseg2Frame=0x20000; return; } /******************************************************************/ Это все. Я не знаю, зачем надо было писать такую монолитную функию, но так есть... /*************************************************************************/ /*Сопровождающие функции. */ /*************************************************************************/ Приведу некоторые служебные функции, которые используются из MiInitMachineDepends(). /******************************************************************/ MiInitializePfn(Frame,Pte,Flag) { TmpPfn=MmPfnDatabase+Frame*0x18; TmpPfn->Pte=Pte; if(!(*Pte&1)){ // not present TmpPfn->RestorePte=*Pte; } else { TmpPfn->RestorePte=0x80; if(*Pte&0x10)TmpPfn->RestorePte=0x180; } TmpPfn->RefCount++; TmpPfn->ShareCounter++; NewFlag=TmpPfn->Flags&0xfeff|0x600; TmpPfn->Flags=NewFlag; TmpPfn->Flags=Flag^(NewFlag)&1^NewFlag; ContFrame=(Pte&0xfffff3ff>>10+0xc0000000)>>12; TmpPfn->ContFrame=ContFrame; (MmPfnDatabase+0x18*ContFrame)->ShareCount++; } 03.Псевдокод для функции MmAccessFault. (NT4.0) =============================================== /*************************************************************************/ MmAccessFault(Wr,Addr,P) { CurIrql=KeGetCurrentIrql(); AddrPte=Addr>>0xa+0xc0000000; // got pte and pde AddrPde=Addr>>0x14+0xc0300000; if(CurIrql>1){ // >APC MiCheckPdeForPagedPool(Addr); if(*AddrPde&1||*AddrPde&0x80)return 0; if(!*AddrPde&1)return 0xd0000006; if(!*AddrPte&1)return 0xd0000006; if(Wr==0)return 0; if(!*AddrPte&0x200)return 0; return 0xd0000006; } if(Addr>=MmSystemRangeStart) // system area { if(P==1)return STATUS_ACCESS_VIOLATION; // если страница присутствует, // но возникло исключение, то ,значит, // ошибка доступа! if(!*AddrPde&1){ // если проблемы с Pde MiCheckPdeForPagedPool(Addr); if(!*AddrPde&1)KeBugCheck... } if(*AddrPde&0x80)return 0;// игнорировать if(*AddrPte&1)return 0; // Теперь есть pte? if(Addr<0xc0000000||Addr>0xc07fffff){ // этот фрейм не из таблицы страниц if(MmSystemLockOwner==CurThread)return 0xd0000006;// r bit on!!! OldIrql=KeRaiseIrql(1); ExAcquireResourceExclusiveLite(MmSystemWsLock); MmSystemLockOwner=CurThread; PteVal=*AddrPte; if(PteVal&1){// еще разок проверим ExReleaseResourceLite(MmSystemWsLock); KeLowerIrql(OldIrql); return 0; } if(PteVal&0x400){//proto??? Ppte=(PteVal&0xfffff800)>>2|(PteVal&0xff<<1)+0xe1000000; } else { if(!PteVal&0xbe0)KeBugCheck... if(!PteVal&0x3e0)KeBugCheck... } Status=MiDispatchFault(Wr,Addr,AddrPte,Ppte,0); if(MmSystemCacheWs.fl0==0x14) {MiGrowWsleHash(MmSystemCacheWs,1);MmSystemCacheWs.fl0==1;} MmSystemLockOwner=0; ExReleaseResourceLite(MmSystemWsLock); KeLowerIrql(OldIrql); if(MmSystemCacheWs.PageFaultCount&0x3ffff==0x30000)KeDelayExecutionThread(0,0,MmShortTime); return Status; } else if(MiCheckPdeForPagedPool(Addr))return 0;//таблица страниц }// конец обработки системной области if(MmDelayPageFaults){// флаг if((MmModifiedPageListHead.Count>=MmModifiedPageMaximum+0x64)&& MmAvailablePages<0x100 && CurProcess->ModifiedPageCount>0x10){ if(CurProcess->BasePriority>=9)Time=Mm30Milliseconds; else Time=MmHalfSecond; KeDelayExecutionThread(0,0,Time); } } OldIrql=KeRaiseIrql(1); ExAcquireFastMutex(WorkingSetLock); if(!*AddrPde&1){// нет pde if(!*AddrPde){// pde==0 Ppte=MiCheckVirtualAddress(Addr,&res); if(res!=0x18) *AddrPde=DemandZeroPde; else { Status=STATUS_ACCESS_VIOLATION; MiCheckPdeForPagedPool(Addr); if(*AddrPde&1)Status=0; goto jmp1; } }// pde!=0 Status=MiDispatchFault(1,Addr,AddrPde,0,CurProcess); if(!*AddrPde&1)goto jmp0; //если pde нет } // здесь уже разобрались с pde, смотрим pte PteVal=*AddrPte; if(PteVal&1){ // pte присутствует Status=0; if(Wr==0){// была попытка _чтения_? if(Status)goto jmp1; KeLowerIrql(KeRaiseIrqlToDpcLevel()); goto jmp1; } // была попытка записи в ReadOnly if(PteVal&0x200){//CopyOnWrite бит. MiCopyOnWrite(Addr,AddrPte); Status=STATUS_PAGE_FAULT_COPY_ON_WRITE; goto jmp1; } if(!PteVal&2)Status=STATUS_ACCESS_VIOLATION;//ReadOnly goto jmp1; } else {// pte не присутствует if(PteVal==0x80){ MiResolveDemandZeroFault(Addr,AddrPte,CurProcess,0); Status=STATUS_PAGE_FAULT_DEMAND_ZERO; goto jmp0; } if(PteVal){// PteVal!=0 Attr=(PteVal&0x3e0)>>5; if(PteVal&0x400){ //ppte if(PteVal&0xfffff000==0xfffff000)Ppte=MiCheckVirtualAddress(Addr,&Res); else { Ppte=(PteVal&0xfffff800)>>2+(PteVal&0xff)<<1+0xe1000000; if(PteVal&0x100)Attr=1; } } } else { // PteVal==0 Ppte=MiCheckVirtualAddress(Addr,&Attr); if(Attr==0x18){ Status=STATUS_ACCESS_VIOLATION; MiCheckPdeForPagedPool(Addr); if(*AddrPte&1)Status=0; goto jmp1; } if(Addr<=MmHighestUserAddress)// добавить 1 к счетчику после WS *(MmWorkingSetList+(Addr>>22))*2+sizeof(WS_LIST))++; if(Attr&0x10){ // посмотреть, может это guard страница *AddrPte=(Attr&0xf)<<5|*AddrPte&0xfffffc1f; if(Ppte)*AddrPte=*AddrPte|0xfffff000|0x400; ExReleaseFastMutex(CurProcess->WorkingSetLock); KeLowerIrql(OldIrql); return MiCheckForUserStackOverflow(Addr); } if(!Ppte){// нет proto pte if(AddrPde!=0xc0300c00)*AddrPte=((Attr<<5)^*AddrPte)&0x3e0^*AddrPte; else *AddrPte=DemandZeroPde; // фаулт на PD OldIrql=KeRaiseIrqlToDpcLevel(); if(CurProcess->ForkInProgress&&CurProcess->ForkInProgress!=CurThread){ MiWaitForkToComplete(CurProcess); Status=0; KeLowerIrql(OldIrql); goto jmp0; } if(MiEnsureAvailablePageOrWait(CurProcess,Addr)) {KeLowerIrql(OldIrql); goto jmp0;} Seed=CurProcess->Seed&MmSecondaryColorMask; CurProcess->Seed++; if(*(MmFreePagesByColor+Seed*8)!=-1)Frame=MiRemoveZeroPage(Seed); if(!Frame){// нету чистых = чистить ручками Frame=RemoveAnypage(Seed); KeLowerIrql(Oldirql); MiZeroPhysicalPage(Frame,Seed); OldIrql=KeRaiseIrqlToDpcLevel(); } CurProcess->NumberOfPrivatePages++; MmInfoCounters->PrivatePages++;//...->0x10++; MiInitializePfn(Frame,AddrPte,1); KeLowerIrql(OldIrql); // заполнить Pte и pfn TmpPfn=Frame*0x18+MmPfnDatabase; Mask=MiDetermineUserGlobalPteMask(AddrPte); i=*AddrPte&0x3e0>>3; Mask=Mask|MmProtectToPteMask[i]; PteVal=Mask|(Frame<<12); if(PteVal&2)PteVal|=0x40; *AddrPte=PteVal; *TmpPfn=CurThread; // добавить в WorkingSet TmpWsle=MiLocateAndReserveWsle(CurProcess->VM); MiUpdateWsle(&TmpWsle,Addr,MmWorkingSetList); Status=STATUS_PAGE_FAULT_DEMAND_ZERO; goto jmp0; } else { // Ppte not null if(Attr==0x100) *AddrPte=((Ppte-0xe1000000)&0xffffff00|0x100)<<2| (Ppte&0x1fc>>1); else { *AddrPte=PrototypePte; *AddrPte=((Attr<<5)^PrototypePte)&0x3e0^PrototypePte; } } }// PteVal был 0 //endif if(Attr!=0x100){ r=MiAccessCheck(AddrPte,Wr,P,Attr); if(r){ ExReleaseFastMutex(WorkingSetLock); KeLowerIrql(OldIrql); if(r!=STATUS_GUARD_PAGE_VIOLATION)return r; return MiCheckForUserStackOverflow(Addr); } } if(Ppte){ if(Ppte<0x80000000||Ppte>=0xa0000000||MmKseg2Frame==0) { OldIrql=KeRaiseIrqlToDpcLevel(); TmpPte=(Ppte>>0xa)+0xc0000000; if(!*TmpPte&1)MiMakeSystemAddressValidPfn(Ppte); Val=*TmpPte; TmpPfn=(Val>>12)*0x18+MmPfnDatabase; TmpPfn->RefCounter++; KeLowerIrql(OldIrql); } } Status=MiDispatchFault(Wr,Addr,AddrPte,Ppte,CurProcess); if(Ppte==0)goto jmp0; if(Ppte>=0x80000000 && Ppte<0xa0000000&&MmKseg2Frame)goto jmp0; OldIrql=KeRaiseIrqlToDpcLevel(); TmpPfn->RefCounter--; KeLowerIrql(OldIrql); } jmp0: ; if(CurProcess->VM.fl0==0x14)MiGrowWsleHash(&CurProcess->VM,0); ExReleaseFastMutex(WorkingSetLock); KeLowerIrql(OldIrql); pc=CurProcess->VM.PageFaultCount; if(pc&0x3ffff!=0x30000)return Status; // определяет частоту фаултов. // Если частота большая - увеличеить размер WorkingSet if(CurThread->Priority<0x10)return Status; KeDelayExecutionThread(0,0,MmShortTime); MmAdjustWorkingSetSize((CurProcess->VM.MinimumWorkingSet+0xa)<<12, (CurProcess->VM.MaximumWorkingSet+0xa)<<12,0); return Status; } /*************************************************************************/ //Vad //0 start address //4 end address //8 ??? //c left tree //10 right tree //14 access //18 ....??? // //34 MiCheckVirtualAddress(Addr,Res)// res это PAGE_XXX в ntddk.h????? { if(Addr>MmHighestUserAddress){// system area if(Addr<0xc0000000||Addr>=0xc03fffff){*Res=0x18;return 0;} // no pt if(Addr>=0xc0384000&&(Addr<=MmLastPteForPagedPool)){*Res=0x18;return 0;} *Res=4;return 0; //PAGE_READWRITE } if(Addr&0xfffff000==0x7ffe0000){ *Res=1; //PAGE_NOACCESS return &MmSharedUserDataPte; } Vad=MiLocateAddress(Addr); if(!Vad){*Res=0x18;return 0;} x=Vad->0x14; if(x&0x80000){MiHandleBankedSection(Addr,Vad);*Res=0x18;return 0;} if(x&80000000){ if(!x&0x40000000){*Res=0x18;return 0;} *Res=(x&0x1f000000)>>24; return 0; } if(x&0x100000)*Res=0x100; else *Res=(x&0x1f000000)>>24; if(Vad->0x20<(Addr-Vad->0)>>0xa+Vad->0x1c) return MiGetProtoPteAddressExtended(Vad,Addr); return (Addr-Vad->0)>>0xa+Vad->0x1c; } PVAD MiLocateAddress(Addr); /****************************************************************************/ MiLocateAddressInTree(Addr,VadRoot) { Ptr=VadRoot; Val=*Ptr; i=0; while(1) { if(!Val)return 0; if(i==0x14)MiReorderTree(Val,Ptr); if(*Val<=Addr){ if(*(Val+4)>=Addr)break; Val=*(Val+0x10); i++; continue; } Val=*(Val+0x0c); i++; } return Val; } /****************************************************************************/ MiAccessCheck(AddrPte,Wr,P,Attr) { if(P==1){ // если прерывание было, но страница присутствует и // запрошенный адрес в системной области = access violation HighestPte=MmHighestUserAddress>>0xa+0xc0000000; if(AddrPte>HighestPte)return STATUS_ACCESS_VIOLATION; } PteVal=*AddrPte; if(PteVal&1){// pte реально присутствует if(!Wr||PteVal&0x202)return 0; return STATUS_ACCESS_VIOLATION; } if((((BYTE*)MmReadWrite)[Attr]-Wr)<0xa)return STATUS_ACCESS_VIOLATION; if(Attr&0x10)return 0; if(CurThread->ApcStateIndex==1)return STATUS_ACCESS_VIOLATION; if(PteVal&0x800 && !PteVal&0x400){ OldIrql=KeRaiseIrqlToDpcLevel(); if(*AddrPte&0x800 && !*AddrPte&0x400){ TmpPfn=MmPfnDatabase+0x18*(*AddrPte>>12); TmpPfn->ContFrame=(Attr&0xf)<<5|((TmpPfn->ContFrame)&fffffc1f); } KeLowerIrql(OldIrql); } *AddrPte=((Attr&0xf)<<5)|*AddrPte&0xfffffc1f; return STATUS_GUARD_PAGE_VIOLATION; } /****************************************************************************/ MiDispatchFault(Wr,Addr,AddrPte,Ppte,Process) { if(Ppte){ OldIrql=KeRaiseIrqlToDpcLevel(); if(Ppte<0x80000000||Ppte>=0xa0000000||MmKseg2Frame==0 && !*((Ppte>>0xa)+0xc0000000))// no present { AddrPte=(Ppte>>0xa)+0xc0000000; Ppte=0; Addr=Ppte; KeLowerIrql(OldIrql); } else { // present if((*AddrPte&1)){KeLowerIrql(OldIrql);return 0;} PtePpte=Ppte; Status=MiResolveProtoPteFault(Wr,Addr,AddrPte,Ppte,&PageBlock,Process); goto endi; } } PteVal=*AddrPte; if(PteVal&0x800){ // transition pte Status=MiResolveTransitionFault(Addr,AddrPte,Process,0); } else if(!PteVal&0xfffff000) { Status=MiResolveDemandZeroFault(Addr,AddrPte,Process,0); } else { PtePpte=AddrPte; Status=MiResolvePageFileFault(Addr,AddrPte,&PageBlock,Process); } endi:; if(Status>=0)return Status; if(Status==0xc0033333) // надо прочитать страницы { PtePpteVal=*PtePpte; Misc=PageBlock.pPfn->Misc; if(Process)ExReleaseFastMutex(Process->WorkingSetLock); else {MmSystemLockOwner=0; ExReleaseResourceLite(&MmSystemWsLock); KeLowerIrql(1); } Status=IoPageRead(PageBlock.FileObject, &PageBlock.Mdl, &PageBlock.AddrInPageFile, &PageBlock.IoStatusBlock); if(Status<0) { PageBlock.IoStatusBlock.Status=Status; PageBlock.IoStatusBlock.Information=0; KeSetEvent(&PageBlock,0,0); } Status=MiWaitForInPageComplete(PageBlock.pPfn, PtePpte,Addr,&PtePpteVal,Misc,Process); InBlockAddrPte=PageBlock->AddrPte; if(PageBlock.Mdl.ByteCount>0){ PagesToWrite=(PageBlock.Mdl.ByteCount+0xfff)>>12; Ptr=&PageBlock.MdlFrameBuffer[0]; for(;PagesToWrite;PagesToWrite--,InBlockAddrPte+=4){ Frame=*Ptr; if(PtePpte==InBlockAddrPte){LastFrame=Frame;continue;} TmpPfn=MmPfnDatabase+0x18*Frame; if(TmpPfn->Flags&2){ TmpPfn->Flags&=0xfffffffd; if(!TmpPfn->Flags&0x800)TmpPfn->Misc=0; } MiDecrementReferenceCount(*Ptr); continue; } } if(Status){ MiDecrementReferenceCount(LastFrame); if(Status==0x87303000){KeLowerIrql(1);return 0;} if(PageBlock->Mdl.ByteCount>0){ PagesToWrite=(PageBlock->Mdl.ByteCount+0xfff)>>12; Ptr=&PageBlock->Mdl.MdlFrameBuffer[0]; for(;PagesToWrite;PagesToWrite--,InBlockAddrPte+=4){ Frame=*Ptr; if(!TmpPfn->Flags&0x800)continue; if(TmpPfn->RefCounter)continue; TmpPfn->Flags&=0xfffff7ff; MiUnlinkPageFromList(TmpPfn); MiRestoreTransitionPte(*Ptr); MiInsertPageInList(&MmFreePageListHead,*Ptr); } } KeLowerIrql(1); return Status; } PageBlock.pPfn->ShareCounter++; PageBlock.pPfn->Flags=PageBlock.pPfn->Flags&0xfffffeff|0x600;//active Mask=MiDetermineUserGlobalPteMask(PtePpte); PteVal=Mask|MmProtectToPteMask[*PtePpte>>5]|(*PtePpte&0xfffff000); if(Wr&&PteVal&2)PteVal|=0x40; if(Ppte){ *PtePpte=PteVal; if(!*AddrPte&1)Status=MiCompleteProtoPteFault(Wr,Addr,AddrPte,Ppte); } else { if(PageBlock.pPfn->Misc==0)PageBlock.pPfn->Misc=CurThread; KeLowerIrql(1); MiAddValidPageToWorkingSet(Addr,PtePpte,PageBlock.pPfn,0); } KeRaiseToDpcLevel(); MiFlushInPageSupportBlock(); KeLowerIrql(1); if(Status)Status=STATUS_PAGE_FAULT_PAGING_FILE; } if(Status==0xc7303001||Status==0x87303000)Status=0; return Status; } /*************************************************************************/ MiResolveDemandZeroFault(Addr,AddrPte,Process,bDpcLevel) { if(!bDpcLevel)OldIrql=KeRaiseIrqlLevel(); if(MiEnsureAvailablePageOrWait(Process,Addr)){ if(!bDpcLevel)KeLowerIrql(1); return 0xc7303001;// не получилось }; if(Process&&!bDpcLevel){ if(Process->ForkInProgress&&Process->ForkInProgress==CurThread) { MiWaitForForkToComplete(Process); if(!bDpcLevel)KeLowerIrql(1); return 0xc7303001; } Process->NumberOfPrivatePages++; Seed=(Process->Seed++)&MmSecondaryColorMask; if(MmFreePagesByColor+Seed*8!=-1) Frame=MiRemoveZeroPage(Seed); if(!Frame){Frame=MiRemoveAnyPage(Seed);ZeroFl=1;} // zero or any page, // but set ZeroFl in such case } else { Seed=(MmSystemPageColor++)&MmSecondaryColorMask; if(bDpcLevel)Frame=MiRemoveZeroPage(Seed); else Frame=MiRemoveAnyPage(Seed); } MmInfoCounters.PrivatePages++; // ZeroFaults?? MmInitializePfn(Frame,AddrPte,1); if(!bDpcLevel)KeLowerIrql(1); if(ZeroFl)MiZeroPhysicalPage(Frame,Seed); TmpPfn=Frame*0x18+MmPfnDatabase; Mask=MmProtectToPteMask[((*AddrPte&0x3e0)>>5)*4]; GlobalMask=MiDetermineUserGlobalPteMask(AddrPte); NewPteVal=Mask|GlobalMask|(Frame<<12); if(NewPteVal&2)NewPteVal|=0x40; *AddrPte=NewPteVal; if(!bDpcLevel){ TmpPfn->Misc=CurThread; MiAddValidPageToWorkingSet(Addr,AddrPte,TmpPfn,0); // add to working set } return STATUS_PAGE_FAULT_DEMAND_ZERO; } /*************************************************************************/ typedef struct _PAGE_SUPPORT_BLOCK{ // size: 0x98 DISPATCHER_HEADER DispHeader; //0 FastMutex IO_STATUS_BLOCK IoStatusBlock; //0x10 LARGE_INTEGER AddrInPageFile;// 0x18 (file offset) DWORD RefCounter; //0x20 (0|1) ??? KTHREAD Thread; //0x24 PFILE_OBJECT FileObject; // 0x28 DWORD AddrPte; //0x2c PPFN pPfn; //0x30 MDL Mdl; //0x34 DWORD MdlFrameBuffer[0x10]; //0x50 LIST_ENTRY PageSupportList; //0x90 список связан с MmInPageSupportList }PAGE_SUPPORT_BLOCK *PAGE_SUPPORT_BLOCK; struct _MmInPageSupportList{ LIST_ENTRY PageSupportList; DWORD Count; }MmInPageSupportList; /****************************************************************************/ /*Create or take from list page support block */ /****************************************************************************/ PPAGE_SUPPORT_BLOCK MiGetInPageSupportBlock(bInsert){ if(!MmInPageSupportList.Count){ KeLowerIrql(1); Block=ExAllocatePoolWithTag(2,0x98,(DWORD)'nImM'); KeInitializeEvent(Block,0,0); KeRaiseIrqlToDpcLevel(); if(!bInsert) { MmInPageSupportList.Count++; Block->Thread=0; Block->PageSupportList.Flink=&MmInPageSupportList.PageSupportList.Flink; Block->PageSupportList.Blink=MmInPageSupportList.PageSupportList.Blink; MmInPageSupportList.PageSupportList.Blink->Flink=&Block->PageSupportList.Flink; MmInPageSupportList.PageSupportList.Blink=&Block->PageSupportList.Flink; return 0; } } else { MmInPageSupportList.Count--; Cur=MmInPageSupportList.PageSupportList.Flink; Next=Cur->Flink; Prev=Cur->Blink; Prev->Flink=Next; Next->Blink=Prev; Block=Cur-0x90; } Block->RefCounter=1; Block->Thread=CurThread; Block->PageSupportList.Flink=0; return Block; } /****************************************************************************/ /*Make Pfn read in progress */ /****************************************************************************/ MiInitializeReadInProgressPfn(pMdl,AddrPte,Block,fl) // fl is 1 when it is a REAL pte (in page table) // else fl==-1, so, ir is shared frame { Cnt=pMdl->ByteCount; if(Cnt<=0)return; Cnt=(Cnt+0xfff)>>12; // in pages FramePtr=pMdl+sizeof(MDL); while(Cnt--)// для всех фрэймов { TmpPfn=*FramePtr*0x18+MmPfnDatabase; TmpPfn->Misc=Block; TmpPfn->Pte=AddrPte; TmpPfn->Trans=*AddrPte; TmpPfn->RefCounter++; TmpPfn->ShareCounter=0; if(fl==-1)TmpPfn->Flags|=8; //shared else TmpPfn->Flags|2; // read in progress ContFrame=TmpPfn->ContFrame=*(AddrPte>>10+0xc0000000)>>12; NewPteVal=(*FramePtr<<12)|0x800; NewPteVal=(*AddrPte&0x3e0)|NewPteVal; HighestPte=(MmHighestUserAddrsss>>0xa)+0xc0000000; if(HighestPte>=AddrPte)NewPteVal|=4; // u/s bit else if(AddrPte<0xc0300000)NewPteVal&=0xfffffffb; // no access from ring 3 else if((MmHighestUserAddress>>0x14+0xc0300000)>=AddrPte)NewPteValue|=4; else NewPteVal&=0xfffffffb; *AddrPte=NewPteValue; FrameBuff+=4; AddrPte+=4; (MmPfnDatabase+0x18*ContFrame)->ShareCounter++; } return; } /****************************************************************************/ MiResolvePageFileFault(Addr,AddrPte,PPAGE_SUPPORT_BLOCK PageSupportBlock,Process) { PteVal=*AddrPte; NumOfPageFile=(PteVal&0x1e)>>1; //00011110>>1 - number of page file (uint64)PageAddr=(uint64)(PteVal>>12)<<12; // addr in page file if(MiEnsureAvailablePageOrWait(Process,Addr)) { KeLowerIrql(1); return 0xc7303001; } Ptr=MiGetInPageSupportBlock(0); if(!Ptr) { KeLowerIrql(1); return 0xc7303001; } *PageSupportBlock=Ptr; MmInfoCounters->0x14++; MmInfoCounters->0x18++; PageFile=MmPagingFile[NumOfPageFile]; pFileObject=PageFile->FileObject; Ptr->FileObject=pFileObject; (uint64)Ptr->AddrInPageFile=(uint64)PageAddr; if(Process){ Seed=(Process->Seed++)&MmSecondaryColorMask; } else { Seed=MmSystemPageColor&MmSecondaryColorMask; MmSystemPageColor++; } Ptr->4=0; Ptr->AddrPte=AddrPte; Ptr->Mdl.Next=0; (word)Ptr->Mdl.Size=0x20; Ptr->Mdl.StartVa=Addr&0xfffff000; (word)Ptr->Mdl.Flags=0|0x42; Ptr->Mdl.ByteCount=0x1000; if(AddrPte<0xc0000000||AddrPte>0xc03fffff)fl=-1; else fl=1; // if AddrPte is not in page table... Frame=MiRemoveAnyPage(Seed); TmpPfn=Frame*0x18+MmPfnDatabase; Ptr->pPfn=TmpPfn; Ptr->MdlFrameBuffer[0]=Frame; MiInitializeReadInProgressPfn(&Ptr->Mdl,AddrPte,Ptr,fl); KeLowerIrql(1); return 0xc0033333; // эта красивое значение означает, что // необходимо последующее чтение страницы IoPageRead } /**************************************************************************/ MiResolveTransitionFault(Addr,AddrPte,Process,fl) { if(!fl)KeRaiseIrqlToDpcLevel(); PteVal=*AddrPte; if(PteVal&0x401||!PteVal&0x800){ if(!fl)KeLowerIrql(1); return 0xc7303001; } MmInfoCounters->TransitionFaults++; //8 Frame=PteVal>>12; TmpPfn=MmPfnDatabase+Frame*0x18; flags=TmpPfn->Flags; if(flags&0x800) // in page error { if(!fl)KeLowerIrql(1); return TmpPfn->Misc; } if(flags&0x2) // read in progress { TmpPfn->RefCounter++; PageSupportBlock=TmpPfn->Misc; PageSupportBlock->RefCounter++; KeLowerIrql(1); if(Process) ExReleaseFastMutex(Process->WorkingSetLock); else { MmSystemLockOwner=0; ExReleaseResourceLite(MmSystemWsLock); KeLowerIrql(1); } // read in progress, wait for end of transition Res=MiWaitForInPageComplete(TmpPfn,AddrPte,Addr,&PteVal,PageSupportBlock,Process); if(Res){ MiDecrementReferenceCount(Frame); if(flags&0x800){// in page error Res=TmpPfn->Misc; if(!TmpPfn->RefCounter){ TmpPfn->Flags=flags&0xf7ff; MiUnlinkPageFromList(TmpPfn); MiRestoreTransitionPte(Frame); MiInsertPageInList(&MmFreePageListHead,Frame); } } if(!fl)KeLowerIrql(1); return Res; } } else { // no read in progress if(flags&0x700!=0x600){// если фрэйм находится в каком либо списке //!Active MiUnlinkPageFromList(TmpPfn); TmpPfn->RefCounter++; } } TmpPfn->ShareCounter++; TmpPfn->Flags=flags&0xfeff|0x600; // make Pfn active mask=MiDetermineUserGlobalPteMask(AddrPte); PteVal=mask|MmProtectToPteMask[((*AddrPte&0x3e0)>>5)*4]|(*AddrPte&0xfffff000); if(TmpPfn->Flags&1 && PteVal&2 && !PteVal&0x200)PteVal|=0x40; else PteVal&=0xffffffbf; *AddrPte=PteVal; if(!fl){ if(!TmpPfn->Misc)TmpPfn->Misc=CurThread; KeLowerIrql(1); MiAddValidPageToWorkingSet(Addr,AddrPte,TmpPfn,0); } return STATUS_PAGE_FAULT_TRANSITION; } /*************************************************************************/ MiResolveProtoPteFault(Wr,Addr,AddrPte,Ppte,pPageBlock,Process) { PpteVal=*Ppte; if(PpteVal&1){ // present??? - (proto pte TmpPfn=MmPfnDatabase+(PpteVal>>12)*0x18; TmpPfn->ShareCounter++; lo_fl=1; Status=0; MmInfoCounters.8++;//transfaults?? } else { if(!PpteVal){KeLowerIrql(1);return STATUS_ACCESS_VIOLATION;} if(*AddrPte&0xfffff000!=0x0xfffff000) { if(!*AddrPte&0x100){ res=MiAccessCheck(Ppte,Wr,0,(*Ppte&0x3e0)>>5); if(res){KeLowerIrql(1);return res;} Val=*Ppte; } else goto jmp0; } if(Val&0xa0==0xa0)Status=1; jmp0:; if(!PpteVal&0xfffffc01&&Status){ KeLowerIrql(1); *AddrPte=0x80; return MiResolveDemandZeroFault(Addr,AddrPte,Process,0); } if(PpteVal&0x400)// MappedFile { Status=MiResolveMappedFileFault(Addr,AddrPte,pPageBlock,Process); lo_fl=1; goto endi; } if(PpteVal&0x800){//TransitionFault Status=MiResolveTransitionFault(Addr,AddrPte,Process,1); lo_fl=1; goto endi; } if(!PpteVal&0xfffff000){ Status=MiResolveDemandZeroFault(Addr,AddrPte,Process,1); lo_fl=1; goto endi; } Status=MiResolvePageFileFault(Addr,AddrPte,pPageBlock,Process); } endi:; if(Status<0){ if(lo_fl)KeLowerIrql(1); return Status; } TmpPfn=(*AddrPte>>12)*0x18+MmPfnDatabase; TmpPfn->Flags|=8;// shared TmpPte=(AddrPte>>10)+0xc0000000; TmpPfn2=(*TmpPte>>12)*0x18+MmPfnDatabase; TmpPfn2->ShareCounter++; if(*AddrPte&0xfffff000==0xfffff000)Attr=*AddrPte&0x3e0; else Attr=TmpPfn->Trans&0x3e0|0x400; Attr>>=1; Mask=MiDetermineUserGlobalPteMask(AddrPte); PpteVal=Mask|MmProtectToPteMask[Attr&0x1f0>>4]|(*AddrPte&0xfffff000); if(Wr&&!PpteVal&0x200) { TmpPfn->Flags|=1; // modif PpteVal|=0x40; if(!TmpPfn->Trans&0x400&&!TmpPfn->Flags&4) { MiReleasePageFileSpace(TmpPfn->Trans); TmpPfn->Trans&=0xfff; } } AddrPte=PpteVal; if(!TmpPfn->Misc)TmpPfn->Misc=CurThread; KeLowerIrql(1); MiAddValidPageToWorkingSet(Addr,AddrPte, TmpPfn, Attr); return Status; } /*****************************************************************************/ MiCompleteProtoPteFault(Wr,Addr,AddrPte,Ppte) { PpteVal=*Ppte; TmpPfn=MmPfnDatabase+(PpteVal>>12)*0x18; TmpPfn->Flags|=0x8; TmpPte=AddrPte>>0xa+0xc0000000; TmpPfn2=(*TmpPte>>12)*0x18+MmPfnDatabase; TmpPfn2->ShareCounter++; if(*AddrPte&0xfffff000!=0xfffff000) Attr=TmpPfn->Trans&0x3e0|0x400; else Attr=*AddrPte&0x3e0; Attr>>=1; Mask=MiDetermineUserGlobalMask(AddrPte); NewVal=Mask|MmProtectToPteMask[Attr&0x1f0>>4]|(*Ppte&0xfffff000); if(Wr&&!PpteVal&0x200) { TmpPfn->Flags|=1; // modif PpteVal|=0x40; if(!TmpPfn->Trans&0x400&&!TmpPfn->Flags&4) { MiReleasePageFileSpace(TmpPfn->Trans); TmpPfn->Trans&=0xfff; } } *AddrPte=PpteVal; if(!TmpPfn->Misc)TmpPfn->Misc=CurThread; KeLowerIrql(1); MiAddValidPageToWorkingSet(Addr,AddrPte, TmpPfn, Attr); return 0; } /*************************************************************************/ 04.Вытеснение страниц в файлы откачки. Псевдокод. (NT4.0) ========================================================= ================================== typedef struct _MAPPING_FILE_HEADER{ LIST_ENTRY MdlQueryList; KEVENT MappedFileEvent; //MiMappedFileEvent }PAGING_FILE_HEADER *PPAGING_FILE_HEADER; typedef struct _PAGING_FILE_HEADER{ LIST_ENTRY MdlQueryList; KEVENT PageFileEvent; }PAGING_FILE_HEADER *PPAGING_FILE_HEADER; typedef struct _PAGEFILE_MDL{ // играет роль ApcContext пр вызове MiWriteComplete LIST_ENTRY MdlQuery; //0 очередь DWORD Unknown3; //8 DWORD Unknown4; //c IO_STATUS_BLOCK IoStatus; //10 (IoAsynchronousPageWrite) PIRP AssociatedIrp; // 18 (IoAsynchronousPageWrite) DWORD StartPageForFlushing;//1c ==BitRangeStart-1 PPAGING_FILE_HEADER MmPagingFileHeader; //20 PLIST_ENTRY MdlQueryHead; // 24 offset MmPagingFileHeader / MmFreePagingSpaceLow PPAGING_FILE PagingFileAssociated; //28 DWORD Unused0; // 2c DWORD Unknown1; // 30 поля как то связано с сетью??? DWORD Unknown2; // 34 всегда 0 для stand-alone машины MDL Mdl; //38 // MDL Next 0 38h dd ? (0) (MiGatherPagefilePages) // Size 4 3ch dw ? (20h) then ClasterSize*4+1ch (1c-header size) // Flags 6 3eh dw ? (0)|2 MDL_PAGES_LOCKED // Process 8 40h dd // MappedVa c 44h dd // StartVa 10 48h dd (flags&0x70<<8) 111000000000000 // ByteCount 14 4ch dd 1000h bytes to write (num of pages<<12) /---ByteOffset18 50h dd 0 // 54h dd FrameNum for PageFile //------------------------------------------------------------------ // 58h ... Frames * MmModifiedWriteClasterSize times }PAGEFILE_MDL *PPAGEFILE_MDL; typedef struct _PAGING_FILE{ DWORD MinPagesNumber; //0 DWORD MaxPagesNumber; //4 DWORD MaxPagesForFlushing; //8 (максимум страниц на вытеснение) DWORD FreePages; //c(Free pages in PageFile) DWORD UsedPages; //10 занятых страниц DWORD MaxUsedPages; //14 DWORD CurFlushingPosition; //18 -??? DWORD Reserved1; //1c PPAGEFILE_MDL Mdl1; // 20 0x61 - empty ??? PPAGEFILE_MDL Mdl2; // 24 0x61 - empty ??? PRTL_BITMAP PagefileMap; // 28 0 - свободно, 1 - содержит вытесненную стр. PFILE_OBJECT FileObject; //2c DWORD NumberOfPageFile; //30 UNICODE_STRING FileName; //34 DWORD Lock; //3d }PAGING_FILE *PPAGING_FILE; DWORD MmNumberOfActiveMdlEntries; DWORD MmNumberOfPagingFiles; #define MAX_NUM_OF_PAGE_FILES 16 PPAGING_FILE MmPagingFile[MAX_NUM_OF_PAGE_FILES]; PAGING_FILE_HEADER MmPagingFileHeader; LIST_ENTRY MmFreePagingSpaceLow; MAPPED_FILE_HEADER MmMappedFileHeader; DWORD MmModifiedWriteClasterSize=0x10; PMAPPEDFILE_MDL MmMappedFileMdl[4]; /*****************************************************/ MiModifiedPageWriterWorker() { // вытеснение "грязных" страниц в pagefile while(1) { // ждем у события KeWaitForSingleObject(MmModifiedPageWriterEvent,8,0,0,0); for(i=0;iLocks=0; OldIrql=KeRaiseirqlToDpcLevel(); while(1) { //while1 if(MmAvailablePages=0x20)break; PfnOfModifPage=MmModifiedNoWritePageListHead.FirstFn; TmpPfn=(MmPfnDatabase+0x18*PfnOfModifPage); if(TmpPfn->Trans&0x80000000) { Trans=TmpPfn->Trans; x=Trans&0x1e<<2|Trans&0x7ffff800>>4+MmSubsectionBase; } else { Trans=TmpPfn->Trans; x=MmSubsectionPoolEnd-Trans&0x1e<<2|Trans&0xfffff800>>4; } if(!*(*x+0x20)&0x8){ MiUnlinkPageFromList(TmpPfn); MiInsertPageInList(&MmModifiedPageListHead,PfnOfModifPage); } else { MmModNoWriteInser=0; break; } Counter++; if(!MmModifiedNoWritePageListHead.Counter)break; } //while }//if // if no modif. pages if(MmModifiedPageListHead.Counter==0){KeLowerIrql(OldIrql); MmModifiedPageWriterEvent.Header.SignalState=0; break;} // got first frame if((MmModifiedPageListHead.Counter-MmTotalPagesForPagingFile)<=MmTotalPagingFile) { if(MmTotalPagesForPagingFile==0){ fn=-1; } else fn=MmModifiedPageListByColor.FirstFn; } else { fn=MmModifiedPageListHead.FirtFn; } TmpPfn=MmPfnDatabase+0x18*fn; trans=TmpPfn->Trans; if(!(trans&0x400)){ // page file if(MmMappedFileHeader.Flink==&MmMappedFileHeader.Flink) {// empty MappedFile mdl query if(MmTotalPagesForPagingFile==0)fn=-1; else fn=MmModifiedPageListByColor.FirstFn; if(fn==-1)fn=MmModifiedPageListHead.FirstFn; TmpPfn=fn*0x18+MmPfnDatabase; } } else { // mapping file if(MmPagingFileHeader.Flink==&MmPagingFileHeader.Flink&&!trans) { // empty PagingFile mdl query and null trans while(1) { fn=TmpPfn->NextRef; if(fn!=-1) { TmpPfn=MmPfnDatabase+0x18*fn; if(TmpPfn->Trans&0x400)break; } else { fn=-1; if(MmTotalPagesForPagingFile==0)break; fn=MmModifyedPageListByColor.FirstFn; break; } } TmpPfn=fn*0x18+MmPfnDatabase; } // looking for first mapped pte }//else if(!TmpPfn->Trans&0x400){// paging MiGatherPagefilePages(TmpPfn,fn); // real flush } else if(MmMappedFileHeader.Flink!=&MmMappedFileHeader.Flink) { MiGatherMappedPages(TmpPfn,pfn); // real flush } else { MiMappedFileEvent.Header.SignalState=0; KeLowerIrql(OldIrql); KeWaitForSingleObject( &MiMappedFileEvent,0x13,0,0,&Mm30Milliseconds); OldIrql=KeRaiseIrqlToDpcLevel(); continue; } if(MmSystemShutdown){KeLowerIrql(OldIrql);return;} if(MmWriteAllModifiedPages)continue; if(MmAvailablePages<=MmFreeGoal||MmModifiedPageListHead.Counter>=MmFreeGoal) { if(MmMoreThanEnoughFreePages>=MmAvailablePages)continue; } KeLowerIrql(OldIrql); MmModifiedPageWriterEvent.Header.SignalState=0; break; }//while1 } } /***==========================*********************/ MiGatherPagefilePages(Farme,FrameNum) {// реальное вытеснение фрэймов в файл Color=(Frame->Flags&0x70)>>4; if(MmPagingFileHeader.Flink==&MmPagingFileHeader){ MmPagingFileEvent.Header.SignalState=0; KeLowerIrql(0); KeWaitForSingleObject(&MmPagingFileEvent,0x13,0,0,&Mm30Milliseconds); KeRaiseIrqlToDpcLevel(); return; } // request // delete it pPagingFileMdl=MmPagingFileHeader.Flink; pAfterRequest=pPagingFileMdl->MdlQuery.Flink; pBeforeRequest=pPagingFileMdl->MdlQuery.Blink; pBeforeRequest->MdlQuery.Blink=pPagingFileMdl->MdlQuery.Flink; pPagingFileMdl->MdlQuery.Flink->MdlQuery.Blink=pPagingFileMdl->MdlQuery.Blink; // ClasterSize=MmModifiedWriteClasterSize; // pPagingFile=pPagingFileMdl->PagingFileAssociated; pIoFileObject=pPagingFile->FileObject; while(1){ // search loop if(MmModifiedWriteClusterSize+pPagingFile->CurFlushingPosition> pPagingFile->MaxPagesForFlushing&&pPagingFile->Lock==0) { pPagingFile->Lock=1; pPagingFile->CurFlushingPosition=0; } BitRangeStart=RtlFindClearBitsAndSet(pPagingFile->PagefileMap, ClasterSize,pPagingFile->CurFlushingPosition); if(BitRangeStart!=-1)break; if(pPagingFile->CurFlushingPosition!=0)pPagingFile->CurFlushingPosition=0; else { ClasterSize>>=1; fragment_fl=1; } if(!ClasterSize)break; } // search loop if(BitRangeStart==-1){ pPagingFileMdl->MdlQuery.Flink=&MmFreePagingSpaceLow; pPagingFileMdl->MdlQuery.Blink=MmFreePagingSpaceLow.Blink; MmFreePagingSpaceLow.Blink->MdlQuery.Flink=pPagingFileMdl; pPagingFileMdl->MdlQueryHead=MmFreePagingSpaceLow; MmNumberOfActiveMdlEntries--; return MiPageFileFull(); } pPagingFile->FreePages-=ClasterSize; pPagingFile->UsedPages+=ClasterSize; if(pPagingFile->FreePages<32)fragment_fl=1; UINT64 Lseek=(UINT64)BitRangeStart<<12; // .. дальше идет инициализация pPagingFileMdl->Mdl // не интересно - см. базу. if(ClasterSize){// if PfnCount=0; CurFrame=FrameNum; RtlRangeMul2048=BitRangeStart<<11; while(1){ //while pTrans=&Frame->Trans; if(!*pTrans&0x400){ PfnCount++; MiUnlinkPageFrameFromList(Frame); // добавить CurFrame в MDL // .... // CurFrame=MmModifiedPageListByColor.FirstFn; Frame->RefCounter++; Frame->Flags=Frame->Flags&0xfe|4; *pTrans=*Trans&0x3e0| (pPagingFIle->NumberOfPageFile| BitRangeStartMul2048)<<1; BitRangeStartmul2048+=0x800; // inc 1 } else { CurFrame=MmModifiedPageListByColor.(FirstFn+Color<<4); } if(CurFrame==-1)break; Frame=CurFrame*0x18+MmPfnDatabase; if(ClasterSize==PfnCount)break; }//while if(ClasterSize){ //if RtlClearBits(pPagingFile->PagefileMap,BitRangeStart,ClasterSize-PfnCount); pPagingFile->FreePages+=ClasterSize-PfnCount; pPagingFile->UsedPages-=ClasterSize-PfnCount; if(PfnCount){ //if if(PagingFileMdl->PagingFileHeader==PagingFileMdl->PagingFileHeader->MdlQueryList.Next) { //if KeSetEvent(PagingFileMdl->PagingFileHeader- >PageFileEvent,0,0); } //if pHeader=PagingFileMdl->PagingFileHeader; pPrev=pHeader->MdlQueryList.Blink; PagingFileMdl->MdlQuery.Flink=pHeader; PagingFileMdl->MdlQuery.Blink=pPrev; pPrev->MdlQuery.Flink=PagingFileMdl; pHeader->MdlQueryMdl.Blink=PagingFileMdl; return; } //if }//if } //if if(pPagingFile->MaxUsedPagesUsedPages)pPagingFile->MaxUsedPages=pPagingFile- >UsedPages; pPagingFileMdl->Mdl.ByteCount=PfnCount<<12; pPagingFileMdl->StartPageForFlushing=BitRangeStart-1; TotalFlushingToPageFile++; TotalByesFlushWrittenToPagesFile+=PfnCount; KeLowerIrql(0); res=IoAsynchronousPageWrite( pIoFileObject, &pPagingFileMdl->Mdl, &Lseek,MiWriteComplete, pPagingFileMdl, &pPagingFileMdl->IoStatus, &pPagingFileMdl->AssociatedIrp); &pPagingFileMdl->IoStatus.Status=res; &pPagingFileMdl->IoStatus.Information=0; OldIrql=KeRaiseIrql(1); MiWriteComplete(pPagingFileMdl,&pPagingFileMdl->IoStatus,0); KeLowerIrql(OldIrql); KeRaiseIrqlToDpcLevel(); if(frarment_fl)MiPageFileFull(); } 05.Создание процесса. Псевдокод. (NT4.0) ======================================== /*****************************************************************/ /* -- Here it is, just wrapper -- */ NtCreateProcess( OUT Handle, IN ACCESS_MASK Access, IN POBJECT_ATTRIBUTES ObjectAttrib, IN HANDLE Parent, IN BOOLEAN InheritHandles, IN HANDLE SectionHandle, IN HANDLE DebugPort, IN HANDLE ExceptionPort ) { if(Parent) { ret=PspCreateProcess(Handle, Access, ObjectAttrib, Parent, InheritHandles, SectionHandle, DebugPort, ExceptionPort); } else ret=STATUS_INVALID_PARAMETER; return ret; } /*************Internal, not exported function ********************/ PspCreateProcess( OUT PHANDLE Handle, IN ACCESS_MASK Access, IN POBJECT_ATTRIBUTES ObjectAttrib, IN HANDLE Parent, IN BOOLEAN InheritHandles, IN HANDLE SectionHandle, IN HANDLE DebugPort, IN HANDLE ExceptionPort ) { PrevMode=ExGetPreviousMode(); if(Parent) { //Get pointer to father's body ObReferenceObjectByHandle(Parent,0x80,PsProcessType,PrevMode,&pFather,0); AffinityMask=pFather->Affinity; // on witch processors will be executed Prior=8; } else { pFather=0; AffinityMask=KeActiveProcessors; Prior=8; } if(SectionHandle) { //Get pointer to image section's body ObReferenceObjectByHandle(SectionHandle,0x8,MmSectionObjectType,PrevMode,&pSection,0); } else { pSection=0; } if(DebugPort) { // Get pointer to debug port ObReferenceObjectByHandle(DebugPort,0,LpcObjectType,PrevMode,&pDebugPort); } else { pDebugPort=0; } if(ExceptPort) { // Get pointer to except port ObReferenceObjectByHandle(ExceptPort,0,LpcObjectType,PrevMode,&pExceptPort); } else { pExceptPort=0; } // size of process body - 504 bytes // creating process object... (type object PsProcessType) ObCreateObject(PrevMode,PsProcessType,ObjectAttrib,PrevMode,0,504,&pProcess); // clear body memset(pProcess,0,504); pProcess->CreateProcessReported=0; pProcess->DebugPort=pDebugPort; pProcess->ExceptPort=pExceptPort; // Inherit Quota Block, if pFather==NULL, PspDefaultQuotaBlock PspInheritQuota(pProcess,pFather); if(pFather){ pProcess->DefaultHardErrorMode=pFather->DefaultHardErrorMode; pProcess->InheritedFromUniqueProcessId=pFather->UniqueProcessId; } else { pProcess->InheritedFromUniqueProcessId=0; pProcess->DefaultHardErrorMode=1; } pProcess->StatusExit=STATUS_PENDING; //0x103 pProcess->LockCount=1; pProcess->LockOwner=0; // init kevent LockEvent skipped... PspInitializeProcessSecurity(pFather,pProcess); // struct PROCESS_ADDRESS_SPACE_RESULT{ // dword Dt; // dict. table phys. addr. // dword HypSpace; // hyp space page phys. addr. // dword WorkingSet; // working set page phys. addr. // }CASResult; MmCreateProcessAddressSpace(PsMinimumWorkingSet,pProcess,&CASResult); pProcess->MinimumWorkingSet=MinWorkingSet; pProcess->MaximumWorkingSet=MaximumWorkingSet; KeInitializeProcess(pProcess,Prior,AffinityMask,&CASResult,pProcess->DefaultHardErrorProcessing&0x4); pProcess->ForegroundQuantum=PspForegroundQuantum; if(pFather) // if there is father and inherithandle, so, inherit handle db { pFather2=0; if(bInheritHandle)pFather2=pFather; ObInitProcess(pFather2,pProcess); // see info about ObjectManager } if(pSection) { MmInitializeProcessAddressSpace(pProcess,0,pSection); ObDereferenceObject(pSection); res=ObInitProcess2(pProcess); //work with unknown byte +0x22 in process if(res>=0)PspMapSystemDll(pProcess,0); Flag=1; //Created addr space } else { // if there is futher, but no section, so, do operation like fork() if(pFatherProcess){ if(PsInitialSystemProcess==pFather){ MmRes=MmInitializeProcessAddressSpace(pProcess,0,0); } else { pProcess->SectionBaseAddress=pFather->SectionBaseAddress; MmRes=MmInitializeProcessAddressSpace(pProcess,pFather,0); Flag=1; //created addr space } } } ObInsertObject(pProcess,0,Access,0,0,&ProcHandle); ExAcquireFastMutex(PspActiveProcessMutex); // insert process object in list of active processes pProcess->ActiveProcessLinks.Flink=&PsActiveProcessHead; pProcess->ActiveProcessLinks.Blink=PsActiveProcessHead.Blink; *PsActiveProcessHead.Blink=&pProcess->ActiveProcessLinks; ExReleaseFastMutex(PspActiveProcessMutex); KeInitializeMutant(pProcess->ProcessMutant,0); if(pFather&&Flag) {// if created addr space CreatePebPar2=0; if(pSection)// if created from section { pProcess->pPeb=MmCreatePeb(pProcess,&CreatePebPar2); if(pFather->pPeb&&pFather->pPeb->SystemReserved) { ZwWriteVirtualMemory(ProcHan, &pProcess->pPeb->SystemReserved, &pFather->pPeb->SystemReserved, 4, 0); } } else { // if created from father ZwWriteVirtualMemory(ProcHan,pProcess->pPeb,CreatePebPar2,8,0); } if(SectionHandle){ ZwDuplicateObject(-1,SectionHandle,ProcHan,&res,0,0,2); } else { ZwDuplicateObject(FatherProcess,pFather->SectionHandle,ProcHan,&res,0,0); } pProcess->SectionHandle=res; } // finally, security operations if(pFather&&PspInitialSystemProcessHandle!=Father) { ObGetObjectSecurity(pProcess,&SecurityDescriptor,&MemoryAllocated); pToken=PsReferencePrimaryToken(pProcess); AccessRes=SeAccessCheck(SecurityDescriptor,&SecurityContext, 0,0x2000000, 0,0,&PsProcessToken->GenericMapping, PrevMode,pProcess->GrantedAccess, &AccessStatus); ObDereferenceObject(pToken); ObReleaseObjectSecuryty(SecurityDescriptor,MemoryAllocated); if(!AccessRes)pProcess->GrantedAccess=0; pProcess->GrantedAccess|=0x6fb; } else{ pProcess->GrantedAccess=0x1f0fff; } if(SeDetailedAuditing)SeAuditProcessCreation(pProcess,pFather); KeQuerySystemTime(&pProcess->CreateTime); *Handle=ProcHan; return res; } // //**************************************************************************/ KeInitializeProcess(pProcess,BasePriority,AffinityMask,pResult,ErrorMode) { // working with dispatcher heder skipped // ....... // pProcess->BasePriority=BasePriority; pProcess->AffinityMask=AffinityMask; pProcess->ErrorMode=ErrorMode; pProcess->PageDirectoryBase=pResult->0; pProcess->PageHyperspaceBase=pResult->4; pProcess->StackCount=0x7fff; pProcess->ForegroundQuantum;=6; pProcess->State=Ready;//0; pProcess->IopmOffset=0x20ad; // IOMAP BASE!!! // You can patch kernel here and // got i/o port control ;) pProcess->TimerStamp=KeTickCount; } /**************************************************************************/ MmCreateProcessAddressSpace(MinWorkingSet,pProcess,Result) { MiChargeCommitment(3,0); Rnd=RtlRandom(MmProcessColorSeed); pProcess->Seed=(WORD)Rnd; KeInitializeSpinLock(pProcess->CreateAddressSpaceLock); CurSeed=(CurProcess->Seed)&MmSecondaryColorMask; CurProcess->Seed++; ExAcqurieFastMutex(pProcess->WorkingSetLock); OldIrql=KeRaiseIrqlToDpcLevel(); MmProcessCommit+=3;// eat 3 pages, see later MmResidentAvailablePages-=MinWorkingSet; MiEnsureAvailablePageOrWait(CurProcess,0); if(*(MmFreePagesByColor+CurSeed*8)!=-1){ Frame=MiRemoveZeroPage(CurSeed); } else Frame=0; if(!Frame) { Frame=MiRemoveAnyPage(CurSeed); KeLowerIrql(OldIrql); MiZeroPhysicalPage(Frame,CurSeed); // in fact CurSeed not used, ;) LastIrql=KeRaiseIrqlToDpcLevel(); } PhysAddr=Frame<<0xc; *Res=PhysAddr; MiEnsureAvailablePageOrWait(CurProcess,0); CurSeed=(CurProcess->Seed)&MmSecondaryColorMask; CurProcess->Seed++; if(*(MmFreePagesByColor+CurSeed*8)!=-1){ Frame2=MiRemoveZeroPage(CurSeed); } else Frame2=0; if(!Frame2) { Frame2=MiRemoveAnyPage(CurSeed); KeLowerIrql(OldIrql); MiZeroPhysicalPage(Frame2,CurSeed); // CurSeed not used LastIrql=KeRaiseIrqlToDpcLevel(); } PhysAddr2=Frame2<<0xc; *(Res+4)=PhysAddr2; MiEnsureAvailablePageOrWait(CurProcess,0); CurSeed=CurProcess->Seed&MmSecondaryColorMask; CurProcess->Seed++; if(*(MmFreePagesByColor+CurSeed*8)!=-1){ Frame3=MiRemoveZeroPage(CurSeed); } else Frame3=0; if(!Frame3) { Frame3=MiRemoveAnyPage(CurSeed); KeLowerIrql(OldIrql); MiZeroPhysicalPage(Frame3,CurSeed); // CurSeed not used LastIrql=KeRaiseIrqlToDpcLevel(); } KeLowerIrql(OldIrql); pProcess->WorkingSetPage=Frame3; // WorkingSetPage (MmPfnDatabase+0x18*Frame)->Pte=0xc0300000; ValidPde_U=ValidPdePde&0xeff^Frame2; // HyperSpace /**************IMPORTANT!!!!!!!!!!!!!!************************/ /* ВАЖНО! Тут происходит инициализация PD */ /*************************************************************/ Va=MiMapPageInHyperSpace(Frame,&LastIrql); // no we got Va of our new Page Directory // Fill some fields *(Va+0xc04)=ValidPde_U; // HyperSpace ValidPde_U=ValidPde_U&0xfff^PhysAddr; // DT *(Va+0xc00)=ValidPde_U; // self-pde // copy from current process, kernel address mapping memcpy( (MmVirtualBias+0x80000000)>>0x14+Va, // it's like that we found, // what MmVirtualBias is it ;) (MmVirtualBias+0x80000000)>>0x14+0xc0300000, 0x80 // 32 pdes -> 4Mb*32=128Mb ); memcpy( // copy pdes, corresponding to NonPagedArea MmNonPagedSystemStart>>0x14+Va, MmNonPagedSystemStart>>0x14+0xc0300000, (0xc0300ffc-MmNonPagedSystemStart>>0x14+0xc0300000)&0xfffffffc+4); memcpy(Va+0xc0c, // cache, forgot about it now, it's another story ;) 0xc0300c0c, (MmSystemCacheEnd>>0x14)-0xc0c+4 ); KeLowerIrql(LastIrql); ExReleaseFastMutex(pProcess->WorkingSetLock); return 1; } /************************************************************************/ int MmInitializeProcessAddressSpace(pProcess,ParentProcess,pSection) { KeAttachProcess(pProcess); // useful, but undocumented function // ... initialize AddressCreationLock; and WorkingSetLock // pProcess->VM.WorkingSetList=MmWorkingSetList; KeQuerySystemTime(&pProcess->VM.InitializeAddrSpaceTime); OldIrql=KeRaiseIrqlToDpcLevel(); MiInitializePfn(*(0xc0300c00)>>12,0xc0300c00,1); MiInitializePfn(*(0xc0300c04)>>12,0xc0300c04,1); *(MmWorkingSetList>>10+0xc0000000)=0x80; WorkingSetPage=pProcess->WorkingSetPage; MiInitializePfn(pProcess->WorkingSetPage,MmWorkingSetList>>10+0xc0000000,1); KeLowerIrql(OldIrql); MiInitializeWorkingSetList(pProcess); Mask=MiDetermineUserGlobalPteMask((MmWorkingSetList>>10+0xc0000000)); WorkingSetPagePte=Mask|WorkingSetPage<<0xc|2|0x40; if(MmVirtualBias&&ParentProcess==0) { if(pSection) { if(ExVerifySuite(1)==0||BYTE((pSection->0x14)-0x1c)&0x20) { // вставить VAD описывающий MmHighestUserAddress-0x80000000 // .... MiInsertVad(... // .... } } // вставить VAD описывающий 0x7ffe0000-0x7ffe0fff // .... MiInsertVad(... // .... } if(pSection) { // пока нет информации о структуре Section. // работа с ее полями } //.... //... if(byte [eax+0x20]&0x20){ err=MmMapViewOfSection(pSection,ebx,&var_14,0,0,&var_20,&var_18,1,0,4); } KeDetachProcess(); return err; } else { if(ParentProcess){ memcpy(pProcess->ImageFileName,ParentProcess->ImageFileName, strlen(ParentProcess->ImageFileName)+1); MiCloneProcessAddressSpace(Par2,pProcess,PdFrame,WorkingSetPage); } else { KeDetachProcess(); return 0; } } } 06.Псевдокод KeAttachProcess/KeDetachProcess. (NT4.0) ===================================================== ----------------------------------------------------------------------------- /************************ KeAttachProcess ***************************/ // just wrapper // KeAttachProcess(EPROCESS *Process) { KiAttachProcess(Process,KeRaiseIrqlToSynchLevel); } /************************ KiAttachProcess ***************************/ KiAttachProcess(EPROCESS *Process,Irql){ //CurThread=fs:124h //CurProcess=CurThread->ApcState.Process; if(CurProcess!=Process){ if(CurProcess->ApcStateIndex || KPCR->DpcRoutineActive)KeBugCheckEx... } //if we already in process's context if(CurProcess==Process){KiUnlockDispatcherDatabase(Irql);return;} Process->StackCount++; KiMoveApcState(&CurThread->ApcState,&CurThread->SavedApcState); // init lists CurThread->ApcState.ApcListHead[0].Blink=&CurThread->ApcState.ApcListHead[0]; CurThread->ApcState.ApcListHead[0].Flink=&CurThread->ApcState.ApcListHead[0]; CurThread->ApcState.ApcListHead[1].Blink=&CurThread->ApcState.ApcListHead[1]; CurThread->ApcState.ApcListHead[1].Flink=&CurThread->ApcState.ApcListHead[1];; //fill curtheads's fields CurThread->ApcState.Process=Process; CurThread->ApcState.KernelApcInProgress=0; CurThread->ApcState.KernelApcPending=0; CurThread->ApcState.UserApcPending=0; CurThread->ApcState.ApcStatePointer.SavedApcState=&CurThread->SavedApcState; CurThread->ApcState.ApcStatePointer.ApcState=&CurThread->ApcState; CurThread->ApcStateIndex=1; //if process ready, just swap it... if(!Process->State)//state==0, ready { KiSwapProcess(Process,CurThread->SavedApcState.Process); KiUnlockDispatcherDatabase(Irql); return; } CurThread->State=1; //ready? CurThread->ProcessReadyQueue=1; //put Process in Thread's waitlist CurThread->WaitListEntry.Flink=&Process->ReadyListHead.Flink; CurThread->WaitListEntry.Blink=Process->ReadyListHead.Blink; Process->ReadyListHead.Flink->Flink=&CurThread->WaitListEntry.Flink; Process->ReadyListHead.Blink=&CurThread->WaitListEntry.Flink; // else, move process to swap list and wait if(Process->State==1){//idle? Process->State=2; //trans Process->SwapListEntry.Flink=&KiProcessInSwapListHead.Flink; Process->SwapListEntry.Blink=KiProcessInSwapListHead.Blink; KiProcessInSwapListHead.Blink=&Process->SwapListEntry.Flink; KiSwapEvent.Header.SignalState=1; if(KiSwapEvent.Header.WaitListHead.Flink!=&KiSwapEvent.Header.WaitListHead.Flink) KiWaitTest(&KiSwapEvent,0xa); //fastcall } CurThread->WaitIrql=Irql; KiSwapThread(); return; } /************************* KiSwapProcess ****************************/ KiSwapProcess(EPROCESS* NewProcess, EPROCESS* OldProcess) { // just reload cr3 and small work with TSS // TSS=KPCR->TSS; // xor eax,eax // mov gs,ax TSS->CR3=NewProcess->DirectoryTableBase;//0x1c // mov cr3,NewProcess->DirectoryTableBase TSS->IopmOffset=NewProcess->IopmOffset;//0x66 if(WORD(NewProcess->LdtDescriptor)==0){lldt 0x00; return;//} //GDT=KPCR->GDT; (QWORD)GDT->0x48=(QWORD)NewProcess->LdtDescriptor; (QWORD)GDT->0x108=(QWORD)NewProcess->Int21Descriptor; lldt 0x48; return; } /************************** KiSwapThread ****************************/ KiSwapThread() { //NextThread=KPRCB->NextThread; //take next thread (may be Idle) if(!NextThread){ ecx=0x10; esi=KiReadySummary; esi>>=0x10; if(!esi){ecx=0;esi=KiReadySummary;} esi>>=0x8; if(esi)ecx+=8; esi=KiReadySummary; esi>>=cl; ecx+=3; if(esi>=0x10)ecx+=4; esi=ecx; not ecx; edi=KiReadySummary; edi<<=cl; Swt40: ; if(edi<0){ ecx=KiDispatcherReadyListHead[esi*8].Flink; edx=ecx-5c; //ethread* KiDispatcherReadyListHead[esi*8].Flink=ecx.Flink; ecx.Flink.Blink=ecx.Blink; if(ecx.Flink==ecx.Blink){ KiReadySummary=1<IdleThread; } goto Swt40; } } //CurThread=KPRCB->CurThread; //KPRCB->NextThread=0; res=SwapContext(NextThread,CurThread,CurThread->WaitIrql); Irql=NextThread->WaitIrql; Stat=NextThread->WaitStatus; if(res){ KeLowerIrql(1); KiDeliverApc(0,0,0); //KPRCB->ApcBypassCounte++; Irql=0; } KeLowerIrql(Irql); return Stat; } /************************* SwapContext ******************************/ SwapContext(NextThread,CurThread,WaitIrql) { NextThread.State=ThreadStateRunning; //2 KPCR.DebugActive=NextThread.DebugActive; cli(); //Save Stack CurThread.KernelStack=esp; //Set stack KPCR.StackLimit=NextThread.StackLimit; KPCR.StackBase=NextThread.InitialStack; tmp=NextThread.InitialStack-0x70; newcr0=cr0&0xfffffff1|NextThread.NpxState|*(tmp+0x6c); if(newcr0!=cr0)reloadcr0(); if(!*(tmp-0x1c)&0x20000)tmp-=0x10; TSS=KPCB.TSS; TSS->ESP0=tmp; //set pTeb KPCB.Self=NextThread.pTeb; esp=NextThread.KernelStack; sti(); //correct GDT GDT=KPCB.GDT; WORD(GDT->0x3a)=NextThread.pTeb; BYTE(GDT->0x3c)=NextThread.pTeb>>16; BYTE(GDT->0x3f)=NextThread.pTeb>>24; //if we must swap processes, do it (like KiSwapProcess) if(CurThread.ApcState.Process!=NextThread.ApcState.Process) { Process=NextThread.ApcState.Process; gs=0; TSS->CR3=Process->DirectoryBaseTable; TSS->IopmOffset=Process->IopmOffset;//0x66 ldt=0; if(Process->LdtDescriptor){ GDT->0x48=(uint32)Process->LdtDescriptor; IDT=KPCB.IDT; IDT->0x108=(uint32)Process->Int21Desriptor; ldt=0x48; } lidt(ldt); } NextThread->ContextSwitches++; KPCB->KeContextSwitches++; if(!NextThread->ApcState.KernelApcPending)return 0; //popf; // jnz HalRequestSoftwareInterrupt// return 0 return 1; } /**************************** KeDetachProcess ******************************/ KeDetachProcess(EPROCESS *Process,Irql){ //CurThread=fs:124h OldIrql = KeRaiseIrqlToSynchLevel() if(!CurThread->ApcStateIndex)return; //CurProcess=CurThread->ApcState.Process; if(!(--CurProcess.StackCount)) { CurProcess.State=2; //transition CurProcess->SwapListEntry.Flink=&KiProcessOutSwapListHead.Flink; CurProcess->SwapListEntry.Blink=KiProcessOutSwapListHead.Blink; KiProcessOutSwapListHead.Flink->Flink=&CurProcess->SwapListEntry.Flink; KiProcessOutSwapListHead.Blink=&CurProcess->SwapListEntry.Flink; KiSwapEvent.Header.SignalState=1; if(KiSwapEvent.Header.WaitListHead.Flink!=&KiSwapEvent.Header.WaitListHead) { KiWaitTest(&KiSwapEvent,0xa); } } KiMoveApcState(&CurThread->SavedApcState,&CurThread->ApcState); CurThread->SavedApcState.Process=0; CurThread->ApcStatePointer.SavedApcState=CurThread->ApcState; CurThread->ApcStatePointer.ApcState=CurThread->SavedApcState; CurThread->ApcStateIndex=0; if(CurThread->ApcState.ApcListHead.Flink!=&CurThread->ApcState.ApcListHead.Flink) { CurThread.ApcState.KernelApcPending=1; HalRequestSoftwareInterrupt(1); } KiSwapProcess(CurThread->ApcState.Process,CurProcess); KiUnlockDispatcherDatabase(OldIrql); } /*****************************************************************************/ 07.Псевдокод ExMapHandleToPointer (NT5.0) ========================================= ExMapHandleToPointer(Table,Handle) { TableEntry=ExpLookupHandleTableEntry(Table,Handle); if(!TableEntry)return 0; return ExLockHandleTableEntry(Table,TableEntry); } ExpLookupHandleTableEntry(Table,Handle) { l1=(Handle>>18)&0xff; l2=(Handle>>10)&0xff; l3=(Handle>>2)&0xff; if(Handle&0xfc000000)return 0; pPtr=Table->0x8; pPtr=pPtr+l1*4; if(pPtr) { pPtr=pPtr+l2*4; if(pPtr) { return pPtr+l3*8; } } return 0; } ExLockHandleTableEntry(Table,TableEntry) // Table not used { ObjectPointer = TableEntry->0x00; if (!ObjectPointer)return 0; if (ObjectPointer > 0) { NewObjectPointer = ObjectPointer | 0x80000000; //xmpxchg NewObjectPointer,ObjectPointer in ObjectPointer } else { // wait logic } return 1; } 08.Псевдокод функций, работающих с объектом "секция" (NT5.0) ============================================================ /****************************************************************/ from NT5 /****************************************************************/ DWORD MmMakeFileAccess[]= {1,1,0x20,0x21,3,1,0x23,0x21}; MmCreateSection(pSection,pObjectAttrib,pMaxSize,PageProtection,AllocAttrib,FileHan,FileObj) { if(AllocAttrib&0x10000000) { PageProtection|=0x200; // PAGE_NOCACHE } ProtectionMask=MiMakeProtectionMask(PageProtection); // from PAGE_ to mask MmMakeFileAccess[ProtectionMask&7]; bMode=CurThread->PreviouseMode; if(FileHan==0)&&FileObj==0{ if(AllocAttrib&0x1000000){ return 0xc0000020; } status=MiCreatePagingFileMap (pSectStruct,pMaxSize,ProtectionMask,AllocAttrib); if(status<0)return status; SectionSizeLo=pSectStruct->0x10; SectionSizeHi=pSectStruct->0x14; pCtrl=pSectStruct->0; // create_section_object ControlFlags=pCtrl->Flags; Status=ObCreateObject(pObjAttrib,bMode,0,0x28,0x28+pSectStruct->0x8*4,pCtrl ->Subsections*32+56,&pSectBody); if(Status<0).... //error memmove(pSectBody,&SetionBody,0x28); pSectBody->0=0; pSectBody->0x22|=1; if(AllocAttrib&0x400000)pSectBody->0x22|=0x80; if(PageProtection&0x44)PSectBody->0x21|=8; if(AllocAttrib&0x200000){//based pSectBody->0x20|=40; ExAcquireFastMutex(&MmSectionBasedMutex); res=MiFindEmptySectionBaseDown(pSectBody->0x18,MmHighSectionBase); pSectBody->0=res; pSectBody->4=pSectBody->0x18+res-1; MiInsertBasedSection(pSectBody); ExReleaseFastMutex(&MmSectionBasedMutex); } // not based LoSize=pSectBody->0x18; HiSize=pSectbody->0x1c; pSectPtr=pSectBody->pSectStruct; pSectBody->0x18=pSectPtr->0x10; pSectBody->0x1c=pSectPtr->0x14; if(!pSectBody->0x24&0x44){ memcpy(SectBodyCopy,pSectBody,40); MmExtendSection(SectBodyCopy,&LoSize,bFileMap); } // ???? } } /****************************************************************************/ MmExtendSection(pSectObj,pSize,bFileMap) { pSegment=pSectObj=>pSectStruct; pControl=pSegment->pControl; if(pControl->Flags&0x400)return 0xc0000087;//phys memory if(pControl->Flags&0x20)return 0xc0000087;//image if(!pControl->FileObject)return 0xc0000087;//image CurThread->KernelApcDisable --; ExAcquireResourceExclusiveLite(&MmSectionExtendedResource,1); SizeInPages=*pSize>>12; if(!pControl->Flags&WasPurged){ if(*pSizeSize){ *pSize=pSectionObject->Size; // goto exit; } } if(!bFile){ ExReleaseResourceLite(&MmSectionExtendedResource); ExAcquireResourceExclusiveLite(&MmSectionExtendedSetResource,1); FsRtlGetFileSize(pControl->FileObject,&FileSize); if(*pSize>FileSize){ if(PSectionObject->PgProtection&0x44) { FsRtlSetFileSize(pControl ->FileObject,pSize); } else { ExReleaseResourceLite(&MmSectionEx... return 0xC0000087h; } } ExReleaseResourceLite(&MmSectionExtendSetResource); ExAcquireResourceExclusiveLite(&MmSectionExtendedResource,1); } pSubsection=pControl+sizeof(Control); while(pSubsection->pNext)pSubsection=pSubsection->pNext; // look for last pSegment=pSectionObject->pSegment; if(SizeInPages>pSegment->TotalPtes) { if(SizeInPages-(pSegment->TotalPtes) < pSubsection->UnusedPtes) { PtesToBeAllocated=0; ExtendedPtes=SizeInPages-(pSegment->TotalPtes); Delta=SizeInPages-(pSegment->TotalPtes); } else { PtesToBeAllocated=SizeInPages-(pSegment->TotalPtes) - pSubsection->UnusedPtes; ExtendedPtes=pSubsection->UnusedPtes; Delta=pSubsection->UnusedPtes; } pSubsection->PtesInSubsect+=Delta; pSubsection->UnusedPtes-=Delta; pSegment=pControl->pSegment; pSegment->SizeOfSegment+=Delta<<12; pSegment->TotalPtes+=Delta; if(!PtesToBeAllocated) { StartingSectHi=pSubsection->Flags>>10 & 0x3ff; StartingSector=pSubsection->StartingSector | StartingSectHi<<32; SizeInPages=*pSize>>12; pSubsection->NumberOfSectors=SizeInPages-StartingSector; pSubsection->Flags=pSubsection ->Flags&0xfffff|(*pSize&0xffffffff)<<20; pSegment->Sile(Lo,Hi)=*pSize; pSectionObject->Size=*pSize;//0x18, 0x1c //... // free MmSectionExtendedResource and return 0 } else {// alloc ptes s1=(PtesToBeAllocated*4 + 0xfff) & 0xfffff000; pProtoPtes=ExAllocatePoolWithTag(1,s1); pSubsectionNew=ExAllocatePoolWithTag(0,0x20); pControl->Unknown3+=0x40; pControl->Unknown2+=s1; StartingSector=pSubsection->StartingSector|pSubsection ->Flags<<32; TmpQword=pSegment->SizeOfSegment>>12 - StartingSector; if (pSubsection->Flags&0xfff00000) { // sector offset TmpQword ++; } pSubsection->NumberOfSectors=TmpQword&0xffffffff; s1>>=2; pSubsectionNew->Flags=0; pSubsectionNew->pNext=0; pSubsectionNew->UnusedPte=s1-PtesToBeAllocated; pSubsectionNew->pControlArea=pControlArea; SizeInPages+=pSubsection->NumberOfSectors; pSubsectionNew->StartingSector=SizeInPages; pSubsectionNew->Flags=StartingSector&0x3ff<<10; TmpQword=(*pSize>>12) - SizeInPages|(StartingSector<<32); pSubsectionNew->NumberOfSectors=TmpQword&0xffffffff; StartingSector=TmpQword&0xffffffff00000000; pSubsectionNew->Flags = (*pSize&0xffffffff)<<20 | pSubsectionNew->Flags&0xffffffff; pPtr= pProtoPtes; pProtoPtes= pPtr+s1*4; if (!pControl->FileObject) { PPte=bFile; } else if(pSubsectionNew>=0xa0000000) { PPte=(pSubsectionNew-MmSubsectionBase<<4) & 0xfffff800 | (pSubsectionNew-MmSubsectionBase>>2) &0x1e | 0x80000000; } else { PPte=(MmNonPagedPoolEnd-pSubsectionNew << 4) & 0x7ffff800 | (MmNonPagedPoolEnd-pSubsectionNew >> 2) & 0x1e; } pSegment = pControl->pSegment; PteVal= pSegment->PteTemplate ^ PPte & 0x3e0 ^ PPte | 0x400; pSubsectionNew->Flags = PteVal>>1 & 0x1f0 | pSubsectionNew ->Flags&0xfffffe0f; if(pPtr < pProtoPtes ){ memset(pPtr,PteVal,pProtoPtes-pPtr); } pSubsection->Next=pSubsectionNew; pControl->pSegment->TotalPtes+= PtesToBeAllocated; }//else pControl->PSegment->SizeOfSegment=*pSize;// lo & hi pSectionObject->Size=*pSize; // 0x18,0x1c - lo & hi }// if pte resize exit: // // free all resources } /****************************************************************************/ MiCreatePagingFileMap(pSection,pMaxSize,ProtMask,AllocAttrib) { if(*(QWORD*)pMaxSize==0)return 0xc00000f2; if(*(DWORD)(pMaxSize+4))return 0xc0000040; if(*(QWORD*)pMaxSize>0xfff00000)return 0xc0000040; Pages=*(DWORD)(pMaxSize)>>12+(*(DWORD)(pMaxSize)&0xfff!=0); if(AllocAttrib&0x8000000){ if(!MiChargeCommitment(Pages,0))return 0xc000012d; } SectPtr=ExAllocatePoolWithTag(1,0x3c+Pages*4,'tSmM');//_MMSECT if(!SectPtr){if(AllocAttrib&0x8000000)MiReturnCommitment(Pages); return 0xc000009a;} *pSection=SectPtr; CtrlPtr=ExAllocatePoolWithTag(0,0x58,'aCmM');//_MMCONTROL if(!CtrlPtr){... return 0xc000009a; } memset(CtrlPtr,0,0x58); CtrlPtr->SectionRef=1; CtrlPtr->UserRef=1; CtrlPtr->Subsections=1; if(AllocAttrib&0x200000)CtrlPtr->Flags|=Based; if(AllocAttrib&0x4000000)CtrlPtr->Flags|=Reserve; if(pMaxSize!=NULL)CtrlPtr->Flags|=Commit; AllocAttrib=ProtMask&0x1f; CtrlPtr->Flags=(ProtMask&0x1f<<4)|CtrlPtr->Flags&0xfffffe0f;// 0x3c CtrlPtr->PtesInSubsect=Pages; CtrlPtr->ControlArea=CtrlPtr; memset(SectPtr,0,0x40); SectPtr->0x0=CtrlPtr; SectPtr->0x34=&SectPtr->0x34; SectPtr->0x10=Pages<<12; SectPtr->0x14=0; SectPtr->0x8=Pages; if((64+Pages*4)>4056)CtrlPtr->Unknown2=(4159+Pages*4)&0xfffff000; CtrlPtr->Unknown2=(103+Pages*4)&0xffffffe0; CtrlPtr->BasePte = SectPtr->0x34; // sunsect PteBase=CtrlPtr->BasePte; if(pMaxSize){ Pte=_ZeroPte&0xfffffc1f | AllocAttrib<<5 ; //ZeroPte+ other 5 bits!!!! SectPtr->0x24=Pages; ExAcquireFastMutex(&MmSectionCommitMutex); MmSharedCommit+=SectPtr->0x24; ExReleaseFastMutex(&MmSectionCommitMutex); } SectPtr->0x28=SectPtr->0x28&0xfffffc1f|AllocAttrib<<5; while(Pages--)PteVase[Pages]=SectPtr->0x28; return 0; } 09.Некоторые системные сервисы ============================== /***************************** Менеджер объектов *****************************************/ typedef enum _OBJECTINFOCLASS { BaseObjectInfo, NameObjectInfo, TypeObjectInfo, AllTypesObjectInfo, HandleObjectInfo } OBJECTINFOCLASS; NTSYSAPI NTSTATUS NTAPI NtQueryObject( HANDLE ObjHandle, OBJECTINFOCLASS ObjectInfoClass, OUT PVOID ObjectInfo, // буфер под информацию DWORD ObjectInfoLen, // длина буфера OUT PDWORD RetInfoLen // доина записанной информации ); typedef struct _BASE_OBJECT_INFO{ DWORD HandleAttributes, ACCESS_MASK GrantedAccess, DWORD HandleCount, DWORD RefCount, DWORD PagedPollQuota, DWORD NonPagedPollQuota, DWORD ReservedAndAlwaysNull[3], DWORD NameObjectInfoLength, DWORD TypeObjectInfoLength, DWORD SecurityDescriptorLengh, LARGE_INTEGER SymLinkCreationTime //время от 1601 года }; typedef struct _NAME_OBJECT_INFO{ UNICODE_STRING Name; // тут должно быть место под имя. Параметр ObjectInfo может быть 0 // что бы узнать нужный размер под буфер. }NAME_OBJECT_INFO; typedef struct _TYPE_OBJECT_INFO{ UNICODE_STRING Name; DWORD InstanceCount; DWORD HandleCount; DWORD PeakObjects; DWORD PeakHandles; DWORD AllowedAttributesMask; GENERIC_MAPPING GenericMapping; DWORD AllowedAccessMask; BOOLEAN bInNameSpace; BOOLEAN bHandleDBInfo; BOOLEAN Align[2]; DWORD Unknown6; // см. поле unknown6 в объекте-типе DWORD DefaultPagedPollQuota; DWORD DefaultNonPagedPollQuota; }TYPE_OBJECT_INFO; typedef struct _ALL_TYPES_OBJECT_INFO{ DWORD NumOfTypes; TYPE_OBJECT_INFO [ANY_SIZE_ARRAY]; }ALL_TYPES_OBJECT_INFO; typedef struct _HANDLE_OBJECT_INFO{ BOOLEAN Inherit; BOOLEAN ProtectFromClose; }HANDLE_OBJECT_INFO; //Функции для работы с любым объектом NTSYSAPI NTSTATUS NTAPI NtClose(IN HANDLE Handle); NTSYSAPI NTSTATUS NTAPI NtMakeTemporaryObject( IN HANDLE Handle ); #define DUPLICATE_CLOSE_SOURCE 0x00000001 #define DUPLICATE_SAME_ACCESS 0x00000002 NTSYSAPI NTSTATUS NTAPI NtDuplicateObject( IN HANDLE SourceProcessHandle, IN HANDLE SourceHandle, IN HANDLE TargetProcessHandle, OUT PHANDLE TargetHandle OPTIONAL, IN ACCESS_MASK DesiredAccess, IN ULONG Attributes,//OBJ_xxx IN ULONG Options ); //Объект каталог #define DIRECTORY_QUERY (0x0001) #define DIRECTORY_TRAVERSE (0x0002) #define DIRECTORY_CREATE_OBJECT (0x0004) #define DIRECTORY_CREATE_SUBDIRECTORY (0x0008) #define DIRECTORY_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | 0xF) NTSYSAPI NTSTATUS NTAPI NtCreateDirectoryObject( OUT PHANDLE DirectoryHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes ); NTSYSAPI NTSTATUS NTAPI NtOpenDirectoryObject( OUT PHANDLE DirectoryHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes ); typedef struct _OBJECT_NAMETYPE_INFO { UNICODE_STRING ObjectName; UNICODE_STRING ObjectType; } OBJECT_NAMETYPE_INFO, *POBJECT_NAMETYPE_INFO; typedef enum _DIRECTORYINFOCLASS { ObjectArray, ObjectByOne } DIRECTORYINFOCLASS, *PDIRECTORYINFOCLASS; NTSYSAPI NTSTATUS NTAPI NtQueryDirectoryObject( IN HANDLE DirectoryObjectHandle, OUT PVOID ObjectInfoBuffer, IN ULONG ObjectInfoBufferLength, IN DIRECTORYINFOCLASS DirectoryInformationClass, IN BOOLEAN First, IN OUT PULONG ObjectIndex, OUT PULONG LengthReturned ); //Объект символическая ссылка #define SYMBOLIC_LINK_QUERY (0x0001) #define SYMBOLIC_LINK_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | 0x1) NTSYSAPI NTSTATUS NTAPI NtCreateSymbolicLinkObject( OUT PHANDLE ObjectHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes, IN PUNICODE_STRING SubstituteString ); NTSYSAPI NTSTATUS NTAPI NtOpenSymbolicLinkObject( OUT PHANDLE ObjectHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes ); typedef struct _OBJECT_NAME_INFORMATION { UNICODE_STRING Name; } OBJECT_NAME_INFORMATION, *POBJECT_NAME_INFORMATION; NTSYSAPI NTSTATUS NTAPI NtQuerySymbolicLinkObject( IN HANDLE ObjectHandle, OUT POBJECT_NAME_INFORMATION SubstituteString, OUT PULONG SubstituteStringLength //в байтах ); /*****************************Менеджер памяти *****************************************/ NTSYSAPI NTSTATUS NTAPI NtAllocateVirtualMemory( HANDLE Process, OUT PVOID *BaseAddr, DWORD ZeroBits, OUT PDWORD RegionSize, DWORD AllocationType,// MEM_RESERVE|MEM_COMMIT|MEM_TOP_DOWN DWORD Protect); // PAGE_XXXX... NTSYSAPI NTSTATUS NTAPI NtFreeVirtualMemory( HANDLE Process, OUT PVOID* BaseAddr, OUT PULONG RegionSize, DWORD FreeType //MEM_DECOMMIT|MEM_RELEASE ); NTSYSAPI NTSTATUS NTAPI NtCreateSection( OUT PHANDLE Section, ACCESS_MASK DesirdAccess, //SECTION_MAP_XXX... POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, PLARGE_IBTEGER MaximumSize OPTIONAL, DWORD SectionPageProtection, //PAGE_... DWORD AllocationAttributes, //SEC_XXX HANDLE FileHandle OPTIONAL // NULL - pagefile ); typedef enum _SECTION_INHERIT { ViewShare=1; ViewUnmap=2; }SECTION_INHERIT; NTSYSAPI NTSTATUS NTAPI NtMapViewOfSection( HANDLE Section, HANDLE Process, OUT PVOID *BaseAddress, DWORD ZeroBits, DWORD CommitSize, OUT PLARGE_INTEGER SectionOffset OPTIONAL, OUT PDWORD ViewSize, SECTION_INHERIT InheritDisposition, DWORD AllocationType, //MEM_TOP_DOWN,MEM_LARGE_BAGE,MEM_AUTO_ALIGN=0x40000000 DWORD ProtectionType // PAGE_... ); #define UNLOCK_TYPE_NON_PRIVILEGED 0x00000001L #define UNLOCK_TYPE_PRIVILEGED 0x00000002L NTSYSAPI NTSTATUS NTAPI NtLockVirtualMemory( IN HANDLE ProcessHandle, IN OUT PVOID *RegionAddress, IN OUT PULONG RegionSize, IN ULONG UnlockTypeRequired ); NTSYSAPI NTSTATUS NTAPI NtUnlockVirtualMemory( IN HANDLE ProcessHandle, IN OUT PVOID *RegionAddress, IN OUT PULONG RegionSize, IN ULONG UnlockTypeRequiested ); NTSYSAPI NTSTATUS NTAPI NtReadVirtualMemory( IN HANDLE ProcessHandle, IN PVOID StartAddress, OUT PVOID Buffer, IN ULONG BytesToRead, OUT PULONG BytesReaded OPTIONAL ); NTSYSAPI NTSTATUS NTAPI NtWriteVirtualMemory( IN HANDLE ProcessHandle, IN PVOID StartAddress, IN PVOID Buffer, IN ULONG BytesToWrite, OUT PULONG BytesWritten OPTIONAL ); NTSYSAPI NTSTATUS NTAPI NtProtectVirtualMemory( IN HANDLE ProcessHandle, IN OUT PVOID *RegionAddress, IN OUT PULONG RegionSize, IN ULONG DesiredProtection, OUT PULONG OldProtection ); NTSYSAPI NTSTATUS NTAPI NtFlushVirtualMemory( IN HANDLE ProcessHandle, IN PVOID* StartAddress, IN PULONG BytesToFlush, OUT PIO_STATUS_BLOCK StatusBlock ); typedef enum _MEMORYINFOCLASS { MemoryBasicInformation, MemoryWorkingSetInformation, // еще есть класс 2 - это информация из VAD, я пока не знаю // структуру VAD полностью, что бы описать соотв. INFO структуру } MEMORYINFOCLASS; typedef struct _MEMORY_BASIC_INFORMATION { PVOID BaseAddress; PVOID AllocationBase; ULONG AllocationProtect; ULONG RegionSize; ULONG State; ULONG Protect; ULONG Type; } MEMORY_BASIC_INFORMATION, *PMEMORY_BASIC_INFORMATION; #define WSFRAMEINFO_SHARED_FRAME 0x100 #define WSFRAMEINFO_INTERNAL_USE 0x4 #define WSFRAMEINFO_UNKNOWN 0x3 typedef struct _MEMORY_WORKING_SET_INFORMATION { ULONG SizeOfWorkingSet; DWORD WsEntries[ANYSIZE_ARRAY]; // is Page VA | WSFRAMEINFO... } MEMORY_ENTRY_INFORMATION, *PMEMORY_ENTRY_INFORMATION; NTSYSAPI NTSTATUS NTAPI NtQueryVirtualMemory( IN HANDLE ProcessHandle, IN PVOID RegionAddress, IN MEMORYINFOCLASS MemoryInformationClass, IN PVOID VirtualMemoryInfo, IN ULONG Length, OUT PULONG ActualLength OPTIONAL ); --------------------------------------------------------------------------- (c)Gloomy aka Peter Kosyh, Melancholy Coding'2001 http://gloomy.cjb.net mailto:gl00my@mail.ru