Copy Link
Add to Bookmark
Report

xine-2.016

eZine's profile picture
Published in 
Xine
 · 26 Apr 2019

  


/-----------------------------\
| Xine - issue #2 - Phile 016 |
\-----------------------------/

HOW TO STAY RESIDENT IN MEMORY
==============================
by Beol

Introduction
------------

Staying resident in memory and patching the OS-funtions is much easier
on Amiga than on most other systems. The problem virus-writers will have
is to patch the system in a way, so AV-ware won't yell about changed
vectors...



Get some memory
---------------

Before patching the OS, we need to get some memory which will not be
overwritten. Using hardcoded addresses isn't a good idea, because chances
are big that this memory is or will be in use.

Probably the best way is to get some memory is to use the AllocMem()
function. AmigaOS doesn't keep track of who allocated memory, so unlike
under MS-DOS it's impossible to notice that there's memory missing.
If you plan to let your virus be resetresident, you should take care to
allocate mem, which will be available directly after reset (just alloc
chip-memory using the MEMF_CHIP flag).

Another method I like, is to get the lower bound of the systemstack
(ExecBase->SysStkLower). This works because the system allocates some
kbytes for stack, but uses only some 100 bytes. I like this one, because
system stack doesn't move until the next reset, so when the virus is
executed, it doesn't need to check if it's allready in memory: it just
copies itself to SysStkLower. No problem if it was allready there...



Copying virus
-------------

Once we've got some memory, we copy the virus to it using a simple
copy loop. Don't forget, that it's very important to keep the whole
virus PC-relativ!!
It is also very important to flush the caches before jumping to
the new location. This is very easy:

move.l 4.w,a6 ;Get ExecBase
jsr _LVOCacheClearU(a6) ;clear caches

This system routine cleares all caches and is garanteed to handle all
processors (from 68000-68060) right.



Marking presence
----------------

Most viruses will need to recognize if they are allready in memory.
It's best to check the patches. Another method consists in writing
a magic number into fixed places (e.g. ExecBase->LastAlert). This is
no good idea, because AV-ware will remove the patches but leave the
mark => the virus will not reinstall itself, when called.




Patching
========

The easy way
------------

The easiest way of patching the system is to just patch the library
vectors. This needs some work (Patch/compute library checksum/...) but
fortunately there is a system-function doing all this (SetFunction()).
This way we can intercept dos.library calls like:
* LoadSeg() - If you want to infect only when a proggy is executed
* Open() - If you want to infect a proggy when it's accessed
* Read() - To do filestealth
* Seek() - To do filestealth
* Examine()/ExamineFH()/ExamineNext() - For directory stealth

The problem is that every AV will recognise the changed vectors. So the
user will be aware of the virus.


Illegal Access
--------------

This one is used in the Illegal Access virus. It fools old AV but new
AV-wares won't be cheated.

A library vector is 6 bytes. The first two bytes are $4ef9 (opcode
for JMP $xxxxxxxx.l) followed by the address of the function. When
a programm uses a library-function, it JSRs to the vector of the
function and thus JSRs to the function. The old (stupid) AVs just
check if the address of the function lies in the ROM.

What Illegal Access does: it leaves the address, but changes the $4ef9
opcode to $4AFC (ILLEGAL). When a programm wants to call a function,
it JSRs to the vector and thus executes an ILLEGAL. This will cause
a Illegal-Opcode-Exception. Illegal Access patched the corresponding
exception vector and using the stackframe can figure out which function
the proggy wanted to call.

Unfortunately modern AV check for $4ef9 too, so this one is just a waste
of time.



Changing the code of the function
---------------------------------

This one is AFAIK used on PeeCee. The problem on Amiga: the OS functions
are in a ROM => this just won't work. One could copy the ROM to RAM and
use the MMU to simulate the original addresses, but every Amiga-user
would notice the lack of 512k RAM.

I tried to patch the code of filehandlers, but this doesn't work very
well. Most of the code lies in ROM and patching code in RAM ain't easy
either.


Use Packetlevel IO!
-------------------

The best way to escape all these problems, is to use IO on another level
than dos.library: using direct communication with handlers thru packets.
I will write a whole file describing how to do packet-IO, so just a brief
overview:

Filehandlers are processes just Wait()ing for a message to arrive at
their messageport. To every message they get there is attached a so
called packet, which describes what to do. The handler gets the
packet, executes the desired function and sends the packet back to the
sender. (Note that this way you can realize async-IO.)

What a packetlevel-virus does, is intercept these packets. This can be
done by several ways:

* Patch the Process->pr_PktWait field. (Points to a function called when
a process waits for a packet)
* Patch the Task->tc_Launch field. (Points to a function called when a
process gets CPU-time)
* Patch the stack of the handlers.
* Patch the interrupts used for taskswitching.

Modern AVs check for pr_PktWait, tc_Launch and tc_Switch fields, but there
are more ways of intercepting packets -> just use your imagination!
(Only experienced Amiga Programmers will be able to patch the system this
way -> beginners should try the conventional methods first!)




Surviving Resets
================

Standard Way
------------

The Amiga-OS has some nice features making it easy to stay reset-resident:

ExecBase->ColdCapture, ExecBase->CoolCapture and ExecBase->WarmCapture
point to routines that will be called during different phases of boot.
Normaly they are set to 0, but some programms and many viruses use these
to reinstall themselves after reset. When changing them, you have to
compute the ExecBase->ChkSum otherwise the OS will rebuild a new
ExecBase after reset. To compute the checksum use this code:

move.l 4.w,a6 ;get ExecBase
lea SoftVer(a6),a0 ;beginning of checksummed structure
moveq #0,d0
moveq #24-1,d1 ;Checksum over 24 words
.l add.w (a0)+,d0 ;Add the words
dbf d1,.l
not.w d0
move.w d0,(a0) ;Store checksum in ExecBase->ChkSum
jsr _LVOClearCacheU(a6) ;Avoid troubles with copyback caches

A very sober programmer, you would do the patching and checksumming in
a Forbid()/Permit() lock, but chances are nearly 0 that another task will
do this the same time as you.

The memory pointed to by Cold-,Cool- and WarmCapture must be available
after reset (e.g. AutoConfig boards won't), so it's wise to use
chipmemory to install the virus. (Chipmemory is garanteed to exist).

The WarmCapture will be called first, when the system is still in a
very raw state: there is not even a stack! So you can't call subroutines
or save data on stack. Ofcourse you can't RTS from the warmcapture,
instead you must do a JMP (a5), because you will get the returnaddress
in a5. In the WarmCapture you can't call any OS-function, so you won't
be able to do many useful things. Infact only very few viruses use
this one.

ColdCapture and CoolCapture are far more useful. Usually you will use
this to AllocAbs() the memory you're using (To prevent being overwritten)
and patch some systemfunctions.

This is very useful for BootBlock viruses as all they need (ExecBase,
trackdisk.device) is allready installed, but linkviruses have a little
problem: neither dos.library, nor the filehandlers are ready yet.
Best way is to patch the OpenLibrary() function and wait until a
OpenLibrary("dos.library",ver) succeeds and then patch dos.library
or handlers and remove the OpenLibrary() patch. Or use another way
of staying reset-resident.


ROMTags
-------

On startup, the AmigaOS searches the ROM after socalled ROMTags and
executes them after priority. These ROMTags contain the initcode for
all parts of the system. Of course you cannot change the ROM, but the
OS allows you to replace or add modules. This is done using two ExecBase
variables: ExecBase->KickMemPtr and ExecBase->KickTagPtr.

KickMemPtr points to a list of MemEntry structures, that will be allocated
at startup. (The memory must be available at this time=>use chipmem!)

KickTagPtr points to a array of pointers to ROMTag structures the last
item of the Array is NULL or an address with bit 31 set. In the latter
case the last item points to another array of this type. (You must ofcourse
clear bit 31). This way you can add your own ROMTag array by overwritting
the NULL at the end of the last array with a pointer to your array (but
don't forget to set bit 31!). But chances are 99:1 that KickTagPtr is 0
anyway, so you can directly install your array, which will usually contain
only one entry.

A ROMTag is just a Resident structure and looks like this:

WORD MatchWord (=$4afc)
LONG MatchTag (Pointer to the above)
LONG EndSkip (??)
BYTE Flags
BYTE Version
BYTE Type (Type of resident (LIBRARY,DEVICE,...))
BYTE Priority (The higher the priority, the earlier it will be installed)
LONG Name (Pointer to name)
LONG IdString (Pointer to IDstring)
LONG Init (Poniter to Initialisation routine or to AutoInit-struct)

This method is especially interesting for us linkviruswriters as
we can set a flag called RTF_AFTERDOS which will make sure, that the
resident is called after dos.library has been installed. And you can
set the priority to very low (-128), so everything else will be
installed. (dos.library has priority -120)

After altering the KickTagPtr or the KickMemPtr (or the data pointed to
by them), you have to call SumKickData() (no arguments) and store the
result in ExecBase->KickCkeckSum. (And flush caches).



KBResetHandler
--------------

The problem with all the ColdCapture etc. stuff is that ever Viruskiller
will notice the changed vectors.

One way to avoid this: Using the keyboard.device, you can install a
ResetHandler wich will be called when the user want's to do a reset
(by pressing CTRL-AMIGA-AMIGA). This is hard work as you need to
initialise a MsgPort, an IORequest, open the device, init an interrupt
structure, do an IO-Commmand and close the device. And this won't work
on all amigas.

Anyway, if you've done everything right, it's pretty cool because
AV-warez can't easily check ResetHandlers. When your reset handler
is called, you have enough time (some seconds) to patch the resetvectors
you want and perform a reset, before a Viruskiller can notice what's
going on!


FileSystem
----------

By far the best way of staying reset resident is to infect the filesystem
in the RigidDiskBlock (RDB) Area of the harddisk! This will allways be called
when the harddisk is mounted (every reboot!). I cannot understand why
no virus uses this feature!? In the near future I will write the first
FileSystem infecting Virus.

For information about RDB look at the devices/hardblocks.h includes.

← 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