Exam Tracking: ExamCookie

Ich habe erfahren, dass die dänische Regierung nicht nur das Programm Digital Exam Monitor, das wir im vorherigen Artikel analysiert und vollständig umgangen haben, ausgesetzt hat , sondern dieses System möglicherweise eine Woche, nachdem wir sie über die Hacking-Methode informiert hatten, vollständig heruntergefahren hat . Ich möchte nicht glauben, dass die dänische Regierung die Idee der Überwachung von Prüfungen nur wegen uns aufgegeben hat, aber unsere Arbeit wurde deutlich wahrgenommen.

In diesem Artikel werden die technischen Details der Funktionsweise eines anderen Tools zur Verfolgung von Schulkindern beschrieben: ExamCookie. Wenn Sie nur das System umgehen möchten, scrollen Sie zum entsprechenden Abschnitt.

ExamCookie


Vor kurzem kam dieses Tool aufgrund einer Untersuchung des Verstoßes gegen die DSGVO in die Nachrichten. Wir haben uns entschlossen, während der Prüfungen einen Blick auf den zweitgrößten Konkurrenten des oben genannten Schulverfolgungssystems zu werfen : ExamCookie . Dies ist ein kommerzielles Tracking-System, das von mehr als 20 dänischen Schulen verwendet wird. Auf der Website gibt es keine andere Dokumentation als die folgende Beschreibung:

ExamCookie ist eine einfache Software, die die Computeraktivität des Schülers während der Prüfung überwacht, um sicherzustellen, dass die Regeln eingehalten werden. Das Programm verbietet Studenten, illegale Hilfe in Anspruch zu nehmen.

ExamCookie speichert alle Aktivitäten auf dem Computer: aktive URLs, Netzwerkverbindungen, Prozesse, Zwischenablage und Screenshots beim Ändern der Fenstergröße.

Das Programm funktioniert einfach: Wenn Sie an der Prüfung teilnehmen, führen Sie sie auf Ihrem Computer aus und überwachen Ihre Aktivitäten. Wenn die Prüfung abgeschlossen ist, wird das Programm geschlossen und Sie können es vom Computer entfernen.

Um mit der Nachverfolgung zu beginnen, müssen Sie Ihr UNI-Login verwenden, das auf verschiedenen Bildungsseiten funktioniert, oder Anmeldeinformationen manuell eingeben. Wir haben das Tool nicht verwendet, daher können wir nicht sagen, in welchen Fällen die manuelle Eingabe verwendet wird. Möglicherweise wird dies für Studenten durchgeführt, die kein UNI-Login haben, was wir nicht für möglich halten.



Binäre Informationen


Das Programm kann von der ExamCookie-Homepage heruntergeladen werden. Es ist eine x86 .NET-Anwendung. Als Referenz hat der analysierte binäre MD5-Hash 63AFD8A8EC26C1DC368D8FF8710E337D Signatur EXAMCOOKIE APS vom 24. April 2019. Wie der letzte Artikel gezeigt hat, kann die Analyse der .NET-Binärdatei kaum als Reverse Engineering bezeichnet werden, da die Kombination aus einfach zu lesendem IL-Code und Metadaten einen perfekten Quellcode liefert.

Im Gegensatz zum vorherigen Überwachungsprogramm haben die Entwickler dieses Tools es nicht nur aus dem Debug-Protokoll gelöscht, sondern auch verschleiert. Zumindest haben sie es versucht :-)

Verschleierung (Lachen zu Tränen)


Als wir die Anwendung in dnSpy öffneten, bemerkten wir schnell einen fehlenden Einstiegspunkt:

 // Token: 0x0600003D RID: 61 RVA: 0x00047BB0 File Offset: 0x00045FB0 [STAThread] [DebuggerHidden] [EditorBrowsable(EditorBrowsableState.Advanced)] [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)] internal static void Main(string[] Args) { } 

Seltsamerweise wird normalerweise eine Art Wrapper angenommen, der die Körper der Methoden vom Konstruktor des Moduls ändert, der zum eigentlichen Einstiegspunkt läuft. Mal sehen:

 // Token: 0x06000001 RID: 1 RVA: 0x00058048 File Offset: 0x00055048 static <Module>() { <Module>.\u206B\u202B\u200B\u206F\u206C\u202D\u200D\u200E\u202D\u206B\u206F\u206F\u202C\u202A\u206B\u202E\u202A\u206C\u202A\u206C\u200B\u206A\u202D\u206C\u202C\u206C\u200F\u202C\u206C\u202C\u200C\u206A\u200C\u206C\u200B\u206B\u202B\u206E\u202C\u202B\u202E(); <Module>.\u206C\u200D\u200F\u200E\u200C\u200C\u200F\u200F\u206E\u206A\u206A\u200B\u202C\u206A\u206B\u200D\u206E\u200E\u202D\u206B\u202C\u206C\u202D\u206D\u200C\u200F\u206E\u200F\u206E\u206A\u202B\u206B\u200E\u206B\u202E\u206F\u206A\u202E\u202C\u202A\u202E(); <Module>.\u200B\u202D\u200F\u200F\u202A\u206D\u202C\u206B\u206E\u202A\u206F\u206C\u200D\u200C\u202D\u200F\u202B\u202C\u202B\u206D\u206D\u202D\u206E\u200D\u206D\u206A\u202A\u202C\u200C\u206F\u206B\u206E\u200D\u202E\u206F\u200C\u206B\u200E\u206D\u206A\u202E(); } 

Cool. Es ist 2019 und die Leute benutzen immer noch Confuser (Ex).

Wir haben diesen Dekomprimierungscode sofort erkannt und die Assembler-Header überprüft:

  [Modul: ConfusedBy ("Confuser.Core 1.1.0 + a36320377a")] 

Im Moment dachten wir, dass der Code tatsächlich verschleiert sein würde, da der obige Konstruktor die Körper und Ressourcen der Methode entschlüsselt. Zu unserer Überraschung entschied sich der Entwickler der Verschleierung jedoch, die Metadaten nicht umzubenennen:



Dies tötet das ganze Summen des Reverse Engineering. Wie bereits in einem früheren Artikel erwähnt , möchte ich auf das eigentliche Problem eines ordnungsgemäß geschützten und qualitativ hochwertigen Überwachungsinstruments stoßen, dessen Analyse mehr als fünf Minuten dauern wird.

In jedem Fall ist das Entpacken einer durch confuser (ex) geschützten Binärdatei sehr einfach: Verwenden Sie den Dumper für .NET-Binärdateien oder den Haltepunkt für die break-Anweisung in <MODULE> .ctor und sichern Sie sich. Der Vorgang dauert 30 Sekunden, und dieser Packer bleibt immer mein Favorit, da der Schutz vor dem Debuggen überhaupt nicht funktioniert .

Wir haben uns für MegaDumper entschieden: Dies ist etwas schneller als manuelles Dumping:



Nach dem Speichern der ExamCookie-Binärdatei sollte die folgende Meldung angezeigt werden:



Jetzt haben Sie ein Verzeichnis mit allen Assembler-Fragmenten, die in den entsprechenden Prozess geladen werden, diesmal mit entschlüsselten Methodenkörpern.

Wer auch immer diese Verschleierung implementiert hat, Gott sei Dank, hat zumindest die Zeilen verschlüsselt:

 else if (System.Windows.Forms.Clipboard.ContainsData(DataFormats.SymbolicLink)) { Module1.DebugPrint(<Module>.smethod_5<string>(1582642794u), new object[0]); } else if (System.Windows.Forms.Clipboard.ContainsData(DataFormats.Tiff)) { Module1.DebugPrint(<Module>.smethod_2<string>(4207351461u), new object[0]); } else if (System.Windows.Forms.Clipboard.ContainsData(DataFormats.UnicodeText)) { Module1.DebugPrint(<Module>.smethod_5<string>(3536903244u), new object[0]); } else if (System.Windows.Forms.Clipboard.ContainsData(DataFormats.WaveAudio)) { Module1.DebugPrint(<Module>.smethod_2<string>(2091555364u), new object[0]); } 

Ja, der gute alte String-Verschlüsselungs-Confuser (Ex), die beste Pseudo-Sicherheit in der Welt von .NET. Es ist gut, dass Confuser (Ex) so oft gehackt wurde, dass im Internet für jeden Mechanismus Deobfuscation-Tools verfügbar sind, sodass wir nichts mit .NET zu tun haben. Führen Sie den ConfuserExStringDecryptor von CodeCracker auf dem Binärdump aus:



Das vorherige Snippet wird folgendermaßen konvertiert:

 else if (System.Windows.Forms.Clipboard.ContainsData(DataFormats.SymbolicLink)) { Module1.DebugPrint("ContainsData.SymbolicLink", new object[0]); } else if (System.Windows.Forms.Clipboard.ContainsData(DataFormats.Tiff)) { Module1.DebugPrint("ContainsData.Tiff", new object[0]); } else if (System.Windows.Forms.Clipboard.ContainsData(DataFormats.UnicodeText)) { Module1.DebugPrint("ContainsData.UnicodeText", new object[0]); } else if (System.Windows.Forms.Clipboard.ContainsData(DataFormats.WaveAudio)) { Module1.DebugPrint("ContainsData.WaveAudio", new object[0]); } 

Das ist der gesamte Schutz der Anwendung, der in weniger als einer Minute unterbrochen wurde. Wir werden unsere Tools hier nicht veröffentlichen, da wir sie nicht entwickelt haben und keinen Quellcode haben. Aber jeder, der den Job wiederholen möchte, kann sie auf Tuts4You finden . Wir haben kein tuts4you-Konto mehr, daher können wir keine Verknüpfung zu den Spiegeln herstellen.

Funktionalität


Überraschenderweise wurde keine echte "versteckte Funktionalität" gefunden. Wie auf der Website angegeben, werden die folgenden Informationen regelmäßig an den Server gesendet:

  • Prozessliste (alle 5000 ms)
  • Aktive Anwendung (alle 1000 ms)
  • Zwischenablage (alle 500 ms)
  • Screenshot (alle 5000 ms)
  • Liste der Netzwerkadapter (alle 20.000 ms)

Der Rest der Anwendung ist sehr langweilig, daher haben wir beschlossen, den gesamten Initialisierungsvorgang zu überspringen und direkt zu den Funktionen zu wechseln, die für die Erfassung von Informationen verantwortlich sind.

Adapter


Netzwerkadapter werden von der Funktion .NET NetworkInterface.GetAllNetworkInterfaces() genau wie im vorherigen Artikel zusammengestellt :

 NetworkInterface[] allNetworkInterfaces = NetworkInterface.GetAllNetworkInterfaces(); foreach (NetworkInterface networkInterface in allNetworkInterfaces) { try { // ... // TEXT FORMATTING OMITTED // ... dictionary.Add(networkInterface.Id, stringBuilder.ToString()); stringBuilder.Clear(); } catch (Exception ex) { AdapterThread.OnExceptionEventHandler onExceptionEvent = this.OnExceptionEvent; if (onExceptionEvent != null) { onExceptionEvent(ex); } } } result = dictionary; 

Aktive Anwendung


Das wird interessant. Anstatt alle geöffneten Fenster zu registrieren, steuert das Dienstprogramm nur die aktive Anwendung. Die Implementierung ist übertrieben, daher präsentieren wir einen schönen Pseudocode:

 var whiteList = { "devenv", "ExamCookie.WinClient", "ExamCookie.WinClient.vshost", "wermgr", "ShellExperienceHost" }; // GET WINDOW INFORMATION var foregroundWindow = ApplicationThread.GetForegroundWindow(); ApplicationThread.GetWindowRect(foregroundWindow, ref rect); ApplicationThread.GetWindowThreadProcessId(foregroundWindow, ref processId); var process = Process.GetProcessById(processId); if (process == null) return; // LOG BROWSER URL if (IsBrowser(process)) { var browserUrl = UiAutomation32.GetBrowserUrl(process.Id, process.ProcessName); // SEND BROWSER URL TO SERVER if (ValidBrowserUrl(browserUrl)) { ReportToServer(browserUrl); } } else if (!whiteList.contains(process.ProcessName, StringComparer.OrdinalIgnoreCase)) { ReportToServer(process.MainWindowTitle); } 

Großartig ... Leute verwenden immer noch Prozessnamen, um sie zu unterscheiden. Sie hören nie auf und denken nicht: „Moment mal, Sie können die Namen der Prozesse nach Belieben ändern“, damit wir diesen Schutz sicher umgehen können.

Wenn Sie einen vorherigen Artikel über ein anderes Prüfungsverfolgungsprogramm lesen, werden Sie diese unterdurchschnittliche Implementierung für Browser wahrscheinlich erkennen:

 private bool IsBrowser(System.Diagnostics.Process proc) { bool result; try { string left = proc.ProcessName.ToLower(); if (Operators.CompareString(left, "iexplore", false) != 0 && Operators.CompareString(left, "chrome", false) != 0 && Operators.CompareString(left, "firefox", false) != 0 && Operators.CompareString(left, "opera", false) != 0 && Operators.CompareString(left, "cliqz", false) != 0) { if (Operators.CompareString(left, "applicationframehost", false) != 0) { result = false; } else { result = proc.MainWindowTitle.Containing("Microsoft Edge"); } } else { result = true; } } catch (Exception ex) { result = false; } return result; } 

 private string GetBrowserName(string name) { if (Operators.CompareString(name.ToLower(), "iexplore", false) == 0) { return "IE-Explorer"; } else if (Operators.CompareString(name.ToLower(), "chrome", false) == 0) { return "Chrome"; } else if (Operators.CompareString(name.ToLower(), "firefox", false) == 0) { return "Firefox"; } else if (Operators.CompareString(name.ToLower(), "opera", false) == 0) { return "Opera"; } else if (Operators.CompareString(name.ToLower(), "cliqz", false) == 0) { return "Cliqz"; } else if (Operators.CompareString(name.ToLower(), "applicationframehost", false) == 0) { return "Microsoft Edge"; } return ""; } 

Und die Kirsche auf dem Kuchen:

 private static string GetBrowserUrlById(object processId, string name) { // ... automationElement.GetCurrentPropertyValue(/*...*/); return url; } 

Dies ist buchstäblich die gleiche Implementierung wie im vorherigen Artikel. Es ist schwer zu verstehen, dass die Entwickler immer noch nicht erkannt haben, wie schlimm es ist. Jeder kann die URL im Browser bearbeiten, dies ist nicht einmal eine Demonstration wert.

Erkennung virtueller Maschinen


Im Gegensatz zu den Aussagen der Website setzt das Starten in einer virtuellen Maschine ein Flag. Die Implementierung ist ... interessant.

 File.WriteAllBytes("ecvmd.exe", Resources.VmDetect); using (Process process = new Process()) { process.StartInfo = new ProcessStartInfo("ecvmd.exe", "-d") { CreateNoWindow = true, UseShellExecute = false, RedirectStandardOutput = true }; process.Start(); try { using (StreamReader standardOutput = process.StandardOutput) { result = standardOutput.ReadToEnd().Replace("\r\n", ""); } } catch (Exception ex3) { result = "-5"; } } 

Aus irgendeinem Grund schreiben sie eine externe Binärdatei auf die Festplatte und führen sie aus. Dann verlassen sie sich vollständig auf die E / A-Ergebnisse. Das passiert wirklich ziemlich oft, aber die Übertragung solch wichtiger Arbeiten auf einen anderen ungeschützten Prozess ist mittelmäßig. Mal sehen, mit welcher Datei wir es zu tun haben:



Also verwenden wir jetzt C ++? Nun, Interoperabilität ist eigentlich nicht unbedingt schlecht. Und das kann bedeuten, dass wir jetzt wirklich am Reverse Engineering arbeiten müssen (!!). Schauen wir uns die IDA an:

 int __cdecl main(int argc, const char **argv, const char **envp) { int v3; // ecx BOOL v4; // ebx int v5; // ebx int *v6; // eax int detect; // eax bool vbox_key_exists; // bl char vpcext; // bh char vmware_port; // al char *vmware_port_exists; // ecx char *vbox_detected; // edi char *vpcext_exists; // esi int v14; // eax int v15; // eax int v16; // eax int v17; // eax int v18; // eax int v20; // [esp+0h] [ebp-18h] HKEY result; // [esp+Ch] [ebp-Ch] HKEY phkResult; // [esp+10h] [ebp-8h] if ( argc != 2 ) goto LABEL_20; v3 = strcmp(argv[1], "-d"); if ( v3 ) v3 = -(v3 < 0) | 1; if ( !v3 ) { v4 = (unsigned __int8)vm_detect::vmware_port() != 0; result = 0; v5 = (vm_detect::vpcext() != 0 ? 2 : 0) + v4; RegOpenKeyExA(HKEY_LOCAL_MACHINE, "HARDWARE\\ACPI\\DSDT\\VBOX__", 0, 0x20019u, &result); v6 = sub_402340(); LABEL_16: sub_404BC0((int)v6, v20); return 0; } detect = strcmp(argv[1], "-s"); if ( detect ) detect = -(detect < 0) | 1; if ( !detect ) { LABEL_20: phkResult = 0; vbox_key_exists = RegOpenKeyExA(HKEY_LOCAL_MACHINE, "HARDWARE\\ACPI\\DSDT\\VBOX__", 0, 0x20019u, &phkResult) == 0; vpcext = vm_detect::vpcext(); vmware_port = vm_detect::vmware_port(); vmware_port_exists = "1"; vbox_detected = "1"; if ( !vbox_key_exists ) vbox_detected = "0"; vpcext_exists = "1"; if ( !vpcext ) vpcext_exists = "0"; if ( !vmware_port ) vmware_port_exists = "0"; result = (HKEY)vmware_port_exists; v14 = std::print((int)&dword_433310, "VMW="); v15 = std::print(v14, (const char *)result); v16 = std::print(v15, ",VPC="); v17 = std::print(v16, vpcext_exists); v18 = std::print(v17, ",VIB="); v6 = (int *)std::print(v18, vbox_detected); goto LABEL_16; } return 0; } 

Dadurch wird das Vorhandensein des VMWare-E / A-Ports 'VX' überprüft:

 int __fastcall vm_detect::vmware_port() { int result; // eax result = __indword('VX'); LOBYTE(result) = 0; return result; } 

Als nächstes wird die Ausführung der Anweisung zur Erweiterung des virtuellen PCs überprüft, die nur beim Start in einer virtualisierten Umgebung funktionieren sollte, wenn sie bei falscher Verarbeitung nicht zu einem Maschinenabsturz führt;):

 char vm_detect::vpcext() { char result; // al result = 1; __asm { vpcext 7, 0Bh } return result; } 

... kein echtes Reverse Engineering, nur 30 Sekunden, um zwei Funktionen umzubenennen :(

Dieses Programm liest einfach den Registrierungsschlüssel und führt zwei Hypervisor-Überprüfungen durch, die im Vergleich zu ihrem anderen Programm seltsam aussehen. Ich frage mich, wo sie es kopiert haben? Oh, schauen Sie, ein Artikel mit dem Titel "Methoden zum Erkennen virtueller (sic) Maschinen" , der diese Methoden erklärt :). In jedem Fall können diese Erkennungsvektoren umgangen werden, indem Sie die .vmx-Datei bearbeiten oder eine erweiterte Version eines Hypervisors Ihrer Wahl verwenden.

Datenschutz


Wie bereits erwähnt, läuft derzeit eine Untersuchung wegen Nichteinhaltung der DSGVO. Auf der Website heißt es:

Die Daten werden verschlüsselt und an einen sicheren Microsoft Azure-Server gesendet, auf den nur mit den richtigen Anmeldeinformationen zugegriffen werden kann. Nach der Prüfung werden die Daten bis zu drei Monate gespeichert.

Wir sind uns nicht ganz sicher, wie sie die "Sicherheit" des Servers bestimmen, da die Anmeldeinformationen in der Anwendung fest codiert und in den Metadatenressourcen in vollständig klarem Text gespeichert sind:

  Endpunkt: https://examcookiewinapidk.azurewebsites.net
 Benutzername: VfUtTaNUEQ
 Passwort: AwWE9PHjVc 

Wir haben den Inhalt des Servers nicht untersucht (dies ist illegal), können jedoch davon ausgehen, dass dort vollständiger Zugriff gewährt wird. Da das Konto in der Anwendung fest codiert ist, besteht keine Isolation zwischen den Schülerdatencontainern.

Rechtliche Hinweise: Wir behalten uns das Recht vor, API-Anmeldeinformationen zu veröffentlichen, da diese in einer öffentlichen Binärdatei gespeichert sind und daher nicht illegal abgerufen werden. Die Verwendung mit böswilliger Absicht verstößt jedoch eindeutig gegen das Gesetz. Wir empfehlen daher dringend, dass die Leser die oben genannten Anmeldeinformationen in keiner Weise verwenden und nicht für mögliche Handlungen verantwortlich sind.

Umgehen


Da diese Anwendung unglaublich an Digital Exam Monitor erinnert, haben wir gerade den Ayyxam- Code aktualisiert, um ExamCookie zu unterstützen.

Prozessliste


Die .NET-Prozessschnittstelle speichert Prozessdaten intern mithilfe des ntdll!NtQuerySystemInformation . Das Ausblenden von Prozessen erfordert einige Arbeit, da an vielen Stellen Informationen über den Prozess angezeigt werden. Glücklicherweise ruft .NET nur einen bestimmten Informationstyp ab, sodass Sie nicht alle Latebros- Methoden verwenden müssen.

Code zur Umgehung der Validierung aktiver Prozesse.

 NTSTATUS WINAPI ayyxam::hooks::nt_query_system_information( SYSTEM_INFORMATION_CLASS system_information_class, PVOID system_information, ULONG system_information_length, PULONG return_length) { // DONT HANDLE OTHER CLASSES if (system_information_class != SystemProcessInformation) return ayyxam::hooks::original_nt_query_system_information( system_information_class, system_information, system_information_length, return_length); // HIDE PROCESSES const auto value = ayyxam::hooks::original_nt_query_system_information( system_information_class, system_information, system_information_length, return_length); // DONT HANDLE UNSUCCESSFUL CALLS if (!NT_SUCCESS(value)) return value; // DEFINE STRUCTURE FOR LIST struct SYSTEM_PROCESS_INFO { ULONG NextEntryOffset; ULONG NumberOfThreads; LARGE_INTEGER Reserved[3]; LARGE_INTEGER CreateTime; LARGE_INTEGER UserTime; LARGE_INTEGER KernelTime; UNICODE_STRING ImageName; ULONG BasePriority; HANDLE ProcessId; HANDLE InheritedFromProcessId; }; // HELPER FUNCTION: GET NEXT ENTRY IN LINKED LIST auto get_next_entry = [](SYSTEM_PROCESS_INFO* entry) { return reinterpret_cast<SYSTEM_PROCESS_INFO*>( reinterpret_cast<std::uintptr_t>(entry) + entry->NextEntryOffset); }; // ITERATE AND HIDE PROCESS auto entry = reinterpret_cast<SYSTEM_PROCESS_INFO*>(system_information); SYSTEM_PROCESS_INFO* previous_entry = nullptr; for (; entry->NextEntryOffset > 0x00; entry = get_next_entry(entry)) { constexpr auto protected_id = 7488; if (entry->ProcessId == reinterpret_cast<HANDLE>(protected_id) && previous_entry != nullptr) { // SKIP ENTRY previous_entry->NextEntryOffset += entry->NextEntryOffset; } // SAVE PREVIOUS ENTRY FOR SKIPPING previous_entry = entry; } return value; } 

Puffer


ole32.dll!OleGetClipboard , das sehr anfällig für Hooks ist, ist für die interne Implementierung von Puffern in .NET verantwortlich. Anstatt viel Zeit mit der Analyse interner Strukturen zu verbringen, können Sie einfach S_OK , und die .NET-Fehlerbehandlung S_OK den Rest:

 std::int32_t __stdcall ayyxam::hooks::get_clipboard(void* data_object[[maybe_unused]]) { // LOL return S_OK; } 

Dadurch wird der gesamte Puffer vor dem ExamCookie-Überwachungstool ausgeblendet, ohne die Funktionalität des Programms zu beeinträchtigen.

Screenshots


Wie immer nehmen die Leute eine fertige .NET-Implementierung der gewünschten Funktion. Um diese Funktion zu umgehen, mussten wir im vorherigen Code nicht einmal etwas ändern. Screenshots werden von der Graphics.CopyFromScreen .NET-Funktion gesteuert. Es ist im Wesentlichen ein Wrapper zum Übertragen von gdi32!BitBlt , der gdi32!BitBlt . Wie in Videospielen zur Bekämpfung von Anti-Cheat-Systemen, die Screenshots machen, können wir den BitBlt-Hook verwenden und unerwünschte Informationen ausblenden, bevor wir einen Screenshot machen.


Websites öffnen


Die Grabber-URL wird vollständig aus dem vorherigen Programm kopiert, sodass wir unseren Code erneut verwenden können, um den Schutz zu umgehen. Im letzten Artikel haben wir die AutomationElement-Struktur dokumentiert, wodurch der folgende Hook gestartet wird:

 std::int32_t __stdcall ayyxam::hooks::get_property_value(void* handle, std::int32_t property_id, void* value) { constexpr auto value_value_id = 0x755D; if (property_id != value_value_id) return ayyxam::hooks::original_get_property_value(handle, property_id, value); auto result = ayyxam::hooks::original_get_property_value(handle, property_id, value); if (result != S_OK) // SUCCESS? return result; // VALUE URL IS STORED AT 0x08 FROM VALUE STRUCTURE class value_structure { public: char pad_0000[8]; //0x0000 wchar_t* value; //0x0008 }; auto value_object = reinterpret_cast<value_structure*>(value); // ZERO OUT OLD URL std::memset(value_object->value, 0x00, std::wcslen(value_object->value) * 2); // CHANGE TO GOOGLE.COM constexpr wchar_t spoofed_url[] = L"https://google.com"; std::memcpy(value_object->value, spoofed_url, sizeof(spoofed_url)); return result; } 

Erkennung virtueller Maschinen


Die verzögerte Erkennung einer virtuellen Maschine kann auf zwei Arten umgangen werden: 1) ein Patch eines Programms, das auf die Festplatte geschrieben wird; oder 2) eine Umleitung des Prozesserstellungsprozesses zu einer Dummy-Anwendung. Letzteres scheint deutlich einfacher :). Process.Start() ruft Process.Start() CreateProcess es einfach ein und leiten Sie es an eine beliebige Dummy-Anwendung weiter, die das Zeichen '0' druckt.

 BOOL WINAPI ayyxam::hooks::create_process( LPCWSTR application_name, LPWSTR command_line, LPSECURITY_ATTRIBUTES process_attributes, LPSECURITY_ATTRIBUTES thread_attributes, BOOL inherit_handles, DWORD creation_flags, LPVOID environment, LPCWSTR current_directory, LPSTARTUPINFOW startup_information, LPPROCESS_INFORMATION process_information ) { // REDIRECT PATH OF VMDETECT TO DUMMY APPLICATION constexpr auto vm_detect = L"ecvmd.exe"; if (std::wcsstr(application_name, vm_detect)) { application_name = L"dummy.exe"; } return ayyxam::hooks::original_create_process( application_name, command_line, process_attributes, thread_attributes, inherit_handles, creation_flags, environment, current_directory, startup_information, process_information); } 

Herunterladen


Das gesamte Projekt ist im Github-Repository verfügbar. Das Programm fügt die x86-Binärdatei in den entsprechenden Prozess ein.

Source: https://habr.com/ru/post/de453536/


All Articles