記憶體中的資料儲存

sfftlt_發表於2019-10-03

記憶體中的資料儲存

複習一下計算機原理的知識,整理一下資料在記憶體中的儲存以及編碼方式,主要是學習一下整數、浮點數的編碼方式,以及由此導致的安全問題。水平有限,歸納不到位的地方還請指正。

知識小貼士

資料在記憶體中都是按照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/

相關文章