2016-04-07 7 views
0

Als Teil meines Projekts muss ich kleine Codes in ein C-Programm namens Prüfsummenschutz einfügen. Diese Wächter berechnen den Prüfsummenwert eines Teils des Codes unter Verwendung einer Funktion (addieren, xor usw.), die auf den Befehls-Opcodes operiert. Wenn also jemand die Anweisungen (Hinzufügen, Ändern, Löschen) in dieser Code-Region manipuliert hat, ändert sich der Prüfsummenwert und es wird ein Eindringen festgestellt.Verschleierung von Prüfsummenschutz

Hier ist die Forschungsarbeit, die über diese Technik spricht:

https://www.cerias.purdue.edu/assets/pdf/bibtex_archive/2001-49.pdf

Hier ist die Wache Vorlage:

guard: 
     add ebp, -checksum 
     mov eax, client_addr 

for: 
     cmp eax, client_end 
     jg end 
     mov ebx, dword[eax] 
     add ebp, ebx 
     add eax, 4 
     jmp for 
end: 

Nun, ich habe zwei Fragen.

  1. Wäre es besser, die Wachen in die Baugruppe zu setzen, als sie in das Quellprogramm zu schreiben?

  2. Angenommen, ich lege sie in die Baugruppe (an einer geeigneten Stelle), welche Art von Verschleierung sollte ich verwenden, um zu verhindern, dass die Schutzschablone gut sichtbar ist? (Da, wenn ich mehr als 1 Wache haben, sollte der Angreifer nicht einfach alle guard Vorlagen herausfinden, und deaktivieren Sie alle Wachen zusammen, dass der Code ohne Sicherheit verlassen würde)

Vielen Dank im Voraus.

Antwort

1

Aus Sicht des Angreifers (ohne Quellen) ist die erste Frage egal; Er manipuliert den endgültigen binären Maschinencode, egal ob er aus .c oder .s erzeugt wurde, macht keinen Unterschied. Also würde ich mich hauptsächlich darum kümmern, wie man die richtige Binärdatei mit entsprechenden Prüfsummen erzeugt. Ich bin mir nicht bewusst, wie man eine korrekte Prüfsumme in der C-Quelle bekommt. Aber ich kann mir vorstellen, ein externes Tool über Assembler-Dateien laufen zu lassen, die von einem C-Compiler auf irgendeine Weise nach der Verarbeitung erzeugt wurden - bevor die .s-Dateien in .o kompiliert werden. Aber ... Beachten Sie, dass einige Aufrufe und Adressen nur relative Offsets sind, und die in den Speicher geladene Binärdatei wird vom OS Loader entsprechend der Linkertabelle gepatcht, um diese auf die realen Speicheradressen zu verweisen. Somit ändern sich die Datenbytes (Opcodes bleiben fest).

Ihre Wächtervorlage berücksichtigt dies nicht und führt auch Prüfsummen für ganze Opcodes mit Datenbytes aus (einige fortgeschrittene Wächter haben Opcode-Definitionen und Prüfsummen/verschlüsseln/entschlüsseln nur die Opcodes selbst ohne Operandenbytes).

Sonst ist es nett, dass das Ergebnis beschädigt Ebp-Wert ist, ruinieren alle C-Code um (*) Arbeiten mit Stack-Variablen. Aber es ist immer noch ein künstlicher Test, du kannst einfach beides auskommentieren, ebb, -checksum hinzufügen und ebp hinzufügen, ebx macht den Wächter unschädlich.

(*) Beachten Sie, dass Sie die Wache zwischen einigen klassischen C-Code setzen müssen, um einige echte Laufzeitprobleme von ungültigen Ebp-Wert zu bekommen. Wenn Sie es am Ende der Subroutine, die mit Pop-Ebp endet, setzen würde, würde alles gut funktionieren.

So auf die zweite Frage:

Sie wollen auf jeden Fall mehr bösartige Weise richtigen Wert zu schützen, als nur EBP Schaden. Gewöhnlich ist es am schwierigsten (zu entfernen), den Prüfsummenwert als Teil einer Berechnung zu verwenden, und schließlich die Ergebnisse nur geringfügig zu verzerren, so dass eine ernsthafte Nutzung der SW unmöglich sein wird, aber es wird Zeit brauchen, um vom Benutzer bemerkt zu werden.

Sie können auch eine echte Code-Schleife verwenden, um Ihre Prüfsummen hinzuzufügen, so einfach überspringen ganze Schleife wird auch gültigen Code überspringen (aber ich kann mir vorstellen, diese nur von Hand in generierte Baugruppe von C hinzugefügt, so dass Sie haben um es nach jeder neuen Kompilation einer bestimmten C-Quelle wiederherzustellen).

Dann kann die bestimmte Guard-Vorlage durch jede erdenkliche Mutation (verschiedene Register, modifizierte Reihenfolge der Anweisungen, Anweisungsvarianten) verschleiert werden, versuchen Sie, über Viren mit Mutationscodierung zu suchen, um einige Ideen zu erhalten.

Und ich habe dieses Papier nicht gelesen, aber von den Abbildungen würde ich sagen, der Hauptpunkt ist, diese Schutzbereiche zu überlappen, so das Ausflicken eines von ihnen wird einen anderen beeinflussen, der für mich wie das Extra klingt Zucker, um es etwas funktionsfähig zu machen (obwohl dies immer noch wie normale Herausforderung für 8-Bit-Cracker aussieht;), nicht einmal "hart" Ebene). Aber das bedeutet auch, dass Sie entweder ein sehr schlaues externes Werkzeug benötigen, um diesen zyklischen Baum der Abhängigkeiten zu berechnen, und die Schutzvorlagen in der richtigen Reihenfolge einzufügen, oder es manuell wieder komplett machen.

Natürlich muss man es nach jeder neuen C-Compilation tun, also ist es die Mühe wert, nur auf etwas sehr Kostbarem oder teurem oder solidem stabilem, wo man für die nächsten 10 Jahre keine weitere Revision produziert oder so ...: D

+0

Vielen Dank für die Antwort. Aber ich habe Zweifel. 1. Sie sagten "Aber ... Denken Sie daran, dass einige Aufrufe und Adressen nur relative Offsets sind und die in den Speicher geladene Binärdatei vom OS Loader entsprechend der Linkertabelle gepatcht wird, um diese auf die realen Speicheradressen zu verweisen. Somit ändern sich die Datenbytes (Opcodes bleiben fest). " Wie komme ich hier zurecht? – ak0817

+0

Hängt davon ab ... Aus der Assembly sieht es aus wie x86-Plattform. Sie können diesen Artikel überprüfen, um eine Idee zu bekommen, was verschoben wird und wie: http://eli.thegreenplace.net/2011/08/25/load-time-relocation-of-shared-libraries Um dies zu umgehen, haben Sie um nur internen Code zu schützen (keine externe Symbolnutzung). Aber das ist nur ein Teil davon, interner Code wird immer noch wegen Adressraum-Randomisierung verschoben. Sie möchten auch PIC (https://en.wikipedia.org/wiki/Position-independent_code) verwenden. Ich bin nicht OS-Experte, um diese beiden zu garantieren, binäre Load-Time-Patches zu verhindern, aber es gibt eine Chance. – Ped7g

+0

Eine andere Möglichkeit besteht darin, einen Sicherheitscode zu erstellen, der nur mit Opcode-Befehlen und nicht mit Datenbytes funktioniert. Also wird es nur das Opcode-Byte holen und dann den Speicherzeiger entsprechend der Befehlslänge vergrößern (der binäre Opcode kann auf irgendeine logische Weise analysiert werden, um die Befehlslänge auf einigen CPUs zu berechnen, aber x86 kann bereits so komplex sein, dass die Nachschlagetabelle dies kann) hier von Nutzen sein ... oder beides mischen, besonders wenn Sie wissen, dass ein bestimmter Wächter nur über eine Teilmenge von Opcodes läuft, so kann Ihre Logik für Opcodes außerhalb dieses Bereichs fehlschlagen = zusätzlicher Wachtest). – Ped7g