LastExceed / ExoTracker

1 stars 1 forks source link

Package fails to build #2

Open Einfachirgendwa1 opened 1 week ago

Einfachirgendwa1 commented 1 week ago

More specifically, win_mem fails to build. The last change to win_mem was approx. 4 years ago and the github repo listed on crates.io is gone (https://crates.io/crates/win_mem links to https://github.com/nevalackin/win_mem, which doesn't exist) and I couldn't find anything about it online. I don't know if and how much you still care about this project, but I'm definitly going to investigate this myself and maybe make a PR if I find a fix. Or maybe I'm just dumb and made a stupid mistake.

   Compiling autocfg v1.4.0
   Compiling proc-macro2 v1.0.89
   Compiling unicode-ident v1.0.13
   Compiling cfg-if v1.0.0
   Compiling libc v0.2.161
[...]
   Compiling win_mem v0.2.2
error[E0433]: failed to resolve: could not find `um` in `winapi`
 --> /home/[name]/.cargo/registry/src/index.crates.io-6f17d22bba15001f/win_mem-0.2.2/src/snapshot.rs:1:13
  |
1 | use winapi::um::tlhelp32::{CreateToolhelp32Snapshot, TH32CS_SNAPMODULE, TH32CS_SNAPMODULE32, TH32CS_SNAPPROCESS};
  |             ^^ could not find `um` in `winapi`

error[E0433]: failed to resolve: could not find `um` in `winapi`
 --> /home/[name]/.cargo/registry/src/index.crates.io-6f17d22bba15001f/win_mem-0.2.2/src/snapshot.rs:2:13
  |
2 | use winapi::um::winnt::HANDLE;
  |             ^^ could not find `um` in `winapi`

error[E0433]: failed to resolve: could not find `shared` in `winapi`
 --> /home/[name]/.cargo/registry/src/index.crates.io-6f17d22bba15001f/win_mem-0.2.2/src/module.rs:1:13
  |
1 | use winapi::shared::minwindef::DWORD;
  |             ^^^^^^ could not find `shared` in `winapi`

error[E0433]: failed to resolve: could not find `shared` in `winapi`
 --> /home/[name]/.cargo/registry/src/index.crates.io-6f17d22bba15001f/win_mem-0.2.2/src/process.rs:4:13
  |
4 | use winapi::shared::minwindef::{DWORD, FALSE, LPCVOID, LPVOID, TRUE};
  |             ^^^^^^ could not find `shared` in `winapi`

error[E0433]: failed to resolve: could not find `um` in `winapi`
 --> /home/[name]/.cargo/registry/src/index.crates.io-6f17d22bba15001f/win_mem-0.2.2/src/process.rs:5:13
  |
5 | use winapi::um::handleapi::INVALID_HANDLE_VALUE;
  |             ^^ could not find `um` in `winapi`

error[E0433]: failed to resolve: could not find `um` in `winapi`
 --> /home/[name]/.cargo/registry/src/index.crates.io-6f17d22bba15001f/win_mem-0.2.2/src/process.rs:6:13
  |
6 | use winapi::um::memoryapi::{ReadProcessMemory, WriteProcessMemory};
  |             ^^ could not find `um` in `winapi`

error[E0433]: failed to resolve: could not find `um` in `winapi`
 --> /home/[name]/.cargo/registry/src/index.crates.io-6f17d22bba15001f/win_mem-0.2.2/src/process.rs:7:13
  |
7 | use winapi::um::processthreadsapi::OpenProcess;
  |             ^^ could not find `um` in `winapi`

error[E0433]: failed to resolve: could not find `um` in `winapi`
 --> /home/[name]/.cargo/registry/src/index.crates.io-6f17d22bba15001f/win_mem-0.2.2/src/process.rs:8:13
  |
8 | use winapi::um::tlhelp32::{Module32FirstW, Module32NextW, MODULEENTRY32W, Process32FirstW, Process32NextW, PROCESSENTRY32W};
  |             ^^ could not find `um` in `winapi`

error[E0433]: failed to resolve: could not find `um` in `winapi`
 --> /home/[name]/.cargo/registry/src/index.crates.io-6f17d22bba15001f/win_mem-0.2.2/src/process.rs:9:13
  |
9 | use winapi::um::winnt::{HANDLE, PROCESS_ALL_ACCESS};
  |             ^^ could not find `um` in `winapi`

error[E0433]: failed to resolve: could not find `um` in `winapi`
 --> /home/[name]/.cargo/registry/src/index.crates.io-6f17d22bba15001f/win_mem-0.2.2/src/utils.rs:3:13
  |
3 | use winapi::um::handleapi::{CloseHandle, INVALID_HANDLE_VALUE};
  |             ^^ could not find `um` in `winapi`

error[E0433]: failed to resolve: could not find `um` in `winapi`
 --> /home/[name]/.cargo/registry/src/index.crates.io-6f17d22bba15001f/win_mem-0.2.2/src/utils.rs:4:13
  |
4 | use winapi::um::winnt::{HANDLE, WCHAR};
  |             ^^ could not find `um` in `winapi`

error[E0554]: `#![feature]` may not be used on the stable release channel
 --> /home/[name]/.cargo/registry/src/index.crates.io-6f17d22bba15001f/win_mem-0.2.2/src/lib.rs:1:1
  |
1 | #![feature(min_const_generics)]
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove the attribute
  |
  = help: the feature `min_const_generics` has been stable since `1.51.0` and no longer requires an attribute to enable

Some errors have detailed explanations: E0433, E0554.
For more information about an error, try `rustc --explain E0433`.
error: could not compile `win_mem` (lib) due to 12 previous errors
warning: build failed, waiting for other jobs to finish...
Einfachirgendwa1 commented 1 week ago

Oh, nvm, I'm stupid, this just only builds on windows: From https://stackoverflow.com/questions/77218919/the-compiler-cant-find-um-in-winapi:

The modules of winapi are only available if cfg(windows) is present due to its [conditional compilation](https://github.com/retep998/winapi-rs/blob/0.3.6/src/lib.rs#L7). If you target windows but write the source code on a different platform, make sure to setup cross compilation as noted by iceburg in the comment section.
LastExceed commented 1 week ago

yeah i couldnt find out how to do process memory reading cross platform, so i picked a windows-only lib for simplicity. iirc i even modified the lib locally (i seriously had no idea what i was doing), so its very well possible that this repo actually never built on windows either lol

if you're interested in this project, i could port it to windows-rs so it at least compiles on windows, but idk how to make it work on other platforms

Einfachirgendwa1 commented 4 days ago

yeah, making it cross platform would probably be a huge pain as the game only includes a native windows build, so you would have to find a way to access memory managed by proton. But tbh I have no idea why you can just access other programs memory regions without a segfault in general, I have never done something like this. I guess if you do find a way, you could just make a bunch of #[cfg(windows)] and #[cfg(not(windows))]? its also not like i actually use linux to play this game, i just like linux for programming.

btw, compiling on windows also doesnt work, because of

error[E0554]: `#![feature]` may not be used on the stable release channel
 --> /home/[name]/.cargo/registry/src/index.crates.io-6f17d22bba15001f/win_mem-0.2.2/src/lib.rs:1:1
  |
1 | #![feature(min_const_generics)]
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove the attribute
  |
  = help: the feature `min_const_generics` has been stable since `1.51.0` and no longer requires an attribute to enable

You could probably just cargo vendor and then just remove that attribute, but that seems like a very temporary solution

LastExceed commented 4 days ago

I have no idea why you can just access other programs memory regions without a segfault in general

A direct memory access in the form of a deref would indeed segfault. what im doing ultimately boils down to this function from the Windows API, so I'd need something similar for each platform. Given that even CheatEngine works under wine, its certainly possible, I'm just lacking the necessary know-how

cargo vendor

nah, if i'm gonna fix it, then i'd do it properly and get rid of the win-mem dependency entirely. And looking at the code now I might as well just rewrite the whole thing. I don't even know what modifications I made to win-mem back then, and figuring that out would likely be just as much effort

Einfachirgendwa1 commented 4 days ago

Given that even CheatEngine works under wine, its certainly possible

Really? That's cool, I didn't know that.

Do you think something like this might work or are there problems with vram?

fn read_process_memory(pid: u64, address: u64, size: usize) -> Vec<u8> {
    let mut mem_file = File::open(&format!("/proc/{pid}/mem")).unwrap();

    mem_file.seek(SeekFrom::Start(address)).unwrap();
    let mut buf = vec![0; size];
    mem_file.read(&mut buf).unwrap();

    buf
}

I might as well just rewrite the whole thing

Good luck!

LastExceed commented 4 days ago

no idea, i'm not that familiar with other platforms. but thats not even the issue. the hard part is finding the concrete addresses, since the pointer is relative to UnityPlayer.dll

Einfachirgendwa1 commented 4 days ago

This should find the dll:

use std::{fs::File, io::Read};

use sysinfo::System;

fn main() {
    for (pid, proc) in System::new_all().processes() {
        if proc.name() == "EXO ONE.exe" {
            let mut maps_file = File::open(&format!("/proc/{pid}/maps")).unwrap();
            let mut maps = String::new();
            maps_file.read_to_string(&mut maps).unwrap();

            let unity_player = maps
                .split('\n')
                .filter(|line| !line.is_empty())
                .map(str::split_whitespace)
                .find_map(|mut line| {
                    let address = line.next().unwrap().split_once('-').unwrap().0;

                    let path: String = line.skip(4).collect();
                    if path.ends_with("/UnityPlayer.dll") {
                        Some(address);
                    } else {
                        None
                    }
                })
                .expect("UnityPlayer.dll not found.");

            let unity_player = u64::from_str_radix(unity_player, 16).unwrap() as *const u8;
            println!("{unity_player:p}");

            break;
        }
    }
}
 ~/dev/rust/linux_read_process_memory $ sudo target/debug/linux_read_process_memory
0x6ffffc150000

but tbh i dont really get your code to find the value. can you explain to me what these offsets are? image

Einfachirgendwa1 commented 4 days ago

regardless, i just finished it and it actually works!

use std::{
    fs::File,
    io::{Read, Seek, SeekFrom},
    mem::forget,
};

use nalgebra::Vector3;
use sysinfo::System;

struct Game {
    mem_file: File,
}

impl Game {
    fn read_mem<T>(&mut self, address: usize) -> &'static T {
        let mut buf = vec![0; size_of::<T>()];
        self.mem_file.seek(SeekFrom::Start(address as u64)).unwrap();
        self.mem_file.read(&mut buf).unwrap();

        let static_ref = unsafe { &*(buf.as_ptr() as *const T) };
        forget(buf);
        static_ref
    }

    fn resolve_multilevel_pointer(&mut self, base: usize, offsets: &[usize]) -> usize {
        let mut address = base;

        for offset in offsets {
            address = self.read_mem::<usize>(address) + offset;
        }

        address
    }
}

fn main() {
    for (pid, proc) in System::new_all().processes() {
        if proc.name() == "EXO ONE.exe" {
            let mut game = Game {
                mem_file: File::open(format!("/proc/{pid}/mem")).unwrap(),
            };

            let mut maps_file = File::open(format!("/proc/{pid}/maps")).unwrap();
            let mut maps = String::new();
            maps_file.read_to_string(&mut maps).unwrap();

            let unity_player = maps
                .split('\n')
                .filter(|line| !line.is_empty())
                .map(str::split_whitespace)
                .find_map(|mut line| {
                    let address = line.next().unwrap().split_once('-').unwrap().0;

                    let path: String = line.skip(4).collect();
                    if path.ends_with("/UnityPlayer.dll") {
                        Some(address)
                    } else {
                        None
                    }
                })
                .expect("UnityPlayer.dll not found.");

            let unity_player = usize::from_str_radix(unity_player, 16).unwrap();

            let address = game.resolve_multilevel_pointer(
                unity_player + 0x01A03D00,  //0x0156C900
                &[0x58, 0x158, 0x28, 0xA0], //0x3F8, 0x1A8, 0x28, 0xA0
            );

            let velocity = game.read_mem::<Vector3<f32>>(address + 0x30);

            println!("{velocity}");

            return;
        }
    }

    panic!("Exo One is not running!");
}

It panics when the game doesn't run, show [0, 0, 0] when in the main menu and some values when in a level. I'm sure you can make this way better than I did it as I'm still learning rust, but at least it works.