We all know about s memory search WinDbg command but it only searches the current virtual memory range. This is fine if we have a kernel memory or a user dump where we have uniform virtual space but for complete memory dumps we have many virtual to physical address mappings to cover user space of various processes. This is better illustrated on the following highly simplified picture where the typical current virtual space in a complete memory dump is enclosed in the shadowed box and consists of the kernel space and process A virtual address space ranges:

Therefore some data will be present in physical memory but not accessible through virtual memory search. To search through all physical memory there is !search WinDbg command and by default it searches for specific 32-bit value on 32-bit Windows and 64-bit value on 64-bit Windows. The latter means that we can search for 8 character string fragments on 64-bit Windows. For example, if we want to search for occurrences of ”ImaSrv.exe” string we can specify “ImaS” on 32-bit platform and “ImaSrv.e” on 64-bit platform. Taking into account little endian byte ordering we get the following hexadecimal equivalents:
0: kd> .formats 'SamI'
Evaluate expression:
Hex: 53616d49
Decimal: 1398893897
Octal: 12330266511
Binary: 01010011 01100001 01101101 01001001
Chars: SamI
Time: Wed Apr 30 22:38:17 2014
Float: low 9.68201e+011 high 0
Double: 6.91145e-315
0: kd> .formats 'e.vrSamI'
Evaluate expression:
Hex: 652e7672`53616d49
Decimal: 7290895080156654921
Octal: 0624563547112330266511
Binary: 01100101 00101110 01110110 01110010 01010011 01100001 01101101 01001001
Chars: e.vrSamI
Time: Mon Dec 5 23:20:15.665 24704 (GMT+0)
Float: low 9.68201e+011 high 5.14923e+022
Double: 2.46885e+179
Physical memory search gives us plenty of results:
0: kd> !search 53616d49
Searching PFNs in range 00000001 - 0013FFFF for [53616D49 - 53616D49]
Pfn Offset Hit Va Pte
- - - - - - - - - - - - - - - - - - - - - - - - - - -
000079FA 000004C4 53616D49 A3AFB4C4 C051D7D8
a3afb340+0x184 : Proc (Protected) -- Process objects
00011442 00000848 53616D49 66EC2848 C0337610
00011442 0000093C 53616D49 66EC293C C0337610
0001328A 000009F4 43616D49 672E59F4 C0339728
000156F6 000009F4 43616D49 672E59F4 C0339728
00018C7C 000009DC 43616D49 671F49DC C0338FA0
0001ADF0 000003D4 52616D49 00000000 DC3E3B48
0001ADF0 000003E4 52616D49 00000000 DC3E3B48
00020BCE 000009DC 43616D49 671F49DC C0338FA0
...
...
...
We can dump either a virtual address if it is available and valid by using normal d* commands or dump a physical address by using their !d* extension equivalents, for example:
Pfn Offset Hit Va Pte
- - - - - - - - - - - - - - - - - - - - - - - - - - -
00011442 00000848 53616D49 66EC2848 C0337610
0: kd> !dc 11442000+00000848
#11442848 53616d49 65747379 6c642e6d 0000006c ImaSystem.dll...
#11442858 00000000 00000000 00000000 45cd0da0 ...............E
#11442868 00000000 0000293c 00000001 00000012 ....<)..........
#11442878 00000012 00002888 000028d0 00002918 .....(...(...)..
#11442888 00001160 000010b0 00001020 00001000 `....... .......
#11442898 00001130 00001010 000010a0 00001030 0...........0...
#114428a8 000020d8 000020cc 00001300 000013c0 . ... ..........
#114428b8 00001200 00001050 00001040 00001080 ....P...@.......
Note: Physical addresses are formed from PFN (Page Frame Numbers) by shifting them to the left by 12 bits (by adding 3 zeroes to the left). For example: 00011442 -> 11442000.
The cool feature of !search command is that it automatically recognizes pool tags and in our case it has found the process object:
Pfn Offset Hit Va Pte
- - - - - - - - - - - - - - - - - - - - - - - - - - -
000079FA 000004C4 53616D49 A3AFB4C4 C051D7D8
a3afb340+0×184 : Proc (Protected) — Process objects
…
…
…
0: kd> !pool A3AFB4C4
Pool page a3afb340 region is Nonpaged pool
a3afb000 size: 120 previous size: 0 (Allocated) MQAC
a3afb120 size: 20 previous size: 120 (Allocated) VadS
a3afb140 size: 98 previous size: 20 (Allocated) File (Protected)
a3afb1d8 size: 30 previous size: 98 (Allocated) MQAC
a3afb208 size: 20 previous size: 30 (Allocated) VadS
a3afb228 size: 28 previous size: 20 (Free) CcBc
a3afb250 size: 30 previous size: 28 (Allocated) Vad
a3afb280 size: 30 previous size: 30 (Allocated) Vad
a3afb2b0 size: 20 previous size: 30 (Allocated) VadS
a3afb2d0 size: 40 previous size: 20 (Allocated) SeTd
a3afb310 size: 30 previous size: 40 (Allocated) Vad
*a3afb340 size: 298 previous size: 30 (Allocated) *Proc (Protected)
Pooltag Proc : Process objects, Binary : nt!ps
a3afb5d8 size: 8 previous size: 298 (Free) Irp
a3afb5e0 size: 20 previous size: 8 (Allocated) VadS
a3afb600 size: 8 previous size: 20 (Free) Irp
a3afb608 size: 30 previous size: 8 (Allocated) Even (Protected)
a3afb638 size: 30 previous size: 30 (Allocated) Vad
a3afb668 size: 40 previous size: 30 (Allocated) Vadl
a3afb6a8 size: 70 previous size: 40 (Allocated) NWFS
a3afb718 size: 30 previous size: 70 (Allocated) Vad
a3afb748 size: 28 previous size: 30 (Allocated) NpFr Process: a3afb360
a3afb770 size: 98 previous size: 28 (Allocated) File (Protected)
a3afb808 size: 60 previous size: 98 (Allocated) MmCa
a3afb868 size: 98 previous size: 60 (Allocated) File (Protected)
a3afb900 size: 30 previous size: 98 (Allocated) Even (Protected)
a3afb930 size: 20 previous size: 30 (Allocated) VadS
a3afb950 size: 98 previous size: 20 (Allocated) File (Protected)
a3afb9e8 size: 30 previous size: 98 (Allocated) MQAC
a3afba18 size: 120 previous size: 30 (Allocated) MQAC
a3afbb38 size: 50 previous size: 120 (Allocated) NpFc Process: a5659d88
a3afbb88 size: 20 previous size: 50 (Allocated) Port
a3afbba8 size: 98 previous size: 20 (Allocated) File (Protected)
a3afbc40 size: 30 previous size: 98 (Allocated) MQAC
a3afbc70 size: 120 previous size: 30 (Allocated) MQAC
a3afbd90 size: 270 previous size: 120 (Allocated) Thre (Protected)
0: kd> dc A3AFB4C4 l10
a3afb4c4 53616d49 652e7672 00006578 00000000 ImaSrv.exe......
a3afb4d4 00000000 00000000 00000000 a3afbfd4 ................
a3afb4e4 a282fe44 00000000 f7a60500 0000004c D...........L...
a3afb4f4 001f07fb 00008005 00000000 7ffdd000 ................
Seems the search has found ImageFileName field of _EPROCESS structure. The field has 0×164 offset and we can dump the whole structure:
0: kd> dt _EPROCESS A3AFB4C4-0x164
ntdll!_EPROCESS
+0x000 Pcb : _KPROCESS
+0x078 ProcessLock : _EX_PUSH_LOCK
+0x080 CreateTime : _LARGE_INTEGER 0x1c86f66`5b95204a
+0x088 ExitTime : _LARGE_INTEGER 0x0
+0x090 RundownProtect : _EX_RUNDOWN_REF
+0x094 UniqueProcessId : 0x000009d0
+0x098 ActiveProcessLinks : _LIST_ENTRY [ 0xa3af2598 - 0xa3b0a0b8 ]
+0x0a0 QuotaUsage : [3] 0x17030
+0x0ac QuotaPeak : [3] 0x18028
+0x0b8 CommitCharge : 0x37b6
+0x0bc PeakVirtualSize : 0x132d4000
+0x0c0 VirtualSize : 0x12d64000
+0x0c4 SessionProcessLinks : _LIST_ENTRY [ 0xa3af25c4 - 0xa3b0a0e4 ]
+0x0cc DebugPort : (null)
+0x0d0 ExceptionPort : 0xd738e828
+0x0d4 ObjectTable : 0xdc23a008 _HANDLE_TABLE
+0x0d8 Token : _EX_FAST_REF
+0x0dc WorkingSetPage : 0x11741f
+0x0e0 AddressCreationLock : _KGUARDED_MUTEX
+0x100 HyperSpaceLock : 0
+0x104 ForkInProgress : (null)
+0x108 HardwareTrigger : 0
+0x10c PhysicalVadRoot : 0xa3c21448 _MM_AVL_TABLE
+0x110 CloneRoot : (null)
+0x114 NumberOfPrivatePages : 0x318d
+0x118 NumberOfLockedPages : 7
+0x11c Win32Process : 0xbc33d968
+0x120 Job : (null)
+0x124 SectionObject : 0xdc2710c8
+0x128 SectionBaseAddress : 0x00400000
+0x12c QuotaBlock : 0xa3bb2f38 _EPROCESS_QUOTA_BLOCK
+0x130 WorkingSetWatch : (null)
+0x134 Win32WindowStation : 0x00000078
+0x138 InheritedFromUniqueProcessId : 0x00000228
+0x13c LdtInformation : (null)
+0x140 VadFreeHint : (null)
+0x144 VdmObjects : (null)
+0x148 DeviceMap : 0xd7d0ff30
+0x14c Spare0 : [3] (null)
+0x158 PageDirectoryPte : _HARDWARE_PTE_X86
+0x158 Filler : 0
+0x160 Session : 0xf79d5000
+0×164 ImageFileName : [16] “ImaSrv.exe”
+0×174 JobLinks : _LIST_ENTRY [ 0×0 - 0×0 ]
+0×17c LockedPagesList : (null)
+0×180 ThreadListHead : _LIST_ENTRY [ 0xa3afbfd4 - 0xa282fe44 ]
+0×188 SecurityPort : (null)
+0×18c PaeTop : 0xf7a60500
+0×190 ActiveThreads : 0×4c
+0×194 GrantedAccess : 0×1f07fb
+0×198 DefaultHardErrorProcessing : 0×8005
+0×19c LastThreadExitStatus : 0
+0×1a0 Peb : 0×7ffdd000 _PEB
+0×1a4 PrefetchTrace : _EX_FAST_REF
+0×1a8 ReadOperationCount : _LARGE_INTEGER 0xf01d3
+0×1b0 WriteOperationCount : _LARGE_INTEGER 0×3b08c
+0×1b8 OtherOperationCount : _LARGE_INTEGER 0×67845
+0×1c0 ReadTransferCount : _LARGE_INTEGER 0×9b087eec
+0×1c8 WriteTransferCount : _LARGE_INTEGER 0×39f8a27a
+0×1d0 OtherTransferCount : _LARGE_INTEGER 0×25dd749
+0×1d8 CommitChargeLimit : 0
+0×1dc CommitChargePeak : 0×394b
+0×1e0 AweInfo : (null)
+0×1e4 SeAuditProcessCreationInfo : _SE_AUDIT_PROCESS_CREATION_INFO
+0×1e8 Vm : _MMSUPPORT
+0×230 MmProcessLinks : _LIST_ENTRY [ 0xa3af2730 - 0xa3b0a250 ]
+0×238 ModifiedPageCount : 0xc835
+0×23c JobStatus : 0
+0×240 Flags : 0×4d0801
+0×240 CreateReported : 0y1
+0×240 NoDebugInherit : 0y0
+0×240 ProcessExiting : 0y0
+0×240 ProcessDelete : 0y0
+0×240 Wow64SplitPages : 0y0
+0×240 VmDeleted : 0y0
+0×240 OutswapEnabled : 0y0
+0×240 Outswapped : 0y0
+0×240 ForkFailed : 0y0
+0×240 Wow64VaSpace4Gb : 0y0
+0×240 AddressSpaceInitialized : 0y10
+0×240 SetTimerResolution : 0y0
+0×240 BreakOnTermination : 0y0
+0×240 SessionCreationUnderway : 0y0
+0×240 WriteWatch : 0y0
+0×240 ProcessInSession : 0y1
+0×240 OverrideAddressSpace : 0y0
+0×240 HasAddressSpace : 0y1
+0×240 LaunchPrefetched : 0y1
+0×240 InjectInpageErrors : 0y0
+0×240 VmTopDown : 0y0
+0×240 ImageNotifyDone : 0y1
+0×240 PdeUpdateNeeded : 0y0
+0×240 VdmAllowed : 0y0
+0×240 SmapAllowed : 0y0
+0×240 CreateFailed : 0y0
+0×240 DefaultIoPriority : 0y000
+0×240 Spare1 : 0y0
+0×240 Spare2 : 0y0
+0×244 ExitStatus : 259
+0×248 NextPageColor : 0xf91e
+0×24a SubSystemMinorVersion : 0 ”
+0×24b SubSystemMajorVersion : 0×4 ”
+0×24a SubSystemVersion : 0×400
+0×24c PriorityClass : 0×6 ”
+0×250 VadRoot : _MM_AVL_TABLE
+0×270 Cookie : 0×5a583219
We can also see that by default !search command finds entries differing in a single bit, for example:
Pfn Offset Hit Va Pte
- - - - - - - - - - - - - - - - - - - - - - - - - - -
...
...
...
00011442 0000093C 53616D49 66EC293C C0337610
0001328A 000009F4 43616D49 672E59F4 C0339728
…
…
…
0: kd> !dc 0001328A9F4
#1328a9f4 43616d49 6f6d6d6f 64702e6e 00000062 ImaCommon.pdb...
#1328aa04 672e7170 00000000 00000000 ffffffff pq.g............
#1328aa14 00000000 00000000 672e5a04 00000000 .........Z.g....
#1328aa24 00000000 00000000 00000001 672e5a1c .............Z.g
#1328aa34 00000000 00000000 00000000 672e7170 ............pq.g
#1328aa44 672e5a24 00000000 00000000 00004c24 $Z.g........$L..
#1328aa54 00000000 00000000 00000000 00000000 ................
#1328aa64 00000000 672e7138 00000000 ffffffff ....8q.g........
In the case of kernel memory dumps physical memory search might be better alternative to virtual memory search if we need to see pool tags corresponding to search hits or search for data differing in some bits, for example:
3: kd> .ignore_missing_pages 1
Suppress kernel summary dump missing page error message
3: kd> s -d 80000000 L?20000000 53616d49
86a6eeec 53616d49 652e7672 00006578 00000000 ImaSrv.exe......
3: kd> !search 53616d49
Debuggee is a kernel summary dump, some physical pages may not be present.
Searches will miss hits from those pages.
Searching PFNs in range 00000001 - 0007FFFF for [53616D49 - 53616D49]
Pfn Offset Hit Va Pte
- - - - - - - - - - - - - - - - - - - - - - - - - - -
00005DED 00000EEC 53616D49 86A6EEEC C021A9B8
86a6ed68+0x184 : Proc (Protected) -- Process objects
Search done.
- Dmitry Vostokov @ DumpAnalysis.org -