PEB_LDR_DATA

0

Zaczne od tego, ze system WinXP 32-bit, x86.

Bawiac sie na Windowsie dzisiaj natrafilem na pewna nie scislosc, ktorej nie moge za zadne skarby rozwiazac, a mianowicie.

Mamy sobie strukture TEB(z FG wyciagam adresik), a w niej na offsecie 0x30 mamy adres PEB'a. Udaje sie do tego PEB'a, bo chce sobie adresik kernel32 nabyc, na razie standardowo bez SEH.
Struktura PEB wyglada tak(wersja krotsza z MSDN):

typedef struct _PEB {
  BYTE                          Reserved1[2];
  BYTE                          BeingDebugged;
  BYTE                          Reserved2[1];
  PVOID                         Reserved3[2];
  PPEB_LDR_DATA                 Ldr;
  PRTL_USER_PROCESS_PARAMETERS  ProcessParameters;
  BYTE                          Reserved4[104];
  PVOID                         Reserved5[52];
  PPS_POST_PROCESS_INIT_ROUTINE PostProcessInitRoutine;
  BYTE                          Reserved6[128];
  PVOID                         Reserved7[1];
  ULONG                         SessionId;
} PEB, *PPEB;

No i dobra tu wszystko jest zrozumiale, wiec udaje sie do struktury PPEB_LDR_DATA, poniewaz w niej maja byc zapisane informacje o zaladowanych do przestrzeni adresowej modulach/bibliotekach.
W roznych zrodlach juz ta struktura sie rozni, ale doszedlem do wniosku, ze ta wersja bedzie najwlasciwsza.

typedef struct _PEB_LDR_DATA
{
     ULONG Length;                                     
     UCHAR Initialized;                                
     PVOID SsHandle;
     LIST_ENTRY InLoadOrderModuleList;
     LIST_ENTRY InMemoryOrderModuleList;
     LIST_ENTRY InInitializationOrderModuleList;
     PVOID EntryInProgress;
} PEB_LDR_DATA, *PPEB_LDR_DATA;

Tutaj juz zaczynaja pojawiac sie moje watpliwosci. Wzoruje sie na tym opisie.
http://undocumented.ntinternals.net/UserMode/Structures/PEB_LDR_DATA.html

Natomiast wszystko staje sie zagmatwane, gdy mam taki kod:

find_kernel_32:
	push	esi
	xor	eax, eax
	mov	eax, [fs:0x30]		        ; FS + 0x30 -> PEB
	mov	eax, [eax+0x0C]		; PEB->Ldr
	mov	esi, [eax+0x1C]		        ; ?????
	lodsd				                ; z DS:ESI do EAX
	mov	eax, [eax+0x08]		; PEB->Ldr.???.flink.base_address
	pop	esi

Lecialem sobie po kolei w Olly'm ogarnac jak to jest po kolei ale za malo na razie mam informacji.

Czytalem i wywnioskowalem ze z PEB->Ldr udaje sie do InInitializationOrderModuleList; w PEB_LDR_DATA, czyli kod mov esi, [eax+0x1C].

Na OpenRC znalazlem fajna tabelke z tymi strukturami, ale to tez nie rozwiewa moich watpliwosci.

Chodzi o to, ze InInitializationOrderModuleList; jest typu LIST_ENTRY, czyli jak podaje nirsoft.net:

typedef struct _LIST_ENTRY
{
     PLIST_ENTRY Flink;
     PLIST_ENTRY Blink;
} LIST_ENTRY, *PLIST_ENTRY;

Wedlug mnie flink wskazuje na pierwszy element listy, a blink na wlasnie nie wiem jaki ?

Do tego dochodzi taki potworek, ktory nie rozumiem zupelnie jak jest powiazany z tym skoro ta struktura tak wyglada i nie ma zadnego w oczy rzucajacego sie zwiazku z ponizsza, poza takimi samymi polami typu LIST_ENTRY.

typedef struct _LDR_MODULE {

LIST_ENTRY InLoadOrderModuleList; 
LIST_ENTRY InMemoryOrderModuleList; 
LIST_ENTRY InInitializationOrderModuleList; 
PVOID BaseAddress; 
PVOID EntryPoint;                              ;   :)
ULONG SizeOfImage; 
UNICODE_STRING FullDllName; 
UNICODE_STRING BaseDllName; 
ULONG Flags; 
SHORT LoadCount; 
SHORT TlsIndex; 
LIST_ENTRY HashTableEntry; 
ULONG TimeDateStamp;

} LDR_MODULE, *PLDR_MODULE;

Interesuje mnie to LDR_MODULE, ale jesli z PEB_LDR_DATA ide do LIST_ENTRY InInitializationOrderModuleList; to jakim cudem w nastepnym kroku trafiam do _LDR_MODULE ?

Nie rozumiem za bardzo mozliwosci aby sie w ten sposob przemiescic. Skoro to _LDR_MODULE zawiera pola LIST_ENTRY, a ja juz z PEB_LDR_DATA trafiam do LIST_ENTRY, ktore wskazuje tylko na pola LIST_ENTRY wiec jak to sie dzieje ?

Bede wdzieczny nawet za krotkie wyjasnienie, bo takie cos nie wiele mi mowi:

InMemoryOrderModuleList

    The head of a doubly-linked list that contains the loaded modules for the process. Each item in the list is a pointer to an LDR_DATA_TABLE_ENTRY structure. For more information, see Remarks.

Zwlaszcza, ze inaczej PEB_LDR_DATA wyglada na kazdej z tych 3 stron, tj nirsoft, undocument i msdn.

0

W LIST_ENTRY masz flink i blink które mi sie wydają być nie pierwszym elementem i jakimś tylko wskaźnikami na następny (Forward LINK) i poprzedni (Backward LINK) element listy

0

Bardzo mozliwe tylko skad sie wzielo z tego LIST_ENTRY to _LDR_MODULE, przeciez struktura LIST_ENTRY ma tylko pointery na LIST_ENTRY ?

Tlumaczac to wyjasnienie z ramki:

 Poczetak podwojnie laczonej listy zawiera zalodowane moduly dla procesu. Kazdy element listy jest wskaznikiem do struktury LDR_DATA_TABLE_ENTRY. Po wiecej informacji zobacz uwagi.

Czyli ta struktura wchodzi jeszcze w gre:

typedef struct _LDR_DATA_TABLE_ENTRY {
    BYTE Reserved1[2];
    LIST_ENTRY InMemoryOrderLinks;
    PVOID Reserved2[2];
    PVOID DllBase;
    PVOID EntryPoint;
    PVOID Reserved3;
    UNICODE_STRING FullDllName;
    BYTE Reserved4[8];
    PVOID Reserved5[3];
    union {
        ULONG CheckSum;
        PVOID Reserved6;
    };
    ULONG TimeDateStamp;
} LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;

Wszystko by sie zgadzalo gdyby nie ten kodzik w asmie, ktory wrzucilem i te inne struktury z nirsoft i undocumented.

Jeszcze wrzuce opis tego kodu ze strony:

    XOR     ECX, ECX                    ; ECX = 0
    MOV     ESI, [FS:ECX + 0x30]        ; ESI = &(PEB) ([FS:0x30])
    MOV     ESI, [ESI + 0x0C]           ; ESI = PEB->Ldr
    MOV     ESI, [ESI + 0x1C]           ; ESI = PEB->Ldr.InInitOrder (ntdll.dll)
    LODSD                               ; EAX = PEB->Ldr.InInitOrder.flink (kernel32.dll)
    MOV     EBP, [EAX + 0x08]           ; EBP = PEB->Ldr.InInitOrder.flink.base_address

Idzie inna droga zupelnie, niz mialby isc przez to LDR_DATA_TABLE_ENTRY, dlatego tez juz sie pogubilem troche w tym, bo z kazdego zrodla inne informacje sa ;p

0

Zainwestuj w Debugging Tools For Windows i poprawnie skonfigurowane symbole. Pomiędzy wersjami Windows PEB itd. się różnią. Poprawne pobranie kernel32 z PEB wygląda np. tak:

                mov     eax, large fs:30h ; ProcessEnvironmentBlock
                mov     eax, [eax+PEB.Ldr]
                mov     eax, [eax+PEB_LDR_DATA.InMemoryOrderModuleList.Flink]
                mov     eax, [eax+LIST_ENTRY.Flink]
                mov     eax, [eax+LIST_ENTRY.Flink]
                mov     eax, [eax+10h]
                push    eax
                push    eax
                mov     ebx, eax
                add     ebx, [eax+IMAGE_DOS_HEADER.e_lfanew]
                mov     ebx, [ebx+IMAGE_NT_HEADERS.OptionalHeader.DataDirectory.VirtualAddress] ; export

...kod wzięty z tego malware'u co kilka wątków niżej wisi. Czyli bierzemy z inMemory i idzemy dwa moduły do przodu, kolejność jest zawsze taka sama.

Teraz wyjaśnienie - do czego Ldr służy to wiesz, nie wiesz jednak jak działają standardowe systemowe listy dwukierunkowe: LIST_ENTRY to po prostu para wskaźników na poprzedni i następny element listy. Dokładnie omówione w DDK, kernel mode bez tego zwyczajnie nie istnieje, całe executive na tym bazuje.

Mówiłem o toolsach i symbolach? To teraz pokażę po co i dlaczego:

0:000> dt _PEB
ntdll!_PEB
   +0x000 InheritedAddressSpace : UChar
   +0x001 ReadImageFileExecOptions : UChar
   +0x002 BeingDebugged    : UChar
   +0x003 BitField         : UChar
   +0x003 ImageUsesLargePages : Pos 0, 1 Bit
   +0x003 SpareBits        : Pos 1, 7 Bits
   +0x004 Mutant           : Ptr32 Void
   +0x008 ImageBaseAddress : Ptr32 Void
   +0x00c Ldr              : Ptr32 _PEB_LDR_DATA
   +0x010 ProcessParameters : Ptr32 _RTL_USER_PROCESS_PARAMETERS
   +0x014 SubSystemData    : Ptr32 Void
   +0x018 ProcessHeap      : Ptr32 Void
   +0x01c FastPebLock      : Ptr32 _RTL_CRITICAL_SECTION
   +0x020 AtlThunkSListPtr : Ptr32 Void
   +0x024 SparePtr2        : Ptr32 Void
   +0x028 EnvironmentUpdateCount : Uint4B
   +0x02c KernelCallbackTable : Ptr32 Void
   +0x030 SystemReserved   : [1] Uint4B
   +0x034 SpareUlong       : Uint4B
   +0x038 FreeList         : Ptr32 _PEB_FREE_BLOCK
   +0x03c TlsExpansionCounter : Uint4B
   +0x040 TlsBitmap        : Ptr32 Void
   +0x044 TlsBitmapBits    : [2] Uint4B
   +0x04c ReadOnlySharedMemoryBase : Ptr32 Void
   +0x050 ReadOnlySharedMemoryHeap : Ptr32 Void
   +0x054 ReadOnlyStaticServerData : Ptr32 Ptr32 Void
   +0x058 AnsiCodePageData : Ptr32 Void
   +0x05c OemCodePageData  : Ptr32 Void
   +0x060 UnicodeCaseTableData : Ptr32 Void
   +0x064 NumberOfProcessors : Uint4B
   +0x068 NtGlobalFlag     : Uint4B
   +0x070 CriticalSectionTimeout : _LARGE_INTEGER
   +0x078 HeapSegmentReserve : Uint4B
   +0x07c HeapSegmentCommit : Uint4B
   +0x080 HeapDeCommitTotalFreeThreshold : Uint4B
   +0x084 HeapDeCommitFreeBlockThreshold : Uint4B
   +0x088 NumberOfHeaps    : Uint4B
   +0x08c MaximumNumberOfHeaps : Uint4B
   +0x090 ProcessHeaps     : Ptr32 Ptr32 Void
   +0x094 GdiSharedHandleTable : Ptr32 Void
   +0x098 ProcessStarterHelper : Ptr32 Void
   +0x09c GdiDCAttributeList : Uint4B
   +0x0a0 LoaderLock       : Ptr32 _RTL_CRITICAL_SECTION
   +0x0a4 OSMajorVersion   : Uint4B
   +0x0a8 OSMinorVersion   : Uint4B
   +0x0ac OSBuildNumber    : Uint2B
   +0x0ae OSCSDVersion     : Uint2B
   +0x0b0 OSPlatformId     : Uint4B
   +0x0b4 ImageSubsystem   : Uint4B
   +0x0b8 ImageSubsystemMajorVersion : Uint4B
   +0x0bc ImageSubsystemMinorVersion : Uint4B
   +0x0c0 ImageProcessAffinityMask : Uint4B
   +0x0c4 GdiHandleBuffer  : [34] Uint4B
   +0x14c PostProcessInitRoutine : Ptr32     void
   +0x150 TlsExpansionBitmap : Ptr32 Void
   +0x154 TlsExpansionBitmapBits : [32] Uint4B
   +0x1d4 SessionId        : Uint4B
   +0x1d8 AppCompatFlags   : _ULARGE_INTEGER
   +0x1e0 AppCompatFlagsUser : _ULARGE_INTEGER
   +0x1e8 pShimData        : Ptr32 Void
   +0x1ec AppCompatInfo    : Ptr32 Void
   +0x1f0 CSDVersion       : _UNICODE_STRING
   +0x1f8 ActivationContextData : Ptr32 _ACTIVATION_CONTEXT_DATA
   +0x1fc ProcessAssemblyStorageMap : Ptr32 _ASSEMBLY_STORAGE_MAP
   +0x200 SystemDefaultActivationContextData : Ptr32 _ACTIVATION_CONTEXT_DATA
   +0x204 SystemAssemblyStorageMap : Ptr32 _ASSEMBLY_STORAGE_MAP
   +0x208 MinimumStackCommit : Uint4B
   +0x20c FlsCallback      : Ptr32 Ptr32 Void
   +0x210 FlsListHead      : _LIST_ENTRY
   +0x218 FlsBitmap        : Ptr32 Void
   +0x21c FlsBitmapBits    : [4] Uint4B
   +0x22c FlsHighIndex     : Uint4B

Czyli dokładna definicja PEB konkretnie dla mojego Windows Server 2003. Idąc dalej:

0:000> ?? @$teb->ProcessEnvironmentBlock->Ldr->InLoadOrderModuleList.Flink->Flink->Flink
struct _LIST_ENTRY * 0x00092000
 [ 0x92c08 - 0x91f38 ]
   +0x000 Flink            : 0x00092c08 _LIST_ENTRY [ 0x92cc8 - 0x92000 ]
   +0x004 Blink            : 0x00091f38 _LIST_ENTRY [ 0x92000 - 0x91ed0 ]

0:000> dt _LDR_DATA_TABLE_ENTRY 0x92000
ntdll!_LDR_DATA_TABLE_ENTRY
   +0x000 InLoadOrderLinks : _LIST_ENTRY [ 0x92c08 - 0x91f38 ]
   +0x008 InMemoryOrderLinks : _LIST_ENTRY [ 0x92c10 - 0x91f40 ]
   +0x010 InInitializationOrderLinks : _LIST_ENTRY [ 0x92cd8 - 0x91f48 ]
   +0x018 DllBase          : 0x7c800000 Void
   +0x01c EntryPoint       : 0x7c8246b6 Void
   +0x020 SizeOfImage      : 0x109000
   +0x024 FullDllName      : _UNICODE_STRING "C:\WINDOWS\system32\kernel32.dll"
   +0x02c BaseDllName      : _UNICODE_STRING "kernel32.dll"
   +0x034 Flags            : 0x84004
   +0x038 LoadCount        : 0xffff
   +0x03a TlsIndex         : 0
   +0x03c HashLinks        : _LIST_ENTRY [ 0x7c999890 - 0x7c999890 ]
   +0x03c SectionPointer   : 0x7c999890 Void
   +0x040 CheckSum         : 0x7c999890
   +0x044 TimeDateStamp    : 0x49c51fca
   +0x044 LoadedImports    : 0x49c51fca Void
   +0x048 EntryPointActivationContext : (null)
   +0x04c PatchInformation : (null)

Przydatne?

0

Bardzo przydatne :)

Czyli z LIST_ENTRY ide dalej, i dalej, z tym ze w drugim kroku wchodze do LDR_DATA_TABLE_ENTRY, a nie juz do nastepnej struktury LIST_ENTRY, czy jak ?
Nie lapie po prostu tego wyjsca z tej listy do struktury innego typu, poniewaz zawiera same dwa wskazniki na typ LIST_ENTRY, chyba ze to jest rzutowane po prostu.

Doczytam jeszcze DDK, dzieki wielkie.

0

LIST_ENTRY to po prostu para wskaźników na następny/poprzedni obiekt. W kodzie wyżej jest pewien 'trick' - zobacz, że struktura opisująca moduł też zaczyna się poprzez LIST_ENTRY, więc już wedle tego LIST_ENTRY przechodzisz do przodu.

BTW, sorry, nie DDK a WDK, przywykłem do starych nazw. Obecnie najnowsze wersje Debugging Toolsów są właśnie częścią Windows Driver Kit.

http://msdn.microsoft.com/en-us/library/ff563802(VS.85).aspx - omówione działanie i przeznaczenie LIST_ENTRY.

0

Dzieki jeszcze raz. Dotyczam i mam nadzieje, ze wszystko stanie sie jasne, ale jak mowisz ze jest dokladnie w WDK opisane to na pewno bede wiedzial o co chodzi :)

1 użytkowników online, w tym zalogowanych: 0, gości: 1