---
title: 'Assembly Writeup (pwn.college)'
---
Visit Course: https://pwn.college/computing-101/
---
# Most common byte
**Problem statement:**
First of all, the concept of new register is introduced in this problem which is RBP (Stack Base Pointer). It is used to to tell us where the stack frame first initialized from which is used to construct list.
```assembly
; setup the base of the stack as the current top
mov rbp, rsp
; move the stack 0x14 bytes (5 * 4) down
; acts as an allocation
sub rsp, 0x14
; assign list[2] = 1337
mov eax, 1337
mov [rbp-0xc], eax
; do more operations on the list ...
; restore the allocated space
mov rsp, rbp
ret
```
As you can see, the rbp save the current rsp address which is used as the highest address in the contiguous list. Then substract rsp by 0x14 in order to initialize the list size. Using displacement (offset) to interact with list element (modify it)
>[!Warning]
>We have to restore the stack to its base initialization or it will run out. As the aforemention, substract the exact willing list size.
Now the real problem statement is to immplement this status satisify this
```c++
most_common_byte(src_addr, size):
i = 0
while i <= size-1:
curr_byte = [src_addr + i]
[stack_base - curr_byte * 2] += 1
i += 1
b = 0
max_freq = 0
max_freq_byte = 0
while b <= 0xff:
if [stack_base - b * 2] > max_freq:
max_freq = [stack_base - b * 2]
max_freq_byte = b
b += 1
return max_freq_byte
```
For more information read the full problem in lieu of these summary lines.
**Solution**:
```assembly
.intel_syntax noprefix
.global _start
.most_common_byte:
# rdi is scr_addr, rsi is size
# init rcx as a counter
xor rcx, rcx
push rbp
mov rbp, rsp
sub rsp, 600
.while_restore:
cmp rcx, 512
jnb .exit_while_restore
mov rax, rbp
sub rax, rcx
sub rax, 8
mov WORD PTR [rax], 0
add rcx, 2
jmp .while_restore
.exit_while_restore:
# ------------------------------
xor rcx, rcx
.while_loop_1:
cmp rcx, rsi
jae .exit_loop_1
movzx eax, BYTE PTR [rdi + rcx]
mov edx, 2
mul edx
mov rdx, rbp
sub rdx, rax
sub rdx, 8
inc WORD PTR [rdx]
xor rdx, rdx
inc rcx
jmp .while_loop_1
.exit_loop_1:
# ------------------------------
# ------------------------------
xor rcx, rcx # b
xor r9, r9 # max_freq
xor r10, r10 # max_freq_byte
.while_loop_2:
cmp rcx, 0xff
ja .exit_loop_2
.if:
mov eax, ecx
mov edx, 2
mul edx
mov rdx, rbp
sub rdx, rax
sub rdx, 8
cmp WORD PTR [rdx], r9w
jna .exit_if
movzx r9, WORD PTR [rdx]
mov r10, rcx
.exit_if:
inc rcx
jmp .while_loop_2
.exit_loop_2:
# ------------------------------
mov rax, r10
mov rsp, rbp
pop rbp
ret
_start:
call .most_common_byte
```
Well, I first initialize the most_common_bytes function and call it.
Inside the function, I divided into three part. The first is to allocate list memory on stack as well as assigning all value equal to zero for further calculation.
In order not to against the Call Convention. We have to accept the registe RDI as the scr_addr and RSI as the size in the function parameters. During the whole assembling process. There is a few notes that you may need to notice.
>[!Note]
>* At first glance, everyone knew it a Call Convention
>* Secondly, RBP is a callee-saved register. So you must rollback to its base value
>* Furthermore, when dereference the register, you have to specify its type. For example, `BYTE PTR`, `WORD PTR`, `DWORD PTR`, `QWORD PTR` for CPU to understand it. Noticely, [register] need to judge as a bytes and each value stored in stack is considered as 2-byte data which is DWORD.
>* Lastly, don't forget RAX is our last return value and the `ret` in the end.
The final flag is: `pwn.college{4w3wgqB5EEkY_TgOeuJsNS4zGGl.dZTMywiN3UTNzEzW}`
```
```