Listing 1: libase.c Source to Libase
/* LiBase - Library Rebase utility * Change base address of PE Executables based on a hash * History of bases is saved in an INI file * * Usage: libase <filename> [filename ...] */ #include <windows.h> #include <imagehlp.h> #include <assert.h> #include <io.h> #include <stdio.h> #include <string.h> #include <time.h> unsigned short HashName(const unsigned char *name, unsigned short modulus) { unsigned short h, g; for (h = 0; *name; ++name) { h = (unsigned short)((h << 2) + *name); if ((g = (unsigned short)(h & 0xf000u)) != 0) h ^= (unsigned short)(g >> 12); h &= (unsigned short)~g; } return (unsigned short)(h % modulus); } void storebase(unsigned long base, char *modulename, char *ininame) { char *AppName = "Generated bases"; char *start, *token; char item[20], modlist[1024]; /* look up the currect string */ sprintf(item, "%08x", base); GetPrivateProfileString(AppName, item, "", modlist, sizeof modlist, ininame); /* check if not already there */ for (token = modlist; token != NULL; token = start) { start = strstr(token, modulename); if (start != NULL && (start == token || strchr(", ", *(start - 1)) != NULL)) break; if (start != NULL) { assert(strlen(start) >= strlen(modulename)); start += strlen(modulename); } } /* module not yet in list? add it */ if (token == NULL) { if (strlen(modlist) > 0) strcat(modlist, ", "); strcat(modlist, modulename); WritePrivateProfileString(AppName, item, modlist, ininame); } } int main(int argc, char *argv[]) { char *AppName = "Configuration"; char ininame[_MAX_PATH], *ext, value[32]; unsigned long StartBase, BaseSeparation; short NumBases; BOOL IgnoreCase; int index; unsigned long oldsize, newsize; unsigned long oldbase, newbase; unsigned long save_newbase; HANDLE hFind; WIN32_FIND_DATA ffdata; BOOL result; if (argc < 2) { printf("LIBASE:\tChange base address of PE Executables " "based on a hash\n" "\tVersion 1.00\n\n" "Usage:\tlibase <filename> [filename ...]\n"); return 1; } /* convert .EXE name to .INI name */ GetModuleFileName(NULL, ininame, sizeof ininame); ext = strrchr(ininame, '.'); assert(ext != NULL && strcmpi(ext, ".exe") == 0); strcpy(ext, ".ini"); /* get configuration */ IgnoreCase = GetPrivateProfileInt(AppName, "IgnoreCase", TRUE, ininame); GetPrivateProfileString(AppName, "StartBase", "0x60000000", value, sizeof value, ininame); StartBase = strtoul(value, NULL, 0); GetPrivateProfileString(AppName, "BaseSeparation", "0x00100000", value, sizeof value, ininame); BaseSeparation = strtoul(value, NULL, 0); /* the number of different bases depends on the range * and the minimum distance between the bases; addresses * above 0x70000000L are reserved for system components. */ NumBases = (short)((0x70000000L - StartBase) / BaseSeparation); for (index = 1; index < argc; index++) { /* check most common errors separately */ if (access(argv[index],0) < 0) { printf("LIBASE:\tfile \"%s\" not found\n", argv[index]); return 1; } if (access(argv[index],6) < 0) { printf("LIBASE:\tfile \"%s\" is read-only\n", argv[index]); return 1; } /* the hash is different for upper and lower case * characters, so get the case of the filename as * stored on disk (not the case on the command line) */ hFind = FindFirstFile(argv[index], &ffdata); assert(hFind != INVALID_HANDLE_VALUE); FindClose(hFind); /* but if case must be ignored... * simply convert to upper case */ if (IgnoreCase) strupr(ffdata.cFileName); newbase = HashName((unsigned char *)ffdata.cFileName, NumBases) * BaseSeparation + StartBase; /* Rebase */ save_newbase = newbase; result = ReBaseImage(argv[index], "", TRUE, FALSE, FALSE, 0, &oldsize, &oldbase, &newsize, &newbase, time(NULL)); if (result) { printf("LIBASE:\tmodule \"%s\" rebased " "from 0x%08lx to 0x%08lx\n", ffdata.cFileName, oldbase, save_newbase); if (newsize > BaseSeparation) printf("\tNOTE: size (0x%08lx) exceeds " "base separation (0x%08lx)\n", newsize, BaseSeparation); storebase(save_newbase, ffdata.cFileName, ininame); } else { DWORD LastError = GetLastError(); printf("LIBASE:\terror processing \"%s\"\n", argv[index]); if (LastError != 0) { LPTSTR MsgBuf; FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ARGUMENT_ARRAY, NULL, LastError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&MsgBuf, 0, (va_list *)&argv[index]); printf("[%d] %s\n", LastError, MsgBuf); LocalFree(MsgBuf); } return 1; } } return 0; } /* End of File */