Exemplo n.º 1
0
/**
 * @brief Checks whether injected code is in good shape and injects if not yet injected.
 *
 * If injected code is not found injection is attempted unless 3rd party overwrote
 * original code at injection location.
 */
void HardHook::check() {
	if (memcmp(baseptr, replace, 6) != 0) {
		if (memcmp(baseptr, orig, 6) == 0) {
			fods("HH: Restoring function %p", baseptr);
			inject(true);
		} else {
			fods("HH: Function %p replaced by third party. Lost.");
		}
	}
}
Exemplo n.º 2
0
/**
 * @brief Checks whether injected code is in good shape and injects if not yet injected.
 *
 * If injected code is not found injection is attempted unless 3rd party overwrote
 * original code at injection location.
 */
void HardHook::check() {
	if (memcmp(baseptr, replace, CODEREPLACESIZE) != 0) {
		// The instructions do not match our replacement instructions
		// If they match the original code, inject our hook.
		if (memcmp(baseptr, orig, CODEREPLACESIZE) == 0) {
			fods("HardHook: Reinjecting hook into function %p", baseptr);
			//TODO: Why do we want to force, even without a trampoline?!?
			inject(true);
		} else {
			fods("HardHook: Function %p replaced by third party. Lost injected hook.");
		}
	}
}
Exemplo n.º 3
0
void checkD3D9Hook(bool preonly) {
	if (bChaining) {
		ods("D3D9: Causing a chain");
		return;
	}

	bChaining = true;

	HMODULE hD3D = GetModuleHandle("D3D9.DLL");

	if (hD3D != NULL) {
		if (! bHooked) {
			char procname[2048];
			GetModuleFileName(NULL, procname, 2048);
			fods("D3D9: CreateWnd in unhooked D3D App %s", procname);
			bHooked = true;

			// Add a ref to ourselves; we do NOT want to get unloaded directly from this process.
			GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, reinterpret_cast<char *>(&HookCreate), &hSelf);

			// Can we use the prepatch data?
			GetModuleFileName(hD3D, procname, 2048);
			if (_stricmp(d3dd->cFileName, procname) == 0) {
				unsigned char *raw = (unsigned char *) hD3D;
				HookCreateRaw((voidFunc)(raw + d3dd->iOffsetCreate));
				if (d3dd->iOffsetCreateEx)
					HookCreateRawEx((voidFunc)(raw + d3dd->iOffsetCreateEx));
			} else if (! preonly) {
				fods("D3D9 Interface changed, can't rawpatch");
				pDirect3DCreate9 d3dc9 = reinterpret_cast<pDirect3DCreate9>(GetProcAddress(hD3D, "Direct3DCreate9"));
				ods("Got %p", d3dc9);
				if (d3dc9) {
					IDirect3D9 *id3d9 = d3dc9(D3D_SDK_VERSION);
					if (id3d9) {
						HookCreate(id3d9);
						id3d9->Release();
					} else {
						ods("Failed Direct3DCreate9");
					}
				} else {
					ods("D3D Library without Direct3DCreate9?");
				}
			} else {
				bHooked = false;
			}
		}
	}

	bChaining = false;
}
Exemplo n.º 4
0
/**
 * @brief Injects redirection code into the target function.
 *
 * Replaces the first 6 Bytes of the function indicated by baseptr
 * with the replacement code previously generated (usually a jump
 * to mumble code). If a trampoline is available this injection is not needed
 * as control flow was already permanently redirected by HardHook::setup .
 *
 * @param force Perform injection even when trampoline is available.
 */
void HardHook::inject(bool force) {
	if (! baseptr)
		return;
	if (! force && bTrampoline)
		return;

	DWORD origProtect;
	if (VirtualProtect(baseptr, CODEREPLACESIZE, PAGE_EXECUTE_READWRITE, &origProtect)) {
		for (int i = 0; i < CODEREPLACESIZE; ++i) {
			baseptr[i] = replace[i]; // Replace with jump to new code
		}

		DWORD tempProtect;
		VirtualProtect(baseptr, CODEREPLACESIZE, origProtect, &tempProtect);

		FlushInstructionCache(GetCurrentProcess(), baseptr, CODEREPLACESIZE);
	}

	// Verify that the injection was successful
	for (int i = 0; i < CODEREPLACESIZE; ++i) {
		if (baseptr[i] != replace[i]) {
			fods("HardHook: Injection failure noticed at byte %d", i);
		}
	}
}
Exemplo n.º 5
0
void checkDXGIHook(bool preonly) {
	if (bChaining) {
		ods("DXGI: Causing a chain");
		return;
	}

	if (! dxgi->iOffsetPresent || ! dxgi->iOffsetResize)
		return;

	bChaining = true;

	HMODULE hDXGI = GetModuleHandleW(L"DXGI.DLL");
	HMODULE hD3D10 = GetModuleHandleW(L"D3D10CORE.DLL");

	if (hDXGI && hD3D10) {
		if (! bHooked) {
			wchar_t procname[2048];
			GetModuleFileNameW(NULL, procname, 2048);
			fods("DXGI: Hookcheck '%ls'", procname);
			bHooked = true;

			// Add a ref to ourselves; we do NOT want to get unloaded directly from this process.
			GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, reinterpret_cast<char *>(&checkDXGIHook), &hSelf);

			// Can we use the prepatch data?
			GetModuleFileNameW(hDXGI, procname, 2048);
			if (_wcsicmp(dxgi->wcDXGIFileName, procname) == 0) {
				unsigned char *raw = (unsigned char *) hDXGI;
				HookPresentRaw((voidFunc)(raw + dxgi->iOffsetPresent));
				HookResizeRaw((voidFunc)(raw + dxgi->iOffsetResize));

				GetModuleFileNameW(hD3D10, procname, 2048);
				if (_wcsicmp(dxgi->wcD3D10FileName, procname) == 0) {
					unsigned char *raw = (unsigned char *) hD3D10;
					HookAddRelease((voidFunc)(raw + dxgi->iOffsetAddRef), (voidFunc)(raw + dxgi->iOffsetRelease));
				}
			} else if (! preonly) {
				fods("DXGI Interface changed, can't rawpatch");
			} else {
				bHooked = false;
			}
		}
	}

	bChaining = false;
}
Exemplo n.º 6
0
// EnsureMinHookInitialized ensures that the MinHook
// library is initialized. If MinHook is already
// initialized, calling this function is a no-op.
static void EnsureMinHookInitialized() {
	// Ensure MH_Initialize is only called once.
	if (InterlockedCompareExchange(&minhook_init_once, 1, 0) == 0) {
		MH_STATUS status = MH_Initialize();
		if (status != MH_OK && status != MH_ERROR_ALREADY_INITIALIZED) {
			fods("HardHook: Failed to initialize minhook; MH_Initialize returned %s", MH_StatusToString(status));
		}
	}
}
Exemplo n.º 7
0
/**
 * @brief Makes sure the given replacement function is run once func is called.
 *
 * Tries to construct a trampoline for the given function (@see HardHook::cloneCode)
 * and then injects replacement function calling code into the first 6 bytes of the
 * original function (@see HardHook::inject).
 *
 * @param func Pointer to function to redirect.
 * @param replacement Pointer to code to redirect to.
 */
void HardHook::setup(voidFunc func, voidFunc replacement) {
	if (baseptr)
		return;

	fods("HardHook: Setup: Asked to replace %p with %p", func, replacement);

	unsigned char *fptr = reinterpret_cast<unsigned char *>(func);
	unsigned char *nptr = reinterpret_cast<unsigned char *>(replacement);

	call = (voidFunc) cloneCode((void **) &fptr);

	if (call) {
		bTrampoline = true;
	} else {
		// Could not create a trampoline. Use alternative method instead.
		bTrampoline = false;
		call = func;
	}

	DWORD origProtect;
	if (VirtualProtect(fptr, CODEPROTECTSIZE, PAGE_EXECUTE_READ, &origProtect)) {
		unsigned char **iptr = reinterpret_cast<unsigned char **>(&replace[1]);
		replace[0] = 0x68; // PUSH immediate        1 Byte
		*iptr = nptr;      // (imm. value = nptr)   4 Byte
		replace[5] = 0xc3; // RETN                  1 Byte

		// Save original 6 bytes at start of original function
		for (int i = 0; i < CODEREPLACESIZE; ++i)
			orig[i] = fptr[i];

		baseptr = fptr;

		//TODO: Why do we want to force, even without a trampoline?!? We may
		//      break the x86 instructions.
		//      This is only safe as long as we always restore before calling .call.
		inject(true);

		DWORD tempProtect;
		VirtualProtect(fptr, CODEPROTECTSIZE, origProtect, &tempProtect);
	} else {
		fods("HardHook: setup failed; failed to make original code read and executable");
	}
}
Exemplo n.º 8
0
/**
 * @brief Makes sure the given replacement function is run once func is called.
 *
 * Uses MinHook to put the hook in place.
 *
 * @param func Pointer to function to redirect.
 * @param replacement Pointer to code to redirect to.
 */
void HardHook::setup(voidFunc func, voidFunc replacement) {
	m_func = func;
	m_replacement = replacement;

	MH_STATUS status = MH_CreateHook((LPVOID) func, (LPVOID)replacement, (LPVOID *)&call);
	if (status != MH_OK) {
		fods("HardHook: setup failed, MH_CreateHook returned %s", MH_StatusToString(status));
	}

	inject(true);
}
Exemplo n.º 9
0
/**
 * @brief Injects redirection code into the target function.
 *
 * @param force No-op in the MinHook-based HardHook implementation.
 */
void HardHook::inject(bool force) {
	if (!force) {
		// MinHook guarantees the presence of a trampoline, so
		// inject() and restore() are no-ops unless force is
		// set to true.
		return;
	}

	MH_STATUS status = MH_EnableHook((LPVOID)m_func);
	if (status != MH_OK) {
		fods("HardHook: inject() failed: MH_EnableHook returned %s", MH_StatusToString(status));
	}
}
Exemplo n.º 10
0
/**
 * @brief Makes sure the given replacement function is run once func is called.
 *
 * Tries to construct a trampoline for the given function (@see HardHook::cloneCode)
 * and then injects replacement function calling code into the first 6 bytes of the
 * original function (@see HardHook::inject).
 *
 * @param func Pointer to function to redirect.
 * @param replacement Pointer to code to redirect to.
 */
void HardHook::setup(voidFunc func, voidFunc replacement) {
	if (baseptr)
		return;

	unsigned char *fptr = reinterpret_cast<unsigned char *>(func);
	unsigned char *nptr = reinterpret_cast<unsigned char *>(replacement);

	fods("HardHook: Asked to replace %p with %p", func, replacement);

	call = (voidFunc) cloneCode((void **) &fptr);

	if (call) {
		bTrampoline = true;
	} else {
		// Could not create a trampoline. Use alternative method instead.
		bTrampoline = false;
		call = func;
	}

	DWORD oldProtect;
	if (VirtualProtect(fptr, 16, PAGE_EXECUTE_READ, &oldProtect)) {
		unsigned char **iptr = reinterpret_cast<unsigned char **>(&replace[1]);
		replace[0] = 0x68; // PUSH immediate        1 Byte
		*iptr = nptr;      // (imm. value = nptr)   4 Byte
		replace[5] = 0xc3; // RETN                  1 Byte

		for (int i=0;i<6;i++) // Save original 6 bytes at start of original function
			orig[i] = fptr[i];

		baseptr = fptr;
		inject(true);

		DWORD restoreProtect;
		VirtualProtect(fptr, 16, oldProtect, &restoreProtect);
	} else {
		fods("HardHook: Failed vprotect");
	}
}
Exemplo n.º 11
0
/**
 * @brief Injects redirection code into the target function.
 *
 * Replaces the first 6 Bytes of the function indicated by baseptr
 * with the replacement code previously generated (usually a jump
 * to mumble code). If a trampoline is available this injection is not needed
 * as control flow was already permanently redirected by HardHook::setup .
 *
 * @param force If true injection will be performed even when trampoline is available.
 */
void HardHook::inject(bool force) {
	DWORD oldProtect, restoreProtect;
	int i;

	if (! baseptr)
		return;
	if (! force && bTrampoline)
		return;

	if (VirtualProtect(baseptr, 6, PAGE_EXECUTE_READWRITE, &oldProtect)) {
		for (i=0;i<6;i++)
			baseptr[i] = replace[i]; // Replace with jump to new code
		VirtualProtect(baseptr, 6, oldProtect, &restoreProtect);
		FlushInstructionCache(GetCurrentProcess(),baseptr, 6);
	}
	for (i=0;i<6;i++)
		if (baseptr[i] != replace[i])
			fods("HH: Injection failure at byte %d", i);
}
Exemplo n.º 12
0
/**
 * @brief No-op in MinHook-based HardHook implementation.
 */
void HardHook::check() {
		fods("HardHook: unused 'check' method called for MinHook-based HardHook");
}
Exemplo n.º 13
0
void HardHook::print() {
	fods("HardHook: unused 'print' method called for MinHook-based HardHook");
}
Exemplo n.º 14
0
void readConfig( const char* filename ) {
    /* States:
     * 0 : reading new entities ( to: 1, 3, 4, 5 )
     * 1 : reading machine
     * 2 : reading role
     * 3 : reading core
     * 4 : reading file
     * 5 : reading test ( to: 2 )
     */
    int state = 0;

    struct machine m;
    struct role r;
    struct file f;
    struct core c;
    struct test t;

    xmlTextReaderPtr xmlRead = xmlReaderForFile( filename, NULL, XML_PARSE_NONET | XML_PARSE_NOENT | XML_PARSE_NOCDATA | XML_PARSE_NOXINCNODE | XML_PARSE_COMPACT );
    if( !xmlRead )
        quit( "Could not open %s for reading as XML config\n", filename );

    xmlTextReaderSetErrorHandler( xmlRead, xmlErrorHandler, 0 );

    int nodeType, ret;
    xmlChar* nodeName;
    while( 1 ) {
        if( ( ret = xmlTextReaderRead( xmlRead ) ) != 1 ) {
            if( ret < 0 )
                quit( "Error occurred\n" );
            if( state )
                quit( "No more nodes to read, but state is not 0. Incomplete elements.\n" );
            xmlTextReaderClose( xmlRead );
            return;
        }
        nodeType = xmlTextReaderNodeType( xmlRead );
        
        nodeName = NULL;
        switch( nodeType ) {
            case XmlNodeType.Element :
                nodeName = xmlTextReaderLocalName( xmlRead );
                switch( state ) {
                    case 0 :
                        if( !strcmp( nodeName, "machine" ) ) {
                            state = 1;
                            bzero( m, sizeof( struct machine ) );
                            readValidRequiredAttribute( m.name, "machine", "name" );
                            readValidRequiredAttribute( m.address, "machine", "address" );
                            if( !strcmp( m.address, "DAS4" ) ) {
                                readValidRequiredAttribute( m.count, "machine", "DAS4 node count" );
                                char* end = NULL;
                                m.icount = strtol( m.count, &end, 10 );
                                if( end == m.count || *end || m.icount < 1 )
                                    quit( "Invalid DAS4 node count for machine %s\n", m.name );
                            }
                            break;
                        }
                        if( !strcmp( nodeName, "core" ) ) {
                            state = 3;
                            bzero( c, sizeof( struct core ) );
                            readValidRequiredAttribute( c.name, "core", "name" );
                            break;
                        }
                        if( !strcmp( nodeName, "file" ) ) {
                            state = 4;
                            bzero( f, sizeof( struct file ) );
                            readValidRequiredAttribute( f.name, "file", "name" );
                            readValidRequiredAttribute( f.size, "file", "size" );
                            char* end = NULL;
                            f.isize = strtol( f.size, &end, 10 );
                            if( end == f.size || f.isize < 1 )
                                quit( "Invalid size specifier for file %s\n", f.name );
                            if( *end && *(end+1) )
                                quit( "Invalid size specifier for file %s\n", f.name );
                            if( *end ) {
                                switch( *end ) {
                                    case 'b' :
                                    case 'B' :
                                        break;
                                    case 'k' :
                                    case 'K' :
                                        f.isize *= 1024;
                                        break;
                                    case 'm' :
                                    case 'M' :
                                        f.isize *= 1024 * 1024;
                                        break;
                                    case 'g' :
                                    case 'G' :
                                        f.isize *= 1024 * 1024 * 1024;
                                        break;
                                    case 't' :
                                    case 'T' :
                                        f.isize *= 1024 * 1024 * 1024 * 1024;
                                        break;
                                    default :
                                        quit( "Invalid size specifier for file %s\n", f.name );
                                }
                            }
                            if( f.isize > 512 * 1024 * 1024 ) {
                                int p = 512*1024*1024;
                                while( p < f.isize )
                                    p <<= 1;
                                if( p != f.isize )
                                    quit( "Invalid size specifier for file %s: sizes above 512M should be powers of 2\n", f.name );
                            }
                            if( f.isize & 0x3 )
                                quit( "Invalid size specifier for file %s: sizes should be a multiple of 4\n", f.name );
                            break;
                        }
                        if( !strcmp( nodeName, "test" ) ) {
                            state = 5;
                            bzero( t, sizeof( struct test ) );
                            readValidRequiredAttribute( t.name, "test", "name" );
                            break;
                        }
                        break;
                    case 1 :
                        if( !strcmp( nodeName, "tmpDir" ) ) {
                            onlyOne( m.tmpdir, "machine", "tmpDir" );
                            readValidString( m.tmpdir, "temporary directory location" );
                            skipToEndElement( "tmpDir" );
                            break;
                        }
                        if( !strcmp( nodeName, "params" ) ) {
                            onlyOne( m.params, "machine", "params" );
                            readValidString( m.params, "params" );
                            skipToEndElement( "params" );
                            break;
                        }
                        printf( "Unexpected element %s in machine %s\n", nodeName, m.name );
                        break;
                    case 2 :
                        if( !strcmp( nodeName, "machine" ) ) {
                            if( r.machineCount > 255 )
                                quit( "Maximum of 256 machines per role passed on line %d\n", xmlTextReaderGetParserLineNumber( xmlRead ) );
                            readValid( r.machine[r.machineCount], "machine name" );
                            r.machineCount++;
                            skipToEndElement( "machine" );
                            break;
                        }
                        if( !strcmp( nodeName, "user" ) ) {
                            onlyOne( r.user, "role", "user" );
                            readValidString( r.user, "user" );
                            skipToEndElement( "user" );
                            break;
                        }
                        if( !strcmp( nodeName, "core" ) ) {
                            onlyOne( r.core, "role", "core" );
                            readValidString( r.core, "core name" );
                            skipToEndElement( "core" );
                            break;
                        }
                        if( !strcmp( nodeName, "file" ) ) {
                            onlyOne( r.file, "role", "file" );
                            readValidString( r.file, "file name" );
                            skipToEndElement( "file" );
                            break;
                        }
                        if( !strcmp( nodeName, "params" ) ) {
                            onlyOne( r.params, "role", "params" );
                            readValidString( r.params, "params" );
                            skipToEndElement( "params" );
                            break;
                        }
                        printf( "Unexpected element %s in role on line %d\n", nodeName, xmlTextReaderGetParserLineNumber( xmlRead ) );
                        break;
                    case 3 :
                        if( !strcmp( nodeName, "params" ) ) {
                            onlyOne( c.params, "core", "params" );
                            readValidString( c.params, "params" );
                            skipToEndElement( "params" );
                            break;
                        }
                        if( !strcmp( nodeName, "localDir" ) ) {
                            onlyOne( c.localdir, "core", "localDir" );
                            readValidString( c.localdir, "local core directory" );
                            skipToEndElement( "localDir" );
                            break;
                        }
                        if( !strcmp( nodeName, "compilationDir" ) ) {
                            onlyOne( c.compdir, "core", "compilationDir" );
                            readValidString( c.compdir, "relative compilation directory" );
                            skipToEndElement( "compilationDir" );
                            break;
                        }
                        if( !strcmp( nodeName, "program" ) ) {
                            onlyOne( c.program, "core", "program" );
                            readValidString( c.program, "program name" );
                            skipToEndElement( "program" );
                            break;
                        }
                        printf( "Unexpected element %s in core %s\n", nodeName, c.name );
                        skipToEndElement( nodeName );
                        break;
                    case 4 :
                        if( !strcmp( nodeName, "offset" ) ) {
                            onlyOne( c.offset, "file", "offset" );
                            readValidString( c.offset, "offset" );
                            char* end = NULL;
                            f.ioffset = strtol( f.offset, &end, 10 );
                            if( end == f.offset || *end || f.ioffset < 0 || f >= f.isize )
                                quit( "Invalid file offset for file %s\n", f.name );
                            skipToEndElement( "offset" );
                            break;
                        }
                        printf( "Unexpected element %s in file %s\n", nodeName, f.name );
                        skipToEndElement( nodeName );
                        break;
                    case 5 :
                        if( !strcmp( nodeName, "role" ) ) {
                            state = 2;
                            bzero( r, sizeof( struct role ) );
                            readValidRequiredAttribute( r.type, "role", "type" );
                            if( strcmp( r.type, "seed" ) && strcmp( r.type, "leech" ) )
                                quit( "Invalid value for attribute 'type' for role on line %d, expected 'seed' or 'leech'\n", xmlTextReaderGetParserLineNumber( xmlRead ) );
                            break;
                        }
                        quit( "Unexpected element %s in test on line %d\n", nodeName, xmlTextReaderGetParserLineNumber( xmlRead ) );
                    default :
                        quit( "State sanity\n", nodeName );
                }
                break;
            case XmlNodeType.EndElement :
                nodeName = xmlTextReaderLocalName( xmlRead );
                switch( state ) {
                    case 0 :
                        quit( "End element %s found while not in entity\n", nodeName );
                    case 1 :
                        if( !strcmp( nodeName, "machine" ) ) {
                            memcpy( machines + machineCount, &m, sizeof( struct machine ) );
                            machineCount++;
                            state = 0;
                        }
                        break;
                    case 2 :
                        if( !strcmp( nodeName, "role" ) ) {
                            mempcy( t.roles + r.roleCount, &r, sizeof( struct role ) );
                            t.roleCount++;
                            state = 5;
                        }
                        break;
                    case 3 :
                        if( !strcmp( nodeName, "core" ) ) {
                            memcpy( cores + coreCount, &c, sizeof( struct core ) );
                            coreCount++;
                            state = 0;
                        }
                        break;
                    case 4 :
                        if( !strcmp( nodeName, "file" ) ) {
                            memcpy( files + fileCount, &f, sizeof( struct file ) );
                            fileCount++;
                            state = 0;
                        }
                        break;
                    case 5 :
                        if( !strcmp( nodeName, "test" ) ) {
                            memcpy( tests + testCount, &t, sizeof( struct test ) );
                            testCount++;
                            state = 0;
                        }
                        break;
                    default :
                        quit( "State sanity\n" );
                }
            default :
        }
        if( nodeName )
            free( nodeName );
    }
}

void validateConfigAndGenerateScripts( ) {
    int i, j, k, l;
    bool found;

    // == Validate test-role references to machines, cores and files
    // == Also register which machine uses which cores and which files
    for( i = 0; i < testCount; i++ ) {
        for( j = 0; j < tests[i].roleCount; j++ ) {
            // Check for validity of each role's core
            found = false;
            for( k = 0; k < coreCount; k++ ) {
                if( !strcmp( cores[k].name, tests[i].roles[j].core ) ) {
                    found = true;
                    break;
                }
            }
            if( !found )
                quit( "Test %s role %i refers to core %s which does not exist\n", tests[i].name, j, tests[i].roles[j].core );
            // Check for validity of each role's file
            found = false;
            for( k = 0; k < fileCount; k++ ) {
                if( !strcmp( files[k].name, tests[i].roles[j].file ) ) {
                    found = true;
                    break;
                }
            }
            if( !found )
                quit( "Test %s role %i refers to file %s which does not exist\n", tests[i].name, j, tests[i].roles[j].file );
            // Check for validity of each role's machines
            for( l = 0; l < tests[i].roles[j].machineCount; l++ ) {
                found = false;
                for( k = 0; k < machineCount; k++ ) {
                    if( !strcmp( machines[k].name, tests[i].roles[j].machines[l] ) ) {
                        // Machine found: register used core with the machine if needed
                        for( m = 0; m < machines[k].coreCount; m++ ) {
                            if( !strcmp( machines[k].cores[m], tests[i].roles[j].core ) ) {
                                found = true;
                                break;
                            }
                        }
                        if( !found )
                            machines[k].cores[machines[k].coreCount++] = tests[i].roles[j].core;
                        // Machine found: register used file with the machine if needed, only if seeding
                        if( !strcmp( tests[i].roles[j].type, "seed" ) ) {
                            found = false;
                            for( m = 0; m < machines[k].fileCount; m++ ) {
                                if( !strcmp( machines[k].files[m], tests[i].roles[j].file ) ) {
                                    found = true;
                                    break;
                                }
                            }
                            if( !found )
                                machines[k].files[machines[k].fileCount++] = tests[i].roles[j].file;
                        }
                        // Machine found
                        found = true;
                        break;
                    }
                }
                if( !found )
                    quit( "Test %s role %i refers to machine %s which does not exist\n", tests[i].name, j, tests[i].roles[j].machines[l] );
            }
        }
    }

    // Create temporary script
    FILE* script = tmpfile();
    if( !script )
        quit( "Can't create temporary script\n" );
    fprintf( script, "#!/bin/bash\n" );

    // == Check validity of machines and users: can each machine be accessed?
    for( i = 0; i < machineCount; i++ ) {
        // Creates a function in the script for sending command to the machine using ssh
        // Call using
        //    ssh_machine_%i "commands" || cleanup -1
        // where %i is the index of the machine in machines. Also be sure to return non-zero from your commands on error.
        fprintf( script, "function ssh_machine_%i {\n", i );
        if( strcmp( machines[i].address, "DAS4" ) )
            fprintf( script, "    ssh -T -n -o BatchMode=yes -h \"%s\"", machines[i].address );
        else
            fprintf( script, "    ssh -T -n -o BatchMode=yes -h fs3.das4.tudelft.nl" );
        if( machines[i].user )
            fprintf( script, " -l \"%s\"", machines[i].user );
        if( machines[i].params )
            fprintf( script, " %s", machines[i].params );
        fprintf( script, " $1 || return -1;\n" );
        fprintf( script, "}\n" );
        // Creates a function in the script for sending files to the machine using scp
        // Call using
        //    scp_to_machine_%i localfile remotefile
        fprintf( script, "function scp_to_machine_%i {\n", i );
        fprintf( script, "scp -o BatchMode=yes " );
        if( machines[i].params )
            fprintf( script, "%s ", machines[i].params );
        fprintf( script, "$1 ", l );
        if( machines[i].user )
            fprintf( script, "\"%s\"@", machines[i].user );
        if( strcmp( machines[i].address, "DAS4" ) )
            fprintf( script, "\"%s\"", machines[i].address );
        else
            fprintf( script, "fs3.das4.tudelft.nl" );
        fprintf( script, ":$2 || cleanup -1\n", i, l )
        fprintf( script, "}\n" );
        // Creates a function in the script for retrieving files from the machine using scp
        // Call using
        //    scp_from_machine_%i remotefile localfile
        fprintf( script, "function scp_from_machine_%i {\n", i );
        fprintf( script, "scp -o BatchMode=yes " );
        if( machines[i].params )
            fprintf( script, "%s ", machines[i].params );
        if( machines[i].user )
            fprintf( script, "\"%s\"@", machines[i].user );
        if( strcmp( machines[i].address, "DAS4" ) )
            fprintf( script, "\"%s\"", machines[i].address );
        else
            fprintf( script, "fs3.das4.tudelft.nl" );
        fprintf( script, ":$1 $2 || cleanup -1\n", i, l )
        fprintf( script, "}\n" );
        // Checks reachability of machine
        fprintf( script, "ssh_machine_%i || exit -1\n", i );
    }

    // == Check validity of each core: can each core be packaged? Can it be compiled locally and does the program then exist?
    // Create a cleanup file. This file should have code appended to cleanup things when errors occur or testing has finished. See existing code for examples of concatenating to it.
    // The cleanup function is available after this as well. Call it with an exit argument to end the script cleanly.
    fprintf( script, "CLEANUPFILE=`mktemp`\n" );
    fprintf( script, "chmod +x CLEANUPFILE\n" );
    fprintf( script, "[ -x CLEANUPFILE ] || exit -1\n" );
    fprintf( script, "function cleanup {\n" );
    fprintf( script, "    (\ncat <<EOL\nrm $CLEANUPFILE\nEOL\n) >> $CLEANUPFILE\n" );
    fprintf( script, "    . $CLEANUPFILE\n" );
    fprintf( script  "    exit $1\n" );
    fprintf( script, "}\n" );
    // Create a local temporary directory for storage
    fprintf( script, "TARDIR=`mktemp -d`\n[ \"X${TARDIR}X\" == \"XX\" ] && exit -1\n" );
    fprintf( script, "(\ncat <<EOL\n#!/bin/bash\nrm -rf $TARDIR\nEOL\n) >> $CLEANUPFILE\n" );
    fprintf( script, "CURDIR=`pwd`\n" );
    // Create a tarball for the testenvironment in the temporary local storage
    fprintf( script, "make clean || cleanup -1\n" );
    fprintf( script, "tar cf ${TARDIR}/testenvironment.tar . || cleanup -1\n" );
    fprintf( script, "bzip2 ${TARDIR}/testenvironment.tar || cleanup -1\n" );
    // Check whether the needed tools of the testenvironment compile locally
    fprintf( script, "make genfakedata || cleanup -1\n" );
    for( i = 0; i < coreCount; i++ ) {
        if( !cores[i].localdir )
            cores[i].localdir = strdup( "../" );
        // Create a tarball for the core in the temporary local storage
        fprintf( script, "cd %s || cleanup -1\n", cores[i].localdir );
        fprintf( script, "make clean\n" ); // Not checked: SHOULD be available, but...
        fprintf( script, "tar cf ${TARDIR}/core_%i.tar . || cleanup -1\n", i );
        fprintf( script, "bzip2 ${TARDIR}/core_%i.tar || cleanup -1\n", i );
        if( !cores[i].compdir )
            cores[i].compdir = strdup( "testenvironment/" );
        // Check whether the core compiles locally and the program exists after
        fprintf( script, "cd %s || cleanup -1\n", cores[i].compdir );
        fprintf( script, "make || cleanup -1\n" );
        if( !cores[i].program )
            cores[i].program = strdup( "swift" );
        fprintf( script, "[ -x %s ] || cleanup -1\n", cores[i].program );
        fprintf( script, "cd ${CURDIR}\n" );
    }

    // For each file, precalculate the hash
    for( i = 0; i < fileCount; i++ ) {
        // Create some temporary file to write fake data to. These fake data files will be regenerated at each machine since generating is faster than copying.
        size_t size = files[i].isize;
        FILE* data = tmpfile();
        if( !data )
            quit( "can't create temporary data file\n" );
        int datan = fileno( data );
        int filesize;
        if( size > 512*1024*1024 )
            filesize = 512*1024*1024;
        else
            filesize = size;
        if( generateFakeData( datan, filesize ) )
            quit( "could not write fake data\n" );
        
        MemoryHashStorage mhs;
        FileOffsetDataStorage fods( datan, files[i].ioffset );
        if( !fods.valid() )
            quit( "can't read back from temporary data file\n" );
        HashTree ht( fods, Sha1Hash::ZERO, mhs );
        Sha1Hash hash = ht.root_hash();
        if( size > filesize ) {
            MemoryHashStorage mhs2;
            int max = size/filesize;
            for( j = 0; j < max; j++ )
                mhs2.setHash( bin64(0,j), hash );
            int lvl = 0;
            do {
                max >>= 1;
                lvl++;
                for( j = 0; j < max; j++ )
                    mhs2.hashLeftRight( bin64_t(lvl, j) );
            } while( max > 1 );
            files[i].hash = mhs.getHash( bin64_t(lvl, 0) );
        }
        else
Exemplo n.º 15
0
/**
 * @brief Tries to construct a trampoline from original code.
 *
 * A trampoline is called by an injected mumble function to return
 * control flow to the original code.
 *
 * For this to work we have to save all commands overlapping the first 6 bytes
 * of code in the original function. This is needed so the first redirection,
 * to our mumble code, can be inserted in their place.
 *
 * As commands must not be destroyed they have to be disassembled to get their length.
 * All encountered commands will be part of the trampoline and stored in pCode (shared
 * for all trampolines).
 *
 * If code is encountered that can not be moved into the trampoline (conditionals etc.)
 * construction fails and and NULL is returned. If enough commands can be saved the
 * trampoline is finalized by appending a jump back to the original code. The return value
 * in this case will be the address of the newly constructed trampoline.
 *
 * pCode + offset to trampoline:
 *     [SAVED CODE FROM ORIGINAL > 6 bytes][JUMP BACK TO ORIGINAL CODE]
 *
 * @param porig Original code
 * @return Pointer to trampoline on success. NULL if trampoline construction failed.
 */
void *HardHook::cloneCode(void **porig) {


	DWORD oldProtect, restoreProtect;
	if (! pCode || uiCode > 4000) {
		uiCode = 0;
		pCode = VirtualAlloc(NULL, 4096, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
	}

	unsigned char *o = (unsigned char *) *porig;
	unsigned char *n = (unsigned char *) pCode;
	n += uiCode;
	unsigned int idx = 0;

	if (!VirtualProtect(o, 16, PAGE_EXECUTE_READ, &oldProtect)) {
		fods("HardHook: Failed vprotect (1)");
		return NULL;
	}

	while (*o == 0xe9) { // JMP
		unsigned char *tmp = o;
		int *iptr = reinterpret_cast<int *>(o+1);
		// Follow jmp relative to next command. It doesn't make a difference
		// if we actually perform all the jumps or directly jump to the end of
		// the chain. Hence these jumps need not be part of the trampoline.
		o += *iptr + 5;

		fods("HardHook: Chaining from %p to %p", *porig, o);
		*porig = o;

		// Assume jump took us out of our read enabled zone, get rights for the new one
		VirtualProtect(tmp, 16, oldProtect, &restoreProtect);
		if (!VirtualProtect(o, 16, PAGE_EXECUTE_READ, &oldProtect)) {
			fods("HardHook: Failed vprotect (2)");
			return NULL;
		}
	}

	do {
		unsigned char opcode = o[idx];
		unsigned char a = o[idx+1];
		unsigned char b = o[idx+2];
		unsigned int extra = 0;

		n[idx] = opcode;
		idx++;

		switch (opcode) {
			case 0x50: // PUSH
			case 0x51:
			case 0x52:
			case 0x53:
			case 0x54:
			case 0x55:
			case 0x56:
			case 0x57:
			case 0x58: // POP
			case 0x59:
			case 0x5a:
			case 0x5b:
			case 0x5c:
			case 0x5d:
			case 0x5e:
			case 0x5f:
				break;
			case 0x68: // PUSH immediate
				extra = 4;
				break;
			case 0x81: // CMP immediate
				extra = modrmbytes(a,b) + 5;
				break;
			case 0x83:	// CMP
				extra = modrmbytes(a,b) + 2;
				break;
			case 0x8b:	// MOV
				extra = modrmbytes(a,b) + 1;
				break;
			default:
				fods("HardHook: Unknown opcode at %d: %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x", idx-1, o[0], o[1], o[2], o[3], o[4], o[5], o[6], o[7], o[8], o[9], o[10], o[11]);
				VirtualProtect(o, 16, oldProtect, &restoreProtect);
				return NULL;
				break;
		}
		for (unsigned int i=0;i<extra;++i)
			n[idx+i] = o[idx+i];
		idx += extra;

	} while (idx < 6);
	VirtualProtect(o, 16, oldProtect, &restoreProtect);

	n[idx++] = 0xe9; // Add a relative jmp back to the original code
	int offs = o - n - 5;

	int *iptr = reinterpret_cast<int *>(&n[idx]);
	*iptr = offs;
	idx += 4;

	uiCode += idx;
	FlushInstructionCache(GetCurrentProcess(), n, idx);

	return n;
}
Exemplo n.º 16
0
void HardHook::print() {
	fods("HardHook: code replacement: %02x %02x %02x %02x %02x => %02x %02x %02x %02x %02x (currently effective: %02x %02x %02x %02x %02x)",
	     orig[0], orig[1], orig[2], orig[3], orig[4],
	     replace[0], replace[1], replace[2], replace[3], replace[4],
	     baseptr[0], baseptr[1], baseptr[2], baseptr[3], baseptr[4]);
}
Exemplo n.º 17
0
void HardHook::setupInterface(IUnknown *unkn, LONG funcoffset, voidFunc replacement) {
	fods("HardHook: setupInterface: Replacing %p function #%ld", unkn, funcoffset);
	void **ptr = reinterpret_cast<void **>(unkn);
	ptr = reinterpret_cast<void **>(ptr[0]);
	setup(reinterpret_cast<voidFunc>(ptr[funcoffset]), replacement);
}
Exemplo n.º 18
0
void HardHook::print() {
	fods("HardHook: %02x %02x %02x %02x %02x => %02x %02x %02x %02x %02x (%02x %02x %02x %02x %02x)",
	     orig[0], orig[1], orig[2], orig[3], orig[4],
	     replace[0], replace[1], replace[2], replace[3], replace[4],
	     baseptr[0], baseptr[1], baseptr[2], baseptr[3], baseptr[4]);
}
Exemplo n.º 19
0
void checkOpenGLHook() {
    if (bChaining) {
        return;
        ods("Causing a chain");
    }

    bChaining = true;

    HMODULE hGL = GetModuleHandle("OpenGL32.DLL");

    if (hGL != NULL) {
        if (! bHooked) {
            char procname[1024];
            GetModuleFileName(NULL, procname, 1024);
            fods("OpenGL: Unhooked OpenGL App %s", procname);
            bHooked = true;

            // Add a ref to ourselves; we do NOT want to get unloaded directly from this process.
            GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, reinterpret_cast<char *>(&checkOpenGLHook), &hSelf);

            INJECT(wglSwapBuffers);
            // INJECT(wglSwapLayerBuffers);

            GLDEF(wglCreateContext);
            GLDEF(glGenTextures);
            GLDEF(glDeleteTextures);
            GLDEF(glEnable);
            GLDEF(glDisable);
            GLDEF(glBlendFunc);
            GLDEF(glColorMaterial);
            GLDEF(glViewport);
            GLDEF(glMatrixMode);
            GLDEF(glLoadIdentity);
            GLDEF(glOrtho);
            GLDEF(glBindTexture);
            GLDEF(glPushMatrix);
            GLDEF(glColor4ub);
            GLDEF(glTranslatef);
            GLDEF(glBegin);
            GLDEF(glEnd);
            GLDEF(glTexCoord2f);
            GLDEF(glVertex2f);
            GLDEF(glPopMatrix);
            GLDEF(glTexParameteri);
            GLDEF(glTexEnvi);
            GLDEF(glTexImage2D);
            GLDEF(glTexSubImage2D);
            GLDEF(glPixelStorei);
            GLDEF(wglMakeCurrent);
            GLDEF(wglGetCurrentContext);
            GLDEF(wglGetCurrentDC);

            hGL = GetModuleHandle("GDI32.DLL");
            if (hGL) {
                // INJECT(SwapBuffers);
                GLDEF(GetDeviceCaps);
            } else {
                ods("OpenGL: Failed to find GDI32");
            }
        } else {
            hhwglSwapBuffers.check();
        }
    }

    bChaining = false;
}
Exemplo n.º 20
0
/**
 * @brief Tries to construct a trampoline from original code.
 *
 * A trampoline is the replacement code that features the original code plus
 * a jump back to the original instructions that follow.
 * It is called to execute the original behavior. As it is a replacement for
 * the original, the original can then be overwritten.
 * The size of the trampoline is at least CODEREPLACESIZE. Thus, CODEREPLACESIZE
 * bytes of the original code can afterwards be overwritten (and the trampoline
 * called after those instructions for the original logic).
 * CODEREPLACESIZE has to be smaller than CODEPROTECTSIZE.
 *
 * As commands must not be destroyed they have to be disassembled to get their length.
 * All encountered commands will be part of the trampoline and stored in pCode (shared
 * for all trampolines).
 *
 * If code is encountered that can not be moved into the trampoline (conditionals etc.)
 * construction fails and NULL is returned. If enough commands can be saved the
 * trampoline is finalized by appending a jump back to the original code. The return value
 * in this case will be the address of the newly constructed trampoline.
 *
 * pCode + offset to trampoline:
 *     [SAVED CODE FROM ORIGINAL which is >= CODEREPLACESIZE bytes][JUMP BACK TO ORIGINAL CODE]
 *
 * @param porig Original code
 * @return Pointer to trampoline on success. NULL if trampoline construction failed.
 */
void *HardHook::cloneCode(void **porig) {

	if (! pCode || uiCode > 4000) {
		pCode = VirtualAlloc(NULL, 4096, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
		uiCode = 0;
	}
	// If we have no memory to clone to, return.
	if (! pCode) {
		return NULL;
	}

	unsigned char *o = (unsigned char *) *porig;
	unsigned char *n = (unsigned char *) pCode;
	n += uiCode;
	unsigned int idx = 0;

	DWORD origProtect;
	if (!VirtualProtect(o, CODEPROTECTSIZE, PAGE_EXECUTE_READ, &origProtect)) {
		fods("HardHook: CloneCode failed; failed to make original code read and executable");
		return NULL;
	}

	// Follow relative jumps to next instruction. On execution it doesn't make
	// a difference if we actually perform all the jumps or directly jump to the
	// end of the chain. Hence these jumps need not be part of the trampoline.
	while (*o == 0xe9) { // JMP
		unsigned char *tmp = o;
		int *iptr = reinterpret_cast<int *>(o+1);
		o += *iptr + 5;

		fods("HardHook: CloneCode: Skipping jump from %p to %p", *porig, o);
		*porig = o;

		// Assume jump took us out of our read enabled zone, get rights for the new one
		DWORD tempProtect;
		VirtualProtect(tmp, CODEPROTECTSIZE, origProtect, &tempProtect);
		if (!VirtualProtect(o, CODEPROTECTSIZE, PAGE_EXECUTE_READ, &origProtect)) {
			fods("HardHook: CloneCode failed; failed to make jump target code read and executable");
			return NULL;
		}
	}

	do {
		unsigned char opcode = o[idx];
		unsigned char a = o[idx+1];
		unsigned char b = o[idx+2];
		unsigned int extra = 0;

		n[idx] = opcode;
		++idx;

		switch (opcode) {
			case 0x50: // PUSH
			case 0x51:
			case 0x52:
			case 0x53:
			case 0x54:
			case 0x55:
			case 0x56:
			case 0x57:
			case 0x58: // POP
			case 0x59:
			case 0x5a:
			case 0x5b:
			case 0x5c:
			case 0x5d:
			case 0x5e:
			case 0x5f:
				break;
			case 0x6a: // PUSH immediate
				extra = 1;
				break;
			case 0x68: // PUSH immediate
				extra = 4;
				break;
			case 0x81: // CMP immediate
				extra = modrmbytes(a,b) + 5;
				break;
			case 0x83:	// CMP
				extra = modrmbytes(a,b) + 2;
				break;
			case 0x8b:	// MOV
				extra = modrmbytes(a,b) + 1;
				break;
			default: {
				int rmop = ((a>>3) & 7);
				if (opcode == 0xff && rmop == 6) { // PUSH memory
					extra = modrmbytes(a,b) + 1;
					break;
				}

				fods("HardHook: CloneCode failed; Unknown opcode at %d: %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x",
						idx-1, o[0], o[1], o[2], o[3], o[4], o[5], o[6], o[7], o[8], o[9], o[10], o[11]);
				DWORD tempProtect;
				VirtualProtect(o, CODEPROTECTSIZE, origProtect, &tempProtect);
				return NULL;
				break;
			}
		}

		for (unsigned int i = 0; i < extra; ++i)
			n[idx+i] = o[idx+i];
		idx += extra;

	} while (idx < CODEREPLACESIZE);

	DWORD tempProtect;
	VirtualProtect(o, CODEPROTECTSIZE, origProtect, &tempProtect);

	// Add a relative jmp back to the original code
	n[idx++] = 0xe9;
	int *iptr = reinterpret_cast<int *>(&n[idx]);
	int offs = o - n - 5;
	*iptr = offs;
	idx += 4;

	uiCode += idx;

	FlushInstructionCache(GetCurrentProcess(), n, idx);

	fods("HardHook: trampoline creation successful at %p", n);

	return n;
}