你知道的,我的汇编全是靠它学的。
Assembly Crash Course
1. set-register
要求:rdi = 0x1337
1 2 3 4
| .intel_syntax noprefix .global _start _start: mov rdi, 0x1337
|
2. set-multiple-registers
In this level, you will work with multiple registers. Please set the following:
rax = 0x1337
r12 = 0xCAFED00D1337BEEF
rsp = 0x31337
1 2 3 4 5 6
| .intel_syntax noprefix .global _start _start: mov rax, 0x1337 mov r12, 0xCAFED00D1337BEEF mov rsp, 0x31337
|
3. add-to-register
Do the following:
1 2 3 4
| .intel_syntax noprefix .global _start _start: add rdi, 0x331337
|
4. linear-equation-registers
1 2 3 4 5 6 7
| .intel_syntax noprefix .global _start _start: imul rdi, rsi add rdx, rdi mov rax, rdx
|
5. integer-division
1 2 3 4 5
| .intel_syntax noprefix .global _start _start: mov rax, rdi div rsi
|
6. modulo-operation
div操作之后,余数会被存于rdx(dx)中。
1 2 3 4 5 6
| .intel_syntax noprefix .global _start _start: mov rax, rdi div rsi mov rax, rdx
|
7. set-upper-byte
1 2 3 4 5 6 7 8 9 10
| MSB LSB +----------------------------------------+ | rax | +--------------------+-------------------+ | eax | +---------+---------+ | ax | +----+----+ | ah | al | +----+----+
|
Using only one move instruction, please set the upper 8 bits of the ax
register to 0x42
.
1 2 3 4
| .intel_syntax noprefix .global _start _start: mov ah, 0x42
|
8. efficient-modulo
Using only the following instruction(s):
Please compute the following:
rax = rdi % 256
rbx = rsi % 65536
1 2 3 4 5 6 7
| .intel_syntax noprefix .global _start _start: mov rcx, rdi mov al, cl mov rdx, rsi mov bx, dx
|
shl
指令:
exp:
1 2 3 4 5 6
| .intel_syntax noprefix .global _start _start: shr rdi, 32 mov rbx, rdi mov al, bl
|
10. bitwise-and
如果不使用以下说明:mov
、xchg
,请执行以下操作:
将 rax
设置为 (rdi AND rsi)
的值
1 2 3 4 5 6
| .intel_syntax noprefix .global _start _start: and rdi, rsi and rax, 0 xor rax, rdi
|
11. check-even
1 2 3 4 5 6
| .intel_syntax noprefix .global _start _start: and rdi, 1 and rax, 1 xor rax, rdi
|
12. memory-read
请执行以下操作:将存储在 0x404000
的值放入 rax
中。确保 rax
中的值是存储在 0x404000
的原始值。
1 2 3 4 5
| .intel_syntax noprefix .global _start _start: mov rax, [0x404000]
|
13. memory-write
1 2 3 4 5
| .intel_syntax noprefix .global _start _start: mov [0x404000], rax
|
14. memory-increment
1 2 3 4 5 6 7
| .intel_syntax noprefix .global _start _start: mov rax, [0x404000] mov rbx , rax add rbx , 0x1337 mov [0x404000], rbx
|
15. byte-access
Here is the breakdown of the names of memory sizes:
以下是内存大小名称的细分:
- Quad Word = 8 Bytes = 64 bits
四字 = 8 字节 = 64 位
- Double Word = 4 bytes = 32 bits
双字 = 4 字节 = 32 位
- Word = 2 bytes = 16 bits
字 = 2 字节 = 16 位
- Byte = 1 byte = 8 bits
字节 = 1 字节 = 8 位
1 2 3 4
| .intel_syntax noprefix .global _start _start: mov al, [0x404000]
|
在 x86_64 中,您可以在取消引用地址时访问这些大小,就像使用更大或更小的 register 访问一样:
mov al, [address]
<=> moves the least significant byte from address to rax
mov al, [address]
<=> 将最低有效字节从 address 移动到 rax
mov ax, [address]
<=> moves the least significant word from address to rax
mov ax, [address]
<=> 将最低有效字从 address 移动到 rax
mov eax, [address]
<=> moves the least significant double word from address to rax
mov eax, [address]
<=> 将最低有效双字从 address 移动到 rax
mov rax, [address]
<=> moves the full quad word from address to rax
mov rax, [address]
<=> 将完整的四元字从 address 移动到 rax
16. memory-size-access
1 2 3 4 5 6 7
| .intel_syntax noprefix .global _start _start: mov al, [0x404000] mov bx, [0x404000] mov ecx, [0x404000] mov rdx, [0x404000]
|
17. little-endian-write
值得注意的是,值的存储顺序与我们表示它们的顺序相反。example:
这就是小端存储(Little Endian)。
exp
1 2 3 4 5 6 7
| .intel_syntax noprefix .global _start _start: mov rax, 0xdeadbeef00001337 mov [rdi], rax mov rax, 0xc0ffee0000 mov [rsi], rax
|
18. memory-sum
内存是连续存储的,因此可以使用偏移量来获取指定字节。例如:
1 2 3 4 5 6 7 8
| ;[0x1337] = 0x00000000deadbeef ;[0x1337] = 0xef ;[0x1337 + 1] = 0xbe ;[0x1337 + 2] = 0xad ... ;[0x1337 + 7] = 0x00 ; 假设我需要访问某个地址的第5个字节。那么可以: mov al, [address+4]
|
题目要求:
- Load two consecutive quad words from the address stored in
rdi
.
从存储在 rdi
中的地址加载两个连续的四字。
- Calculate the sum of the previous steps’ quad words.
计算前面步骤的四边形词的总和。
- Store the sum at the address in
rsi
.
将总和存储在 rsi
中的地址。
1 2 3 4 5 6 7
| .intel_syntax noprefix .global _start _start: mov rax, [rdi] mov rbx, [rdi+8] add rax, rbx mov [rsi], rax
|
19. stack-substraction
1 2 3 4 5 6
| .intel_syntax noprefix .global _start _start: pop rax sub rax, rdi push rax
|
20. swap-stack-values
1 2 3 4 5 6 7
| .intel_syntax noprefix .global _start _start: push rdi push rsi pop rdi pop rsi
|
21. average-stack-values
除法还是很坑的,记得一定是rdx:rax / reg
,商在rax中,余数在rdx中。因此,在调用div的时候一定要清空rdx寄存器(如果被除数没有占用到rdx的话)
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| .intel_syntax noprefix .global _start _start: mov rdx, [rsp] mov rcx, [rsp+0x8] mov rbx, [rsp+0x10] mov rax, [rsp+0x18] add rax, rbx add rax, rcx add rax, rdx mov rbx, 4 mov rdx, 0 div rbx push rax
|
22. absolute-jump
绝对跳转,指的是跳转到指定地址
1 2 3 4 5
| .intel_syntax noprefix .global _start _start: mov rax,0x403000 jmp rax
|
23. relative-jump
对于所有跳转,有三种类型:
- Relative jumps: jump + or - the next instruction.
相对跳转:jump + 或 - 下一条指令。
- Absolute jumps: jump to a specific address.
Absolute jumps:跳转到指定地址。
- Indirect jumps: jump to the memory address specified in a register.
Indirect jumps:跳转到 register 中指定的 memory 地址。
jmp (reg1 | addr | +/-offset)
要求:
- Make the first instruction in your code a
jmp
.
将代码中的第一条指令设为 jmp
。
- Make that
jmp
a relative jump to 0x51 bytes from the current position.
使该 jmp
相对跳转到 0x51 字节的当前位置。
- At the code location where the relative jump will redirect control flow, set
rax
to 0x1.
在相对跳转将重定向控制流的代码位置,将 rax
设置为 0x1。
1 2 3 4 5 6 7 8 9
| .intel_syntax noprefix .global _start _start: jmp set_rax .rept 0x51 nop .endr set_rax: mov rax,0x1
|
24. jump-trampoline
1 2 3 4 5 6 7 8 9 10 11
| .intel_syntax noprefix .global _start _start: jmp set_rax .rept 0x51 nop .endr set_rax: pop rdi mov rbx, 0x403000 jmp rbx
|
25. conditional-jump
挖草,巨坑的一点!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| .intel_syntax noprefix .global _start _start: mov eax, [rdi] cmp eax, 0x7f454c46 je flag_1 cmp eax, 0x00005A4D je flag_2 jmp flag_3
flag_1: mov eax, [rdi+4] add eax, [rdi+8] add eax, [rdi+12] jmp done flag_2: mov eax, [rdi+4] sub eax, [rdi+8] sub eax, [rdi+12] jmp done flag_3: mov eax, [rdi+4] imul eax,[rdi+8] imul eax, [rdi+12] jmp done done:
|
注意的是mov eax, [rdi]
,如果用mov rax, [rdi]
会出问题,因为会读取rdi
地址上的pword,那么永远走的都是else下的语句。服了。
26. indirect-jump
1 2 3 4 5 6 7 8 9 10 11 12 13
| .intel_syntax noprefix .global _start _start: mov rax, rdi cmp rax, 3 jg default imul rax,8 add rax, rsi jmp [rax] default: mov rax, rsi add rax, 0x20 jmp [rax]
|
这里其实也有坑,需要好好把控[]
会解析地址。例如下面的exp:
1 2 3 4 5 6 7 8 9 10 11
| .intel_syntax noprefix .global _start _start: mov rax, rdi cmp rax, 3 jg default mov rax, [rsi + rdi * 8] jmp rax default: mov rax, [rsi + 0x20] jmp rax
|
27. average-loop
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| .intel_syntax noprefix .global _start _start: mov rcx, 0 mov rax, 0 mov rbx, rdi loop_start: add rax, [rbx] inc rcx add rbx, 0x8 cmp rcx, rsi jg loop_end jmp loop_start loop_end: mov rbx, rsi div rbx
|
依然是要注意[]
的使用,要认知是取内存指向的值,还是取内存进行加减。
28. count-non-zero
感觉主要问题是,我没理解题目的意思。理解后就很简单了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| .intel_syntax noprefix .global _start _start: mov rax, 0 loop_start: cmp rdi, 0 je loop_end mov bl, [rdi] cmp bl, 0 je loop_end inc rdi inc rax jmp loop_start
loop_end:
|
29. string lower
这个还行,一遍过了。还记得系统调用的时候,第一个参数是用rdi
存储,第二个参数是用rsi
存储
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| .intel_syntax noprefix .global _start _start: mov rbx, 0 cmp rdi, 0 jne loop_start jmp done loop_start: mov cl, [rdi] cmp cl, 0x00 je done cmp cl, 0x5a jle exe_1 inc rdi jmp loop_start exe_1: mov rcx, rdi mov rax, 0x403000 mov rdi, [rdi] call rax mov rdi, rcx mov [rdi], rax inc rbx inc rdi jmp loop_start done: mov rax, rbx ret
|
30. most-common-byte
这道题卡了半天吧得,主要是对寄存器不熟悉,重复用了一些寄存器,然后导致出现问题,后面用普通寄存器r8~15
解决的,普通寄存器也得用,不然变量不够存的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| .intel_syntax noprefix .global _start _start: push rbp mov rbp, rsp sub rsp, 0x200 mov rcx, 0
loop_count_bytes: cmp rcx, rsi jge loop_count_bytes_end
mov dl, [rdi + rcx] movzx rax, dl mov rbx, rbp sub rbx, rax inc byte ptr [rbx] inc rcx jmp loop_count_bytes
loop_count_bytes_end: mov rcx, 0 mov rdx, 0 mov rax, 0
loop_find_max: cmp rcx, 0xff jg loop_find_max_end mov rbx, rbp sub rbx, rcx mov r8b, [rbx] movzx rbx, r8b cmp rbx, rdx jle skip_update mov rdx, rbx mov rax, rcx inc rcx jmp loop_find_max
skip_update: inc rcx jmp loop_find_max
loop_find_max_end: mov rsp, rbp pop rbp ret
|