.net wpf程序 移花接木

最近在研究C# .net桌面程序。非常有趣

软件是国外作者写的 公司要求修改翻译

从最初的开源变成闭源再到加壳. 一路让我这个小小的职员好蛋疼.

软件是VS2015 C# WPF 程序 在不脱壳的情况下 实现挂钩类托管函数 遍历WPF控件汉化

首先通过各种手段脱壳目标程序,哪怕是不能运行都没关系。只要找到程序main函数。,找到Main的命名空间,然后自己创建一个一样的WPF程序 和他的命名空间一样就可以

这里我的目标程序命名空间是 MainApp

生成以后把文件后缀改成DLL

之后我们创建一个 C# winform 程序删除程序中默认的对话框 添加引用上面生成的文件

因为目标程序是WPF 程序 所以还得添加默认程序集

WindowsBase 和 PresentationFramework

下面开始写代码

|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | using HookDetour; using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Threading.Tasks; using System.Windows.Forms; namespace Load { ``//``这里是一个开源的hook库 根据名字自己google ``class hookClass : IMethodMonitor ``{ ``[MethodImpl(MethodImplOptions.NoInlining)] ``[Monitor(``"System.Windows"``, ``"Application"``)] ``//``目标方法的名称空间,类名 ``public static void LoadComponent(Uri resourceLocator,bool b) ``{ ``Console.WriteLine(resourceLocator); ``//mainwindow``.baml ``var uri = new System.Uri(@``"pack://application:,,,/MainApp;component/MainWindow.xaml"``); ``old_LoadComponent(uri, b); ``} ``[MethodImpl(MethodImplOptions.NoInlining)] ``[Original] ``//``原函数标记 ``public static void old_LoadComponent(Uri resourceLocator, bool b) ``{ ``Console.WriteLine(``"null"``); ``} ``} ``static class Program ``{ ``static MainApp.App pMainApp; ``private static void AppRun(object sender, object args) ``{ ``//``在这里开始干坏事 ``Console.WriteLine(``"程序已经启动"``); ``} ``[STAThread] ``static void Main() ``{ ``//``建立目标程序导出的类 储存起来,方便找对应方法和变量 ``pMainApp = new MainApp.App(); ``//``需要程序托管之类的操作需要初始化以后才能干,这里监听 Startup ``pMainApp.Startup += new System.Windows.StartupEventHandler(AppRun); ``//``部分.net 程序查找不到自身目录资源,需要HOOK添加空间名 ``//``这个HOOK 不一定需要,有些程序加壳以后会自行修复这个问题, ``//hook LoadComponent 这个函数 ``hookClass hk = new hookClass(); ``var hookfun = hk.GetType().GetMethod(``"LoadComponent"``); ``var hookori = hk.GetType().GetMethod(``"old_LoadComponent"``); ``//``通过 MainApp.App 得到父类 ,根据父类查找 LoadComponent函数 ``MethodInfo LoadComponentFunction = pMainApp.GetType().BaseType.GetMethod(``"LoadComponent"``, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static, System.Type.DefaultBinder, new Type[] { typeof(Uri),typeof(bool) },null); ``IDetour engine = DetourFactory.CreateDetourEngine(); ``engine.Patch(LoadComponentFunction, hookfun, hookori); ``pMainApp.InitializeComponent(); ``pMainApp.Run(); ``} ``} } |

到了这里程序已经启动好了。把目标程序启动了以后 程序进程看见的就是自己的进程,

运行内容就是目标程序内容

然后根据反射调用和获取目标程序的函数和变量

这里需要注意的是有些.net壳会导致无法 Assembly.LoadFrom 失败,

但是你编写的程序是VS已经帮你加载到程序里面了。所以可以通过遍历获取到Assembly

目标程序包含的程序集也可以通过这个方式查找,然后根据Assembly获取对应类的函数

|----------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | //``这里节省资源,我就把Assembly储存起来了 public static Assembly GetAssembly() { ``if (m_MainAppAssembly == null) ``{ ``foreach (Assembly ay ``in AppDomain.CurrentDomain.GetAssemblies()) ``{ ``if (ay.FullName.IndexOf(``"AppMain"``) > -1) ``{ ``m_CatchemAssembly = ay; ``break``; ``} ``} ``} ``return m_MainAppAssembly ; } |

获取到Assembly 基本上你可以控制整个程序的流程了

//根据Assembly得到MianApp.MainWindow类 然后在类里找到 GlobalValue 变量
Assembly amy = GetAssembly();
var GlobalValue = amy.GetType("MianApp.MainWindow").GetField("GlobalValue");
//得到变量内容,参数是对应的对象
GlobalValue.GetValue(null);
//设置变量内容
GlobalValue.SetValue(null, "GGGG");

剩下的就是挂钩了 当然建议你还是使用第三方的库

pMainApp.GetType().GetMethod("LoadComponent").MethodHandle.GetFunctionPointer();

这样就可以获取 LoadComponent 的函数地址, 如果你不知道目标类有什么函数的话可以通过

GetMethods 来获取到,记得查看参数BindingFlags 选项,这个选项可以影响到你获取的结果

如果函数名有相同的 需要自己定义参数类型获取,不然会抛异常

这里值得注意的是 GetFunctionPointer 函数不一定就能返回正确的结果,在加壳的程序里

你有可能获取的地址是错误的,因为程序没执行过这个函数。所以你可以选择等待程序调用过

这个函数你再去挂钩,或者自己手动调用一次,随便传入参数。捕获一下异常,然后再挂钩。

遍历WPF控件 获取到主窗口对象然后 VisualTreeHelper 这个类可以帮助你获取控件对象

相关推荐
CodeCraft Studio37 分钟前
【实用技能】使用 TX Text Control 创建带有嵌入式附件的 PDF 文档
pdf·asp.net·.net
djk88883 小时前
.net6.0(.net Core)读取 appsettings.json 配置文件
json·.net·.netcore
喵叔哟6 小时前
16. 【.NET 8 实战--孢子记账--从单体到微服务】--汇率获取定时器
微服务·oracle·.net
当下就是最好10 小时前
WPF应用程序的生命周期-笔记
wpf
zhy81030212 小时前
.net6 使用 FreeSpire.XLS 实现 excel 转 pdf - docker 部署
pdf·.net·excel
初九之潜龙勿用12 小时前
C#校验画布签名图片是否为空白
开发语言·ui·c#·.net
慧都小妮子13 小时前
Spire.PDF for .NET【页面设置】演示:打开 PDF 时自动显示书签或缩略图
java·pdf·.net
霍先生的虚拟宇宙网络15 小时前
.net 支持跨平台(桌面)系列技术汇总
.net
djk888815 小时前
.net的winfrom程序 窗体透明&打开窗体时出现在屏幕右上角
.net
九鼎科技-Leo1 天前
什么是 WPF 中的依赖属性?有什么作用?
windows·c#·.net·wpf