Calling the Windows API in Assembly Language
by
Qark [VLAD]

            If you didn't read the windows document in VLAD#4 or don't
            know anything about lowlevel windows structures, then turn
            back now!

                    -----------------------------------

            Although I designed this document with a view to virus writing,
            I've never seen any information like this anywhere, so it
            could just as easily be used as a general low-level windows text.
            Feel free to use it as such.

            I worked out the 'procedure ordinal number listing' by using
            a diskeditor to increase the 'procedure ordinal number' in the
            disk file, and seeing which API was produced by viewing the file
            with a disassembler.  This took many hours.  I only did it for
            the KERNEL functions because they are the only ones that are useful
            for viruses.  If you require pretty windows and scroll bars then
            change the 'index into the module reference table' to refer to GDI
            or USER and work out the 'procedure ordinal numbers' for yourself.

                    -----------------------------------

            To work out the parameters to enter into the API, you will need
            an API listing.  These are normally of phone book proportions
            and I'm not about to type one out, so grab one from your local
            library.  If you can, check to make sure that the book you are
            thinking of choosing lists the selector functions such as
            'AllocCStoDSAlias'.  These functions are considered obselete
            by Windows 3.1, but they are still there, and should be listed!

            All parameters passed into an API are done using the stack.
            The values shown in the API listing need to be PUSH'ed in order.
            Any return data will be passed back in AX if it is a word, and
            DX:AX if a dword.  (I might be wrong about this, but it has worked
            so far!)

            For example, my 'Windows API Bible' (which doesnt list the selector
            API functions) says to call "_lopen", which opens a file the same
            as int 21 AH=3dh, do this:
            Syntax: int _lopen (LPSTR lppathname, int ireadwrite);
            Returns: int, file handle, or -1 if error.

            Let's analyse the syntax.
            The 'int' at the start means the return value will be an integer,
            which is a word, and thus passed in AX.  If it had said 'LONG' then
            we'd know it was passing back in DX:AX.
            LPSTR is a pointer to an asciiz string (the book tells us this) so
            push the segment, and then offset of the filename to be opened.
            'ireadwrite' is the openmode, so based on experience, 2 will be the
            word pushed to open in read/write mode.

            Now here is the full fileopen API all written up, including
            relocation entry and call:
                    ...
                    push    ds              ;ds:dx=filename
                    push    dx
                    mov     ax,2            ;open in read/write mode
                    push    ax
            apicall:
                    db      9ah             ;Call Far Ptr
                    dw      0ffffh          ;Windows needs these.
                    dw      0
                    mov     bx,ax           ;file handle into BX
                    ...

            The relocation item is setout like so:

                    db      3               ;32 bit pointer
                    db      1               ;Import Ordinal
                    dw      offset apicall + 1      ;Offset of api entry
                    dw      1               ;Index into module reference table
                                            ;of KERNAL.
                    dw      55h             ;Indicate '_lopen' API call.
                                            ;This is the 'procedure ordinal
                                            ;number'

            In the relocation I have assumed that the kernal is the first
            thing in the module reference table.  Don't assume this.  In a virus
            you will have to search for it.

            I got the '55h' by checking the table below.  The 'procedure ordinal
            number' indicates which API the relocation is talking about.
            If you changed the '55h' to a '56h' it would be a '_lwrite' API
            call instead.  Check below to see why.

            When in doubt, ask me about it.

                    -----------------------------------

            Procedure Ordinal Number Listing for KERNAL functions.

            '*' indicates a handy function.
            If the procedure 'doesnt exist' theres a chance it may be an
            undocumented API.

            01h     -       FatalExit
            02h     -       ExitKernal
            03h     -       GetVersion
            04h     -       LocalInit
            05h     -       LocalAlloc
            06h     -       LocalRealloc
            07h     -       LocalFree
            08h     -       LocalLock
            09h     -       LocalUnlock
            0ah     -       LocalSize
            0bh     -       LocalHandle
            0ch     -       LocalFlags
            0dh     -       LocalCompact
            0eh     -       LocalNotify
            0fh     -       GlobalAlloc

            10h     -       GlobalRealloc
            11h     -       GlobalFree
            12h     -       GlobalLock
            13h     -       GlobalUnlock
            14h     -       GlobalSize
            15h     -       GlobalHandle
            16h     -       GlobalFlags
            17h     -       LockSegment                     *
            18h     -       UnlockSegment
            19h     -       GlobalCompact
            1ah     -       GlobalFreeAll
            1bh     -       ??? Doesnt exist ???
            1ch     -       GlobalMasterHandle
            1dh     -       Yield
            1eh     -       WaitEvent
            1fh     -       PostEvent

            20h     -       SetPriority
            21h     -       LockCurrentTask
            22h     -       SetTaskQueue
            23h     -       GetTaskQueue
            24h     -       GetCurrentTask
            25h     -       GetCurrentPDB
            26h     -       SetTaskSignalProc
            27h     -       ??? Doesnt exist ???
            28h     -       ??? Doesnt exist ???
            29h     -       EnableDos
            2ah     -       DisableDos
            2bh     -       ??? Doesnt exist ???
            2ch     -       ??? Doesnt exist ???
            2dh     -       LoadModule
            2eh     -       FreeModule
            2fh     -       GetModuleHandle

            30h     -       GetModuleUsage
            31h     -       GetModuleFileName
            32h     -       GetProcAddress
            33h     -       MakeProcInstance
            34h     -       FreeProcInstance
            35h     -       CallProcInstance
            36h     -       GetInstaceData
            37h     -       Catch
            38h     -       Throw
            39h     -       GetProfileInt
            3ah     -       GetProfileString
            3bh     -       WriteProfileString
            3ch     -       FindResource
            3dh     -       LoadResource
            3eh     -       LockResource
            3fh     -       FreeResource

            40h     -       AccessResource
            41h     -       SizeofResource
            42h     -       AllocResource
            43h     -       SetResourceHandler
            44h     -       InitAtomTable
            45h     -       FindAtom
            46h     -       AddAtom
            47h     -       DeleteAtom
            48h     -       GetAtomName
            49h     -       GetAtomHandle
            4ah     -       OpenFile
            4bh     -       OpenPathName
            4ch     -       DeletePathName
            4dh     -       Reserved1
            4eh     -       Reserved2
            4fh     -       Reserved3

            50h     -       Reserved4
            51h     -       _lclose                         *
            52h     -       _lread                          *
            53h     -       _lcreat                         *
            54h     -       _llseek                         *
            55h     -       _lopen                          *
            56h     -       _lwrite                         *
            57h     -       Reserved5
            58h     -       lstrcpy
            59h     -       lstrcat
            5ah     -       lstrlen
            5bh     -       InitTask
            5ch     -       GetTempDrive
            5dh     -       GetCodeHandle
            5eh     -       DefineHandleTable
            5fh     -       LoadLibrary

            60h     -       FreeLibrary
            61h     -       GetTempFileName
            62h     -       GetLastDiskChange
            63h     -       GetLPErrMode
            64h     -       ValidateCodeSegments
            65h     -       NoHookDosCall
            66h     -       Dos3Call                        *
            67h     -       NetBIOSCall
            68h     -       GetCodeInfo
            69h     -       GetExeVersion
            6ah     -       SetSwapAreaSize
            6bh     -       SetErrorMode
            6ch     -       SwitchStackTo
            6dh     -       SwitchStackBack
            6eh     -       PatchCodeHandle
            6fh     -       GlobalWire

            70h     -       GlobalUnwire
            71h     -       __AHShift
            72h     -       __AHinCR
            73h     -       OutputDebugString
            74h     -       InitLib
            75h     -       OldYield
            76h     -       GetTaskQueueDS
            77h     -       GetTaskQueueES
            78h     -       UndefDynLink
            79h     -       LocalShrink
            7ah     -       IsTaskLocked
            7bh     -       KbDrSt
            7ch     -       EnableKernal
            7dh     -       DisableKernal
            7eh     -       MemoryFreed
            7fh     -       GetPrivateProfileInt

            80h     -       GetPrivateProfileString
            81h     -       WritePrivateProfileString
            82h     -       FileCDR
            83h     -       GetDosEnvironment
            84h     -       GetWinFlags
            85h     -       GetExePtr
            86h     -       GetWindowsDirectory
            87h     -       GetSystemDirectory
            88h     -       GetDriveType
            89h     -       FatalAppExit
            8ah     -       GetHeapSpaces
            8bh     -       Dosignal
            8ch     -       SetSigHandler
            8dh     -       InitTask1
            8eh     -       ??? Doesnt exist ???
            8fh     -       ??? Doesnt exist ???

            90h     -       ??? Doesnt exist ???
            91h     -       ??? Doesnt exist ???
            92h     -       ??? Doesnt exist ???
            93h     -       ??? Doesnt exist ???
            94h     -       ??? Doesnt exist ???
            95h     -       ??? Doesnt exist ???
            96h     -       Directed Yield
            97h     -       WinOldApCall
            98h     -       GetNumTasks
            99h     -       ??? Doesnt exist ???
            9ah     -       ??? Doesnt exist ???
            9bh     -       GetTaskDS
            9ch     -       LimitEMSPages
            9dh     -       GetCurPID
            9fh     -       GlobalHandleNoRip

            0a0h    -       EMSCopy
            0a1h    -       LocalCountFree
            0a2h    -       LocalHeapSize
            0a3h    -       GlobalLRUOldest
            0a4h    -       GlobalLRUNewest
            0a5h    -       A20Proc
            0a6h    -       WinExec
            0a7h    -       GetExpWinVer
            0a8h    -       DirectResAlloc
            0a9h    -       GetFreeSpace
            0aah    -       AllocCStoDSAlias                *
            0abh    -       AllocDStoCSAlias                *
            0ach    -       AllocAlias                      *
            0adh    -       __ROMBIOS
            0aeh    -       __a000h
            0afh    -       AllocSelector                   *

            0b0h    -       FreeSelector                    *
            0b1h    -       PrestoChangoSelector            *
            0b2h    -       __winflags
            0b3h    -       __d000h
            0b4h    -       LongPtrAdd
            0b5h    -       __b000h
            0b6h    -       __b800h
            0b7h    -       __0000h
            0b8h    -       GlobalDosAlloc                  *
            0b9h    -       GlobalDosFree                   *
            0bah    -       GetSelectorBase                 *
            0bbh    -       SetSelectorBase                 *
            0bch    -       GetSelectorLimit                *
            0bdh    -       SetSelectorLimit                *
            0beh    -       __e000h
            0bfh    -       GlobalPageLock

            0c0h    -       GlobalPageUnlock
            0c1h    -       __0040h
            0c2h    -       __f000h
            0c3h    -       __c000h
            0c4h    -       SelectorAccessRights            *
            0c5h    -       GlobalFix
            0c6h    -       GlobalUnfix
            0c7h    -       SetHandleCount
            0c8h    -       ValidateFreeSpaces
            0c9h    -       ReplaceInst
            0cah    -       RegisterPtrAce
            0cbh    -       DebugBreak
            0cch    -       SwapRecording
            0cdh    -       CvwBreak
            0ceh    -       AllocSelectorArray
            0cfh    -       IsDBCSLeadByte

            0d0h    -       ??? Doesnt exist ???
            0d1h    -       ??? Doesnt exist ???

            0e0h    -       ??? Doesnt exist ???

            0f0h    -       ??? Doesnt exist ???

                    -----------------------------------