зеркало из https://github.com/github/msysgit.git
MinGWify 'depends'
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
This commit is contained in:
Родитель
f768fdfad9
Коммит
df724b0324
|
@ -0,0 +1 @@
|
|||
*.o
|
|
@ -0,0 +1,10 @@
|
|||
TARGET=depends.exe
|
||||
OBJS=directory.o image.o depends.o
|
||||
|
||||
CFLAGS=-g
|
||||
LIBS=-limagehlp
|
||||
|
||||
all: $(TARGET)
|
||||
|
||||
$(TARGET): $(OBJS)
|
||||
$(CC) -o $@ $^ $(LIBS)
|
|
@ -1,36 +1,36 @@
|
|||
w00w00 improved version of depends.exe (minus the GUI + automated searching)
|
||||
Matt Conover (shok@dataforce.net)
|
||||
April 2003
|
||||
|
||||
This will find *.exe, *.dll, *.sys, and *.pyd (Python DLLs) that imports a certain DLL or function in a DLL (e.g., import wsock32.dll or import msvcrt.dll!_snprintf) or export a certain function. It can be useful when you don't know what libraries export a certain function (like RtlInitUnicodeString) or you want to find all applications using a function in a DLL with a known vulnerability.
|
||||
|
||||
Usage: w00depends test.dll c:\dir\test.exe
|
||||
Report if c:\dir\test.exe imports test.dll
|
||||
|
||||
Examples:
|
||||
w00depends test.dll!funcname c:\dir\test.exe
|
||||
Report if c:\dir\test.exe imports test.dll!funcname
|
||||
w00depends test.dll c:\dir
|
||||
Find executables importing test.dll in c:\dir
|
||||
w00depends test.dll!funcname c:\dir
|
||||
Find executables importing funcname from test.dll in c:\dir
|
||||
w00depends test!funcname c:\dir
|
||||
Find executables importing funcname from test.dll in c:\dir
|
||||
w00depends test!ord_1234 c:\dir
|
||||
Find executables importing ordinal 1234 (in decimal) from test.dll in c:\dir
|
||||
w00depends -e funcname c:\dir
|
||||
Find all DLLs exporting funcname in c:\dir
|
||||
|
||||
Output will look like this:
|
||||
C:\> w00depends kernel32!CreateFileA c:\winnt\system32
|
||||
Match found: c:\winnt\system32\ACrd10SM.dll imports kernel32!createfilea
|
||||
Match found: c:\winnt\system32\actmovie.exe imports kernel32!createfilea
|
||||
Match found: c:\winnt\system32\ACUMon.exe imports kernel32!createfilea
|
||||
Match found: c:\winnt\system32\ADVAPI32.DLL imports kernel32!createfilea
|
||||
Match found: c:\winnt\system32\advpack.dll imports kernel32!createfilea
|
||||
Match found: c:\winnt\system32\atmadm.exe imports kernel32!createfilea
|
||||
Match found: c:\winnt\system32\AUTMGR32.EXE imports kernel32!createfilea
|
||||
Match found: c:\winnt\system32\Axntbc32.dll imports kernel32!createfilea
|
||||
Match found: c:\winnt\system32\Axntcp32.dll imports kernel32!createfilea
|
||||
Match found: c:\winnt\system32\cabinet.dll imports kernel32!createfilea
|
||||
Match found: c:\winnt\system32\catsrvut.dll imports kernel32!createfilea
|
||||
w00w00 improved version of depends.exe (minus the GUI + automated searching)
|
||||
Matt Conover (shok@dataforce.net)
|
||||
April 2003
|
||||
|
||||
This will find *.exe, *.dll, *.sys, and *.pyd (Python DLLs) that imports a certain DLL or function in a DLL (e.g., import wsock32.dll or import msvcrt.dll!_snprintf) or export a certain function. It can be useful when you don't know what libraries export a certain function (like RtlInitUnicodeString) or you want to find all applications using a function in a DLL with a known vulnerability.
|
||||
|
||||
Usage: w00depends test.dll c:\dir\test.exe
|
||||
Report if c:\dir\test.exe imports test.dll
|
||||
|
||||
Examples:
|
||||
w00depends test.dll!funcname c:\dir\test.exe
|
||||
Report if c:\dir\test.exe imports test.dll!funcname
|
||||
w00depends test.dll c:\dir
|
||||
Find executables importing test.dll in c:\dir
|
||||
w00depends test.dll!funcname c:\dir
|
||||
Find executables importing funcname from test.dll in c:\dir
|
||||
w00depends test!funcname c:\dir
|
||||
Find executables importing funcname from test.dll in c:\dir
|
||||
w00depends test!ord_1234 c:\dir
|
||||
Find executables importing ordinal 1234 (in decimal) from test.dll in c:\dir
|
||||
w00depends -e funcname c:\dir
|
||||
Find all DLLs exporting funcname in c:\dir
|
||||
|
||||
Output will look like this:
|
||||
C:\> w00depends kernel32!CreateFileA c:\winnt\system32
|
||||
Match found: c:\winnt\system32\ACrd10SM.dll imports kernel32!createfilea
|
||||
Match found: c:\winnt\system32\actmovie.exe imports kernel32!createfilea
|
||||
Match found: c:\winnt\system32\ACUMon.exe imports kernel32!createfilea
|
||||
Match found: c:\winnt\system32\ADVAPI32.DLL imports kernel32!createfilea
|
||||
Match found: c:\winnt\system32\advpack.dll imports kernel32!createfilea
|
||||
Match found: c:\winnt\system32\atmadm.exe imports kernel32!createfilea
|
||||
Match found: c:\winnt\system32\AUTMGR32.EXE imports kernel32!createfilea
|
||||
Match found: c:\winnt\system32\Axntbc32.dll imports kernel32!createfilea
|
||||
Match found: c:\winnt\system32\Axntcp32.dll imports kernel32!createfilea
|
||||
Match found: c:\winnt\system32\cabinet.dll imports kernel32!createfilea
|
||||
Match found: c:\winnt\system32\catsrvut.dll imports kernel32!createfilea
|
||||
|
|
|
@ -1,371 +1,371 @@
|
|||
#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;
|
||||
}
|
||||
#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;
|
||||
}
|
|
@ -1,432 +1,432 @@
|
|||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include "directory.h"
|
||||
|
||||
#define MAX_WILDCARDS 10
|
||||
|
||||
// Internal functions only
|
||||
BOOL AddFileToSearchResult(PDIRECTORY_INFO pDirectory, char *BasePathName, char *Filename);
|
||||
BOOL MergeSearchResults(PDIRECTORY_INFO pBaseDir, PDIRECTORY_INFO pSubDir);
|
||||
BOOL MergeSearchResultsAndClose(PDIRECTORY_INFO pBaseDir, PDIRECTORY_INFO pSubDir);
|
||||
PSEARCH_RESULTS GetLastSearchResult(PSEARCH_RESULTS pSearchResult);
|
||||
DWORD GetSearchResultCount(PSEARCH_RESULTS pSearchResult);
|
||||
void DumpSearchResults(PSEARCH_RESULTS pSearchResults);
|
||||
|
||||
BOOL IsSameExtension(char *Extension1, char *Extension2)
|
||||
{
|
||||
if (_stricmp(Extension1, Extension2) == 0) return TRUE;
|
||||
else return FALSE;
|
||||
}
|
||||
|
||||
void PrintWildcardError()
|
||||
{
|
||||
fprintf(stderr, "Error: invalid wildcards for filename\n"
|
||||
"Wildcards can be:\n"
|
||||
"\tfilename match \"filename\"\n"
|
||||
"\tfilename.ext match \"filename.ext\"\n"
|
||||
"\t* match all files (with or without extensions)\n"
|
||||
"\t*.* match all files with extensions\n"
|
||||
"\t*. match all files without extensions\n"
|
||||
"\t*.ext match all files ending in \".ext\"\n"
|
||||
"\t*.ext1;*.ext2 match all files ending in \".ext1\" or \".ext2\"\n");
|
||||
}
|
||||
|
||||
PDIRECTORY_INFO DirectoryOpen(char *Directory, BOOL RecurseSubDirs)
|
||||
{
|
||||
PDIRECTORY_INFO pDirectory;
|
||||
char tmpdir[MAX_PATH+1];
|
||||
|
||||
if (!Directory) return NULL;
|
||||
//printf("Opening directory %s (RecurseSubDirs = %d)\n", Directory, RecurseSubDirs);
|
||||
|
||||
pDirectory = (PDIRECTORY_INFO)malloc(sizeof(DIRECTORY_INFO));
|
||||
if (!pDirectory)
|
||||
{
|
||||
fprintf(stderr, "Unable to allocate %d bytes\n", sizeof(DIRECTORY_INFO));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
_snprintf(tmpdir, sizeof(tmpdir), "%s\\*", Directory);
|
||||
pDirectory->hFileList = FindFirstFile(tmpdir, &pDirectory->BasePath);
|
||||
if (pDirectory->hFileList == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
fprintf(stderr, "Invalid path \"%s\"\n", Directory);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pDirectory->Initialized = TRUE;
|
||||
pDirectory->Finished = FALSE;
|
||||
pDirectory->RecurseSubDirs = RecurseSubDirs;
|
||||
pDirectory->pSearchResults = NULL;
|
||||
|
||||
_snprintf(pDirectory->BasePathName, sizeof(pDirectory->BasePathName), "%s", Directory);
|
||||
return pDirectory;
|
||||
}
|
||||
|
||||
void DirectoryClose(PDIRECTORY_INFO pDirectory)
|
||||
{
|
||||
PSEARCH_RESULTS pLast;
|
||||
|
||||
if (!pDirectory || !pDirectory->Initialized) return;
|
||||
//printf("Closing %s\n", pDirectory->BasePathName);
|
||||
|
||||
// Free the search results, if any
|
||||
if (pDirectory->pSearchResults)
|
||||
{
|
||||
assert(pDirectory->pSearchResults->Previous == NULL);
|
||||
|
||||
pLast = GetLastSearchResult(pDirectory->pSearchResults);
|
||||
assert(pLast);
|
||||
while (pLast->Previous)
|
||||
{
|
||||
assert(pLast->FilePath);
|
||||
if (pLast->FilePath)
|
||||
{
|
||||
//printf("Deallocating entry for %s\n", pLast->FilePath);
|
||||
free(pLast->FilePath);
|
||||
pLast->FilePath = NULL;
|
||||
}
|
||||
pLast = pLast->Previous;
|
||||
free(pLast->Next);
|
||||
pLast->Next = NULL;
|
||||
}
|
||||
|
||||
assert(pDirectory->pSearchResults == pLast);
|
||||
assert(pDirectory->pSearchResults->FilePath);
|
||||
|
||||
if (pDirectory->pSearchResults->FilePath)
|
||||
{
|
||||
//printf("Deallocating entry for %s\n", pDirectory->pSearchResults->FilePath);
|
||||
free(pDirectory->pSearchResults->FilePath);
|
||||
pDirectory->pSearchResults->FilePath = NULL;
|
||||
}
|
||||
|
||||
pDirectory->pSearchResults->Next = NULL;
|
||||
free(pDirectory->pSearchResults);
|
||||
pDirectory->pSearchResults = NULL;
|
||||
}
|
||||
|
||||
FindClose(pDirectory->hFileList);
|
||||
pDirectory->Initialized = FALSE;
|
||||
free(pDirectory);
|
||||
}
|
||||
|
||||
// This will match all files in a directory (or subdirectories if recursion is enabled)
|
||||
// Currently, this will not match any directories or specific filenames
|
||||
// Must use "*", "*.ext", or "*.ext1;*.ext2"
|
||||
// This is definitely not efficient and may crash when dealing with very deep levels
|
||||
BOOL DirectorySearch(PDIRECTORY_INFO pDirectory, char *FileWildcard)
|
||||
{
|
||||
int i, WildcardCount = 0;
|
||||
BOOL IsDirectory;
|
||||
BOOL RecurseSubDirs, MatchAllFiles = FALSE;
|
||||
char tmpSubDir[MAX_PATH+1];
|
||||
char *tmpWildcard, *Wildcard, *Wildcards[MAX_WILDCARDS];
|
||||
char *BasePathName, *Filename, *FileExtension, *tmpFileExtension;
|
||||
PDIRECTORY_INFO pNewDirectory;
|
||||
|
||||
if (!pDirectory || !pDirectory->Initialized || pDirectory->Finished) return FALSE;
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
// Setup wildcards
|
||||
|
||||
if (!FileWildcard)
|
||||
{
|
||||
MatchAllFiles = TRUE;
|
||||
}
|
||||
else if (!FileWildcard[0] || strchr(FileWildcard, ','))
|
||||
{
|
||||
PrintWildcardError();
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!(tmpWildcard = Wildcard = strdup(FileWildcard)))
|
||||
{
|
||||
fprintf(stderr, "Error allocating %d bytes\n", strlen(FileWildcard)+1);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
while (*tmpWildcard && (tmpFileExtension = strchr(tmpWildcard, ';')))
|
||||
{
|
||||
*tmpFileExtension++ = '\0';
|
||||
if (WildcardCount == MAX_WILDCARDS - 1) return FALSE;
|
||||
|
||||
if (tmpWildcard[0] == '*' && !tmpWildcard[1])
|
||||
{
|
||||
MatchAllFiles = TRUE;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (tmpWildcard[0] == '*' && tmpWildcard[1] != '.')
|
||||
{
|
||||
PrintWildcardError();
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Wildcards[WildcardCount++] = strdup(tmpWildcard);
|
||||
tmpWildcard = tmpFileExtension;
|
||||
}
|
||||
}
|
||||
|
||||
if (MatchAllFiles || (tmpWildcard[0] == '*' && !tmpWildcard[1]))
|
||||
{
|
||||
MatchAllFiles = TRUE;
|
||||
for (i = 0; i < WildcardCount; i++) free(Wildcards[i]);
|
||||
WildcardCount = 0;
|
||||
}
|
||||
else if (*tmpWildcard)
|
||||
{
|
||||
Wildcards[WildcardCount++] = strdup(tmpWildcard);
|
||||
free(Wildcard);
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
// Iterate through subdirectories
|
||||
|
||||
RecurseSubDirs = pDirectory->RecurseSubDirs;
|
||||
BasePathName = pDirectory->BasePathName;
|
||||
Filename = pDirectory->BasePath.cFileName;
|
||||
|
||||
//printf("=== Searching in %s (RecurseSubDirs = %d)\n", BasePathName, RecurseSubDirs);
|
||||
while (TRUE)
|
||||
{
|
||||
IsDirectory = pDirectory->BasePath.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
|
||||
FileExtension = strrchr(Filename, '.');
|
||||
|
||||
// Match if the currently found item is a subdirectory and recursion is enabled
|
||||
if (IsDirectory && RecurseSubDirs && *Filename != '.')
|
||||
{
|
||||
_snprintf(tmpSubDir, sizeof(tmpSubDir), "%s\\%s", BasePathName, Filename);
|
||||
if (!(pNewDirectory = DirectoryOpen(tmpSubDir, TRUE))) return FALSE;
|
||||
if (!(DirectorySearch(pNewDirectory, FileWildcard))) return FALSE;
|
||||
if (!MergeSearchResults(pDirectory, pNewDirectory)) return FALSE;
|
||||
DirectoryClose(pNewDirectory);
|
||||
}
|
||||
|
||||
// Try to match the current file to a wildcard or filename
|
||||
else if (!IsDirectory)
|
||||
{
|
||||
//printf("Found %s\\%s\n", BasePathName, Filename);
|
||||
|
||||
if (MatchAllFiles)
|
||||
{
|
||||
if (!AddFileToSearchResult(pDirectory, BasePathName, Filename)) return FALSE;
|
||||
}
|
||||
else if (FileExtension)
|
||||
{
|
||||
FileExtension++; // point to one byte past "." (the file extension)
|
||||
for (i = 0; i < WildcardCount; i++)
|
||||
{
|
||||
if (Wildcards[i][0] == '*')
|
||||
{
|
||||
if (!Wildcards[i][1] || Wildcards[i][2] == '*')
|
||||
{
|
||||
if (!AddFileToSearchResult(pDirectory, BasePathName, Filename)) return FALSE;
|
||||
break;
|
||||
}
|
||||
else if (Wildcards[i][2] && IsSameExtension(FileExtension, Wildcards[i] + 2))
|
||||
{
|
||||
if (!AddFileToSearchResult(pDirectory, BasePathName, Filename)) return FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (IsSameExtension(Filename, Wildcards[i]))
|
||||
{
|
||||
if (!AddFileToSearchResult(pDirectory, BasePathName, Filename)) return FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; i < WildcardCount; i++)
|
||||
{
|
||||
if (Wildcards[i][0] == '*' && Wildcards[i][1] == '.' && !Wildcards[i][2])
|
||||
{
|
||||
if (!AddFileToSearchResult(pDirectory, BasePathName, Filename)) return FALSE;
|
||||
break;
|
||||
}
|
||||
else if (IsSameExtension(Filename, Wildcards[i])) // match file
|
||||
{
|
||||
if (!AddFileToSearchResult(pDirectory, BasePathName, Filename)) return FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!FindNextFile(pDirectory->hFileList, &pDirectory->BasePath))
|
||||
{
|
||||
if (GetLastError() == ERROR_NO_MORE_FILES) break;
|
||||
fprintf(stderr, "FindNextFile failed: error code 0x%08lx\n", GetLastError());
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
pDirectory->Finished = TRUE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
PSEARCH_RESULTS GetLastSearchResult(PSEARCH_RESULTS pSearchResult)
|
||||
{
|
||||
while (pSearchResult && pSearchResult->Next) pSearchResult = pSearchResult->Next;
|
||||
return pSearchResult;
|
||||
}
|
||||
|
||||
BOOL AddFileToSearchResult(PDIRECTORY_INFO pDirectory, char *BasePathName, char *Filename)
|
||||
{
|
||||
DWORD PathLength;
|
||||
PSEARCH_RESULTS pSearchResults;
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
// Allocate a new search result set or append to an existing one
|
||||
|
||||
if (!pDirectory->pSearchResults)
|
||||
{
|
||||
pSearchResults = pDirectory->pSearchResults = malloc(sizeof(SEARCH_RESULTS));
|
||||
if (!pSearchResults)
|
||||
{
|
||||
fprintf(stderr, "Error allocating %d bytes\n", sizeof(SEARCH_RESULTS));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
pSearchResults->Previous = NULL;
|
||||
}
|
||||
else // an existing entry
|
||||
{
|
||||
pSearchResults = GetLastSearchResult(pDirectory->pSearchResults);
|
||||
if (!(pSearchResults->Next = malloc(sizeof(SEARCH_RESULTS))))
|
||||
{
|
||||
fprintf(stderr, "Error: unable to allocate %d bytes\n", sizeof(SEARCH_RESULTS));
|
||||
return FALSE;
|
||||
}
|
||||
pSearchResults->Next->Previous = pSearchResults;
|
||||
pSearchResults = pSearchResults->Next;
|
||||
}
|
||||
|
||||
pSearchResults->Next = NULL;
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
// Save path to filename for the search result
|
||||
|
||||
PathLength = strlen(pDirectory->BasePathName) + strlen(Filename) + 2;
|
||||
if (PathLength > MAX_PATH)
|
||||
{
|
||||
fprintf(stderr, "Error: File path is too large\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!(pSearchResults->FilePath = (char *)malloc(PathLength)))
|
||||
{
|
||||
fprintf(stderr, "Error: unable to allocate %d bytes\n", PathLength);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
sprintf(pSearchResults->FilePath, "%s\\%s", BasePathName, Filename);
|
||||
//printf("Added %s\n", pSearchResults->FilePath);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL MergeSearchResults(PDIRECTORY_INFO pBaseDir, PDIRECTORY_INFO pSubDir)
|
||||
{
|
||||
DWORD PathLength;
|
||||
PSEARCH_RESULTS pDestination, pSource;
|
||||
|
||||
if (!pBaseDir || !pSubDir) return FALSE;
|
||||
pSource = pSubDir->pSearchResults;
|
||||
if (!pSource) return TRUE; // subdirectory is empty (don't merge)
|
||||
assert(pSource->Previous == NULL);
|
||||
|
||||
if (!pBaseDir->pSearchResults) // merge subdirectory into empty result set
|
||||
{
|
||||
pDestination = pBaseDir->pSearchResults = malloc(sizeof(SEARCH_RESULTS));
|
||||
if (!pDestination)
|
||||
{
|
||||
fprintf(stderr, "Error allocating %d bytes\n", sizeof(SEARCH_RESULTS));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
pDestination->Previous = NULL;
|
||||
pDestination->Next = NULL;
|
||||
}
|
||||
else // merge subdirectory with an existing result set
|
||||
{
|
||||
assert(pBaseDir->pSearchResults->Previous == NULL);
|
||||
pDestination = GetLastSearchResult(pBaseDir->pSearchResults);
|
||||
pDestination->Next = malloc(sizeof(SEARCH_RESULTS));
|
||||
if (!pDestination->Next)
|
||||
{
|
||||
fprintf(stderr, "Error: unable to allocate %d bytes\n", sizeof(SEARCH_RESULTS));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
pDestination->Next->Previous = pDestination;
|
||||
pDestination = pDestination->Next;
|
||||
pDestination->Next = NULL;
|
||||
}
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
assert(pSource->FilePath != NULL);
|
||||
PathLength = strlen(pSource->FilePath) + 1;
|
||||
if (!(pDestination->FilePath = (char *)malloc(PathLength)))
|
||||
{
|
||||
fprintf(stderr, "Error: unable to allocate %d bytes\n", PathLength);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
strcpy(pDestination->FilePath, pSource->FilePath);
|
||||
//printf("Merged %s\n", pDestination->FilePath);
|
||||
|
||||
pSource = pSource->Next;
|
||||
if (!pSource) break;
|
||||
|
||||
pDestination->Next = malloc(sizeof(SEARCH_RESULTS));
|
||||
if (!pDestination->Next)
|
||||
{
|
||||
fprintf(stderr, "Error: unable to allocate %d bytes\n", sizeof(SEARCH_RESULTS));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
pDestination->Next->Previous = pDestination;
|
||||
pDestination = pDestination->Next;
|
||||
pDestination->Next = NULL;
|
||||
}
|
||||
|
||||
//printf("New base directory contains:\n");
|
||||
//DumpSearchResults(pSubDir->pSearchResults);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
DWORD GetSearchResultCount(PSEARCH_RESULTS pSearchResult)
|
||||
{
|
||||
DWORD Count = 0;
|
||||
|
||||
if (!pSearchResult) return 0;
|
||||
while (pSearchResult && pSearchResult->Next)
|
||||
{
|
||||
pSearchResult = pSearchResult->Next;
|
||||
Count++;
|
||||
}
|
||||
|
||||
return Count + 1;
|
||||
}
|
||||
|
||||
void DumpSearchResults(PSEARCH_RESULTS pSearchResults)
|
||||
{
|
||||
PSEARCH_RESULTS tmpResult;
|
||||
|
||||
if (!pSearchResults) return;
|
||||
|
||||
printf("Total records: %d\n", GetSearchResultCount(pSearchResults));
|
||||
for (tmpResult = pSearchResults; tmpResult; tmpResult = tmpResult->Next)
|
||||
{
|
||||
if (tmpResult->FilePath) printf("\t%s\n", tmpResult->FilePath);
|
||||
}
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include "directory.h"
|
||||
|
||||
#define MAX_WILDCARDS 10
|
||||
|
||||
// Internal functions only
|
||||
BOOL AddFileToSearchResult(PDIRECTORY_INFO pDirectory, char *BasePathName, char *Filename);
|
||||
BOOL MergeSearchResults(PDIRECTORY_INFO pBaseDir, PDIRECTORY_INFO pSubDir);
|
||||
BOOL MergeSearchResultsAndClose(PDIRECTORY_INFO pBaseDir, PDIRECTORY_INFO pSubDir);
|
||||
PSEARCH_RESULTS GetLastSearchResult(PSEARCH_RESULTS pSearchResult);
|
||||
DWORD GetSearchResultCount(PSEARCH_RESULTS pSearchResult);
|
||||
void DumpSearchResults(PSEARCH_RESULTS pSearchResults);
|
||||
|
||||
BOOL IsSameExtension(char *Extension1, char *Extension2)
|
||||
{
|
||||
if (_stricmp(Extension1, Extension2) == 0) return TRUE;
|
||||
else return FALSE;
|
||||
}
|
||||
|
||||
void PrintWildcardError()
|
||||
{
|
||||
fprintf(stderr, "Error: invalid wildcards for filename\n"
|
||||
"Wildcards can be:\n"
|
||||
"\tfilename match \"filename\"\n"
|
||||
"\tfilename.ext match \"filename.ext\"\n"
|
||||
"\t* match all files (with or without extensions)\n"
|
||||
"\t*.* match all files with extensions\n"
|
||||
"\t*. match all files without extensions\n"
|
||||
"\t*.ext match all files ending in \".ext\"\n"
|
||||
"\t*.ext1;*.ext2 match all files ending in \".ext1\" or \".ext2\"\n");
|
||||
}
|
||||
|
||||
PDIRECTORY_INFO DirectoryOpen(char *Directory, BOOL RecurseSubDirs)
|
||||
{
|
||||
PDIRECTORY_INFO pDirectory;
|
||||
char tmpdir[MAX_PATH+1];
|
||||
|
||||
if (!Directory) return NULL;
|
||||
//printf("Opening directory %s (RecurseSubDirs = %d)\n", Directory, RecurseSubDirs);
|
||||
|
||||
pDirectory = (PDIRECTORY_INFO)malloc(sizeof(DIRECTORY_INFO));
|
||||
if (!pDirectory)
|
||||
{
|
||||
fprintf(stderr, "Unable to allocate %d bytes\n", sizeof(DIRECTORY_INFO));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
_snprintf(tmpdir, sizeof(tmpdir), "%s\\*", Directory);
|
||||
pDirectory->hFileList = FindFirstFile(tmpdir, &pDirectory->BasePath);
|
||||
if (pDirectory->hFileList == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
fprintf(stderr, "Invalid path \"%s\"\n", Directory);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pDirectory->Initialized = TRUE;
|
||||
pDirectory->Finished = FALSE;
|
||||
pDirectory->RecurseSubDirs = RecurseSubDirs;
|
||||
pDirectory->pSearchResults = NULL;
|
||||
|
||||
_snprintf(pDirectory->BasePathName, sizeof(pDirectory->BasePathName), "%s", Directory);
|
||||
return pDirectory;
|
||||
}
|
||||
|
||||
void DirectoryClose(PDIRECTORY_INFO pDirectory)
|
||||
{
|
||||
PSEARCH_RESULTS pLast;
|
||||
|
||||
if (!pDirectory || !pDirectory->Initialized) return;
|
||||
//printf("Closing %s\n", pDirectory->BasePathName);
|
||||
|
||||
// Free the search results, if any
|
||||
if (pDirectory->pSearchResults)
|
||||
{
|
||||
assert(pDirectory->pSearchResults->Previous == NULL);
|
||||
|
||||
pLast = GetLastSearchResult(pDirectory->pSearchResults);
|
||||
assert(pLast);
|
||||
while (pLast->Previous)
|
||||
{
|
||||
assert(pLast->FilePath);
|
||||
if (pLast->FilePath)
|
||||
{
|
||||
//printf("Deallocating entry for %s\n", pLast->FilePath);
|
||||
free(pLast->FilePath);
|
||||
pLast->FilePath = NULL;
|
||||
}
|
||||
pLast = pLast->Previous;
|
||||
free(pLast->Next);
|
||||
pLast->Next = NULL;
|
||||
}
|
||||
|
||||
assert(pDirectory->pSearchResults == pLast);
|
||||
assert(pDirectory->pSearchResults->FilePath);
|
||||
|
||||
if (pDirectory->pSearchResults->FilePath)
|
||||
{
|
||||
//printf("Deallocating entry for %s\n", pDirectory->pSearchResults->FilePath);
|
||||
free(pDirectory->pSearchResults->FilePath);
|
||||
pDirectory->pSearchResults->FilePath = NULL;
|
||||
}
|
||||
|
||||
pDirectory->pSearchResults->Next = NULL;
|
||||
free(pDirectory->pSearchResults);
|
||||
pDirectory->pSearchResults = NULL;
|
||||
}
|
||||
|
||||
FindClose(pDirectory->hFileList);
|
||||
pDirectory->Initialized = FALSE;
|
||||
free(pDirectory);
|
||||
}
|
||||
|
||||
// This will match all files in a directory (or subdirectories if recursion is enabled)
|
||||
// Currently, this will not match any directories or specific filenames
|
||||
// Must use "*", "*.ext", or "*.ext1;*.ext2"
|
||||
// This is definitely not efficient and may crash when dealing with very deep levels
|
||||
BOOL DirectorySearch(PDIRECTORY_INFO pDirectory, char *FileWildcard)
|
||||
{
|
||||
int i, WildcardCount = 0;
|
||||
BOOL IsDirectory;
|
||||
BOOL RecurseSubDirs, MatchAllFiles = FALSE;
|
||||
char tmpSubDir[MAX_PATH+1];
|
||||
char *tmpWildcard, *Wildcard, *Wildcards[MAX_WILDCARDS];
|
||||
char *BasePathName, *Filename, *FileExtension, *tmpFileExtension;
|
||||
PDIRECTORY_INFO pNewDirectory;
|
||||
|
||||
if (!pDirectory || !pDirectory->Initialized || pDirectory->Finished) return FALSE;
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
// Setup wildcards
|
||||
|
||||
if (!FileWildcard)
|
||||
{
|
||||
MatchAllFiles = TRUE;
|
||||
}
|
||||
else if (!FileWildcard[0] || strchr(FileWildcard, ','))
|
||||
{
|
||||
PrintWildcardError();
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!(tmpWildcard = Wildcard = strdup(FileWildcard)))
|
||||
{
|
||||
fprintf(stderr, "Error allocating %d bytes\n", strlen(FileWildcard)+1);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
while (*tmpWildcard && (tmpFileExtension = strchr(tmpWildcard, ';')))
|
||||
{
|
||||
*tmpFileExtension++ = '\0';
|
||||
if (WildcardCount == MAX_WILDCARDS - 1) return FALSE;
|
||||
|
||||
if (tmpWildcard[0] == '*' && !tmpWildcard[1])
|
||||
{
|
||||
MatchAllFiles = TRUE;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (tmpWildcard[0] == '*' && tmpWildcard[1] != '.')
|
||||
{
|
||||
PrintWildcardError();
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Wildcards[WildcardCount++] = strdup(tmpWildcard);
|
||||
tmpWildcard = tmpFileExtension;
|
||||
}
|
||||
}
|
||||
|
||||
if (MatchAllFiles || (tmpWildcard[0] == '*' && !tmpWildcard[1]))
|
||||
{
|
||||
MatchAllFiles = TRUE;
|
||||
for (i = 0; i < WildcardCount; i++) free(Wildcards[i]);
|
||||
WildcardCount = 0;
|
||||
}
|
||||
else if (*tmpWildcard)
|
||||
{
|
||||
Wildcards[WildcardCount++] = strdup(tmpWildcard);
|
||||
free(Wildcard);
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
// Iterate through subdirectories
|
||||
|
||||
RecurseSubDirs = pDirectory->RecurseSubDirs;
|
||||
BasePathName = pDirectory->BasePathName;
|
||||
Filename = pDirectory->BasePath.cFileName;
|
||||
|
||||
//printf("=== Searching in %s (RecurseSubDirs = %d)\n", BasePathName, RecurseSubDirs);
|
||||
while (TRUE)
|
||||
{
|
||||
IsDirectory = pDirectory->BasePath.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
|
||||
FileExtension = strrchr(Filename, '.');
|
||||
|
||||
// Match if the currently found item is a subdirectory and recursion is enabled
|
||||
if (IsDirectory && RecurseSubDirs && *Filename != '.')
|
||||
{
|
||||
_snprintf(tmpSubDir, sizeof(tmpSubDir), "%s\\%s", BasePathName, Filename);
|
||||
if (!(pNewDirectory = DirectoryOpen(tmpSubDir, TRUE))) return FALSE;
|
||||
if (!(DirectorySearch(pNewDirectory, FileWildcard))) return FALSE;
|
||||
if (!MergeSearchResults(pDirectory, pNewDirectory)) return FALSE;
|
||||
DirectoryClose(pNewDirectory);
|
||||
}
|
||||
|
||||
// Try to match the current file to a wildcard or filename
|
||||
else if (!IsDirectory)
|
||||
{
|
||||
//printf("Found %s\\%s\n", BasePathName, Filename);
|
||||
|
||||
if (MatchAllFiles)
|
||||
{
|
||||
if (!AddFileToSearchResult(pDirectory, BasePathName, Filename)) return FALSE;
|
||||
}
|
||||
else if (FileExtension)
|
||||
{
|
||||
FileExtension++; // point to one byte past "." (the file extension)
|
||||
for (i = 0; i < WildcardCount; i++)
|
||||
{
|
||||
if (Wildcards[i][0] == '*')
|
||||
{
|
||||
if (!Wildcards[i][1] || Wildcards[i][2] == '*')
|
||||
{
|
||||
if (!AddFileToSearchResult(pDirectory, BasePathName, Filename)) return FALSE;
|
||||
break;
|
||||
}
|
||||
else if (Wildcards[i][2] && IsSameExtension(FileExtension, Wildcards[i] + 2))
|
||||
{
|
||||
if (!AddFileToSearchResult(pDirectory, BasePathName, Filename)) return FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (IsSameExtension(Filename, Wildcards[i]))
|
||||
{
|
||||
if (!AddFileToSearchResult(pDirectory, BasePathName, Filename)) return FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; i < WildcardCount; i++)
|
||||
{
|
||||
if (Wildcards[i][0] == '*' && Wildcards[i][1] == '.' && !Wildcards[i][2])
|
||||
{
|
||||
if (!AddFileToSearchResult(pDirectory, BasePathName, Filename)) return FALSE;
|
||||
break;
|
||||
}
|
||||
else if (IsSameExtension(Filename, Wildcards[i])) // match file
|
||||
{
|
||||
if (!AddFileToSearchResult(pDirectory, BasePathName, Filename)) return FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!FindNextFile(pDirectory->hFileList, &pDirectory->BasePath))
|
||||
{
|
||||
if (GetLastError() == ERROR_NO_MORE_FILES) break;
|
||||
fprintf(stderr, "FindNextFile failed: error code 0x%08lx\n", GetLastError());
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
pDirectory->Finished = TRUE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
PSEARCH_RESULTS GetLastSearchResult(PSEARCH_RESULTS pSearchResult)
|
||||
{
|
||||
while (pSearchResult && pSearchResult->Next) pSearchResult = pSearchResult->Next;
|
||||
return pSearchResult;
|
||||
}
|
||||
|
||||
BOOL AddFileToSearchResult(PDIRECTORY_INFO pDirectory, char *BasePathName, char *Filename)
|
||||
{
|
||||
DWORD PathLength;
|
||||
PSEARCH_RESULTS pSearchResults;
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
// Allocate a new search result set or append to an existing one
|
||||
|
||||
if (!pDirectory->pSearchResults)
|
||||
{
|
||||
pSearchResults = pDirectory->pSearchResults = malloc(sizeof(SEARCH_RESULTS));
|
||||
if (!pSearchResults)
|
||||
{
|
||||
fprintf(stderr, "Error allocating %d bytes\n", sizeof(SEARCH_RESULTS));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
pSearchResults->Previous = NULL;
|
||||
}
|
||||
else // an existing entry
|
||||
{
|
||||
pSearchResults = GetLastSearchResult(pDirectory->pSearchResults);
|
||||
if (!(pSearchResults->Next = malloc(sizeof(SEARCH_RESULTS))))
|
||||
{
|
||||
fprintf(stderr, "Error: unable to allocate %d bytes\n", sizeof(SEARCH_RESULTS));
|
||||
return FALSE;
|
||||
}
|
||||
pSearchResults->Next->Previous = pSearchResults;
|
||||
pSearchResults = pSearchResults->Next;
|
||||
}
|
||||
|
||||
pSearchResults->Next = NULL;
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
// Save path to filename for the search result
|
||||
|
||||
PathLength = strlen(pDirectory->BasePathName) + strlen(Filename) + 2;
|
||||
if (PathLength > MAX_PATH)
|
||||
{
|
||||
fprintf(stderr, "Error: File path is too large\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!(pSearchResults->FilePath = (char *)malloc(PathLength)))
|
||||
{
|
||||
fprintf(stderr, "Error: unable to allocate %d bytes\n", PathLength);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
sprintf(pSearchResults->FilePath, "%s\\%s", BasePathName, Filename);
|
||||
//printf("Added %s\n", pSearchResults->FilePath);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL MergeSearchResults(PDIRECTORY_INFO pBaseDir, PDIRECTORY_INFO pSubDir)
|
||||
{
|
||||
DWORD PathLength;
|
||||
PSEARCH_RESULTS pDestination, pSource;
|
||||
|
||||
if (!pBaseDir || !pSubDir) return FALSE;
|
||||
pSource = pSubDir->pSearchResults;
|
||||
if (!pSource) return TRUE; // subdirectory is empty (don't merge)
|
||||
assert(pSource->Previous == NULL);
|
||||
|
||||
if (!pBaseDir->pSearchResults) // merge subdirectory into empty result set
|
||||
{
|
||||
pDestination = pBaseDir->pSearchResults = malloc(sizeof(SEARCH_RESULTS));
|
||||
if (!pDestination)
|
||||
{
|
||||
fprintf(stderr, "Error allocating %d bytes\n", sizeof(SEARCH_RESULTS));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
pDestination->Previous = NULL;
|
||||
pDestination->Next = NULL;
|
||||
}
|
||||
else // merge subdirectory with an existing result set
|
||||
{
|
||||
assert(pBaseDir->pSearchResults->Previous == NULL);
|
||||
pDestination = GetLastSearchResult(pBaseDir->pSearchResults);
|
||||
pDestination->Next = malloc(sizeof(SEARCH_RESULTS));
|
||||
if (!pDestination->Next)
|
||||
{
|
||||
fprintf(stderr, "Error: unable to allocate %d bytes\n", sizeof(SEARCH_RESULTS));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
pDestination->Next->Previous = pDestination;
|
||||
pDestination = pDestination->Next;
|
||||
pDestination->Next = NULL;
|
||||
}
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
assert(pSource->FilePath != NULL);
|
||||
PathLength = strlen(pSource->FilePath) + 1;
|
||||
if (!(pDestination->FilePath = (char *)malloc(PathLength)))
|
||||
{
|
||||
fprintf(stderr, "Error: unable to allocate %d bytes\n", PathLength);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
strcpy(pDestination->FilePath, pSource->FilePath);
|
||||
//printf("Merged %s\n", pDestination->FilePath);
|
||||
|
||||
pSource = pSource->Next;
|
||||
if (!pSource) break;
|
||||
|
||||
pDestination->Next = malloc(sizeof(SEARCH_RESULTS));
|
||||
if (!pDestination->Next)
|
||||
{
|
||||
fprintf(stderr, "Error: unable to allocate %d bytes\n", sizeof(SEARCH_RESULTS));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
pDestination->Next->Previous = pDestination;
|
||||
pDestination = pDestination->Next;
|
||||
pDestination->Next = NULL;
|
||||
}
|
||||
|
||||
//printf("New base directory contains:\n");
|
||||
//DumpSearchResults(pSubDir->pSearchResults);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
DWORD GetSearchResultCount(PSEARCH_RESULTS pSearchResult)
|
||||
{
|
||||
DWORD Count = 0;
|
||||
|
||||
if (!pSearchResult) return 0;
|
||||
while (pSearchResult && pSearchResult->Next)
|
||||
{
|
||||
pSearchResult = pSearchResult->Next;
|
||||
Count++;
|
||||
}
|
||||
|
||||
return Count + 1;
|
||||
}
|
||||
|
||||
void DumpSearchResults(PSEARCH_RESULTS pSearchResults)
|
||||
{
|
||||
PSEARCH_RESULTS tmpResult;
|
||||
|
||||
if (!pSearchResults) return;
|
||||
|
||||
printf("Total records: %d\n", GetSearchResultCount(pSearchResults));
|
||||
for (tmpResult = pSearchResults; tmpResult; tmpResult = tmpResult->Next)
|
||||
{
|
||||
if (tmpResult->FilePath) printf("\t%s\n", tmpResult->FilePath);
|
||||
}
|
||||
}
|
|
@ -1,23 +1,23 @@
|
|||
#ifndef DIRECTORY_H
|
||||
#define DIRECTORY_H
|
||||
|
||||
typedef struct _DIRECTORY_INFO {
|
||||
HANDLE hFileList;
|
||||
BOOL Initialized;
|
||||
BOOL Finished;
|
||||
BOOL RecurseSubDirs;
|
||||
char BasePathName[MAX_PATH+1];
|
||||
WIN32_FIND_DATA BasePath; // do not reference this
|
||||
struct _SEARCH_RESULTS *pSearchResults; // use this!
|
||||
} DIRECTORY_INFO, *PDIRECTORY_INFO;
|
||||
|
||||
typedef struct _SEARCH_RESULTS {
|
||||
struct _SEARCH_RESULTS *Previous, *Next;
|
||||
char *FilePath;
|
||||
} SEARCH_RESULTS, *PSEARCH_RESULTS;
|
||||
|
||||
PDIRECTORY_INFO DirectoryOpen(char *Directory, BOOL RecurseSubDirs);
|
||||
BOOL DirectorySearch(PDIRECTORY_INFO pDirectory, char *FileWildcard);
|
||||
void DirectoryClose(PDIRECTORY_INFO pDirectory);
|
||||
|
||||
#endif // DIRECTORY_H
|
||||
#ifndef DIRECTORY_H
|
||||
#define DIRECTORY_H
|
||||
|
||||
typedef struct _DIRECTORY_INFO {
|
||||
HANDLE hFileList;
|
||||
BOOL Initialized;
|
||||
BOOL Finished;
|
||||
BOOL RecurseSubDirs;
|
||||
char BasePathName[MAX_PATH+1];
|
||||
WIN32_FIND_DATA BasePath; // do not reference this
|
||||
struct _SEARCH_RESULTS *pSearchResults; // use this!
|
||||
} DIRECTORY_INFO, *PDIRECTORY_INFO;
|
||||
|
||||
typedef struct _SEARCH_RESULTS {
|
||||
struct _SEARCH_RESULTS *Previous, *Next;
|
||||
char *FilePath;
|
||||
} SEARCH_RESULTS, *PSEARCH_RESULTS;
|
||||
|
||||
PDIRECTORY_INFO DirectoryOpen(char *Directory, BOOL RecurseSubDirs);
|
||||
BOOL DirectorySearch(PDIRECTORY_INFO pDirectory, char *FileWildcard);
|
||||
void DirectoryClose(PDIRECTORY_INFO pDirectory);
|
||||
|
||||
#endif // DIRECTORY_H
|
||||
|
|
|
@ -1,30 +1,30 @@
|
|||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
#include "image.h"
|
||||
|
||||
PIMAGE_SECTION_HEADER GetSection(LOADED_IMAGE Image, DWORD RVA)
|
||||
{
|
||||
DWORD i;
|
||||
PIMAGE_SECTION_HEADER pSection;
|
||||
|
||||
for (i = 0, pSection = Image.Sections; i < Image.NumberOfSections; i++, pSection++)
|
||||
{
|
||||
if (RVA >= pSection->VirtualAddress &&
|
||||
RVA < pSection->VirtualAddress + pSection->Misc.VirtualSize)
|
||||
{
|
||||
return pSection;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
BYTE *GetAddressFromRVA(LOADED_IMAGE Image, DWORD RVA)
|
||||
{
|
||||
int delta;
|
||||
PIMAGE_SECTION_HEADER pSection;
|
||||
|
||||
if (!(pSection = GetSection(Image, RVA))) return NULL;
|
||||
delta = (int)(pSection->VirtualAddress - pSection->PointerToRawData);
|
||||
return (BYTE *)Image.MappedAddress + RVA - delta;
|
||||
}
|
||||
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
#include "image.h"
|
||||
|
||||
PIMAGE_SECTION_HEADER GetSection(LOADED_IMAGE Image, DWORD RVA)
|
||||
{
|
||||
DWORD i;
|
||||
PIMAGE_SECTION_HEADER pSection;
|
||||
|
||||
for (i = 0, pSection = Image.Sections; i < Image.NumberOfSections; i++, pSection++)
|
||||
{
|
||||
if (RVA >= pSection->VirtualAddress &&
|
||||
RVA < pSection->VirtualAddress + pSection->Misc.VirtualSize)
|
||||
{
|
||||
return pSection;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
BYTE *GetAddressFromRVA(LOADED_IMAGE Image, DWORD RVA)
|
||||
{
|
||||
int delta;
|
||||
PIMAGE_SECTION_HEADER pSection;
|
||||
|
||||
if (!(pSection = GetSection(Image, RVA))) return NULL;
|
||||
delta = (int)(pSection->VirtualAddress - pSection->PointerToRawData);
|
||||
return (BYTE *)Image.MappedAddress + RVA - delta;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
#ifndef IMAGE_H
|
||||
#define IMAGE_H
|
||||
|
||||
#include <imagehlp.h>
|
||||
PIMAGE_SECTION_HEADER GetSection(LOADED_IMAGE Image, DWORD RVA);
|
||||
BYTE *GetAddressFromRVA(LOADED_IMAGE Image, DWORD RVA);
|
||||
|
||||
#ifndef IMAGE_H
|
||||
#define IMAGE_H
|
||||
|
||||
#include <imagehlp.h>
|
||||
PIMAGE_SECTION_HEADER GetSection(LOADED_IMAGE Image, DWORD RVA);
|
||||
BYTE *GetAddressFromRVA(LOADED_IMAGE Image, DWORD RVA);
|
||||
|
||||
#endif // IMAGE_H
|
|
@ -1,124 +0,0 @@
|
|||
# Microsoft Developer Studio Project File - Name="w00depends" - Package Owner=<4>
|
||||
# Microsoft Developer Studio Generated Build File, Format Version 6.00
|
||||
# ** DO NOT EDIT **
|
||||
|
||||
# TARGTYPE "Win32 (x86) Console Application" 0x0103
|
||||
|
||||
CFG=w00depends - Win32 Debug
|
||||
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
|
||||
!MESSAGE use the Export Makefile command and run
|
||||
!MESSAGE
|
||||
!MESSAGE NMAKE /f "w00depends.mak".
|
||||
!MESSAGE
|
||||
!MESSAGE You can specify a configuration when running NMAKE
|
||||
!MESSAGE by defining the macro CFG on the command line. For example:
|
||||
!MESSAGE
|
||||
!MESSAGE NMAKE /f "w00depends.mak" CFG="w00depends - Win32 Debug"
|
||||
!MESSAGE
|
||||
!MESSAGE Possible choices for configuration are:
|
||||
!MESSAGE
|
||||
!MESSAGE "w00depends - Win32 Release" (based on "Win32 (x86) Console Application")
|
||||
!MESSAGE "w00depends - Win32 Debug" (based on "Win32 (x86) Console Application")
|
||||
!MESSAGE
|
||||
|
||||
# Begin Project
|
||||
# PROP AllowPerConfigDependencies 0
|
||||
# PROP Scc_ProjName ""
|
||||
# PROP Scc_LocalPath ""
|
||||
CPP=cl.exe
|
||||
RSC=rc.exe
|
||||
|
||||
!IF "$(CFG)" == "w00depends - Win32 Release"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 0
|
||||
# PROP BASE Output_Dir "Release"
|
||||
# PROP BASE Intermediate_Dir "Release"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 0
|
||||
# PROP Output_Dir "Release"
|
||||
# PROP Intermediate_Dir "Release"
|
||||
# PROP Ignore_Export_Lib 0
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /c
|
||||
# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /FD /c
|
||||
# SUBTRACT CPP /YX /Yc /Yu
|
||||
# ADD BASE RSC /l 0x409 /d "NDEBUG"
|
||||
# ADD RSC /l 0x409 /d "NDEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
LINK32=link.exe
|
||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
|
||||
# ADD LINK32 kernel32.lib imagehlp.lib /nologo /subsystem:console /machine:I386
|
||||
|
||||
!ELSEIF "$(CFG)" == "w00depends - Win32 Debug"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 1
|
||||
# PROP BASE Output_Dir "Debug"
|
||||
# PROP BASE Intermediate_Dir "Debug"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 1
|
||||
# PROP Output_Dir "Debug"
|
||||
# PROP Intermediate_Dir "Debug"
|
||||
# PROP Ignore_Export_Lib 0
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /GZ /c
|
||||
# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FD /GZ /c
|
||||
# SUBTRACT CPP /YX /Yc /Yu
|
||||
# ADD BASE RSC /l 0x409 /d "_DEBUG"
|
||||
# ADD RSC /l 0x409 /d "_DEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
LINK32=link.exe
|
||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
|
||||
# ADD LINK32 kernel32.lib imagehlp.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
|
||||
|
||||
!ENDIF
|
||||
|
||||
# Begin Target
|
||||
|
||||
# Name "w00depends - Win32 Release"
|
||||
# Name "w00depends - Win32 Debug"
|
||||
# Begin Group "Source Files"
|
||||
|
||||
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\directory.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\image.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\w00depends.c
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "Header Files"
|
||||
|
||||
# PROP Default_Filter "h;hpp;hxx;hm;inl"
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\directory.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\image.h
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "Resource Files"
|
||||
|
||||
# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
|
||||
# End Group
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\ReadMe.txt
|
||||
# End Source File
|
||||
# End Target
|
||||
# End Project
|
|
@ -1,29 +0,0 @@
|
|||
Microsoft Developer Studio Workspace File, Format Version 6.00
|
||||
# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
|
||||
|
||||
###############################################################################
|
||||
|
||||
Project: "w00depends"=.\w00depends.dsp - Package Owner=<4>
|
||||
|
||||
Package=<5>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
Package=<4>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
###############################################################################
|
||||
|
||||
Global:
|
||||
|
||||
Package=<5>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
Package=<3>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
###############################################################################
|
||||
|
Загрузка…
Ссылка в новой задаче