日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > asp.net >内容正文

asp.net

.NET程序加壳的基本原理和方式浅析

發(fā)布時(shí)間:2023/12/4 asp.net 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 .NET程序加壳的基本原理和方式浅析 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

.NET程序加殼的基本原理和方式淺析

  加殼程序是一種常用的保護(hù)應(yīng)用程序的辦法,確切的說是一種加密辦法。取名為殼,意思是說這種對程序的保護(hù)辦法就像植物種子的外殼,咱們運(yùn)用一段程序?qū)⒃蹅兊闹鞒绦虬谄溟g,不能輕易被其他人看見。
  被加殼的程序在運(yùn)轉(zhuǎn)時(shí)先要運(yùn)轉(zhuǎn)一段附加的指令,這段附加的指令完結(jié)有關(guān)操作后會發(fā)動主程序。
  加殼的辦法大致可分為壓縮和加密。
  傳統(tǒng)的非保管程序,加殼的目標(biāo)是匯編指令;對.NET程序的加殼目標(biāo)則是元數(shù)據(jù)和IL代碼。對.NET程序的加殼,在理論和辦法上并沒有啥創(chuàng)新,目前都是直接承繼與Windows程序的加殼理論和辦法。大多數(shù).NET加殼工具也是傳統(tǒng)的加殼工具在本身功能上供給了拓展。純.NET完成的加殼工具仍是很少。加殼的辦法許多,咱們這兒以常見的保管壓縮殼為例進(jìn)行解說。
  為了探究其壓縮原理,咱們先創(chuàng)立一段代碼用于試驗(yàn)。
  用于加殼程序源碼:
  class Program?
{?
static void Main(string[] args)?
{?
DoSth();?
}?
public static void DoSth()?
{?
}?
}
  代碼終究生成ForCompress.exe文件。運(yùn)用Reflector檢查其IL代碼,。
  Main辦法的IL代碼
?.method private hidebysig static void Main(string[] args) cil managed
  {
  .entrypoint
  .maxstack 8
  L_0000: nop
  L_0001: call void ForCompress.Program::DoSth()
  L_0006: nop
  L_0007: ret
  }
  此刻,ForCompress.exe在Reflector中結(jié)果如圖1所示。
  
   ForCompress.exe的構(gòu)造
  
  下面咱們發(fā)動一款.NET壓縮工具,NETZ來對ForCompress.exe進(jìn)行加殼。加殼以后,咱們再次發(fā)動Reflector來檢查加殼的文件。如圖2所示。
  
   加殼以后的ForCompress.exe文件
  比照圖1和圖2,咱們發(fā)現(xiàn)稱號空間ForCompress變成了netz,類Progress變成了NetzStartter。程序集多多了個(gè)資本文件app.resources。下面咱們打開NetzStartter類,來檢查其下的辦法。如圖3所示。
  
  圖3 NetzStartter類的辦法
  從圖3中咱們能夠看出,NetzStartter類界說了一系列咱們"不認(rèn)識"的辦法,可是卻沒有代碼的DoSth辦法。下面咱們來剖析一下加殼以后的exe文件的發(fā)動進(jìn)程。
  首要定位到Main辦法,檢查其源代碼,如代碼清單9-16所示。
  代碼清單9-16 NetzStartter類的Main辦法
  [STAThread]
  public static int Main(string[] args)
  {
  try
  {
  InitXR();
  AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(NetzStarter.NetzResolveEventHandler);
  return StartApp(args);
  }
  catch (Exception exception)
  {
  string str = " .NET Runtime: ";
  Log(string.Concat(new object[] { "#Error: ", exception.GetType().ToString(), Environment.NewLine, exception.Message, Environment.NewLine, exception.StackTrace, Environment.NewLine, exception.InnerException, Environment.NewLine, "Using", str, Environment.Version.ToString(), Environment.NewLine, "Created with", str, "2.0.50727.4927" }));
  return -1;
  }
  }
  代碼清單9-16中的Main辦法中,首要調(diào)用了InitXR辦法,然后為AppDomain.CurrentDomain.AssemblyResolve事情添加處置辦法,最終調(diào)用StartApp辦法。咱們首要看看InitXR辦法做了些啥事情。InitXR辦法源碼如代碼清單9-17所示。
  代碼清單9-17 InitXR辦法源碼
  private static void InitXR()
  {
  try
  {
  string str = @"file:\";
  string str2 = "-netz.resources";
  string directoryName = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
  if (directoryName.StartsWith(str))
  {
  directoryName = directoryName.Substring(str.Length, directoryName.Length - str.Length);
  }
  string[] files = Directory.GetFiles(directoryName, "*" + str2);
  if ((files != null) && (files.Length > 0))
  {
  xrRm = new ArrayList();
  for (int i = 0; i < files.Length; i++)
  {
  string fileName = Path.GetFileName(files[i]);
  ResourceManager manager = ResourceManager.CreateFileBasedResourceManager(fileName.Substring(0, fileName.Length - str2.Length) + "-netz", directoryName, null);
  if (manager != null)
  {
  xrRm.Add(manager);
  }
  }
  }
  }
  catch
  {
  }
  }
  代碼清單9-17的代碼很明晰,在特定的文件途徑中搜索資本文件,然后添加到全局變量xrRm中。
  Main辦法中的AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(NetzStarter.NetzResolveEventHandler)一句代碼也無需多言,僅僅指定程序集解析失敗時(shí)的事情處置。
  如今咱們看StartApp辦法的源碼,如代碼清單9-18所示。
  代碼清單9-18 StartApp辦法源碼
  public static int StartApp(string[] args)
  {
  byte[] resource = GetResource("A6C24BF5-3690-4982-887E-11E1B159B249");
  if (resource == null)
  {
  throw new Exception("application data cannot be found");
  }
  int num = InvokeApp(GetAssembly(resource), args);
  resource = null;
  return num;
  }
  StartApp辦法,從姓名上看,應(yīng)該是調(diào)用被加密的源程序。在辦法體內(nèi),首要調(diào)用了GetResource辦法,回來了指定的資本,然后調(diào)用InvokeApp辦法進(jìn)入主程序。為了弄清楚來龍去脈,咱們先看看GetResource辦法終究做了啥?代碼清單9-19是GetResource辦法的源碼。
  代碼清單9-19 GetResource辦法源碼
  private static byte[] GetResource(string id)
  {
  byte[] buffer = null;
  if (rm == null)
  {
  rm = new ResourceManager("app", Assembly.GetExecutingAssembly());
  }
  try
  {
  inResourceResolveFlag = true;
  string name = MangleDllName(id);
  if ((buffer == null) && (xrRm != null))
  {
  for (int i = 0; i < xrRm.Count; i++)
  {
  try
  {
  ResourceManager manager = (ResourceManager) xrRm[i];
  if (manager != null)
  {
  buffer = (byte[]) manager.GetObject(name);
  }
  }
  catch
  {
  }
  if (buffer != null)
  {
  break;
  }
  }
  }
  if (buffer == null)
  {
  buffer = (byte[]) rm.GetObject(name);
  }
  }
  finally
  {
  inResourceResolveFlag = false;
  }
  return buffer;
  }
  如今咱們對代碼清單9-19的代碼做扼要的剖析。
  if (rm == null)
  {
  rm = new ResourceManager("app", Assembly.GetExecutingAssembly());
  }
  上面這句代碼從當(dāng)時(shí)程序會集獲取稱號為app的資本文件,回到圖9-20,咱們能夠看到app. Resources文件是內(nèi)嵌在程序會集的,能夠被獲取。接下來的代碼獲取指定稱號的資本,然后以byte數(shù)組的方式回來。回來的資本的用處是啥呢?咱們持續(xù)剖析。
  InvokeApp(GetAssembly(resource), args);
  上面是StartApp辦法最終的調(diào)用,GetAssembly辦法,從姓名上看是獲取程序集,其參數(shù)是GetResource辦法回來的byte數(shù)組。咱們到它的源碼中一探終究。GetAssembly辦法的源碼如代碼清單9-20所示。
  代碼清單9-20 GetAssembly辦法源碼
  private static Assembly GetAssembly(byte[] data)
  {
  MemoryStream stream = null;
  Assembly assembly = null;
  try
  {
  stream = UnZip(data);
  stream.Seek(0L, SeekOrigin.Begin);
  assembly = Assembly.Load(stream.ToArray());
  }
  finally
  {
  if (stream != null)
  {
  stream.Close();
  }
  stream = null;
  }
  return assembly;
  }
  代碼清單9-20的代碼也很簡單,從byte數(shù)組轉(zhuǎn)化到程序集。這兒咱們唯一需求留意的當(dāng)?shù)厥窍旅孢@句代碼:
  stream = UnZip(data);
  UnZip辦法對byte數(shù)組進(jìn)行解壓縮。這個(gè)辦法是整個(gè)程序運(yùn)轉(zhuǎn)的最要害的辦法,可是解壓縮的詳細(xì)完成咱們不去重視。如果您感興趣的話能夠自行研討。
  得到程序集以后,才真實(shí)的開端履行InvokeApp辦法,咱們看代碼清單9-21。
  代碼清單9-21 InvokeApp源碼
  private static int InvokeApp(Assembly assembly, string[] args)
  {
  MethodInfo entryPoint = assembly.EntryPoint;
  ParameterInfo[] parameters = entryPoint.GetParameters();
  object[] objArray = null;
  if ((parameters != null) && (parameters.Length > 0))
  {
  objArray = new object[] { args };
  }
  object obj2 = entryPoint.Invoke(null, objArray);
  if ((obj2 != null) && (obj2 is int))
  {
  return (int) obj2;
  }
  return 0;
  }
  從代碼清單9-21中咱們看到,這段代碼首要獲取程序集的入口函數(shù),也即是Main辦法,然后履行。到這兒,程序才真實(shí)的從外殼程序轉(zhuǎn)到真實(shí)的主程序。
  結(jié)合上面的剖析,咱們總結(jié)一下一個(gè)純.NET壓縮殼程序的運(yùn)轉(zhuǎn)流程:
  1) 程序運(yùn)轉(zhuǎn)時(shí)首要運(yùn)轉(zhuǎn)外殼程序。
  2) 外殼程序從其資本中讀取主程序的原始數(shù)據(jù)。
  3) 對原始數(shù)據(jù)解壓縮,轉(zhuǎn)化成程序集。
  4) 運(yùn)轉(zhuǎn)主程序。
  這種加殼辦法的兩個(gè)要害點(diǎn),一個(gè)是主程序作為殼程序的資本文件存在,第二個(gè)是先對資本文件解密然后再反射履行。


轉(zhuǎn)載于:https://blog.51cto.com/smallant/1541058

創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎勵(lì)來咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎

總結(jié)

以上是生活随笔為你收集整理的.NET程序加壳的基本原理和方式浅析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。