int main(int argc, const char *argv[]) { if (argc <= 1) { return -1; } char dsk[MAX_PATH], dir[MAX_PATH]; _splitpath(argv[1], dsk, dir, NULL, NULL); FILE *f = fopen(argv[1], "rt"); if (!f) { return -2; } DWORD err = 0; ULONG_PTR newImageBase = 0x30000000; char file[MAX_PATH]; while (fgets(file, MAX_PATH, f)) { if (char *eoln = strchr(file, '\n')) { *eoln = '\0'; } ULONG_PTR oldImageSize = 0, oldImageBase = 0, newImageSize = 0; char flnm[MAX_PATH]; _makepath(flnm, dsk, dir, file, NULL); BOOL ret = ReBaseImage(flnm, NULL, TRUE, FALSE, FALSE, 0, &oldImageSize, &oldImageBase, &newImageSize, &newImageBase, 0); err = GetLastError(); if (err) { printf("rebase %s: error %i\n", file, err); } else { printf("rebase %s: %08x -> %08x, size %i\n", file, oldImageBase, newImageBase, newImageSize); } newImageBase = ((newImageBase + newImageSize)&~65535) + 65536; } fclose(f); return err; }
int main( int argc, char** argv ) { fprintf( stderr, "DLL base address scheduler v.1.2, copyright 2001-2002 (c) George Hazan.\n\n" ); //----[ Command line parsing ]-------------------------------------------------------- for ( int i=1; i < argc; i++ ) { if ( argv[ i ][ 0 ] != '/' ) { LBL_Usage: fprintf( stderr, "Usage: Rebaser.exe [/BASE:<hex_digit>] [/CHECK]\n" ); return 200; } if ( memicmp( &argv[ i ][ 1 ], "BASE:", 5 ) == 0 ) sscanf( &argv[ i ][ 6 ], "%08X", &glbOffset ); else if ( memicmp( &argv[ i ][ 1 ], "CHECK", 5 ) == 0 ) { glbCheckMode = true; glbOffset = 0x400000; } else goto LBL_Usage; } //----[ Command line ok, opening data files ]----------------------------------------- fprintf( stdout, "Scanning DLLs...\n" ); int locResult = 0; char locFileName[ MAX_PATH ]; while ( fgets( locFileName, sizeof( locFileName ), stdin ) != NULL ) { rtrim( locFileName ); fprintf( stdout, "Processing '%s'...\n", locFileName ); //----| If we need to check files only, check them |------------------------------- if ( glbCheckMode ) { DWORD locOldImageSize, locOldBase, locNewSize, locNewBase; if ( !ReBaseImage( locFileName, NULL, FALSE, FALSE, FALSE, FALSE, &locOldImageSize, &locOldBase, &locNewSize, &locNewBase, 0 )) PrintWin32Error( GetLastError() ); if ( locOldBase == glbOffset ) { fprintf( stdout, "Image is not based\n\n" ); locResult = 2; } continue; } //----| Preparing files |---------------------------------------------------------- LBL_Ok: HANDLE locFileHandle = CreateFile( locFileName, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0 ); if ( locFileHandle == INVALID_HANDLE_VALUE ) { fprintf( stdout, "File '%s' cannot be opened, skipped.\n\n", locFileName ); locResult = 2; continue; } FILETIME locCreateTime, locAccessTime, locModifyTime; GetFileTime( locFileHandle, &locCreateTime, &locAccessTime, &locModifyTime ); CloseHandle( locFileHandle ); //----| Processing |--------------------------------------------------------------- DWORD locOldImageSize, locOldBase, locNewSize; if ( !ReBaseImage( locFileName, NULL, TRUE, FALSE, FALSE, FALSE, &locOldImageSize, &locOldBase, &locNewSize, &glbOffset, 0 )) { PrintWin32Error( GetLastError() ); locResult = 2; } glbOffset += locNewSize; //----| Write down the original file timestamp |----------------------------------- locFileHandle = CreateFile( locFileName, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0 ); if ( locFileHandle != INVALID_HANDLE_VALUE ) { SetFileTime( locFileHandle, &locCreateTime, &locAccessTime, &locModifyTime ); CloseHandle( locFileHandle ); } } return locResult; }
VOID ReBaseFile( LPSTR CurrentImageName, BOOL fReBase ) { DWORD dw; CHAR Buffer[ MAX_PATH+1 ]; LPSTR FilePart; ULONG ThisImageExpectedSize = 0; ULONG ThisImageRequestedBase = NewImageBase; ULONG TimeStamp; if ( !InitialBase && !BaseAddrFile ) { fprintf( stderr, "REBASE: -b switch must specify a non-zero base --or--\n" ); fprintf( stderr, " -i must specify a filename\n" ); exit( REBASE_ERR ); } if ( BaseAddrFile && ( InitialBase || fGoingDown || CoffBaseDotTxt ) ) { fprintf( stderr, "REBASE: -i is incompatible with -b, -d, and -c\n" ); exit( REBASE_ERR ); } dw = GetFullPathName( CurrentImageName, sizeof(Buffer), Buffer, &FilePart ); if ( dw == 0 || dw > sizeof(Buffer) ) { FilePart = CurrentImageName; } _strlwr( FilePart ); // Lowercase for consistency when displayed. if ( BaseAddrFile && !(ThisImageRequestedBase = FindInBaseAddrFile( FilePart, &ThisImageExpectedSize )) ) { fprintf( stdout, "REBASE: %-16s Not listed in %s\n", FilePart, BaseAddrFileName ); } if (fSplitSymbols && !fSumOnly ) { if ( SplitSymbols( CurrentImageName, (PCHAR) SymbolPath, (PCHAR) DebugFilePath, SplitFlags ) ) { if ( fVerbose ) { fprintf( stdout, "REBASE: %16s symbols split into %s\n", FilePart, DebugFilePath ); } } else if (GetLastError() != ERROR_ALREADY_ASSIGNED && GetLastError() != ERROR_BAD_EXE_FORMAT) { fprintf( stdout, "REBASE: %-16s - unable to split symbols (%u)\n", FilePart, GetLastError() ); } } NewImageSize = (ULONG) -1; // Hack so we can tell when system images are skipped. time( (time_t *) &TimeStamp ); if (!ReBaseImage( CurrentImageName, (PCHAR) SymbolPath, fReBase && !fSumOnly, fRebaseSysfileOk, fGoingDown, ThisImageExpectedSize, &OriginalImageSize, &OriginalImageBase, &NewImageSize, &ThisImageRequestedBase, TimeStamp ) ) { if (ThisImageRequestedBase == 0) { fprintf(stderr, "REBASE: %-16s ***Grew too large (Size=0x%x; ExpectedSize=0x%x)\n", FilePart, OriginalImageSize, ThisImageExpectedSize); } else { if (GetLastError() == ERROR_BAD_EXE_FORMAT) { if (fVerbose) { fprintf( stderr, "REBASE: %-16s DOS or OS/2 image ignored\n", FilePart ); } } else if (GetLastError() == ERROR_INVALID_ADDRESS) { if (fVerbose) { fprintf( stderr, "REBASE: %-16s Rebase failed. Relocations are missing\n", FilePart ); } if (RebaseLog) { fprintf( RebaseLog, "%16s based at 0x%08x (size 0x%08x) Unable to rebase.\n", FilePart, OriginalImageBase, OriginalImageSize); } } else { fprintf( stderr, "REBASE: *** RelocateImage failed (%s). Image may be corrupted\n", FilePart ); } } ReturnCode = REBASE_ERR; return; } else { if (GetLastError() == ERROR_INVALID_DATA) { fprintf(stderr, "REBASE: Warning: DBG checksum did not match image.\n"); } } // Keep track of the lowest base address. if (MinBase > NewImageBase) { MinBase = NewImageBase; } if ( fSumOnly || !fReBase ) { if (!fQuiet) { fprintf( stdout, "REBASE: %16s mapped at %08x\n", FilePart, OriginalImageBase, OriginalImageSize); } } else { if (RebaseLog) { fprintf( RebaseLog, "%16s rebased to 0x%08x (size 0x%08x)\n", FilePart, fGoingDown ? ThisImageRequestedBase : NewImageBase, NewImageSize); } if ((NewImageSize != (ULONG) -1) && (OriginalImageBase != (fGoingDown ? ThisImageRequestedBase : NewImageBase)) && ( fVerbose || fQuiet ) ) { if ( fVerbose ) { fprintf( stdout, "REBASE: %16s initial base at 0x%08x (size 0x%08x)\n", FilePart, OriginalImageBase, OriginalImageSize); } fprintf( stdout, "REBASE: %16s rebased to 0x%08x (size 0x%08x)\n", FilePart, fGoingDown ? ThisImageRequestedBase : NewImageBase, NewImageSize); if ( fVerbose && fSplitSymbols) { fprintf( stdout, "REBASE: %16s updated image base in %s\n", FilePart, DebugFilePath ); } } if (fRemoveRelocs) { RemoveRelocations(CurrentImageName); } } if ( CoffBaseDotTxt ) { if ( !fCoffBaseIncExt ) { char *n; if ( n = strrchr(FilePart,'.') ) { *n = '\0'; } } fprintf( CoffBaseDotTxt, "%-16s 0x%08x 0x%08x\n", FilePart, fSumOnly ? OriginalImageBase : (fGoingDown ? ThisImageRequestedBase : NewImageBase), NewImageSize); } NewImageBase = ThisImageRequestedBase; // Set up the next one... }
int main(int argc, char *argv[]) { byte *dll_1, *dll_2, *p1, *p2, *iat_start1, *iat_end1, *iat_start2, *iat_end2; bool has_iat = false; MEMORY_BASIC_INFORMATION info; void *drcontext = dr_standalone_init(); uint writable_pages = 0, reserved_pages = 0, IAT_pages = 0; uint matched_pages = 0, second_matched_pages = 0, unmatched_pages = 0; uint exact_match_pages = 0, exact_no_match_pages = 0; char reloc_file[MAX_PATH] = {0}, orig_file[MAX_PATH], *input_file; uint old_size = 0, new_size = 0; uint old_base = 0, new_base = 0x69000000; /* unlikely to collide */ /* user specified option defaults */ uint arg_offs = 1; bool use_second_pass = true; bool assume_header_match = true; uint second_pass_offset = 16; /* FIXME arbitrary, what's a good choice? */ bool assume_IAT_written = true; bool spin_for_debugger = false; if (argc < 2) return usage(argv[0]); while (argv[arg_offs][0] == '-') { if (strcmp(argv[arg_offs], "-vv") == 0) { vv = true; } else if (strcmp(argv[arg_offs], "-v") == 0) { v = true; } else if (strcmp(argv[arg_offs], "-no_second_pass") == 0) { use_second_pass = false; } else if (strcmp(argv[arg_offs], "-second_pass_offset") == 0) { if ((uint)argc <= arg_offs+1) return usage(argv[0]); second_pass_offset = atoi(argv[++arg_offs]); } else if (strcmp(argv[arg_offs], "-no_assume_IAT_written") == 0) { assume_IAT_written = false; } else if (strcmp(argv[arg_offs], "-spin_for_debugger") == 0) { spin_for_debugger = true; } else { return usage(argv[0]); } arg_offs++; } input_file = argv[arg_offs++]; if (arg_offs != argc) return usage(argv[0]); _snprintf(reloc_file, sizeof(reloc_file), "%s.reloc.dll", input_file); reloc_file[sizeof(reloc_file)-1] = '\0'; if (!CopyFile(input_file, reloc_file, FALSE)) { LPSTR msg = NULL; uint error = GetLastError(); FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_ALLOCATE_BUFFER, 0, GetLastError(), 0, msg, 0, NULL); VERBOSE_PRINT("Copy Error %d (0x%x) = %s\n", error, error, msg); return 1; } snprintf(orig_file, sizeof(orig_file), "%s.orig.dll", input_file); orig_file[sizeof(orig_file)-1] = '\0'; if (!CopyFile(input_file, orig_file, FALSE)) { LPSTR msg = NULL; uint error = GetLastError(); FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_ALLOCATE_BUFFER, 0, GetLastError(), 0, msg, 0, NULL); VERBOSE_PRINT("Copy Error %d (0x%x) = %s\n", error, error, msg); return 1; } if (ReBaseImage(reloc_file, "", TRUE, FALSE, FALSE, 0, &old_size, &old_base, &new_size, &new_base, 0)) { VERBOSE_PRINT("Rebased imsage \"%s\" from 0x%08x to 0x%08x\n" "Size changed from %d bytes to %d bytes\n", input_file, old_base, new_base, old_size, new_size); } else { LPSTR msg = NULL; uint error = GetLastError(); FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_ALLOCATE_BUFFER, 0, GetLastError(), 0, msg, 0, NULL); VERBOSE_PRINT("Rebase Error %d (0x%x) = %s\n", error, error, msg); return 1; } dll_1 = (byte *)ALIGN_BACKWARD(LoadLibraryExA(orig_file, NULL, DONT_RESOLVE_DLL_REFERENCES), PAGE_SIZE); p1 = dll_1; dll_2 = (byte *)ALIGN_BACKWARD(LoadLibraryExA(reloc_file, NULL, DONT_RESOLVE_DLL_REFERENCES), PAGE_SIZE); p2 = dll_2; VVERBOSE_PRINT("Loaded dll @ 0x%08x and 0x%08x\n", dll_1, dll_2); if (dll_1 == NULL || dll_2 == NULL) { VERBOSE_PRINT( "Error loading %s\n", input_file); return 1; } /* Handle the first page specially since I'm seeing problems with a handful of * dlls that aren't really getting rebased. mcupdate_GenuineIntel.dll for ex. * (which does have relocations etc.) not sure what's up, but it's only a couple of * dlls so will ignore them. If we really rebased the header should differ. */ if (memcmp(dll_1, dll_2, PAGE_SIZE) == 0) { printf("%s - ERROR during relocating\n", input_file); return 1; } else { exact_no_match_pages++; if (assume_header_match) /* We could modify the hash function to catch header pages. */ matched_pages++; else unmatched_pages++; } p1 += PAGE_SIZE; p2 += PAGE_SIZE; if (assume_IAT_written && get_IAT_section_bounds(dll_1, &iat_start1, &iat_end1)) { has_iat = true; ASSERT(get_IAT_section_bounds(dll_2, &iat_start2, &iat_end2) && iat_start1 - dll_1 == iat_start2 - dll_2 && iat_end1 - dll_1 == iat_end2 - dll_2); } while (dr_virtual_query(p1, &info, sizeof(info)) == sizeof(info) && info.State != MEM_FREE && info.AllocationBase == dll_1) { /* we only check read-only pages (assumption writable pages aren't shareable) */ ASSERT(p1 == info.BaseAddress); if (info.State != MEM_COMMIT) { reserved_pages += info.RegionSize / PAGE_SIZE; VVERBOSE_PRINT("skipping %d reserved pages\n", info.RegionSize / PAGE_SIZE); p1 += info.RegionSize; p2 += info.RegionSize; } else if (!prot_is_writable(info.Protect)) { uint i; for (i = 0; i < info.RegionSize / PAGE_SIZE; i++) { bool exact = false; if (assume_IAT_written && has_iat && iat_end1 > p1 && iat_start1 < p1 + PAGE_SIZE) { /* overlaps an IAT page */ IAT_pages++; p1 += PAGE_SIZE; p2 += PAGE_SIZE; continue; } if (memcmp(p1, p2, PAGE_SIZE) == 0) { VVERBOSE_PRINT("Page Exact Match\n"); exact_match_pages++; exact = true; } else { VVERBOSE_PRINT("Page Exact Mismatch\n"); exact_no_match_pages++; } if (compare_pages(drcontext, p1, p2, 0)) { VVERBOSE_PRINT("Matched page\n"); matched_pages++; } else { VVERBOSE_PRINT("Failed to match page\n"); if (use_second_pass && compare_pages(drcontext, p1, p2, second_pass_offset)) { second_matched_pages++; } else { unmatched_pages++; } ASSERT(!exact); } p1 += PAGE_SIZE; p2 += PAGE_SIZE; } } else { writable_pages += info.RegionSize / PAGE_SIZE; VVERBOSE_PRINT("skipping %d writable pages\n", info.RegionSize / PAGE_SIZE); p1 += info.RegionSize; p2 += info.RegionSize; } } VERBOSE_PRINT("%d exact match, %d not exact match\n%d hash_match, %d second_hash_match, %d hash_mismatch\n", exact_match_pages, exact_no_match_pages, matched_pages, second_matched_pages, unmatched_pages); printf("%s : %d pages - %d w %d res %d IAT = %d same %d differ : %d hash differ %d first hash differ : %d%% found, %d%% found first hash\n", input_file, writable_pages + reserved_pages + IAT_pages + exact_match_pages + exact_no_match_pages, writable_pages, reserved_pages, IAT_pages, exact_match_pages, exact_no_match_pages, unmatched_pages, unmatched_pages + second_matched_pages, (100 * (matched_pages + second_matched_pages - exact_match_pages))/exact_no_match_pages, (100 * (matched_pages - exact_match_pages))/exact_no_match_pages); while (spin_for_debugger) Sleep(1000); return 0; }