Comments 29
Все это бесполезно если не использовать IL2CPP. Две минуты и ваша защита уже отломана.
Да и возникает вопрос вполне справедливых наездов пользователей из-за ложных срабатываний - переустановка или клонирование винды (а иногда и даже банальный апгрейд на новую версию десятки) практически наверняка закончится изменением серийника тома и отваливанием защиты.
Насчёт шифрования это понятно. Меня вот мучает другой вопрос, как с помощью Unity выдрать серийный номер самого жёсткого диска? Т.к. с библиотекой System.Management Unity не умеет работать... :(
[StructLayout(LayoutKind.Sequential, Size = 12)]
private class DRIVERSTATUS
{
public byte DriveError;
public byte IDEStatus;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
public byte[] Reserved;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
public int[] Reserved2;
public DRIVERSTATUS()
{
Reserved = new byte[2];
Reserved2 = new int[2];
}
}
[StructLayout(LayoutKind.Sequential)]
private class IDSECTOR
{
public short GenConfig;
public short NumberCylinders;
public short Reserved;
public short NumberHeads;
public short BytesPerTrack;
public short BytesPerSector;
public short SectorsPerTrack;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
public short[] VendorUnique;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
public char[] SerialNumber;
public short BufferClass;
public short BufferSize;
public short ECCSize;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
public char[] FirmwareRevision;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 40)]
public char[] ModelNumber;
public short MoreVendorUnique;
public short DoubleWordIO;
public short Capabilities;
public short Reserved1;
public short PIOTiming;
public short DMATiming;
public short BS;
public short NumberCurrentCyls;
public short NumberCurrentHeads;
public short NumberCurrentSectorsPerTrack;
public int CurrentSectorCapacity;
public short MultipleSectorCapacity;
public short MultipleSectorStuff;
public int TotalAddressableSectors;
public short SingleWordDMA;
public short MultiWordDMA;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 382)]
public byte[] Reserved2;
public IDSECTOR()
{
VendorUnique = new short[3];
Reserved2 = new byte[382];
FirmwareRevision = new char[8];
SerialNumber = new char[20];
ModelNumber = new char[40];
}
}
[StructLayout(LayoutKind.Sequential)]
private class SENDCMDOUTPARAMS
{
public int BufferSize;
public DRIVERSTATUS Status;
public IDSECTOR IDS;
public SENDCMDOUTPARAMS()
{
Status = new DRIVERSTATUS();
IDS = new IDSECTOR();
}
}
[DllImport("kernel32.dll")]
private static extern int CloseHandle(int hObject);
[DllImport("kernel32.dll")]
private static extern int CreateFile(
string lpFileName,
uint dwDesiredAccess,
int dwShareMode,
int lpSecurityAttributes,
int dwCreationDisposition,
int dwFlagsAndAttributes,
int hTemplateFile
);
[DllImport("kernel32.dll")]
private static extern int DeviceIoControl(
int hDevice,
int dwIoControlCode,
[In(), Out()] SENDCMDINPARAMS lpInBuffer,
int lpInBufferSize,
[In(), Out()] SENDCMDOUTPARAMS lpOutBuffer,
int lpOutBufferSize,
ref int lpBytesReturned,
int lpOverlapped
);
private const int OPEN_EXISTING = 3;
private const uint GENERIC_READ = 0x80000000;
private const uint GENERIC_WRITE = 0x40000000;
private const int FILE_SHARE_READ = 0x1;
private const int FILE_SHARE_WRITE = 0x2;
private const int INVALID_HANDLE_VALUE = -1;
private const int DFP_RECEIVE_DRIVE_DATA = 0x7C088;
public static string getSerial()
{
int returnSize = 0;
int driveNumber = 0;
SENDCMDINPARAMS sci = new SENDCMDINPARAMS();
SENDCMDOUTPARAMS sco = new SENDCMDOUTPARAMS();
if (System.Environment.OSVersion.Platform != PlatformID.Win32NT)
{
return null;
}
int handle = CreateFile(@"\\.\PhysicalDrive0", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);
if (handle == INVALID_HANDLE_VALUE)
{
return null;
}
sci.DriveNumber = (byte)driveNumber;
sci.BufferSize = Marshal.SizeOf(sco);
sci.DriveRegs.DriveHead = (byte)(0xA0 | driveNumber << 4);
sci.DriveRegs.Command = 0xEC;
sci.DriveRegs.SectorCount = 1;
sci.DriveRegs.SectorNumber = 1;
var result = DeviceIoControl(handle, DFP_RECEIVE_DRIVE_DATA, sci, Marshal.SizeOf(sci), sco, Marshal.SizeOf(sco), ref returnSize, 0);
CloseHandle(handle);
if (result != 0)
{
// Fix byte order
char[] buf = new char[sco.IDS.SerialNumber.Length];
buf[sco.IDS.SerialNumber.Length - 1] = sco.IDS.SerialNumber[sco.IDS.SerialNumber.Length - 1];
for (int i = 0; i < sco.IDS.SerialNumber.Length; i += 2)
{
buf[i] = sco.IDS.SerialNumber[i + 1];
buf[i + 1] = sco.IDS.SerialNumber[i];
}
return new string(buf);
}
return null;
}
Получилось решить данную задачу чуть-чуть проще: написанием отдельной библиотеки dll и подключением ее к Unity
https://github.com/FranzDevBy/Serial-Number-Disk-in-Unity
Гарантируется латинским алфавитом.
А PhysicalDrive7 в какой разъём SATA (порядковый номер) на материнской плате приходит? Или вообще в разъем M.2?
При чём здесь SATA? Я втыкаю флешку — появляется PhysicalDrive8, и в списке «Select * from Win32_DiskDrive» он где-то в середине (а мог бы и первым встать, и попасть вашей «защите» на проверку серийника — гарантий никаких нет, что так не будет).
Это так наивно. Ваша защита ломается даже интересующимися студентом за часы. Не говоря уже о людях с опытом.
Насколько увеличился доход от продаж после внедрения вами этой защиты в свой продукт?
Вместо этой защиты, как мне кажется, больший результат принесли бы другие действия, например: Показ сообщения что вы типа пират и это не хорошо, купите игру со скидкой например или задонатьте для отключения этого сообщения ну или что-то в этом роде. В игру играть, я бы на вашем месте разрешил, даже в пиратскую.
По мне так гуманнее будет сделать внутриигровую авторизацию через стимовский аккаунт. Удобнее и надежнее
Так против всего есть методы. Денува ломается так же как и все остальное.
Просто то, что в статье - какой-то гемор для пользователя.
Против Денувы нет метода, даже несмотря на то, что она ломается.
Денува - это сервис гибридной войны против пиратов. Там не только протектор, с ним как раз всё плохо. Там и телеметрия похлеще виндовой и как следствие - работа с со спецслужбами, и армия ботов и доктрина с целью - чтобы никто не взламывал
нет метода...она ломается
Ломается. Так что метод как таковой есть ))
С заинлайненными проверками, например, не всё так просто. Каждый случай уникален и сложность взлома зависит скорей от того, как именно разработчики применили защиту и насколько легко автоматически распознать такие вставки или подменить для них входные данные.
Что прямо вот правда "Кому" "воруют"? На рутрекере нет ее.
Ну ведь хоть какая-то защита, но она будет
Вспомнил, как в начале карьеры не получил ни копей прибыли от готового продукта, так как сильно боялся, что его будут воровать, а сообразить должную защиту я не смог :)
Вызовы Close внутри using выглядят лишними.
Защита от копирования Unity-проекта с использованием библиотеки kernel32.dll