Zine.net online

Witaj na Zine.net online Zaloguj się | Rejestracja | Pomoc
w Szukaj

mgrzeg.net - Admin on Rails :)

nt!_EPROCESS a csrss!_CSR_PROCESS, czyli o odkrywaniu ukrytego dwa słowa

Prawie miesiąc temu pisałem o MAX_PATH i pod koniec nieco przydługiego wpisu opisałem technikę pozwalającą załadować moduł, który zapisany jest w postaci alternatywnego strumienia pliku. Niejako na marginesie wspomniałem, iż alternatywne strumienie plików nie są widoczne wprost w eksploratorze windows, a zatem tak zapisany moduł jest przed nami niejako ‘ukryty’ i dzięki temu taka technika przy odrobinie wyobraźni może stanowić pożywkę dla autorów wszelkiego rodzaju niechcianych aplikacji.

DKOM

Dziś jednak poświęcę kilka słów innym obiektom systemowym - procesom. Sięgnę do bardzo popularnej techniki stosowanej przez twórców rootkitów - DKOM (Direct Kernel Object Manipulation), z której pomocą można wyczyniać różne cuda na poziomie jądra systemu. W poprzednim wpisie rzuciłem zagadkę, której rozwiązanie okazało się ciekawą zabawą, a chodziło w niej o modyfikację listy procesów jądra systemu (w opisywanym przypadku chodziło o Windows 7 64-bit). Powtórzmy zatem całość, tym razem dla odmiany w Windows XP Prof SP3 32-bit.

Zacznijmy od wyciągnięcia listy aktywnych procesów:

0: kd> !process 0 0
**** NT ACTIVE PROCESS DUMP ****
PROCESS 863c4830  SessionId: none  Cid: 0004    Peb: 00000000  ParentCid: 0000
    DirBase: 06d40020  ObjectTable: e1002e40  HandleCount: 249.
    Image: System
PROCESS 85ff4be8  SessionId: none  Cid: 021c    Peb: 7ffd5000  ParentCid: 0004
    DirBase: 06d40040  ObjectTable: e101ddf8  HandleCount:  19.
    Image: smss.exe
PROCESS 85e40020  SessionId: 0  Cid: 0264    Peb: 7ffdb000  ParentCid: 021c
    DirBase: 06d40060  ObjectTable: e155c878  HandleCount: 403.
    Image: csrss.exe
PROCESS 861b9020  SessionId: 0  Cid: 027c    Peb: 7ffd7000  ParentCid: 021c
    DirBase: 06d40080  ObjectTable: e1534818  HandleCount: 473.
    Image: winlogon.exe
PROCESS 85e7d3d0  SessionId: 0  Cid: 02a8    Peb: 7ffdc000  ParentCid: 027c
    DirBase: 06d400a0  ObjectTable: e14d6918  HandleCount: 270.
    Image: services.exe
PROCESS 85da4880  SessionId: 0  Cid: 02b4    Peb: 7ffdb000  ParentCid: 027c
    DirBase: 06d400c0  ObjectTable: e1735358  HandleCount: 349.
    Image: lsass.exe
PROCESS 85e942e0  SessionId: 0  Cid: 0364    Peb: 7ffd4000  ParentCid: 02a8
    DirBase: 06d400e0  ObjectTable: e1690f00  HandleCount:  25.
    Image: vmacthlp.exe
PROCESS 862e0980  SessionId: 0  Cid: 0374    Peb: 7ffde000  ParentCid: 02a8
    DirBase: 06d40100  ObjectTable: e16959b8  HandleCount: 205.
    Image: svchost.exe
PROCESS 85da8980  SessionId: 0  Cid: 03b8    Peb: 7ffdc000  ParentCid: 02a8
    DirBase: 06d40120  ObjectTable: e17553e8  HandleCount: 245.
    Image: svchost.exe
PROCESS 85fd6b58  SessionId: 0  Cid: 0418    Peb: 7ffdf000  ParentCid: 02a8
    DirBase: 06d40140  ObjectTable: e16dd668  HandleCount: 1167.
    Image: svchost.exe
PROCESS 86058020  SessionId: 0  Cid: 0474    Peb: 7ffdb000  ParentCid: 02a8
    DirBase: 06d40160  ObjectTable: e16d4d28  HandleCount:  59.
    Image: svchost.exe
PROCESS 85da74f0  SessionId: 0  Cid: 04e0    Peb: 7ffde000  ParentCid: 02a8
    DirBase: 06d40180  ObjectTable: e14e5930  HandleCount: 198.
    Image: svchost.exe
PROCESS 85ff7aa8  SessionId: 0  Cid: 05a0    Peb: 7ffda000  ParentCid: 02a8
    DirBase: 06d401c0  ObjectTable: e1604138  HandleCount: 141.
    Image: spoolsv.exe
PROCESS 85ff5ac8  SessionId: 0  Cid: 06a4    Peb: 7ffde000  ParentCid: 0690
    DirBase: 06d40200  ObjectTable: e156ad78  HandleCount: 308.
    Image: explorer.exe
PROCESS 8608d8e0  SessionId: 0  Cid: 0704    Peb: 7ffdf000  ParentCid: 06a4
    DirBase: 06d401a0  ObjectTable: e1aafdc0  HandleCount:  49.
    Image: VMwareTray.exe
PROCESS 8608cda0  SessionId: 0  Cid: 070c    Peb: 7ffde000  ParentCid: 06a4
    DirBase: 06d40220  ObjectTable: e156ccd0  HandleCount: 111.
    Image: VMwareUser.exe
PROCESS 85d9f8b0  SessionId: 0  Cid: 009c    Peb: 7ffdf000  ParentCid: 02a8
    DirBase: 06d40240  ObjectTable: e1d39650  HandleCount: 224.
    Image: vmtoolsd.exe
PROCESS 85e47748  SessionId: 0  Cid: 0138    Peb: 7ffd4000  ParentCid: 02a8
    DirBase: 06d40260  ObjectTable: e17472b8  HandleCount:  99.
    Image: VMUpgradeHelper.exe
PROCESS 862d4770  SessionId: 0  Cid: 0230    Peb: 7ffda000  ParentCid: 0374
    DirBase: 06d402e0  ObjectTable: e1d1d740  HandleCount: 186.
    Image: wmiprvse.exe
PROCESS 85d29d00  SessionId: 0  Cid: 0258    Peb: 7ffd8000  ParentCid: 02a8
    DirBase: 06d40300  ObjectTable: e1d8f538  HandleCount: 102.
    Image: TPAutoConnSvc.exe
PROCESS 8623f4d8  SessionId: 0  Cid: 0498    Peb: 7ffdf000  ParentCid: 02a8
    DirBase: 06d40320  ObjectTable: e1ed28c0  HandleCount: 106.
    Image: alg.exe
PROCESS 85efa3c0  SessionId: 0  Cid: 07c4    Peb: 7ffde000  ParentCid: 0418
    DirBase: 06d40340  ObjectTable: e1d77f68  HandleCount:  28.
    Image: wscntfy.exe
PROCESS 8621b6e8  SessionId: 0  Cid: 05b0    Peb: 7ffd7000  ParentCid: 0258
    DirBase: 06d40280  ObjectTable: e1776278  HandleCount:  72.
    Image: TPAutoConnect.exe
PROCESS 860d3020  SessionId: 0  Cid: 04c0    Peb: 7ffda000  ParentCid: 06a4
    DirBase: 06d402c0  ObjectTable: e14cc678  HandleCount:  30.
    Image: cmd.exe
PROCESS 862f1b10  SessionId: 0  Cid: 0614    Peb: 7ffde000  ParentCid: 0418
    DirBase: 06d402a0  ObjectTable: e105f468  HandleCount: 177.
    Image: wuauclt.exe
PROCESS 85fdfda0  SessionId: 0  Cid: 0684    Peb: 7ffd6000  ParentCid: 0418
    DirBase: 06d401e0  ObjectTable: e1d21288  HandleCount: 134.
    Image: wuauclt.exe

Każdy z elementów powyższej listy opisywany jest strukturą EPROCESS, której kształ zależny jest od konkretnej wersji systemu, a dla badanego wygląda tak:

0: kd> dt nt!_eprocess
  +0x000 Pcb              : _KPROCESS
  +0x06c ProcessLock      : _EX_PUSH_LOCK
  +0x070 CreateTime       : _LARGE_INTEGER
  +0x078 ExitTime         : _LARGE_INTEGER
  +0x080 RundownProtect   : _EX_RUNDOWN_REF
  +0x084 UniqueProcessId  : Ptr32 Void
  +0x088 ActiveProcessLinks : _LIST_ENTRY
  +0x090 QuotaUsage       : [3] Uint4B
  +0x09c QuotaPeak        : [3] Uint4B
  +0x0a8 CommitCharge     : Uint4B
  +0x0ac PeakVirtualSize  : Uint4B
  +0x0b0 VirtualSize      : Uint4B
  +0x0b4 SessionProcessLinks : _LIST_ENTRY
  +0x0bc DebugPort        : Ptr32 Void
  +0x0c0 ExceptionPort    : Ptr32 Void
  +0x0c4 ObjectTable      : Ptr32 _HANDLE_TABLE
  +0x0c8 Token            : _EX_FAST_REF
  +0x0cc WorkingSetLock   : _FAST_MUTEX
  +0x0ec WorkingSetPage   : Uint4B
  +0x0f0 AddressCreationLock : _FAST_MUTEX
  +0x110 HyperSpaceLock   : Uint4B
  +0x114 ForkInProgress   : Ptr32 _ETHREAD
  +0x118 HardwareTrigger  : Uint4B
  +0x11c VadRoot          : Ptr32 Void
  +0x120 VadHint          : Ptr32 Void
  +0x124 CloneRoot        : Ptr32 Void
  +0x128 NumberOfPrivatePages : Uint4B
  +0x12c NumberOfLockedPages : Uint4B
  +0x130 Win32Process     : Ptr32 Void
  +0x134 Job              : Ptr32 _EJOB
  +0x138 SectionObject    : Ptr32 Void
  +0x13c SectionBaseAddress : Ptr32 Void
  +0x140 QuotaBlock       : Ptr32 _EPROCESS_QUOTA_BLOCK
  +0x144 WorkingSetWatch  : Ptr32 _PAGEFAULT_HISTORY
  +0x148 Win32WindowStation : Ptr32 Void
  +0x14c InheritedFromUniqueProcessId : Ptr32 Void
  +0x150 LdtInformation   : Ptr32 Void
  +0x154 VadFreeHint      : Ptr32 Void
  +0x158 VdmObjects       : Ptr32 Void
  +0x15c DeviceMap        : Ptr32 Void
  +0x160 PhysicalVadList  : _LIST_ENTRY
  +0x168 PageDirectoryPte : _HARDWARE_PTE
  +0x168 Filler           : Uint8B
  +0x170 Session          : Ptr32 Void
  +0x174 ImageFileName    : [16] UChar
  +0x184 JobLinks         : _LIST_ENTRY
  +0x18c LockedPagesList  : Ptr32 Void
  +0x190 ThreadListHead   : _LIST_ENTRY
  +0x198 SecurityPort     : Ptr32 Void
  +0x19c PaeTop           : Ptr32 Void
  +0x1a0 ActiveThreads    : Uint4B
  +0x1a4 GrantedAccess    : Uint4B
  +0x1a8 DefaultHardErrorProcessing : Uint4B
  +0x1ac LastThreadExitStatus : Int4B
  +0x1b0 Peb              : Ptr32 _PEB
  +0x1b4 PrefetchTrace    : _EX_FAST_REF
  +0x1b8 ReadOperationCount : _LARGE_INTEGER
  +0x1c0 WriteOperationCount : _LARGE_INTEGER
  +0x1c8 OtherOperationCount : _LARGE_INTEGER
  +0x1d0 ReadTransferCount : _LARGE_INTEGER
  +0x1d8 WriteTransferCount : _LARGE_INTEGER
  +0x1e0 OtherTransferCount : _LARGE_INTEGER
  +0x1e8 CommitChargeLimit : Uint4B
  +0x1ec CommitChargePeak : Uint4B
  +0x1f0 AweInfo          : Ptr32 Void
  +0x1f4 SeAuditProcessCreationInfo : _SE_AUDIT_PROCESS_CREATION_INFO
  +0x1f8 Vm               : _MMSUPPORT
  +0x238 LastFaultCount   : Uint4B
  +0x23c ModifiedPageCount : Uint4B
  +0x240 NumberOfVads     : Uint4B
  +0x244 JobStatus        : Uint4B
  +0x248 Flags            : Uint4B
  +0x248 CreateReported   : Pos 0, 1 Bit
  +0x248 NoDebugInherit   : Pos 1, 1 Bit
  +0x248 ProcessExiting   : Pos 2, 1 Bit
  +0x248 ProcessDelete    : Pos 3, 1 Bit
  +0x248 Wow64SplitPages  : Pos 4, 1 Bit
  +0x248 VmDeleted        : Pos 5, 1 Bit
  +0x248 OutswapEnabled   : Pos 6, 1 Bit
  +0x248 Outswapped       : Pos 7, 1 Bit
  +0x248 ForkFailed       : Pos 8, 1 Bit
  +0x248 HasPhysicalVad   : Pos 9, 1 Bit
  +0x248 AddressSpaceInitialized : Pos 10, 2 Bits
  +0x248 SetTimerResolution : Pos 12, 1 Bit
  +0x248 BreakOnTermination : Pos 13, 1 Bit
  +0x248 SessionCreationUnderway : Pos 14, 1 Bit
  +0x248 WriteWatch       : Pos 15, 1 Bit
  +0x248 ProcessInSession : Pos 16, 1 Bit
  +0x248 OverrideAddressSpace : Pos 17, 1 Bit
  +0x248 HasAddressSpace  : Pos 18, 1 Bit
  +0x248 LaunchPrefetched : Pos 19, 1 Bit
  +0x248 InjectInpageErrors : Pos 20, 1 Bit
  +0x248 VmTopDown        : Pos 21, 1 Bit
  +0x248 Unused3          : Pos 22, 1 Bit
  +0x248 Unused4          : Pos 23, 1 Bit
  +0x248 VdmAllowed       : Pos 24, 1 Bit
  +0x248 Unused           : Pos 25, 5 Bits
  +0x248 Unused1          : Pos 30, 1 Bit
  +0x248 Unused2          : Pos 31, 1 Bit
  +0x24c ExitStatus       : Int4B
  +0x250 NextPageColor    : Uint2B
  +0x252 SubSystemMinorVersion : UChar
  +0x253 SubSystemMajorVersion : UChar
  +0x252 SubSystemVersion : Uint2B
  +0x254 PriorityClass    : UChar
  +0x255 WorkingSetAcquiredUnsafe : UChar
  +0x258 Cookie           : Uint4B

Szczegółowy opis tej struktury można znaleźć w książkach Marka Russinovicha poświęconym wnętrzu systemu Windows, a my dzisiaj przyjrzymy się bliżej kilku jej elementom. Szczególnie zainteresowanym polecam użycie przełącznika -r, ja przez wzgląd na ostatnich już chyba czytelników nie zrobiłem tego :). Najbardziej interesuje nas w tym momencie ActiveProcessLinks, rzućmy na nią okiem:

0: kd> dt nt!_eprocess ActiveProcessLinks.
  +0x088 ActiveProcessLinks  :
     +0x000 Flink               : Ptr32 _LIST_ENTRY
     +0x004 Blink               : Ptr32 _LIST_ENTRY

Oczywiście skorzystaliśmy z polecenia dt (dump type) dla struktury _EPROCESS, tym razem wyspecyfikowaliśmy, że zależy nam na elemencie ActiveProcessLinks, a kropka na końcu to prośba o zrzut dodatkowego poziomu.
Zwróćmy uwagę na przesunięcie elementu ActiveProcessLinks w ramach tej struktury - dla Windows XP Prof SP3 wynosi ono 0x088, a w poprzednim moim wpisie możemy znaleźć jego wartość dla Windows 7 Prof SP1 64-bit i równe ono było 0x188. Zapamiętajmy te wartości, bowiem na pewno jeszcze do nich sięgniemy.

Ukryjmy coś!

Postanowiłem zagiąć parol na procesie lsass.exe i zmodyfikować dwukierunkową listę procesów w taki sposób, żeby ominąć ten właśnie proces. Użyję ponownie polecenia dt, tym razem jednak zrobię zrzut struktury konkretnego elementu (wyróżnienie na liście procesów z początku tego tekstu) :

0: kd> dt nt!_eprocess ActiveProcessLinks. ImageFileName 85da4880
  +0x088 ActiveProcessLinks  :  [ 0x85e94368 - 0x85e7d458 ]
     +0x000 Flink               : 0x85e94368 _LIST_ENTRY [ 0x862e0a08 - 0x85da4908 ]
     +0x004 Blink               : 0x85e7d458 _LIST_ENTRY [ 0x85da4908 - 0x861b90a8 ]
  +0x174 ImageFileName       : [16]  "lsass.exe"

Wyciągnąłem dodatkowo informację o nazwie procesu, dzięki czemu wiemy na pewno o którym procesie mowa.
Jak się można łatwo domyśleć, element Flink wskazuje na kolejny element listy, natomiast Blink - poprzedni. Wystarczy zatem, aby zmodyfikować:
- element Flink poprzedniego elementu z listy i zastąpić obecny wpis (wskazujący na lsass.exe) Flinkiem z lsass.exe;
- element Blink następnego elementu z listy i zastąpić obecny wpis (wskazujący na lsass.exe) Blinkiem z lsass.exe.
W naszym przypadku elementy Blink i Flink wskazują odpowiednio na:

0: kd> dt nt!_eprocess ActiveProcessLinks. ImageFileName 0x85e7d458-0x88
  +0x088 ActiveProcessLinks  :  [ 0x85da4908 - 0x861b90a8 ]
     +0x000 Flink               : 0x85da4908 _LIST_ENTRY [ 0x85e94368 - 0x85e7d458 ]
     +0x004 Blink               : 0x861b90a8 _LIST_ENTRY [ 0x85e7d458 - 0x85e400a8 ]
  +0x174 ImageFileName       : [16]  "services.exe"

oraz

0: kd> dt nt!_eprocess ActiveProcessLinks. ImageFileName 0x85e94368-0x88
  +0x088 ActiveProcessLinks  :  [ 0x862e0a08 - 0x85da4908 ]
     +0x000 Flink               : 0x862e0a08 _LIST_ENTRY [ 0x85da8a08 - 0x85e94368 ]
     +0x004 Blink               : 0x85da4908 _LIST_ENTRY [ 0x85e94368 - 0x85e7d458 ]
  +0x174 ImageFileName       : [16]  "vmacthlp.exe"

Oczywiście musiałem skorzystać z wartości przesunięcia elementu ActiveProcessLinks względem początku struktury, ponieważ powiązanie występuje niejako ‘w środku’ struktury _EPROCESS pomiędzy elementami typu _LIST_ENTRY i takie właśnie adresy występują na tej liście, a nie adresy wskazujące na początek analizowanej struktury.
Wiemy już zatem, co mamy zrobić, więc skorzystamy z polecenia pozwalającego na modyfikację pamięci i wpiszemy odpowiednio:

0: kd> f 0x85e7d458 L4 0x68 0x43 0xe9 0x85
Filled 0x4 bytes

do wypełnienia Blinka naszym Flinkiem

0: kd> f 0x85e94368+0x4 L4 0x58 0xd4 0xe7 0x85
Filled 0x4 bytes

do wypełnienia Flinka+1 (czyli Blinka dla Flinka ;)) naszym Blinkiem. Jasne? :) Jak nie, to przyjrzyjcie się uważnie adresom i pamiętając o tym, że liczby wpisujemy w odwrotnej kolejności, niż je widzimy (0x85e7d458 -> 0x58 0xd4 0xe7 0x85) zauważcie, co jest rzeczywiście wpisywane.
Gotowe :)
No, właściwie moglibyśmy jeszcze zmodyfikować Flink i Blink dla procesu lsass.exe (nikt za nas tego już nie zrobi, a po zakończeniu procesów wskazywanych przez Flink i Blink nasze wskaźniki stają się nieprawidłowe), ale pozostawiam to jako drobne ćwiczenie.

Wznawiamy działanie systemu, sprawdzamy co widzą tasklist oraz pslist:

>tasklist
Nazwa obrazu                 PID
========================= ======
System Idle Process            0
System                         4
smss.exe                     540
csrss.exe                    612
winlogon.exe                 636
services.exe                 680
vmacthlp.exe                 868
svchost.exe                  884
svchost.exe                  952
svchost.exe                 1048
svchost.exe                 1140
svchost.exe                 1248
spoolsv.exe                 1440
explorer.exe                1700
VMwareTray.exe              1796
VMwareUser.exe              1804
vmtoolsd.exe                 156
VMUpgradeHelper.exe          312
wmiprvse.exe                 560
TPAutoConnSvc.exe            600
alg.exe                     1176
wscntfy.exe                 1988
TPAutoConnect.exe           1456
cmd.exe                     1216
wuauclt.exe                 1556
wuauclt.exe                 1668
tasklist.exe                1788

>PsList.exe
pslist v1.29 - Sysinternals PsList
Copyright (C) 2000-2009 Mark Russinovich
Sysinternals
Process information for []:

Name                Pid
Idle                  0
System                4
smss                540
csrss               612
winlogon            636
services            680
vmacthlp            868
svchost             884
svchost             952
svchost            1048
svchost            1140
svchost            1248
spoolsv            1440
explorer           1700
VMwareTray         1796
VMwareUser         1804
vmtoolsd            156
VMUpgradeHelper     312
wmiprvse            560
TPAutoConnSvc       600
alg                1176
wscntfy            1988
TPAutoConnect      1456
cmd                1216
wuauclt            1556
wuauclt            1668
wpabaln            1932
PsList              764

Do tej listy dorzucamy jeszcze zrzut listy procesów z trybu jądra:

0: kd> !process 0 0
**** NT ACTIVE PROCESS DUMP ****
PROCESS 863c4830  SessionId: none  Cid: 0004    Peb: 00000000  ParentCid: 0000
    DirBase: 06d40020  ObjectTable: e1002e40  HandleCount: 254.
    Image: System
PROCESS 85ff4be8  SessionId: none  Cid: 021c    Peb: 7ffd5000  ParentCid: 0004
    DirBase: 06d40040  ObjectTable: e101ddf8  HandleCount:  19.
    Image: smss.exe
PROCESS 85e40020  SessionId: 0  Cid: 0264    Peb: 7ffdb000  ParentCid: 021c
    DirBase: 06d40060  ObjectTable: e155c878  HandleCount: 367.
    Image: csrss.exe
PROCESS 861b9020  SessionId: 0  Cid: 027c    Peb: 7ffd7000  ParentCid: 021c
    DirBase: 06d40080  ObjectTable: e1534818  HandleCount: 466.
    Image: winlogon.exe
PROCESS 85e7d3d0  SessionId: 0  Cid: 02a8    Peb: 7ffdc000  ParentCid: 027c
    DirBase: 06d400a0  ObjectTable: e14d6918  HandleCount: 263.
    Image: services.exe
PROCESS 85e942e0  SessionId: 0  Cid: 0364    Peb: 7ffd4000  ParentCid: 02a8
    DirBase: 06d400e0  ObjectTable: e1690f00  HandleCount:  25.
    Image: vmacthlp.exe
PROCESS 862e0980  SessionId: 0  Cid: 0374    Peb: 7ffde000  ParentCid: 02a8
    DirBase: 06d40100  ObjectTable: e16959b8  HandleCount: 203.
    Image: svchost.exe
PROCESS 85da8980  SessionId: 0  Cid: 03b8    Peb: 7ffdc000  ParentCid: 02a8
    DirBase: 06d40120  ObjectTable: e17553e8  HandleCount: 253.
    Image: svchost.exe
PROCESS 85fd6b58  SessionId: 0  Cid: 0418    Peb: 7ffdf000  ParentCid: 02a8
    DirBase: 06d40140  ObjectTable: e16dd668  HandleCount: 1157.
    Image: svchost.exe
PROCESS 86058020  SessionId: 0  Cid: 0474    Peb: 7ffdb000  ParentCid: 02a8
    DirBase: 06d40160  ObjectTable: e16d4d28  HandleCount:  59.
    Image: svchost.exe
PROCESS 85da74f0  SessionId: 0  Cid: 04e0    Peb: 7ffde000  ParentCid: 02a8
    DirBase: 06d40180  ObjectTable: e14e5930  HandleCount: 197.
    Image: svchost.exe
PROCESS 85ff7aa8  SessionId: 0  Cid: 05a0    Peb: 7ffda000  ParentCid: 02a8
    DirBase: 06d401c0  ObjectTable: e1604138  HandleCount: 140.
    Image: spoolsv.exe
PROCESS 85ff5ac8  SessionId: 0  Cid: 06a4    Peb: 7ffde000  ParentCid: 0690
    DirBase: 06d40200  ObjectTable: e156ad78  HandleCount: 304.
    Image: explorer.exe
PROCESS 8608d8e0  SessionId: 0  Cid: 0704    Peb: 7ffdf000  ParentCid: 06a4
    DirBase: 06d401a0  ObjectTable: e1aafdc0  HandleCount:  49.
    Image: VMwareTray.exe
PROCESS 8608cda0  SessionId: 0  Cid: 070c    Peb: 7ffde000  ParentCid: 06a4
    DirBase: 06d40220  ObjectTable: e156ccd0  HandleCount: 118.
    Image: VMwareUser.exe
PROCESS 85d9f8b0  SessionId: 0  Cid: 009c    Peb: 7ffdf000  ParentCid: 02a8
    DirBase: 06d40240  ObjectTable: e1d39650  HandleCount: 228.
    Image: vmtoolsd.exe
PROCESS 85e47748  SessionId: 0  Cid: 0138    Peb: 7ffd4000  ParentCid: 02a8
    DirBase: 06d40260  ObjectTable: e17472b8  HandleCount:  98.
    Image: VMUpgradeHelper.exe
PROCESS 85d29d00  SessionId: 0  Cid: 0258    Peb: 7ffd8000  ParentCid: 02a8
    DirBase: 06d40300  ObjectTable: e1d8f538  HandleCount: 102.
    Image: TPAutoConnSvc.exe
PROCESS 8623f4d8  SessionId: 0  Cid: 0498    Peb: 7ffdf000  ParentCid: 02a8
    DirBase: 06d40320  ObjectTable: e1ed28c0  HandleCount: 107.
    Image: alg.exe
PROCESS 85efa3c0  SessionId: 0  Cid: 07c4    Peb: 7ffde000  ParentCid: 0418
    DirBase: 06d40340  ObjectTable: e1d77f68  HandleCount:  28.
    Image: wscntfy.exe
PROCESS 8621b6e8  SessionId: 0  Cid: 05b0    Peb: 7ffd7000  ParentCid: 0258
    DirBase: 06d40280  ObjectTable: e1776278  HandleCount:  72.
    Image: TPAutoConnect.exe
PROCESS 860d3020  SessionId: 0  Cid: 04c0    Peb: 7ffda000  ParentCid: 06a4
    DirBase: 06d402c0  ObjectTable: e14cc678  HandleCount:  32.
    Image: cmd.exe
PROCESS 85fdfda0  SessionId: 0  Cid: 0684    Peb: 7ffd6000  ParentCid: 0418
    DirBase: 06d401e0  ObjectTable: e1d21288  HandleCount: 131.
    Image: wuauclt.exe
PROCESS 85dc4da0  SessionId: 0  Cid: 078c    Peb: 7ffdf000  ParentCid: 027c
    DirBase: 06d40360  ObjectTable: e10ac3a0  HandleCount:  58.
    Image: wpabaln.exe

...i oczywiście zauważamy, że brakuje procesu lsass.exe.

ZwQuerySystemInformation

W komentarzach do poprzedniego wpisu, gdy wszystko już było jasne spytałem o to, gdzie szukać naszego procesu, skoro ‘tradycyjne metody’ (jak to ujął Grzegorz) oparte o funkcję ZwQuerySystemInformation przeczesują listę ActiveProcessLinks, będąć oczywiście ślepe na lsass.exe. Padło kilka propozycji, ja jednak postaram się zademonstrować jedną z rzadziej omawianych, a przy tym o tyle ciekawą, że nie wymaga dostępu do systemu w trybie jądra.

CSRSS to the rescue!

We wspomnianej wcześniej książce o internalsach windowsów, w rozdziale poświęconym procesom oraz ich tworzeniu znajduje się część dotycząca podsystemu Win32 (o którym już wspominałem we wpisie poświęconym MAX_PATH). W wydaniu poświęconemu Windows 2000 (ale także w kolejnych) znajdziemy dosyć zdawkowy punkt (str. 282 wydania polskiego):

"10. Blok nowego procesu umieszczany jest na liście procesów podsystemu Win32".

Aha! Zatem csrss jest cwany, niezależny i ma własną listę procesów Win32 (posixowych na niej zatem nie ma). OK, tylko jak się do niej dobrać?
Na rewelacyjnym forum sysinternalsowym jakiś czas temu znalazł się wątek, gdzie przedstawione zostało narzędzie CsrWalker, które dobiera się do procesu csrss i jego wewnętrznych struktur, właśnie w celu wyciągnięcia informacji o ukrytych procesach.
W oparciu o przedstawioną tam metodę spróbuję przedstawić krok po kroku co i jak należy zrobić, aby samemu powtórzyć tę metodę, korzystając wyłącznie z dwóch debuggerów - jednego pracującego w trybie jądra, a drugiego w trybie użytkownika, albowiem jest to zalecany przez Microsoft sposób debuggowania procesu csrss.

Gotuj się!

Będziemy potrzebowali:

- Windows XP zainstalowanych w ramach maszyny wirtualnej VMware Player;
- Windbg na maszynie hoście (u mnie jest to Win7 Ult. 64-bit) oraz ntsd na gościu;
- Narzędzia Virtual KD, które baaaardzo usprawnia debugowanie w trybie jądra maszyny wirtualnej - działa równie dobrze zarówno z Windows XP jak i Windows 7 64-bit, a dostępne jest tu: http://virtualkd.sysprogs.org/ (przy okazji, jak ktoś zna odpowiednie narzędzie dla Virtual PC to chętnie się zapoznam!)
- Połączenia z internetem do ściągania publicznych symboli bibliotek systemowych

i to chyba na tyle :)

Po 'zainstalowaniu' Virtual KD (czyli uruchomieniu target/vminstall.exe na systemie gościu oraz uruchomieniu na hoście vmmon64.exe (vmmon.exe)) bez większego problemu możemy rozpocząć sprawne debugowanie naszej maszyny wirtualnej - Virtual KD doda za nas odpowiedni wpis w boot.ini oraz wystawi odpowiedni pipe do komunikacji na \\.\pipe\kd_NAZWA_MASZYNY.
W następnym kroku włączamy w rejestrze debugowanie procesu csrss, albo poprzez użycie narzędzia gflags:

>gflags /r +20000

albo modyfikację klucza:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager
i zmianie wartości GlobalFlag typu DWORD na 0x00020000

Restart, uruchamiamy system pod kontrolą WinDbg w trybie jądra, po czym uruchamiamy w działającym już systemie debugger w trybie użytkownika:

>ntsd --

który automatycznie zestawia nam debugowanie procesu csrss i output przerzuca do WinDbg działającego na hoście.
Zakładam, że wszystkie powyższe kroki zakończyły się sukcesem, więc mamy działające dwa debuggery (pracujący w tle na gościu ntsd oraz WinDbg na hoście). U mnie dla przykładu ostatni krok zaskutkował następującym wpisem w WinDbg:

Microsoft (R) Windows Debugger Version 6.11.0001.404 X86
Copyright (c) Microsoft Corporation. All rights reserved.
*** wait with pending attach
Network paths are disallowed, symbol server is not available.
Set your symbol path to a symbol tree on the local machine.
Network paths are disallowed, symbol server is not available.
Set your symbol path to a symbol tree on the local machine.
Symbol search path is: *** Invalid ***
****************************************************************************
* Symbol loading may be unreliable without a symbol search path.           *
* Use .symfix to have the debugger choose a symbol path.                   *
* After setting your symbol path, use .reload to refresh symbol locations. *
****************************************************************************
Executable search path is:
ModLoad: 4a680000 4a685000   \??\C:\WINDOWS\system32\csrss.exe
ModLoad: 7c900000 7c9b1000   C:\WINDOWS\system32\ntdll.dll
ModLoad: 75b10000 75b1b000   C:\WINDOWS\system32\CSRSRV.dll
ModLoad: 75b20000 75b30000   C:\WINDOWS\system32\basesrv.dll
ModLoad: 75b30000 75b7b000   C:\WINDOWS\system32\winsrv.dll
ModLoad: 77f10000 77f59000   C:\WINDOWS\system32\GDI32.dll
ModLoad: 7c800000 7c8fd000   C:\WINDOWS\system32\KERNEL32.dll
ModLoad: 7e360000 7e3f1000   C:\WINDOWS\system32\USER32.dll
ModLoad: 7e690000 7e740000   C:\WINDOWS\system32\sxs.dll
ModLoad: 77dc0000 77e6c000   C:\WINDOWS\system32\ADVAPI32.dll
ModLoad: 77e70000 77f02000   C:\WINDOWS\system32\RPCRT4.dll
ModLoad: 77fe0000 77ff1000   C:\WINDOWS\system32\Secur32.dll

Nie zwlekając na nic, sprawdzamy PID csrss (w zrzucie procesów patrzymy na Cid) i po wskoczeniu do trybu jądra (ctrl+break w WinDbg) dajemy sygnał, że chcemy przeskoczyć do trybu użytkownika.

PROCESS 85e40020  SessionId: 0  Cid: 0264    Peb: 7ffdb000  ParentCid: 021c
    DirBase: 06d40060  ObjectTable: e155c878  HandleCount: 367.
    Image: csrss.exe
0: kd> !bpid 0x0264
Finding winlogon.exe (0)...
Waiting for winlogon.exe to break.  This can take a couple of minutes...
Break instruction exception - code 80000003 (first chance)
Stepping to g_BreakinProcessId check...
Break into process 264 set.  The next break should be in the desired process.
(264.6b4): Break instruction exception - code 80000003 (first chance)
eax=7ffae000 ebx=00000000 ecx=0015d7dc edx=0068fa98 esi=0015bde4 edi=00000000
eip=7c90120e esp=0137ffb8 ebp=0137ffec iopl=3         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=0038  gs=0000             efl=00003202
*** ERROR: Symbol file could not be found.  Defaulted to export symbols for C:\WINDOWS\system32\ntdll.dll -
ntdll!DbgBreakPoint:
7c90120e cc              int     3

Jesteśmy w csrss, czeka na nas ładny prompt z Input>

W tym miejscu musimy się zatrzymać i zastanowić co dalej.

CSRSS internals

Lista procesów w ramach csrss przechowywana jest w strukturze opisywanej przez _CSR_PROCESS. Jak się okazuje, w publicznych symbolach dla csrsrv.dll oraz csrss.exe dla Windows XP nie możemy znaleźć opisu tej struktury, jednak dla Windows 7 a i owszem :) Śpieszę zatem z zestawieniem sesji debuggera z lokalnym systemem i czym prędzej wykonuję zrzut:

lkd> dt csrss!_CSR_PROCESS -r
  +0x000 ClientId         : _CLIENT_ID
     +0x000 UniqueProcess    : Ptr64 Void
     +0x008 UniqueThread     : Ptr64 Void
  +0x010 ListLink         : _LIST_ENTRY
     +0x000 Flink            : Ptr64 _LIST_ENTRY
        +0x000 Flink            : Ptr64 _LIST_ENTRY
        +0x008 Blink            : Ptr64 _LIST_ENTRY
     +0x008 Blink            : Ptr64 _LIST_ENTRY
        +0x000 Flink            : Ptr64 _LIST_ENTRY
        +0x008 Blink            : Ptr64 _LIST_ENTRY
  +0x020 ThreadList       : _LIST_ENTRY
     +0x000 Flink            : Ptr64 _LIST_ENTRY
        +0x000 Flink            : Ptr64 _LIST_ENTRY
        +0x008 Blink            : Ptr64 _LIST_ENTRY
     +0x008 Blink            : Ptr64 _LIST_ENTRY
        +0x000 Flink            : Ptr64 _LIST_ENTRY
        +0x008 Blink            : Ptr64 _LIST_ENTRY
  +0x030 NtSession        : Ptr64 _CSR_NT_SESSION
     +0x000 SessionLink      : _LIST_ENTRY
        +0x000 Flink            : Ptr64 _LIST_ENTRY
        +0x008 Blink            : Ptr64 _LIST_ENTRY
     +0x010 SessionId        : Uint4B
     +0x014 ReferenceCount   : Uint4B
     +0x018 RootDirectory    : _STRING
        +0x000 Length           : Uint2B
        +0x002 MaximumLength    : Uint2B
        +0x008 Buffer           : Ptr64 Char
  +0x038 ClientPort       : Ptr64 Void
  +0x040 ClientViewBase   : Ptr64 Char
  +0x048 ClientViewBounds : Ptr64 Char
  +0x050 ProcessHandle    : Ptr64 Void
  +0x058 SequenceNumber   : Uint4B
  +0x05c Flags            : Uint4B
  +0x060 DebugFlags       : Uint4B
  +0x064 ReferenceCount   : Uint4B
  +0x068 ProcessGroupId   : Uint4B
  +0x06c ProcessGroupSequence : Uint4B
  +0x070 LastMessageSequence : Uint4B
  +0x074 NumOutstandingMessages : Uint4B
  +0x078 ShutdownLevel    : Uint4B
  +0x07c ShutdownFlags    : Uint4B
  +0x080 Luid             : _LUID
     +0x000 LowPart          : Uint4B
     +0x004 HighPart         : Int4B
  +0x088 ServerDllPerProcessData : [1] Ptr64 Void

Jak widać, w Windows 7 struktura _CSR_PROCESS zawiera na początku pole zawierające element typu _CLIENT_ID, które z kolei zawiera dwa elementy: UniqueProcess, czyli PID, a tuż za nim UniqueThread, czyli TID. Oczywiście jesteśmy optymistami i zakładamy, że struktura _CSR_PROCESS dla Windows XP nie różni się aż tak zasadniczo i PID procesu również znajduje się na początku.
Podobnie, jak miało to miejsce w ramach struktury _EPROCESS, tu również mamy do czynienia z dwukierunkową listą powiązanych ze sobą procesów i powiązanie również ma miejsce w środku struktury. Odpowiada za nie pole ListLink, które umiejscowione jest tuż za identyfikatorem procesu i wątku.

Dobrze, wiemy już zatem jak się dobrać do listy procesów dla danej struktury _CSR_PROCESS, jednak w przeciwieństwie do struktury _EPROCESS, do której mieliśmy szybki dostęp po wylistowaniu procesów (jej adres dla danego procesu był dostępny wprost w zrzucie), tu nie mamy tak komfortowej sytuacji i musimy nieco pogrzebać.
We wspomnianym wątku na forum sysinternalsów, autor zaproponował przyjrzeć się kodowi eksportowanej funkcji CsrLockProcessByClientId z biblioteki csrsrv.dll
Dla naszych Windows XP mamy coś takiego:

EBP+0x8      0x75B15304
EBP+0xC      0x75B152E7, 0x75B152F6, 0x75B15316, 0x75B15320
SYM:_CsrProcessStructureLock    0x75B152DB
SYM:_CsrRootProcess    0x75B152ED
; Section: .text
; Number of Parameters: 2
; Prologue Size: 8 (0x08) bytes
; Does not use SEH
;= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
; EXP: CsrLockProcessByClientId (18)
; SYM:_CsrLockProcessByClientId@8
0x75B152D3: 8BFF                   MOV         EDI,EDI         
0x75B152D5: 55                     PUSH        EBP             
0x75B152D6: 8BEC                   MOV         EBP,ESP         
0x75B152D8: 53                     PUSH        EBX             
0x75B152D9: 56                     PUSH        ESI             
0x75B152DA: 57                     PUSH        EDI             
; end of prologue
0x75B152DB: BFA089B175             MOV         EDI,_CsrProcessStructureLock; (0x75B189A0); .data:99A9k9
0x75B152E0: 57                     PUSH        EDI             
0x75B152E1: FF151811B175           CALL        DWORD PTR [NTDLL.DLL!RtlEnterCriticalSection]; (0x75B11118)
0x75B152E7: 8B550C                 MOV         EDX,DWORD PTR [EBP+0xC]
0x75B152EA: 832200                 AND         DWORD PTR [EDX],0x0
0x75B152ED: 8B351C89B175           MOV         ESI,DWORD PTR [_CsrRootProcess]; (0x75B1891C); .data:0xDE 0x3F 0xE5 0x3F
0x75B152F3: 83C608                 ADD         ESI,0x8         
0x75B152F6: C7450C010000C0         MOV         DWORD PTR [EBP+0xC],STATUS_UNSUCCESSFUL; EBP+0xC ERR:(0xC0000001)
0x75B152FD: 8BCE                   MOV         ECX,ESI         
0x75B152FF: 8D41F8                 LEA         EAX,[ECX-0x8]    ; <==0x75B1530D(*+0xE)
0x75B15302: 8B18                   MOV         EBX,DWORD PTR [EAX]
0x75B15304: 3B5D08                 CMP         EBX,DWORD PTR [EBP+0x8]
0x75B15307: 7417                   JE          0x75B15320       ; (*+0x19)
0x75B15309: 8B09                   MOV         ECX,DWORD PTR [ECX]
0x75B1530B: 3BCE                   CMP         ECX,ESI         
0x75B1530D: 75F0                   JNE         0x75B152FF       ; (*-0xE)
0x75B1530F: 57                     PUSH        EDI             
0x75B15310: FF151011B175           CALL        DWORD PTR [NTDLL.DLL!RtlLeaveCriticalSection]; (0x75B11110)
0x75B15316: 8B450C                 MOV         EAX,DWORD PTR [EBP+0xC]; <==0x75B15329(*+0x13)
0x75B15319: 5F                     POP         EDI             
0x75B1531A: 5E                     POP         ESI             
0x75B1531B: 5B                     POP         EBX             
0x75B1531C: 5D                     POP         EBP             
0x75B1531D: C20800                 RET         0x8             
;                                                                               
0x75B15320: 83650C00               AND         DWORD PTR [EBP+0xC],0x0; <==0x75B15307(*-0x19)
0x75B15324: FF4048                 INC         DWORD PTR [EAX+0x48]
0x75B15327: 8902                   MOV         DWORD PTR [EDX],EAX
0x75B15329: EBEB                   JMP         0x75B15316       ; (*-0x13)
0x75B1532B: CC                     INT        
0x75B1532C: CC                     INT        
0x75B1532D: CC                     INT        
0x75B1532E: CC                     INT        
0x75B1532F: CC                     INT        

przy czym najciekawszy fragment dotyczy linii

0x75B152ED: 8B351C89B175           MOV         ESI,DWORD PTR [_CsrRootProcess]; (0x75B1891C); .data:0xDE 0x3F 0xE5 0x3F

gdzie do rejestru ESI trafia adres _CsrRootProcess, którego możemy się już uczepić w dalszych poszukiwaniach.

Odpowiedni kod dla Windows 7 będzie wyglądał mniej więcej tak:

;********************************************************************************
; CsrLockProcessByClientId (0x000007FF710968BC)
; FunctionStart: 0x000007FF710968BC
; FunctionEnd: 0x000007FF71096946
; Version: 0x01
; Flags: 0x00
; Size Of Prologue: 0x19
; Frame Register: 0x00
; Frame Offset: 0x00
;    Export Symbol: CsrLockProcessByClientId
;    Debug Symbol:  CsrLockProcessByClientId
0x000007FF710968BC: 488BC4                          MOV     RAX,RSP
0x000007FF710968BF: 48895808                        MOV     QWORD PTR [RAX+0x08],RBX
0x000007FF710968C3: 48896810                        MOV     QWORD PTR [RAX+0x10],RBP
0x000007FF710968C7: 48897018                        MOV     QWORD PTR [RAX+0x18],RSI
0x000007FF710968CB: 48897820                        MOV     QWORD PTR [RAX+0x20],RDI
0x000007FF710968CF: 4154                            PUSH    R12
0x000007FF710968D1: 4883EC20                        SUB     RSP,0x20
; End of prologue.
0x000007FF710968D5: 488B2DC47E0000                  MOV     RBP,QWORD PTR [CsrRootProcess] ; (0x000007FF7109E7A0)
0x000007FF710968DC: 48832200                        AND     QWORD PTR [RDX],0x00
0x000007FF710968E0: 4C8BE1                          MOV     R12,RCX
0x000007FF710968E3: 4883C510                        ADD     RBP,0x10
0x000007FF710968E7: 488D0D927F0000                  LEA     RCX,QWORD PTR [CsrProcessStructureLock] ; (0x000007FF7109E880)
0x000007FF710968EE: 488BF2                          MOV     RSI,RDX
0x000007FF710968F1: 488BDD                          MOV     RBX,RBP
0x000007FF710968F4: BF010000C0                      MOV     EDI,0xC0000001
0x000007FF710968F9: FF15E9A8FFFF                    CALL    QWORD PTR [__imp_RtlEnterCriticalSection] ; (0x000007FF710911E8)
0x000007FF710968FF: 488D43F0                        LEA     RAX,QWORD PTR [RBX-0x10]
0x000007FF71096903: 4C3920                          CMP     QWORD PTR [RAX],R12
0x000007FF71096906: 7417                            JE      0x000007FF7109691F
0x000007FF71096908: 488B1B                          MOV     RBX,QWORD PTR [RBX]
0x000007FF7109690B: 483BDD                          CMP     RBX,RBP
0x000007FF7109690E: 75EF                            JNE     0x000007FF710968FF
0x000007FF71096910: 488D0D697F0000                  LEA     RCX,QWORD PTR [CsrProcessStructureLock] ; (0x000007FF7109E880)
0x000007FF71096917: FF15E3A8FFFF                    CALL    QWORD PTR [__imp_RtlLeaveCriticalSection] ; (0x000007FF71091200)
0x000007FF7109691D: EB0A                            JMP     0x000007FF71096929
;
0x000007FF7109691F: 33FF                            XOR     EDI,EDI
0x000007FF71096921: F083406401                      LOCK ADD  DWORD PTR [RAX+0x64],0x01
0x000007FF71096926: 488906                          MOV     QWORD PTR [RSI],RAX
0x000007FF71096929: 488B5C2430                      MOV     RBX,QWORD PTR [RSP+0x30]
0x000007FF7109692E: 488B6C2438                      MOV     RBP,QWORD PTR [RSP+0x38]
0x000007FF71096933: 488B742440                      MOV     RSI,QWORD PTR [RSP+0x40]
0x000007FF71096938: 8BC7                            MOV     EAX,EDI
0x000007FF7109693A: 488B7C2448                      MOV     RDI,QWORD PTR [RSP+0x48]
0x000007FF7109693F: 4883C420                        ADD     RSP,0x20
0x000007FF71096943: 415C                            POP     R12
0x000007FF71096945: C3                              RET    
;
i odpowiednia linijka to:
0x000007FF710968D5: 488B2DC47E0000                  MOV     RBP,QWORD PTR [CsrRootProcess] ; (0x000007FF7109E7A0)

Wyposażeni w taką wiedzę możemy powrócić do naszego debuggera i spróbować sięgnąć po to, czego szukamy.

1...2...3...szukam!

Ustawiamy pułapkę na omawianej funkcji:

0:011> bp csrsrv!CsrLockProcessByClientId

po czym wznawiamy debugger i czekamy, aż csrss wróci do nas. Po kilku chwilach jesteśmy ponownie w debugerze trybu użytkownika i możemy krok po kroku przejechać do miejsca, które nas interesuje:

Breakpoint 0 hit
eax=0119f748 ebx=7c90d7e0 ecx=0119f6e4 edx=7c90e4f4 esi=0119f784 edi=00000000
eip=75b152d3 esp=0119f6f4 ebp=0119f75c iopl=3         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00003246
CSRSRV!CsrLockProcessByClientId:
75b152d3 8bff            mov     edi,edi
0:009> t
t
eax=0119f748 ebx=7c90d7e0 ecx=0119f6e4 edx=7c90e4f4 esi=0119f784 edi=00000000
eip=75b152d5 esp=0119f6f4 ebp=0119f75c iopl=3         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00003246
CSRSRV!CsrLockProcessByClientId+0x2:
75b152d5 55              push    ebp
0:009> t
t
eax=0119f748 ebx=7c90d7e0 ecx=0119f6e4 edx=7c90e4f4 esi=0119f784 edi=00000000
eip=75b152d6 esp=0119f6f0 ebp=0119f75c iopl=3         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00003246
CSRSRV!CsrLockProcessByClientId+0x3:
75b152d6 8bec            mov     ebp,esp
0:009> t
t
eax=0119f748 ebx=7c90d7e0 ecx=0119f6e4 edx=7c90e4f4 esi=0119f784 edi=00000000
eip=75b152d8 esp=0119f6f0 ebp=0119f6f0 iopl=3         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00003246
CSRSRV!CsrLockProcessByClientId+0x5:
75b152d8 53              push    ebx
0:009> t
t
eax=0119f748 ebx=7c90d7e0 ecx=0119f6e4 edx=7c90e4f4 esi=0119f784 edi=00000000
eip=75b152d9 esp=0119f6ec ebp=0119f6f0 iopl=3         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00003246
CSRSRV!CsrLockProcessByClientId+0x6:
75b152d9 56              push    esi
0:009> t
t
eax=0119f748 ebx=7c90d7e0 ecx=0119f6e4 edx=7c90e4f4 esi=0119f784 edi=00000000
eip=75b152da esp=0119f6e8 ebp=0119f6f0 iopl=3         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00003246
CSRSRV!CsrLockProcessByClientId+0x7:
75b152da 57              push    edi
0:009> t
t
eax=0119f748 ebx=7c90d7e0 ecx=0119f6e4 edx=7c90e4f4 esi=0119f784 edi=00000000
eip=75b152db esp=0119f6e4 ebp=0119f6f0 iopl=3         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00003246
CSRSRV!CsrLockProcessByClientId+0x8:
75b152db bfa089b175      mov     edi,offset CSRSRV!CsrMoveSatisfiedWait+0x2414 (75b189a0)
0:009> t
t
eax=0119f748 ebx=7c90d7e0 ecx=0119f6e4 edx=7c90e4f4 esi=0119f784 edi=75b189a0
eip=75b152e0 esp=0119f6e4 ebp=0119f6f0 iopl=3         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00003246
CSRSRV!CsrLockProcessByClientId+0xd:
75b152e0 57              push    edi
0:009> t
t
eax=0119f748 ebx=7c90d7e0 ecx=0119f6e4 edx=7c90e4f4 esi=0119f784 edi=75b189a0
eip=75b152e1 esp=0119f6e0 ebp=0119f6f0 iopl=3         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00003246
CSRSRV!CsrLockProcessByClientId+0xe:
75b152e1 ff151811b175    call    dword ptr [CSRSRV+0x1118 (75b11118)] ds:0023:75b11118={ntdll!RtlEnterCriticalSection (7c901000)}
0:009> p
p
eax=00000000 ebx=7c90d7e0 ecx=7ffd4000 edx=75b189a0 esi=0119f784 edi=75b189a0
eip=75b152e7 esp=0119f6e4 ebp=0119f6f0 iopl=3         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00003246
CSRSRV!CsrLockProcessByClientId+0x14:
75b152e7 8b550c          mov     edx,dword ptr [ebp+0Ch] ss:0023:0119f6fc=0119f748
0:009> t
t
eax=00000000 ebx=7c90d7e0 ecx=7ffd4000 edx=0119f748 esi=0119f784 edi=75b189a0
eip=75b152ea esp=0119f6e4 ebp=0119f6f0 iopl=3         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00003246
CSRSRV!CsrLockProcessByClientId+0x17:
75b152ea 832200          and     dword ptr [edx],0    ds:0023:0119f748=00540000
0:009> t
t
eax=00000000 ebx=7c90d7e0 ecx=7ffd4000 edx=0119f748 esi=0119f784 edi=75b189a0
eip=75b152ed esp=0119f6e4 ebp=0119f6f0 iopl=3         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00003246
CSRSRV!CsrLockProcessByClientId+0x1a:
75b152ed 8b351c89b175    mov     esi,dword ptr [CSRSRV!CsrMoveSatisfiedWait+0x2390 (75b1891c)] ds:0023:75b1891c=00162810
0:009> t
t
eax=00000000 ebx=7c90d7e0 ecx=7ffd4000 edx=0119f748 esi=00162810 edi=75b189a0
eip=75b152f3 esp=0119f6e4 ebp=0119f6f0 iopl=3         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00003246
CSRSRV!CsrLockProcessByClientId+0x20:
75b152f3 83c608          add     esi,8

I gotowe! W rejestrze ESI mamy adres interesującej nas struktury, więc nie pozostaje nam nic innego, jak zrobić kilka zrzutów.

0:009> dd @esi
dd @esi
00162810  00000264 00000268 001646b8 00170840
00162820  001639e0 00173528 00000000 00000000
00162830  00000000 00000000 00000000 00000000
00162840  ffffffff 00000005 00000000 00000000
00162850  00000000 00000000 0000000c 00000000
00162860  00000000 00000000 0000000b 00000000
00162870  00000000 00000000 00000000 00000000
00162880  00000000 00163ab8 00000000 00000000

Już pierwszy zrzut jest bardzo obiecujący. Gołym okiem widać, że pierwszy element to PID csrss. Zakasajmy zatem rękawy i jedźmy z tym koksem :)
Zrzucamy pid procesu oraz wskaźnik na kolejny element listy procesów.

0:009> dd 00162810 l1; dd 00162810+8 l1
dd 00162810 l1; dd 00162810+8 l1
00162810  00000264
00162818  001646b8

Tym razem oraz w następnych zrzutach musimy przesunąć się o 8 bajtów wstecz, aby uzyskać PID procesu.

0:009> dd 001646b8-8 l1; dd 001646b8 l1
dd 001646b8-8 l1; dd 001646b8 l1
001646b0  0000027c
001646b8  0017ddb0
0:009> dd 0017ddb0-8 l1; dd 0017ddb0 l1
dd 0017ddb0-8 l1; dd 0017ddb0 l1
0017dda8  000002a8
0017ddb0  0016ab78

Przed kolejnym zrzutem chwila napięcia...

0:009> dd 0016ab78-8 l1; dd 0016ab78 l1
dd 0016ab78-8 l1; dd 0016ab78 l1
0016ab70  000002b4
0016ab78  0017dc38

…i wszystko jasne! Dla testu jeszcze kilka dalszych zrzutów

0:009> dd 0017dc38-8 l1; dd 0017dc38 l1
dd 0017dc38-8 l1; dd 0017dc38 l1
0017dc30  00000364
0017dc38  0016a208
0:009> dd 0016a208-8 l1; dd 0016a208 l1
dd 0016a208-8 l1; dd 0016a208 l1
0016a200  00000374
0016a208  00173bf8

Jak widać, kolejne PIDy procesów na liście _CSR_PROCESS to:
264, 27c, 2a8, 2b4, 364, 374...
Jeśli porównamy to z oryginalną listą procesów (przed modyfikacją):

PROCESS 863c4830  SessionId: none  Cid: 0004    Peb: 00000000  ParentCid: 0000
    DirBase: 06d40020  ObjectTable: e1002e40  HandleCount: 249.
    Image: System
PROCESS 85ff4be8  SessionId: none  Cid: 021c    Peb: 7ffd5000  ParentCid: 0004
    DirBase: 06d40040  ObjectTable: e101ddf8  HandleCount:  19.
    Image: smss.exe
PROCESS 85e40020  SessionId: 0  Cid: 0264    Peb: 7ffdb000  ParentCid: 021c
    DirBase: 06d40060  ObjectTable: e155c878  HandleCount: 403.
    Image: csrss.exe
PROCESS 861b9020  SessionId: 0  Cid: 027c    Peb: 7ffd7000  ParentCid: 021c
    DirBase: 06d40080  ObjectTable: e1534818  HandleCount: 473.
    Image: winlogon.exe
PROCESS 85e7d3d0  SessionId: 0  Cid: 02a8    Peb: 7ffdc000  ParentCid: 027c
    DirBase: 06d400a0  ObjectTable: e14d6918  HandleCount: 270.
    Image: services.exe
PROCESS 85da4880  SessionId: 0  Cid: 02b4    Peb: 7ffdb000  ParentCid: 027c
    DirBase: 06d400c0  ObjectTable: e1735358  HandleCount: 349.
    Image: lsass.exe
PROCESS 85e942e0  SessionId: 0  Cid: 0364    Peb: 7ffd4000  ParentCid: 02a8
    DirBase: 06d400e0  ObjectTable: e1690f00  HandleCount:  25.
    Image: vmacthlp.exe
PROCESS 862e0980  SessionId: 0  Cid: 0374    Peb: 7ffde000  ParentCid: 02a8
    DirBase: 06d40100  ObjectTable: e16959b8  HandleCount: 205.
    Image: svchost.exe

Oraz po modyfikacji:

PROCESS 863c4830  SessionId: none  Cid: 0004    Peb: 00000000  ParentCid: 0000
    DirBase: 06d40020  ObjectTable: e1002e40  HandleCount: 254.
    Image: System
PROCESS 85ff4be8  SessionId: none  Cid: 021c    Peb: 7ffd5000  ParentCid: 0004
    DirBase: 06d40040  ObjectTable: e101ddf8  HandleCount:  19.
    Image: smss.exe
PROCESS 85e40020  SessionId: 0  Cid: 0264    Peb: 7ffdb000  ParentCid: 021c
    DirBase: 06d40060  ObjectTable: e155c878  HandleCount: 367.
    Image: csrss.exe
PROCESS 861b9020  SessionId: 0  Cid: 027c    Peb: 7ffd7000  ParentCid: 021c
    DirBase: 06d40080  ObjectTable: e1534818  HandleCount: 466.
    Image: winlogon.exe
PROCESS 85e7d3d0  SessionId: 0  Cid: 02a8    Peb: 7ffdc000  ParentCid: 027c
    DirBase: 06d400a0  ObjectTable: e14d6918  HandleCount: 263.
    Image: services.exe
PROCESS 85e942e0  SessionId: 0  Cid: 0364    Peb: 7ffd4000  ParentCid: 02a8
    DirBase: 06d400e0  ObjectTable: e1690f00  HandleCount:  25.
    Image: vmacthlp.exe
PROCESS 862e0980  SessionId: 0  Cid: 0374    Peb: 7ffde000  ParentCid: 02a8
    DirBase: 06d40100  ObjectTable: e16959b8  HandleCount: 203.
    Image: svchost.exe

to widzimy, że CSRSS zawiera aktualną listę swoich (Win32) procesów i modyfikacja listy ActiveProcessLinks na poziomie jądra nie ma na nią żadnego wpływu.

Podsumowanko i krok do przodu

Ukrywanie procesów poprzez bezpośrednią modyfikację obiektów jądra to jedna z wielu metod mających na celu to samo: wyprowadzenie nas w pole i ukrycie pewnych obiektów, których mamy nie widzieć. Podobną do wyżej opisanej technikę można z powodzeniem stosować do usuwania sterownika z listy sterowników, etc. Inne metody postaram się przybliżać w kolejnych wpisach, bo chyba nie ma lepszego sposobu na poznanie mechanizmów rządzących systemem, jak właśnie poprzez analizę zagrożeń, a taka wiedza raczej nie jest szeroko obecna w narodzie :)

Niektórzy zastanawiają się zapewne jak to jest możliwe, że proces usunięty z listy procesów dalej “działa” i właściwie nic się złego z nim nie dzieje. Otóż algorytm szeregowania procesów jest skomplikowany i opiera się o wątki i ich priorytety, a lista służy tylko celom ‘statystycznym’.

Kończąc dywagacje dotyczące struktury _EPROCESS pozostawiam kilka zagadek:
- co jest wyświetlane przez Task Manager (tasklist) jako ‘nazwa obrazu’ i w jaki sposób osiągnąć listę procesów z procesami bez nazw, lub o tej samej nazwie?
- czy lista procesów może zawierać tylko jedną pozycję - np. explorer.exe, lub być w ogóle pusta?
- co się stanie jak podwiążemy któryś proces z listy rekurencyjnie (Flink->Flink, Blink pozostawiając bez zmian)?
Oczywiście zachęcam do przetestowania opisanej wyżej techniki na systemie w dowolnej wersji z dowolnym SP, etc.

Technika przeszukiwania listy procesów w oparciu o wewnętrzne struktury procesu csrss to jedna z wielu możliwości sprawdzenia, czy aby coś nam się nie chce w systemie ukryć przed naszym widokiem. Może nie jest tak często stosowana, jednak warta jest poświęcenia chwili uwagi, albowiem pozwala na weryfikację stanu systemu w trybie użytkownika (narzędzie CsrWalker to zwykły program pracujący w trybie użytkownika). Zabawa w myśliwego z wykorzystaniem WinDbg na dłuższą metę jest nieco męcząca, więc w przyszłości sięgniemy po kod i pobawimy się w pisanie sterowników pracujących w trybie jądra. Tylko w ten sposób możemy mówić o względnie ‘równych’ szansach w walce z programami modyfikującymi jądro systemu.

Opublikowane 6 czerwca 2011 03:57 przez mgrzeg
Filed under: ,

Powiadamianie o komentarzach

Jeżeli chciałbyś otrzymywać email gdy ta wypowiedź zostanie zaktualizowana, to zarejestruj się tutaj

Subskrybuj komentarze za pomocą RSS

Komentarze:

 

gt said:

Jak ja lubię takie posty. :)

Niby się to wie, ale zawsze brakuje czasu, żeby samodzielnie dłubać.

Do ostatniej linii twojego posta dodałbym tylko, że skoro ktoś może coś zrobić w trybie jądra, to tak naprawdę to już nie jest mój system tylko jego. Niby wsadzając swój kod mam równe szanse, ale to tak jak dwóch userów z prawami admina, gdzie jeden jest złośliwy a drugi usiłuje obronić system. Szanse teoretycznie równe, ale psuje się zwykle łatwiej niż broni ;)

czerwca 6, 2011 08:49
 

dotnetomaniak.pl said:

Dziękujemy za publikację - Trackback z dotnetomaniak.pl

czerwca 6, 2011 09:51
 

mgrzeg said:

@gt: jak ja lubię takie komentarze! :)

Oczywiście chodzi mi bardziej o pokazanie pewnych mechanizmów systemowych, niż zachęcanie do pisania własnego antyrootkita, ale kto wie? ;)

Nie napisałem tego ani w tekście, ani w komentarzach do poprzedniego wpisu, ale CSRSS może stanowić źródło informacji o procesach w jeszcze inny sposób - csrss trzyma uchwyty do wszystkich 'własnych' procesów i wątków, więc jeśli ukryty jest proces użytkownika (obsługiwany przez podsystem Win32), to wystarczy przejrzeć w process explorerze listę uchwytów procesów dla csrss.exe i wszystko stanie się jasne :). W Windows 7 jest trochę więcej roboty niż w XP, ponieważ mamy > 1 procesów csrss.exe - po jednym dla każdej sesji z osobna (oczywiście usługi osobno).

m.

czerwca 7, 2011 21:19
 

PH said:

Nieziemskie!

Jedyna rzecz, jaka mi się nie podoba w DKOM, to fakt, że jest ono "nieoficjalne", a wewnętrzne struktury kernela zmieniają się wraz z kolejnymi SP albo innymi łatami. I tak naprawdę napisanie czegoś działającego później na innej maszynie niż developera wymaga baaaardzo dużo zachodu (głównie przez wykrywanie wersji systemu, na którym działa i łatanie swojego algorytmu)...

Garść praktycznych porad można zaczerpnąć z książki: "Rootkity. Sabotowanie jądra systemu Windows" [http://helion.pl/ksiazki/rootkity-sabotowanie-jadra-systemu-windows-greg-hoglund-jamie-butler,rootki.htm]. Tylko ta pozycja i kody rootkitów niestety bardzo szybko się starzeją... Michał, może dopiszesz kolejne rozdziały poruszające tematykę Windows 7 ?? :)

czerwca 8, 2011 15:54
 

mgrzeg said:

@PH: świetna książka! Przyznaję bez bicia, że to m.in. ona zainspirowała mnie do napisania tego tekstu i zamierzam skorzystać ze zmodyfikowanych nieco przeze mnie źródeł FU przy kolejnych wpisach. Szkoda, że rootkit.com nie działa... a Greg Hoglund zdaje się zaprzestał pisywać na te tematy...

Jest jeszcze kilka innych pozycji poświęconych tej tematyce (choć nie widziałem nigdzie tłumaczeń na polski), w tym w szczególności trzeba wspomnieć o 'The rootkit Arsenal. Escape and Evasion in the Dark Corners of the System' Billa Blundena (http://www.amazon.com/Rootkit-Arsenal-Escape-Evasion-Corners/dp/1598220616), w której już jest trochę n/t Visty. Wszyscy autorzy jednak zdecydowanie odcinają się od 64-bit wersji systemu twierdząc, że na razie najpopularniejsze są 32-bitowce :)

Zaczynając tę serię myślałem głównie o tym, żeby dostarczyć troszkę wiedzy o wewnętrznych mechanizmach systemowych tak, żeby każdy chętny mógł wieczorkiem usiąść do kompa i w kilka chwil powtórzyć samodzielnie całą zabawę. Wiele osób korzysta z narzędzi sysinternals, ale domyślam się, że tylko garstka kojarzy co się kryje za wszelkimi skrótami typu IRP, ETL, w jaki sposób skorzystać z symboli, ramki stosu, etc. Spróbuję chociaż część z tego bogactwa zademonstrować i mam nadzieję, że chociaż jedną osobę zachęcę do samodzielnych zabaw :)

m.

czerwca 8, 2011 19:51
 

PH said:

Miło mi, że udało mi się cię rozgryźć :)

Z tym większym zapałem czekam na kolejny odcinek.

czerwca 10, 2011 00:34
 

Polski TechNet Blog said:

Czasem zdarza się tak, że warto spojrzeć głębiej do środka systemu. Nie mam tu na myśli żadnych naprawdę

czerwca 22, 2011 09:21
 

Niewidzialne procesy « Windows 4 Solaris said:

czerwca 22, 2011 15:07
 

Niewidzialne procesy « Windows 4 Solaris said:

czerwca 22, 2011 15:07
 

Niewidzialne procesy | Polski TechNet Blog said:

kwietnia 29, 2016 14:55

Co o tym myślisz?

(wymagane) 
(opcjonalne)
(wymagane) 

  
Wprowadź kod: (wymagane)
Wyślij

Subskrypcje

W oparciu o Community Server (Personal Edition), Telligent Systems