Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Win32/Win64 API (native code) (https://www.delphipraxis.net/17-win32-win64-api-native-code/)
-   -   ASLR und HighEntropy - Probleme (https://www.delphipraxis.net/211817-aslr-und-highentropy-probleme.html)

Harry Stahl 6. Nov 2022 14:20

ASLR und HighEntropy - Probleme
 
Habe mit Delphi 11.2 jetzt eine Anwendung für 64-Bit Windows kompiliert und festgestellt, dass es eine Schutzverletzung für diesen code gibt:

Delphi-Quellcode:
{$J+}
procedure DrawDots (x, y: Integer; c: TCanvas); StdCall;
const
  Counter: Byte = 0;
begin
  counter := counter shl 1;

  if counter = 0 then counter := 1;

  case counter of
    1, 2, 4, 8 : C.pixels[x,y] := clWhite;
  else
    C.pixels[x, y] := clBlack;
  end;
end;
{$J-}

procedure hs_Rectangle (c: TCanvas; x1, y1, x2, y2: Integer);
begin
  LineDDA (x1, y1, x2, y1, @DrawDots, LongInt (C));
  LineDDA (x1, y1, x1, y2, @DrawDots, LongInt (C));
  LineDDA (x1, y2, x2, y2, @DrawDots, LongInt (C));
  LineDDA (x2, y1, x2, y2, @DrawDots, LongInt (C));
end;
Standardmäßig war hier die Option "High-Entropy für 64 Bit-ASLR (Adress Space Layout Randomization) aktiviert.
Wenn man diese Option ausschaltet, läuft wieder alles ohne Probleme.

Alternativ kann man das hier auch fixen (muss man auch), indem man statt "LongInt" "INT64" verwendet.

Ich muss gestehen, das ist so eine Art old legacy code, den ich irgendwann mal irgendwo kopiert habe und mir darüber dann keine weiteren Gedanken mehr gemacht habe.

Unter Win32 ist das mit LongInt kein Problem, da ja jedes Programm eh nur 2GB Adressraum zur Verfügung hat (mal abgesehen von dem Trick es auf 3 GB zu puschen). Unter Win64 habe ich bislang kein Problem gehabt, wahrscheinlich liegen im Compilat bzw. auf dem Heap caller und aufgerufende Funktion immer nah genug zusammen.

Mit der ALSR High Entrpoie Funktion wird aber anscheinend die aufgerufene Funktion in einen Adressbereich > 2GB verschoben, so dass es dann kracht.

Auch wenn man das hier leicht fixen kann, ich habe ASLR high-entropie erst mal ausgeschaltet. Mein PixPower" Programm hat inzwischen mehr als 1 Mio Zeilen Source-Code, davon eine Reihe von Dritt-Komponenten und old legagy code, da ist eher anzunehmen, dass dort ähnliche Hunde begraben liegen.

Wollte mit dieser Info mal auf die Problematik aufmerksam machen und fragen, ob Ihr evtl. auch schon ähnliche Stolperstellen diesbezüglich gefunden habt. Vom Compiler gab es übrigens keine Warnung oder Hinweis...

himitsu 6. Nov 2022 14:32

AW: ASLR und HighEntropy - Probleme
 
Das hat nicht direkt mit ASLR zu tun.
OK, indirekt schon, weil Speicher/Pointer normal vorwiegend unten liegen, aber nun auch über alle Adressen besser verteilt sind.


Object/Pointer zu LongInt casten?

Rate mal, was da aus dem 64 Bit-Zeiger wird, wenn du ihn in 32 Bit rein quetschst.


NativeInt
IntPtr
...
oder hier ganz genau LPARAM, als Typ für den Cast.


Und schreibbare Konstanten?
Warum Counter nicht global,
oder anstatt des Canvas ein Datenobjekt/-record übergeben, wo Canvas und Counter drin liegen?

Harry Stahl 6. Nov 2022 15:50

AW: ASLR und HighEntropy - Probleme
 
Ja, hatte mit IFDEF Win32 / Win64 gearbeitet, aber die Lösung mit NativeInt bzw. LParam ist natürlich geschickter.

Ansonsten: Ich sagte ja, das ist eine Prodecure die ich mal irgendwo vor vielen Jahren übernommen hatte und dann ist sie völlig außer Fokus geraten.

Warum die Lösung so gemacht wurde, weiß ich auch nicht. Evtl. aus Geschwindigkeitsgründen?

Sherlock 8. Nov 2022 12:11

AW: ASLR und HighEntropy - Probleme
 
Ich bin ja nicht so der Held was direkte Bytemanipulationen betrifft, aber ist das Ergebnis hier nicht immer das selbe nämlich 1?
Delphi-Quellcode:
const
  Counter: Byte = 0;
begin
  counter := counter shl 1;

  if counter = 0 then counter := 1;
Aus Geschwindigkeitsgründen würde ich einfach nur
Delphi-Quellcode:
C.pixels[x,y] := clWhite;
schreiben.

Und welchen Sinn macht es constanten änderbar zu machen?

Sherlock

himitsu 8. Nov 2022 13:10

AW: ASLR und HighEntropy - Probleme
 
Ja, das perverse da dran ist
Delphi-Quellcode:
{$J+}
.
-> schreibbare Konstanten ... sowas wie eine globale Variable

typisierte Konstanten sind eigentlich schreibgeschützte Variablen, nur dass der Compiler den Schreibzugriff normalerweise verbietet ... außer man schaltet es ab.


aber mathematisch dürfte ein
Delphi-Quellcode:
{global} var
  counter: Byte = 0;
begin
  counter := counter shl 1;

  if counter = 0 then counter := 1;

  case counter of
    1, 2, 4, 8 :
Delphi-Quellcode:
{global} var
  counter: Byte = 0;
begin
  counter := (counter + 1) mod 8;

  if counter < 4 then
oder
Delphi-Quellcode:
{global} var
  counter: Byte = 0;
begin
  Inc(counter);
  if counter >= 8 then
    counter := 0;

  if counter < 4 then
entsprechen

Harry Stahl 8. Nov 2022 14:28

AW: ASLR und HighEntropy - Probleme
 
Zitat:

Zitat von Sherlock (Beitrag 1514475)
Ich bin ja nicht so der Held was direkte Bytemanipulationen betrifft, aber ist das Ergebnis hier nicht immer das selbe nämlich 1?
Delphi-Quellcode:
const
  Counter: Byte = 0;
begin
  counter := counter shl 1;

  if counter = 0 then counter := 1;
Aus Geschwindigkeitsgründen würde ich einfach nur
Delphi-Quellcode:
C.pixels[x,y] := clWhite;
schreiben.

Und welchen Sinn macht es constanten änderbar zu machen?

Sherlock

Wie gesagt, ich habe mir das nicht ausgedacht. Aber ein gewisser Sinn wäre hier zu erkennen, indem man eine "globale" Variable hat, die aber nur in dieser Funktion zur Verfügung steht. Somit vermeidet man also die "globalen" Variablen, die an anderer Stelle von anderen Funktionen ungewollte verändert werden könnten.

Wie himitsu bereits schrieb ergibt es daher tatsächlich nicht jedesmal den gleichen Wert (weil der Zustand des letzten Aufrufs halt beibehalten wurde).

Aber zurück zum Thema ASLR: Anscheinend sind hier bislang noch keinem anderem Anwender Probleme mit ASLR untergekommen? Das wäre ja positiv...

pustekuchen 8. Nov 2022 14:57

AW: ASLR und HighEntropy - Probleme
 
Eine änderbaren Konstante entspricht ein static variable, die es in Delphi nicht gibt.

himitsu 8. Nov 2022 15:24

AW: ASLR und HighEntropy - Probleme
 
Das CONST mit {$J+} könnte man als "private globale Inlinevariable" betrachten.
https://docwiki.embarcadero.com/RADS...tants_(Delphi)

Vom besseren "Verständnis" her, würde ich aber vom
Delphi-Quellcode:
{$J+}
bzw.
Delphi-Quellcode:
{$WRITEABLECONST ON}
abraten.
-> also stattdessen eine "richtige" globale Variable, bzw. als Private in eine Klasse, oder Dergleichen.

Aber wenn doch, wäre es wenigstens angebracht die "langen" Varianten solcher Settings zu verwenden, weil bissl "verständlicher".



Nja, auf "normalen" Windows-Versionen dürft ASLR doch standardmäßig deaktiviert sein.
Ich glaub nur auf Windows-Server wird sowas eventuell per Default auf Aktiv gestellt sein.
Somit kommen die meisten Nutzer damit nicht in Berührung.

Und da Windows normal versucht kleine Speicheradressen zu belegen, außer ASLR ist aktiv, oder z.B. VirtualAlloc+MEM_TOP_DOWN,
fallen Fehler seltener auf, wenn z.B. Pointer durch falsche Casts/Typen auf 32 Bit abgescnitten werden. (so wie es hier der Fall war)


Einen winzigen Nachteil hat ASLR noch.
* normal kann Arbeitsspeicher von Executables (EXE/DLL/BPL) wiederverwendet werden, was Ladezeit und bissl Speicher spart.
* wenn ASLR aktiv ist, liegt theoretsch jede EXE/DLL wo anders in den virtuellen Speichern, also wird sie überall exlusiv (mehrmals) geladen, weil dabei ja Adressen im Code überall anders übersetzt werden müssen.

* gut, dass es JETZT knallt, ist kein Fehler des ASLR ... bei vollem Programmspeicher hätte es so oder so geknallt

* der Vorteil ist dann aber dass "bösartige" Überläufe auf "feste" Adressen nun höchstwahrscheinlich nicht das kaputt machen, was sie wollten
* * wenn der Böse aber sich vorher die "richtige" Position besorgt, dann hilft ASLR auch nichts

https://learn.microsoft.com/de-de/wi...-in-windows-10

DaCoda 8. Nov 2022 15:32

AW: ASLR und HighEntropy - Probleme
 
Counter wird aber immer 1 sein, weil 0 SHL 1 immer eine 0 bleibt.
Somit ist der Code ja eh unnütz...

himitsu 8. Nov 2022 15:53

AW: ASLR und HighEntropy - Probleme
 
NEIN, weil es effektiv SO arbeitet:
Delphi-Quellcode:
var
  Counter: Byte = 0;

procedure DrawDots (x, y: Integer; c: TCanvas); StdCall;
begin

Es wird ein BIT in jedem Durchlauf reihum durch das Byte geschoben ... ähnlich einem ROL (wegen dem IF =0)

Delphi-Quellcode:
var
  Counter: Byte = 0;

procedure DrawDots (x, y: Integer; c: TCanvas); StdCall;
begin
  counter := counter shl 1;

  if counter = 0 then counter := 1;

  case counter of
    1, 2, 4, 8 : C.pixels[x,y] := clWhite;
  else
    C.pixels[x, y] := clBlack;
  end;
end;
Delphi-Quellcode:
var
  Counter: Byte = $1;

procedure DrawDots (x, y: Integer; c: TCanvas); StdCall;
begin
  case counter of
    1, 2, 4, 8 : C.pixels[x,y] := clWhite;
  else
    C.pixels[x, y] := clBlack;
  end;

  counter := counter rol 1;
end;
Delphi-Quellcode:
var
  Counter: Byte = 0; // oder Integer oder egal (weil alles durch 8 teilbar)

procedure DrawDots (x, y: Integer; c: TCanvas); StdCall;
begin
  Inc(Counter)
  if not Ord(Counter shr 2) of
    C.pixels[x,y] := clWhite;
  else
    C.pix

Zusammen mit dem CASE ergibt es
* es wird von 1 bis 8 gezählt (1 Byte = 8 Bits)
* und wenn es 1 bis 4 ist, wird es weiß

-> 4 Mal Weiß, 4 Mal Schwarz, 4 Mal Weiß, 4 Mal Schwarz usw.

(mein Beispiel oben zählt von 0 bis 7, weil es so einfacher zu berechnen ist, aber effektiv kommt es auf's Gleiche raus)


Alle Zeitangaben in WEZ +1. Es ist jetzt 12:10 Uhr.
Seite 1 von 2  1 2      

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz