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: 2279
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 b[ARGC],MINARGC jae .okay mov ah,WRITESTR mov dx,usagemsg DOS mov b[errlvl],255 jmp Fino .okay: mov si,ARGV+1 call scanofs jc Fino call fixbyte Fino: mov ah,GOODBYE mov al,b[errlvl] DOS ; end Main ; proc fixargs: xor ch,ch mov cl,b[ARGC] 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 b[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 b[di+2],0 ; NUL (for ASCIIZ filename) mov b[ARGC],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,b[oldbyte] jnz .close call seekbyte .write: mov ah,WRITEFILE mov bx,[handle] mov cx,1 mov dx,newbyte DOS jc .close mov b[errlvl],0 .close: mov ah,CLOSEFILE mov bx,[handle] DOS .ret: ret ; endp ; proc seekbyte: mov ax,SEEKSETFILE mov bx,[handle] mov cx,w[ofs+2] mov dx,w[ofs] 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,w[ofs] mov dx,w[ofs+2] mov cl,4 .shift: rcl ax,1 rcl dx,1 loop .shift pop cx mov w[ofs],ax mov w[ofs+2],dx .add: pop ax xor ah,ah add w[ofs],ax adc w[ofs+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: 2279
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 14:13:52 -0600 +++ bytefix.new 2017-03-10 12:19:20 -0600 @@ -40,3 +40,3 @@ DOS - mov b[errlvl],255 + neg b[errlvl] jmp Fino @@ -48,4 +48,3 @@ Fino: - mov ah,GOODBYE - mov al,b[errlvl] + mov ax,w[errlvl] 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,w[ofs] - mov dx,w[ofs+2] mov cl,4 .shift: - rcl ax,1 - rcl dx,1 + rcl w[ofs],1 + rcl w[ofs+2],1 loop .shift pop cx - mov w[ofs],ax - mov w[ofs+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: 2279
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 b[ARGC],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,w[errlvl] DOS ; end Main proc fixargs xor ch,ch mov cl,b[ARGC] 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 b[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 b[di+2],0 ; NUL (for ASCIIZ filename) mov b[ARGC],cl ret endp proc fixbyte cmp b[BYTE1],'?' 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 b[BYTE1],'?' jnz .compare mov al,[foundbyte] mov [errlvl],al jmp .close .compare: mov al,[foundbyte] cmp al,b[oldbyte] 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,w[ofs+2] mov dx,w[ofs] 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 w[ofs],1 rcl w[ofs+2],1 loop .shift pop cx .add: pop ax xor ah,ah add w[ofs],ax adc w[ofs+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: 2279
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 w[BYTE1+3] push w[BYTE1] 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 b[di+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 w[ofs],1 rcl w[ofs+2],1 loop .shift pop cx .add: pop ax xor ah,ah add w[ofs],ax adc w[ofs+2],0 .continue: loop .load .bye: } ; -------------------------------------------------------------------- ; section .text org 100h Main: charargs fixargs cmp b[ARGC],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,w[errlvl] DOS ; end Main ; -------------------------------------------------------------------- proc fixbyte cmp b[BYTE1],'?' 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 b[BYTE1],'?' jnz .compare mov al,[foundbyte] mov [errlvl],al jmp .close .compare: cmp b[BYTE1],'!' 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,w[ofs+2] mov dx,w[ofs] 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 b[si],'!' 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 © 2004-2018, Tomasz Grysztar.

Powered by rwasa.