Jump to content

Recommended Posts

Posted (edited)

a little function called _AssembleIt() makes Wards "embedded" FASM-Assembler more embedded. The function is a "wrapper" for all the FASMxxx() and FASMyyy()-stuff.

EDIT 03-20-2011:

AssembleIt now includes a possibility to show the content of registers, flags,XMM-registers, FPU-registers and the stack during the runtime of the asm-code. Someone called this a "Debugger", it´s really not a debugger, it´s a chaotic piece of a script.

*/Sry, but i am not be able to put pictures or links in this post/*

There are some nice features (i.e. running the asm-code until a register contains a specific content), so it could help sometimes...

You can find AssembleIt and an example how to use it here or in the attached zipfile. Have fun!

After including the AssembleIt.au3 the Assemblercode can be written like:

;Example for _AssembleIt()
;32 Bit only!
#include <AssembleIt.au3>

Func _Add_int()                         ;any functionname, used by _AssembleIt()
    _("use32")                          ;32 Bit
    _("mov eax,dword[esp+4]")           ;read 1st parameter in Register EAX=22
    _("add eax,dword[esp+8]")           ;add 2nd parameter EAX=EAX+33
    _("ret")                            ;Returns result in EAX back to the calling function  ;NO STACK CLEANING NECESSARY!
EndFunc                                 ;==>_Add_int

;_AssembleIt($Returntype, $Name_of_Func_with_code, $Type1 = "type", $Param1 = 0, $Type2 = "type", $Param2 = 0....up to 20 params)
$ret = _AssembleIt("int", "_Add_int", "int", 22, "int", 33)  ;thats all^^
MsgBox(0, 'Result _Add_int()', $ret)  ;no array returned by _AssembleIt()

Syntax check is integrated, and some more. See the examples!

If your Assemblercode is running well and you don´t want to drag all the _ASMcode()-functions, AssembleIt.au3, FASM.au3 and MemoryDll.au3 with your script, it is now easy to make a "standalone" Version using a CallWindowProcW-call (which is much faster btw.)

If you have a Script:

#include <AssembleIt.au3>
#include <GDIPlus.au3>
;32Bit only!

Func _grayscale()
    _("use32")                              ;32Bit!

    _("mov esi,dword[esp+4]")                  ;Startadress Bitmapdata (Pixel)
    _("mov ecx,dword[esp+8]")                  ;number of Pixel
    _("mov edi,21845")                      ;konstant, *21845/2^16 is approximately 1/3 (replaces the slow DIV 3)

    _("_loop1:")                            ;until ecx=0
    _("mov edx,[esi]")                      ;load pixel  AARRGGBB  (RR+GG+BB)/3 = colour grayscale
    _("mov al,dl")                          ;lowbyte (BB) Pixel to lowbyte al
    _("movzx bx,dh")                        ;highbyte (GG) Pixel to lowbyte of bx (bh is 0)
    _("shr edx,8")                          ;shift RR into dh
    _("add ax,bx")                          ;BB + GG
    _("movzx bx,dh")                        ;highbyte (RR) Pixel to lowbyte of bx (bh ist 0)
    _("add ax,bx")                          ;and add: dx=RR+GG+BB
    _("mul edi")                            ;ax=ax*21845      *21845/2^16 is about 1/3
    _("shr eax,16")                            ;ax=ax/2^16   in al is now the greyscale colour for RR, GG und BB
    _("movzx dx,al")                        ;grayscale to dl,  dh = 0
    _("shl edx,16")                            ;grayscale to RR,  AA = 0!
    _("mov dh,al")                          ;grayscale to GG
    _("mov dl,al")                          ;grayscale to BB    edx is now 00alalal = grayscale AARRGGBB
    _("mov [esi],edx")                      ;write pixel

    _("add esi,4")                          ;address next pixel: 4 Byte = 1 dword = 1 Pixel
    _("sub ecx,1")                          ;counter (next pixel)
    _("ja _loop1")                          ;until ecx=0
    ;upper 3 lines are faster than _("loop _loop1")            ;until ecx=0
    _("ret ")                                  ;return
EndFunc                                        ;==>_grayscale


$file = FileOpenDialog("Select 24 or 32 Bpp image!", @ScriptDir, "Image (*.jpg;*.bmp)", 1 + 2)
if @error then exit

_GDIPlus_Startup()
$hBitmap = _GDIPlus_BitmapCreateFromFile($file)
$iWidth = _GDIPlus_ImageGetWidth($hBitmap)
$iHeight = _GDIPlus_ImageGetHeight($hBitmap)
$hBitmapData = _GDIPlus_BitmapLockBits($hBitmap, 0, 0, $iWidth, $iHeight, BitOR($GDIP_ILMREAD, $GDIP_ILMWRITE), $GDIP_PXF32RGB)
$Scan = DllStructGetData($hBitmapData, "Scan0")
$Stride = DllStructGetData($hBitmapData, "Stride")
$tPixelData = DllStructCreate("dword[" & (Abs($Stride * $iHeight)) & "]", $Scan)


;$_ASSEMBLEIT_FLAG = 0   ;after uncomment this line, run the script, and replace the following line with the content of the clipboard, then delete #include <AssembleIt.au3> and the _grayscale()-function
$ret=_AssembleIt("ptr","_grayscale","ptr", DllStructGetPtr($tPixelData), "int", $iWidth * $iHeight)  ;ptr als Rückgabe, um die hexzahlen schön zu sehen

_GDIPlus_BitmapUnlockBits($hBitmap, $hBitmapData)
_GDIPlus_ImageSaveToFile($hBitmap, @ScriptDir & "\greyscale.jpg")
_GDIPlus_Shutdown()

ShellExecute(@ScriptDir & "\greyscale.jpg")

uncomment the line "$_ASSEMBLEIT_FLAG = 0" and run the script again._AssembleIt() creates now 3 lines AutoItcode and writes them into the Clipboard.

Replace the line "$_ASSEMBLEIT_FLAG = 0" with the content of the clipboard (ctrl+v) and replace the param-variables (types were transfered) with the right ones from the "$ret=_AssembleIt("ptr"....blahblah)". Delete the "#include <AssembleIt.au3>" and the the function _grayscale() to get the following script

#include <GDIPlus.au3>
;32Bit only!

$file = FileOpenDialog("Select 24 or 32 Bpp image!", @ScriptDir, "Image (*.jpg;*.bmp)", 1 + 2)
if @error then exit

_GDIPlus_Startup()
$hBitmap = _GDIPlus_BitmapCreateFromFile($file)
$iWidth = _GDIPlus_ImageGetWidth($hBitmap)
$iHeight = _GDIPlus_ImageGetHeight($hBitmap)
$hBitmapData = _GDIPlus_BitmapLockBits($hBitmap, 0, 0, $iWidth, $iHeight, BitOR($GDIP_ILMREAD, $GDIP_ILMWRITE), $GDIP_PXF32RGB)
$Scan = DllStructGetData($hBitmapData, "Scan0")
$Stride = DllStructGetData($hBitmapData, "Stride")
$tPixelData = DllStructCreate("dword[" & (Abs($Stride * $iHeight)) & "]", $Scan)


Global $tCodeBuffer = DllStructCreate("byte[61]") ;reserve Memory for opcodes
DllStructSetData($tCodeBuffer, 1,"0x8B7424048B4C2408BF555500008B1688D0660FB6DEC1EA086601D8660FB6DE6601D8F7E7C1E810660FB6D0C1E21088C688C2891683C60483E90177D1C3") ;write opcodes into memory
$ret=DllCall("user32.dll", "ptr", "CallWindowProcW", "ptr", DllStructGetPtr($tCodeBuffer),"int",DllStructGetPtr($tPixelData), "int", $iWidth * $iHeight,"int",0,"int",0)

_GDIPlus_BitmapUnlockBits($hBitmap, $hBitmapData)
_GDIPlus_ImageSaveToFile($hBitmap, @ScriptDir & "\greyscale.jpg")
_GDIPlus_Shutdown()

ShellExecute(@ScriptDir & "\greyscale.jpg")

I have written a "tutorial" (unfortunately for you in german language) how to put and get AutoIt-variables into the ASM-code. There are also some examples how to use ASM-variables (VAR db 8 dup(7) ) in the ASM-code without a "org "&FasmGetBasePtr($Fasm), SSE-examples, speedup ASM with LUT and more....please feel free to ask me if you have questions. I am not an Assembler-"crack", but i like to speed up some functions with a little ASM...

After i had written this tutorial, i wrote _AssembleIt() . And now i am too lazy to rewrite all FASMxxx()-stuff-examples into _AssembleIt()-style . Apologize....

I see _AssembleIt() as a proof of concept, so i expect your comments/tips/hints/improvements!

AssembleIt.zip

Edited by AndyG
Posted (edited)

AndyG,

Global $tCodeBuffer = DllStructCreate("byte[61]") ;reserve Memory for opcodes
DllStructSetData($tCodeBuffer, 1,"0xC3") ;write opcodes into memory (cut short)

Be wary of allocating memory from the Heap, and then executing code there.

Thats a big no-no. DEP (Data Execution Prevention) can prevent the code from running, or cause it to crash.

Use VirtualAlloc, or GlobalAlloc with VirtualProtect to set up code execution areas.

*edit: copy and paste goof

Edited by Ascend4nt
Posted

@Ascendant,

DEP (Data Execution Prevention) can prevent...

that´s surely true. I never had activated/permitted DEP in any way, and perhaps that is the reason why i do not have any problems with(out) itPosted Image

But yes, to avoid possible errors, Global/Local-alloc is far away from no-no. Although MSDN mentioned

Memory objects allocated by GlobalAlloc and LocalAlloc are in private, committed pages with read/write access that cannot be accessed by other processes

and

Although the GlobalAlloc, LocalAlloc, and HeapAlloc functions ultimately allocate memory from the same heap, each provides a slightly different set of functionality.

, i´ll trust you.
$pointer_tCodeBuffer=dllcall("kernel32.dll","ptr","GlobalAlloc","uint",0x40, "ulong_ptr", 61)  ;0x40=GPTR
Global $tCodeBuffer = DllStructCreate("byte[61]",$pointer_tCodeBuffer[0]) ;reserve Memory for opcodes

Somehow I already thought this... doing archaic things is also one of my preferences.  ;)
Posted

Well, I guess you learn something new everyday. I was under the impression that GlobalAlloc used a different allocation resource than HeapAlloc does, since it is a type of 'sharing' memory resource. But nope - by using the API calls GetProcessHeap+HeapAlloc and comparing the results to GlobalAlloc, I see they both use the same heap (verified with VirtualQuery). Of course, DllStructCreate gives a completely different memory address - but that's due to those functions using a different heap (each process generally has a few heaps to draw resources from).

I've always used VirtualAlloc myself, and it was only when I saw trancexx's GIF code that I began to consider using GlobalAlloc. However I'm not so sure that's a good idea now. This one quote from MSDN still makes me doubt this is a good idea at all:

It is best to avoid using VirtualProtect to change page protections on memory blocks allocated by GlobalAlloc, HeapAlloc, or LocalAlloc, because multiple memory blocks can exist on a single page. The heap manager assumes that all pages in the heap grant at least read and write access.

While the protection type of PAGE_EXECUTE_READWRITE doesn't remove the regular access types, it can potentially cause a slight security risk if other memory blocks in the same page exist. Not a huge deal though..

I think now however that the best method (a least for me personally) would be to use either VirtualAlloc or create a new Heap (HeapCreate), which would be created specifically for executing machine code.

Hmm, well I apologize for the length of this post. I suppose your method would work with VirtualProtect, but you'll lose the allocation you make if you create it locally and don't return the DLLStruct (pointers to it will be invalidated once the struct is gone). That'd be at least one good reason to allocate the memory using an API call. (Remember DLLStructCreate accepts pointers, and this is where you'll need it)

Thanks for making me dig a little deeper into this stuff. MSDN is a great resource, but its difficult at times to find out how certain things connect together ;)

Posted

AndyG

Referring to the image data, and in particular Scan0 - The element Scan0, which is in the $tagGDIPBITMAPDATA structure, which is returned from the _GDIPlus_BitmapLockBits() function, is a pointer to the first (index 0) scan line of the bitmap.

Note the variable $Scan is the same value, and can replace DllStructGetPtr($tPixelData) in your script. And, it appears "$tPixelData = DllStructCreate("dword[" & (Abs($Stride * $iHeight)) & "]", $Scan)" is not necessary (redundant) when $Scan is used.

I thought you might find that interesting.

Posted (edited)

@Malkey, 

you are right! The struct that you mentioned is one of the relics from the making of Assemblercode based on some older AutoIt-dllstructsetdata(Work_with_Bitmapdata)-Scripts. 

Sometimes it is useful to ask:"Hey, whats going on in the memory?". From AutoIt, the only chance you have to "see" some Bytes is the usage of dllstruct()....From time to time my first try of an idea is implemented in Autoitcode. Then i have to write/read Bits and Bytes and without dllstruct() nothing would ever happen  ;)

Edited by AndyG
  • 4 months later...
Posted (edited)

AssembleIt() now with a "debugger", see first post please.

/edit/ i cannot edit the first post...always get a message "You must enter a post."

EDIT 03-20-2011: AssembleIt now includes a possibility to show the content of registers, flags, xmm-registers, FPU-registers and the stack during the runtime of the asm-code. Someone called this a "Debugger", it´s really not a debugger, it´s a chaotic piece of a script. :)

picture

There are some nice features (i.e. running the asm-code until a register contains a specific content), so it could help sometimes...

You can find AssembleIt and an example how to use it here or in the attached zipfile. Have fun!

Edited by AndyG

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...