Tuesday, October 20, 2009

Dependency Checker

This is a simple light weight utility to find which all dll/exe/ocx in a folder uses a particular dll.
Download
Source File(DependsChecker_Src.zip)
Execuatble(DependsChecker_bin.zip)

My development environment usually includes large number of binaries. And I was working in some core library module which is used by many other dlls. So whenever I change something in the header file of this code library, I have to rebuild all the dependent libraries. Rebuilding the entire environment was not practical all times. So I had to create such an utility so that I can find out who all uses this code library and can rebuild those modules only.

How to Use

  1. In the “Dll Name” edit box, enter the name of the dll for which we have to search for.
  2. In the “Path” edit box, enter the folder in which we have to search for dlls/exe/ocx that uses dll entered in the “Dll Name” edit box.
  3. Click “Start” button.

Upon clicking the Start button, the list control starts’ populating the Dll, OCX and EXE’s that uses the specified dll. Please note that this application will not list dynamic dependencies and so we cannot enter ocx or COM dll as “Dll Name”.

How it works

When the start button is clicked, the application loop through each Dll, OCX and EXE’s in the specified folder. It opens each binary, parse the PE (Portable Executable) file format.
For example consider that user32.dll is specified in the "Dll name" edit box and the path is "c:\windows\system32". When user clicks on the “start” button, the application took a loop to find EXEs, dll's and OCXs in the specified folder. Intitally it enumarets all the EXEs. Suppose we got "calc.exe" as file name. The next thing to do is to map the binary file to memory. This is performed with the help of CreateFileMapping() and MapViewOfFile() function.


CFile fl;
if( !fl.Open( csExeName, CFile::modeReadCFile::shareDenyNone, 0 ))
{
CString csMsg;
csMsg.Format( _T(" Failed to open file %s"), csExeName );
AfxMessageBox( csMsg );
continue;
}
HANDLE hSM = CreateFileMapping( (HANDLE)fl.m_hFile, 0,PAGE_READONLY,0,0, _T("some_sM"));
LPVOID pBinary = MapViewOfFile( hSM,FILE_MAP_READ,0,0, fl.GetLength());
if( CheckForDependecy( csDllName, pBinary ))
{
m_List.InsertItem( 0, fl.GetFileName() );
}
UnmapViewOfFile( pBinary );
CloseHandle( hSM );
fl.Close();

As you can see in the above code, after the binary is loaded to the memory, the memory address is passed to the CheckForDependecy() function. The function cast the memory address to a IMAGE_DOS_HEADER pointer.
PIMAGE_DOS_HEADER pDOSHeader = (PIMAGE_DOS_HEADER) lpStartAddress;
After this, it will try to get the IMAGE_NT_HEADERS from pDOSHeader. Usually the 16 bit binaries will not be having this header. So we will ignore such binaries at this point.


// Get the PE header.
PIMAGE_NT_HEADERS pNTHeader = MakePtr(PIMAGE_NT_HEADERS, pDOSHeader, pDOSHeader->e_lfanew);
if( IsBadReadPtr( pNTHeader, sizeof( IMAGE_NT_HEADERS)))
{
return false;
};

May be because of the property of data in the file, it may occur that the pNTHeader points to a valid memory. So we will add one more checking to confirm that we are dealing with PE file (The famous DRWATSON.EXE fails at this checking!!!ya it is not a PE file).


char* pSig = (char*)&pNTHeader->Signature;
if( pSig[0] != 'P' pSig[1] != 'E')
{
return false;
}

The next task is to find the IMAGE_IMPORT_DESCRIPTOR. The IMAGE_NT_HEADERS.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]. VirtualAddress holds the relative address of IMAGE_IMPORT_DESCRIPTOR from the starting of the memory. We can use the ImageRvaToVa() API to convert the relative adress to virtual address. There's one IMAGE_IMPORT_DESCRIPTOR for each imported executable. So we will loop through each item and check whether it is for importing the specified dll (“user32.dll” in our case )



PIMAGE_IMPORT_DESCRIPTOR pImportDesc = (PIMAGE_IMPORT_DESCRIPTOR) ImageRvaToVa( pNTHeader, lpStartAddress, pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].
VirtualAddress, 0 );
while( pImportDesc && pImportDesc->Name )
{
// pImportDesc->Name holds the name of the import library
PVOID pName = ImageRvaToVa( pNTHeader, lpStartAddress, pImportDesc->Name , 0 );
PSTR szCurrMod = (PSTR)pName;
if( IsBadReadPtr( szCurrMod, 1 ))
{
continue;
}
CString cs = szCurrMod;
if( 0 == cs.CollateNoCase( csDllName ))
{
// everything pass. We have found one dependency
return true;
}
// Move to the next import library
pImportDesc++;
}

And for the records, let me say that, there are 1111 files in my system32 folder that has dependency with the user32.dll( Vista SP1 ).

Saturday, April 18, 2009

Centralizing modeless child dialog

Normally when we call the DoModal() function of a dialog, the dialog will created and displayed at the center of the parent dialog.



But when a modless dialog is displayed, the child dialog will be displayed at the top left portion of the parent dialog.



I noticed this when a codeproject user asked how to centralize a modeless child dialog. Initially I thought that MFC might be doing some thing in the DoModal() function. So I stepped into the DoModal() function. But I couldn't find any difference in the dialog creation in CDialog::DoModal and CDialog::Create().
Another difference that I know between a modal and modeless dialog is that, in the case of the modal dialog, the parent window will be disabled. MFC does this inside the DoModal() function. To try my luck I disabled the parent window before calling the Create function of dialog. Surprisingly it worked! The modeless child dialog came at the center of parent dialog.

So if you want to centralize a modeless dialog, just disable the parent dialog before create and re-enable it after the creation.
void CDialogBased2Dlg::OnBnClickedButton1()
{
EnableWindow( FALSE );
m_ChildDlg.Create( ChildDialog::IDD, this );
EnableWindow( TRUE );
m_ChildDlg.ShowWindow( SW_SHOW );
}

Saturday, December 20, 2008

Function to get the local system Administrator Name

A codeproject poster asked this question. He was already aware of the NetLocalGroupGetMembers function with which, was can the list of users in any groups in the system. How were he wasn't quite sure how to use it and there wasn't any sample code in the internet. So I wrote a sample and posted in codeproject and here is the copy of it.
LPLOCALGROUP_MEMBERS_INFO_1  pstMembersInfo = 0;
DWORD entriesread = 0;
DWORD totalentries = 0;
if( 0 != NetLocalGroupGetMembers( NULL, _T("Administrators"), 1, (LPBYTE*)
&pstMembersInfo,MAX_PREFERRED_LENGTH,
&entriesread, &totalentries, 0 ))
{
AfxMessageBox( _T("NetLocalGroupGetMembers failed !"));
return ;
}
for( DWORD dwIdx =0; dwIdx < entriesread; dwIdx ++ )
{
AfxMessageBox( pstMembersInfo[dwIdx].lgrmi1_name );
}
NetApiBufferFree( pstMembersInfo );

Monday, October 27, 2008

How to find whether the parent process is GUI or Console

This is not 100% fool proof. How ever in normal cases, this works great. This technique can be used to find out, whether the child application was launched from a GUI application or from a Console application.

if( AttachConsole( ATTACH_PARENT_PROCESS ))
{
AfxMessageBox( _T("Parent process is a console application"));
}
else
{
AfxMessageBox( _T("Parent process is not a console application"));
}

Tuesday, August 26, 2008

new with empty bracket

Have you ever wrote a statement like..

int *pnValue = new int[];

One of my friend asked me what will happen if the above statement is executed. Executed ??? I though the code won't even compile. Surprisingly it compile and even returned a pointer. Wow that was some thing unbelievable.

OK now the question is, what will be size of memory that pnValue points?

The two API's in windows that allocates and de allocates the memeory are HeapAlloc and HeepFree. The CRT functions malloc and free are actually wrappers the above API. The new, new[], delete, delete[] are again another wrapper around the malloc and free. So when ever you allocates some memory using new or new[], it will finally reach the HeapAlloc function. This function is defined as

LPVOID WINAPI HeapAlloc(
__in HANDLE hHeap,
__in DWORD dwFlags,
__in SIZE_T dwBytes
);


From the above definition, you can see that the third parameter to this function is the number of BYTES to be allocated . So to find out what "new int[]" returns, we can put a break point in the entry point of HeapAlloc and check the value of dwBytes( in dis assembly ).

when I tried, the dwBytes turned out be 1 !!! This one byte cannot even hold one int variable. That means any further operation using such a pointer will possibly crash.

Another interesting thing is "int *pnValue = new int[0];" also returns a pointer pointing a memory of 1 byte long.

Wednesday, August 20, 2008

How to open Popup Blocker Settings window of IE programmatically

How to open Popup Blocker Settings window of IE programmatically??

Well it is with the help of "DisplayPopupWindowManagementDialog" function in the "C:\WINDOWS\system32\inetcpl.cpl".

But here rather just showing a misterious function, I would like to explain the methods by which I found out the name of function.

This question was asked by some one in the codeproject and at that time I was also unaware of any function for this. How ever I felt it interesting so just decided to have a try.

At first I took this "Popup Blocker Settings " dialog in the IE. My first intention was to find out the dll name which created the dialog. There is an application called WinID[^] with which we can find which dll created a perticular windows. In one of my previous post, I have explained How to find which dll / exe created a window.[^] using code. Below is a screenshot of what WinID showed me for the "Popup Blocker Settings" dialog .



It told me that "USER32.dll" has created the dialog. Liar... I was much sure that user32.dll isn't the real dll behind it. So this technique to find the dll didn't really work. So I had to find another way...

Every window has a thread associated with it. If you have the window handle, you can easily retirive the thread Id associated with it using the GetWindowThreadProcessId function. Any way I am not going to code for this. Tools like spy++, WinID displays the thread id of the window if we select a window using it. So the Thread ID displayed in Spy++ was 0xB94( 2964 in decimal ).

If we took the properties of a process in the process explorer, it will list all the threads in the process and each thread's call stack. So the thing next to do is to select the iexplorer process, select the thread with ID 2964 and took its call stack.



And in the call stack, there was only one un familiar dll and function the "inetcpl.cpl" and the DisplayPopupWindowManagementDialog function in it. So I found out the "inetcpl.cpl" file in the system32 folder and when double clicked on it, huiii it shows the "internet options" dialog.

The control panel files (.cpl ), are just a dll with a some special export functions( If you want to know more about control panel files I suggest you to read Paul DiLascia's Q&A[^] article ). With the dependency walker, I confirmed the presence of DisplayPopupWindowManagementDialog in it. But to call this function, I need to the find how it is declared, what all are the arguments etc. Fortunately some else has already document the function proto and with a google search, I was able to find it out. Happy ending!!!!

And ho ya here is the sample code..

typedef BOOL (WINAPI *DisplayPopupWindowP)( HANDLE hWnd, LPCTSTR lpCaption );
void CDialogBasedDlg::OnBnClickedButton1()
{
HMODULE hModule = LoadLibrary( _T("inetcpl.cpl") );
DisplayPopupWindowP DisplayPopupWindowManagementDialog =
( DisplayPopupWindowP)GetProcAddress(hModule,
"DisplayPopupWindowManagementDialog" );
if( !DisplayPopupWindowManagementDialog )
{
return;//error
}
DisplayPopupWindowManagementDialog( m_hWnd,
_T("www.Sitetounblock.com"));
}

Sunday, August 17, 2008

GetFinalPathNameByHandle API Hungs

GetFinalPathNameByHandle is an new API introduced in windows vista. As you can read from MSDN, the purpose of this API is to return the file name corresponding to a file handle .

Some months back, I have written a small utility OpenedFileFinder which list all the file that are opened under a certain folder. While writing this application,the main problem I came across was to get the file name from the handle. Initially I used a function called NtQueryObject(). But the problem with this API is that if we try to query the details for certain object such as pipes, directory handles etc, it will hangs. So in my application finally I have to introduce a driver to get round of this hanging problem. When I found the new GetFinalPathNameByHandle(), I was so happy and I thought at least I can avoid the driver in the vista. So I had a try on this API. But I came to find that this API also have the same hanging problem which I described earlier.

It seems the GetFinalPathNameByHandle is also using the same NtQueryObject() to get the file name and so it hangs. Any how, I have reported this bug to the microsoft connect. Let us see how they solve the problem.

Another API, that worth mentioning here is GetFileInformationByHandleEx(), which is also a new API introduced in Vista. Using this API also, I can get the file name from a handle. So I decided to check whether the same problem exists in this API also. Surprisingly it worked fine. And in MSDN also it is mentioned that it uses a driver for attaining the task. So I highly suggest every one to use GetFileInformationByHandleEx() API instead of GetFinalPathNameByHandle().