Created
September 11, 2012 11:39
-
-
Save ynkdir/3697773 to your computer and use it in GitHub Desktop.
Replace import DLL name.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Replace import DLL name. | |
* | |
* XXX: 32bit only | |
* | |
* Usage: | |
* peirep.exe /replace msvcrt.dll msvcr100.dll app.exe out.exe | |
* | |
* Reference: | |
* http://msdn.microsoft.com/msdnmag/issues/02/03/PE2/default.aspx | |
* http://forums.belution.com/ja/vc/000/234/78s.shtml | |
* http://nienie.com/~masapico/api_ImageDirectoryEntryToData.html | |
* http://www.geocities.jp/i96815/windows/win09.html | |
* http://hp.vector.co.jp/authors/VA050396/index.html | |
*/ | |
#include <windows.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <time.h> | |
#define TO_DOS_HEADER(base) ((PIMAGE_DOS_HEADER)(base)) | |
#define TO_NT_HEADERS(base) ((PIMAGE_NT_HEADERS)((LPBYTE)(base) + TO_DOS_HEADER(base)->e_lfanew)) | |
/* VC8/include/delayimp.h */ | |
#if !defined(_DELAY_IMP_VER) | |
typedef DWORD RVA; | |
typedef struct ImgDelayDescr { | |
DWORD grAttrs; // attributes | |
RVA rvaDLLName; // RVA to dll name | |
RVA rvaHmod; // RVA of module handle | |
RVA rvaIAT; // RVA of the IAT | |
RVA rvaINT; // RVA of the INT | |
RVA rvaBoundIAT; // RVA of the optional bound IAT | |
RVA rvaUnloadIAT; // RVA of optional copy of original IAT | |
DWORD dwTimeStamp; // 0 if not bound, | |
// O.W. date/time stamp of DLL bound to (Old BIND) | |
} ImgDelayDescr, * PImgDelayDescr; | |
enum DLAttr { // Delay Load Attributes | |
dlattrRva = 0x1, // RVAs are used instead of pointers | |
// Having this set indicates a VC7.0 | |
// and above delay load descriptor. | |
}; | |
#endif | |
static void *memmem(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen); | |
static size_t fgetsize(FILE *f); | |
static int read_file(const char *path, char **pbuf, size_t *psize); | |
static int write_file(const char *path, char *buf, size_t size); | |
static char *rva_to_ptr(char *base, RVA rva); | |
static void replace_import_dll_name(const char *modulepath, const char *fromname, const char *toname, const char *outpath); | |
static void * | |
memmem(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen) | |
{ | |
const char *a = haystack; | |
const char *b = needle; | |
size_t i; | |
if (haystacklen == 0 || needlelen == 0) | |
return (void *)haystack; | |
for (i = 0; i + needlelen <= haystacklen; ++i) { | |
if (a[i] == b[0] && memcmp(&a[i], needle, needlelen) == 0) | |
return (void *)&a[i]; | |
} | |
return NULL; | |
} | |
static size_t | |
fgetsize(FILE *f) | |
{ | |
fpos_t cur; | |
fpos_t end; | |
if (fgetpos(f, &cur) != 0) | |
return (size_t)-1; | |
if (fseek(f, 0L, SEEK_END) != 0) | |
return (size_t)-1; | |
if (fgetpos(f, &end) != 0) | |
return (size_t)-1; | |
if (fsetpos(f, &cur) != 0) | |
return (size_t)-1; | |
return (size_t)end; | |
} | |
static int | |
read_file(const char *path, char **pbuf, size_t *psize) | |
{ | |
FILE *f; | |
size_t size; | |
char *buf; | |
f = fopen(path, "rb"); | |
if (f == NULL) | |
return -1; | |
size = fgetsize(f); | |
if (size == (size_t)-1) { | |
fclose(f); | |
return -1; | |
} | |
buf = malloc(size); | |
if (buf == NULL) { | |
fclose(f); | |
return -1; | |
} | |
if (fread(buf, 1, size, f) != size) { | |
fclose(f); | |
free(buf); | |
return -1; | |
} | |
fclose(f); | |
*pbuf = buf; | |
*psize = size; | |
return 0; | |
} | |
static int | |
write_file(const char *path, char *buf, size_t size) | |
{ | |
FILE *f; | |
f = fopen(path, "wb"); | |
if (f == NULL) | |
return -1; | |
if (fwrite(buf, 1, size, f) != size) { | |
fclose(f); | |
return -1; | |
} | |
fclose(f); | |
return 0; | |
} | |
static char * | |
rva_to_ptr(char *base, RVA rva) | |
{ | |
PIMAGE_DATA_DIRECTORY dir; | |
PIMAGE_SECTION_HEADER psec; | |
DWORD i; | |
dir = TO_NT_HEADERS(base)->OptionalHeader.DataDirectory | |
+ IMAGE_DIRECTORY_ENTRY_IMPORT; | |
psec = (PIMAGE_SECTION_HEADER)(TO_NT_HEADERS(base) + 1); | |
for (i = 0; i < TO_NT_HEADERS(base)->FileHeader.NumberOfSections; i++) { | |
if (psec[i].VirtualAddress <= rva | |
&& rva < psec[i].VirtualAddress + psec[i].SizeOfRawData) { | |
return base + rva + (psec[i].PointerToRawData - psec[i].VirtualAddress); | |
} | |
} | |
return NULL; | |
} | |
static void | |
replace_import_dll_name(const char *modulepath, const char *fromname, const char *toname, const char *outpath) | |
{ | |
char *p; | |
size_t size; | |
PIMAGE_DOS_HEADER pdos; | |
PIMAGE_NT_HEADERS pnt; | |
PIMAGE_SECTION_HEADER psec; | |
DWORD i; | |
char *pname; | |
char tmpbuf[1024]; | |
size_t tmpsize; | |
RVA tonamerva; | |
PIMAGE_IMPORT_DESCRIPTOR Imp; | |
PIMAGE_DATA_DIRECTORY dir; | |
int off; | |
if (read_file(modulepath, &p, &size) != 0) | |
return; | |
// check dos header | |
pdos = TO_DOS_HEADER(p); | |
if (pdos->e_magic != IMAGE_DOS_SIGNATURE || pdos->e_lfanew == 0) { | |
free(p); | |
return; // not executable file | |
} | |
// check nt header | |
pnt = TO_NT_HEADERS(p); | |
if (pnt->Signature != IMAGE_NT_SIGNATURE | |
|| pnt->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC) { | |
free(p); | |
return; // not PE file | |
} | |
// get section table | |
psec = (PIMAGE_SECTION_HEADER)(pnt + 1); | |
pname = NULL; | |
// add new name if not exists | |
// XXX: do not work when there is extra space. | |
for (i = 0; i < pnt->FileHeader.NumberOfSections; i++) { | |
if (strcmp(psec[i].Name, ".rdata") == 0) { | |
tmpsize = strlen(toname) + 2; | |
tmpbuf[0] = 0; | |
strcpy(&tmpbuf[1], toname); | |
tmpbuf[tmpsize - 1] = 0; | |
pname = memmem(&p[psec[i].PointerToRawData], psec[i].SizeOfRawData, | |
tmpbuf, tmpsize); | |
if (pname == NULL) { | |
pname = &p[psec[i].PointerToRawData] + psec[i].SizeOfRawData; | |
memcpy(pname, tmpbuf, tmpsize); | |
psec[i].SizeOfRawData += tmpsize; | |
} | |
++pname; | |
tonamerva = psec[i].VirtualAddress | |
+ (pname - &p[psec[i].PointerToRawData]); | |
break; | |
} | |
} | |
if (pname == NULL) | |
return; | |
dir = pnt->OptionalHeader.DataDirectory + IMAGE_DIRECTORY_ENTRY_IMPORT; | |
Imp = (PIMAGE_IMPORT_DESCRIPTOR)rva_to_ptr(p, dir->VirtualAddress); | |
for ( ; Imp->OriginalFirstThunk != 0; ++Imp) { | |
if (stricmp(rva_to_ptr(p, Imp->Name), fromname) == 0) | |
Imp->Name = tonamerva; | |
} | |
write_file(outpath, p, size); | |
free(p); | |
} | |
int | |
main(int argc, char **argv) | |
{ | |
DWORD_PTR Base; | |
if (argc == 6 && stricmp(argv[1] + 1, "REPLACE") == 0) { | |
replace_import_dll_name(argv[4], argv[2], argv[3], argv[5]); | |
} else { | |
printf("usage: %s [option] [file]\n", argv[0]); | |
printf("\n"); | |
printf(" /REPLACE fromname toname exepath outpath\n"); | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment