Seite 1 von 1

ExecuteMemory()

Verfasst: 10.05.2009 20:18
von cxAlex
Angeregt durch den Code von Helle aus diesem Thread habe ich eine allgemeine Procedure geschrieben um ASM - Code aus dem Speicher auszuführen. Das sollte z.B. enorm schnelle Eval() - Proceduren oder JIT - Compiler ermöglichen.

Code: Alles auswählen

; Führt Assemblercode aus dem Speicher aus und gib den Inhalt von EAX zurück
Procedure ExecuteMemory(Code, Size)
  Protected vCode, RtVar
  vCode = VirtualAllocEx_(GetCurrentProcess_(), #Null, Size + SizeOf(Byte), #MEM_COMMIT, #PAGE_EXECUTE_READWRITE)
  CopyMemory(Code, vCode, Size)
  PokeB(vCode + Size, $C3); !RET
  CompilerIf #PB_Compiler_Processor = #PB_Processor_x64
    !call qword[p.v_vCode]
  CompilerElse
    !call dword[p.v_vCode]
  CompilerEndIf
  !Mov dword[p.v_RtVar], EAX
  VirtualFreeEx_(GetCurrentProcess_(), vCode, Size + SizeOf(Byte), #MEM_DECOMMIT)
  ProcedureReturn RtVar
EndProcedure

Debug ExecuteMemory(?Code1, ?Code2-?Code1)

DataSection
  Code1:
  Data.b $B8, $FF, $00, $00, $00 ; !MOV EAX, 255
  Code2:
EndDataSection
Gruß, Alex

Verfasst: 10.05.2009 20:34
von milan1612
Interessant, haette nicht gedacht dass das so einfach geht :allright:

Verfasst: 10.05.2009 21:48
von Batze
Warum so kompliziert? In dem Thread stand doch schon dass es das rüberkopieren garnicht braucht.

Code: Alles auswählen

; Führt Assemblercode in (!) dem Speicher aus und gib den Inhalt von EAX zurück
Procedure ExecuteMemory(Code, Size)
  Protected RtVar, OldProtect, Dummy
  ; vCode = VirtualAllocEx_(GetCurrentProcess_(), #Null, Size + SizeOf(Byte), #MEM_COMMIT, #PAGE_EXECUTE_READWRITE)
  
  If VirtualProtect_(Code, Size, #PAGE_EXECUTE_READWRITE, @OldProtect)
    PokeB(Code + Size-1, $C3); !RET
    CompilerIf #PB_Compiler_Processor = #PB_Processor_x64
      ! CALL qword [p.v_Code]
    CompilerElse
      ! CALL dword [p.v_Code]
    CompilerEndIf
      ! MOV dword [p.v_RtVar], eax
    VirtualProtect_(Code, Size, OldProtect, Dummy)
  EndIf
  
  ProcedureReturn RtVar
EndProcedure

Debug ExecuteMemory(?Code1, ?Code2-?Code1)

DataSection
  Code1:
  Data.b $B8, $FF, $00, $00, $00, 0 ; !MOV EAX, 255  (+ Ein leeres Byte (man könnte auch !RET selber reinschreiben) )
  Code2:
EndDataSection

Verfasst: 11.05.2009 20:33
von Josef Sniatecki
:shock: Habe nicht gedacht, dass man einfach so einen Speicherblock ausführen kann. Bis jetzt kannte ich nur Jumps auf variable Labels.
Thx für die Codes. Wenn ich ASM könnte, dann würde ich sie gut verwenden
können. :wink:

Verfasst: 11.05.2009 22:41
von Thorium
Josef Sniatecki hat geschrieben::shock: Habe nicht gedacht, dass man einfach so einen Speicherblock ausführen kann.
Naja, der reguläre Code muss ja auch im Speicher liegen. :wink: Alles was man machen muss ist die Speicherregion in der der Code liegt als Executable flagen, falls sie das nicht sowieso schon ist.

Auf älteren Systemen funktioniert das sogar ohne das es als Executable markiert ist. Aber seid dem VX-Bit geht das hardwareseitig nicht mehr und ab XP (wenn ich mich nicht irre) gibt es auch eine softwareseitige Prüfung ob der Code ausgeführt werden darf.

Verfasst: 11.05.2009 22:46
von ts-soft
Und wie Flag ich jetzt eine Exe im Speicher als Executable und führe sie aus?

Bitte keine Verweis auf die nicht funktionierenden Codes hier im Forum, die
kenne ich.

Verfasst: 11.05.2009 23:51
von Thorium
ts-soft hat geschrieben:Und wie Flag ich jetzt eine Exe im Speicher als Executable und führe sie aus?

Bitte keine Verweis auf die nicht funktionierenden Codes hier im Forum, die
kenne ich.
Das funktioniert nicht so ohne weiteres ne ganze .exe auszuführen. Jede .exe hat eine Image Base. Das ist die Adresse an die sie im Speicher geladen wird. Nun gibt es Anweisungen in der .exe die absolute Adressen beinhalten und von dieser Image Base ausgehen. Läd man die .exe einfach so in den Speicher, werden diese Anweisungen in die Scheiße greifen. ^^
Das lässt sich aber lösen. Für diesen Fall gibt die sogenannten Relocations. Das sind Informationen über diese Anweisungen mit absoluten Adressen. Man kann die Infos auslesen und die Relocations anwenden. Heisst man ändert die Anweisungen auf die neuen Adressen ab. Allerdings müssen die Relocationinfos nicht in der .exe enthalten sein. Da eine regulär geladene .exe immer an ihre Image Base geladen wird. Viele .exe Packer und Optimierer entfernen die Relocationinfos aus der .exe.

Das zweite Problem sind die Imports von DLL-Funktionen. Die müssen alle initialisiert werden. Es gibt eine Import Table in der .exe auf die der Code der .exe zugreift um DLL-Funktionen aufzurufen. Beim regulären starten einer .exe initialisiert der PE-Loader von Windows die Import Table. Also läd alle benötigten DLL's und trägt die Funktionsadressen in die Import Table ein. Das müsste man auch per Hand machen.

Dann sollte das funktionieren.