# 1. Set a register: > In this level you will work with registers! Please set the following: > rdi = 0x1337 ``` section .text 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 ``` section .text global _start start: mov rax, 0x1337 mov r12, 0xCAFED00D1337BEEF mov rsp, 0x31337 ``` # 3. Addition: > Do the following: > add 0x331337 to rdi ``` section .text global _start start: add rdi, 0x331337 ``` # 4. Multiplication: > Using your new knowledge, please compute the following: > f(x) = mx + b, where: > m = rdi > x = rsi > b = rdx ``` section .text global _start start: mov rax, rdi imul rax, rsi add rax, rdx ``` # 5. Division: > Please compute the following: > speed = distance / time, where: > distance = rdi > time = rsi > speed = rax -When you calculate `rax/register`, the result will save in rax and the remainder save in rdx. ``` section .text global _start start: mov rax, rdi dil rax, rsi ``` # 6. Modulus: > Please compute the following: > rdi % rsi -The remainder will save in rdx. ``` section .text global _start start: mov rax, rdi div rsi xor rax, rax mov rax, rdx ``` # 7. Register sizes: > Another cool concept in x86 is the ability to independently access to lower register bytes. > > Each register in x86_64 is 64 bits in size, and in the previous levels we have accessed > the full register using rax, rdi or rsi. > > We can also access the lower bytes of each register using different register names. > > For example the lower 32 bits of rax can be accessed using eax, the lower 16 bits using ax, > the lower 8 bits using al. > > LSB MSB > +----------------------------------------+ > | rax | > +--------------------+-------------------+ > | eax | > +---------+---------+ > | ax | > +----+----+ > | al | ah | > +----+----+ > > Lower register bytes access is applicable to almost all registers. > > Using only one move instruction, please set the upper 8 bits of the ax register to 0x42. ``` section .text global _start start: mov ah, 0x42 ``` # 8. Register sizes for modulus: > Using only the following instruction(s): > mov > > Please compute the following: > rax = rdi % 256 > rbx = rsi % 65536 ``` section .text global _start start: mov rax, dil mov rbx, si ``` # 9. Bitwise shift: > Using only the following instructions: > mov, shr, shl > > Please perform the following: > Set rax to the 5th least significant byte of rdi. > > For example: > rdi = | B7 | B6 | B5 | B4 | B3 | B2 | B1 | B0 | > Set rax to the value of B4 ``` section .text global _start start: shl rdi, 8 mov al, dil ``` # 10. Bitwise and: > Without using the following instructions: > mov, xchg > > Please perform the following: > rax = rdi AND rsi > > i.e. Set rax to the value of (rdi AND rsi) ``` section .text global _start start: xor rax, rax xor rax, rdi and rax, rsi ``` # 11. Bitwise logic: > Using only the following instructions: > and, or, xor > > Implement the following logic: > if x is even then > y = 1 > else > y = 0 > > where: > x = rdi > y = rax ``` section .text global _start start: xor rax, rax or rax, 1 and rdi, 1 xor rax, rdi ``` # 12. Memory reads: > Please perform the following: > Place the value stored at 0x404000 into rax > > Make sure the value in rax is the original value stored at 0x404000. ``` section .text global _start start: mov rax, [0x404000] ``` # 13. Memory writes: > Please perform the following: > Place the value stored in rax to 0x404000 ``` section .text global _start start: mov [0x404000], rax ``` # 14. Memory reads and writes: > Please perform the following: > Place the value stored at 0x404000 into rax > Increment the value stored at the address 0x404000 by 0x1337 > > Make sure the value in rax is the original value stored at 0x404000 and make sure > that [0x404000] now has the incremented value. ``` section .text global _start start: mov rax, [0x404000] mov rbx, 0x1337 add [0x404000], rbx ``` # 15. Read one size data: > Please perform the following: > Set rax to the byte at 0x404000 ``` section .text global _start start: mov al, [0x404000] ``` # 16. Read multiple data sizes: > Please perform the following: > Set rax to the byte at 0x404000 > Set rbx to the word at 0x404000 > Set rcx to the double word at 0x404000 > Set rdx to the quad word at 0x404000 ``` section .text global _start start: mov al, [0x404000] mov bx, [0x404000] mov ecx, [0x404000] mov rdx, [0x404000] ``` # 17. Dynamic address memory writes: > Using the earlier mentioned info, perform the following: > Set [rdi] = 0xdeadbeef00001337 > Set [rsi] = 0xc0ffee0000 ``` section .text global _start start: mov rax, qword 0xdeadbeef00001337 mov rbx, 0xc0ffee0000 mov [rdi], rax mov [rsi], rbx ``` # 18. Consecutive memory reads: > Perform the following: > Load two consecutive quad words from the address stored in rdi > Calculate the sum of the previous steps quad words. > Store the sum at the address in rsi ``` section .text global _start start: xor rax, rax add rax, [rdi] add rax, [rdi + 8] mov [rsi], rax ``` # 19. The stack: > Using these instructions, take the top value of the stack, subtract rdi from it, then put it back. ``` section .text global _start start: pop rax sub rax, rdi push rax ``` # 20. Swap register values with the stack: > Using only following instructions: > push, pop > > Swap values in rdi and rsi. > i.e. > If to start rdi = 2 and rsi = 5 > Then to end rdi = 5 and rsi = 2 ``` section .text global _start start: push rdi pop rax push rsi pop rdi push rax pop rsi ``` # 21. Memory reads and writes with the stack: > Without using pop, please calculate the average of 4 consecutive quad words stored on the stack. > > Push the average on the stack. ``` section .text global _start start: mov rax, [rsp] add rax, [rsp+ 8] add rax, [rsp + 16] add rax, [rsp + 24] mov rbx, 4 div rbx push rax ``` # 22. Absolute jump: > Jump to the absolute address 0x403000 ``` section .text global _start start: mov rax, 0x403000 jmp rax ``` # 23. Relative jump: > Using the above knowledge, perform the following: > Make the first instruction in your code a jmp > Make that jmp a relative jump to 0x51 bytes from the current position > At the code location where the relative jump will redirect control flow set rax to 0x1 - You need to use nop-sled. ``` .global _start _start: .intel_syntax noprefix jmp next .rept 0x51 nop .endr next: mov rax, 0x1 ``` # 24. Control flow: ``` Now, we will combine the two prior levels and perform the following: Create a two jump trampoline: Make the first instruction in your code a jmp Make that jmp a relative jump to 0x51 bytes from its current position At 0x51 write the following code: Place the top value on the stack into register rdi jmp to the absolute address 0x403000 ``` ``` .global _start _start: .intel_syntax noprefix jmp next .rept 0x51 nop .endr next: pop rdi mov rax, 0x403000 jmp rax ``` # 25. Conditional branches: > Using the above knowledge, implement the following: > if [x] is 0x7f454c46: > y = [x+4] + [x+8] + [x+12] > else if [x] is 0x00005A4D: > y = [x+4] - [x+8] - [x+12] > else: > y = [x+4] * [x+8] * [x+12] > > where: > x = rdi, y = rax. -See condition in assembly at https://www.tutorialspoint.com/assembly_programming/assembly_conditions.htm. ``` section .text global _start start: mov eax, [rdi] cmp eax, 0x7f454c46 je con1 cmp eax, 0x00005A4D je con2 jmp con3 con1: mov eax, dword [rdi + 4] add eax, dword [rdi + 8] add eax, dword [rdi + 12] jmp end con2: mov eax, dword [rdi + 4] sub eax, dword [rdi + 8] sub eax, dword [rdi + 12] jmp end con3: mov eax, dword [rdi + 4] imul eax, dword [rdi + 8] imul eax, dword [rdi + 12] jmp end end: ``` # 26. Jump tables: > Using the above knowledge, implement the following logic: > if rdi is 0: > jmp 0x403016 > else if rdi is 1: > jmp 0x4030eb > else if rdi is 2: > jmp 0x4031e2 > else if rdi is 3: > jmp 0x403287 > else: > jmp 0x403329 > > Please do the above with the following constraints: > Assume rdi will NOT be negative > Use no more than 1 cmp instruction > Use no more than 3 jumps (of any variant) > We will provide you with the number to 'switch' on in rdi. > We will provide you with a jump table base address in rsi. -rdi register save value which is also index to jmp. -rsi save the base address of starting jump. ``` section .text global _start start: cmp rdi, 3 jle okey jmp [rsi + 32] okey: jmp [rsi + rdi * 8] ``` # 27. Computing averages: > Please compute the average of n consecutive quad words, where: > rdi = memory address of the 1st quad word > rsi = n (amount to loop for) > rax = average computed. ``` section .text global _start start: xor rbx, rbx mov rax, [rdi] jmp loop_computed loop_computed: inc rbx add rax, [rdi + rbx * 8] cmp rbx, rsi jle loop_computed jmp end end: div rsi ``` # 28. Implementing strlen: > Using the above knowledge, please perform the following: > Count the consecutive non-zero bytes in a contiguous region of memory, where: > rdi = memory address of the 1st byte > rax = number of consecutive non-zero bytes > > Additionally, if rdi = 0, then set rax = 0 (we will check)! > > An example test-case, let: > rdi = 0x1000 > [0x1000] = 0x41 > [0x1001] = 0x42 > [0x1002] = 0x43 > [0x1003] = 0x00 > > then: rax = 3 should be set ``` section .text global _start _start: xor rax, rax cmp rdi, 0 jne loop jmp end loop: mov bl, [rdi] cmp bl, 0 je end inc rax inc rdi jmp loop end: ``` # 29. Using library functions: > Please implement the following logic: > str_lower(src_addr): > i = 0 > if src_addr != 0: > while [src_addr] != 0x00: > if [src_addr] <= 0x5a: > [src_addr] = foo([src_addr]) > i += 1 > src_addr += 1 > return i 1. The important point: + Foo takes a single argument as a value(rdi regisrer) and returns a value(rax register). + Foo is provided at 0x403000foo is provided at 0x403000. + Src_addr is an address in memory (where the string is located) and [src_addr] refers to the byte that exists at src_addr. + The function foo accepts **a byte** as its first argument and *returns* **a byte**. + Return value of rax register. + Ret with no argument pops the return address off of the stack and jumps to it. Some calling conventions (like __stdcall) specify that the callee function cleans up the stack. 2. Solution for this: + Save the value of rdi, rax register before calling function(you have to search topic **calling convention** for corresponding architecture; not only when calling foo function but also other funtion, the agrument are %rdi, %rsi, %rdx, %rcx, %r8 and %r9, respectively). -This level will provide you the knowledge for calling convention, ret. Both of them are very important, you should look for topic about that problem because they are relative the bigger knowledge. ``` section .text global _start _start: xor rax, rax xor rbx, rbx cmp rdi, 0 je end jmp str_lower str_lower: ;Compare src_addr with 0 cmp rdi, 0 je end ;Compare [src_addr] with 0 mov bl, [rdi] cmp rbx, 0 je end ;Compare [src_addr] with 0x5a cmp rbx, 0x5a jg next ;jump if greater push rdi ;save the value of rdi push rax ;save the value of rdi xor rdi, rdi ;make that rdi is 0 mov dil, bl ;take first agrument(a byte) mov rcx, 0x403000 call rcx ;call function mov bl, al ;take result after call function to bl(rbx) pop rax ;restore rax pop rdi ;restore rdi mov [rdi], bl ;take result inc rax jmp next next: inc rdi jmp str_lower end: ret ``` # 30. Compute the most common byte: > Once, again, please make function(s) that implements the following: > most_common_byte(src_addr, size): > i = 0 > while i <= size-1: > curr_byte = [src_addr + i] > [stack_base - curr_byte] += 1 > i += 1 > > b = 0 > max_freq = 0 > max_freq_byte = 0 > while b <= 0xff: > if [stack_base - b] > max_freq: > max_freq = [stack_base - b] > max_freq_byte = b > b += 1 > > return max_freq_byte -In level 29, we know what does `ret` work. And now, we will study about `stack frame`, it is essential to solve this challenge. -I don't know exactly why without this, my program will crash, I have search and see that explain in: https://www.freebuf.com/articles/database/321326.html ``` section .text global _start start: push 0 mov rbp, rsp sub rsp, rsi ;the size is the value in rsi xor rax, rax xor rbx, rbx sub si, 1 ;size - 1 jmp loop1 loop1: cmp rax, rsi ;i jg next xor rbx, rbx mov bl, [rdi + rax] mov r11, rbp sub r11, rbx inc byte [r11] inc rax jmp loop1 next: xor rbx, rbx ;b xor rcx, rcx ;max_freq xor rax, rax ;max_freq_byte jmp loop2 loop2: cmp bx, 0xff jg end xor rdi, rdi mov r9, rbp sub r9, rbx mov dl, [r9] cmp dl, cl jg find inc bx jmp loop2 find: mov cl, dl mov al, bl jmp loop2 end: mov rsp, rbp pop rbx ret ```