内存中的数据存储

发布者:Seclusion
发布于:2019-10-03 16:43

内存中的数据存储

复习一下计算机原理的知识,整理一下数据在内存中的存储以及编码方式,主要是学习一下整数、浮点数的编码方式,以及由此导致的安全问题。水平有限,归纳不到位的地方还请指正。

知识小贴士

数据在内存中都是按照0/1来排列存储的,在内存层面是没有整数、浮点数之类的区别的;到了语言层面才会谈及这些问题:程序按照程序员声明的数据类型,读取内存,并根据预先设定好的编码方式得到相应数据的值。

存储方式

首先我们要注意一下大小端存储方式的区别,存储方式使用的是大端存储还是小段存储和使用的平台有关。

小端存储就低位数据存储在低地址,大端存储正好相反。

整数

编码

整数的编码有原码、反码、补码三类,计算机内对于整数的存储用补码表示。

上面三种编码方式都是针对signed 整数来说的,对于unsigned自然没必要折腾这些了,当然无符号整数在内存中的编码方式就是原码。

定义

三种编码方式定义如下:

对于正数来说,原码、反码以及补码是其本身;负数的原码是其本身,反码是对原码除符号位之外的各位取反,补码则是反码加1。

举例

原码: +0:0 000 0000,-0:1 000 0000

  反码: +0:0 000 0000,-0: 1 111 1111

  补码: +0:0 000 0000,-0: 1 111 1111+1=1 0000 0000,因为计算机会进行截断,只取低8位,所以-0的补码表示形式为0000 0000。

表示范围

可以看到,只有补码下的+0和-0表示方式是相同的,并且规定补码下的1 000 0000表示为-128(-2^n-1),表示范围较其他两中编码方式多了一个数字。

补码:-2^(n-1)~2^(n-1)-1

原码:-2^(n-1)+1~2^(n-1)-1

反码:-2^(n-1)+1~2^(n-1)-1

计算

补码可以直接带着符号位进行加减运算(不了解的可以去查查资料,网上一大堆),也是因为这个优势加上表示范围大,所以整数的编码方式采用补码的方式。

安全问题

首先先了解一下各种类型的取值范围:

  类型   字节 范围  
  short int  2byte(word)   0~32767(0~0x7fff)
  -32768~-1(0x8000~0xffff)
  unsigned short int   2byte(word)   0~65535(0~0xffff)
  int   4byte(dword)  0~2147483647(0~0x7fffffff)
 -2147483648~-1(0x80000000~0xffffffff)
  unsigned int   4byte(dword)  0~4294967295(0~0xffffffff)
  long int   8byte(qword)   正: 0~0x7fffffffffffffff
  负: 0x8000000000000000~0xffffffffffffffff
  unsigned long int   8byte(qword)   0~0xffffffffffffffff









关于整数溢出的东西ctf-wiki讲得很清楚,其中需要注意的就是边界、有无符号的问题,一般都是在数字范围边界处加减导致的数据错误,以及有无符号数的问题。

比如:

将-1赋值给一个unsigned 数,-1在内存中是0xffffffff(假如是int)来表示的,但是如果按照unsigned来读取的话就会变成一个很大的数;

再有就是数据在边界数加减的话会导致错误,比如无符号0xffffffff(int)+1变成0;

还有就是大范围赋值给小范围,小范围会按照低位截断来读取的,比如

long int a = 0x1000000000000000; int b = 0; b =a ;

那么最后b的值就会按照低位截断,读取a的低四个字节,最终b = 0;

wiki上面还提到了 在汇编层面,有符号是通过寄存器来运算的;而无符号是通过内存来计算的。

abs函数的经典漏洞

abs()函数通过man指令查一下用法

RETURN VALUE
      Returns the absolute value of the integer argument, of the appropriate integer type for the function.

参数是一个int类型的数,返回值是参数的绝对值;

我们知道int类型的数字范围在计算机中表示的话,负数是比整数多一个的(也就是0x80000000),那么0x80000000当做参数穿进去是得不到正确的绝对值的。会出现什么样的后果呢,我们来看一下。

测试脚本:

#include <stdio.h><br>
#include <stdlib.h><br>​<br>
int main()<br>
{<br>        
int a = -0x80000000;<br>        
int b = abs(a);<br>        
printf("the return value of abs(a) is : %d(10)  0x%x(16) .\n",b,b);<br>​<br>        
return 0;<br>
}

效果:

the return value of abs(a) is : -2147483648(10)  0x80000000(16) .

可以看到,当我们输入最小的负数时,abs并不能正确处理,这个问题是计算机整数表示本身设置的问题,以后利用这个函数的时候可要记得规避这个问题。

例子

2019-qwb-babycpp其中便包含了这个漏洞的利用。


浮点数

iddm正在抽时间写o(╥﹏╥)o




reference:

https://www.cnblogs.com/knsbyoo/p/9028056.html
https://ctf-wiki.github.io/ctf-wiki/pwn/linux/integeroverflow/intof-zh/

声明:该文观点仅代表作者本人,转载请注明来自看雪