软件大局观--演讲记录

参考演讲视频:

【C++】调试专题辅导_哔哩哔哩_bilibili  --看了下日期是2015.8,时间真快,10年过去了。不过思想是不会过时的。

Windows 32 bit的程序,以winmine.exe为例,说明一个理念。

1. 内存,32bit,4G, 低2G为用户空间,高2G为内核空间

windbg打开winmine.exe

!address可以看到32bit程序的内存分布

0:009> !address

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

  BaseAddr EndAddr+1 RgnSize     Type       State                 Protect             Usage
-----------------------------------------------------------------------------------------------
+        0    10000    10000             MEM_FREE    PAGE_NOACCESS                      Free       
+    10000    11000     1000 MEM_IMAGE   MEM_COMMIT  PAGE_READONLY                      <unknown>  [MZ..............]
     11000    14000     3000 MEM_IMAGE   MEM_COMMIT  PAGE_EXECUTE_READ                  <unknown>  [........q.VV....]
     14000    15000     1000 MEM_IMAGE   MEM_COMMIT  PAGE_READONLY                      <unknown>  [.P.......P......]
     15000    16000     1000 MEM_IMAGE   MEM_COMMIT  PAGE_READWRITE                     <unknown>  [.ML.4......p....]
     16000    17000     1000 MEM_IMAGE   MEM_COMMIT  PAGE_READONLY                      <unknown>  [.........E......]
     17000    18000     1000 MEM_IMAGE   MEM_COMMIT  PAGE_EXECUTE_READ                  <unknown>  [..p..3...A......]
     18000    1a000     2000 MEM_IMAGE   MEM_COMMIT  PAGE_READONLY                      <unknown>  [................]
+    1a000    20000     6000             MEM_FREE    PAGE_NOACCESS                      Free       
+    20000    23000     3000 MEM_MAPPED  MEM_COMMIT  PAGE_READONLY                      MappedFile "\Device\HarddiskVolume3\Windows\System32\l_intl.nls"
+    23000    30000     d000             MEM_FREE    PAGE_NOACCESS                      Free       
+    30000    40000    10000 MEM_MAPPED  MEM_COMMIT  PAGE_READWRITE                     MappedFile "PageFile"
+    40000    5f000    1f000 MEM_MAPPED  MEM_COMMIT  PAGE_READONLY                      Other      [API Set Map]
+    5f000    60000     1000             MEM_FREE    PAGE_NOACCESS                      Free       
+    60000    93000    33000 MEM_PRIVATE MEM_RESERVE                                    <unknown>  
     93000    96000     3000 MEM_PRIVATE MEM_COMMIT  PAGE_READWRITE|PAGE_GUARD          <unknown>  
     96000    a0000     a000 MEM_PRIVATE MEM_COMMIT  PAGE_READWRITE                     <unknown>  [................]
+    a0000    d9000    39000 MEM_PRIVATE MEM_RESERVE                                    Stack      [~0; 87ec.127e4]
     d9000    db000     2000 MEM_PRIVATE MEM_COMMIT  PAGE_READWRITE|PAGE_GUARD          Stack      [~0; 87ec.127e4]
     db000    e0000     5000 MEM_PRIVATE MEM_COMMIT  PAGE_READWRITE                     Stack      [~0; 87ec.127e4]
+    e0000    e4000     4000 MEM_MAPPED  MEM_COMMIT  PAGE_READONLY                      Other      [System Default Activation Context Data]
+    e4000    f0000     c000             MEM_FREE    PAGE_NOACCESS                      Free       
+    f0000    f2000     2000 MEM_MAPPED  MEM_COMMIT  PAGE_READONLY                      Other      [Activation Context Data]
+    f2000   100000     e000             MEM_FREE    PAGE_NOACCESS                      Free       

先说第一段:0-10000,000代表4K,10代表16,16页内存,PAGE_NOACCESS代表不可访问,这时操作系统为支持C++的内存0不可访问的定义,支持程序员的编程习惯,这段区域代表空指针。从上面的分布可以看到,不只是0时空指针,小于64K都是空指针。为什么?这时因为写代码经常定义结构体struct或者class,访问时访问结构的字段偏移,这样访问,struct头上为空,加上偏移就不是0了,也是不可访问。这个知识很重要。内存意外写时最难调试的BUG,这个机制就预防了空指针。这也告诉我们定义struct不要超过64K,容易把其他内容写掉。操作系统用心良苦,避免程序的低级错误。

还有栈空间

栈上面有reserve和free,不放应用数据,这样就不容易被栈溢出踩掉。

+    a0000    d9000    39000 MEM_PRIVATE MEM_RESERVE                                    Stack      [~0; 87ec.127e4]
     d9000    db000     2000 MEM_PRIVATE MEM_COMMIT  PAGE_READWRITE|PAGE_GUARD          Stack      [~0; 87ec.127e4]
     db000    e0000     5000 MEM_PRIVATE MEM_COMMIT  PAGE_READWRITE                     Stack      [~0; 87ec.127e4]
设计非常好,~0,表示0号线程的栈。后面是进程ID.线程ID,栈分为3个部分,PAGE_READWRITE是正在用的,PAGE_GUARD这时保护的,用完了碰到GUARD触发缺页异常,会增长栈grow。RESERVE都用完了,栈就会溢出。

dll注入,taobao.dll会注入,还会有些不靠谱的软件勾到winmine进程里面,我的机器上也有,就不说是谁了,以安全软件的名义勾进来。做什么不得而知。

winmine.exe的位置:我们VC编译的放到4000位置,微软写的放到10 00000,16M的位置。exe是不能重定位的,在vsdutio link的时候有个选项,可以改。

+  1000000  1001000     1000 MEM_IMAGE   MEM_COMMIT  PAGE_READONLY                      Image      [winmine; "winmine.exe"]
   1001000  1005000     4000 MEM_IMAGE   MEM_COMMIT  PAGE_EXECUTE_READ                  Image      [winmine; "winmine.exe"]
   1005000  1006000     1000 MEM_IMAGE   MEM_COMMIT  PAGE_READWRITE                     Image      [winmine; "winmine.exe"]
   1006000  1020000    1a000 MEM_IMAGE   MEM_COMMIT  PAGE_READONLY                      Image      [winmine; "winmine.exe"]
000:4K, 00000:1M  10加5个0,16M

观察堆

如何看到堆的位置:!heap  有14个堆,不能debug

0:001> !heap
Failed to read heap keySEGMENT HEAP ERROR: failed to initialize the extention
Index   Address  Name      Debugging options enabled
  1:   00410000                 tail checking free checking validate parameters
  2:   00ba0000                 tail checking free checking validate parameters
  3:   00d00000                 tail checking free checking validate parameters
  4:   00dd0000                 tail checking free checking validate parameters
  5:   00fb0000                 tail checking free checking validate parameters
  6:   00f40000                 tail checking free checking validate parameters
  7:   02a20000                 tail checking free checking validate parameters
  8:   02ba0000                 tail checking free checking validate parameters
  9:   02d30000                 tail checking free checking validate parameters
 10:   03060000                 tail checking free checking validate parameters
 11:   03b00000                 tail checking free checking validate parameters
 12:   03c70000                 tail checking free checking validate parameters
 13:   03e20000                 tail checking free checking validate parameters
 14:   03bb0000                 tail checking free checking validate parameters

向上搜索可以找到:

bac000   baf000     3000 MEM_PRIVATE MEM_RESERVE                                    Heap       [ID: 1; Handle: 00ba0000; Type: Segment]
查看其中一个堆:!heap 00ba0000 -A

heap中再细分segment, segment上busy表示占用了。

0:001> !heap 00ba0000 -A
Failed to read heap keySEGMENT HEAP ERROR: failed to initialize the extention
Index   Address  Name      Debugging options enabled
  2:   00ba0000 
    Segment at 00ba0000 to 00baf000 (0000c000 bytes committed)
    Flags:                40001062
    ForceFlags:           40000060
    Granularity:          8 bytes
    Segment Reserve:      00100000
    Segment Commit:       00002000
    DeCommit Block Thres: 00000200
    DeCommit Total Thres: 00002000
    Total Free Size:      00000a3b
    Max. Allocation Size: 7ffdefff
    Lock Variable at:     00ba0258
    Next TagIndex:        0000
    Maximum TagIndex:     0000
    Tag Entries:          00000000
    PsuedoTag Entries:    00000000
    Virtual Alloc List:   00ba009c
    Uncommitted ranges:   00ba008c
            00bac000: 00003000  (12288 bytes)
    FreeList[ 00 ] at 00ba00c0: 00ba7120 . 00ba5f68  
        00ba5f60: 00020 . 00010 [104] - free
        00ba6c60: 00230 . 00018 [104] - free
        00ba65a8: 00058 . 00018 [104] - free
        00ba5be0: 00020 . 00018 [104] - free
        00ba5cf8: 00028 . 00018 [104] - free
        00ba3290: 00098 . 00018 [104] - free
        00ba6cb0: 00038 . 00068 [104] - free
        00ba6d78: 00028 . 00100 [104] - free
        00ba68d8: 00028 . 00120 [104] - free
        00ba7118: 00230 . 04ec8 [104] - free

    Segment00 at 00ba0000:
        Flags:           00000000
        Base:            00ba0000
        First Entry:     00ba04a8
        Last Entry:      00baf000
        Total Pages:     0000000f
        Total UnCommit:  00000003
        Largest UnCommit:00000000
        UnCommitted Ranges: (1)

    Heap entries for Segment00 in Heap 00ba0000
         address: psize . size  flags   state (requested size)
        00ba0000: 00000 . 004a8 [101] - busy (4a7)
        00ba04a8: 004a8 . 00118 [107] - busy (117), tail fill Internal 
        00ba05c0: 00118 . 00230 [107] - busy (214), tail fill
        00ba07f0: 00230 . 00498 [107] - busy (480), tail fill
        00ba0c88: 00498 . 00070 [107] - busy (54), tail fill
        00ba0cf8: 00070 . 00098 [107] - busy (80), tail fill
        00ba0d90: 00098 . 00098 [107] - busy (80), tail fill
        00ba0e28: 00098 . 00098 [107] - busy (80), tail fill
        00ba0ec0: 00098 . 00038 [107] - busy (20), tail fill
        00ba0ef8: 00038 . 00020 [107] - busy (4), tail fill
        00ba0f18: 00020 . 00028 [107] - busy (10), tail fill
        00ba0f40: 00028 . 00028 [107] - busy (10), tail fill
        00ba0f68: 00028 . 00038 [107] - busy (1a), tail fill
        00ba0fa0: 00038 . 00098 [107] - busy (80), tail fill
        00ba1038: 00098 . 00098 [107] - busy (80), tail fill
        00ba10d0: 00098 . 00230 [107] - busy (214), tail fill
        00ba1300: 00230 . 00230 [107] - busy (214), tail fill
        00ba1530: 00230 . 00048 [107] - busy (30), tail fill
        00ba1578: 00048 . 00048 [107] - busy (30), tail fill
        00ba15c0: 00048 . 00048 [107] - busy (30), tail fill
        00ba1608: 00048 . 00048 [107] - busy (30), tail fill
        00ba1650: 00048 . 00048 [107] - busy (30), tail fill
        00ba1698: 00048 . 00048 [107] - busy (30), tail fill
        00ba16e0: 00048 . 00028 [107] - busy (c), tail fill
        00ba1708: 00028 . 00028 [107] - busy (c), tail fill
        00ba1730: 00028 . 00030 [107] - busy (c), tail fill
        00ba1760: 00030 . 00040 [107] - busy (25), tail fill

重新跑这个程序:

0:001> .restart /f

进程初始状态的堆栈:

0:000> k
 # ChildEBP RetAddr  
00 000df820 77b92cf1 ntdll!LdrpDoDebuggerBreak+0x2b
01 000dfa68 77b3e831 ntdll!LdrpInitializeProcess+0x1a8e
02 000dfab8 77b6d103 ntdll!_LdrpInitialize+0xd5
03 000dfcf0 77b3e750 ntdll!LdrpInitializeInternal+0xc7
04 000dfd04 77b3e6f1 ntdll!LdrpInitialize+0x3b
05 000dfd10 00000000 ntdll!LdrInitializeThunk+0x11

还可以更早停下来,加载ntdll的时候就停下来,把模块加载事件enable就可以。今天先到这里,未完待续。周末出去happy一下。
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值