I used the CreateThread call and the Heap functions to create a simple sample program that spawns a separate thread that displays a MessageBox

Try running it and you will see a MessageBox. However, unlike a normal MessageBox in your application, this one is on a separate thread, and thus the main thread can continue processing.

The code allocates some memory and writes some bytes of x86 machine code to execute. Those bytes simply put up the MessageBox and return.

The MessageBox strings need to be allocated and freed, and the strings and the code must not be freed until after the thread terminates by Returning.

 

 

 

 

 

CLEAR ALL

CLEAR

#define CREATE_SUSPENDED                  0x00000004

#define INFINITE            0xFFFFFFFF 

#define WAIT_TIMEOUT                     258

 

 

DECLARE integer LoadLibrary IN WIN32API string

DECLARE integer FreeLibrary IN WIN32API integer

DECLARE integer GetProcAddress IN WIN32API integer hModule, string procname

DECLARE integer CreateThread IN WIN32API integer lpThreadAttributes, ;

      integer dwStackSize, integer lpStartAddress, integer lpParameter, integer dwCreationFlags, integer @ lpThreadId

DECLARE integer ResumeThread IN WIN32API integer thrdHandle

DECLARE integer CloseHandle IN WIN32API integer Handle

DECLARE integer GetProcessHeap IN WIN32API

DECLARE integer HeapAlloc IN WIN32API integer hHeap, integer dwFlags, integer dwBytes

DECLARE integer HeapFree IN WIN32API integer hHeap, integer dwFlags, integer lpMem

DECLARE integer WaitForSingleObject IN WIN32API integer hHandle, integer dwMilliseconds

 

hModule = LoadLibrary("user32")

adrMessageBox=GetProcAddress(hModule,"MessageBoxA")

FreeLibrary(hModule)

 

hProcHeap = GetProcessHeap()

sCaption="This is a MessageBox running in a separate thread"+CHR(0)     && null terminate string

adrCaption = HeapAlloc(hProcHeap, 0, LEN(sCaption))   && allocate memory for string

SYS(2600,adrCaption,LEN(sCaption),sCaption)     && copy string into allocated mem

 

* int 3 = cc  (Debug Breakpoint: attach a debugger dynamically)

* nop = 90

* push 0  = 6a 00

* push eax = 50

* push 0x12345678 = 68 78 56 34 12

* ret 4 = c2 04 00

* mov eax, esp    = 8B c4

* mov eax, 0x12345678 = B8 78 56 34 12

* call eax  = ff d0

sCode=""

*sCode = sCode + CHR(0xcc)

sCode = sCode + CHR(0x6a) + CHR(0x00)     && push 0

sCode = sCode + CHR(0x68) + BINTOC(adrCaption,"4rs")  && push the string caption

sCode = sCode + CHR(0x68) + BINTOC(adrCaption,"4rs")  && push the string caption

sCode = sCode + CHR(0x6a) + CHR(0x00)     && push the hWnd

sCode = sCode + CHR(0xb8) + BINTOC(adrMessageBox,"4rs")     && move eax, adrMessageBox

sCode = sCode + CHR(0xff) + CHR(0xd0)     && call eax

sCode = sCode + CHR(0xc2)+CHR(0x04)+CHR(0x00)   && ret 4

 

AdrCode=HeapAlloc(hProcHeap, 0, LEN(sCode))     && allocate memory for the code

 

SYS(2600,AdrCode, LEN(sCode), sCode)      && copy the code into the string

 

dwThreadId =0

?"Starting thread count = ",GetThreadCount()

 

hThread = CreateThread(0,1024, AdrCode, 0, CREATE_SUSPENDED, @dwThreadId)

?"Thread handle = ",hThread

?"Thread ID = ", dwThreadID

ResumeThread(hThread)   && Start the thread

 

i=0

DO WHILE WaitForSingleObject(hThread, 100) = WAIT_TIMEOUT   && wait 100 msecs for the thread to finish

      ?i,"Current thread count",GetThreadCount()

      i=i+1

ENDDO

?"Final thread count = ",GetThreadCount()

 

 

 

 

?"Close",CloseHandle(hThread)

HeapFree(hProcHeap, 0, AdrCode)     && if the thread hasn't finished, we're releasing the executing code and it'll crash

HeapFree(hProcHeap, 0, adrCaption)

 

RETURN

 

 

PROCEDURE GetThreadCount as Integer

      *Use WMI to get process information

      objWMIService = GetObject("winmgmts:\\.\root\cimv2")

      colItems = objWMIService.ExecQuery("Select * from Win32_Process where processid = "+TRANSFORM(_vfp.ProcessId))

      For Each objItem in colItems

            nRetval = objItem.ThreadCount

      NEXT

      RETURN nRetval