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

相关推荐
光泽雨2 小时前
WPF中的依赖属性
wpf
海马3 小时前
Spring Cloud 开发知识整理
spring·spring cloud·wpf
闻哥3 小时前
分布式任务调度框架:XXL-Job / ElasticJob / DolphinScheduler / SchedulerX 架构对比与选型
分布式·架构·wpf
波力海苔夹心脆67513 小时前
C# 机器视觉实战:单相机引导机械手精准贴合,从拍照、偏差计算(平移+旋转)到坐标补偿全解
开发语言·经验分享·数码相机·c#·视觉检测·.net
慧都小妮子13 小时前
Stimulsoft 2026.4 发布:Markdown 组件、桑基图与 .NET 11 支持
.net·数据可视化·stimulsoft·版本更新·报表控件·桑基图·.net 11
预立科技16 小时前
CDN(内容分发网络)知识总结
网络·wpf·cdn
波力海苔夹心脆6751 天前
C# 视觉检测实战:PLC 按钮触发 VisionPro 检测,OK 亮灯 / NG 灭灯(西门子 PLC,含界面显示与图片存档)
开发语言·经验分享·c#·自动化·视觉检测·.net
hez20102 天前
一行代码在 .NET 项目里启用 Satori GC
c#·.net·.net core·gc·clr
FuckPatience2 天前
WPF DataGrid 行根据某个属性循环变色动画
wpf
QUDONG_biubiubiu2 天前
.NET Runtime 6.0/7.0/8.0/9.0下载修复教程,软件打不开这样解决
.net·net runtime下载·net运行库修复·net runtime安装