首页
课程
问答
CTF
社区
招聘
峰会
发现
排行榜
知识库
工具下载
看雪20年
看雪商城
证书查询
登录
注册
首页
社区
课程
招聘
发现
问答
CTF
排行榜
知识库
工具下载
峰会
看雪商城
证书查询
社区
Pwn
发新帖
0
1
[原创]整数溢出的处理方式
发表于: 2026-5-21 09:33
4330
[原创]整数溢出的处理方式
Tajang
2026-5-21 09:33
4330
在做 `pwnable.kr` 的 `horcruxes` 时候,遇到整数溢出的问题,导致脚本不稳定。 这里打算写一下计算机处理整数溢出的方法,以及以后写脚本如何处理溢出。也研究一下一些算法的原理。 ## 计算机组成基础 本来想从数学原理,原码、反码、补码详细阐述,并且加上数学证明。没想到知乎大佬写得太棒了。甚至没有什么可删减的,我全部复制也没什么意义。 把链接放在这里,作为前置知识,本篇就只讲代码手动处理溢出的方式与原理。 <a href="elink@53eK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6*7K9s2g2S2L8X3I4S2L8W2)9J5k6i4A6Z5K9h3S2#2i4K6u0W2j5$3!0E0i4K6u0r3M7q4)9J5c8U0V1&6x3o6R3J5x3U0x3$3">二进制的原码、反码、补码——狂风吹我心</a>:这些码产生的原因,以及如何运算,举例丰富。 <a href="elink@6c6K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6*7K9s2g2S2L8X3I4S2L8W2)9J5k6i4A6Z5K9h3S2#2i4K6u0W2j5$3!0E0i4K6u0r3M7q4)9J5c8U0f1$3y4e0t1K6x3K6l9#2y4H3`.`.">一文读懂二进制补码 - 从计数原理开始说起 ——红色的红</a>:完整的数学证明,各种情况的举例证明,非常详细的论证。 **计算机中均采用补码进行加减运算**,有符号整数溢出,采用补码 $2^{32}$ 回绕的方式。 ## 简单原理 补码的字面是无符号的,只不过我们把左起第一位比特定义为符号位 无符号范围:0 ~ 4294967295,有符号范围:-2147483648 ~ 2147483647 ```text 0x00000000 ~ 0x7FFFFFFF => 0 到 2147483647 0x80000000 ~ 0xFFFFFFFF => 负数 ``` 正数很明显是和补码字面对应的,无需操作,而要处理的就是负数。 后半段被映射成负数: | 补码字面(HEX表达) | 无符号 | 有符号 | | :-----------------: | :--------: | :---------: | | 0x7FFFFFFF | 2147483647 | 2147483647 | | 0x80000000 | 2147483648 | -2147483648 | | 0xFFFFFFFF | 4294967295 | -1 | 规则就是:如果值 >= $2^{31}$,有符号值 = 无符号值 - $2^{32}$ 后面的例子都用`9993111111111`和`9992111111111`来解释。首先太长了需要先截断到32位再进行回绕。 | 例子 | HEX | 截断后HEX | 截断后BIN | 正负 | | ------------- | ------------- | ---------- | -------------------------------- | --- | | 9993111111111 | 0x916b3d685c7 | 0xb3d685c7 | 10110011110101101000010111000111 | 负 | | 9992111111111 | 0x916783bbbc7 | 0x783bbbc7 | 01111000001110111011101111000111 | 正 | 所以我们要求有符号值 ,上面例子中: 负数 = 0xb3d685c7 - $2^{32}$ = -1277786681 正数在有效范围内,保留。 ## 代码处理 ### C语言 C语言是固定长度寄存器运算的,对于无符号整数天然就有截断,天然回绕,要注意的是有符号整数: ```c #include <stdio.h> #include <limits.h> int main() { int a = INT_MAX; int b = INT_MIN; int c = 9993111111111; // int型 默认就是32位的 printf("%d\n", a + 1); printf("%d\n", b - 1); printf("%d\n", c); char str[20]; strcpy(str, "9993111111111"); int val = atoi(str); printf("%d\n", val); } ``` 输出 ```text -2147483648 2147483647 -1277786681 -1277786681 ``` ### Python 由于Python是无限精度,导致机器计算出具体值后,与程序存的值不一致,因为程序存的是溢出后的。这里写一下手动把值转换成32位溢出情况下的值。 Python有三种方式处理溢出: #### 1、ctypes自动处理: ```python import ctypes arr = 9993111111111 res = ctypes.c_int32(arr).value print(res) # 输出:-1277786681 ``` #### 2、位运算(最快) ```python arr = 9993111111111 res = arr & 0xFFFFFFFF # 截断 if res > 0x7FFFFFFF: # 判断正负 res -= 0x100000000 # 减去2^32 print(res) # 输出:-1277786681 ``` #### 3、区间折叠 ```python arr = 9993111111111 res = ((arr + 2**31) % 2**32) - 2**31 print(res) # 输出:-1277786681 ``` 32位有符号范围是$[-2^{31}, 2^{31}-1]$,即[-2147483648, 2147483647] 但 `% 2**32` 的结果范围是:$[0, 2^{32}-1]$,也就是无符号范围。 怎么把 无符号 区间重新“折叠”回 有符号 区间? 1. 整体右移$2^{31}$,原本$[-2^{31}, 2^{31}-1]$ 变成 $[0, 2^{32}-1]$,这样两区间就对齐了。 2. 取模,通过`% 2**32`强制限制在 $[0, 2^{32}-1]$,做这一步是因为代码里没有截断,等价于保留低 32 位,如果有截断,就不需要这一步。 3. 再平移回来,通过$- 2^{31}$ ,把区间平移回:$[-2^{31}, 2^{31}-1]$,于是得到了有符号整数
传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!!
收藏
・
0
点赞
・
1
打赏
分享
分享到微信
分享到QQ
分享到微博
赞赏记录
参与人
雪币
留言
时间
wx_晨梦
谢谢你的细致分析,受益匪浅!
2026-7-16 07:31
查看更多
赞赏
×
1 雪花
5 雪花
10 雪花
20 雪花
50 雪花
80 雪花
100 雪花
150 雪花
200 雪花
支付方式:
微信支付
赞赏留言:
快捷留言
感谢分享~
精品文章~
原创内容~
精彩转帖~
助人为乐~
感谢分享~
最新回复
(
0
)
游客
登录
|
注册
方可回帖
回帖
表情
雪币赚取及消费
高级回复
返回
Tajang
15
发帖
25
回帖
50
RANK
关注
私信
他的文章
[求助]Pwnable.kr 的 echo2,理解漏洞原理,但是细节总是有问题,求大佬解答。
3339
[原创]整数溢出的处理方式
4330
[原创]Vehicle Cybersecurity Competition CTF 2025 Writeup
3829
[翻译]RAMN 抗干扰汽车微型网络
3902
关于我们
联系我们
企业服务
看雪公众号
专注于PC、移动、智能设备安全研究及逆向工程的开发者社区
看原图
赞赏
×
雪币:
+
留言:
快捷留言
为你点赞!
返回
顶部