1. Control operation

Control operations, as their names indicate, control the progress of the program. To control it, these instructions are based on the EFLAGS registers, to make the decisions.
There are two types

  • Conditional jump (Jxx)
  • Unconditional jump (JMP)

Regarding unconditional jumps, we can compare them to the GOTO instruction in C. It allows you to jump anywhere in the program.
For conditional jumps, that's when the value of EFLAGS makes decisions.
Code C below shows the principle of conditional jumps:

int main(int ac, char **av)
{
    int a = 12;
    int b = 1;

    if (a == b)
      printf("bad\n");
    else:
      printf("ok\n");
    return 0;
}

In assembler, we can translate the following program by this:

global _start

section .text
_start:
    mov rax, 0xc
    mov rbx, 0x1

    cmp rax, rbx
    je printBad ; jmp if Zero flag is set
    call printOK

    mov rax, 60d
    syscall

printBad:
    mov rax, 0x1
    mov rdi, 0x1
    mov rsi, bad
    mov rdx, 0x4
    syscall
    ret

printOK:
    mov rax, 0x1
    mov rdi, 0x1
    mov rsi, ok
    mov rdx, 0x3
    syscall
    ret

section .data
    bad: db "bad", 0x0a, 0x0d
    ok: db "ok", 0x0a, 0x0d

In the assembly code above, when comparing the registers RAX and RBX, the flag ZF is set to 1 if the comparison is good. In this case, the statement je means "Jump if Equal", which means that if the Zero Flag is set, then we can jump, otherwise we continue the program.
For all of the conditional jump instructions, I recommend going to the intel manual on page 490.

1.1 Example

global _start

section .text
_start:
    jmp prepareLoop

doNothing:
    mov rax, 0x1
    syscall

prepareLoop:
    mov rcx, 10

print:
    push rcx
    call write
    pop rcx
    dec rcx
    cmp rcx, 0
    jnz print
    call exit

write:
    mov rax, 0x1
    mov rdi, 0x1
    mov rsi, hello
    mov rdx, 6
    syscall
    ret

exit:
    mov rax, 60
    syscall

section .data
    hello: db "Hello", 0x0a

2. Loop

Loops can simplify the work done in the example above.
Instead of using the jnz statement, you can use the LOOP statement, which has the following characteristics:

  • Decreases RCX automatically
  • When RCX == 0, the loop stops
  • There are variants like LOOPE, LOOPNE

2.2 Example

global _start

section .text
_start:
    jmp prepareLoop

doNothing:
    mov rax, 0x1
    syscall

prepareLoop:
    mov rcx, 10

print:
    push rcx
    call write
    pop rcx
    cmp rcx, 0
    loop print
    call exit

write:
    mov rax, 0x1
    mov rdi, 0x1
    mov rsi, hello
    mov rdx, 6
    syscall
    ret

exit:
    mov rax, 60
    syscall

section .data
    hello: db "Hello", 0x0a

3. Strings manipulation

3.1. String Movements

In assembler, there are specific instructions for strings manipulation, namely:

  • Load (Memory to register)
    • lodsb / lodsw / lodsd / loadsq
  • Store (Register to memory)
    • stosb / stosw / stosd / stosq
  • Move (Memory to memory)
    • movsb / movsw / movsd / movsq

3.1.1. Example (rot13)

global _start

section .text
_start:
    call check_argc
    call store_argv1
    call perform_caesar
    call write
    jmp exit

write:
    mov rax, 0x1
    mov rdi, 0x1
    lea rsi, [str2]
    mov rdx, 0x14
    syscall
    jmp short exit

perform_caesar:
    push rbp
    mov rbp, rsp

    lea rdi, [str2]
    mov rbx, 0xd
    mov rcx, 0x4

looper:
    lodsb
    add al, bl
    stosb
    loop looper
    cld
    rep movsb
    leave
    ret

store_argv1:
    push rbp
    mov rbp, rsp

    mov rsi, [rbp + 0x20]
    lea rdi, [str]

    leave
    ret

check_argc:
    push rbp
    mov rbp, rsp
    mov rax, [rbp+0x10]
    cmp rax, 0x2
    jne error
    leave
    ret

error:
    mov rax, 0x1
    mov rdi, 0x1
    mov rsi, bad_argc
    mov rdx, len_bad_argc
    syscall

exit:
    mov rax, 0x3c
    syscall

section .data
    bad_argc: db "Need 1 arguments", 0xa, 0
    len_bad_argc equ $-bad_argc

section .bss
    str: resb 30
    str2: resb 30

3.2. String comparison

As before, there are specific instructions for comparing strings of characters:

  • memory to register
    • scasb / scasw/ scasd / scasq
      • compare with al / ax / eax / rax
  • memory to memory
    • cmpsb / cmpsw / cmpsd / cmpsq
      • Compare RSI with RDI

3.2.1. Example

global _start

section .text

_start:
    lea rsi, [str1]
    lea rdi, [str2]
    cmpsq
    jz success

    mov rax, str2
    lea rdi, [str1]
    scasq
    jz success

    mov rax, 0xaabbccddeeff1122
    lea rdi, [var1]
    scasq
    jz success

    call exit

success:
    mov rax, 0x1
    mov rdi, rax
    lea rsi, [str3]
    mov rdx, 8
    syscall
    ret

exit:
    mov rax, 0x3c
    syscall

section .data

    str1: db "NekoSecurity", 0x00
    str2: db "Assembly", 0x00
    str3: db "IsEqual", 0x0a, 0x00
    var1: dq 0xaabbccddeeff1122

4. Exercices

You should normally be able to do the following exercises:
These exercises were found on the internet.

4.1. Exercice 1

Write a program that modifies each character of a string by the formula:
NEW_LETTER = 33 + ((OLD_LETTER * 42 / 3 + 13) % 94)

4.2. Exercice 2

Write a program that modifies a string in a binary:
Use only of:

  • SYS_OPEN
  • SYS_READ
  • SYS_WRITE
  • SYS_LSEEK

4.3. Exercice 3

Write a program that realizes a Cipher Caesar

5. Conclusion

There are still aspects that have not been addressed and that they will not be. Indeed I did not talk about the macros, the use of the LIBC but the purpose of this tutorial is primarily to focus on writing shellcode. I do not see the used to learn the aspects outlined below.

I hope this tutorial will be useful and will make you want to continue :)

6 Reference

Assembly exercice 1