/*
DLLVers v0.01 (c) 2005 Kostya Kortchinsky <kostya[dot]kortchinsky[at]gmail[dot]com>

Lists all the DLL and EXE in %WINDIR%\system32 and prints their version number
and ImageBase. Quite useful to fastly track down unchanged binaries through
service packs and localizations.
*/
 
#define _WIN32_WINNT 0x0501

#include <windows.h>
#include <string.h>
#include <stdio.h>
#include <dbghelp.h>

#pragma comment(lib, "version")
#pragma comment(lib, "dbghelp")

DWORD GetBaseAddress(char *FileName)
{
  HMODULE hModule;
  HANDLE hFile, hFileMapping;
  PIMAGE_NT_HEADERS pNtHeader;
  DWORD dwBaseAddress;

  if(!(hFile = CreateFileA(FileName, GENERIC_READ, 1,
    NULL, OPEN_EXISTING, 0, (HANDLE)NULL)))
  {
      return (-1);
  }
  if(!(hFileMapping = CreateFileMappingA(hFile, NULL, PAGE_READONLY | SEC_COMMIT, 0, 0, NULL)))
  {
    CloseHandle(hFile);
    return (-1);
  }
  CloseHandle(hFile);
  if(!(hModule = (HMODULE)MapViewOfFile(hFileMapping, FILE_MAP_READ, 0, 0, 0)))
  {
    CloseHandle(hFileMapping);
    return (-1);
  }
  CloseHandle(hFileMapping);
  pNtHeader = ImageNtHeader((PVOID)hModule);
#ifdef DEBUG
  printf("%d\n", pNtHeader->FileHeader.SizeOfOptionalHeader);
#endif
  dwBaseAddress = pNtHeader->OptionalHeader.ImageBase;
  UnmapViewOfFile((PVOID)hModule);

  return dwBaseAddress;
}

void PrintVersion(char *FileName)
{
  DWORD dwLen, dwHandle, dwBaseAddress;
  LPTSTR lpData, lpBuffer;
	UINT BufLen;
	VS_FIXEDFILEINFO *pFileInfo;
	char *p = FileName + strlen(FileName);

  while (*p != '\\' && p >= FileName)
    p--;
  p++;
  p = _strlwr(p);
  if (strstr(FileName, ".dll") == NULL && strstr(FileName, ".exe") == NULL)
    return;
  if ((dwLen = GetFileVersionInfoSize(FileName, &dwHandle)) == 0)
  {
#ifdef DEBUG
    printf("%s (null) ", p);
#endif
    return;
  }
	if ((lpData = (LPTSTR)malloc(dwLen)) == NULL)
	{
    printf("malloc() error\n");
    exit(-1);
  }
	if (GetFileVersionInfo(FileName, dwHandle, dwLen, lpData) == FALSE)
  {
		free(lpData);
#ifdef DEBUG
    printf("%s (null) ", p);
#endif
		return;
	}
	if (VerQueryValue(lpData, "\\", (LPVOID)&pFileInfo, (PUINT)&BufLen) == FALSE)
	{
#ifdef DEBUG
		printf ("%s (null) ", p);
#endif
	}
  else
  {
#ifdef DEBUG
  printf("%d.%d.%d.%d\n", HIWORD(pFileInfo->dwFileVersionMS), LOWORD(pFileInfo->dwFileVersionMS), HIWORD(pFileInfo->dwFileVersionLS), LOWORD(pFileInfo->dwFileVersionLS));
#endif
    if (HIWORD(pFileInfo->dwFileVersionMS) > 4 && (dwBaseAddress = GetBaseAddress(FileName)) != -1)
		  printf("%s %d.%d.%d.%d %08x\n", p, HIWORD(pFileInfo->dwFileVersionMS), LOWORD(pFileInfo->dwFileVersionMS), HIWORD(pFileInfo->dwFileVersionLS), LOWORD(pFileInfo->dwFileVersionLS), dwBaseAddress);
	}
  free(lpData);
}

int main(int argc, char *argv[])
{
  WIN32_FIND_DATA FindFileData;
  HANDLE hFind = INVALID_HANDLE_VALUE;
  DWORD dwError;
  char Path[MAX_PATH + 1], SearchPath[MAX_PATH + 1], FileName[MAX_PATH + 1];
  
  ExpandEnvironmentStrings("%WINDIR%", Path, sizeof(Path));
  strcat(Path, "\\system32\\");
  strcpy(SearchPath, Path);
  strcat(SearchPath, "*");
  hFind = FindFirstFile(SearchPath, &FindFileData);
  
  if (hFind == INVALID_HANDLE_VALUE) 
  {
    printf("Invalid file handle. Error is %u\n", GetLastError());
    return (-1);
  } 
  else 
  {
    strcpy(FileName, Path);
    strcat(FileName, FindFileData.cFileName);
    PrintVersion(FileName);
#ifdef DEBUG
    printf("First file name is %s\n", FindFileData.cFileName);
#endif
    while (FindNextFile(hFind, &FindFileData) != 0) 
    {
#ifdef DEBUG
      printf ("Next file name is %s\n", FindFileData.cFileName);
#endif
      strcpy(FileName, Path);
      strcat(FileName, FindFileData.cFileName);
      PrintVersion(FileName);
    }
    dwError = GetLastError();
    FindClose(hFind);
    if (dwError != ERROR_NO_MORE_FILES) 
    {
#ifdef DEBUG
       printf("FindNextFile error. Error is %u\n", dwError);
#endif
       return (-1);
    }
  }
  return (0);
}
