Skip to main content

Deep Dive to Windows, Part 3 (Extension)



This is the extension of part 3. I'd like to explain few things in details. 
In part 3 we started discussion on PEB_LDR_DATA structure. The more details 
on it can be referenced in following MSDN article:

http://msdn.microsoft.com/en-us/library/windows/desktop/aa813708%28v=vs.85%29.aspx

As per MSDN, the structure looks like below: 
typedef struct _PEB_LDR_DATA {
  BYTE       Reserved1[8];
  PVOID      Reserved2[3];
  LIST_ENTRY InMemoryOrderModuleList;
} PEB_LDR_DATA, *PPEB_LDR_DATA;
 
The highlighted part according to MSDN, "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."
 
The data type is LIST_ENTRY. According to MSDN, the structure is like below:

typedef struct _LIST_ENTRY {
   struct _LIST_ENTRY *Flink;
   struct _LIST_ENTRY *Blink;
} LIST_ENTRY, *PLIST_ENTRY, *RESTRICTED_POINTER PRLIST_ENTRY;
 
Let's see what WinDbg says about it.
Executed following command in WinDbg:
 
0:000> dt nt!_LIST_ENTRY
ntdll!_LIST_ENTRY
   +0x000 Flink            : Ptr32 _LIST_ENTRY
   +0x004 Blink            : Ptr32 _LIST_ENTRY
 
So, it's a doubly link list. Let's see what items they are pointing to. 
To know that, executed following commands: 

a) 0:000> !peb
    PEB at 7efde000
    InheritedAddressSpace:    No
    ReadImageFileExecOptions: No
    BeingDebugged:            Yes
    ImageBaseAddress:         00400000
    Ldr                       77c80200
    Ldr.Initialized:          Yes
    Ldr.InInitializationOrderModuleList: 00883288 . 00884308
    Ldr.InLoadOrderModuleList:           008831e8 . 00884018
    Ldr.InMemoryOrderModuleList:         008831f0 . 00884020

b) 0:000> dt nt!_PEB_LDR_DATA 77c80200
   ntdll!_PEB_LDR_DATA
   +0x000 Length           : 0x30
   +0x004 Initialized      : 0x1 ''
   +0x008 SsHandle         : (null) 
   +0x00c InLoadOrderModuleList : _LIST_ENTRY [ 0x8831e8 - 0x884018 ]
   +0x014 InMemoryOrderModuleList : _LIST_ENTRY [ 0x8831f0 - 0x884020 ]
   +0x01c InInitializationOrderModuleList : _LIST_ENTRY [ 0x883288 - 0x884308 ]
   +0x024 EntryInProgress  : (null) 
   +0x028 ShutdownInProgress : 0 ''
   +0x02c ShutdownThreadId : (null) 

c) 0:000> dt nt!_PEB_LDR_DATA 77c80200 InInitializationOrderModuleList.Flink /r1
   ntdll!_PEB_LDR_DATA
   +0x01c InInitializationOrderModuleList    :  [ 0x883288 - 0x884308 ]
   +0x000 Flink                              : 0x00883288 _LIST_ENTRY [ 0x883720 - 0x77c8021c ]






d) 0:000> lm
start    end        module name
00400000 0041c000   Sample_Hello   (deferred)             
65140000 65261000   MSVCR80D   (deferred)             
65270000 6536e000   MSVCP80D   (deferred)             
75a10000 75b20000   kernel32   (deferred)             
75bf0000 75c37000   KERNELBASE   (deferred)             
76b10000 76bbc000   msvcrt     (deferred)             
77b80000 77d00000   ntdll      (pdb symbols)

Now Expanding Flink gives following results (matches with start 
address of respective module displayed by lm):
0:000> dd 00883288
00883288  00883720 77c8021c 77b80000 00000000 77b80000 ==> ntdll
00883298  00180000 003c003a 00883308 00140012
008832a8  77bc5b74 00004004 0000ffff 77c848c0
008832b8  77c848c0 4ec49b8f 00000000 00000000
008832c8  008832c8 008832c8 008832d0 008832d0
008832d8  008832d8 008832d8 00000000 7de70000
008832e8  00000000 00000000 abababab abababab
008832f8  00000000 00000000 7fbbcb78 1c00fea9

0:000> dd 00883720 
00883720  00883608 00883288 75bf0000 75bf74b1 75bf0000 ==> KERNELBASE
00883730  00047000 00460044 008836b0 001e001c
00883740  008836d8 00084004 0000ffff 77c848d0
00883750  77c848d0 506dbe50 00000000 00000000
00883760  00883760 00883760 00883768 00883768
00883770  008837a0 008837a0 77bbc960 7d850000
00883780  2f96faba 01cde9d0 abababab abababab
00883790  00000000 00000000 71bbcb76 1800fea9

0:000> dd 00883608 
00883608  00884028 00883720 75a10000 75a232b3 75a10000 ==> kernel32
00883618  00110000 00420040 00883598 001a0018
00883628  008835c0 00084004 0000ffff 77c84880
00883638  77c84880 506dbe4f 00000000 00000000
00883648  00883648 00883648 00883650 00883650
00883658  008837c8 00883688 77bbc960 7dd60000
00883668  2f8b13d9 01cde9d0 abababab abababab
00883678  00000000 00000000 71bbcb76 1800fea9

0:000> dd 00884028
00884028  00884498 00883608 76b10000 76b1a472 76b10000 ==> msvcrt
00884038  000ac000 003e003c 00883fc0 00160014
00884048  00883fe8 00000004 0000ffff 77c848b8
00884058  77c848b8 4eeaf722 00000000 00000000
00884068  00884068 00884068 00884070 00884070
00884078  008840f8 008840a8 77bbc960 6ff50000
00884088  300b9e28 01cde9d0 abababab abababab
00884098  00000000 00000000 71bbcb76 1800fea9

0:000> dd 00884498
00884498  00884308 00884028 65140000 65142f90 65140000 ==> MSVCR80D
008844a8  00121000 00e200e0 00884388 001a0018
008844b8  00884450 10000004 0000ffff 77c848f8
008844c8  77c848f8 4dcddbed 00000000 00000000
008844d8  008844d8 008844d8 008844e0 008844e0
008844e8  00884148 00884120 77bbc944 10200000
008844f8  300b9e28 01cde9d0 abababab abababab
00884508  00000000 00000000 71bbcb76 1800fea9

0:000> dd 00884308 
00884308  77c8021c 00884498 65270000 652f1450 65270000 ==> MSVCP80D
00884318  000fe000 00e200e0 008841f8 001a0018
00884328  008842c0 10000004 0000ffff 77c84808
00884338  77c84808 4dcddc5b 00000000 00000000
00884348  00884348 00884348 00884350 00884350
00884358  00884198 00884170 77bbc944 10480000
00884368  2fd73fe2 01cde9d0 abababab abababab
00884378  00000000 00000000 54bbcb53 1e00fea9

0:000> dd 77c8021c 
77c8021c  00883288 00884308 00000000 00000000 00000000 ==> No module
77c8022c  00000000 00000000 00000000 00000000
77c8023c  00000000 00000000 00000000 00000000
77c8024c  00000000 00000000 00000000 00000000
77c8025c  00000000 00000000 00000000 00000000
77c8026c  00000000 00000000 00000000 00000000
77c8027c  00000000 00000000 00000000 00000000
77c8028c  00000000 00000000 00000000 00000000

More to follow

Happy debugging

Comments

Popular posts from this blog

Reversing char array without splitting the array to tokens

 I was reading about strdup, a C++ function and suddenly an idea came to my mind if this can be leveraged to aid in reversing a character array without splitting the array into words and reconstructing it again by placing spaces and removing trailing spaces. Again, I wanted an array to be passed as a function argument and an array size to be passed implicitly with the array to the function. Assumed, a well-formed char array has been passed into the function. No malformed array checking is done inside the function. So, the function signature and definition are like below: Below is the call from the client code to reverse the array without splitting tokens and reconstructing it. Finally, copy the reversed array to the destination.  For GNU C++, we should use strdup instead _strdup . On run, we get the following output: Demo code

XOR (Exclusive OR) for branchless coding

The following example shows the array reversing using the  XOR operator . No need to take any additional variable to reverse the array.   int main(int argc, _TCHAR* argv[]) { char str[] = "I AM STUDENT"; int length = strlen(str); for(int i = 0; i < ((length/2)); i++) { str[i] ^= str[length - (1+i)]; str[length - (1+i)] ^= str[i]; str[i] ^= str[length - (1+i)]; } cout << str << endl; return 0; } The above example is one of the uses of XOR but XOR comes in handy when we can do branchless coding  methods like butterfly switch etc. Sometimes this is very effective in speeding up the execution.  Let's see one of the uses of XOR in branchless coding. I am taking a simple example of Y = | X |.  Yes, I am generating abs of a supplied number. So, my function signature/definition in C++ looks like below: int absoluteBranch( int x) {     if (x < 0 ) {         return -x;     }     else {         retur

Power of Two

  I n this post will be discussing how to calculate if a number is a power of two or not. As an example, 8 is a power of two but the number 10 is not. There are many ways we can solve this. First , we will take an approach which is simple and iterative. In this case, we will calculate the power of two one by one and check with the supplied number. The below code illustrates it. bool isPowerofTwo(unsigned num) { auto y = 1; while (0 != y) { if (num == y) return true; if (num < y) return false; y <<= 1; } return false; } Second , assuming, the number is a 32-bit number, this is also an iterative solution. In this scenario, iterating all bits and counting the set bits. Any number which is a power of 2 will have only one bit set and the rest will be zeros. As an example, 8 in binary representation is 1000. Using this observation, we can implement an iterative solution. bool isPowerofTwo(unsigned num) { auto one_count = 0; for (auto index = 0; index < 32;