Page 1 of 2
Real-time machine-code execution
Posted: Tue Sep 04, 2012 1:32 am
by Crusiatus Black
Hey all,
This is more of a thing that was interesting me for quite a while. I know you can allocate a buffer with execution
permissions, which you in turn can fill with opcodes and data like below (calling MessageBoxA).
Code: Select all
Import "user32.lib"
MessageBoxA(hWnd.l, szMessage.s, szTitle.s, dwFlags.l)
EndImport
Procedure assemblyCall()
Protected requiredSize = 28
; 4x 1byte push with 4 dword values = 20
; 1x MOV EAX, DWORD = 5 bytes
; 1x CALL EAX = 2 bytes
; 1x return = 1 byte.
vm = VirtualAlloc_(#Null, requiredSize, #MEM_COMMIT, #PAGE_EXECUTE_READWRITE)
If(vm)
Protected szTitle.s = "Hello World!!"
Protected szMessage.s = "Testing executing the contents of this buffer."
Protected Flags = #MB_ICONINFORMATION | #MB_YESNO
Protected dwOffset = 0
Protected *function = @MessageBoxA()
; MsgBoxStyle - PUSH Flags
PokeA(vm + dwOffset, $68): dwOffset + 1
PokeL(vm + dwOffset, Flags): dwOffset + 4
; szTitle - PUSH lpszTitle
PokeA(vm + dwOffset, $68): dwOffset + 1
PokeL(vm + dwOffset, @szTitle): dwOffset + 4
; szMessage - PUSH lpszMessage
PokeA(vm + dwOffset, $68): dwOffset + 1
PokeL(vm + dwOffset, @szMessage): dwOffset + 4
; hWindowHandle - PUSH 0
PokeA(vm + dwOffset, $68): dwOffset + 1
PokeL(vm + dwOffset, 0): dwOffset + 4
; push function = MOV EAX, function
PokeA(vm + dwOffset, $B8): dwOffset + 1
PokeL(vm + dwOffset, *function): dwOffset + 4
; Call
PokeA(vm + dwOffset, $FF): dwOffset + 1 ; CALL EAX
PokeA(vm + dwOffset, $D0): dwOffset + 1
PokeA(vm + dwOffset, $C3): dwOffset + 1 ;RETN
eax_result.l = CallFunctionFast(vm)
If(eax_result = #IDYES)
Debug "You pressed yes :)"
Else
Debug "You pressed no :("
EndIf
VirtualFree_(vm, 0, #MEM_RELEASE)
EndIf
EndProcedure
assemblyCall()
Now, I was wondering because this is quite interesting to me, is there something available or doable
that can assemble / compile assembly code and execute it dynamically? I mean, I know it must be possible,
because this code works for me. But this isn't really an easy read.
I would like a real-time assembler like this, because then I'd be able to use assembly dynamically. Extending
scripting languages with it etc.
Anyhow, just my curiosity here. I'm curious of what is currently possible.
I remember that something like this has been done in AutoIt a while ago, dynamically assembling and executing FASM code.
Thanks.
Re: Real-time machine-code execution
Posted: Tue Sep 04, 2012 2:07 am
by jack
interesting, you could use the fasmDLL to do the assembling
http://board.flatassembler.net/topic.php?t=6239
Re: Real-time machine-code execution
Posted: Tue Sep 04, 2012 2:31 am
by Crusiatus Black
Hey Jack,
That's pretty cool! I never knew about a FASM dll, it would be even more awesome if there was
a static library instead of a DLL, but I'm not going to get into compiling static libraries with FASM haha.
Anyhow, this works too, thanks for the link man, this is really interesting.
Code: Select all
; The following structure resides at the beginning of memory block provided
; to the fasm_Assemble function. The condition field contains the same value
; as the one returned by function.
; When function returns FASM_OK condition, the output_length and
; output_data fields are filled - with pointer to generated output
; (somewhere within the provided memory block) and the count of bytes stored
; there.
; When function returns FASM_ERROR, the error_code is filled with the
; code of specific error that happened and error_line is a pointer to the
; LINE_HEADER structure, providing information about the line that caused
; the error.
Structure FASM_STATE
condition.l
StructureUnion
output_length.l
error_code.l
EndStructureUnion
StructureUnion
output_data.l
error_line.l
EndStructureUnion
EndStructure
; The following structure has two variants - it either defines the line
; that was loaded directly from source, or the line that was generated by
; macroinstruction. First case has the highest bit of line_number set to 0,
; while the second case has this bit set.
; In the first case, the file_path field contains pointer to the path of
; source file (empty string if it's the source that was provided directly to
; fasm_Assemble function), the line_number is the number of line within
; that file (starting from 1) and the file_offset field contains the offset
; within the file where the line starts.
; In the second case the macro_calling_line field contains the pointer to
; LINE_HEADER structure for the line which called the macroinstruction, and
; the macro_line field contains the pointer to LINE_HEADER structure for the
; line within the definition of macroinstruction, which generated this one.
Structure LINE_HEADER
file_path.l
line_number.l
StructureUnion
file_offset.l
macro_calling_line.l
EndStructureUnion
Macro_line.l
EndStructure
; General errors and conditions
#FASM_OK = 0 ; FASM_STATE points to output
#FASM_WORKING = 1
#FASM_ERROR = 2 ; FASM_STATE contains error code
#FASM_INVALID_PARAMETER = -1
#FASM_OUT_OF_MEMORY = -2
#FASM_STACK_OVERFLOW = -3
#FASM_SOURCE_NOT_FOUND = -4
#FASM_UNEXPECTED_END_OF_SOURCE = -5
#FASM_CANNOT_GENERATE_CODE = -6
#FASM_FORMAT_LIMITATIONS_EXCEDDED = -7
#FASM_WRITE_FAILED = -8
; Error codes for FASM_ERROR condition
#FASMERR_FILE_NOT_FOUND = -101
#FASMERR_ERROR_READING_FILE = -102
#FASMERR_INVALID_FILE_FORMAT = -103
#FASMERR_INVALID_MACRO_ARGUMENTS = -104
#FASMERR_INCOMPLETE_MACRO = -105
#FASMERR_UNEXPECTED_CHARACTERS = -106
#FASMERR_INVALID_ARGUMENT = -107
#FASMERR_ILLEGAL_INSTRUCTION = -108
#FASMERR_INVALID_OPERAND = -109
#FASMERR_INVALID_OPERAND_SIZE = -110
#FASMERR_OPERAND_SIZE_NOT_SPECIFIED = -111
#FASMERR_OPERAND_SIZES_DO_NOT_MATCH = -112
#FASMERR_INVALID_ADDRESS_SIZE = -113
#FASMERR_ADDRESS_SIZES_DO_NOT_AGREE = -114
#FASMERR_DISALLOWED_COMBINATION_OF_REGISTERS = -115
#FASMERR_LONG_IMMEDIATE_NOT_ENCODABLE = -116
#FASMERR_RELATIVE_JUMP_OUT_OF_RANGE = -117
#FASMERR_INVALID_EXPRESSION = -118
#FASMERR_INVALID_ADDRESS = -119
#FASMERR_INVALID_VALUE = -120
#FASMERR_VALUE_OUT_OF_RANGE = -121
#FASMERR_UNDEFINED_SYMBOL = -122
#FASMERR_INVALID_USE_OF_SYMBOL = -123
#FASMERR_NAME_TOO_LONG = -124
#FASMERR_INVALID_NAME = -125
#FASMERR_RESERVED_WORD_USED_AS_SYMBOL = -126
#FASMERR_SYMBOL_ALREADY_DEFINED = -127
#FASMERR_MISSING_END_QUOTE = -128
#FASMERR_MISSING_END_DIRECTIVE = -129
#FASMERR_UNEXPECTED_INSTRUCTION = -130
#FASMERR_EXTRA_CHARACTERS_ON_LINE = -131
#FASMERR_SECTION_NOT_ALIGNED_ENOUGH = -132
#FASMERR_SETTING_ALREADY_SPECIFIED = -133
#FASMERR_DATA_ALREADY_DEFINED = -134
#FASMERR_TOO_MANY_REPEATS = -135
#FASMERR_SYMBOL_OUT_OF_SCOPE = -136
#FASMERR_USER_ERROR = -140
#FASMERR_ASSERTION_FAILED = -141
DataSection
fasm_dll: IncludeBinary "FASM.dll"
EndDataSection
Prototype.l fasm_GetVersion()
Prototype.l fasm_Assemble(*lpszSource, *lpChunk, dwMemorySize.l, dwPassesLimit = 100, hDisplayPipe = #Null)
Prototype.l fasm_AssembleFile(*lpszSourceFile, *lpChunk, dwMemorySize.l, dwPassesLimit = 100, hDisplayPipe = #Null)
Global fasm_GetVersion .fasm_GetVersion = 0
Global fasm_Assemble .fasm_Assemble = 0
Global fasm_AssembleFile.fasm_AssembleFile = 0
Global fasm_hLibrary = 0
Procedure fasm_init()
fasm_hLibrary = LoadLibraryM(?fasm_dll)
If(fasm_hLibrary)
fasm_GetVersion = GetProcAddressM(fasm_hLibrary, "fasm_GetVersion")
fasm_Assemble = GetProcAddressM(fasm_hLibrary, "fasm_Assemble")
fasm_AssembleFile = GetProcAddressM(fasm_hLibrary, "fasm_AssembleFile")
ProcedureReturn 1
EndIf
EndProcedure
Procedure fasm_close()
If(fasm_hLibrary)
FreeLibraryM(fasm_hLibrary)
fasm_GetVersion = 0
fasm_Assemble = 0
fasm_AssembleFile = 0
EndIf
EndProcedure
If(fasm_init())
*lpOut.FASM_STATE = AllocateMemory(1024)
szSource.s = "use32" + #CRLF$
szSource.s + "push 0" + #CRLF$
szSource.s + "xor eax,eax" + #CRLF$
Debug fasm_Assemble(@szSource, *lpOut, 1024)
Debug *lpOut\output_length
EndIf
Re: Real-time machine-code execution
Posted: Tue Sep 04, 2012 2:53 am
by Crusiatus Black
That being said, I managed assembling the code, execution isn't quite working yet ;p
Re: Real-time machine-code execution
Posted: Tue Sep 04, 2012 3:46 am
by Crusiatus Black
There we go! Man, this is fun.
Code: Select all
; The following structure resides at the beginning of memory block provided
; to the fasm_Assemble function. The condition field contains the same value
; as the one returned by function.
; When function returns FASM_OK condition, the output_length and
; output_data fields are filled - with pointer to generated output
; (somewhere within the provided memory block) and the count of bytes stored
; there.
; When function returns FASM_ERROR, the error_code is filled with the
; code of specific error that happened and error_line is a pointer to the
; LINE_HEADER structure, providing information about the line that caused
; the error.
Structure FASM_STATE
condition.l
StructureUnion
output_length.l
error_code.l
EndStructureUnion
StructureUnion
output_data.l
error_line.l
EndStructureUnion
EndStructure
; The following structure has two variants - it either defines the line
; that was loaded directly from source, or the line that was generated by
; macroinstruction. First case has the highest bit of line_number set to 0,
; while the second case has this bit set.
; In the first case, the file_path field contains pointer to the path of
; source file (empty string if it's the source that was provided directly to
; fasm_Assemble function), the line_number is the number of line within
; that file (starting from 1) and the file_offset field contains the offset
; within the file where the line starts.
; In the second case the macro_calling_line field contains the pointer to
; LINE_HEADER structure for the line which called the macroinstruction, and
; the macro_line field contains the pointer to LINE_HEADER structure for the
; line within the definition of macroinstruction, which generated this one.
Structure LINE_HEADER
file_path.l
line_number.l
StructureUnion
file_offset.l
macro_calling_line.l
EndStructureUnion
Macro_line.l
EndStructure
; General errors and conditions
#FASM_OK = 0 ; FASM_STATE points to output
#FASM_WORKING = 1
#FASM_ERROR = 2 ; FASM_STATE contains error code
#FASM_INVALID_PARAMETER = -1
#FASM_OUT_OF_MEMORY = -2
#FASM_STACK_OVERFLOW = -3
#FASM_SOURCE_NOT_FOUND = -4
#FASM_UNEXPECTED_END_OF_SOURCE = -5
#FASM_CANNOT_GENERATE_CODE = -6
#FASM_FORMAT_LIMITATIONS_EXCEDDED = -7
#FASM_WRITE_FAILED = -8
; Error codes for FASM_ERROR condition
#FASMERR_FILE_NOT_FOUND = -101
#FASMERR_ERROR_READING_FILE = -102
#FASMERR_INVALID_FILE_FORMAT = -103
#FASMERR_INVALID_MACRO_ARGUMENTS = -104
#FASMERR_INCOMPLETE_MACRO = -105
#FASMERR_UNEXPECTED_CHARACTERS = -106
#FASMERR_INVALID_ARGUMENT = -107
#FASMERR_ILLEGAL_INSTRUCTION = -108
#FASMERR_INVALID_OPERAND = -109
#FASMERR_INVALID_OPERAND_SIZE = -110
#FASMERR_OPERAND_SIZE_NOT_SPECIFIED = -111
#FASMERR_OPERAND_SIZES_DO_NOT_MATCH = -112
#FASMERR_INVALID_ADDRESS_SIZE = -113
#FASMERR_ADDRESS_SIZES_DO_NOT_AGREE = -114
#FASMERR_DISALLOWED_COMBINATION_OF_REGISTERS = -115
#FASMERR_LONG_IMMEDIATE_NOT_ENCODABLE = -116
#FASMERR_RELATIVE_JUMP_OUT_OF_RANGE = -117
#FASMERR_INVALID_EXPRESSION = -118
#FASMERR_INVALID_ADDRESS = -119
#FASMERR_INVALID_VALUE = -120
#FASMERR_VALUE_OUT_OF_RANGE = -121
#FASMERR_UNDEFINED_SYMBOL = -122
#FASMERR_INVALID_USE_OF_SYMBOL = -123
#FASMERR_NAME_TOO_LONG = -124
#FASMERR_INVALID_NAME = -125
#FASMERR_RESERVED_WORD_USED_AS_SYMBOL = -126
#FASMERR_SYMBOL_ALREADY_DEFINED = -127
#FASMERR_MISSING_END_QUOTE = -128
#FASMERR_MISSING_END_DIRECTIVE = -129
#FASMERR_UNEXPECTED_INSTRUCTION = -130
#FASMERR_EXTRA_CHARACTERS_ON_LINE = -131
#FASMERR_SECTION_NOT_ALIGNED_ENOUGH = -132
#FASMERR_SETTING_ALREADY_SPECIFIED = -133
#FASMERR_DATA_ALREADY_DEFINED = -134
#FASMERR_TOO_MANY_REPEATS = -135
#FASMERR_SYMBOL_OUT_OF_SCOPE = -136
#FASMERR_USER_ERROR = -140
#FASMERR_ASSERTION_FAILED = -141
DataSection
fasm_dll: IncludeBinary "FASM.dll"
EndDataSection
Prototype.l fasm_GetVersion()
Prototype.l fasm_Assemble(*lpszSource, *lpChunk, dwMemorySize.l, dwPassesLimit = 100, hDisplayPipe = #Null)
Prototype.l fasm_AssembleFile(*lpszSourceFile, *lpChunk, dwMemorySize.l, dwPassesLimit = 100, hDisplayPipe = #Null)
Prototype.l fasm_Procedure()
Global fasm_GetVersion .fasm_GetVersion = 0
Global fasm_Assemble .fasm_Assemble = 0
Global fasm_AssembleFile.fasm_AssembleFile = 0
Global fasm_hLibrary = 0
Procedure fasm_init()
fasm_hLibrary = LoadLibraryM(?fasm_dll)
If(fasm_hLibrary)
fasm_GetVersion = GetProcAddressM(fasm_hLibrary, "fasm_GetVersion")
fasm_Assemble = GetProcAddressM(fasm_hLibrary, "fasm_Assemble")
fasm_AssembleFile = GetProcAddressM(fasm_hLibrary, "fasm_AssembleFile")
ProcedureReturn 1
EndIf
EndProcedure
Procedure fasm_close()
If(fasm_hLibrary)
FreeLibraryM(fasm_hLibrary)
fasm_GetVersion = 0
fasm_Assemble = 0
fasm_AssembleFile = 0
EndIf
EndProcedure
Procedure fasm_Compile(*lpszSource, *lpdwBufferSize = 0)
Protected result = 0
Protected chunkSize.l = 4096
Protected *line.LINE_HEADER = 0
Protected *lpOut.FASM_STATE = AllocateMemory(chunkSize)
If(*lpOut)
Protected assemblerResult.l = fasm_Assemble(*lpszSource, *lpOut, SizeOf(FASM_STATE) + chunkSize)
If(assemblerResult <> #FASM_OK And assemblerResult <> #FASM_OUT_OF_MEMORY)
Debug "Error"
Debug *lpOut\error_code
*line = *lpOut\error_line
Debug *line\line_number
Else
While(assemblerResult = #FASM_OUT_OF_MEMORY)
chunkSize + 1024
*lpOut.FASM_STATE = ReAllocateMemory(*lpOut, chunkSize)
assemblerResult.l = fasm_Assemble(*lpszSource, *lpOut, SizeOf(FASM_STATE) + chunkSize)
If(assemblerResult <> #FASM_OK And assemblerResult <> #FASM_OUT_OF_MEMORY)
Debug "Error"
Debug *lpOut\error_code
*line = *lpOut\error_line
Debug *line\line_number
Break
EndIf
Wend
If(assemblerResult = #FASM_OK)
*vm = VirtualAlloc_(#Null, *lpOut\output_length, #MEM_COMMIT, #PAGE_EXECUTE_READWRITE)
If(*vm)
CopyMemory(*lpOut\output_data, *vm, *lpOut\output_length)
If(*lpdwBufferSize)
PokeL(*lpdwBufferSize, *lpOut\output_length)
EndIf
result = *vm
EndIf
EndIf
EndIf
FreeMemory(*lpOut)
EndIf
ProcedureReturn result
EndProcedure
Procedure fasm_Free(*lpvm)
VirtualFree_(*lpvm, 0, #MEM_RELEASE)
EndProcedure
If(fasm_init())
test.l = 10
asm.s + "use32" + #LF$
asm.s + "org 100h" + #LF$
asm.s + "xor eax, eax" + #LF$
asm.s + "mov eax, 100" + #LF$
asm.s + "add eax, 20" + #LF$
asm.s + "ret" + #LF$
dwSize.l
*chunk.fasm_Procedure = fasm_Compile(@asm, @dwSize)
If(*chunk)
Debug *chunk()
fasm_Free(*chunk)
EndIf
EndIf
Re: Real-time machine-code execution
Posted: Tue Sep 04, 2012 4:06 am
by jack
excellent!

Re: Real-time machine-code execution
Posted: Tue Sep 04, 2012 1:31 pm
by Crusiatus Black
So, I've got this to work, I'm assuming assembling and executing is possible, but
the second assembly example in this code causes a read error exception at address 6 or 7,
and 6 or 7 are the results MessageBoxA can return in this case. I'm not sure why this is
happening, because executing assembly like this is different from the PB inline assembly.
Any assembler experts here?
Code: Select all
; The following structure resides at the beginning of memory block provided
; to the fasm_Assemble function. The condition field contains the same value
; as the one returned by function.
; When function returns FASM_OK condition, the output_length and
; output_data fields are filled - with pointer to generated output
; (somewhere within the provided memory block) and the count of bytes stored
; there.
; When function returns FASM_ERROR, the error_code is filled with the
; code of specific error that happened and error_line is a pointer to the
; LINE_HEADER structure, providing information about the line that caused
; the error.
Structure FASM_STATE
condition.l
StructureUnion
output_length.l
error_code.l
EndStructureUnion
StructureUnion
output_data.l
error_line.l
EndStructureUnion
EndStructure
; The following structure has two variants - it either defines the line
; that was loaded directly from source, or the line that was generated by
; macroinstruction. First case has the highest bit of line_number set to 0,
; while the second case has this bit set.
; In the first case, the file_path field contains pointer to the path of
; source file (empty string if it's the source that was provided directly to
; fasm_Assemble function), the line_number is the number of line within
; that file (starting from 1) and the file_offset field contains the offset
; within the file where the line starts.
; In the second case the macro_calling_line field contains the pointer to
; LINE_HEADER structure for the line which called the macroinstruction, and
; the macro_line field contains the pointer to LINE_HEADER structure for the
; line within the definition of macroinstruction, which generated this one.
Structure LINE_HEADER
file_path.l
line_number.l
StructureUnion
file_offset.l
macro_calling_line.l
EndStructureUnion
Macro_line.l
EndStructure
; General errors and conditions
#FASM_OK = 0 ; FASM_STATE points to output
#FASM_WORKING = 1
#FASM_ERROR = 2 ; FASM_STATE contains error code
#FASM_INVALID_PARAMETER = -1
#FASM_OUT_OF_MEMORY = -2
#FASM_STACK_OVERFLOW = -3
#FASM_SOURCE_NOT_FOUND = -4
#FASM_UNEXPECTED_END_OF_SOURCE = -5
#FASM_CANNOT_GENERATE_CODE = -6
#FASM_FORMAT_LIMITATIONS_EXCEDDED = -7
#FASM_WRITE_FAILED = -8
; Error codes for FASM_ERROR condition
#FASMERR_FILE_NOT_FOUND = -101
#FASMERR_ERROR_READING_FILE = -102
#FASMERR_INVALID_FILE_FORMAT = -103
#FASMERR_INVALID_MACRO_ARGUMENTS = -104
#FASMERR_INCOMPLETE_MACRO = -105
#FASMERR_UNEXPECTED_CHARACTERS = -106
#FASMERR_INVALID_ARGUMENT = -107
#FASMERR_ILLEGAL_INSTRUCTION = -108
#FASMERR_INVALID_OPERAND = -109
#FASMERR_INVALID_OPERAND_SIZE = -110
#FASMERR_OPERAND_SIZE_NOT_SPECIFIED = -111
#FASMERR_OPERAND_SIZES_DO_NOT_MATCH = -112
#FASMERR_INVALID_ADDRESS_SIZE = -113
#FASMERR_ADDRESS_SIZES_DO_NOT_AGREE = -114
#FASMERR_DISALLOWED_COMBINATION_OF_REGISTERS = -115
#FASMERR_LONG_IMMEDIATE_NOT_ENCODABLE = -116
#FASMERR_RELATIVE_JUMP_OUT_OF_RANGE = -117
#FASMERR_INVALID_EXPRESSION = -118
#FASMERR_INVALID_ADDRESS = -119
#FASMERR_INVALID_VALUE = -120
#FASMERR_VALUE_OUT_OF_RANGE = -121
#FASMERR_UNDEFINED_SYMBOL = -122
#FASMERR_INVALID_USE_OF_SYMBOL = -123
#FASMERR_NAME_TOO_LONG = -124
#FASMERR_INVALID_NAME = -125
#FASMERR_RESERVED_WORD_USED_AS_SYMBOL = -126
#FASMERR_SYMBOL_ALREADY_DEFINED = -127
#FASMERR_MISSING_END_QUOTE = -128
#FASMERR_MISSING_END_DIRECTIVE = -129
#FASMERR_UNEXPECTED_INSTRUCTION = -130
#FASMERR_EXTRA_CHARACTERS_ON_LINE = -131
#FASMERR_SECTION_NOT_ALIGNED_ENOUGH = -132
#FASMERR_SETTING_ALREADY_SPECIFIED = -133
#FASMERR_DATA_ALREADY_DEFINED = -134
#FASMERR_TOO_MANY_REPEATS = -135
#FASMERR_SYMBOL_OUT_OF_SCOPE = -136
#FASMERR_USER_ERROR = -140
#FASMERR_ASSERTION_FAILED = -141
DataSection
fasm_dll: IncludeBinary "FASM.dll"
EndDataSection
Prototype.l fasm_GetVersion()
Prototype.l fasm_Assemble(*lpszSource, *lpChunk, dwMemorySize.l, dwPassesLimit = 100, hDisplayPipe = #Null)
Prototype.l fasm_AssembleFile(*lpszSourceFile, *lpChunk, dwMemorySize.l, dwPassesLimit = 100, hDisplayPipe = #Null)
Prototype.l fasm_Procedure()
Global fasm_GetVersion .fasm_GetVersion = 0
Global fasm_Assemble .fasm_Assemble = 0
Global fasm_AssembleFile.fasm_AssembleFile = 0
Global fasm_hLibrary = 0
Procedure fasm_init()
fasm_hLibrary = LoadLibraryM(?fasm_dll)
If(fasm_hLibrary)
fasm_GetVersion = GetProcAddressM(fasm_hLibrary, "fasm_GetVersion")
fasm_Assemble = GetProcAddressM(fasm_hLibrary, "fasm_Assemble")
fasm_AssembleFile = GetProcAddressM(fasm_hLibrary, "fasm_AssembleFile")
ProcedureReturn 1
EndIf
EndProcedure
Procedure fasm_close()
If(fasm_hLibrary)
FreeLibraryM(fasm_hLibrary)
fasm_GetVersion = 0
fasm_Assemble = 0
fasm_AssembleFile = 0
EndIf
EndProcedure
Procedure fasm_Compile(*lpszSource, *lpdwBufferSize = 0)
Protected result = 0
Protected chunkSize.l = 4096
Protected *line.LINE_HEADER = 0
Protected *lpOut.FASM_STATE = AllocateMemory(chunkSize)
If(*lpOut)
Protected assemblerResult.l = fasm_Assemble(*lpszSource, *lpOut, SizeOf(FASM_STATE) + chunkSize)
If(assemblerResult <> #FASM_OK And assemblerResult <> #FASM_OUT_OF_MEMORY)
Debug "Error"
Debug *lpOut\error_code
*line = *lpOut\error_line
Debug *line\line_number
Else
While(assemblerResult = #FASM_OUT_OF_MEMORY)
chunkSize + 1024
*lpOut.FASM_STATE = ReAllocateMemory(*lpOut, chunkSize)
assemblerResult.l = fasm_Assemble(*lpszSource, *lpOut, SizeOf(FASM_STATE) + chunkSize)
If(assemblerResult <> #FASM_OK And assemblerResult <> #FASM_OUT_OF_MEMORY)
Debug "Error"
Debug *lpOut\error_code
*line = *lpOut\error_line
Debug *line\line_number
Break
EndIf
Wend
If(assemblerResult = #FASM_OK)
*vm = VirtualAlloc_(#Null, *lpOut\output_length, #MEM_COMMIT, #PAGE_EXECUTE_READWRITE)
If(*vm)
CopyMemory(*lpOut\output_data, *vm, *lpOut\output_length)
If(*lpdwBufferSize)
PokeL(*lpdwBufferSize, *lpOut\output_length)
EndIf
result = *vm
EndIf
EndIf
EndIf
FreeMemory(*lpOut)
EndIf
ProcedureReturn result
EndProcedure
Procedure fasm_Free(*lpvm)
VirtualFree_(*lpvm, 0, #MEM_RELEASE)
EndProcedure
Import "user32.lib"
MessageBoxA(hWnd.l, szMessage.s, szTitle.s, dwFlags.l)
EndImport
If(fasm_init())
; works
asm.s + "use32" + #LF$
asm.s + "org 100h" + #LF$
asm.s + "xor eax, eax" + #LF$
asm.s + "mov eax, 100" + #LF$
asm.s + "add eax, 20" + #LF$
asm.s + "ret" + #LF$
flags = #MB_YESNO | #MB_ICONINFORMATION
hWnd = 0
szTitle.s = "Hello World!!"
szMessage.s = "This function was executed through an FASM assembler via PureBasic! 0_o"
hwnd = 0
pfunc = @MessageBoxA()
asm2.s + "use32" + #LF$
asm2.s + "org 100h" + #LF$
asm2.s + "mov [esp+12], dword " + Str(flags) + "" + #LF$
asm2.s + "mov [esp+08], dword " + Str(@szTitle) + #LF$
asm2.s + "mov [esp+04], dword " + Str(@szMessage) + #LF$
asm2.s + "mov [esp+00], dword " + Str(hwnd) + #LF$
asm2.s + "xor eax, eax" + #LF$
asm2.s + "mov ecx, dword " + Str(@MessageBoxA()) + "" + #LF$
asm2.s + "call ecx" + #LF$
asm2.s + "ret" + #LF$
dwSize.l = 0
; works, returns 120
*myMessageBox.fasm_Procedure = fasm_Compile(@asm, @dwSize)
If(*myMessageBox)
Debug *myMessageBox()
fasm_Free(*myMessageBox)
EndIf
; Doesn't work, tries interpreting the MessageBoxA result as memory address?
*myMessageBox.fasm_Procedure = fasm_Compile(@asm2, @dwSize)
If(*myMessageBox)
Debug *myMessageBox()
fasm_Free(*myMessageBox)
EndIf
EndIf
Re: Real-time machine-code execution
Posted: Tue Sep 04, 2012 2:21 pm
by wilbert
What is LoadLibraryM ?
I get an error message on that.
Re: Real-time machine-code execution
Posted: Tue Sep 04, 2012 2:25 pm
by Crusiatus Black
LoadLibraryM is a procedure from the LoadDllMemory library in PBOSL
http://pbosl.purearea.net/index.php?site=Libs
It allows you to load a library from a memory buffer (e.g. a IncludeBinary label) and
call its functions.
Re: Real-time machine-code execution
Posted: Tue Sep 04, 2012 2:33 pm
by wilbert
Got it
Not about your problem, simply push your variables like this
Code: Select all
asm2.s + "push dword " + Str(flags) + "" + #LF$
asm2.s + "push dword " + Str(@szTitle) + #LF$
asm2.s + "push dword " + Str(@szMessage) + #LF$
asm2.s + "push dword " + Str(hwnd) + #LF$
instead of using the mov instruction.
Windows internal calls are usually stdcall meaning that the called procedure cleans up the stack.
So after the procedure is done, it adjusts the stack pointer for the four dwords you placed on the stack but since your code didn't change the stack pointer, it crashes.
Re: Real-time machine-code execution
Posted: Tue Sep 04, 2012 2:36 pm
by jack
yes, I just found out the same thing.
Re: Real-time machine-code execution
Posted: Tue Sep 04, 2012 2:37 pm
by Crusiatus Black
Ahh great, that works, thanks mate! The additional info is appreciated too!
Awesome, I like this haha!
Re: Real-time machine-code execution
Posted: Tue Sep 04, 2012 2:53 pm
by jack
Trond posted some code to compile expressions to asm that you may find interesting
http://www.purebasic.fr/english/viewtop ... 7&start=30
he also started compiler tutorial somewhere.
Re: Real-time machine-code execution
Posted: Tue Sep 04, 2012 3:25 pm
by Crusiatus Black
Cool, that's a fun read! Thanks. With this FASM dll one could execute the generated code!

Re: Real-time machine-code execution
Posted: Wed Sep 05, 2012 9:58 am
by DoctorLove
Well, im doing it all with
http://www.oxygenbasic.org/
Its a simple DLL which compiles and execute basic code on the fly.
The language is Mature and basic to learn.
MAC osx and Linux are in the making.
Im sold to it.