玩玩.net的ildasm與ilasm
之前有個朋友拿個vb6的程式給我.
說這是他請別人寫的,需要密碼才能開啟使用,
可是他忘了密碼是甚麼,而且沒有原始碼,
希望看看有沒有辦法"找到".
程式的功能是甚麼已經有點不記得了,因為不是重點.
重點是他的密碼並沒有在資料庫中,因為翻遍資料庫(Access)中的資料表沒有找到任何訊息.
所以猜測密碼應該是在包在程式裡了.
所以直接用十六進位編輯器(ultraedit)開啟那個執行檔.
在檔案中看到password的字樣,而就在附近看到了"疑似"密碼的字串.
然後使用那個密碼試著登入.果然真的是密碼...
不知道各位看了上面這個例子會有甚麼想法!!
回到主題.
今天要介紹的是ildasm跟ilasm的功能.
在msdn上的介紹寫著 :
MSIL 反組譯工具是 MSIL 組譯工具 (Ilasm.exe) 的附屬工具。Ildasm.exe 使用包含 Microsoft Intermediate Language (MSIL) 程式碼的可攜式執行檔 (PE),並建立可以做為 Ilasm.exe 的輸入檔的文字檔。
如果你跟我一樣看了還是不懂他是用來做甚麼的話,那就先往下看.
為了測試,我們要先寫個主控台程式(ConsoleApplication).
主要的功能如下:
讓使用者輸入帳號密碼,
然後判斷是否跟我們設定好的字串相同.
如果相同就顯示welcome,
如果不同就顯示Access Deny.
程式碼如下:
using System;
namespace LoginConsole
{
class Program
{
static void Main(string[] args)
{
string UserId = "ajun";
string UserPwd = "password";Console.Write("Please enter your id : ");
string uid = Console.ReadLine();
Console.Write("Please enter your password : ");
string pwd = Console.ReadLine();if ((uid == UserId) && (UserPwd == pwd))
{
Console.WriteLine("Welcome!");
}
else
{
Console.WriteLine("Access Deny!");
}
}
}
}
寫好後編譯成exe檔.(假設我們編譯完後的執行檔的名稱為 LoginConsole.exe)
然後開啟一個dos視窗.
因為我是用vs.net 2005.
所以要將路徑切換到到
C:\Windows\Microsoft.NET\Framework\v2.0.50727
因為ildasm.exe是放在這個路徑下.
當然.如果你是透過"Visual Studio 2005命令提示字元"啟動命令視窗的話,就不用切換目錄了.
然後執行下列的指令 :
ildasm LoginConsole.exe
這時就會跳出ildasm的視窗如下 :
點開其中的 Main : void(string[])
就可以看到如下反組譯的視窗畫面
而內容如下 :
.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
// 程式碼大小 104 (0x68)
.maxstack 2
.locals init ([0] string UserId,
[1] string UserPwd,
[2] string uid,
[3] string pwd,
[4] bool CS$4$0000)
IL_0000: nop
IL_0001: ldstr "ajun"
IL_0006: stloc.0
IL_0007: ldstr "password"
IL_000c: stloc.1
IL_000d: ldstr "Please enter your id : "
IL_0012: call void [mscorlib]System.Console::Write(string)
IL_0017: nop
IL_0018: call string [mscorlib]System.Console::ReadLine()
IL_001d: stloc.2
IL_001e: ldstr "Please enter your password : "
IL_0023: call void [mscorlib]System.Console::Write(string)
IL_0028: nop
IL_0029: call string [mscorlib]System.Console::ReadLine()
IL_002e: stloc.3
IL_002f: ldloc.2
IL_0030: ldloc.0
IL_0031: call bool [mscorlib]System.String::op_Equality(string,
string)
IL_0036: brfalse.s IL_0044
IL_0038: ldloc.1
IL_0039: ldloc.3
IL_003a: call bool [mscorlib]System.String::op_Equality(string,
string)
IL_003f: ldc.i4.0
IL_0040: ceq
IL_0042: br.s IL_0045
IL_0044: ldc.i4.1
IL_0045: stloc.s CS$4$0000
IL_0047: ldloc.s CS$4$0000
IL_0049: brtrue.s IL_005a
IL_004b: nop
IL_004c: ldstr "Welcome!"
IL_0051: call void [mscorlib]System.Console::WriteLine(string)
IL_0056: nop
IL_0057: nop
IL_0058: br.s IL_0067
IL_005a: nop
IL_005b: ldstr "Access Deny!"
IL_0060: call void [mscorlib]System.Console::WriteLine(string)
IL_0065: nop
IL_0066: nop
IL_0067: ret
} // end of method Program::Main
而從這內容就可以很清楚的看到我們所設定的帳號密碼.
到這.我想大家應該比較清楚ildasm.exe的功能了.
再來在說一下ilasm.exe,
ildasm是用來做反組譯的,
而ilasm就是用來作組譯用的.
至於怎麼用.看一下下面的用法.
現在我們先用ildasm.exe來產生剛剛所寫的程式的PE檔.
語法如下 :
ildasm /source LoginConsole.exe /out:LoginConsoleFake.txt
其中的/source參數是用來"顯示原始程式行做為註解".
然後我們就可以得到下面這個LoginConsoleFake.txt的檔案.
// Microsoft (R) .NET Framework IL Disassembler. Version 2.0.50727.42
// Copyright (c) Microsoft Corporation. All rights reserved.// Metadata version: v2.0.50727
.assembly extern mscorlib
{
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
.ver 2:0:0:0
}
.assembly LoginConsole
{
.custom instance void [mscorlib]System.Reflection.AssemblyFileVersionAttribute::.ctor(string) = ( 01 00 07 31 2E 30 2E 30 2E 30 00 00 ) // ...1.0.0.0..
.custom instance void [mscorlib]System.Runtime.InteropServices.GuidAttribute::.ctor(string) = ( 01 00 24 65 30 31 65 31 37 32 31 2D 37 32 62 63 // ..$e01e1721-72bc
2D 34 33 61 62 2D 38 65 62 62 2D 34 66 66 38 34 // -43ab-8ebb-4ff84
31 62 65 34 65 37 36 00 00 ) // 1be4e76..
.custom instance void [mscorlib]System.Runtime.InteropServices.ComVisibleAttribute::.ctor(bool) = ( 01 00 00 00 00 )
.custom instance void [mscorlib]System.Reflection.AssemblyTrademarkAttribute::.ctor(string) = ( 01 00 00 00 00 )
.custom instance void [mscorlib]System.Reflection.AssemblyCopyrightAttribute::.ctor(string) = ( 01 00 13 43 6F 70 79 72 69 67 68 74 20 28 43 29 // ...Copyright (C)
20 20 32 30 30 38 00 00 ) // 2008..
.custom instance void [mscorlib]System.Reflection.AssemblyProductAttribute::.ctor(string) = ( 01 00 0C 4C 6F 67 69 6E 43 6F 6E 73 6F 6C 65 00 // ...LoginConsole.
00 )
.custom instance void [mscorlib]System.Reflection.AssemblyCompanyAttribute::.ctor(string) = ( 01 00 00 00 00 )
.custom instance void [mscorlib]System.Reflection.AssemblyConfigurationAttribute::.ctor(string) = ( 01 00 00 00 00 )
.custom instance void [mscorlib]System.Reflection.AssemblyDescriptionAttribute::.ctor(string) = ( 01 00 00 00 00 )
.custom instance void [mscorlib]System.Reflection.AssemblyTitleAttribute::.ctor(string) = ( 01 00 0C 4C 6F 67 69 6E 43 6F 6E 73 6F 6C 65 00 // ...LoginConsole.
00 )// --- 以下為自動加入的自訂屬性,請勿取消註解 -------
// .custom instance void [mscorlib]System.Diagnostics.DebuggableAttribute::.ctor(valuetype [mscorlib]System.Diagnostics.DebuggableAttribute/DebuggingModes) = ( 01 00 07 01 00 00 00 00 ).custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 )
.custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78 // ....T..WrapNonEx
63 65 70 74 69 6F 6E 54 68 72 6F 77 73 01 ) // ceptionThrows.
.hash algorithm 0x00008004
.ver 1:0:0:0
}
.module LoginConsole.exe
// MVID: {71069530-5126-4026-B70A-03F69CFFD29A}
.imagebase 0x00400000
.file alignment 0x00001000
.stackreserve 0x00100000
.subsystem 0x0003 // WINDOWS_CUI
.corflags 0x00000001 // ILONLY
// Image base: 0x009C0000// =============== CLASS MEMBERS DECLARATION ===================
.class private auto ansi beforefieldinit LoginConsole.Program
extends [mscorlib]System.Object
{
.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
// 程式碼大小 104 (0x68)
.maxstack 2
.locals init ([0] string UserId,
[1] string UserPwd,
[2] string uid,
[3] string pwd,
[4] bool CS$4$0000)
.language '{3F5162F8-07C6-11D3-9053-00C04FA302A1}', '{994B45C4-E6E9-11D2-903F-00C04FA302A1}', '{5A869D0B-6611-11D3-BD2A-0000F80849BD}'
// Source File 'D:\Project\LoginConsole\LoginConsole\Program.cs'
//000010: {
IL_0000: nop
//000011: string UserId = "ajun";
IL_0001: ldstr "ajun"
IL_0006: stloc.0
//000012: string UserPwd = "password";
IL_0007: ldstr "password"
IL_000c: stloc.1
//000013:
//000014: Console.Write("Please enter your id : ");
IL_000d: ldstr "Please enter your id : "
IL_0012: call void [mscorlib]System.Console::Write(string)
IL_0017: nop
//000015: string uid = Console.ReadLine();
IL_0018: call string [mscorlib]System.Console::ReadLine()
IL_001d: stloc.2
//000016: Console.Write("Please enter your password : ");
IL_001e: ldstr "Please enter your password : "
IL_0023: call void [mscorlib]System.Console::Write(string)
IL_0028: nop
//000017: string pwd = Console.ReadLine();
IL_0029: call string [mscorlib]System.Console::ReadLine()
IL_002e: stloc.3
//000018:
//000019: if ((uid == UserId) && (UserPwd == pwd))
IL_002f: ldloc.2
IL_0030: ldloc.0
IL_0031: call bool [mscorlib]System.String::op_Equality(string,
string)
IL_0036: brfalse.s IL_0044IL_0038: ldloc.1
IL_0039: ldloc.3
IL_003a: call bool [mscorlib]System.String::op_Equality(string,
string)
IL_003f: ldc.i4.0
IL_0040: ceq
IL_0042: br.s IL_0045IL_0044: ldc.i4.1
IL_0045: stloc.s CS$4$0000
IL_0047: ldloc.s CS$4$0000
IL_0049: brtrue.s IL_005a//000020: {
IL_004b: nop
//000021: Console.WriteLine("Welcome!");
IL_004c: ldstr "Welcome!"
IL_0051: call void [mscorlib]System.Console::WriteLine(string)
IL_0056: nop
//000022: }
IL_0057: nop
IL_0058: br.s IL_0067//000023: else
//000024: {
IL_005a: nop
//000025: Console.WriteLine("Access Deny!");
IL_005b: ldstr "Access Deny!"
IL_0060: call void [mscorlib]System.Console::WriteLine(string)
IL_0065: nop
//000026: }
IL_0066: nop
//000027: }
IL_0067: ret
} // end of method Program::Main.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{
// 程式碼大小 7 (0x7)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]System.Object::.ctor()
IL_0006: ret
} // end of method Program::.ctor} // end of class LoginConsole.Program
// =============================================================
// *********** 反組譯作業完成 ***********************
// 警告: 已建立 Win32 資源檔 LoginConsoleFake.res
再來我們將這個檔案做些小調整.
從檔案中我們可以很容易看出哪個是帳號密碼的設定.
所以我們直接改一下密碼.將他改為1234.
IL_0007: ldstr "password"
改為
IL_0007: ldstr "1234"
存檔後.在dos的視窗輸入下列指令
ilasm LoginConsoleFake.txt
當執行完成後,它會產生一個LoginConsoleFake.exe的檔案.
這時你就可以執行它.然後輸入新的密碼看看!!
我想這時你應該對於ildasm跟ilasm有初步的認識了...
雖然這並不是一個很正面的例子.
但是,我想應該是可以讓人比較有興趣...
其實,ildasm有更正面的用法,
像是黑暗執行緒寫的這篇,
或是你想要看看對於sqlconnection使用using跟使用close()與Dispose(),
在編譯後所進行的動作有甚麼差異.
也都是可以透過這個工具來進行.
最後,你或許會覺得.net的程式就這麼"透明",這麼不安全嗎??
其實有攻就有防.
下個主題或許可以來說一下.net的"混淆器"(obfuscator).