├── .github └── workflows │ └── pedeps.yml ├── .gitignore ├── .travis.yml ├── Changelog.txt ├── LICENSE ├── Makefile ├── README.md ├── build ├── copypedeps.cbp ├── copypedeps.depend ├── listpedeps.cbp ├── listpedeps.depend ├── listperesources.cbp ├── listperesources.depend ├── pedeps.cbp ├── pedeps.depend ├── pedeps.dll.cbp ├── pedeps.dll.depend └── pedeps.workspace ├── doc └── Doxyfile ├── lib ├── pedeps.c ├── pedeps.h ├── pedeps_version.h ├── pestructs.c └── pestructs.h └── src ├── copypedeps.c ├── listpedeps.c └── listperesources.c /.github/workflows/pedeps.yml: -------------------------------------------------------------------------------- 1 | name: GitHub-CI for pedeps 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | workflow_dispatch: 9 | 10 | jobs: 11 | build: 12 | name: ${{ matrix.config.name }} 13 | runs-on: ${{ matrix.config.os }} 14 | strategy: 15 | fail-fast: false 16 | matrix: 17 | config: 18 | - { 19 | name: "Ubuntu GCC", artifact: "linux.tar.bz2", 20 | os: ubuntu-latest, 21 | cc: "gcc", cxx: "g++", 22 | configure_method: "", build_method: "make" 23 | } 24 | - { 25 | name: "macOS Clang", artifact: "macos.tar.bz2", 26 | os: macos-latest, 27 | cc: "clang", cxx: "clang++", 28 | configure_method: "", build_method: "make" 29 | } 30 | - { 31 | name: "Windows MinGW", artifact: "win64-MinGW.tar.bz2", 32 | os: windows-latest, 33 | cc: "x86_64-w64-mingw32-gcc.exe", cxx: "x86_64-w64-mingw32-g++.exe", 34 | configure_method: "", build_method: "make" 35 | } 36 | # - { 37 | # name: "winlibs 32-bit", artifact: "win32-winlibs.tar.bz2", 38 | # os: windows-latest, 39 | # cc: "gcc.exe", cxx: "g++.exe", winlibs_bits: "32", winlibs_url: "https://github.com/brechtsanders/winlibs_mingw/releases/download/10.2.0-11.0.0-9.0.0-r3/winlibs-i686-posix-dwarf-gcc-10.2.0-mingw-w64-8.0.0-r3.7z", 40 | # configure_method: "", build_method: "make" 41 | # } 42 | # - { 43 | # name: "winlibs 64-bit", artifact: "win64-winlibs.tar.bz2", 44 | # os: windows-latest, 45 | # cc: "gcc.exe", cxx: "g++.exe", winlibs_bits: "64", winlibs_url: "https://github.com/brechtsanders/winlibs_mingw/releases/download/10.2.0-11.0.0-9.0.0-r3/winlibs-x86_64-posix-seh-gcc-10.2.0-mingw-w64-8.0.0-r3.7z", 46 | # configure_method: "", build_method: "make" 47 | # } 48 | steps: 49 | - uses: actions/checkout@v1 50 | # - if: contains( matrix.config.name, 'winlibs' ) 51 | # name: Install winlibs 52 | # run: | 53 | # curl -k -L -# -o winlibs.7z ${{ matrix.config.winlibs_url }} 54 | # 7z x -y -bd -oD:\Prog\winlibs winlibs.7z 55 | # Remove-Item winlibs.7z 56 | # echo "D:\Prog\winlibs\mingw${{ matrix.config.winlibs_bits }}\bin" >> $env:GITHUB_PATH 57 | # echo "CC=gcc" >> $GITHUB_ENV 58 | # echo "CXX=g++" >> $GITHUB_ENV 59 | - if: matrix.config.cc == 'cl' 60 | uses: ilammy/msvc-dev-cmd@v1 61 | with: 62 | arch: ${{ matrix.config.arch }} 63 | # - name: Configure 64 | # run: | 65 | # echo "MAKEDIR=." >> $env:GITHUB_ENV 66 | - name: Build libavl 67 | run: | 68 | curl -# http://ftp.debian.org/debian/pool/main/liba/libavl/libavl_0.3.5.orig.tar.gz --output libavl.tar.gz 69 | tar xfz libavl.tar.gz 70 | cd avl-0.3.5 71 | ${{ matrix.config.cc }} -O2 -fomit-frame-pointer -pipe -w -c -o avl.o avl.c 72 | ar rcs libavl.a avl.o 73 | mkdir -p ../deps/include 74 | mkdir -p ../deps/lib 75 | sed -e "s/\(avl_node_t \*new\)/\1node/g" avl.h > ../deps/include/avl.h 76 | cp libavl.a ../deps/lib/ 77 | - if: matrix.config.build_method == 'make' 78 | name: Build + install (make) 79 | run: | 80 | ${{ matrix.config.cc }} --version 81 | make install PREFIX=build_result DOXYGEN= CC=${{ matrix.config.cc }} CFLAGS="-O3 -Ilib -Ideps/include" AVLLIBS="-Ldeps/lib -lavl" 82 | # echo "LD_LIBRARY_PATH=$(pwd)/build_result/lib:$LD_LIBRARY_PATH" >> $GITHUB_ENV 83 | 84 | 85 | 86 | ####TO DO: dependancy from: http://ftp.debian.org/debian/pool/main/liba/libavl/libavl_0.3.5.orig.tar.gz 87 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.7z 2 | *.zip 3 | *.tar.gz 4 | *.tar.xz 5 | *.URL 6 | build/bin 7 | build/obj 8 | build/*.layout 9 | info/ 10 | test/ 11 | TO_DO.txt 12 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: c 2 | jobs: 3 | include: 4 | - name: "Linux GCC" 5 | os: linux 6 | compiler: gcc 7 | - name: "Linux Clang" 8 | os: linux 9 | compiler: clang 10 | # - name: "Mac OS X Clang" 11 | # os: osx 12 | # compiler: clang 13 | 14 | addons: 15 | apt: 16 | packages: 17 | - doxygen 18 | - graphviz 19 | - libavl-dev 20 | # homebrew: 21 | # packages: 22 | # - doxygen 23 | # - graphviz 24 | 25 | script: 26 | - make install CC=$CC PREFIX=$(pwd)/build_result 27 | -------------------------------------------------------------------------------- /Changelog.txt: -------------------------------------------------------------------------------- 1 | 0.1.15 2 | 3 | 2024-09-14 Brecht Sanders https://github.com/brechtsanders/ 4 | 5 | * fix Makefile to support ARM64 6 | * added function pefile_get_image_base_address() 7 | * added function pe_get_machine_bits() 8 | * changed output of listpedeps to also include OS bits and image base address 9 | 10 | 0.1.14 11 | 12 | 2024-09-10 Brecht Sanders https://github.com/brechtsanders/ 13 | 14 | * fixed -s flag in listpedeps 15 | * add multiple flags listpedeps including -h for command line help 16 | 17 | 0.1.13 18 | 19 | 2023-02-18 Brecht Sanders https://github.com/brechtsanders/ 20 | 21 | * copypedeps -q flag added for quiet mode 22 | * copypedeps -v flag added for verbose mode 23 | * copypedeps now accepts path as source in which case *.dll and *.exe files are copied 24 | 25 | 0.1.12 26 | 27 | 2023-02-03 Brecht Sanders https://github.com/brechtsanders/ 28 | 29 | * pe_get_arch_name() now also returns armv7 and aarch64 where needed 30 | * tested on Windows on ARM with CLang+MinGW-w64 (aarch64-w64-mingw32) 31 | 32 | 0.1.11 33 | 34 | 2021-12-22 Brecht Sanders https://github.com/brechtsanders/ 35 | 36 | * fix Makefile: don't specify -Wl,-soname when building for Windows 37 | * fix GitHub action to build libavl prerequisite 38 | 39 | 0.1.10 40 | 41 | 2021-06-21 Brecht Sanders https://github.com/brechtsanders/ 42 | 43 | * fix issue that file handle wasn't closed by pefile_close() 44 | 45 | 0.1.9 46 | 47 | 2020-05-06 Brecht Sanders https://github.com/brechtsanders/ 48 | 49 | * added pefile_is_stripped() to check if the file was stripped (= debug info was removed) 50 | * added pefile_list_resources() for iterating through resource groups and resources 51 | 52 | 0.1.8 53 | 54 | 2020-03-29 Brecht Sanders https://github.com/brechtsanders/ 55 | 56 | * added pefile_read() for reading data from the PE file 57 | * added pefile_list_resources() for iterating through resources 58 | 59 | 0.1.7 60 | 61 | 2020-03-07 Brecht Sanders https://github.com/brechtsanders/ 62 | 63 | * added pefile_get_file_version_major() and pefile_get_file_version_minor() 64 | * added pefile_is_dll() 65 | * added pefile_is_stripped() 66 | * fixed Doxygen warnings about missing comments by adding comments to pestructs.h 67 | * added .travis.yml to allow building with Travis CI (on Linux) 68 | * when Doxygen is available HTML documentation is installed in {PREFIX}/share/pedeps/html 69 | 70 | 0.1.6 71 | 72 | 2019-06-30 Brecht Sanders https://github.com/brechtsanders/ 73 | 74 | * added support for imports using ordinal number instead of function name 75 | * avoid looking for additional .idata sections (didn't work correctly) 76 | 77 | 0.1.5 78 | 79 | 2019-04-21 Brecht Sanders https://github.com/brechtsanders/ 80 | 81 | * added -n parameter to copypedeps (to not overwrite files) 82 | * fixed Linux build 83 | 84 | 0.1.4 85 | 86 | 2019-04-20 Brecht Sanders https://github.com/brechtsanders/ 87 | 88 | * added copypedeps tool to copy a file along with all its dependancies 89 | 90 | 0.1.3 91 | 92 | 2019-03-10 Brecht Sanders https://github.com/brechtsanders/ 93 | 94 | * fixed issue with exports pointing in section but outside specified section length 95 | 96 | 0.1.2 97 | 98 | 2019-03-09 Brecht Sanders https://github.com/brechtsanders/ 99 | 100 | * modified Makefile to remove lib prefix from .dll and .def file on Windows 101 | * modified Makefile to also generate .def file on Windows 102 | * edited README.md: removed reference to CMake 103 | * removed PEio_fread()/PEio_ftell()/PEio_fseek()/PEio_fclose() from pedeps.h 104 | * fixed abort from PEfile_list_imports_fn/PEfile_list_exports_fn by returning non-zero 105 | * added Doxygen documentation in header files 106 | * added pedeps_get_version()/pedeps_get_version_string() 107 | 108 | 0.1.1 109 | 110 | 2019-03-09 Brecht Sanders https://github.com/brechtsanders/ 111 | 112 | * fixed missing ftello()/fseeko() on old MinGW (i.e. not MinGW-w64) 113 | * fixed Makefile to also generate .def file on Windows (using MinGW) 114 | * fixed Makefile for building binary packages on Windows (using MinGW) 115 | 116 | 0.1.0 117 | 118 | 2019-03-07 Brecht Sanders https://github.com/brechtsanders/ 119 | 120 | * initial release 121 | 122 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Brecht Sanders 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | ifeq ($(OS),) 2 | OS = $(shell uname -s) 3 | endif 4 | PREFIX = /usr/local 5 | CC = gcc 6 | AR = ar 7 | LIBPREFIX = lib 8 | LIBEXT = .a 9 | ifeq ($(OS),Windows_NT) 10 | BINEXT = .exe 11 | SOLIBPREFIX = 12 | SOEXT = .dll 13 | else ifeq ($(OS),Darwin) 14 | BINEXT = 15 | SOLIBPREFIX = lib 16 | SOEXT = .dylib 17 | else 18 | BINEXT = 19 | SOLIBPREFIX = lib 20 | SOEXT = .so 21 | endif 22 | CFLAGS = 23 | LDFLAGS = 24 | INCS = -Ilib 25 | CFLAGS += $(INCS) -Os 26 | STATIC_CFLAGS = -DBUILD_PEDEPS_STATIC 27 | SHARED_CFLAGS = -DBUILD_PEDEPS_DLL 28 | LIBS = 29 | ifeq ($(OS),Darwin) 30 | STRIPFLAG = 31 | else 32 | STRIPFLAG = -s 33 | endif 34 | MKDIR = mkdir -p 35 | RM = rm -f 36 | RMDIR = rm -rf 37 | CP = cp -f 38 | CPDIR = cp -rf 39 | DOXYGEN = $(shell which doxygen) 40 | 41 | OSALIAS := $(OS) 42 | ifeq ($(OS),Windows_NT) 43 | ifneq (,$(findstring aarch64,$(shell $(CC) --version))) 44 | OSALIAS := winARM64 45 | else 46 | ifneq (,$(findstring x86_64,$(shell $(CC) --version))) 47 | OSALIAS := win64 48 | else 49 | OSALIAS := win32 50 | endif 51 | endif 52 | endif 53 | 54 | AVLLIBS = -lavl 55 | ifeq ($(OS),Windows_NT) 56 | COPYDEPSLDFLAGS = -lshlwapi 57 | else 58 | COPYDEPSLDFLAGS = 59 | endif 60 | 61 | libpedeps_OBJ = lib/pedeps.o lib/pestructs.o 62 | libpedeps_LDFLAGS = 63 | libpedeps_SHARED_LDFLAGS = 64 | ifneq ($(OS),Windows_NT) 65 | SHARED_CFLAGS += -fPIC 66 | endif 67 | ifeq ($(OS),Windows_NT) 68 | libpedeps_SHARED_LDFLAGS += -Wl,--out-implib,$(LIBPREFIX)$@$(LIBEXT) -Wl,--output-def,$(@:%$(SOEXT)=%.def) 69 | OS_LINK_FLAGS = -shared 70 | else 71 | ifeq ($(OS),Darwin) 72 | OS_LINK_FLAGS = -dynamiclib -o $@ 73 | else 74 | OS_LINK_FLAGS = -shared -Wl,-soname,$@ $(STRIPFLAG) 75 | endif 76 | endif 77 | 78 | UTILS_BIN = src/listpedeps$(BINEXT) src/copypedeps$(BINEXT) 79 | 80 | COMMON_PACKAGE_FILES = README.md LICENSE Changelog.txt 81 | SOURCE_PACKAGE_FILES = $(COMMON_PACKAGE_FILES) Makefile doc/Doxyfile lib/*.h lib/*.c src/*.c build/*.workspace build/*.cbp 82 | 83 | default: all 84 | 85 | all: static-lib shared-lib utils 86 | 87 | %.o: %.c 88 | $(CC) -c -o $@ $< $(CFLAGS) 89 | 90 | %.static.o: %.c 91 | $(CC) -c -o $@ $< $(STATIC_CFLAGS) $(CFLAGS) 92 | 93 | %.shared.o: %.c 94 | $(CC) -c -o $@ $< $(SHARED_CFLAGS) $(CFLAGS) 95 | 96 | static-lib: $(LIBPREFIX)pedeps$(LIBEXT) 97 | 98 | shared-lib: $(SOLIBPREFIX)pedeps$(SOEXT) 99 | 100 | $(LIBPREFIX)pedeps$(LIBEXT): $(libpedeps_OBJ:%.o=%.static.o) 101 | $(AR) cr $@ $^ 102 | 103 | $(SOLIBPREFIX)pedeps$(SOEXT): $(libpedeps_OBJ:%.o=%.shared.o) 104 | $(CC) -o $@ $(OS_LINK_FLAGS) $^ $(libpedeps_SHARED_LDFLAGS) $(libpedeps_LDFLAGS) $(LDFLAGS) $(LIBS) 105 | 106 | utils: $(UTILS_BIN) 107 | 108 | #src/listpedeps$(BINEXT): src/listpedeps.static.o $(LIBPREFIX)pedeps$(LIBEXT) 109 | # $(CC) -o $@ $(@:%$(BINEXT)=%.static.o) $(LIBPREFIX)pedeps$(LIBEXT) $(libpedeps_LDFLAGS) $(LDFLAGS) $(STRIPFLAG) 110 | 111 | ifeq ($(OS),Windows_NT) 112 | src/listpedeps$(BINEXT): src/listpedeps.static.o $(LIBPREFIX)pedeps$(LIBEXT) 113 | $(CC) --static $(STRIPFLAG) -o $@ src/listpedeps.static.o $(LIBPREFIX)pedeps$(LIBEXT) $(libpedeps_LDFLAGS) $(LDFLAGS) 114 | src/copypedeps$(BINEXT): src/copypedeps.static.o $(LIBPREFIX)pedeps$(LIBEXT) 115 | $(CC) --static $(STRIPFLAG) -o $@ src/copypedeps.static.o $(LIBPREFIX)pedeps$(LIBEXT) $(libpedeps_LDFLAGS) $(LDFLAGS) $(COPYDEPSLDFLAGS) $(AVLLIBS) 116 | else 117 | src/listpedeps$(BINEXT): src/listpedeps.static.o $(LIBPREFIX)pedeps$(LIBEXT) 118 | $(CC) $(STRIPFLAG) -o $@ src/listpedeps.static.o $(LIBPREFIX)pedeps$(LIBEXT) $(libpedeps_LDFLAGS) $(LDFLAGS) 119 | src/copypedeps$(BINEXT): src/copypedeps.static.o $(LIBPREFIX)pedeps$(LIBEXT) 120 | $(CC) $(STRIPFLAG) -o $@ src/copypedeps.static.o $(LIBPREFIX)pedeps$(LIBEXT) $(libpedeps_LDFLAGS) $(LDFLAGS) $(COPYDEPSLDFLAGS) $(AVLLIBS) 121 | endif 122 | 123 | .PHONY: doc 124 | doc: 125 | ifdef DOXYGEN 126 | $(DOXYGEN) doc/Doxyfile 127 | endif 128 | 129 | install: all doc 130 | $(MKDIR) $(PREFIX)/include $(PREFIX)/lib $(PREFIX)/bin 131 | $(CP) lib/*.h $(PREFIX)/include/ 132 | $(CP) *$(LIBEXT) $(PREFIX)/lib/ 133 | $(CP) $(UTILS_BIN) $(PREFIX)/bin/ 134 | ifeq ($(OS),Windows_NT) 135 | $(CP) *$(SOEXT) $(PREFIX)/bin/ 136 | $(CP) *.def $(PREFIX)/lib/ 137 | else 138 | $(CP) *$(SOEXT) $(PREFIX)/lib/ 139 | endif 140 | ifdef DOXYGEN 141 | $(CPDIR) doc/man/* $(PREFIX)/man/ 142 | $(MKDIR) $(PREFIX)/share/pedeps/html 143 | $(CPDIR) doc/html/* $(PREFIX)/share/pedeps/html/ 144 | endif 145 | 146 | .PHONY: version 147 | version: 148 | sed -ne "s/^#define\s*PEDEPS_VERSION_[A-Z]*\s*\([0-9]*\)\s*$$/\1./p" lib/pedeps_version.h | tr -d "\n" | sed -e "s/\.$$//" > version 149 | 150 | .PHONY: package 151 | package: version 152 | tar cfJ pedeps-$(shell cat version).tar.xz --transform="s?^?pedeps-$(shell cat version)/?" $(SOURCE_PACKAGE_FILES) 153 | 154 | .PHONY: package 155 | binarypackage: version 156 | ifneq ($(OS),Windows_NT) 157 | $(MAKE) PREFIX=binarypackage_temp_$(OSALIAS) install 158 | tar cfJ pedeps-$(shell cat version)-$(OSALIAS).tar.xz --transform="s?^binarypackage_temp_$(OSALIAS)/??" $(COMMON_PACKAGE_FILES) binarypackage_temp_$(OSALIAS)/* 159 | else 160 | #$(MAKE) PREFIX=binarypackage_temp_$(OSALIAS) install DOXYGEN= 161 | $(MAKE) PREFIX=binarypackage_temp_$(OSALIAS) install 162 | cp -f $(COMMON_PACKAGE_FILES) binarypackage_temp_$(OSALIAS) 163 | rm -f pedeps-$(shell cat version)-$(OSALIAS).zip 164 | cd binarypackage_temp_$(OSALIAS) && zip -r9 ../pedeps-$(shell cat version)-$(OSALIAS).zip $(COMMON_PACKAGE_FILES) * && cd .. 165 | endif 166 | rm -rf binarypackage_temp_$(OSALIAS) 167 | 168 | .PHONY: clean 169 | clean: 170 | $(RM) lib/*.o src/*.o *$(LIBEXT) *$(SOEXT) $(UTILS_BIN) version doc/doxygen_sqlite3.db 171 | ifeq ($(OS),Windows_NT) 172 | $(RM) *.def 173 | endif 174 | $(RMDIR) doc/html doc/man 175 | 176 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | pedeps 2 | ====== 3 | 4 | Cross-platform C library to read data from PE/PE+ files (the format of Windows .exe and .dll files). 5 | 6 | Description 7 | ----------- 8 | 9 | The pedeps C library provides functions to retrieve data from Windows .exe and .dll files. 10 | 11 | These files are in either PE (Windows 32-bit) or PE+ (Windows 64-bit) format, which are extensions of the COFF format. 12 | 13 | Currently the library allows iterating through: 14 | - exported symbols 15 | - imported symbols from dependency .dll files 16 | 17 | Goal 18 | ---- 19 | The library was written with the following goals in mind: 20 | - written in standard C, but allows being used by C++ 21 | - hiding the complexity of the file format 22 | - portable across different platforms (Windows, macOS, *nix) 23 | - no dependencies 24 | 25 | Libraries 26 | --------- 27 | 28 | The following libraries are provided: 29 | - `-lpedeps` - requires `#include ` (and optionally `#include `) 30 | 31 | Command line utilities 32 | ---------------------- 33 | Some command line utilities are included: 34 | - `listpedeps` - show information and list imported and exported symbols 35 | - `copypedeps` - copy file(s) to a folder along with all dependency files 36 | 37 | Dependencies 38 | ------------ 39 | The library has no depencancies. 40 | 41 | The utilities have the following dependency: 42 | - [libavl](http://packages.debian.org/search?keywords=libavl-dev) (only for copypedeps) 43 | 44 | Building from source 45 | -------------------- 46 | ### Requirements: 47 | - a C compiler like gcc or clang, on Windows MinGW and MinGW-w64 are supported 48 | - a Linux/Unix shell environment (like bash, which is also present on macOS), on Windows MSYS is supported 49 | - the make command 50 | 51 | ### Building 52 | - To build run: `make` 53 | - To install run: `make install` 54 | - To install to a specific folder run: `make install PREFIX=/usr/local` 55 | 56 | ### Microsoft Visual C++ 57 | - Building from source using MSVC is not supported. However, binary downloads are available for Windows (both 32-bit and 64-bit). They include a .def file that can be used to generate the .lib file with the following commands (run from a prompt inside the lib folder of the extracted binary package): 58 | + for Windows 32-bit: `lib /def:pedeps.def /out:pedeps.lib /machine:X86` 59 | + for Windows 64-bit: `lib /def:pedeps.def /out:pedeps.lib /machine:X64` 60 | 61 | License 62 | ------- 63 | pedeps is released under the terms of the MIT License (MIT), see LICENSE.txt. 64 | 65 | This means you are free to use pedeps in any of your projects, from open source to commercial. 66 | -------------------------------------------------------------------------------- /build/copypedeps.cbp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 104 | 105 | -------------------------------------------------------------------------------- /build/copypedeps.depend: -------------------------------------------------------------------------------- 1 | # depslib dependency file v1.0 2 | 1676750820 source:z:\pedeps\src\copypedeps.c 3 | "pestructs.h" 4 | "pedeps.h" 5 | "pedeps_version.h" 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 1609594062 z:\pedeps\lib\pestructs.h 22 | 23 | 24 | 25 | 1609673336 z:\pedeps\lib\pedeps.h 26 | 27 | 28 | 29 | 1675435307 z:\pedeps\lib\pedeps_version.h 30 | 31 | -------------------------------------------------------------------------------- /build/listpedeps.cbp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 106 | 107 | -------------------------------------------------------------------------------- /build/listpedeps.depend: -------------------------------------------------------------------------------- 1 | # depslib dependency file v1.0 2 | 1726326788 source:z:\pedeps\src\listpedeps.c 3 | "pestructs.h" 4 | "pedeps.h" 5 | "pedeps_version.h" 6 | 7 | 8 | 9 | 10 | 11 | 12 | 1726326143 z:\pedeps\lib\pestructs.h 13 | 14 | 15 | 16 | 1726326648 z:\pedeps\lib\pedeps.h 17 | 18 | 19 | 20 | 1588784084 source:\\server\users\brecht\sources\cpp\pedeps\src\listpedeps.c 21 | "pestructs.h" 22 | "pedeps.h" 23 | 24 | 25 | 26 | 27 | 28 | 29 | 1583705114 \\server\users\brecht\sources\cpp\pedeps\lib\pestructs.h 30 | 31 | 32 | 33 | 1585500023 \\server\users\brecht\sources\cpp\pedeps\lib\pedeps.h 34 | 35 | 36 | 37 | 1726320078 z:\pedeps\lib\pedeps_version.h 38 | 39 | -------------------------------------------------------------------------------- /build/listperesources.cbp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 106 | 107 | -------------------------------------------------------------------------------- /build/listperesources.depend: -------------------------------------------------------------------------------- 1 | # depslib dependency file v1.0 2 | 1609672951 source:z:\pedeps\src\listperesources.c 3 | "pestructs.h" 4 | "pedeps.h" 5 | 6 | 7 | 8 | 9 | 10 | 11 | 1609594062 z:\pedeps\lib\pestructs.h 12 | 13 | 14 | 15 | 1609673336 z:\pedeps\lib\pedeps.h 16 | 17 | 18 | 19 | 1607887895 source:\\server\users\brecht\sources\cpp\pedeps\src\listperesources.c 20 | "pestructs.h" 21 | "pedeps.h" 22 | 23 | 24 | 25 | 26 | 27 | 28 | 1583705114 \\server\users\brecht\sources\cpp\pedeps\lib\pestructs.h 29 | 30 | 31 | 32 | 1585500023 \\server\users\brecht\sources\cpp\pedeps\lib\pedeps.h 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /build/pedeps.cbp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 110 | 111 | -------------------------------------------------------------------------------- /build/pedeps.depend: -------------------------------------------------------------------------------- 1 | # depslib dependency file v1.0 2 | 1588787129 source:\\server\users\brecht\sources\cpp\pedeps\lib\pedeps.c 3 | "pedeps_version.h" 4 | "pedeps.h" 5 | "pestructs.h" 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 1588787638 \\server\users\brecht\sources\cpp\pedeps\lib\pedeps_version.h 14 | 15 | 1585500023 \\server\users\brecht\sources\cpp\pedeps\lib\pedeps.h 16 | 17 | 18 | 19 | 1583705114 \\server\users\brecht\sources\cpp\pedeps\lib\pestructs.h 20 | 21 | 22 | 23 | 1583705120 source:\\server\users\brecht\sources\cpp\pedeps\lib\pestructs.c 24 | "pestructs.h" 25 | 26 | 27 | 1726326143 source:z:\pedeps\lib\pedeps.c 28 | "pedeps_version.h" 29 | "pedeps.h" 30 | "pestructs.h" 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 1726320078 z:\pedeps\lib\pedeps_version.h 39 | 40 | 1726326648 z:\pedeps\lib\pedeps.h 41 | 42 | 43 | 44 | 1726326143 z:\pedeps\lib\pestructs.h 45 | 46 | 47 | 48 | 1726326143 source:z:\pedeps\lib\pestructs.c 49 | "pestructs.h" 50 | 51 | 52 | -------------------------------------------------------------------------------- /build/pedeps.dll.cbp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 105 | 106 | -------------------------------------------------------------------------------- /build/pedeps.dll.depend: -------------------------------------------------------------------------------- 1 | # depslib dependency file v1.0 2 | -------------------------------------------------------------------------------- /build/pedeps.workspace: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /doc/Doxyfile: -------------------------------------------------------------------------------- 1 | PROJECT_NAME = "pedeps" 2 | OUTPUT_DIRECTORY = doc 3 | INPUT = 4 | EXTRACT_ALL = NO 5 | EXTRACT_PRIVATE = NO 6 | EXTRACT_STATIC = NO 7 | FILE_PATTERNS = README.md *.h 8 | USE_MDFILE_AS_MAINPAGE = README.md 9 | RECURSIVE = YES 10 | GENERATE_MAN = YES 11 | GENERATE_HTML = YES 12 | GENERATE_LATEX = NO 13 | #GENERATE_LATEX = YES 14 | #USE_PDFLATEX = YES 15 | #PDF_HYPERLINKS = YES 16 | SORT_MEMBER_DOCS = NO 17 | EXCLUDE_SYMBOLS = DLL_EXPORT_PEDEPS 18 | -------------------------------------------------------------------------------- /lib/pedeps.c: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | Copyright (C) 2019 Brecht Sanders All Rights Reserved 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | The above copyright notice and this permission notice shall be included in 10 | all copies or substantial portions of the Software. 11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 12 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 13 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 14 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 15 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 16 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 17 | THE SOFTWARE. 18 | *****************************************************************************/ 19 | 20 | #include "pedeps_version.h" 21 | #include "pedeps.h" 22 | #include "pestructs.h" 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #define READ_STRING_STEP 32 31 | 32 | DLL_EXPORT_PEDEPS void pedeps_get_version (int* pmajor, int* pminor, int* pmicro) 33 | { 34 | if (pmajor) 35 | *pmajor = PEDEPS_VERSION_MAJOR; 36 | if (pminor) 37 | *pminor = PEDEPS_VERSION_MINOR; 38 | if (pmicro) 39 | *pmicro = PEDEPS_VERSION_MICRO; 40 | } 41 | 42 | DLL_EXPORT_PEDEPS const char* pedeps_get_version_string () 43 | { 44 | return PEDEPS_VERSION_STRING; 45 | } 46 | 47 | //////////////////////////////////////////////////////////////////////// 48 | 49 | struct pefile_struct { 50 | PEio_read_fn read_fn; 51 | PEio_tell_fn tell_fn; 52 | PEio_seek_fn seek_fn; 53 | PEio_close_fn close_fn; 54 | void* iohandle; 55 | struct PEheader_DOS dosheader; 56 | struct PEheader_PE peheader; 57 | struct PEheader_COFF coffheader; 58 | union PEheader_optional* optionalheader; 59 | struct PEheader_data_directory* datadir; 60 | struct PEheader_optional_commonext* pecommonext; 61 | struct peheader_imagesection* sections; 62 | }; 63 | 64 | //////////////////////////////////////////////////////////////////////// 65 | 66 | static inline struct peheader_imagesection* find_section (pefile_handle pe_file, uint32_t rva) 67 | { 68 | return pe_find_rva_section(pe_file->sections, pe_file->coffheader.NumberOfSections, rva); 69 | } 70 | 71 | void* read_data_at (pefile_handle pe_file, uint32_t offset, void* buf, size_t buflen) 72 | { 73 | uint64_t origfilepos; 74 | void* data; 75 | //allocate buffer dynamically if NULL pointer was given 76 | if (!buf) { 77 | if ((data = malloc(buflen)) == NULL) 78 | return NULL; 79 | } else { 80 | data = buf; 81 | } 82 | //remember original file position 83 | origfilepos = (pe_file->tell_fn)(pe_file->iohandle); 84 | //read data at position 85 | if ((pe_file->seek_fn)(pe_file->iohandle, offset) != 0 || (pe_file->read_fn)(pe_file->iohandle, data, buflen) < buflen) { 86 | if (!buf) 87 | free(data); 88 | data = NULL; 89 | } 90 | //restore original file position 91 | (pe_file->seek_fn)(pe_file->iohandle, origfilepos); 92 | return data; 93 | } 94 | 95 | char* read_string_at (pefile_handle pe_file, uint32_t offset) 96 | { 97 | uint64_t origfilepos; 98 | char* data = NULL; 99 | size_t dataallocated = 0; 100 | size_t datalen = 0; 101 | //remember original file position 102 | origfilepos = (pe_file->tell_fn)(pe_file->iohandle); 103 | //read data at position 104 | if ((pe_file->seek_fn)(pe_file->iohandle, offset) == 0 && (data = (char*)malloc(dataallocated = READ_STRING_STEP)) != NULL) { 105 | size_t i; 106 | size_t len; 107 | //read next block 108 | while ((len = (pe_file->read_fn)(pe_file->iohandle, data + datalen, READ_STRING_STEP)) > 0) { 109 | //done if terminating zero was found 110 | for (i = datalen; i < datalen + len; i++) { 111 | if (!data[i]) 112 | break; 113 | } 114 | datalen += len; 115 | if (i < datalen) 116 | break; 117 | //allocate more data 118 | if ((data = (char*)realloc(data, dataallocated += READ_STRING_STEP)) == NULL) { 119 | free(data); 120 | data = NULL; 121 | break; 122 | } 123 | } 124 | } 125 | //restore original file position 126 | (pe_file->seek_fn)(pe_file->iohandle, origfilepos); 127 | return data; 128 | } 129 | 130 | wchar_t* read_len_wstring_at (pefile_handle pe_file, uint32_t offset) 131 | { 132 | uint64_t origfilepos; 133 | wchar_t* data = NULL; 134 | uint16_t datalen; 135 | //remember original file position 136 | origfilepos = (pe_file->tell_fn)(pe_file->iohandle); 137 | //read data at position, starting with string length 138 | if ((pe_file->seek_fn)(pe_file->iohandle, offset) == 0 && (pe_file->read_fn)(pe_file->iohandle, &datalen, sizeof(datalen)) == sizeof(datalen)) { 139 | if ((data = (wchar_t*)malloc((datalen + 1) * sizeof(wchar_t))) != NULL) { 140 | //set terminating zero 141 | data[datalen] = 0; 142 | //set actual lentgh in bytes 143 | datalen *= sizeof(wchar_t); 144 | //read wide string data 145 | if ((pe_file->read_fn)(pe_file->iohandle, data, datalen) < datalen) { 146 | free(data); 147 | data = NULL; 148 | } 149 | } 150 | } 151 | //restore original file position 152 | (pe_file->seek_fn)(pe_file->iohandle, origfilepos); 153 | return data; 154 | } 155 | 156 | int pefile_process_import_section (pefile_handle pe_file, struct peheader_imagesection* section, uint32_t fileposition, uint32_t sectionlength, PEfile_list_imports_fn callbackfn, void* callbackdata) 157 | { 158 | //process import directory 159 | struct peheader_imageimportdirectory imgimpdir; 160 | char* modulename; 161 | uint32_t importlookupvalue; 162 | int importlookupbyname; 163 | int done; 164 | uint64_t oldpos = (pe_file->tell_fn)(pe_file->iohandle); 165 | uint32_t pos = fileposition; 166 | int result = 0; 167 | //iterate trough import directory 168 | while (pos + sizeof(imgimpdir) <= fileposition + sectionlength && read_data_at(pe_file, pos, &imgimpdir, sizeof(imgimpdir)) && !(imgimpdir.ImportLookupTable == 0 && imgimpdir.TimeDateStamp == 0 && imgimpdir.ForwarderChain == 0 && imgimpdir.Name == 0 && imgimpdir.ImportAddressTable == 0)) { 169 | //get module name 170 | modulename = read_string_at(pe_file, imgimpdir.Name - section->VirtualAddress + section->PointerToRawData); 171 | //position at import lookup table 172 | (pe_file->seek_fn)(pe_file->iohandle, imgimpdir.ImportLookupTable - section->VirtualAddress + section->PointerToRawData); 173 | importlookupvalue = 0; 174 | importlookupbyname = 0; 175 | done = 0; 176 | //iterate through import lookup table 177 | while (result == 0 && !done) { 178 | switch (pe_file->optionalheader->common.Signature) { 179 | case PE_SIGNATURE_PE32: 180 | { 181 | uint32_t importlookupentry; 182 | if ((pe_file->read_fn)(pe_file->iohandle, &importlookupentry, sizeof(importlookupentry)) == sizeof(importlookupentry)) { 183 | if (importlookupentry == 0) { 184 | done++; 185 | } else { 186 | importlookupbyname = ((importlookupentry & 0x80000000) == 0); 187 | importlookupvalue = importlookupentry & (importlookupbyname ? 0x7FFFFFFF : 0x0000FFFF); 188 | } 189 | } 190 | } 191 | break; 192 | case PE_SIGNATURE_PE64: 193 | { 194 | uint64_t importlookupentry; 195 | if ((pe_file->read_fn)(pe_file->iohandle, &importlookupentry, sizeof(importlookupentry)) == sizeof(importlookupentry)) { 196 | if (importlookupentry == 0) { 197 | done++; 198 | } else { 199 | importlookupbyname = ((importlookupentry & 0x8000000000000000) == 0); 200 | importlookupvalue = importlookupentry & (importlookupbyname ? 0x000000007FFFFFFF : 0x000000000000FFFF); 201 | } 202 | } 203 | } 204 | break; 205 | } 206 | if (!done) { 207 | if (importlookupbyname) { 208 | char* functionname; 209 | if ((functionname = read_string_at(pe_file, importlookupvalue + 2 - section->VirtualAddress + section->PointerToRawData)) != NULL) { 210 | result = (*callbackfn)(modulename, functionname, callbackdata); 211 | free(functionname); 212 | } 213 | } else { 214 | char ordinal[7]; 215 | snprintf(ordinal, sizeof(ordinal), "@%" PRIu16, (uint16_t)importlookupvalue); 216 | result = (*callbackfn)(modulename, ordinal, callbackdata); 217 | } 218 | } 219 | } 220 | /* 221 | if (imgimpdir.ForwarderChain) 222 | printf("ForwarderChain: 0x%08" PRIX32 "\n", imgimpdir.ForwarderChain);///// 223 | */ 224 | if (modulename) 225 | free(modulename); 226 | //move to position of next import directory 227 | pos += sizeof(imgimpdir); 228 | } 229 | (pe_file->seek_fn)(pe_file->iohandle, oldpos); 230 | return result; 231 | } 232 | 233 | int pefile_process_export_section (pefile_handle pe_file, struct peheader_imagesection* section, uint32_t fileposition, uint32_t sectionlength, PEfile_list_exports_fn callbackfn, void* callbackdata) 234 | { 235 | struct peheader_imageexportdirectory imgexpdir; 236 | char* modulename; 237 | char* functionname; 238 | int isdata; 239 | char* functionforwardername; 240 | uint32_t i; 241 | uint32_t* functionaddr; 242 | uint32_t* functionnamerva; 243 | uint16_t* functionnameordinal; 244 | struct peheader_imagesection* s; 245 | int result = 0; 246 | //read export directory 247 | if (read_data_at(pe_file, fileposition, &imgexpdir, (sectionlength < sizeof(imgexpdir) ? sectionlength : sizeof(imgexpdir))) == NULL) 248 | return 1; 249 | //process export directory 250 | modulename = read_string_at(pe_file, imgexpdir.Name - section->VirtualAddress + section->PointerToRawData); 251 | //read Export Address Table (EAT) 252 | if (imgexpdir.AddressOfFunctions && (functionaddr = read_data_at(pe_file, imgexpdir.AddressOfFunctions - section->VirtualAddress + section->PointerToRawData, NULL, sizeof(uint32_t) * imgexpdir.NumberOfFunctions)) != NULL) { 253 | if (imgexpdir.NumberOfNames == 0) { 254 | for (i = 0; i < imgexpdir.NumberOfFunctions; i++) { 255 | isdata = 0; 256 | if ((s = find_section(pe_file, functionaddr[i])) == NULL || (s /*&& s != section*/ && (s->Characteristics & PE_IMGSECTION_TYPE_CODE) == 0)) 257 | isdata = 1; 258 | else 259 | isdata = 0; 260 | result = (*callbackfn)(modulename, NULL, i + imgexpdir.Base, isdata, NULL, callbackdata); 261 | } 262 | } else { 263 | //read Export Ordinal Table (EOT) 264 | functionnameordinal = read_data_at(pe_file, imgexpdir.AddressOfNameOrdinals - section->VirtualAddress + section->PointerToRawData, NULL, sizeof(uint16_t) * imgexpdir.NumberOfNames); 265 | //read Export Name Table (ENT) 266 | if ((functionnamerva = read_data_at(pe_file, imgexpdir.AddressOfNames - section->VirtualAddress + section->PointerToRawData, NULL, sizeof(uint32_t) * imgexpdir.NumberOfNames)) != NULL) { 267 | for (i = 0; result == 0 && i < imgexpdir.NumberOfNames; i++) { 268 | if ((functionname = read_string_at(pe_file, functionnamerva[i] - section->VirtualAddress + section->PointerToRawData)) != NULL) { 269 | //forwarded function if address points within export section 270 | //if (functionaddr[functionnameordinal[i]] >= section->VirtualAddress && functionaddr[functionnameordinal[i]] < section->VirtualAddress + section->SizeOfRawData) 271 | if (functionaddr[functionnameordinal[i]] >= section->VirtualAddress && functionaddr[functionnameordinal[i]] < section->VirtualAddress + sectionlength) 272 | functionforwardername = read_string_at(pe_file, functionaddr[functionnameordinal[i]] - section->VirtualAddress + section->PointerToRawData); 273 | else 274 | functionforwardername = NULL; 275 | //data entry if function points outside known sections or within non-code section 276 | if ((s = find_section(pe_file, functionaddr[functionnameordinal[i]])) == NULL || (s /*&& s != section*/ && (s->Characteristics & PE_IMGSECTION_TYPE_CODE) == 0)) 277 | isdata = 1; 278 | else 279 | isdata = 0; 280 | //run callback function, except if function pointer points to current section but outside specified sectionlength 281 | if (!(functionaddr[functionnameordinal[i]] >= section->VirtualAddress + sectionlength && functionaddr[functionnameordinal[i]] < section->VirtualAddress + section->SizeOfRawData)) 282 | result = (*callbackfn)(modulename, functionname, (functionnameordinal && functionnameordinal[i] <= imgexpdir.NumberOfFunctions ? functionnameordinal[i] + imgexpdir.Base : 0), isdata, functionforwardername, callbackdata); 283 | if (functionforwardername) 284 | free(functionforwardername); 285 | free(functionname); 286 | } 287 | } 288 | free(functionnamerva); 289 | } 290 | if (functionnameordinal) 291 | free(functionnameordinal); 292 | } 293 | free(functionaddr); 294 | } 295 | free(modulename); 296 | return result; 297 | } 298 | 299 | //////////////////////////////////////////////////////////////////////// 300 | 301 | DLL_EXPORT_PEDEPS const char* pefile_status_message (int statuscode) 302 | { 303 | switch (statuscode) { 304 | case PE_RESULT_SUCCESS: 305 | return "success"; 306 | case PE_RESULT_OPEN_ERROR: 307 | return "file open error"; 308 | case PE_RESULT_READ_ERROR: 309 | return "file read error"; 310 | case PE_RESULT_SEEK_ERROR: 311 | return "file seek error"; 312 | case PE_RESULT_OUT_OF_MEMORY: 313 | return "memory allocation error"; 314 | case PE_RESULT_NOT_PE: 315 | return "not a PE file"; 316 | case PE_RESULT_NOT_PE_LE: 317 | return "wrong endianness"; 318 | case PE_RESULT_WRONG_IMAGE: 319 | return "wrong image type"; 320 | default: 321 | return "(unknown status code)"; 322 | } 323 | } 324 | 325 | DLL_EXPORT_PEDEPS pefile_handle pefile_create () 326 | { 327 | pefile_handle pe_file; 328 | if ((pe_file = (struct pefile_struct*)malloc(sizeof(struct pefile_struct))) != NULL) { 329 | pe_file->read_fn = NULL; 330 | pe_file->tell_fn = NULL; 331 | pe_file->seek_fn = NULL; 332 | pe_file->close_fn = NULL; 333 | pe_file->iohandle = NULL; 334 | pe_file->optionalheader = NULL; 335 | pe_file->datadir = NULL; 336 | pe_file->pecommonext = NULL; 337 | pe_file->sections = NULL; 338 | } 339 | return pe_file; 340 | } 341 | 342 | DLL_EXPORT_PEDEPS int pefile_open_custom (pefile_handle pe_file, void* iohandle, PEio_read_fn read_fn, PEio_tell_fn tell_fn, PEio_seek_fn seek_fn, PEio_close_fn close_fn) 343 | { 344 | pe_file->iohandle = iohandle; 345 | pe_file->read_fn = read_fn; 346 | pe_file->tell_fn = tell_fn; 347 | pe_file->seek_fn = seek_fn; 348 | pe_file->close_fn = close_fn; 349 | //read DOS header 350 | if ((pe_file->seek_fn)(pe_file->iohandle, 0) != 0) 351 | return PE_RESULT_SEEK_ERROR; 352 | if ((pe_file->read_fn)(pe_file->iohandle, &(pe_file->dosheader), sizeof(struct PEheader_DOS)) != sizeof(struct PEheader_DOS)) 353 | return PE_RESULT_READ_ERROR; 354 | //check for MZ in the beginning of the file 355 | if (pe_file->dosheader.e_magic != 0x5A4D) 356 | return PE_RESULT_NOT_PE; 357 | //read PE header 358 | if ((pe_file->seek_fn)(pe_file->iohandle, pe_file->dosheader.e_lfanew) != 0) 359 | return PE_RESULT_SEEK_ERROR; 360 | if ((pe_file->read_fn)(pe_file->iohandle, &(pe_file->peheader), sizeof(struct PEheader_PE)) != sizeof(struct PEheader_PE)) 361 | return PE_RESULT_READ_ERROR; 362 | //check for little endian PE signature 363 | if (pe_file->peheader.signature != 0x00004550) 364 | return PE_RESULT_NOT_PE_LE; 365 | //read COFF header 366 | if ((pe_file->read_fn)(pe_file->iohandle, &(pe_file->coffheader), sizeof(struct PEheader_COFF)) != sizeof(struct PEheader_COFF)) 367 | return PE_RESULT_READ_ERROR; 368 | //read optional header 369 | if (pe_file->coffheader.SizeOfOptionalHeader == 0) { 370 | pe_file->optionalheader = NULL; 371 | } else { 372 | if ((pe_file->optionalheader = malloc(pe_file->coffheader.SizeOfOptionalHeader)) == NULL) 373 | return PE_RESULT_OUT_OF_MEMORY; 374 | if ((pe_file->read_fn)(pe_file->iohandle, pe_file->optionalheader, pe_file->coffheader.SizeOfOptionalHeader) != pe_file->coffheader.SizeOfOptionalHeader) { 375 | free(pe_file->optionalheader); 376 | pe_file->optionalheader = NULL; 377 | return PE_RESULT_READ_ERROR; 378 | } 379 | } 380 | //check image signature (267 for 32 bit Windows, 523 for 64 bit Windows, and 263 for a ROM image) 381 | switch (pe_file->optionalheader->common.Signature) { 382 | case PE_SIGNATURE_PE32: 383 | pe_file->pecommonext = &(pe_file->optionalheader->opt32.commonext); 384 | pe_file->datadir = pe_file->optionalheader->opt32.datadirs; 385 | break; 386 | case PE_SIGNATURE_PE64: 387 | pe_file->pecommonext = &(pe_file->optionalheader->opt64.commonext); 388 | pe_file->datadir = pe_file->optionalheader->opt64.datadirs; 389 | break; 390 | /* 391 | case 0x0107: 392 | imagetype = "ROM"; 393 | break; 394 | default: 395 | imagetype = "unknown"; 396 | break; 397 | */ 398 | default: 399 | free(pe_file->optionalheader); 400 | pe_file->optionalheader = NULL; 401 | return PE_RESULT_WRONG_IMAGE; 402 | } 403 | //read all sections 404 | if ((pe_file->sections = malloc(sizeof(struct peheader_imagesection) * pe_file->coffheader.NumberOfSections)) == NULL) { 405 | free(pe_file->optionalheader); 406 | pe_file->optionalheader = NULL; 407 | return PE_RESULT_OUT_OF_MEMORY; 408 | } 409 | if ((pe_file->read_fn)(pe_file->iohandle, pe_file->sections, sizeof(struct peheader_imagesection) * pe_file->coffheader.NumberOfSections) != sizeof(struct peheader_imagesection) * pe_file->coffheader.NumberOfSections) { 410 | free(pe_file->optionalheader); 411 | pe_file->optionalheader = NULL; 412 | free(pe_file->sections); 413 | pe_file->sections = NULL; 414 | return PE_RESULT_READ_ERROR; 415 | } 416 | return 0; 417 | } 418 | 419 | uint64_t PEio_fread (void* iohandle, void* buf, uint64_t buflen) 420 | { 421 | if (!iohandle) 422 | return 0; 423 | return (uint64_t)fread(buf, 1, buflen, (FILE*)iohandle); 424 | } 425 | 426 | uint64_t PEio_ftell (void* iohandle) 427 | { 428 | #if defined(_WIN32) && !defined(__MINGW64_VERSION_MAJOR) 429 | return (uint64_t)ftell((FILE*)iohandle); 430 | #else 431 | return (uint64_t)ftello((FILE*)iohandle); 432 | #endif 433 | } 434 | 435 | int PEio_fseek (void* iohandle, uint64_t pos) 436 | { 437 | #if defined(_WIN32) && !defined(__MINGW64_VERSION_MAJOR) 438 | return fseek((FILE*)iohandle, (long)pos, SEEK_SET); 439 | #else 440 | return fseeko((FILE*)iohandle, (off_t)pos, SEEK_SET); 441 | #endif 442 | } 443 | 444 | void PEio_fclose (void* iohandle) 445 | { 446 | fclose((FILE*)iohandle); 447 | } 448 | 449 | DLL_EXPORT_PEDEPS int pefile_open_file (pefile_handle pe_file, const char* filename) 450 | { 451 | FILE* filehandle; 452 | if ((filehandle = fopen(filename, "rb")) == NULL) { 453 | return 1; 454 | } 455 | return pefile_open_custom(pe_file, filehandle, &PEio_fread, &PEio_ftell, &PEio_fseek, &PEio_fclose); 456 | } 457 | 458 | DLL_EXPORT_PEDEPS void pefile_close (pefile_handle pe_file) 459 | { 460 | if (pe_file->close_fn) { 461 | (pe_file->close_fn)(pe_file->iohandle); 462 | } 463 | pe_file->read_fn = NULL; 464 | pe_file->tell_fn = NULL; 465 | pe_file->seek_fn = NULL; 466 | pe_file->close_fn = NULL; 467 | pe_file->iohandle = NULL; 468 | if (pe_file->optionalheader) { 469 | free(pe_file->optionalheader); 470 | pe_file->optionalheader = NULL; 471 | } 472 | pe_file->datadir = NULL; 473 | pe_file->pecommonext = NULL; 474 | if (pe_file->sections) { 475 | free(pe_file->sections); 476 | pe_file->sections = NULL; 477 | } 478 | } 479 | 480 | DLL_EXPORT_PEDEPS void pefile_destroy (pefile_handle pe_file) 481 | { 482 | pefile_close(pe_file); 483 | free(pe_file); 484 | } 485 | 486 | DLL_EXPORT_PEDEPS uint64_t pefile_read (pefile_handle pe_file, uint64_t filepos, uint64_t datalen, void* buf, size_t buflen, pefile_readdata_fn callbackfn, void* callbackdata) 487 | { 488 | uint64_t origfilepos; 489 | uint64_t dataread = 0; 490 | void* localbuffer = NULL; 491 | //check if a buffer is provided or one should be allocated 492 | if (buf == NULL) { 493 | if (buflen == 0) 494 | buflen = 256; 495 | if ((localbuffer = malloc(buflen)) == NULL) 496 | return 0; 497 | buf = localbuffer; 498 | } else if (buflen == 0) { 499 | return 0; 500 | } 501 | //remember original file position 502 | origfilepos = (pe_file->tell_fn)(pe_file->iohandle); 503 | //read data at position 504 | if ((pe_file->seek_fn)(pe_file->iohandle, filepos) == 0) { 505 | while ((buflen = (pe_file->read_fn)(pe_file->iohandle, buf, (dataread + buflen <= datalen ? buflen : datalen - dataread))) > 0) { 506 | dataread += buflen; 507 | if (callbackfn(buf, buflen, callbackdata) != 0) 508 | break; 509 | } 510 | } 511 | //restore original file position 512 | (pe_file->seek_fn)(pe_file->iohandle, origfilepos); 513 | if (localbuffer) 514 | free(localbuffer); 515 | return dataread; 516 | } 517 | 518 | DLL_EXPORT_PEDEPS uint16_t pefile_get_signature (pefile_handle pe_file) 519 | { 520 | return (pe_file && pe_file->optionalheader ? pe_file->optionalheader->common.Signature : 0); 521 | } 522 | 523 | DLL_EXPORT_PEDEPS uint16_t pefile_get_machine (pefile_handle pe_file) 524 | { 525 | return (pe_file ? pe_file->coffheader.Machine : 0); 526 | } 527 | 528 | DLL_EXPORT_PEDEPS uint16_t pefile_get_subsystem (pefile_handle pe_file) 529 | { 530 | return (pe_file && pe_file->pecommonext ? pe_file->pecommonext->Subsystem : 0); 531 | } 532 | 533 | DLL_EXPORT_PEDEPS uint16_t pefile_get_min_os_major (pefile_handle pe_file) 534 | { 535 | //return (pe_file && pe_file->pecommonext ? pe_file->pecommonext->MajorOSVersion : 0); 536 | return (pe_file && pe_file->pecommonext ? pe_file->pecommonext->MajorSubsystemVersion : 0); 537 | } 538 | 539 | DLL_EXPORT_PEDEPS uint16_t pefile_get_min_os_minor (pefile_handle pe_file) 540 | { 541 | //return (pe_file && pe_file->pecommonext ? pe_file->pecommonext->MinorOSVersion : 0); 542 | return (pe_file && pe_file->pecommonext ? pe_file->pecommonext->MinorSubsystemVersion : 0); 543 | } 544 | 545 | DLL_EXPORT_PEDEPS uint16_t pefile_get_file_version_major (pefile_handle pe_file) 546 | { 547 | return (pe_file && pe_file->pecommonext ? pe_file->pecommonext->MajorImageVersion : 0); 548 | } 549 | 550 | DLL_EXPORT_PEDEPS uint16_t pefile_get_file_version_minor (pefile_handle pe_file) 551 | { 552 | return (pe_file && pe_file->pecommonext ? pe_file->pecommonext->MinorImageVersion : 0); 553 | } 554 | 555 | DLL_EXPORT_PEDEPS int pefile_is_dll (pefile_handle pe_file) 556 | { 557 | return (pe_file && ((pe_file->coffheader.Characteristics & PE_CHARACTERISTIC_IMAGE_FILE_DLL) != 0) ? 1 : 0); 558 | } 559 | 560 | typedef int (*pefile_iterate_section_fn) (pefile_handle pe_file, struct peheader_imagesection* section, uint32_t fileposition, uint32_t sectionlength, void* callbackfn, void* callbackdata); 561 | 562 | int pefile_iterate_sections (pefile_handle pe_file, int sectionindex, const char* sectionname, size_t maxsectionsize, pefile_iterate_section_fn iteratefn, void* callbackfn, void* callbackdata) 563 | { 564 | uint32_t datadirentries = 0; 565 | switch (pe_file->optionalheader->common.Signature) { 566 | case PE_SIGNATURE_PE32: 567 | datadirentries = pe_file->optionalheader->opt32.NumberOfRvaAndSizes; 568 | break; 569 | case PE_SIGNATURE_PE64: 570 | datadirentries = pe_file->optionalheader->opt64.NumberOfRvaAndSizes; 571 | break; 572 | default: 573 | return PE_RESULT_WRONG_IMAGE; 574 | } 575 | 576 | //process directory specified in data directory 577 | uint32_t processeddir = 0; 578 | if (sectionindex != -1) { 579 | if (sectionindex < datadirentries && pe_file->datadir[sectionindex].VirtualAddress) { 580 | struct peheader_imagesection* rvasection; 581 | if ((rvasection = find_section(pe_file, pe_file->datadir[sectionindex].VirtualAddress)) != NULL) { 582 | iteratefn(pe_file, rvasection, pe_file->datadir[sectionindex].VirtualAddress - rvasection->VirtualAddress + rvasection->PointerToRawData, pe_file->datadir[PE_DATA_DIR_IDX_IMPORT].Size, callbackfn, callbackdata); 583 | processeddir = pe_file->datadir[sectionindex].VirtualAddress - rvasection->VirtualAddress + rvasection->PointerToRawData; 584 | } 585 | } 586 | } 587 | 588 | //process each section looking for the section by name 589 | if (sectionname) { 590 | uint16_t currentsection; 591 | struct peheader_imagesection* section; 592 | for (currentsection = 0; currentsection < pe_file->coffheader.NumberOfSections; currentsection++) { 593 | section = &(pe_file->sections[currentsection]); 594 | /////TO DO: handle case where name is longer than 8 characters (in which case name is slash followed by decimal value of offset) 595 | if (section->PointerToRawData && section->SizeOfRawData >= maxsectionsize && memcmp(section->Name, sectionname, 8) == 0) { 596 | //process directory 597 | if (section->PointerToRawData != processeddir && section->SizeOfRawData >= maxsectionsize) { 598 | iteratefn(pe_file, section, section->PointerToRawData, section->SizeOfRawData, callbackfn, callbackdata); 599 | } 600 | } 601 | } 602 | } 603 | return 0; 604 | } 605 | 606 | const char debug_section_name[8] = {'.', 'd', 'e', 'b', 'u', 'g', 0, 0}; 607 | 608 | int process_debug_section (pefile_handle pe_file, struct peheader_imagesection* section, uint32_t fileposition, uint32_t sectionlength, void* callbackfn, void* callbackdata) 609 | { 610 | ++*(unsigned int*)callbackdata; 611 | return 0; 612 | } 613 | 614 | DLL_EXPORT_PEDEPS int pefile_is_stripped (pefile_handle pe_file) 615 | { 616 | if (pe_file) { 617 | unsigned int debugsectioncount = 0; 618 | //check if charachteristics mark as stripped 619 | if ((pe_file->coffheader.Characteristics & PE_CHARACTERISTIC_IMAGE_FILE_DEBUG_STRIPPED) != 0) 620 | return 1; 621 | //check if there is no debug directory 622 | pefile_iterate_sections(pe_file, PE_DATA_DIR_IDX_DEBUG, debug_section_name, 0/*size of debug section here*/, process_debug_section, NULL, &debugsectioncount); 623 | if (debugsectioncount) 624 | return 0; 625 | /////TO DO: check if an .rdata section is used as debug section 626 | } 627 | return 0; 628 | } 629 | 630 | DLL_EXPORT_PEDEPS uint64_t pefile_get_image_base_address (pefile_handle pe_file) 631 | { 632 | switch (pe_file->optionalheader->common.Signature) { 633 | case PE_SIGNATURE_PE32: 634 | return (uint64_t)pe_file->optionalheader->opt32.ImageBase; 635 | break; 636 | case PE_SIGNATURE_PE64: 637 | return pe_file->optionalheader->opt64.ImageBase; 638 | break; 639 | default: 640 | return 0; 641 | } 642 | } 643 | 644 | const char import_section_name[8] = {'.', 'i', 'd', 'a', 't', 'a', 0, 0}; 645 | 646 | DLL_EXPORT_PEDEPS int pefile_list_imports (pefile_handle pe_file, PEfile_list_imports_fn callbackfn, void* callbackdata) 647 | { 648 | /* 649 | return pefile_iterate_sections (pe_file, PE_DATA_DIR_IDX_IMPORT, import_section_name, sizeof(struct peheader_imageimportdirectory), (pefile_iterate_section_fn)pefile_process_import_section, callbackfn, callbackdata); 650 | */ 651 | uint32_t datadirentries = 0; 652 | switch (pe_file->optionalheader->common.Signature) { 653 | case PE_SIGNATURE_PE32: 654 | datadirentries = pe_file->optionalheader->opt32.NumberOfRvaAndSizes; 655 | break; 656 | case PE_SIGNATURE_PE64: 657 | datadirentries = pe_file->optionalheader->opt64.NumberOfRvaAndSizes; 658 | break; 659 | default: 660 | return PE_RESULT_WRONG_IMAGE; 661 | } 662 | 663 | //process import directory specified in data directory 664 | uint32_t processedimpdir = 0; 665 | { 666 | if (PE_DATA_DIR_IDX_IMPORT < datadirentries && pe_file->datadir[PE_DATA_DIR_IDX_IMPORT].VirtualAddress) { 667 | struct peheader_imagesection* rvasection; 668 | if ((rvasection = find_section(pe_file, pe_file->datadir[PE_DATA_DIR_IDX_IMPORT].VirtualAddress)) != NULL) { 669 | pefile_process_import_section(pe_file, rvasection, pe_file->datadir[PE_DATA_DIR_IDX_IMPORT].VirtualAddress - rvasection->VirtualAddress + rvasection->PointerToRawData, pe_file->datadir[PE_DATA_DIR_IDX_IMPORT].Size, callbackfn, callbackdata); 670 | processedimpdir = rvasection->PointerToRawData; 671 | } 672 | } 673 | } 674 | 675 | //process each section 676 | uint16_t currentsection; 677 | struct peheader_imagesection* section; 678 | for (currentsection = 0; currentsection < pe_file->coffheader.NumberOfSections; currentsection++) { 679 | section = &(pe_file->sections[currentsection]); 680 | if (section->PointerToRawData && section->SizeOfRawData >= sizeof(struct peheader_imageimportdirectory) && memcmp(section->Name, import_section_name, 8) == 0) { 681 | if (section->PointerToRawData != processedimpdir && section->SizeOfRawData >= sizeof(struct peheader_imageimportdirectory)) { 682 | /////TO DO: test this scenario (additional .idata sections) 683 | /////TO DO: correct addressing 684 | /* 685 | if (pefile_process_import_section(pe_file, section, section->PointerToRawData, section->SizeOfRawData, callbackfn, callbackdata) != 0) 686 | break; 687 | */ 688 | } 689 | } 690 | } 691 | return 0; 692 | } 693 | 694 | const char export_section_name[8] = {'.', 'e', 'd', 'a', 't', 'a', 0, 0}; 695 | 696 | DLL_EXPORT_PEDEPS int pefile_list_exports (pefile_handle pe_file, PEfile_list_exports_fn callbackfn, void* callbackdata) 697 | { 698 | return pefile_iterate_sections (pe_file, PE_DATA_DIR_IDX_EXPORT, export_section_name, sizeof(struct peheader_imageexportdirectory), (pefile_iterate_section_fn)pefile_process_export_section, callbackfn, callbackdata); 699 | } 700 | 701 | const char resource_section_name[8] = {'.', 'r', 's', 'r', 'c', 0, 0, 0}; 702 | 703 | int pefile_process_resource_directory (pefile_handle pe_file, struct peheader_imagesection* section, uint32_t startfileposition, uint32_t fileposition, PEfile_list_resourcegroups_fn groupcallbackfn, PEfile_list_resources_fn entrycallbackfn, void* callbackdata, unsigned int level, struct pefile_resource_directory_struct* parentinfo) 704 | { 705 | uint32_t i; 706 | struct peheader_imageresourcedirectory imgresdir; 707 | struct peheader_imageresourcedirectory_entry* resentries; 708 | struct peheader_imageresourcedirectory_entry* resentry; 709 | int cbresult = PE_CB_RETURN_CONTINUE; 710 | int abort = 0; 711 | //read resource directory 712 | if (read_data_at(pe_file, fileposition, &imgresdir, sizeof(imgresdir)) == NULL) 713 | return PE_CB_RETURN_ERROR; 714 | //read resource entries 715 | if ((resentries = read_data_at(pe_file, fileposition + sizeof(imgresdir), NULL, (imgresdir.NumberOfNamedEntries + imgresdir.NumberOfIdEntries) * sizeof(struct peheader_imageresourcedirectory_entry))) == NULL) 716 | return PE_CB_RETURN_ERROR; 717 | resentry = resentries; 718 | //read resource entries 719 | for (i = 0; !abort && i < imgresdir.NumberOfNamedEntries + imgresdir.NumberOfIdEntries; i++) { 720 | if ((resentry->OffsetToData & PE_RESOURCE_ENTRY_DIR_MASK) != 0) { 721 | //resource entry is a directory 722 | struct pefile_resource_directory_struct info; 723 | info.parent = parentinfo; 724 | info.name = NULL; 725 | if ((info.isnamed = ((resentry->Name & PE_RESOURCE_ENTRY_NAME_MASK) != 0 ? 1 : 0)) != 0) { 726 | //named entry 727 | info.id = 0; 728 | info.name = read_len_wstring_at(pe_file, startfileposition + (resentry->Name & ~PE_RESOURCE_ENTRY_NAME_MASK)); 729 | } else { 730 | //entry identified by ID 731 | info.id = resentry->Name; 732 | } 733 | if (!parentinfo && groupcallbackfn) 734 | cbresult = groupcallbackfn(&info, callbackdata); 735 | if (cbresult == PE_CB_RETURN_CONTINUE || cbresult == PE_CB_RETURN_LAST) 736 | cbresult = pefile_process_resource_directory(pe_file, section, startfileposition, startfileposition + (resentry->OffsetToData & ~PE_RESOURCE_ENTRY_DIR_MASK), groupcallbackfn, entrycallbackfn, callbackdata, level + 1, &info); 737 | else if (cbresult != PE_CB_RETURN_SKIP) 738 | abort = 1; 739 | if (info.name) 740 | free(info.name); 741 | if (cbresult == PE_CB_RETURN_LAST || cbresult == PE_CB_RETURN_ABORT) 742 | break; 743 | } else { 744 | //resource entry is data 745 | struct peheader_imageresource_data_entry resdata; 746 | if (read_data_at(pe_file, startfileposition + resentry->OffsetToData, &resdata, sizeof(resdata))) { 747 | cbresult = entrycallbackfn(pe_file, parentinfo, resdata.OffsetToData - section->VirtualAddress + section->PointerToRawData, resdata.Size, resdata.CodePage, callbackdata); 748 | if (cbresult == PE_CB_RETURN_ABORT) 749 | abort = 1; 750 | } 751 | } 752 | resentry++; 753 | } 754 | //clean up 755 | free(resentries); 756 | return (abort ? PE_CB_RETURN_ABORT : PE_CB_RETURN_ABORT); 757 | } 758 | 759 | struct pefile_list_resources_callback_struct { 760 | PEfile_list_resourcegroups_fn groupcallbackfn; 761 | PEfile_list_resources_fn entrycallbackfn; 762 | void* callbackdata; 763 | }; 764 | 765 | int pefile_process_resource_section (pefile_handle pe_file, struct peheader_imagesection* section, uint32_t fileposition, uint32_t sectionlength, PEfile_list_resources_fn callbackfn, void* callbackdata) 766 | { 767 | struct pefile_list_resources_callback_struct* data = (struct pefile_list_resources_callback_struct*)callbackdata; 768 | return pefile_process_resource_directory(pe_file, section, fileposition, fileposition, data->groupcallbackfn, data->entrycallbackfn, data->callbackdata, 0, NULL); 769 | } 770 | 771 | DLL_EXPORT_PEDEPS int pefile_list_resources (pefile_handle pe_file, PEfile_list_resourcegroups_fn groupcallbackfn, PEfile_list_resources_fn entrycallbackfn, void* callbackdata) 772 | { 773 | struct pefile_list_resources_callback_struct data; 774 | data.groupcallbackfn = groupcallbackfn; 775 | data.entrycallbackfn = entrycallbackfn; 776 | data.callbackdata = callbackdata; 777 | return pefile_iterate_sections(pe_file, PE_DATA_DIR_IDX_RESOURCE, resource_section_name, sizeof(struct peheader_imageresourcedirectory), (pefile_iterate_section_fn)pefile_process_resource_section, NULL, &data); 778 | } 779 | -------------------------------------------------------------------------------- /lib/pedeps.h: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | Copyright (C) 2019 Brecht Sanders All Rights Reserved 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | The above copyright notice and this permission notice shall be included in 10 | all copies or substantial portions of the Software. 11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 12 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 13 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 14 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 15 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 16 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 17 | THE SOFTWARE. 18 | *****************************************************************************/ 19 | 20 | /** 21 | * @file pedeps.h 22 | * @brief pedeps library header file with main functions 23 | * @author Brecht Sanders 24 | * 25 | * This header file defines the functions needed to process PE(+) files 26 | */ 27 | 28 | #ifndef INCLUDED_PE_IO_H 29 | #define INCLUDED_PE_IO_H 30 | 31 | #include 32 | #include 33 | 34 | /*! \cond PRIVATE */ 35 | #if !defined(DLL_EXPORT_PEDEPS) 36 | # if defined(_WIN32) && defined(BUILD_PEDEPS_DLL) 37 | # define DLL_EXPORT_PEDEPS __declspec(dllexport) 38 | # elif defined(_WIN32) && !defined(STATIC) && !defined(BUILD_PEDEPS_STATIC) && !defined(BUILD_PEDEPS) 39 | # define DLL_EXPORT_PEDEPS __declspec(dllimport) 40 | # else 41 | # define DLL_EXPORT_PEDEPS 42 | # endif 43 | #endif 44 | /*! \endcond */ 45 | 46 | #ifdef __cplusplus 47 | extern "C" { 48 | #endif 49 | 50 | /*! \brief get pedeps library version string 51 | * \param pmajor pointer to integer that will receive major version number 52 | * \param pminor pointer to integer that will receive minor version number 53 | * \param pmicro pointer to integer that will receive micro version number 54 | * \sa pedeps_get_version_string() 55 | */ 56 | DLL_EXPORT_PEDEPS void pedeps_get_version (int* pmajor, int* pminor, int* pmicro); 57 | 58 | /*! \brief get pedeps library version string 59 | * \return version string 60 | * \sa pedeps_get_version() 61 | */ 62 | DLL_EXPORT_PEDEPS const char* pedeps_get_version_string (); 63 | 64 | /*! \brief handle type used by pedeps library 65 | * \sa pefile_create() 66 | * \sa pefile_open_custom() 67 | * \sa pefile_open_file() 68 | * \sa pefile_close() 69 | * \sa pefile_destroy() 70 | */ 71 | typedef struct pefile_struct* pefile_handle; 72 | 73 | /*! \brief status result codes used by pedeps library 74 | * \sa pefile_status_message() 75 | * \sa pefile_open_custom() 76 | * \sa pefile_open_file() 77 | * \sa pefile_close() 78 | * \sa pefile_destroy() 79 | * \sa pefile_list_imports() 80 | * \sa pefile_list_exports() 81 | * \name PE_RESULT_* 82 | * \{ 83 | */ 84 | #define PE_RESULT_SUCCESS 0 /**< success */ 85 | #define PE_RESULT_OPEN_ERROR 1 /**< error opening file */ 86 | #define PE_RESULT_READ_ERROR 2 /**< error reading file */ 87 | #define PE_RESULT_SEEK_ERROR 3 /**< error positiong withing file */ 88 | #define PE_RESULT_OUT_OF_MEMORY 4 /**< error allocating memory */ 89 | #define PE_RESULT_NOT_PE 5 /**< not a PE file */ 90 | #define PE_RESULT_NOT_PE_LE 6 /**< not a little endian PE file */ 91 | #define PE_RESULT_WRONG_IMAGE 7 /**< invalid file image type */ 92 | /*! @} */ 93 | 94 | /*! \brief get text message describing the status code 95 | * \param statuscode status code 96 | * \return text message describing the status code 97 | * \sa PE_RESULT_* 98 | */ 99 | DLL_EXPORT_PEDEPS const char* pefile_status_message (int statuscode); 100 | 101 | /*! \brief create handle for use with the pedeps library 102 | * \return handle 103 | * \sa pefile_handle 104 | * \sa pefile_open_custom() 105 | * \sa pefile_open_file() 106 | * \sa pefile_close() 107 | * \sa pefile_destroy() 108 | * \sa pefile_list_imports() 109 | * \sa pefile_list_exports() 110 | */ 111 | DLL_EXPORT_PEDEPS pefile_handle pefile_create (); 112 | 113 | /*! \brief function type used by pefile_open_custom() for reading data from file 114 | * \param iohandle I/O handle data passed to pefile_open_custom() 115 | * \param buf buffer where data will be read to 116 | * \param buflen size of \b buf 117 | * \return number of bytes read 118 | * \sa pefile_open_custom() 119 | * \sa pefile_create() 120 | * \sa PEio_tell_fn 121 | * \sa PEio_seek_fn 122 | * \sa PEio_close_fn 123 | */ 124 | typedef uint64_t (*PEio_read_fn) (void* iohandle, void* buf, uint64_t buflen); 125 | 126 | /*! \brief function type used by pefile_open_custom() for determining file position 127 | * \param iohandle I/O handle data passed to pefile_open_custom() 128 | * \return file position 129 | * \sa pefile_open_custom() 130 | * \sa PEio_read_fn 131 | * \sa PEio_seek_fn 132 | * \sa PEio_close_fn 133 | */ 134 | typedef uint64_t (*PEio_tell_fn) (void* iohandle); 135 | 136 | /*! \brief function type used by pefile_open_custom() for positioning within file 137 | * \param iohandle I/O handle data passed to pefile_open_custom() 138 | * \param pos file position 139 | * \return 0 on success 140 | * \sa pefile_open_custom() 141 | * \sa PEio_read_fn 142 | * \sa PEio_tell_fn 143 | * \sa PEio_close_fn 144 | */ 145 | typedef int (*PEio_seek_fn) (void* iohandle, uint64_t pos); 146 | 147 | /*! \brief function type used by pefile_open_custom() for closing file 148 | * \param iohandle I/O handle data passed to pefile_open_custom() 149 | * \sa pefile_open_custom() 150 | * \sa PEio_read_fn 151 | * \sa PEio_tell_fn 152 | * \sa PEio_seek_fn 153 | */ 154 | typedef void (*PEio_close_fn) (void* iohandle); 155 | 156 | /*! \brief function type used by pefile_open_custom() for positioning within file 157 | * \param pe_file handle as returned by pefile_create() 158 | * \param iohandle I/O handle data to be passed passed to the custom functions 159 | * \param read_fn custom function for reading data from file 160 | * \param tell_fn custom function for determining file position 161 | * \param seek_fn custom function for positioning within file 162 | * \param close_fn custom function for closing file (NULL to leave open) 163 | * \return 0 on success or one of the PE_RESULT_* status result codes 164 | * \sa pefile_create() 165 | * \sa pefile_open_file() 166 | * \sa PEio_read_fn 167 | * \sa PEio_tell_fn 168 | * \sa PEio_seek_fn 169 | * \sa PEio_close_fn 170 | * \sa PE_RESULT_* 171 | */ 172 | DLL_EXPORT_PEDEPS int pefile_open_custom (pefile_handle pe_file, void* iohandle, PEio_read_fn read_fn, PEio_tell_fn tell_fn, PEio_seek_fn seek_fn, PEio_close_fn close_fn); 173 | 174 | /*! \brief function type used by pefile_open_custom() for positioning within file 175 | * \param pe_file handle as returned by pefile_create() 176 | * \param filename path of file to open 177 | * \return 0 on success or one of the PE_RESULT_* status result codes 178 | * \sa pefile_create() 179 | * \sa pefile_open_custom() 180 | * \sa PE_RESULT_* 181 | */ 182 | DLL_EXPORT_PEDEPS int pefile_open_file (pefile_handle pe_file, const char* filename); 183 | 184 | /*! \brief function type used by pefile_read() for reading data from file 185 | * \param buf buffer containing data 186 | * \param buflen size of buffer (in bytes) 187 | * \param callbackdata callback data passed via pefile_read() 188 | * \return 0 to continue reading or non-zero to abort 189 | * \sa pefile_open_file() 190 | * \sa pefile_open_custom() 191 | * \sa PEio_read_fn 192 | * \sa PEio_tell_fn 193 | * \sa PEio_seek_fn 194 | */ 195 | typedef int (*pefile_readdata_fn) (void* buf, size_t buflen, void* callbackdata); 196 | 197 | /*! \brief close open file 198 | * \param pe_file handle as returned by pefile_create() 199 | * \sa pefile_open_custom() 200 | * \sa pefile_open_file() 201 | * \sa pefile_destroy() 202 | */ 203 | DLL_EXPORT_PEDEPS void pefile_close (pefile_handle pe_file); 204 | 205 | /*! \brief clean up handle and associated data 206 | * \param pe_file handle as returned by pefile_create() 207 | * \sa pefile_create() 208 | * \sa pefile_destroy() 209 | */ 210 | DLL_EXPORT_PEDEPS void pefile_destroy (pefile_handle pe_file); 211 | 212 | /*! \brief read data directly from the open file 213 | * \param pe_file handle as returned by pefile_create() 214 | * \param filepos the position within the file to start reading data from 215 | * \param datalen the size of the data to read 216 | * \param buf the buffer to use (or NULL to automatically allocate one) 217 | * \param buflen the size of the buffer to use (ignored if BUF is NULL) 218 | * \param callbackfn callback function called for block of data read 219 | * \param callbackdata callback data passed to \b callbackfn 220 | * \return total number of bytes read or 0 on error or if no data was read 221 | * \sa pefile_create() 222 | * \sa pefile_readdata_fn 223 | */ 224 | DLL_EXPORT_PEDEPS uint64_t pefile_read (pefile_handle pe_file, uint64_t filepos, uint64_t datalen, void* buf, size_t buflen, pefile_readdata_fn callbackfn, void* callbackdata); 225 | 226 | /*! \brief PE file format identifiers as returned by pefile_get_signature() 227 | * \sa pefile_get_signature() 228 | * \name PE_SIGNATURE_* 229 | * \{ 230 | */ 231 | /*! \brief Windows 32-bit PE file */ 232 | #define PE_SIGNATURE_PE32 0x010B 233 | /*! \brief Windows 64-bit PE+ file */ 234 | #define PE_SIGNATURE_PE64 0x020B 235 | /*! @} */ 236 | 237 | /*! \brief get PE file format identifier 238 | * \param pe_file handle as returned by pefile_create() 239 | * \return file format identifier 240 | * \sa pefile_create() 241 | * \sa PE_SIGNATURE_* 242 | */ 243 | DLL_EXPORT_PEDEPS uint16_t pefile_get_signature (pefile_handle pe_file); 244 | 245 | /*! \brief machine architecture identifiers as returned by pefile_get_machine() 246 | * \sa pefile_get_machine() 247 | * \name PE_MACHINE_* 248 | * \{ 249 | */ 250 | #define PE_MACHINE_X86 0x014C /**< Windows x86 (32-bit) */ 251 | #define PE_MACHINE_X64 0x8664 /**< Windows AMD64 (64-bit) */ 252 | #define PE_MACHINE_IA64 0x0200 /**< Windows Itanium */ 253 | #define PE_MACHINE_ARM 0x01C0 /**< Windows ARM little endian */ 254 | #define PE_MACHINE_ARMNT 0x01C4 /**< Windows ARMv7 Thumb-2 little endian */ 255 | #define PE_MACHINE_ARM64 0xAA64 /**< Windows ARM64 little endian */ 256 | /*! @} */ 257 | 258 | /*! \brief get machine architecture identifier 259 | * \param pe_file handle as returned by pefile_create() 260 | * \return machine architecture identifier 261 | * \sa pefile_create() 262 | * \sa PE_MACHINE_* 263 | */ 264 | DLL_EXPORT_PEDEPS uint16_t pefile_get_machine (pefile_handle pe_file); 265 | 266 | /*! \brief OS subsystem identifiers as returned by pefile_get_subsystem() 267 | * \sa pefile_get_subsystem() 268 | * \name PE_SUBSYSTEM_* 269 | * \{ 270 | */ 271 | #define PE_SUBSYSTEM_WIN_GUI 2 /**< Windows GUI application */ 272 | #define PE_SUBSYSTEM_WIN_CONSOLE 3 /**< Windows console application */ 273 | /*! @} */ 274 | 275 | /*! \brief get OS subsystem identifier 276 | * \param pe_file handle as returned by pefile_create() 277 | * \return OS subsystem identifier 278 | * \sa pefile_create() 279 | * \sa PE_SUBSYSTEM_* 280 | */ 281 | DLL_EXPORT_PEDEPS uint16_t pefile_get_subsystem (pefile_handle pe_file); 282 | 283 | /*! \brief get major version number of minimum spported OS version 284 | * \param pe_file handle as returned by pefile_create() 285 | * \return major version number of minimum spported OS version 286 | * \sa pefile_get_min_os_minor() 287 | * \sa pefile_create() 288 | */ 289 | DLL_EXPORT_PEDEPS uint16_t pefile_get_min_os_major (pefile_handle pe_file); 290 | 291 | /*! \brief get minor version number of minimum spported OS version 292 | * \param pe_file handle as returned by pefile_create() 293 | * \return minor version number of minimum spported OS version 294 | * \sa pefile_get_min_os_major() 295 | * \sa pefile_create() 296 | */ 297 | DLL_EXPORT_PEDEPS uint16_t pefile_get_min_os_minor (pefile_handle pe_file); 298 | 299 | /*! \brief get major file version number 300 | * \param pe_file handle as returned by pefile_create() 301 | * \return major version number of file version 302 | * \sa pefile_get_file_version_minor() 303 | * \sa pefile_create() 304 | */ 305 | DLL_EXPORT_PEDEPS uint16_t pefile_get_file_version_major (pefile_handle pe_file); 306 | 307 | /*! \brief get minjor file version number 308 | * \param pe_file handle as returned by pefile_create() 309 | * \return minor version number of file version 310 | * \sa pefile_get_file_version_major() 311 | * \sa pefile_create() 312 | */ 313 | DLL_EXPORT_PEDEPS uint16_t pefile_get_file_version_minor (pefile_handle pe_file); 314 | 315 | /*! \brief determine if file is a DLL 316 | * \param pe_file handle as returned by pefile_create() 317 | * \return non-zero if file is a DLL file, otherwise zero (EXE file) 318 | * \sa pefile_create() 319 | */ 320 | DLL_EXPORT_PEDEPS int pefile_is_dll (pefile_handle pe_file); 321 | 322 | /*! \brief determine if debugging information was stripped 323 | * \param pe_file handle as returned by pefile_create() 324 | * \return non-zero if debugging information was stripped, otherwise zero 325 | * \sa pefile_create() 326 | */ 327 | DLL_EXPORT_PEDEPS int pefile_is_stripped (pefile_handle pe_file); 328 | 329 | /*! \brief get image base address 330 | * \param pe_file handle as returned by pefile_create() 331 | * \return image base address 332 | * \sa pefile_create() 333 | */ 334 | DLL_EXPORT_PEDEPS uint64_t pefile_get_image_base_address (pefile_handle pe_file); 335 | 336 | /*! \brief callback function called by pefile_list_imports() for each imported symbol 337 | * \param modulename name of module file where symbol is imported from 338 | * \param functionname name of imported symbol 339 | * \param callbackdata callback data passed via pefile_list_imports() 340 | * \return 0 to continue processing, non-zero to abort 341 | * \sa pefile_list_imports() 342 | */ 343 | typedef int (*PEfile_list_imports_fn) (const char* modulename, const char* functionname, void* callbackdata); 344 | 345 | /*! \brief iterate through all imported symbols 346 | * \param pe_file handle as returned by pefile_create() 347 | * \param callbackfn callback function called for each imported symbol 348 | * \param callbackdata callback data passed to \b callbackfn 349 | * \return 0 on success or one of the PE_RESULT_* status result codes 350 | * \sa pefile_create() 351 | * \sa PEfile_list_imports_fn 352 | */ 353 | DLL_EXPORT_PEDEPS int pefile_list_imports (pefile_handle pe_file, PEfile_list_imports_fn callbackfn, void* callbackdata); 354 | 355 | /*! \brief callback function called by PEfile_list_exports_fn() for each exported symbol 356 | * \param modulename name of module file (should match the file being processed) 357 | * \param functionname name of exported symbol 358 | * \param ordinal ordinal number of exported symbol 359 | * \param isdata 0 for function, non-zero for data variable 360 | * \param functionforwardername name of forwarder function (notation: module.function) or NULL of not forwarded 361 | * \param callbackdata callback data passed via pefile_list_exports() 362 | * \return 0 to continue processing, non-zero to abort 363 | * \sa pefile_list_exports() 364 | * \sa pefile_create() 365 | */ 366 | typedef int (*PEfile_list_exports_fn) (const char* modulename, const char* functionname, uint16_t ordinal, int isdata, char* functionforwardername, void* callbackdata); 367 | 368 | /*! \brief iterate through all exported symbols 369 | * \param pe_file handle as returned by pefile_create() 370 | * \param callbackfn callback function called for each exported symbol 371 | * \param callbackdata callback data passed to \b callbackfn 372 | * \return 0 on success or one of the PE_RESULT_* status result codes 373 | * \sa pefile_create() 374 | * \sa PEfile_list_exports_fn 375 | */ 376 | DLL_EXPORT_PEDEPS int pefile_list_exports (pefile_handle pe_file, PEfile_list_exports_fn callbackfn, void* callbackdata); 377 | 378 | /*! \brief structure to hold resource directory group or entry information 379 | * \sa pefile_list_resources() 380 | * \sa PEfile_list_resourcegroups_fn() 381 | * \sa PEfile_list_resources_fn() 382 | * \sa PE_RESOURCE_TYPE_* 383 | */ 384 | struct pefile_resource_directory_struct { 385 | int isnamed; /**< non-zero if entry has a name, zero if it has an ID */ 386 | wchar_t* name; /**< entry name if isnamed is non-zero (undefined if isnamed is zero) */ 387 | uint32_t id; /**< entry ID if isnamed is zero (undefined if isnamed is non-zero), one of the PE_RESOURCE_TYPE_* values if parent is NULL */ 388 | struct pefile_resource_directory_struct* parent; /**< parent entry (NULL if top level entry) */ 389 | }; 390 | 391 | /*! \brief return values for resource group callback function 392 | * \sa pefile_list_resources() 393 | * \sa PEfile_list_resourcegroups_fn() 394 | * \name PE_CB_RETURN_* 395 | * \{ 396 | */ 397 | #define PE_CB_RETURN_CONTINUE 0 /**< continue processing */ 398 | #define PE_CB_RETURN_SKIP -1 /**< skip processing this resource group */ 399 | #define PE_CB_RETURN_LAST 1 /**< process this resource group and abort processing after */ 400 | #define PE_CB_RETURN_ABORT 2 /**< abort processing */ 401 | #define PE_CB_RETURN_ERROR 9 /**< processing error */ 402 | /*! @} */ 403 | 404 | /*! \brief function type used by pefile_list_resources() when a resource group is found 405 | * \param resourcegroupinfo pointer to resource group information 406 | * \param callbackdata callback data passed via pefile_list_resources() 407 | * \return one of the PE_CB_RETURN_* values 408 | * \sa pefile_list_resources() 409 | * \sa struct pefile_resource_directory_struct 410 | * \sa PE_CB_RETURN_* 411 | * \sa PEfile_list_resources_fn 412 | */ 413 | typedef int (*PEfile_list_resourcegroups_fn) (struct pefile_resource_directory_struct* resourcegroupinfo, void* callbackdata); 414 | 415 | /*! \brief function type used by pefile_list_resources() when a resource entry is found 416 | * \param pe_file handle as returned by pefile_create() 417 | * \param resourceinfo pointer to resource entry information 418 | * \param fileposition position in the file where data is stored 419 | * \param datalen length of data 420 | * \param codepage codepage identifier (resources can exist multiple times with different codepage) 421 | * \param callbackdata callback data passed via pefile_list_resources() 422 | * \return 0 to continue reading or non-zero to abort 423 | * \sa pefile_list_resources() 424 | * \sa pefile_create() 425 | * \sa struct pefile_resource_directory_struct 426 | * \sa PEfile_list_resourcegroups_fn 427 | */ 428 | typedef int (*PEfile_list_resources_fn) (pefile_handle pe_file, struct pefile_resource_directory_struct* resourceinfo, uint32_t fileposition, uint32_t datalen, uint32_t codepage, void* callbackdata); 429 | 430 | /*! \brief iterate through all resources 431 | * \param pe_file handle as returned by pefile_create() 432 | * \param groupcallbackfn callback function called for resource group 433 | * \param entrycallbackfn callback function called for resource entry 434 | * \param callbackdata callback data passed to \b groupcallbackfn and \b entrycallbackfn 435 | * \return 0 on success or one of the PE_RESULT_* status result codes 436 | * \sa pefile_create() 437 | * \sa PEfile_list_resourcegroups_fn 438 | * \sa PEfile_list_resources_fn 439 | */ 440 | DLL_EXPORT_PEDEPS int pefile_list_resources (pefile_handle pe_file, PEfile_list_resourcegroups_fn groupcallbackfn, PEfile_list_resources_fn entrycallbackfn, void* callbackdata); 441 | 442 | #ifdef __cplusplus 443 | } 444 | #endif 445 | 446 | #endif 447 | -------------------------------------------------------------------------------- /lib/pedeps_version.h: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | Copyright (C) 2019 Brecht Sanders All Rights Reserved 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | *****************************************************************************/ 22 | 23 | /** 24 | * @file pedeps_version.h 25 | * @brief pedeps header file with version information. 26 | * @author Brecht Sanders 27 | * 28 | * Only use this header file when version information is needed at compile 29 | * time. Otherwise the version functions in the libraries should be used. 30 | * \sa PEDEPS_VERSION_* 31 | * \sa PEDEPS_VERSION 32 | * \sa PEDEPS_VERSION_STRING 33 | * \sa pedeps_get_version() 34 | * \sa pedeps_get_version_string() 35 | */ 36 | 37 | #ifndef INCLUDED_PEDEPS_VERSION_H 38 | #define INCLUDED_PEDEPS_VERSION_H 39 | 40 | /*! \brief version number constants 41 | * \sa pedeps_get_version() 42 | * \sa pedeps_get_version_string() 43 | * \name PEDEPS_VERSION_* 44 | * \{ 45 | */ 46 | /*! \brief major version number */ 47 | #define PEDEPS_VERSION_MAJOR 0 48 | /*! \brief minor version number */ 49 | #define PEDEPS_VERSION_MINOR 1 50 | /*! \brief micro version number */ 51 | #define PEDEPS_VERSION_MICRO 15 52 | /*! @} */ 53 | 54 | /*! \brief packed version number */ 55 | #define PEDEPS_VERSION (PEDEPS_VERSION_MAJOR * 0x01000000 + PEDEPS_VERSION_MINOR * 0x00010000 + PEDEPS_VERSION_MICRO * 0x00000100) 56 | 57 | /*! \cond PRIVATE */ 58 | #define PEDEPS_VERSION_STRINGIZE_(major, minor, micro) #major"."#minor"."#micro 59 | #define PEDEPS_VERSION_STRINGIZE(major, minor, micro) PEDEPS_VERSION_STRINGIZE_(major, minor, micro) 60 | /*! \endcond */ 61 | 62 | /*! \brief string with dotted version number \hideinitializer */ 63 | #define PEDEPS_VERSION_STRING PEDEPS_VERSION_STRINGIZE(PEDEPS_VERSION_MAJOR, PEDEPS_VERSION_MINOR, PEDEPS_VERSION_MICRO) 64 | 65 | /*! \brief string with name of pedeps library */ 66 | #define PEDEPS_NAME "pedeps" 67 | 68 | /*! \brief string with name and version of pedeps library \hideinitializer */ 69 | #define PEDEPS_FULLNAME PEDEPS_NAME " " PEDEPS_VERSION_STRING 70 | 71 | #endif 72 | -------------------------------------------------------------------------------- /lib/pestructs.c: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | Copyright (C) 2019 Brecht Sanders All Rights Reserved 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | The above copyright notice and this permission notice shall be included in 10 | all copies or substantial portions of the Software. 11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 12 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 13 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 14 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 15 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 16 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 17 | THE SOFTWARE. 18 | *****************************************************************************/ 19 | 20 | #include "pestructs.h" 21 | #include 22 | 23 | DLL_EXPORT_PEDEPS struct peheader_imagesection* pe_find_rva_section (struct peheader_imagesection* sections, uint16_t sectioncount, uint32_t rva) 24 | { 25 | uint16_t i; 26 | for (i = 0; i < sectioncount; i++) { 27 | if (rva >= sections[i].VirtualAddress && rva < sections[i].VirtualAddress + sections[i].SizeOfRawData) 28 | return &(sections[i]); 29 | } 30 | return NULL; 31 | } 32 | 33 | DLL_EXPORT_PEDEPS const char* pe_get_arch_name (uint16_t machine) 34 | { 35 | switch (machine) { 36 | case 0x014C: return "x86"; 37 | //case 0x0162: return "MIPS R3000"; 38 | //case 0x0168: return "MIPS R10000"; 39 | //case 0x0169: return "MIPS little endian WCI v2"; 40 | //case 0x0183: return "old Alpha AXP"; 41 | //case 0x0184: return "Alpha AXP"; 42 | //case 0x01A2: return "Hitachi SH3"; 43 | //case 0x01A3: return "Hitachi SH3 DSP"; 44 | //case 0x01A6: return "Hitachi SH4"; 45 | //case 0x01A8: return "Hitachi SH5"; 46 | //case 0x01C0: return "ARM little endian"; 47 | //case 0x01C2: return "Thumb"; 48 | case 0x01C4: return "armv7"; 49 | //case 0x01D3: return "Matsushita AM33"; 50 | //case 0x01F0: return "PowerPC little endian"; 51 | //case 0x01F1: return "PowerPC with floating point support"; 52 | case 0x0200: return "ia64"; 53 | //case 0x0266: return "MIPS16"; 54 | case 0x0268: return "m68k"; 55 | case 0x0284: return "alpha"; 56 | //case 0x0366: return "MIPS with FPU"; 57 | //case 0x0466: return "MIPS16 with FPU"; 58 | case 0x0EBC: return "EFI Byte Code"; 59 | case 0x8664: return "x86_64"; 60 | //case 0x9041: return "Mitsubishi M32R little endian"; 61 | case 0xAA64: return "aarch64"; 62 | //case 0xC0EE: return "clr pure MSIL"; 63 | default: return "(unknown)"; 64 | } 65 | return NULL; 66 | } 67 | 68 | DLL_EXPORT_PEDEPS const char* pe_get_machine_name (uint16_t machine) 69 | { 70 | switch (machine) { 71 | case 0x014C: return "Intel 386 (x86)"; 72 | case 0x0162: return "MIPS R3000"; 73 | case 0x0168: return "MIPS R10000"; 74 | case 0x0169: return "MIPS little endian WCI v2"; 75 | case 0x0183: return "old Alpha AXP"; 76 | case 0x0184: return "Alpha AXP"; 77 | case 0x01A2: return "Hitachi SH3"; 78 | case 0x01A3: return "Hitachi SH3 DSP"; 79 | case 0x01A6: return "Hitachi SH4"; 80 | case 0x01A8: return "Hitachi SH5"; 81 | case 0x01C0: return "ARM little endian"; 82 | case 0x01C2: return "Thumb"; 83 | case 0x01C4: return "ARMv7"; 84 | case 0x01D3: return "Matsushita AM33"; 85 | case 0x01F0: return "PowerPC little endian"; 86 | case 0x01F1: return "PowerPC with floating point support"; 87 | case 0x0200: return "Intel IA64"; 88 | case 0x0266: return "MIPS16"; 89 | case 0x0268: return "Motorola 68000 series"; 90 | case 0x0284: return "Alpha AXP 64-bit"; 91 | case 0x0366: return "MIPS with FPU"; 92 | case 0x0466: return "MIPS16 with FPU"; 93 | case 0x0EBC: return "EFI Byte Code"; 94 | case 0x8664: return "AMD AMD64 (x64)"; 95 | case 0x9041: return "Mitsubishi M32R little endian"; 96 | case 0xAA64: return "ARM64 little endian"; 97 | case 0xC0EE: return "clr pure MSIL"; 98 | default: return "(unknown)"; 99 | } 100 | return NULL; 101 | } 102 | 103 | DLL_EXPORT_PEDEPS int pe_get_machine_bits (uint16_t machine) 104 | { 105 | switch (machine) { 106 | case 0x014C: return 32; 107 | case 0x01C0: return 32; 108 | case 0x01C4: return 32; 109 | case 0x0200: return 64; 110 | case 0x8664: return 64; 111 | case 0xAA64: return 64; 112 | default: return 0; 113 | } 114 | return 0; 115 | } 116 | 117 | DLL_EXPORT_PEDEPS const char* pe_get_subsystem_name (uint16_t subsystem) 118 | { 119 | switch (subsystem) { 120 | case 0: return "generic"; 121 | case 1: return "native"; //(device drivers and native system processes) 122 | case 2: return "Windows GUI"; 123 | case 3: return "Windows console"; //Windows CUI 124 | case 5: return "OS/2 console"; //OS/2 CUI 125 | case 7: return "POSIX console"; //POSIX CUI 126 | case 9: return "Windows CE GUI"; 127 | case 10: return "EFI"; //Extensible Firmware Interface (EFI) 128 | case 11: return "EFI/boot"; //EFI driver with boot services 129 | case 12: return "EFI/runtime"; //EFI driver with run-time services 130 | case 13: return "EFI ROM image"; 131 | case 14: return "Xbox"; 132 | case 16: return "boot application"; 133 | default: return "(unknown)"; 134 | } 135 | return NULL; 136 | } 137 | 138 | DLL_EXPORT_PEDEPS const char* pe_get_resourceid_name (uint32_t resourceid) 139 | { 140 | switch (resourceid) { 141 | case PE_RESOURCE_TYPE_CURSOR: return "cursor"; 142 | case PE_RESOURCE_TYPE_BITMAP: return "bitmap"; 143 | case PE_RESOURCE_TYPE_ICON: return "icon"; 144 | case PE_RESOURCE_TYPE_MENU: return "menu"; 145 | case PE_RESOURCE_TYPE_DIALOG: return "dialog"; 146 | case PE_RESOURCE_TYPE_STRING: return "string"; 147 | case PE_RESOURCE_TYPE_FONTDIR: return "fontdir"; 148 | case PE_RESOURCE_TYPE_FONT: return "font"; 149 | case PE_RESOURCE_TYPE_ACCELERATOR: return "accelerator"; 150 | case PE_RESOURCE_TYPE_RCDATA: return "rcdata"; 151 | case PE_RESOURCE_TYPE_MESSAGETABLE: return "messagetable"; 152 | case PE_RESOURCE_TYPE_GROUP_CURSOR: return "group_cursor"; 153 | case PE_RESOURCE_TYPE_GROUP_ICON: return "group_icon"; 154 | case PE_RESOURCE_TYPE_VERSION: return "version"; 155 | case PE_RESOURCE_TYPE_DLGINCLUDE: return "dlginclude"; 156 | case PE_RESOURCE_TYPE_PLUGPLAY: return "plugplay"; 157 | case PE_RESOURCE_TYPE_VXD: return "vxd"; 158 | case PE_RESOURCE_TYPE_ANICURSOR: return "anicursor"; 159 | case PE_RESOURCE_TYPE_ANIICON: return "aniicon"; 160 | case PE_RESOURCE_TYPE_HTML: return "html"; 161 | case PE_RESOURCE_TYPE_MANIFEST: return "manifest"; 162 | default: return "(unknown)"; 163 | } 164 | return NULL; 165 | } 166 | 167 | DLL_EXPORT_PEDEPS const char* pe_version_fileinfo_get_type_name (uint32_t filetype) 168 | { 169 | switch (filetype) { 170 | case PE_VERSION_FILEINFO_TYPE_APP: return "Application"; 171 | case PE_VERSION_FILEINFO_TYPE_DLL: return "DLL"; 172 | case PE_VERSION_FILEINFO_TYPE_DRV: return "Device driver"; 173 | case PE_VERSION_FILEINFO_TYPE_FONT: return "Font"; 174 | case PE_VERSION_FILEINFO_TYPE_VXD: return "Virtual device"; 175 | case PE_VERSION_FILEINFO_TYPE_STATIC_LIB: return "Static-link library"; 176 | default: return "(unknown file type)"; 177 | } 178 | return NULL; 179 | } 180 | 181 | DLL_EXPORT_PEDEPS const char* pe_version_fileinfo_get_subtype_name (uint32_t filetype, uint32_t filesubtype) 182 | { 183 | switch (filetype) { 184 | case PE_VERSION_FILEINFO_TYPE_DRV: 185 | switch (filesubtype) { 186 | case PE_VERSION_FILEINFO_SUBTYPE_DRV_COMM: return "communications driver"; 187 | case PE_VERSION_FILEINFO_SUBTYPE_DRV_DISPLAY: return "display driver"; 188 | case PE_VERSION_FILEINFO_SUBTYPE_DRV_INSTALLABLE: return "installable driver"; 189 | case PE_VERSION_FILEINFO_SUBTYPE_DRV_KEYBOARD: return "keyboard driver"; 190 | case PE_VERSION_FILEINFO_SUBTYPE_DRV_LANGUAGE: return "language driver"; 191 | case PE_VERSION_FILEINFO_SUBTYPE_DRV_MOUSE: return "mouse driver"; 192 | case PE_VERSION_FILEINFO_SUBTYPE_DRV_NETWORK: return "network driver"; 193 | case PE_VERSION_FILEINFO_SUBTYPE_DRV_PRINTER: return "printer driver"; 194 | case PE_VERSION_FILEINFO_SUBTYPE_DRV_SOUND: return "sound driver"; 195 | case PE_VERSION_FILEINFO_SUBTYPE_DRV_SYSTEM: return "system driver"; 196 | case PE_VERSION_FILEINFO_SUBTYPE_DRV_VERSIONED_PRINTER: return "versioned printer driver"; 197 | default: return "(unknown driver type)"; 198 | } 199 | break; 200 | case PE_VERSION_FILEINFO_TYPE_FONT: 201 | switch (filesubtype) { 202 | case PE_VERSION_FILEINFO_SUBTYPE_FONT_RASTER: return "raster font"; 203 | case PE_VERSION_FILEINFO_SUBTYPE_FONT_TRUETYPE: return "TrueType font"; 204 | case PE_VERSION_FILEINFO_SUBTYPE_FONT_VECTOR: return "vector font"; 205 | default: return "(unknown font type)"; 206 | } 207 | break; 208 | case PE_VERSION_FILEINFO_TYPE_VXD: 209 | return "(subtype value is virtual device identifier)"; 210 | default: 211 | return "-"; 212 | } 213 | return NULL; 214 | } 215 | 216 | -------------------------------------------------------------------------------- /lib/pestructs.h: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | Copyright (C) 2019 Brecht Sanders All Rights Reserved 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | The above copyright notice and this permission notice shall be included in 10 | all copies or substantial portions of the Software. 11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 12 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 13 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 14 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 15 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 16 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 17 | THE SOFTWARE. 18 | *****************************************************************************/ 19 | 20 | /** 21 | * @file pestructs.h 22 | * @brief pedeps library header file with PE(+) data structures 23 | * @author Brecht Sanders 24 | * 25 | * This header file defines the structures needed by the pedeps library 26 | */ 27 | 28 | #ifndef INCLUDED_PE_STRUCTURES_H 29 | #define INCLUDED_PE_STRUCTURES_H 30 | 31 | #include 32 | #include 33 | 34 | /*! \cond PRIVATE */ 35 | #if !defined(DLL_EXPORT_PEDEPS) 36 | # if defined(_WIN32) && defined(BUILD_PEDEPS_DLL) 37 | # define DLL_EXPORT_PEDEPS __declspec(dllexport) 38 | # elif defined(_WIN32) && !defined(STATIC) && !defined(BUILD_PEDEPS_STATIC) && !defined(BUILD_PEDEPS) 39 | # define DLL_EXPORT_PEDEPS __declspec(dllimport) 40 | # else 41 | # define DLL_EXPORT_PEDEPS 42 | # endif 43 | #endif 44 | /*! \endcond */ 45 | 46 | #ifdef __cplusplus 47 | extern "C" { 48 | #endif 49 | 50 | /*! \brief DOS header 51 | */ 52 | struct PEheader_DOS { 53 | uint16_t e_magic; /**< Magic number */ 54 | uint16_t e_cblp; /**< Bytes on last page of file */ 55 | uint16_t e_cp; /**< Pages in file */ 56 | uint16_t e_crlc; /**< Relocations */ 57 | uint16_t e_cparhdr; /**< Size of header in paragraphs */ 58 | uint16_t e_minalloc; /**< Minimum extra paragraphs needed */ 59 | uint16_t e_maxalloc; /**< Maximum extra paragraphs needed */ 60 | uint16_t e_ss; /**< Initial (relative) SS value */ 61 | uint16_t e_sp; /**< Initial SP value */ 62 | uint16_t e_csum; /**< Checksum */ 63 | uint16_t e_ip; /**< Initial IP value */ 64 | uint16_t e_cs; /**< Initial (relative) CS value */ 65 | uint16_t e_lfarlc; /**< File address of relocation table */ 66 | uint16_t e_ovno; /**< Overlay number */ 67 | uint16_t e_res[4]; /**< Reserved words */ 68 | uint16_t e_oemid; /**< OEM identifier (for e_oeminfo) */ 69 | uint16_t e_oeminfo; /**< OEM information; e_oemid specific */ 70 | uint16_t e_res2[10]; /**< Reserved words */ 71 | uint32_t e_lfanew; /**< File address of new exe header */ 72 | }; 73 | 74 | /*! \brief PE header 75 | * \sa PE_SIGNATURE_* 76 | */ 77 | struct PEheader_PE { 78 | uint32_t signature; /**< PE file signature */ 79 | }; 80 | 81 | /*! \brief COFF header 82 | * \sa PE_CHARACTERISTIC_* 83 | */ 84 | struct PEheader_COFF { 85 | uint16_t Machine; /**< The number that identifies the type of target machine. */ 86 | uint16_t NumberOfSections; /**< The number of sections. This indicates the size of the section table, which immediately follows the headers. */ 87 | uint32_t TimeDateStamp; /**< The low 32 bits of the number of seconds since 00:00 January 1, 1970 (a C run-time time_t value), that indicates when the file was created. */ 88 | uint32_t PointerToSymbolTable; /**< The file offset of the COFF symbol table, or zero if no COFF symbol table is present. This value should be zero for an image because COFF debugging information is deprecated. */ 89 | uint32_t NumberOfSymbols; /**< The number of entries in the symbol table. This data can be used to locate the string table, which immediately follows the symbol table. This value should be zero for an image because COFF debugging information is deprecated. */ 90 | uint16_t SizeOfOptionalHeader; /**< The size of the optional header, which is required for executable files but not for object files. This value should be zero for an object file. */ 91 | uint16_t Characteristics; /**< The flags that indicate the attributes of the file. */ 92 | }; 93 | 94 | /*! \brief PE/COFF header charachteristics masks 95 | * \sa PEheader_COFF 96 | * \name PE_CHARACTERISTIC_* 97 | * \{ 98 | */ 99 | #define PE_CHARACTERISTIC_IMAGE_FILE_RELOCS_STRIPPED 0x0001 /**< Relocation information was stripped from the file. The file must be loaded at its preferred base address. If the base address is not available, the loader reports an error. */ 100 | #define PE_CHARACTERISTIC_IMAGE_FILE_EXECUTABLE_IMAGE 0x0002 /**< The file is executable (there are no unresolved external references). */ 101 | #define PE_CHARACTERISTIC_IMAGE_FILE_LINE_NUMS_STRIPPED 0x0004 /**< COFF line numbers were stripped from the file. */ 102 | #define PE_CHARACTERISTIC_IMAGE_FILE_LOCAL_SYMS_STRIPPED 0x0008 /**< COFF symbol table entries were stripped from file. */ 103 | #define PE_CHARACTERISTIC_IMAGE_FILE_AGGRESIVE_WS_TRIM 0x0010 /**< Aggressively trim the working set. This value is obsolete. */ 104 | #define PE_CHARACTERISTIC_IMAGE_FILE_LARGE_ADDRESS_AWARE 0x0020 /**< The application can handle addresses larger than 2 GB. */ 105 | #define PE_CHARACTERISTIC_IMAGE_FILE_BYTES_REVERSED_LO 0x0080 /**< The bytes of the word are reversed. This flag is obsolete. */ 106 | #define PE_CHARACTERISTIC_IMAGE_FILE_32BIT_MACHINE 0x0100 /**< The computer supports 32-bit words. */ 107 | #define PE_CHARACTERISTIC_IMAGE_FILE_DEBUG_STRIPPED 0x0200 /**< Debugging information was removed and stored separately in another file. */ 108 | #define PE_CHARACTERISTIC_IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP 0x0400 /**< If the image is on removable media, copy it to and run it from the swap file. */ 109 | #define PE_CHARACTERISTIC_IMAGE_FILE_NET_RUN_FROM_SWAP 0x0800 /**< If the image is on the network, copy it to and run it from the swap file. */ 110 | #define PE_CHARACTERISTIC_IMAGE_FILE_SYSTEM 0x1000 /**< The image is a system file. */ 111 | #define PE_CHARACTERISTIC_IMAGE_FILE_DLL 0x2000 /**< The image is a DLL file. While it is an executable file, it cannot be run directly. */ 112 | #define PE_CHARACTERISTIC_IMAGE_FILE_UP_SYSTEM_ONLY 0x4000 /**< The file should be run only on a uniprocessor computer. */ 113 | #define PE_CHARACTERISTIC_IMAGE_FILE_BYTES_REVERSED_HI 0x8000 /**< The bytes of the word are reversed. This flag is obsolete. */ 114 | /*! @} */ 115 | 116 | /*! \brief common section in the beginning of the optional header 117 | */ 118 | struct PEheader_optional_common { 119 | uint16_t Signature; /**< The unsigned integer that identifies the state of the image file. Decimal number 267 for 32 bit, 523 for 64 bit, and 263 for a ROM image. */ 120 | uint8_t MajorLinkerVersion; /**< The linker major version number. */ 121 | uint8_t MinorLinkerVersion; /**< The linker minor version number. */ 122 | uint32_t SizeOfCode; /**< The size of the code (text) section, or the sum of all code sections if there are multiple sections. */ 123 | uint32_t SizeOfInitializedData; /**< The size of the initialized data section, or the sum of all such sections if there are multiple data sections */ 124 | uint32_t SizeOfUninitializedData; /**< The size of the uninitialized data section (BSS), or the sum of all such sections if there are multiple BSS sections. */ 125 | uint32_t AddressOfEntryPoint; /**< The RVA of the code entry point. The address of the entry point relative to the image base when the executable file is loaded into memory. For program images, this is the starting address. For device drivers, this is the address of the initialization function. An entry point is optional for DLLs. When no entry point is present, this field must be zero. */ 126 | uint32_t BaseOfCode; /**< The address that is relative to the image base of the beginning-of-code section when it is loaded into memory. */ 127 | }; 128 | 129 | /*! \brief data directory 130 | * \sa PE_DATA_DIR_IDX_* 131 | */ 132 | struct PEheader_data_directory { 133 | uint32_t VirtualAddress; /**< RVA of the table. The RVA is the address of the table relative to the base address of the image when the table is loaded. */ 134 | uint32_t Size; /**< Size in bytes. */ 135 | }; 136 | 137 | /*! \brief data directory indices 138 | * \sa PEheader_data_directory 139 | * \name PE_DATA_DIR_IDX_* 140 | * \{ 141 | */ 142 | #define PE_DATA_DIR_IDX_EXPORT 0 /**< export directory */ 143 | #define PE_DATA_DIR_IDX_IMPORT 1 /**< import directory */ 144 | #define PE_DATA_DIR_IDX_RESOURCE 2 /**< resource directory */ 145 | #define PE_DATA_DIR_IDX_EXCEPTION 3 /**< exception directory */ 146 | #define PE_DATA_DIR_IDX_SECURITY 4 /**< security directory */ 147 | #define PE_DATA_DIR_IDX_BASERELOC 5 /**< base relocation table */ 148 | #define PE_DATA_DIR_IDX_DEBUG 6 /**< debug directory */ 149 | #define PE_DATA_DIR_IDX_ARCHITECTURE 7 /**< architecture specific data */ 150 | #define PE_DATA_DIR_IDX_GLOBALPTR 8 /**< RVA of GP */ 151 | #define PE_DATA_DIR_IDX_TLS 9 /**< TLS directory */ 152 | #define PE_DATA_DIR_IDX_LOAD_CONFIG 10 /**< load configuration directory */ 153 | #define PE_DATA_DIR_IDX_BOUND_IMPORT 11 /**< bound import directory in headers */ 154 | #define PE_DATA_DIR_IDX_IAT 12 /**< import address table */ 155 | #define PE_DATA_DIR_IDX_DELAY_IMPORT 13 /**< delay load import descriptors */ 156 | #define PE_DATA_DIR_IDX_COM_DESCRIPTOR 14 /**< COM runtime descriptor */ 157 | #define PE_DATA_DIR_IDX_RESERVED 15 /**< reserved for future use */ 158 | #define PE_DATA_DIR_IDX_COUNT 16 /**< number of indeces defined */ 159 | /*! @} */ 160 | 161 | /*! \brief common section within the optional header 162 | * \sa PE_DLLCHARACTERISTICS_* 163 | */ 164 | struct PEheader_optional_commonext { 165 | uint32_t SectionAlignment; /**< The alignment (in bytes) of sections when they are loaded into memory. It must be greater than or equal to FileAlignment. The default is the page size for the architecture. */ 166 | uint32_t FileAlignment; /**< The alignment factor (in bytes) that is used to align the raw data of sections in the image file. The value should be a power of 2 between 512 and 64 K, inclusive. The default is 512. If the SectionAlignment is less than the architecture's page size, then FileAlignment must match SectionAlignment. */ 167 | uint16_t MajorOSVersion; /**< The major version number of the required operating system. */ 168 | uint16_t MinorOSVersion; /**< The minor version number of the required operating system. */ 169 | uint16_t MajorImageVersion; /**< The major version number of the image. */ 170 | uint16_t MinorImageVersion; /**< The minor version number of the image. */ 171 | uint16_t MajorSubsystemVersion; /**< The major version number of the subsystem. */ 172 | uint16_t MinorSubsystemVersion; /**< The minor version number of the subsystem. */ 173 | uint32_t Win32VersionValue; /**< Reserved, must be zero. */ 174 | uint32_t SizeOfImage; /**< The size (in bytes) of the image, including all headers, as the image is loaded in memory. It must be a multiple of SectionAlignment. */ 175 | uint32_t SizeOfHeaders; /**< The combined size of an MS-DOS stub, PE header, and section headers rounded up to a multiple of FileAlignment. */ 176 | uint32_t Checksum; /**< The image file checksum. The algorithm for computing the checksum is incorporated into IMAGHELP.DLL. The following are checked for validation at load time: all drivers, any DLL loaded at boot time, and any DLL that is loaded into a critical Windows process. */ 177 | uint16_t Subsystem; /**< The subsystem that is required to run this image. For more information, see Windows Subsystem. */ 178 | uint16_t DLLCharacteristics; /**< For more information, see DLL Characteristics later in this specification. */ 179 | }; 180 | 181 | /*! \brief DLL characteristics 182 | * \sa PEheader_optional_commonext 183 | * \name PE_DLLCHARACTERISTICS_* 184 | * \{ 185 | */ 186 | #define PE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA 0x0020 /**< Image can handle a high entropy 64-bit virtual address space. */ 187 | #define PE_DLLCHARACTERISTICS_DYNAMIC_BASE 0x0040 /**< DLL can be relocated at load time. */ 188 | #define PE_DLLCHARACTERISTICS_FORCE_INTEGRITY 0x0080 /**< Code Integrity checks are enforced. */ 189 | #define PE_DLLCHARACTERISTICS_NX_COMPAT 0x0100 /**< Image is NX compatible. */ 190 | #define PE_DLLCHARACTERISTICS_NO_ISOLATION 0x0200 /**< Isolation aware, but do not isolate the image. */ 191 | #define PE_DLLCHARACTERISTICS_NO_SEH 0x0400 /**< Does not use structured exception (SE) handling. No SE handler may be called in this image. */ 192 | #define PE_DLLCHARACTERISTICS_NO_BIND 0x0800 /**< Do not bind the image. */ 193 | #define PE_DLLCHARACTERISTICS_APPCONTAINER 0x1000 /**< Image must execute in an AppContainer. */ 194 | #define PE_DLLCHARACTERISTICS_WDM_DRIVER 0x2000 /**< A WDM driver. */ 195 | #define PE_DLLCHARACTERISTICS_GUARD_CF 0x4000 /**< Image supports Control Flow Guard. */ 196 | #define PE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE 0x8000 /**< Terminal Server aware. */ 197 | /*! @} */ 198 | 199 | /*! \brief PE (32-bit) optional header 200 | */ 201 | struct PEheader_optional32 { 202 | struct PEheader_optional_common common; /**< common fields of optional header */ 203 | uint32_t BaseOfData; /**< The address that is relative to the image base of the beginning-of-data section when it is loaded into memory. */ 204 | /*The next 21 fields are an extension to the COFF optional header format*/ 205 | uint32_t ImageBase; /**< The preferred address of the first byte of image when loaded into memory; must be a multiple of 64 K. The default for DLLs is 0x10000000. The default for Windows CE EXEs is 0x00010000. The default for Windows NT, Windows 2000, Windows XP, Windows 95, Windows 98, and Windows Me is 0x00400000. */ 206 | struct PEheader_optional_commonext commonext; /**< common section within the optional header */ 207 | uint32_t SizeOfStackReserve; /**< The size of the stack to reserve. Only SizeOfStackCommit is committed; the rest is made available one page at a time until the reserve size is reached. */ 208 | uint32_t SizeOfStackCommit; /**< The size of the stack to commit. */ 209 | uint32_t SizeOfHeapReserve; /**< The size of the local heap space to reserve. Only SizeOfHeapCommit is committed; the rest is made available one page at a time until the reserve size is reached. */ 210 | uint32_t SizeOfHeapCommit; /**< The size of the local heap space to commit. */ 211 | uint32_t LoaderFlags; /**< Reserved, must be zero. */ 212 | uint32_t NumberOfRvaAndSizes; /**< The number of data-directory entries in the remainder of the optional header. Each describes a location and size. */ 213 | struct PEheader_data_directory datadirs[1]; /**< placeholder for the first data directory */ 214 | }; 215 | 216 | /*! \brief PE+ (64-bit) optional header 217 | */ 218 | struct PEheader_optional64 { 219 | struct PEheader_optional_common common; /**< common fields of optional header */ 220 | /*The next 21 fields are an extension to the COFF optional header format*/ 221 | uint64_t ImageBase; /**< The preferred address of the first byte of image when loaded into memory; must be a multiple of 64 K. The default for DLLs is 0x10000000. The default for Windows CE EXEs is 0x00010000. The default for Windows NT, Windows 2000, Windows XP, Windows 95, Windows 98, and Windows Me is 0x00400000. */ 222 | struct PEheader_optional_commonext commonext; /**< common section within the optional header */ 223 | uint64_t SizeOfStackReserve; /**< The size of the stack to reserve. Only SizeOfStackCommit is committed; the rest is made available one page at a time until the reserve size is reached. */ 224 | uint64_t SizeOfStackCommit; /**< The size of the stack to commit. */ 225 | uint64_t SizeOfHeapReserve; /**< The size of the local heap space to reserve. Only SizeOfHeapCommit is committed; the rest is made available one page at a time until the reserve size is reached. */ 226 | uint64_t SizeOfHeapCommit; /**< The size of the local heap space to commit. */ 227 | uint32_t LoaderFlags; /**< Reserved, must be zero. */ 228 | uint32_t NumberOfRvaAndSizes; /**< The number of data-directory entries in the remainder of the optional header. Each describes a location and size. */ 229 | struct PEheader_data_directory datadirs[1]; /**< placeholder for the first data directory */ 230 | }; 231 | 232 | /*! \brief union of different optional headers 233 | */ 234 | union PEheader_optional { 235 | struct PEheader_optional_common common; /**< common fields of optional header */ 236 | struct PEheader_optional32 opt32; /**< PE (32-bit) optional header */ 237 | struct PEheader_optional64 opt64; /**< PE+ (64-bit) optional header */ 238 | }; 239 | 240 | /*! \brief image section header 241 | * \sa PE_IMGSECTION_TYPE_* 242 | */ 243 | struct peheader_imagesection { 244 | uint8_t Name[8]; /**< An 8-byte, null-padded UTF-8 encoded string. If the string is exactly 8 characters long, there is no terminating null. For longer names, this field contains a slash (/) that is followed by an ASCII representation of a decimal number that is an offset into the string table. Executable images do not use a string table and do not support section names longer than 8 characters. Long names in object files are truncated if they are emitted to an executable file. */ 245 | union { 246 | uint32_t PhysicalAddress; /**< The file address. */ 247 | uint32_t VirtualSize; /**< The total size of the section when loaded into memory. If this value is greater than SizeOfRawData, the section is zero-padded. This field is valid only for executable images and should be set to zero for object files. */ 248 | } Misc; /**< union with 2 possible meanings of this field */ 249 | uint32_t VirtualAddress; /**< For executable images, the address of the first byte of the section relative to the image base when the section is loaded into memory. For object files, this field is the address of the first byte before relocation is applied; for simplicity, compilers should set this to zero. Otherwise, it is an arbitrary value that is subtracted from offsets during relocation. */ 250 | uint32_t SizeOfRawData; /**< The size of the section (for object files) or the size of the initialized data on disk (for image files). For executable images, this must be a multiple of FileAlignment from the optional header. If this is less than VirtualSize, the remainder of the section is zero-filled. Because the SizeOfRawData field is rounded but the VirtualSize field is not, it is possible for SizeOfRawData to be greater than VirtualSize as well. When a section contains only uninitialized data, this field should be zero. */ 251 | uint32_t PointerToRawData; /**< The file pointer to the first page of the section within the COFF file. For executable images, this must be a multiple of FileAlignment from the optional header. For object files, the value should be aligned on a 4-byte boundary for best performance. When a section contains only uninitialized data, this field should be zero. */ 252 | uint32_t PointerToRelocations; /**< The file pointer to the beginning of relocation entries for the section. This is set to zero for executable images or if there are no relocations. */ 253 | uint32_t PointerToLinenumbers; /**< The file pointer to the beginning of line-number entries for the section. This is set to zero if there are no COFF line numbers. This value should be zero for an image because COFF debugging information is deprecated. */ 254 | uint16_t NumberOfRelocations; /**< The number of relocation entries for the section. This is set to zero for executable images. */ 255 | uint16_t NumberOfLinenumbers; /**< The number of line-number entries for the section. This value should be zero for an image because COFF debugging information is deprecated. */ 256 | uint32_t Characteristics; /**< The flags that describe the characteristics of the section. */ 257 | }; 258 | 259 | /*! \brief image section types 260 | * \sa peheader_imagesection 261 | * \name PE_IMGSECTION_TYPE_* 262 | * \{ 263 | */ 264 | #define PE_IMGSECTION_TYPE_CODE 0x00000020 /**< The section contains executable code. */ 265 | #define PE_IMGSECTION_TYPE_INITIALIZED_DATA 0x00000040 /**< The section contains initialized data. */ 266 | #define PE_IMGSECTION_TYPE_UNINITIALIZED_DATA 0x00000080 /**< The section contains uninitialized data. */ 267 | #define PE_IMGSECTION_TYPE_LINK_INFO 0x00000200 /**< The section contains comments or other information. The .drectve section has this type. This is valid for object files only. */ 268 | #define PE_IMGSECTION_TYPE_LINK_REMOVE 0x00000800 /**< The section will not become part of the image. This is valid only for object files. */ 269 | #define PE_IMGSECTION_TYPE_LINK_COMDAT 0x00001000 /**< The section contains COMDAT data. */ 270 | #define PE_IMGSECTION_TYPE_NO_DEFER_SPEC_EXC 0x00004000 /**< Reset speculative exceptions handling bits in the TLB entries for this section. */ 271 | #define PE_IMGSECTION_TYPE_GPREL 0x00008000 /**< The section contains data referenced through the global pointer (GP). */ 272 | //#define PE_IMGSECTION_TYPE_MEM_PURGEABLE 0x00020000 /**< Reserved for future use. */ 273 | //#define PE_IMGSECTION_TYPE_MEM_LOCKED 0x00040000 /**< Reserved for future use. */ 274 | //#define PE_IMGSECTION_TYPE_MEM_PRELOAD 0x00080000 /**< Reserved for future use. */ 275 | #define PE_IMGSECTION_TYPE_ALIGN_1BYTES 0x00100000 /**< Align data on a 1-byte boundary. Valid only for object files. */ 276 | #define PE_IMGSECTION_TYPE_ALIGN_2BYTES 0x00200000 /**< Align data on a 2-byte boundary. Valid only for object files. */ 277 | #define PE_IMGSECTION_TYPE_ALIGN_4BYTES 0x00300000 /**< Align data on a 4-byte boundary. Valid only for object files. */ 278 | #define PE_IMGSECTION_TYPE_ALIGN_8BYTES 0x00400000 /**< Align data on an 8-byte boundary. Valid only for object files. */ 279 | #define PE_IMGSECTION_TYPE_ALIGN_16BYTES 0x00500000 /**< Align data on a 16-byte boundary. Valid only for object files. */ 280 | #define PE_IMGSECTION_TYPE_ALIGN_32BYTES 0x00600000 /**< Align data on a 32-byte boundary. Valid only for object files. */ 281 | #define PE_IMGSECTION_TYPE_ALIGN_64BYTES 0x00700000 /**< Align data on a 64-byte boundary. Valid only for object files. */ 282 | #define PE_IMGSECTION_TYPE_ALIGN_128BYTES 0x00800000 /**< Align data on a 128-byte boundary. Valid only for object files. */ 283 | #define PE_IMGSECTION_TYPE_ALIGN_256BYTES 0x00900000 /**< Align data on a 256-byte boundary. Valid only for object files. */ 284 | #define PE_IMGSECTION_TYPE_ALIGN_512BYTES 0x00A00000 /**< Align data on a 512-byte boundary. Valid only for object files. */ 285 | #define PE_IMGSECTION_TYPE_ALIGN_1024BYTES 0x00B00000 /**< Align data on a 1024-byte boundary. Valid only for object files. */ 286 | #define PE_IMGSECTION_TYPE_ALIGN_2048BYTES 0x00C00000 /**< Align data on a 2048-byte boundary. Valid only for object files. */ 287 | #define PE_IMGSECTION_TYPE_ALIGN_4096BYTES 0x00D00000 /**< Align data on a 4096-byte boundary. Valid only for object files. */ 288 | #define PE_IMGSECTION_TYPE_ALIGN_8192BYTES 0x00E00000 /**< Align data on an 8192-byte boundary. Valid only for object files. */ 289 | #define PE_IMGSECTION_TYPE_LNK_NRELOC_OVFL 0x01000000 /**< The section contains extended relocations. */ 290 | #define PE_IMGSECTION_TYPE_MEM_DISCARDABLE 0x02000000 /**< The section can be discarded as needed. */ 291 | #define PE_IMGSECTION_TYPE_MEM_NOT_CACHED 0x04000000 /**< The section cannot be cached. */ 292 | #define PE_IMGSECTION_TYPE_MEM_NOT_PAGED 0x08000000 /**< The section is not pageable. */ 293 | #define PE_IMGSECTION_TYPE_MEM_SHARED 0x10000000 /**< The section can be shared in memory. */ 294 | #define PE_IMGSECTION_TYPE_MEM_EXECUTE 0x20000000 /**< The section can be executed as code. */ 295 | #define PE_IMGSECTION_TYPE_MEM_READ 0x40000000 /**< The section can be read. */ 296 | #define PE_IMGSECTION_TYPE_MEM_WRITE 0x80000000 /**< The section can be written to. */ 297 | /*! @} */ 298 | 299 | /*! \brief image export directory 300 | */ 301 | struct peheader_imageexportdirectory { 302 | uint32_t Characteristics; /**< Reserved, must be 0. */ 303 | uint32_t TimeDateStamp; /**< The time and date that the export data was created. */ 304 | uint16_t MajorVersion; /**< The major version number. The major and minor version numbers can be set by the user. */ 305 | uint16_t MinorVersion; /**< The minor version number. */ 306 | uint32_t Name; /**< The address of the ASCII string that contains the name of the DLL. This address is relative to the image base. */ 307 | uint32_t Base; /**< The starting ordinal number for exports in this image. This field specifies the starting ordinal number for the export address table. It is usually set to 1. */ 308 | uint32_t NumberOfFunctions; /**< The number of entries in the export address table. */ 309 | uint32_t NumberOfNames; /**< The number of entries in the name pointer table. This is also the number of entries in the ordinal table. */ 310 | uint32_t AddressOfFunctions; /**< The address of the export address table, relative to the image base. (RVA) */ 311 | uint32_t AddressOfNames; /**< The address of the export name pointer table, relative to the image base. The table size is given by the Number of Name Pointers field. (RVA) */ 312 | uint32_t AddressOfNameOrdinals; /**< The address of the ordinal table, relative to the image base. (RVA) */ 313 | }; 314 | 315 | /*! \brief image import directory 316 | */ 317 | struct peheader_imageimportdirectory { 318 | uint32_t ImportLookupTable; /**< The RVA of the import lookup table. This table contains a name or ordinal for each import. (The name "Characteristics" is used in Winnt.h, but no longer describes this field.) (RVA) */ 319 | uint32_t TimeDateStamp; /**< The stamp that is set to zero until the image is bound. After the image is bound, this field is set to the time/data stamp of the DLL. */ 320 | uint32_t ForwarderChain; /**< The index of the first forwarder reference. */ 321 | uint32_t Name; /**< The address of an ASCII string that contains the name of the DLL. This address is relative to the image base. (RVA) */ 322 | uint32_t ImportAddressTable; /**< The RVA of the import address table. The contents of this table are identical to the contents of the import lookup table until the image is bound. (RVA) */ 323 | }; 324 | 325 | /*! \brief image resource directory 326 | */ 327 | struct peheader_imageresourcedirectory { 328 | uint32_t Characteristics; /**< */ 329 | uint32_t TimeDateStamp; /**< */ 330 | uint16_t MajorVersion; /**< */ 331 | uint16_t MinorVersion; /**< */ 332 | uint16_t NumberOfNamedEntries; /**< */ 333 | uint16_t NumberOfIdEntries; /**< */ 334 | }; 335 | 336 | /*! \brief image resource directory entry 337 | */ 338 | struct peheader_imageresourcedirectory_entry { 339 | uint32_t Name; /**< offset to resource name if high bit is set, or resource ID */ 340 | uint32_t OffsetToData; /**< offset to image resource directory if high bit is set, or offset to data */ 341 | }; 342 | 343 | #define PE_RESOURCE_ENTRY_NAME_MASK 0x80000000 /**< mask to determe if the Name field in an image resource directory entry is an offset to an image resource directory string (otherwise it is a resource ID) */ 344 | #define PE_RESOURCE_ENTRY_DIR_MASK 0x80000000 /**< mask to determe if the OffsetToData field in an image resource directory entry is an offset to an image resource directory (otherwise it is an offset to data) */ 345 | 346 | /*! \brief image resource data entry 347 | */ 348 | struct peheader_imageresource_data_entry { 349 | uint32_t OffsetToData; /**< (RVA) */ 350 | uint32_t Size; /**< */ 351 | uint32_t CodePage; /**< */ 352 | uint32_t Reserved; /**< */ 353 | }; 354 | 355 | /*! \brief image resource directory string 356 | */ 357 | struct peheader_imageresource_string { 358 | uint16_t Length; /**< string length */ 359 | wchar_t NameString[1]; /**< Unicode string data */ 360 | }; 361 | 362 | /*! \brief locate section pointed to by relative virtual address (RVA) 363 | * \param sections pointer to array of image sections 364 | * \param sectioncount number of image sections in \b sections 365 | * \param rva relative virtual address 366 | * \return pointer to section or NULL if not found 367 | * \sa peheader_imagesection 368 | */ 369 | DLL_EXPORT_PEDEPS struct peheader_imagesection* pe_find_rva_section (struct peheader_imagesection* sections, uint16_t sectioncount, uint32_t rva); 370 | 371 | /*! \brief get short machine architecture name 372 | * \param machine machine architecture code 373 | * \return short machine architecture name (e.g.: "x86" or "x86_64") 374 | * \sa PEheader_optional_common 375 | */ 376 | DLL_EXPORT_PEDEPS const char* pe_get_arch_name (uint16_t machine); 377 | 378 | /*! \brief get long machine architecture name 379 | * \param machine machine architecture code 380 | * \return long machine architecture name 381 | * \sa PEheader_optional_common 382 | */ 383 | DLL_EXPORT_PEDEPS const char* pe_get_machine_name (uint16_t machine); 384 | 385 | /*! \brief get number of bits native for architecture 386 | * \param machine machine architecture code 387 | * \return number of architecture bits 388 | * \sa PEheader_optional_common 389 | */ 390 | DLL_EXPORT_PEDEPS int pe_get_machine_bits (uint16_t machine); 391 | 392 | /*! \brief get subsystem name 393 | * \param subsystem subsystem code 394 | * \return subsystem name (e.g.: "icon" or "string") 395 | * \sa PEheader_optional_commonext 396 | */ 397 | DLL_EXPORT_PEDEPS const char* pe_get_subsystem_name (uint16_t subsystem); 398 | 399 | /*! \brief resource types 400 | * \sa peheader_imageresourcedirectory_entry 401 | * \name PE_RESOURCE_TYPE_* 402 | * \{ 403 | */ 404 | #define PE_RESOURCE_TYPE_CURSOR 1 /**< cursor */ 405 | #define PE_RESOURCE_TYPE_BITMAP 2 /**< bitmap */ 406 | #define PE_RESOURCE_TYPE_ICON 3 /**< icon */ 407 | #define PE_RESOURCE_TYPE_MENU 4 /**< menu */ 408 | #define PE_RESOURCE_TYPE_DIALOG 5 /**< dialog */ 409 | #define PE_RESOURCE_TYPE_STRING 6 /**< string */ 410 | #define PE_RESOURCE_TYPE_FONTDIR 7 /**< fontdir */ 411 | #define PE_RESOURCE_TYPE_FONT 8 /**< font */ 412 | #define PE_RESOURCE_TYPE_ACCELERATOR 9 /**< accelerator */ 413 | #define PE_RESOURCE_TYPE_RCDATA 10 /**< rcdata */ 414 | #define PE_RESOURCE_TYPE_MESSAGETABLE 11 /**< messagetable */ 415 | #define PE_RESOURCE_TYPE_GROUP_CURSOR 12 /**< group_cursor */ 416 | #define PE_RESOURCE_TYPE_GROUP_ICON 14 /**< group_icon */ 417 | #define PE_RESOURCE_TYPE_VERSION 16 /**< version */ 418 | #define PE_RESOURCE_TYPE_DLGINCLUDE 17 /**< dlginclude */ 419 | #define PE_RESOURCE_TYPE_PLUGPLAY 19 /**< plugplay */ 420 | #define PE_RESOURCE_TYPE_VXD 20 /**< vxd */ 421 | #define PE_RESOURCE_TYPE_ANICURSOR 21 /**< anicursor */ 422 | #define PE_RESOURCE_TYPE_ANIICON 22 /**< aniicon */ 423 | #define PE_RESOURCE_TYPE_HTML 23 /**< html */ 424 | #define PE_RESOURCE_TYPE_MANIFEST 24 /**< manifest */ 425 | /*! @} */ 426 | 427 | /*! \brief get resource ID name 428 | * \param resourceid resource ID 429 | * \return resource ID name (e.g.: "Windows GUI" or "Windows console") 430 | * \sa peheader_imageresourcedirectory_entry 431 | * \sa PE_RESOURCE_TYPE_* 432 | */ 433 | DLL_EXPORT_PEDEPS const char* pe_get_resourceid_name (uint32_t resourceid); 434 | 435 | /*! \brief version file info flags 436 | * \sa peheader_fixedfileinfo 437 | * \name PE_VERSION_FILEINFO_FLAG_* 438 | * \{ 439 | */ 440 | #define PE_VERSION_FILEINFO_FLAG_DEBUG 0x00000001L /**< file contains debugging information or is compiled with debugging features enabled */ 441 | #define PE_VERSION_FILEINFO_FLAG_PRERELEASE 0x00000002L /**< file is a development version, not a commercially released product */ 442 | #define PE_VERSION_FILEINFO_FLAG_PATCHED 0x00000004L /**< file has been modified and is not identical to the original shipping file of the same version number */ 443 | #define PE_VERSION_FILEINFO_FLAG_PRIVATEBUILD 0x00000008L /**< file was not built using standard release procedures; if this flag is set, the StringFileInfo structure should contain a PrivateBuild entry */ 444 | #define PE_VERSION_FILEINFO_FLAG_INFOINFERRED 0x00000010L /**< file's version structure was created dynamically; therefore, some of the members in this structure may be empty or incorrect; this flag should never be set in a file's VS_VERSIONINFO data */ 445 | #define PE_VERSION_FILEINFO_FLAG_SPECIALBUILD 0x00000020L /**< file was built by the original company using standard release procedures but is a variation of the normal file of the same version number; if this flag is set, the StringFileInfo structure should contain a SpecialBuild entry */ 446 | /*! @} */ 447 | 448 | /*! \brief version file info flags 449 | * \sa peheader_fixedfileinfo 450 | * \sa pe_version_fileinfo_get_type_name 451 | * \sa PE_VERSION_FILEINFO_FLAG_* 452 | * \name PE_VERSION_FILEINFO_TYPE_* 453 | * \{ 454 | */ 455 | #define PE_VERSION_FILEINFO_TYPE_UNKNOWN 0x00000000L /**< file type is unknown to the system */ 456 | #define PE_VERSION_FILEINFO_TYPE_APP 0x00000001L /**< file contains an application */ 457 | #define PE_VERSION_FILEINFO_TYPE_DLL 0x00000002L /**< file contains a DLL */ 458 | #define PE_VERSION_FILEINFO_TYPE_DRV 0x00000003L /**< file contains a device driver; if dwFileType is VFT_DRV, dwFileSubtype contains a more specific description of the driver */ 459 | #define PE_VERSION_FILEINFO_TYPE_FONT 0x00000004L /**< file contains a font; if dwFileType is VFT_FONT, dwFileSubtype contains a more specific description of the font file */ 460 | #define PE_VERSION_FILEINFO_TYPE_VXD 0x00000005L /**< file contains a virtual device */ 461 | #define PE_VERSION_FILEINFO_TYPE_STATIC_LIB 0x00000007L /**< file contains a static-link library */ 462 | /*! @} */ 463 | 464 | /*! \brief version file info flags 465 | * \sa peheader_fixedfileinfo 466 | * \sa PE_VERSION_FILEINFO_FLAG_* 467 | * \name PE_VERSION_FILEINFO_SUBTYPE_DRV_* 468 | * \{ 469 | */ 470 | #define PE_VERSION_FILEINFO_SUBTYPE_DRV_COMM 0x0000000AL /**< file contains a communications driver */ 471 | #define PE_VERSION_FILEINFO_SUBTYPE_DRV_DISPLAY 0x00000004L /**< file contains a display driver */ 472 | #define PE_VERSION_FILEINFO_SUBTYPE_DRV_INSTALLABLE 0x00000008L /**< file contains an installable driver */ 473 | #define PE_VERSION_FILEINFO_SUBTYPE_DRV_KEYBOARD 0x00000002L /**< file contains a keyboard driver */ 474 | #define PE_VERSION_FILEINFO_SUBTYPE_DRV_LANGUAGE 0x00000003L /**< file contains a language driver */ 475 | #define PE_VERSION_FILEINFO_SUBTYPE_DRV_MOUSE 0x00000005L /**< file contains a mouse driver */ 476 | #define PE_VERSION_FILEINFO_SUBTYPE_DRV_NETWORK 0x00000006L /**< file contains a network driver */ 477 | #define PE_VERSION_FILEINFO_SUBTYPE_DRV_PRINTER 0x00000001L /**< file contains a printer driver */ 478 | #define PE_VERSION_FILEINFO_SUBTYPE_DRV_SOUND 0x00000009L /**< file contains a sound driver */ 479 | #define PE_VERSION_FILEINFO_SUBTYPE_DRV_SYSTEM 0x00000007L /**< file contains a system driver */ 480 | #define PE_VERSION_FILEINFO_SUBTYPE_DRV_VERSIONED_PRINTER 0x0000000CL /**< file contains a versioned printer driver */ 481 | #define PE_VERSION_FILEINFO_SUBTYPE_UNKNOWN 0x00000000L /**< driver type is unknown by the system */ 482 | /*! @} */ 483 | 484 | /*! \brief version file info flags 485 | * \sa peheader_fixedfileinfo 486 | * \sa PE_VERSION_FILEINFO_FLAG_* 487 | * \name PE_VERSION_FILEINFO_SUBTYPE_FONT_* 488 | * \{ 489 | */ 490 | #define PE_VERSION_FILEINFO_SUBTYPE_FONT_RASTER 0x00000001L /**< file contains a raster font */ 491 | #define PE_VERSION_FILEINFO_SUBTYPE_FONT_TRUETYPE 0x00000003L /**< file contains a TrueType font */ 492 | #define PE_VERSION_FILEINFO_SUBTYPE_FONT_VECTOR 0x00000002L /**< file contains a vector font */ 493 | #define PE_VERSION_FILEINFO_SUBTYPE_FONT_UNKNOWN 0x00000000L /**< font type is unknown by the system */ 494 | /*! @} */ 495 | 496 | /*! \brief get file type name 497 | * \param filetype file type 498 | * \return file type name 499 | * \sa peheader_fixedfileinfo 500 | * \sa PE_VERSION_FILEINFO_TYPE_* 501 | */ 502 | DLL_EXPORT_PEDEPS const char* pe_version_fileinfo_get_type_name (uint32_t filetype); 503 | 504 | /*! \brief get file subtype name 505 | * \param filetype file type 506 | * \param filesubtype file subtype 507 | * \return file subtype name 508 | * \sa peheader_fixedfileinfo 509 | * \name PE_VERSION_FILEINFO_SUBTYPE_DRV_* 510 | * \name PE_VERSION_FILEINFO_SUBTYPE_FONT_* 511 | * \sa PE_VERSION_FILEINFO_TYPE_* 512 | */ 513 | DLL_EXPORT_PEDEPS const char* pe_version_fileinfo_get_subtype_name (uint32_t filetype, uint32_t filesubtype); 514 | 515 | /*! \brief fixed file information 516 | */ 517 | struct peheader_fixedfileinfo { 518 | uint32_t dwSignature; 519 | uint16_t dwStrucVersionLo; 520 | uint16_t dwStrucVersionHi; 521 | uint16_t dwFileVersion2; 522 | uint16_t dwFileVersion1; 523 | uint16_t dwFileVersion4; 524 | uint16_t dwFileVersion3; 525 | uint16_t dwProductVersion2; 526 | uint16_t dwProductVersion1; 527 | uint16_t dwProductVersion4; 528 | uint16_t dwProductVersion3; 529 | uint32_t dwFileFlagsMask; 530 | uint32_t dwFileFlags; 531 | uint32_t dwFileOS; 532 | uint32_t dwFileType; 533 | uint32_t dwFileSubtype; 534 | uint32_t dwFileDateHi; 535 | uint32_t dwFileDateLo; 536 | }; 537 | 538 | /*! \brief version information 539 | */ 540 | struct peheader_versioninfo { 541 | uint16_t wLength; 542 | uint16_t wValueLength; 543 | uint16_t wType; 544 | wchar_t szKey[15]; 545 | uint16_t Padding1[1]; 546 | struct peheader_fixedfileinfo Value; 547 | uint16_t Padding2[1]; 548 | uint16_t Children[1]; 549 | }; 550 | 551 | /*! \brief version information child / string table / string entry 552 | * \sa PE_VERSION_FILEINFO_STRING_TYPE_* 553 | */ 554 | struct peheader_fileinfo_entry { 555 | uint16_t wLength; 556 | uint16_t wValueLength; 557 | uint16_t wType; 558 | wchar_t szKey[1]; 559 | }; 560 | 561 | /*! \brief file info entry type flags 562 | * \sa peheader_fileinfo_entry 563 | * \name PE_VERSION_FILEINFO_STRING_TYPE_* 564 | * \{ 565 | */ 566 | #define PE_VERSION_FILEINFO_STRING_TYPE_BINARY 0 /**< binary */ 567 | #define PE_VERSION_FILEINFO_STRING_TYPE_TEXT 1 /**< text */ 568 | 569 | #ifdef __cplusplus 570 | } 571 | #endif 572 | 573 | #endif 574 | -------------------------------------------------------------------------------- /src/copypedeps.c: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | Copyright (C) 2019 Brecht Sanders All Rights Reserved 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | The above copyright notice and this permission notice shall be included in 10 | all copies or substantial portions of the Software. 11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 12 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 13 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 14 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 15 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 16 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 17 | THE SOFTWARE. 18 | *****************************************************************************/ 19 | 20 | #include "pestructs.h" 21 | #include "pedeps.h" 22 | #include "pedeps_version.h" 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #ifdef _WIN32 33 | #include 34 | #include 35 | #else 36 | #include 37 | #endif 38 | #include 39 | 40 | #ifdef _WIN32 41 | #define realpath(N,R) _fullpath((R),(N),_MAX_PATH) 42 | #if defined(_WIN32) && !defined(__MINGW64_VERSION_MAJOR) 43 | #define strcasecmp stricmp 44 | #define strncasecmp strnicmp 45 | #endif 46 | #define PATHCMP strcasecmp 47 | #define PATHNCMP strncasecmp 48 | #define PATHSEPARATOR '\\' 49 | #define ISPATHSEPARATOR(c) ((c) == '\\' || (c) == '/') 50 | #define PATHLISTSEPARATOR ';' 51 | #else 52 | #ifndef PATH_MAX 53 | #include 54 | #endif 55 | #ifndef O_BINARY 56 | #define O_BINARY 0 57 | #endif 58 | #define PATHCMP strcmp 59 | #define PATHNCMP strncmp 60 | #define PATHSEPARATOR '/' 61 | #define ISPATHSEPARATOR(c) ((c) == '/') 62 | #define PATHLISTSEPARATOR ':' 63 | #endif 64 | 65 | #define APPLICATION_NAME "copypedeps" 66 | 67 | int file_exists (const char* path) 68 | { 69 | struct stat statbuf; 70 | if (stat(path, &statbuf) == 0 && S_ISREG(statbuf.st_mode)) 71 | return 1; 72 | return 0; 73 | } 74 | 75 | int folder_exists (const char* path) 76 | { 77 | struct stat statbuf; 78 | if (stat(path, &statbuf) == 0 && S_ISDIR(statbuf.st_mode)) 79 | return 1; 80 | return 0; 81 | } 82 | 83 | const char* get_filename_from_path (const char* path) 84 | { 85 | size_t i; 86 | if (!path || !*path) 87 | return NULL; 88 | i = strlen(path); 89 | while (i-- > 0) { 90 | if (ISPATHSEPARATOR(path[i])) 91 | return (path[i + 1] ? path + i + 1 : NULL); 92 | } 93 | return path; 94 | } 95 | 96 | uint64_t get_block_size (const char* path) 97 | { 98 | #ifdef _WIN32 99 | char* rootpath; 100 | DWORD sectors_per_cluster; 101 | DWORD bytes_per_sector; 102 | DWORD number_of_free_clusters; 103 | DWORD total_number_of_clusters; 104 | if ((rootpath = strdup(path)) == NULL) 105 | return 0; 106 | if (!PathStripToRootA(rootpath)) { 107 | free(rootpath); 108 | return 0; 109 | } 110 | if (!GetDiskFreeSpaceA(rootpath, §ors_per_cluster, &bytes_per_sector, &number_of_free_clusters, &total_number_of_clusters)) 111 | return 0; 112 | free(rootpath); 113 | return sectors_per_cluster * bytes_per_sector; 114 | #else 115 | struct stat statbuf; 116 | if (stat(path, &statbuf) != 0) 117 | return 0; /////TO DO: strip filename and try with directory in case of error 118 | return statbuf.st_blksize; 119 | #endif 120 | } 121 | 122 | int copy_file (const char* srcfile, const char* dstfile, int overwrite) 123 | { 124 | void* buf; 125 | uint64_t buflen; 126 | uint64_t blocksize; 127 | int srchandle; 128 | int dsthandle; 129 | ssize_t n; 130 | int result = 0; 131 | //open source file 132 | if ((srchandle = open(srcfile, O_RDONLY | O_BINARY)) == -1) { 133 | return 1; 134 | } 135 | //open destination file 136 | if ((dsthandle = open(dstfile, O_WRONLY | O_BINARY | O_CREAT | (overwrite ? O_TRUNC : O_EXCL), S_IWUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH)) == -1) { 137 | close(srchandle); 138 | return 2; 139 | } 140 | //determine buffer size based on largest block size 141 | buflen = 4096; 142 | if ((blocksize = get_block_size(srcfile)) > buflen) 143 | buflen = blocksize; 144 | if ((blocksize = get_block_size(dstfile)) > buflen) 145 | buflen = blocksize; 146 | //allocate buffer 147 | if ((buf = malloc(buflen)) == NULL) { 148 | result = -1; 149 | } else { 150 | //copy data 151 | while ((n = read(srchandle, buf, buflen)) > 0) { 152 | if (write(dsthandle, buf, n) < n) { 153 | result = 3; 154 | break; 155 | } 156 | } 157 | } 158 | //close files 159 | close(srchandle); 160 | close(dsthandle); 161 | //delete destination file on error 162 | if (result != 0) 163 | unlink(dstfile); 164 | //deallocate buffer 165 | free(buf); 166 | //copy create/access/write timestamps 167 | if (result == 0) { 168 | #if _WIN32 169 | HANDLE handle; 170 | FILETIME creationtime; 171 | FILETIME accesstime; 172 | FILETIME writetime; 173 | if ((handle = CreateFileA(srcfile, GENERIC_READ | FILE_READ_ATTRIBUTES, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL)) != INVALID_HANDLE_VALUE) { 174 | if (GetFileTime(handle, &creationtime, &accesstime, &writetime)) { 175 | CloseHandle(handle); 176 | if ((handle = CreateFileA(dstfile, GENERIC_READ | FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL)) != INVALID_HANDLE_VALUE) { 177 | //SYSTEMTIME st; 178 | //GetSystemTime(&st); 179 | //SystemTimeToFileTime(&st, &writetime); 180 | SetFileTime(handle, &creationtime, &accesstime, &writetime); 181 | CloseHandle(handle); 182 | } 183 | } 184 | } 185 | #else 186 | struct stat srctimes; 187 | struct utimbuf dsttimes; 188 | //get source file date and time values 189 | if (stat(srcfile, &srctimes) == 0) { 190 | //set destination file date and time values 191 | dsttimes.actime = srctimes.st_atime; 192 | dsttimes.modtime = srctimes.st_mtime;//or use time(NULL) 193 | utime(dstfile, &dsttimes); 194 | } 195 | #endif 196 | } 197 | return result; 198 | } 199 | 200 | struct string_list_struct { 201 | char* data; 202 | struct string_list_struct* next; 203 | }; 204 | 205 | void string_list_free (struct string_list_struct** list) 206 | { 207 | struct string_list_struct* next; 208 | struct string_list_struct* p = *list; 209 | while (p) { 210 | next = p->next; 211 | free(p->data); 212 | free(p); 213 | p = next; 214 | } 215 | *list = NULL; 216 | } 217 | 218 | struct string_list_struct* string_list_append_allocated (struct string_list_struct** list, char* data) 219 | { 220 | struct string_list_struct** p = list; 221 | while (*p) { 222 | p = &((*p)->next); 223 | } 224 | if ((*p = (struct string_list_struct*)malloc(sizeof(struct string_list_struct))) != NULL) { 225 | (*p)->data = data; 226 | (*p)->next = NULL; 227 | } 228 | return *p; 229 | } 230 | 231 | struct string_list_struct* string_list_append (struct string_list_struct** list, const char* data) 232 | { 233 | return string_list_append_allocated(list, (data ? strdup(data) : NULL)); 234 | } 235 | 236 | struct dependancy_info_struct { 237 | int recursive; 238 | int overwrite; 239 | int dryrun; 240 | int verbose; 241 | avl_tree_t* filelist; 242 | char* preferredpath; 243 | struct string_list_struct* pathlist; 244 | }; 245 | 246 | char* get_base_path (const char* path) 247 | { 248 | char* result = NULL; 249 | if (path) { 250 | size_t pos = strlen(path); 251 | while (pos > 0) { 252 | pos--; 253 | if (ISPATHSEPARATOR(path[pos])) 254 | break; 255 | } 256 | if ((result = (char*)malloc(pos + 1)) != NULL) { 257 | memcpy(result, path, pos); 258 | result[pos] = 0; 259 | } 260 | } 261 | return result; 262 | } 263 | 264 | typedef int (*iterate_path_list_callback_fn)(const char* path, void* callbackdata); 265 | 266 | size_t iterate_path_list (const char* pathlist, char pathseparator, iterate_path_list_callback_fn callbackfunction, void* callbackdata) 267 | { 268 | char* path; 269 | int status; 270 | size_t count = 0; 271 | size_t startpos = 0; 272 | size_t endpos = 0; 273 | if (pathseparator == 0) 274 | pathseparator = PATHLISTSEPARATOR; 275 | while (pathlist[startpos]) { 276 | endpos = startpos; 277 | while (pathlist[endpos] && pathlist[endpos] != pathseparator) { 278 | endpos++; 279 | } 280 | if (endpos > startpos && (path = (char*)malloc(endpos - startpos + 1)) != NULL) { 281 | memcpy(path, pathlist + startpos, endpos - startpos); 282 | path[endpos - startpos] = 0; 283 | status = (*callbackfunction)(path, callbackdata); 284 | free(path); 285 | if (status != 0) 286 | break; 287 | } 288 | startpos = endpos; 289 | while (pathlist[startpos] && pathlist[startpos] == pathseparator) 290 | startpos++; 291 | } 292 | return count; 293 | } 294 | 295 | //returns non-zero path1 is under path2 296 | int is_in_path (const char* path1, const char* path2) 297 | { 298 | char full_path1[PATH_MAX]; 299 | char full_path2[PATH_MAX]; 300 | if (realpath(path1, full_path1) && realpath(path2, full_path2)) { 301 | size_t len1 = strlen(full_path1); 302 | size_t len2 = strlen(full_path2); 303 | if (len1 >= len2) { 304 | if (PATHNCMP(full_path1, full_path2, len2) == 0) { 305 | if (full_path2[len2] == 0 || ISPATHSEPARATOR(full_path2[len2])) 306 | return 1; 307 | } 308 | } 309 | } 310 | return 0; 311 | } 312 | 313 | int iterate_path_add (const char* path, void* callbackdata) 314 | { 315 | if (!is_in_path(path, getenv("windir"))) 316 | string_list_append((struct string_list_struct**)callbackdata, path); 317 | return 0; 318 | } 319 | 320 | char* search_path (const char* preferredpath, struct string_list_struct* pathlist, const char* filename) 321 | { 322 | size_t filenamelen; 323 | struct string_list_struct* p; 324 | char* s; 325 | size_t l; 326 | if (!filename || !*filename) 327 | return NULL; 328 | if (file_exists(filename)) 329 | return strdup(filename); 330 | filenamelen = strlen(filename); 331 | //check preferred path 332 | if ((s = (char*)malloc((l = strlen(preferredpath)) + filenamelen + 2)) != NULL) { 333 | memcpy(s, preferredpath, l); 334 | s[l] = PATHSEPARATOR; 335 | memcpy(s + l + 1, filename, filenamelen + 1); 336 | if (file_exists(s)) 337 | return s; 338 | free(s); 339 | } 340 | //check search path 341 | p = pathlist; 342 | while (p) { 343 | if ((s = (char*)malloc((l = strlen(p->data)) + filenamelen + 2)) != NULL) { 344 | memcpy(s, p->data, l); 345 | s[l] = PATHSEPARATOR; 346 | memcpy(s + l + 1, filename, filenamelen + 1); 347 | if (file_exists(s)) 348 | return s; 349 | free(s); 350 | } 351 | p = p->next; 352 | } 353 | return NULL; 354 | } 355 | 356 | int add_dependancies (struct dependancy_info_struct* depinfo, const char* filename); 357 | 358 | int iterate_dependancies_add (const char* modulename, const char* functionname, void* callbackdata) 359 | { 360 | struct dependancy_info_struct* depinfo = (struct dependancy_info_struct*)callbackdata; 361 | if (modulename) { 362 | char* path; 363 | if ((path = search_path(depinfo->preferredpath, depinfo->pathlist, modulename)) != NULL) { 364 | //new module, recursively add dependancies if wanted 365 | if (avl_insert(depinfo->filelist, path) != NULL) { 366 | if (depinfo->recursive) { 367 | add_dependancies(depinfo, path); 368 | } 369 | } else { 370 | //module already listed, no further action needed 371 | free(path); 372 | } 373 | } 374 | } 375 | return 0; 376 | } 377 | 378 | int add_dependancies (struct dependancy_info_struct* depinfo, const char* filename) 379 | { 380 | pefile_handle pehandle; 381 | char* path; 382 | //determine path 383 | if ((path = search_path(depinfo->preferredpath, depinfo->pathlist, filename)) == NULL) { 384 | fprintf(stderr, "Error: unable to locate %s in PATH\n", filename); 385 | return 1; 386 | } 387 | //create PE object 388 | if ((pehandle = pefile_create()) == NULL) { 389 | fprintf(stderr, "Error creating PE handle\n"); 390 | return 2; 391 | } 392 | //open PE file 393 | if (pefile_open_file(pehandle, path) == 0) { 394 | //check all dependancies 395 | pefile_list_imports(pehandle, iterate_dependancies_add, depinfo); 396 | //close PE file 397 | pefile_close(pehandle); 398 | } 399 | //destroy PE object 400 | pefile_destroy(pehandle); 401 | //clean up 402 | free(path); 403 | return 0; 404 | } 405 | 406 | void add_file_to_list (const char* filepath, struct dependancy_info_struct* depinfo) 407 | { 408 | //add current file 409 | avl_insert(depinfo->filelist, strdup(filepath)); 410 | //determine preferred path (same folder as current file) 411 | depinfo->preferredpath = get_base_path(filepath); 412 | //add dependancies 413 | add_dependancies(depinfo, filepath); 414 | //clean up preferred path 415 | free(depinfo->preferredpath); 416 | depinfo->preferredpath = NULL; 417 | } 418 | 419 | void show_help () 420 | { 421 | printf( 422 | "Usage: " APPLICATION_NAME " [-h|-?] [-r] srcfile [...] dstfolder\n" 423 | "Parameters:\n" 424 | " -h -? \tdisplay command line help\n" 425 | " -r \trecursively copy dependancies\n" 426 | " -n \tdon't overwrite existing files\n" 427 | " -d \tdry run: don't actually copy, just display copy actions\n" 428 | " -q \tquiet mode, only show errors\n" 429 | " -v \tverbose mode (display copy actions)\n" 430 | "Description:\n" 431 | "Copies .exe and .dll files and all their dependancies to the destination folder.\n" 432 | "Version: " PEDEPS_VERSION_STRING " (library version: %s)\n" 433 | "", pedeps_get_version_string() 434 | ); 435 | } 436 | 437 | int main (int argc, char* argv[]) 438 | { 439 | int i; 440 | char* dst; 441 | size_t dstlen; 442 | struct dependancy_info_struct depinfo; 443 | avl_tree_t* filelist; 444 | //show help page if no parameters were given or help was requested 445 | for (i = 1; i < argc; i++) { 446 | if (argv[i][0] == '-' && (argv[i][1] == 'h' || argv[i][1] == '?') && argv[i][2] == 0) 447 | break; 448 | } 449 | if (argc <= 2 || i < argc) { 450 | show_help(); 451 | return 0; 452 | } 453 | //check if last parameter is an existing directory 454 | if ((dstlen = strlen(argv[argc - 1])) == 0) { 455 | fprintf(stderr, "Empty destination folder name not allowed\n"); 456 | return 1; 457 | } 458 | if ((dst = (char*)malloc(dstlen + 2)) == NULL) { 459 | fprintf(stderr, "Memory allocation error\n"); 460 | return 1; 461 | } 462 | memcpy(dst, argv[argc - 1], dstlen + 1); 463 | if (!ISPATHSEPARATOR(dst[dstlen - 1])) { 464 | dst[dstlen++] = PATHSEPARATOR; 465 | dst[dstlen] = 0; 466 | } 467 | if (!folder_exists(argv[argc - 1])) { 468 | fprintf(stderr, "Destination folder not found: %s\n", dst); 469 | return 2; 470 | } 471 | //initialize sorted list (AVL tree) 472 | if ((filelist = avl_alloc_tree((avl_compare_t)PATHCMP, free)) == NULL) { 473 | fprintf(stderr, "Memory allocation error\n"); 474 | return 3; 475 | } 476 | //initialize 477 | depinfo.recursive = 0; 478 | depinfo.overwrite = 1; 479 | depinfo.dryrun = 0; 480 | depinfo.verbose = 1; 481 | depinfo.filelist = filelist; 482 | depinfo.preferredpath = NULL; 483 | depinfo.pathlist = NULL; 484 | //determine search path 485 | iterate_path_list(getenv("PATH"), 0, iterate_path_add, &depinfo.pathlist); 486 | //process all parameters and get dependancies of the requested files 487 | for (i = 1; i < argc - 1; i++) { 488 | if (argv[i][0] == '-' && argv[i][1] == 'r' && argv[i][2] == 0) { 489 | depinfo.recursive = 1; 490 | } else if (argv[i][0] == '-' && argv[i][1] == 'n' && argv[i][2] == 0) { 491 | depinfo.overwrite = 0; 492 | } else if (argv[i][0] == '-' && argv[i][1] == 'd' && argv[i][2] == 0) { 493 | depinfo.dryrun = 1; 494 | } else if (argv[i][0] == '-' && argv[i][1] == 'q' && argv[i][2] == 0) { 495 | depinfo.verbose = 0; 496 | } else if (argv[i][0] == '-' && argv[i][1] == 'v' && argv[i][2] == 0) { 497 | depinfo.verbose++; 498 | } else { 499 | if (folder_exists(argv[i])) { 500 | DIR* dirhandle; 501 | struct dirent* direntry; 502 | size_t pathlen; 503 | size_t len; 504 | char* srcpath; 505 | if (depinfo.verbose >= 2) 506 | printf("Folder specified, copying *.dll and *.exe from: %s\n", argv[i]); 507 | if ((dirhandle = opendir(argv[i])) == NULL) { 508 | fprintf(stderr, "Error reading directory: %s\n", argv[i]); 509 | } else { 510 | pathlen = strlen(argv[i]); 511 | if (pathlen > 0 && (argv[i][pathlen - 1] == PATHSEPARATOR 512 | #ifdef _WIN32 513 | || argv[i][pathlen - 1] == '/' 514 | #endif 515 | )) 516 | pathlen--; 517 | while ((direntry = readdir(dirhandle)) != NULL) { 518 | len = strlen(direntry->d_name); 519 | if (len >= 4 && (strcasecmp(direntry->d_name + len - 4, ".dll") == 0 || strcasecmp(direntry->d_name + len - 4, ".exe") == 0)) { 520 | if ((srcpath = (char*)malloc(strlen(argv[i]) + len + 2)) == NULL) { 521 | fprintf(stderr, "Memory allocation error\n"); 522 | return 4; 523 | } else { 524 | memcpy(srcpath, argv[i], pathlen); 525 | srcpath[pathlen] = PATHSEPARATOR; 526 | strcpy(srcpath + pathlen + 1, direntry->d_name); 527 | add_file_to_list(srcpath, &depinfo); 528 | free(srcpath); 529 | } 530 | } 531 | } 532 | closedir(dirhandle); 533 | } 534 | } else if (file_exists(argv[i])) { 535 | add_file_to_list(argv[i], &depinfo); 536 | } else { 537 | fprintf(stderr, "File not found: %s\n", argv[i]); 538 | } 539 | } 540 | } 541 | //free search path 542 | string_list_free(&depinfo.pathlist); 543 | //copy dependancies 544 | avl_node_t* entry; 545 | unsigned int entryindex = 0; 546 | while ((entry = avl_at(filelist, entryindex)) != NULL) { 547 | const char* filename; 548 | char* dstpath; 549 | if ((filename = get_filename_from_path((const char*)entry->item)) != NULL) { 550 | if ((dstpath = (char*)malloc(dstlen + strlen(filename) + 1)) != NULL) { 551 | memcpy(dstpath, dst, dstlen); 552 | strcpy(dstpath + dstlen, filename); 553 | if (!depinfo.overwrite && file_exists(dstpath)) { 554 | if (depinfo.verbose >= 1) 555 | printf("Not overwriting existing file: %s\n", dstpath); 556 | } else { 557 | if (depinfo.dryrun) { 558 | if (depinfo.verbose >= 1) 559 | printf("%s -> %s\n", (const char*)entry->item, dstpath); 560 | } else { 561 | if (copy_file((const char*)entry->item, dstpath, depinfo.overwrite) != 0) 562 | fprintf(stderr, "Error copying %s to %s\n", (const char*)entry->item, dstpath); 563 | else if (depinfo.verbose >= 2) 564 | printf("%s -> %s\n", (const char*)entry->item, dstpath); 565 | } 566 | } 567 | free(dstpath); 568 | } 569 | } 570 | entryindex++; 571 | } 572 | //clean up 573 | avl_free_tree(filelist); 574 | free(dst); 575 | return 0; 576 | } 577 | -------------------------------------------------------------------------------- /src/listpedeps.c: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | Copyright (C) 2019 Brecht Sanders All Rights Reserved 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | The above copyright notice and this permission notice shall be included in 10 | all copies or substantial portions of the Software. 11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 12 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 13 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 14 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 15 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 16 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 17 | THE SOFTWARE. 18 | *****************************************************************************/ 19 | 20 | #include "pestructs.h" 21 | #include "pedeps.h" 22 | #include "pedeps_version.h" 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #define APPLICATION_NAME "listpedeps" 30 | 31 | struct progdata_struct 32 | { 33 | int showinfo; 34 | int showimports; 35 | int showexports; 36 | int details; 37 | char* lastmodule; 38 | }; 39 | 40 | int listimports (const char* modulename, const char* functionname, void* callbackdata) 41 | { 42 | struct progdata_struct* progdata = (struct progdata_struct*)callbackdata; 43 | if (progdata->details) { 44 | printf("%s: %s\n", modulename, functionname); 45 | } else { 46 | if (!progdata->lastmodule || strcmp(modulename, progdata->lastmodule) != 0) { 47 | if (progdata->lastmodule) 48 | free(progdata->lastmodule); 49 | progdata->lastmodule = strdup(modulename); 50 | printf("%s\n", modulename); 51 | } 52 | } 53 | return 0; 54 | } 55 | 56 | int listexports (const char* modulename, const char* functionname, uint16_t ordinal, int isdata, char* functionforwardername, void* callbackdata) 57 | { 58 | printf("%s: %s @ %" PRIu16 "%s%s%s\n", modulename, functionname, ordinal, (isdata ? " DATA": ""), (functionforwardername ? "; forwarder: " : ""), (functionforwardername ? functionforwardername : "")); 59 | return 0; 60 | } 61 | 62 | void show_help () 63 | { 64 | printf( 65 | "Usage: " APPLICATION_NAME " [-h|-?] [-v] [-n] [-i] [-s] [-x] srcfile [...]\n" 66 | "Parameters:\n" 67 | " -h -? \tdisplay command line help and exit\n" 68 | " -v \tdisplay version and exit\n" 69 | " -n \tdon't show file info\n" 70 | " -i \tlist imports\n" 71 | " -s \tshort import list without symbols\n" 72 | " -x \tlist exports\n" 73 | "Description:\n" 74 | "Lists dependencies of .exe and .dll files.\n" 75 | "Version: " PEDEPS_VERSION_STRING " (library version: %s)\n" 76 | "", pedeps_get_version_string() 77 | ); 78 | } 79 | 80 | int main (int argc, char* argv[]) 81 | { 82 | int i; 83 | pefile_handle pehandle; 84 | struct progdata_struct progdata = { 85 | .showinfo = 1, 86 | .showimports = 0, 87 | .showexports = 0, 88 | .details = 1, 89 | .lastmodule = NULL 90 | }; 91 | int status = 0; 92 | 93 | //check command line arguments 94 | if (argc <= 1) { 95 | fprintf(stderr, "Error: no filename given\n"); 96 | show_help(); 97 | return 1; 98 | } 99 | if (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "-?") == 0 || strcmp(argv[1], "--help") == 0) { 100 | show_help(); 101 | return 0; 102 | } 103 | if (strcmp(argv[1], "-v") == 0 || strcmp(argv[1], "--version") == 0) { 104 | printf(APPLICATION_NAME " " PEDEPS_VERSION_STRING "\n"); 105 | return 0; 106 | } 107 | 108 | //create PE object 109 | if ((pehandle = pefile_create()) == NULL) { 110 | fprintf(stderr, "Error creating object\n"); 111 | return 2; 112 | } 113 | 114 | for (i = 1; i < argc; i++) { 115 | if (strcmp(argv[i], "-n") == 0 || strcmp(argv[i], "--noinfo") == 0) { 116 | progdata.showinfo = 0; 117 | } else if (strcmp(argv[i], "-i") == 0 || strcmp(argv[i], "--imports") == 0) { 118 | progdata.showimports = 1; 119 | } else if (strcmp(argv[i], "-s") == 0 || strcmp(argv[i], "--short") == 0) { 120 | progdata.showimports = 1; 121 | progdata.details = 0; 122 | } else if (strcmp(argv[i], "-x") == 0 || strcmp(argv[i], "--exports") == 0) { 123 | progdata.showexports = 1; 124 | } else { 125 | printf("[%s]\n", argv[i]); 126 | //open PE file 127 | if ((status = pefile_open_file(pehandle, argv[i])) != 0) { 128 | fprintf(stderr, "Error opening PE file %s: %s\n", argv[i], pefile_status_message(status)); 129 | return 3; 130 | } 131 | if (progdata.showinfo) { 132 | //display information 133 | uint16_t mach = pefile_get_machine(pehandle); 134 | int bits = pe_get_machine_bits(mach); 135 | printf("architecture: %s\n", pe_get_arch_name(mach)); 136 | printf("machine name: %s\n", pe_get_machine_name(mach)); 137 | printf("machine bits: %i-bit\n", bits); 138 | printf("subsystem: %s\n", pe_get_subsystem_name(pefile_get_subsystem(pehandle))); 139 | printf("DLL: %s\n", (pefile_is_dll(pehandle) ? "yes" : "no")); 140 | printf("stripped: %s\n", (pefile_is_stripped(pehandle) ? "yes" : "no")); 141 | printf("file version: %" PRIu16 ".%" PRIu16 "\n", pefile_get_file_version_major(pehandle), pefile_get_file_version_minor(pehandle)); 142 | printf("minimum OS: Windows version %" PRIu16 ".%" PRIu16 "\n", pefile_get_min_os_major(pehandle), pefile_get_min_os_minor(pehandle)); 143 | //printf("image base address: 0x%0*" PRIx64 "\n", bits / 4, pefile_get_image_base_address(pehandle)); 144 | printf("image base address: 0x%" PRIx64 "\n", pefile_get_image_base_address(pehandle)); 145 | } 146 | //list imports 147 | if (progdata.showimports) { 148 | printf("IMPORTS\n"); 149 | status = pefile_list_imports(pehandle, listimports, &progdata); 150 | } 151 | //list exports 152 | if (progdata.showexports) { 153 | printf("EXPORTS\n"); 154 | status = pefile_list_exports(pehandle, listexports, &progdata); 155 | } 156 | //close PE file 157 | pefile_close(pehandle); 158 | //clean up 159 | if (progdata.lastmodule) { 160 | free(progdata.lastmodule); 161 | progdata.lastmodule = NULL; 162 | } 163 | } 164 | } 165 | //destroy PE object 166 | pefile_destroy(pehandle); 167 | return status; 168 | } 169 | 170 | -------------------------------------------------------------------------------- /src/listperesources.c: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | Copyright (C) 2019 Brecht Sanders All Rights Reserved 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | The above copyright notice and this permission notice shall be included in 10 | all copies or substantial portions of the Software. 11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 12 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 13 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 14 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 15 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 16 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 17 | THE SOFTWARE. 18 | *****************************************************************************/ 19 | 20 | #include "pestructs.h" 21 | #include "pedeps.h" 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | int save_data (void* buf, size_t buflen, void* callbackdata) 29 | { 30 | fwrite(buf, 1, buflen, (FILE*)callbackdata); 31 | return 0; 32 | } 33 | 34 | /* 35 | struct pefile_list_version_struct { 36 | 37 | void* callbackdata; 38 | }; 39 | */ 40 | 41 | int pefile_list_version_info_group (struct pefile_resource_directory_struct* info, void* callbackdata) 42 | { 43 | /**/ 44 | if (info->isnamed) { 45 | wprintf(L"[\"%s\"]\n", info->name); 46 | } else { 47 | printf("[%s|%lu]\n", pe_get_resourceid_name(info->id), (unsigned long)info->id); 48 | } 49 | /**/ 50 | return (info->id == PE_RESOURCE_TYPE_VERSION ? PE_CB_RETURN_CONTINUE : PE_CB_RETURN_SKIP); 51 | } 52 | 53 | int pefile_list_version_info (pefile_handle pe_file, struct pefile_resource_directory_struct* info, uint32_t fileposition, uint32_t datalen, uint32_t codepage, void* callbackdata) 54 | { 55 | int versioninfofound = 0; 56 | if (info && info->parent && !info->parent->isnamed && info->parent->id == PE_RESOURCE_TYPE_VERSION) { 57 | struct peheader_versioninfo* versioninfo; 58 | if ((versioninfo = (struct peheader_versioninfo*)read_data_at(pe_file, fileposition, NULL, datalen)) != NULL) { 59 | //http://systemmanager.ru/windowsce3_0_documentationarchive.en/html/_wcesdk_win32_vs_versioninfo_str.htm 60 | //http://systemmanager.ru/windowsce3_0_documentationarchive.en/html/_wcesdk_win32_vs_fixedfileinfo_str.htm 61 | if (wcsncmp(versioninfo->szKey, L"VS_VERSION_INFO", 15) == 0) { 62 | struct peheader_fileinfo_entry* fileinfochild; 63 | struct peheader_fixedfileinfo* fileinfo = NULL; 64 | if (versioninfo->wValueLength >= 0) { 65 | fileinfo = &(versioninfo->Padding1); 66 | while (fileinfo->dwSignature != 0xFEEF04BD) { 67 | if ((uint8_t*)fileinfo + sizeof(struct peheader_fixedfileinfo) >= (uint8_t*)versioninfo + versioninfo->wLength) { 68 | fileinfo = NULL; 69 | break; 70 | } 71 | fileinfo = (struct peheader_versioninfo*)((uint8_t*)fileinfo + 1); 72 | } 73 | } 74 | if (fileinfo) { 75 | versioninfofound = 1; 76 | printf("Structure version %lu.%lu\n", (unsigned long)fileinfo->dwStrucVersionHi, (unsigned long)fileinfo->dwStrucVersionLo); 77 | printf("File version %u.%u.%u.%u\n", (unsigned)fileinfo->dwFileVersion1, (unsigned)fileinfo->dwFileVersion2, (unsigned)fileinfo->dwFileVersion3, (unsigned)fileinfo->dwFileVersion4); 78 | printf("Product version %u.%u.%u.%u\n", (unsigned)fileinfo->dwProductVersion1, (unsigned)fileinfo->dwProductVersion2, (unsigned)fileinfo->dwProductVersion3, (unsigned)fileinfo->dwProductVersion4); 79 | printf("File type: %s\n", pe_version_fileinfo_get_type_name(fileinfo->dwFileType)); 80 | printf("File subtype: %s\n", pe_version_fileinfo_get_subtype_name(fileinfo->dwFileType, fileinfo->dwFileSubtype)); 81 | printf("Debugging information: %s\n", (fileinfo->dwFileFlags & PE_VERSION_FILEINFO_FLAG_DEBUG ? "Yes" : "No")); 82 | //skip padding 83 | fileinfochild = (struct peheader_fileinfo_entry*)((uint8_t*)fileinfo + versioninfo->wValueLength); 84 | if (fileinfochild->wLength == 0) 85 | fileinfochild = (struct peheader_fileinfo_entry*)((uint8_t*)fileinfochild + 2); 86 | while (fileinfochild->wLength > 0 && (uint8_t*)fileinfochild + fileinfochild->wLength < (uint8_t*)versioninfo + versioninfo->wLength) { 87 | if (fileinfochild->wType = PE_VERSION_FILEINFO_STRING_TYPE_TEXT) { 88 | printf("Text version resource\n"); 89 | } else if (fileinfochild->wType = PE_VERSION_FILEINFO_STRING_TYPE_BINARY) { 90 | printf("Binary version resource\n"); 91 | } else { 92 | printf("Invalid version resource type\n"); 93 | } 94 | wprintf(L"-> %s\n", fileinfochild->szKey);///// 95 | if (wcsncmp(fileinfochild->szKey, L"StringFileInfo", 14) == 0) { 96 | struct peheader_fileinfo_entry* strtable; 97 | struct peheader_fileinfo_entry* str; 98 | strtable = (struct peheader_fileinfo_entry*)(fileinfochild->szKey + 14); 99 | while ((uint8_t*)strtable + strtable->wLength < (uint8_t*)versioninfo + versioninfo->wLength) { 100 | //skip padding 101 | if (strtable->wLength == 0) 102 | strtable = (struct peheader_fileinfo_entry*)((uint8_t*)strtable + 2); 103 | //check data type 104 | if (strtable->wType = PE_VERSION_FILEINFO_STRING_TYPE_TEXT) { 105 | printf("Text string table\n"); 106 | } else if (strtable->wType = PE_VERSION_FILEINFO_STRING_TYPE_BINARY) { 107 | printf("Binary string table\n"); 108 | } else { 109 | printf("Invalid string table type\n"); 110 | } 111 | //show table name (= 8-digit hexadecimal language / code page information) 112 | wprintf(L"- %s\n", strtable->szKey); 113 | str = (struct peheader_fileinfo_entry*)((uint8_t*)strtable->szKey + 8 * 2); 114 | if (str->wLength == 0) 115 | str = (struct peheader_fileinfo_entry*)((uint8_t*)str + 2); 116 | while (str->wLength > 0 && (uint8_t*)str + str->wLength < (uint8_t*)strtable + strtable->wLength) { 117 | wprintf(L" - %s = \"%s\"\n", str->szKey, (wchar_t*)((uint8_t*)str + str->wLength) - str->wValueLength); 118 | str = (struct peheader_fileinfo_entry*)((uint8_t*)str + str->wLength); 119 | } 120 | strtable = (struct peheader_fileinfo_entry*)((uint8_t*)strtable + strtable->wLength); 121 | } 122 | } else if (wcsncmp(fileinfochild->szKey, L"VarFileInfo", 11) == 0) { 123 | struct peheader_fileinfo_entry* strtable; 124 | struct peheader_fileinfo_entry* str; 125 | strtable = (struct peheader_fileinfo_entry*)(fileinfochild->szKey + 14); 126 | while ((uint8_t*)strtable + strtable->wLength < (uint8_t*)versioninfo + versioninfo->wLength) { 127 | //skip padding 128 | if (strtable->wLength == 0) 129 | strtable = (struct peheader_fileinfo_entry*)((uint8_t*)strtable + 2); 130 | //check data type 131 | if (strtable->wType = PE_VERSION_FILEINFO_STRING_TYPE_TEXT) { 132 | printf("Text string table\n"); 133 | } else if (strtable->wType = PE_VERSION_FILEINFO_STRING_TYPE_BINARY) { 134 | printf("Binary string table\n"); 135 | } else { 136 | printf("Invalid string table type\n"); 137 | } 138 | //show table name (= 8-digit hexadecimal language / code page information) 139 | wprintf(L"- %s\n", strtable->szKey); 140 | 141 | strtable = (struct peheader_fileinfo_entry*)((uint8_t*)strtable + strtable->wLength); 142 | } 143 | } 144 | fileinfochild = (struct peheader_fileinfo_entry*)((uint8_t*)fileinfochild + fileinfochild->wLength); 145 | } 146 | } 147 | } 148 | free(versioninfo); 149 | } 150 | /* 151 | wprintf(L"%*s\n", (int)datalen / sizeof(wchar_t), (wchar_t*)data); 152 | /////See also: https://docs.microsoft.com/en-us/windows/win32/menurc/string-str?redirectedfrom=MSDN 153 | */ 154 | } 155 | return (versioninfofound ? PE_CB_RETURN_ABORT : PE_CB_RETURN_CONTINUE); 156 | } 157 | 158 | int list_resourcegroups (struct pefile_resource_directory_struct* info, void* callbackdata) 159 | { 160 | if (info->isnamed) { 161 | wprintf(L"[\"%s\"]\n", info->name); 162 | } else { 163 | printf("[%s|%lu]\n", pe_get_resourceid_name(info->id), (unsigned long)info->id); 164 | } 165 | //if (info->id == 2) return PE_CB_RETURN_LAST;///// 166 | return PE_CB_RETURN_CONTINUE; 167 | } 168 | 169 | int list_resources (pefile_handle pe_file, struct pefile_resource_directory_struct* info, uint32_t fileposition, uint32_t datalen, uint32_t codepage, void* callbackdata) 170 | { 171 | if (info->isnamed) { 172 | wprintf(L"- \"%s\"\n", info->name); 173 | } else { 174 | printf("- ID: %lu\n", (unsigned long)info->id); 175 | } 176 | 177 | if (info->parent && info->parent->isnamed && (wcscmp(info->parent->name, L"PNG") == 0 || wcscmp(info->parent->name, L"AVI") == 0)) { 178 | FILE* dst; 179 | wchar_t* filename = NULL; 180 | size_t filenamelen = 0; 181 | if (info->isnamed) { 182 | filenamelen = _snwprintf(NULL, 0, L"%s.%s", info->name, info->parent->name); 183 | if ((filename = (wchar_t*)(malloc((filenamelen + 1) * sizeof(wchar_t)))) != NULL) 184 | filenamelen = _snwprintf(filename, filenamelen + 1, L"%s.%s", info->name, info->parent->name); 185 | } else { 186 | filenamelen = _snwprintf(NULL, 0, L"ID_%" PRIu32 ".%s", info->id, info->parent->name); 187 | if ((filename = (wchar_t*)(malloc((filenamelen + 1) * sizeof(wchar_t)))) != NULL) 188 | filenamelen = _snwprintf(filename, filenamelen + 1, L"ID_%" PRIu32 ".%s", info->id, info->parent->name); 189 | } 190 | wprintf(L"Saving to file: %s\n", filename); 191 | if ((dst = _wfopen(filename, L"wb")) != NULL) { 192 | pefile_read(pe_file, fileposition, datalen, NULL, 0, save_data, (void*)dst); 193 | fclose(dst); 194 | } 195 | free(filename); 196 | } else 197 | 198 | if (info && info->parent && !info->parent->isnamed && info->parent->id == PE_RESOURCE_TYPE_HTML) { 199 | void* data; 200 | printf("Contents:\n"); 201 | if ((data = read_data_at(pe_file, fileposition, NULL, datalen)) != NULL) { 202 | printf("%*s\n.\n", (int)datalen, (char*)data); 203 | free(data); 204 | } 205 | } 206 | //return PE_CB_RETURN_ABORT;///// 207 | return PE_CB_RETURN_CONTINUE; 208 | } 209 | 210 | int main (int argc, char* argv[]) 211 | { 212 | int i; 213 | pefile_handle pehandle; 214 | int status = 0; 215 | 216 | //show version number 217 | printf("pedeps library version: %s\n", pedeps_get_version_string()); 218 | 219 | //determine filename 220 | if (argc <= 1) { 221 | fprintf(stderr, "Error: no filename given\n"); 222 | return 1; 223 | } 224 | 225 | //create PE object 226 | if ((pehandle = pefile_create()) == NULL) { 227 | fprintf(stderr, "Error creating object\n"); 228 | return 2; 229 | } 230 | 231 | for (i = 1; i < argc; i++) { 232 | printf("[%s]\n", argv[i]); 233 | //open PE file 234 | if ((status = pefile_open_file(pehandle, argv[i])) != 0) { 235 | fprintf(stderr, "Error opening PE file %s: %s\n", argv[i], pefile_status_message(status)); 236 | return 3; 237 | } 238 | //display version information 239 | pefile_list_resources(pehandle, pefile_list_version_info_group, pefile_list_version_info, NULL); 240 | //list resource information 241 | //pefile_list_resources(pehandle, list_resourcegroups, list_resources, NULL); 242 | //close PE file 243 | pefile_close(pehandle); 244 | } 245 | //destroy PE object 246 | pefile_destroy(pehandle); 247 | return status; 248 | } 249 | 250 | --------------------------------------------------------------------------------