• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 512
  • Last Modified:

DLL development

Hi all,

I'm currently developing a DLL in Visual Studio.net which will act as a password filter for the LSASS.exe process. I'm trying to test it using a small program, but the program is crashing. As this is my first time writing a DLL I'm a bit confused as to how to actually invoke a function called 'PasswordFilter' from the DLL. Could anyone help me, and also explain what the difference between _cdecl and _stdcall declarations is?

Rgds
Pushpop


code:

// Test.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#define DLL "Password.dll"
#include <windows.h>

typedef VOID (*MYPROC)(LPTSTR);
int main(int argc, char * argv[])
{
      FARPROC ProcAdd;
      BOOL test = false;
      HMODULE hmod;
      if((hmod = LoadLibrary(DLL))==NULL)
      {
            printf("problem loading library");
      }
      else
            printf("the library, %s , loaded correctly",DLL);

      void(*dll_fn)() = ( (*)())GetProcAddress(hmod, "PasswordFilter");// Get the address of the function to call
      
      dll_fn();
 
      


}


0
pushpop
Asked:
pushpop
  • 6
  • 4
  • 3
1 Solution
 
AlexFMCommented:
You don't test whether GetProcAddress succeeded.
Using dumpbin utility see what functions are exported from Dll. To prevent C++ name mangling use extern "C" in Dll code.
0
 
AxterCommented:
You can easily determine the problem, by running it using the debugger, and step through the code.
When you get to the part that crashes, examine the variables.

Make sure your DLL is in a path that can be accessed by the executable.

I notice the program does a check for getting the DLL handle, but then it continues, instead of quiting.

When testing, you should copy the DLL to the same path as the executable (debug/release).
0
 
AxterCommented:
Do you have function PasswordFilter inside a *.def file of the DLL project?

What method are you using to export the  function in your dll?
0
The new generation of project management tools

With monday.com’s project management tool, you can see what everyone on your team is working in a single glance. Its intuitive dashboards are customizable, so you can create systems that work for you.

 
pushpopAuthor Commented:
Quoth the debugger:

Unhandled exception at 0x00000000 in Test.exe: 0xC0000005: Access violation reading location 0x00000000.

I presume its to do with the way I'm casting the function pointer?
0
 
pushpopAuthor Commented:
This is my .def file

LIBRARY PasswordFilterRegEx

EXPORTS
      InitializeChangeNotify
      PasswordChangeNotify
      PasswordFilter
0
 
pushpopAuthor Commented:
And this is my dll!



///////////////////////////////////////////////////////////////
//Filename:Password.cpp                                                             //
//                                                                                           //
//Authors: DevX.com, Eric Chubb (PWC,GTS,WILTON PLACE)             //
//                                                                                           //
//Last modified: 10/05/06                                                       //
//                                                                                           //
//Purpose: DLL for LSASS.exe which acts as a                         //
//password filter for AD logon                                                 //
//                                                                                           //
//Criteria for acceptable passwords include minimum 8 chars  //
//with at least one of those being a numeric character             //
///////////////////////////////////////////////////////////////

#include "stdafx.h"                                    //requisite header files
#include <stdio.h>
#include <windows.h>
#include <ntsecapi.h>
#include <comdef.h>
#include <string>
#include <time.h>
#include <wchar.h>

#define LOGFILE "c:\\FilterLog.txt"    // log destination
using namespace std;


// Default DllMain implementation
BOOL APIENTRY DllMain( HANDLE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                               )
{
      switch (ul_reason_for_call)  //optional startup checks
      {
            case DLL_PROCESS_ATTACH:
            
            case DLL_THREAD_ATTACH:
            
            case DLL_THREAD_DETACH:
            
            case DLL_PROCESS_DETACH:
            
            break;
      }
    return TRUE;
}

// This is a helper function to write log lines to file
// only applies if LSASS.exe defines _WRITE_LOGS


void WriteToLog(const char* str)
{
      #ifdef _WRITE_LOGS
      if (NULL == str)
      {
            return;
      }
      FILE* log;
      log = fopen(LOGFILE, "w");
      if (NULL == log)
      {
            return;
      }
      fprintf(log, "%s\r\n", str);
      fclose(log);
#endif

      return;
}

/////////////////////////////////////////////
// Exported function                                 //
// -----------------                                 //
// Initialization of Password filter.         //
// This implementation just returns TRUE   //
// to let LSA know everything is fine         //
/////////////////////////////////////////////

BOOLEAN __stdcall InitializeChangeNotify(void)
{
      WriteToLog("InitializeChangeNotify()");
      return TRUE;
}

/////////////////////////////////////////////////
// Exported function                                       //
// -----------------                                       //
// This function is called by LSA when password//
// was successfully changed.                           //
//                                                                     //
// This implementation just returns 0 (Success)//
/////////////////////////////////////////////////

NTSTATUS __stdcall PasswordChangeNotify(
  PUNICODE_STRING UserName,
  ULONG RelativeId,
  PUNICODE_STRING NewPassword
)
{
      WriteToLog("PasswordChangeNotify()");
      return 0;
}
////////////////////////////////////////////
// Exported function                                //
// -----------------                                //
// this function actually validates       //
// a new password.                        //
//                                        //
// Returns True if accepted               //
////////////////////////////////////////////

 // apparently this function type *HAS* to have this signature or else
 // LSASS will be unable to call the function........
 
                                       
BOOLEAN _stdcall PasswordFilter(    //these are the variables which will be passed in
  PUNICODE_STRING AccountName,             //by LSASS.exe on runtime      
  PUNICODE_STRING FullName,                   //your guess is as good as mine on what
  PUNICODE_STRING Password,          //exactly a PUNICODE_STRING is
  BOOLEAN SetOperation
)
{
      WriteToLog("Entering PasswordFilter()");
      int count = 0;
      wstring wstrPassword;      
      wchar_t* wszPassword = NULL;
      bool bMatch = FALSE;                  //if both testOne and testTwo are true, bMatch is too
      bool testOne = FALSE;                  //both of these test conditions must
      bool testTwo = FALSE;                  //be satisfied for the password to be
      try                                                //accepted
      {
            
            wszPassword = new wchar_t[Password->Length + 1];
            if (NULL == wszPassword)
            {
                  throw E_OUTOFMEMORY;
            }
            wcsncpy(wszPassword, Password->Buffer, Password->Length);
            wszPassword[Password->Length] = 0;

            WriteToLog("Going to check password");
            wstrPassword = wszPassword;

            // Validate password against GUID criteria
            
            if (wcslen(wszPassword) < 8) // if password shorter than 8 chars
            {
                  testOne = false;
            }
            else
                  testOne = true;
            
            while(count < wcslen(wszPassword))
            {
                  if(iswdigit(wszPassword[count]))  //if there is at least one digit*/
                  {
                        testTwo = true;
                                             /// our criteria have been satisfied */
                  }
                  count++;
            }

            if(testOne == true && testTwo ==true)
            {
                  bMatch = true;
            }
            else
                  bMatch = false;

            if (bMatch)      //we're in business
            {
                  WriteToLog("Password satisfies criteria");
                  MessageBox(NULL,"Congratulations, your password is accepted!","Password Accepted",NULL);
            }
            else            // try again
            {
                  MessageBox(NULL,"Sorry, but you're password is not acceptable","Password Error",NULL);
                  WriteToLog("Password does NOT match specified GUID criteria");
            }
            throw S_OK;
      }
      catch(HRESULT)
      {
      }
      catch(...)
      {
            WriteToLog("catch(...)");
      }
      // Erase all temporary password data
      // for security reasons
      wstrPassword.replace(0, wstrPassword.length(), wstrPassword.length(), (wchar_t)'?');
      wstrPassword.erase();
      
      
      if (NULL != wszPassword)
      {
            ZeroMemory(wszPassword, Password->Length);

            // Assure that there is no compiler optimizations and read random byte
            // from cleaned password string
            srand(time(NULL));
            wchar_t wch = wszPassword[rand() % Password->Length];
            delete [] wszPassword;
            wszPassword = NULL;
      }
      return bMatch;
}

//EOF
0
 
AlexFMCommented:
dll_fn();

Why do you call PasswordFilter without parameters?
0
 
AlexFMCommented:
You must also provide exact function prototype:

void(*dll_fn)()

and function has type:

BOOLEAN _stdcall PasswordFilter(    //these are the variables which will be passed in
  PUNICODE_STRING AccountName,           //by LSASS.exe on runtime    
  PUNICODE_STRING FullName,                //your guess is as good as mine on what
  PUNICODE_STRING Password,          //exactly a PUNICODE_STRING is
  BOOLEAN SetOperation)
0
 
AxterCommented:
To add to above comment, you should use a typedef to declare your function pointer.
typedef BOOLEAN (*PasswordFilter_TYPE)(PUNICODE_STRING AccountName,           //by LSASS.exe on runtime    
  PUNICODE_STRING FullName,                //your guess is as good as mine on what
  PUNICODE_STRING Password,          //exactly a PUNICODE_STRING is
  BOOLEAN SetOperation);

Then

PasswordFilter_TYPE dll_fn = ( PasswordFilter_TYPE)GetProcAddress(hmod, "PasswordFilter");
0
 
pushpopAuthor Commented:
Ok, that typedef presumably goes outside the body of main?
0
 
pushpopAuthor Commented:
Sorry, scrub that last question. The article I consulted states that LSASS.exe can only use the function prototypes if they are as is. So either the article is wrong or I can't debug the DLL :-<
0
 
AxterCommented:
>>Ok, that typedef presumably goes outside the body of main?

It can be inside or outside main.

>>The article I consulted states that LSASS.exe can only use the function prototypes if they are as is

So are you using the right prototype?
0
 
pushpopAuthor Commented:
Yeah im literally copied and pasted it from the article so I hope so :-D

My question that time was meant to be, what file do you put the typedef in, in the DLL code or in the test program?
0

Featured Post

2018 Annual Membership Survey

Here at Experts Exchange, we strive to give members the best experience. Help us improve the site by taking this survey today! (Bonus: Be entered to win a great tech prize for participating!)

  • 6
  • 4
  • 3
Tackle projects and never again get stuck behind a technical roadblock.
Join Now