程式碼產生器
寫程式也寫了四五年了,每天這樣下來總覺得好像機器人一樣,寫來寫去都差不多一樣的東西,麻痺到自己都感覺自己跟剛畢業的學生的程度差不了多少,回想當初為什麼會開始寫程式,就是想當駭客,於是就冒著不怕死的危險,跑到中國的黑客教學網下載了一堆東西來研究,當然啦結果就像我想像的一樣駭客沒當成反而成了害客,但是也不是全然沒有收穫,其中一項就是我想要介紹的東西【 程式碼產生器】(這個很白話了,但是我還是解釋一下,就是寫一個程式,這個程式的用途是幫人家寫程式) 。
為什麼會想到寫【 程式碼產生器】?就是因為之前有下載一套軟體,那個軟體只要設定一些參數,下一些簡單的dos語法,就會幫你包裝出一個攻擊性的木馬,好了廢話不多說,下面就開始介紹如何簡單的實作出程式碼產生器。
1. 首先介紹的是如何產生Nampspace(專有名詞,在下面的程式都不再另外介紹)
2. 類別、結構、介面、列舉型別的型別宣告
3. 欄位、屬性與建構子宣告
4. 方法宣告(分成有參數與無參數)
a. 有參數
b. 無參數
5. 特殊方法(Try ... Catch ... Finally)
6. 轉出Source Code (.cs檔)
7. Build dll檔
此範例只是一個簡單的範例,已上的語法就可以動態產生出需要的dll檔,如果需要像本文一開始說的產生出一個執行檔讓人加設定,就需要更完整的程式碼進行編譯(如程式進入點,Winform畫面),但這就是一個大工程了,在還沒有這麼多美國時間之前我就先寫到這了,另外下面介紹一下該用另外一支AP使用Reflection(映射)的方式來呼叫此dll檔的方法。
InvokeMember函式說明請參閱MSDN
public object InvokeMember(string, BindingFlags, Binder, object, object[]);
string : 要呼叫的函式名稱
BindingFlags : 要調用的函式屬性,可多選
Binder : null就會使用默認的Binding對像
object : 要叫用指定成員的 Object
object[] : 是否有參數(若無可以為空值)
為什麼會想到寫【 程式碼產生器】?就是因為之前有下載一套軟體,那個軟體只要設定一些參數,下一些簡單的dos語法,就會幫你包裝出一個攻擊性的木馬,好了廢話不多說,下面就開始介紹如何簡單的實作出程式碼產生器。
1. 首先介紹的是如何產生Nampspace(專有名詞,在下面的程式都不再另外介紹)
//使用C#程式碼產生器 Microsoft.CSharp.CSharpCodeProvider csprovider = new Microsoft.CSharp.CSharpCodeProvider(); //提供一個CodeDom程式圖形的容器 CodeCompileUnit ccunit = new CodeCompileUnit(); //命名空間的宣告 CodeNamespace cnamespace = new CodeNamespace("MyNamespace"); //加入參考 cnamespace.Imports.Add(new CodeNamespaceImport("System")); ccunit.Namespaces.Add(cnamespace);
2. 類別、結構、介面、列舉型別的型別宣告
//類別、結構、介面、列舉型別的型別宣告 CodeTypeDeclaration ctype = new CodeTypeDeclaration("AutoProgram"); //取得型別的基底型別 MyNamespace.CodeDom.MyBase //ctype.BaseTypes.Add("MyNamespace.CodeDom.MyBase"); //取得型別成員的註解集合 ctype.Comments.Add(new CodeCommentStatement("程式碼產生器自動產生", false)); ccunit.Namespaces[0].Types.Add(ctype);
3. 欄位、屬性與建構子宣告
//欄位宣告 CodeMemberField cmfield = new CodeMemberField("System.String", "_text"); cmfield.Attributes = MemberAttributes.Private; //cmfield.Type = new CodeTypeReference("System.String"); //cmfield.Name = "_text"; //cmfield.InitExpression = new System.CodeDom.CodeObjectCreateExpression("1", new System.CodeDom.CodeExpression[] { }); ctype.Members.Add(cmfield); //屬性宣告 CodeMemberProperty cmproperty = new CodeMemberProperty(); cmproperty.Name = "Text"; cmproperty.Attributes = MemberAttributes.Public; cmproperty.Type = new CodeTypeReference("System.String"); cmproperty.GetStatements.Add(new CodeMethodReturnStatement(new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), "_text"))); cmproperty.SetStatements.Add(new CodeAssignStatement(new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), "_text"), new CodePropertySetValueReferenceExpression())); ctype.Members.Add(cmproperty); //建構子宣告 CodeConstructor cconstructor = new CodeConstructor(); cconstructor.Statements.Add(new CodeAssignStatement(new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), "Text"), new CodeVariableReferenceExpression("\"HelloWord\""))); cconstructor.Attributes = MemberAttributes.Public; ctype.Members.Add(cconstructor);
4. 方法宣告(分成有參數與無參數)
a. 有參數
//表示型別方法的宣告 CodeMemberMethod cmmethod = new CodeMemberMethod(); cmmethod.Name = "HelloWord"; //共用的方法 cmmethod.Attributes = MemberAttributes.Public; //回傳的資料型態 cmmethod.ReturnType = new CodeTypeReference("System.String"); //參數 cmmethod.Parameters.Add(new CodeParameterDeclarationExpression(typeof(string), "text")); //回傳值 cmmethod.Statements.Add(new CodeMethodReturnStatement(new CodeArgumentReferenceExpression("text"))); ctype.Members.Add(cmmethod);
b. 無參數
//表示型別方法的宣告 CodeMemberMethod cmmethod = new CodeMemberMethod(); cmmethod.Name = "HelloWord"; //共用的方法 cmmethod.Attributes = MemberAttributes.Public; //回傳的資料型態 cmmethod.ReturnType = new CodeTypeReference("System.String"); //回傳值 cmmethod.Statements.Add(new CodeMethodReturnStatement(new CodeArgumentReferenceExpression("this._text"))); ctype.Members.Add(cmmethod);
5. 特殊方法(Try ... Catch ... Finally)
//方法宣告(加入Try Catch) CodeMemberMethod cmmethod = new CodeMemberMethod(); cmmethod.Name = "HelloWord"; cmmethod.Attributes = MemberAttributes.Public; cmmethod.ReturnType = new CodeTypeReference("System.String"); CodeTryCatchFinallyStatement ctrycatch = new CodeTryCatchFinallyStatement(); CodeConditionStatement ccstatement = new CodeConditionStatement(); //try子句 ccstatement.Condition = new CodeVariableReferenceExpression("this._text != null"); //下面兩種回傳方式都可 ccstatement.TrueStatements.Add(new CodeMethodReturnStatement(new CodeArgumentReferenceExpression("this._text"))); ccstatement.FalseStatements.Add(new CodeVariableReferenceExpression("return \"Error\"")); ctrycatch.TryStatements.Add(ccstatement); //catch子句 CodeCatchClause ccatch = new CodeCatchClause("ex", new CodeTypeReference("System.ApplicationException")); ccatch.Statements.Add(new CodeVariableReferenceExpression("throw ex")); ctrycatch.CatchClauses.Add(ccatch); //finall子句 //ctrycatch.FinallyStatements.Add(new CodeVariableReferenceExpression("")); cmmethod.Statements.Add(ctrycatch); ctype.Members.Add(cmmethod);
6. 轉出Source Code (.cs檔)
//定義產生程式碼的介面 System.CodeDom.Compiler.ICodeGenerator generator = csprovider.CreateGenerator(filename + ".cs"); //提供可以使用定位點字串(String)語彙基元(Token)縮行新排的文字寫入器 System.CodeDom.Compiler.IndentedTextWriter writer = new System.CodeDom.Compiler.IndentedTextWriter(new System.IO.StreamWriter(filename + ".cs"), Environment.NewLine); generator.GenerateCodeFromCompileUnit(ccunit, writer, new System.CodeDom.Compiler.CodeGeneratorOptions());
7. Build dll檔
System.CodeDom.Compiler.ICodeCompiler compiler = csprovider.CreateCompiler(); //Compiler System.CodeDom.Compiler.CompilerParameters cparameters = new System.CodeDom.Compiler.CompilerParameters(); cparameters.OutputAssembly = filename + ".dll"; //加入需要的參考 cparameters.ReferencedAssemblies.Add("System.dll"); cparameters.GenerateInMemory = false; cparameters.TreatWarningsAsErrors = true; cparameters.WarningLevel = 3; System.CodeDom.Compiler.CompilerResults cr = compiler.CompileAssemblyFromDom(cparameters, ccunit);
此範例只是一個簡單的範例,已上的語法就可以動態產生出需要的dll檔,如果需要像本文一開始說的產生出一個執行檔讓人加設定,就需要更完整的程式碼進行編譯(如程式進入點,Winform畫面),但這就是一個大工程了,在還沒有這麼多美國時間之前我就先寫到這了,另外下面介紹一下該用另外一支AP使用Reflection(映射)的方式來呼叫此dll檔的方法。
InvokeMember函式說明請參閱MSDN
public object InvokeMember(string, BindingFlags, Binder, object, object[]);
string : 要呼叫的函式名稱
BindingFlags : 要調用的函式屬性,可多選
Binder : null就會使用默認的Binding對像
object : 要叫用指定成員的 Object
object[] : 是否有參數(若無可以為空值)
//呼叫dll private void button_Call_Click(object sender, EventArgs e) { try { string filename = this.textBox_Path.Text.Trim() + @"\" + this.textBox_Name.Text.Trim() + ".dll"; if (System.IO.File.Exists(filename)) { string str = ""; Assembly assembly = System.Reflection.Assembly.LoadFile(filename); Type type = assembly.GetType("MyNamespace.AutoProgram"); object instance = Activator.CreateInstance(type); if (!string.IsNullOrEmpty(this.textBox_CallText.Text.Trim())) { object[] arguments = new object[] { this.textBox_CallText.Text.Trim() }; str = type.InvokeMember("HelloWord", BindingFlags.InvokeMethod | BindingFlags.Instance | BindingFlags.Public, null, instance, arguments ).ToString(); MessageBox.Show("您呼叫的是有參數的方法,回傳值 : " + str); } else { object[] arguments = new object[0]; str = type.InvokeMember("HelloWord", BindingFlags.InvokeMethod | BindingFlags.Instance | BindingFlags.Public, null, instance, arguments ).ToString(); MessageBox.Show("您呼叫的是沒參數的方法,回傳值 : " + str); } } } catch (Exception ex) { MessageBox.Show(ex.ToString()); } }
本文附件 :
留言
張貼留言
您好,我是 Lawrence,這裡是我的開發筆記的網誌,如果你對我的文章有任何疑問或者有錯誤的話,歡迎留言讓我知道。