liwj 发表于 2023-10-12 03:46

学习记录-用C语言写补丁

// ConsoleApplication_GetBaseAddress.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"

#include<stdio.h>
#include<windows.h>
#include<psapi.h>
#include<direct.h>
#include <string.h>

int _tmain(int argc, _TCHAR* argv[])
{
        //获取当前目录
        char path;
        getcwd(path, 100);
        //printf("current work path:%s\n", path);
        char *zifu = getcwd(path, 100);
        //printf("current work path:%s\n", zifu);
        char *zifu2 = "\\MindMaster.exe";//修改该值即可
        char *zifu3 = strcat(zifu, zifu2);
        printf("启动MindMaster:%s\n", zifu3);
        //运行外部的程序
        WinExec(zifu3, SW_SHOW);
        //延时
        int a;
        a = 15000;
        Sleep(a);
        //获取窗口句柄
        HWND hWnd = FindWindow(NULL, "MindMaster");
        if (hWnd == NULL){        //如果无法获取句柄则报错
                printf("无法获取窗口句柄,请检查进程是否存在!\n");
                system("pause");
                return -1;
        }
        DWORD pro_id;
        GetWindowThreadProcessId(hWnd, &pro_id);        //获取进程ID
        if (pro_id == 0){
                printf("无法获取进程ID\n");
                system("pause");
                return 0;
        }
        printf("进程id: %d\n", pro_id);

        HANDLE hpro = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ, FALSE, pro_id);
        if (hpro == 0){
                printf("无法获取进程句柄");
        }
        printf("进程句柄id: %d\n", hpro);

        // 获取每一个模块加载基址
        DWORD pro_base = NULL;
        DWORD prodll_base = NULL;
        HMODULE hModule = { 0 };
        DWORD dwRet = 0;
        int num = 0;
        int bRet = EnumProcessModulesEx(hpro, (HMODULE *)(hModule), sizeof(hModule), &dwRet, NULL);
        if (bRet == 0){
                printf("EnumProcessModules");
        }

        // 总模块个数
        num = dwRet / sizeof(HMODULE);
        printf("总模块个数: %d\n", num);

        // 打印每一个模块加载基址
        char lpBaseName;
        for (int i = 0; i < num; i++){
                GetModuleBaseNameA(hpro, hModule, lpBaseName, sizeof(lpBaseName));
                printf("%-2d %-25s基址: 0x%p\n", i, lpBaseName, hModule);
        }

        pro_base = (DWORD)hModule; prodll_base = (DWORD)hModule;
        printf("程序基址: 0x%p\n", pro_base); printf("objectmodule基址: 0x%p\n", prodll_base);
/////////////////////////////////////////////////////////////////////////////
        DWORD tounaofenbao = pro_base + 0x78eb95;
        printf("头脑风暴基地址: 0x%p\n", tounaofenbao);
        //ReadProcessMemory(hpro, (PVOID)tounaofenbao, &tounaofenbao, 4, 0); 为什么注释掉,因为把eb95的值7C 79 FA 83 转换成了地址
        //tounaofenbao = tounaofenbao + 0x0;
        DWORD Tnfb_value = 2088368771;//OD显示的二进制顺序是 83 FA 79 7C 在换算的时候要倒着念 7C 79 FA 83 把7C 79 FA 83换成十进制就得到2088368771
        WriteProcessMemory(hpro, (LPVOID)tounaofenbao, &Tnfb_value, 4, 0);//是修改成功了 但程序确自动退出了 找到原因了 加上7C后就正确了 保持4个字节
        //甘特图
        DWORD gantetu = pro_base + 0x6122E1;
        printf("甘特图基地址: 0x%p\n", gantetu);
        //DWORD GTU_value = 2425393296;
        char GTU_value = {0x90,0x90,0x90,0x90,0x90,0x90};
        WriteProcessMemory(hpro, (LPVOID)gantetu, GTU_value, 6, 0);
        DWORD gantetu2 = pro_base + 0x6122E9;
        printf("甘特图基地址: 0x%p\n", gantetu2);
       
        char GTU_value2 = { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 };
        WriteProcessMemory(hpro, (LPVOID)gantetu2, GTU_value2, 6, 0);
        //主题风格
        DWORD zhutifengge = pro_base + 0x68C118;
        printf("主题风格基地址: 0x%p\n", zhutifengge);
       
        char zhutifengge_value = { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 };
        WriteProcessMemory(hpro, (LPVOID)zhutifengge, zhutifengge_value, sizeof(zhutifengge_value), 0);
DWORD zhutifengge2 = pro_base + 0x68C122;
       
        printf("主题风格基地址2: 0x%p\n", zhutifengge2);
       
        char zhutifengge_value2 = { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 };
        WriteProcessMemory(hpro, (LPVOID)zhutifengge2, zhutifengge_value2, sizeof(zhutifengge_value2), 0);
        //复制图片功能
        DWORD tup = prodll_base + 0x127B60;
        printf("复制图片功能基地址: 0x%p\n", tup);
       
        char tup_value = { 0xeb, 0x3b};
        WriteProcessMemory(hpro, (LPVOID)tup, tup_value, sizeof(tup_value), 0);

        //图标功能
        DWORD tub = pro_base + 0x706206;
        printf("图标功能基地址: 0x%p\n", tub);
       
        char tub_value = { 0x90, 0x90 };
        WriteProcessMemory(hpro, (LPVOID)tub, tub_value, sizeof(tub_value), 0);
        DWORD tub2 = pro_base + 0x70620C;
        printf("图标功能基地址: 0x%p\n", tub2);
       
        char tub2_value = { 0xeb, 0x22 };
        WriteProcessMemory(hpro, (LPVOID)tub2, tub2_value, sizeof(tub2_value), 0);

        return 0;
}

爱飞的猫 发表于 2023-10-12 07:16

本帖最后由 爱飞的猫 于 2023-10-12 07:20 编辑

1. 请使用代码框功能格式化代码
2. `prodll_base = (DWORD)hModule;` 请判断 DLL 名称,而非写死。系统更新/旧版本可能偏移就错了
* MSVC 实际上是 C++ 编译器,你可以用 `std::map<std::string, HMODULE>` 来记录模块信息或访问。
3. 使用 `CreateProcess` 并带上 `CREATE_SUSPENDED`,可以已暂停模式启动进程,补丁完后再继续主程序运行。
4. 为什么不直接用字节数组呢?相比你现在的写法并不会带来额外的性能上的开销。
5. 你可以使用数值或表达式,不需要全都先赋值到变量再使用,如 `Sleep(15'000);`。

(4) 直接使用字节数组:

```cpp
      char Tnfb_value[] = {0x83, 0xFA, 0x79}; // 如果只需要补 3 个字节,那就写 3 个字节即可。
      WriteProcessMemory(hpro, (LPVOID)tounaofenbao, Tnfb_value, sizeof(Tnfb_value), 0);//是修改成功了 但程序确自动退出了 找到原因了 加上7C后就正确了 保持4个字节
```

(2) 使用 `std::map` 储存数据

```cpp
#include <iostream>
#include <string>
#include <map>

int main()
{
    std::map<std::string, int> map1{};
    map1["abc"] = 123;
    map1["def"] = 456;
   
    std::cout << "map1: " << map1["abc"] << std::endl;
    std::cout << "map1: " << map1["def"] << std::endl;
    std::cout << "map1: " << map1["zzz"] << std::endl;
   
    /*
   * 输出:
   *   map1: 123
   *   map1: 456
   *   map1: 0
   */
}
```

王成 发表于 2023-10-12 07:47

感谢教学!

dubuqingyun 发表于 2023-10-12 07:48

谢谢分享。

yaphoo 发表于 2023-10-12 08:14

感谢分享

tlf 发表于 2023-10-12 08:37

sunnyAlvis 发表于 2023-10-12 08:47

非常不错,感谢分享

danielau 发表于 2023-10-12 08:52

楼主很强!进来学习

hiilink 发表于 2023-10-12 08:53

感谢分享,学习了。

LuckyClover 发表于 2023-10-12 08:59

爱飞的猫 发表于 2023-10-12 07:16
1. 请使用代码框功能格式化代码
2. `prodll_base = (DWORD)hModule;` 请判断 DLL 名称,而非写死 ...

大佬牛批
页: [1] 2
查看完整版本: 学习记录-用C语言写补丁