flat assembler
Message board for the users of flat assembler.

flat assembler > DOS > BYTEFIX -- change a hex byte in a binary file

Author
Thread Post new topic Reply to topic
rugxulo



Joined: 09 Aug 2005
Posts: 2341
Location: Usono (aka, USA)
Not quite a full hex editor, but it's very small and usable inside .BAT files (automated/scriptable). It tries to check for most common errors, too.

Alas, it could definitely be written "better", but for now this will have to do.

Code:
; BYTEFIX.ASM -- change a hex byte in a binary file
;
; rugxulo _AT_ gmail
;
; public domain, free for any use, nenies proprajho, "Christus Rex!"


ARGC=80h
ARGV=81h
BYTE1=ARGV+1+8+1
CR=13
FILENAME=ARGV+1+8+1+2+1+2+1
LF=10
MINARGC=15+1

CLOSEFILE=3Eh
GOODBYE=4Ch
OPENFILERW=3D02h
READFILE=3Fh
SEEKSETFILE=4200h
WRITEFILE=40h
WRITESTR=9

DOS equ int 21h

b equ byte
w equ word


; section .text

org 100h ; DOS .COM

Main
  call fixargs
  cmp bARGC,MINARGC
  jae .okay
  mov ah,WRITESTR
  mov dx,usagemsg
  DOS
  mov berrlvl,255
  jmp Fino
.okay
  mov si,ARGV+1
  call scanofs
  jc Fino
  call fixbyte
Fino
  mov ah,GOODBYE
  mov al,berrlvl
  DOS
; end Main


; proc
fixargs
  xor ch,ch
  mov cl,bARGC
  jcxz .ret
  push cx
  call stripblanks
  pop cx
  mov si,ARGV+1
  mov di,si
.loop
  lodsb
  push cx
  mov bx,'az'
  push bx
  call rangecheck
  pop cx
  sbb bl,bl
  or bl,not ' '
  and al,bl
  stosb
  loop .loop
.ret
  ret
; endp


; proc
stripblanks
  mov di,ARGV
  lea si,di+1
  inc cx
  mov al,' '
  rep scasb
  dec di
  mov bARGC,cl
  xchg si,di
  push cx cx
  rep movsb
  pop cx di
  add di,ARGV
  mov al,' '
  std
  rep scasb
  cld
  inc cx
  mov bdi+2,0 ; NUL for ASCIIZ filename
  mov bARGC,cl
  ret
; endp


; proc
fixbyte
  call getbytes
.open
  mov ax,OPENFILERW
  mov dx,FILENAME
  DOS
  jc .ret
  mov handle,ax
.seek
  call seekbyte
  jc .close
.read
  mov ah,READFILE
  mov bx,handle
  mov cx,1
  mov dx,foundbyte
  DOS
  jc .close
.compare
  mov al,foundbyte
  cmp al,boldbyte
  jnz .close
  call seekbyte
.write
  mov ah,WRITEFILE
  mov bx,handle
  mov cx,1
  mov dx,newbyte
  DOS
  jc .close
  mov berrlvl,0
.close
  mov ah,CLOSEFILE
  mov bx,handle
  DOS
.ret
  ret
; endp


; proc
seekbyte
  mov ax,SEEKSETFILE
  mov bx,handle
  mov cx,wofs+2
  mov dx,wofs
  DOS
  ret
;endp


; proc
getbytes
  mov si,BYTE1
  call hexbyte
  mov oldbyte,al
  call hexbyte
  mov newbyte,al
  ret
; endp


; proc
hexbyte
  lodsb
  call ishex
  jc .ret
  call asc2hex
  mov cl,4
  shl al,cl
  mov dl,al
  lodsb
  push dx
  call ishex
  pop dx
  jc .ret
  call asc2hex
  add dl,al
  inc si
  xchg ax,dx
.ret
  ret
; endp


; proc
scanofs
  mov cx,8
.load
  lodsb
  push cx
  call ishex
  pop cx
  jc .ret
  push cx
  call asc2hex
  pop cx
.adjust
  push ax cx
  mov ax,wofs
  mov dx,wofs+2
  mov cl,4
.shift
  rcl ax,1
  rcl dx,1
  loop .shift
  pop cx
  mov wofs,ax
  mov wofs+2,dx
.add
  pop ax
  xor ah,ah
  add wofs,ax
  adc wofs+2,0
.continue
  loop .load
.ret
  ret
; endp


; proc
asc2hex
  cmp al,40h
  adc al,69h
  daa
  mov ah,al
  and al,15
  mov cl,4
  shr ah,cl
  aad
  ret
; endp


; proc
ishex
  mov cx,'09'
  push cx
  call rangecheck
  sbb bh,bh

; mov cx,'af'
; push cx
; call rangecheck
; sbb bl,bl
; and bh,bl

  mov cx,'AF'
  push cx
  call rangecheck
  sbb bl,bl
  and bh,bl

  neg bh
  clc
  lahf
  or ah,bh
  sahf

  ret       ; return CF if not valid hex char
; endp


; proc
rangecheck ; in upper_limit shl 8 + lower_limit
  pop bp
  pop dx    ; mov dx,sp+2
  push bp
.check
  cmp al,dl
  sbb ch,ch
  inc dh
  cmp al,dh
  cmc
  sbb dl,dl
  or dl,ch
  cmp dl,1  ; set CF if DL == 0
  cmc       ; return NC if AL within valid range
  ret
; endp


; section .data

errlvl db 1
handle dw 0
ofs    dd 0
usagemsg db CR,LF,'Usage  bytefix.com CaFe5150 1a 2b file.dat',CR,LF,'$'


; section .bss

oldbyte rb 1
newbyte rb 1
foundbyte rb 1

; EOF
    
Post 08 Mar 2017, 01:32
View user's profile Send private message Visit poster's website Reply with quote
rugxulo



Joined: 09 Aug 2005
Posts: 2341
Location: Usono (aka, USA)
rugxulo wrote:

Alas, it could definitely be written "better", but for now this will have to do.


Code:
--- bytefix.old 2017-03-07 141352 -0600
+++ bytefix.new 2017-03-10 121920 -0600
@@ -40,3 +40,3 @@
   DOS
-  mov berrlvl,255
+  neg berrlvl
   jmp Fino
@@ -48,4 +48,3 @@
 Fino
-  mov ah,GOODBYE
-  mov al,berrlvl
+  mov ax,werrlvl
   DOS
@@ -109,2 +108,5 @@
   call getbytes
+.issame
+  cmp al,di-2
+  jz .ret
 .open
@@ -161,6 +163,7 @@
   mov si,BYTE1
+  mov di,oldbyte
   call hexbyte
-  mov oldbyte,al
-  call hexbyte
-  mov newbyte,al
+  stosb
+  call hexbyte ; newbyte
+  stosb
   ret
@@ -206,12 +209,8 @@
   push ax cx
-  mov ax,wofs
-  mov dx,wofs+2
   mov cl,4
 .shift
-  rcl ax,1
-  rcl dx,1
+  rcl wofs,1
+  rcl wofs+2,1
   loop .shift
   pop cx
-  mov wofs,ax
-  mov wofs+2,dx
 .add
@@ -261,7 +260,3 @@
 
-  neg bh
-  clc
-  lahf
-  or ah,bh
-  sahf
+  shr bh,1
 
@@ -292,3 +287,3 @@
 
-errlvl db 1
+errlvl db 1, GOODBYE
 handle dw 0
    
Post 10 Mar 2017, 20:39
View user's profile Send private message Visit poster's website Reply with quote
rugxulo



Joined: 09 Aug 2005
Posts: 2341
Location: Usono (aka, USA)
Made a (very) few fixes and improvements. Is it worth keeping the original version (and/or diff)? Meh, but for now, for completeness, I'll leave 'em "as is".

Code:
; BYTEFIX.ASM -- change a hex byte in a binary file
;
; rugxulo _AT_ gmail
;
; public domain, free for any use, nenies proprajho, "Christus Rex!"


ARGC=80h
ARGV=81h
BYTE1=ARGV+1+8+1
CR=13
FILENAME=ARGV+1+8+1+2+1+2+1
LF=10
MINARGC=15+1

CLOSEFILE=3Eh
GOODBYE=4Ch
OPENFILERW=3D02h
READFILE=3Fh
SEEKSETFILE=4200h
WRITEFILE=40h
WRITESTR=9

DOS equ int 21h

b equ byte
w equ word

macro proc name 
  if used name
name

endp fix end if


; section .text

org 100h

Main
  call fixargs
  cmp bARGC,MINARGC
  jae .okay
  mov ah,WRITESTR
  mov dx,usagemsg
  DOS
  neg errlvl
  jmp Fino
.okay
  mov si,ARGV+1
  call scanofs
  jc Fino
  call fixbyte
Fino
  mov ax,werrlvl
  DOS
; end Main


proc fixargs
  xor ch,ch
  mov cl,bARGC
  jcxz .ret
  push cx
  call stripblanks
  pop cx
  mov si,ARGV+1
  mov di,si
.loop
  lodsb
  push cx
  mov bx,'az'
  push bx
  call rangecheck
  pop cx
  sbb bl,bl
  or bl,not ' '
  and al,bl
  stosb
  loop .loop
.ret
  ret
endp


proc stripblanks
  mov di,ARGV
  lea si,di+1
  inc cx
  mov al,' '
  rep scasb
  dec di
  mov bARGC,cl
  xchg si,di
  push cx cx
  rep movsb
  pop cx di
  add di,ARGV
  mov al,' '
  std
  rep scasb
  cld
  inc cx
  mov bdi+2,0 ; NUL for ASCIIZ filename
  mov bARGC,cl
  ret
endp


proc fixbyte
  cmp bBYTE1,'?'
  jz .open
  call getbytes
  jc .ret
.issame
  cmp al,di-2
  jz .ret
.open
  mov ax,OPENFILERW
  mov dx,FILENAME
  DOS
  jc .ret
  mov handle,ax
.seek
  call seekbyte
  jc .close
.read
  mov ah,READFILE
  mov bx,handle
  mov cx,1
  mov dx,foundbyte
  DOS
  jc .close
.query
  cmp bBYTE1,'?'
  jnz .compare
  mov al,foundbyte
  mov errlvl,al
  jmp .close
.compare
  mov al,foundbyte
  cmp al,boldbyte
  jnz .close
  call seekbyte
.write
  mov ah,WRITEFILE
  mov bx,handle
  mov cx,1
  mov dx,newbyte
  DOS
  jc .close
  dec errlvl
.close
  mov ah,CLOSEFILE
  mov bx,handle
  DOS
.ret
  ret
endp


proc seekbyte
  mov ax,SEEKSETFILE
  mov bx,handle
  mov cx,wofs+2
  mov dx,wofs
  DOS
  ret
endp


proc getbytes
  mov si,BYTE1
  mov di,oldbyte
  call hexbyte
  jc .ret
  call hexbyte ; newbyte
.ret
  ret
endp


proc hexbyte
  lodsb
  call ishex
  jc .ret
  call asc2hex
  mov cl,4
  shl al,cl
  mov dl,al
  lodsb
  push dx
  call ishex
  pop dx
  jc .ret
  call asc2hex
  add dl,al
  inc si
  xchg ax,dx
  stosb
.ret
  ret
endp


proc scanofs
  mov cx,8
.load
  lodsb
  push cx
  call ishex
  pop cx
  jc .ret
  push cx
  call asc2hex
  pop cx
.adjust
  push ax cx
  mov cl,4
.shift
  rcl wofs,1
  rcl wofs+2,1
  loop .shift
  pop cx
.add
  pop ax
  xor ah,ah
  add wofs,ax
  adc wofs+2,0
.continue
  loop .load
.ret
  ret
endp


proc asc2hex
  cmp al,40h
  adc al,69h
  daa
  mov ah,al
  and al,15
  mov cl,4
  shr ah,cl
  aad
  ret
endp


proc ishex
  mov cx,'09'
  push cx
  call rangecheck
  sbb bh,bh

; mov cx,'af'
; push cx
; call rangecheck
; sbb bl,bl
; and bh,bl

  mov cx,'AF'
  push cx
  call rangecheck
  sbb bl,bl
  and bh,bl

  shr bh,1

  ret       ; return CF if not valid hex char
endp


proc rangecheck
            ; in upper_limit shl 8 + lower_limit
  pop bp
  pop dx    ; mov dx,sp+2
  push bp
.check
  cmp al,dl
  sbb ch,ch
  inc dh
  cmp al,dh
  cmc
  sbb dl,dl
  or dl,ch
  cmp dl,1  ; set CF if DL == 0
  cmc       ; return NC if AL within valid range
  ret
endp


; section .data

errlvl db 1, GOODBYE
handle dw 0
ofs    dd 0
usagemsg db CR,LF,'Usage  bytefix.com CaFe5150 Ed A1 file.dat',CR,LF,'$'


; section .bss

oldbyte rb 1
newbyte rb 1
foundbyte rb 1

; EOF
    
Post 16 Mar 2017, 03:13
View user's profile Send private message Visit poster's website Reply with quote
rugxulo



Joined: 09 Aug 2005
Posts: 2341
Location: Usono (aka, USA)
Here's another improvement ... but I'm not too confident about it. Despite some light testing, I'm worried about bugs. Also, it's hitting the 512-byte limit, which was my goal to stay under. At this point I'm considering rewriting (again) in Turbo Pascal (hey, 4 kb output isn't too bloated, heheh).

Code:
; BYTEFIX.ASM -- change a hex byte in a binary file
;
; rugxulo _AT_ gmail
;
; public domain, free for any use, nenies proprajho, "Christus Rex!"


ARGC=80h
ARGV=81h
BYTE1=ARGV+1+8+1
CR=13
FILENAME=ARGV+1+8+1+2+1+2+1
LF=10
MINARGC=15+1

CLOSEFILE=3Eh
GOODBYE=4Ch
OPENFILERW=3D02h
READFILE=3Fh
SEEKSETFILE=4200h
WRITEFILE=40h
WRITESTR=9

DOS equ int 21h

b equ byte
w equ word

macro proc name 
  if used name
name


end fix end if

macro endp 
.ret
  ret
  end


macro charargs 
  push wBYTE1+3
  push wBYTE1
  mov di,charbyte1
  rept 2 \
    pop ax
    stosw
  \


macro stripblanks 
  mov di,ARGV
  lea si,di+1
  inc cx
  mov al,' '
  rep scasb
  dec di
  mov ARGC,cl
  xchg si,di
  push cx cx
  rep movsb
  pop cx di
  add di,ARGV
  mov al,' '
  std
  rep scasb
  cld
  inc cx
  mov bdi+2,0 ; NUL for ASCIIZ filename
  mov ARGC,cl


macro fixargs 
  local .loop,.bye

  xor ch,ch
  mov cl,ARGC
  jcxz .bye
  push cx
  stripblanks
  pop cx
  mov si,ARGV+1
  mov di,si
.loop
  lodsb
  push cx
  mov bx,'az'
  push bx
  call rangecheck
  pop cx
  sbb bl,bl
  or bl,not ' '
  and al,bl
  stosb
  loop .loop
.bye


macro scanofs 
  local .load,.adjust,.shift,.add,.continue,.bye

  mov cx,8
.load
  lodsb
  push cx
  call ishex
  pop cx
  jc .bye
  push cx
  call asc2hex
  pop cx
.adjust
  push ax cx
  mov cl,4
.shift
  rcl wofs,1
  rcl wofs+2,1
  loop .shift
  pop cx
.add
  pop ax
  xor ah,ah
  add wofs,ax
  adc wofs+2,0
.continue
  loop .load
.bye


; --------------------------------------------------------------------
; section .text
org 100h
Main
  charargs
  fixargs
  cmp bARGC,MINARGC
  jae .okay
  mov ah,WRITESTR
  mov dx,usagemsg
  DOS
  neg errlvl
  jmp Fino
.okay
  mov si,ARGV+1
  scanofs
  jc Fino
  call fixbyte
Fino
  mov ax,werrlvl
  DOS
; end Main
; --------------------------------------------------------------------


proc fixbyte
  cmp bBYTE1,'?'
  jz .open
  call getbytes
  jc .ret
.issame
  mov al,oldbyte
  cmp al,newbyte
  jz .ret
.open
  mov ax,OPENFILERW
  mov dx,FILENAME
  DOS
  jc .ret
  mov handle,ax
.seek
  call seekbyte
  jc .close
.read
  mov ah,READFILE
  mov bx,handle
  mov cx,1
  mov dx,foundbyte
  DOS
  jc .close
.query
  cmp bBYTE1,'?'
  jnz .compare
  mov al,foundbyte
  mov errlvl,al
  jmp .close
.compare
  cmp bBYTE1,'!'
  jz .seekagain
.noforce
  mov al,foundbyte
  cmp al,oldbyte
  jnz .close
.seekagain
  call seekbyte
.write
  mov ah,WRITEFILE
  mov bx,handle
  mov cx,1
  mov dx,newbyte
  DOS
  jc .close
  dec errlvl
.close
  mov ah,CLOSEFILE
  mov bx,handle
  DOS
endp


proc seekbyte
  mov ax,SEEKSETFILE
  mov bx,handle
  mov cx,wofs+2
  mov dx,wofs
  DOS
endp


proc getbytes
  push ax
  mov di,oldbyte
  push di
  mov ax,charbyte1
  mov cx,charbyte2
  xchg al,ch
  cmp cx,''''''
  jnz .hex
  mov cx,2
.check
  xchg ah,al
  mov dx,'!~'
  push dx
  call rangecheck
  jc .bye
  loop .check
  xchg ah,al
  stosw
  jmp .bye
.hex
  mov si,BYTE1
  cmp bsi,'!'
  jnz .noforce
  add si,3
  inc di
  jmp .byte2
.noforce
  call hexbyte
  jc .bye
.byte2
  call hexbyte ; newbyte
.bye
  pop di ax
endp


proc hexbyte
  lodsb
  call ishex
  jc .ret
  call asc2hex
  mov cl,4
  shl al,cl
  mov dl,al
  lodsb
  push dx
  call ishex
  pop dx
  jc .ret
  call asc2hex
  add dl,al
  inc si
  xchg ax,dx
  stosb
endp


proc asc2hex
  cmp al,40h
  adc al,69h
  daa
  mov ah,al
  and al,15
  mov cl,4
  shr ah,cl
  aad
endp


proc ishex
  mov cx,'09'
  push cx
  call rangecheck
  sbb bh,bh

; mov cx,'af'
; push cx
; call rangecheck
; sbb bl,bl
; and bh,bl

  mov cx,'AF'
  push cx
  call rangecheck
  sbb bl,bl
  and bh,bl

  shr bh,1  ; return CF if not valid hex char
endp


proc rangecheck
            ; in upper_limit shl 8 + lower_limit
  pop bp
  pop dx    ; mov dx,sp+2
  push bp
.check
  cmp al,dl
  sbb ch,ch
  inc dh
  cmp al,dh
  cmc
  sbb dl,dl
  or dl,ch
  cmp dl,1  ; set CF if DL == 0
  cmc       ; return NC if AL within valid range
endp


; --------------------------------------------------------------------
; section .data
errlvl db 1, GOODBYE
ofs    dd 0
usagemsg db CR,LF,'Usage BYTEFIX CaFe5150 Ed A1 my.dat',CR,LF,'$'
; --------------------------------------------------------------------


; --------------------------------------------------------------------
; section .bss
oldbyte rb 1
newbyte rb 1
foundbyte rb 1
charbyte1 rw 1
charbyte2 rw 1
handle rw 1
; --------------------------------------------------------------------

; EOF
    
Post 10 Aug 2017, 00:52
View user's profile Send private message Visit poster's website 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-2019, Tomasz Grysztar.

Powered by rwasa.