Schönes Tut
(Ich bin nur zufällig durch deine Signatur hierher gekommen. Manchmal ist man aber auch neugierig...)
Was einen Anfänger verwirren könnte ist folgende Zeile:
Delphi-Quellcode:
function ShowText : PChar;
asm
JMP @start
@test:
DB '
Hallo Du!', 0
@start: LEA EAX, @test
RET
end;
Du sprichst davon, dass hinter dem Label test eine
Variable steht. Das könnte für Frustration sorgen, da die Speicherseiten in die der Code am Anfang geladen werden, "nur" mit 'Execute and Read' ausgestattet sind. Demnach kann man da nicht speichern und demnach ist es keine Variable sondern eine Konstante. Stört in deiner Funktion ja auch nicht weiter, denn du greifst ja nicht schreibend auf diese Speicherplätze zu.
Aber der eine oder andere könnte ja auf die Idee kommen, auf diese Art lokale Variablen anzulegen. Und das klappt nicht (==>Frustration).
Also müsste man (insofern du überhaupt willst) etwas über lokale Variablen erzählen (EBP+Stack)
Oder, man holt ganz weit aus (da ich im Erklären/Tut schreiben nicht so gut bin, nehme ich lieber gleich Code):
Delphi-Quellcode:
var MBI: TMemoryBasicInformation;
tmp:integer;
memory:pointer;
begin
memory:=@Showtext;
VirtualQuery(memory, MBI, SizeOf(MBI));
Virtualprotect(memory,mbi.RegionSize,page_execute_readWRITE,@tmp);
...und verändert einfach die Zugriffsrechte auf die Speicherseiten.
Jetzt könnte man mit "mov byte ptr [eax],64" aus Dem "H" von Hallo ein "A" machen.
Oder man legt die Funktion in einen neu alloziierten Speicherbereich und tobt sich da aus (inkl. selbst modifiziertem code)
Delphi-Quellcode:
program Pasm;
{$APPTYPE CONSOLE}
uses windows;
//Die Assembler-Routine mit einer statischen/lokalen Variable hinter @1
//Hier wird der Parameter c entsprechend mit add (oder sub) zur statischen Variable @1 gerechnet und zurückgegeben
function testasm(c:integer):integer;
asm
jmp @2
//Variable überspringen
@1: dd 10
//unsere 32bit-Variable (static)
@2: call @3
//Addresse von @1 in edx speichern
@3: pop edx
sub edx,9
add eax,[edx]
//@1 zu c addieren
//Speichern des Ergebnisses in @1
mov [edx],eax
//normalerweise: EAccessViolation;
//aber wir dürfen ja in unserem eigenen Speicherbereich (siehe VirtualAlloc)schreiben
{Hier wäre eigentlich soweit Schluss, aber man kann ja auch noch etwas rumspielen ;-)
und mal einen Befehl verändern}
// verändern von "add eax,[edx]" zu "sub eax,[edx]"
// =>verändern von $0302 zu $2B02
//und natürlich auch wieder zurück
add edx,13
//Addresse auf den add-Befehl errechnen
cmp byte ptr [edx],$03
//gucken, was drinn ist
je @4
mov byte ptr [edx],$03
//und ändern
ret
@4: mov byte ptr [edx],$2b
//oder eben wieder zurückändern
end;
//wird als Referenz benötigt um "size" zu bestimmen
procedure dispatch;
asm
nop
end;
var memory:pointer;
size:cardinal;
result:integer;
i:integer;
begin
//function testasm in eine neue Speicherseite kopieren -->memory
size:=cardinal(@dispatch)-cardinal(@testasm);
//Größe der Funktion testasm ermitteln
memory:=Virtualalloc(
nil,size,MEM_COMMIT,PAGE_EXECUTE_READWRITE);
//Ich will auf meinem neuen Speicherbereich (memory)
//ausführen,lesen und schreiben
movememory(memory,@testasm,size);
//copy
//kleine Test-Schleife
for i:=1
to 10
do begin
asm
mov eax,i
call memory
mov result,eax
end;
writeln(result);
end;
//folgende Zeile würde hier so nicht funktionieren
//writeln(testasm(2));
virtualfree(memory,size,MEM_DECOMMIT);
readln;
end.
Es reicht fürs erste sicherlich aus dem Wort Variable in deinem Tut "Konstante" zu machen
Für die Einführung in
asm würde alles weitere nur verwirren.
Edit: Wie langweilig, wäre doch das Leben ohne Fehler; Ich habe mal eine sinnlose Variable aus dem zweiten CodeSchnippsel von mir entfernt.
Edit2: Fehler über Fehler
(im code zum ändern von add und sub)
Dieser Beitrag ist für Jugendliche unter 18 Jahren nicht geeignet.