Statistics

Members: 1925
News: 293
Web Links: 1
Visitors: 3821683

Who's Online

We have 1 guest online
Damn Vulnerable LinuxDamn Vulnerable Linux (DVL) is a Linux-based (modified Damn Small Linux) tool for IT-Security & IT-Anti- Security and Attack & Defense. [CLICK HERE FOR MORE INFOS! ]

Featured Conference Video

T16-Recon2006-Joe_Stewart-OllyBonE.gif OllyBone - Semi-Automatic Unpacking on IA-32. View the conference video here!
Home
Using COM in Assembly Language
User Rating: / 0
PoorBest 
Written by Lord Lucipher   


This article will discuss how to use COM interfaces in your assembly language programs. It will not discuss what COM is and how it is used, but rather how it can be used when programming in assembler. It will discuss only how to use existing interfaces, and not how to actually implement new ones; this will be shown in a future atricle.

 

 

About COM

Here is a brief introduction to the basics behind COM.

A COM object is one in which access to an object's data is achieved exclusively through one or more sets of related functions. These function sets are called interfaces, and the functions of an interface are called methods. COM requires that the only way to gain access to the methods of an interface is through a pointer to the interface.

An interface is actually a contract that consists of a group of related function prototypes whose usage is defined but whose implementation is not. An interface definition specifies the interface's member functions, called methods, their return types, the number and types of their parameters, and what they must do. There is no implementation associated with an interface. An interface implementation is the code a programmer supplies to carry out the actions specified in an interface definition.

An instance of an interface implementation is actually a pointer to an array of pointers to methods (a function table that refers to an implementation of all of the methods specified in the interface). Any code that has a pointer through which it can access the array can call the methods in that interface.

Using a COM object assembly language

Access to a COM object occurs through a pointer. This pointer points to a table of function pointers in memory, called a virtual function table, or vtable in short. This vtable contains the addresses of each of the objects methods. To call a method, you indirectly call it through this pointer table.

Here is an example of a C++ interface, and how its methods are called:

        interface IInterface
{
HRESULT QueryInterface( REFIID iid, void ** ppvObject );
ULONG AddRef();
ULONG Release();
Function1( INT param1, INT param2);
Function2( INT param1 );
}
// calling the Function1 method
pObject->Function1( 0, 0);

Now here is how the same functionality can be implemented using assembly language:

        ; defining the interface
; each of these values are offsets in the vtable
QueryInterface          equ             0h
AddRef                  equ             4h
Release                 equ             8h
Function1               equ             0Ch
Function2               equ             10h
; calling the Function1 method in asm
; the method is called by obtaining the address of the objects
; vtable and then calling the function addressed by the proper
; offset in the table
push    param2
push    param1
mov     eax, pObject
push    eax
mov     eax, [eax]
call    [eax + Function1]

You can see this is somewhat different than calling a function normally. Here, pObject points to the Interface's vTable. At the Function1(0Ch) offset in this table is a pointer to the actual function we wish to call.

Using HRESULT's

The return value of OLE APIs and methods is an HRESULT. This is not a handle to anything, but is merely a 32-bit value with several fields encoded in the value. The parts of an HRESULT are shown below.

HRESULTs are 32 bit values layed out as follows:

3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 +-+-+-+-+-+---------------------+-------------------------------+ |S|R|C|N|r| Facility | Code | +-+-+-+-+-+---------------------+-------------------------------+

S - Severity Bit

     Used to indicate success or failure
0 - Success
1 - Fail
By noting that this bit is actually the sign bit of the 32-bit value,
checking success/failure is simply performed by checking its sign:
call       ComFunction        ; call the function
test       eax,eax            ; now check its return value
js         error              ; jump if signed (meaning error returned)
; success, so continue

R - reserved portion of the facility code, corresponds to NT's

second severity bit.

C - reserved portion of the facility code, corresponds to NT's

C field.

N - reserved portion of the facility code. Used to indicate a

mapped NT status value.

r - reserved portion of the facility code. Reserved for internal

     use. Used to indicate HRESULT values that are not status
values, but are instead message ids for display strings.

Facility - is the facility code

     FACILITY_WINDOWS    = 8
FACILITY_STORAGE    = 3
FACILITY_RPC        = 1
FACILITY_WIN32      = 7
FACILITY_CONTROL    = 10
FACILITY_NULL       = 0
FACILITY_ITF        = 4
FACILITY_DISPATCH   = 2
To retreive the Facility,
call       ComFunction    ; call the function
shr        eax, 16        ; shift the HRESULT to the right by 16 bits
and        eax, 1FFFh     ; mask the bits, so only the facility remains
; eax now contains the HRESULT's Facility code

Code - is the facility's status code

     To get the Facility's status code,
call       ComFunction             ; call the function
and        eax, 0000FFFFh          ; mask out the upper 16 bits
; eax now contains the HRESULT's Facility's status code

Using COM with MASM

If you use MASM to assemble your programs, you can use some of its capabilities to make calling COM functions very easy. Using invoke, you can make COM calls look almost as clean as regular calls, plus you can add type checking to each function.

Defining the interface:

     IInterface_Function1Proto     typedef proto :DWORD
IInterface_Function2Proto     typedef proto :DWORD, :DWORD
IInterface_Function1          typedef ptr IInterface_Function1Proto
IInterface_Function2          typedef ptr IInterface_Function2Proto
IInterface struct DWORD
QueryInterface          IUnknown_QueryInterface         ?
AddRef                  IUnknown_AddRef                 ?
Release                 IUnknown_Release                ?
Function1               IInterface_Function1            ?
Function2               Interface_Function2             ?
IInterface ends

Using the interface to call COM functions:

     mov     eax, pObject
mov     eax, [eax]
invoke  (IInterface [eax]).Function1, 0, 0

As you can see, the syntax may seem a bit strange, but it allows for a simple method using the function name itself instead of offsets, as well as type checking.

A Sample program written using COM

Here is some sample source code which uses COM written in straight assembly language, so it should be compatable with any assembler you prefer with only minor changes necessary.

This program uses the Windows Shell Interfaces to show the contents of the Desktop folder in a window. The program is not complete, but shows how the COM library is initialized, de-initialized, and used. I also shows how the shell library is used to get folders and obcets, and how to perform actions on them.

..386
..model flat, stdcall

include windows.inc             ; include the standard windows header
include shlobj.inc              ; this include file contains the shell namespace
; definitions and constants

;---------------------------------------------------------- ..data

        wMsg                    MSG     <?>
g_hInstance             dd      ?
g_pShellMalloc          dd      ?
pshf                    dd      ?       ; shell folder object
peidl                   dd      ?       ; enum id list object
lvi                     LV_ITEM <?>
iCount                  dd      ?
strret                  STRRET  <?>
shfi                    SHFILEINFO <?>
...

;---------------------------------------------------------- ..code
; Entry Point
start:

push 0h
call GetModuleHandle
mov g_hInstance,eax

call InitCommonControls

; initialize the Component Object Model(COM) library ; this function must be called before any COM functions are called

push 0
call CoInitialize

    test    eax,eax                         ; error when the MSB = 1
; (MSB = the sign bit)
js      exit                            ; js = jump if signed

; Get the Shells IMalloc object pointer, and save it to a global variable

push offset g_pShellMalloc
call SHGetMalloc

    cmp     eax, E_FAIL
jz      shutdown

; here we would set up the windows, list view, message loop, and so on.... ; we would also call the FillListView procedure... ; ....

; Cleanup
; Release IMalloc Object pointer

mov eax, g_pShellMalloc
push eax

    mov     eax, [eax]
call    [eax + Release]         ; g_pShellMalloc->Release();
shutdown
; close the COM library

call CoUninitialize

exit
push wMsg.wParam call ExitProcess ; Program Terminates Here

;---------------------------------------------------------- FillListView proc

; get the desktop shell folder, saved to pshf

push offset pshf
call SHGetDesktopFolder

; get the objects of the desktop folder using the EnumObjects method of ; the desktop's shell folder object

push offset peidl
push SHCONTF_NONFOLDERS
push 0
mov eax, pshf
push eax
mov eax, [eax]
call [eax + EnumObjects]

; now loop through the enum id list
idlist_loop:
; Get next id list item

push 0
push offset pidl
push 1
mov eax, peidl
push eax
mov eax, [eax]
call [eax + Next]
test eax,eax
jnz idlist_endloop

    mov     lvi.imask, LVIF_TEXT or LVIF_IMAGE
mov     lvi.iItem,

; Get the item's name by using the GetDisplayNameOf method

push offset strret
push SHGDN_NORMAL
push offset pidl
mov eax, pshf
push eax
mov eax, [eax]
call [eax + GetDisplayNameOf]
; GetDisplayNameOf returns the name in 1 of 3 forms, so get the correct ; form and act accordingly

    cmp     strret.uType, STRRET_CSTR
je      strret_cstr
cmp     strret.uType, STRRET_OFFSET
je      strret_offset
strret olestr
; here you could use WideCharToMultiByte to get the string, ; I have left it out because I am lazy jmp strret_end
strret cstr
lea eax, strret.cStr jmp strret_end
strret offset
mov eax, pidl add eax, strret.uOffset
strret end
mov lvi.pszText, eax

; Get the items icon

push SHGFI_PIDL or SHGFI_SYSICONINDEX or SHGFI_SMALLICON or SHGFI_ICON push sizeof SHFILEINFO
push offset shfi
push 0
push pidl
call SHGetFileInfo

    mov     eax, shfi.iIcon
mov     lvi.iImage, eax

; now add item to the list

push offset lvi
push 0
push LVM_INSERTITEM
push hWndListView
call SendMessage

; repeat the loop
idlist_endloop:

; now free the enum id list
; Remember all allocated objects must be released...

mov eax, peidl
push eax
mov eax,[eax]
call [eax + Release]

; free the desktop shell folder object

mov eax, pshf
push eax
mov eax,[eax]
call [eax + Release]

ret
FillListView endp

END start

Conclusion


Well, that is about it for using COM with assembly language. Hopefully, my next article will go into how to define your own interfaces. As you can see, using COM is not difficult at all, and with it you can add a very powerful capability to your assembly language programs.