示例dump分析:空指针访问二
代码
1 2 3 4 5 6 7 8 |
int main() { init_breakpad(); int* p = nullptr; *p = 42; std::cout << "Hello World!\n"; } |
分析步骤
!analyze -v
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 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 |
0:000> !analyze -v ******************************************************************************* * * * Exception Analysis * * * ******************************************************************************* KEY_VALUES_STRING: 1 Key : AV.Dereference Value: NullPtr Key : AV.Fault Value: Write Key : Analysis.CPU.mSec Value: 1186 Key : Analysis.DebugAnalysisProvider.CPP Value: Create: 8007007e on DESKTOP-NRIG174 Key : Analysis.DebugData Value: CreateObject Key : Analysis.DebugModel Value: CreateObject Key : Analysis.Elapsed.mSec Value: 1096 Key : Analysis.Init.CPU.mSec Value: 3281 Key : Analysis.Init.Elapsed.mSec Value: 299672 Key : Analysis.Memory.CommitPeak.Mb Value: 102 Key : Analysis.System Value: CreateObject Key : WER.OS.Branch Value: vb_release Key : WER.OS.Timestamp Value: 2019-12-06T14:06:00Z Key : WER.OS.Version Value: 10.0.19041.1 ADDITIONAL_XML: 1 OS_BUILD_LAYERS: 1 CONTEXT: (.ecxr) rax=0000000000000000 rbx=0000000000000000 rcx=bbe259c6e8750000 rdx=00007ff62b70c140 rsi=0000000000000000 rdi=0000000000000000 rip=00007ff62b616c1e rsp=000000000014fcf0 rbp=000000000014fd10 r8=00000000ffffffff r9=0000000000000001 r10=0000000000000003 r11=000000000014f380 r12=0000000000000000 r13=0000000000000000 r14=0000000000000000 r15=0000000000000000 iopl=0 nv up ei pl zr na po nc cs=0033 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010246 aet_breakpad_test!main+0x2e: 00007ff6`2b616c1e c7002a000000 mov dword ptr [rax],2Ah ds:00000000`00000000=???????? Resetting default scope EXCEPTION_RECORD: (.exr -1) ExceptionAddress: 00007ff62b616c1e (aet_breakpad_test!main+0x000000000000002e) ExceptionCode: c0000005 (Access violation) ExceptionFlags: 00000000 NumberParameters: 2 Parameter[0]: 0000000000000001 Parameter[1]: 0000000000000000 Attempt to write to address 0000000000000000 PROCESS_NAME: aet_breakpad_test.exe WRITE_ADDRESS: 0000000000000000 ERROR_CODE: (NTSTATUS) 0xc0000005 - 0x%p 0x%p %s EXCEPTION_CODE_STR: c0000005 EXCEPTION_PARAMETER1: 0000000000000001 EXCEPTION_PARAMETER2: 0000000000000000 FAULTING_LOCAL_VARIABLE_NAME: p STACK_TEXT: 00000000`0014fcf0 00007ff6`2b622019 : 0000bbe2`00000000 00007ff6`2b6a4c78 00000000`00000000 00007ff6`2b622c6d : aet_breakpad_test!main+0x2e 00000000`0014fe10 00007ff6`2b621ec2 : 00007ff6`2b70b000 00007ff6`2b70b330 00000000`00000000 00000000`00000000 : aet_breakpad_test!invoke_main+0x39 00000000`0014fe60 00007ff6`2b621d7e : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : aet_breakpad_test!__scrt_common_main_seh+0x132 00000000`0014fed0 00007ff6`2b6220ae : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : aet_breakpad_test!__scrt_common_main+0xe 00000000`0014ff00 00007ff8`23537374 : 00000000`00310000 00000000`00000000 00000000`00000000 00000000`00000000 : aet_breakpad_test!mainCRTStartup+0xe 00000000`0014ff30 00007ff8`2367cc91 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : kernel32!BaseThreadInitThunk+0x14 00000000`0014ff60 00000000`00000000 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : ntdll!RtlUserThreadStart+0x21 FAULTING_SOURCE_LINE: Q:\google_code\breakpad\src\src\client\windows\aet_test\aet_breakpad_test\aet_breakpad_test.cpp FAULTING_SOURCE_FILE: Q:\google_code\breakpad\src\src\client\windows\aet_test\aet_breakpad_test\aet_breakpad_test.cpp FAULTING_SOURCE_LINE_NUMBER: 45 FAULTING_SOURCE_CODE: 41: int main() { 42: init_breakpad(); 43: 44: int* p = nullptr; > 45: *p = 42; 46: 47: /*int a = 0; 48: std::string test = "hello"; 49: std::cout << a << std::endl; 50: SYMBOL_NAME: aet_breakpad_test!main+2e MODULE_NAME: aet_breakpad_test IMAGE_NAME: aet_breakpad_test.exe STACK_COMMAND: ~0s ; .ecxr ; kb FAILURE_BUCKET_ID: NULL_POINTER_WRITE_c0000005_aet_breakpad_test.exe!main OS_VERSION: 10.0.19041.1 BUILDLAB_STR: vb_release OSPLATFORM_TYPE: x64 OSNAME: Windows 10 FAILURE_ID_HASH: {b382b65f-0772-5700-a467-eabbe9d5e6c4} Followup: MachineOwner --------- |
- 信息
1
RAX
寄存器中存储了地址0x00000000
,导致mov dword ptr [rax], 2Ah
指令尝试向内存地址0
写入值0x2A
(十进制42
)时触发异常- 在
Windows
系统中,地址0x00000000
属于 保留的无效内存区域(称为空指针地址),任何读写操作都会触发 访问违规异常(STATUS_ACCESS_VIOLATION
,异常码0xC0000005
)
1 2 3 4 5 6 |
CONTEXT: (.ecxr) rax=0000000000000000 rbx=0000000000000000 rcx=bbe259c6e8750000 aet_breakpad_test!main+0x2e: 00007ff6`2b616c1e c7002a000000 mov dword ptr [rax],2Ah ds:00000000`00000000=???????? Resetting default scope |
- 信息
2
- 从异常信息来看,这是一个内存访问违规(
Access Violation
)问题 - 异常地址:
00007ff62b616c1e
(对应代码位置aet_breakpad_test!main+0x2e
)
表明问题发生在main
函数的偏移0x2E
处 - 异常地址:
00007ff62b616c1e
,通常表示导致异常的指令本身的存放地址 - 异常码:
c0000005
,表示 无效的内存访问操作
- 从异常信息来看,这是一个内存访问违规(
1 2 3 4 |
EXCEPTION_RECORD: (.exr -1) ExceptionAddress: 00007ff62b616c1e (aet_breakpad_test!main+0x000000000000002e) ExceptionCode: c0000005 (Access violation) ExceptionFlags: 00000000 |
- 信息
2
总结:- 执行
mov dword ptr [rax],2Ah
这个指令的时候发生了异常,该指令存放在00007ff62b616c1e
这个地址 - 反汇编该地址如下:
- 或者直接在
windbg
的汇编窗口里查看,如下图:
- 执行
1 2 3 4 5 6 7 8 9 10 |
0:000> u 00007ff62b616c1e aet_breakpad_test!main+0x2e [Q:\google_code\breakpad\src\src\client\windows\aet_test\aet_breakpad_test\aet_breakpad_test.cpp @ 45]: 00007ff6`2b616c1e c7002a000000 mov dword ptr [rax],2Ah 00007ff6`2b616c24 33c0 xor eax,eax 00007ff6`2b616c26 488da5e8000000 lea rsp,[rbp+0E8h] 00007ff6`2b616c2d 5f pop rdi 00007ff6`2b616c2e 5d pop rbp 00007ff6`2b616c2f c3 ret 00007ff6`2b616c30 cc int 3 00007ff6`2b616c31 cc int 3 |
- 查看上面的堆栈内容,可以看到是
main
函数里面的
1 2 3 4 5 6 7 8 |
STACK_TEXT: 00000000`0014fcf0 00007ff6`2b622019 : 0000bbe2`00000000 00007ff6`2b6a4c78 00000000`00000000 00007ff6`2b622c6d : aet_breakpad_test!main+0x2e 00000000`0014fe10 00007ff6`2b621ec2 : 00007ff6`2b70b000 00007ff6`2b70b330 00000000`00000000 00000000`00000000 : aet_breakpad_test!invoke_main+0x39 00000000`0014fe60 00007ff6`2b621d7e : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : aet_breakpad_test!__scrt_common_main_seh+0x132 00000000`0014fed0 00007ff6`2b6220ae : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : aet_breakpad_test!__scrt_common_main+0xe 00000000`0014ff00 00007ff8`23537374 : 00000000`00310000 00000000`00000000 00000000`00000000 00000000`00000000 : aet_breakpad_test!mainCRTStartup+0xe 00000000`0014ff30 00007ff8`2367cc91 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : kernel32!BaseThreadInitThunk+0x14 00000000`0014ff60 00000000`00000000 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : ntdll!RtlUserThreadStart+0x21 |
windbg
里面查看异常上下文ds:00000000 00000000
表示通过 数据段基址(ds
)加上偏移量0x00000000
访问内存地址
1 2 3 4 5 6 7 8 9 10 11 |
0:000> .ecxr rax=0000000000000000 rbx=0000000000000000 rcx=bbe259c6e8750000 rdx=00007ff62b70c140 rsi=0000000000000000 rdi=0000000000000000 rip=00007ff62b616c1e rsp=000000000014fcf0 rbp=000000000014fd10 r8=00000000ffffffff r9=0000000000000001 r10=0000000000000003 r11=000000000014f380 r12=0000000000000000 r13=0000000000000000 r14=0000000000000000 r15=0000000000000000 iopl=0 nv up ei pl zr na po nc cs=0033 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010246 aet_breakpad_test!main+0x2e: 00007ff6`2b616c1e c7002a000000 mov dword ptr [rax],2Ah ds:00000000`00000000=???????? |
观察
- 指针
p
是空指针
1 2 |
0:000> dv /i /v prv local 00000000`0014fd18 p = 0x00000000`00000000 |
验证
其他
rbp+8
地址处的8
字节内存(QWORD
)初始化为0
rbp
是基址指针,通常指向当前栈帧的基址rbp+8
可能是栈帧中的 局部变量或参数位置- 在
x86/x64
架构中,内存操作数不能直接操作立即数,必须通过寄存器中转- 因此需将指针值(
0
)加载到rax
,再通过rax
间接访问内存地址
- 因此需将指针值(
1 2 3 |
00007ff6`2b616c12 48c7450800000000 mov qword ptr [rbp+8],0 00007ff6`2b616c1a 488b4508 mov rax,qword ptr [rbp+8] 00007ff6`2b616c1e c7002a000000 mov dword ptr [rax],2Ah |
总结
- 对空指针的访问
示例dump分析:重复释放同一堆内存二
代码
1 2 3 4 5 6 7 8 9 |
int main() { init_breakpad(); int* p = new int(42); delete p; delete p; // 重复释放同一内存 return 0; } |
观察分析
!analyze -v
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 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 |
0:000> !analyze -v ******************************************************************************* * * * Exception Analysis * * * ******************************************************************************* KEY_VALUES_STRING: 1 Key : AV.Fault Value: Read Key : Analysis.CPU.mSec Value: 1061 Key : Analysis.DebugAnalysisProvider.CPP Value: Create: 8007007e on DESKTOP-NRIG174 Key : Analysis.DebugData Value: CreateObject Key : Analysis.DebugModel Value: CreateObject Key : Analysis.Elapsed.mSec Value: 1060 Key : Analysis.Init.CPU.mSec Value: 2249 Key : Analysis.Init.Elapsed.mSec Value: 22350 Key : Analysis.Memory.CommitPeak.Mb Value: 103 Key : Analysis.System Value: CreateObject Key : WER.OS.Branch Value: vb_release Key : WER.OS.Timestamp Value: 2019-12-06T14:06:00Z Key : WER.OS.Version Value: 10.0.19041.1 ADDITIONAL_XML: 1 OS_BUILD_LAYERS: 1 CONTEXT: (.ecxr) rax=00000000000080f3 rbx=0000000000000000 rcx=0000000000008123 rdx=00000000ffffffff rsi=0000000000000000 rdi=0000000000000000 rip=00007ff7c158e08e rsp=000000000014fbf0 rbp=000000000014fcb0 r8=00000000ffffffff r9=0000000000000001 r10=0000000000000003 r11=000000000014fa40 r12=0000000000000000 r13=0000000000000000 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=00010206 aet_breakpad_test!_free_dbg+0x2e: 00007ff7`c158e08e 8b401c mov eax,dword ptr [rax+1Ch] ds:00000000`0000810f=???????? Resetting default scope EXCEPTION_RECORD: (.exr -1) ExceptionAddress: 00007ff7c158e08e (aet_breakpad_test!_free_dbg+0x000000000000002e) ExceptionCode: c0000005 (Access violation) ExceptionFlags: 00000000 NumberParameters: 2 Parameter[0]: 0000000000000000 Parameter[1]: 000000000000810f Attempt to read from address 000000000000810f PROCESS_NAME: aet_breakpad_test.exe READ_ADDRESS: 000000000000810f ERROR_CODE: (NTSTATUS) 0xc0000005 - 0x%p 0x%p %s EXCEPTION_CODE_STR: c0000005 EXCEPTION_PARAMETER1: 0000000000000000 EXCEPTION_PARAMETER2: 000000000000810f STACK_TEXT: 00000000`0014fbf0 00007ff7`c1502ea8 : 00000000`00008123 00007ff7`ffffffff 00000000`0014fca4 00007ff7`c1501553 : aet_breakpad_test!_free_dbg+0x2e 00000000`0014fc30 00007ff7`c15015c8 : 00000000`00008123 00000000`01dfebb0 00000000`01dfedb0 00000000`00000000 : aet_breakpad_test!operator delete+0x18 00000000`0014fc60 00007ff7`c14fbda2 : 00000000`00008123 00000000`00000004 00000002`00000000 00000000`00000002 : aet_breakpad_test!operator delete+0x18 00000000`0014fc90 00007ff7`c1502019 : 000006a6`00000000 00007ff7`c1584c78 00000000`00000000 00007ff7`c1502c6d : aet_breakpad_test!main+0xd2 00000000`0014fe10 00007ff7`c1501ec2 : 00007ff7`c15eb000 00007ff7`c15eb330 00000000`00000000 00000000`00000000 : aet_breakpad_test!invoke_main+0x39 00000000`0014fe60 00007ff7`c1501d7e : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : aet_breakpad_test!__scrt_common_main_seh+0x132 00000000`0014fed0 00007ff7`c15020ae : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : aet_breakpad_test!__scrt_common_main+0xe 00000000`0014ff00 00007ff8`23537374 : 00000000`00392000 00000000`00000000 00000000`00000000 00000000`00000000 : aet_breakpad_test!mainCRTStartup+0xe 00000000`0014ff30 00007ff8`2367cc91 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : kernel32!BaseThreadInitThunk+0x14 00000000`0014ff60 00000000`00000000 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : ntdll!RtlUserThreadStart+0x21 FAULTING_SOURCE_LINE: minkernel\crts\ucrt\src\appcrt\heap\debug_heap.cpp FAULTING_SOURCE_FILE: minkernel\crts\ucrt\src\appcrt\heap\debug_heap.cpp FAULTING_SOURCE_LINE_NUMBER: 1026 FAULTING_SOURCE_CODE: No source found for 'minkernel\crts\ucrt\src\appcrt\heap\debug_heap.cpp' SYMBOL_NAME: aet_breakpad_test!_free_dbg+2e MODULE_NAME: aet_breakpad_test IMAGE_NAME: aet_breakpad_test.exe STACK_COMMAND: ~0s ; .ecxr ; kb FAILURE_BUCKET_ID: INVALID_POINTER_READ_c0000005_aet_breakpad_test.exe!_free_dbg OS_VERSION: 10.0.19041.1 BUILDLAB_STR: vb_release OSPLATFORM_TYPE: x64 OSNAME: Windows 10 FAILURE_ID_HASH: {a7fb9fee-4ecd-ba26-2003-cf7ac09825a3} Followup: MachineOwner --------- |
- 信息
1
- 从异常信息来看,这是一个内存访问违规(
Access Violation
)问题 - 异常地址:
00007ff7c158e08e
(对应代码位置aet_breakpad_test!_free_dbg+0x000000000000002e
)
表明问题发生在_free_dbg
函数的偏移0x2E
处 - 异常地址:
00007ff7c158e08e
,通常表示导致异常的指令本身的存放地址 - 异常码:
c0000005
,表示 无效的内存访问操作
- 从异常信息来看,这是一个内存访问违规(
1 2 3 4 5 6 7 8 |
EXCEPTION_RECORD: (.exr -1) ExceptionAddress: 00007ff7c158e08e (aet_breakpad_test!_free_dbg+0x000000000000002e) ExceptionCode: c0000005 (Access violation) ExceptionFlags: 00000000 NumberParameters: 2 Parameter[0]: 0000000000000000 Parameter[1]: 000000000000810f Attempt to read from address 000000000000810f |
- 信息
1
总结:- 反汇编如下:
- 当前执行位置在
_free_dbg
函数偏移0x2e
处,对应debug_heap.cpp
第1026
行的代码 _free_dbg
是Windows CRT
(C
运行时库)中用于调试堆内存释放的函数,比普通free
函数多出调试信息校验逻辑- 这表明程序可能正在释放动态分配的内存块,但触发了调试堆的校验失败
1 2 3 4 5 6 7 8 9 10 |
0:000> u 00007ff7c158e08e aet_breakpad_test!_free_dbg+0x2e [minkernel\crts\ucrt\src\appcrt\heap\debug_heap.cpp @ 1026]: 00007ff7`c158e08e 8b401c mov eax,dword ptr [rax+1Ch] 00007ff7`c158e091 89442420 mov dword ptr [rsp+20h],eax 00007ff7`c158e095 eb08 jmp aet_breakpad_test!_free_dbg+0x3f (00007ff7`c158e09f) 00007ff7`c158e097 8b442448 mov eax,dword ptr [rsp+48h] 00007ff7`c158e09b 89442420 mov dword ptr [rsp+20h],eax 00007ff7`c158e09f 8b442420 mov eax,dword ptr [rsp+20h] 00007ff7`c158e0a3 89442424 mov dword ptr [rsp+24h],eax 00007ff7`c158e0a7 8b542424 mov edx,dword ptr [rsp+24h] |
1 2 |
0:000> ? rax + 1Ch Evaluate expression: 33039 = 00000000`0000810f |
- 信息
1
总结:- 在
Windows
用户态中,地址0x0000XXXX
通常属于 保留地址空间(如空指针区域),此处内存不可访问
- 在
1 2 3 4 5 6 7 8 9 |
0:000> dq 00000000`0000810f 00000000`0000810f ????????`???????? ????????`???????? 00000000`0000811f ????????`???????? ????????`???????? 00000000`0000812f ????????`???????? ????????`???????? 00000000`0000813f ????????`???????? ????????`???????? 00000000`0000814f ????????`???????? ????????`???????? 00000000`0000815f ????????`???????? ????????`???????? 00000000`0000816f ????????`???????? ????????`???????? 00000000`0000817f ????????`???????? ????????`???????? |
- 信息
1
总结:- 如果内存属性不可访问:
Protect
字段显示为PAGE_NOACCESS
,表明该地址未被分配或已被释放 - 但是看不到相关信息
- 如果内存属性不可访问:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
0:000> !address @rax+1C Mapping file section regions... Mapping module regions... Mapping PEB regions... Mapping TEB and stack regions... Mapping heap regions... Mapping page heap regions... Mapping other regions... Mapping stack trace database regions... Mapping activation context regions... Usage: <unknown> Base Address: 00000000`00000000 End Address: 00000000`0014ea58 Region Size: 00000000`0014ea58 ( 1.307 MB) State: <info not present at the target> Protect: <info not present at the target> Type: <info not present at the target> Allocation Base: <info not present at the target> Allocation Protect: <info not present at the target> Content source: 0 (invalid), length: 146949 |
- 信息
2
- 其实使用
k
,就可以看到连着调了两次delete
,到这里可以确定问题并检查代码了 - 但是实际的负责情况,可能看不这么全,只能结合这个信息查看代码定位
- 其实使用
1 2 3 4 5 6 7 8 9 10 11 12 13 |
0:000> k *** Stack trace for last set context - .thread/.cxr resets it # Child-SP RetAddr Call Site 00 00000000`0014fbf0 00007ff7`c1502ea8 aet_breakpad_test!_free_dbg+0x2e [minkernel\crts\ucrt\src\appcrt\heap\debug_heap.cpp @ 1026] 01 00000000`0014fc30 00007ff7`c15015c8 aet_breakpad_test!operator delete+0x18 [D:\a\_work\1\s\src\vctools\crt\vcstartup\src\heap\delete_scalar.cpp @ 34] 02 00000000`0014fc60 00007ff7`c14fbda2 aet_breakpad_test!operator delete+0x18 [D:\a\_work\1\s\src\vctools\crt\vcstartup\src\heap\delete_scalar_size.cpp @ 31] 03 00000000`0014fc90 00007ff7`c1502019 aet_breakpad_test!main+0xd2 [Q:\google_code\breakpad\src\src\client\windows\aet_test\aet_breakpad_test\aet_breakpad_test.cpp @ 46] 04 00000000`0014fe10 00007ff7`c1501ec2 aet_breakpad_test!invoke_main+0x39 [D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl @ 79] 05 00000000`0014fe60 00007ff7`c1501d7e aet_breakpad_test!__scrt_common_main_seh+0x132 [D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl @ 288] 06 00000000`0014fed0 00007ff7`c15020ae aet_breakpad_test!__scrt_common_main+0xe [D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl @ 331] 07 00000000`0014ff00 00007ff8`23537374 aet_breakpad_test!mainCRTStartup+0xe [D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_main.cpp @ 17] 08 00000000`0014ff30 00007ff8`2367cc91 kernel32!BaseThreadInitThunk+0x14 09 00000000`0014ff60 00000000`00000000 ntdll!RtlUserThreadStart+0x21 |
- 信息
2
- 继续切换栈帧查看其他信息,只能看出来这个
block
不可访问
- 继续切换栈帧查看其他信息,只能看出来这个
1 2 3 4 |
0:000> .frame 01 01 00000000`0014fc30 00007ff7`c15015c8 aet_breakpad_test!operator delete+0x18 [D:\a\_work\1\s\src\vctools\crt\vcstartup\src\heap\delete_scalar.cpp @ 34] 0:000> dv /i /v prv param 00000000`0014fc60 block = 0x00000000`00008123 |
1 2 3 4 5 |
0:000> .frame 02 02 00000000`0014fc60 00007ff7`c14fbda2 aet_breakpad_test!operator delete+0x18 [D:\a\_work\1\s\src\vctools\crt\vcstartup\src\heap\delete_scalar_size.cpp @ 31] 0:000> dv /i /v prv param 00000000`0014fc90 block = 0x00000000`00008123 prv param 00000000`0014fc98 __formal = 4 |
- 信息
2
- 看到相关位置
1 2 3 4 |
0:000> .frame 03 03 00000000`0014fc90 00007ff7`c1502019 aet_breakpad_test!main+0xd2 [Q:\google_code\breakpad\src\src\client\windows\aet_test\aet_breakpad_test\aet_breakpad_test.cpp @ 46] 0:000> dv /v /i prv local 00000000`0014fcb8 p = 0x00000000`00008123 |
结论
- 对堆指针的多次释放
验证
- 用
windbg
动态调试,根据上面观察到的aet_breakpad_test!main
,在这里打断点fdfdfdfd
:调试堆的 已释放内存块头部标记,表示该内存块已被释放abababab
:未初始化或填充区域的标记,用于检测越界访问(如访问未初始化的内存)dddddddd
:堆块尾部填充,用于检测缓冲区溢出(如写入超出分配的内存块尾部)
1 2 3 4 5 6 7 8 9 10 11 12 |
0:000> dw 0x00000000`01dbecf0 00000000`01dbecf0 002a 0000 fdfd fdfd abab abab abab abab 00000000`01dbed00 abab abab abab abab abab abab abab abab 00000000`01dbed10 041d 0000 0000 0000 0000 0000 0000 0000 00000000`01dbed20 00ef 0000 0000 0000 ee33 2b9d bf48 0000 00000000`01dbed30 4de0 01dd 0000 0000 36a0 01dd 0000 0000 00000000`01dbed40 4de0 01dd 0000 0000 36a0 01dd 0000 0000 00000000`01dbed50 dddd dddd dddd dddd 0001 0000 005c 0502 00000000`01dbed60 dddd dddd dddd dddd dddd dddd dddd dddd 0:000> ? 2a Evaluate expression: 42 = 00000000`0000002a |
- 执行完第一次
delete
就变成不可访问了
1 2 |
0:000> dv /i /v prv local 00000000`0014fcb8 p = 0x00000000`00008123 |
- 执行第二次
delete
的时候,就如下
1 2 3 4 |
0:000> dv /i /v prv local 00000000`0014fc14 actual_use = 0n1 prv param 00000000`0014fc30 block = 0x00000000`00008123 prv param 00000000`0014fc38 block_use = 0n-1 |
总结
其他总结如下:
RAX
寄存器
- 在
x64
架构中,RAX
是通用寄存器,常用于存储函数返回值或临时数据
mov
概述
- 汇编语言中最基础且核心的数据传输指令
- 其核心功能是将源操作数的值复制到目标操作数中,且源操作数的内容保持不变
核心功能
- 数据复制
MOV
指令的本质是数据拷贝而非物理移动- 例如:
MOV EAX, EBX
将EBX
寄存器的值复制到EAX
中,EBX
的值不变MOV [0x2000], 0x2A
将立即数0x2A
写入内存地址0x2000
处
- 支持的传输方向
- 立即数 → 寄存器/内存:如
MOV AX, 0x050A
- 寄存器 ↔ 寄存器:如
MOV EAX, EBX
- 寄存器 ↔ 内存:如
MOV [EBX], EAX
将EAX
的值存入EBX
指向的内存单元 - 段寄存器操作:部分场景允许段寄存器与通用寄存器之间的传输(如
MOV DS, AX
),但CS
(代码段寄存器)和IP
(指令指针)不能作为目标操作数
- 立即数 → 寄存器/内存:如
操作数类型与限制
- 源操作数(
Source
)- 立即数:如
MOV EAX, 10
- 寄存器:如
MOV EBX, EAX
- 内存地址:如
MOV ECX, [0x1234]
- 立即数:如
- 目标操作数(
Destination
)- 寄存器:如
MOV EDX, 0xABCD
- 内存地址:如
MOV [EDI], 0x20
- 段寄存器:部分允许(如
MOV ES, AX
),但CS
和IP
不可直接操作
- 寄存器:如
- 关键限制
- 内存到内存禁止:
MOV
指令不支持两个内存单元直接传输,需通过寄存器中转(如MOV AX, [0x01]; MOV [0x02], AX
) - 立即数不可作为目标:如
MOV 0x1000, AX
是非法操作 - 段寄存器间禁止传输:如
MOV DS, ES
无效
- 内存到内存禁止:
应用场景
- 变量初始化与赋值
- 将立即数加载到寄存器:
MOV AL, 0x5
- 全局变量初始化:如
MOV DWORD PTR [var], 42
- 将立即数加载到寄存器:
- 内存与寄存器交互
- 数据存取:如
MOV [EBP-4], EAX
栈帧变量操作 - 数组操作:通过基址+变址寻址访问数组元素
- 数据存取:如
- 系统编程与调试
- 寄存器状态设置:如设置堆栈指针
MOV ESP, 0x7C00
- 寄存器状态设置:如设置堆栈指针
注意事项与扩展功能
- 标志位不受影响
MOV
指令不会修改CPU
状态标志(如ZF
、CF
),仅传输数据
- 变体指令
MOVZX
(零扩展):如MOVZX EAX, AL
将8
位AL
零扩展为32
位EAX
MOVSX
(符号扩展):如MOVSX EDX, BL
将8
位有符号数扩展为32
位MOVS
(串操作):用于块数据传输
ds
寄存器
概述
- 数据段寄存器(
Data Segment Register
),用于指定数据段的内存基址 - 在
x86/x64
架构中,数据段通常存储全局变量、静态数据等
内存地址计算与段寄存器的关系
- 在
x86/x64
架构中,内存访问指令的操作数地址由段寄存器(如ds
)和通用寄存器(如rax
)共同决定 - 默认段寄存器:
- 当指令未显式指定段寄存器时,大多数内存操作默认使用
ds
作为数据段基址寄存器 - 若
rax=0
,则实际访问的物理地址为ds.base + 0x0
,即 数据段基址对应的起始地址
- 当指令未显式指定段寄存器时,大多数内存操作默认使用
1 |
mov dword ptr [rax], 2Ah ; 默认使用 ds 段基址,实际地址 = ds.base + rax |
- 段基址的作用:
ds
存储的是 数据段的基地址(实模式下直接左移4
位,保护模式下通过段描述符表计算)
windbg
查看类型占几个字节
1 2 |
0:000> ?? sizeof(int) unsigned int64 4 |
查看某个指针占几个字节
1 2 |
0:000> ?? sizeof(p) unsigned int64 8 |
对指针解引用
1 2 3 4 5 6 7 8 9 |
0:000> dw poi(p) 00000000`01dbecf0 002a 0000 fdfd fdfd abab abab abab abab 00000000`01dbed00 abab abab abab abab abab abab abab abab 00000000`01dbed10 041d 0000 0000 0000 0000 0000 0000 0000 00000000`01dbed20 00ef 0000 0000 0000 ee33 2b9d bf48 0000 00000000`01dbed30 4de0 01dd 0000 0000 36a0 01dd 0000 0000 00000000`01dbed40 4de0 01dd 0000 0000 36a0 01dd 0000 0000 00000000`01dbed50 dddd dddd dddd dddd 0001 0000 005c 0502 00000000`01dbed60 dddd dddd dddd dddd dddd dddd dddd dddd |
本文为原创文章,版权归Aet所有,欢迎分享本文,转载请保留出处!
你可能也喜欢
- ♥ Dump分析:重复释放堆内存,死锁03/17
- ♥ Windows 核心编程 _ 用户模式:线程同步三07/23
- ♥ 大话数据结构_图表示01/14
- ♥ 打包_7z生成自解压打包exe07/11
- ♥ Windows进程通信相关03/10
- ♥ Soui五05/30