Reputation: 1132
I have a program which loads DLLs and I need to call one of the non-exported functions it contains. Is there any way I can do this, via searching in a debugger or otherwise? Before anyone asks, yes I have the prototypes and stuff for the functions.
Upvotes: 12
Views: 11895
Reputation: 365707
Even if you can find the function address, it's not in general safe to call a function created by a compiler that thought it was making a "private" internal-use-only function.
Modern compilers with link-time-optimization enabled may make a specialized version of a function that only does what the specific callers need it to do.
Don't assume that a block of machine code that looks like the function you want actually follows the standard ABI and implements everything the source code says.
In gcc's case, it does use special names for specialized versions of a function that aren't inlined but take advantage of a special case (like constant propagation) from multiple callers.
e.g. in this objdump -drwC
output (where -C
is demangle):
42944c: e8 cf 13 0e 00 call 50a820 429451: 48 8b 7b 48 mov rdi,QWORD PTR [rbx+0x48] 429455: 48 89 ee mov rsi,rbp 429458: e8 b3 10 0e 00 call 50a510
gcc emits code that calls two different clones of the same function, specialized for two different compile-time-constants. (This is from http://endless-sky.github.io/, which desperately needs LTO because even trivial accessor functions for its XY position class are in Point.cpp, not Point.h, so they can only be inlined by LTO.)
LTO can even make .lto_priv
static versions of data: like
mov rcx,QWORD PTR [rip+0x412ff7] # 83dbe0 <_ZN12_GLOBAL__N_116playerGovernmentE.lto_priv.898>
So even if you find a function that looks like what you want, calling it from a new place might violate the assumptions that Link-Time-Optimization took advantage of.
Upvotes: 2
Reputation: 31404
Yes there is, at least sort of, but it isn't a good idea.
In C/C++ all a function pointer is, is an address in memory. So if you somehow where able to find the address of this function you could call it.
Let me ask some questions though, how do you know this DLL contains this function? Do you have the source code? Otherwise I don't know how you could know for certain that this function exists or if it is safe to call. But if you have the source code, then just expose the function. If the DLL writer didn't expose this function, they never expect you to call it and can change/remove the implementation at any time.
Warnings aside, you can find the function address if you have debug symbols or a MAP file you can find the offset in the DLL. If you don't have anything but the DLL, then there is no way to know where that function exists in the DLL - it is not stored in the DLL itself.
Once you have the offset you can then insert that into the code like so:
const DWORD_PTR funcOffset = 0xDEADBEEF;
typedef void (*UnExportedFunc)();
....
void CallUnExportedFunc() {
// This will get the DLL base address (which can vary)
HMODULE hMod = GetModuleHandle("My.dll");
// Calcualte the acutal address
DWORD_PTR funcAddress = (DWORD_PTR)hMod + funcOffset;
// Cast the address to a function poniter
UnExportedFunc func = (UnExportedFunc)funcAddress;
// Call the function
func();
}
Also realize that the offset of this function WILL CHANGE EVERY TIME the DLL is rebuilt so this is very fragile and let me say again, not a good idea.
Upvotes: 15
Reputation: 1825
I realize this question rather is old, but shf301 has the right idea here. The only thing I would add is to implement a pattern search on the target library. If you have IDA or OllyDbg, you can search for the function and view the binary/hex data which surrounds that function's starting address.
In most cases, there will be some sort of binary signature which rarely changes. The signature may hold wildcards which may change between builds, but ultimately there should be at least one successful hit while searching for this pattern, unless extremely drastic changes have occurred between builds (at which point, you could just figure out the new signature for that particular version).
The way that you would implement a binary pattern search is like so:
bool bCompare(const PBYTE pData, const PBYTE bMask, const PCHAR szMask)
{
for(;*szMask;++szMask,++pData,++bMask)
if(*szMask=='x' && *pData!=*bMask)
return 0;
return (*szMask) == NULL;
}
DWORD FindPattern(DWORD dwAddress, DWORD dwLen, PBYTE bMask, PCHAR szMask)
{
for(DWORD i=0; i<dwLen; i++)
if (bCompare((PBYTE)(dwAddress+i),bMask,szMask))
return (DWORD)(dwAddress+i);
return 0;
}
Example usage:
typedef void (*UnExportedFunc)();
//...
void CallUnExportedFunc()
{
// This will get the DLL base address (which can vary)
HMODULE hMod = GetModuleHandleA( "My.dll" );
// Get module info
MODULEINFO modinfo = { NULL, };
GetModuleInformation( GetCurrentProcess(), hMod, &modinfo, sizeof(modinfo) );
// This will search the module for the address of a given signature
DWORD dwAddress = FindPattern(
hMod, modinfo.SizeOfImage,
(PBYTE)"\xC7\x06\x00\x00\x00\x00\x89\x86\x00\x00\x00\x00\x89\x86",
"xx????xx????xx"
);
// Calculate the acutal address
DWORD_PTR funcAddress = (DWORD_PTR)hMod + dwAddress;
// Cast the address to a function poniter
UnExportedFunc func = (UnExportedFunc)funcAddress;
// Call the function
func();
}
The way that this works is by passing in the base address of the loaded library via GetModuleHandle
, specifying the length (in bytes) to search, the binary data to search for, and a mask which specifies which bytes of the binary string are valid ('x') and which are to be overlooked ('?'). The function will then walk through the memory space of the loaded module, searching for a match. In some cases, there may be more than one match and in this case, it's wise to make your signature a little more pronounced to where there is only one match.
Again, you would need to do the initial binary search in a disassembly application in order to know what this signature is, but once you have that then this method should work a little better than manually finding the function offset every time the target is built. Hope this helps.
Upvotes: 8
Reputation: 6843
The most general way to do this (and it's still a bad idea, as everyone else pointed out already) is to scan the DLL code at runtime after it's loaded, and look for a known, unique section of code in that function, and then use code similar to that in shf301's answer to call it. If you know that the DLL won't ever change, than any solution based on determining the offset in the DLL should work.
To find that unique section of code, disassemble the DLL using a disassembler that can show you the machine code in addition to the assembly language mnemonics (I can't think of anything that won't do that) and watch out for call and jmp instructions.
I actually had to do something similar once to apply a binary patch to a DOS exe; it was a bug fix, and the code wasn't under revision control so that was the only way to fix it.
I'd be really curious to know why you need this, by the way.
Upvotes: 0
Reputation: 29524
If the function you want isn't exported, then it won't be in the export address table. Assuming Visual Studio was used to produce this DLL and you have its associated PDB (program database) file, then you can use Microsoft's DIA (debug interface access) APIs to locate the desired function either by name or, approximately, by signature.
Once you have the function (symbol) from the PDB, you will also have its RVA (relative virtual address). You can add the RVA to the loaded module's base address to determine the absolute virtual address in memory where the function is stored. Then, you can make a function call through that address.
Alternatively, if this is just a one-off thing that you need to do (i.e. you don't need a programmatic solution), you can use windbg.exe in the Debugging Tools for Windows toolkit to attach to your process and discover the address of the function you care about. In WinDbg, you can use the x
command to "examine symbols" in a module.
For example, you can do x mymodule!*foo*
to see all functions whose name contains "foo". As long as you have symbols (PDB) loaded for your module, this will show you the non-export functions as well. Use .hh x
to get help on the x
command.
Upvotes: 3
Reputation: 3218
I'm afraid there are no "safe" way to do so if referred library does not explicitly export its object (class/func). Because you will have no idea where is the required object mapped in code memory.
However, by using RE tools, you can find offset for interested object within the library, then add it to any known exported object address to obtain the "real" memory location. After that, prepare a function prototype etc and cast into your local structure for usage.
Upvotes: 0