I'm tracing dmp file which seems like crashed calling virtual function of broken object instance.
it seems that vft of the broken object pointer pointed wrong address(0x3822a497) and program crashed immediately after call edx to 0x3822a497 (LAST_CONTROL_TRANSFER: from 00ccde67 to 3822a497), and instruction pointer (EIP) couldn't even go one step further. then, shouldn't it be edx=0x3822a497? but both Visual Studio and Windbg indicates edx=0x1e4dcc0.
Can somebody explain how could it happen?
EDIT: I trusted LAST_CONTROL_TRANSFER too much, but still mystery exists. please first see updated suppositions 1,2,3 below and give me a possible scenario.
Result of windbg !analyze -v
Failed calling InternetOpenUrl, GLE=12029
FAULTING_IP:
+8cde67
3822a497 006e00 add byte ptr [esi],ch
EXCEPTION_RECORD: ffffffff -- (.exr 0xffffffffffffffff)
ExceptionAddress: 3822a497
ExceptionCode: c0000005 (Access violation)
ExceptionFlags: 00000000
NumberParameters: 2
Parameter[0]: 00000001
Parameter[1]: 0138d2cc
Attempt to write to address 0138d2cc
PROCESS_NAME: DDD.exe
ADDITIONAL_DEBUG_TEXT:
Use '!findthebuild' command to search for the target build information.
If the build information is available, run '!findthebuild -s ; .reload' to set symbol path and load symbols.
FAULTING_MODULE: 76df0000 kernel32
DEBUG_FLR_IMAGE_TIMESTAMP: 518275c9
MODULE_NAME: DDD
ERROR_CODE: (NTSTATUS) 0xc0000005 - 0x%08lx
EXCEPTION_CODE: (NTSTATUS) 0xc0000005 - 0x%08lx
EXCEPTION_PARAMETER1: 00000001
EXCEPTION_PARAMETER2: 0138d2cc
WRITE_ADDRESS: 0138d2cc
FOLLOWUP_IP:
DDD+8cde67
00ccde67 ?? ???
FAILED_INSTRUCTION_ADDRESS:
+591b2faf0239d8f4
3822a497 006e00 add byte ptr [esi],ch
MOD_LIST: <ANALYSIS/>
FAULTING_THREAD: 00000650
BUGCHECK_STR: APPLICATION_FAULT_BAD_INSTRUCTION_PTR_INVALID_POINTER_WRITE_WRONG_SYMBOLS
PRIMARY_PROBLEM_CLASS: BAD_INSTRUCTION_PTR
DEFAULT_BUCKET_ID: BAD_INSTRUCTION_PTR
LAST_CONTROL_TRANSFER: from 00ccde67 to 3822a497
STACK_TEXT:
WARNING: Frame IP not in any known module. Following frames may be wrong.
0018cfe0 00ccde67 1a75cb52 00000000 28e86c00 0x3822a497
0018cfe4 1a75cb52 00000000 28e86c00 00000011 DDD+0x8cde67
0018cfe8 00000000 28e86c00 00000011 29b52260 0x1a75cb52
STACK_COMMAND: ~0s; .ecxr ; kb
SYMBOL_STACK_INDEX: 1
SYMBOL_NAME: DDD+8cde67
FOLLOWUP_NAME: MachineOwner
IMAGE_NAME: DDD.exe
BUCKET_ID: WRONG_SYMBOLS
FAILURE_BUCKET_ID: BAD_INSTRUCTION_PTR_c0000005_DDD.exe!Unknown
WATSON_STAGEONE_URL: http://watson.microsoft.com/...
Followup: MachineOwner
---------
0:000>
Result of windbg .excr
0:000> .ecxr
eax=0018d0c8 ebx=78b3b6a8 ecx=00cddb00 edx=01e4dcc0 esi=0138d2cc edi=0018cfc8
eip=3822a497 esp=0018cfe4 ebp=00000002 iopl=0 nv up ei ng nz na po nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00210282
3822a497 006e00 add byte ptr [esi],ch ds:002b:0138d2cc=??
Result of windbg r
Last set context:
eax=0018d0c8 ebx=78b3b6a8 ecx=00cddb00 edx=01e4dcc0 esi=0138d2cc edi=0018cfc8
eip=3822a497 esp=0018cfe4 ebp=00000002 iopl=0 nv up ei ng nz na po nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00210282
3822a497 006e00 add byte ptr [esi],ch ds:002b:0138d2cc=??
Disassembly before LAST_CONTROL_TRANSFER: from 00ccde67 to 3822a497
current_time = timeGetTime();
00CCDE34 call dword ptr [__imp__timeGetTime#0 (17EE5FCh)]
(*it)->proc();
00CCDE3A mov eax,dword ptr [ebx]
00CCDE3C test eax,eax
00CCDE3E je 00CCDFFE
00CCDE44 test edi,edi
00CCDE46 je 00CCDFFE
00CCDE4C cmp dword ptr [eax+4],edi
00CCDE4F ja 00CCDFFE
00CCDE55 cmp edi,dword ptr [eax+8]
00CCDE58 jae 00CCDFFE
00CCDE5E mov ecx,dword ptr [edi]
00CCDE60 mov eax,dword ptr [ecx]
00CCDE62 mov edx,dword ptr [eax+0Ch]
00CCDE65 call edx
00CCDE67 push 0
EDIT
Oh I forgot to put stack state.
stack (esp=0x18cfe4)
0x0018CFA4 00000000 00000000 00000000 00000000 ................
0x0018CFB4 00000000 00000000 00000000 00000000 ................
0x0018CFC4 00000000 fffffd34 000002e4 fffffd34 ....4?..?...4?..
0x0018CFD4 000002cc 00000019 00000000 0018d0c8 ?...........??..
0x0018CFE4 >00ccde67 1a75cb52 00000000 28e86c00 g??.R?u......l?(
0x0018CFF4 00000011 29b52260 00000000 78b3c718 ....`"?).....??x
0x0018D004 29b522a0 00000000 78b3b6ac 29b522a0 ?"?)....???x?"?)
0x0018D014 00000000 78b3b6a8 1a75cb52 00000140 ....???xR?u.#...
0x0018D024 01e4f688 1a75cb52 0018d050 0170d884 ???.R?u.P?..??p.
0x0018D034 ffffffff 0018d05c 0098ec41 1a75cb36 ....\?..A??.6?u.
Disassembly around eip (0x3822A497)
3822A490 54 push esp
3822A491 00 db 00h
3822A492 65 db 65h
3822A493 00 72 00 add byte ptr [edx],dh
3822A496 61 popad
3822A497 00 6E 00 add byte ptr [esi],ch
3822A49A 69 00 74 00 65 00 imul eax,dword ptr [eax],650074h
Memory dump around eip (0x3822A497)
0x3822A480 55da14f5 80000000 00001e08 00000024 ?.?U........$...
0x3822A490 00650054 00610072 0069006e 00650074 T.e.r.a.n.i.t.e.
0x3822A4A0 004e0020 00630065 006c006b 00630061 .N.e.c.k.l.a.c.
0x3822A4B0 00000065 4d747cba 55da14f2 80000000 e...?|tM?.?U....
Obviously this is not valid instructions but wide characters text.
I think it is very likely that callee broke edx information as xwlan said.
( And I thought LAST_CONTROL_TRANSFER is some kind of trustful information. It was just displaying last callstack entry to eip )
But my suppositions still don't make a sense. Can somebody make a scenario that makes sense?
Suppose 1: instruction jumped before 0x3822A497 and executed popad
I think this makes most sense. (e.g. could jumped by some indirection jump/call to pointer to text buffer 0x3822A490)
If so, popad would executed, which pops EDI, ESI, EBP, EBX, EDX, ECX, and EAX from stack.
Then why can't I find these register's values from stack?
For example, if so, shouldn't I see 0x00000002 (ebp), 0x01e4dcc0 (edx) from stack near 0x0018CFE4 (esp)?
Suppose 2: callee was not 0x3822A497 , instruction jumped exactly to 0x3822A497
I think it is very rare case.
If jump was by indirect call/jmp, nothing would pointed to 0x3822A497 which is odd number,
If jump was by relative call/jmp, the call instruction would be near 0x3822A497,
but I can't find such a relative calls when I disassembly from every point near 0x3822A497
and because it has ##, 00, ##, 00, ## pattern of wide character text,
most possible jump instruction jumps to next instruction pointer, for example:
3822A494 72 00 > jb 3822A496
3822A496 61 popad
3822A497 00 6E 00 add byte ptr [esi],ch
Suppose 3: Callee was 0x3822A497
then why edx is not 0x3822A497. (First question)
You're putting too much faith in the call stack, you're likely missing a frame here (probably some sort of FPO related artifact). I suspect that EDX wasn't the bad EIP, it held the address of a valid function that eventually set up the invalid EIP.
If I were you, I would reconstruct EDX at the time of the crash and see what function it is. Then you can try to figure out what that function might have done to trash EIP (probably a stack overflow). If you're feeling lucky/lazy, you could hope that EDX has stayed unmolested and see what, "uf #edx" gets you.
look like stack corruption, "esp=0018cfe4 ebp=00000002", ebp is apparently a bad value.
i'd suggest check the code "00CCDE65 call edx", the edx looks like point to a virtual function, this function and its callee corrupt the stack. dds esp in windbg can help to dump current stack memory to check whether there's any suspicious values, e.g. any string?
Related
Edit:
I've investigated more, and the problem reported below seems to happen only when I use Visual Studio 2017 to pause the process. It also seems that when rip is pointing to an invalid location, it's always a +1 byte offset from the correct instruction start.
Also, for context, this is a large C++ project with lots of dlls, some compiled with MSVC 2015, the rest with icc (intel compiler 2017). This is run in a python process using boost C++/python bindings.
Original post:
I am pausing my program randomly to see what are my threads doing during some heavy computation.
Note that I am not debugging a crash, resuming the program works fine.
Howver the VS debugger is sometimes unable to dissassemble the machine code.
For instance, on one thread where rip=000007FE8B048EE2, it shows this:
000007FE8B048EDE ?? ??
000007FE8B048EDF ?? ??
000007FE8B048EE0 ?? ??
000007FE8B048EE1 ?? ??
}
if (params.derandomize) {
000007FE8B048EE2 adc ebp,eax
GetRNG().Seed(id);
000007FE8B048EE4 pop rax
000007FE8B048EE5 wait
000007FE8B048EE6 adc byte ptr [rax],al
000007FE8B048EE8 mov rcx,rax
The decoded x86 instructions also seem wrong (adc, pop, wait, adc ??), so I tried to attach WinDBG as well (non invasive mode):
0:019> u rip
somedll!<lambda239>::operator()+0x132:
000007fe`8b048ee2 13e8 adc ebp,eax
000007fe`8b048ee4 58 pop rax
000007fe`8b048ee5 9b wait
000007fe`8b048ee6 1000 adc byte ptr [rax],al
000007fe`8b048ee8 4889c1 mov rcx,rax
000007fe`8b048eeb 8b9570080000 mov edx,dword ptr [rbp+870h]
000007fe`8b048ef1 e8fa911000 call somedll!bla::bla::blabla::blabla::Seed (000007fe`8b1520f0)
000007fe`8b048ef6 4c8ba5b0080000 mov r12,qword ptr [rbp+8B0h]
Ok, it's the same garbage...
But then I tried to dissassemble from an address slightly above rip:
0:019> u rip-30
somedll!<lambda239>::operator()+0x102:
000007fe`8b048eb2 00488b add byte ptr [rax-75h],cl
000007fe`8b048eb5 084863 or byte ptr [rax+63h],cl
000007fe`8b048eb8 81d003000048 adc eax,48000003h
000007fe`8b048ebe 83f8ff cmp eax,0FFFFFFFFh
000007fe`8b048ec1 740a je somedll!<lambda239>::operator()+0x11d (000007fe`8b048ecd)
000007fe`8b048ec3 4889c2 mov rdx,rax
000007fe`8b048ec6 48899570080000 mov qword ptr [rbp+870h],rdx
000007fe`8b048ecd 486381e0030000 movsxd rax,dword ptr [rcx+3E0h]
0:019> u
somedll!<lambda239>::operator()+0x124:
000007fe`8b048ed4 483bd0 cmp rdx,rax
000007fe`8b048ed7 7501 jne somedll!<lambda239>::operator()+0x12a (000007fe`8b048eda)
000007fe`8b048ed9 cc int 3
000007fe`8b048eda 80b96303000000 cmp byte ptr [rcx+363h],0
000007fe`8b048ee1 7413 je somedll!<lambda239>::operator()+0x146 (000007fe`8b048ef6)
000007fe`8b048ee3 e8589b1000 call somedll!bla::bla::blabla::GetRNG (000007fe`8b152a40)
000007fe`8b048ee8 4889c1 mov rcx,rax
000007fe`8b048eeb 8b9570080000 mov edx,dword ptr [rbp+870h]
0:019> u
somedll!<lambda239>::operator()+0x141:
000007fe`8b048ef1 e8fa911000 call somedll!bla::bla::blabla::blabla::Seed (000007fe`8b1520f0)
000007fe`8b048ef6 4c8ba5b0080000 mov r12,qword ptr [rbp+8B0h]
000007fe`8b048efd 488d95f0070000 lea rdx,[rbp+7F0h]
000007fe`8b048f04 488d8dc0070000 lea rcx,[rbp+7C0h]
000007fe`8b048f0b 498b0424 mov rax,qword ptr [r12]
000007fe`8b048f0f 4c8da570080000 lea r12,[rbp+870h]
000007fe`8b048f16 488942d0 mov qword ptr [rdx-30h],rax
000007fe`8b048f1a 4c8962d8 mov qword ptr [rdx-28h],r12
the first instructions "add byte ptr" and "or byte ptr" at 000007fe`8b048eb2 don't make sense because rip-30 likely falls in the middle of an instruction, but after it seems to resync because it corresponds to the source code:
if (id == params.dbgbreak_id) {
__debugbreak();
}
if (params.derandomize) {
GetRNG().Seed(id);
}
000007fe`8b048ecd 486381e0030000 movsxd rax,dword ptr [rcx+3E0h]
000007fe`8b048ed4 483bd0 cmp rdx,rax // if (id == params.dbgbreak_id) {
000007fe`8b048ed7 7501 jne somedll!<lambda239>::operator()+0x12a (000007fe`8b048eda)
000007fe`8b048ed9 cc int 3 // __debugbreak(); }
000007fe`8b048eda 80b96303000000 cmp byte ptr [rcx+363h],0 // if (params.derandomize)
000007fe`8b048ee1 7413 je somedll!<lambda239>::operator()+0x146 (000007fe`8b048ef6)
000007fe`8b048ee3 e8589b1000 call somedll!bla::bla::blabla::GetRNG (000007fe`8b152a40)
000007fe`8b048ee8 4889c1 mov rcx,rax
000007fe`8b048eeb 8b9570080000 mov edx,dword ptr [rbp+870h]
000007fe`8b048ef1 e8fa911000 call somedll!bla::bla::blabla::blabla::Seed (000007fe`8b1520f0)
clearly there is no instruction begining at 000007fe8b048ee2 !
There is je at 000007fe8b048ee1, and call at 000007fe8b048ee3
So... I thought, hmmm there's a bug in the debugger... let's check the registers:
0:019> r
rax=ffffffffffffffff rbx=000000000021d420 rcx=000000000021d5d0
rdx=0000000002696568 rsi=0000000000005d38 rdi=0000000056eefc40
rip=000007fe8b048ee2 rsp=0000000056eef5b0 rbp=0000000056eef5e0
r8=0000000000000006 r9=000000000021d0b8 r10=0000000006456570
r11=0000000000000006 r12=0000000056eefe50 r13=00000000069a8820
r14=000000000021d1a8 r15=0000000056eefe60
iopl=0 nv up ei pl zr na po nc
cs=0033 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246
What?? rip=000007fe8b048ee2 ?? How is that possible?
It explains why the debugger is showing garbage: it is trying to dissassemble starting from rip, but rip points to the middle of an instruction.
But why is the reported rip wrong? Is the OS culprit?
Am I missing something?
Short Version
Application Verifier says there is an access violation when running the code:
var
shi: TShellExecuteInfo;
begin
shi := Default(TShellExecuteInfo);
shi.cbSize := SizeOf(TShellExecuteInfo);
shi.lpFile := PChar('C:\Windows');
ShellExecuteEx(#shi);
end;
What's wrong with it?
Long Version
I'm running my application under the Application Verifier, with the option to detect heap corruption enabled:
Heaps: Checks the heap errors.
During the call to ShellExecuteEx, an exception comes up, indicating that there is heap corruption.
Running inside a debugger allows me to decode the exception:
ExceptionAddress: 0000000074b254ad (KERNELBASE!ParseURLW+0x000000000000002d)
ExceptionCode: c0000005 (Access violation)
ExceptionFlags: 00000000
NumberParameters: 2
Parameter[0]: 0000000000000000
Parameter[1]: 0000000008e26fe8
Attempt to read from address 0000000008e26fe8
Running outside a debugger, the application crashes (WerFault takes a post-mortem and the process dies).
What is wrong with the code?
Example
program ShellExecuteTestApp;
{$APPTYPE CONSOLE}
uses
System.SysUtils,
Winapi.ShellAPI;
var
shi: TShellExecuteInfo;
begin
try
shi := Default(TShellExecuteInfo);
shi.cbSize := SizeOf(TShellExecuteInfo);
shi.lpFile := PChar('C:\Windows');
WriteLn('shi.cbSize: '+IntToStr(shi.cbSize));
WriteLn('shi.lpFile: "'+shi.lpFile+'"');
ShellExecuteEx(#shi);
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
Before crashing, it outputs:
shi.cbSize: 60
shi.lpFile: "C:\Windows"
I thought perhaps it was the common bug from CreateProcess, so i made sure the lpFile was writable:
var
file: string;
shi: TShellExecuteInfo;
begin
file := 'C:\Windows';
UniqueString({var} file);
shi := Default(TShellExecuteInfo);
shi.cbSize := SizeOf(TShellExecuteInfo);
shi.lpFile := PChar(file);
ShellExecuteEx(#shi);
end;
Memory dumps
Using a 32-bit build (to keep pointers easier to read), the memory being passed to ShellExecuteEx
00423EBC 0000003C cbSize 60 bytes
00000000 fMask SEE_MASK_DEFAULT
00000000 Wnd null
00000000 lpVerb null
0041C600 lpFile ==> 0x0041C60C
00000000 lpParameters null
00000000 lpDirectory null
00000001 nShow SW_NORMAL
00000000 hInstApp 0
00000000 lpIDList null
00000000 lpClass null
00000000 hkeyClass 0
00000000 dwHotKey 0
00000000 hMonitor null
00000000 hProcess null
With the one pointer to a wide char:
0041C60C 43 00 3A 00 5C 00 57 00 C.:.\.W.
0041C614 69 00 6E 00 64 00 6F 00 i.n.d.o.
0041C61C 77 00 73 00 00 00 00 00 w.s.....
It then calls:
ShellExecuteTestApp.dpr.29: ShellExecuteEx(#shi);
0041C51F 68BC3E4200 push $00423ebc ;push address of shi structure
0041C524 E85BD6FFFF call ShellExecuteEx ;call imported function
Winapi.ShellAPI.pas.1798: function ShellExecuteEx; external shell32 name 'ShellExecuteExW';
00419B84 FF250C444200 jmp dword ptr [$0042440c] ;jump to ShellExecuteW inside shell32
shell32.ShellExecuteExW:
75520060 8BFF mov edi,edi
75520062 55 push ebp
75520063 8BEC mov ebp,esp
75520065 83E4F8 and esp,-$08
75520068 51 push ecx
75520069 53 push ebx
7552006A 56 push esi
7552006B 8B7508 mov esi,[ebp+$08]
7552006E 57 push edi
7552006F 833E3C cmp dword ptr [esi],$3c
75520072 7540 jnz $755200b4
75520074 8B5E04 mov ebx,[esi+$04]
75520077 F7C300011000 test ebx,$00100100
7552007D 7427 jz $755200a6
7552007F 8BCE mov ecx,esi
75520081 E836000000 call $755200bc --> failure is this way
And then there's a lot of stuff i can't follow, until the error finally happens in ParseUrlW:
HRESULT ParseURL(
_In_ LPCTSTR pcszUrl,
_Inout_ PARSEDURL *ppu
);
with dump:
KERNELBASE.ParseURLW:
74B25480 8BFF mov edi,edi
74B25482 55 push ebp
74B25483 8BEC mov ebp,esp ;save stack pointer
74B25485 8B4508 mov eax,[ebp+$08] ;restore pcszUrl into EAX
74B25488 83EC0C sub esp,$0c
74B2548B 85C0 test eax,eax ;test that pcszUrl param supplied
74B2548D 0F8493010000 jz $74b25626
Note: At this moment EAX contains address 0x0908BFE8:
0908BFE8: 00 00 00 00 00 00 00 00 ........
The supplied pcszUrl string is empty? Actually no, the address is invalid. But we don't know that yet until the code tries to touch it
74B25493 57 push edi ;save EDI
74B25494 8B7D0C mov edi,[ebp+$0c] ;get PARSEDURL into edi
74B25497 85FF test edi,edi
74B25499 0F8410630300 jz $74b5b7af
Note: At this moment edi contains 0977FBDC
PARSEDURL structure
0977FBCD 00000018 cbSize 24 bytes
753F5BC0 pszProtocol [uninitialized junk]
0977FEC4 cchProtocol [uninitialized junk]
092ECFC8 pszSuffix [uninitialized junk]
78E6E41E cchSuffix [uninitialized junk]
0977FE98 nScheme [uninitialized junk]
74B2549F 833F18 cmp dword ptr [edi],$18 ;test that struct size is what we expect (24 bytes)
74B254A2 0F8507630300 jnz $74b5b7af
74B254A8 53 push ebx ;save ebx
74B254A9 8BD0 mov edx,eax ;save pcszUrl into edx
74B254AB 33DB xor ebx,ebx
74B254AD 0FB700 movzx eax,[eax] ;Attempt to copy 4 bytes of the string into EAX (access violation)
The code tries to copy the first word from 0x0908BFE8 using Move with Zero-Extend. But that address is invalid, giving the access violation:
access violation at 0x74b254ad: read of address 0x0908bfe8
So somewhere in the code of ShellExecuteExW, it sets up an invalid call to ParseUrlW.
WinDBG
32-bit WinDbg, debugging 32-bit application, with symbols:
*******************************************************************************
* *
* Exception Analysis *
* *
*******************************************************************************
*** ERROR: Module load completed but symbols could not be loaded for image00400000
FAULTING_IP:
KERNELBASE!ParseURLW+2d
74b254ad 0fb700 movzx eax,word ptr [eax]
EXCEPTION_RECORD: ffffffff -- (.exr 0xffffffffffffffff)
ExceptionAddress: 74b254ad (KERNELBASE!ParseURLW+0x0000002d)
ExceptionCode: c0000005 (Access violation)
ExceptionFlags: 00000000
NumberParameters: 2
Parameter[0]: 00000000
Parameter[1]: 07634fe8
Attempt to read from address 07634fe8
CONTEXT: 00000000 -- (.cxr 0x0;r)
eax=07634fe8 ebx=00000000 ecx=07634fe8 edx=07634fe8 esi=00000000 edi=093dfbdc
eip=74b254ad esp=093dfbb4 ebp=093dfbc8 iopl=0 nv up ei pl zr na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010246
KERNELBASE!ParseURLW+0x2d:
74b254ad 0fb700 movzx eax,word ptr [eax] ds:002b:07634fe8=????
FAULTING_THREAD: 00003ff4
DEFAULT_BUCKET_ID: INVALID_POINTER_READ
PROCESS_NAME: image00400000
ERROR_CODE: (NTSTATUS) 0xc0000005 - The instruction at 0x%p referenced memory at 0x%p. The memory could not be %s.
EXCEPTION_CODE: (NTSTATUS) 0xc0000005 - The instruction at 0x%p referenced memory at 0x%p. The memory could not be %s.
EXCEPTION_PARAMETER1: 00000000
EXCEPTION_PARAMETER2: 07634fe8
READ_ADDRESS: 07634fe8
FOLLOWUP_IP:
shell32!GetUrlSchemeW+28
754c66be 85c0 test eax,eax
NTGLOBALFLAG: 2000100
APPLICATION_VERIFIER_FLAGS: 80000001
APP: image00400000
ANALYSIS_VERSION: 6.3.9600.17237 (debuggers(dbg).140716-0327) x86fre
PRIMARY_PROBLEM_CLASS: INVALID_POINTER_READ
BUGCHECK_STR: APPLICATION_FAULT_INVALID_POINTER_READ
LAST_CONTROL_TRANSFER: from 754c66be to 74b254ad
STACK_TEXT:
093dfbc8 754c66be 07634fe8 093dfbdc 00000000 KERNELBASE!ParseURLW+0x2d
093dfbf8 75522df8 0746fff0 07604f68 00000002 shell32!GetUrlSchemeW+0x28
093dfe98 75522b1a 093dfec4 00000000 0746fff0 shell32!CShellExecute::CreateParsingBindCtx+0x1d6
093dfecc 755224da 00000000 0746fff0 00000000 shell32!CShellExecute::ParseOrValidateTargetIdList+0x37
093dfef0 7551fd5a 093dff80 768b983a 07604f68 shell32!CShellExecute::_DoExecute+0x40
093dfef8 768b983a 07604f68 768b9770 768b9770 shell32!<lambda_e76b82c5cb7f9f82cbe0fd97ad5190bf>::<lambda_invoker_stdcall>+0x1a
093dff80 73d08484 0019fd94 73d08460 21439000 shcore!_WrapperThreadProc+0xca
093dff94 772c2fea 0019fd94 25ae5778 00000000 KERNEL32!BaseThreadInitThunk+0x24
093dffdc 772c2fba ffffffff 772dec22 00000000 ntdll!__RtlUserThreadStart+0x2f
093dffec 00000000 768b9770 0019fd94 00000000 ntdll!_RtlUserThreadStart+0x1b
STACK_COMMAND: .cxr 0x0 ; kb
SYMBOL_STACK_INDEX: 1
SYMBOL_NAME: shell32!GetUrlSchemeW+28
FOLLOWUP_NAME: MachineOwner
MODULE_NAME: shell32
IMAGE_NAME: shell32.dll
DEBUG_FLR_IMAGE_TIMESTAMP: 0
FAILURE_BUCKET_ID: INVALID_POINTER_READ_c0000005_shell32.dll!GetUrlSchemeW
BUCKET_ID:
APPLICATION_FAULT_INVALID_POINTER_READ_shell32!GetUrlSchemeW+28
ANALYSIS_SOURCE: UM
FAILURE_ID_HASH_STRING: um:invalid_pointer_read_c0000005_shell32.dll!geturlschemew
FAILURE_ID_HASH: {89d9bcf0-5ef6-4e90-df6b-f05dc028e062}
Followup: MachineOwner
---------
Bonus Reading
Access Violation ShellExecute in delphi7
As #RaymondChen said, it's a bug in Windows 10.
I only encountered it because Application Verifier caught it.
it's a one-in-a-million chance that you'd actually ever encounter it in the wild
Raymond's too modest to accept reputation; so i use his answer as my own.
A code that has been running OK for years started to fail with an Access Violation in KernelBase.dll. I think that some Win10 upgrade must have changed something on that dll.
I found this Question and thanks to the comment of #David Heffernan I added the line
ExecInfo.lpParameters := '';
and that solved the problem.
var
ExecInfo: TShellExecuteInfo;
begin
ExecInfo.cbSize := SizeOf(ExecInfo);
ExecInfo.fMask := SEE_MASK_NOCLOSEPROCESS;
ExecInfo.Wnd := 0; // Handle;
ExecInfo.lpVerb := 'runas';
ExecInfo.lpFile := PChar(sPath + sFileName);
ExecInfo.lpDirectory := PChar(sPath);
ExecInfo.nShow := SW_HIDE;
ExecInfo.lpParameters := ''; //PJR#20210125 Added this line to avoid AccessViolation in KernelBase.dll due to a bug in some version of Win10.
if ShellExecuteEx(#ExecInfo) then
(...)
I'm trying to programatically generate a stack trace. When my users are having a crash, in particular a random one, it's hard to talk them through the process of getting a dump so I can fix the problem. In the past once they would send me the trace I would cross reference the addresses in it to the Intermediate/foo.map file to figure out which function was the problem (is that the best way?)
I built a library from various examples I found around the net, to output a minidump to make my job easier. I staged a crash, but the stack trace I get from the minidump file is wildly different from a live stack trace I get from attaching windbg. Examples of both are below:
MiniDump.dmp:
KERNELBASE.dll!76a6c42d()
[Frames below may be incorrect and/or missing, no symbols loaded for KERNELBASE.dll]
KERNELBASE.dll!76a6c42d()
kernel32.dll!75bd14bd()
game.exe!00759035()
game.exe!00575ba3()
WinDbg.exe:
0:000:x86> kv
ChildEBP RetAddr Args to Child
00186f44 00bc8ea9 19460268 0018a9b7 03f70a28 Minidump!crashme+0x2 (FPO: [0,0,0]) (CONV: cdecl) [c:\project\debug\minidump.cpp # 68]
0018795c 00b9ef31 0018796c 03f56c00 6532716d Main!LoadPlugin+0x339 (FPO: [1,642,4]) (CONV: cdecl) [c:\project\main\pluginloader.cpp # 129]
00188968 00b9667d 19460268 0018a9ac 00000000 Main!Command+0x1f1 (FPO: [2,1024,4]) (CONV: cdecl) [c:\project\main\commands.cpp # 2617]
*** WARNING: Unable to verify checksum for C:\Game\game.exe
*** ERROR: Module load completed but symbols could not be loaded for C:\Game\game.exe
0018b1a8 005b5095 19460268 0018beac 00000000 Main!Hook::Detour+0x52d (FPO: [2,2570,0]) (CONV: thiscall) [c:\project\main\hook.cpp # 275]
WARNING: Stack unwind information not available. Following frames may be wrong.
0018b1b4 00000000 19495200 19495200 00000006 game+0x1b5095
game.exe is not mine, and I don't have the source/symbols. The Main.dll is injected into game.exe and it provides front end functionality to load additional DLLs from within the game. The debug code, and the staged crash is in Minidump.dll. After Main.dll loads Minidump it calls AfterLoad(), which sets the exception filter, and then triggers the crash. The relevant minidump code is below:
When I opened the MiniDump.dmp I pointed it to all of my symbol files (with the exception of game.exe, which I don't have) and that part seems like it's working. I do point it to the game.exe binary since I have that. The stack trace I get out of it just really isn't helpful though. My ultimate goal is that the user can just load the DLL, cause the crash, and email the dump file to me. Then I'll attach the symbol files and binaries and be able to diagnose the problem for them. Am I doing something wrong, or is it just not possible to get what I want.
typedef BOOL (WINAPI *MINIDUMPWRITEDUMP)(
HANDLE hProcess,
DWORD ProcessId,
HANDLE hFile,
MINIDUMP_TYPE DumpType,
CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam
);
LONG WINAPI WriteDumpFilter(struct _EXCEPTION_POINTERS *pExceptionPointers)
{
HANDLE hFile = NULL;
HMODULE hDll = NULL;
MINIDUMPWRITEDUMP pMiniDumpWriteDump = NULL;
_MINIDUMP_EXCEPTION_INFORMATION ExceptionInformation = {0};
//load MiniDumpWriteDump
hDll = LoadLibrary(TEXT("DbgHelp.dll"));
pMiniDumpWriteDump = (MINIDUMPWRITEDUMP)GetProcAddress(hDll, "MiniDumpWriteDump");
//create output file
hFile = CreateFile( _T( "C:\\temp\\MiniDump.dmp"),
GENERIC_READ|GENERIC_WRITE, 0, NULL,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
//bail if we don't have a file
if ((hFile != NULL) && (hFile != INVALID_HANDLE_VALUE))
{
//get exception information
ExceptionInformation.ThreadId = GetCurrentThreadId();
ExceptionInformation.ExceptionPointers = pExceptionPointers;
ExceptionInformation.ClientPointers = TRUE;
//write the debug dump
pMiniDumpWriteDump( GetCurrentProcess(), GetCurrentProcessId(),
hFile, MiniDumpWithFullMemory, &ExceptionInformation,
NULL, NULL );
//close the debug output file
CloseHandle(hFile);
}
return EXCEPTION_EXECUTE_HANDLER;
}
VOID crashme() {int* foo = 0; *foo = 0;}
VOID AfterLoad(VOID)
{
SetUnhandledExceptionFilter(WriteDumpFilter);
crashme();
}
I tried to trim some of the fat out of all the details to simplify the problem, but I can be more explicit if needed. I found the good write-up on CodeProject, and I tried finding more background information to read in order to help me understand the problem, but what I could find didn't help me understand they were just step-by-steps to get it running (which is already is). Anyone have any idea what I'm doing wrong, or maybe point me to relevant reading?
After Sergei's suggestion I did .ecxr in windbg and got better output, but it still doesn't match the trace I get when I hook windbg straight up to the process and trigger the crash. Here is the minidump trace;
*** Stack trace for last set context - .thread/.cxr resets it
ChildEBP RetAddr Args to Child
WARNING: Stack unwind information not available. Following frames may be wrong.
0018e774 00759035 e06d7363 00000001 00000003 KERNELBASE!RaiseException+0x58
0018e7b4 00575ba3 00000000 00000000 00000001 game+0x359035
0018fc50 0057788a 009855ef 0018fdcb 00000001 game+0x175ba3
0018fc78 77b7e013 012d9230 002d91d0 002d9200 game+0x17788a
0018fc90 77ba9567 00290000 00000000 002d91d0 ntdll!RtlFreeHeap+0x7e
0018fd6c 0076ece2 0018ff78 007e1b7e ffffffff ntdll!LdrRemoveLoadAsDataTable+0x4e0
002bbc38 5c306174 61666544 00746c75 5d4c3055 game+0x36ece2
002bbc3c 61666544 00746c75 5d4c3055 8c000000 0x5c306174
002bbc40 00746c75 5d4c3055 8c000000 00000101 0x61666544
002bbc44 5d4c3055 8c000000 00000101 01000000 game+0x346c75
002bbc48 8c000000 00000101 01000000 00000000 0x5d4c3055
002bbc4c 00000000 01000000 00000000 0000006e 0x8c000000
and the trace from attaching the debugger to the process
0:000:x86> kv
ChildEBP RetAddr Args to Child
00186f44 00bc8ea9 19460268 0018a9b7 03f70a28 Minidump!crashme+0x2 (FPO: [0,0,0]) (CONV: cdecl) [c:\project\debug\minidump.cpp # 68]
0018795c 00b9ef31 0018796c 03f56c00 6532716d Main!LoadPlugin+0x339 (FPO: [1,642,4]) (CONV: cdecl) [c:\project\main\pluginloader.cpp # 129]
00188968 00b9667d 19460268 0018a9ac 00000000 Main!Command+0x1f1 (FPO: [2,1024,4]) (CONV: cdecl) [c:\project\main\commands.cpp # 2617]
*** WARNING: Unable to verify checksum for C:\Game\game.exe
*** ERROR: Module load completed but symbols could not be loaded for C:\Game\game.exe
0018b1a8 005b5095 19460268 0018beac 00000000 Main!Hook::Detour+0x52d (FPO: [2,2570,0]) (CONV: thiscall) [c:\project\main\hook.cpp # 275]
WARNING: Stack unwind information not available. Following frames may be wrong.
0018b1b4 00000000 19495200 19495200 00000006 game+0x1b5095
I don't have the source for game.exe (I have it for the DLLs which is where the error is), but I decompiled game.exe and here is what is at game+0x359035.
.text:00759001 ; =============== S U B R O U T I N E =======================================
.text:00759001
.text:00759001 ; Attributes: library function bp-based frame
.text:00759001
.text:00759001 ; __stdcall _CxxThrowException(x, x)
.text:00759001 __CxxThrowException#8 proc near ; CODE XREF: .text:0040100Fp
.text:00759001 ; sub_401640+98p ...
.text:00759001
.text:00759001 dwExceptionCode = dword ptr -20h
.text:00759001 dwExceptionFlags= dword ptr -1Ch
.text:00759001 nNumberOfArguments= dword ptr -10h
.text:00759001 Arguments = dword ptr -0Ch
.text:00759001 var_8 = dword ptr -8
.text:00759001 var_4 = dword ptr -4
.text:00759001 arg_0 = dword ptr 8
.text:00759001 arg_4 = dword ptr 0Ch
.text:00759001
.text:00759001 push ebp
.text:00759002 mov ebp, esp
.text:00759004 sub esp, 20h
.text:00759007 mov eax, [ebp+arg_0]
.text:0075900A push esi
.text:0075900B push edi
.text:0075900C push 8
.text:0075900E pop ecx
.text:0075900F mov esi, offset unk_853A3C
.text:00759014 lea edi, [ebp+dwExceptionCode]
.text:00759017 rep movsd
.text:00759019 mov [ebp+var_8], eax
.text:0075901C mov eax, [ebp+arg_4]
.text:0075901F mov [ebp+var_4], eax
.text:00759022 lea eax, [ebp+Arguments]
.text:00759025 push eax ; lpArguments
.text:00759026 push [ebp+nNumberOfArguments] ; nNumberOfArguments
.text:00759029 push [ebp+dwExceptionFlags] ; dwExceptionFlags
.text:0075902C push [ebp+dwExceptionCode] ; dwExceptionCode
.text:0075902F call ds:RaiseException
.text:00759035 pop edi
.text:00759036 pop esi
.text:00759037 leave
.text:00759038 retn 8
.text:00759038 __CxxThrowException#8 endp
My error that I'm triggering is in Minidump.dll, but this code at the top of the stack is in game.exe. There could be plenty going on inside the game.exe that I'm unaware of, could it maybe be hijacking the error that I'm triggering somehow? I.E., I trigger the error in the DLL, but something setup in the game.exe captures program flow before the exception filter that writes the minidump is called?
If that's the case, when I attach the debugger to the process, trigger the error and get the right output that points to the error being in my DLL, then that means game.exe isn't capturing the program flow before the debugger can do the trace. How could I make my minidump code behave the same way... This is getting into territory I'm not terribly familiar with. Any ideas?
I chased further back, and the function calling that one, has this line in it:
.text:00575A8D mov esi, offset aCrashDumpTooLa ; "Crash dump too large to send.\n"
So, I think game.exe is hijacking the exception to do it's own dump before my code tries to get the dump. And then my dumps trace is just a trace of game.exe's dump process...
Answer
I've got it figured out. I'm not sure how to answer my own post, so here is the deal.
.text:0057494A push offset aDbghelp_dll ; "DbgHelp.dll"
.text:0057494F call ds:LoadLibraryA
.text:00574955 test eax, eax
.text:00574957 jz short loc_5749C8
.text:00574959 push offset aMinidumpwrited ; "MiniDumpWriteDump"
.text:0057495E push eax ; hModule
.text:0057495F call ds:GetProcAddress
.text:00574965 mov edi, eax
.text:00574967 test edi, edi
.text:00574969 jz short loc_5749C8
.text:0057496B mov edx, lpFileName
.text:00574971 push 0 ; hTemplateFile
.text:00574973 push 80h ; dwFlagsAndAttributes
.text:00574978 push 2 ; dwCreationDisposition
.text:0057497A push 0 ; lpSecurityAttributes
.text:0057497C push 0 ; dwShareMode
.text:0057497E push 40000000h ; dwDesiredAccess
.text:00574983 push edx ; lpFileName
.text:00574984 call ds:CreateFileA
.text:0057498A mov esi, eax
.text:0057498C cmp esi, 0FFFFFFFFh
.text:0057498F jz short loc_5749C8
.text:00574991 call ds:GetCurrentThreadId
.text:00574997 push 0
.text:00574999 push 0
.text:0057499B mov [ebp+var_1C], eax
.text:0057499E lea eax, [ebp+var_1C]
.text:005749A1 push eax
.text:005749A2 push 0
.text:005749A4 push esi
.text:005749A5 mov [ebp+var_18], ebx
.text:005749A8 mov [ebp+var_14], 1
.text:005749AF call ds:__imp_GetCurrentProcessId
.text:005749B5 push eax
.text:005749B6 call ds:GetCurrentProcess
.text:005749BC push eax
.text:005749BD call edi
.text:005749BF push esi ; hObject
.text:005749C0 call ds:CloseHandle
.text:005749C6 jmp short loc_574A02
Thats from game.exe. It turns out game.exe does it's own minidump. My minidump was triggering after theirs so what I was seeing in my stack trace was a trace of their dump process. I found a dmp file in the game''s installation directory and once I loaded my symbols into it, it showed the correct output I was after.
You are doing just fine. When you open the minidump you generated, after you load the symbols, do
.ecxr
first to set context to what you saved in ExceptionInformation parameter to MiniDumpWriteDump(). Then you will have a legit stack trace.
We use a similar dump generation mechanism at the place where I work.
there are some future gotchas though. You want to check whether your dump catch mechanism is triggered on things like an abort() call.
For that, check out _set_invalid_parameter_handler() and signal(SIGABRT, ...).
I figured it out. Basically game.exe had its own MiniDumpWriteDump code that was triggering before my code. So the stack trace I was getting wasn't a trace of the error, it was a trace of game.exe doing its own MiniDump. I put more details up in the original post.
Thanks!
I'm spending lot of time doing crash debugging of Win32 apps. One thing i'm very curious to know about is, How to find whether any address belongs to stack / heap or program code section. Is there any windbg/ollydbg plugin available for this purpose? Or I've to to it manually from memory map?
Ex:
0:000> r
eax=00930264 ebx=008e0000 ecx=41414592 edx=00930000 esi=41414141 edi=008e0441
eip=00407289 esp=0012fae0 ebp=0012faf4 iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=0038 gs=0000 efl=00010206
MyApp+0x7289:
00407289 8b1437 mov edx,dword ptr [edi+esi] ds:0023:41cf4582=????????
0:000> u eip
MyApp+0x7289:
00407289 8b1437 mov edx,dword ptr [edi+esi]
0040728c 8b4c3704 mov ecx,dword ptr [edi+esi+4]
00407290 57 push edi
00407291 e89ae8ffff call MyApp+0x5b30 (00405b30)
00407296 897d14 mov dword ptr [ebp+14h],edi
00407299 5f pop edi
0040729a 85c0 test eax,eax
0040729c 741e je MyApp+0x72bc (004072bc)
In this case i wanna know which register pointing to which section (code/stack/heap )so that i can proceed further to the root cause.
Thanks in Advance.
0:000> ?#esi+#edi
Evaluate expression: 36278408 = 02299088
0:000> !address 02299088
ProcessParametrs 00311020 in range 00310000 00410000
Environment 02294848 in range 02290000 02390000
02290000 : 02290000 - 00100000
Type 00020000 MEM_PRIVATE
Protect 00000004 PAGE_READWRITE
State 00001000 MEM_COMMIT
Usage RegionUsageHeap
Handle 00310000
I am learning Windbg. And for practice, I am debugging a 64bit fre app that create a process.
I added a breakpoint on CreateProcess (bp KERNEL32!CreateProcessWStub)
When the breakpoint is hit, I disassemble the code (u) and it looks like this:
Breakpoint 0 hit
KERNEL32!CreateProcessWStub:
000007f9`f8024ab4 4c8bdc mov r11,rsp
0:000> u #rip L20
KERNEL32!CreateProcessWStub:
000007f9`f8024ab4 4c8bdc mov r11,rsp
000007f9`f8024ab7 4883ec58 sub rsp,58h
000007f9`f8024abb 488b8424a8000000 mov rax,qword ptr [rsp+0A8h]
000007f9`f8024ac3 498943f0 mov qword ptr [r11-10h],rax
000007f9`f8024ac7 488b8424a0000000 mov rax,qword ptr [rsp+0A0h]
000007f9`f8024acf 498943e8 mov qword ptr [r11-18h],rax
000007f9`f8024ad3 488b842498000000 mov rax,qword ptr [rsp+98h]
000007f9`f8024adb 498943e0 mov qword ptr [r11-20h],rax
000007f9`f8024adf 488b842490000000 mov rax,qword ptr [rsp+90h]
000007f9`f8024ae7 498943d8 mov qword ptr [r11-28h],rax
000007f9`f8024aeb 8b842488000000 mov eax,dword ptr [rsp+88h]
000007f9`f8024af2 89442428 mov dword ptr [rsp+28h],eax
000007f9`f8024af6 8b842480000000 mov eax,dword ptr [rsp+80h]
000007f9`f8024afd 89442420 mov dword ptr [rsp+20h],eax
000007f9`f8024b01 ff1591951100 call qword ptr [KERNEL32!_imp_CreateProcessW (000007f9`f813e098)]
000007f9`f8024b07 4883c458 add rsp,58h
That call to _imp_CreateProcessW is misleading because when I trace (t) to the point where I am right at that call, that's is what I see
KERNEL32!CreateProcessWStub+0x4d:
000007f9`f8024b01 ff1591951100 call qword ptr [KERNEL32!_imp_CreateProcessW (000007f9`f813e098)] ds:000007f9`f813e098={KERNELBASE!CreateProcessW (000007f9`f7578960)}
So it looks like _imp_CreateProcessW address is a relative address (left by the linker?).
And that the data segment register (ds) is used somehow to resolve the final address (in this case, KERNELBASE!CreateProcessW (000007f9`f7578960))
This doesn't make sense though because I read that segments are not used in modern architecture (except for the fs and gs register that hold TCB's address)
My questions are:
what's going on there?
why is CreateProcessW not present in kernel32.dll (only the stub is). MSDN say that CreateProcess is in kernel32.dll
what's the story behind symbols that start with imp. Are they linker artifacts?
Thanks!!!
Note: I run .symfix and .reload at the beginning.
The value of the registers at that moment (right before the call):
0:000> r
rax=0000000000000000 rbx=0000000000000048 rcx=0000000000000000
rdx=0000000000535138 rsi=0000000000000000 rdi=0000000000000000
rip=000007f9f8024b01 rsp=00000000004df550 rbp=0000000000000000
r8=0000000000000000 r9=0000000000000000 r10=0000000000000000
r11=00000000004df5a8 r12=0000000000000000 r13=000007f7abfb1258
r14=0000000000000000 r15=0000000000000000
iopl=0 nv up ei pl nz na po nc
cs=0033 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000206
IIRC __imp_ and stubs were introduced to take care of SxS. You will notice that most if not all kernel32 & kernelbase calls end up calling __imp_.
If regards to stubs, a quick example is
IsDebuggerPresent()
Doing a GetProcAddress on this will return the address of IsDebuggerPresentStub which will jump to IsDebuggerPresent, which in turn will jump to:
_imp__IsDebuggerPresent
In essence, you're correct. The _imp__XXX works a bit like a VFT.