<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>evelien&apos;s blog</title><description>interesting things i did</description><link>https://evelien.sh/</link><language>en-us</language><item><title>Modern day herobrine</title><link>https://evelien.sh/blog/modern-day-herobrine/</link><guid isPermaLink="true">https://evelien.sh/blog/modern-day-herobrine/</guid><description>shepan - Minecraft bot that joins servers</description><pubDate>Fri, 07 Jul 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;One day I got bored and decided to rewrite my project &lt;a href=&quot;/projects/slowstack&quot;&gt;slowstack&lt;/a&gt; in C# because fuck Javascript. Shepan was the part of this project that would check if the server had &lt;code&gt;online-mode&lt;/code&gt; set to &lt;code&gt;true&lt;/code&gt; or not. After rewriting the software I wanted to see how fast I could join server (including the ti
me it takes to save to my database) and so the drama began.&lt;/p&gt;
&lt;h2&gt;What happened?&lt;/h2&gt;
&lt;p&gt;Within a few weeks of running Shepan I started seeing posts on subreddits like &lt;a href=&quot;https://reddit.com/r/Minecraft&quot;&gt;r/Minecraft&lt;/a&gt;, &lt;a href=&quot;https://reddit.com/r/admincraft&quot;&gt;r/admincraft&lt;/a&gt; and other websites about my bot Shepan that joins Minecraft servers. I was surprised to see that people were talking about my bot and that it
was getting so much attention. I was also surprised that there are people who are looking at their console logs 24/7. Below is a screenshot someone posted on reddit of their console logs, I can now see why people were getting mad.&lt;/p&gt;
&lt;p&gt;import { Image } from &quot;astro:assets&quot;;
import shepanConsoleLogs from &quot;../../assets/shepan-console-logs.webp&quot;;&lt;/p&gt;
&lt;p&gt;&amp;lt;Image
src={shepanConsoleLogs}
alt=&quot;a screenshot of minecraft server logs full of shepan join attempts&quot;
loading=&quot;eager&quot;
/&amp;gt;&lt;/p&gt;
&lt;p&gt;Around the same time a guy named TheAirBlow was also running his own scanner and spam joined servers. Mojang contacted him via email and he invited them to a discord server where they asked some questions about the project and why people were spam joining Minecraft servers (hi IP_Justice :3). They told us their tic
ket system was getting flooded with tickets about people spam joining servers and asked us to stop. My bot was already shut down at this point so I didn&apos;t have to do anything.
After all the posts on reddit and other websites I decided to shut down Shepan because I felt bad for the server owners and I didn&apos;t want to get in trouble with Mojang. I also got bored with the project and wanted to work on something else.&lt;/p&gt;
&lt;h2&gt;Sending packets&lt;/h2&gt;
&lt;p&gt;When I was writing the software I had no idea how the Minecraft protocol worked so I had to do some research. I found a &lt;a href=&quot;https://wiki.vg/Protocol&quot;&gt;wiki&lt;/a&gt; that explained the protocol, turns out you only need to send a &lt;a href=&quot;https://wiki.vg/Protocol#Handshake&quot;&gt;handshake packet&lt;/a&gt; and a &lt;a href=&quot;https://wiki.vg/Protocol#Login_Start&quot;&gt;login start packet&lt;/a&gt; to show up in someone else&apos;s console logs. So that&apos;s exactly what I did, I opened a connection to the server, sent the two packets and just closed the connection after getting the response. I did however encounter some issues, Minecraft&apos;s protocol version 759 and 760 had a different login start p
acket structure than the other versions. To fix this issue I just checked the protocol version and sent the correct packet structure. The second issue I encountered was that not all of my code was running in async mode, this caused the program to hang for a few seconds when it was sending packets. I fixed this by ma
king sure all of my code was running in async mode.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Server owners don&apos;t like it when you spam join their Minecraft server&lt;/li&gt;
&lt;li&gt;Mojang is scary&lt;/li&gt;
&lt;li&gt;I didn&apos;t know software that I write could actually run and not crash.&lt;/li&gt;
&lt;li&gt;Free DDOS&lt;/li&gt;
&lt;li&gt;cta&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I would not recommend spam joining Minecraft servers.
Until next time.&lt;/p&gt;
</content:encoded></item><item><title>Writing a Phasmophobia cheat</title><link>https://evelien.sh/blog/writing-a-phasmophobia-cheat/</link><guid isPermaLink="true">https://evelien.sh/blog/writing-a-phasmophobia-cheat/</guid><description>A tutorial on how to write a Phasmophobia cheat in C++.</description><pubDate>Fri, 29 Dec 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Okay, so you&apos;ve decided you wanna cheat in a co-op horror game, fucking weirdo. Anyway before we start we need some info about the game, like what game engine is it using, is it x64 or x86 and does it have an anticheat? Phasmophobia is made in Unity, x64 and does &lt;strong&gt;not&lt;/strong&gt; have an anticheat which makes our job a lot easier.&lt;/p&gt;
&lt;h2&gt;Setting up the project&lt;/h2&gt;
&lt;p&gt;Ight, open up Visual Studio and create a new DLL C++ project. I am kinda really fucking lazy so instead of writing our own hook functions we&apos;ll just use &lt;a href=&quot;https://github.com/microsoft/Detours&quot;&gt;MS-Detours&lt;/a&gt; for this project. To add Detours to our project head into &lt;code&gt;project properties -&amp;gt; Linker -&amp;gt; Input&lt;/code&gt; then add your &lt;code&gt;detours.lib&lt;/code&gt; file to Additional Dependencies. You&apos;ll also need to include the &lt;code&gt;detours.h&lt;/code&gt; header file, &lt;a href=&quot;https://github.com/Microsoft/Detours/wiki/FAQ#where-can-i-find-detourslib-and-detoursh&quot;&gt;How the fuck do I do this?&lt;/a&gt;. Also set the C++ Language standard and the C Language standard to &lt;code&gt;latest&lt;/code&gt; or something similar.&lt;/p&gt;
&lt;h2&gt;Getting function addresses and structs&lt;/h2&gt;
&lt;p&gt;Phasmophobia uses something called IL2CPP which means we can&apos;t just throw the dll in something like &lt;a href=&quot;https://github.com/dnSpy/dnSpy&quot;&gt;DnSpy&lt;/a&gt; and look at the code. To get past this I normally would just use &lt;a href=&quot;https://github.com/djkaty/Il2CppInspector&quot;&gt;Il2CppInspector&lt;/a&gt; but that project has been dead for quite some time and doesn&apos;t work with the newer Unity version that Phasmophobia is using, so we&apos;ll be using &lt;a href=&quot;https://github.com/SamboyCoding/Cpp2IL&quot;&gt;Cpp2IL&lt;/a&gt; instead.&lt;/p&gt;
&lt;p&gt;To use this, all you have to do is run this command:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.\Cpp2IL.exe --game-path=&quot;C:\Program Files (x86)\Steam\steamapps\common\Phasmophobia&quot; --parallel --analyze-all
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;or wherever you have installed your Phasmophobia. Once this is finished you can open up something like &lt;a href=&quot;https://github.com/dnSpy/dnSpy&quot;&gt;DnSpy&lt;/a&gt;, I&apos;ll be using &lt;a href=&quot;https://www.jetbrains.com/decompiler/&quot;&gt;Jetbrains dotPeek&lt;/a&gt; for this however.&lt;/p&gt;
&lt;p&gt;Now that we have our decompiler open we can start looking for things we want, like the ghost type. Most things will be located in the &lt;code&gt;Assembly-CSharp.dll&lt;/code&gt; file, so open that up and look for the &lt;code&gt;GhostAI&lt;/code&gt; class. To get the GhostAI object we can hook the &lt;code&gt;GhostAI::Start&lt;/code&gt; function.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[Address(RVA = &quot;0x158C940&quot;, Offset = &quot;0x158B740&quot;, VA = &quot;0x18158C940&quot;)]
private void Start()
{
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can see that the function is located at base address + RVA (&lt;code&gt;0x158F920&lt;/code&gt;). That&apos;s great and all but how do we get the ghost type? Below are all the fields of the &lt;code&gt;GhostAI&lt;/code&gt; class.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[Token(Token = &quot;0x20000E9&quot;)]
public class GhostAI : MonoBehaviour
{
  [Cpp2IlInjected.FieldOffset(Offset = &quot;0x20&quot;)]
  [Token(Token = &quot;0x40005D2&quot;)]
  private readonly ഠദവടസളഠഺദ മപജജഫലസഞട;
  [Cpp2IlInjected.FieldOffset(Offset = &quot;0x28&quot;)]
  [Token(Token = &quot;0x40005D3&quot;)]
  public GhostAI.വബബരരറമഞഥ \u0D3Bഺര\u0D3Bപഠനളസ;
  [Cpp2IlInjected.FieldOffset(Offset = &quot;0x30&quot;)]
  [Token(Token = &quot;0x40005D4&quot;)]
  public PhotonView ശനടധലപണഴവ;
  [Cpp2IlInjected.FieldOffset(Offset = &quot;0x38&quot;)]
  [Token(Token = &quot;0x40005D5&quot;)]
  public GhostInfo ഝറഴജഴഫഹഥജ;
  [Cpp2IlInjected.FieldOffset(Offset = &quot;0x40&quot;)]
  [Token(Token = &quot;0x40005D6&quot;)]
  public NavMeshAgent ലഠഴഺമഫമ\u0D3Bഠ;
  [Cpp2IlInjected.FieldOffset(Offset = &quot;0x48&quot;)]
  [Token(Token = &quot;0x40005D7&quot;)]
  public GhostAudio വദറതയല��മഝ;
  [Cpp2IlInjected.FieldOffset(Offset = &quot;0x50&quot;)]
  [Token(Token = &quot;0x40005D8&quot;)]
  public GhostInteraction ഷഥഴഡണഫഞഢഺ;
  [Cpp2IlInjected.FieldOffset(Offset = &quot;0x58&quot;)]
  [Token(Token = &quot;0x40005D9&quot;)]
  public GhostActivity യഞമഡശദദനണ;
  [Cpp2IlInjected.FieldOffset(Offset = &quot;0x60&quot;)]
  [Token(Token = &quot;0x40005DA&quot;)]
  [HideInInspector]
  public GhostModel നഢനനഴബഞസത;
  [Cpp2IlInjected.FieldOffset(Offset = &quot;0x68&quot;)]
  [Token(Token = &quot;0x40005DB&quot;)]
  [SerializeField]
  private GhostModel eventModel;
  [Cpp2IlInjected.FieldOffset(Offset = &quot;0x70&quot;)]
  [Token(Token = &quot;0x40005DC&quot;)]
  public GhostModel[] സയഠഝഷഠറഭബ;
  [Cpp2IlInjected.FieldOffset(Offset = &quot;0x78&quot;)]
  [Token(Token = &quot;0x40005DD&quot;)]
  public GhostModel[] നറഫളശഴശഠണ;
  [Cpp2IlInjected.FieldOffset(Offset = &quot;0x80&quot;)]
  [Token(Token = &quot;0x40005DE&quot;)]
  private bool \u0D3Bടധഢദജഞയധ;
  [Cpp2IlInjected.FieldOffset(Offset = &quot;0x84&quot;)]
  [Token(Token = &quot;0x40005DF&quot;)]
  [HideInInspector]
  public ShadowCastingMode തശപളഠളതഡവ;
  [Cpp2IlInjected.FieldOffset(Offset = &quot;0x88&quot;)]
  [Token(Token = &quot;0x40005E0&quot;)]
  [HideInInspector]
  public List&amp;lt;Vector3&amp;gt; മനഥഴഴണഢഺജ;
  [Cpp2IlInjected.FieldOffset(Offset = &quot;0x90&quot;)]
  [Token(Token = &quot;0x40005E1&quot;)]
  private float ഭജ\u0D3Bഢഴബശഹഫ;
  [Cpp2IlInjected.FieldOffset(Offset = &quot;0x98&quot;)]
  [Token(Token = &quot;0x40005E2&quot;)]
  public SanityDrainer \u0D3Bഺഝഷബഷഩണഩ;
  [Cpp2IlInjected.FieldOffset(Offset = &quot;0xA0&quot;)]
  [Token(Token = &quot;0x40005E3&quot;)]
  [HideInInspector]
  public bool ണഺശഥശഥധതറ;
  [Cpp2IlInjected.FieldOffset(Offset = &quot;0xA4&quot;)]
  [Token(Token = &quot;0x40005E4&quot;)]
  public LayerMask ജഥഭടജഞലഹപ;
  [Cpp2IlInjected.FieldOffset(Offset = &quot;0xA8&quot;)]
  [Token(Token = &quot;0x40005E5&quot;)]
  public Transform പനതദയഢഠശസ;
  [Cpp2IlInjected.FieldOffset(Offset = &quot;0xB0&quot;)]
  [Token(Token = &quot;0x40005E6&quot;)]
  public Transform ജളഠദഹളഝദഝ;
  [Cpp2IlInjected.FieldOffset(Offset = &quot;0xB8&quot;)]
  [Token(Token = &quot;0x40005E7&quot;)]
  public Transform ബഺപടഫബധസഭ;
  [Cpp2IlInjected.FieldOffset(Offset = &quot;0xC0&quot;)]
  [Token(Token = &quot;0x40005E8&quot;)]
  [HideInInspector]
  public float പഫപഞഺദഴദഷ;
  [Cpp2IlInjected.FieldOffset(Offset = &quot;0xC4&quot;)]
  [Token(Token = &quot;0x40005E9&quot;)]
  [HideInInspector]
  public float ഢറഴഝണബനഭസ;
  [Cpp2IlInjected.FieldOffset(Offset = &quot;0xC8&quot;)]
  [Token(Token = &quot;0x40005EA&quot;)]
  [HideInInspector]
  public float ജ\u0D3Bഹ\u0D3Bമഭ\u0D3Bശബ;
  [Cpp2IlInjected.FieldOffset(Offset = &quot;0xCC&quot;)]
  [Token(Token = &quot;0x40005EB&quot;)]
  [HideInInspector]
  public bool ജയമടയഩപമഞ;
  [Cpp2IlInjected.FieldOffset(Offset = &quot;0xCD&quot;)]
  [Token(Token = &quot;0x40005EC&quot;)]
  [HideInInspector]
  public bool ടലഡഹഫഢയമഩ;
  [Cpp2IlInjected.FieldOffset(Offset = &quot;0xD0&quot;)]
  [Token(Token = &quot;0x40005ED&quot;)]
  [HideInInspector]
  public Vector3 ലന\u0D3Bസതഷ\u0D3Bഴഹ;
  [Cpp2IlInjected.FieldOffset(Offset = &quot;0xE0&quot;)]
  [Token(Token = &quot;0x40005EE&quot;)]
  public GameObject ധഺമലയളടണഥ;
  [Cpp2IlInjected.FieldOffset(Offset = &quot;0xE8&quot;)]
  [Token(Token = &quot;0x40005EF&quot;)]
  [HideInInspector]
  public bool ഥനള\u0D3B\u0D3Bഝശവഭ;
  [Cpp2IlInjected.FieldOffset(Offset = &quot;0xE9&quot;)]
  [Token(Token = &quot;0x40005F0&quot;)]
  [HideInInspector]
  public bool ഭമഫവഫസഢഞണ;
  [Cpp2IlInjected.FieldOffset(Offset = &quot;0xEA&quot;)]
  [Token(Token = &quot;0x40005F1&quot;)]
  [HideInInspector]
  public bool ണഷഺവദഠഭഹസ;
  [Cpp2IlInjected.FieldOffset(Offset = &quot;0xEB&quot;)]
  [Token(Token = &quot;0x40005F2&quot;)]
  [HideInInspector]
  public bool യഫവമളവറഺമ;
  [Cpp2IlInjected.FieldOffset(Offset = &quot;0xF0&quot;)]
  [Token(Token = &quot;0x40005F3&quot;)]
  [HideInInspector]
  public WhiteSage ഷഹഴശരഥധഩപ;
  [Cpp2IlInjected.FieldOffset(Offset = &quot;0xF8&quot;)]
  [Token(Token = &quot;0x40005F4&quot;)]
  private float പഴളണഞഞഷഹഥ;
  [Cpp2IlInjected.FieldOffset(Offset = &quot;0xFC&quot;)]
  [Token(Token = &quot;0x40005F5&quot;)]
  [HideInInspector]
  public bool ണഩഞബഹമഝഝന;
  [Cpp2IlInjected.FieldOffset(Offset = &quot;0xFD&quot;)]
  [Token(Token = &quot;0x40005F6&quot;)]
  [HideInInspector]
  public bool ഷധ\u0D3Bതതഩലളത;
  [Cpp2IlInjected.FieldOffset(Offset = &quot;0xFE&quot;)]
  [Token(Token = &quot;0x40005F7&quot;)]
  [HideInInspector]
  public bool രഠ\u0D3Bലതബബനജ;
  [Cpp2IlInjected.FieldOffset(Offset = &quot;0x100&quot;)]
  [Token(Token = &quot;0x40005F8&quot;)]
  [HideInInspector]
  public Player ദഫഥഩഩഭഹഩമ;
  [Cpp2IlInjected.FieldOffset(Offset = &quot;0x108&quot;)]
  [Token(Token = &quot;0x40005F9&quot;)]
  [HideInInspector]
  public int റഹവധനലഷ\u0D3Bള;
  [Cpp2IlInjected.FieldOffset(Offset = &quot;0x10C&quot;)]
  [Token(Token = &quot;0x40005FA&quot;)]
  [HideInInspector]
  public Vector3 ഭണഺവഢഞരഹ\u0D3B;
  [Cpp2IlInjected.FieldOffset(Offset = &quot;0x118&quot;)]
  [Token(Token = &quot;0x40005FB&quot;)]
  private readonly float[] ജഡജസഠമററല;
  [Cpp2IlInjected.FieldOffset(Offset = &quot;0x120&quot;)]
  [Token(Token = &quot;0x40005FC&quot;)]
  private readonly float[] നസഩണഥവവരഭ;
  [Cpp2IlInjected.FieldOffset(Offset = &quot;0x128&quot;)]
  [Token(Token = &quot;0x40005FD&quot;)]
  private readonly float[] ഝയഩബതഥഥശയ;
  [Cpp2IlInjected.FieldOffset(Offset = &quot;0x130&quot;)]
  [Token(Token = &quot;0x40005FE&quot;)]
  private int ഡലടഫഡണഭഢഷ;
  [Cpp2IlInjected.FieldOffset(Offset = &quot;0x134&quot;)]
  [Token(Token = &quot;0x40005FF&quot;)]
  private int ധശഷണനരളളഹ;
  [Cpp2IlInjected.FieldOffset(Offset = &quot;0x138&quot;)]
  [Token(Token = &quot;0x4000600&quot;)]
  private int ഩഞബഴഝഥഺദധ;
  [Cpp2IlInjected.FieldOffset(Offset = &quot;0x13C&quot;)]
  [Token(Token = &quot;0x4000601&quot;)]
  private int മഹധശതദഫഫഷ;
  [Cpp2IlInjected.FieldOffset(Offset = &quot;0x140&quot;)]
  [Token(Token = &quot;0x4000602&quot;)]
  private int ഩധഝഭളഠയശര;
  [Cpp2IlInjected.FieldOffset(Offset = &quot;0x148&quot;)]
  [Token(Token = &quot;0x4000603&quot;)]
  private readonly float[] ണഭബധബശവ\u0D3Bണ;
  [Cpp2IlInjected.FieldOffset(Offset = &quot;0x150&quot;)]
  [Token(Token = &quot;0x4000604&quot;)]
  private readonly float[] ഹഡ\u0D3Bറനഫഫഝന;
  [Cpp2IlInjected.FieldOffset(Offset = &quot;0x158&quot;)]
  [Token(Token = &quot;0x4000605&quot;)]
  private readonly float[] വബശഠജണളഠഺ;
  [Cpp2IlInjected.FieldOffset(Offset = &quot;0x160&quot;)]
  [Token(Token = &quot;0x4000606&quot;)]
  private float ഩളഢരറരധ\u0D3Bഴ;
  [Cpp2IlInjected.FieldOffset(Offset = &quot;0x168&quot;)]
  [Token(Token = &quot;0x4000607&quot;)]
  private readonly int[] ഭഢഝഭതഫദവ\u0D3B;
  [Cpp2IlInjected.FieldOffset(Offset = &quot;0x170&quot;)]
  [Token(Token = &quot;0x4000608&quot;)]
  private readonly int[] ശയഹഡറഡഥടല;
  [Cpp2IlInjected.FieldOffset(Offset = &quot;0x178&quot;)]
  [Token(Token = &quot;0x4000609&quot;)]
  private readonly int[] ധലഢപബഡമഭല;
  [Cpp2IlInjected.FieldOffset(Offset = &quot;0x180&quot;)]
  [Token(Token = &quot;0x400060A&quot;)]
  private readonly int[] \u0D3Bണഫസഫയഠസന;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Ghost type is probably an enum but where is it? You can find it in the &lt;code&gt;GhostTraits&lt;/code&gt; class, to get there, go the &lt;code&gt;GhostInfo&lt;/code&gt; class then go the first type that is being used in the &lt;code&gt;GhostInfo&lt;/code&gt; class, in this case it is &lt;code&gt;പദഴലടഫഺഷവ&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[Token(Token = &quot;0x20000F7&quot;)]
public class GhostInfo : MonoBehaviourPun
{
  [FieldOffset(Offset = &quot;0x28&quot;)]
  [Token(Token = &quot;0x4000652&quot;)]
  [HideInInspector]
  public പദഴലടഫഺഷവ ളവയഥസരഹഥട;
  [FieldOffset(Offset = &quot;0x68&quot;)]
  [Token(Token = &quot;0x4000653&quot;)]
  [SerializeField]
  private GhostAI ghost;
  [FieldOffset(Offset = &quot;0x70&quot;)]
  [Token(Token = &quot;0x4000654&quot;)]
  [HideInInspector]
  public LevelRoom ഹഷഹധതജഺലള;
  [FieldOffset(Offset = &quot;0x78&quot;)]
  [Token(Token = &quot;0x4000655&quot;)]
  [HideInInspector]
  public float ഫഥമതഹഷഫഩബ;
  [FieldOffset(Offset = &quot;0x7C&quot;)]
  [Token(Token = &quot;0x4000656&quot;)]
  private bool ണടറളശഥസറപ;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Which will bring us to this struct, the first field (ബണജഷസഷണഞഴ) is the ghost type and the second one (ഹഭഴഞഴന\u0D3Bഥഝ) is the mimic type.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[Token(Token = &quot;0x200015E&quot;)]
[SerializeField]
public struct പദഴലടഫഺഷവ
{
  [FieldOffset(Offset = &quot;0x0&quot;)]
  [Token(Token = &quot;0x400086D&quot;)]
  public പദഴലടഫഺഷവ.ഝഡശഭഡഡഷഴജ ബണജഷസഷണഞഴ;
  [FieldOffset(Offset = &quot;0x4&quot;)]
  [Token(Token = &quot;0x400086E&quot;)]
  public പദഴലടഫഺഷവ.ഝഡശഭഡഡഷഴജ ഹഭഴഞഴന\u0D3Bഥഝ;
  [FieldOffset(Offset = &quot;0x8&quot;)]
  [Token(Token = &quot;0x400086F&quot;)]
  public List&amp;lt;ദസഫനഠശഢപവ&amp;gt; ഠഥളഡഠലഹമത;
  [FieldOffset(Offset = &quot;0x10&quot;)]
  [Token(Token = &quot;0x4000870&quot;)]
  public List&amp;lt;ദസഫനഠശഢപവ&amp;gt; ഭടഞ\u0D3Bറഝമനത;
  [FieldOffset(Offset = &quot;0x18&quot;)]
  [Token(Token = &quot;0x4000871&quot;)]
  public int \u0D3Bദഞന\u0D3Bഫഺടഡ;
  [FieldOffset(Offset = &quot;0x1C&quot;)]
  [Token(Token = &quot;0x4000872&quot;)]
  public bool ഥഭദടബശനദവ;
  [FieldOffset(Offset = &quot;0x20&quot;)]
  [Token(Token = &quot;0x4000873&quot;)]
  public string തണവബഝഝഹവഹ;
  [FieldOffset(Offset = &quot;0x28&quot;)]
  [Token(Token = &quot;0x4000874&quot;)]
  public int തഺറഡദഠഹരജ;
  [FieldOffset(Offset = &quot;0x2C&quot;)]
  [Token(Token = &quot;0x4000875&quot;)]
  public int സയഡലരണഷദന;
  [FieldOffset(Offset = &quot;0x30&quot;)]
  [Token(Token = &quot;0x4000876&quot;)]
  public bool ദജഷനജഭധജദ;
  [FieldOffset(Offset = &quot;0x34&quot;)]
  [Token(Token = &quot;0x4000877&quot;)]
  public int ബഭഞപരയധഠണ;
  [FieldOffset(Offset = &quot;0x38&quot;)]
  [Token(Token = &quot;0x4000878&quot;)]
  public int യലളനഹഝയതഠ;
  [FieldOffset(Offset = &quot;0x3C&quot;)]
  [Token(Token = &quot;0x4000879&quot;)]
  public bool ല\u0D3Bസഺഢവസളഫ;

  [Token(Token = &quot;0x200015F&quot;)]
  public enum ഝഡശഭഡഡഷഴജ
  {
    [Token(Token = &quot;0x400087B&quot;)] Spirit,
    [Token(Token = &quot;0x400087C&quot;)] Wraith,
    [Token(Token = &quot;0x400087D&quot;)] Phantom,
    [Token(Token = &quot;0x400087E&quot;)] Poltergeist,
    [Token(Token = &quot;0x400087F&quot;)] Banshee,
    [Token(Token = &quot;0x4000880&quot;)] Jinn,
    [Token(Token = &quot;0x4000881&quot;)] Mare,
    [Token(Token = &quot;0x4000882&quot;)] Revenant,
    [Token(Token = &quot;0x4000883&quot;)] Shade,
    [Token(Token = &quot;0x4000884&quot;)] Demon,
    [Token(Token = &quot;0x4000885&quot;)] Yurei,
    [Token(Token = &quot;0x4000886&quot;)] Oni,
    [Token(Token = &quot;0x4000887&quot;)] Yokai,
    [Token(Token = &quot;0x4000888&quot;)] Hantu,
    [Token(Token = &quot;0x4000889&quot;)] Goryo,
    [Token(Token = &quot;0x400088A&quot;)] Myling,
    [Token(Token = &quot;0x400088B&quot;)] Onryo,
    [Token(Token = &quot;0x400088C&quot;)] TheTwins,
    [Token(Token = &quot;0x400088D&quot;)] Raiju,
    [Token(Token = &quot;0x400088E&quot;)] Obake,
    [Token(Token = &quot;0x400088F&quot;)] Mimic,
    [Token(Token = &quot;0x4000890&quot;)] Moroi,
    [Token(Token = &quot;0x4000891&quot;)] Deogen,
    [Token(Token = &quot;0x4000892&quot;)] Thaye,
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Creating our SDK&lt;/h2&gt;
&lt;p&gt;Back in Visual Studio we are, let&apos;s start by creating a simple SDK that we can use. I&apos;ll create a new header file called &lt;code&gt;sdk.h&lt;/code&gt; and add a base address and a macro to define functions. I&apos;ll also create another header file &lt;code&gt;GhostAI.h&lt;/code&gt; and add the GhostAI structs to it and define the GhostAI::Start function.
Because GhostAI derives from MonoBehaviour and GhostInfo from MonoBehaviourPun we&apos;ll have to add those fields to the &lt;code&gt;GhostAIFields&lt;/code&gt; struct too, I&apos;ll give you the &lt;code&gt;MonoBehaviour&lt;/code&gt; and the &lt;code&gt;MonoBehaviourPun&lt;/code&gt; structs. We won&apos;t need to add every field from the actual GhostAI class, just the ones we need; so up until the GhostInfo field.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// sdk.h
#pragma once

#define DECLARE_FUNCTION_POINTER(NAME, TYPE, ADDRESS) \
using NAME = TYPE; \
inline NAME NAME##_ptr = reinterpret_cast&amp;lt;NAME&amp;gt;(BASE_ADDRESS + ADDRESS);

namespace SDK
{
  const auto BASE_ADDRESS = reinterpret_cast&amp;lt;uintptr_t&amp;gt;(GetModuleHandleW(L&quot;GameAssembly.dll&quot;));
}

// MonoBehaviour.h
namespace SDK
{
  struct __declspec(align(8)) Object1Fields
  {
    void* m_CachedPtr;
    void* m_CancellationTokenSource;
  };

  struct Component1Fields
  {
    Object1Fields _;
  };

  struct BehaviourFields
  {
    Component1Fields _;
  };

  struct MonoBehaviourFields
  {
    BehaviourFields _;
  };

  struct MonoBehaviour
  {
    void* Clazz; // MonoBehaviourClass
    void* Monitor; // MonitorData
    MonoBehaviourFields Fields;
  };

  struct MonoBehaviourPunFields
  {
    MonoBehaviourFields _;
    void* pvCache;
  };

  struct MonoBehaviourPunCallbacksFields
  {
    MonoBehaviourPunFields _;
  };
}

// GhostAI.h
#pragma once
#include &quot;sdk.h&quot;

namespace SDK
{
  struct GhostAIFields
  {
    MonoBehaviourFields _;
    void* Field0;
    int32_t Field1;
    void* Field2;
    GhostInfo* GhostInfo; // Only field we care about
  };

  struct GhostAI
  {
    void* Clazz; // GhostAI class
    void* Monitor; // Monitor Data
    GhostAIFields Fields;
  };

  DECLARE_FUNCTION_POINTER(GhostAI_Start, void(*)(GhostAI* ghostAI, void* methodInfo), 0x158C940);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Okay great, now we&apos;ll need to create the &lt;code&gt;GhostInfo&lt;/code&gt; struct and the &lt;code&gt;GhostTrait&lt;/code&gt; struct. Don&apos;t forget to include them in the &lt;code&gt;sdk.h&lt;/code&gt;. We will need every field from the &lt;code&gt;GhostTrait&lt;/code&gt; struct because the &lt;code&gt;GhostType&lt;/code&gt; field will only be valid after &lt;code&gt;Name&lt;/code&gt; isn&apos;t a nullptr anymore.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// GhostInfo.h
#pragma once
#include &quot;sdk.h&quot;

namespace SDK
{
  struct GhostInfoFields
  {
    MonoBehaviourPunFields _;
    GhostTraits GhostTraits; // very important 1!!!1
    // don&apos;t care about other fields
  };

  struct GhostInfo
  {
    void* Clazz; // GhostInfo class
    void* Monitor; // Monitor Data
    GhostInfoFields Fields;
  };
}

// GhostTraits.h
#pragma once
#include &quot;sdk.h&quot;

namespace SDK
{
  enum class GhostType: int32_t
  {
    Spirit,
    Wraith,
    Phantom,
    Poltergeist,
    Banshee,
    Jinn,
    Mare,
    Revenant,
    Shade,
    Demon,
    Yurei,
    Oni,
    Yokai,
    Hantu,
    Goryo,
    Myling,
    Onryo,
    TheTwins,
    Raiju,
    Obake,
    Mimic,
    Moroi,
    Deogen,
    Thaye,
  };

  struct GhostTraits
  {
    GhostType GhostType_;
    GhostType MimicType;
    // don&apos;t care about the other ones
    void* Field2;
    void* Field3;
    int32_t Field4;
    bool Field5;
    void* Name;
    int32_t Field7;
    int Field8;
    bool Field9;
    int32_t Field10;
    int32_t Field11;
    bool Field12;
  };
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Hooking the GhostAI::Start function&lt;/h2&gt;
&lt;p&gt;Back in our &lt;code&gt;dllmain.cpp&lt;/code&gt; we can create our &quot;HackThread&quot;, define our &lt;code&gt;GhostAI_Start&lt;/code&gt; function and hook it using Detours.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// dllmain.cpp
HMODULE hHackModule = nullptr;
HANDLE hHackThread = nullptr;

void hkGhostAI_Start(SDK::GhostAI* _ghostAI, void* methodInfo)
{
  // Calling original function
  SDK::GhostAI_Start_ptr(_ghostAI, methodInfo);
}

DWORD WINAPI HackThread()
{
  // Detouring GhostAI.Start
  DetourTransactionBegin();
  DetourUpdateThread(GetCurrentThread());
  DetourAttach(&amp;amp;reinterpret_cast&amp;lt;PVOID&amp;amp;&amp;gt;(SDK::GhostAI_Start_ptr), hkGhostAI_Start);
  DetourTransactionCommit();

  // No exiting the cheat yet
  while (true)
  {
    if (GetAsyncKeyState(VK_END) &amp;amp; 1)
    {
      break;
    }

    Sleep(100);
  }

  // Un-detouring GhostAI.Start
  DetourTransactionBegin();
  DetourUpdateThread(GetCurrentThread());
  DetourDetach(&amp;amp;reinterpret_cast&amp;lt;PVOID&amp;amp;&amp;gt;(SDK::GhostAI_Start_ptr), hkGhostAI_Start);
  DetourTransactionCommit();

  CloseHandle(hHackThread);
  FreeLibraryAndExitThread(hHackModule, 0);
}


BOOL APIENTRY DllMain(HMODULE hModule, DWORD ulReasonForCall, LPVOID lpReserved)
{
  if (ulReasonForCall == DLL_PROCESS_ATTACH)
  {
    hHackModule = hModule;
    hHackThread = CreateThread(nullptr, 0, reinterpret_cast&amp;lt;LPTHREAD_START_ROUTINE&amp;gt;(HackThread), hModule, 0, nullptr);
  }

  return TRUE;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Displaying the ghost type&lt;/h2&gt;
&lt;p&gt;Woah almost there, now to display the ghost type I&apos;ll just add a simple console using &lt;code&gt;AllocConsole&lt;/code&gt;. We&apos;ll also need to save the GhostAI pointer to a global variable so we can use it.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// dllmain.cpp
SDK::GhostAI* ghostAI = nullptr;

void hkGhostAI_Start(SDK::GhostAI* _ghostAI, void* methodInfo)
{
  // Saving ghostAI pointer
  ghostAI = _ghostAI;

  // Calling original function
  SDK::GhostAI_Start_ptr(ghostAI, methodInfo);
}

DWORD WINAPI HackThread()
{
  // Beep boop I&apos;m a console
  FILE* f;
  AllocConsole();
  freopen_s(&amp;amp;f, &quot;CONOUT$&quot;, &quot;w&quot;, stdout);

  // other code

  // when exiting after removing hook
  // Bye bye console
  FreeConsole();
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Cool, now that we can print stuff to a console, let&apos;s print the ghost type. To do this we&apos;ll need to convert the enum to a string, I&apos;ll just use a switch statement for this because I&apos;m stupid. We will print via the HackThread while loop &apos;cause &lt;code&gt;ghostInfo&lt;/code&gt; can be a nullptr.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// GhostTraits.h
inline std::string GhostTypeToString(GhostType ghostType)
{
  switch (ghostType)
  {
  case GhostType::Spirit:
    return &quot;Spirit&quot;;
  case GhostType::Wraith:
    return &quot;Wraith&quot;;
  case GhostType::Phantom:
    return &quot;Phantom&quot;;
  case GhostType::Poltergeist:
    return &quot;Poltergeist&quot;;
  case GhostType::Banshee:
    return &quot;Banshee&quot;;
  case GhostType::Jinn:
    return &quot;Jinn&quot;;
  case GhostType::Mare:
    return &quot;Mare&quot;;
  case GhostType::Revenant:
    return &quot;Revenant&quot;;
  case GhostType::Shade:
    return &quot;Shade&quot;;
  case GhostType::Demon:
    return &quot;Demon&quot;;
  case GhostType::Yurei:
    return &quot;Yurei&quot;;
  case GhostType::Oni:
    return &quot;Oni&quot;;
  case GhostType::Yokai:
    return &quot;Yokai&quot;;
  case GhostType::Hantu:
    return &quot;Hantu&quot;;
  case GhostType::Goryo:
    return &quot;Goryo&quot;;
  case GhostType::Myling:
    return &quot;Myling&quot;;
  case GhostType::Onryo:
    return &quot;Onryo&quot;;
  case GhostType::TheTwins:
    return &quot;The Twins&quot;;
  case GhostType::Raiju:
    return &quot;Raiju&quot;;
  case GhostType::Obake:
    return &quot;Obake&quot;;
  case GhostType::Mimic:
    return &quot;Mimic&quot;;
  case GhostType::Moroi:
    return &quot;Moroi&quot;;
  case GhostType::Deogen:
    return &quot;Deogen&quot;;
  case GhostType::Thaye:
    return &quot;Thaye&quot;;
  default:
    return &quot;Unknown&quot;;
  }
}

// dllmain.cpp
bool shouldPrint = false;

void hkGhostAI_Start(SDK::GhostAI* _ghostAI, void* methodInfo)
{
  // Saving ghostAI pointer
  ghostAI = _ghostAI;
  shouldPrint = true;

  // Calling original function
  SDK::GhostAI_Start_ptr(ghostAI, methodInfo);
}

DWORD WINAPI HackThread()
{
    // code

    while (true)
    {
      /// oooooo spooky ghost
      if (shouldPrint &amp;amp;&amp;amp; ghostAI)
      {
        if (const auto ghostInfo = ghostAI-&amp;gt;Fields.GhostInfo)
        {
          // if name is a nullptr then the ghost type isn&apos;t valid yet
          if (ghostInfo-&amp;gt;Fields.GhostTraits.Name)
          {
            const auto ghostType = ghostInfo-&amp;gt;Fields.GhostTraits.GhostType_;
            std::cout &amp;lt;&amp;lt; &quot;Ghost type: &quot; &amp;lt;&amp;lt; GhostTypeToString(ghostType) &amp;lt;&amp;lt; std::endl;
            shouldPrint = false;
          }
        }
      }

      if (GetAsyncKeyState(VK_END) &amp;amp; 1)
      {
          break;
      }

      Sleep(100);
    }

    // more code
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Anti-kick&lt;/h2&gt;
&lt;p&gt;During the development of &lt;a href=&quot;https://evelien.sh/projects/asthmaphobia&quot;&gt;Asthmaphobia&lt;/a&gt; I found out that you can create an anti-kick hack by just hooking &lt;code&gt;ServerManager_KickPlayerNetworked&lt;/code&gt; and then not calling the original function :) Have fun.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;That&apos;s it, the basics for creating your own shitty Phasmophobia cheat. Source code for this project can be found on &lt;a href=&quot;https://github.com/evelien-x64/phasmophobia-cheat&quot;&gt;GitHub&lt;/a&gt;. Yes I know the code is bad, it isn&apos;t meant to be good code.&lt;/p&gt;
&lt;p&gt;&amp;lt;style&amp;gt;
pre {
max-height: 400px;
}
&amp;lt;/style&amp;gt;&lt;/p&gt;
</content:encoded></item></channel></rss>