12/2006 by Zadig.
Introduction:
BeOS comes with a nice feature called replicants. Replicants are graphic objects that can be used by any application. This allows to reuse big parts of code. For example NetPositive is a replicant. This allows any application to add a NetPositive view in it. When originaly presented by be inc, this features was compared to activex components of windows: They both are binary objects that can be embedded in any application. However this behaviour brings some security problems because a replicant is part of the host application and not a standalone application. Thus replicants are probably the easiest way for a malware to hide in a BeOS system. All tests of this document where done on Zeta 1.1, but similar results should be obtained on any BeOS compatible system.
II- Images, addons, and replicants.
IV- Identification of replicants.
Before trying to identify a replicant running in an application we must know what defines an application. An application can be considered as several things depending on where we look. From a storage point of view an application is identified by a Mime-type and has executable attributes. System wise, a running application is composed of several parts: Each running application is a team, and a team is composed of several elements: threads, images and areas:
There are several shell tools available to list these elements on a running application. The following example shows the content of a running terminal:
>ps ... /boot/beos/apps/Terminal (team 119) (uid 0) (gid 0) 17551 Terminal 17555 Terminal 2 17556 RNodeManager ... >listimage 119 TEAM 119 (/boot/beos/apps/Terminal): ID name text data ---------------------------------------------------------------- 1370 /boot/beos/apps/Terminal 0x80000000 0x80037f40 1371 /boot/beos/system/lib/libzeta.so 0xec354000 0xec3e56a0 1372 /boot/beos/system/lib/libbe.so 0xec0a8000 0xec2d27a0 1373 /boot/beos/system/lib/libtracker.so 0xec6e0000 0xec87d540 1374 /boot/beos/system/lib/libroot.so 0xec000000 0xec074120 ... >listarea 119 memory: total: 524288KB, used: 328816KB, left: 195472KB /boot/beos/apps/Terminal (team 119) ID name address size --------------------------------------------------------- 21253 user stack of Terminal fc000000 ffd000 4000 21255 Terminal_seg0 80000000 37000 2e000 21256 Terminal_seg1 80037000 12000 12000 21257 libzeta.so_seg0 ec354000 91000 81000 21258 libzeta.so_seg1 ec3e5000 1a000 1a000 21259 libbe.so_seg0 ec0a8000 22a000 1e9000 21260 libbe.so_seg1 ec2d2000 82000 81000 21261 libtracker.so_seg0 ec6e0000 19d000 15b000 21262 libtracker.so_seg1 ec87d000 6b000 6a000 21263 libroot.so_seg0 ec000000 74000 72000 21264 libroot.so_seg1 ec074000 34000 c000 ... 21281 heap 80049000 2f000 1f000 21285 rw_server_area d0000000 1000 1000 21286 ro_server_area de000000 1000 1000 21287 global_ro_server_area df000000 9000 9000 21290 user stack of Terminal 2 fcffd000 3d000 3000 21291 user stack of fd03a000 3d000 1000 21300 user stack of fd077000 3d000 1000 21301 user stack of fd0b4000 3d000 1000
In this truncated example there ios a running terminal in the team 119 that is composed of 5 images: The application and 4 libraries. 2 areas are needed for each library. These areas correspond to the code and data segments of the elf files. Finally some other areas are created for the stacks of each thread. These are the main elements that will be used in this text.
BeOS systems recognize 3 types of images: Application, library, and addon. An application is an executable code that can be launched. A library is a shared library (!). An addon is some code that can be loaded by an application. Basically an addon can be seen as an application or a library that has been loaded by another application. This last sentence is very important because it says one very specific thing about BeOS binaries: On BeOS all elf files are DYN files. This means that applications and libraries have the same elf type. We will see later that this is very important for the replicants.
There are several solutions to load addons from an application. The first way is to use the function:
image_id load_add_on(const char *pathname)This allows to load the addon in the application by providing the elf file of the addon. But there is also another way to load addons indirectly:
BArchivable *instantiate_object(BMessage *archive)
This allows to instantiate a new object of a class. If the archive param contains only the class name, the class definition is searched in the application code. However you can also add a mime-type information that will tell the system in which addon the class is defined. In this case the system will search for the addon, load it and instantiate the class. The important point here is that when using the second method, the addon must have registered a mime-type to be loadable. Otherwise the system does not know where to load the file.
Now let's see what is a replicant. Basically a replicant is just an addon with mandatory elements:
For the purpose of this document, the MalRep replicant has been written. The sources of MalRep are available at [MALREP]. This replicant is just a small square with a context menu to try the different techniques explained here. To be considered as really hidden to the user, a replicant must meet two conditions:
Hiding a replicant is quite simple. The BView of the replicant must just implement the Draw virtual method. In this method it must set its own color to the one of its parent BView:
void MalRepView::Draw(BRect c_UpdateRect)
{
if(Parent() != NULL)
{
SetHighColor(Parent()->ViewColor());
FillRect(c_UpdateRect);
}
}
That is all: The replicant is invisible with only 5 lines of code. However
to make MalRep visible for the tests, a white rectangle is drawn on the
borders of the view:
SetHighColor(255,255,255);
StrokeRect(BRect(0.0,0.0,10.0,10.0));
There are several solutions to make the replication automatic:
BMessenger MalRepView::MessengerForShelfer()
{
BMessage c_Request(B_GET_PROPERTY), c_Reply;
BMessenger c_Host;
BMessenger c_Result;
c_Request.AddSpecifier("Messenger");
c_Request.AddSpecifier("View", "view");
c_Request.AddSpecifier("Window", (int32) 0);
c_Host = BMessenger("application/N3S.shelfer", -1);
if (c_Host.SendMessage(&c_Request, &c_Reply) == B_OK)
c_Reply.FindMessenger("result", &c_Result);
return c_Result;
}
This code is specific to Shelfer. Different specifiers would be needed for
other host applications. Then sending the message to force replication just
require 3 lines of code:
status_t MalRepView::ExportToShelfer()
{
status_t i_ret;
BMessenger c_Target;
c_Target = MessengerForShelfer();
BMessage c_Request(B_ARCHIVED_OBJECT);
Archive(&c_Request, false);
i_ret = c_Target.SendMessage(&c_Request);
return(i_ret);
}
The Archive method will archive our BView class in a message. It is then sent
to the host app. This process is quite the same than when using a dragger.
The replicant is now hidden, and replicates automatically when the
application is started.
Starting MalRep in Shelfer confirms that replicants are hidden from the system: MalRep is not visible in the team monitor. Only shelfer is listed.
Let's see first how to detect that a replicant is running in an application. This can be done by listing the images loaded by the team. The API get_next_image_info lists all images of a team. It can be used to build a list of the images. A first filter can be applied by looking at the images type: All potential replicants have a B_ADD_ON_IMAGE type. Finally if the image file has a mime type it can be considered as a replicant. All this can be done in a few lines of code:
while(get_next_image_info(0, &i_Cookie, &s_Info) == B_OK)
{
BNode c_ImgNode(s_Info.name);
BNodeInfo c_ImgNodeInfo(&c_ImgNode);
c_File.SetTo(s_Info.name, B_READ_ONLY);
if(c_Res.SetTo(&c_File) != B_OK)
continue;
sz_Mime = (char*)c_Res.LoadResource('MIMS', "BEOS:APP_SIG", &i_Size);
if(sz_Mime == NULL)
continue;
if(s_Info.type == B_ADD_ON_IMAGE)
{
printf("replicant '%s' is running in image %d\n",
sz_Mime, s_Info.id);
}
else if(s_Info.type == B_APP_IMAGE)
{
printf("I am application '%s' loaded in image %d\n",
sz_Mime, s_Info.id);
}
}
This method is easy to use and allow any application to check if another
application contains replicants.
Telling if the current context has been called from a replicant is much more difficult. Only few options are available:
Current BHandler:
Replicants are always BViews. This means that they are attached to a window, i.e a BLooper. If there is a way to find the current BHandler of the BLooper, then the replicant should be identified. The current BLooper can be found by using the static method:
BLooper *LooperForThread(thread_id thread)So we can identify the current BLooper when we are called from its context. Now we must know its active BHandler. The list of BHandlers of a BLooper can be obtained with the following method:
BHandler *HandlerAt(int32 index)But we still have to know which one has been called. Unfortunataly it seems that it is not possible: The context of the current called handler is not saved anywhere. This solution is a dead end.
Stack call:
An obvious solution is to look at the stack call and stop at the first caller that is in a replicant image space. The code is not shown here because it is too long and without special interest. Thus you should read the sources in [MALREP] to study it. This method works well but has some limitations:
Replicant injection is an easy way to hide some code in a BeOS system. BeOS
is still a niche OS and there is no known malware yet on this system.
However it will probably get more success when Haiku R1 will be out. Then a
lot of changes will be necessary to make the os more secure. Since security
was not an important concern when it was designed, there are probably a lot of
possible attacks of this kind. The developpers of Zeta already began to work
on this: The upcoming R1.5 will add multi-user support. This should remove a
lot of threats but it is just the begining.
Zadig.
[REP1] :
Replicants - More application than an application.
http://haiku-os.org/node/85
[REP2] :
RepliShow - A Replicable Image Viewer.
http://haiku-os.org/node/87
[MALREP] :
http://www.reveng.cjb.net/downloader.php?file=malrep.zip
[SHELFER] :
http://www.bebits.com/app/3910
[SCRIPTING] :
The ZETA Developer Guide - scripting.
http://www.zeta-os.com/cms/custom/API/Scripting.html