As in last post, I started putting together a utility for generation of minidump, intention is to have it be part of bigger workflow. I got most of it right, but had some fun getting the flags and process access right.
First, I started with OpenProcess
but had opened the process with PROCESS_QUERY_INFORMATION
and PROCESS_VM_READ
access rights only. Documentation link.
Second, referring documentation for MiniDumpWriteDump , I was looking for flags to be passed as documented for MINIDUMP_TYPE
. The way enumeration is done it is hard to specify MiniDumpWithHandleData
and MiniDumpWithThreadInfo
at the same time, so really doesn’t help and it does not even addup with the options as listed by .dumpdebug
command in windbg.
1
2
3
4
5
6
7
8
9
10
11
12
| 0:000> .dumpdebug
----- User Mini Dump Analysis
MINIDUMP_HEADER:
Version A793 (A063)
NumberOfStreams 15
Flags 1105
0001 MiniDumpWithDataSegs
0004 MiniDumpWithHandleData
0100 MiniDumpWithProcessThreadData
1000 MiniDumpWithThreadInfo
|
MINIDUMP_TYPE
MS documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| typedef enum _MINIDUMP_TYPE {
00 MiniDumpNormal,
01 MiniDumpWithDataSegs,
02 MiniDumpWithFullMemory,
03 MiniDumpWithHandleData,
04 MiniDumpFilterMemory,
05 MiniDumpScanMemory,
06 MiniDumpWithUnloadedModules,
07 MiniDumpWithIndirectlyReferencedMemory,
08 MiniDumpFilterModulePaths,
09 MiniDumpWithProcessThreadData,
10 MiniDumpWithPrivateReadWriteMemory,
11 MiniDumpWithoutOptionalData,
12 MiniDumpWithFullMemoryInfo,
13 MiniDumpWithThreadInfo,
...
25 MiniDumpValidTypeFlags
} MINIDUMP_TYPE;
|
On futher digging I found this in dotnet
repository on github
:
link
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
| public enum MINIDUMP_TYPE : uint
{
MiniDumpNormal = 0,
MiniDumpWithDataSegs = 1 << 0,
MiniDumpWithFullMemory = 1 << 1,
MiniDumpWithHandleData = 1 << 2,
MiniDumpFilterMemory = 1 << 3,
MiniDumpScanMemory = 1 << 4,
MiniDumpWithUnloadedModules = 1 << 5,
MiniDumpWithIndirectlyReferencedMemory = 1 << 6,
MiniDumpFilterModulePaths = 1 << 7,
MiniDumpWithProcessThreadData = 1 << 8,
MiniDumpWithPrivateReadWriteMemory = 1 << 9,
MiniDumpWithoutOptionalData = 1 << 10,
MiniDumpWithFullMemoryInfo = 1 << 11,
MiniDumpWithThreadInfo = 1 << 12,
MiniDumpWithCodeSegs = 1 << 13,
MiniDumpWithoutAuxiliaryState = 1 << 14,
MiniDumpWithFullAuxiliaryState = 1 << 15,
MiniDumpWithPrivateWriteCopyMemory = 1 << 16,
MiniDumpIgnoreInaccessibleMemory = 1 << 17,
MiniDumpWithTokenInformation = 1 << 18,
MiniDumpWithModuleHeaders = 1 << 19,
MiniDumpFilterTriage = 1 << 20,
MiniDumpWithAvxXStateContext = 1 << 21,
MiniDumpWithIptTrace = 1 << 22,
MiniDumpValidTypeFlags = (-1) ^ ((~1) << 22)
}
|
This aligns quite well with the flags we have observed so far. Now, the question is why am I not able to get handles
in the dump file. My first guess is that I have not opened file with proper acess rights. To confirm I went about looking at what is process explorer doing. :). I attached to procexp64 process and started dumping trace
first, set the breakpoint at function dbgcore!MiniDumpWriteDump
and go
1
2
| 0:012> bp dbgcore!MiniDumpWriteDump
0:012> g
|
after selecting the location to save memory-dump, break point is hit and looking at traceback:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| Breakpoint 0 hit
dbgcore!MiniDumpWriteDump:
00007ff9`73686790 4055 push rbp
0:000> k
# Child-SP RetAddr Call Site
00 00000075`94cfe938 00007ff7`eb92869c dbgcore!MiniDumpWriteDump
01 00000075`94cfe940 00007ff7`eb91d04b procexp64+0x7869c
02 00000075`94cfe990 00007ff7`eb8fc2b0 procexp64+0x6d04b
03 00000075`94cfef30 00007ff7`eb924d59 procexp64+0x4c2b0
04 00000075`94cfef70 00007ff7`eb8fc3af procexp64+0x74d59
05 00000075`94cff490 00007ff7`eb9285f6 procexp64+0x4c3af
06 00000075`94cff4d0 00007ff9`84e274d6 procexp64+0x785f6
07 00000075`94cff510 00007ff9`84e26ff2 USER32!UserCallWinProcCheckWow+0x266
08 00000075`94cff690 00007ff7`eb9559ad USER32!DispatchMessageWorker+0x1b2
09 00000075`94cff710 00007ff7`eb95dcc4 procexp64+0xa59ad
0a 00000075`94cff8c0 00007ff9`82387974 procexp64+0xadcc4
0b 00000075`94cff900 00007ff9`851ba261 KERNEL32!BaseThreadInitThunk+0x14
0c 00000075`94cff930 00000000`00000000 ntdll!RtlUserThreadStart+0x21
|
Function procexp64+0x7869c
calls MiniDumpWriteDump
, so basically it will setup and pass in the parameters.
On Winx64, first 4 parameters are passed in registers and rest on stack. Luckily we need the first four params to confirm, based on signature of MiniDumpWriteDump
.
1
2
3
4
5
6
7
8
9
10
11
| 0:000> r
rax=0000000000000000 rbx=0000000000001105 rcx=0000000000000ad4
rdx=0000000000002d10 rsi=0000000000000ad4 rdi=0000000000000000
rip=00007ff973686790 rsp=0000007594cfe938 rbp=0000000000000e44
r8=0000000000000e44 r9=0000000000001105 r10=0000000000000000
r11=0000000000000246 r12=0000000000010003 r13=0000000000009f20
r14=0000000000000e44 r15=0000000000000ad4
iopl=0 nv up ei pl zr na po nc
cs=0033 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246
dbgcore!MiniDumpWriteDump:
00007ff9`73686790 4055 push rbp
|
The params are passed in this order: ProcessHandle (rcx)
, ProcessId (rdx)
, File (r8)
& MinDumpOpts (r9)
.
Here the rcx
is set to 0xad4
and r8
is set to 0xe44
and r9
is 0x1105
. This 0x1105
(decimal: 4357
) is our option value for sure, but what about process.
!handle
is a great extension to query status/details of various handles:
1
2
3
| 0:000> !handle ad4
Handle ad4
Type Process
|
Per documentation here, you can pass 0x7
as option to print further information:
1
2
3
4
5
6
7
8
9
10
| 0:000> !handle ad4 7
Handle ad4
Type Process
Attributes 0
GrantedAccess 0x1fffff:
Delete,ReadControl,WriteDac,WriteOwner,Synch
Terminate,CreateThread,,VMOp,VMRead,VMWrite,DupHandle,CreateProcess,SetQuota,SetInfo,QueryInfo,SetPort
HandleCount 15
PointerCount 435679
Name <none>
|
The process is opend with access 0x1fffff
, which is actually PROCESS_ALL_ACCESS
. So that answers my query about how the process should be opened. :)
I just wanted to check how procexp
opened the file (I specified the register r8
directly and windbg translated it to 0xe44 handle value):
1
2
3
4
5
6
7
8
9
| 0:000> !handle r8 7
Handle e44
Type File
Attributes 0
GrantedAccess 0x120196:
ReadControl,Synch
Write/Add,Append/SubDir/CreatePipe,WriteEA,ReadAttr,WriteAttr
HandleCount 2
PointerCount 32769
|
So far we have established that the first 4 parameters to MiniDumpWriteDump
, now about remaining 3:
recall the stack we are at is:
1
2
3
4
5
| 0:000> k
# Child-SP RetAddr Call Site
00 00000075`94cfe938 00007ff7`eb92869c dbgcore!MiniDumpWriteDump
01 00000075`94cfe940 00007ff7`eb91d04b procexp64+0x7869c
02 00000075`94cfe990 00007ff7`eb8fc2b0 procexp64+0x6d04b
|
to look at the calling function disassembly type uf
command, it disassmbles function containing specified address.
Here we will pass in the return address from calling function: procexp64+0x7869c
. Here Line#19 is MiniDumpWriteDump
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
| 0:000> uf procexp64+0x7869c
procexp64+0x78610:
00007ff7`4fd58610 48895c2408 mov qword ptr [rsp+8],rbx
00007ff7`4fd58615 48896c2410 mov qword ptr [rsp+10h],rbp
00007ff7`4fd5861a 4889742418 mov qword ptr [rsp+18h],rsi
00007ff7`4fd5861f 57 push rdi
00007ff7`4fd58620 4883ec40 sub rsp,40h
...
...
00007ff7`4fd58674 ff15667e0500 call qword ptr [procexp64+0xd04e0 (00007ff7`4fdb04e0)]
00007ff7`4fd5867a 448bcb mov r9d,ebx
00007ff7`4fd5867d 4c8bc5 mov r8,rbp
00007ff7`4fd58680 8bd0 mov edx,eax
00007ff7`4fd58682 33c0 xor eax,eax
00007ff7`4fd58684 488bce mov rcx,rsi
00007ff7`4fd58687 4889442430 mov qword ptr [rsp+30h],rax
00007ff7`4fd5868c 4889442428 mov qword ptr [rsp+28h],rax
00007ff7`4fd58691 4889442420 mov qword ptr [rsp+20h],rax
00007ff7`4fd58696 ff15fc860b00 call qword ptr [procexp64+0x130d98 (00007ff7`4fe10d98)]
00007ff7`4fd5869c 488b5c2450 mov rbx,qword ptr [rsp+50h]
00007ff7`4fd586a1 488b6c2458 mov rbp,qword ptr [rsp+58h]
00007ff7`4fd586a6 488b742460 mov rsi,qword ptr [rsp+60h]
00007ff7`4fd586ab 4883c440 add rsp,40h
00007ff7`4fd586af 5f pop rdi
00007ff7`4fd586b0 c3 ret
|
To confirm that just type, here .frame
shows current frame. We set breakpoint at dbgcore!MiniDumpWriteDump
so that sounds right.
1
2
| 0:000> .frame
00 00000075`94cfe938 00007ff7`eb92869c dbgcore!MiniDumpWriteDump
|
One can inspect the register values at a particular frame doc link
1
2
3
4
5
6
7
8
9
10
11
12
| 0:000> .frame /r 0
00 00000075`94cfe938 00007ff7`eb92869c dbgcore!MiniDumpWriteDump
rax=0000000000000000 rbx=0000000000001105 rcx=0000000000000ad4
rdx=0000000000002d10 rsi=0000000000000ad4 rdi=0000000000000000
rip=00007ff973686790 rsp=0000007594cfe938 rbp=0000000000000e44
r8=0000000000000e44 r9=0000000000001105 r10=0000000000000000
r11=0000000000000246 r12=0000000000010003 r13=0000000000009f20
r14=0000000000000e44 r15=0000000000000ad4
iopl=0 nv up ei pl zr na po nc
cs=0033 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000244
dbgcore!MiniDumpWriteDump:
00007ff9`73686790 4055 push rbp
|
to look at registers of previous frame:
1
2
3
4
5
6
7
8
9
10
11
12
| 0:000> .frame /r 1
01 00000075`94cfe940 00007ff7`eb91d04b procexp64+0x7869c
rax=0000000000000000 rbx=0000000000001105 rcx=0000000000000ad4
rdx=0000000000002d10 rsi=0000000000000ad4 rdi=0000000000000000
rip=00007ff7eb92869c rsp=0000007594cfe940 rbp=0000000000000e44
r8=0000000000000e44 r9=0000000000001105 r10=0000000000000000
r11=0000000000000246 r12=0000000000010003 r13=0000000000009f20
r14=0000000000000e44 r15=0000000000000ad4
iopl=0 nv up ei pl zr na po nc
cs=0033 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000244
procexp64+0x7869c:
00007ff7`eb92869c 488b5c2450 mov rbx,qword ptr [rsp+50h] ss:00000075`94cfe990=0000023d59070420
|
Here the these are just before calling dbgcore!MiniDumpWriteDump
and disassembly at this location:
1
2
3
4
5
6
7
8
9
| 00007ff7`4fd5867a 448bcb mov r9d,ebx
00007ff7`4fd5867d 4c8bc5 mov r8,rbp
00007ff7`4fd58680 8bd0 mov edx,eax
00007ff7`4fd58682 33c0 xor eax,eax
00007ff7`4fd58684 488bce mov rcx,rsi
00007ff7`4fd58687 4889442430 mov qword ptr [rsp+30h],rax
00007ff7`4fd5868c 4889442428 mov qword ptr [rsp+28h],rax
00007ff7`4fd58691 4889442420 mov qword ptr [rsp+20h],rax
00007ff7`4fd58696 ff15fc860b00 call qword ptr [procexp64+0x130d98 (00007ff7`4fe10d98)]
|
Lines 6-8 is where the parameters are passed on stack for this function, note rax
is 0\nullptr
.
Thus the call to MiniDumpWriteDump
is:
1
2
| MiniDumpWriteDump(0xad4, 0x2d10, 0xe44, 0x1105, nullptr, nullptr, nullptr);
MiniDumpWriteDump(hProc, pid, hFile, 0x1105, nullptr, nullptr, nullptr);
|
With this information set, I know that I need to:
- Open the process with
PROCESS_ALL_ACCESS
- Pass flags
0x1105
- pass
nullptr
to last 3 parameters
Links of interest (click to expand..)
- Process Access Rights
- MiniDumpWriteDump
- MINIDUMP_TYPE
- MiniDumpType-dotnet
- !handle
- .frame