代码之家  ›  专栏  ›  技术社区  ›  Ian Boyd

应用程序验证程序在调用ShellExecuteEx时报告访问冲突

  •  2
  • Ian Boyd  · 技术社区  · 6 年前

    短版

    应用程序验证程序说,运行代码时存在访问冲突:

    var
       shi: TShellExecuteInfo;
    begin
       shi := Default(TShellExecuteInfo);
       shi.cbSize := SizeOf(TShellExecuteInfo);
       shi.lpFile := PChar('C:\Windows');
       ShellExecuteEx(@shi);
    end;
    

    怎么了?

    长版

    我正在运行我的应用程序 Application Verifier ,并启用检测堆损坏的选项:

    • :检查堆错误。

    enter image description here

    在呼叫期间 ShellExecuteex公司 ,将出现异常,指示存在堆损坏。

    在调试器中运行允许我解码异常:

    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
    

    运行 外部 一个调试器,应用程序崩溃(werfault进行事后分析,进程死亡)。

    密码怎么了?

    例子

    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.
    

    在崩溃之前,它输出:

    shi.cbSize: 60
    shi.lpFile: "C:\Windows"
    

    我想也许是 common bug from CreateProcess ,所以我确定 lpFile 可写:

    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;
    

    禁止内存转储

    使用32位构建(以使指针更易于读取),将内存传递给 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
    

    用一个指向宽字符的指针:

    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.....
    

    然后它会调用:

    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
    

    然后有很多事情我无法理解,直到错误最终发生在 ParseUrlW :

    HRESULT ParseURL(
      _In_    LPCTSTR   pcszUrl,
      _Inout_ PARSEDURL *ppu
    );
    

    转储:

    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
    

    注释 :此时此刻 埃克斯 包含地址0x0908bfe8:

    0908BFE8: 00 00 00 00 00 00 00 00  ........
    

    提供的pcszurl字符串为空?实际上没有,地址无效。但我们还不知道,直到代码试图触及它


    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
    

    注释 :此时此刻 电子数据交换 包含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)
    

    代码尝试使用 Move with Zero-Extend . 但该地址无效,导致访问冲突:

    0x74B254AD的访问冲突:读取地址0x0908bfe8

    所以在密码里的某个地方 外壳执行器 ,它设置了一个无效的调用 帕瑟尔 .

    调试工具

    32位Windbg,调试32位应用程序,带符号:

    *******************************************************************************
    *                                                                             *
    *                        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
    ---------
    

    额外阅读

    1 回复  |  直到 6 年前
        1
  •  2
  •   Ian Boyd    6 年前

    正如@raymondchen所说,这是windows 10中的一个bug。

    雷蒙德太谦虚了,不能接受名声,所以我把他的回答当作自己的回答。