Sunday, December 4, 2011

Обектно ориентиране в Windows (2)

И така, в тази част мисля да обърна внимание на структурите, които се на практика описват един обект. За целта на тази статия  ще взема за пример, произволен _EPROCESS обект. За момента е необходимо да знаете, че всеки процес в Windows има (освен всички останали) _EPROCESS структура, която съдържа един вид "accounting" информация. За да видим всички работещи процеси е необходимо да се изпълни командата !process 0 0  

Ето какво изкарва Windbg (ще пейстна само 1 entry, което ще изпозлвам за дискусията по-долу):

PROCESS 85b4c030  SessionId: 1  Cid: 0520    Peb: 7ffd6000  ParentCid: 0560
    DirBase: 3ee8f1a0  ObjectTable: 8ce0fa48  HandleCount: 759.
    Image: explorer.exe

Както се вижда _EPROCESS структурата се намира на адрес 0x85b4c030, съответно ако използваме командата dt nt!_EPROCESS 85b4c030 Windbg ще интерпрететира памета от този адрес до 85b4c030 + sizeof(_EPROCESS) като _EPROCESS и ще ни даде стойностите на различните полета (под-структури) за дадения процес: 


kd> dt nt!_EPROCESS 85b4c030
   +0x000 Pcb              : _KPROCESS
   +0x098 ProcessLock      : _EX_PUSH_LOCK
   +0x0a0 CreateTime       : _LARGE_INTEGER 0x1ccb28c`3e22d03a
   +0x0a8 ExitTime         : _LARGE_INTEGER 0x0
   +0x0b0 RundownProtect   : _EX_RUNDOWN_REF
   +0x0b4 UniqueProcessId  : 0x00000520 Void
   +0x0b8 ActiveProcessLinks : _LIST_ENTRY [ 0x84fd33f8 - 0x85b0a0e8 ]
   +0x0c0 ProcessQuotaUsage : [2] 0x6040
   +0x0c8 ProcessQuotaPeak : [2] 0x6d3c
   +0x0d0 CommitCharge     : 0x1706
   +0x0d4 QuotaBlock       : 0x85d57180 _EPROCESS_QUOTA_BLOCK
   +0x0d8 CpuQuotaBlock    : (null) 
   +0x0dc PeakVirtualSize  : 0xe9a0000
   +0x0e0 VirtualSize      : 0xcdec000
   +0x0e4 SessionProcessLinks : _LIST_ENTRY [ 0x84fd3424 - 0x85b0a114 ]
   +0x0ec DebugPort        : (null) 
   +0x0f0 ExceptionPortData : 0x841d5c90 Void
   +0x0f0 ExceptionPortValue : 0x841d5c90
   +0x0f0 ExceptionPortState : 0y000
   +0x0f4 ObjectTable      : 0x8ce0fa48 _HANDLE_TABLE
   +0x0f8 Token            : _EX_FAST_REF
   +0x0fc WorkingSetPage   : 0x104e8
   +0x100 AddressCreationLock : _EX_PUSH_LOCK
   +0x104 RotateInProgress : (null) 
   +0x108 ForkInProgress   : (null) 
   +0x10c HardwareTrigger  : 0
   +0x110 PhysicalVadRoot  : (null) 
   +0x114 CloneRoot        : (null) 
   +0x118 NumberOfPrivatePages : 0xf61
   +0x11c NumberOfLockedPages : 0
   +0x120 Win32Process     : 0xfe9bfe30 Void
   +0x124 Job              : (null) 
   +0x128 SectionObject    : 0x940657d8 Void
   +0x12c SectionBaseAddress : 0x00170000 Void
   +0x130 Cookie           : 0xe99c86ae
   +0x134 Spare8           : 0
   +0x138 WorkingSetWatch  : (null) 
   +0x13c Win32WindowStation : 0x00000030 Void
   +0x140 InheritedFromUniqueProcessId : 0x00000560 Void
   +0x144 LdtInformation   : (null) 
   +0x148 VdmObjects       : (null) 
   +0x14c ConsoleHostProcess : 0
   +0x150 DeviceMap        : 0x8fc39720 Void
   +0x154 EtwDataSource    : (null) 
   +0x158 FreeTebHint      : 0x7ff9f000 Void
   +0x160 PageDirectoryPte : _HARDWARE_PTE
   +0x160 Filler           : 0
   +0x168 Session          : 0x8a8b5000 Void
   +0x16c ImageFileName    : [15]  "explorer.exe"
   +0x17b PriorityClass    : 0x2 ''
   +0x17c JobLinks         : _LIST_ENTRY [ 0x0 - 0x0 ]
   +0x184 LockedPagesList  : (null) 
   +0x188 ThreadListHead   : _LIST_ENTRY [ 0x85b31fb0 - 0x850f3ef8 ]
   +0x190 SecurityPort     : (null) 
   +0x194 PaeTop           : 0x8508f1a0 Void
   +0x198 ActiveThreads    : 0x21
   +0x19c ImagePathHash    : 0xa80e4f97
   +0x1a0 DefaultHardErrorProcessing : 0
   +0x1a4 LastThreadExitStatus : 0n0
   +0x1a8 Peb              : 0x7ffd6000 _PEB
   +0x1ac PrefetchTrace    : _EX_FAST_REF
   +0x1b0 ReadOperationCount : _LARGE_INTEGER 0x364
   +0x1b8 WriteOperationCount : _LARGE_INTEGER 0x4
   +0x1c0 OtherOperationCount : _LARGE_INTEGER 0x79c6
   +0x1c8 ReadTransferCount : _LARGE_INTEGER 0x2f8dae
   +0x1d0 WriteTransferCount : _LARGE_INTEGER 0x368
   +0x1d8 OtherTransferCount : _LARGE_INTEGER 0x3be11
   +0x1e0 CommitChargeLimit : 0
   +0x1e4 CommitChargePeak : 0x2029
   +0x1e8 AweInfo          : (null) 
   +0x1ec SeAuditProcessCreationInfo : _SE_AUDIT_PROCESS_CREATION_INFO
   +0x1f0 Vm               : _MMSUPPORT
   +0x25c MmProcessLinks   : _LIST_ENTRY [ 0x84fd359c - 0x85b0a28c ]
   +0x264 HighestUserAddress : 0x7fff0000 Void
   +0x268 ModifiedPageCount : 0x41
   +0x26c Flags2           : 0xd000
   +0x26c JobNotReallyActive : 0y0
   +0x26c AccountingFolded : 0y0
   +0x26c NewProcessReported : 0y0
   +0x26c ExitProcessReported : 0y0
   +0x26c ReportCommitChanges : 0y0
   +0x26c LastReportMemory : 0y0
   +0x26c ReportPhysicalPageChanges : 0y0
   +0x26c HandleTableRundown : 0y0
   +0x26c NeedsHandleRundown : 0y0
   +0x26c RefTraceEnabled  : 0y0
   +0x26c NumaAware        : 0y0
   +0x26c ProtectedProcess : 0y0
   +0x26c DefaultPagePriority : 0y101
   +0x26c PrimaryTokenFrozen : 0y1
   +0x26c ProcessVerifierTarget : 0y0
   +0x26c StackRandomizationDisabled : 0y0
   +0x26c AffinityPermanent : 0y0
   +0x26c AffinityUpdateEnable : 0y0
   +0x26c PropagateNode    : 0y0
   +0x26c ExplicitAffinity : 0y0
   +0x270 Flags            : 0x144d0801
   +0x270 CreateReported   : 0y1
   +0x270 NoDebugInherit   : 0y0
   +0x270 ProcessExiting   : 0y0
   +0x270 ProcessDelete    : 0y0
   +0x270 Wow64SplitPages  : 0y0
   +0x270 VmDeleted        : 0y0
   +0x270 OutswapEnabled   : 0y0
   +0x270 Outswapped       : 0y0
   +0x270 ForkFailed       : 0y0
   +0x270 Wow64VaSpace4Gb  : 0y0
   +0x270 AddressSpaceInitialized : 0y10
   +0x270 SetTimerResolution : 0y0
   +0x270 BreakOnTermination : 0y0
   +0x270 DeprioritizeViews : 0y0
   +0x270 WriteWatch       : 0y0
   +0x270 ProcessInSession : 0y1
   +0x270 OverrideAddressSpace : 0y0
   +0x270 HasAddressSpace  : 0y1
   +0x270 LaunchPrefetched : 0y1
   +0x270 InjectInpageErrors : 0y0
   +0x270 VmTopDown        : 0y0
   +0x270 ImageNotifyDone  : 0y1
   +0x270 PdeUpdateNeeded  : 0y0
   +0x270 VdmAllowed       : 0y0
   +0x270 CrossSessionCreate : 0y0
   +0x270 ProcessInserted  : 0y1
   +0x270 DefaultIoPriority : 0y010
   +0x270 ProcessSelfDelete : 0y0
   +0x270 SetTimerResolutionLink : 0y0
   +0x274 ExitStatus       : 0n259
   +0x278 VadRoot          : _MM_AVL_TABLE
   +0x298 AlpcContext      : _ALPC_PROCESS_CONTEXT
   +0x2a8 TimerResolutionLink : _LIST_ENTRY [ 0x0 - 0x0 ]
   +0x2b0 RequestedTimerResolution : 0
   +0x2b4 ActiveThreadsHighWatermark : 0x25
   +0x2b8 SmallestTimerResolution : 0
   +0x2bc TimerResolutionStackRecord : (null) 
 
Самата структура е доста обемна и сама по себе си заслужава отделен постинг, за да се опишат по-интересните полета, особено от гледна точка на rootkit development, но за момента искам да илюстрирам нещо друго - ако изпълним командата !object 85b4c030 ще видим следното: 

kd> !object 85b4c030
Object: 85b4c030  Type: (841338f0) Process
    ObjectHeader: 85b4c018 (new version)
    HandleCount: 5  PointerCount: 368 
 
Малко проста математика: 0x85b4c030 - 0x85b4c018 = 0x18 - тоест големината на _OBJECT_HEADER структурата е 0x18 байта (или 24 байта в десетична бройна система) и на практика тази структура е винаги _ПРЕДИ_  _EPROCESS структурата (или всяка друга, която дефинира executive обектите. Hint: ако искате да видите всички обекти, използвайте командата: !object \objecttypes ). Ето я и _OBJECT_HEADER структурата на Explorer.exe:

kd> dt _OBJECT_HEADER (0x85b4c030 - 0x18)
nt!_OBJECT_HEADER
   +0x000 PointerCount     : 0n398
   +0x004 HandleCount      : 0n5
   +0x004 NextToFree       : 0x00000005 Void
   +0x008 Lock             : _EX_PUSH_LOCK
   +0x00c TypeIndex        : 0x7 ''
   +0x00d TraceFlags       : 0 ''
   +0x00e InfoMask         : 0x8 ''
   +0x00f Flags            : 0 ''
   +0x010 ObjectCreateInfo : 0x85d57180 _OBJECT_CREATE_INFORMATION
   +0x010 QuotaBlockCharged : 0x85d57180 Void
   +0x014 SecurityDescriptor : 0x9024301a Void
   +0x018 Body             : _QUAD

Полетата на тази структура са горе-долу самодокументиращи се - брояч колко pointer-а има отворени към този обект (Explorer.exe в случая), колко handles има отворени, NextToFree не го знам какво е :Д, Lock - използващ се, когато object manager-а оперира върху този обект, за да се избегнат race conditions, Flags - флагове, които описват как точно трябва да се държи този обект - например тук са флагове като OBJ_INHERIT, OBJ_EXCLUSIVE, OBJ_KERNEL_HANDLE etc. 

TypeIndex

И така. TypeIndex полето е индекс в таблица, която указва кой обект от какъв тип е. Тази таблица е глобална и следният и може да бъде достъпена като nt!ObTypeIndexTable. За да се разбере какъв тип обект отговаря на даден header просто трябва да се използва следната формула: nt!ObTypeIndexTable + ( TypeIndex * sizeof(void *) ), в WinDBG това би изглеждало по следният начин: dt _OBJECT_TYPE poi(nt!ObTypeIndexTable + (7 * @$ptrsize)) или dt _OBJECT_TYPE poi(nt!ObTypeIndexTable + (7 * 4)) (големината на pointer на 32 битова машина е винаги 4 байта (32 бита), респективно за 64 битова архитектура това би било 8 байта/64 бита)).


kd> dt _OBJECT_TYPE poi(nt!ObTypeIndexTable + (7 * @$ptrsize))
ntdll!_OBJECT_TYPE
   +0x000 TypeList         : _LIST_ENTRY [ 0x841338f0 - 0x841338f0 ]
   +0x008 Name             : _UNICODE_STRING "Process"
   +0x010 DefaultObject    : (null) 
   +0x014 Index            : 0x7 ''
   +0x018 TotalNumberOfObjects : 0x25
   +0x01c TotalNumberOfHandles : 0xd6
   +0x020 HighWaterNumberOfObjects : 0x28
   +0x024 HighWaterNumberOfHandles : 0xde
   +0x028 TypeInfo         : _OBJECT_TYPE_INITIALIZER
   +0x078 TypeLock         : _EX_PUSH_LOCK
   +0x07c Key              : 0x636f7250
   +0x080 CallbackList     : _LIST_ENTRY [ 0x84133970 - 0x84133970 ]

Както виждаме правилно успяхме да получим _OBJECT_TYPE  за обект от тип Process. Полетата тук също бих казал, че са самодокументиращи се - първо виждаме, че всички _OBJECT_TYPE  структури са навързани в двоен linke-list, всяка има име, (незадължителен) обект по подразбиране за синхронизация, index  е индексът във ObTypeIndexTable. Броят обекти от даден тип - в случаят 0x25 или 37 процеса, броят handles, които са отворени към _EPROCESS обекти, HighWater не ги знам за какво са, TypeInfo ще го дискутирам в следващ постинг, но точно там нещата стават интересни ;-) TypeLock  се използва за синхронизация, когато се оперира върху тази структура (която има глобално значение, за всички обекти от тип _EPROCESS), CallbackList е двоен linked-list  с callbackovete, които трябва да бъдат извикани (Hint: ObRegisterCallbacks)

И така смятам да спра до тук, а в следващият постинг вече ще дам реален пример какво точно може да се направи с _OBJECT_TYPE_INITIALIZER структурата, за да може да се извиква нащ код винаги, когато се случва нещо с обект от даден тип.