flat assembler
Message board for the users of flat assembler.

Index > High Level Languages > [Tutorial] Using FASM to create python modules

Author
Thread Post new topic Reply to topic
OzzY



Joined: 19 Sep 2003
Posts: 1029
Location: Everywhere
OzzY 07 May 2007, 18:15
Hello!
I've being playing with Python, and I have to say it's a wonderful language!
It really makes life easier.

Now, I'm here to show you how to use FASM to create new modules for using in Python. Razz

1) The first step is to create a DLL in FASM:
Code:
; TESTDLL.DLL

format PE GUI 4.0 DLL
entry DllEntryPoint

include 'win32a.inc'

section '.code' code readable executable

proc DllEntryPoint hinstDLL,fdwReason,lpvReserved
        mov     eax,TRUE
        ret
endp

; void showMessage(char * msg);

proc showMessage, msg
     invoke MessageBox,0,[msg],[msg],0
ret
endp

proc addnums, x : DWORD, y : DWORD
     mov eax, [x]
     add eax, [y]
     ret
endp

section '.idata' import data readable writeable

  library user,'USER32.DLL'

  import user,\
         MessageBox,'MessageBoxA'

section '.edata' export data readable

  export 'testDLL.DLL',\
         showMessage,'_showMessage',\
         addnums,'_addnums'

section '.reloc' fixups data discardable
    

As you can see, it's pretty easy to do. You can just modify the template that comes in \examples folder.

2) Now we can wrap the calling of that function in a nice python module (you can wrap as many functions as you need):
This is python code:
Code:
# fasmmodule.py
from ctypes import *

mydll = windll.LoadLibrary("testDLL.dll")

def showMessage(n):
    mydll._showMessage(n)

def addnums(x, y):
    return mydll._addnums(x, y)
    


3) Now you can use that function just like you do with any Python Module:
Code:
# test.py
from fasmmodule import *

showMessage("Hello world!")

print addnums(2,3)
    


There you go! Use the power of ASM in a easy and syntax-clear scripting language known as Python!
Just remember to put the DLL and the Module on your path or script directory!
You can even generate the EXE with py2exe to distribute your application.

Feel free to leave comments!
And I hope you like my simple tutorial.

EDIT: Added addnums function example. Should be enough if you want to do you complex calculus in FASM and use it your Python program. I'll add more data passing soon.


Last edited by OzzY on 07 May 2007, 18:45; edited 1 time in total
Post 07 May 2007, 18:15
View user's profile Send private message Reply with quote
vid
Verbosity in development


Joined: 05 Sep 2003
Posts: 7105
Location: Slovakia
vid 07 May 2007, 18:24
maybe you could experiment with more data passing in/out of ASM DLL. For example some structures
Post 07 May 2007, 18:24
View user's profile Send private message Visit poster's website AIM Address MSN Messenger ICQ Number Reply with quote
Nikolay Petrov



Joined: 22 Apr 2004
Posts: 101
Location: Bulgaria
Nikolay Petrov 20 May 2007, 12:19
Wink


Description:
Download
Filename: PyConsole.rar
Filesize: 121.25 KB
Downloaded: 1292 Time(s)


_________________
regards
Post 20 May 2007, 12:19
View user's profile Send private message Reply with quote
treeform



Joined: 09 Jul 2007
Posts: 6
treeform 09 Jul 2007, 05:10
I been doing very similar thing with with "pyFasm" library in which you can using inline fasm code in python ... verry neat but still buggy and incomplete and works only in linux
Post 09 Jul 2007, 05:10
View user's profile Send private message Reply with quote
Rahsennor



Joined: 07 Jul 2007
Posts: 61
Rahsennor 09 Jul 2007, 08:35
I've been doing the same thing (Accessing a FASM DLL) for Lua. It's almost exactly the same, only you have to access the Lua stack explicitly. This looks much easier.

1st post! Very Happy
Post 09 Jul 2007, 08:35
View user's profile Send private message Reply with quote
DVicthor



Joined: 13 Sep 2013
Posts: 3
Location: Nigeria
DVicthor 16 Sep 2013, 16:38
Instead of creating a python function for all the exported functions in the DLL, you could just:
Code:
def bind(name):
    mydll = windll.LoadLibrary('testDLL.dll')
    if hasattr(mydll,name):
        func = getattr(mydll,name)
        return func
    else:
        raise AttributeError("Function '%s' does not exist in mydll!" % name)
    

And then bind a function like:
Code:
showMessage = bind('_showMessage')
addnums = bind('_addnums')
    

It makes your code cleaner and saves you some time that would be wasted typing.

_________________
Code until your brain explodes! Very Happy
Post 16 Sep 2013, 16:38
View user's profile Send private message Reply with quote
kador



Joined: 03 Jun 2023
Posts: 4
kador 26 Jul 2023, 14:18
I have tried to extend the example (EXAMPLES/WIN64/DLL) accordingly (WRITEMSG.ASM):
Code:
entry DllEntryPoint

include 'win64a.inc'

section '.text' code readable executable

proc DllEntryPoint hinstDLL,fdwReason,lpvReserved
        mov     eax,TRUE
        ret
endp

proc WriteMessage uses rbx rsi rdi, message
        mov     rdi,rcx                         ; first parameter passed in RCX
        invoke  GetStdHandle,STD_OUTPUT_HANDLE
        mov     rbx,rax
        xor     al,al
        or      rcx,-1
        repne   scasb
        dec     rdi
        mov     r8,-2
        sub     r8,rcx
        sub     rdi,r8
        invoke  WriteFile,rbx,rdi,r8,bytes_count,0
        ret
endp

proc addnums uses rax, x : QWORD, y : QWORD
     mov     rax, [x]
     add     rax, [y]
     ret
endp

section '.bss' data readable writeable

  bytes_count dd ?

section '.edata' export data readable

  export 'WRITEMSG.DLL', WriteMessage,'_WriteMessage', addnums,'_addnums'

section '.reloc' fixups data readable discardable

  if $=$$
    dd 0,8              ; if there are no fixups, generate dummy entry
  end if

section '.idata' import data readable writeable

  library kernel32,'KERNEL32.DLL'

  include 'api/kernel32.inc'  
    


I can complile the source code, but I can't access it with Python (see DVictor, test2.py):
Code:
from ctypes import *


def bind(name):
    mydll = windll.LoadLibrary('.\WRITEMSG.DLL')
    if hasattr(mydll,name):
        func = getattr(mydll,name)
        return func
    else:
        raise AttributeError("Function '%s' does not exist in mydll!" % name)
    
    
WriteMessage = bind('_WriteMessage')
addnums = bind('_addnums')

WriteMessage("Hallo Welt")
print()
print(addnums(3,5))
    

The output is confusing to me:

> python test2.py
H
1157775757

The output provides neither the correct text ("Hallo Welt!") nor the correct sum.
Can someone help me?
many thanks
Daniel (kador)
Post 26 Jul 2023, 14:18
View user's profile Send private message Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20172
Location: In your JS exploiting you and your system
revolution 26 Jul 2023, 17:58
You are missing the format line.
Code:
format PE GUI 4.0 DLL
;...    
Post 26 Jul 2023, 17:58
View user's profile Send private message Visit poster's website Reply with quote
kador



Joined: 03 Jun 2023
Posts: 4
kador 27 Jul 2023, 10:39
Thank you revolution, you have noticed that correctly. However, that was just a carelessness when copying the sorucecode. A GUI is not needed, of course. The first two original lines are:

format PE64 console DLL
entry DLLEntryPoint

It makes no difference which of the first two lines I use ('PE64 GUI 4.0' or 'PE64 console') the output is the same:

> python .\test2.py
H
-1429192307
Post 27 Jul 2023, 10:39
View user's profile Send private message Reply with quote
Roman



Joined: 21 Apr 2012
Posts: 1708
Roman 27 Jul 2023, 11:31
Maybe Unicode in python ?

Write simple fasm tester your dll.
And what show(value) fasm tester.
Than search what wrong do python with your dll.
Post 27 Jul 2023, 11:31
View user's profile Send private message Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20172
Location: In your JS exploiting you and your system
revolution 27 Jul 2023, 12:07
You can't mention Unicode without saying how it is encoded.

You will need to examine the format of the data that Python sends.

For text strings it might be UTF-32, or UFT-16.

For integers, it could be a Python object, or a pointer to a 64-bit value. Also keep in mind that Python supports arbitrary precision integers, so a basic 64-bit value might not even exist in the data it sends.

I suggest that if trying to navigate the Python docs is too painful, then use a debugger to examine the incoming data.
Post 27 Jul 2023, 12:07
View user's profile Send private message Visit poster's website Reply with quote
kador



Joined: 03 Jun 2023
Posts: 4
kador 28 Jul 2023, 11:25
For me, the problem is now solved. I have used the register eax instead of the register rax in the procedure addnums. 32 bits are enough for me. The question with the string is still open. However, I'm beginning to think that this is less a question for flat assembler and more a question for the Python module ctypes. I noticed that even the 32 bit example from OzzY only outputs the first letter of the string. I will ask in appropriate forums and post the solution here if necessary. I can do without the WriteMessage function, because it outputs text to the console, which I can also do directly with Python. For completeness I post the code for the function addnums 64 bit.

Code:
format PE64 console DLL
entry DllEntryPoint

include 'win64a.inc'

section '.text' code readable executable

proc DllEntryPoint hinstDLL,fdwReason,lpvReserved
        mov     eax,TRUE
        ret
endp

proc addnums, x : DWORD, y : DWORD ; addiert ganze Zahlen im 32-Bit-Bereich (-2147483648 bis 2147483647)
     mov     eax, [x]
     add     eax, [y]
     ret
endp

section '.bss' data readable writeable

  bytes_count dd ?

section '.edata' export data readable

  export 'WRITEMSG.DLL', addnums,'_addnums'

section '.reloc' fixups data readable discardable

  if $=$$
    dd 0,8              ; if there are no fixups, generate dummy entry
  end if

section '.idata' import data readable writeable

  library kernel32,'KERNEL32.DLL'

  include 'api/kernel32.inc'
    

Python:
Code:
from ctypes import *


def bind(name):
    mydll = windll.LoadLibrary('.\WRITEMSG.DLL')
    if hasattr(mydll,name):
        func = getattr(mydll,name)
        return func
    else:
        raise AttributeError("Function '%s' does not exist in mydll!" % name)
    
    
addnums = bind('_addnums')

print(addnums(0,1))
print(addnums(1,1))
print(addnums(1,2))
print(addnums(2,3))
print(addnums(3,5))
print(addnums(5,8))
    

Output:
> python .\test2.py
1
2
3
5
8
13

Many thanks for the help
Daniel
Post 28 Jul 2023, 11:25
View user's profile Send private message Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20172
Location: In your JS exploiting you and your system
revolution 28 Jul 2023, 12:05
Looking at the code, I see that you are using [x] and [y] directly. Strictly by the fastcall convention this is not guaranteed to work. The first two values will be in RCX and RDX.
Code:
proc addnums, x, y
     mov     rax, rcx
     add     rax, rdx
;    lea     rax, [rcx + rdx] ; alternative single instruction
     ret
endp    
Post 28 Jul 2023, 12:05
View user's profile Send private message Visit poster's website Reply with quote
ProMiNick



Joined: 24 Mar 2012
Posts: 789
Location: Russian Federation, Sochi
ProMiNick 28 Jul 2023, 12:52
kador wrote:
A GUI is not needed, of course.
format PE64 console DLL

when we create PE with console format we additionaly attach 3 pipes: STDIN, STDOUT, STDERR but nothing is reduced against GUI
So, correct would be
A console is not needed, of course. because GUI is more lighter form of PE (but in case of DLL seems no matter)
format PE64 GUI DLL

_________________
I don`t like to refer by "you" to one person.
My soul requires acronim "thou" instead.
Post 28 Jul 2023, 12:52
View user's profile Send private message Send e-mail Reply with quote
kador



Joined: 03 Jun 2023
Posts: 4
kador 28 Jul 2023, 13:47
Thanks again for the help, I appreciate it very much!
Thanks revolution for the tip? Thanks ProMiNick for the teaching.
Now I have also been able to solve the string problem.
Python 3 distinguishes str and byte. If I pass the string as follows, everything works fine!
b "Hello world!"
Kind regards
Post 28 Jul 2023, 13:47
View user's profile Send private message Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  


< Last Thread | Next Thread >
Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2024, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.