欢迎来到 嗅灵易学

零基础也能上手的脚本技术课,一对一答疑带你入门

[原创].net wpf程序 移花接木

[原创].net wpf程序 移花接木

最近在研究C# .net桌面程序。非常有趣
软件是国外作者写的 公司要求修改翻译
从最初的开源变成闭源再到加壳. 一路让我这个小小的职员好蛋疼.
软件是VS2015 C# WPF 程序 在不脱壳的情况下 实现挂钩类托管函数 遍历WPF控件汉化
首先通过各种手段脱壳目标程序,哪怕是不能运行都没关系。只要找到程序main函数。,找到Main的命名空间,然后自己创建一个一样的WPF程序 和他的命名空间一样就可以
这里我的目标程序命名空间是 MainApp

生成以后把文件后缀改成DLL
之后我们创建一个 C# winform 程序删除程序中默认的对话框 添加引用上面生成的文件
因为目标程序是WPF 程序 所以还得添加默认程序集
WindowsBase 和 PresentationFramework
下面开始写代码


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获取对应类的函数
        //这里节省资源,我就把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 这个类可以帮助你获取控件对象
多年不打字不吹牛逼都不会发贴了。文字描述的不好见谅

上传的附件 1.jpg

注意:上传附件及图片大小不得大于30M。

⚠️ 版权声明:
本博客所有内容(含教程、源码、工具)仅供个人技术学习与研究交流使用,严禁商用、倒卖、二次分发及非法用途
未经作者书面授权,任何组织或个人不得转载、复制或用于其他平台,违者将追究相关责任。

0 0 0 举报
复制成功