public inbox for [email protected]
 help / color / mirror / Atom feed
* Re: Please give me some help with assembly code!
       [not found] <CAG51281dxVNqg=sHBYsxKFGaD7605gUY3+HXggkFZhO_QrnQ0w@mail.gmail.com>
@ 2022-03-24  6:31 ` Ammar Faizi
  2022-03-24  6:34   ` Ammar Faizi
  0 siblings, 1 reply; 3+ messages in thread
From: Ammar Faizi @ 2022-03-24  6:31 UTC (permalink / raw)
  To: Anisa Elezi; +Cc: Ammar Faizi, GNU/Weeb Mailing List

On 3/24/22 12:32 AM, Anisa Elezi wrote:
> Hi Ammar,
> Hope you are well!

I am good :))

> I am Anisa, a student of Computer Science. I am studying malware analysis and one of our coursework has to do with assembly language. I was looking at your videos but still I am really struggling with some points.

Please use plain text mode and always CC the relevant list next time.
Read also: https://people.kernel.org/tglx/notes-about-netiquette

> 1. If I put the user ID as this format pXXXXXXX, which has p char and 7 digits, how can I check whether the input has this format or not ?

Simply do a loop and check all of those characters. Start traversing
from the first byte, make sure it contains char 'p', increment the
pointer, deference in a byte, do cmp, and so on...

That being said, the string consists of 9 bytes:
    - char 'p'.
    - 7 digit numbers.
    - A NUL char (this is the mark for the end of string).

Playing a bit with this on my Linux x86-64 System V ABI, the validate
function looks like this (note, the registers usage may differ on
a different platform/OS):

; bool validate_name(const char *name);
;
; --- System V ABI ---
; - The first argument goes in rdi.
; - The return value goes in rax.
; - rax, rdi, rsi, rdx, rcx are call-clobbered.
; - Returns 1 if username matches pXXXXXXX pattern,
;   otherwise returns 0.
validate_name:
         xor     eax, eax        ; Set return value to false.
         cmp     byte [rdi], 'p' ; Is the first byte is 'p'?

         jne     .out_ret        ; Jump to .out_ret if the first
                                 ; character is not p, bail out!

         inc     rdi             ; Increment the pointer, start moving
                                 ; to the second byte.

         xor     esi, esi        ; Prepare a loop counter.
.do_loop:
         mov     dl, [rdi]       ; Take one byte.

         cmp     dl, '0'         ; If it's below '0', then it's not
                                 ; a number.
         jb      .out_ret        ; Return false.

         cmp     dl, '9'         ; If it's above '9', then it's not
                                 ; a number.
         ja      .out_ret        ; Return false.

         inc     esi             ; Increment the loop counter.
         inc     rdi             ; Increment the string pointer.
         cmp     esi, 7
         jl      .do_loop        ; Jump back to the top if esi < 6

         cmp     byte [rdi], 0   ; Make sure the 8th byte is a NUL
                                 ; char (end of string).
         jne     .out_ret        ; Return false if it isn't a NUL char.

         mov     eax, 1          ; Return true
.out_ret:
         ret


> 2. If I have added some user in an array , how can I delete a user with a specific ID ?

Recall in C, we have a function called memmove(), this can do it.

First, you need to find the index of that user data. After that
you can simply do something like:

    if (num_of_elements == (idx + 1)) {
       /* The index is located at the end, just drop the counter */
       num_of_elements--;
    } else {
       /* Shift all elements after that index to the front. */
       memmmove(&array[idx], &array[idx - 1], sizeof(*arr) * num_of_elements - idx);
       num_of_elements--;
    }

Feel free to use "rep movsb" for the memmove() implementation.


> Here are the requirements of my coursework:
> 
> Your system must be able to store the following information about computers -
> /● Computer name
> ● IP address
> ● OS (can be any one of Linux, Windows, or Mac OSX)
> ● User ID of main user
> ● Date of purchase/
> /
> /Your system must be able to store the following information about people -
> ● /Surname name
> ● First Name
> ● Dept (can be any one of Development, IT Support, Finance, or HR)
> ● User ID
> ● Email address/
> /
> /Your system must allow the following operations –
> ● /Add/delete user
> ● Add/delete computer
> ● Search for computer given a computer name
> ● Search for a user’s given a user ID
> ● List all users
> ● List all computers/
> /
> /You should make the following assumptions about the system -
> /● First names and surnames, all have a maximum size of 64 chars
> ● Computer names are unique, and are in the form of cXXXXXXX where XXXXXXX is any 7 digit number
> ● User IDs are unique, and are in the form of pXXXXXXX where XXXXXXX is any
> 7 digit number
> ● Email addresses are in the form @helpdesk.co.uk <http://helpdesk.co.uk>
> ● There is a maximum of 100 users and 500 computers on the system/
> /--------------------------------------------------------------------------------------------------------/
> /Here is also a basic code that I found related to this coursework but i really struggled on this:/
> /; This include line is an absolute path to the I/O library. You may wish to change it to suit your own file system.
> %include "/home/malware/asm/joey_lib_io_v6_release.asm"
> 
> ; "global main" defines the entry point of the executable upon linking.
> ; In other words, "main" defines the point in the code from which the final executable starts execution.
> global main
> 
> ; The ".data" section is where initialised data in memory is defined. This is where we define strings and other predefined data.
> ; This section is read/write but NOT executable. If it were executable, someone could modify the data to be malicious executable code and then execute it.
> ; We don't want that! See "Data Execution Prevention (DEP)".
> ; "db" means "Define Byte", which allocates 1 byte.
> ; We could also use:
> ; "dw" = "Define Word", which allocates 2 bytes
> ; "dd" = "Define Doubleword", which allocates 4 bytes
> ; "dq" = "Define Quadword, which allocates 8 bytes
> section .data
>      str_main_menu db 10,\
>                              "Main Menu", 10,\
>                              " 1. Add User", 10,\
>                              " 2. List All Users", 10, \
>                              " 3. Count Users", 10,\
>                              " 4. Exit", 10,\
>                              "Please Enter Option 1 - 4", 10, 0
>      ; Note - after each string we add bytes of value 10 and zero (decimal). These are ASCII codes for linefeed and NULL, respectively.
>      ; The NULL is required because we are using null-terminated strings. The linefeed makes the console drop down a line, which saves us having to call "print_nl_new" function separately.
>      ; In fact, some strings defined here do not have a linefeed character. These are for occations when we don't want the console to drop down a line when the program runs.
>      str_program_exit db "Program exited normally.", 10, 0
>      str_option_selected db "Option selected: ", 0
>      str_invalid_option db "Invalid option, please try again.", 10, 0
>      str_enter_surname db "Enter surname:", 10, 0
>      str_enter_forename db "Enter forename:", 10, 0
>      str_enter_age db "Enter age:", 10, 0
>      str_enter_id db "Enter ID:", 10, 0
>      str_array_full db "Can't add - storage full.", 10, 0
>      str_number_of_users db "Number of users: ", 0
> 
>      ; Here we define the size of the block of memory that we want to reserve to hold the users' details
>      ; A user record stores the following fields:
>      ; forename = 64 bytes (string up to 63 characters plus a null-terminator)
>      ; surname = 64 bytes (string up to 63 characters plus a null-terminator)
>      ; Age = 1 byte (we're assuming that we don't have any users aged over 255 years old. Although if we entered Henry IV, this may be a problem!)
>      ; User ID = 64 bytes (string up to 63 characters plus a null terminator)
> 
>      ; Total size of user record is therefore 64+64+64+1 = 193 bytes
>      size_user_record equ 193
>      max_num_users equ 100 ; 100 users maximum in array (we can make this smaller in debugging for testing array limits etc.)
>      size_users_array equ size_user_record*max_num_users ; This calculation is performed at build time and is therefore hard-coded in the final executable.
>      ; We could have just said something like "size_users_array equ 19300". However, this is less human-readable and more difficult to modify the number of users / user record fields.
>      ; The compiled code would be identical in either case.
> 
>      current_number_of_users dq 0 ; this is a variable in memory which stores the number of users which have currently been entered into the array.
> 
> ; The ".bss" section is where we define uninitialised data in memory. Unlike the .data section, this data does not take up space in the executable file (apart from its definition, of course).
> ; Upon execution, this data is initialised to zero. This section is read/write but NOT executable, for the same reasons as .data section above.
> ; The syntax differs slightly from that of the .data section:
> ; resb = Reserve a Byte (1 byte)
> ; resw = Reserve a Word (2 bytes)
> ; resd = Reserve a Doubleword (4 bytes)
> ; resq = Reserve a Quadword (8 bytes)
> section .bss
>      users: resb size_users_array; space for max_num_users user records. "resb
> 
> ; The ".text" section contains the executable code. This area of memory is generally read-only so that the code cannot be mucked about with at runtime by a mischievous user.
> section .text
> 
> add_user:
> ; Adds a new user into the array
> ; We need to check that the array is not full before calling this function. Otherwise buffer overflow will occur.
> ; No parameters (we are using the users array as a global)
>      push rbx
>      push rcx
>      push rdx
>      push rdi
>      push rsi
> 
>      mov rcx, users ; base address of users array
>      mov rax, QWORD[current_number_of_users] ; why QWORD
>      ;value of current_number_of_users
>      mov rbx, size_user_record ; 193 bytes
>      ;size_user_record is an immediate operand since it is defined at build time.
>      mul rbx ; calculate address offset (returned in RAX).
>      ; RAX now contains the offset of the next user record. We need to add it to the base address of users record to get the actual address of the next empty user record.
>      add rcx, rax ; calculate address of next unused users record in array
>      ; RCX now contins address of next empty user record in the array, so we can fill up the data.
> 
>      ; get forename
>      mov rdi, str_enter_forename
>      call print_string_new ; print message
>      call read_string_new ; get input from user
>      mov rsi, rax ; address of new string into rsi
>      mov rdi, rcx ; address of memory slot into rdi
>      call copy_string ; copy string from input buffer into user record in array
>      ; get surname
>      add rcx, 64 ; move along by 64 bytes (which is the size reserved for the forename string)
>      mov rdi, str_enter_surname
>      call print_string_new ; print message
>      call read_string_new ; get input from user
>      mov rsi, rax ; address of new string into rsi
>      mov rdi, rcx ; address of memory slot into rdi
>      call copy_string ; copy string from input buffer into user record in array
>      ; get age
>      add rcx, 64 ; move along by 64 bytes (which is the size reserved for the surname string)
>      mov rdi, str_enter_age
>      call print_string_new ; print message
>      call read_uint_new ; get input from user
>      ; inputted number is now in the RAX register
>      mov BYTE[rcx], al ; we are only going to copy the least significant byte of RAX (AL), because our age field is only one byte
>      ; get user id
>      inc rcx ; move along by 1 byte (which is the size of age field)
>      mov rdi, str_enter_id
>      call print_string_new ; print message
>      call read_string_new ; get input from user
>      mov rsi, rax ; address of new string into rsi
>      mov rdi, rcx ; address of memory slot into rdi
>      call copy_string ; copy string from input buffer into user record in array
> 
>      inc QWORD[current_number_of_users] ; increment our number of users counter, since we have just added a record into the array.
>      pop rsi
>      pop rdi
>      pop rdx
>      pop rcx
>      pop rbx
>      ret ; End function add_user
> 
> 
> list_all_users:
> ; Takes no parameters (users is global)
> ; Lists full details of all users in the array
>      push rbx
>      push rcx
>      push rdx
>      push rdi
>      push rsi
> 
>      lea rsi, [users] ; load base address of the users array into RSI. In other words, RSI points to the users array.
>      mov rcx, [current_number_of_users] ; we will use RCX for the counter in our loop
> 
>      ;this is the start of our loop
>    .start_loop:
>      cmp rcx, 0
>      je .finish_loop ; if the counter is a zero then we have finished our loop
>      ;display the user record
>      mov rdi, rsi ; put the pointer to the current record in RDI, to pass to the print_string_new function
>      ;display forename
>      call print_string_new
>      mov rdi, ' ' ; space character, between forename and surname.
>      call print_char_new ; print a space
>      ;display surname
>      lea rdi, [rsi + 64] ; move the pointer along by 64 bytes from the base address of the record (the size of the forename string)
>      call print_string_new
>      call print_nl_new
>      ;display age
>      movzx rdi, BYTE[rsi + 128] ; dereferrence [RSI + 128] into RDI. 128 bytes is the combined size of the forename and surname strings.
>                                                  ;We need to zero extend (movzx) because the age in memory is one byte and the RDI register is 8 bytes.
>      call print_uint_new ; print the age
>      call print_nl_new
>      lea rdi, [rsi + 129] ; move the pointer along by 129 bytes from the base address of the record (combined size of the forename and surname strings, and age)
>      call print_string_new
>      call print_nl_new
>      call print_nl_new
>      add rsi, size_user_record ; move the address to point to the next record in the array
>      dec rcx ; decrement our counter variable
>      jmp .start_loop ; jump back to the start of the loop (unconditional jump)
>    .finish_loop:
> 
>      pop rsi
>      pop rdi
>      pop rdx
>      pop rcx
>      pop rbx
>      ret ; End function list_all_users
> 
> display_number_of_users:
> ; No parameters
> ; Displays number of users in list (to STDOUT)
>      push rdi
>      mov rdi, str_number_of_users
>      call print_string_new
>      mov rdi, [current_number_of_users]
>      call print_uint_new
>      call print_nl_new
>      pop rdi
>      ret ; End function display_number_of_users
> 
> display_main_menu:
> ; No parameters
> ; Prints main menu
>      push rdi
>      mov rdi, str_main_menu
>      call print_string_new
>      pop rdi
>      ret ; End function display_main_menu
> 
> main:
>      mov rbp, rsp; for correct debugging
>      ; We have these three lines for compatability only
>      push rbp
>      mov rbp, rsp
>      sub rsp,32
> 
>    .menu_loop:
>      call display_main_menu
>      call read_int_new ; menu option (number) is in RAX
>      mov rdx, rax ; store value in RDX
>      ; Print the selected option back to the user
>      mov rdi, str_option_selected
>      call print_string_new
>      mov rdi, rdx
>      call print_int_new
>      call print_nl_new
>      ; Now jump to the correct option
>      cmp rdx, 1
>      je .option_1
>      cmp rdx, 2
>      je .option_2
>      cmp rdx, 3
>      je .option_3
>      cmp rdx, 4
>      je .option_4
>      ; If we get here, the option was invalid. Display error and loop back to input option.
>      mov rdi, str_invalid_option
>      call print_string_new
>      jmp .menu_loop
> 
>    .option_1: ; 1. Add User
>      ; Check that the array is not full
>      mov rdx, [current_number_of_users] ; This is indirect, hence [] to dereference
>      cmp rdx, max_num_users ; Note that max_num_users is an immediate operand since it is defined at build-time
>      jl .array_is_not_full ; If current_number_of_users < max_num_users then array is not full, so add new user.
>      mov rdi, str_array_full ; display "array is full" message and loop back to main menu
>      call print_string_new
>      jmp .menu_loop
>    .array_is_not_full:
>      call add_user
>      jmp .menu_loop
> 
>    .option_2: ; 2. List All Users
>      call display_number_of_users
>      call print_nl_new
>      call list_all_users
>      jmp .menu_loop
> 
>    .option_3: ; 3. Count Users
>      call display_number_of_users
>      jmp .menu_loop
> 
>    .option_4: ; 4. Exit
>      ; In order to exit the program we just display a message and return from the main function.
>      mov rdi, str_program_exit
>      call print_string_new
> 
>      xor rax, rax ; return zero
> 
>      ; and these lines are for compatability
>      add rsp, 32
>      pop rbp
> 
>      ret ; End function main/
> /
> /
> /
> /
> /
> /

-- 
Ammar Faizi

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: Please give me some help with assembly code!
  2022-03-24  6:31 ` Please give me some help with assembly code! Ammar Faizi
@ 2022-03-24  6:34   ` Ammar Faizi
  2022-03-24  9:39     ` Anisa Elezi
  0 siblings, 1 reply; 3+ messages in thread
From: Ammar Faizi @ 2022-03-24  6:34 UTC (permalink / raw)
  To: Anisa Elezi; +Cc: GNU/Weeb Mailing List

On 3/24/22 1:31 PM, Ammar Faizi wrote:
>          inc     rdi             ; Increment the string pointer.
>          cmp     esi, 7
>          jl      .do_loop        ; Jump back to the top if esi < 6

^ That comment got a typo, should be if esi < 7, of course.

-- 
Ammar Faizi

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: Please give me some help with assembly code!
  2022-03-24  6:34   ` Ammar Faizi
@ 2022-03-24  9:39     ` Anisa Elezi
  0 siblings, 0 replies; 3+ messages in thread
From: Anisa Elezi @ 2022-03-24  9:39 UTC (permalink / raw)
  To: Ammar Faizi; +Cc: GNU/Weeb Mailing List


Thank you so much for your help Ammar,

You really helped me a lot!

Thank you again!

Have a nice day!

Anisa

On Thu, 24 Mar 2022 at 06:35, Ammar Faizi <[email protected]> wrote:

> On 3/24/22 1:31 PM, Ammar Faizi wrote:
> >          inc     rdi             ; Increment the string pointer.
> >          cmp     esi, 7
> >          jl      .do_loop        ; Jump back to the top if esi < 6
>
> ^ That comment got a typo, should be if esi < 7, of course.
>
> --
> Ammar Faizi
>

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2022-03-24  9:40 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
     [not found] <CAG51281dxVNqg=sHBYsxKFGaD7605gUY3+HXggkFZhO_QrnQ0w@mail.gmail.com>
2022-03-24  6:31 ` Please give me some help with assembly code! Ammar Faizi
2022-03-24  6:34   ` Ammar Faizi
2022-03-24  9:39     ` Anisa Elezi

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox