Subversion Repositories DevTools

Rev

Go to most recent revision | Details | 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
    */
486
    while ( *path )
487
    {
488
        next = strchr( path, ';' );
489
        if ( next )
490
        {
491
            *next = 0;
492
        }
493
        AddPath( path );
494
 
495
        if ( !next )
496
        {
497
            break;
498
        }
499
        path = next + 1;
500
    }
501
}
502
 
503
//----------------------------------------------------------------------------
504
// FUNCTION           : AddUserDll
505
//
506
// DESCRIPTION        : Add the initial user DLL to the list of EXE/DLLs to
507
//                      process. If the user has specified an absolute path
508
//                      then use the path as a part of the search path.
509
//
510
//
511
// INPUTS             : namep       - Pointer to the DLL's name
512
//
513
// RETURNS            :
514
//
515
void AddUserDll( char * name )
516
{
517
    dlist_t *dptr;
518
    char *ptr;
519
    char *path = NULL;
520
    char *name_ptr = NULL;
521
 
522
    if ( verbose )
523
        printf("AddUserDll: %s\n", name );
524
 
525
    /*
526
    **  Allow for '/' and '\' and locate the last '\' in the string
527
    */
528
    for ( ptr = name; *ptr; ptr++)
529
    {
530
        if ( *ptr == '/' )
531
            *ptr = '\\';
532
 
533
        if ( *ptr == '\\' )
534
            name_ptr = ptr;
535
    }
536
 
537
    /*
538
    **  Split into path and name
539
    */
540
    if ( name_ptr )
541
    {
542
        if (verbose > 1) printf( "Absolute path detected\n");
543
 
544
        path = (char *)malloc( name_ptr - name + 1 );
545
        path[0] = 0;
546
 
547
        strncat(path, name, name_ptr - name );
548
        name = name_ptr + 1;
549
    }
550
    else
551
    {
552
        path = ".";
553
    }
554
 
555
    /*
556
    **  Scan the list of existing source dirs
557
    */
558
    dptr = dlist;
559
    while ( dptr )
560
    {
561
        if ( strcmp ( dptr->name, name ) == 0 )
562
            return;
563
 
564
        dptr = dptr->next;
565
    }
566
 
567
    /*
568
    **  Entry not found
569
    **  Create a new one and insert information
570
    */
571
    dptr = (dlist_t *)malloc( sizeof(dlist_t) );
572
    memset( (void *)dptr, 0, sizeof( *dptr));
573
 
574
    dptr->next = dlist;
575
    dlist = dptr;
576
 
577
    dptr->name = (char *)malloc(strlen(name)+1);
578
    strcpy( dptr->name, name );
579
 
580
    if (verbose > 1) printf ("Adding: %s\n", name);
581
 
582
    /*
583
    **  Add the source path to the DLL to the search list
584
    */
585
    AddPath ( path );
586
}
587
 
588
//----------------------------------------------------------------------------
589
// FUNCTION           : AddFoundDll
590
//
591
// DESCRIPTION        : Add a new DLL to a list of DLL's
592
//                      If the DLL is already in the list just skip it.
593
//
594
//
595
// INPUTS             : namep       - Pointer to the DLL's name
596
//
597
// RETURNS            :
598
//
599
void AddFoundDll( char * name )
600
{
601
    dlist_t *dptr;
602
 
603
    if ( verbose )
604
        printf("AddFoundDll: %s\n", name );
605
 
606
    /*
607
    **  Scan the list of existing source dirs
608
    */
609
    dptr = dlist;
610
    while ( dptr )
611
    {
612
        if ( strcmp ( dptr->name, name ) == 0 )
613
            return;
614
 
615
        dptr = dptr->next;
616
    }
617
 
618
    /*
619
    **  Entry not found
620
    **  Create a new one and insert information
621
    */
622
    dptr = (dlist_t *)malloc( sizeof(dlist_t) );
623
    memset( (void *)dptr, 0, sizeof( *dptr));
624
 
625
    dptr->next = dlist;
626
    dlist = dptr;
627
 
628
    dptr->name = (char *)malloc(strlen(name)+1);
629
    strcpy( dptr->name, name );
630
 
631
    if (verbose > 1) printf ("Adding: %s\n", name);
632
}
633
 
634
 
635
//----------------------------------------------------------------------------
636
// FUNCTION           : ProcessNextDll
637
//
638
// DESCRIPTION        : Locate the next DLL to explore
639
//
640
//
641
// INPUTS             : None
642
//
643
// RETURNS            : A pointer to a DLL entry to process
644
//                      The entry will have a full path attached
645
//
646
 
647
dlist_t *ProcessNextDll( void )
648
{
649
    dlist_t *dptr;
650
    plist_t *pptr;
651
 
652
    for ( ; ; )
653
    {
654
        /*
655
        **  Scan the list of existing source dirs
656
        */
657
        for ( dptr = dlist; dptr ; dptr = dptr->next)
658
        {
659
            if ( ! dptr->processed )
660
            {
661
                break;
662
            }
663
        }
664
 
665
        /*
666
        **  Exit if we do not have any more DLLs to process
667
        */
668
        if ( ! dptr )
669
        {
670
            return NULL;
671
        }
672
 
673
        /*
674
        **  Mark the entry as processed
675
        **  If we don't find the path to the DLL then the path will be left as
676
        **  NULL, but the entry will still have been processed
677
        */
678
        dptr->processed = TRUE;
679
 
680
        /*
681
        **  Locate the DLL in the users PATH and other specified directories
682
        */
683
        for ( pptr = plist; pptr; pptr = pptr->next )
684
        {
685
            int plen = strlen( dptr->name ) + 1 + strlen( pptr->name ) + 1;
686
            char *buf = (char *)malloc( plen );
687
 
688
            /*
689
            **  Create the name of the file
690
            */
691
            _snprintf( buf, plen, "%s\\%s", pptr->name, dptr->name );
692
 
693
 
694
            /*
695
            **  Attempt to open it
696
            */
697
            if (verbose > 2) printf( "Looking for: %s\n", buf );
698
            if ( _access ( buf, 0 ) != -1 )
699
            {
700
                /*
701
                **  File does exist
702
                **  Add the path information to the entry
703
                */
704
                dptr->path = buf;
705
                if (verbose > 1) printf( "   FOUND: %s\n", buf );
706
                return dptr;
707
            }
708
        }
709
 
710
        /*
711
        **  File not found
712
        **  Try another
713
        */
714
    }
715
}
716
 
717
//----------------------------------------------------------------------------
718
// FUNCTION           : PrintSummary
719
//
720
// DESCRIPTION        : Display summary information on DLLs discovered
721
//
722
//
723
// INPUTS             : None
724
//
725
// RETURNS            : Nothing
726
//
727
void PrintSummary( void )
728
{
729
    dlist_t *dptr;
730
 
731
    for ( dptr = dlist; dptr ; dptr = dptr->next)
732
    {
733
        printf( "%30s", dptr->name );
734
        if ( dptr->path )
735
        {
736
            printf( " : %s\n", dptr->path );
737
        }
738
        else
739
        {
740
            printf( " : NOT FOUND\n");
741
        }
742
    }
743
}
744