anonymouse <any_anonymouse yahoo com> |
Friday, June 8 2007 13:05.38 CDT |
c1de0x asked how to find the paramenter count for a specific function here
https://www.openrce.org/forums/posts/496
windbg dot command fnent (.fnent) has an ability to find the number of params for a specific function if the associated pdb file was available
and i had also tried to under stand how it accomplishes it
by trying to debug windbg with ollydbg :)
but i got lost or rather pretty bored watching one single function (dbgeng.OutputFunctionEntry) executing about trillion instruction
i didnt want to deal with com i knew there must be a simple
function thats the core
so i had logged all the calls that dbgeng made to dbghelp
and then left it in limbo
after c1de0x asked i pasted that information to the thread
asotirov replied back in that thread psymfunctiontableaccess64() is the function that does all the grunt work behind this ability
i knew that was the only function that was called directly by dbgeng
so since the interest sparked again i though let me patch together a quick and dirty hack to see how this function works and to my delight it works pretty well :)
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
typedef PVOID (WINAPI *PSymFunctionTableAccess64)(
HANDLE hProcess,
DWORD64 AddrBase
);
typedef BOOL (WINAPI *PSymInitialize)(
HANDLE hProcess,
PCSTR UserSearchPath,
BOOL fInvadeProcess
);
typedef DWORD (WINAPI *PSymLoadModule)(
HANDLE hProcess,
HANDLE hFile,
PCSTR ImageName,
PCSTR ModuleName,
DWORD BaseOfDll,
DWORD SizeOfDll
);
typedef BOOL (WINAPI *PSymUnloadModule)(
HANDLE hProcess,
DWORD BaseOfDll
);
typedef BOOL (WINAPI *PSymCleanup)(
HANDLE hProcess
);
int main(int argc, char* argv[])
{
PSymFunctionTableAccess64 psymfunctiontableaccess64;
PSymInitialize psyminit;
PSymLoadModule psymloadmodule;
PSymUnloadModule psymunloadmodule;
PSymCleanup psymcleanup;
FPO_DATA *pfpodata;
HINSTANCE dbghlp_dll;
if ( argc != 3 )
{
printf( "Syntax: fnent <filename> <FunctionName>\n" );
return 1;
}
char * pszExeName = argv[1];
DWORD64 FunctionAddress;
FunctionAddress = (DWORD64)GetProcAddress(LoadLibrary(argv[1]),argv[2]);
HANDLE hProcess = 0;
dbghlp_dll = LoadLibrary("dbghelp.dll");
if(dbghlp_dll)
{
psyminit = (PSymInitialize) GetProcAddress(dbghlp_dll,"SymInitialize");
psymloadmodule = (PSymLoadModule) GetProcAddress(dbghlp_dll,"SymLoadModule");
psymunloadmodule = (PSymUnloadModule) GetProcAddress(dbghlp_dll,"SymUnloadModule");
psymcleanup = (PSymCleanup) GetProcAddress(dbghlp_dll,"SymCleanup");
psymfunctiontableaccess64 = (PSymFunctionTableAccess64) GetProcAddress(dbghlp_dll,"SymFunctionTableAccess64");
if((psyminit) && (psymloadmodule) && (psymunloadmodule) &&(psymcleanup) && (psymfunctiontableaccess64))
{
printf("dbghelp dll loaded and address retrieved\n");
}
else
{
printf("dbghelp loaded but get proc failed\n");
return 1;
}
}
else
{
printf("load lib failed\n");
return 1;
}
if ( !psyminit( hProcess, 0, FALSE ) )
{
printf( "SymInitialize failed\n" );
return 1;
}
DWORD dwModuleBase = psymloadmodule( hProcess, 0, pszExeName, 0, 0, 0 );
if ( !dwModuleBase )
{
printf( "SymLoadModuleFailed\n" );
return 1;
}
pfpodata = (FPO_DATA *)psymfunctiontableaccess64(0,FunctionAddress);
printf("pfpodata returned is %x\n",pfpodata);
if(pfpodata !=0)
{
printf("pfpodata->ulOffStart is %x\n",pfpodata->ulOffStart);
printf("pfpodata->cbProcSize is %x\n",pfpodata->cbProcSize);
printf("pfpodata->cdwLocals is %x\n",pfpodata->cdwLocals);
}
psymunloadmodule( hProcess, dwModuleBase );
psymcleanup( hProcess );
return 0;
}
test:/>fnent ntdll.dll ZwCreateFile
dbghelp dll loaded and address retrieved
pfpodata returned is 1140620
pfpodata->ulOffStart is 2595e
pfpodata->cbProcSize is f
pfpodata->cdwLocals is 0
test:/>
since this is a quick and dirty hack you would need the application and its pdb in the same directory as the executable
and there is no error checking of any kind in the code
also many casts may be absolutely crap :) like casting GetProc as DWORD64 :)
usage
compile this a cpp and run like this
fnent.exe module Functionname
anon , very valuable stuff , thanks .
now do you think there is a chance we could do more or less the same when pdb is not available but the binary contains debug info ? fact is i already know the answer but i'd like to read your comments on this too |
|
My utility, PEBrowse, employs two methods for extracting this information. If FPO data is present in the executable, it reads the OMAP records raw. Otherwise, it will fall back on MSDIA. You can use PEBrowse's Structure display to see how the OMAP records are organized in a binary. |
[quote]
now do you think there is a chance we could do more or less the same when pdb is not available but the binary contains debug info ?[/quote]
if you notice i have neither included dbghelp.h nor have typedeffed the FPO_DATA structure and this still seems to work
wonder why ?
thats because this FPO_DATA structure is defined in winnt.h
which gets included if we include <windows.h>
and im used a pretty outdated compiler and the header files that came with this compiler
created Tuesday, June 27, 2000, 5:01:00 AM
modified Tuesday, June 27, 2000, 5:01:00 AM
accessed Yesterday, June 08, 2007
say about 8 years old headers and they still work
the newest form of pdb viz PDB10 or RSDS signature probably didnt even exist by then
a seperate .dbg file or embedded .dbg information in executable or the old pdb format NB10 Signature
were probably the only available debug information
so my guess is as good as yours
it should be absolutely possible to extract the same information if you have an embedded debug information
in the executable
though i dont have an executable with embedded debug info atm if i lay my hands on one ill sure check it out
|
anonymouse: thanks a lot mate. This is just what I was looking for.
smidgeon: MSDIA?
|
|
MSDIA is Microsoft's published and preferred mechanism for accessing debug information. Documentation for this can be found usually in your VS.NET installation under the sub-directory "Visual Studio SDKs". It is a COM-based engine that shares a lot of code with DBGHELP. |
anonymouse:
I keep getting an error ("Attempt to access invalid address") from my calls to SymFunctionTableAccess64.
Any idea what I'm doing wrong? |
c1de0x,
the error you mention is not a part of dbghlp.dll
if i remember correct this error had something to do with ntvdm being misconfigured
anyway i grepped dbghlp before posting and the string isnt there
but i find that string is in kernel32.dll at .rsrc section
77EE368C %2....PAttempt to access invalid address.....PArithmetic resul
also consider scanning your system
i attached the source and binary to my repositary
see if that helps
copy of fnent.exe
|
|