C# Anti-Debug метод OutputDebugString работает неправильно

Итак, недавно я читал о механизмах анти-отладки и популярном методе, с которым я столкнулся, чтобы проверить, отлаживается ли текущий процесс, это OutputDebugString. Я написал этот фрагмент кода, но он работает не совсем так, как предполагалось. Может ли кто-нибудь пролить свет на то, почему или что я делаю неправильно?

private static bool stub_OutputDebugString()
{
    uint ErrCode = 0x12A6;
    Native.SetLastError(ErrCode);
    Native.OutputDebugString("System.Core\n");
    if (Marshal.GetLastWin32Error() == (int)ErrCode)
    {
        //Debugger Detected
        return true;
    }
    else
    {
        //No Debugger Detected
        return false;
    }
}

Мои подписи P/Invoke

[DllImport("kernel32.dll", SetLastError = true)]
public static extern void SetLastError(uint dwErrCode);

[DllImport("kernel32.dll", SetLastError = true)]
public static extern void OutputDebugString(string lpOutputString);

Примечание. Я прочитал о том, как GetLastError не следует вызывать из собственной среды, поскольку значение может быть изменено, поэтому я использую Marshal.GetLastWin32Error()

Код должен работать, но последняя ошибка не меняется, когда я пытаюсь отладить приложение с помощью windbg или любого другого отладчика.


person Cra0    schedule 04.12.2015    source источник


Ответы (2)


Ваше рассуждение о GetLastError() (его не следует использовать, поскольку последняя ошибка может быть перезаписана платформой .NET Framework из-за любой другой внутренней/невидимой/фоновой операции) также относится к SetLastError() . Просто вы не можете надежно вызвать его и ожидать, что его значение сохранится без изменений, пока вы не вызовете Marshal.GetLastWin32Error().

Мы можем обсудить, как обойти эту проблему, однако...

... этот метод имеет (каким-то) смысл для собственного кода, потому что OutputDebugString() широко используется, а дизассемблировать скомпилированный код сложнее (тогда вы защитите себя с помощью некоторого запутанного кода). Однако управляемый код легко декомпилировать и по-прежнему легко читать и понимать, такая простая запутанность не поможет, и вам следует просто использовать свойство System.Diagnostics.Debugger.IsAttached.


Если вы действительно хотите обнаружить отладчик (даже если очень легко увидеть, что вы делаете, это не обеспечит достаточной защиты), вам придется все усложнить, потому что вы можете захотеть защититься от отладчика. управляемый отладчик или собственный отладчик. Да они разные.

Если управляемый отладчик не построен поверх собственного, то при вызове собственного IsDebuggerPresent() вы всегда получите FALSE для управляемого отладчика, где Debugger.IsAttached вернет true. Также возможен и противоположный сценарий: с подключенным родным отладчиком вы получите TRUE из IsDebuggerPresent(), но false из Debugger.IsAttached. В большом мире вы встретите все три типа отладчика. Чтобы лучше обсудить IsDebuggerPresent(), вы можете прочитать Антиотладка.

Вы можете проверить оба, но вы все еще далеки от обнаружения отладчиков, потому что они проверяют только локальные управляемые/собственные отладчики, но у вас нет информации об удаленных отладчиках (если вы также не вызываете CheckRemoteDebuggerPresent()) или отладчиках, которые не живут в user- режиме (если вы также не играете с NtQuerySystemInformation). Есть несколько более надежных методов, но вы не можете использовать их в управляемом мире (см. также Обнаружение системного отладчика).

Одним из возможных решений является отладка вашего собственного процесса с помощью DebugActiveProcess(), если вы терпите неудачу (и это не ошибка разрешения), тогда подключается другой отладчик, более того, пока вы не останетесь подключенным, другой отладчик не сможет подключиться. Обратите внимание, что процесс не может отлаживать себя (AFAIK), тогда это должно быть выполнено из дочернего процесса (который каким-то образом взаимодействует с основным процессом, который вы хотите защитить). В этом нет ничего нового, в основном тот же метод, описанный в Как определить, запущен ли текущий процесс GDB?, но специфичен для Windows .

См. также Отладчики не должны изменять поведение и управляемый и . Встроенные API отладки для получения дополнительной информации по этой теме.

person Adriano Repetti    schedule 04.12.2015
comment
Я знаю, что нативный код можно декомпилировать и просмотреть. Но это другой вопрос. Такие вещи, как IsDebuggerPresent и тому подобное, легко обойти, но я хотел бы проверить большинство из них, даже если простой хук обошел бы их. - person Cra0; 04.12.2015
comment
Вы не поняли мою мысль. Единственная причина использовать OutputDebugString() вместо IsDebuggerPresent() — в нативном коде — это ОБФУСКАЦИЯ этой проверки. Это не лучше, не надежнее и не безопаснее. В управляемом коде эта запутанность не имеет смысла, потому что когда вы его декомпилируете... у вас даже есть хорошо отформатированный исходный код. Тогда вернемся к вашему основному вопросу: вы не можете этого сделать, потому что SetLastError() не будет работать. Однако побочным вопросом будет: зачем вам это нужно? Вы хотите предотвратить отладку... почему? - person Adriano Repetti; 04.12.2015
comment
Да, основная цель состоит в том, чтобы предотвратить или ограничить отладку моего собственного процесса, используя как можно больше различных методов. - person Cra0; 04.12.2015
comment
woops ment удалось. Я посмотрел на обфускаторы для .NET-приложений, таких как confuserEx, и изучил несколько трюков, просто пытаясь понять достойный способ прекратить отладку, спасибо за ваш ответ, хотя он был информативным. - person Cra0; 04.12.2015
comment
Нет, мой вопрос о другом. Я вижу, вы хотите прекратить отладку, я бы знал, зачем вам это нужно. Затем код развертывается и выполняется на клиентском компьютере, если у вас нет устройства с поддержкой DRM, не имеет значения, сколько усилий вы приложите к этому... они могут проверять, изменять и, в конечном итоге, отлаживать ваш код. - person Adriano Repetti; 04.12.2015

почему бы просто не использовать IsDebuggerPresent функция?.. Я считаю, что она существует для той цели, которую вы хотите.

person CaldasGSM    schedule 04.12.2015
comment
Да, это проще, но он не проверяет удаленные отладчики и отладчики, не относящиеся к пользовательскому режиму. - person Adriano Repetti; 04.12.2015