Bladerunner
May 13th, 1999, 12:07 AM
Greetings all.
I am trying to implement a form of function sub-classing or thunking.
I need to replace an exported function in a Win 32 application at
run-time. My replacement code is contained in a DLL which is loaded
by the EXE containing the function I want to replace. The function is
exported, but of course the points where it is called is from
inaccessible code (had it been called via a vector I would have had no
problem!).
The method I am trying to implement is a variation of a method that
works flawlessly in DOS, i.e., simply replacing the entry code for the
function being replaced by a jump instruction to the address of the
replacement function. Assuming the parameter list is identical, the
stack gets setup the same, the new function is executed, and your
return address is unaffected (you can't execute the original function
from within your replacement though or you will create an infinite
loop).
Here is what the code looks like to implement the thunk:
typedef struct {
char opcode;
char (*address);
} FUNC_HEADER;
typedef struct { // THUNKING STRUCTURE AND DEFINITION
char *targetfunc; // address of the function being thunked
union func_start {
char newcodepfx[5]; // raw bytes
FUNC_HEADER fstart; // separated fields
};
void XP // thunker ...
thunkfunc(
THUNK_STRUCT *thunk,
void *oldfunc,
void *newfunc,
char *desc)
{
DWORD curacs;
void *nfunc;
if (thunk == NULL || oldfunc == NULL || newfunc == NULL) {
catastro(spf("Invalid address for %s thunk",desc));
}
if (VirtualProtect(oldfunc,(DWORD) 5,PAGE_EXECUTE_READWRITE,&curacs)
== FALSE) {
catastro(spf("Unable to thunk %s [Error=%ld]",desc,
GetLastError()));
}
txtlog(spf("thunkfunc(): oldfunc=[%lX], newfunc=[%lX]",oldfunc,
newfunc),TESTLOG,"",1);
thunk->targetfunc=oldfunc; // get target function address
thunk->newcodepfx[0]=233; // jump near instruction
thunk->fstart.address=newfunc;
txtlog(spf("thunkfunc(): fstart.opcode=[%X], fstart.address=[%lX]",
thunk->fstart.opcode,thunk->fstart.address),TESTLOG,"",1);
// _asm pushf;
// _asm cli;
*(thunk->targetfunc+0)=thunk->newcodepfx[0];
nfunc=&newfunc;
memmove(thunk->targetfunc+1,nfunc,4);
txtlog(spf("thunkfunc(): oldfunc now points to [%lX]",
thunk->targetfunc),TESTLOG,"",1);
txtlog(
spf("thunkfunc(): oldfunc values are [%X] [%X] [%X] [%X] [%X]",
*(thunk->targetfunc+0),*(thunk->targetfunc+1),
*(thunk->targetfunc+2),*(thunk->targetfunc+3),
*(thunk->targetfunc+4)),TESTLOG,"",1);
// _asm popf;
if (VirtualProtect(oldfunc,(DWORD) 5,curacs,&curacs) == FALSE) {
catastro(spf("Unable to thunk %s [Error=%ld]",desc,
GetLastError()));
}
}
The _asm statements are temporarily commented out because I do not
have a 32 bit Assembler which is required in order to have them
compiled by Borland C++ 5.0. The spf() function is a simple string
concatenation function used to tie a variable number of strings
together. The catastro() function is a fatal exit routine. The
thunking structure is in flux, some of its members are now irrelevant
and are used now just for validation.
Here is my problem: everything works hunky dory up to the point where
the jmp instruction executes but the instruction does *not* assemble to
a jump to the correct address of my replacement function. Subsequently
when the target function is called (which should then jump to the new
location, the jump is made to a different location.
Even when running under Borland's TD32 debugger and assembling the jump
instruction by hand to the address (either direct numeric or by function
name) of the replacement function, the assembled instruction shows up
instantaneously as a jump to some other strange location. It is as if
the address for the replacement function (which I verify under the
debugger and with the txtlog() logging), needs some sort of adjustment
to be accepted correctly.
I have verified the opcode and address bytes being correctly planted
into the 1st 5 bytes of the target function, furthermore to avoid any
problems with Win 32s use of jump tables I use GetProcAddress() to
obtain the address of both the target and replacement functions (and
they verify correctly under the debugger). I am getting no other
errors of any kind, the protection attribute changes work flawlessly,
etc.
Does anyone have any knowledge which could help me out here. I confess
that I am not big on Win 32 knowledge, and my only resource is Richter's
book "Advanced Windows" (which has helped me tremendously already). My
DLL is in the EXE's process space and in its memory map, so I don't
believe I am violating any memory referencing rules. The exception
that ends up being thrown is of course because I end up at an address
with no code!
Here are some actual values from a debugging session:
oldfunc address : 00443E69 (EXE load base is 00400000)
newfunc address : 018814A4 (DLL load base is 01880000)
value at oldfunc
address after
assembling the
following
instruction - jmp 018814A4 (or jmp <newfuncname>)
jmp 01CD14A6 (where did this come from???)
I would be very grateful for any assistance on this problem.
Paul A. Beswick
Soft Arts Ltd.
66 & 68 Barry Street
1st Floor
Kingston
Jamaica, W.I.
Tel.#s: 876-920-5201/5173 (Voice)
876-920-9036 (Fax)
I am trying to implement a form of function sub-classing or thunking.
I need to replace an exported function in a Win 32 application at
run-time. My replacement code is contained in a DLL which is loaded
by the EXE containing the function I want to replace. The function is
exported, but of course the points where it is called is from
inaccessible code (had it been called via a vector I would have had no
problem!).
The method I am trying to implement is a variation of a method that
works flawlessly in DOS, i.e., simply replacing the entry code for the
function being replaced by a jump instruction to the address of the
replacement function. Assuming the parameter list is identical, the
stack gets setup the same, the new function is executed, and your
return address is unaffected (you can't execute the original function
from within your replacement though or you will create an infinite
loop).
Here is what the code looks like to implement the thunk:
typedef struct {
char opcode;
char (*address);
} FUNC_HEADER;
typedef struct { // THUNKING STRUCTURE AND DEFINITION
char *targetfunc; // address of the function being thunked
union func_start {
char newcodepfx[5]; // raw bytes
FUNC_HEADER fstart; // separated fields
};
void XP // thunker ...
thunkfunc(
THUNK_STRUCT *thunk,
void *oldfunc,
void *newfunc,
char *desc)
{
DWORD curacs;
void *nfunc;
if (thunk == NULL || oldfunc == NULL || newfunc == NULL) {
catastro(spf("Invalid address for %s thunk",desc));
}
if (VirtualProtect(oldfunc,(DWORD) 5,PAGE_EXECUTE_READWRITE,&curacs)
== FALSE) {
catastro(spf("Unable to thunk %s [Error=%ld]",desc,
GetLastError()));
}
txtlog(spf("thunkfunc(): oldfunc=[%lX], newfunc=[%lX]",oldfunc,
newfunc),TESTLOG,"",1);
thunk->targetfunc=oldfunc; // get target function address
thunk->newcodepfx[0]=233; // jump near instruction
thunk->fstart.address=newfunc;
txtlog(spf("thunkfunc(): fstart.opcode=[%X], fstart.address=[%lX]",
thunk->fstart.opcode,thunk->fstart.address),TESTLOG,"",1);
// _asm pushf;
// _asm cli;
*(thunk->targetfunc+0)=thunk->newcodepfx[0];
nfunc=&newfunc;
memmove(thunk->targetfunc+1,nfunc,4);
txtlog(spf("thunkfunc(): oldfunc now points to [%lX]",
thunk->targetfunc),TESTLOG,"",1);
txtlog(
spf("thunkfunc(): oldfunc values are [%X] [%X] [%X] [%X] [%X]",
*(thunk->targetfunc+0),*(thunk->targetfunc+1),
*(thunk->targetfunc+2),*(thunk->targetfunc+3),
*(thunk->targetfunc+4)),TESTLOG,"",1);
// _asm popf;
if (VirtualProtect(oldfunc,(DWORD) 5,curacs,&curacs) == FALSE) {
catastro(spf("Unable to thunk %s [Error=%ld]",desc,
GetLastError()));
}
}
The _asm statements are temporarily commented out because I do not
have a 32 bit Assembler which is required in order to have them
compiled by Borland C++ 5.0. The spf() function is a simple string
concatenation function used to tie a variable number of strings
together. The catastro() function is a fatal exit routine. The
thunking structure is in flux, some of its members are now irrelevant
and are used now just for validation.
Here is my problem: everything works hunky dory up to the point where
the jmp instruction executes but the instruction does *not* assemble to
a jump to the correct address of my replacement function. Subsequently
when the target function is called (which should then jump to the new
location, the jump is made to a different location.
Even when running under Borland's TD32 debugger and assembling the jump
instruction by hand to the address (either direct numeric or by function
name) of the replacement function, the assembled instruction shows up
instantaneously as a jump to some other strange location. It is as if
the address for the replacement function (which I verify under the
debugger and with the txtlog() logging), needs some sort of adjustment
to be accepted correctly.
I have verified the opcode and address bytes being correctly planted
into the 1st 5 bytes of the target function, furthermore to avoid any
problems with Win 32s use of jump tables I use GetProcAddress() to
obtain the address of both the target and replacement functions (and
they verify correctly under the debugger). I am getting no other
errors of any kind, the protection attribute changes work flawlessly,
etc.
Does anyone have any knowledge which could help me out here. I confess
that I am not big on Win 32 knowledge, and my only resource is Richter's
book "Advanced Windows" (which has helped me tremendously already). My
DLL is in the EXE's process space and in its memory map, so I don't
believe I am violating any memory referencing rules. The exception
that ends up being thrown is of course because I end up at an address
with no code!
Here are some actual values from a debugging session:
oldfunc address : 00443E69 (EXE load base is 00400000)
newfunc address : 018814A4 (DLL load base is 01880000)
value at oldfunc
address after
assembling the
following
instruction - jmp 018814A4 (or jmp <newfuncname>)
jmp 01CD14A6 (where did this come from???)
I would be very grateful for any assistance on this problem.
Paul A. Beswick
Soft Arts Ltd.
66 & 68 Barry Street
1st Floor
Kingston
Jamaica, W.I.
Tel.#s: 876-920-5201/5173 (Voice)
876-920-9036 (Fax)