マシンレベルのプログラムや制御するためのデータで3.10
3.10.1は、ポインタを理解しました
統一的にポインタ、異なるデータ構造要素を参照します。
1)各ポインタは型に対応します。(ポインタ型のマシンコード;. C言語の一部ではないプログラマがエラーに対処避けるために設けられた抽象化である)
2)各ポインタ値を有しています。この値は、指定された型のオブジェクトのアドレスです。特別なNULL(0)
値はどこにも指していないポインタを表します。
3)「&」演算子は、ポインタを作成します。
4)演算子は、間接的にポインタを参照するために使用されます。
5)配列とポインタ密接。参照としてポインタ変数のような(しかし、変更しない)アレイの名前とすることができます。たとえば、a[3]
同等*(a+3)
。
配列参照とポインタ操作は、オブジェクトのサイズによってオフセットスケーリングする必要があります。
6)ポインタは、その値を変更することなく、唯一の種類を変更する、別のタイプの1つのタイプからキャストします。1つの効果は、鋳造伸縮ポインタ演算を変更することです。
例えば:
char *p = 'c' ;
(int *)p + 7 的结果为 p + 28;
(int *)(p + 7) 的结果为 p + 7。
(さらにより優先さキャスト)
7)関数へのポインタがあると。これは、これらの参照は、呼び出しプログラムのいくつかの他の一部とすることができるコードの参照として非常に強力なストレージと転送機能を提供します。
例えば:
int fun(int x, int *p);
/** 声明指针 fp ,将它赋值为这个函数 */
int (*fp)(int, int *);
fp = fun;
/** 函数调用 */
int y = 1;
int result = fp(3, &y);
関数ポインタの値は、第1の命令アドレスのマシンコード表現の関数です。
3.10.2アプリケーション:GDBデバッガを使用して
まず、実行objdumpのプログラムのバージョンを解体取得します。起動するには、次のコマンドラインGDB:
linux> gdb prog
通常のアプローチは、関心の手続きの場所の近くにブレークポイントを設定することです。
コマンド | 効果 |
---|---|
quit |
やめますGDB |
run |
プログラムを実行します(コマンドライン引数は、ここで与えられました) |
kill |
プログラムを停止 |
break sth |
機能ではsth 入り口にブレークポイントを設定するには |
break *0x400540 |
アドレスでの0x400540 セットブレークポイント |
delete 1 |
ブレークポイントを削除します1 |
delete |
すべてのブレークポイントを削除します。 |
stepi |
実行1 命令の |
stepi 4 |
実行4 命令の |
nexti |
同様にstepi 、関数呼び出しの単位で |
continue |
続けます |
finish |
現在の関数が戻るまで実行 |
disas sth |
分解機能sth |
disas 0x400540 |
分解0x400540 機能近く |
disas 0x400540.0x40054d |
指定された範囲内で分解 |
print /x $rip |
プログラムカウンタの進出力(%rip) 値 |
print $rip |
プログラムカウンタの小数点の出力(%rip) 値 |
print /t $rip |
プログラムカウンタのバイナリ出力(%rip) 値 |
print 0x100 |
出力0x100 小数 |
print /x 555 |
出力555 進 |
print /x ($rsp + 8) |
進出力%rsp + 8 |
print *(long *) 0x7fff ffff e818 |
アドレスでの出力0x7fff ffff e818 長整数 |
print *(long *) (%rsp + 8) |
アドレスでの出力%rsp + 8 長整数 |
x/2g 0x7fffffffe818 |
アドレスをチェック0x7fffffffe818 ダブルワード開始(8 バイト) |
x/20b sth |
機能をチェックsth する前に20 バイト |
info frame |
情報現在のスタックフレーム |
info registers |
すべてのレジスタ |
help |
関連する取得しGDB た情報を |
3.10.3メモリバッファオーバーフローおよびクロスボーダー参照
バッファオーバーフローbuffer overflow
()。文字列を格納するために、スタック上に割り当てられた文字列が、文字列は、配列に割り当てられた領域よりも長くなっています。
例:
echo
対応アセンブリ:
情報は、国境を越えた損傷であろう:
バッファオーバーフローより致命的な使用のプログラムが実行する不本意であったであろう機能を実行できるようにすることです。これは、安全な、最も一般的なコンピュータネットワーク攻撃システムの一つです。
バッファオーバーフロー攻撃に対する3.10.4
1.スタックのランダム化
为了在系统中插入攻击代码,攻击者既要插入代码,也要插入指向这段代码的指针,这个指针也是攻击字符串的一部分。产生这个指针需要知道这个字符串放置的栈地址。
栈随机化的思想使得栈的位置在程序每次运行时都有变化。这类技术称为地址空间布局随机化(Address-Space Layout Randomization
),简称ASLR。
通常攻击者使用空操作雪橇(nop sled
),使程序”滑过“目标序列,即在实际攻击代码前插入一段很长的nop
(读作“no op”
,no operation
的缩写)指令。
示例:
个字节的nop sled
能破解
的栈随机化需要枚举
次。
2. 栈破坏检测
计算机的第二道防线是能够检测到何时栈已经被破坏。
GCC提供一种栈保护者机制,来检测缓冲区越界。其思想是在栈帧中任何局部缓冲区与栈状态之间存储一个特殊的金丝雀(canary
),也称为哨兵值(guard value
),是在程序每次运行时随机产生的。
echo
函数示例:
程序第三行通过段地址%fs:40
从内存读入金丝雀的值,保存在栈中;
程序第十一行取出该值与原地址的值作比较,不相等则栈异常。
tips
:
容易越界的参数尽可能放置在栈底,以保护其他参数。
示例:
图(b
)中,参数v
比数组参数buf
更靠近栈顶,vbuf
缓冲越界不会破坏v
。
3. 限制可执行代码区域
最后一招是消除攻击者向系统插入可执行代码的能力。
随机化、栈保护和限制哪部分内存可以存储可执行代码——是用于最小化程序缓冲区溢出攻击漏洞三种最常见的机制。
3.10.5 支持变长栈帧
前面所讲的各种函数的机器级代码,都有一个共同点,即编译器能够预先确定需要为栈帧分配多少空间。
下面示例为局部存储是变长的。
%rbp
称为帧指针(frame pointer
)有时称为基址帧(base pointer
);
leave
指令将栈帧指针恢复到它之前的值(第20行)。等价于:
movq %rbp, %rsp ;Set stack pointer to begining of frame
popq %rbp ;Restore saved %rbp and set stack ptr to end of caller's frame
重点习题:
答案: