2017-2018-1 20155215 《信息安全系統設計基礎》第13周學習總結

2017-2018-1 學號 《信息安全系統設計基礎》第13周學習總結

我認爲最重要的一章是第三章。本章主要學習的就是彙編語言,信息安全的核心思惟方式就是「逆向」,反彙編就是直接的逆向工程。因此我這篇博客寫的是第三章的內容總結。html


教材學習內容總結

程序的機器級表示

歷史數組

  • Intel處理器系列:俗稱x86,開始時是第一代單芯片、16位微處理器之一。
  • DOS時代的平坦模式,不區分用戶空間和內核空間,很不安全;
  • 8086的分段模式;
  • IA32的帶保護模式的平坦模式
  • 每一個後繼處理器的設計都是後向兼容的,能夠保證較早版本上編譯的代碼在較新的處理器上運行。

程序編碼:安全

  • GCC將源代碼轉化爲可執行代碼的步驟:
    • C預處理器——擴展源代碼-生成.i文件
    • 編譯器——產生兩個源代碼的彙編代碼-——生成.s文件
    • 彙編器——將彙編代碼轉化成二進制目標代碼——生成.o文件
    • 連接器——產生可執行代碼文件
gcc -o mstore mstore.c
gcc -Og -S mstore.c
gcc -Og -c mstore.c

兩種抽象:
- 指令集結構ISA:是機器級程序的格式和行爲,定義了處理器狀態、指令的格式,以及每條指令對狀態的影響。
- 機器級程序使用的存儲器地址是虛擬地址,看上去是一個很是大的字節數組,其實是將多個硬件存儲器和操做系統軟件組合起來。oop

機器級代碼學習

控制測試

一、條件碼編碼

CF:進位標誌 
ZF:零標誌
SF:符號標誌
OF:溢出標誌

二、訪問條件碼操作系統

SET指令根據t=a-b的結果設置條件碼;
能夠條件跳轉到程序的某個其餘部分;
能夠有條件的傳送數據。翻譯

三、跳轉指令及其編碼設計

jump指令

直接跳轉:後面跟標號做爲跳轉目標
間接跳轉:*後面跟一個操做數指示符
其餘跳轉指令

除了jump指令外,其餘跳轉指令都是有條件的。有條件跳轉是指根據條件碼的某個組合,或者跳轉或者繼續執行下一條指令。

四、循環

循環結構的三種形式

do-while:先執行循環體語句,再執行判斷,循環體至少執行一次。
while: 把循環改爲do-while的樣子,而後用goto翻譯 
for: 把循環改爲do-while的樣子,而後用goto翻譯
彙編中用條件測試和跳轉組合實現循環的效果。大多數彙編器根據do-while形式來產生循環代碼,其餘的循環會首先轉換成do-while形式,而後再編譯成機器代碼。

五、switch語句

跳轉表是一種很是有效的實現多重分支的方法,是一個數組,表項i是一個代碼段的地址,這個代碼段實現當開關索引值等於i時程序應該採起的動做。

教材學習

  • 課本上P114頁的代碼如圖所示:
long mult2(long,long);

void multstore(long x,long y,long *dest){

   long t= mult2(x,y);
   *dest = t;
}

  • 課本上P116頁的代碼以下所示
#include<stdio.h>
void multstore(long,long,long*);

int main(){
    long d;
    multstore(2,3,&d);
    printf("2*3 --> %ld\n",d);
    return 0;
}

long mult2(long a,long b){

    long s=a*b;
    return s;

}
  • 輸入指令
gcc -Og -o prog ms1.c mstore.c
objdump -d prog

  • 生成的彙編代碼以下:

  • 與P114的代碼的反彙編結果對比可看出來,代碼是差很少的,

家庭做業

3.58

store_prod:  
  movq      %rdx, %rax               (y-->%rax)(設爲b0)  
  cqto                               (將%rax符號拓展位八字,拓展的y的高位數據保存在%rdx裏,此值爲y的高位:b1)  
  movq      %rsi, %rcx               (x-->%rcx )(設爲a0)  
  sarq      $63,  %rcx               (拓展x的符號位爲64位,並保存到%rcx,此值爲x的高位:a1)  
  imulq     %rax, %rcx               (k1 = b0*a1)  
  imulq     %rsi, %rdx               (k2 = a0*b1)  
  addq      %rdx, %rcx               (k1+k2)  
  mulq      %rsi                     (128位無符號全乘法,計算 %rsi  * %rax  ,結果的高64位存儲在:%rdx,低64位存儲在:%rax)  
  addq      %rcx, %rdx               (k1+k2+%rdx)    
  movq      %rax, (%rdi)             (存儲最終的低64位結果到內存)     
  movq      %rdx, 8(%rdi)            (存儲最終的高64位結果到內存)     
  ret
  • 等價的C代碼爲(((y-z)<<63)>>63)^((y-z)*x)

  • 3.59
  • %rdx與%rax共同表明一個128位數的意思,是指用能夠用計算公式%rdx*2^64+%rax來表示這個數,而並非把這%rdx和%rax的二進制串串連起來表示這個數,區別在於,當這個數爲負數的時候,%rdx是-1.意思是全部位都爲1,而若是串連起來的話,顯然只有%rdx的第一位爲1,後面全爲0.所以這裏的數學公式推理才正確,因此對於彙編的第10行爲何要加上%rcx,就不要用串連起來的表示方法去想象這一行的正確性,而應該用數學公式去推.
    下面用x0,y0來分別表示x和y的低位,用x1,y1來分別表示x和y的高位,用W表示2^64,所以下面的公式成立:
p = x * y
   = (x1*W + x0) * (y1*W + y0) 
   = (x1*y1*W*W) + W(x1*y0+x0*y1) + x0*y0

公式中x1y1WW超過了128位,並且未超出128位部分始終全爲0,所以能夠去掉.因而公式變成了p=W(x1y0+x0y1) + x0y0,而後能夠繼續轉化,注意這裏的x0y0是極可能會超出64位的,假設x0y0的超出64位的部分爲z1,未超出64位的部分爲z0.那麼公式能夠變成以下:

p = W(x1y0+x0y1+z1) + z0
1
很明顯,須要將x1y0+x0y1+z1放到最終結果的高位,即(%rdi),z0放到最終結果的低位,即8(%rdi)
而後仔細翻譯下各個語句

store_prod:
    movq   %rdx, %rax   # %rax = y0.
    cqto                # 有符號運算,所以用cqto,這裏會自動關聯%rdx和%rax分別表示高位和低位,假如y是負數,那麼%rdx全部位都是1(此時值是-1),不然,%rdx全爲0, %rdx = y1.
    movq   %rsi, %rcx   # %rcx = x0.
    sarq   $63,  %rcx   # 將%rcx向右移63位,跟%rdx的含義同樣,要麼是-1,要麼是0, %rcx = x1.
    imulq  %rax, %rcx   # %rcx = y0 * x1
    imulq  %rsi, %rdx   # %rdx = x0 * y1
    addq   %rdx, %rcx   # %rcx = y0 * x1 + x0 * y1
    mulq   %rsi         # 無符號計算 x0*y0,並將x0*y0的128位結果的高位放在%rdx,低位放在%rax,所以這裏%rdx = z1, %rax = z0.
    addq   %rcx, %rdx   # %rdx = y0*x1+x0*y1+z1
    movq   %rax, (%rdi) # 將%rax的值放到結果的低位
    movq   %rdx, 8(%rdi)# 將%rdx的值放到結果的高位,能夠發現跟上面用數學公式推理的結果徹底一致!!!!
    ret

****3.60**

loop:
    movl  %esi, %ecx # %ecx=n;
    movl  $1, %edx   # %edx=1; --> mask 
    movl  $0, %eax   # %eax=0; --> result
    jmp   .L2
.L3:
    movq  %rdi, %r8  # %r8=x;
    andq  %rdx, %r8  # %r8=x&%rdx; -->x&mask
    orq   %r8, %rax  # %rax=%rax | (x&%rdx); -->result |= x & mask
    salq  %cl, %rdx  # %rdx=%rdx<<(n&0xFF); -->mask<<=(n&0xFF)
.L2:
    testq %rdx, %rdx
    jne   .L3.       # if %rdx!=0 goto L3. -->mask!=0
    rep; ret

A.

%rdi, %r8 --> x
%esi, %ecx --> n
%rdx --> mask
%rax --> result

B.

result = 0;
mask = 1;

C.

mask != 0

D.

mask<<=(n&0xFF)

E.

result |= x & mask

F.

long loop(long x, int n)
{
    long result = 0;
    long mask;
    for(mask = 1;mask != 0;mask = mask << (n&0xFF)){
        result |= x & mask;
    }
    return result;
}

3.61

傳送指令會對條件分別求值,因而假如xp爲空指針,那麼這裏產生對空指針讀數據的操做,顯然是不能夠的。因而這裏不能存在*xp,能夠用指針來代替,最後判斷出值以後,再進行讀取數據,所以這裏0也必須賦予一個地址,因而須要加個變量來存儲0這個數字。所以答案能夠是:

long cread_alt(long *xp)
{
    int t=0;
    int *p = xp ? xp : &t;
    return *p;
}

**3.62

這個題就是純翻譯彙編,沒有什麼可講的。

case MODE_A:
    result = *p2;
    action = *p1;
    *p2 = action;
    break;
case MODE_B:
    result = *p1 + *p2;
    *p1 = result;
    break;
case MODE_C:
    *p1 = 59;
    result = *p2;
    break;
case MODE_D:
    result = *p2;
    *p1 = result;
    result = 27;
    break;
case MODE_E:
    result = 27;
    break;
default:
    result = 12;

**3.63

<switch_prob>:
    400590: 48 83 ee 3c    sub $0x3c, %rsi
    # 說明下面的數都要加上60 
    400594: 48 83 fe 05    cmp $0x5, %rsi
    400598: 77 29          ja  4005c3 <switch_prob+0x33>
    # 若是大於65,跳到4005c3那一行
    40059a: ff 24 f5 f8 06 40 00   jmpq *0x4006f8(,%rsi,8)
    # 跳到跳轉表對應的位置,假設跳轉表對應數組a[x],那麼分別跳到a[0x4006f8+8*(n-60)]的位置
    4005a1: 48 8d 04 fd 00 00 00   lea  0x0(,%rdi,8),%rax
    # 60和62會跳到這個位置
    4005a8: 00
    400593: c3             retq
    4005aa: 48 89 f8       mov %rdi, %rax
    # 63會跳到這個位置
    4005ad: 48 c1 f8 03    sar $0x3, %rax
    4005b1: c3             retq
    4005b2: 48 89 f8       mov %rdi, %rax
    # 64會跳到這個位置
    4005b5: 48 c1 e0 04    shl $0x4, %rax
    4005b9: 48 29 f8       sub %rdi, %rax
    4005bc: 48 89 c7       mov %rax, %rdi
    4005bf: 48 0f af ff    imul %rdi, %rdi
    # 65會跳到這個位置
    4005c3: 48 8d 47 4b    lea 0x4b(%rdi), %rax
    # 大於65和61會跳到這個位置
    4005c7: c3             retq

根據上面的分析過程可得答案以下:

long switch_prob(long x, long n){
    long result = x;
    switch(n):{
        case 60:
        case 62:
            result = x * 8;
            break;
        case 63:
            result = result >> 3;
            break;
        case 64:
            result = (result << 4) - x;
            x = result;
        case 65:
            x = x * x;
        case 61: # 也能夠去掉這行
        default:
            result = x + 0x4b;
    }
}

***3.64

store_ele:
    leaq  (%rsi, %rsi, 2), %rax  # %rax = 3 * j
    leaq  (%rsi, %rax, 4), %rax  # %rax = 13 * j
    leaq  %rdi, %rsi             # %rsi = i
    salq  $6, %rsi               # %rsi * = 64
    addq  %rsi, %rdi             # %rdi = 65 * i
    addq  %rax, %rdi             # %rdi = 65 * i + 13 * j
    addq  %rdi, %rdx             # %rdx = 65 * i + 13 * j + k
    movq  A(, %rdx, 8), %rax     # %rax = A + 8 * (65 * i + 13 * j + k)
    movq  %rax, (%rcx)           # *dest = A[65 * i + 13 * j + k]
    movl  $3640, %eax            # sizeof(A) = 3640
    ret

A.

&D[i][j][k] = XD + L(i * S * T + j * T + k)

B.

由A題目中的公式以及彙編至第9行第10行計算出來的可得:

S * T = 65
T = 13
S * T * R * 8 = 3640

很容易能夠計算出來

R = 7
S = 5
T = 13

*3.65

.L6:
    movq  (%rdx), %rcx  # t1 = A[i][j]
    movq  (%rax), %rsi  # t2 = A[j][i]
    movq  %rsi, (%rdx)  # A[i][j] = t2
    movq  %rcx, (%rax)  # A[j][i] = t1
    addq  $8, %rdx      # &A[i][j] += 8
    addq  $120, %rax    # &A[j][i] += 120
    cmpq  %rdi, %rax    
    jne   .L6           # if A[j][i] != A[M][M]

A.

從2~5行裏沒法區分A[i][j]和A[j][i],只能從第6和7行來看,A[i][j]每次只移動一個單位,因此每次+8的寄存器%rdx就是指的A[i][j]。

B.

由於寄存器%rdx是A[i][j],因此另外一個寄存器%rax是A[j][i]。

C.

A[j][i]每次移動一行的距離,因此可得公式:8 * M = 120,顯然,M=15。

*3.66

sum_col:
    leaq   1(, %rdi, 4), %r8        # %r8 = 4 * n + 1
    leaq   (%rdi, %rdi, 2), %rax    # result = 3 * n
    movq   %rax, %rdi               # %rdi = 3 * n
    testq  %rax, %rax
    jle    .L4                      # if %rax <= 0, goto L4
    salq   $3, %r8                  # %r8 = 8 * (4 * n + 1)
    leaq   (%rsi, %rdx, 8), %rcx    # %rcx = A[0][j]
    movl   $0, %eax                 # result = 0
    movl   $0, %edx                 # i = 0
.L3:
    addq   (%rcx), %rax             # result = result + A[i][j]
    addq   $1, %rdx                 # i += 1
    addq   %r8, %rcx                # 這裏每次+8*(4n+1),說明每一行有4n+1個,所以NC(n)爲4*n+1
    cmpq   %rdi, %rdx               
    jne    .L3                      # 這裏說明一直循環到3*n才結束,因此能夠說明一共有3n行,所以NR(n)爲3*n
    rep; ret
.L4:
    movl $0, %eax
    ret

根據上述代碼中的分析,能夠得出

NR(n) = 3 * n
NC(n) = 4 * n + 1
  • 3.67
    相對於%rsp的偏移量 | 存儲的值
    ---|---
    %rsp+24| z
    %rsp+16| &z
    %rsp+| y
    %rsp | x

  • 3.68

首先,結構體str2類型的最長單位是long,因此按照8位對齊,str1一樣,也是按照8位對齊.
再來看彙編代碼:

setVal:
    movslq  8(%rsi), %rax
    # 說明str2的t從第8位開始的,由於按照8位對齊,所以sizeof(array[B])小於等於8
    # 由於下邊的t是int類型,只佔4個字節,爲了避免讓t與array共佔8個字節,因此sizeof(array[B])大於4,所以可得5<=B<=8.
    addq    32(%rsi), %rax
    # 說明str2的u從第32位開始的,所以t與s佔了24個字節,能夠將2個s放在t的一行,佔滿8個字節,剩下的s佔據兩行,所以可得7<=A<=10.
    movq    %rax, 184(%rdi)
    # 說明str1的y從第184位開始的,所以184-8<A*B*4<=184

根據彙編代碼推出的三個公式:

5<=B<=8
7<=A<=10
184-8<A*B*4<=184

能夠算出惟一解爲:

A=9
B=5
  • 3.69
<test>:
    mov    0x120(%rsi), %ecx
    # 這句話是訪問bp的first,說明first與a一共佔了288個字節
    add    (%rsi), %rcx
    # %rcx = n
    lea    (%rdi, %rdi, 4), %rax
    # %rax = 5 * i
    lea    (%rsi, %rax, 8), %rax
    # %rax = &bp + 40 * i
    mov    0x8(%rax), %rdx
    # ap->idx = %rax + 8
    # 這兩句代表了&bp->a[i]的地址計算公式,即&bp+8+40i,所以能夠說明,a的總大小是40
    # +8說明first本身佔8個字節,按照的8位對齊,所以a的第一個元素確定是8個字節的.
    movslq %ecx, %rcx
    # 在這裏將n進行了類型轉換,int型轉換成了long型,所以說明ap裏的x數組必定是long型
    mov    %rcx, 0x10(%rax, %rdx, 8)
    # 這句說明了ap->x[ap->idx]的地址計算公式是&bp + 16 + idx * 8
    # +16說明了包含了first以及idx,說明idx是a的第一個元素,根據上面得出的第一個元素確定是8個字節的結論,說明idx是long類型.
    # 再由於一共佔大小40,因此x數組的元素個數爲(40 - 8) / 8 = 4
    retq
  • 3.70

注意是union類型

A.

e1.p     0
e1.y     8
e2.x     0
e2.next  8

B.

16

C.

這一問比較有難度,邏輯性也很強,仍是建議儘可能可以本身推出來.下面來仔細推一下,這題就很差從頭開始一句句的推了, 須要跳躍性的推理(什麼鬼).

1   proc:
2       movq    8(%rdi), %rax
3       movq    (%rax), %rdx
4       movq    (%rdx), %rdx
5       subq    8(%rax), %rdx
6       movq    %rdx, (%rdi)
7       ret

先來看proc的C代碼,等式右邊中間有個減號,所以,能夠去彙編裏找到第5行的subq,因此2~4行就是賦值的被減數.
第3行和第4行代碼分別加了兩次星號,所以能夠說明是((A).B)結構,根據第二行,由於是偏移量+8,取得是第二個值,e1.y不是指針,所以只能是e2.next,因而A爲e2.next;同理,B說明也是指針,沒有偏移量,是取得第一個值,所以只能是e1.p.因此被減數就推出來了爲((up->e2.next).e1.p)
再看第5行,減數的偏移量是相對於%rax+8,上一條步驟中,%rax是(up->e2.next),取第二個值,並且彙編代碼中並未加星號,所以說明不是指針,那麼只能e1.y,所以減數是(up->e2.next).e1.y
最後只剩等式左邊,來看第6行,偏移量爲0說明取得第一個值,且從C代碼中看未加星號,所以不是指針,因此只能是e2.x.
根據上述推理,能夠得出C代碼爲:

void proc(union ele *up){
    up->e2.x = *(*(up->e2.next).e1.p) - *(up->e2.next).e1.y;
}

本週結對學習狀況

- [20155232](http://www.cnblogs.com/lsqsjsj/p/8052671.html)
- 結對學習內容
    - 最重要的一章的學習
    - 分享學習體會

其餘(感悟、思考等,可選)

xxx xxx

相關文章
相關標籤/搜索