VOGONS


Writing a patch in ASM *SOLVED*

Topic actions

Reply 20 of 35, by Akuma

User metadata
Rank Member
Rank
Member
ripsaw8080 wrote:

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.

So next program hangs because it cannot return ? Or next program hangs because it waits on the former iret ?

ripsaw8080 wrote:

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.

I will look into this 😁

ripsaw8080 wrote:

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. 😉

I have no problem if the thread gets moved to where it belongs, but I cant do this myself.

cyclone3d wrote:

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.

I can make it work all sorts of ways, but I wanted to do this in assembly. Thanks though 😁

Reply 21 of 35, by BloodyCactus

User metadata
Rank Oldbie
Rank
Oldbie
Akuma wrote:
ripsaw8080 wrote:

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.

So next program hangs because it cannot return ? Or next program hangs because it waits on the former iret ?

no, the INT 0x16 now points into trash so when its called, system hangs. you need to re-hook it to its original value before you quit your app

--/\-[ Stu : Bloody Cactus :: http://kråketær.com :: http://mega-tokyo.com ]-/\--

Reply 22 of 35, by pantercat

User metadata
Rank Newbie
Rank
Newbie

Well, this is not my code 😉

I have written:

lea bx, EXEC_INFO

and not:

mov bx, EXEC_INFO

LEA != MOV.

LEA (or PUSH and POP, as ripsaw8080 said) should eliminate 2nd issue. Maybe with nasm you must write:

lea bx, [EXEC_INFO]

But well, I'm not an expert, but if you want to use my code as a base, my advice is: compile my code with no modifications first. My code follows A86 syntax, so get A86, put A86.COM and A86.LIB and WHATEVER.ASM in the same directory as "La Colmena CGA/EGA/Hercules" and compile with:

A86 WHATEVER.ASM

Then run WHATEVER.COM and when you see it works, then have fun modifying it as much as you want. But remember: I'm just a learner. 😀

PS: make sure you've La Colmena CGA/EGA/Hercules/VGA-16 version and NOT VGA-256 version. The bytes to modify will be in different memory addresses.

Reply 23 of 35, by ripsaw8080

User metadata
Rank DOSBox Author
Rank
DOSBox Author

LEA BX loads the effective address into BX rather than the value at that address, it does not change ES. LES BX would change ES, but it is not really applicable in this case, so the push/pop is the simple solution.

Reply 24 of 35, by pantercat

User metadata
Rank Newbie
Rank
Newbie

I see why ES should be preserved, but even if ES is destroyed, the loader works nevertheless. Even if I comment entire EXEC_INFO it still works 😕 , so I'm leaning toward DOSBox doing some magic and requiring only DS:DX pointing to the ASCIIZ filename. I bet this wouldn't end well in pure DOS 🤣

Anyway, Akuma, here is a revised full source of the LOADER. Thank you all for your comments.

;; A86 LOADER.ASM
;; La Colmena CGA/EGA/Hercules/VGA-16 loader

SIZE EQU 1024
OVERLAY segment para 'code'
assume cs:OVERLAY, ds:OVERLAY
org 100h

START: jmp INITCODE

OLDINT dw 0,0

NEWINT proc far
cmp ah, 1
jnz EXIT

cmp Word Ptr [0097], 0d75h
jnz EXIT

mov Word Ptr [0097], 9090h

EXIT:
jmp DWord Ptr cs:[OLDINT]
NEWINT endp

INITCODE:
mov sp, SIZE
mov bx, SIZE/16
mov ah, 4ah
int 21h

mov ax, 3516h
int 21h
mov OLDINT[0], bx
mov OLDINT[2], es

push cs
pop es

mov ax,2516h
lea dx, NEWINT
int 21h

lea bx, EXEC_INFO
mov DWord Ptr [bx], 0
mov DWord Ptr [bx+2], 80h
mov Word Ptr [bx+4], cs
mov Word Ptr [bx+6], 5ch
mov Word Ptr [bx+8], cs
mov Word Ptr [bx+0ah], 6ch
mov Word Ptr [bx+0ch], cs

lea dx, FILENAME
mov ax, 4b00h
int 21h

mov dx, OLDINT[0]
mov ds, OLDINT[2]
mov ax,2516h
int 21h
Show last 12 lines

push cs
pop ds
mov ax, 4c00h
int 21h

FILENAME db "COLMENA.EXE",0
EXEC_INFO db 22 DUP (0)

OVERLAY ends

end START

Keep in mind that this instruction:

mov Word Ptr [0097], 9090h

is MOVing bytes in DS:[0097]. It's ok in this case, because when mov is executed the bytes you want to patch are in DS:[0097]. But this is not always true. You usually have to figure out the segment where you want to patch looking at the values that were pushed on the stack. You can do something like:

push bp
mov bp, sp
push es
push ax
mov ax,[bp+6h] ; more info later
mov es, ax

cmp Word Ptr es:[032b], 0374h
jne ALREADYPATCHED

mov Word Ptr es:[032b], 03ebh

ALREADYPATCHED:
pop ax
pop es
pop bp
...
EXIT:
jmp DWord Ptr cs:[OLDINT]
NEWINT endp

Hint: you can change data view to SS:BP (DOSBox debugger -> d ss:bp)

but maybe it's quicker just to put some instructions like:
mov ax,[bp]
mov ax,[bp+2h]
mov ax,[bp+4h]
mov ax,[bp+6h]
...

and step into them looking at AX value.

Let's say you're looking for segment where bytes 74 03 are. Let's say you step in mov ax,[bp+6h] and AX=03C0. You already know the offset, say it's 032b, so you'll go to 3c0:32b (DOSBox debugger -> d 3c0:32b) and if you see 7403 congrats, you have found the segment pushed on the stack, you can code mov ax,[bp+6h]

Last edited by pantercat on 2019-11-10, 11:06. Edited 1 time in total.

Reply 25 of 35, by ripsaw8080

User metadata
Rank DOSBox Author
Rank
DOSBox Author

Well, it's true that few games care about finding environment variables, but the most significant potential problem with a bad pointer to the parameter block comes when the child program releases its environment block on termination. The effect might not be noticeable (e.g. crash, hang, or error) depending on what happens to be in memory where ES:BX is pointing, but arbitrary behavior should be avoided of course. 😉

Reply 26 of 35, by akuma667

User metadata
Rank Newbie
Rank
Newbie

Sorry guys, I had an unfortunate accident, my password database got corrupted amongst other things
and I have no backup 😊 No important data is lost except for that. *phew*

So I will contact an admin and ask how to go about this, just letting everyone know
as I appreciate your feedback. If you PM me and I don't respond, this is why.

This might take a while, we'll see.

Reply 27 of 35, by akuma667

User metadata
Rank Newbie
Rank
Newbie

I think I found the problem, its probably me and my coding but I have that feeling...

When I convert:

A86: jmp dword ptr cs:[INTORIG]  
into
NASM: jmp dword [cs:INTORIG]

After compiling:

A86: jmp dword ptr cs:[INTORIG]  ---> 2E FF 2E 66 01
to
NASM: jmp dword [cs:INTORIG] ---> 2E 66 FF 26 67 01

When I convert:

A86: jmp dword ptr cs:[INTORIG]  
into
NASM: jmp WORD [cs:INTORIG]

After compiling:

A86: jmp dword ptr cs:[INTORIG]  ---> 2E FF 26 66 01
to
NASM: jmp WORD [cs:INTORIG] ---> 2E FF 2E 66 01

When I manually patch 2E into 26 , all starts working 😁
(because it changed WORD into DWORD and gets the same length as the A86 compiled version.

So is this my syntax error, or is this a bug ?

Reply 28 of 35, by BloodyCactus

User metadata
Rank Oldbie
Rank
Oldbie

the "2E 66 FF 26 67 01" first 0x66 is a 32bit size override.

I use "jmp far [cs: xxxxxx]" in nasm instead of jump dword

--/\-[ Stu : Bloody Cactus :: http://kråketær.com :: http://mega-tokyo.com ]-/\--

Reply 29 of 35, by akuma667

User metadata
Rank Newbie
Rank
Newbie
BloodyCactus wrote:

the "2E 66 FF 26 67 01" first 0x66 is a 32bit size override.

I use "jmp far [cs: xxxxxx]" in nasm instead of jump dword

That's it! 😁

My syntax error it was: when using 'jmp far [cs:xxxxx[' all works like it should.
I will mark this thread solved when I regain access to my account.

Thanks BloodyCactus, you just gave me the last piece of the puzzle 😁

Reply 30 of 35, by akuma667

User metadata
Rank Newbie
Rank
Newbie
pantercat wrote:
Well, this is not my code ;) […]
Show full quote

Well, this is not my code 😉

I have written:

lea bx, EXEC_INFO

and not:

mov bx, EXEC_INFO

LEA != MOV.

Actually it is your code 😉

You have written:

lea bx, EXEC_INFO

and I converted it to:

mov bx, EXEC_INFO

A86:LEA != A86:MOV , but A86:LEA == NASM:MOV following http://left404.com/2011/01/04/converting-x86- … masm-to-nasm-3/ and since I get the exact binary this way its a proper conversion afaict.

But the code was extremely helpful, thanks again for that 😁
.

Reply 32 of 35, by Akuma

User metadata
Rank Member
Rank
Member

Just out of curiosity what if the address of the patch falls outside the max offset of FFFFh ?
eg: cs=0 segment=cs offset=10000h

You have to point the segment value to a location where the offset can reach it.
How would one make this work 😕 ?

Reply 34 of 35, by Akuma

User metadata
Rank Member
Rank
Member

I searched and read some stuff today but its still confusing.
So I need to assign a base address to ds ?
I want cs+10000h, so 1000h/10h=1000h

mov bx,1000h
mov ds,bx ?
mov byte [ds:1h],'A' 😕

Reply 35 of 35, by BloodyCactus

User metadata
Rank Oldbie
Rank
Oldbie

you need to know its posistion from a register value called in your ISR.

so something like

push ds
mov ax,ds
add ax,0x1000
mov ds,ax
mov b[0x0001] = 'A'
pop ds

--/\-[ Stu : Bloody Cactus :: http://kråketær.com :: http://mega-tokyo.com ]-/\--