home *** CD-ROM | disk | FTP | other *** search
- ;A patcher with search capability, the patch becomes usefull for more versions!
- ;Multiple string patching added!
- ;Multiple file patching added!
- ;TO-DO: - comments (almost finished)
- ; - finish interface / readible output (almost finished)
- ; - for each file add an array of approved filesizes
- ; - print also filesizes if they don't match
- ; - possibility for correcting date/attributes
- ; - (longterm) CRC-32 correcting possibility
- ;Copyright (c) 1998,1999 Anarchriz. All rights reserved.
- ;currently version 28.01.1999
-
- .model tiny
-
- .stack 200h
-
- NUMBEROFFILES equ 2 ; <--
-
- STEPSIZE equ 32768
- MAXSTRINGSIZE equ 32
- MAXSTRINGS equ 32
- MAXFILES equ 8
- LOCATIONFILESIZE equ 6
-
- .data
-
- ;Messages
- beginMsg db 'The Patcher version 28.01.1999 - copyright (c) 1998,1999 Anarchriz',10,13,'$'
- patchMsg db 'Test patch Message, by Anarchriz ;)',10,13,'$'
- patchingMsg db 'Patching file: $'
- filesizeMsg db ' The expected filesize and the current filesize do not match, continue?',10,13
- db ' y)es, a)lways or n)o : $'
- offsetMsg db ' Expected offset ######## and found ######## for string ##, continue ?',10,13
- db ' y)es, a)lways or n)o : $'
- newline db 10,13,'$'
- succesMsg db 'Patching was succesfull!',10,13,'$'
-
- ;Error Messages
- noFilesToPatchErrorMsg db 'ERROR: no files to patch',10,13,'$'
- filenameTolongMsg db 'ERROR: given filename to long',10,13,'$'
- fileNotFoundMsg db 'ERROR: did not found the file to patch',10,13,'$'
- readErrorMsg db 'ERROR: error on reading file',10,13,'$'
- moveErrorMsg db 'ERROR: error on moving file pointer',10,13,'$'
- writeErrorMsg db 'ERROR: error on writing file',10,13,'$'
- errorOnOpeningMsg db 'ERROR: error on opening the file',10,13,'$'
- nothingToDoErrorMsg db 'ERROR: no string(s) to search & patch',10,13,'$'
- stringNotFoundMsg db 'String(s) to search&patch not found or multiple occurrences.',10,13,'$'
- closeErrorMsg db 'ERROR: error on closing file',10,13,'$'
- noSuccesMsg db 'Patching was not succesfull!',10,13,'$'
-
- ;Variables
-
- patchFiles db 'blabla.txt',0 ;Filename, ends with an 0x0 !!
- dd 12345h ;Expected filesize
- dw 2 ;number of strings to patch
-
- db 3 ;begin first patch&search string
- db 'abc'
- db 'def'
- dd 2ch
-
- db 4 ;begin second patch&search string
- db 31h, 32h, 33h, 34h
- db 32h, 33h, 34h, 31h
- dd 84h
-
- db 'blabla2.txt',0 ;FILE 2 !
- dd 12345h
- dw 2
-
- db 6
- db 'qwertz'
- db 'zullez'
- dd 46
-
- db 6
- db 'qwerty'
- db 'rtyuio'
- dd 0cbah
-
- offsetsStrings dw MAXSTRINGS+1 dup (?)
- firstChars db MAXSTRINGS dup (?)
- foundOffsets dd MAXSTRINGS dup (0ffffffffh)
-
- tempOffset dd (?)
- patchFilesOffset dw (?)
- beginStringsOffset dw (?)
- numberOfStrings dw (?)
- continueAlways db 0 ;flag to check if user wants to continue always
- fileNumber db 0
- fileHandle dw 0
- bufferEdge db MAXSTRINGSIZE-1 dup (0)
- asciiHex db '0123456789ABCDEF'
- dta db 64 dup (?)
- readBuffer db STEPSIZE dup (?)
-
- .code
- .386
- start:
- ; INIT
- mov ax, @data
- mov ds, ax
-
- push ds
- pop es ;es=ds
-
- xor ebx, ebx
-
- ;* set DiskTransferArea for function findfile *
- mov ah, 1ah
- mov dx, offset dta
- int 21h
-
- ;* print start messages *
- mov dx, offset beginMsg
- call PrintMsg
-
- mov dx, offset patchMsg
- call PrintMsg
-
- ;* check if we have something to do *
- mov ax, NUMBEROFFILES
- cmp ax, 0
- jbe noFilesToPatchError ;fatal error
-
- ;* set base offset for first file *
- mov [patchFilesOffset], offset patchFiles
- ; INIT end
-
- BigPatchLoop:
- ;* check if filename is to long *
- mov al, 0
- cld
- mov di, [patchFilesOffset]
- mov cx, 256
- repne scasb
- jz EOFfilename
- jmp filenameTolong ;fatal error
-
- ;* get the number of strings to search&patch for this file
- ; and the offset of the beginning of the strings set *
- EOFfilename:
- add di, 4
- mov ax, [di]
- mov [numberOfStrings], ax
- inc di
- inc di
- mov [beginStringsOffset], di
-
- ;* check if we have something to do *
- mov cx, [numberOfStrings] ;NUMBEROFSTRINGS
- cmp cx, 0
- je nothingToDoError ;fatal error (chosen)
-
-
- ;* print which file we are currently patching *
- mov dx, offset patchingMsg
- call PrintMsg
- mov byte ptr[di-7], '$' ;make 0 terminated string printable
- mov dx, [patchFilesOffset]
- call PrintMsg
- mov byte ptr[di-7], 0 ;restore string
- mov dx, offset newline
- call PrintMsg
-
- ;* get & check the size of the file to patch *
- mov dx, [patchFilesOffset]
- call FindFile
- cmp ax, 0ffffh
- je fileNotFound ;fatal error
-
- cmp [continueAlways], 1
- je equalFilesize ;no question needed
-
- mov eax, dword ptr[dta+1ah] ;filesize in DTA
- mov di, [beginStringsOffset]
- cmp eax, dword ptr[di-LOCATIONFILESIZE] ;filesize in patchFiles
- je equalFilesize
-
- mov ax, offset filesizeMsg
- call AskYesNo
- cmp al,'y'
- je equalFilesize
- cmp al,'a'
- jne forcedExit
-
- mov [continueAlways], 1
-
- equalFilesize:
- ;* open file to patch *
- mov dx, [patchFilesOffset]
- call OpenFile
- cmp ax, 0ffffh
- je errorOnOpening ;fatal error
-
- mov [fileHandle], ax
-
- ;* init the strings to search for *
- call InitStrings
-
- ;* search the offsets of the strings *
- mov si, offset fileHandle
- mov [tempOffset], 0
- call SearchString
- cmp ax, 0
- jne doubleOrNotFoundError ;fatal error
-
- ;note: there is no check for if the offsets+strings overlap
-
- cmp [continueAlways], 1
- je equalOffsets
-
- ;* check if the offsets match the expected ones *
- call CheckOffsets
- cmp ax, 0ffffh
- je forcedExit
-
- equalOffsets:
- ;* move and write new strings to file *
- mov si, offset fileHandle
- call WriteOffsets
- cmp ax,0ffffh
- je writeError ;fatal error
- cmp ax,0fffeh
- je moveError ;fatal error
-
- mov si, offset fileHandle
- call CloseFile
- cmp ax, 0ffffh
- je closeError ;fatal error
-
- ;* now preparing to patch next file (resetting foundOffsets) if needed *
- inc [fileNumber]
- cmp [fileNumber], NUMBEROFFILES
- je AllDone
-
- xor ebx, ebx
- mov bx, [numberOfStrings]
- mov ax, [offsetsStrings+2*ebx]
- mov [patchFilesOffset], ax
- initFoundOffsetsLoop:
- dec ebx
- mov [foundOffsets+4*ebx], 0ffffffffh
- cmp ebx, 0
- jne initFoundOffsetsLoop
-
- jmp BigPatchLoop
-
- AllDone:
- ;successfull!
- mov dx, offset succesMsg
- call PrintMsg
-
- mov al, 0
- jmp exit
-
- ;**************************
- ;* Exit *
- ;**************************
- exit:
- cmp al, 0
- je exitNow
- mov dx, offset nosuccesMsg
- call PrintMsg
- exitNow:
- mov ah, 4ch
- int 21h
-
- closeExit:
- push ax
- mov si, offset fileHandle
- call CloseFile
- cmp ax, 0ffffh
- pop ax
- je closeError
- jmp exit
-
- forcedExit:
- mov al,11
- jmp closeExit
- ;**************************
- ;* Error handlers *
- ;**************************
- noFilesToPatchError: ;should never happen
- mov dx, offset noFilesToPatchErrorMsg
- call PrintMsg
- mov al, 1
- jmp exit
-
- filenameTolong: ;should never happen
- mov dx, offset filenameTolongMsg
- call PrintMsg
- mov al, 2
- jmp exit
-
- nothingToDoError: ;should never happen
- mov dx, offset nothingToDoErrorMsg
- call PrintMsg
- mov al, 5
- jmp exit
-
- fileNotFound:
- mov dx, offset fileNotFoundMsg
- call PrintMsg
- mov al, 3
- jmp exit
-
- errorOnOpening: ;happens when file is read-only
- mov dx, offset errorOnOpeningMsg
- call PrintMsg
- mov al, 4
- jmp exit
-
-
- doubleOrNotFoundError:
- mov dx, offset stringNotFoundMsg
- call PrintMsg
- mov al, 6
- jmp closeExit
-
- readError: ;bad sectors?
- mov dx, offset readErrorMsg
- call PrintMsg
- mov al, 7
- jmp closeExit
-
- moveError: ;should never happen
- mov dx, offset moveErrorMsg
- call PrintMsg
- mov al, 8
- jmp closeExit
-
- writeError: ;bad sectors?
- mov dx, offset writeErrorMsg
- call PrintMsg
- mov al, 9
- jmp closeExit
-
- closeError: ;removed floppy?
- mov dx, offset closeErrorMsg
- call PrintMsg
- mov al, 10
- jmp exit
-
- ;**************************
- ;* String routines *
- ;**************************
-
- ;Parameters: foundOffsets
- ; offsetsStrings ;array with offsets of the strings to search&patch
- ;returns: ax=0 ok.
- ; ax=ffff not ok, user said no
- CheckOffsets proc
- push ebx
- push dx
- push di
-
- xor ecx, ecx
- mov cx, [numberOfStrings] ;NUMBEROFSTRINGS
- xor ebx, ebx
- checkOffsetLoop:
- mov eax, [foundOffsets+4*ebx];found offset of the string
- mov di, [offsetsStrings+2*ebx+2]
- cmp eax, dword ptr[di-4] ;expected offset of the string
- jne askOffset
- checkOffsetLoop2:
- inc ebx
- cmp ebx, ecx
- jne checkOffsetLoop
- jmp checkOffsetOk
-
- askOffset:
- ;* print question with offsetnumbers *
- push cx
- mov dx, offset offsetMsg + 35
- mov cl, 8
- ; eax=foundOffset
- call AsciiOffset
- mov dx, offset offsetMsg + 55
- mov al, bl
- mov cl, 2
- call AsciiOffset
- mov dx, offset offsetMsg + 16
- mov cl, 8
- mov eax, dword ptr[di-4] ;=expected offset
- call AsciiOffset
- pop cx
-
- mov ax, offset offsetMsg
- call AskYesNo ;ask to continue if offsets are not equal
- cmp al,'y'
- je checkOffsetLoop2
- cmp al,'a'
- jne checkOffsetError
- mov [continueAlways], 1 ;never ask anymore
- checkOffsetOk:
- xor ax, ax
- checkOffsetReturn:
- pop di
- pop dx
- pop ebx
- ret
-
- checkOffsetError:
- mov ax, 0ffffh
- jmp checkOffsetReturn
- CheckOffsets endp
-
- InitStrings proc
- push ax
- push bx
- push cx
- push dx
- push di
- push si
-
- mov bx, [beginStringsOffset] ;begin offset of strings tabel
- mov di, 0
- mov si, 0
- mov cx, [numberOfStrings] ;NUMBEROFSTRINGS
- initStringsLoop:
- cmp cx, 0
- je initStringsReturn
-
- mov [offsetsStrings+di], bx
- xor ax, ax
- mov al, [bx]
- shl ax, 1
- inc bx
- mov dl, [bx]
- mov [firstChars+si], dl
- add ax, 4
- add bx, ax
-
- inc di
- inc di
- inc si
- dec cx
- jmp initStringsLoop
-
- initStringsReturn:
- mov [offsetsStrings+di], bx ;offset after all other offsets
-
- pop si
- pop di
- pop dx
- pop cx
- pop bx
- pop ax
- ret
- InitStrings endp
-
- ;Parameters: ds:si pointer to file handle
- ;returns: ax=ffff no strings found
- ; ax=fffe double strings found
- ; ax=0 all ok.
- SearchString proc
- push ebx
- push cx
- push dx
- push di
-
- ;* first STEPSIZE bytes and init this search *
- readLoop:
- mov dx, offset readBuffer
- call ReadFile
- cmp ax, 0ffffh
- je readError
- cmp ax, 0
- je noMoreStrings
- mov bx, dx
- sub bx, (MAXSTRINGSIZE-1) ; point to MAXSTRINGSIZE-1 bytes before readbuffer (bufferEdge)
-
- initSearch:
- ;di: points to the first character of each string
- ;ax: is bytes read (functions as counter)
- ;bx: is pointer to buffer where we are searching in
- mov di, 0
- searchLoop:
- mov cl, [firstChars+di]
- cmp byte ptr[bx], cl
- je checkString
- searchLoop2:
- inc di
- cmp di, [numberOfStrings] ;NUMBEROFSTRINGS
- jne searchLoop
- searchLoop3:
- inc bx
- dec ax
- cmp ax, 0
- jne initSearch
-
- ;* copy MAXSTRINGSIZE-1 bytes from end readBuffer to bufferEdge *
- push si
- mov di, offset bufferEdge
- mov si, offset readBuffer + STEPSIZE - (MAXSTRINGSIZE-1)
- mov cx, MAXSTRINGSIZE - 1
- cld
- rep movsb
- pop si
-
- add [tempOffset], STEPSIZE
- jmp readLoop
-
- checkString:
- ;* first character matched, now check the rest of the string *
- push cx
- push si
- push di
-
- mov si, bx
- inc si
- shl di, 1
-
- mov di, [offsetsStrings+di]
- xor cx, cx
- mov cl, [di]
- dec cx ;cx=stringsize-1
- inc di ;strings beginnen 1 later + 1 char
- inc di
- cld
- repz cmpsb ;compare ds:si with es:di for cx bytes
-
- pop di
- pop si
- pop cx
- je foundString
-
- jmp searchLoop2 ;no match, continue checking first character of ither strings
-
- foundString:
- ;* now found a string, store offset if not already found *
- push ebx
- push di
-
- sub bx, offset readBuffer
- movsx ebx, bx
- add ebx, [tempOffset]
- shl di, 2
- cmp [foundOffsets+di], 0ffffffffh
- jne doubleStrings
- mov [foundOffsets+di], ebx
-
- pop di
- pop ebx
- jmp searchLoop3 ;continue searching strings
-
- noMoreStrings:
- ;* end of search, check if a string is not found *
- xor ebx, ebx
- mov bx, [numberOfStrings] ;NUMBEROFSTRINGS
- noMoreStringsLoop:
- dec ebx
- cmp [foundOffsets+4*ebx],0ffffffffh
- je stringsNotFound
- cmp ebx, 0
- jne noMoreStringsLoop
- xor ax, ax
-
- searchStringReturn:
- pop di
- pop dx
- pop cx
- pop ebx
- ret
-
- stringsNotFound:
- mov ax,0ffffh
- jmp searchStringReturn
- doubleStrings:
- pop di
- pop ebx
- mov ax,0fffeh
- jmp searchStringReturn
-
- SearchString endp
-
- ;Parameters: ds:si pointer to file handle
- ; foundOffsets
- ; offsetsStrings
- ;returns: ax=ffff error while writing
- ; ax=fffe error while moving file pointer
- ; ax=0 all ok. I hope ;)
- WriteOffsets proc
- push ebx
- push dx
- push di
-
- xor ebx, ebx
-
- writeOffsetsLoop:
- mov eax, [foundOffsets+4*ebx]
- ;si pointer filehandle
- call MoveFile
- cmp eax, 0ffffffffh
- je writeOffsetsMoveError
-
- mov di, [offsetsStrings+2*ebx]
- xor dx, dx
- mov dl, [di]
- mov ax, dx ;ax holds stringsize
- inc dx
- add dx, di ;dx now holds the offset of new string
-
- ;si=offset fileHandle
- call WriteFile
- cmp ax, 0ffffh
- je writeOffsetsWriteError
-
- inc ebx
- cmp bx, [numberOfStrings] ; I suppose ebx < 65536
- jne writeOffsetsLoop
-
- xor ax, ax
-
- writeOffsetsReturn:
- pop di
- pop dx
- pop ebx
- ret
-
- writeOffsetsMoveError:
- mov ax, 0fffeh
- jmp writeOffsetsReturn
- writeOffsetsWriteError:
- mov ax, 0ffffh
- jmp writeOffsetsReturn
- WriteOffsets endp
-
- ;**************************
- ;*** File routines ***
- ;**************************
- ;eax=offset ; ds:si=pointer filehandle
- ;return eax=0ffffffffh on error
- MoveFile proc
- push bx
- push cx
- push dx
-
- mov dx, ax
- shr eax, 16
- mov cx, ax
-
- mov ax, 4200h
- mov bx, [si]
- int 21h
- jc moveFileError
-
- moveFileReturn:
- pop dx
- pop cx
- pop bx
- ret
-
- moveFileError:
- mov eax, 0ffffffffh
- jmp moveFileReturn
- MoveFile endp
-
- ;ds:dx=pointer filename
- ;return: ax<0ffffh=handle.;ax=true=open error.
- OpenFile proc
- mov ax, 3d02h
- int 21h
- jc open_error
-
- ret
- open_error:
- mov ax, 0ffffh
- ret
- OpenFile endp
-
- ;ds:dx=pointer readbuffer ; ds:si=pointer filehandle
- ;return ax=ax=read bytes;ax=0ffffh=read error.
- ReadFile proc
- push bx
- push cx
-
- mov ah, 3fh
- mov bx, [si]
- mov cx, STEPSIZE
- int 21h
- jc read_error
-
- ReadFile_return:
- pop cx
- pop bx
- ret
- read_error:
- mov ax, 0ffffh
- jmp ReadFile_return
- ReadFile endp
-
- ;ds:dx=pointer (write)readbuffer ; ds:si=pointer filehandle ; ax=bytes to write
- ;return ax=written bytes;ax=0ffffh=write error.
- WriteFile proc
- push bx
- push cx
-
- mov cx, ax
- mov ah, 40h
- mov bx, [si]
- int 21h
- jc write_error
-
- WriteFile_return:
- pop cx
- pop bx
- ret
- write_error:
- mov ax, 0ffffh
- jmp WriteFile_return
- WriteFile endp
-
- ;ds:si=pointer filehandle
- CloseFile proc
- push bx
- mov ah, 3eh
- mov bx, [si]
- cmp bx, 0
- je doNotClose
- int 21h
- jc close_error
- mov word ptr[si], 0
- doNotClose:
- xor ax,ax
- CloseFile_return:
- pop bx
- ret
- close_error:
- mov ax, 0ffffh
- jmp CloseFile_return
- CloseFile endp
-
-
- ;ds:dx=point file spec
- ;return: ax=ffffh -> file not found else ax=n/a
- FindFile proc
- push cx
-
- xor cx, cx
- mov ah, 4eh
- int 21h
- jc not_found
-
- FindFile_return:
- pop cx
- ret
-
- not_found:
- mov ax, 0ffffh
- jmp FindFile_return
- FindFile endp
-
-
- ;****************************
- ;* Miscellaneous routines *
- ;****************************
- PrintMsg proc
- push ax
- mov ah,9
- int 21h
- pop ax
- ret
- PrintMsg endp
-
- ;ax=offset question
- ;returns: al=key in ascii
- AskYesNo proc
- push dx
-
- mov dx, ax
- call PrintMsg
- xor ax, ax
- int 16h
-
- cmp al, 61h
- jae askYesNoLowercase
- add al, 34
- askYesNoLowercase:
-
- mov dl, al
- mov ah, 2
- int 21h
-
- mov dx, offset newline
- call PrintMsg
-
- pop dx
- ret
- AskYesNo endp
-
- ;parameters: eax offset to convert
- ; cl length in characters
- ; ds:dx pointer to writebuffer (at least 8 bytes)
- ;returns: nothing
- AsciiOffset proc
- push eax
- push bx
- push cx
- push si
-
- mov si, dx
- mov ch, 0
- add si, cx
- asciiOffsetLoop:
- mov bx, ax
- and bx, 0000000000001111b
- mov bl, [asciiHex+bx]
- mov [si], bl
- shr eax, 4
- dec si
- dec cl
- jnz asciiOffsetLoop
-
- pop si
- pop cx
- pop bx
- pop eax
- ret
- AsciiOffset endp
-
- ;Alert! This routine does NOT work! It gives divide by zero error!
- ;Parameters: eax filesize to convert
- ; ds:dx pointer to writebuffer (at least 10 bytes)
- DecimalFilesize proc
- push eax
- push ebx
- push ecx
- push edx
- push di
-
- mov ecx, 1000000000 ;10^9
- mov di, dx
-
- decimalFilesizeLoop:
- div ecx ;eax=eax/ecx ;
- add al, 30h
- mov [di], al
-
- mov ebx, edx
- mov eax, ecx
- mov ecx, 10
- div ecx
- mov ecx, eax
- mov eax, ebx
- inc di
- cmp ecx, 0
- jne decimalFilesizeLoop
-
- pop di
- pop edx
- pop ecx
- pop ebx
- pop eax
- ret
- DecimalFilesize endp
-
- end start
-