Flag: Tornado! Hurricane!

Blogs >> anonymouse's Blog

Created: Friday, June 8 2007 13:05.38 CDT  
Printer Friendly ...
Find Number of Arguments Of A Module.Function From Associated pdb
Author: anonymouse # Views: 14412

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












Blog Comments
MohammadHosein Posted: Friday, June 8 2007 13:46.24 CDT
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

smidgeonsoft Posted: Saturday, June 9 2007 08:52.45 CDT
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.

anonymouse Posted: Saturday, June 9 2007 11:21.24 CDT
[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



c1de0x Posted: Sunday, June 10 2007 06:45.19 CDT
anonymouse: thanks a lot mate. This is just what I was looking for.

smidgeon: MSDIA?

smidgeonsoft Posted: Sunday, June 10 2007 07:52.20 CDT
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.

c1de0x Posted: Monday, July 2 2007 02:46.32 CDT
anonymouse:

I keep getting an error ("Attempt to access invalid address") from my calls to SymFunctionTableAccess64.

Any idea what I'm doing wrong?

anonymouse Posted: Monday, July 2 2007 10:15.38 CDT
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




Add New Comment
Comment:









There are 31,316 total registered users.


Recently Created Topics
[help] Unpacking VMP...
Mar/12
Reverse Engineering ...
Jul/06
hi!
Jul/01
let 'IDAPython' impo...
Sep/24
set 'IDAPython' as t...
Sep/24
GuessType return une...
Sep/20
About retrieving the...
Sep/07
How to find specific...
Aug/15
How to get data depe...
Jul/07
Identify RVA data in...
May/06


Recent Forum Posts
Finding the procedur...
rolEYder
Question about debbu...
rolEYder
Identify RVA data in...
sohlow
let 'IDAPython' impo...
sohlow
How to find specific...
hackgreti
Problem with ollydbg
sh3dow
How can I write olly...
sh3dow
New LoadMAP plugin v...
mefisto...
Intel pin in loaded ...
djnemo
OOP_RE tool available?
Bl4ckm4n


Recent Blog Entries
halsten
Mar/14
Breaking IonCUBE VM

oleavr
Oct/24
Anatomy of a code tracer

hasherezade
Sep/24
IAT Patcher - new tool for ...

oleavr
Aug/27
CryptoShark: code tracer ba...

oleavr
Jun/25
Build a debugger in 5 minutes

More ...


Recent Blog Comments
nieo on:
Mar/22
IAT Patcher - new tool for ...

djnemo on:
Nov/17
Kernel debugger vs user mod...

acel on:
Nov/14
Kernel debugger vs user mod...

pedram on:
Dec/21
frida.github.io: scriptable...

capadleman on:
Jun/19
Using NtCreateThreadEx for ...

More ...


Imagery
SoySauce Blueprint
Jun 6, 2008

[+] expand

View Gallery (11) / Submit