Writing a patch in ASM *SOLVED*

Having problems with a specific game or application? Post your problems here!

Writing a patch in ASM *SOLVED*

Postby Akuma » 2019-8-06 @ 10:01

Fella's,

I have a game that requires a patch to run properly, there is a bug and I do not want to touch the original exe.
After some googling I cant find much information on how to write one in ASM.

EDIT: I want to patch the program in memory, its compressed.

How do I go about this? (I am new to this)
Last edited by Akuma on 2019-11-22 @ 15:58, edited 2 times in total.
Akuma
Newbie
 
Posts: 80
Joined: 2019-7-24 @ 14:47

Re: Wrting a patch in ASM

Postby VileRancour » 2019-8-07 @ 16:02

You provide little information on what you're trying to do (or why a copy of the EXE won't do), but I'm inferring that you'd like to patch the game in-memory and then run it?

If so, a good start might be DOS function 4Bh/AL=1 (load but do not execute).
web  /   blog   /   tube
User avatar
VileRancour
Oldbie
 
Posts: 1731
Joined: 2003-5-14 @ 22:11
Location: 1-01-80 0:00a

Re: Wrting a patch in ASM

Postby ph4nt0m » 2019-8-07 @ 18:54

If you know the byte sequence to be patched, open the EXE in a hex editor of your choice, do the job and save as a copy.
User avatar
ph4nt0m
Member
 
Posts: 234
Joined: 2018-1-01 @ 19:03

Re: Wrting a patch in ASM

Postby kjliew » 2019-8-07 @ 20:18

Check out Binary diff/patch utilities
http://www.daemonology.net/bsdiff/
kjliew
Oldbie
 
Posts: 530
Joined: 2004-1-08 @ 03:03

Re: Writing a patch in ASM

Postby Akuma » 2019-8-08 @ 07:25

VileRancour wrote:You provide little information on what you're trying to do (or why a copy of the EXE won't do), but I'm inferring that you'd like to patch the game in-memory and then run it?

If so, a good start might be DOS function 4Bh/AL=1 (load but do not execute).

My bad, I wasn't too clear about what I wanted, but yes I want to patch the game in-memory.

ph4nt0m wrote:If you know the byte sequence to be patched, open the EXE in a hex editor of your choice, do the job and save as a copy.

Forgot to mention that the executable is compressed, the byte sequence cannot be patched. I searched all files for it, I can only find it in memory. Also I think the file loads a couple of others files too. In-memory patching was what I was looking for.

kjliew wrote:Check out Binary diff/patch utilities http://www.daemonology.net/bsdiff/

Thank you, I will take a look.
Akuma
Newbie
 
Posts: 80
Joined: 2019-7-24 @ 14:47

Re: Writing a patch in ASM

Postby pantercat » 2019-8-08 @ 08:06

Akuma wrote:Forgot to mention that the executable is compressed, the byte sequence cannot be patched. I searched all files for it, I can only find it in memory. Also I think the file loads a couple of others files too. In-memory patching was what I was looking for.


I know what you mean. You have at least two ways to do it.
-write a TSR in ASM that captures some INT used by the executable you want to patch
-or capture INT and use the functions "Modify Allocated Memory Block" (INT 21h/4Ah) and "EXEC/Load and Execute Program" (INT 21h/4Bh).

Not long ago I wrote a couple of loaders to crack two games. The posts are in spanish, but I think the source code in ASM could be useful.

http://www.vlan7.org/2019/02/ms-dos-cra ... gador.html
http://www.vlan7.org/2019/04/haciendo-u ... -para.html

Happy reversing.
pantercat
Newbie
 
Posts: 46
Joined: 2018-9-06 @ 17:22

Re: Writing a patch in ASM

Postby Akuma » 2019-8-08 @ 09:02

That is extremely helpful, thank you sir.

What I got so far writing my first ASM program, is a simple 'Hello world'.
1. I need to figure out how to patch in-memory
2. When to patch, the executable needs to decompress itself first, otherwise whats the point.
3. I would probably have to wait for the OEP, then patch it, if it doesnt decompress and loads something else too.

Code: Select all
.MODEL TINY
.DATA
    msg db "Hello, world!$",0dh     ; [var] [declare bytes] "message$", no. bytes in hex
.CODE
    org 100h                                ; required by com file
START:
    mov ah, 09                            ; int21h: function print text
    lea dx, msg                           ; refer to msg to print
    int 21h

    mov ax, 4c00h                      ; return to dos
    int 21h
END START


I got it to produce a nice small com file with TASM.
Code: Select all
C:\>DEL TEST.MAP
 
C:\>DEL TEST.OBJ
 
C:\>DEL TEST.COM
 
C:\>TASM\BIN\TASM.EXE TEST.ASM TEST.OBJ
Turbo Assembler  Version 4.1  Copyright (c) 1988, 1996 Borland International
 
Assembling file:   TEST.ASM
Error messages:    None
Warning messages:  None
Passes:            1
Remaining memory:  466k
 
 
C:\>TASM\BIN\TLINK.EXE /t TEST.OBJ
Turbo Link  Version 7.1.30.1. Copyright (c) 1987, 1996 Borland International
 
C:\>test
Hello, world!
C:\>
 
Akuma
Newbie
 
Posts: 80
Joined: 2019-7-24 @ 14:47

Re: Writing a patch in ASM

Postby VileRancour » 2019-8-08 @ 13:19

A generic approach for in-memory patching is, if you tell DOS to load-but-do-not-execute the file, it is in memory and you get the segment address of the program's PSP; from there you can write to whatever locations you want within the program code. Of course, it's a good idea to test your planned patch first by using something like the DOSBox debugger to directly modify the routine in memory.

A compressed EXE is a whole different ballpark however. You might want to use some analysis tools to find out more (identify the packing scheme and perhaps find the original entry point). Ben Castricum's UNP may be a good place to start, along with its trace command "t".

I haven't tackled this before, but if I were to try writing such a loader, my approach might be to patch the unpacking code in-memory, so that once it's done unpacking (and is ready to jump to the OEP) it returns control to my loader. Then a second routine would patch the already-unpacked code in RAM with the required changes and make the jump.

Not sure if this is the best kind of project to tackle when at the hello-world level, but I did worse when I had less, so good luck. :D
web  /   blog   /   tube
User avatar
VileRancour
Oldbie
 
Posts: 1731
Joined: 2003-5-14 @ 22:11
Location: 1-01-80 0:00a

Re: Writing a patch in ASM

Postby ripsaw8080 » 2019-8-08 @ 14:07

A common method with patch TSRs/loaders is to set up an interrupt handler and watch for a particular function that is called after the target program's code is decrypted and/or decompressed, then modify memory relative to the interrupt's return address that was pushed on the stack. For example, programs often call INT 21h/30h to get the DOS version as one of the first things they do, but that's not necessarily the ideal function to watch for. It's a good idea to check the memory you intend to modify to see if it contains expected values, which ensures you're patching the right thing and also not performing the patch more than once.
User avatar
ripsaw8080
DOSBox Author
 
Posts: 4426
Joined: 2006-4-25 @ 23:24

Re: Writing a patch in ASM

Postby BloodyCactus » 2019-8-08 @ 14:25

yeah better to hook an interrupt vector, if the app was written in C you know its going to do a dos version check or anything is garunteed to do a memory realloc (0x4A). you can hook that and patch what you need to patch.
--/\-[ Stu : Bloody Cactus :: http://kråketær.com :: http://mega-tokyo.com ]-/\--
User avatar
BloodyCactus
Oldbie
 
Posts: 945
Joined: 2016-2-03 @ 13:34
Location: Lexington VA

Re: Writing a patch in ASM

Postby Akuma » 2019-8-08 @ 18:47

VileRancour wrote:A generic approach for in-memory patching is, if you tell DOS to load-but-do-not-execute the file, it is in memory and you get the segment address of the program's PSP; from there you can write to whatever locations you want within the program code. Of course, it's a good idea to test your planned patch first by using something like the DOSBox debugger to directly modify the routine in memory.

A compressed EXE is a whole different ballpark however. You might want to use some analysis tools to find out more (identify the packing scheme and perhaps find the original entry point). Ben Castricum's UNP may be a good place to start, along with its trace command "t".

I haven't tackled this before, but if I were to try writing such a loader, my approach might be to patch the unpacking code in-memory, so that once it's done unpacking (and is ready to jump to the OEP) it returns control to my loader. Then a second routine would patch the already-unpacked code in RAM with the required changes and make the jump.

Not sure if this is the best kind of project to tackle when at the hello-world level, but I did worse when I had less, so good luck. :D


Unpacking has never been a real problem for me, although there are some wonderful exceptions that still haunt me to this day.
(The INC loader from the Operation Wolf release iirc, thats a real nasty one)..ermm back to the topic at hand.

I plan on doing the following:
1. Write hello world
2. Write a patch for hello world, to: Hello patch!, that would hopefully cover the basics.
(debugging with dosbox debugger)
3. Deal with the unpacking, find the oep.
4. Write the patch, test and verify it.
5. Praise and glory!

I will take that luck sir!

ripsaw8080 wrote:A common method with patch TSRs/loaders is to set up an interrupt handler and watch for a particular function that is called after the target program's code is decrypted and/or decompressed, then modify memory relative to the interrupt's return address that was pushed on the stack. For example, programs often call INT 21h/30h to get the DOS version as one of the first things they do, but that's not necessarily the ideal function to watch for. It's a good idea to check the memory you intend to modify to see if it contains expected values, which ensures you're patching the right thing and also not performing the patch more than once.


I read through some code today from 'pantercat', they hooked into INT10. I think it was something like mov ax,3510h or something.
This is going to be hard on my brain =). Yes, one iteration, that's a good one. Noted.

BloodyCactus wrote:yeah better to hook an interrupt vector, if the app was written in C you know its going to do a dos version check or anything is garunteed to do a memory realloc (0x4A). you can hook that and patch what you need to patch.


Thank you, although most of this is 'hocus pocus' to me now. I'll get it to work eventually. I always do.:D
Akuma
Newbie
 
Posts: 80
Joined: 2019-7-24 @ 14:47

Re: Writing a patch in ASM

Postby Akuma » 2019-8-09 @ 08:18

I see that there are a lot of different ASM-compilers, I just found out that the syntax differs too.
So my question which one of them do you recommend I use and why? Thank you
  • MASM
  • TASM
  • A86
Akuma
Newbie
 
Posts: 80
Joined: 2019-7-24 @ 14:47

Re: Writing a patch in ASM

Postby BloodyCactus » 2019-8-09 @ 12:28

NASM unless your compiling it on a 286 or something. TASM would be the fallback if you dont want to learn NASM.
--/\-[ Stu : Bloody Cactus :: http://kråketær.com :: http://mega-tokyo.com ]-/\--
User avatar
BloodyCactus
Oldbie
 
Posts: 945
Joined: 2016-2-03 @ 13:34
Location: Lexington VA

Re: Writing a patch in ASM

Postby Akuma » 2019-8-10 @ 12:02

Hmm...its kinda working, but with a couple of issues.

1. It only works on my machine in dosbox, because its patching absolute, not relative ?
2. Its not stable, if I exit the game, the OS becomes unstable, it hangs second time around ?
3. I understand 80% of what I pieced together ?

If anyone can shed some light on this, Im all ears :D


Code: Select all
OVL     segment for 'code'
        assume cs:OVL, ds:OVL

org     100h                        ; output a .COM program

START:
mov     sp, 1024                 ; set stack pointer (size in bytes)
mov     bx, 1024/16             ; set bx=bytes/16, es=mem segment
mov     ah, 4ah                   ; change memory allocation
int     21h                           ; commit

mov     ax, 3521h               ; get OLDINT
int     21h                            ; commit

mov     OLDINT[0], bx         ; safe OLDINT to call later
mov     OLDINT[2], es         ; ?? no idea ??

mov     ax, 2521h                ; set NEWINT
lea     dx, NEWINT              ; with pointer to NEWINT proc far routine
int     21h

lea     bx, EXEC_INFO         ; ?? no idea ??
lea     dx, FILENAME           ; pointer to FILENAME
mov     ax, 4b00h                 ; load and run FILENAME
int     21h                             ; commit

mov     ax, 4c00h                 ; ah=exit, al=return code
int     21h                             ; commit

OLDINT  dw 0,0                    ; original INT

NEWINT  proc far
pushf                                   ; safe flags
cmp     dx, 029DAh               ; compare if INT is called with X
jnz     EXIT                          ; yes: goto CHECK, no: goto EXIT

CHECK:
push    bp                            ; safe 'bp'
mov     bp, sp                      ; 'bp' points to top of the stack
push    es                            ; safe 'es'
mov     es, [bp]                    ; copy bp to 'es'
cmp     word ptr es:[0XXXX], 0XXXXh ; if data matches search query
jne     RESTORE                  ; yes: goto PATCH , no: goto RESTORE

PATCH:                              ; --------------- patch -------------------
mov     byte ptr es:[0XXXX], 0XXh   ; change byte offset es:xxxx to xxxh
                                    ; ------------- end patch -----------------
   
RESTORE:
pop     es                          ; restore 'es'
pop     bp                          ; restore 'bp'

EXIT:
popf                                ; restore flags
jmp     dword ptr cs:[OLDINT]       ; jump to OLDINT

NEWINT endp

FILENAME    db "GAME.EXE",0      ; program to execute
EXEC_INFO   db 22 DUP (0)           ; ?? no idea : 22x 00h for what ??

OVL ends
end START


Is there a way to use a fixed font for the code window ?
Attachments
PATCHASM.ZIP
(996 Bytes) Downloaded 9 times
Akuma
Newbie
 
Posts: 80
Joined: 2019-7-24 @ 14:47

Re: Writing a patch in ASM

Postby VileRancour » 2019-8-10 @ 12:38

At a first glance, it looks like you aren't setting up the interrupt chain correctly. Keep in mind that an "INT XXh" instruction pushes the flags onto the stack, then the far return address (dword), then jumps to the interrupt handler. The handler routine normally ends with an IRET instruction, which does the reverse (pops the CS:IP then the flags, and resumes).

So to properly call the old interrupt handler, your EXIT section should emulate the INT instruction by pushing the flags (PUSHF) and the far return address (e.g. PUSH CS, then CALL a far jump to the old handler, which pushes IP during the CALL). Then once the old handler returns (with an IRET), your NEWINT should also terminate with an IRET, since it also gets called with "INT XXh" and has to preserve the expected state. This also means there's no need for the existing PUSHF/POPF pair.

This might be some relevant reading material: https://web.archive.org/web/20080222000 ... oehrl.html. There may be other issues, but I'd start with that.

(Edit:) also, your EXEC_INFO structure should contain a parameter block as described here: http://faydoc.tripod.com/structures/15/1590.htm - it's probably a good idea to actually set up the values. ;) More info here: http://www.ctyme.com/intr/rb-2939.htm
web  /   blog   /   tube
User avatar
VileRancour
Oldbie
 
Posts: 1731
Joined: 2003-5-14 @ 22:11
Location: 1-01-80 0:00a

Re: Writing a patch in ASM

Postby BloodyCactus » 2019-8-10 @ 14:44

you cant do a 4c exit whilst trapping int21, you need to release your int21 hook back to its original values before you exit.
your execinfo needs to be valid with fcb/psp pointers, cli, etc
--/\-[ Stu : Bloody Cactus :: http://kråketær.com :: http://mega-tokyo.com ]-/\--
User avatar
BloodyCactus
Oldbie
 
Posts: 945
Joined: 2016-2-03 @ 13:34
Location: Lexington VA

Re: Writing a patch in ASM

Postby Akuma » 2019-11-06 @ 15:05

I had some time on my hands, so I started coding again:
So I wrote a filepatcher :D (in 'nasm' as suggested)

How can I make this better ?

Code: Select all
[bits 16]                           ;16 bit code generation
[org 0x0100]                        ;com-file = start address 0x100
[section .text]                     ;code section

start:
jmp         begin

%macro printf 1
mov         dx,%1                   ;select message set in parameter %1
mov         ah,09h                  ;select print function
int         21h                     ;commit
%endmacro

;http://spike.scu.edu.au/~barry/interrupts.html
;open,close,seek,write
%macro patch 4
mov         ax,04200h               ;select seek file, pos: start of file
mov         bx,[handle]             ;bx = file handle
mov         cx,%1                   ;cx = segment
mov         dx,%2                   ;dx = offset
int         21h                     ;commit
jc          error                   ;if carry flag set jump to error
mov         ah,40h                  ;select write file
mov         bx,[handle]             ;bx = file handle
mov         cx,%3                   ;cx = no. bytes to write
mov         dx,%4                   ;ds:dx -> data to write
int         21h                     ;commit
jc          error                   ;if carry flag set jump to error
%endmacro

;function: open file
fopen:
mov         dx,filename             ;load filename into dx
mov         ax,03D02h               ;select open file
int         21h                     ;commit
jc          error                   ;if carry flag set jump to error
mov         [handle],ax             ;store file handle
ret                                 ;return to caller

; function: close file
fclose:
mov         ax,03E00h               ;select close file
int         21h                     ;commit
jc          error                   ;if carry flag set jump to error
ret                                 ;return to caller

error:
printf      error1
jmp         exit                    ;jump to exit

begin:
printf      title                   ;print message
call        fopen                   ;open file to be patched
patch       p1seg,p1ofs,p1len,p1dat
patch       p2seg,p2ofs,p2len,p2dat
patch       p3seg,p3ofs,p3len,p3dat
call        fclose                  ;close file
printf      success                 ;print message

exit:
mov         ax,04C00h               ;select return to dos
int         21h                     ;commit

[section .data]
filename    db 'filename.exe',0     ;target filename
title       db 'Patch for program: blah blah blah',0AH,0DH,'$'
error1      db 'Failure',0AH,0DH,'$'
success     db 'Success',0AH,0DH,'$'
handle      dw 0

;patch1
p1seg       equ 00000h              ;segment: most significant byte
p1ofs       equ 00000h              ;offset: least significant byte
p1dat       db  0x90,0x90,0         ;string
p1len       equ $-p1dat             ;length

p2seg       equ 00000h              ;segment: most significant byte
p2ofs       equ 00100h              ;offset: least significant byte
p2dat       db  0x90,0x90,0         ;string
p2len       equ $-p2dat             ;length

p3seg       equ 00000h              ;segment: most significant byte
p3ofs       equ 00200h              ;offset: least significant byte
p3dat       db  0x90,0x90,0         ;string
p3len       equ $-p3dat             ;length


BTW:is there a way to use a fixed size font for the code window ?
Akuma
Newbie
 
Posts: 80
Joined: 2019-7-24 @ 14:47

Re: Writing a patch in ASM

Postby Akuma » 2019-11-08 @ 12:18

The file patcher was a good stepping stone, but I'm still stuck with the loader.
Now I switched to NASM as BloodyCactus suggested, but I'm running into some conversion trouble.

So I adapted the code as best I knew how according to this: http://left404.com/2011/01/04/convertin ... to-nasm-3/ , but I can't get it to work.

Thus I grabbed one of pantercat's loaders, tried a conversion, but dosbox screams bloody murder on execution.
error: illegal read from cs:ip (continuously), obviously I messed up somewhere but I cant figure out where as
the code compiles. My best guess would be the exit: jump but this isnt jeopardy :D

Some help would be appreciated:

Code: Select all
[bits 16]                           ;16 bit code generation
[org 0x0100]                        ;com-file = start address 0x100
[section .text]                     ;code section

START:
jmp INITCODE                        ; Codigo de inicializacion

NEWINT:
    cmp ah, 1                       ; Se ha llamado a INT 16h con la AH=1 ?
    jnz EXIT                        ; NO: saltamos a la INT 16h del sistema
    cmp word [0097], 0d75h          ; ¿Tenemos en [0097] los opcodes 75 0D?
    jnz EXIT                        ; NO: saltamos a la INT 16h del sistema
    mov word [0097], 9090h          ; escribimos los 90 90 en [0097]

EXIT:
    jmp dword [cs:OLDINT]           ; Saltamos a la INT 16h del sistema

INITCODE:
    mov sp, SIZE                    ; redefinimos la pila
    mov bx, SIZE/16
    mov ah, 4Ah                     ; redimensionamos bloque memoria
    int 21h

    mov dx, MSG
    mov ah, 9                       ; Escribimos texto por pantalla
    int 21h

    xor ah, ah                      ; Esperamos pulsacion de tecla
    int 16h

    mov ax, 3516h                   ; Queremos el valor del puntero a la INT16
    int 21h
    mov word [OLDINT+0], bx         ; Guardamos puntero a la INT 16h
    mov word [OLDINT+2], es         ;  (necesitaremos llamarla despues)

    mov ax,2516h                    ; Sobreescribimos en el vector INT 16h
    mov dx, NEWINT                  ; un puntero a nuestra rutina NEWINT
    int 21h

    mov bx, EXEC_INFO
    mov dword [bx+00h], 0
    mov dword [bx+02h], 80h         ; PSP
    mov word  [bx+04h], cs
    mov word  [bx+06h], 5Ch         ; FCB 0
    mov word  [bx+08h], cs
    mov word  [bx+0ah], 6Ch         ; FCB 1
    mov word  [bx+0ch], cs

    mov dx, FILENAME
    mov ax, 4b00h
    int 21h                         ; cargar y ejecutar programa

    push cs
    pop ds                          ; DS = CS
    mov ax, 4c00h                   ; terminar
    int 21h

[section .data]
SIZE        EQU 1024                ; este programa y su pila caben en 1 KB
FILENAME    db "COLMENA.EXE",0      ; programa a ejecutar
EXEC_INFO   times 22 db (0h)
MSG         db 0dh,0ah
            db "La Colmena CGA/EGA/Hercules/VGA-16 loader.",0dh,0ah
            db "2019, vlan7",0dh,0ah,"$"
OLDINT      dw 0,0                  ; Espacio para el puntero a la INT 16h
Akuma
Newbie
 
Posts: 80
Joined: 2019-7-24 @ 14:47

Re: Writing a patch in ASM

Postby ripsaw8080 » 2019-11-08 @ 16:59

The most obvious issue is that INT 16 is not "unhooked" before the program terminates; but that would only causes a crash after termination when the program's memory block is released, leaving the INT 16 handler code likely to be overwritten by the next program executed.

A more subtle issue is that INT 21/35 is changing the value of ES, and INT 21/4B uses ES:BX as a pointer to the child program's parameter block. So, you should have a PUSH CS / POP ES or so after the ES value has been stored in memory.

Those are the issues that I notice at a glance, not necessarily the only issues.

BTW, when the subject matter is applicable to DOS programming in general and not just for DOSBox, such topics are best posted in Milliways. ;)
User avatar
ripsaw8080
DOSBox Author
 
Posts: 4426
Joined: 2006-4-25 @ 23:24

Re: Writing a patch in ASM

Postby cyclone3d » 2019-11-08 @ 17:35

What about using one of those old DOS Game cheater programs that you load up before your game. Then you load the game and press a hotkey sequence and it drops to the game cheater and lets you edit memory values and then go back to the game.

Generally used for changing lives, ammo, etc, but I would think it would work for patching as well.

I think some of them might have let you save profiles.. don't remember though. I haven't used one in years.
User avatar
cyclone3d
l33t
 
Posts: 3563
Joined: 2015-4-08 @ 06:06
Location: Huntsville, AL USA

Next

Return to DOSBox Games/Apps

Who is online

Users browsing this forum: No registered users and 3 guests