blob: 72cbe891df2eefb069538040b4781712acf64ff5 [file] [log] [blame]
#include <windows.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include "directory.h"
#include "image.h"
#define EXECUTABLES "*.exe;*.dll;*.sys;*.pyd"
int SearchImport(char *ImportDLL, char *ImportFunction, char *SourcePath);
int SearchExport(char *ExportFunction, char *SourcePath);
int SearchImportWithImageHlp(char *InputPath, char *ImportDLL, char *ImportFunction);
int SearchExportWithImageHlp(char *InputPath, char *ExportFunction);
void Usage(char *ProgramName)
{
printf("Usage: %s test.dll c:\\dir\\test.exe\n", ProgramName);
printf("\tReport if c:\\dir\\test.exe imports test.dll\n");
printf("\nExamples:\n");
printf("%s test.dll!funcname c:\\dir\\test.exe\n", ProgramName);
printf("\tReport if c:\\dir\\test.exe imports test.dll!funcname\n");
printf("%s test.dll c:\\dir\n", ProgramName);
printf("\tFind executables importing test.dll in c:\\dir\n");
printf("%s test.dll!funcname c:\\dir\n", ProgramName);
printf("\tFind executables importing funcname from test.dll in c:\\dir\n");
printf("%s test!funcname c:\\dir\n", ProgramName);
printf("\tFind executables importing funcname from test.dll in c:\\dir\n");
printf("%s test!ord_1234 c:\\dir\n", ProgramName);
printf("\tFind executables importing ordinal 1234 (in decimal) from test.dll in c:\\dir\n");
printf("\tNOTE: this only works if there is no name associated with the function\n");
printf("%s -e funcname c:\\dir\n", ProgramName);
printf("\tFind all DLLs exporting funcname in c:\\dir\n");
}
// Try to match Target against Source
BOOL CompareFilenames(char *Target, char *Source)
{
DWORD i;
BOOL HasExtension = FALSE;
if (!Target || !Source || !Target[0] || !Source[0]) return FALSE;
if (strchr(Source, '.')) HasExtension = TRUE;
// If we don't need to consider that the source may lack an extension,
// then the lengths must be the same
if (HasExtension && strlen(Target) != strlen(Source)) return FALSE;
for (i = 0; i < strlen(Source); i++)
{
if (tolower(Target[i]) != tolower(Source[i])) return FALSE;
}
if (HasExtension)
{
if (Target[i]) return FALSE;
else return TRUE;
}
else
{
if (Target[i] == '.') return TRUE;
else return FALSE;
}
}
int main(int argc, char* argv[])
{
char *ImportFunction;
if (argc < 2)
{
Usage(argv[0]);
return -1;
}
if (argv[1][0] == '-')
{
if (tolower(argv[1][1]) != 'e')
{
fprintf(stderr, "Error: -e is the only valid option\n");
Usage(argv[0]);
return -1;
}
if (argc != 3 && argc != 4)
{
fprintf(stderr, "Error: incorrect number of parameters for export searching\n");
Usage(argv[0]);
return -1;
}
if (strchr(argv[2], '!'))
{
fprintf(stderr, "Error: you cannot pass a dll!func format with -e\n");
Usage(argv[0]);
return -1;
}
if (argc == 4) return SearchExport(argv[2], argv[3]);
else return SearchExport(argv[2], NULL);
}
else
{
if (argc != 3)
{
fprintf(stderr, "Error: incorrect number of parameters for import searching\n");
Usage(argv[0]);
return -1;
}
if ((ImportFunction = strchr(argv[1], '!')) != NULL)
{
*ImportFunction++ = '\0';
return SearchImport(argv[1], ImportFunction, argv[2]);
}
else return SearchImport(argv[1], NULL, argv[2]);
}
return 0;
}
int SearchImport(char *ImportDLL, char *ImportFunction, char *SourcePath)
{
PDIRECTORY_INFO pDirectory;
PSEARCH_RESULTS result;
if (!(pDirectory = DirectoryOpen(SourcePath, TRUE))) return -1;
if (!DirectorySearch(pDirectory, EXECUTABLES)) return -1;
for (result = pDirectory->pSearchResults; result; result = result->Next)
{
SearchImportWithImageHlp(result->FilePath, ImportDLL, ImportFunction);
}
DirectoryClose(pDirectory);
return 0;
}
int SearchImportWithImageHlp(char *InputPath, char *ImportDLL, char *ImportFunction)
{
DWORD i = 0;
BOOL ModuleFound;
char *Filename, *ModuleName;
// Used to read import table
LOADED_IMAGE Image;
IMAGE_DATA_DIRECTORY ImportDirectory;
PIMAGE_IMPORT_DESCRIPTOR pImportDescriptor;
PIMAGE_THUNK_DATA pThunk, pThunkIAT;
PIMAGE_IMPORT_BY_NAME pOrdinalName;
USHORT ImportOrdinal = 0;
BOOL UseOrdinal = FALSE;
if (!(Filename = strrchr(InputPath, '\\')))
{
fprintf(stderr, "Error: unexpected file \"%s\"\n", InputPath);
return -1;
}
*Filename++ = '\0';
//printf("Loading %s\n", Filename);
// TODO: under what circumstances does this fail?
if (!MapAndLoad(Filename, InputPath, &Image, FALSE, TRUE))
{
fprintf(stderr, "Unable to map and load %s\n", Filename);
return -1;
}
ImportDirectory = Image.FileHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
if (!ImportDirectory.VirtualAddress) return 0; // no imports
if (ImportDirectory.Size < sizeof(IMAGE_IMPORT_DESCRIPTOR))
{
fprintf(stderr, "Error loading %s: invalid import descriptor table (size < sizeof(IMAGE_IMPORT_DESCRIPTOR))\n", Filename);
if (!UnMapAndLoad(&Image)) fprintf(stderr, "Error unloading %s (error code 0x%08lx)\n", Filename, GetLastError());
return -1;
}
pImportDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)GetAddressFromRVA(Image, ImportDirectory.VirtualAddress);
if (!pImportDescriptor)
{
fprintf(stderr, "Error loading %s: invalid import descriptor table (invalid RVA)\n", Filename);
if (!UnMapAndLoad(&Image)) fprintf(stderr, "Error unloading %s (error code 0x%08lx)\n", Filename, GetLastError());
return -1;
}
for (i = 0, ModuleFound = FALSE; i < ImportDirectory.Size / sizeof(IMAGE_IMPORT_DESCRIPTOR); i++)
{
ModuleName = (char *)GetAddressFromRVA(Image, pImportDescriptor->Name);
if (!ModuleName || !ModuleName[0]) break;
if (CompareFilenames(ModuleName, ImportDLL))
{
ModuleFound = TRUE;
break;
}
pImportDescriptor++;
}
if (!ModuleFound)
{
if (!UnMapAndLoad(&Image))
{
fprintf(stderr, "Error unloading %s (error code 0x%08lx)\n", Filename, GetLastError());
return 0;
}
return -1;
}
if (!ImportFunction)
{
printf("Match found: %s\\%s imports the library %s\n", InputPath, Filename, ImportDLL);
if (!UnMapAndLoad(&Image)) fprintf(stderr, "Error unloading %s (error code 0x%08lx)\n", Filename, GetLastError());
return 1;
}
if (strncmp(ImportFunction, "ord_", 4) == 0)
{
ImportOrdinal = atoi(ImportFunction + 4);
if (!ImportOrdinal && ImportFunction[4] != '0')
{
fprintf(stderr, "Error: you passed an invalid ordinal\n");
fprintf(stderr, "Should be in the format ord_1234 where 1234 is a decimal number\n");
if (!UnMapAndLoad(&Image)) fprintf(stderr, "Error unloading %s (error code 0x%08lx)\n", Filename, GetLastError());
return -1;
}
UseOrdinal = TRUE;
}
pThunkIAT = (PIMAGE_THUNK_DATA)GetAddressFromRVA(Image, pImportDescriptor->FirstThunk);
if (!pImportDescriptor->OriginalFirstThunk) pThunk = pThunkIAT;
else pThunk = (PIMAGE_THUNK_DATA)GetAddressFromRVA(Image, pImportDescriptor->OriginalFirstThunk);
if (!pThunk || !pThunkIAT)
{
fprintf(stderr, "Error loading %s: invalid import descriptor table (neither thunk is set)\n", Filename);
if (!UnMapAndLoad(&Image)) fprintf(stderr, "Error unloading %s (error code 0x%08lx)\n", Filename, GetLastError());
return -1;
}
for (; ; pThunk++, pThunkIAT++)
{
if (!pThunk->u1.AddressOfData) break;
if (UseOrdinal && pThunk->u1.Ordinal & IMAGE_ORDINAL_FLAG)
{
if (ImportOrdinal == IMAGE_ORDINAL(pThunk->u1.Ordinal))
{
printf("Match found: %s\\%s imports ordinal %d from %s\n", InputPath, Filename, ImportOrdinal, ImportDLL);
if (!UnMapAndLoad(&Image)) fprintf(stderr, "Error unloading %s (error code 0x%08lx)\n", Filename, GetLastError());
return 1;
}
}
else
{
pOrdinalName = (PIMAGE_IMPORT_BY_NAME)GetAddressFromRVA(Image, (DWORD)pThunk->u1.AddressOfData);
if (!pOrdinalName) continue;
if (_stricmp(pOrdinalName->Name, ImportFunction) == 0)
{
printf("Match found: %s\\%s imports %s!%s\n", InputPath, Filename, ImportDLL, pOrdinalName->Name);
if (!UnMapAndLoad(&Image)) fprintf(stderr, "Error unloading %s (error code 0x%08lx)\n", Filename, GetLastError());
return 1;
}
}
}
if (!UnMapAndLoad(&Image)) fprintf(stderr, "Error unloading %s (error code 0x%08lx)\n", Filename, GetLastError());
return 0;
}
int SearchExport(char *ExportFunction, char *SourcePath)
{
PDIRECTORY_INFO pDirectory;
PSEARCH_RESULTS result;
if (!(pDirectory = DirectoryOpen(SourcePath, TRUE))) return -1;
if (!DirectorySearch(pDirectory, EXECUTABLES)) return -1;
for (result = pDirectory->pSearchResults; result; result = result->Next)
{
SearchExportWithImageHlp(result->FilePath, ExportFunction);
}
DirectoryClose(pDirectory);
return 0;
}
int SearchExportWithImageHlp(char *InputPath, char *ExportFunction)
{
char *Filename, *FunctionName;
// Used to read export table
PIMAGE_EXPORT_DIRECTORY pExportTable;
IMAGE_DATA_DIRECTORY ExportDirectory;
LOADED_IMAGE Image;
DWORD *pFunctions; // an RVA
DWORD *pNames; // an RVA
USHORT *pNameOrdinals;
USHORT i, j;
if (!(Filename = strrchr(InputPath, '\\')))
{
fprintf(stderr, "Error: unexpected file \"%s\"\n", InputPath);
return -1;
}
*Filename++ = '\0';
printf("Loading %s\n", Filename);
if (!MapAndLoad(Filename, InputPath, &Image, FALSE, TRUE))
{
fprintf(stderr, "Unable to map and load %s\n", Filename);
return -1;
}
ExportDirectory = Image.FileHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
if (!ExportDirectory.VirtualAddress) return 0; // no exports
if (ExportDirectory.Size < sizeof(IMAGE_EXPORT_DIRECTORY))
{
fprintf(stderr, "Error loading %s: invalid export table (size < sizeof(IMAGE_EXPORT_DIRECTORY))\n", Filename);
if (!UnMapAndLoad(&Image)) fprintf(stderr, "Error unloading %s (error code 0x%08lx)\n", Filename, GetLastError());
return -1;
}
pExportTable = (PIMAGE_EXPORT_DIRECTORY)GetAddressFromRVA(Image, ExportDirectory.VirtualAddress);
if (!pExportTable)
{
fprintf(stderr, "Error loading %s: invalid export table (invalid RVA)\n", Filename);
if (!UnMapAndLoad(&Image)) fprintf(stderr, "Error unloading %s (error code 0x%08lx)\n", Filename, GetLastError());
return -1;
}
pFunctions = (DWORD *)GetAddressFromRVA(Image, pExportTable->AddressOfFunctions);
pNameOrdinals = (USHORT *)GetAddressFromRVA(Image, pExportTable->AddressOfNameOrdinals);
pNames = (DWORD *)GetAddressFromRVA(Image, pExportTable->AddressOfNames);
if (!pFunctions || !pNameOrdinals || !pNames)
{
fprintf(stderr, "Error loading %s: invalid export table (invalid name/function/ordinal RVAs)\n", Filename);
if (!UnMapAndLoad(&Image)) fprintf(stderr, "Error unloading %s (error code 0x%08lx)\n", Filename, GetLastError());
return -1;
}
// Rather than just read directly from pNames, we do this to ensure that we're matching
// a function instead of a variable
for (i = 0; i < pExportTable->NumberOfFunctions; i++)
{
if (!pFunctions[i]) continue;
for (j = 0; j < pExportTable->NumberOfNames; j++)
{
if (i == pNameOrdinals[j])
{
FunctionName = (char *)GetAddressFromRVA(Image, pNames[j]);
if (_stricmp(FunctionName, ExportFunction) == 0)
{
printf("Match found: %s\\%s exports %s\n", InputPath, Filename, FunctionName);
exit(0);
if (!UnMapAndLoad(&Image))
{
fprintf(stderr, "Error unloading %s (error code 0x%08lx)\n", Filename, GetLastError());
return -1;
}
return 1;
}
}
}
}
return 0;
}