Jump to content

Autoit api thread * update


Celtic88
 Share

Recommended Posts

hello ! 

just for fun 

simple code to call dll api in new  thread ...

*update 21/02/2021 

 -add callback for return api call

-add x64 

 

;by celtic 88

#include <Memory.au3>
#include <WinAPISys.au3>
#include <WinAPIProc.au3>
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <WinAPIEx.au3>
#include <WindowsConstants.au3>
#include <WinAPIMem.au3>

Global $thread_Class = 'thread_Class1'
Local $hProc = DllCallbackRegister('thread_WM', 'lresult', 'hwnd;uint;wparam;lparam')
Local $tClass = DllStructCreate('wchar[' & StringLen($thread_Class) + 1 & ']')
DllStructSetData($tClass, 1, $thread_Class)
Local $tWCEX = DllStructCreate($tagWNDCLASSEX)
DllStructSetData($tWCEX, 'Size', DllStructGetSize($tWCEX))
DllStructSetData($tWCEX, 'hWndProc', DllCallbackGetPtr($hProc))
DllStructSetData($tWCEX, 'ClassName', DllStructGetPtr($tClass))
_WinAPI_RegisterClassEx($tWCEX)

Global $opcode_struct = 'ptr WaitForSingleObject;' & _
        'ptr SendMessage;' & _
        'ptr GetLastError;' & _
        'ptr henvent;' & _
        'ptr hwnd;' & _
        'ptr pproc;' & _
        'ptr isprocessing;' & _
        'ptr lreturn;ptr hreturn;' & _
        'ptr LastError;' & _
        'ptr exitthread;' & _
        'ptr parm[100];ptr rsv[20];WCHAR callback[100]'
Local $opcode = '0x668CC83C337449' & _
        '8B7C24046AFFFF770CFF1785C07403FF47288B5F2885DB75118D772C8B0E85C97405FF348EE2FBFF571489471C895720FF570889472431C0894718535750FF7710FF570485DB74BCC3' & _
        '4881EC480300004889CB4831D248FFCA488B4B18FF134885C0740448FF43504C8B7B504D85FF753A488D735848AD4885C0742C4989C64831C94883C10448AD50E2FB4983EE04493' & _
        '9CE7E0E4C89F1488D7C244048AD48ABE2FA415941585A59FF53284889433848895340FF5310488943484831D2488953304D89F94989D8488B4B20FF53084D85FF74804881C448030000C3'
Global $pshll = _MemVirtualAlloc(0, BinaryLen($opcode), $MEM_COMMIT, $PAGE_EXECUTE_READWRITE)
DllStructSetData(DllStructCreate('byte[' & BinaryLen($opcode) & ']', $pshll), 1, $opcode)

Func thread_WM($hWnd, $iMsg, $wParam, $lParam) ;window call back
    If $iMsg = $WM_NULL Then
        Local $thi = DllStructCreate($opcode_struct, $wParam)
        If $lParam <> 0 Then DllStructSetData($thi, 'rsv', -2, 4)
        DllStructSetData($thi, 'rsv', DllStructGetData($thi, 'rsv', 4) + 1, 4)
        Call(DllStructGetData($thi, 'callback'), $thi, DllStructGetData($thi, 'rsv', 4))
        If $lParam <> 0 Then
            _WinAPI_DestroyWindow($hWnd)
            _WinAPI_CloseHandle(DllStructGetData($thi, 'henvent'))
            _MemGlobalFree($wParam)
        EndIf
    EndIf
    Return _WinAPI_DefWindowProc($hWnd, $iMsg, $wParam, $lParam)
EndFunc   ;==>thread_WM

Func thread_create($scallback) ; create new remote api thread
    Local $thi = DllStructCreate($opcode_struct, _MemGlobalAlloc(DllStructGetSize(DllStructCreate($opcode_struct)), $GPTR))
    DllStructSetData($thi, 'WaitForSingleObject', _WinAPI_GetProcAddress(_WinAPI_LoadLibrary('kernel32'), 'WaitForSingleObject'))
    DllStructSetData($thi, 'SendMessage', _WinAPI_GetProcAddress(_WinAPI_LoadLibrary('user32'), 'SendMessageW'))
    DllStructSetData($thi, 'GetLastError', _WinAPI_GetProcAddress(_WinAPI_LoadLibrary('kernel32'), 'GetLastError'))
    DllStructSetData($thi, 'henvent', _WinAPI_CreateEvent(0, 0, 0, 0)) ;
    DllStructSetData($thi, 'hwnd', _WinAPI_CreateWindowEx(0, $thread_Class, '', 0, 0, 0, 0, 0, 0))
    Local $thid = DllCall('kernel32', 'hwnd', 'CreateThread', 'ptr', 0, 'dword', 0, 'ptr', _
            $pshll, 'ptr', DllStructGetPtr($thi), 'long', 0, 'int*', 0)
    DllStructSetData($thi, 'rsv', $thid[0], 2)
    DllStructSetData($thi, 'rsv', $thid[6], 3)
    DllStructSetData($thi, 'callback', $scallback)
    Call(DllStructGetData($thi, 'callback'), $thi, DllStructGetData($thi, 'rsv', 4))
    Return $thi
EndFunc   ;==>thread_create

Func thread_close($thi) ; close remote api thread
    DllStructSetData($thi, 'exitthread', 1)
    _WinAPI_SetEvent(DllStructGetData($thi, 'henvent'))
EndFunc   ;==>thread_close

Func thread_isrunning($thi) ; check if remote api thread is closed or no
    Return (DllStructGetData($thi, 'exitthread') = 0)
EndFunc   ;==>thread_isrunning

Func thread_GetLastError($thi) ; Get Last Error in remote thread
    Return DllStructGetData($thi, 'LastError')
EndFunc   ;==>thread_GetLastError

Func thread_getreturn($thi) ; get api call return
    Return DllStructGetData($thi, 'lreturn')
EndFunc   ;==>thread_getreturn

Func thread_call($thi, $pproc) ; dllcall $pproc = address of api
    DllStructSetData($thi, 'pproc', $pproc)
    DllStructSetData($thi, 'isprocessing', 1)
    _WinAPI_SetEvent(DllStructGetData($thi, 'henvent'))
    DllStructSetData($thi, 'rsv', 0, 1)
EndFunc   ;==>thread_call

Func thread_addcallparameters($thi, $val) ; add dllcall parameters
    Local $idx = DllStructGetData($thi, 'rsv', 1) + 1
    DllStructSetData($thi, 'rsv', $idx, 1)
    DllStructSetData($thi, 'parm', $idx, 1)
    DllStructSetData($thi, 'parm', $val, $idx + 1)
EndFunc   ;==>thread_addcallparameters

Func thread_callsimple($thi, $dll, $nproc, $p1 = Default, $p2 = Default, $p3 = Default, _
        $p4 = Default, $p5 = Default, $p6 = Default, $p7 = Default, $p8 = Default, _
        $p9 = Default, $p10 = Default, $p11 = Default, $p12 = Default, $p13 = Default, _
        $p14 = Default, $p15 = Default, $p16 = Default, $p17 = Default, $p18 = Default) ; simple call api ;)
    Local $cp = 1
    While Execute('$p' & $cp & ' <> Default')
        thread_addcallparameters($thi, Execute('$p' & $cp))
        $cp += 1
    WEnd
    thread_call($thi, _WinAPI_GetProcAddress(_WinAPI_LoadLibrary($dll), $nproc))
EndFunc   ;==>thread_callsimple


Opt("MustDeclareVars", 1)
Global $s1, $s2
Func __thread_callback($thi, $phase)
    Switch $phase
        Case -1 ;thread is closed
            MsgBox(0, '', 'thread is closed return ' & thread_getreturn($thi) & ' error ' & thread_GetLastError($thi))
        Case 0 ;thread is started
            $s1 = _WinAPI_CreateString('i love autoit')
            $s2 = _WinAPI_CreateString('from remote thread')
            thread_callsimple($thi, 'user32', 'MessageBoxW', 0, $s1, $s2, 0x00000006)
;~          ;DllCall('user32', 'int', 'MessageBoxW', 'hwnd', 0, 'ptr', $s1, 'ptr', $s2, 'uint', 0x00000006)
        Case 1 ;return first call
            _WinAPI_FreeMemory($s1)
            _WinAPI_FreeMemory($s2)
            MsgBox(0, '', 'callback api return ' & thread_getreturn($thi) & ' error ' & thread_GetLastError($thi))
            $s2 = DllStructCreate('dword')
            DllStructSetData($s2, 1, 1024)
            $s1 = DllStructCreate('wchar[1024]')
            thread_callsimple($thi, 'Advapi32', 'GetUserNameW', DllStructGetPtr($s1), DllStructGetPtr($s2))
;~          ;DllCall('Advapi32', 'BOOL', 'GetUserNameW', 'ptr', DllStructGetPtr($s1), 'ptr', DllStructGetPtr($s2))
        Case 2 ;return second call
            MsgBox(0, '', 'callback api return : ' & thread_getreturn($thi) & _
                    @CRLF & ' error : ' & thread_GetLastError($thi) & _
                    @CRLF & ' string len : ' & DllStructGetData($s2, 1) & _
                    @CRLF & ' user name : ' & DllStructGetData($s1, 1) & _
                    '')
            thread_close($thi) ;endif thread
        Case 3 ; return previous call

    EndSwitch
EndFunc   ;==>__thread_callback

Local $rth = thread_create('__thread_callback')

While thread_isrunning($rth)
    ConsoleWrite('thread is running' & @CRLF)
    Sleep(1000)
WEnd

 

 

Edited by Celtic88
Link to comment
Share on other sites

assembly source code x32 and x64

update 21/02/2021

 

;by celtic88

use32
include 'c:\fasm\INCLUDE\win32ax.inc'
startcode:
mov        ax, cs
cmp        al, $33 ;$23 ; WoW64
je        __apithread_64

macro strucx lab, dty {struct lab
WaitForSingleObject dty ?
SendMessage dty ?
GetLastError dty ?
henvent     dty ?
hwnd      dty ?
pproc   dty ?
isprocessing   dty ?
returnlow   dty ?
returnhigh  dty ?
LastError  dty ?
exitthread  dty ?
;!parm dty 100 dup (?)
ends}

strucx apithreadInfo,dd

use32
__apithread:
MOV edi, [esp+4]
.l_startthread:
push -1
push [edi + apithreadInfo.henvent]
call [edi + apithreadInfo.WaitForSingleObject]
test eax, eax
jz @f
inc [edi + apithreadInfo.exitthread]
@@:
mov ebx, [edi + apithreadInfo.exitthread]
test ebx, ebx
jnz .l_exitthread

lea esi, [edi + sizeof.apithreadInfo]
mov ecx, dword [esi]
test ecx, ecx
jz .l_noparm
@@:
push dword [esi+ecx*4]
loop @b
.l_noparm:call [edi + apithreadInfo.pproc]

.l_exitthread:
MOV [edi + apithreadInfo.returnlow], eax
MOV [edi + apithreadInfo.returnhigh], edx
call [edi + apithreadInfo.GetLastError]
MOV [edi + apithreadInfo.LastError], eax
xor eax, eax
MOV [edi + apithreadInfo.isprocessing], eax
push ebx
push edi
push eax
push [edi + apithreadInfo.hwnd]
call [edi + apithreadInfo.SendMessage]
test ebx, ebx
jz .l_startthread
ret

;///////////////////////////////////////////////////////////////////////////////////// x 64
strucx apithreadInfo64,dq
align 2
__apithread_64:
use64
sub rsp,32+(8*100)+8
;!or rsp,8
mov rbx, rcx
.l_startthread:
xor rdx, rdx
dec rdx
mov rcx, [rbx + apithreadInfo64.henvent]
call [rbx + apithreadInfo64.WaitForSingleObject]
test rax, rax
jz @f
inc [rbx + apithreadInfo64.exitthread]
@@:
mov r15, [rbx + apithreadInfo64.exitthread]
test r15, r15
jnz .l_exitthread

lea rsi, [rbx + sizeof.apithreadInfo64]
LODSq
test rax, rax
jz .l_noparm
mov r14, rax
xor rcx, rcx
add rcx, 4
@@:LODSq
push rax
loop @b

sub r14, 4
cmp r14, rcx
jle .l_skip
mov rcx, r14
lea rdi, [rsp+8*4+32] ; push rax *4
@@:LODSq
stosq
loop @b
.l_skip:

pop r9 r8 rdx rcx
.l_noparm:call [rbx + apithreadInfo64.pproc]

.l_exitthread:
 MOV [rbx + apithreadInfo64.returnlow], rax
 MOV [rbx + apithreadInfo64.returnhigh], rdx
call [rbx + apithreadInfo64.GetLastError]
MOV [rbx + apithreadInfo64.LastError], rax
xor rdx, rdx
mov [rbx + apithreadInfo64.isprocessing],rdx
mov r9, r15
mov r8, rbx
mov rcx, [rbx + apithreadInfo64.hwnd]
call [rbx + apithreadInfo64.SendMessage]
test r15, r15
jz .l_startthread
add rsp,32+(8*100)+8
ret

 

 

Edited by Celtic88
Link to comment
Share on other sites

  • 2 years later...

For anyone interested, I recreated the above using fasmg by @Beege --

#include <String.au3>
#include "fasmg.au3"

Global $g_sFasm

_Ex_Compile()

Func _Ex_Compile()
    $g_sFasm = ''

    _('macro strucx lab, dty')
    _('    struc lab')
    _('        .WaitForSingleObject dty ?')
    _('        .SendMessage dty ?')
    _('        .GetLastError dty ?')
    _('        .henvent     dty ?')
    _('        .hwnd      dty ?')
    _('        .pproc   dty ?')
    _('        .isprocessing   dty ?')
    _('        .returnlow   dty ?')
    _('        .returnhigh  dty ?')
    _('        .LastError  dty ?')
    _('        .exitthread  dty ?')
    _('    end struc')

    _('    virtual at 0')
    _('    lab lab')
    _('    sizeof.lab = $')
    _('    end virtual')
    _('end macro')
    
    _('use32')

    _('startcode:')
    _('mov        ax, cs')
    _('cmp        al, $33')  ; $23 ; WoW64
    _('je        __apithread_64')
    
    
    _('strucx apithreadInfo,dd')

    _('use32')
    _('__apithread:')
    _('MOV edi, [esp+4]')
    _('.l_startthread:')
    _('push -1')
    _('push [edi + apithreadInfo.henvent]')
    _('call [edi + apithreadInfo.WaitForSingleObject]')
    _('test eax, eax')
    _('jz @f')
    _('inc [edi + apithreadInfo.exitthread]')
    _('@@:')
    _('mov ebx, [edi + apithreadInfo.exitthread]')
    _('test ebx, ebx')
    _('jnz .l_exitthread')

    _('lea esi, [edi + sizeof.apithreadInfo]')
    _('mov ecx, dword [esi]')
    _('test ecx, ecx')
    _('jz .l_noparm')
    _('@@:')
    _('push dword [esi+ecx*4]')
    _('loop @b')
    _('.l_noparm:call [edi + apithreadInfo.pproc]')

    _('.l_exitthread:')
    _('MOV [edi + apithreadInfo.returnlow], eax')
    _('MOV [edi + apithreadInfo.returnhigh], edx')
    _('call [edi + apithreadInfo.GetLastError]')
    _('MOV [edi + apithreadInfo.LastError], eax')
    _('xor eax, eax')
    _('MOV [edi + apithreadInfo.isprocessing], eax')
    _('push ebx')
    _('push edi')
    _('push eax')
    _('push [edi + apithreadInfo.hwnd]')
    _('call [edi + apithreadInfo.SendMessage]')
    _('test ebx, ebx')
    _('jz .l_startthread')
    _('ret')

    ;///////////////////////////////////////////////////////////////////////////////////// x 64
    _('strucx apithreadInfo64,dq')
   _('use64')

    _('align 2')
    _('__apithread_64:')

    _('sub rsp,32+(8*100)+8')
;!or rsp,8
    _('mov rbx, rcx')
    _('.l_startthread:')
    _('xor rdx, rdx')
    _('dec rdx')
    _('mov rcx, [rbx + apithreadInfo64.henvent]')
    _('call [rbx + apithreadInfo64.WaitForSingleObject]')
    _('test rax, rax')
    _('jz @f')
    _('inc [rbx + apithreadInfo64.exitthread]')
    _('@@:')
    _('mov r15, [rbx + apithreadInfo64.exitthread]')
    _('test r15, r15')
    _('jnz .l_exitthread')

    _('lea rsi, [rbx + sizeof.apithreadInfo64]')
    _('LODSq')
    _('test rax, rax')
    _('jz .l_noparm')
    _('mov r14, rax')
    _('xor rcx, rcx')
    _('add rcx, 4')
    _('@@:LODSq')
    _('push rax')
    _('loop @b')

    _('sub r14, 4')
    _('cmp r14, rcx')
    _('jle .l_skip')
    _('mov rcx, r14')
    _('lea rdi, [rsp+8*4+32]') ; push rax *4
    _('@@:LODSq')
    _('stosq')
    _('loop @b')
    _('.l_skip:')

    _('pop r9 r8 rdx rcx')
    _('.l_noparm:call [rbx + apithreadInfo64.pproc]')

    _('.l_exitthread:')
    _(' MOV [rbx + apithreadInfo64.returnlow], rax')
    _('MOV [rbx + apithreadInfo64.returnhigh], rdx')
    _('call [rbx + apithreadInfo64.GetLastError]')
    _('MOV [rbx + apithreadInfo64.LastError], rax')
    _('xor rdx, rdx')
    _('mov [rbx + apithreadInfo64.isprocessing],rdx')
    _('mov r9, r15')
    _('mov r8, rbx')
    _('mov rcx, [rbx + apithreadInfo64.hwnd]')
    _('call [rbx + apithreadInfo64.SendMessage]')
    _('test r15, r15')
    _('jz .l_startthread')
    _('add rsp,32+(8*100)+8')
    _('ret')
   
    Local $tBinary = _fasmg_CompileAu3($g_sFasm)
    If @error Then Exit (ConsoleWrite($tBinary & @CRLF))
        
EndFunc 

Func _($sFasmCmd)
    $g_sFasm &= $sFasmCmd & @LF
EndFunc   ;==>_
Link to comment
Share on other sites

  • 2 weeks later...

I've added inline comments in an effort to better understand the inner workings of this code. Feel free to respond with any additions or corrections --

#include "fasmg.au3"

Global $g_sFasm

_Ex_Compile()

#Tidy_ILC_Pos=62
Func _Ex_Compile()
    $g_sFasm = ''

    _('macro strucx lab, dty')
    _('    struc lab')
    _('        .WaitForSingleObject dty ?')
    _('        .SendMessage         dty ?')
    _('        .GetLastError        dty ?')
    _('        .hevent              dty ?')                  ; event handle
    _('        .hwnd                dty ?')                  ; window handle
    _('        .pproc               dty ?')                  ; address of API function
    _('        .isprocessing        dty ?')                  ; TODO why is this needed?
    _('        .returnlow           dty ?')
    _('        .returnhigh          dty ?')
    _('        .LastError           dty ?')
    _('        .exitthread          dty ?')                  ; exit flag
    _('    end struc')

    _('    virtual at 0')                                    ; calc / store struct size
    _('    lab lab')
    _('    sizeof.lab = $')
    _('    end virtual')
    _('end macro')

    _('use32')

    _('startcode:')
    _('mov        ax, cs')
    _('cmp        al, $33')                                  ; detect 64 bit
    _('je        __apithread_64')


    _('strucx apithreadInfo, dd')

    _('use32')
    _('__apithread:')
    _('MOV edi, [esp+4]')
    _('.l_startthread:')
    _('push -1')                                             ; wait indefinitely
    _('push [edi + apithreadInfo.hevent]')
    _('call [edi + apithreadInfo.WaitForSingleObject]')
    _('test eax, eax')                                       ; was the event triggered?
    _('jz @f')
    _('inc [edi + apithreadInfo.exitthread]')                ; set flag to exit thread
    _('@@:')
    _('mov ebx, [edi + apithreadInfo.exitthread]')           ; check if thread should exit
    _('test ebx, ebx')
    _('jnz .l_exitthread')

    _('lea esi, [edi + sizeof.apithreadInfo]')               ; check if parameters supplied
    _('mov ecx, dword [esi]')
    _('test ecx, ecx')
    _('jz .l_noparm')
    _('@@:')
    _('push dword [esi+ecx*4]')                              ; load parameters on the stack
    _('loop @b')
    _('.l_noparm:')
    _('call [edi + apithreadInfo.pproc]')                    ; call the target API

    _('.l_exitthread:')
    _('MOV [edi + apithreadInfo.returnlow], eax')
    _('MOV [edi + apithreadInfo.returnhigh], edx')
    _('call [edi + apithreadInfo.GetLastError]')
    _('MOV [edi + apithreadInfo.LastError], eax')            ; save error code
    _('xor eax, eax')
    _('MOV [edi + apithreadInfo.isprocessing], eax')         ; set flag to zero
    _('push ebx')
    _('push edi')
    _('push eax')
    _('push [edi + apithreadInfo.hwnd]')
    _('call [edi + apithreadInfo.SendMessage]')
    _('test ebx, ebx')
    _('jz .l_startthread')
    _('ret')

    ; Begin x64 coding
    _('strucx apithreadInfo64, dq')
    _('use64')

    _('align 2')
    _('__apithread_64:')

    _('sub rsp,32+(8*100)+8')
    ;!or rsp,8
    _('mov rbx, rcx')
    _('.l_startthread:')
    _('xor rdx, rdx')
    _('dec rdx')
    _('mov rcx, [rbx + apithreadInfo64.hevent]')
    _('call [rbx + apithreadInfo64.WaitForSingleObject]')
    _('test rax, rax')
    _('jz @f')
    _('inc [rbx + apithreadInfo64.exitthread]')
    _('@@:')
    _('mov r15, [rbx + apithreadInfo64.exitthread]')
    _('test r15, r15')
    _('jnz .l_exitthread')

    _('lea rsi, [rbx + sizeof.apithreadInfo64]')
    _('LODSq')
    _('test rax, rax')
    _('jz .l_noparm')
    _('mov r14, rax')
    _('xor rcx, rcx')
    _('add rcx, 4')
    _('@@:LODSq')
    _('push rax')
    _('loop @b')

    _('sub r14, 4')
    _('cmp r14, rcx')
    _('jle .l_skip')
    _('mov rcx, r14')
    _('lea rdi, [rsp+8*4+32]')
    _('@@:LODSq')
    _('stosq')
    _('loop @b')
    _('.l_skip:')

    _('pop r9 r8 rdx rcx')
    _('.l_noparm:call [rbx + apithreadInfo64.pproc]')

    _('.l_exitthread:')
    _(' MOV [rbx + apithreadInfo64.returnlow], rax')
    _('MOV [rbx + apithreadInfo64.returnhigh], rdx')
    _('call [rbx + apithreadInfo64.GetLastError]')
    _('MOV [rbx + apithreadInfo64.LastError], rax')
    _('xor rdx, rdx')
    _('mov [rbx + apithreadInfo64.isprocessing],rdx')
    _('mov r9, r15')
    _('mov r8, rbx')
    _('mov rcx, [rbx + apithreadInfo64.hwnd]')
    _('call [rbx + apithreadInfo64.SendMessage]')
    _('test r15, r15')
    _('jz .l_startthread')
    _('add rsp,32+(8*100)+8')
    _('ret')

    Local $tBinary = _fasmg_CompileAu3($g_sFasm)
    If @error Then Exit (ConsoleWrite($tBinary & @CRLF))

EndFunc   ;==>_Ex_Compile

Func _($sFasmCmd)
    $g_sFasm &= $sFasmCmd & @LF
EndFunc   ;==>_

 

Link to comment
Share on other sites

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
 Share

×
×
  • Create New...