I've been recently playing a game called Grey Hack on steam. It's a game about hacking that is pretty realistic. It contains real-world Linux commands (such as ls, cd, etc.) and a semi-realistic Linux-like filesystem (/etc, /bin, /var). It even has its own scripting/programming language so you can write your own exploits. But this isn't an advertisement for Grey Hack (even though I would recommend playing it); this is about where my idea came from. I've also been playing some other (less realistic) hacking games such as NITE Team 4 and Hacknet. As I played these games, I was very entertained by the Hollywood mentality of "it just works" with all the hacking mechanics; just typing
hack and an IP address to gain access to a machine. I fantasized about a hyper-realistic hacking game, the Arma III of hacking games, if you will. I dug through the big game platforms (Steam, Epic, GOG, etc. ) to find even something close to my ideas, but I found nothing. Grey Hack is the closest to what I was imagining, but it still isn't all I imagined. After a few days of wishing my "dream" game existed, I had a genius idea why don't I just make it myself? I am a software engineer, after all!
I wrote the first line of code for the first version of the project in November 2019. This code is not public because it's outright embarrassing (really crappy code, lol), but it was a start, a way for me to plan out my ideas. The initial version started out well. There was a pretty good imitation of the Linux file system and a big chunk of the GNU Coreutils had replicas, but the code was starting to look like Italian cuisine: spaghetti. It wasn't planned out well, and as I added new stuff, I had to re-arrange my entire code base to get my new changes to work. On top of these limitations, I was missing significant features that were on my wish list. One of these major features was the ability to write and compile my own binaries to run on the virtual "system." But to implement this feature, I knew I had one of two options: implement my own C/C++-like programming language to interact with the game OR re-write the game in c/c++, and I bet you can guess which option I went with...
I decided to re-write the game in C++ regardless of my lack of knowledge (compared to python). I decided to go with C++ because it was the language, I wanted my game to run (since most of Linux is written in C/C++). I decided I would do this by giving the game users a "dumbed down" version of the gcc/g++ compiler. I had the idea of replacing the standard Linux LibC with my own custom version that interfaces with the game world instead of the host computer. The only issue is that I have never even created a shared library before, so I needed to learn. After a few weeks of researching libraries, shared libraries, other various topics (running c without LibC, etc. ), I started re-creating what I had running in python. However, shortly after starting, I hit a major roadblock. I can't even express this because I'm not sure the proper terminology for this issue, but I'll try to explain it. I was writing a function to retrieve an item in the "filesystem" from a given computer. In python, I had a function that worked like this:
result = file_system.find_file("/var/log/auth.log"). It would return a class object that represented the
/var/log/auth.log file (which logs all authorization-related requests: sudo logins, ssh logins, etc.). In python, I could modify this class object (write to it, changing permissions, etc.) , and these changes could be observed in the file system. After trying to write this function in C++, I had a significant issue. My function would return the class object, but changes I make to it wouldn't affect the game's filesystem. I couldn't figure out why this was until I made a discovery that completely halted my progress. After printing the memory address of the instance returned by the
find_file function, I noticed that it was different from the instance in the filesystem. This means that my function was returning a copy of the object instead of a reference to the original. No matter what I tried, I could not get this working the way I wanted. At this point, I gave into my lack of C/C++ knowledge and took a break from the project.
In early March 2021, I got inspired and decided to re-start the project, but I wanted to have a finished product this time. I started by re-reading my old tries and noting down the good parts and the bad parts. I planned out how my program would be organized and got to work. For the first week, I submitted at least one commit per day and was making major progress. Within the span of 10 days, I had more functionality than what I initially started with in my first demo. Not only did all my original concepts work as good, if not better than the originals, I also had many other features, such as a proper database for tracking users, groups, etc, documentation in the form of docstrings, and much more. However, at this point in the project, I ran into another major issue: I didn't know enough about how Linux operated to create a faithful recreation. This is where the main topic of this article comes into play: my deep dive into the world of Linux. I figured to be able to create an accurate representation of Linux, I needed to learn more than just the basics. At this point, I've been using Linux (Arch specifically) as my primary operating system for almost 2 years, and I've been managing Linux-based servers at work and at home for 4-5 years, but even this knowledge wasn't enough.
When I first started writing the current version, I quickly realized I needed someone (besides myself) to test my code, preferably someone with limited Linux knowledge. After only a little while of my friend playing around with the system, I realized I would need some instructions. I recognized that Linux's man-pages would do well here. But, here's where my first Linux-knowledge-related issue started: what even are man-pages? Where are they? Are they written by hand or automatically generated? You get the idea. I knew what a man-page was and how to use them, but that's about it. This first challenge actually introduced me to a new method of learning: community discord servers. After a short, in-depth discussion with some lovely members of a programming discord server, I was convinced that I learned enough about man-pages to be able to add a semi-realistic implementation to my game.
As I continued work on the project, I ran into more instances where I didn't have sufficient knowledge to implement a specific feature. Whenever this happened, I took my time to research the given topic in-depth to learn how it works behind the scenes. I'm not going to discuss EVERY topic I researched and learned about along the way (because there is A LOT of them), but I will list a few of them here:
- Logging (What's logged, where it's logged, and when)
- How Linux treats files/directories in its file system
- How apt package repos work
- How Linux handles file permissions
- How Linux handles the difference between system binaries, user binaries, and other misc binaries
- Many more topics
I wanted my re-creations of components of a Linux system to be as faithful to the real world as possible, which is why I was required to learn, in a more in-depth way, how a Linux system works.
In its current stage, this "game" probably couldn't be considered a game. It might be regarded as a "simulator" at best. However, I have plans to make the "game" more like a game. There are still many features that Linux has that my game doesn't, which I plan to implement in the near future. Another major thing that makes my "game" seem less like a game is the fact that it is CLI only; there is no "desktop environment"/GUI yet. I want to add more features and make sure they work well before starting a UI for the game. I plan on writing some graphics with PyGame (which I actually have a small demo for), but my lack of knowledge might make this difficult.
I don't even think I mentioned the name of the project yet. The project is called
blackhat-simulator! It is hosted on GitHub and is open to pull requests from anyone interested. Please feel free to read through my code, criticize my implementations, open an issue, or submit a pull request if you're interested in my project. I would love to hear your opinion on my project!
Thanks for reading!