flat assembler
Message board for the users of flat assembler.

Index > Macroinstructions > [GOTCHA] cominvk cannot work with register based structs

Author
Thread Post new topic Reply to topic
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20357
Location: In your JS exploiting you and your system
revolution 11 Jul 2010, 07:56
[edit]See below for the revised bug report.[/edit]
[edit2]demoting to a GOTCHA since this seems to be the intended action of the macros.[/edit2]

cominvk and comcall cannot work with register based dynamically allocated objects.

Consider this:
Code:
include 'win32ax.inc'

interface IStreamList,\
 QueryInterface,\
   AddRef,\
   Release,\
  Read,\
     Write,\
    Seek,\
     SetSize,\
  CopyTo,\
   Commit,\
   Revert,\
   LockRegion,\
       UnlockRegion,\
     Stat,\
     Clone

.code

struct        STREAM_STUFF
        stream1 IStreamList
 stream2 IStreamList
ends     ;STREAM_STUFF

start:
;...
     invoke  LocalAlloc,LMEM_FIXED,sizeof.STREAM_STUFF
   mov     ebx,eax
;...
     cominvk ebx+STREAM_STUFF.stream1,SetSize,100,0
;...
      invoke  ExitProcess,0

.end start    
Assembles to:
Code:
00401000 >/$  6A 08           PUSH    8                                ; /Size = 8
00401002  |.  6A 00     PUSH    0                                ; |Flags = LMEM_FIXED
00401004  |.  FF15 46204000 CALL    [<&KERNEL32.LocalAlloc>]         ; \LocalAlloc
0040100A  |.  89C3           MOV     EBX,EAX
0040100C  |.  6A 00          PUSH    0
0040100E  |.  6A 64        PUSH    64
00401010  |.  8B03        MOV     EAX,[EBX]
00401012  |.  50           PUSH    EAX
00401013  |.  8B00       MOV     EAX,[EAX]
00401015  |.  FF5418 18            CALL    [EAX+EBX+18]        ;<----- should be call [eax+0x18]
00401019  |.  6A 00         PUSH    0                                ; /ExitCode = 0
0040101B  \.  FF15 42204000 CALL    [<&KERNEL32.ExitProcess>]             ; \ExitProcess    
The call to the COM tabel is corrupted by the presence of the EBX pointer.

;-- ------------------------------------------------------------------------------------------------------

There is a way to temporarily bypass the problem with this:
Code:
      virtual at ebx
              .STREAM_STUFF_VIRTUALISED STREAM_STUFF
      end virtual
 cominvk .STREAM_STUFF_VIRTUALISED.stream1,SetSize,100,0    
Assembles to:
Code:
0040100C  |.  6A 00      PUSH    0
0040100E  |.  6A 64        PUSH    64
00401010  |.  8B03        MOV     EAX,[EBX]
00401012  |.  50           PUSH    EAX
00401013  |.  8B00       MOV     EAX,[EAX]
00401015  |.  FF50 18      CALL    [EAX+18]            ;<----- now the code is correct    
Can the COM32.INC file macros be changed to do this correctly without the virtual block?


Last edited by revolution on 11 Jul 2010, 11:12; edited 5 times in total
Post 11 Jul 2010, 07:56
View user's profile Send private message Visit poster's website Reply with quote
Tomasz Grysztar



Joined: 16 Jun 2003
Posts: 8356
Location: Kraków, Poland
Tomasz Grysztar 11 Jul 2010, 08:55
It's the comcall that should be used for such purpose. Check out how the USECOM example does it:
Code:
        mov     ebx,[ShellTaskBar]
        comcall ebx,ITaskBarList,HrInit
        comcall ebx,ITaskBarList,AddTab,[hwnd]
        comcall ebx,ITaskBarList,ActivateTab,[hwnd]    
Post 11 Jul 2010, 08:55
View user's profile Send private message Visit poster's website Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20357
Location: In your JS exploiting you and your system
revolution 11 Jul 2010, 09:31
But this won't compile:
Code:
 comcall ebx+STREAM_STUFF.stream2,SetSize,100,0 ;error: extra characters on line.
        comcall [ebx+STREAM_STUFF.stream2],SetSize,100,0 ;error: undefined symbol 'SetSize.100'.    
I am a dummy, I can't figure out how to make the macros work with the structure. Question
Post 11 Jul 2010, 09:31
View user's profile Send private message Visit poster's website Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20357
Location: In your JS exploiting you and your system
revolution 11 Jul 2010, 09:40
Oh, nevermind.
Code:
comcall    ebx,STREAM_STUFF.stream2,SetSize,100,0    
Post 11 Jul 2010, 09:40
View user's profile Send private message Visit poster's website Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20357
Location: In your JS exploiting you and your system
revolution 11 Jul 2010, 09:49
Reopen the bug:
Code:
  comcall ebx,STREAM_STUFF.stream1,SetSize,100,0
      comcall ebx,STREAM_STUFF.stream2,SetSize,100,0    
Generates the same code for both calls:
Code:
0040100C  |.  6A 00         PUSH    0
0040100E  |.  6A 64         PUSH    64
00401010  |.  53            PUSH    EBX
00401011  |.  8B03          MOV     EAX,[EBX]
00401013  |.  FF50 18       CALL    [EAX+18]
00401016  |.  6A 00         PUSH    0
00401018  |.  6A 64         PUSH    64
0040101A  |.  53            PUSH    EBX
0040101B  |.  8B03          MOV     EAX,[EBX]
0040101D  |.  FF50 18       CALL    [EAX+18]    
It should be something like this:
Code:
00401020  |.  6A 00         PUSH    0
00401022  |.  6A 64         PUSH    64
00401024  |.  8B03          MOV     EAX,[EBX]
00401026  |.  50            PUSH    EAX
00401027  |.  8B00          MOV     EAX,[EAX]
00401029  |.  FF50 18       CALL    [EAX+18]
0040102C  |.  6A 00         PUSH    0
0040102E  |.  6A 64         PUSH    64
00401030  |.  8B43 04       MOV     EAX,[EBX+4]
00401033  |.  50            PUSH    EAX
00401034  |.  8B00          MOV     EAX,[EAX]
00401036  |.  FF50 18       CALL    [EAX+18]    
Post 11 Jul 2010, 09:49
View user's profile Send private message Visit poster's website Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20357
Location: In your JS exploiting you and your system
revolution 11 Jul 2010, 10:11
Is this what we are expected to do?
Code:
      mov     eax,[ebx+STREAM_STUFF.stream2]
      comcall eax,STREAM_STUFF.stream2,SetSize,100,0    
Seems clumsy though.

If we wanted this
Code:
      mov     eax,[ebx+STREAM_STUFF.stream2]
      comcall eax,STREAM_STUFF.stream2,SetSize,eax,addr ecx+4    
then we can't do it so easily because eax needs to be another register.
Post 11 Jul 2010, 10:11
View user's profile Send private message Visit poster's website Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20357
Location: In your JS exploiting you and your system
revolution 11 Jul 2010, 10:27
There, I fixed it:
Code:
macro cominvk object,proc,[arg]
 { common
    if ~ arg eq
   reverse
     pushd arg
   common
    end if
    mov eax,[object]
    push eax
    mov eax,[eax]
       local secondbyte,offset
     virtual
             call [eax+object#.#proc]
            load secondbyte byte from $$+1
              if secondbyte and 0xc0 = 0x80
                       load offset dword from $-4
          else if secondbyte and 0xc0 = 0x40
                  load offset byte from $-1
           else
                        offset =0
           end if
      end virtual
    call dword[eax+offset] }    
Nice:
Code:
    cominvk ebx+STREAM_STUFF.stream2,SetSize,100,0    
Code:
0040100C  |.  6A 00         PUSH    0
0040100E  |.  6A 64         PUSH    64
00401010  |.  8B43 04       MOV     EAX,[EBX+4]
00401013  |.  50            PUSH    EAX
00401014  |.  8B00          MOV     EAX,[EAX]
00401016  |.  FF50 18       CALL    [EAX+18]    
[edit] Made the virtual block more robust for all call types.
Post 11 Jul 2010, 10:27
View user's profile Send private message Visit poster's website Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20357
Location: In your JS exploiting you and your system
revolution 12 Jul 2010, 00:34
COM64.INC version:
Code:
macro cominvk object,proc,[arg]
 { common
    macro call dummy
    \{ mov rax,[object]
       mov rax,[rax]
         local firstbyte,modregrmbyte,offset
         virtual
                     call [rax+object#.#proc]
                    load firstbyte byte from $$
                 if firstbyte and 0xf0 = 0x40
                                load modregrmbyte byte from $$+2
                    else
                                load modregrmbyte byte from $$+1
                    end if
                      if modregrmbyte and 0xc0 = 0x80
                             load offset dword from $-4
                  else if modregrmbyte and 0xc0 = 0x40
                                load offset byte from $-1
                   else
                                offset = 0
                  end if
              end virtual
         call qword[rax+offset] \}
    fastcall proc,[object],arg
    purge call }    
Untested Embarassed
Post 12 Jul 2010, 00:34
View user's profile Send private message Visit poster's website Reply with quote
Tomasz Grysztar



Joined: 16 Jun 2003
Posts: 8356
Location: Kraków, Poland
Tomasz Grysztar 31 Aug 2010, 09:30
OK, previously I did not really understand what really you problem was. Yes, first parameter to "cominvk" has to be directly defined interface label - however that not necessarily is a problem.

I think that the proper way to do this would be:
Code:
include 'win32ax.inc'

interface IStreamList,\ 
        QueryInterface,\ 
        AddRef,\ 
        Release,\ 
        Read,\ 
        Write,\ 
        Seek,\ 
        SetSize,\ 
        CopyTo,\ 
        Commit,\ 
        Revert,\ 
        LockRegion,\ 
        UnlockRegion,\ 
        Stat,\ 
        Clone 

.code 

struct  STREAM_STUFF 
        stream1 IStreamList 
        stream2 IStreamList 
ends    ;STREAM_STUFF 

virtual at ebx
  ebx_stuff STREAM_STUFF
end virtual

start: 
;... 
        invoke  LocalAlloc,LMEM_FIXED,sizeof.STREAM_STUFF 
        mov     ebx,eax 
;...

        cominvk ebx_stuff.stream1,SetSize,100,0
;... 
        invoke  ExitProcess,0 

.end start    

or even:
Code:
include 'win32ax.inc'
include 'macro/masm.inc'

interface IStreamList,\ 
        QueryInterface,\ 
        AddRef,\ 
        Release,\ 
        Read,\ 
        Write,\ 
        Seek,\ 
        SetSize,\ 
        CopyTo,\ 
        Commit,\ 
        Revert,\ 
        LockRegion,\ 
        UnlockRegion,\ 
        Stat,\ 
        Clone 

.code 

struct  STREAM_STUFF 
        stream1 IStreamList 
        stream2 IStreamList 
ends    ;STREAM_STUFF 

start: 
;... 
        invoke  LocalAlloc,LMEM_FIXED,sizeof.STREAM_STUFF 
        mov     ebx,eax 
;...

    assume ebx:STREAM_STUFF

        cominvk ebx.stream1,SetSize,100,0

    assume ebx:none
;... 
        invoke  ExitProcess,0 

.end start    
Post 31 Aug 2010, 09:30
View user's profile Send private message Visit poster's website Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20357
Location: In your JS exploiting you and your system
revolution 31 Aug 2010, 09:52
I think that the macros could be improved by either just doing it correctly (as in my last example) or generate an error. The current situation is to generate wrong code with no error.
Post 31 Aug 2010, 09:52
View user's profile Send private message Visit poster's website Reply with quote
Tomasz Grysztar



Joined: 16 Jun 2003
Posts: 8356
Location: Kraków, Poland
Tomasz Grysztar 31 Aug 2010, 10:21
OK, error checking you have.
Post 31 Aug 2010, 10:21
View user's profile Send private message Visit poster's website 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.