常量,通常指在程式中出現的數字1,2,3
,等,字串
「hello world
」,以及陣列名稱等,他們都屬於常量。在程式中是不允許修改他們的值。
虛假常量
const挑戰真正常量
define
下面一段程式:
**前面定義了:
程式除錯,反彙編如下:
如上圖所示:
首先:程式是將立即數8bah
(立即數可以作為彙編的運算元)直接儲存到
const
修飾的常量
cnum
中,其位址為
ebp-0ch;
第一條cout指令輸出
cnum
ebp-0ch
,同時將其存入
ecx並進棧,作為
cout
函式呼叫的引數;
第二條cout指令輸出
cnum
的值:
可以看到,程式中並沒有使用到cnum
變數的位址
[ebp-0ch]
,而是通過直接將立即數:
8bah(=2234
)直接壓棧,作為
cout
函式的引數;
也就是說當程式中需要用到cnum
的值得時候,系統已經用「真正的值」對其進行了替換。
綜上所述,可以發現,所謂的const
修飾的常量,其本質還是變數,程式依然是在堆疊中進行空間分配。那麼程式又是通過什麼來阻止程式設計師修改
const
修飾的變數的呢?《
c++反彙編與逆向分析技術揭秘》一書中曾提到,
const
關鍵字的作用域是在程式編譯過程中,也就是說程式在編譯過程中通過某種檢測能夠阻止對
const
修飾的變數的修改。可以嘗試對
cnum
變數進行修改,然後對檔案進行編譯,發現編譯過程中就會出現錯誤。那麼到底怎麼才能修改
cnum
記憶體中的數值呢?現在的限制條件只有
const
關鍵字一條,那麼我們可以將
cnum
的位址複製給乙個沒有
const
修飾的指標,例如
pnum
,然後通過
pnum
來修改記憶體中的值。嘗試如下。
int *pnum=(int*)&cnum;
*pnum=1111;
cout<
cnum所指向的記憶體空間中的數值已經修改,但是編譯過的程式中出現
cnum
的地方還是維持原來的數值(
(既然在出現cnum
的地方,編譯器已經用已知的預設值對其進行了替換,那麼修改變數記憶體中的值起始對程式應該是沒有任何影響的。)
真正的常量:數字、字元、字串
程式中的數字、字元都是直接作為立即數參與彙編指令運算。即其儲存位置是**段。結果如下圖:(利用vs2008
自帶的反彙編視窗,選中「顯示**位元組」)
可見,十六進製制的數:0x12345678
直接被編譯成了彙編指令,儲存在**段:
0x00411554h
位置。
也可利用微軟visual studio
提供的命令列編譯工具:
dumpbin.exe
(通常存在的路徑是:
c:\program files\microsoft visual studio 9.0\vc\bin\)
dumpbin /all ***.exe,結果截圖如下:
下面看一下字串的儲存:
(測試**同上)
如上圖所示:
第一條指令:
將「hello world
」傳遞給
str字串的時候,直接從檔案的唯讀區
00417810h
讀取,從反彙編**可以看出,程式利用
eax、
ecx、
edx三個暫存器將
00417810h
唯讀區域的字串常量「
hello world
」拷貝到
str所代表的記憶體堆疊空間ebp-38h中。
第二條指令:定義了乙個字串指標,可以看到其彙編指令只有短短的一行,只是將字串在唯讀區域的位址00417880h
傳遞給了指標所指向的堆疊空間。
兩者指令完全相同,都是將所指向的字串的位址傳遞給了i/o
流函式cin。
同樣利用dumpbin.exe
工具可以看到唯讀區域的原始**如下:
js真假判斷
自從接觸js的真假判斷後,感覺整個世界都發生了變化。一些不是boolean的東東可以參與if判斷返回true和false。在c 中,只有布林值或布林表示式才可以參與if判斷,進行流程控制。我總結了一下發現,在js裡,一般認為有內容或存在的 值或物件,0除外 進行判斷時就是true值,而沒有內容或不存...
Vue真假分頁
一共100條資料,我要分10頁顯示,每頁顯示10條 一共100條資料,我要分5頁顯示,每頁顯示20條 一共99條資料,我要分5頁顯示,每頁顯示20條 理論上這三個引數,獲取任意兩個,便可知道第三個,但由於鎮假分頁的概念,所以在真分頁中只能選擇 pagenum,和pagesize,不然則是假分頁啦,既...
真假Root賬號
真假 root 賬號 本案例 於 unix linux網路日誌分析與流量監控 一書,主要講述了新老管理員在unix伺服器交接時,新任管理員發現了系統的passwd shadow均被修改,隨後管理員開始深入調查,更多的問題浮出水面,到底那台伺服器被做過什麼 手腳 呢?難度係數 故事人物 趙雲 新任管理...