OVH Cloud OVH Cloud

[Debugging] LOAD_DLL_DEBUG_INFO

15 réponses
Avatar
TigrouMeow
Bonjour,

J'aimerais connaitre les DLL utilisés par certains exécutables, pour cela
je m'attache à l'exe en tant que debugger et je fouine LOAD_DLL_DEBUG_INFO
quand je reçois un message de debug pour ça.

Par contre dans cette structure impossible de chopper le nom de la dll
ou du fichier ! Comment faire simplement?

Merci beaucoup !

--
Meow ;o)

10 réponses

1 2
Avatar
Olivier Huet
Bonjour,


TigrouMeow a écrit :
Bonjour,

J'aimerais connaitre les DLL utilisés par certains exécutables, pour cela
je m'attache à l'exe en tant que debugger et je fouine LOAD_DLL_DEBUG_INFO
quand je reçois un message de debug pour ça.

Par contre dans cette structure impossible de chopper le nom de la dll
ou du fichier ! Comment faire simplement?




Tu devrais lire le livre "Debugging Applications for Microsoft® .NET and
Microsoft Windows®", de John Robbins.


Je n'ai pas regardé super en détail, mais je crois que ce bout de code
issu du code associé à son bouquin te correspond (en principe on peut
réutiliser son code, alors j'espère que je ne commet pas d'infraction en
le postant :-) ) :

Sur réception de LOAD_DLL_DEBUG_EVENT, il fait :


static
DWORD LoadDllDebugEvent ( CDebugBaseUser * pUserClass ,
LPDEBUGGEEINFO pData ,
LPDEBUG_EVENT pDE )
{
TCHAR szDLLName[ MAX_PATH ] ;
szDLLName[ 0 ] = _T ( '' ) ;

BOOL bRet = TRUE ;

// If NTDLL.DLL has not come in, in essense this is the first
// DLL into the process, I can't look into the debuggee to get
// the full path. NTDLL.DLL is special and on W2K, the value
// passed in the lpImageName just points to zero. On XP, it
// points to just "ntdll.dll" so I need to hunt it down.
if ( FALSE == pData->GetSeenNTDLLLoad ( ) )
{
// Mark that I've seen it.
pData->SetSeenNTDLLLoad ( ) ;

// As I am debugging locally, get the Windows directory.
UINT uiLen = GetWindowsDirectory ( szDLLName , MAX_PATH ) ;
ASSERT ( uiLen > 0 ) ;

// Whack on the backslash.
szDLLName[ uiLen ] = _T ( '' ) ;
uiLen++ ;
szDLLName[ uiLen ] = _T ( '' ) ;

_tcscpy ( szDLLName + uiLen , _T ( "NTDLL.DLL" ) ) ;
}
else
{
// The value in lpImageName is a pointer to the full path
// and name of the DLL being loaded. The address is in the
// debuggee address space.
LPCVOID lpPtr = 0 ;
DWORD dwBytesRead = 0 ;
HANDLE hProcess = pData->GetProcessHandle ( ) ;

bRet = DBG_ReadProcessMemory ( hProcess ,
pDE->u.LoadDll.lpImageName ,
&lpPtr ,
sizeof ( LPCVOID ) ,
&dwBytesRead ) ;
ASSERT ( TRUE == bRet ) ;
if ( ( TRUE == bRet ) && ( 0 != lpPtr ) )
{
// If the name in the debuggee is UNICODE, I can read it
// directly into the szDLLName variable as all this code
// is UNICODE.
if ( TRUE == pDE->u.LoadDll.fUnicode )
{
// Occasionally, you can't read the whole buffer that
// contains the name so I need to step down until
// I can be sure there's no name at all.
DWORD dwSize = MAX_PATH * sizeof ( TCHAR ) ;
do
{

bRet = DBG_ReadProcessMemory ( hProcess ,
lpPtr ,
szDLLName ,
dwSize ,
&dwBytesRead ) ;
dwSize = dwSize - 20 ;
}
while ( ( FALSE == bRet ) && ( dwSize > 20 ) ) ;
}
else
{
// Read the ANSI string and convert it to UNICODE.
char szAnsiName[ MAX_PATH ] ;
bRet = DBG_ReadProcessMemory ( hProcess ,
lpPtr ,
szAnsiName ,
MAX_PATH ,
&dwBytesRead ) ;
ASSERT ( TRUE == bRet ) ;
if ( TRUE == bRet )
{
BSUAnsi2Wide ( szAnsiName , szDLLName , MAX_PATH ) ;
}
}
}
}
// If I could not get the DLL name, I'll resort to seeing if get it
// with GetModuleFileNameEx. If that can't get it. We've got
// trouble in River City. Interestingly, you can't use
// GetModuleFileNameEx except if the above fails. What you're
// seeing if you can't get the filename is a rebased DLL.
if ( _T ( '' ) == szDLLName[ 0 ] )
{
DWORD dwRet GetModuleFileNameEx ( pData->GetProcessHandle ( ) ,
(HMODULE)pDE->u.LoadDll.lpBaseOfDll ,
szDLLName ,
MAX_PATH ) ;
if ( 0 == dwRet )
{
// Fill the final DLL name with something.
_tcscpy ( szDLLName ,
_T ( "UNABLE TO EXTRACT DLL NAME!!" ) ) ;
}
}

// Upper case the name as that's the way I like it (uuh, uuh).
_tcsupr ( szDLLName ) ;

IMAGEHLP_MODULE64 stModInfo ;

// Load the module into the symbol engine.
pData->SymLoadModule ( pDE->u.LoadDll.hFile ,
szDLLName ,
pDE->u.LoadDll.lpBaseOfDll ) ;

FillModuleInfo ( pData , pDE->u.LoadDll.lpBaseOfDll , &stModInfo );

DWORD dwRet = pUserClass->LoadDllEvent ( pDE->dwProcessId ,
pDE->dwThreadId ,
pDE->u.LoadDll ,
szDLLName ,
stModInfo ) ;

return ( dwRet ) ;
}


Bonne chance !
Olivier Huet
Avatar
yarocco
Olivier Huet wrote:

Arg, ne prononce pas le nom de ce langage dans un thread où il est question
de debugging !! :-)

Désolé, mais moi aussi je suis alergique - la dernière fois que je l'ai
utilisé c'est certe un peu vieux (la dernière version sous Win16), mais
c'était vraiment une horreur : un cauchemar !!!
Olivier Huet





Bon, je viens ajouter ma couche :)

J'ai appris a programmer (si on peut dire ca) avec Delphi et je trouve
vraiment qu'il est super meme si justement on fait des choses enormes
sans rien comprendre ce qui rend les questions des debutants vraiments
stupides dans le sens que quelqu'un qui voit les rouages mis en place ne
serait que pour creer la fenetre principale d'une appli pensera autrement.
Bref, apres quelques annees(j'ai commence avec D2, puis D5 juska la 7),
je le trouve pas mal du tout. Juste quelques gros defauts qui je pense
ne seront jamais corriges :
-Taille des exe
-optimisation de la VCL et RTL
et quelques autres mais moins importants (que je n'ai pas en tete :)).
Sinon, niveau debug, je le trouve pas mauvais du tout justement, il y a
une fenetre CPU (registres + desassembleur) avec une correspondance
entre ASM et code delphi (ca sert quand on comprend pas trop l'ASM), des
"watches", bref ce que je demande a un debugger :)
Il est vrai que je ne l'emploi pas completement (toute la partie
internet par exemple) et donc je ne connais pas reellement ses limites,
cependant je trouve qu'il permet deja de faire au moins autant qu'en
C/C++ (excepte pour les drivers mais je m'y suis pas encore plonge non
plus...). Quand au BASM (ASM integre), je trouve ca pas mal du tout car
ca permet d'approcher l'assembleur plutot dooucement (on garde le code
"interace" en Delphi et on met du BASM pour les parties critiques ou
simplements les procedures). J'ai procede ainsi et je sais qu'etant
maintenant completement en ASM, ca m'a facilite la chose (experience
personnelle mais qui je pense peut se generaliser).
Enfin, tout ca pour dire que Delphi est quand meme un outil et un
langage assez puissant qui n'a vraiment rien a voir avec VB et qui, je
pense, n'a pas grand chose a envier au C/C++ (et ses compilos).
Avatar
Vincent Burel
"TigrouMeow" wrote in message
news:423d9ce2$0$22781$
Bonjour,

J'aimerais connaitre les DLL utilisés par certains exécutables, pour cela
je m'attache à l'exe en tant que debugger et je fouine LOAD_DLL_DEBUG_INFO
quand je reçois un message de debug pour ça.

Par contre dans cette structure impossible de chopper le nom de la dll
ou du fichier ! Comment faire simplement?

Merci beaucoup !



si le but est seulement de connaitre les DLL liés à un exe, utilisez donc le
dependency walker , livré avec VC (program tool : "depends"... ) ... vous
pourrez même voir les fonctions des DLL utilisées... magique ? non, tout
cela doit être dans le PE de l'executable en toute rigueur, suffit
d'interpréter le PE. Et ca c'est super facile, puisque même AMcD y arrive
:-)

VB
Avatar
TigrouMeow
"Vincent Burel" a écrit dans le message de
news: 423e9ccf$0$19348$

"TigrouMeow" wrote in message
news:423d9ce2$0$22781$
Bonjour,

J'aimerais connaitre les DLL utilisés par certains exécutables, pour cela
je m'attache à l'exe en tant que debugger et je fouine
LOAD_DLL_DEBUG_INFO
quand je reçois un message de debug pour ça.

Par contre dans cette structure impossible de chopper le nom de la dll
ou du fichier ! Comment faire simplement?

Merci beaucoup !



si le but est seulement de connaitre les DLL liés à un exe, utilisez donc
le
dependency walker , livré avec VC (program tool : "depends"... ) ... vous
pourrez même voir les fonctions des DLL utilisées... magique ? non, tout
cela doit être dans le PE de l'executable en toute rigueur, suffit
d'interpréter le PE. Et ca c'est super facile, puisque même AMcD y arrive
:-)



En fait, je dois absolument connaitre le chargement et déchargement des DLL
utilisés par le programme... par exemple quand on ouvre la boite de dialogue
MFC de l'ouverture de fichier, il y a 5 DLL qui se chargent et à la
fermeture
elles se ferment.
Avatar
TigrouMeow
"Olivier Huet" a écrit dans le message
de news: 423de176$0$837$
Bonjour,

TigrouMeow a écrit :
Bonjour,

J'aimerais connaitre les DLL utilisés par certains exécutables, pour cela
je m'attache à l'exe en tant que debugger et je fouine
LOAD_DLL_DEBUG_INFO
quand je reçois un message de debug pour ça.

Par contre dans cette structure impossible de chopper le nom de la dll
ou du fichier ! Comment faire simplement?




Tu devrais lire le livre "Debugging Applications for Microsoft® .NET and
Microsoft Windows®", de John Robbins.


Je n'ai pas regardé super en détail, mais je crois que ce bout de code
issu du code associé à son bouquin te correspond (en principe on peut
réutiliser son code, alors j'espère que je ne commet pas d'infraction en
le postant :-) ) :

Sur réception de LOAD_DLL_DEBUG_EVENT, il fait :


static
DWORD LoadDllDebugEvent ( CDebugBaseUser * pUserClass ,
LPDEBUGGEEINFO pData ,
LPDEBUG_EVENT pDE )
{
TCHAR szDLLName[ MAX_PATH ] ;
szDLLName[ 0 ] = _T ( '' ) ;

BOOL bRet = TRUE ;

// If NTDLL.DLL has not come in, in essense this is the first
// DLL into the process, I can't look into the debuggee to get
// the full path. NTDLL.DLL is special and on W2K, the value
// passed in the lpImageName just points to zero. On XP, it
// points to just "ntdll.dll" so I need to hunt it down.
if ( FALSE == pData->GetSeenNTDLLLoad ( ) )
{
// Mark that I've seen it.
pData->SetSeenNTDLLLoad ( ) ;

// As I am debugging locally, get the Windows directory.
UINT uiLen = GetWindowsDirectory ( szDLLName , MAX_PATH ) ;
ASSERT ( uiLen > 0 ) ;

// Whack on the backslash.
szDLLName[ uiLen ] = _T ( '' ) ;
uiLen++ ;
szDLLName[ uiLen ] = _T ( '' ) ;

_tcscpy ( szDLLName + uiLen , _T ( "NTDLL.DLL" ) ) ;
}
else
{
// The value in lpImageName is a pointer to the full path
// and name of the DLL being loaded. The address is in the
// debuggee address space.
LPCVOID lpPtr = 0 ;
DWORD dwBytesRead = 0 ;
HANDLE hProcess = pData->GetProcessHandle ( ) ;

bRet = DBG_ReadProcessMemory ( hProcess ,
pDE->u.LoadDll.lpImageName ,
&lpPtr ,
sizeof ( LPCVOID ) ,
&dwBytesRead ) ;
ASSERT ( TRUE == bRet ) ;
if ( ( TRUE == bRet ) && ( 0 != lpPtr ) )
{
// If the name in the debuggee is UNICODE, I can read it
// directly into the szDLLName variable as all this code
// is UNICODE.
if ( TRUE == pDE->u.LoadDll.fUnicode )
{
// Occasionally, you can't read the whole buffer that
// contains the name so I need to step down until
// I can be sure there's no name at all.
DWORD dwSize = MAX_PATH * sizeof ( TCHAR ) ;
do
{

bRet = DBG_ReadProcessMemory ( hProcess ,
lpPtr ,
szDLLName ,
dwSize ,
&dwBytesRead ) ;
dwSize = dwSize - 20 ;
}
while ( ( FALSE == bRet ) && ( dwSize > 20 ) ) ;
}
else
{
// Read the ANSI string and convert it to UNICODE.
char szAnsiName[ MAX_PATH ] ;
bRet = DBG_ReadProcessMemory ( hProcess ,
lpPtr ,
szAnsiName ,
MAX_PATH ,
&dwBytesRead ) ;
ASSERT ( TRUE == bRet ) ;
if ( TRUE == bRet )
{
BSUAnsi2Wide ( szAnsiName , szDLLName , MAX_PATH ) ;
}
}
}
}
// If I could not get the DLL name, I'll resort to seeing if get it
// with GetModuleFileNameEx. If that can't get it. We've got
// trouble in River City. Interestingly, you can't use
// GetModuleFileNameEx except if the above fails. What you're
// seeing if you can't get the filename is a rebased DLL.
if ( _T ( '' ) == szDLLName[ 0 ] )
{
DWORD dwRet > GetModuleFileNameEx ( pData->GetProcessHandle ( ) ,
(HMODULE)pDE->u.LoadDll.lpBaseOfDll ,
szDLLName ,
MAX_PATH ) ;
if ( 0 == dwRet )
{
// Fill the final DLL name with something.
_tcscpy ( szDLLName ,
_T ( "UNABLE TO EXTRACT DLL NAME!!" ) ) ;
}
}

// Upper case the name as that's the way I like it (uuh, uuh).
_tcsupr ( szDLLName ) ;

IMAGEHLP_MODULE64 stModInfo ;

// Load the module into the symbol engine.
pData->SymLoadModule ( pDE->u.LoadDll.hFile ,
szDLLName ,
pDE->u.LoadDll.lpBaseOfDll ) ;

FillModuleInfo ( pData , pDE->u.LoadDll.lpBaseOfDll , &stModInfo );

DWORD dwRet = pUserClass->LoadDllEvent ( pDE->dwProcessId ,
pDE->dwThreadId ,
pDE->u.LoadDll ,
szDLLName ,
stModInfo ) ;

return ( dwRet ) ;
}



Ca c'est du gros code ! Et apparemment il prévoit tous les cas, car d'un
système
à l'autre la manière de récupérer le nom de la DLL n'est à priori pas le
même !
En fait moi j'ai réussi à récupérer son nom en effectuant un MapViewOfFile
et
GetMappedFileName. C'est le code le moins bourrin que j'ai trouvé à faire.

Par contre j'aurais bien aimé ce code (car c'est sur que le mien sous
Windows
95 ne passera pas et renverra rien), mais je sais pas du tout à quoi
correspond
CDebugBaseUser ?
Avatar
AMcD®
Vincent Burel wrote:

Et ca
c'est super facile, puisque même AMcD y arrive :-)



N'insiste pas, je suis en grève pendant quelque temps. Pour les questions
techniques, s'adresser aux gros cadors super-pro, tu sais, ceux qui font
tout avec Delphi là. Comment, ils passent pas souvent ? Ha ben mince alors.
Prononce le mot Delphi, ils viendront au moins t'insulter.

Désolé mais je n'ai pas apprécié qu'on me traite d'intégriste, de raciste et
d'ayatollah. Je n'ai toujours pas reçu d'excuse. Alors, pour tout ce qui est
debugging, driver, PE, etc. regardez la doc de Delphi, ça doit bien y être
dedans voyons...

--
AMcD®

http://arnold.mcdonald.free.fr/
Avatar
Vincent Burel
"TigrouMeow" wrote in message
news:423e9ece$0$21811$
En fait, je dois absolument connaitre le chargement et déchargement des


DLL
utilisés par le programme... par exemple quand on ouvre la boite de


dialogue
MFC de l'ouverture de fichier, il y a 5 DLL qui se chargent et à la
fermeture
elles se ferment.



Ha pour les DLL dynamiquement chargés, lors de l'exécution du program, faut
faire autrement... Par exemple vous loadez votre appli dans VC++ et vous la
lancez (F5), le debugger se mettra en route automatiquement, la liste des
DLL chargé s'affiche dans la VIEW / OUTPUT.

VB
Avatar
TigrouMeow
"Vincent Burel" a écrit dans le message de
news: 423eb123$0$19338$

"TigrouMeow" wrote in message
news:423e9ece$0$21811$
En fait, je dois absolument connaitre le chargement et déchargement des


DLL
utilisés par le programme... par exemple quand on ouvre la boite de


dialogue
MFC de l'ouverture de fichier, il y a 5 DLL qui se chargent et à la
fermeture
elles se ferment.



Ha pour les DLL dynamiquement chargés, lors de l'exécution du program,
faut
faire autrement... Par exemple vous loadez votre appli dans VC++ et vous
la
lancez (F5), le debugger se mettra en route automatiquement, la liste des
DLL chargé s'affiche dans la VIEW / OUTPUT.



Oui je sais bien mais je veux que ça soit MON programme qui le fasse, et
non pas Visual Studio :)
Avatar
Vincent Burel
"AMcD®" wrote in message
news:423eae06$0$22843$
Vincent Burel wrote:

Désolé mais je n'ai pas apprécié qu'on me traite d'intégriste, de raciste


et
d'ayatollah. Je n'ai toujours pas reçu d'excuse.



ha ouai... tu es sur que ces insultes infames t'étaient adressées
personnellement . Ca m'étonne beaucoup qu'un autre programmeur adopte un tel
comportement envers toi. D'ailleurs ca ne se fait pas du tout dans cette
profession où respect mutuel, rigueur et honnèteté intellectuel sont les
pilliers fondateurs :-).

VB
Avatar
Olivier Huet
Bonjour,


"TigrouMeow" wrote in message
news:423e9f87$0$21827$
Par contre j'aurais bien aimé ce code (car c'est sur que le mien sous
Windows
95 ne passera pas et renverra rien), mais je sais pas du tout à quoi
correspond
CDebugBaseUser ?



Heu en fait je ne suis pas tout à fait sûr que tout son code passe sous 95 :
au début il dit qu'il le garantit pour les windows de la famille NT.

Sinon je crois que CDebugBaseUser correspond à sa classe de base pour ce qui
gère l'interface utilisateur : je ne crois pas qu'il y mette du métier
(après survol rapide :-) )


Olivier Huet
1 2