Quantcast
Channel: Nikolay Igotti
Viewing all articles
Browse latest Browse all 30

Overriding symbols on Win32

$
0
0
Today I was asked it it's possible to implement something similar to Linux's LD_PRELOAD for Windows, to allow override of particular symbol. I answered yes, and here's how I did it (some dynamic code generation involved :)).
#include<windows.h>
#include<stdio.h>
#include<stdlib.h>typedefunsignedchar* address;class Code {
  address buf; int size;int idx; enum reg {
    ax=0, cx, dx, bx, sp, bp, si, di
  };void init_sys();void generate(void* where, void* new_where);bool put_byte(unsignedchar b) {if (idx >= size) {return false;	  
    }
    buf[idx++] = b;return true;	
  }bool put_int(int i) {if (idx >= size-4) {return false;	  
    }
    *(int*)(buf+idx) = i;
    idx +=4; return true;
  }void pop(reg r) {
    put_byte(0x58 | r);
  }void push(reg r) {
    put_byte(0x50 | r);
  }void add(reg r, int imm8) {
    put_byte(0x83);
    put_byte(0xc0 | r);
    put_byte(imm8 & 0xff);
  }void jmp(reg r) {
    put_byte(0xff);
    put_byte(0xe0 | r);
  }void jmp(address where) {int off = buf_rel(where);
    put_byte(0xe9);
    put_int(off);
  }void call(address where) {int off = buf_rel(where);
    put_byte(0xe8);
    put_int(off);
  }static address abs(address base, int off) {return base+off+5;
  }staticint rel(address dest, address cur) {return (int)(dest - cur - 5);
  }int buf_rel(address w) {return rel(w, buf+idx);
  }public:
  Code(void* sym, void* new_where);
  ~Code();	
};voidCode::init_sys() {
  SYSTEM_INFO si;
  GetSystemInfo(&si);
  size =  si.dwPageSize;
}Code::Code(void* sym, void* new_where) : buf(NULL), size(-1), idx(0) {
  init_sys();
  buf = (address) VirtualAlloc(NULL, size, MEM_COMMIT | MEM_RESERVE,
			       PAGE_EXECUTE_READWRITE);// compute addressint off = *(int*)((address)sym+1);
  address real_sym = abs((address)sym, off);
  generate(real_sym, new_where);
  off = rel(buf, (address)sym);// and patch jumptable  DWORD old = 0;
  VirtualProtect(sym, 5, PAGE_READWRITE, &old);
  *(int*)((address)sym+1) = off;
  VirtualProtect(sym, 5, old, &old);
}Code::~Code() {
  VirtualFree(buf, size, MEM_RELEASE);
  buf = NULL;
  size = 0;	
}voidCode::generate(void* old, void* new_where) {
  call((address)new_where);
  jmp((address)old);
  FlushInstructionCache(GetCurrentProcess(), buf, size);
}// must be void/void to not corrupt stackvoidmy_exit(void) {
  printf("custom exit\n");
  getchar();
}intmain(int argc, char* argv[])
{// intentional leak, to avoid execution of code in unmapped areanew Code(&exit, &my_exit);

  printf("OK\n");  //exit(0);return 0;
}

Viewing all articles
Browse latest Browse all 30

Trending Articles