* 06-07-2003 CSH Created
*/
#include <stdio.h>
+#include <string.h>
#include <windows.h>
/* Valid values for Command parameter of TestRoutine */
/* Routines provided by the driver */
extern PVOID AllocateMemory(ULONG Size);
extern VOID FreeMemory(PVOID Base);
+
+
+typedef struct _API_DESCRIPTION
+{
+ PCHAR FileName;
+ PCHAR FunctionName;
+ PVOID FunctionAddress;
+ PVOID MockFunctionAddress;
+} API_DESCRIPTION, *PAPI_DESCRIPTION;
+
+extern API_DESCRIPTION ExternalDependencies[];
+extern ULONG MaxExternalDependency;
+
+static inline PVOID
+FrameworkGetFunction(PAPI_DESCRIPTION ApiDescription)
+{
+ HMODULE hModule;
+ PVOID Function;
+
+ hModule = GetModuleHandleA(ApiDescription->FileName);
+ if (hModule != NULL)
+ {
+ Function = GetProcAddress(hModule, ApiDescription->FunctionName);
+ }
+ else
+ {
+ hModule = LoadLibraryA(ApiDescription->FileName);
+ if (hModule != NULL)
+ {
+ Function = GetProcAddress(hModule, ApiDescription->FunctionName);
+ //FreeLibrary(hModule);
+ }
+ }
+ return Function;
+}
+
+static inline PVOID STDCALL
+FrameworkGetHookInternal(ULONG index)
+{
+ PVOID address;
+
+ if (index > MaxExternalDependency)
+ return NULL;
+
+ if (ExternalDependencies[index].MockFunctionAddress != NULL)
+ return ExternalDependencies[index].MockFunctionAddress;
+
+ if (ExternalDependencies[index].FunctionAddress != NULL)
+ return ExternalDependencies[index].FunctionAddress;
+
+ address = FrameworkGetFunction(&ExternalDependencies[index]);
+ ExternalDependencies[index].FunctionAddress = address;
+
+ return address;
+}
+
+
+static inline VOID
+_SetHook(PCHAR name,
+ PVOID address)
+{
+ PAPI_DESCRIPTION api;
+ ULONG index;
+
+ for (index = 0; index <= MaxExternalDependency; index++)
+ {
+ api = &ExternalDependencies[index];
+ if (strcmp(api->FunctionName, name) == 0)
+ {
+ api->FunctionAddress = address;
+ return;
+ }
+ }
+}
+
+typedef struct _HOOK
+{
+ PCHAR FunctionName;
+ PVOID FunctionAddress;
+} HOOK, *PHOOK;
+
+static inline VOID
+_SetHooks(PHOOK hookTable)
+{
+ PHOOK hook;
+
+ hook = &hookTable[0];
+ _SetHook(hook->FunctionName,
+ hook->FunctionAddress);
+}
+
+static inline VOID
+_UnsetHooks(PHOOK hookTable)
+{
+ PHOOK hook;
+
+ hook = &hookTable[0];
+ _SetHook(hook->FunctionName,
+ NULL);
+}
#include <sys/stat.h>
#include <stdlib.h>
#include <string.h>
+#include <ctype.h>
#ifdef WIN32
#include <io.h>
#include <dirent.h>
#include <unistd.h>
#endif
-#include <ctype.h>
#ifndef MAX_PATH
#define MAX_PATH 260
#endif
" return 0;\n"
"}\n";
+static char STUBS_HEADER[] =
+ "/* This file is autogenerated. */\n"
+ "passthrough:\n"
+ " call _FrameworkGetHook@4\n"
+ " test %eax, %eax\n"
+ " je .return\n"
+ " jmp *%eax\n"
+ ".return:\n"
+ " /* This will most likely corrupt the stack */\n"
+ " ret\n"
+ "\n";
+
+static char HOOKS_HEADER[] =
+ "/* This file is autogenerated. */\n"
+ "#include <windows.h>\n"
+ "#include \"regtests.h\"\n"
+ "\n"
+ "API_DESCRIPTION ExternalDependencies[] =\n"
+ "{\n";
+
+static char HOOKS_FOOTER[] =
+ "};\n"
+ "\n"
+ "#define ExternalDependencyCount %d\n"
+ "ULONG MaxExternalDependency = ExternalDependencyCount - 1;\n"
+ "\n"
+ "PVOID STDCALL\n"
+ "FrameworkGetHook(ULONG index)\n"
+ "{\n"
+ " return FrameworkGetHookInternal(index);\n"
+ "}\n";
+
static char HELP[] =
"REGTESTS path file makefile [-u umstubfile] [-k kmstubfile] [-e exestubfile]\n"
+ "REGTESTS -s stublistfile stubsfile hooksfile\n"
"\n"
- " path Path to files\n"
- " file Registration file to create\n"
- " makefile Makefile to create\n"
- " umstubfile Optional stub for running tests internal to a user-mode module\n"
- " kmstubfile Optional stub for running tests internal to a kernel-mode module\n"
- " exestubfile Optional stub for running tests internal to a module in the build environment\n";
+ " path Path to files\n"
+ " file Registration file to create\n"
+ " makefile Makefile to create\n"
+ " umstubfile Optional stub for running tests internal to a user-mode module\n"
+ " kmstubfile Optional stub for running tests internal to a kernel-mode module\n"
+ " exestubfile Optional stub for running tests internal to a module in the build environment\n"
+ " stublistfile File with descriptions of stubs\n"
+ " stubsfile File with stubs to create\n"
+ " hooksfile File with hooks to create\n";
+
+#define INPUT_BUFFER_SIZE 255
+
+void
+write_stubs_header(FILE * out)
+{
+ fputs(STUBS_HEADER, out);
+}
-int main(int argc,
+void
+write_hooks_header(FILE * out)
+{
+ fputs(HOOKS_HEADER, out);
+}
+
+void
+write_hooks_footer(FILE *hooks_out, unsigned long nr_stubs)
+{
+ fprintf(hooks_out, HOOKS_FOOTER, nr_stubs);
+}
+
+char *
+get_undecorate_name(char *buf,
+ char *decoratedname)
+{
+ int start = 0;
+ int end = 0;
+
+ while (start < strlen(decoratedname) && decoratedname[start] == '@')
+ {
+ start++;
+ }
+ strcpy(buf, &decoratedname[start]);
+ end = strlen(buf) - 1;
+ while (end > 0 && isdigit(buf[end]))
+ {
+ end--;
+ }
+ if (buf[end] == '@')
+ {
+ buf[end] = 0;
+ }
+ return buf;
+}
+
+void
+write_stub(FILE *stubs_out, FILE *hooks_out, char *dllname,
+ char *decoratedname, unsigned int stub_index)
+{
+ char buf[300];
+
+ fprintf(stubs_out, ".globl _%s\n", decoratedname);
+ fprintf(stubs_out, "_%s:\n", decoratedname);
+ fprintf(stubs_out, " pushl $%d\n", stub_index);
+ fprintf(stubs_out, " jmp passthrough\n");
+ fprintf(stubs_out, "\n");
+
+ fprintf(hooks_out, " {\"%s\", \"%s\", NULL, NULL},\n",
+ dllname, get_undecorate_name(buf, decoratedname));
+}
+
+void
+create_stubs_and_hooks(
+ FILE *in,
+ FILE *stubs_out,
+ FILE *hooks_out)
+{
+ char line[INPUT_BUFFER_SIZE];
+ char *s;
+ char *dllname;
+ char *decoratedname;
+ int stub_index;
+
+ write_stubs_header(stubs_out);
+
+ write_hooks_header(hooks_out);
+
+ /*
+ * Scan the database. The database is a text file; each
+ * line is a record, which contains data for one stub.
+ * Each record has two columns:
+ *
+ * DLLNAME (e.g. ntdll.dll)
+ * DECORATED NAME (e.g. NtCreateProcess@32, @InterlockedIncrement@4 or printf)
+ */
+ for (
+ /* First stub has index zero */
+ stub_index = 0;
+ /* Go on until EOF or read zero bytes */
+ ((!feof(in)) && (fgets(line, sizeof line, in) != NULL));
+ /* Next stub index */
+ stub_index++)
+ {
+ /*
+ * Remove, if present, the trailing CR.
+ * (os specific?)
+ */
+ if ((s = (char *) strchr(line,'\r')) != NULL)
+ {
+ *s = '\0';
+ }
+
+ /*
+ * Skip comments (#) and empty lines.
+ */
+ s = & line[0];
+ if ((*s) != '#' && (*s) != '\0')
+ {
+ /* Extract the DLL name */
+ dllname = (char *) strtok(s," \t");
+ /* Extract the decorated function name */
+ decoratedname = (char *) strtok(NULL," \t");
+ /* Extract the argument count */
+ write_stub(stubs_out, hooks_out, dllname, decoratedname, stub_index);
+ }
+ }
+
+ write_hooks_footer(hooks_out, stub_index + 1);
+}
+
+int run_stubs(int argc,
+ char **argv)
+{
+ FILE *in;
+ FILE *stubs_out;
+ FILE *hooks_out;
+
+ in = fopen(argv[2], "rb");
+ if (in == NULL)
+ {
+ perror("Failed to open stub description input file");
+ return 1;
+ }
+
+ stubs_out = fopen(argv[3], "wb");
+ if (stubs_out == NULL)
+ {
+ perror("Failed to open stubs output file");
+ return 1;
+ }
+
+ hooks_out = fopen(argv[4], "wb");
+ if (hooks_out == NULL)
+ {
+ perror("Failed to open hooks output file");
+ return 1;
+ }
+
+ create_stubs_and_hooks(in, stubs_out, hooks_out);
+
+ fclose(stubs_out);
+ fclose(hooks_out);
+
+ return 0;
+}
+
+int run_registrations(int argc,
char **argv)
{
char buf[MAX_PATH];
return 1;
}
-
strcpy(buf, convert_path(argv[1]));
if (buf[strlen(buf)] != DIR_SEPARATOR_CHAR)
{
return 0;
}
+
+int main(int argc,
+ char **argv)
+{
+ if (argc < 2)
+ {
+ puts(HELP);
+ return 1;
+ }
+
+ if (strlen(argv[1]) > 1 && argv[1][0] == '-' && argv[1][1] == 's')
+ {
+ return run_stubs(argc, argv);
+ }
+ else
+ {
+ return run_registrations(argc, argv);
+ }
+}