From df724b03248a119407b0ef9906c68bcde8cf0d3a Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 18 Feb 2009 17:25:20 +0100 Subject: [PATCH] MinGWify 'depends' Signed-off-by: Johannes Schindelin --- src/depends/.gitignore | 1 + src/depends/Makefile | 10 + src/depends/README.txt | 72 +-- src/depends/{w00depends.c => depends.c} | 742 +++++++++++++-------------- src/depends/directory.c | 862 ++++++++++++++++---------------- src/depends/directory.h | 46 +- src/depends/image.c | 60 +-- src/depends/image.h | 14 +- src/depends/w00depends.dsp | 124 ----- src/depends/w00depends.dsw | 29 -- 10 files changed, 909 insertions(+), 1051 deletions(-) create mode 100644 src/depends/.gitignore create mode 100644 src/depends/Makefile rename src/depends/{w00depends.c => depends.c} (96%) delete mode 100644 src/depends/w00depends.dsp delete mode 100644 src/depends/w00depends.dsw diff --git a/src/depends/.gitignore b/src/depends/.gitignore new file mode 100644 index 00000000..5761abcf --- /dev/null +++ b/src/depends/.gitignore @@ -0,0 +1 @@ +*.o diff --git a/src/depends/Makefile b/src/depends/Makefile new file mode 100644 index 00000000..4e6306b9 --- /dev/null +++ b/src/depends/Makefile @@ -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) diff --git a/src/depends/README.txt b/src/depends/README.txt index c943dc5c..701ca14f 100644 --- a/src/depends/README.txt +++ b/src/depends/README.txt @@ -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 diff --git a/src/depends/w00depends.c b/src/depends/depends.c similarity index 96% rename from src/depends/w00depends.c rename to src/depends/depends.c index b0d217ee..72cbe891 100644 --- a/src/depends/w00depends.c +++ b/src/depends/depends.c @@ -1,371 +1,371 @@ -#include -#include -#include -#include -#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 +#include +#include +#include +#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; +} diff --git a/src/depends/directory.c b/src/depends/directory.c index 93022eab..348712a7 100644 --- a/src/depends/directory.c +++ b/src/depends/directory.c @@ -1,432 +1,432 @@ -#include -#include -#include -#include -#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 +#include +#include +#include +#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); + } } \ No newline at end of file diff --git a/src/depends/directory.h b/src/depends/directory.h index d8bbaabb..2d00f304 100644 --- a/src/depends/directory.h +++ b/src/depends/directory.h @@ -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 diff --git a/src/depends/image.c b/src/depends/image.c index 737d6ae0..79bacba2 100644 --- a/src/depends/image.c +++ b/src/depends/image.c @@ -1,30 +1,30 @@ -#include -#include -#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 +#include +#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; +} + diff --git a/src/depends/image.h b/src/depends/image.h index d90dbdff..1c4141a2 100644 --- a/src/depends/image.h +++ b/src/depends/image.h @@ -1,8 +1,8 @@ -#ifndef IMAGE_H -#define IMAGE_H - -#include -PIMAGE_SECTION_HEADER GetSection(LOADED_IMAGE Image, DWORD RVA); -BYTE *GetAddressFromRVA(LOADED_IMAGE Image, DWORD RVA); - +#ifndef IMAGE_H +#define IMAGE_H + +#include +PIMAGE_SECTION_HEADER GetSection(LOADED_IMAGE Image, DWORD RVA); +BYTE *GetAddressFromRVA(LOADED_IMAGE Image, DWORD RVA); + #endif // IMAGE_H \ No newline at end of file diff --git a/src/depends/w00depends.dsp b/src/depends/w00depends.dsp deleted file mode 100644 index 79b6b15c..00000000 --- a/src/depends/w00depends.dsp +++ /dev/null @@ -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 diff --git a/src/depends/w00depends.dsw b/src/depends/w00depends.dsw deleted file mode 100644 index a69a64f0..00000000 --- a/src/depends/w00depends.dsw +++ /dev/null @@ -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> -{{{ -}}} - -############################################################################### - -- 2.11.4.GIT