flat assembler
Message board for the users of flat assembler.

Index > Linux > 1st program, random password generator

Author
Thread Post new topic Reply to topic
user71



Joined: 05 Feb 2024
Posts: 1
user71 05 Feb 2024, 16:04
Hello! I'm a novice assembly programmer. Here's my latest attempt:

Code:
;this program makes random passwords
;$ fasm randpw.asm randpw
;Usage: $ ./randpw <length> <number>

format ELF64 executable 3
use64
entry _start

segment readable writeable
length: dd 8 ;default password length
number: dd 1 ;generate one password by default
filename: db '/dev/random', 0
bad_args: db 'PARAMETER ERROR', 10
bad_args_len = $ - bad_args
array: db '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
max = $ - array
newline: db 10
filedes: dd ?
rand: dd ?

segment readable executable
_start:

;first argument
    mov rsi, qword [rsp+16]
    test rsi, rsi ;check for end of arguments
    jz .main_program
    call atoi
    mov [length], ebx

;second argument
    mov rsi, qword [rsp+24]
    test rsi, rsi ;check for end of arguments
    jz .main_program
    call atoi
    mov [number], ebx

    xor r14d, r14d ;counter for number of passwords

.main_program:
    mov eax, 2 ;syscall number for SYS_open
    mov rdi, filename
    mov esi, 0 ;O_RDONLY
    mov edx, 0
    syscall
    mov [filedes], eax ;save file descriptor for later

.next_pw:
    mov r15d, [length]
.main_loop:
    test r15d, r15d
    jz .endline
    dec r15d

    mov eax, 0 ;syscall number for SYS_read
    mov edi, [filedes] ;file descriptor
    mov rsi, rand
    mov edx, 4
    syscall

;index = rand % max
    mov eax, [rand]
    cqo
    mov ebx, max
    div ebx

    mov eax, 1 ;syscall number for SYS_write
    mov edi, 1 ;STDOUT_FILENO
    mov rsi, array ;characters
    add rsi, rdx ;the offset, modulus result from previous computation
    mov edx, 1 ;count
    syscall

    jmp .main_loop

.endline:
    mov eax, 1 ;syscall number for SYS_write
    mov edi, 1 ;STDOUT_FILENO
    mov rsi, newline
    mov edx, 1 ;count
    syscall

    inc r14d
    cmp r14d, [number] ;number of passwords to generate
    jne .next_pw

    mov eax, 60 ;syscall number for SYS_exit
    xor edi, edi ;success exit value
    syscall

atoi: ;takes string pointer in rsi, returns integer in ebx
    push rbp
    mov rbp, rsp

    xor ebx, ebx ;return value

.loop:
    lodsb ;rsi is incremented automatically
    test eax, eax ;end of string, leave loop
    jz .end

;check whether the numbers are within bounds
    cmp eax, '0'
    jb error
    cmp eax, '9'
    ja error

;multiply total by 10 and add the current digit converted to decimal
    sub eax, 48 ;convert current digit from ASCII to decimal
    lea ebx, [ebx * 4 + ebx] ;multiply total by 5
    lea ebx, [ebx * 2 + eax] ;multiply total again by 2 and add the current digit
    jmp .loop

.end:
    leave
    ret

error:
    mov eax, 1 ;syscall number for SYS_write
    mov edi, 2 ;STDERR_FILENO
    mov rsi, bad_args ;pointer to string
    mov edx, bad_args_len ;length of string
    syscall

    mov eax, 60 ;syscall number for SYS_exit
    mov edi, 1 ;failure exit value
    syscall

; vim: set ts=4 sw=4 sts=4 syn=fasm:
    


I was wondering, have I used 32-bit registers in correct places. Thx!


Last edited by user71 on 07 Feb 2024, 16:29; edited 2 times in total
Post 05 Feb 2024, 16:04
View user's profile Send private message Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20006
Location: In your JS exploiting you and your system
revolution 05 Feb 2024, 16:15
The code is fine.

I would recommend is to use lea for the addresses.
Code:
    lea rdi, [filename]    
64-bit code is really efficient when using RIP relative addressing.
Post 05 Feb 2024, 16:15
View user's profile Send private message Visit poster's website Reply with quote
redsock



Joined: 09 Oct 2009
Posts: 417
Location: Australia
redsock 06 Feb 2024, 21:09
Well done re: 32 bit register usage.

On all of my x86_64 Linux distributions, your code and data segments will always start well inside 32 bit space so where you have things like
Code:
mov rdi, filename    
or like @revolution did
Code:
lea rdi, [filename]    
you can safely use the 32 bit registers for these. Same of course for all of your function definitions/symbols/etc.
Code:
mov edi, filename
lea edi, [filename]    
Thanks to ASLR being on by default, stack space and VDSO addresses will always be >32 bits and randomized so you have to treat these with full 64 bit registers.

Also, starting with Linux kernel version 3.17 (released 2014-10-05) there is the getrandom syscall which would simplify some of your program. In <asm/unistd_64.h> this is syscall number 318.

Cheers Smile

_________________
2 Ton Digital - https://2ton.com.au/
Post 06 Feb 2024, 21:09
View user's profile Send private message Reply with quote
Feryno



Joined: 23 Mar 2005
Posts: 508
Location: Czech republic, Slovak republic
Feryno 08 Feb 2024, 04:43
Well done, nice and clean code! Use the LEA for addresses as guys already suggested you. IIRC before checking input args you can add something like this just after the _start:
Code:
_start:
mov ecx,[rsp+8*0] ; argc count of input arguments    

if ecx = 1 then there is only a pointer to your executable (qword [rsp+8*1]), this is useful for obtaining path and executable name, to check whether it was executed using your filename or whether executing using some symbolic link which has different name and path
if ecx = 2 them there is the pointer to your executable (qword [rsp + 8*1]) and the first arg (qword [rsp+8*2])
and so on... you can check args only upto qword [rsp + rcx*8], do not touch anything higher in the rsp using the qword [rsp+8*x] formula as there could be something else (you can grab bogus or ascii string instead of pointer) or there could be no stack anymore and accessing not present memory may cause pagefault... this is just a habit for a good practice
the stack on executable entrypoint looks like this:
[rsp+8*0]=N argc, N is at least 1 everytime because argv0
[rsp+8*1] argv1 the name of the executable
[rsp+8*2] argv2 1st param after executable (if any)
[rsp+8*3] argv3 2nd param after executable (if any)
...
[rsp+8*N] argvN Nth param after executable
qword [rsp+8*(N+1)]=0 end of argv
[rsp+8*(N+2)] envp environment
...
qword [rsp+8*(...)]=0 end of envp
Post 08 Feb 2024, 04:43
View user's profile Send private message Visit poster's website ICQ Number Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  


< Last Thread | Next Thread >
Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2024, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.