Author Topic: Converting hexdump from 32 bit into 64 bit  (Read 7424 times)

Offline acer_f

  • Jr. Member
  • *
  • Posts: 6
Converting hexdump from 32 bit into 64 bit
« on: June 01, 2018, 02:47:01 AM »
Hello everyone.. I was doing some exercise with hexdump and Im trying to convert the hexdump program from 32 bit into 64 bit, The problem is what i dont get the same output as hexdump 32 bit. Could someone please help me to find where exactly the problem is ? Thanks.

Code: [Select]
;----------------------------;
;  ./hexdump1 < (input file) ;
;----------------------------;

SECTION .data                        ; section containing initialised data

    HexStr db " 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",10
    HexLen equ $-HexStr
    Digits db "0123456789ABCDEF"

SECTION .bss                         ; section containing uninitialised data
   
    BUFFLEN EQU 16                   ; We read the file 16 bytes at a time
    Buff resb BUFFLEN               ; Text buffer itself

SECTION .text                        ; section containing code
    global _start                    ; Linker needs this to find the entry point!

_start:
    nop                              ; This no-op keeps gdb happy

Read:
    mov eax, 3                       ; specify sys_read call
    mov ebx, 0                       ; specify File Descriptor 0: Standard Input
    mov ecx, Buff                    ; Pass offset of the buffer to read to
    mov edx, BUFFLEN                 ; Pass number of bytes to read at one pass
    int 80h                          ; Call sys_read to fill the buffer
    mov ebp, eax                     ; Save # of bytes read from file for later
    cmp eax, 0                       ; If eax=0, sys_read reached EOF on stdin
    je Done                          ; Jump if equal (to 0, from compare)

; Set up the registers for the process buffer step:
    mov esi, Buff                    ; Place address of file buffer into esi
    mov edi, HexStr                  ; Place address of line string into edi
    xor ecx, ecx                     ; Clear line string pointer to 0

; Go through the buffer and convert binary values to hex digits:
Scan:
    xor eax, eax                     ; Clear eax to 0

; Here we calculate the offset into the line string, which is ecx x 3
    mov edx, ecx                     ; Copy the pointer into line string into edx
    shl edx, 1                       ; Multiply pointer by 2 using shift left
    add edx, ecx                     ; Complete the multiplication X3
    lea edx, [edx*2+edx]

; Get a character from the buffer and put it in both eax and ebx
    mov al, byte [esi+ecx]           ; Put a byte from the input buffer into al
    mov ebx, eax                     ; Duplicate the byte in bl for second nybble

; Look up low nybble character and insert it into the string:
    and al, 0Fh
    mov al, byte [Digits+eax]        ; Look up the char equivalent of nybble
    mov byte [HexStr+edx+2], al      ; Write the char equivalent to line string

; Look up high nybble character and insert it into the string:
    shr bl, 4                        ; Shift high 4 bits of char into low 4 bits
    mov bl, byte [Digits+ebx]        ; Look up char equivalent of nybble
    mov byte [HexStr+edx+1], bl      ; Write the char equivalent to line string

; Bump the buffer pointer to the next character and see if we are done:
    inc ecx                          ; Increment line string pointer
    cmp ecx, ebp                     ; Compare to the number of characters in the buffer
    jna Scan                         ; Loop back if ecx is <= number of chars in buffer

; Write the line of hexadecimal values to stdout:
    mov eax, 4                       ; Specify sys_Write call
    mov ebx, 1                       ; Specify File Descriptor 1: Standard output
    mov ecx, HexStr                  ; Pass offset of line string
    mov edx, HexLen                  ; Pass size of the line string
    int 80h                          ; make kernell call to display line string
    jmp Read                         ; Loop back and load file buffer again

; All done! Let's end this party:
Done:
    mov eax, 1                       ; Code for Exit Syscall
    mov ebx, 0                       ; Return a code of zero
    int 80h                          ; Make kernel call



Code: [Select]
;-------------------------------;
;   ./hexdump1-64 < inputFile   ;
;-------------------------------;

SECTION .data                       ; section containing initialised data

    HexStr db " 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",10
    HexLen equ $-HexStr
    Digits db "0123456789ABCDEF"

SECTION .bss                         ; section containing uninitialised data

    BUFFLEN EQU 16                   ; We read the file 16 bytes at a time
    Buff resb BUFFLEN                ; Text buffer itself

SECTION .text                        ; section containing code
    global _start                    ; Linker needs this to find the entry point!

_start:
    nop                              ; This no-op keeps gdb happy

Read:
    mov rax, 0                       ; specify sys_read call
    mov rdi, 0                       ; specify File Descriptor 0: Standard Input
    mov rsi, Buff                    ; Pass offset of the buffer to read to
    mov rdx, BUFFLEN                 ; Pass number of bytes to read at one pass
    syscall                          ; Call sys_read to fill the buffer
    mov rbp, rax                     ; Save # of bytes read from file for later
    cmp rax, 0                       ; If eax=0, sys_read reached EOF on stdin
    je Done                          ; Jump if equal (to 0, from compare)

; Set up the registers for the process buffer step:
    mov rbx, Buff                    ; Place address of file buffer into esi
    mov rcx, HexStr                  ; Place address of line string into edi
    xor rsi, rsi                     ; Clear line string pointer to 0

; Go through the buffer and convert binary values to hex digits:
Scan:
    xor rax, rax                     ; Clear eax to 0

; Here we calculate the offset into the line string, which is ecx x 3
    mov rdx, rsi                     ; Copy the pointer into line string into edx
    shl rdx, 1                       ; Multiply pointer by 2 using shift left
    add rdx, rsi                     ; Complete the multiplication X3
    lea rdx, [rdx*2+rdx]             ;

; Get a character from the buffer and put it in both eax and ebx
    mov al, byte [rbx+rsi]           ; Put a byte from the input buffer into al ; al
    mov rdi, rax                     ; Duplicate the byte in bl for second nybble

; Look up low nybble character and insert it into the string:
    and al, 0Fh
    mov al, byte [Digits+rax]        ; Look up the char equivalent of nybble
    mov byte [HexStr+rdx+2], al      ; Write the char equivalent to line string

; Look up high nybble character and insert it into the string:
    shr dl, 4                        ; Shift high 4 bits of char into low 4 bits
    mov dl, byte [Digits+rdi]        ; Look up char equivalent of nybble
    mov byte [HexStr+rdx+1], dl      ; Write the char equivalent to line string

; Bump the buffer pointer to the next character and see if we are done:
    inc rsi                          ; Increment line string pointer
    cmp rsi, rbp                     ; Compare to the number of characters in the buffer
    jna Scan                         ; Loop back if ecx is <= number of chars in buffer

; Write the line of hexadecimal values to stdout:
    mov rax, 1                       ; Specify sys_Write call
    mov rdi, 1                       ; Specify File Descriptor 1: Standard output
    mov rsi, HexStr                  ; Pass offset of line string
    mov rdx, HexLen                  ; Pass size of the line string
    syscall                          ; make kernell call to display line string
    jmp Read                         ; Loop back and load file buffer again

; All done! Let's end this party:
Done:
    mov rax, 60                      ; Code for Exit Syscall
    mov rdi, 0                       ; Return a code of zero
    syscall                          ; Make kernel call

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2667
  • Country: us
Re: Converting hexdump from 32 bit into 64 bit
« Reply #1 on: June 01, 2018, 04:05:07 AM »
Code: [Select]
; Here we calculate the offset into the line string, which is ecx x 3
    mov rdx, rsi                     ; Copy the pointer into line string into edx
    shl rdx, 1                       ; Multiply pointer by 2 using shift left
    add rdx, rsi                     ; Complete the multiplication X3
    lea rdx, [rdx*2+rdx]             ;

I may be in the mood to get into this later... maybe. But this oddity jumps out at me. You multiply by three... and then multiply by three again. The first comment does not match code - ecx is no longer involved. This is not the problem. You do the same thing in the 32-bit code (which does use ecx).

My memory is shot, but this "oddity" looks familiar to me. Have I seen this code before?

To help you solve this yourself... Are you sure this is really the code for the 32-bit version? What difference do you see in the output?

I'll try to get back to you on this, but I really think you only want to multiply by 3 once...

Best,
Frank


Offline acer_f

  • Jr. Member
  • *
  • Posts: 6
Re: Converting hexdump from 32 bit into 64 bit
« Reply #2 on: June 01, 2018, 05:03:02 AM »
Hello. Thanks for your reply.

The example hexdump 32 bit is from the book Assembly Language Step By Step by Jeff Dunteman.

The first one is 32 bit, and the second one is 64 bit but the comments are not correct.

1. When I run the 32 bit version ./hexdump1 < TestHexdump1.txt
I get this output :

Code: [Select]
73 61 64 20 73 61 64 0A 73 61 64 0A 73 61 0A 20
 66 64 C3 A4 0A 72 20 C3 A4 C3 B6 66 0A 77 20 45
 34 35 57 34 36 50 45 46 20 36 20 32 35 66 2B 33
 60 73 0A 64 73 0A 73 60 64 20 0A 73 60 0A 66 20
 0A 60 73 64 0A 60 73 64 0A 73 0A 66 2E 0A 65 77
 0A 0A 73 64 0A 60 73 64 0A 73 0A 66 2E 0A 65 77


2. The 64 bit version ./hexdump1-64 < TestHexdump1.txt
Output:

Code: [Select]
3 01 04 00 03 01 04 0A 03 01 04 0A 03 01 0A 00
 6 04 03 04 0A 02 00 03 04 03 06 06 0A 07 00 05
 4 05 07 04 06 00 05 06 00 06 00 02 05 06 0B 03
 0 03 0A 0
 03 0A 03 00 04 00 0A 03 00 0A 06 00
 A 00 03 04 0A 00 03 04 0A 03 0A 06 0E 0A 05 07
 A 0A 03 04 0A 00 03 04 0A 03 0A 06 0E 0A 05 07

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2667
  • Country: us
Re: Converting hexdump from 32 bit into 64 bit
« Reply #3 on: June 01, 2018, 05:07:18 AM »
There's more wrong with this than multiplying by 3 twice...
Code: [Select]
;-------------------------------;
;   ./hexdump1-64 < inputFile   ;
;-------------------------------;

SECTION .data                       ; section containing initialised data

    HexStr db " 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",10
    HexLen equ $-HexStr
    Digits db "0123456789ABCDEF"

SECTION .bss                         ; section containing uninitialised data

    BUFFLEN EQU 16                   ; We read the file 16 bytes at a time
    Buff resb BUFFLEN                ; Text buffer itself

SECTION .text                        ; section containing code
    global _start                    ; Linker needs this to find the entry point!

_start:
    nop                              ; This no-op keeps gdb happy

Read:
    mov rax, 0                       ; specify sys_read call
    mov rdi, 0                       ; specify File Descriptor 0: Standard Input
    mov rsi, Buff                    ; Pass offset of the buffer to read to
    mov rdx, BUFFLEN                 ; Pass number of bytes to read at one pass
    syscall                          ; Call sys_read to fill the buffer
    mov rbp, rax                     ; Save # of bytes read from file for later
    cmp rax, 0                       ; If eax=0, sys_read reached EOF on stdin
    je Done                          ; Jump if equal (to 0, from compare)

; Set up the registers for the process buffer step:
    mov rbx, Buff                    ; Place address of file buffer into esi

    mov rcx, HexStr                  ; Place address of line string into edi
;;; fortunately not used

    xor rsi, rsi                     ; Clear line string pointer to 0

; Go through the buffer and convert binary values to hex digits:
Scan:
    xor rax, rax                     ; Clear eax to 0

; Here we calculate the offset into the line string, which is ecx x 3
    mov rdx, rsi                     ; Copy the pointer into line string into edx
    shl rdx, 1                       ; Multiply pointer by 2 using shift left
    add rdx, rsi                     ; Complete the multiplication X3

;    lea rdx, [rdx*2+rdx]             ;
;;; 0nly multiply once!


; Get a character from the buffer and put it in both rax and rcx
    mov al, byte [rbx+rsi]           ; Put a byte from the input buffer into al ; al

;;;    mov rdi, rax                     ; Duplicate the byte in bl for second nybble
;;; rdi is not what you want here
mov rcx, rax


; Look up low nybble character and insert it into the string:
    and al, 0Fh
    mov al, byte [Digits+rax]        ; Look up the char equivalent of nybble
    mov byte [HexStr+rdx+2], al      ; Write the char equivalent to line string

; Look up high nybble character and insert it into the string:

;;; you're already using rdx
    shr cl, 4                        ; Shift high 4 bits of char into low 4 bits
    mov cl, byte [Digits+rcx]        ; Look up char equivalent of nybble
    mov byte [HexStr+rdx+1], cl      ; Write the char equivalent to line string

;;; I think that fixes it...

; Bump the buffer pointer to the next character and see if we are done:
    inc rsi                          ; Increment line string pointer
    cmp rsi, rbp                     ; Compare to the number of characters in the buffer
    jna Scan                         ; Loop back if ecx is <= number of chars in buffer

; Write the line of hexadecimal values to stdout:
    mov rax, 1                       ; Specify sys_Write call
    mov rdi, 1                       ; Specify File Descriptor 1: Standard output
    mov rsi, HexStr                  ; Pass offset of line string
    mov rdx, HexLen                  ; Pass size of the line string
    syscall                          ; make kernell call to display line string
    jmp Read                         ; Loop back and load file buffer again

; All done! Let's end this party:
Done:
    mov rax, 60                      ; Code for Exit Syscall
    mov rdi, 0                       ; Return a code of zero
    syscall                          ; Make kernel call

I'm not sure I've got all the comments right, but it "seems to work".

Best,
Frank


Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2667
  • Country: us
Re: Converting hexdump from 32 bit into 64 bit
« Reply #4 on: June 01, 2018, 06:06:09 AM »
Heh! Well we "crossed in the mail".  With all due respect, Jeff Duntemann can't multiply by 9 either! I just downloaded the code from his site. He multiplies by 3 twice, but comments out one. He comments out the shl and add and uses the lea. I commented out the lea and used the shl and add... but we are generally in agreement. In view of the fact that both methods are in the code, I wonder what it actually says in the book...

Anyway, good job on converting it to 64-bit!

Best,
Frank


Offline acer_f

  • Jr. Member
  • *
  • Posts: 6
Re: Converting hexdump from 32 bit into 64 bit
« Reply #5 on: June 03, 2018, 08:03:51 PM »
Hello.. Now I understand why before It was not working properly. Thank your very much for your help . :) :)