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.
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).
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.
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.
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.
1.MODEL TINY 2.DATA 3 msg db "Hello, world!$",0dh ; [var] [declare bytes] "message$", no. bytes in hex 4.CODE 5 org 100h ; required by com file 6START: 7 mov ah, 09 ; int21h: function print text 8 lea dx, msg ; refer to msg to print 9 int 21h 10 11 mov ax, 4c00h ; return to dos 12 int 21h 13END START
I got it to produce a nice small com file with TASM.
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. 😁
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.
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.
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 t […] Show full quote
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. 😁
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.😁
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
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 😁
1OVL segment for 'code' 2 assume cs:OVL, ds:OVL 3 4org 100h ; output a .COM program 5 6START: 7mov sp, 1024 ; set stack pointer (size in bytes) 8mov bx, 1024/16 ; set bx=bytes/16, es=mem segment 9mov ah, 4ah ; change memory allocation 10int 21h ; commit 11 12mov ax, 3521h ; get OLDINT 13int 21h ; commit 14 15mov OLDINT[0], bx ; safe OLDINT to call later 16mov OLDINT[2], es ; ?? no idea ?? 17 18mov ax, 2521h ; set NEWINT 19lea dx, NEWINT ; with pointer to NEWINT proc far routine 20int 21h 21 22lea bx, EXEC_INFO ; ?? no idea ?? 23lea dx, FILENAME ; pointer to FILENAME 24mov ax, 4b00h ; load and run FILENAME 25int 21h ; commit 26 27mov ax, 4c00h ; ah=exit, al=return code 28int 21h ; commit 29 30OLDINT dw 0,0 ; original INT 31 32NEWINT proc far 33pushf ; safe flags 34cmp dx, 029DAh ; compare if INT is called with X 35jnz EXIT ; yes: goto CHECK, no: goto EXIT 36 37CHECK: 38push bp ; safe 'bp' 39mov bp, sp ; 'bp' points to top of the stack 40push es ; safe 'es' 41mov es, [bp] ; copy bp to 'es' 42cmp word ptr es:[0XXXX], 0XXXXh ; if data matches search query 43jne RESTORE ; yes: goto PATCH , no: goto RESTORE 44 45PATCH: ; --------------- patch ------------------- 46mov byte ptr es:[0XXXX], 0XXh ; change byte offset es:xxxx to xxxh 47 ; ------------- end patch ----------------- 48 49RESTORE: 50pop es ; restore 'es' 51pop bp ; restore 'bp' 52 53EXIT: 54popf ; restore flags 55jmp dword ptr cs:[OLDINT] ; jump to OLDINT 56 57NEWINT endp 58 59FILENAME db "GAME.EXE",0 ; program to execute 60EXEC_INFO db 22 DUP (0) ; ?? no idea : 22x 00h for what ??
…Show last 4 lines
61 62OVL ends 63end START
Is there a way to use a fixed font for the code window ?
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.
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
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.
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 😁
Some help would be appreciated:
1[bits 16] ;16 bit code generation 2[org 0x0100] ;com-file = start address 0x100 3[section .text] ;code section 4 5START: 6jmp INITCODE ; Codigo de inicializacion 7 8NEWINT: 9 cmp ah, 1 ; Se ha llamado a INT 16h con la AH=1 ? 10 jnz EXIT ; NO: saltamos a la INT 16h del sistema 11 cmp word [0097], 0d75h ; ¿Tenemos en [0097] los opcodes 75 0D? 12 jnz EXIT ; NO: saltamos a la INT 16h del sistema 13 mov word [0097], 9090h ; escribimos los 90 90 en [0097] 14 15EXIT: 16 jmp dword [cs:OLDINT] ; Saltamos a la INT 16h del sistema 17 18INITCODE: 19 mov sp, SIZE ; redefinimos la pila 20 mov bx, SIZE/16 21 mov ah, 4Ah ; redimensionamos bloque memoria 22 int 21h 23 24 mov dx, MSG 25 mov ah, 9 ; Escribimos texto por pantalla 26 int 21h 27 28 xor ah, ah ; Esperamos pulsacion de tecla 29 int 16h 30 31 mov ax, 3516h ; Queremos el valor del puntero a la INT16 32 int 21h 33 mov word [OLDINT+0], bx ; Guardamos puntero a la INT 16h 34 mov word [OLDINT+2], es ; (necesitaremos llamarla despues) 35 36 mov ax,2516h ; Sobreescribimos en el vector INT 16h 37 mov dx, NEWINT ; un puntero a nuestra rutina NEWINT 38 int 21h 39 40 mov bx, EXEC_INFO 41 mov dword [bx+00h], 0 42 mov dword [bx+02h], 80h ; PSP 43 mov word [bx+04h], cs 44 mov word [bx+06h], 5Ch ; FCB 0 45 mov word [bx+08h], cs 46 mov word [bx+0ah], 6Ch ; FCB 1 47 mov word [bx+0ch], cs 48 49 mov dx, FILENAME 50 mov ax, 4b00h 51 int 21h ; cargar y ejecutar programa 52 53 push cs 54 pop ds ; DS = CS 55 mov ax, 4c00h ; terminar 56 int 21h 57 58[section .data] 59SIZE EQU 1024 ; este programa y su pila caben en 1 KB 60FILENAME db "COLMENA.EXE",0 ; programa a ejecutar
…Show last 6 lines
61EXEC_INFO times 22 db (0h) 62MSG db 0dh,0ah 63 db "La Colmena CGA/EGA/Hercules/VGA-16 loader.",0dh,0ah 64 db "2019, vlan7",0dh,0ah,"$" 65OLDINT dw 0,0 ; Espacio para el puntero a la INT 16h
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. 😉
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.