版权声明:本文为博主原创文章,未经博主允许不得转载。 https://cloud.tencent.com/developer/article/1344528
/*
* 提示:该行代码过长,系统自动注释不进行高亮。一键复制会移除系统注释
* 系统: windows xp sp3 崩溃软件: 公司内部某文档安全软件 调试工具: windbg 反汇编工具: ida pro 5.5 介绍: 该文档安全软件是由公司内部V\*\*工具启动,当在V\*\*工具输入用户密码连接网络后,V\*\*工具会自动把文档安全软件启动, 但每次启动都会coredump. 由于电脑用了windbg作为实时调试器,每次启动windbg都会弹出来, 显示coredump位置 分析过程: coredump信息 (50c4.50d0): Access violation - code c0000005 (!!! second chance !!!) eax=00000000 ebx=01aa5c62 **ecx=00000000** edx=7efefeff esi=01aa4e34 edi=0012dbe0 eip=10009ffb esp=0012d980 ebp=0012dae0 iopl=0 nv up ei pl zr na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 \*\*\* WARNING: Unable to verify checksum for C:\Program Files\MarkAny\Document SAFER\MAAgtClient.DLL \*\*\* ERROR: Symbol file could not be found. Defaulted to export symbols for C:\Program Files\MarkAny\Document SAFER\MAAgtClient.DLL - MAAgtClient!CDRMLogin::SetDocHeaderByServerAcl+0x54a9: **10009ffb 8b01 mov eax,dword ptr [ecx] ds:0023:00000000=????????** 由上面可以看coredump是由于往空地址里取值. 由 \*\*\* ERROR: Symbol file could not be found. Defaulted to export symbols for **C:\Program Files\MarkAny\Document SAFER\MAAgtClient.DLL** - 可知, coredump地址是位于MAAgtClient.DLL 用IDA打开MAAgtClient.DLL, 查看一下coredump地址的汇编, 看一下ecx是由哪里得到的. .text:10009FD1 loc\_10009FD1: ; CODE XREF: \_strcpy+5 j .text:10009FD1 ; \_strcat+52 j ... **.text:10009FD1** mov **ecx**, [esp+4+Source] .text:10009FD5 test ecx, 3 .text:10009FDB jz short loc\_10009FF6 .text:10009FDD .text:10009FDD loc\_10009FDD: ; CODE XREF: \_strcat+7D j .text:10009FDD mov dl, [ecx] .text:10009FDF inc ecx .text:10009FE0 test dl, dl .text:10009FE2 jz short loc\_1000A048 .text:10009FE4 mov [edi], dl .text:10009FE6 inc edi .text:10009FE7 test ecx, 3 .text:10009FED jnz short loc\_10009FDD .text:10009FEF jmp short loc\_10009FF6 .text:10009FF1 ; --------------------------------------------------------------------------- .text:10009FF1 .text:10009FF1 loc\_10009FF1: ; CODE XREF: \_strcat+9E j .text:10009FF1 ; \_strcat+B8 j .text:10009FF1 mov [edi], edx .text:10009FF3 add edi, 4 .text:10009FF6 .text:10009FF6 loc\_10009FF6: ; CODE XREF: \_strcat+6B j .text:10009FF6 ; \_strcat+7F j .text:10009FF6 mov edx, 7EFEFEFFh **.text:10009FFB mov eax, [ecx]** .text:10009FFD add edx, eax .text:10009FFF xor eax, 0FFFFFFFFh .text:1000A002 xor eax, edx .text:1000A004 mov edx, [ecx] .text:1000A006 add ecx, 4 .text:1000A009 test eax, 81010100h .text:1000A00E jz short loc\_10009FF1 .text:1000A010 test dl, dl .text:1000A012 jz short loc\_1000A048 .text:1000A014 test dh, dh .text:1000A016 jz short loc\_1000A03F .text:1000A018 test edx, 0FF0000h .text:1000A01E jz short loc\_1000A032 .text:1000A020 test edx, 0FF000000h .text:1000A026 jz short loc\_1000A02A .text:1000A028 jmp short loc\_10009FF1 从上面看,主要是这一行 **.text:10009FD1 mov ecx, [esp+4+Source]** 给ecx赋值的. Source这个是指代什么的数据呢? 在IDA中, 应该是这个函数开初就有定义. 由 **.text:10009FD1 loc\_10009FD1: ; CODE XREF: \_strcpy+5 j** **.text:10009FD1 ; \_strcat+52 j ...** 可以看到 .text:10009FD1 是由\_strcat, \_strcpy来引用 先看一下\_strcat的开始 **.text:10009F70 ; char \*\_\_cdecl strcat(char \*Dest, const char \*Source)** .text:10009F70 \_strcat proc near ; CODE XREF: sub\_1000F800+E6 p .text:10009F70 ; sub\_1000F800+F7 p ... .text:10009F70 .text:10009F70 Dest = dword ptr 4 **.text:10009F70 Source = dword ptr 8** 和\_strcpy的开始 **.text:10009F60 ; char \*\_\_cdecl strcpy(char \*Dest, const char \*Source)** .text:10009F60 \_strcpy proc near ; CODE XREF: CDRMLogin::GetUserID(char \*)+3C p .text:10009F60 ; CDRMLogin::GetLocalLoginPW(char \*)+51 p ... .text:10009F60 .text:10009F60 Dest = dword ptr 4 **.text:10009F60 Source = dword ptr 8** 可以看到, Source是指向\_strcat, \_strcpy的第二个参数源字符串的地址. 当这个地址为空,就出现coredump. 那么这个空地址是从哪里传进来的? 还有, coredump的函数是\_strcat还是\_strcpy? 看一下堆栈: 0:000> kb ChildEBP RetAddr Args to Child WARNING: Stack unwind information not available. Following frames may be wrong. 0012dae0 0040bd5f 0012dbe0 0012eb4b 01aa5c56 MAAgtClient!CDRMLogin::SetDocHeaderByServerAcl+0x54a9 **0012daf8 7c980d45 01aa4c14 01aa6038 01aa5c62 MADRMAgent!CAclCCF::~CAclCCF+0x2a1f** 0012db54 7c937d3b 0012dc16 00000524 7c920000 ntdll!RtlWalkFrameChain+0xb3 0012dba4 7c937c02 7c920000 0012dc16 0012dc10 ntdll!LdrGetProcedureAddress+0x4b 0012dc74 7c92dfba 7c802277 7c92d34a 00000086 ntdll!RtlCompareUnicodeString+0x412 00000000 00000000 00000000 00000000 00000000 ntdll!NtWriteVirtualMemory+0xc 根据x86的调用约定, 0040bd5f是上一层的调用者返回地址. 详情请见<coredump问题原理探究>第三章. 先看一下0040bd5f是位于哪个模块 0:000> lm start end module name 00390000 003e1000 cipher (deferred) 003f0000 003f9000 Normaliz (deferred) **00400000 0053b000 MADRMAgent (export symbols) C:\Program Files\MarkAny\Document SAFER\MADRMAgent.exe** 01540000 0157f000 Encryption (deferred) 01fe0000 0202a000 VrvHook (deferred) 020e0000 02108000 ImageSAFERFilter (deferred) 10000000 10029000 MAAgtClient C (export symbols) C:\Program Files\MarkAny\Document SAFER\MAAgtClient.DLL 13000000 1308f000 libdb41 (deferred) 1f840000 1f857000 odbcint (deferred) 3e410000 3e4f7000 WININET (deferred) 3eab0000 3ec9c000 iertutil (deferred) 43ce0000 43e14000 urlmon (deferred) 5adc0000 5adf7000 uxtheme (deferred) 5fdd0000 5fe25000 NETAPI32 (deferred) 60fd0000 61025000 hnetcfg (deferred) 61be0000 61bed000 MFC42LOC (deferred) 62c20000 62c29000 LPK (deferred) 68000000 68036000 rsaenh (deferred) 719c0000 719fe000 mswsock (deferred) 71a00000 71a08000 wshtcpip (deferred) 71a10000 71a18000 WS2HELP (deferred) 71a20000 71a37000 WS2\_32 (deferred) 71a40000 71a4b000 WSOCK32 (deferred) 72240000 72245000 sensapi (deferred) 72f70000 72f96000 WINSPOOL (deferred) 73540000 7357d000 ODBC32 (deferred) 73640000 7366e000 msctfime (deferred) 73d30000 73e22000 MFC42 (deferred) 73fa0000 7400b000 USP10 (deferred) 74680000 746cc000 MSCTF (deferred) 759d0000 75a7f000 USERENV (deferred) 75ff0000 76055000 MSVCP60 (deferred) 76060000 761b6000 setupapi (deferred) 762f0000 762f5000 MSIMG32 (deferred) 76300000 7631d000 IMM32 (deferred) 76320000 76367000 comdlg32 (deferred) 76760000 7676c000 cryptdll (deferred) 76990000 76ace000 ole32 (deferred) 76b10000 76b3a000 WINMM (deferred) 76bc0000 76bcb000 psapi (deferred) 76d30000 76d48000 iphlpapi (deferred) 76d70000 76d92000 Apphelp (deferred) 76e50000 76e5e000 rtutils (deferred) 76e60000 76e72000 rasman (deferred) 76e80000 76eaf000 TAPI32 (deferred) 76eb0000 76eec000 RASAPI32 (deferred) 76ef0000 76f17000 DNSAPI (deferred) 76f90000 76f96000 rasadhlp (deferred) 770f0000 7717b000 OLEAUT32 (deferred) 77180000 77283000 COMCTL32 (deferred) 77bd0000 77bd8000 VERSION (deferred) 77be0000 77c38000 msvcrt (deferred) 77c40000 77c65000 msv1\_0 (deferred) 77d10000 77da0000 USER32 (deferred) 77da0000 77e49000 ADVAPI32 (deferred) 77e50000 77ee3000 RPCRT4 (deferred) 77ef0000 77f39000 GDI32 (deferred) 77f40000 77fb6000 SHLWAPI (deferred) 77fc0000 77fd1000 Secur32 (deferred) 78480000 7850e000 MSVCP90 (deferred) 78520000 785c3000 MSVCR90 (deferred) 7c800000 7c91e000 kernel32 (deferred) 7c920000 7c9b6000 ntdll (export symbols) C:\WINDOWS\system32\ntdll.dll 7d590000 7dd84000 SHELL32 (deferred) Unloaded modules: 71dd0000 71de5000 msapsspc.dll 78080000 78091000 MSVCRT40.dll 767c0000 767e9000 schannel.dll 765e0000 76675000 CRYPT32.dll 76db0000 76dc2000 MSASN1.dll 757f0000 75805000 digest.dll 72f10000 72f57000 msnsspc.dll 78080000 78091000 MSVCRT40.dll 02260000 0227c000 DSWrapper.dll 02280000 0228b000 MASYSID.dll 可见0040bd5f是位于C:\Program Files\MarkAny\Document SAFER\MADRMAgent.exe 用IDA打开MADRMAgent.exe , 并跳转0040bd5f的附近汇编. .text:0040BD57 push edx .text:0040BD58 stosw .text:0040BD5A call ?GetUserID@CDRMLogin@@QAEXPAD@Z ; CDRMLogin::GetUserID(char \*) .text:**0040BD5F** lea eax, [esp+102Ch+var\_F38] 看来堆栈有一些调用没有显示.那么看一下CDRMLogin::GetUserID是在哪定义 0:000> x \*!\*GetUserID\* 00396300 cipher!CFlexibleHeader::GetUserID (<no parameter info>) 0039bc80 cipher!CCCF::GetUserID (<no parameter info>) 003a1080 cipher!CDRMLogic::GetUserID (<no parameter info>) **10004473 MAAgtClient!CDRMLogin::GetUserID (<no parameter info>)** 可见, CDRMLogin::GetUserID是在MAAgtClient.DLL定义 看一下它的汇编: .text:10004473 ; int \_\_stdcall CDRMLogin\_\_GetUserID(char \*Dest) .text:10004473 public ?GetUserID@CDRMLogin@@QAEXPAD@Z .text:10004473 ?GetUserID@CDRMLogin@@QAEXPAD@Z proc near ; DATA XREF: .rdata:off\_1001AB68 o .text:10004473 .text:10004473 var\_150 = byte ptr -150h .text:10004473 var\_C = dword ptr -0Ch .text:10004473 var\_4 = dword ptr -4 .text:10004473 Dest = dword ptr 8 .text:10004473 .text:10004473 mov eax, offset sub\_10014714 .text:10004478 call \_\_EH\_prolog .text:1000447D sub esp, 144h .text:10004483 lea ecx, [ebp+var\_150] .text:10004489 call ds:??0CCCF@@QAE@XZ ; CCCF::CCCF(void) .text:1000448F and [ebp+var\_4], 0 .text:10004493 lea ecx, [ebp+var\_150] .text:10004499 call ds:?CheckCCFValidity@CCCF@@QAEHXZ ; CCCF::CheckCCFValidity(void) .text:1000449F lea ecx, [ebp+var\_150] **.text:100044A5 call ds:?GetUserID@CCCF@@QAEPADXZ ; CCCF::GetUserID(void)** **.text:100044AB push eax ; Source** **.text:100044AC push [ebp+Dest] ; Dest** **.text:100044AF call \_strcpy** .text:100044B4 or [ebp+var\_4], 0FFFFFFFFh .text:100044B8 pop ecx .text:100044B9 pop ecx .text:100044BA lea ecx, [ebp+var\_150] .text:100044C0 call ds:??1CCCF@@UAE@XZ ; CCCF::~CCCF(void) .text:100044C6 mov ecx, [ebp+var\_C] .text:100044C9 mov large fs:0, ecx .text:100044D0 leave .text:100044D1 retn 4 .text:100044D1 ?GetUserID@CDRMLogin@@QAEXPAD@Z endp 从 .text:100044A5 call ds:?GetUserID@CCCF@@QAEPADXZ ; CCCF::GetUserID(void) .text:100044AB push eax ; Source .text:100044AC push [ebp+Dest] ; Dest .text:100044AF call \_strcpy
*/
可知,coredump的地址是位于_strcpy, 而_strcpy的第二个参数是CCCF::GetUserID的返回值.
从这里可以看到, 这里的代码是没有对CCCF::GetUserID的返回值进行判空处理, 从而导致coredump
至于是否会由于strcpy而导致栈溢出, 就先不管了.