• C# 简单内存补丁


    写在开头:看了一些视频教程,感觉OD为什么别人学个破解那么容易,我就那么难了呢,可能是没有那么多时间吧。

    解释:个人见解:所谓内存补丁,即:通过修改运行程序的内容,来达到某种目的的操作。修改使用OpenProcess打开,WriteProcessMemory写入,CloseHandle关闭。部分需要读取数据判断使用:ReadProcessMemory

    0x1 看教程

      关于有的学习教程,确实要看看视频才能了解别人的操作,或者很简单一个东西,如果没有别人的指导那么自己操作确实不太容易。

    0x2 学习到部分概念

      肯定不可能一味的模仿,做一样的东西,所以需要学以致用就很关键了。于是乎,用vs2013 c++写了几行代码,用于自己测试,用C#写内存补丁

    0x3 网上检索

      没有人生而知之,所以网上查询也是很关键的一步,查询哪些内容呢?就是查询C#如何写内存补丁,代码大同小异不过不一定能用。

    0x4 代码实践

      网上找到的代码也是要在实践中得出能否使用的。所以这一步也是必不可免的。

    于是乎有了下面的代码。需要使用OD找到代码的位置即和在内存中和代码的相差位置。

    MCF程序  C++ OK方法中

    void CMFCTestDlg::OnBnClickedOk()
    {
        CString str;
        GetDlgItemText(IDC_EDIT1, str);
    
        if (str == "test123456789"){
            ::MessageBox(NULL, L"OK", L"提示", 0);
        }
        else{
            ::MessageBox(NULL, L"Fail", L"提示", 0);
        }
    }
    View Code

    C#程序中调用,首先贴一个帮助类,来源网上。当然对其中添加和修改了部分方法。

    public abstract class ApiHelper
        {
            [DllImportAttribute("kernel32.dll", EntryPoint = "ReadProcessMemory")]
            public static extern bool ReadProcessMemory
                (
                    IntPtr hProcess,
                    IntPtr lpBaseAddress,
                    IntPtr lpBuffer,
                    int nSize,
                    IntPtr lpNumberOfBytesRead
                );
    
            [DllImportAttribute("kernel32.dll", EntryPoint = "OpenProcess")]
            public static extern IntPtr OpenProcess
                (
                    int dwDesiredAccess,
                    bool bInheritHandle,
                    int dwProcessId
                );
    
            [DllImport("kernel32.dll")]
            private static extern void CloseHandle
                (
                    IntPtr hObject
                );
    
            //写内存
            [DllImportAttribute("kernel32.dll", EntryPoint = "WriteProcessMemory")]
            public static extern bool WriteProcessMemory
            (
                IntPtr hProcess,
                IntPtr lpBaseAddress,
                int[] lpBuffer,
                int nSize,
                IntPtr lpNumberOfBytesWritten
            );
    
            //获取窗体的进程标识ID
            public static int GetPid(string windowTitle)
            {
                int rs = 0;
                Process[] arrayProcess = Process.GetProcesses();
                foreach (Process p in arrayProcess)
                {
                    if (p.MainWindowTitle.IndexOf(windowTitle) != -1)
                    {
                        rs = p.Id;
                        break;
                    }
                }
    
                return rs;
            }
    
            //根据进程名获取PID
            public static int GetPidByProcessName(string processName, ref IntPtr baseAddress)
            {
                Process[] arrayProcess = Process.GetProcessesByName(processName);
                foreach (Process p in arrayProcess)
                {
                    baseAddress = p.MainModule.BaseAddress;
                    return p.Id;
                }
    
                return 0;
            }
    
            //根据进程名获取PID
            public static int GetPidByProcessName(string processName)
            {
                Process[] arrayProcess = Process.GetProcessesByName(processName);
                foreach (Process p in arrayProcess)
                {
                    return p.Id;
                }
    
                return 0;
            }
    
            //根据窗体标题查找窗口句柄(支持模糊匹配)
            public static IntPtr FindWindow(string title)
            {
                Process[] ps = Process.GetProcesses();
                foreach (Process p in ps)
                {
                    if (p.MainWindowTitle.IndexOf(title) != -1)
                    {
                        return p.MainWindowHandle;
                    }
                }
                return IntPtr.Zero;
            }
    
            //读取内存中的值
            public static int ReadMemoryValue(int baseAddress, string processName)
            {
                try
                {
                    byte[] buffer = new byte[2];
                    IntPtr byteAddress = Marshal.UnsafeAddrOfPinnedArrayElement(buffer, 0); //获取缓冲区地址
                    IntPtr hProcess = OpenProcess(0x1F0FFF, false, GetPidByProcessName(processName));
                    ReadProcessMemory(hProcess, (IntPtr)baseAddress, byteAddress, buffer.Length, IntPtr.Zero); //将制定内存中的值读入缓冲区
                    CloseHandle(hProcess);
                    return Marshal.ReadInt32(byteAddress);
                }
                catch
                {
                    return 0;
                }
            }
    
            //将值写入指定内存地址中
            public static bool WriteMemoryValue(int baseAddress, string processName, int[] value)
            {
                IntPtr hProcess = OpenProcess(0x1F0FFF, false, GetPidByProcessName(processName)); //0x1F0FFF 最高权限
                bool result = WriteProcessMemory(hProcess, (IntPtr)baseAddress, value, value.Length, IntPtr.Zero);
                CloseHandle(hProcess);
    
                return result;
            }
        }
    View Code

    最后是在具体按钮中的调用了。

    private string processName = "MFCTest"; //
    
            private void button1_Click(object sender, EventArgs e)
            {
                IntPtr startAddress = IntPtr.Zero;
                int pid = ApiHelper.GetPidByProcessName(processName, ref startAddress);
                if (pid == 0)
                {
                    MessageBox.Show("哥们启用之前该运行吧!");
                    return;
                }
    
                int baseAddress = startAddress.ToInt32() + 0x1000;
                int value = ReadMemoryValue(baseAddress);             // 读取基址(该地址不会改变)
                int address = baseAddress + 0x14F3;                   // 获取2级地址
                value = ReadMemoryValue(address);
                bool result = WriteMemory(address, new int[] { 144 });
                address = address + 0x1;
                result = WriteMemory(address, new int[] { 144 });
    
                MessageBox.Show(result ? "成功" : "失败");
            }
    
    
            //读取制定内存中的值
            public int ReadMemoryValue(int baseAdd)
            {
                return ApiHelper.ReadMemoryValue(baseAdd, processName);
            }
    
            //将值写入指定内存中
            public bool WriteMemory(int baseAdd, int[] value)
            {
                return ApiHelper.WriteMemoryValue(baseAdd, processName, value);
            }
    View Code

    0x5 总结

      只有不断学习才能知道新的知识,同时在学习中进步。很多不懂的概念其实很简单。当然前提是你明白以后。

       其中注意一点。

    测试代码下载:WriteProcessMemory的buffer填入一个数组也是可以的。需要计算长度。然后nSize就是,前面的数组作为几个字节进行使用。

    // 重构了些许代码
    
    
            //将值写入指定内存地址中
            public static bool WriteMemoryValue(int baseAddress, string processName, int[] value, int len)
            {
                IntPtr hProcess = OpenProcess(0x1F0FFF, false, GetPidByProcessName(processName)); //0x1F0FFF 最高权限
                bool result = WriteProcessMemory(hProcess, (IntPtr)baseAddress, value, len, IntPtr.Zero);
                CloseHandle(hProcess);
    
                return result;
            }
    
    // 144=0x90  表示 nop
    bool result = ApiHelper.WriteMemoryValue(address, processName, new int[] { 144 + 144 * 256 }, 2);

     WinTestRe.zip

  • 相关阅读:
    并查集N(The Suspects)
    (并查集)Ubiquitous Religions
    (并查集)How Many Tables
    并查集(畅通工程)
    约瑟夫环(栈和队列)
    队列-排队买饭
    栈的基本操作
    双向队列
    括号匹配
    Queue
  • 原文地址:https://www.cnblogs.com/Supperlitt/p/6714111.html
Copyright © 2020-2023  润新知