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

相关推荐
明耀3 小时前
WPF RadioButton 绑定boolean值
c#·wpf
暮雪倾风4 小时前
【WPF开发】控件介绍-Grid(网格布局)
windows·wpf
一丝晨光5 小时前
Java、PHP、ASP、JSP、Kotlin、.NET、Go
java·kotlin·go·php·.net·jsp·asp
yufei-coder6 小时前
C#基础语法
开发语言·c#·.net
Mudrock__7 小时前
前后端传输文件(图片)
vue·.net
芝麻科技1 天前
使用ValueConverters扩展实现枚举控制页面的显示
wpf·prism
时光追逐者2 天前
WaterCloud:一套基于.NET 8.0 + LayUI的快速开发框架,完全开源免费!
前端·microsoft·开源·c#·.net·layui·.netcore
friklogff2 天前
【C#生态园】打造现代化跨平台应用:深度解析.NET桌面应用工具
开发语言·c#·.net
笑非不退2 天前
Wpf Image 展示方式 图片处理 显示
开发语言·javascript·wpf
@Unity打怪升级2 天前
【C#】CacheManager:高效的 .NET 缓存管理库
开发语言·后端·机器学习·缓存·c#·.net·.netcore