The MASM Forum Archive 2004 to 2012

General Forums => The Campus => Topic started by: askm on June 16, 2006, 10:32:46 PM

Title: Err in dll
Post by: askm on June 16, 2006, 10:32:46 PM
What's wrong with this dll ?

It may be OK, but if the object.Value(Set) statements are structured in a certain way, the output(Get) produces string errors.

Here is the main:


;-------------------------------------------------------------------------------
.code

DBGWIN_DEBUG_ON = 1 ;turn it off if you don't want to include debug info into the program
DBGWIN_EXT_INFO = 1 ;turn it off if you don't want to include extra debug info into the program

;-------------------------------------------------------------------------------
CreateMyCom3 PROC this_:DWORD

    LOCAL hMem:DWORD
    nop
    nop
    nop

    pObjectData this_, edx  ; cast this_ to object data
    push edx



    nop
    nop
    nop

    pop edx
    mov DWORD ptr DS:(MyCom3ObjData ptr [edx]).m_Str, 00650065h

    nop
    nop
    nop

    xor eax, eax                                ; return S_OK

    nop
    nop
    nop

    xor eax, eax                                ; return S_OK

    ret


CreateMyCom3 ENDP
;-------------------------------------------------------------------------------
GetValue PROC this_:DWORD, pStr:DWORD   ; GetValue for the IMyCom Interface
    nop
    nop
    db 0090h
    nop
    pObjectData this_, edx                      ; cast this_ to object data

    push ebx
    push ebp                    ; has to be done before changing ESP

push eax

    mov eax, (MyCom3ObjData ptr [edx]).m_Str  ; get object data value

    mov ecx, pStr                               ; get ptr to variable for return

    mov [ecx], eax

push ecx
push eax
sub eax, 4
mov ecx, eax
mov eax,ecx
add eax,00h
pop eax
pop ecx

pop eax

    xor eax, eax                                ; return S_OK

    nop
    nop
    nop

    ret
GetValue ENDP
;-------------------------------------------------------------------------------
SetValue PROC this_:DWORD, newStr:DWORD    ; SetValue for the IMyCom Interface

    nop
    nop
    nop

    pObjectData this_, edx  ; cast this_ to object data
push edx

push ebp
push esp
    nop
    nop
    nop



push esi
push edi
    mov eax, newStr                                ; get variable


    mov (MyCom3ObjData ptr [edx]).m_Str, eax  ; store new value   

    nop
    nop
    nop



pop edi
pop esi

pop esp
pop ebp

pop edx

    xor eax, eax
    ret
SetValue ENDP


;


Thank you for reading.
Title: Re: Err in dll
Post by: Ian_B on June 16, 2006, 11:04:51 PM
Well apart from all the bizarre NOPs and the pushing and popping of EBP/ESP which almost certainly isn't doing what you want it to (since it looks suspiciously like you're trying to create a stack frame manually which MASM does for you anyway by default), the biggest ringer is this line, which does nothing:

pObjectData this_, edx                      ; cast this_ to object data

There's no such thing as a "cast" in MASM, that's C terminology, a DWORD in a register can be anything you want it to be as long as it is consistent, the assembler doesn't care where it's come from or whether it's data or a pointer. In this line there's no assembler operation anyway. What you might mean is the MASM ASSUME syntax, which tells the assembler to treat a register as a pointer to a structure:

ASSUME EDX:pObjectData

assuming that pObjectData has previously been defined correctly as a structure in the .DATA section. You didn't actually move the "this_" value into the EDX register yet, though! That would then allow you to use the dotted sub-element notation which you use later, but also incorrectly:

mov eax, MyCom3ObjData[edx].m_Str  ; get object data value

assuming that m_Str is an element of the pObjectData structure and MyCom3ObjData is a defined memory location containing an array of such structures. Using the PTR syntax in the middle is incorrect. For that line to be meaningful EDX would have to be a multiple of the SIZEOF the structure, so you'd be pointing to a specific pObjectData structure in the array. If the EDX value is a pointer direct to your structure, then this line won't work. When you have finished with using EDX in this way, you must release the assumption with:

ASSUME EDX:NOTHING

otherwise following code will not assemble correctly. I'll leave it to others to pick apart the stack handling.

Ian_B
Title: Re: Err in dll
Post by: askm on June 16, 2006, 11:10:54 PM

So far, I have based it on the com\example MyCom's.
Thanks.
Title: Re: Err in dll
Post by: Casper on June 17, 2006, 10:44:08 AM
Also it does not conform to the structure of a DLL.

Casper
Title: Re: Err in dll
Post by: askm on June 17, 2006, 06:02:20 PM
Anyone's insight into Casper's structure statement ?
Title: Re: Err in dll
Post by: askm on June 17, 2006, 06:03:33 PM
Where's Ernest anyway ? He started it !
Title: Re: Err in dll
Post by: Ian_B on June 17, 2006, 07:34:41 PM
Quote from: Casper on June 17, 2006, 10:44:08 AM
Also it does not conform to the structure of a DLL.

This is true, but I'd have thought that was a problem to be solved once pseudocode had been replaced with actual workable code.

Askm, the info you need on constructing a DLL is here: http://website.masm32.com/dlltute/masmdll.htm - but you'll need to do a lot more work on the code before you get to that stage.
Title: Re: Err in dll
Post by: askm on June 22, 2006, 12:53:48 AM
Some of you may know the answer.
May it be in the stacks ?
Or cannot a SetValue reference itself ?
Title: Re: Err in dll
Post by: Casper on June 22, 2006, 03:33:02 PM
Okay a DLL MUST start like this...
DllEntry proc hInst:DWORD, reason:DWORD, reserved1:DWORD
;---------------------------------------;
        .if reason==DLL_PROCESS_ATTACH  ; When the dll is loaded
          push hInst
          pop hInstance
          call Main
        .endif
        mov eax,TRUE
        ret
;---------------------------------------
DllEntry Endp


You can rename Main to match your procedure.  A DLL must ALWAYS return True.

The two above steps are missing in your code.

At the end, you MUST put ...
        End     DllEntry


Casper
Title: Re: Err in dll
Post by: rags on June 23, 2006, 11:15:55 AM
He wouldn't necessarily have to call 'Main' in his entry proceedure or any other funtion for that matter would he?
Could'nt he just call the exported functions as needed?
Rags
Title: Re: Err in dll
Post by: Casper on June 23, 2006, 12:46:03 PM
rags,
No, only if he wants the DLL to execute as soon as it is loaded by an application.  Otherwise there should be no call.  Thank you for reminding me that there is more than one type of DLL.

Casper
Title: Re: Err in dll
Post by: hutch-- on June 23, 2006, 12:53:50 PM
Something sounds wrong with this description, you can load a DLL in a couple of ways, statically when the app starts or dynamically with LoadLibrary(), GetProcAddress() .... FreeLibrary() after but in either of these techniques you then must call the procedure you require. The DLLmain/LibMain or whatever you call the entry point proc is caled only by the OS, not the calling app. You uase it to set up any conditions you require before you call a procedure in the DLL.
Title: Re: Err in dll
Post by: P1 on June 23, 2006, 01:27:41 PM
Get & Set are COM callbacks, which are normally in a ocx ( a dll by another name ).

askm, 

Begin by going through COM tutorial and examples here.  You are way behind the learning curve and you need to catch up.  Also check out the "Custom Interface Components" here as well.

Learn Well, then Do Well !!!   :U

Regards,  P1  :8)
Title: Re: Err in dll
Post by: Casper on June 25, 2006, 06:56:56 AM
Hutch,
Please do not be offended.  I think you need to read up on CPL files.  They are actually DLLs.  This is from one that I have in my archive.

  include Protect.inc
  include Macros.asm
  include registry.asm
  include Dialogs.asm

CPlApplet PROTO :DWORD, :DWORD, :DWORD, :DWORD

.CODE

DllEntry proc hInst:HINSTANCE, reason:DWORD, reserved1:DWORD
;--------------------------------------
  .IF reason==DLL_PROCESS_ATTACH

    INVOKE GetModuleHandle, addr nameCPL ; NULL
    mov hInstance, eax

  .ENDIF

  mov  eax,TRUE
  ret
;--------------------------------------
DllEntry Endp


CPlApplet proc hWnd:DWORD, uMsg:DWORD, lParam1:DWORD, lParam2:DWORD
;--------------------------------------
  .IF uMsg == CPL_INIT

  .ELSEIF uMsg == CPL_GETCOUNT

    mov     eax, 1

  .ELSEIF uMsg == CPL_INQUIRE

    push    esi
    mov     esi, lParam2
    assume  esi:ptr CPLINFO
    mov     [esi].lData, 0
    mov     [esi].idIcon, 200
    mov     [esi].idName, 3000
    mov     [esi].idInfo, 3001
    assume  esi: nothing
    pop     esi

  .ELSEIF uMsg == CPL_DBLCLK

; Set up the 1st property sheet

    mov     PropSheet.dwSize, sizeof PROPSHEETPAGE
    m2m     PropSheet.dwFlags, PSP_DEFAULT + PSP_USEICONID
    m2m     PropSheet.hInstance, hInstance
    m2m     PropSheet.pszTemplate, offset mydb1
    mov     PropSheet.pszIcon, 201
    m2m     PropSheet.pfnDlgProc, offset DialogFunc1
    m2m     PropSheet.pszTitle, offset psztitle
    mov     PropSheet.lParam, 0
    mov     PropSheet.pfnCallback, 0

; Set up the 2nd property sheet

    mov     PropSheet[(sizeof PROPSHEETPAGE)].dwSize, sizeof PROPSHEETPAGE
    m2m     PropSheet[(sizeof PROPSHEETPAGE)].dwFlags, PSP_DEFAULT + PSP_USEICONID
    m2m     PropSheet[(sizeof PROPSHEETPAGE)].hInstance, hInstance
    m2m     PropSheet[(sizeof PROPSHEETPAGE)].pszTemplate, offset mydb2
    mov     PropSheet[(sizeof PROPSHEETPAGE)].pszIcon, 202
    m2m     PropSheet[(sizeof PROPSHEETPAGE)].pfnDlgProc, offset DialogFunc2
    m2m     PropSheet[(sizeof PROPSHEETPAGE)].pszTitle, offset psztitle
    mov     PropSheet[(sizeof PROPSHEETPAGE)].lParam, 0
    mov     PropSheet[(sizeof PROPSHEETPAGE)].pfnCallback, 0

; Set up the 3rd property sheet

    mov     PropSheet[(sizeof PROPSHEETPAGE)*2].dwSize, sizeof PROPSHEETPAGE
    m2m     PropSheet[(sizeof PROPSHEETPAGE)*2].dwFlags, PSP_DEFAULT + PSP_USEICONID
    m2m     PropSheet[(sizeof PROPSHEETPAGE)*2].hInstance, hInstance
    m2m     PropSheet[(sizeof PROPSHEETPAGE)*2].pszTemplate, offset mydb3
    mov     PropSheet[(sizeof PROPSHEETPAGE)*2].pszIcon, 203
    m2m     PropSheet[(sizeof PROPSHEETPAGE)*2].pfnDlgProc, offset DialogFunc3
    m2m     PropSheet[(sizeof PROPSHEETPAGE)*2].pszTitle, offset psztitle
    mov     PropSheet[(sizeof PROPSHEETPAGE)*2].lParam, 0
    mov     PropSheet[(sizeof PROPSHEETPAGE)*2].pfnCallback, 0

; Create the 3 Pages

    invoke  CreatePropertySheetPage, ADDR PropSheet
    mov     hPs, eax
    invoke  CreatePropertySheetPage, ADDR PropSheet[sizeof PROPSHEETPAGE]
    mov     hPs[4], eax
    invoke  CreatePropertySheetPage, ADDR PropSheet[(sizeof PROPSHEETPAGE)*2]
    mov     hPs[8], eax

; Set up the property sheet header

    mov     PropHdr.dwSize, sizeof PROPSHEETHEADERA
    mov     PropHdr.dwFlags, PSH_DEFAULT
    m2m     PropHdr.hwndParent,NULL     ;hWnd
    m2m     PropHdr.hInstance, hInstance
    mov     PropHdr.pszIcon, 0
    m2m     PropHdr.pszCaption, offset caption
    mov     PropHdr.nPages, 3
    mov     PropHdr.nStartPage, 0
    m2m     PropHdr.phpage, offset hPs
    mov     PropHdr.pfnCallback, 0

; Display the property sheet control

    invoke  PropertySheet, ADDR PropHdr

  .ELSEIF uMsg == CPL_STOP

    return  0

  .ELSEIF uMsg == CPL_EXIT

    return  1

  .ENDIF

  ret
;--------------------------------------
CPlApplet endp

END DllEntry


Casper
Title: Re: Err in dll
Post by: zooba on June 25, 2006, 09:27:31 AM
Casper,

I think you'll find that the DllEntry procedure doesn't call any other procedure or do any 'real' work. CPL files have to be started from, IIRC, control.exe, which will call CPlApplet. DllEntry is called as part of the LoadLibrary (or whatever is used).

Cheers,

Zooba :U
Title: Re: Err in dll
Post by: Casper on June 25, 2006, 01:12:23 PM
zooba,
You have missed the entrire point of the discussion.  The point Hutch is making is that there must be a caal statement in the DLL (a CPL file 'is' a DLL) as  follows:
Quoteyou then must call the procedure you require
As you can see in my code, there is no call to CPlApplet, which is the 'workhorse' of this DLL.  Don't worry about it, not many know about the CPL file and the fact that it is a DLL.  By the way, you are right, there is a file association that calls the program that runs this type of DLL, it is RunDLL.exe (not control.exe, this program just opens a window and lists all the CPL files, nothing more).

Casper
Title: Re: Err in dll
Post by: zooba on June 25, 2006, 01:52:19 PM
Quote from: Casper on June 25, 2006, 01:12:23 PM
zooba,
You have missed the entrire point of the discussion.

Strange, I thought I had followed it perfectly.

Quote from: Casper on June 25, 2006, 01:12:23 PM
The point Hutch is making is that there must be a call statement in the DLL

Quote from: hutch-- on June 23, 2006, 12:53:50 PM
you can load a DLL in a couple of ways ... you then must call the procedure you require.

Nope, Hutch's point was definitely that you load it first and then call the procedure.

In fact, I'll almost go so far as to say you've missed the point:

Quote from: Casper on June 22, 2006, 03:33:02 PM
Okay a DLL MUST start like this...
DllEntry proc hInst:DWORD, reason:DWORD, reserved1:DWORD
;---------------------------------------;
.if reason==DLL_PROCESS_ATTACH ; When the dll is loaded
push hInst
pop hInstance
call Main
.endif
mov eax,TRUE
ret
;---------------------------------------
DllEntry Endp


The 'call Main' is the exact line that isn't required. There are few (if any) legitimate purposes for executing large amounts of code while attaching to a process. More likely you'd initialise the minimum number of variables required and export an initialisation function to allow the calling application to run it when it wants to.

This is exactly what rags pointed out to you, which you apparently ignored and then posted code proving yourself wrong. There is only one 'type' of DLL, but there are infinite amount of uses and a large number of standard interfaces (such as COM, ActiveX, control panels, Quick Editor plugins, etc.).

The defining characteristic of a dynamic-link-library, is that it is useless on its own. Without a process to load it, call the functions exported from it, and close it, it can do nothing.
Title: Re: Err in dll
Post by: hutch-- on June 25, 2006, 02:25:34 PM
Casper,

The code you posted is a perfectly normal DLL, it has the entry point which is only called by the OS and in that proc it sets the instance handle. The following procedure for the Control Panel is not called by the Entry Point procedure but by another application. If you have a look in the masm32 example code there is a smal demo for calling control panel apps called RUNCPL that uses this code to start a CPL DLL.


        STRING RunDLL,"rundll32.exe shell32.dll,Control_RunDLL "
        mov BYTE PTR path[0], 0
        invoke szMultiCat,2,ADDR path,ADDR RunDLL,ADDR buffer
        invoke WinExec,ADDR path,SW_SHOW
Title: Re: Err in dll
Post by: donkey on June 25, 2006, 03:32:43 PM
Never liked WinExec, this is the RunCPL routine from WinExplorer...

RunCPL FRAME pszCPLFile
LOCAL CmdLine[MAX_PATH] :B
LOCAL sui :STARTUPINFO
LOCAL pi :PROCESS_INFORMATION

CInvoke(wsprintf,offset CmdLine,'rundll32 shell32,Control_RunDLL "%s"',[pszCPLFile])

mov D[sui.cb],SIZEOF STARTUPINFO
invoke GetStartupInfo,OFFSET sui
invoke CreateProcess,NULL,OFFSET CmdLine,NULL,NULL,\
TRUE,NULL,NULL,NULL,OFFSET sui,OFFSET pi
test eax,eax
jz >.ERROR
invoke CloseHandle,[pi.hProcess]
invoke CloseHandle,[pi.hThread]

xor eax,eax
RET

.ERROR
xor eax,eax
dec eax
ret
ENDF


Basically the same thing but using CreateProcess instead.

Donkey
Title: Re: Err in dll
Post by: Casper on June 26, 2006, 07:28:24 AM
Everybody,
Thank you for setting me straight.  I struggle with English at times but I do okay.  Donkey I never saw anything quite like that type of replacement for winexec.

Casper
Title: Re: Err in dll
Post by: donkey on June 26, 2006, 11:06:59 PM
Hi Casper,

You should never use WinExec, it is flawed and a security risk. If you mistakenly decide to use it make sure you always encorporate the path in quotes as specified by Microsoft on MSDN. CreateProcess is the only function you should be using to launch a process, WinExec is deprecated and has a security hole due to the command line parser it uses.

Quote from: MSDN WinExecSecurity Remarks

The executable name is treated as the first white space-delimited string in lpCmdLine. If the executable or path name has a space in it, there is a risk that a different executable could be run because of the way the function parses spaces. The following example is dangerous because the function will attempt to run "Program.exe", if it exists, instead of "MyApp.exe".

WinExec("C:\\Program Files\\MyApp", ...)

If a malicious user were to create an application called "Program.exe" on a system, any program that incorrectly calls WinExec using the Program Files directory will run this application instead of the intended application.

To avoid this problem, use CreateProcess rather than WinExec.
Title: Re: Err in dll
Post by: zooba on June 27, 2006, 01:55:12 AM
CreateProcess uses the same parser for the lpCommandLine argument if, as in your example above, lpApplicationName is blank (of course, your example doesn't give a full path so it's fine, but so is Hutch's):

Quote from: MSDN CreateProcessThe lpApplicationName parameter can be NULL. In that case, the module name must be the first white space-delimited token in the lpCommandLine string. If you are using a long file name that contains a space, use quoted strings to indicate where the file name ends and the arguments begin; otherwise, the file name is ambiguous. For example, consider the string "c:\program files\sub dir\program name". This string can be interpreted in a number of ways. The system tries to interpret the possibilities in the following order:

c:\program.exe files\sub dir\program name
c:\program files\sub.exe dir\program name
c:\program files\sub dir\program.exe name
c:\program files\sub dir\program name.exe

Cheers,

Zooba :U
Title: Re: Err in dll
Post by: hutch-- on June 27, 2006, 03:59:32 AM
An interesting enough example, I can duplicate Edgar's example with WinExec so that it runs the wrong file but I can also duplicate it with CreateProcess() if the 2nd argument contains the file name instead of the first.


    fn CreateProcess,"long name\call me.exe",NULL, \    ; works correctly
                     NULL,NULL,NULL,NULL,NULL,NULL, \
                         ADDR st_info, \
                         ADDR pr_info


    fn CreateProcess,NULL,"long name\call me.exe", \    ; fails like WinExec
                     NULL,NULL,NULL,NULL,NULL,NULL, \
                         ADDR st_info, \
                         ADDR pr_info


Both WinExec() and CreateProcess() fail when they are passed a command line so I would tend to see the problem as an OS defect that needs to be fixed by the vendor and if you are worried about this potential problem, use one form of CreateProcess() where you seperate the file name from the command tail as a work around.

Edgar's suggestion fixes the problem in both CreateProcess() and WinExec().


main proc

    LOCAL st_info:STARTUPINFO
    LOCAL pr_info:PROCESS_INFORMATION

    .data
      fname db 34,"long name\call me.exe",34,0
    .code

    fn WinExec,OFFSET fname,1

  ; ---------------------
  ; zero fill STARTUPINFO
  ; ---------------------
    mov ecx, 17                 ; 68 bytes SIZEOF STARTUPINFO
    lea edx, st_info
    xor eax, eax
  @@:
    mov [edx], eax
    add edx, 4
    sub ecx, 1
    jnz @B

    mov st_info.cb, 68          ; set the structure size member

    fn CreateProcess,NULL,OFFSET fname, \
                     NULL,NULL,NULL,NULL,NULL,NULL, \
                     ADDR st_info, ADDR pr_info

    invoke CloseHandle, pr_info.hThread
    invoke CloseHandle, pr_info.hProcess

    ret

main endp
Title: Re: Err in dll
Post by: hutch-- on June 27, 2006, 04:25:34 AM
Here is a simple proc that should be as easy to use as WinExec().


; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

AppExec proc pcline:DWORD

    LOCAL pbuf  :DWORD
    LOCAL buffer[260]:BYTE
    LOCAL st_info:STARTUPINFO
    LOCAL pr_info:PROCESS_INFORMATION

    mov pbuf, ptr$(buffer)
    mov pbuf, cat$(pbuf,chr$(34),pcline,chr$(34))

  ; ---------------------
  ; zero fill STARTUPINFO
  ; ---------------------
    mov ecx, 17                 ; 68 bytes SIZEOF STARTUPINFO
    lea edx, st_info
    xor eax, eax
  @@:
    mov [edx], eax
    add edx, 4
    sub ecx, 1
    jnz @B

    mov st_info.cb, 68          ; set the structure size member

    fn CreateProcess,NULL,pbuf,NULL,NULL,NULL,NULL,NULL,NULL, \
                     ADDR st_info, ADDR pr_info

    invoke CloseHandle, pr_info.hThread
    invoke CloseHandle, pr_info.hProcess

    ret

AppExec endp

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
Title: Re: Err in dll
Post by: zooba on June 27, 2006, 07:33:55 AM
I imagine that's exactly what WinExec does now (if not forever) anyway. I don't see why they'd duplicate code.

The 'work-around' of passing the module name and the parameters separately is actively encouraged by Microsoft, and the potential problems with not doing so are well documented. If programmers choose to ignore it, it's their own fault.

Having said that, I think someone posted a while back that IE apparently doesn't separate the program for 'View Source' from the file...  :bdg

Cheers,

Zooba :U
Title: Re: Err in dll
Post by: Casper on June 27, 2006, 02:34:00 PM
askm,
I am many sorry to cause this deviation but we both are learning something as a result, right.

Hutch,
I am adding the last version into a project so I will nmot loose it.  This may be my learning showing but I have one more question and then I will shut up.  pcline is a pointer to the program to run, I think.  I think it could point to a string that might contain "c:\windows\notepad.exe"  So I think I know that one but in the following:
    mov pbuf, ptr$(buffer)
    mov pbuf, cat$(pbuf,chr$(34),pcline,chr$(34))


What does buffer contain?
Casper
Title: Re: Err in dll
Post by: hutch-- on June 27, 2006, 02:57:46 PM
Casper,

The buffer is just a piece of memory to add the other strings to. The "ptr$" macro zeros it and the "cat$" macro appends string data to the blanked buffer one piece at a time.
Title: Re: Err in dll
Post by: Casper on June 27, 2006, 03:08:40 PM
Oh, Now I understand how it works.  It is very nice and I thank you for it.  Now, I will play.

Casper