1364847132 发表于 2024-1-10 14:17

Linux下修改Wine运行的PE的内存

众~~~所周知,Wine是个好东西,Linux系统可以用它跑Windows程序。它通过实现一系列的Windows API,将Windows PE (可执行和可载入文件格式)转换为Linux操作系统可以理解的格式。让Windows应用在Linux上找到家的感觉。

再众~~~所周知,Linux下有个有趣的特性——“一切皆文件”。这意味着能在/proc/{pid}/maps里一窥进程的内存分布,还能在/proc/{pid}/mem里随心所欲的“画饼”。理论成立,开始实践。

实践只是为了验证前面的猜想,当然得挑个软柿子捏,于是就找到了一个快20年前的老游戏:“XXX大作战”。



操作第一步,探个究竟,Wine是否真把PE内存镜像本本原原地摆放好了。

通过命令ps -e | grep -i MONE,锁定目标进程PID为17551。



接着,cat /proc/17551/maps | grep exe揭秘了内存布局,果然跟Windows如出一辙,PE文件映射从0x00400000起点开始。



这时就能来点wirte和read操作,悄悄摸进/proc/{pid}/mem修改内存,居然比Windows还要简单。

首先是捕捉游戏进程的PID,一段轮子代码搞定。
int findPid(string processName) {
    FILE *fp;
    char path;
    fp = popen("ps -ef", "r");
    if (fp == nullptr) {
      printf("Failed to run command\n");
      exit(1);
    }
    while (fgets(path, sizeof(path) - 1, fp) != nullptr) {
      if (::strstr(path, processName.c_str()) != nullptr) {
            ::strtok(path, " ");
            auto token = ::strtok(nullptr, " ");
            return stoi(token);
      }
    }
    pclose(fp);
    return -1;
}
接下来,打开对应的mem文件,妙哉,这文件描述符就相当于是Windows的句柄。
int openMem(int pid) {
    char mem_filename;
    sprintf(mem_filename, "/proc/%d/mem", pid);
    return open(mem_filename, O_RDWR);
}
后续两个模板函数分别操控读写内存。
template<class T>
T readMem(long address, int mem_file) {
    T a;
    if (lseek(mem_file, address, SEEK_SET) == -1) {
      ::printf("lseek error %s \n", strerror(errno));
    }
    read(mem_file, &a, sizeof(T));
    return a;
}

template<class T>
void writeMem(long address, T value, int mem_file) {
    if (lseek(mem_file, address, SEEK_SET) == -1) {
      ::printf("lseek error %s \n", strerror(errno));
    }
    write(mem_file, &value, sizeof(T));
}

该有的都有了,最后把它们组合起来,验证一下功能。
#include <string>
#include <cstring>
#include <fcntl.h>
#include <atomic>

const unsigned int num_current_offset = 0x268c; // 当前收集的数量
const unsigned int kind_current_offset = 0x2690; // 当前收集的种类
const unsigned int isShot_current_offset = 0x2680; // 是否可以释放

using namespace std;

int findPid(string processName) {
    FILE *fp;
    char path;
    fp = popen("ps -ef", "r");
    if (fp == nullptr) {
      printf("Failed to run command\n");
      exit(1);
    }
    while (fgets(path, sizeof(path) - 1, fp) != nullptr) {
      if (::strstr(path, processName.c_str()) != nullptr) {
            ::strtok(path, " ");
            auto token = ::strtok(nullptr, " ");
            return stoi(token);
      }
    }
    pclose(fp);
    return -1;
}

int openMem(int pid) {
    char mem_filename;
    sprintf(mem_filename, "/proc/%d/mem", pid);
    return open(mem_filename, O_RDWR);
}

template<class T>
T readMem(long address, int mem_file) {
    T a;
    if (lseek(mem_file, address, SEEK_SET) == -1) {
      ::printf("lseek error %s \n", strerror(errno));
    }
    read(mem_file, &a, sizeof(T));
    return a;
}

template<class T>
void writeMem(long address, T value, int mem_file) {
    if (lseek(mem_file, address, SEEK_SET) == -1) {
      ::printf("lseek error %s \n", strerror(errno));
    }
    write(mem_file, &value, sizeof(T));
}

int main() {
    int pid = findPid("MONE~OUQ.EXE");
    if (pid == -1)
      return -1;
    int mem_file = openMem(pid);
    long address = 0x484a3c;
    auto class_address = readMem<unsigned int>(address, mem_file);
    while (true) {
      writeMem<int>(class_address + num_current_offset, 2, mem_file);
      writeMem<unsigned char>(class_address + kind_current_offset, 21, mem_file);
      writeMem<unsigned char>(class_address + isShot_current_offset, 1, mem_file);
      sleep(1);
    }
    return 0;
}
最后就是效果图啦

ps:因为不是用windows api OpenProcess、ReadProcessMemory、WriteProcessMemory,不知道windows下传统防内存修改方法能不能防得住。

1364847132 发表于 2024-1-10 15:05

可坏 发表于 2024-1-10 14:56
exe是怎么在linux下运行的呀

Wine (“Wine Is Not an Emulator” 的首字母缩写)是一个能够在多种 POSIX-compliant 操作系统(诸如 Linux,macOS 及 BSD 等)上运行 Windows 应用的兼容层。Wine 不是像虚拟机或者模拟器一样模仿内部的 Windows 逻辑,而是將 Windows API 调用翻译成为动态的 POSIX 调用,免除了性能和其他一些行为的内存占用,让你能够干净地集合 Windows 应用到你的桌面。

https://www.winehq.org/

hk137 发表于 2024-1-10 14:42

666 , 收藏了 感谢分享

ciker_li 发表于 2024-1-10 14:46

学习学习

可坏 发表于 2024-1-10 14:56

exe是怎么在linux下运行的呀

mornstar52 发表于 2024-1-10 16:08

Interesting

JuncoJet 发表于 2024-1-10 16:35

大多数依赖显卡的游戏wine都跑不起来:lol

iamok 发表于 2024-1-10 17:07

JuncoJet 发表于 2024-1-10 16:35
大多数依赖显卡的游戏wine都跑不起来

看看现在arm mac上好多游戏还是跑得很好的。

andyle 发表于 2024-1-10 18:26

这个 有点高端

雨卷倾城3236 发表于 2024-1-10 18:56

感谢分享,可能还是硬件要好一些,下载来试用跑不动
页: [1] 2 3
查看完整版本: Linux下修改Wine运行的PE的内存