Приветствую всех, последние две недели я помогал в разработке чита для одной из популярных игр на Unity. Но админы использовали «античит» программы для получения всех dll игры, и конечно отображалась и наша dll с читом которая была заинжекчена. Одна из моих задач была обойти античит и скрыть заинжектированную dll. Я хоть и сталкивался в работе с низкоуровневым программированием, но много вещей не понимал, и в результате столкнулся с множеством проблем.
По началу я решил выполнить поиск всех модулей в процессе вот таким образом:
public static void Search()
{
Console.WriteLine("Введите имя процесса, без .EXE");
string name = Console.ReadLine();
System.Diagnostics.Process[] local_procs = System.Diagnostics.Process.GetProcesses(); //получаем список всех процессов
Process target_proc = local_procs.First(p => p.ProcessName == name);//Выбираем из этого списка нашу программу
ProcessModuleCollection modules = target_proc.Modules; //Получаем коллекция модулей использующие нашу программу
foreach (var dll in modules) //Производим перебор коллекции
{
ProcessModule prDll = (ProcessModule)dll; //Делаем upcast
Console.WriteLine(prDll.ModuleName);
}
}
Но он находил все dll за исключением инжектированных.
Перерыв множество статей в поиске решения проблемы, я решил использовать слепок процесса, как говорилось, этим методо можно получить весь список dll спомощью winapi. И я его испытал, готового решения не было, пришлось переписывать код с C++, в результате получилось:
static void Main(string[] args)
{
Console.WriteLine("Введите имя процесса, без .EXE");
string name = Console.ReadLine();
Process proc = Process.GetProcessesByName(name)[0];
EnumProcessModules((uint)proc.Id);
Console.ReadKey();
}
static void EnumProcessModules(uint procID)
{
var snapshot = CreateToolhelp32Snapshot(SnapshotFlags.Module | SnapshotFlags.Module32, procID);
MODULEENTRY32 mod = new MODULEENTRY32() { dwSize = (uint)Marshal.SizeOf(typeof(MODULEENTRY32)) };
if (!Module32First(snapshot, ref mod))
return;
List<string> modules = new List<string>();
do
{
modules.Add(mod.szModule);
}
while (Module32Next(snapshot, ref mod));
foreach (var t in modules)
{
Console.WriteLine(t);
}
}
[DllImport("kernel32.dll", SetLastError = true)]
static public extern bool CloseHandle(IntPtr hHandle);
[DllImport("kernel32.dll")]
static public extern bool Module32First(IntPtr hSnapshot, ref MODULEENTRY32 lpme);
[DllImport("kernel32.dll")]
static public extern bool Module32Next(IntPtr hSnapshot, ref MODULEENTRY32 lpme);
[DllImport("kernel32.dll", SetLastError = true)]
static public extern IntPtr CreateToolhelp32Snapshot(SnapshotFlags dwFlags, uint th32ProcessID);
public const short INVALID_HANDLE_VALUE = -1;
[Flags]
public enum SnapshotFlags : uint
{
HeapList = 0x00000001,
Process = 0x00000002,
Thread = 0x00000004,
Module = 0x00000008,
Module32 = 0x00000010,
Inherit = 0x80000000,
All = 0x0000001F
}
[StructLayoutAttribute(LayoutKind.Sequential)]
public struct MODULEENTRY32
{
public uint dwSize;
public uint th32ModuleID;
public uint th32ProcessID;
public uint GlblcntUsage;
public uint ProccntUsage;
IntPtr modBaseAddr;
public uint modBaseSize;
IntPtr hModule;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string szModule;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
public string szExePath;
};
К сожалению он вывел тот список что и первый вариант все стандартные dll, а мне все таких надо было найти dll которая была мною инжектирована.
Я приступил к тестированию античита, да бы понять его принцип работы. И обнаружил что он инжектил свою dll в процесс, и получал по всей видимости список модуле. Однако античит был на Delphi и разобраться с ним полностью мне не удалось. Я так же решил использовать инъекцию для получения всех сборок путем рефлексии. Для этого я написал код под Unity который выводит список всех, модулей, и к моему удивлению, я нашел и свою инжектированную dll. И так я приведу пример получения всех сборок под C# приложение, думаю вам без труда составит его перенести под Unity , я не стал его сюда приводить, слишком он большой.
public static void Search()
{
Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
string text="";
foreach (var w in assemblies)
{
foreach (var i in w.GetReferencedAssemblies())
{
text += i.FullName+"\n";
Console.WriteLine(i.FullName);
}
}
File.WriteAllText("D:\\test.txt", text);
}
Надеюсь мои начинания помогут вам, избежать тех ошибок с которыми столкнулся я, и с экономить ваше время.
