Old 15th September 2010, 02:18   #1
Zinthose
Senior Member
 
Join Date: May 2009
Posts: 152
Anouther Newbish System Plugin Question

I have a DLL called SbAdmDll.dll.

The documentation has a function defined as follows...
code:
“extern C” LPWSTR
SBADM_execute(
LPCWSTR exec_xml,
SBADM_CALLBACK callback
);



exec_xml [In] Pointer to a null terminated Unicode string that contains the XML of the command to execute.

callback [In] Optional pointer to a callback function that can be used to receive additional progress and information. This can be NULL if no callback is required. This is primarily intended for use by the command line interface to display more information.
Here is what I interpreted is to be using NSIS....
PHP Code:
InitPluginsDir
SetOutPath $PLUGINSDIR
File SbAdmDll
.dll

StrCpy 
$`${XMLStuff}`

ClearErrors
System
::Call `SbAdmDll::SBADM_execute(w r1,i 0)w .r0`
DetailPrint $
The returned value is "error" which tells me that system::call is choking on something... Any ideas what I may be doing wrong here?
Zinthose is offline   Reply With Quote
Old 15th September 2010, 08:57   #2
punkomat
Junior Member
 
Join Date: Jun 2009
Posts: 10
Check with Depends that your entypoint is propperly exported.
punkomat is offline   Reply With Quote
Old 15th September 2010, 12:56   #3
Zinthose
Senior Member
 
Join Date: May 2009
Posts: 152
I think I found the problem...

I'm recreating the NSIS script using AutoIt's DLL calls. AutoIt is telling me that there are missing DLLs. Good to know...

I guess I'll be prototyping all my NSIS scripts with AutoIt from now on.
Zinthose is offline   Reply With Quote
Old 16th September 2010, 21:01   #4
Zinthose
Senior Member
 
Join Date: May 2009
Posts: 152
I checked with Dependency Walker and everything is in place now but now I'm getting a "function not found in the DLL file" error although I'm using the named as supplied by Dependency Walker:
code:
unsigned short * SBADM_execute(unsigned short const *,int (*)(unsigned long,void *))
I have the function entry point address.. Can I use that in place of the name? At least for this instance / version of the dll?
Dose the system plugin allow for this? If so who would I do it...
Zinthose is offline   Reply With Quote
Old 16th September 2010, 21:53   #5
Anders
Moderator
 
Anders's Avatar
 
Join Date: Jun 2002
Location: ${NSISDIR}
Posts: 5,153
Not really sure how it can return a string (is it just a pointer into exec_xml?) anyway, you don't provide any information about the calling convention, so maybe its cdecl (system plugin uses stdcall by default) try: System::Call 'SbAdmDll::SBADM_execute(w r1,i 0)i.r0 ? c'

IntOp $PostCount $PostCount + 1
Anders is offline   Reply With Quote
Old 17th September 2010, 15:21   #6
Zinthose
Senior Member
 
Join Date: May 2009
Posts: 152
I give up... I think there is something seriously wrong with this dll.. I can't even get the thing to execute in AutoIt.

I'm in touch with the vendor but they are feeding me crap about using the COM DLL instead. (Note the COM DLL requires the DLL I'm trying to call So I would be adding 36K and increasing the complexity exponentially)
Zinthose is offline   Reply With Quote
Old 17th September 2010, 17:40   #7
Anders
Moderator
 
Anders's Avatar
 
Join Date: Jun 2002
Location: ${NSISDIR}
Posts: 5,153
I assume you are talking about a Mcafee thing, in that case, I also found references to another function: SBADMDLL_API void SBADM_free_string(LPWSTR str) so then it makes sense how the first call can return a string. Now we just need to know what SBADMDLL_API is defined as. Do you have a header file or something?

IntOp $PostCount $PostCount + 1
Anders is offline   Reply With Quote
Old 17th September 2010, 21:11   #8
Zinthose
Senior Member
 
Join Date: May 2009
Posts: 152
Your correct...

I'm trying to get examples from McAfee but all I have at the moment is the PDF Scripting Guide provided by McAfee. Here is an excerpt...

SBADM_execute
This is the main function via which all the commands are “executed”.
code:
“extern C” LPWSTR
SBADM_execute(
LPCWSTR exec_xml,
SBADM_CALLBACK callback
);


Parameters:
exec_xml ___[In] Pointer to a null terminated Unicode string that contains the XML of the command to execute (see section 3 for the details of XML format).
callback ___[In] Optional pointer to a callback function that can be used to receive additional progress and information. This can be NULL if no callback is required. This is primarily intended for use by the command line interface to display more information. The supported callback codes are:
code:
SBADM_CALLBACK_CODE_TRACE_A
Return value:
Pointer to a null terminated Unicode string that contains the result XML. If there was an error processing the input XML, then this function will return NULL.
The function will allocate the return buffer. The caller should use the SBADM_free_string() function to free the return buffer when it is no longer required.
Zinthose is offline   Reply With Quote
Old 18th September 2010, 10:49   #9
Anders
Moderator
 
Anders's Avatar
 
Join Date: Jun 2002
Location: ${NSISDIR}
Posts: 5,153
Yeah I saw that already, but like I said, I posted some code that _should_ work, if not, try it without ?c

(Could you maybe upload this dll somewhere so I could take a look at it?)

IntOp $PostCount $PostCount + 1
Anders is offline   Reply With Quote
Old 20th September 2010, 14:56   #10
Zinthose
Senior Member
 
Join Date: May 2009
Posts: 152
Quote:
Originally Posted by Anders View Post
Yeah I saw that already, but like I said, I posted some code that _should_ work, if not, try it without ?c

(Could you maybe upload this dll somewhere so I could take a look at it?)
With and without the ?c option it fails.

Sadly, I don't think I can share the DLL as it is a part of the server installation for the client software I'm managing. I'm pretty sure McAfee's lawyers might grunt in disapproval.

I've ran the DLL through a assembler decompiler in hope I might gleam some insight. I didn't find anything gleamingly obvious but I did get these...
The Undecorated function name is: "?SBADM_execute@@YAPAGPBGP6AHKPAX@Z@Z"
The Address is: 0x0001eab0
The Ordinal is: 0x1

I have no basis except for intuition, but it feels like the issue is with the function name lookup. Can the System plugin call dll functions by the ordinal or address values?Looking at the documentation I'll give GetModuleHandle a try and see if it will work.

For the time being, I'm using the command-line utility in addition to the DLL. I seams stupid that I'm forced to add an exe wrapper to call an added dll that I would call directly if I knew how.

I'm hoping McAfee will provide me with some actual C usage examples so I can get this properly implemented.


Thank you soo much for your assistance.. this one it turning into a problem I'm going to have to solve on my own but your encouraging nudges do help

Here is an interesting quip I conjured I feel is partially relevant, "Bugs are only introduced when you implement someone else's code." It's not actually true but I thought it funny.
Zinthose is offline   Reply With Quote
Old 20th September 2010, 21:11   #11
Anders
Moderator
 
Anders's Avatar
 
Join Date: Jun 2002
Location: ${NSISDIR}
Posts: 5,153
PHP Code:
?SBADM_execute@@YAPAGPBGP6AHKPAX@Z@== unsigned short __cdecl SBADM_execute(unsigned short const *,int (__cdecl*)(unsigned long,void *)) 
...it is cdecl so you need ?c

For fun I compiled a simple dll
PHP Code:
#include <Windows.h>
__declspec(dllexportunsigned short __cdecl SBADM_execute(unsigned short const *xml,int (__cdecl*)(unsigned long,void *)) 
{
    
MessageBoxW(0,L"hello world",xml,0);
    return 
0;
}
BOOL WINAPI DllMain(HANDLE,DWORD,DWORD) {return true;} 
And I'm able to call it with
PHP Code:
outfile test.exe
section
initpluginsdir
setoutpath $pluginsdir
file tempdev
.dll
system
::call 'kernel32::LoadLibrary(t "$pluginsdir\tempdev.dll")i.r0'
system::call 'kernel32::GetProcAddress(i r0,i 1)i.r2' ;ordinal 1
System
::Call '::$2(w "xml w00t",i0)i ?c'
system::call 'kernel32::FreeLibrary(i r0)'
setoutpath $temp
sectionend 

IntOp $PostCount $PostCount + 1
Anders is offline   Reply With Quote
Old 20th September 2010, 21:57   #12
Zinthose
Senior Member
 
Join Date: May 2009
Posts: 152
OMG THANK YOU!!!

It finally works!!!

PHP Code:
outfile test.exe
section
setoutpath 
"C:\Program Files\McAfee\Endpoint Encryption for PC"
system::call 'kernel32::LoadLibrary(t "$OUTDIR\SbAdmDll.dll")i.r0'
system::call 'kernel32::GetProcAddress(i r0,i 1)i.r2' ;ordinal 1
System
::Call '::$2(w "<SafeBoot><SbAdminScripting><SbAdminCommand><Command>GetVersion</Command></SbAdminCommand></SbAdminScripting></SafeBoot>",i0)w .r3 ?c'
DetailPrint $3
system
::call 'kernel32::FreeLibrary(i r0)'
sectionend 
code:
Output folder: C:\Program Files\McAfee\Endpoint Encryption for PC
?<?xml version="1.0"?>
<SafeBoot>
<SbAdminScripting>
<SbAdminConnectionResult>
<ResultCode>0x00000000</ResultCode>
<ResultDescription>The operation completed successfully.
</ResultDescription>
</SbAdminConnectionResult>
<SbAdminCommandResult>
<Command>GetVersion</Command>
<ResultCode>0x00000000</ResultCode>
<ResultDescription>The operation completed successfully.
</ResultDescription>
<Version>5.2.3.5</Version>
</SbAdminCommandResult>
</SbAdminScripting>
</SafeBoot>

Completed



Zinthose is offline   Reply With Quote
Old 20th September 2010, 22:02   #13
Anders
Moderator
 
Anders's Avatar
 
Join Date: Jun 2002
Location: ${NSISDIR}
Posts: 5,153
You should probably call SBADM_free_string to free the returned string (If you only call it once, its probably ok just to leak that memory, but if you call it a lot you might want to free the strings) (But when doing that, the return needs to be i to preserve the pointer, then convert the returned string to a "nsis string" with the system plugin struct syntax)

IntOp $PostCount $PostCount + 1
Anders is offline   Reply With Quote
Old 21st September 2010, 15:51   #14
Zinthose
Senior Member
 
Join Date: May 2009
Posts: 152
Ok, now that we have it working I need to try and address the issue of extracting the DLL into the client system. We don't want to deploy the DLL, only use it to make the change and then ensure the DLL is removed to attempt to prevent any possible security issues.

I found the SetDLLDirectory api call and it explains exactly what I need but the final call to the SbAdmDll.dll still fails error with "MSVC++ Runtime Library RuntimeError...abnormal program termination".

PHP Code:
section
    
;!define UseSetDLLDirectory
    
!ifdef UseSetDLLDirectory
        
## Use the SetDLLDirectory API call to temporarily add the client programs path to the DLL search order.
        ##  MSDN: http://msdn.microsoft.com/en-us/library/ms686203%28VS.85%29.aspx
            
InitPluginsDir
            SetOutPath $PLUGINSDIR
            
            file 
"SbAdmDll.dll"

            
System::Call 'Kernel32::SetDllDirectory(t "C:\Program Files\McAfee\Endpoint Encryption for PC")i .r0'
            
DetailPrint "SetDllDirectory RC=$0" ;<-- Returns 1 so it is a success
    
!else
        
## Extract to actual client application path
            
SetOutPath "C:\Program Files\McAfee\Endpoint Encryption for PC"
            
file "SbAdmDll.dll"
    
!endif
    
    
System::Call 'kernel32::LoadLibrary(t "$OUTDIR\SbAdmDll.dll")i.r0'
    
System::Call 'kernel32::GetProcAddress(i r0,i 1)i.r2' ;ordinal 1
    System
::Call '::$2(w "<SafeBoot><SbAdminScripting><SbAdminCommand><Command>GetVersion</Command></SbAdminCommand></SbAdminScripting></SafeBoot>",i0)w .r3 ?c'
    
DetailPrint $3
    
    System
::Call 'kernel32::FreeLibrary(i r0)'
    
sectionend 
The call works fine when I don't define the UseSetDLLDirectory... any ideas?
Zinthose is offline   Reply With Quote
Old 21st September 2010, 16:01   #15
Anders
Moderator
 
Anders's Avatar
 
Join Date: Jun 2002
Location: ${NSISDIR}
Posts: 5,153
I don't see why you need to use SetDllDirectory.

What about:
SetOutPath $PLUGINSDIR
file "SbAdmDll.dll"
SetOutPath c:\programfiles...
System::Call 'kernel32::LoadLibrary(t "$PLUGINSDIR \SbAdmDll.dll")i.r0'
?

IntOp $PostCount $PostCount + 1
Anders is offline   Reply With Quote
Old 21st September 2010, 16:40   #16
Zinthose
Senior Member
 
Join Date: May 2009
Posts: 152
... Yeah, that is a lot simpler isn't it?

Working good now
Zinthose is offline   Reply With Quote
Old 21st September 2010, 19:35   #17
Zinthose
Senior Member
 
Join Date: May 2009
Posts: 152
I think I know the answer but I'll ask to verify.

The SBADM_free_string function needed to free the memory doesn't have a return value so I'm uncertain if it succeeded.
code:
void __cdecl SBADM_free_string(unsigned short *}
I tried reading the memory value again so see if it was cleared, gives me an error, or is different. But the value is exactly the same as it was before the call to release the memory.
PHP Code:
System::Call `*$3(&w${NSIS_MAX_STRLEN} .r4)
I have two possible conclusions....
  1. The API call to free the memory is failing.
  2. The API call succeeded but the value was left intact at the address.

#2 worries me as it implies that the DLL developers are leaving potentially private data as plain text in the memory space to be easily scanned.

I'm going to try and create a controlled memory and compare the results of the program to see if it is indeed freeing the memory.


UPDATE: I see that the FreeLibrary function is freeing the memory but I think the api call is failing as the memory increases about the same with and without the free_string api call. I'm using....
PHP Code:
System::Call 'kernel32::GetProcAddress(i r0,i 2)i.r2' ;ordinal 2
System
::Call '::$2(i $3) ?c' 

UPDATE: I fixed a typo in my code and ran the loops again... The API is indeed releasing the memory as I'm seeing almost a 1MB memory size difference when looping 1000 times with and without the free string function. It looks like the memory is indeed left intact. That sucks.. I suppose I could let McAfee know but is it really an issue or is this common practice?

Last edited by Zinthose; 21st September 2010 at 21:28.
Zinthose is offline   Reply With Quote
Old 21st September 2010, 20:52   #18
Anders
Moderator
 
Anders's Avatar
 
Join Date: Jun 2002
Location: ${NSISDIR}
Posts: 5,153
System::Call '::$2(i *$3) ?c' is wrong, no need for *, just "i" is what you need ($3 is a memory address already)

Edit: Did you edit the * out of your post or Icanhazgonecrazy?

IntOp $PostCount $PostCount + 1

Last edited by Anders; 21st September 2010 at 22:25.
Anders is offline   Reply With Quote
Reply
Go Back   Winamp & Shoutcast Forums > Developer Center > NSIS Discussion

Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump