Skip to content

Instantly share code, notes, and snippets.

@ynkdir
Created September 11, 2012 11:39
Show Gist options
  • Save ynkdir/3697773 to your computer and use it in GitHub Desktop.
Save ynkdir/3697773 to your computer and use it in GitHub Desktop.
Replace import DLL name.
/*
* 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