.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 这个类可以帮助你获取控件对象

相关推荐
AI行业学习11 小时前
.NET Framework 3.5 SP1 完整离线包【2026.5.31】
.net
学以智用16 小时前
.NET Core 完整特性速查表(终极版)
后端·.net
cdbqss118 小时前
VB2026 动态生成工具栏类 BqGetToolStrip
数据库·oracle·开源·.net·学习方法·教育电商·basic
周杰伦fans18 小时前
掌握 MVVM Light:.NET 桌面应用开发的 MVVM 利器,掌握 ObservableObject、RelayCommand 和 Messenger
c#·wpf
宝桥南山18 小时前
Microsoft Agent Framework(MAF) - 如何将workflow或者A2A client转换成一个AI Agent
microsoft·ai·微软·aigc·.net·.netcore
Ws_19 小时前
WPF 面试题 + 参考答案,偏 C# 桌面端开发高频。
开发语言·c#·wpf
LCG元1 天前
现代Web应用高可用架构设计与性能调优实战
前端·wpf
小二·2 天前
向量数据库深度对比:PGVector vs Qdrant vs Milvus vs Chroma(附性能测试数据)
数据库·wpf·milvus
三天不学习2 天前
YOLO + .NET 10 快速入门:从零搭建实时目标检测应用
yolo·目标检测·.net
0x00073 天前
译 Anders Hejlsberg 谈 C# 与 .NET
开发语言·c#·.net