Subversion Repositories DevTools

Rev

Rev 227 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
227 dpurdie 1
/*============================================================================
2
**
3
**    ERG TRANSIT SYSTEMS      Licensed software
4
**    (C) 2004                 All rights reserved
5
**
6
**============================================================================
7
**
8
**  Project/Product : TOOLS
9
**  Filename        : ShowDLLs.cpp
10
**  Author(s)       : DDP
11
**
12
**  Description     : Display DLLs required by a DLL or EXE
13
**
14
**
15
**  Information     :
16
**   Compiler       : ANSI C
17
**   Target         :
18
**
19
**
20
**  History         :
21
**   Date           Author  Description
22
**   -------------------------------------------------------------------------
23
**   10-Nov-04      DDP     Created
24
**==========================================================================*/
25
 
26
#include <windows.h>
27
#include <winnt.h>
28
#include <stdio.h>
29
#include <math.h>
30
#include <ctype.h>
31
#include  <io.h>
32
#include  <stdlib.h>
33
 
34
 
35
//----------------------------------------------------------------------------
36
//  A structure to hold information on each DLL discovered
37
//
38
typedef struct dlist
39
{
40
    struct dlist * next;
41
    char * name;
42
    char * path;
43
    bool   processed;
44
} dlist_t;
45
 
46
dlist_t *dlist = NULL;
47
 
48
//----------------------------------------------------------------------------
49
//  A structure to hold information on each PATH in which to locate DLLs
50
//
51
typedef struct plist
52
{
53
    struct plist * next;
54
    char * name;
55
} plist_t;
56
 
57
plist_t *plist = NULL;
58
plist_t *plist_last = NULL;
59
 
60
//----------------------------------------------------------------------------
61
//  Prototypes
62
//
63
void main(int argn,char ** argv);
64
void ShowHelp(void);
65
void ParseCmdLine(int argn,char ** argv);
66
void ReportAndExit(void);
67
void DisplayImageFile(void);
68
DWORD ConvertRVAtoFileOffset(DWORD rva);
69
DWORD MapRVA(DWORD rva);
70
void display_IMAGE_IMPORT_DIRECTORY(_IMAGE_DATA_DIRECTORY * pDDImport);
71
void AddUserDll( char * name );
72
void AddFoundDll( char * name );
73
void AddEnvPath ( void );
74
dlist_t *ProcessNextDll( void );
75
void ProcessFile ( char * name );
76
void PrintSummary( void );
77
void AddPath ( char * name );
78
 
79
 
80
//----------------------------------------------------------------------------
81
// Macros
82
//
83
#define CHECK(x) if(x) ReportAndExit();
84
 
85
//----------------------------------------------------------------------------
86
//  Globals
87
//
88
char * pfile;           // the address of the PE file in memory and
89
char * szfname;         // the files name
90
DWORD  cb;              // its size in bytes
91
int    verbose = 0;     // Debug support
92
 
93
 
94
//----------------------------------------------------------------------------
95
// FUNCTION           : main
96
//
97
// DESCRIPTION        : Main entry point
98
//
99
// INPUTS             : argn
100
//                      argv
101
//
102
// RETURNS            :
103
//
104
void main(int argn,char ** argv)
105
{
106
    dlist_t *dptr;
107
 
108
    /*
109
    **  check is help needs to be shown
110
    */
111
    if(argn == 1 || (argn ==2 && strcmp(argv[1],"/?")==0))
112
        ShowHelp();
113
 
114
    /*
115
    **  set all our global flags here
116
    */
117
    ParseCmdLine(argn-1,argv+1);
118
 
119
    /*
120
    **  Prime the paths to be searched
121
    */
122
    AddEnvPath();
123
 
124
    /*
125
    **  Let the magic will then happen.
126
    */
127
    while ( (dptr = ProcessNextDll()) )
128
    {
129
        ProcessFile ( dptr->path );
130
    }
131
 
132
    /*
133
    **  Display useful data to the user
134
    */
135
    PrintSummary();
136
 
137
}
138
 
139
//----------------------------------------------------------------------------
140
// FUNCTION           : ShowHelp
141
//
142
// DESCRIPTION        : Display basic help and exit
143
//
144
//
145
// INPUTS             : None
146
//
147
// RETURNS            : Does not return
148
//
149
void ShowHelp(void)
150
{
151
    printf("Locate DLLs required by a DLL or EXE\n");
152
    printf("Last update: " __DATE__ " "  __TIME__ "\n\n");
153
 
154
    printf("usage: ShowDlls  [options] <filename>\n\n");
155
    printf("\t-h        Display help\n");
156
    printf("\t-p path   Add Path to search list\n");
157
    printf("\t-v        Verbose operation\n");
158
 
159
    exit(1);
160
}
161
 
162
//----------------------------------------------------------------------------
163
// FUNCTION           : ParseCmdLine
164
//
165
// DESCRIPTION        : Extract user options from the command line
166
//
167
// INPUTS             : argn        - Number of arguments
168
//                      argv        - Array of arg pointers
169
//
170
// RETURNS            : Nothing
171
//
172
void ParseCmdLine(int argn,char ** argv)
173
{
174
    for(int i=0;i<argn;i++)
175
    {
176
        if(strcmp("-v",argv[i])==0)
177
        {
178
            verbose++;
179
        }
180
        else if ( strcmp("-p",argv[i])==0 )
181
        {
182
            if ( ++i >= argn )
183
            {
184
                printf( "Error: -p without a path\n" );
185
                exit(1) ;
186
            }
187
            AddPath( argv[i] );
188
        }
189
        else if ( strcmp("-h",argv[i])==0 )
190
        {
191
            ShowHelp();
192
        }
193
        else if ( strcmp("-",argv[i])==0 )
194
        {
195
            printf("Unknown Switch %s. Ignored.\n",argv[i]);
196
        }
197
        else
198
        {
199
            AddUserDll( argv[i] );
200
        }
201
    }
202
}
203
 
204
//----------------------------------------------------------------------------
205
// FUNCTION           : ReportAndExit
206
//
207
// DESCRIPTION        : Error Check and reporting
208
//
209
// INPUTS             : None
210
//
211
// RETURNS            : Does not return
212
//
213
void ReportAndExit(void)
214
{
215
    printf("Error:");
216
    //shamelessly copied from MSDN
217
    LPVOID lpMsgBuf;
218
    FormatMessage( 
219
        FORMAT_MESSAGE_ALLOCATE_BUFFER | 
220
        FORMAT_MESSAGE_FROM_SYSTEM | 
221
        FORMAT_MESSAGE_IGNORE_INSERTS,
222
        NULL,
223
        GetLastError(),
224
        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
225
        (LPTSTR) &lpMsgBuf,
226
        0,
227
        NULL 
228
    );
229
    // Display the string.
230
    printf((char *)lpMsgBuf);
231
    // Free the buffer.
232
    LocalFree( lpMsgBuf );  
233
 
234
    exit(1);
235
}
236
 
237
//----------------------------------------------------------------------------
238
// FUNCTION           : ConvertRVAtoFileOffset
239
//
240
// DESCRIPTION        : Given the RVA this function will calculate the file offset
241
//
242
// INPUTS             : rva     - An RVA
243
//
244
// RETURNS            : File offset
245
//
246
DWORD ConvertRVAtoFileOffset(DWORD rva)
247
{
248
    if(!rva)
249
    {
250
        return 0;
251
    }
252
 
253
    _IMAGE_DOS_HEADER * pDosH;
254
    _IMAGE_FILE_HEADER *    pCoffH;
255
    _IMAGE_OPTIONAL_HEADER * pOptH;
256
    _IMAGE_SECTION_HEADER *  pSecH;
257
 
258
    pDosH = (_IMAGE_DOS_HEADER *)pfile;
259
    pCoffH = (_IMAGE_FILE_HEADER *)((char *)pfile + pDosH->e_lfanew + 4);   //4 byte PE signature
260
    pOptH = (_IMAGE_OPTIONAL_HEADER *)((char *)pCoffH + sizeof(_IMAGE_FILE_HEADER)); //these lie one after the other
261
    pSecH = (_IMAGE_SECTION_HEADER *)((char *)pOptH + sizeof(_IMAGE_OPTIONAL_HEADER)); // ^
262
 
263
    for(int i = 0; i < pCoffH->NumberOfSections; i++ )
264
    {
265
        DWORD rvadiff = rva - pSecH[i].VirtualAddress;
266
        if( rvadiff >= 0 && rvadiff <= pSecH[i].SizeOfRawData)
267
        {
268
            return rvadiff + pSecH[i].PointerToRawData;
269
        }
270
    }
271
    return 0;
272
}
273
//----------------------------------------------------------------------------
274
// FUNCTION           : MapRVA
275
//
276
// DESCRIPTION        : Given an RVA this function will give the actually
277
//                      current memory location which is:
278
//                          file base address + file offset
279
//
280
// INPUTS             : rva     - RVA to convert
281
//
282
// RETURNS            : Mapped address
283
//
284
DWORD MapRVA(DWORD rva)
285
{
286
    if(!rva)
287
    {
288
        return 0;
289
    }
290
 
291
    return ((DWORD)pfile)+ConvertRVAtoFileOffset(rva);
292
}
293
 
294
//----------------------------------------------------------------------------
295
// FUNCTION           : DisplayImageFile
296
//
297
// DESCRIPTION        : Process an file
298
//                      The file has been mapped into memory
299
//                      Calculate file offsets for later processing
300
//
301
// INPUTS             : None
302
//
303
// RETURNS            : Nothing
304
//
305
void DisplayImageFile(void)
306
{
307
    _IMAGE_DOS_HEADER * pDosH;
308
    char *          pPESign;
309
    _IMAGE_FILE_HEADER *    pCoffH;
310
    _IMAGE_OPTIONAL_HEADER * pOptH;
311
    _IMAGE_DATA_DIRECTORY * pDDImport;
312
 
313
    /*
314
    **  Map various structures to locations inside the PE file
315
    **  The PE file is already memory mapped
316
    */
317
    pDosH = (_IMAGE_DOS_HEADER *)pfile;
318
    pPESign = pfile + pDosH->e_lfanew;
319
 
320
    if(!(   pPESign[0] == 'P' &&
321
        pPESign[1] == 'E' &&
322
        pPESign[2] == 0 &&
323
        pPESign[3] == 0 ))
324
    {
325
        printf("This is not a PE file according to the file signature\n");
326
        exit(1);
327
    }
328
 
329
    pCoffH = (_IMAGE_FILE_HEADER *)(pPESign + 4) ;  //4 byte PE signature
330
    pOptH = (_IMAGE_OPTIONAL_HEADER *)((char *)pCoffH + sizeof(_IMAGE_FILE_HEADER)); //these lie one after the other
331
    pDDImport = &(pOptH->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]);
332
 
333
    /*
334
    **  Extact data from the IMPORT DIRECTORY
335
    */
336
    display_IMAGE_IMPORT_DIRECTORY(pDDImport);
337
}
338
 
339
//----------------------------------------------------------------------------
340
// FUNCTION           : display_IMAGE_IMPORT_DIRECTORY
341
//
342
// DESCRIPTION        : Sacn the IMPORT directory and add any DLLs located
343
//                      to the list of DLLs used by the base EXE
344
//
345
// INPUTS             : pDDImport   Address of the Import Data
346
//
347
// RETURNS            :
348
//
349
// PRECONDITION       : The file has been memory mapped
350
//
351
void display_IMAGE_IMPORT_DIRECTORY(_IMAGE_DATA_DIRECTORY * pDDImport)
352
{
353
    if (verbose) printf("IMPORT DIRECTORY ENTRY: %s\n", szfname);
354
 
355
    if(pDDImport->VirtualAddress == 0)
356
    {
357
        if (verbose) printf("\tNo Import Table Present\n");
358
        return;
359
    }
360
 
361
    _IMAGE_IMPORT_DESCRIPTOR * pImpDesc = (_IMAGE_IMPORT_DESCRIPTOR *)MapRVA(pDDImport->VirtualAddress);
362
    while(pImpDesc->Characteristics)
363
    {
364
        if (verbose) printf("\tName = %#x --> \"%s\"\n",pImpDesc->Name,MapRVA(pImpDesc->Name));
365
        AddFoundDll( (char *) MapRVA(pImpDesc->Name) );
366
        pImpDesc++;
367
    }
368
}
369
 
370
//----------------------------------------------------------------------------
371
// FUNCTION           : ProcessFile
372
//
373
// DESCRIPTION        : Process one EXE or DLL file
374
//                      Examine the file for DLLs and add them to the list
375
//                      of discovered DLLs as we go
376
//
377
//
378
// INPUTS             : name    - Name of the file
379
//
380
// RETURNS            : Nothing
381
//
382
void ProcessFile ( char * name )
383
{
384
 
385
    /*
386
    ** open and memory map the named file
387
    */
388
    HANDLE hPE = CreateFile(name,GENERIC_READ,FILE_SHARE_READ,0,OPEN_EXISTING,0,0);
389
    CHECK(hPE == INVALID_HANDLE_VALUE);
390
    HANDLE hmPE = CreateFileMapping(hPE,0,PAGE_READONLY,0,0,"PEfile");
391
    CHECK(hmPE == 0);
392
 
393
    /*
394
    **  file address and size : there are assigned to globals
395
    */
396
    pfile = (char*)MapViewOfFile(hmPE,FILE_MAP_READ,0,0,0);
397
    CHECK(pfile == 0);
398
    cb = GetFileSize(hPE,0);
399
    szfname = name;
400
 
401
    /*
402
    **  at this point the file is opened and mapped to a memory location pointed
403
    **  to by 'pfile' and is valid for 'cb' bytes which is the file size          
404
    **  read the file and do what we want to                                      
405
    **
406
    */
407
    DisplayImageFile();
408
 
409
    /*
410
    **  close the open handles
411
    */
412
    CloseHandle(hPE);
413
    CloseHandle(hmPE);
414
 
415
}
416
 
417
 
418
//----------------------------------------------------------------------------
419
// FUNCTION           : AddPath
420
//
421
// DESCRIPTION        : Add a path to a linked list of paths
422
//                      New entries are added to the end of the list
423
//
424
//
425
// INPUTS             : name    - The path name to add
426
//
427
// RETURNS            : Nothing
428
//
429
void AddPath ( char * name )
430
{
431
    plist_t *ptr;
432
 
433
    /*
434
    **  Create a new entry and insert information
435
    */
436
    ptr = (plist_t *)malloc( sizeof(plist_t) );
437
    memset( (void *)ptr, 0, sizeof( *ptr));
438
 
439
    ptr->name = (char *)malloc(strlen(name)+1);
440
    strcpy( ptr->name, name );
441
 
442
    /*
443
    **  Add entry to the END of the list to preserve search order
444
    */
445
    if ( plist_last )
446
    {
447
        plist_last->next = ptr;
448
    }
449
    plist_last = ptr;
450
    if ( ! plist )
451
    {
452
        plist = ptr;
453
    }
454
 
455
    if (verbose > 1) printf ("Adding Path: %s\n", name);
456
}
457
 
458
//----------------------------------------------------------------------------
459
// FUNCTION           : AddEnvPath
460
//
461
// DESCRIPTION        : Add the users PATH to the list of seach paths
462
//                      This is done to prime the search path
463
//
464
//
465
// INPUTS             : None
466
//
467
// RETURNS            : Nothing
468
//
469
void AddEnvPath ( void )
470
{
471
    char *path;
472
    char *next;
473
 
474
    /*
475
    **  Extract the path from the environment
476
    */
477
    if ( (path = getenv( "PATH" )) == NULL )
478
    {
479
        return;
480
    }
481
 
482
    /*
483
    **  Extract ';' substrings from the path and add them to the
484
    **  list of paths for later searching
485
    */
287 dpurdie 486
    if (verbose > 2) printf ("Raw Path: %s\n", path);
227 dpurdie 487
    while ( *path )
488
    {
489
        next = strchr( path, ';' );
490
        if ( next )
491
        {
492
            *next = 0;
493
        }
494
        AddPath( path );
495
 
496
        if ( !next )
497
        {
498
            break;
499
        }
500
        path = next + 1;
501
    }
502
}
503
 
504
//----------------------------------------------------------------------------
505
// FUNCTION           : AddUserDll
506
//
507
// DESCRIPTION        : Add the initial user DLL to the list of EXE/DLLs to
508
//                      process. If the user has specified an absolute path
509
//                      then use the path as a part of the search path.
510
//
511
//
512
// INPUTS             : namep       - Pointer to the DLL's name
513
//
514
// RETURNS            :
515
//
516
void AddUserDll( char * name )
517
{
518
    dlist_t *dptr;
519
    char *ptr;
520
    char *path = NULL;
521
    char *name_ptr = NULL;
522
 
523
    if ( verbose )
524
        printf("AddUserDll: %s\n", name );
525
 
526
    /*
527
    **  Allow for '/' and '\' and locate the last '\' in the string
528
    */
529
    for ( ptr = name; *ptr; ptr++)
530
    {
531
        if ( *ptr == '/' )
532
            *ptr = '\\';
533
 
534
        if ( *ptr == '\\' )
535
            name_ptr = ptr;
536
    }
537
 
538
    /*
539
    **  Split into path and name
540
    */
541
    if ( name_ptr )
542
    {
543
        if (verbose > 1) printf( "Absolute path detected\n");
544
 
545
        path = (char *)malloc( name_ptr - name + 1 );
546
        path[0] = 0;
547
 
548
        strncat(path, name, name_ptr - name );
549
        name = name_ptr + 1;
550
    }
551
    else
552
    {
553
        path = ".";
554
    }
555
 
556
    /*
557
    **  Scan the list of existing source dirs
558
    */
559
    dptr = dlist;
560
    while ( dptr )
561
    {
562
        if ( strcmp ( dptr->name, name ) == 0 )
563
            return;
564
 
565
        dptr = dptr->next;
566
    }
567
 
568
    /*
569
    **  Entry not found
570
    **  Create a new one and insert information
571
    */
572
    dptr = (dlist_t *)malloc( sizeof(dlist_t) );
573
    memset( (void *)dptr, 0, sizeof( *dptr));
574
 
575
    dptr->next = dlist;
576
    dlist = dptr;
577
 
578
    dptr->name = (char *)malloc(strlen(name)+1);
579
    strcpy( dptr->name, name );
580
 
581
    if (verbose > 1) printf ("Adding: %s\n", name);
582
 
583
    /*
584
    **  Add the source path to the DLL to the search list
585
    */
586
    AddPath ( path );
587
}
588
 
589
//----------------------------------------------------------------------------
590
// FUNCTION           : AddFoundDll
591
//
592
// DESCRIPTION        : Add a new DLL to a list of DLL's
593
//                      If the DLL is already in the list just skip it.
594
//
595
//
596
// INPUTS             : namep       - Pointer to the DLL's name
597
//
598
// RETURNS            :
599
//
600
void AddFoundDll( char * name )
601
{
602
    dlist_t *dptr;
603
 
604
    if ( verbose )
605
        printf("AddFoundDll: %s\n", name );
606
 
607
    /*
608
    **  Scan the list of existing source dirs
609
    */
610
    dptr = dlist;
611
    while ( dptr )
612
    {
613
        if ( strcmp ( dptr->name, name ) == 0 )
614
            return;
615
 
616
        dptr = dptr->next;
617
    }
618
 
619
    /*
620
    **  Entry not found
621
    **  Create a new one and insert information
622
    */
623
    dptr = (dlist_t *)malloc( sizeof(dlist_t) );
624
    memset( (void *)dptr, 0, sizeof( *dptr));
625
 
626
    dptr->next = dlist;
627
    dlist = dptr;
628
 
629
    dptr->name = (char *)malloc(strlen(name)+1);
630
    strcpy( dptr->name, name );
631
 
632
    if (verbose > 1) printf ("Adding: %s\n", name);
633
}
634
 
635
 
636
//----------------------------------------------------------------------------
637
// FUNCTION           : ProcessNextDll
638
//
639
// DESCRIPTION        : Locate the next DLL to explore
640
//
641
//
642
// INPUTS             : None
643
//
644
// RETURNS            : A pointer to a DLL entry to process
645
//                      The entry will have a full path attached
646
//
647
 
648
dlist_t *ProcessNextDll( void )
649
{
650
    dlist_t *dptr;
651
    plist_t *pptr;
652
 
653
    for ( ; ; )
654
    {
655
        /*
656
        **  Scan the list of existing source dirs
657
        */
658
        for ( dptr = dlist; dptr ; dptr = dptr->next)
659
        {
660
            if ( ! dptr->processed )
661
            {
662
                break;
663
            }
664
        }
665
 
666
        /*
667
        **  Exit if we do not have any more DLLs to process
668
        */
669
        if ( ! dptr )
670
        {
671
            return NULL;
672
        }
673
 
674
        /*
675
        **  Mark the entry as processed
676
        **  If we don't find the path to the DLL then the path will be left as
677
        **  NULL, but the entry will still have been processed
678
        */
679
        dptr->processed = TRUE;
680
 
681
        /*
682
        **  Locate the DLL in the users PATH and other specified directories
683
        */
684
        for ( pptr = plist; pptr; pptr = pptr->next )
685
        {
686
            int plen = strlen( dptr->name ) + 1 + strlen( pptr->name ) + 1;
687
            char *buf = (char *)malloc( plen );
688
 
689
            /*
690
            **  Create the name of the file
691
            */
692
            _snprintf( buf, plen, "%s\\%s", pptr->name, dptr->name );
693
 
694
 
695
            /*
696
            **  Attempt to open it
697
            */
698
            if (verbose > 2) printf( "Looking for: %s\n", buf );
699
            if ( _access ( buf, 0 ) != -1 )
700
            {
701
                /*
702
                **  File does exist
703
                **  Add the path information to the entry
704
                */
705
                dptr->path = buf;
706
                if (verbose > 1) printf( "   FOUND: %s\n", buf );
707
                return dptr;
708
            }
709
        }
710
 
711
        /*
712
        **  File not found
713
        **  Try another
714
        */
715
    }
716
}
717
 
718
//----------------------------------------------------------------------------
719
// FUNCTION           : PrintSummary
720
//
721
// DESCRIPTION        : Display summary information on DLLs discovered
722
//
723
//
724
// INPUTS             : None
725
//
726
// RETURNS            : Nothing
727
//
728
void PrintSummary( void )
729
{
730
    dlist_t *dptr;
731
 
732
    for ( dptr = dlist; dptr ; dptr = dptr->next)
733
    {
734
        printf( "%30s", dptr->name );
735
        if ( dptr->path )
736
        {
737
            printf( " : %s\n", dptr->path );
738
        }
739
        else
740
        {
741
            printf( " : NOT FOUND\n");
742
        }
743
    }
744
}
745