ReClass.NET icon indicating copy to clipboard operation
ReClass.NET copied to clipboard

[Unix] Centos 7, can't see process in process list.

Open PunkS7yle opened this issue 4 years ago • 20 comments

Compiled ReClass.NET for unix and tried to open an x86 process with the x86 binary, but it does not show in the list, both processes run as root.. As a safe measure I ran the x64 binary as well and same result. I can see the process in Cheat Engine, but not this. Any ideas ?

PunkS7yle avatar Apr 06 '21 23:04 PunkS7yle

Do you see an other process? Only that one is missing?

KN4CK3R avatar Apr 07 '21 07:04 KN4CK3R

Sorry for the lack of info. I can see the rest of the processes, I have a few game server files started with systemd that aren't discovered by ReClass.NET.

Here's an example

https://i.imgur.com/dom5i10.png

Here's it viewable from CE.

https://i.imgur.com/VutjuGc.png

Processes are 32 bit, as you can see I am running the x86 bin for ReClass.NET, maybe the issue is with the process being started by systemd ?

PunkS7yle avatar Apr 07 '21 09:04 PunkS7yle

ReClass does the following on Unix to detect processes:

  1. Iterate all directories in /proc
  2. Resolve the symlink /proc/<pid>/exe to get the path to the application
  3. Read /proc/<pid>/auxv to get the platform

If 2 or 3 fail the process is skipped. Could you tests these steps manually with the user running ReClass.NET? 2 would be readlink /proc/<pid>/exe and 3 cat /proc/<pid>/auxv

KN4CK3R avatar Apr 07 '21 10:04 KN4CK3R

Here it is:

➜  /proc readlink /proc/4536/exe
/usr/bin/WorldSvr
➜  /proc cat /proc/4536/auxv
  4s�!0s����d4� @s�       0

Kܻ����[ܻ�#

PunkS7yle avatar Apr 07 '21 10:04 PunkS7yle

Could you compile and test this so we see which one fails:

#include <iostream>
#include <fstream>
#include <filesystem>

namespace fs = std::filesystem;

bool is_number(const std::string& s)
{
	auto it = s.begin();
	for (; it != s.end() && std::isdigit(*it); ++it);
	return !s.empty() && it == s.end();
}

enum class Platform
{
	Unknown,
	X86,
	X64
};

Platform GetProcessPlatform(const std::string& auxvPath)
{
	auto platform = Platform::Unknown;

	std::ifstream file(auxvPath);
	if (file)
	{
		char buffer[16];
		while (true)
		{
			file.read(buffer, 16);

			if (!file)
			{
				return Platform::X64;
			}

			if (buffer[4] != 0 || buffer[5] != 0 || buffer[6] != 0 || buffer[7] != 0)
			{
				return Platform::X86;
			}
		}
	}

	return platform;
}

int main(int argc, char *argv[])
{
	fs::path procPath("/proc");

	std::cout << "Root: " << procPath << "\n";

	if (fs::is_directory(procPath))
	{
		for (auto& d : fs::directory_iterator(procPath))
		{
			std::cout << "\n";

			if (fs::is_directory(d))
			{
				std::cout << "Directory: " << d << "\n";

				auto processPath = d.path();

				auto name = processPath.filename().string();
				std::cout << "Name: " << name << "\n";
				if (is_number(name))
				{
					auto exeSymLink = processPath / "exe";
					if (fs::is_symlink(fs::symlink_status(exeSymLink)))
					{
						std::error_code ec;
						auto linkPath = read_symlink(exeSymLink, ec).string();
						if (!ec)
						{
							std::cout << "Proc Path: " << linkPath << "\n";
							
							auto auxvPath = processPath / "auxv";

							auto platform = GetProcessPlatform(auxvPath.string());
							std::cout << "Platform: " << (int)platform << "\n";
						}
						else
						{
							std::cout << "Error: read_symlink failed\n";
						}
					}
					else
					{
						std::cout << "Error: is_symlink failed\n";
					}
				}
				else
				{
					std::cout << "Error: Is not a number\n";
				}
			}
			else
			{
				std::cout << "Not a directory: " << d << "\n";
			}
		}
	}
	else
	{
		std::cout << "Error: is_directory\n";
	}

	return 0;
}

Compile it with g++ -std=c++17 -o proc proc.cpp

KN4CK3R avatar Apr 07 '21 10:04 KN4CK3R

Output for WorldSvr from the compiled proc

Directory: "/proc/4536"
Name: 4536
Proc Path: /usr/bin/WorldSvr
Platform: 1

PunkS7yle avatar Apr 07 '21 11:04 PunkS7yle

Could you please change the code and test again (I hope is it fails now):

#include <unistd.h>

fs::path my_read_symlink(const fs::path& p, std::error_code& ec)
{
	fs::path symlink_path;

	std::string temp(64, '\0');
	for (;; temp.resize(temp.size() * 2))
	{
		ssize_t result;
		if ((result = ::readlink(p.c_str(), /*temp.data()*/ &temp[0], temp.size())) == -1)
		{
			ec.assign(errno, std::system_category());
			break;
		}
		else
		{
			if (result != static_cast<ssize_t>(temp.size()))
			{
				symlink_path = fs::path(std::string(temp.begin(), temp.begin() + result));

				ec.clear();

				break;
			}
		}
	}

	return symlink_path;
}

...
						//auto linkPath = fs::read_symlink(exeSymLink, ec).string();
						auto linkPath = my_read_symlink(exeSymLink, ec).string();
...

KN4CK3R avatar Apr 07 '21 11:04 KN4CK3R

Still same output with updated code

Directory: "/proc/4536"
Name: 4536
Proc Path: /usr/bin/WorldSvr
Platform: 1

PunkS7yle avatar Apr 07 '21 11:04 PunkS7yle

Maybe it's not the native code... Could you recompile ReClass.NET with this change:

diff --git a/ReClass.NET/Program.cs b/ReClass.NET/Program.cs
index f28cb0bd..1a1d16ca 100644
--- a/ReClass.NET/Program.cs
+++ b/ReClass.NET/Program.cs
@@ -82,6 +82,11 @@ namespace ReClassNET
                        {
                                RemoteProcess = new RemoteProcess(coreFunctions);

+                               foreach (var p in Program.CoreFunctions.EnumerateProcesses())
+                               {
+                                       Program.Logger.Log(LogLevel.Error, $"{p.Id} {p.Name} {p.Path}");
+                               }
+
                                MainForm = new MainForm();

                                Application.Run(MainForm);

That will log all available processes. Is WorldSvr logged?

KN4CK3R avatar Apr 07 '21 11:04 KN4CK3R

Recompiled and ran, but I don't see any logs in stdout, I'm starting the program with mono ReClass.NET.exe, are the logs somewhere else ?

Edit: I'm gonna install the vscode extension for mono debugging and try to debug it, will get back to you.

PunkS7yle avatar Apr 07 '21 12:04 PunkS7yle

Just saw the diagnostic window, lol. No WorldSvr logged there.

PunkS7yle avatar Apr 07 '21 12:04 PunkS7yle

That's strange... EnumerateProcesses calls the native code and from the other tests that works. Next try: Use this code with the NativeCore.so from ReClass.NET.

#include <iostream>
#include <locale>
#include <codecvt>
#include <string>
#include <dlfcn.h>

#pragma pack(push, 1)

struct EnumerateProcessData
{
	size_t Id;
	char16_t Name[260];
	char16_t Path[260];
};

#pragma pack(pop)

typedef void(EnumerateProcessCallback)(EnumerateProcessData* data);

int main(int argc, char *argv[])
{
	auto handle = dlopen("./NativeCore.so", 2);
	auto fn = (void(*)(EnumerateProcessCallback callbackProcess))dlsym(handle, "EnumerateProcesses");

	fn([](EnumerateProcessData* data) {
		std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> codecvt;
		std::cout << "Id: " << data->Id << " Name: " << codecvt.to_bytes(data->Name) << " Path: " << codecvt.to_bytes(data->Path) << "\n";
	});

	dlclose(handle);

	return 0;
}

KN4CK3R avatar Apr 07 '21 14:04 KN4CK3R

Compiled and ran, WorldSvr proc is missing from the output

PunkS7yle avatar Apr 07 '21 15:04 PunkS7yle

I found the issue. https://i.imgur.com/6056kmI.png The platform check that happens in NativeCore.so will always fail to show x86 I think ? Recompiled without it and I can see the process. Does CFLAGS = -Wall -fPIC -DRECLASSNET64=1 set to always 1 in Makefile result in RECLASSNET64 always being true ? I don't have that much exp with cflags..

PunkS7yle avatar Apr 07 '21 20:04 PunkS7yle

You are right. The makefile only uses the x64 mode. I will add a platform switch tomorrow. Thank you for finding the error 👍

KN4CK3R avatar Apr 07 '21 21:04 KN4CK3R

Thanks for taking the time to help me through it :D

PunkS7yle avatar Apr 08 '21 09:04 PunkS7yle

Did you ever push an update for this @KN4CK3R? I'm having this issue now where I can only interact with x64 processes in linux, regardless of which reclass binary i run

HoyerHub avatar Oct 05 '22 13:10 HoyerHub

No, sorry. I will have a look at the Makefile ... tomorrow 🥲

KN4CK3R avatar Oct 05 '22 14:10 KN4CK3R

Added the updated Makefile in 2e48bce. Could you test it? Should build binaries for x86 and x64 now.

KN4CK3R avatar Oct 06 '22 22:10 KN4CK3R

Added the updated Makefile in 2e48bce. Could you test it? Should build binaries for x86 and x64 now.

@KN4CK3R Sorry for the slow reply. Something seems to be wrong with the x86 NativeCore.so

~/Documents/GitHub/ReClass.NET$ mono ./build/Debug/x86/ReClass.NET.exe
Gtk-Message: 13:39:02.489: Failed to load module "canberra-gtk-module"


Unhandled Exception:
System.IO.FileNotFoundException: Failed to load native core functions! Couldnt find at location /home/user/Documents/GitHub/ReClass.NET/build/Debug/x86/NativeCore.so
  at ReClassNET.Core.InternalCoreFunctions.Create () [0x0003e] in <2ce2f9ecdfc847ab95f5f713d10f4155>:0 
  at ReClassNET.Core.CoreFunctionsManager..ctor () [0x00013] in <2ce2f9ecdfc847ab95f5f713d10f4155>:0 
  at ReClassNET.Program.Main (System.String[] args) [0x000f0] in <2ce2f9ecdfc847ab95f5f713d10f4155>:0 
[ERROR] FATAL UNHANDLED EXCEPTION: System.IO.FileNotFoundException: Failed to load native core functions! Couldnt find at location /home/user/Documents/GitHub/ReClass.NET/build/Debug/x86/NativeCore.so
  at ReClassNET.Core.InternalCoreFunctions.Create () [0x0003e] in <2ce2f9ecdfc847ab95f5f713d10f4155>:0 
  at ReClassNET.Core.CoreFunctionsManager..ctor () [0x00013] in <2ce2f9ecdfc847ab95f5f713d10f4155>:0 
  at ReClassNET.Program.Main (System.String[] args) [0x000f0] in <2ce2f9ecdfc847ab95f5f713d10f4155>:0 

The file is there and if I replace it with the x64 NativeCore.so it runs but obviously only shows x64 processes

HoyerHub avatar Oct 23 '22 11:10 HoyerHub