首页
课程
问答
CTF
社区
招聘
峰会
发现
排行榜
知识库
工具下载
看雪20年
看雪商城
证书查询
登录
注册
首页
社区
课程
招聘
发现
问答
CTF
排行榜
知识库
工具下载
峰会
看雪商城
证书查询
社区
编程技术
发新帖
10
3
如何确定线程栈的基址?
发表于: 2023-10-29 09:35
16159
如何确定线程栈的基址?
编程难
3
2023-10-29 09:35
16159
## 缘起 很早之前,我遇到过几个与栈相关的问题,当时总结过几篇关于线程栈的文章,分别是 <a href="elink@ad6K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6T1K9h3q4F1j5$3S2W2L8X3N6F1j5h3&6Q4x3X3g2Y4K9i4c8W2k6g2)9J5k6h3W2G2i4K6u0r3j5i4u0@1K9h3y4D9k6i4y4Q4x3V1k6A6L8Y4c8W2M7X3g2K6N6r3W2F1k6#2)9J5k6r3g2^5j5$3g2H3N6r3W2G2L8W2)9J5k6o6m8^5j5K6l9H3x3o6l9H3k6X3c8Q4x3X3c8U0L8$3&6@1K9h3&6#2k6g2)9J5k6r3S2G2N6#2)9J5k6s2c8G2i4K6u0V1K9h3&6U0M7X3g2S2M7$3g2Q4x3X3c8K6N6r3q4U0K9#2)9J5k6s2y4A6P5X3g2Q4x3V1j5`.">《栈大小可以怎么改?》</a>、<a href="elink@35cK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6T1K9h3q4F1j5$3S2W2L8X3N6F1j5h3&6Q4x3X3g2Y4K9i4c8W2k6g2)9J5k6h3W2G2i4K6u0r3j5i4u0@1K9h3y4D9k6i4y4Q4x3V1k6K6N6r3q4U0K9#2)9J5k6s2k6S2M7X3W2S2j5X3I4W2i4K6u0V1N6i4y4S2k6$3g2Q4x3X3c8G2M7s2c8A6L8h3W2*7j5i4c8A6L8$3&6Q4x3X3c8A6L8Y4k6W2M7%4c8A6k6$3q4@1K9h3!0F1i4K6u0r3">《栈局部变量优化探究,意外发现了 vs 的一个 bug ?》</a>、<a href="elink@973K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6T1K9h3q4F1j5$3S2W2L8X3N6F1j5h3&6Q4x3X3g2Y4K9i4c8W2k6g2)9J5k6h3W2G2i4K6u0r3j5i4u0@1K9h3y4D9k6i4y4Q4x3V1k6S2L8X3!0@1K9r3g2J5i4K6u0V1K9h3&6@1k6i4u0W2M7%4c8A6L8X3N6Q4x3X3c8K6N6r3q4U0K9$3!0$3k6i4u0X3L8r3!0%4i4K6u0r3">《栈又溢出了》</a>、<a href="elink@c85K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6T1K9h3q4F1j5$3S2W2L8X3N6F1j5h3&6Q4x3X3g2Y4K9i4c8W2k6g2)9J5k6h3W2G2i4K6u0r3j5i4u0@1K9h3y4D9k6i4y4Q4x3V1k6A6L8Y4c8W2M7X3g2K6N6r3W2F1k6#2)9J5k6r3g2^5j5$3g2H3N6r3W2G2L8W2)9J5k6o6m8^5j5K6l9H3x3o6l9H3k6X3c8Q4x3V1j5`.">《有趣的异常》</a>。在这几篇总结中,简单的总结了栈溢出的原因,设置线程栈大小的方法。但是还有一点没弄清楚:操作系统是怎么知道一个线程的栈大小的?一定记录在某个位置了,否则就不能正确的在栈溢出的时候抛出异常了。不能根据 `PE` 头中的字段判断,因为在创建线程的时候可以指定线程栈大小。`TEB` 中的 `StackLimit` 是真正的栈底吗?带着这些疑问一起来刨根问底吧~ > **友情提示**:结论在文章末尾。 ## !teb 命令 相信,很多小伙伴儿都知道,可以使用 `!teb` 查看线程相关的信息。  其中的 `StackBase` 和 `StackLimit` 分别指示了栈顶和当前栈使用情况。因为栈是从上向下增长的,所以 `StackBase` 的值比较大。 我之前一直认为这两个字段分别指向了栈顶和栈底(线程栈可以到达的最低位置),可以通过这两个字段计算出线程栈大小。后来才发现 `StackLimit` 并没有指向栈底,而是指向了线程栈当前所到达的最低位置。 线程栈默认的大小是 `1MB`。如果计算一下 `StackBase - StackLimit` 的值即可知道,它们的差值是 `256KB`,而不是 `1MB`。  那么当前线程栈的大小是不是 `1MB` 呢?该如何确认呢?可以通过 `vmmap` 确定。 ## vmmap 打开 `vmmap.exe`,并选择想要查看的进程,即可进行查看。 > **注意:** 当选择的进程已经中断到调试器时,`vmmap.exe` 会一直等待,需要让目标进程运行起来。  可以看到,线程 `9804` 的线程栈大小确实是 `1MB`。 根据以上信息,可以确定 `StackLimit` 并不是真正的线程栈栈底。那么,栈底位置到底记录在哪里了呢? 最近在重翻《软件调试》的时候,发现了一个关键函数。 ## 栈空间自动增长的关键函数 在第 `22` 章 `22.8.1` 节 栈空间的自动增长(`P617`)中提到了一个关键函数 `MiCheckForUserStackOverflow`。该函数是判断栈空间能否增长的关键函数。如果知道该函数是如何实现的,就能找到栈底了。 脑子里很快有了三个选项:`google` 搜索,`ReactOS` 和 `server03` 源码。正好电脑上有源码,不用考虑其它两个选项了。 ## 参考源码 知道了函数名,但是还不知道这个函数在哪个文件中实现的。这个简单,在 `File Locator` 中输入 `MiCheckForUserStackOverflow`,很快就找到了关键的文件。  双击打开 `accesschk.c`,找到 `MiCheckForUserStackOverflow`。注释很清晰的解释了这个函数的作用。  > **说明:** 该函数的实现在 `wrk` 中也可以找到,地址是 <mark class="encrypted">9dcK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Y4K9i4c8Z5N6h3u0Q4x3X3g2U0L8$3#2Q4x3V1k6E0K9h3x3I4x3o6q4Q4x3V1k6%4K9h3&6V1L8%4N6K6i4K6u0r3j5X3I4G2j5W2)9J5c8X3#2S2M7%4c8W2M7W2)9J5c8W2N6d9d9#2)9J5k6s2j5I4i4K6u0W2x3W2)9J5c8X3u0S2M7$3g2Q4x3V1k6F1N6r3!0K6i4K6u0r3L8h3#2Q4x3V1k6S2j5$3y4W2M7$3y4Z5K9#2)9J5k6h3y4Q4c8e0y4Q4z5o6m8Q4z5o6t1`.</mark> 整个函数虽然行数很多,但是有大部分是注释,而且考虑了各种情况。我截取了最关键的部分,如下图:  看样子 `teb->DeallocationStack` 记录了栈底。 `StackBase` 减去 `teb->DeallocationStack` 的值应该是栈大小(默认是 `1MB`)。在 `windbg` 中验证一下。 ## 验证 在 `windbg` 中输入如下命令 `dt _teb 0043f000 -y DeallocationStack -y NtTib.StackBase`,只查看 `DeallocationStack` 和 `NtTib.StackBase` 的值。然后计算差值,发现正好是 `1MB` (`0x100000`)。  ## 总结 - `_TEB` 结构体的 `DeallocationStack` 指向线程栈底,而 `NtTib.StackLimit` 指向的是线程栈当前所到达的最低位置。 - 可以在 `dt` 命令中通过 `-y` 选项来显示特定字段。 - `vmmap.exe` 可以非常详细的展示进程虚拟内存情况。 ## 参考资料 - 《软件调试》第一版 第 `22` 章 - `srv03rtm` 源码
登录后可查看完整内容
传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!!
#基础知识
#其他
收藏
・
10
点赞
・
3
打赏
分享
分享到微信
分享到QQ
分享到微博
赞赏记录
参与人
雪币
留言
时间
PLEBFE
为你点赞~
2024-1-3 02:20
yp太阳神
为你点赞~
2023-10-30 10:16
新气象
为你点赞~
2023-10-29 09:55
查看更多
赞赏
×
1 雪花
5 雪花
10 雪花
20 雪花
50 雪花
80 雪花
100 雪花
150 雪花
200 雪花
支付方式:
微信支付
赞赏留言:
快捷留言
感谢分享~
精品文章~
原创内容~
精彩转帖~
助人为乐~
感谢分享~
最新回复
(
7
)
拉闸太子
雪 币:
3
活跃值:
(466)
能力值:
( LV2,RANK:10 )
在线值:
发帖
0
回帖
35
粉丝
1
关注
私信
拉闸太子
2
楼
感谢楼主 学废了
2023-10-30 17:10
0
秋狝
雪 币:
10076
活跃值:
(34141)
能力值:
( LV2,RANK:10 )
在线值:
发帖
0
回帖
1571
粉丝
39
关注
私信
秋狝
3
楼
感谢分享
2023-10-31 17:39
1
简单的简单
雪 币:
10834
活跃值:
(9146)
能力值:
( LV8,RANK:130 )
在线值:
发帖
18
回帖
200
粉丝
189
关注
私信
简单的简单
1
4
楼
只记得老师曾经说过栈的大小是1024
2023-10-31 18:39
0
编程难
雪 币:
8526
活跃值:
(9256)
能力值:
( LV12,RANK:360 )
在线值:
发帖
64
回帖
156
粉丝
112
关注
私信
编程难
3
5
楼
拉闸太子
感谢楼主 学废了
我也废了
2023-11-15 13:12
0
编程难
雪 币:
8526
活跃值:
(9256)
能力值:
( LV12,RANK:360 )
在线值:
发帖
64
回帖
156
粉丝
112
关注
私信
编程难
3
6
楼
简单的简单
只记得老师曾经说过栈的大小是1024[em_78]
可以改 默认保留大小是 1MB
2023-11-15 13:12
0
编程难
雪 币:
8526
活跃值:
(9256)
能力值:
( LV12,RANK:360 )
在线值:
发帖
64
回帖
156
粉丝
112
关注
私信
编程难
3
7
楼
秋狝
感谢分享
感谢阅读
2023-11-15 13:12
0
kagayaki
雪 币:
2095
活跃值:
(9215)
能力值:
( LV3,RANK:20 )
在线值:
发帖
178
回帖
1369
粉丝
30
关注
私信
kagayaki
8
楼
感谢分享。
2026-1-4 16:25
0
游客
登录
|
注册
方可回帖
回帖
表情
雪币赚取及消费
高级回复
返回
编程难
3
64
发帖
156
回帖
360
RANK
关注
私信
他的文章
[原创]调试技巧 | 从 Win7 到 Win10,DLL引用计数查看全攻略
2816
[原创]调试实战 | 使用 GFlags 与 WinDbg 定位 VS2022 “重复释放” 引发的崩溃
2304
[原创]内存都去哪了?探究 VirtualAlloc 分配背后被“浪费”的 60KB
1779
[原创]调试实战 | 记一次有教益的递归栈查看(续)
11445
[原创]调试实战 | 记一次有教益的递归栈查看
11602
关于我们
联系我们
企业服务
看雪公众号
专注于PC、移动、智能设备安全研究及逆向工程的开发者社区
看原图
赞赏
×
雪币:
+
留言:
快捷留言
为你点赞!
返回
顶部