├── guiddb ├── .gitignore └── dec2c.rb ├── efiperun ├── vast │ ├── util │ │ ├── COPYING │ │ ├── operators.hpp │ │ ├── iterator.hpp │ │ └── range_map.hpp │ ├── filesystem.hpp │ ├── COPYING │ └── filesystem.cpp ├── efi_guid.c ├── .gitignore ├── Makefile ├── debugmodule.h ├── peloader.h ├── debugmodule_example.cpp ├── main.h ├── stubs.h ├── efihooks.hpp ├── README.md ├── peloader.c ├── efiperun.cpp ├── stubs.cpp ├── efihooks.cpp └── PeImage.h ├── memdmp ├── .gitignore ├── Makefile ├── make_elf.rb ├── memmap.patch └── dmp2seg.cpp ├── tree ├── efi_guid.c ├── tree.rb └── main.rb ├── README.md └── COPYING /guiddb/.gitignore: -------------------------------------------------------------------------------- 1 | edk2-dec/ 2 | -------------------------------------------------------------------------------- /efiperun/vast/util/COPYING: -------------------------------------------------------------------------------- 1 | ../COPYING -------------------------------------------------------------------------------- /memdmp/.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | dmp2seg 3 | -------------------------------------------------------------------------------- /tree/efi_guid.c: -------------------------------------------------------------------------------- 1 | ../guiddb/efi_guid.c -------------------------------------------------------------------------------- /efiperun/efi_guid.c: -------------------------------------------------------------------------------- 1 | ../guiddb/efi_guid.c -------------------------------------------------------------------------------- /efiperun/.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | jemalloc* 3 | acpi/ 4 | efiperun 5 | -------------------------------------------------------------------------------- /memdmp/Makefile: -------------------------------------------------------------------------------- 1 | CXX=g++ 2 | CXXFLAGS=-std=c++11 3 | 4 | SOURCES=dmp2seg.cpp 5 | OBJECTS=dmp2seg.o 6 | OUTPUT=dmp2seg 7 | 8 | all: $(SOURCES) $(OUTPUT) 9 | 10 | $(OUTPUT): $(OBJECTS) 11 | $(CXX) $(CXXFLAGS) $^ -o $@ 12 | 13 | .cpp.o: 14 | $(CXX) $(CXXFLAGS) -c $< -o $@ 15 | 16 | clean: 17 | rm -f $(OBJECTS) $(OUTPUT) 18 | -------------------------------------------------------------------------------- /efiperun/Makefile: -------------------------------------------------------------------------------- 1 | CC=gcc 2 | CXX=g++ 3 | CFLAGS=-I/usr/include/efi -I/usr/include/efi/x86_64 -I. -DGNU_EFI_USE_MS_ABI -g 4 | CCFLAGS=$(CFLAGS) -std=gnu99 5 | CXXFLAGS=$(CFLAGS) -std=c++11 6 | LDFLAGS= 7 | LIBS=-lpthread 8 | JEMALLOC=jemalloc-3.6.0 9 | 10 | SOURCES=peloader.c efiperun.cpp efihooks.cpp stubs.cpp debugmodule_example.cpp vast/filesystem.cpp 11 | OBJECTS=stubs.o peloader.o efiperun.o efihooks.o debugmodule_example.o vast/filesystem.o jemalloc_custom.a 12 | OUTPUT=efiperun 13 | 14 | all: $(SOURCES) $(OUTPUT) 15 | 16 | $(OUTPUT): $(OBJECTS) 17 | $(CXX) $(LDFLAGS) $^ $(LIBS) -o $@ 18 | 19 | .c.o: 20 | $(CC) $(CCFLAGS) -c $< -o $@ 21 | 22 | stubs.cpp: jemalloc_custom.h 23 | 24 | .cpp.o: 25 | $(CXX) $(CXXFLAGS) -c $< -o $@ 26 | 27 | clean: 28 | rm -f $(OBJECTS) $(OUTPUT) 29 | 30 | jemalloc_custom.h: jemalloc_custom.a $(JEMALLOC)/include/jemalloc/jemalloc.h 31 | cp $(JEMALLOC)/include/jemalloc/jemalloc.h jemalloc_custom.h 32 | 33 | jemalloc_custom.a: $(JEMALLOC)/lib/libjemalloc_pic.a 34 | objcopy --redefine-sym mmap=wrapped_mmap $(JEMALLOC)/lib/libjemalloc_pic.a jemalloc_custom.a 35 | -------------------------------------------------------------------------------- /efiperun/debugmodule.h: -------------------------------------------------------------------------------- 1 | /** 2 | * uefireverse - Tools to help with Reverse Engineering UEFI-based firmware 3 | * Copyright (C) 2015 Jethro G. Beekman 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software Foundation, 17 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | #ifndef DEBUG_MODULE_H 21 | #define DEBUG_MODULE_H 22 | 23 | typedef void (*debug_module_init_fn_t)(); 24 | typedef void (*debug_module_run_fn_t)(); 25 | 26 | void register_debug_module(debug_module_init_fn_t init, debug_module_run_fn_t run); 27 | 28 | #endif //DEBUG_MODULE_H 29 | -------------------------------------------------------------------------------- /efiperun/vast/filesystem.hpp: -------------------------------------------------------------------------------- 1 | #ifndef VAST_FILE_SYSTEM_H 2 | #define VAST_FILE_SYSTEM_H 3 | 4 | # include 5 | 6 | #include 7 | #include 8 | #include 9 | #include "vast/util/iterator.hpp" 10 | #include "vast/util/operators.hpp" 11 | 12 | namespace vast { 13 | 14 | /// An ordered sequence of all the directory entries in a particular directory. 15 | class directory 16 | { 17 | public: 18 | using const_iterator = 19 | class iterator 20 | : public util::iterator_facade< 21 | iterator, 22 | std::input_iterator_tag, 23 | std::string const&, 24 | std::string const& 25 | > 26 | { 27 | public: 28 | iterator(directory* dir = nullptr); 29 | 30 | void increment(); 31 | std::string const& dereference() const; 32 | bool equals(iterator const& other) const; 33 | 34 | private: 35 | std::string current_; 36 | directory const* dir_ = nullptr; 37 | }; 38 | 39 | /// Constructs a directory stream. 40 | /// @param p The path to the directory. 41 | directory(std::string p); 42 | 43 | ~directory(); 44 | 45 | iterator begin(); 46 | iterator end() const; 47 | 48 | /// Retrieves the ::path for this file. 49 | /// @returns The ::path for this file. 50 | std::string const& path() const; 51 | 52 | private: 53 | std::string path_; 54 | DIR* dir_ = nullptr; 55 | }; 56 | 57 | } // namespace vast 58 | 59 | #endif 60 | -------------------------------------------------------------------------------- /efiperun/peloader.h: -------------------------------------------------------------------------------- 1 | /** 2 | * uefireverse - Tools to help with Reverse Engineering UEFI-based firmware 3 | * Copyright (C) 2015 Jethro G. Beekman 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software Foundation, 17 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | #ifndef PELOADER_H 21 | #define PELOADER_H 22 | 23 | typedef struct { 24 | void* mmap_base; 25 | size_t mmap_length; 26 | void* image_base; 27 | void* entry_point; 28 | } loadinfo; 29 | 30 | #ifdef __cplusplus 31 | constexpr bool operator==(loadinfo const& s1, loadinfo const& s2) 32 | { 33 | return s1.mmap_base ==s2.mmap_base && 34 | s1.mmap_length==s2.mmap_length && 35 | s1.image_base ==s2.image_base && 36 | s1.entry_point==s2.entry_point ; 37 | } 38 | #endif 39 | 40 | loadinfo load_pe(int fd); 41 | 42 | #endif //PELOADER_H 43 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | UEFI reverse engineering tools 2 | ============================== 3 | 4 | This is a collection of tools to help reverse UEFI-based firwmare. 5 | 6 | efiperun 7 | -------- 8 | Load and run EFI PE image files on your favorite operation system (Linux). See 9 | ```efiperun/README.md``` for more information. 10 | 11 | guiddb 12 | ------ 13 | Scan .dec files (from e.g. [TianoCore EDK2]) for GUIDs and output them in 14 | C-source file format. A database of known guids is in ```guiddb/efi_guid.c```. 15 | 16 | memdmp 17 | ------ 18 | Tools to dump UEFI memory. There's a patch against [EdkShell] that makes the 19 | ```memmap``` command dump memory, pipe that to a file called ```mdmp```. Then, 20 | run ```dmp2seg``` to convert that output file into many files with the actual 21 | memory contents. Then, run ```make_elf.rb``` to make a single ELF file with all 22 | the memory contents. The ELF file is not executable or anything, it's just a 23 | convenient format to store memory segments. 24 | 25 | tree 26 | ---- 27 | A class file that will provides a Ruby tree abstraction for a firmware tree on 28 | your filesystem previously extracted by UEFIExtract (from [UEFITool]). Use 29 | UEFITool commit bf2c9f59 or newer. 30 | 31 | Also included is an example script that uses said abstraction. 32 | 33 | Other tools 34 | =========== 35 | 36 | I highly recommend [UEFITool] by Nikolaj Schlej. 37 | 38 | [TianoCore EDK2]: https://github.com/tianocore/edk2 39 | [EdkShell]: https://svn.code.sf.net/p/efi-shell/code/trunk/Shell 40 | [UEFITool]: https://github.com/LongSoft/UEFITool 41 | -------------------------------------------------------------------------------- /efiperun/vast/COPYING: -------------------------------------------------------------------------------- 1 | The following applies to files in this directory only. 2 | 3 | Copyright (c) 2014, Matthias Vallentin 4 | and 5 | Copyright (c) 2015, Jethro Beekman 6 | All rights reserved. 7 | 8 | Redistribution and use in source and binary forms, with or without 9 | modification, are permitted provided that the following conditions are met: 10 | 11 | 1. Redistributions of source code must retain the above copyright 12 | notice, this list of conditions and the following disclaimer. 13 | 14 | 2. Redistributions in binary form must reproduce the above copyright 15 | notice, this list of conditions and the following disclaimer in the 16 | documentation and/or other materials provided with the distribution. 17 | 18 | 3. Neither the name of the copyright holder nor the names of its 19 | contributors may be used to endorse or promote products derived from 20 | this software without specific prior written permission. 21 | 22 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 23 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 26 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 27 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 28 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 29 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 30 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 31 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 32 | POSSIBILITY OF SUCH DAMAGE. 33 | -------------------------------------------------------------------------------- /memdmp/make_elf.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # uefireverse - Tools to help with Reverse Engineering UEFI-based firmware 3 | # Copyright (C) 2015 Jethro G. Beekman 4 | # 5 | # This program is free software; you can redistribute it and/or 6 | # modify it under the terms of the GNU General Public License 7 | # as published by the Free Software Foundation; either version 2 8 | # of the License, or (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program; if not, write to the Free Software Foundation, 17 | # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | 19 | require 'base64' 20 | 21 | empty_elf=%w( 22 | f0VMRgIBAQAAAAAAAAAAAAEAPgABAAAAAAAAAAAAAAAAAAAAAAAAAFAAAAAAAAAAAAAAAEAAAAAA 23 | AEAAAgABAAAuc2hzdHJ0YWIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 24 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAMAAAAAAAAAAAAAAAAAAAAAAAAAQAAA 25 | AAAAAAALAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAA==)*"" 26 | EmptyElfName='empty.elf' 27 | IO.write(EmptyElfName,Base64.decode64(empty_elf)) 28 | 29 | counts={} 30 | 31 | cmd=['objcopy'] 32 | output=ARGV.shift 33 | ARGV.sort.each do |filename| 34 | secpfx,addr=File.basename(filename).split(/\s+/) 35 | addr="0x"+addr[0...16] 36 | counts[secpfx]||=0 37 | sectn="#{secpfx}.#{counts[secpfx]}" 38 | counts[secpfx]+=1 39 | cmd<<'--add-section' 40 | cmd<<"#{sectn}=#{filename}" 41 | cmd<<'--change-section-address' 42 | cmd<<"#{sectn}=#{addr}" 43 | cmd<<'--set-section-flags' 44 | cmd<<"#{sectn}=code" 45 | end 46 | cmd< 4 | #include 5 | #include 6 | 7 | # include 8 | # include 9 | # include 10 | # include 11 | # include 12 | # include 13 | # include 14 | # define VAST_CHDIR(P)(::chdir(P) == 0) 15 | # define VAST_CREATE_DIRECTORY(P)(::mkdir(P, S_IRWXU|S_IRWXG|S_IRWXO) == 0) 16 | # define VAST_CREATE_HARD_LINK(F, T)(::link(T, F) == 0) 17 | # define VAST_CREATE_SYMBOLIC_LINK(F, T, Flag)(::symlink(T, F) == 0) 18 | # define VAST_DELETE_FILE(P)(::unlink(P) == 0) 19 | # define VAST_DELETE_DIRECTORY(P)(::rmdir(P) == 0) 20 | # define VAST_MOVE_FILE(F,T)(::rename(F, T) == 0) 21 | 22 | 23 | namespace vast { 24 | 25 | directory::iterator::iterator(directory* dir) 26 | : dir_{dir} 27 | { 28 | increment(); 29 | } 30 | 31 | void directory::iterator::increment() 32 | { 33 | if (! dir_) 34 | return; 35 | 36 | if (! dir_->dir_) 37 | { 38 | dir_ = nullptr; 39 | } 40 | else if (auto ent = ::readdir(dir_->dir_)) 41 | { 42 | auto d = ent->d_name; 43 | assert(d); 44 | auto dot = d[0] == '.' && d[1] == '\0'; 45 | auto dotdot = d[0] == '.' && d[1] == '.' && d[2] == '\0'; 46 | if (dot || dotdot) 47 | increment(); 48 | else 49 | current_ = dir_->path_ + "/" + d; 50 | } 51 | else 52 | { 53 | dir_ = nullptr; 54 | } 55 | } 56 | 57 | std::string const& directory::iterator::dereference() const 58 | { 59 | return current_; 60 | } 61 | 62 | bool directory::iterator::equals(iterator const& other) const 63 | { 64 | return dir_ == other.dir_; 65 | } 66 | 67 | directory::directory(std::string p) 68 | : path_{std::move(p)}, 69 | dir_{::opendir(path_.data())} 70 | { 71 | } 72 | 73 | directory::~directory() 74 | { 75 | if (dir_) 76 | ::closedir(dir_); 77 | } 78 | 79 | directory::iterator directory::begin() 80 | { 81 | return iterator{this}; 82 | } 83 | 84 | directory::iterator directory::end() const 85 | { 86 | return {}; 87 | } 88 | 89 | std::string const& directory::path() const 90 | { 91 | return path_; 92 | } 93 | 94 | } // namespace vast 95 | -------------------------------------------------------------------------------- /memdmp/memmap.patch: -------------------------------------------------------------------------------- 1 | uefireverse - Tools to help with Reverse Engineering UEFI-based firmware 2 | Copyright (C) 2015 Jethro G. Beekman 3 | 4 | This program is free software; you can redistribute it and/or 5 | modify it under the terms of the GNU General Public License 6 | as published by the Free Software Foundation; either version 2 7 | of the License, or (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program; if not, write to the Free Software Foundation, 16 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 17 | 18 | Index: memmap/memmap.c 19 | =================================================================== 20 | --- memmap/memmap.c (revision 64) 21 | +++ memmap/memmap.c (working copy) 22 | @@ -72,6 +72,26 @@ 23 | IN EFI_MEMORY_TYPE Type 24 | ); 25 | 26 | +static void binout(const UINT8* p,UINTN l) 27 | +{ 28 | + CHAR16 outbuf[1025]; 29 | + outbuf[1024]=0; 30 | + UINTN i; 31 | + for (i=0;iNumberOfPages, 59 | Desc->Attribute 60 | ); 61 | + 62 | + SPrint(stderr,128*sizeof(CHAR16),L"%s %lX-%lX %lX %lX\n", Ptr, Desc->PhysicalStart, Desc->PhysicalStart + Bytes - 1, Desc->NumberOfPages, Desc->Attribute); 63 | + ST->StdErr->OutputString(ST->StdErr,stderr); 64 | + 65 | + if (Desc->Type!=EfiConventionalMemory) 66 | + binout((UINT8*)Desc->PhysicalStart,Bytes); 67 | 68 | // 69 | // count pages of each type memory 70 | -------------------------------------------------------------------------------- /efiperun/debugmodule_example.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * uefireverse - Tools to help with Reverse Engineering UEFI-based firmware 3 | * Copyright (C) 2015 Jethro G. Beekman 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software Foundation, 17 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | #include "vast/filesystem.hpp" 25 | 26 | using vast::directory; 27 | 28 | #include "main.h" 29 | #include "debugmodule.h" 30 | 31 | #include "efi_guid.c" 32 | 33 | typedef struct _EFI_ACPI_SUPPORT_PROTOCOL { 34 | void* GetAcpiTable; 35 | EFI_STATUS(EFIAPI *SetAcpiTable)(VOID*, VOID*, BOOLEAN, UINT32, UINTN*); 36 | void* PublishTables; 37 | } EFI_ACPI_SUPPORT_PROTOCOL; 38 | 39 | static void load_acpi_tables() 40 | { 41 | auto* acpi_support=(EFI_ACPI_SUPPORT_PROTOCOL*)find_protocol(&gEfiAcpiSupportProtocolGuid,NULL); 42 | 43 | if (acpi_support) 44 | { 45 | for (auto& file : directory("acpi")) 46 | { 47 | struct stat st={}; 48 | FILE* fp=fopen(file.c_str(),"r"); 49 | if (fp) 50 | { 51 | if (0==fstat(fileno(fp),&st)) 52 | { 53 | void* table=malloc(st.st_size); 54 | if (1==fread(table,st.st_size,1,fp)) 55 | { 56 | acpi_support->SetAcpiTable(acpi_support,table,FALSE,0,NULL); 57 | } 58 | else 59 | { 60 | free(table); 61 | } 62 | } 63 | fclose(fp); 64 | } 65 | } 66 | } 67 | } 68 | 69 | static void init() 70 | { 71 | load_acpi_tables(); 72 | } 73 | 74 | static void run() 75 | { 76 | } 77 | 78 | __attribute__((constructor)) 79 | static void register_module() 80 | { 81 | register_debug_module(init,run); 82 | } 83 | -------------------------------------------------------------------------------- /guiddb/dec2c.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby 2 | # uefireverse - Tools to help with Reverse Engineering UEFI-based firmware 3 | # Copyright (C) 2015 Jethro G. Beekman 4 | # 5 | # This program is free software; you can redistribute it and/or 6 | # modify it under the terms of the GNU General Public License 7 | # as published by the Free Software Foundation; either version 2 8 | # of the License, or (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program; if not, write to the Free Software Foundation, 17 | # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | 19 | if ARGV.count==0 then 20 | $stderr.puts "Usage: dec2c ..." 21 | exit 22 | end 23 | 24 | GuidRE=/g(.*)Guid\s*=\s*{\s*(0x\h+),\s*(0x\h+),\s*(0x\h+),\s*{\s*(0x\h+),\s*(0x\h+),\s*(0x\h+),\s*(0x\h+),\s*(0x\h+),\s*(0x\h+),\s*(0x\h+),\s*(0x\h+)\s*}\s*}/ 25 | CamelCaseRE=/[A-Z]+[^A-Z]+/ 26 | 27 | known={} 28 | 29 | ARGV.each do |f| 30 | guids=IO.read(f).scan(GuidRE) 31 | guids.each{|v|v[1..-1]=v[1..-1].map{|i|i[2..-1].to_i(16)}} 32 | errors=guids.reject{|v|v[0].scan(CamelCaseRE)*""==v[0]} 33 | if errors.count>0 then 34 | $stderr.puts "ERRORS #{f}", errors.map{|v|v[0]} 35 | exit 36 | end 37 | 38 | errors=guids.select{|v| known.include?(v[0]) && known[v[0]]!=v[1..-1] } 39 | if errors.count>0 then 40 | $stderr.puts "ERRORS #{f}", errors.map{|v|v[0]} 41 | exit 42 | end 43 | 44 | guids.each{|v|known[v[0]]=v[1..-1]} 45 | end 46 | 47 | known.each do |k,v| 48 | slens=[8,4,4,2,2,2,2,2,2,2,2] 49 | v=v.zip(slens).map{|i,slen|"%0#{slen}x"%i} 50 | strguid=v*"" 51 | [20,16,12,8].each{|n|strguid[n,0]="-"} 52 | puts "static EFI_GUID g#{k}Guid = { 0x#{v[0..2]*", 0x"}, { 0x#{v[3..10]*", 0x"} } }; // #{strguid}" 53 | end 54 | puts < 24 | #include 25 | 26 | namespace std 27 | { 28 | template<> struct hash 29 | { 30 | constexpr size_t operator()(EFI_GUID const& s) const 31 | { 32 | return ((UINT64*)&s)[0]^((UINT64*)&s)[1]; 33 | } 34 | }; 35 | } 36 | 37 | constexpr bool operator==(EFI_GUID const& s1, EFI_GUID const& s2) 38 | { 39 | return ((UINT64*)&s1)[0]==((UINT64*)&s2)[0] && ((UINT64*)&s1)[1]==((UINT64*)&s2)[1]; 40 | } 41 | 42 | const char* find_pe_caller_id(); 43 | const char* guid_string(EFI_GUID* guid); 44 | void log_protocol(const char* type,EFI_GUID* guid); 45 | void* find_protocol(EFI_GUID* guid,EFI_HANDLE handle); 46 | void install_protocol(EFI_GUID* guid,EFI_HANDLE handle,void* interface); 47 | intptr_t count_handles(EFI_GUID* guid); 48 | void* get_variable(EFI_GUID* guid,CHAR16* name,UINTN* data_size,UINT32* attributes); 49 | void set_variable(EFI_GUID* guid,const CHAR16* name,void* data,UINTN data_size,UINT32 attributes); 50 | void char16_print(const char* prefix, CHAR16* str); 51 | void* get_smst(); 52 | 53 | #include 54 | #include "vast/util/range_map.hpp" 55 | using vast::util::range_map; 56 | 57 | extern range_map g_memory_map; 58 | 59 | struct memory_block 60 | { 61 | void* start; 62 | union { 63 | size_t size; 64 | size_t offset; 65 | }; 66 | std::string name; 67 | }; 68 | 69 | void register_memory(const memory_block& block); // use size member 70 | memory_block lookup_memory(void* address); // use offset member 71 | 72 | #endif //MAIN_H 73 | -------------------------------------------------------------------------------- /memdmp/dmp2seg.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * uefireverse - Tools to help with Reverse Engineering UEFI-based firmware 3 | * Copyright (C) 2015 Jethro G. Beekman 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software Foundation, 17 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | #include 25 | #include 26 | #include 27 | 28 | using std::string; 29 | 30 | static string getline(FILE* fp) 31 | { 32 | string ret{}; 33 | uint16_t c; 34 | while (c!='\n' && !feof(fp)) 35 | { 36 | fread(&c,2,1,fp); 37 | ret+=(char)c; 38 | } 39 | return ret; 40 | } 41 | 42 | static void writebuf(string info,uint16_t* buf,size_t size) 43 | { 44 | // rtrim 45 | info.erase(std::find_if(info.rbegin(), info.rend(), std::not1(std::ptr_fun(std::isspace))).base(), info.end()); 46 | 47 | FILE *fp=fopen(info.c_str(),"w"); 48 | setvbuf(fp,NULL,_IOFBF,BUFSIZ); 49 | for (size_t i=0;i>8)==0xee)) 69 | { 70 | fputs(last_line.c_str(),stdout); 71 | long long int start=strtoull(last_line.c_str()+11,NULL,16); 72 | long long int end=strtoull(last_line.c_str()+28,NULL,16); 73 | buf=(uint16_t*)realloc(buf,(end-start+1)*2); 74 | fread(buf,end-start+1,2,fp); 75 | writebuf(last_line,buf,end-start+1); 76 | } 77 | else 78 | { 79 | last_line=getline(fp); 80 | } 81 | } 82 | fclose(fp); 83 | free(buf); 84 | return 0; 85 | } 86 | -------------------------------------------------------------------------------- /efiperun/stubs.h: -------------------------------------------------------------------------------- 1 | /** 2 | * uefireverse - Tools to help with Reverse Engineering UEFI-based firmware 3 | * Copyright (C) 2015 Jethro G. Beekman 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software Foundation, 17 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | #ifndef STUBS_H 21 | #define STUBS_H 22 | 23 | #include 24 | 25 | EFI_STATUS EFIAPI HandleProtocol(IN EFI_HANDLE Handle,IN EFI_GUID *Protocol,OUT VOID **Interface); 26 | EFI_STATUS EFIAPI LocateProtocol(IN EFI_GUID *Protocol,IN VOID *Registration OPTIONAL,OUT VOID **Interface); 27 | EFI_STATUS EFIAPI InstallProtocolInterface(IN OUT EFI_HANDLE *Handle, IN EFI_GUID *Protocol, IN EFI_INTERFACE_TYPE InterfaceType, IN VOID *Interface); 28 | EFI_STATUS EFIAPI InstallMultipleProtocolInterfaces(IN OUT EFI_HANDLE *Handle, ...); 29 | EFI_STATUS EFIAPI AllocatePool(IN EFI_MEMORY_TYPE PoolType, IN UINTN Size, OUT VOID **Buffer); 30 | EFI_STATUS EFIAPI AllocatePages(IN EFI_ALLOCATE_TYPE Type, IN EFI_MEMORY_TYPE MemoryType, IN UINTN NoPages, OUT EFI_PHYSICAL_ADDRESS *Memory); 31 | VOID EFIAPI SetMem(IN VOID *Buffer, IN UINTN Size, IN UINT8 Value); 32 | VOID EFIAPI CopyMem(IN VOID *Destination, IN VOID *Source, IN UINTN Length); 33 | EFI_STATUS EFIAPI GetNextMonotonicCount(OUT UINT64 *Count); 34 | EFI_STATUS EFIAPI GetNextHighMonotonicCount(OUT UINT32 *HighCount); 35 | EFI_STATUS EFIAPI OutputString(IN SIMPLE_TEXT_OUTPUT_INTERFACE *This, IN CHAR16 *String); 36 | EFI_STATUS EFIAPI GetVariable(IN CHAR16 *VariableName, IN EFI_GUID *VendorGuid, OUT UINT32 *Attributes OPTIONAL, IN OUT UINTN *DataSize, OUT VOID *Data); 37 | EFI_STATUS EFIAPI SetVariable(IN CHAR16 *VariableName, IN EFI_GUID *VendorGuid, IN UINT32 Attributes, IN UINTN DataSize, IN VOID *Data); 38 | EFI_STATUS EFIAPI LocateHandleBuffer(IN EFI_LOCATE_SEARCH_TYPE SearchType, IN EFI_GUID *Protocol OPTIONAL, IN VOID *SearchKey OPTIONAL, IN OUT UINTN *NoHandles, OUT EFI_HANDLE **Buffer); 39 | EFI_STATUS EFIAPI InSmm(IN VOID *This,OUT BOOLEAN *pInSmm); 40 | EFI_STATUS EFIAPI GetSmstLocation(IN VOID *This, IN OUT VOID **Smst); 41 | EFI_STATUS EFIAPI QueryMode(IN SIMPLE_TEXT_OUTPUT_INTERFACE *This, IN UINTN ModeNumber, OUT UINTN *Columns, OUT UINTN *Rows); 42 | EFI_STATUS EFIAPI GetAcpiTable(IN VOID *This, IN INTN Index, OUT VOID **Table, OUT UINT32 *Version, OUT UINTN *Handle); 43 | EFI_STATUS EFIAPI SetAcpiTable(IN VOID *This, IN VOID *Table OPTIONAL, IN BOOLEAN Checksum, IN UINT32 Version, IN OUT UINTN *Handle); 44 | 45 | #endif //STUBS_H 46 | -------------------------------------------------------------------------------- /tree/tree.rb: -------------------------------------------------------------------------------- 1 | # uefireverse - Tools to help with Reverse Engineering UEFI-based firmware 2 | # Copyright (C) 2015 Jethro G. Beekman 3 | # 4 | # This program is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU General Public License 6 | # as published by the Free Software Foundation; either version 2 7 | # of the License, or (at your option) any later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program; if not, write to the Free Software Foundation, 16 | # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 17 | 18 | class Section 19 | attr_reader :children, :index, :name, :parent, :metadata 20 | 21 | def descend(path) 22 | raise TypeError, "expected #{path.inspect} to be an array" unless path.is_a? Array 23 | return self if path.length==0 24 | if path[0].is_a? Numeric then 25 | @children[path[0]].descend(path[1..-1]) 26 | else 27 | opts=@children.select {|c| c.name==path[0] } 28 | raise IndexError, "ambiguous path #{path.inspect}" unless opts.length==1 29 | opts[0].descend(path[1..-1]) 30 | end 31 | end 32 | 33 | # Recursive 34 | def each(&block) 35 | yield self 36 | @children.each{|c|c.each(&block)} 37 | end 38 | include Enumerable 39 | 40 | def inspect 41 | "
" 42 | end 43 | 44 | def to_s 45 | with_ancestors.map{|v|v.name}*"::" 46 | end 47 | 48 | def with_ancestors 49 | return [self] if parent.nil? 50 | parent.with_ancestors+[self] 51 | end 52 | 53 | def body_path 54 | File.join(*with_ancestors[1..-1].map{|v|"#{v.index} #{v.name}"},"body.bin") 55 | end 56 | 57 | private 58 | def add_child(num,name,metadata) 59 | p=self 60 | @children[num]=Section.instance_exec{new(p,num,name,metadata)} 61 | end 62 | 63 | def initialize(parent,index,name,metadata) 64 | @children=[] 65 | @index=index 66 | @name=name.dup.freeze 67 | @parent=parent 68 | @metadata=metadata.dup.freeze 69 | end 70 | 71 | class << self 72 | private :new 73 | private 74 | def parse_section(s) 75 | ret={} 76 | ri=-1 77 | ci=s.index(":") 78 | until ci.nil? 79 | name=s[(ri+1)...ci] 80 | new_ci=s.index(":",ci+1) 81 | ri=new_ci ? s.rindex("\n",new_ci) : -1 82 | value=s[(ci+2)..ri].chomp 83 | if ret.include? name then 84 | ret[name]=[ret[name]] unless ret[name].is_a?(Array) 85 | ret[name] << value 86 | else 87 | ret[name]=value 88 | end 89 | ci=new_ci 90 | end 91 | ret 92 | end 93 | 94 | def parse_dirname(dirname) 95 | raise NameError, "parse_dirname #{dirname}" unless dirname=~/^(\d+) (.+)$/ 96 | [$~[1].to_i,$~[2]] 97 | end 98 | 99 | def read_section(s,basepath) 100 | path=s.split(File::SEPARATOR) 101 | raise NameError, "read_section #{s}" unless path[0]=="." and path[-1]=="info.txt" 102 | [path[1...-1].map{|v|parse_dirname(v)},parse_section(IO.read(File.join(basepath,s)))] 103 | end 104 | 105 | public 106 | def readdir(path) 107 | sections=Hash[IO.popen(['find','-name','info.txt','-print0',:chdir=>path],'r'){|io|io.read}.split("\0").map{|s|read_section(s,path)}] 108 | root=nil 109 | sections.keys.sort.each do |k| 110 | data=sections[k] 111 | if k==[] then 112 | root=new(nil,0,"",data) 113 | else 114 | root.descend(k[0...-1].map{|i,s|i}).instance_exec{add_child(k[-1][0],k[-1][1],data)} 115 | end 116 | end 117 | root.each{|c| c.children.freeze} 118 | root 119 | end 120 | end 121 | end 122 | -------------------------------------------------------------------------------- /efiperun/vast/util/operators.hpp: -------------------------------------------------------------------------------- 1 | #ifndef VAST_UTIL_OPERATORS_H 2 | #define VAST_UTIL_OPERATORS_H 3 | 4 | namespace vast { 5 | namespace util { 6 | 7 | template 8 | struct equality_comparable 9 | { 10 | friend bool operator!=(T const& x, U const& y) 11 | { 12 | return ! (x == y); 13 | } 14 | }; 15 | 16 | template 17 | struct less_than_comparable 18 | { 19 | friend bool operator>(T const& x, U const& y) 20 | { 21 | return y < x; 22 | } 23 | 24 | friend bool operator<=(T const& x, U const& y) 25 | { 26 | return ! (y < x); 27 | } 28 | 29 | friend bool operator>=(T const& x, U const& y) 30 | { 31 | return ! (x < y); 32 | } 33 | }; 34 | 35 | template 36 | struct partially_ordered 37 | { 38 | friend bool operator>(T const& x, U const& y) 39 | { 40 | return y < x; 41 | } 42 | 43 | friend bool operator<=(T const& x, U const& y) 44 | { 45 | return x < y || x == y; 46 | } 47 | 48 | friend bool operator>=(T const& x, U const& y) 49 | { 50 | return y < x || x == y; 51 | } 52 | }; 53 | 54 | template 55 | struct totally_ordered : equality_comparable, less_than_comparable 56 | { 57 | }; 58 | 59 | #define VAST_BINARY_OPERATOR_NON_COMMUTATIVE(NAME, OP) \ 60 | template \ 61 | struct NAME \ 62 | { \ 63 | friend T operator OP(T const& x, U const& y) \ 64 | { \ 65 | T t(x); \ 66 | t OP##= y; \ 67 | return t; \ 68 | } \ 69 | }; 70 | 71 | #define VAST_BINARY_OPERATOR_COMMUTATIVE(NAME, OP) \ 72 | template \ 73 | struct NAME \ 74 | { \ 75 | friend T operator OP(T const& x, U const& y) \ 76 | { \ 77 | T t(x); \ 78 | t OP##= y; \ 79 | return t; \ 80 | } \ 81 | }; 82 | 83 | VAST_BINARY_OPERATOR_COMMUTATIVE(addable, +) 84 | VAST_BINARY_OPERATOR_COMMUTATIVE(multipliable, *) 85 | VAST_BINARY_OPERATOR_NON_COMMUTATIVE(subtractable, -) 86 | VAST_BINARY_OPERATOR_NON_COMMUTATIVE(dividable, /) 87 | VAST_BINARY_OPERATOR_NON_COMMUTATIVE(modable, %) 88 | VAST_BINARY_OPERATOR_COMMUTATIVE(xorable, ^) 89 | VAST_BINARY_OPERATOR_COMMUTATIVE(andable, &) 90 | VAST_BINARY_OPERATOR_COMMUTATIVE(orable, |) 91 | 92 | #undef VAST_BINARY_OPERATOR_COMMUTATIVE 93 | 94 | template 95 | struct additive 96 | : addable, subtractable 97 | {}; 98 | 99 | template 100 | struct multiplicative 101 | : multipliable, dividable 102 | {}; 103 | 104 | template 105 | struct integer_multiplicative 106 | : multiplicative, modable 107 | {}; 108 | 109 | template 110 | struct arithmetic 111 | : additive, multiplicative 112 | {}; 113 | 114 | template 115 | struct integer_arithmetic 116 | : additive, integer_multiplicative 117 | {}; 118 | 119 | template 120 | struct bitwise 121 | : andable, orable, xorable 122 | {}; 123 | 124 | } // namespace util 125 | } // namespace vast 126 | 127 | #endif 128 | -------------------------------------------------------------------------------- /efiperun/efihooks.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * uefireverse - Tools to help with Reverse Engineering UEFI-based firmware 3 | * Copyright (C) 2015 Jethro G. Beekman 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software Foundation, 17 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | #ifndef HOOKS_H 21 | #define HOOKS_H 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #define HOOKFN_T(name,type) EFI_STATUS (*name)(type*,void*,void*,void*,void*) 30 | 31 | template class __attribute__((__packed__)) GenericHook 32 | { 33 | HOOKFN_T(m_pfn,T); 34 | T data; 35 | /* code */ 36 | // This calls m_pfn(&data,...) via fix_hook() 37 | unsigned char op1[3]; // lea IND32(%rip),%r10 4c 8d 15 38 | int op1Index; 39 | unsigned char op2[2]; // movabs IMM64,%rax 48 b8 40 | unsigned long long op2Imm; 41 | unsigned char op3[2]; // jmpq *%rax ff e0 42 | /* end code */ 43 | 44 | static EFI_STATUS EFIAPI fix_hook(void*,void*,void*,void*); 45 | public: 46 | GenericHook(T d,HOOKFN_T(pfn,T)); 47 | void* get_func(); 48 | }; 49 | 50 | struct GuidIndex 51 | { 52 | EFI_GUID guid; 53 | int index; 54 | }; 55 | 56 | template class DummyInterface 57 | { 58 | void* pointers[NUM]; 59 | std::vector> hooks; 60 | public: 61 | DummyInterface(EFI_GUID* pguid,HOOKFN_T(pfn,GuidIndex)); 62 | }; 63 | 64 | template GenericHook::GenericHook(T d,HOOKFN_T(pfn,T)) 65 | : op1{0x4c,0x8d,0x15}, op2{0x48,0xb8}, op3{0xff,0xe0}, data(d), m_pfn(pfn) 66 | { 67 | op1Index=((intptr_t)this)-((intptr_t)&op2); 68 | op2Imm=(intptr_t)&fix_hook; 69 | } 70 | 71 | template void* GenericHook::get_func() 72 | { 73 | /* Unprotect page with code */ 74 | int pagesize=sysconf(_SC_PAGE_SIZE); 75 | int pagemask=pagesize-1; 76 | intptr_t page1=((intptr_t)&op1)&~pagemask; 77 | intptr_t page2=(((intptr_t)&op3)+sizeof(op3)-1)&~pagemask; 78 | mprotect((void*)page1,pagesize,PROT_READ|PROT_WRITE|PROT_EXEC); 79 | if (page2!=page1) 80 | mprotect((void*)page2,pagesize,PROT_READ|PROT_WRITE|PROT_EXEC); 81 | 82 | /* code pointer */ 83 | return &op1; 84 | } 85 | 86 | template EFI_STATUS EFIAPI GenericHook::fix_hook(void* a0,void* a1,void* a2,void* a3) 87 | { 88 | GenericHook* r10; 89 | asm __volatile ("mov %%r10, %0":"=g"(r10)::); 90 | return r10->m_pfn(&r10->data,a0,a1,a2,a3); 91 | } 92 | 93 | template DummyInterface::DummyInterface(EFI_GUID* pguid,HOOKFN_T(pfn,GuidIndex)) 94 | { 95 | hooks.reserve(NUM); 96 | for (int i=0;i```. 87 | 88 | Internals 89 | ========= 90 | 91 | efiperun.cpp - efihooks.cpp 92 | --------------------------- 93 | The brains of the operation. `efiperun` is mostly in charge of memory 94 | management and execution control while `efihooks` installs most of the 95 | standard protocol interfaces. Note that we use a custom memory allocator so 96 | that we can keep track of which module allocates memory. Memory is generally 97 | never freed. 98 | 99 | stubs.cpp - stubs.h 100 | ------------------- 101 | Implementing minimal functionality to make the environment look like EFI. This 102 | is where BootServices functions such as AllocatePool, CopyMem, etc. are 103 | defined. 104 | 105 | peloader.c - peloader.h - PeImage.h 106 | ----------------------------------- 107 | A simple PE image loader that does relocation. This should be fairly 108 | stand-alone. Only tested on 64-bit images. 109 | -------------------------------------------------------------------------------- /efiperun/peloader.c: -------------------------------------------------------------------------------- 1 | /** 2 | * uefireverse - Tools to help with Reverse Engineering UEFI-based firmware 3 | * Copyright (C) 2015 Jethro G. Beekman 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software Foundation, 17 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | #define mmap wrapped_mmap 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | #define EFI_IMAGE_MACHINE_IA32 33 | #define EFI_IMAGE_MACHINE_IA64 34 | #include 35 | #undef EFI_IMAGE_MACHINE_IA32 36 | #undef EFI_IMAGE_MACHINE_IA64 37 | // not using becauses for some reason it does not have PE32+ support 38 | #include "PeImage.h" 39 | 40 | #include "peloader.h" 41 | 42 | //////////////////// from wine //////////////////// 43 | ////////////////// dlls/ntdll/loader.c ////////////////// 44 | 45 | typedef uint32_t UINT, DWORD_PTR; 46 | typedef uint16_t USHORT, WORD; 47 | typedef intptr_t INT_PTR; 48 | 49 | #define FIXME(args...) fprintf(stderr,args) 50 | #define LOWORD(l) ((WORD)((DWORD_PTR)(l) & 0xFFFF)) 51 | #define HIWORD(l) ((WORD)((DWORD_PTR)(l) >> 16)) 52 | 53 | /*********************************************************************** 54 | * LdrProcessRelocationBlock (NTDLL.@) 55 | * 56 | * Apply relocations to a given page of a mapped PE image. 57 | */ 58 | static EFI_IMAGE_BASE_RELOCATION * LdrProcessRelocationBlock( void *page, UINT count, 59 | USHORT *relocs, INT_PTR delta ) 60 | { 61 | while (count--) 62 | { 63 | USHORT offset = *relocs & 0xfff; 64 | int type = *relocs >> 12; 65 | switch(type) 66 | { 67 | case EFI_IMAGE_REL_BASED_ABSOLUTE: 68 | break; 69 | case EFI_IMAGE_REL_BASED_HIGH: 70 | *(short *)((char *)page + offset) += HIWORD(delta); 71 | break; 72 | case EFI_IMAGE_REL_BASED_LOW: 73 | *(short *)((char *)page + offset) += LOWORD(delta); 74 | break; 75 | case EFI_IMAGE_REL_BASED_HIGHLOW: 76 | *(int *)((char *)page + offset) += delta; 77 | break; 78 | case EFI_IMAGE_REL_BASED_DIR64: 79 | *(INT_PTR *)((char *)page + offset) += delta; 80 | break; 81 | default: 82 | FIXME("Unknown/unsupported fixup type %x.\n", type); 83 | return NULL; 84 | } 85 | relocs++; 86 | } 87 | return (EFI_IMAGE_BASE_RELOCATION *)relocs; /* return address of next block */ 88 | } 89 | 90 | ///////////////////////////////////////////////////////// 91 | ///////////////////////////////////////////////////////// 92 | 93 | #define ERRNO_ERROR(s) { perror(#s); goto error; } 94 | #define ERROR(msg) { fputs(msg "\n",stderr); goto error; } 95 | 96 | typedef EFI_IMAGE_NT_HEADERS32 EFI_IMAGE_NT_HEADERS; 97 | typedef EFI_IMAGE_OPTIONAL_HEADER32 EFI_IMAGE_OPTIONAL_HEADER; 98 | 99 | loadinfo load_pe(int fd) 100 | { 101 | struct stat st; 102 | char *pebuf=NULL,*memptr=NULL,*pbase; 103 | EFI_IMAGE_DOS_HEADER* dos; 104 | EFI_IMAGE_NT_HEADERS* nt; 105 | EFI_IMAGE_SECTION_HEADER* shdrs; 106 | EFI_IMAGE_OPTIONAL_HEADER* oh; 107 | EFI_IMAGE_OPTIONAL_HEADER32* oh32=NULL; 108 | EFI_IMAGE_OPTIONAL_HEADER64* oh64=NULL; 109 | int page_bits; 110 | intptr_t base,size; 111 | loadinfo ret={}; 112 | 113 | if (fstat(fd,&st)!=0) ERRNO_ERROR(fstat); 114 | if (!(pebuf=(char*)malloc(st.st_size))) ERRNO_ERROR(malloc); 115 | if (read(fd,pebuf,st.st_size)!=st.st_size) ERRNO_ERROR(read); 116 | 117 | dos=(EFI_IMAGE_DOS_HEADER*)pebuf; 118 | if (dos->e_magic!=EFI_IMAGE_DOS_SIGNATURE) ERROR("Invalid MZ signature"); 119 | nt=(EFI_IMAGE_NT_HEADERS*)(pebuf+dos->e_lfanew); 120 | if (nt->Signature!=EFI_IMAGE_NT_SIGNATURE) ERROR("Invalid PE signature"); 121 | 122 | if (!(nt->FileHeader.Characteristics&EFI_IMAGE_FILE_EXECUTABLE_IMAGE)) ERROR("PE not executable"); 123 | 124 | if (nt->FileHeader.Machine!=EFI_IMAGE_FILE_MACHINE_I386 && nt->FileHeader.Machine!=EFI_IMAGE_MACHINE_X64) ERROR("PE not i386/x86_64"); 125 | 126 | oh=&nt->OptionalHeader; 127 | 128 | if (nt->FileHeader.SizeOfOptionalHeader<2 || !( 129 | (nt->FileHeader.SizeOfOptionalHeader==sizeof(*oh32) && oh->Magic==EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) || 130 | (nt->FileHeader.SizeOfOptionalHeader==sizeof(*oh64) && oh->Magic==EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) ) ) 131 | ERROR("PE Optional header invalid"); 132 | 133 | if (nt->FileHeader.SizeOfOptionalHeader==sizeof(*oh64)) 134 | oh64=(EFI_IMAGE_OPTIONAL_HEADER64*)&nt->OptionalHeader; 135 | else 136 | oh32=(EFI_IMAGE_OPTIONAL_HEADER32*)&nt->OptionalHeader; 137 | #define oh(f) (oh64?oh64->f:oh32->f) 138 | 139 | page_bits=sysconf(_SC_PAGE_SIZE)-1; 140 | 141 | base=oh(ImageBase)&~page_bits; 142 | size=((oh(ImageBase)+oh(SizeOfImage))|page_bits)+1; 143 | if (sizeFileHeader.SizeOfOptionalHeader); 151 | for(int i=0;iFileHeader.NumberOfSections;i++) 152 | { 153 | if (shdrs[i].VirtualAddress!=shdrs[i].PointerToRawData) ERROR("Section VirtualAddress/file offset mismatch"); 154 | memcpy(pbase+shdrs[i].VirtualAddress,pebuf+shdrs[i].PointerToRawData,shdrs[i].SizeOfRawData); 155 | } 156 | 157 | if (!base) 158 | { 159 | EFI_IMAGE_DATA_DIRECTORY *relocs=&oh(DataDirectory)[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC]; 160 | EFI_IMAGE_BASE_RELOCATION *rel=(EFI_IMAGE_BASE_RELOCATION*)(pbase+relocs->VirtualAddress); 161 | EFI_IMAGE_BASE_RELOCATION *end=(EFI_IMAGE_BASE_RELOCATION*)(pbase+relocs->VirtualAddress+relocs->Size); 162 | 163 | while (relSizeOfBlock) 164 | { 165 | if (rel->VirtualAddress >= (memptr+size)-pbase) ERROR("Invalid Relocation"); 166 | rel = LdrProcessRelocationBlock( pbase+rel->VirtualAddress, 167 | (rel->SizeOfBlock-sizeof(*rel))/sizeof(USHORT), 168 | (USHORT*)(rel+1), (intptr_t)pbase ); 169 | if (!rel) goto error; 170 | } 171 | } 172 | 173 | ret.mmap_base=memptr; 174 | ret.mmap_length=size; 175 | ret.image_base=pbase; 176 | ret.entry_point=pbase+oh(AddressOfEntryPoint); 177 | free(pebuf); 178 | return ret; 179 | error: 180 | if (memptr!=0 && memptr!=MAP_FAILED) munmap(memptr,size); 181 | free(pebuf); 182 | return ret; 183 | } 184 | -------------------------------------------------------------------------------- /tree/main.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # uefireverse - Tools to help with Reverse Engineering UEFI-based firmware 3 | # Copyright (C) 2015 Jethro G. Beekman 4 | # 5 | # This program is free software; you can redistribute it and/or 6 | # modify it under the terms of the GNU General Public License 7 | # as published by the Free Software Foundation; either version 2 8 | # of the License, or (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program; if not, write to the Free Software Foundation, 17 | # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | 19 | require './tree' 20 | path='UEFIEXTRACT_DATA_PATH' 21 | root=Section.readdir(path) 22 | 23 | ImageTypeRE=/^(TE|PE32\(\+\)) image$/ 24 | 25 | def guid_string_to_binary(guid_string) 26 | raise unless guid_string=~/^(\h{8})-(\h{4})-(\h{4})-(\h{4})-(\h{12})$/ 27 | r =$~[1].chars.each_slice(2).to_a.reverse*"" 28 | r+=$~[2].chars.each_slice(2).to_a.reverse*"" 29 | r+=$~[3].chars.each_slice(2).to_a.reverse*"" 30 | r+=$~[4] 31 | r+=$~[5] 32 | [r].pack("H*") 33 | end 34 | 35 | def all_indices(string,search,casei) 36 | ret=[] 37 | i=-1 38 | if casei then 39 | search=Regexp.new(search,Regexp::IGNORECASE) 40 | until (i=string.match(search,i+1)).nil? 41 | i=i.offset(0)[0] 42 | ret << i 43 | end 44 | else 45 | until (i=string.index(search,i+1)).nil? 46 | ret << i 47 | end 48 | end 49 | ret 50 | end 51 | 52 | def find_guids(guids,string) 53 | ret={} 54 | guids.each do |guid| 55 | indices=all_indices(string,guid,true)+all_indices(string,guid_string_to_binary(guid),false)+all_indices(string,guid.encode('utf-16le').force_encoding('binary'),true) 56 | ret[guid]=indices if indices.count>0 57 | end 58 | ret 59 | end 60 | 61 | def image_guid(image_section) 62 | if image_section.parent.metadata.include?("File GUID") then 63 | image_section.parent.metadata["File GUID"] 64 | elsif image_section.parent.metadata.include?("Section GUID") && image_section.parent.metadata["Section GUID"]=="FC1BCDB0-7D31-49AA-936A-A4600D9DD083" then 65 | image_section.parent.parent.metadata["File GUID"] 66 | elsif image_section.parent.metadata["Subtype"]=="Compressed" then 67 | image_guid(image_section.parent) 68 | else 69 | raise 70 | end 71 | end 72 | 73 | def image_identify(image_section) 74 | if image_section.parent.metadata.include?("File GUID") then 75 | image_section.parent.metadata["Text"] 76 | elsif image_section.parent.metadata.include?("Section GUID") && image_section.parent.metadata["Section GUID"]=="FC1BCDB0-7D31-49AA-936A-A4600D9DD083" then 77 | image_section.parent.parent.metadata["Text"] 78 | elsif image_section.parent.metadata["Subtype"]=="Compressed" then 79 | image_identify(image_section.parent) 80 | else 81 | raise 82 | end 83 | end 84 | 85 | def image_get_dependency_guids(image_section) 86 | image_section.select{|v|v.metadata["Subtype"]=~/(PEI|DXE) dependency/}.map{|v|v.metadata["Parsed expression"].scan(/PUSH (\h{8}-\h{4}-\h{4}-\h{4}-\h{12})/)}.flatten.map(&:downcase).uniq 87 | end 88 | 89 | def guid_identify(guid) 90 | ret=[] 91 | if $known_guids.include? guid then 92 | ret<<$known_guids[guid][:of_image].metadata["Text"] if $known_guids[guid].include? :of_image 93 | ret<<$known_guids[guid][:edk_name] if $known_guids[guid].include? :edk_name 94 | end 95 | ret << guid if ret.count==0 96 | ret*"/" 97 | end 98 | 99 | $known_guids={} 100 | 101 | images=[] # root.select{...} 102 | images.each{|v|$known_guids[v.metadata["File GUID"].downcase]={:of_image=>v}} 103 | 104 | dependency_guids=images.map do |i| 105 | deps=image_get_dependency_guids(i) 106 | guid=i.metadata["File GUID"].downcase 107 | $known_guids[guid][:has_dependencies]||=[] 108 | $known_guids[guid][:has_dependencies]+=deps 109 | deps.each do |d| 110 | $known_guids[d]||={} 111 | $known_guids[d][:dependency_of]||=[] 112 | $known_guids[d][:dependency_of]<0 then 148 | # puts image_identify(image_section) || image_guid(image_section) 149 | # guids.each do |k,v| 150 | # puts "\t#{k}\t#{v.map{|i|i.to_s(16)}*" "}" 151 | # end 152 | # end 153 | #end 154 | 155 | #///////// Run x86_64 image files 156 | #ios_running={} 157 | #ios_done={} 158 | #images.map{|v|v.select{|v|v.metadata["Subtype"]=~ImageTypeRE}}.flatten.each do |image_section| 159 | # if image_section.metadata["Optional header signature"]=="020Bh" then 160 | # io=IO.popen(['../efiperun/efiperun','--unsafe',File.join(path,image_section.body_path)]) 161 | # ios_running[io]={:image_section=>image_section,:output=>""} 162 | # end 163 | #end 164 | #$stderr.puts "Launched #{ios_running.count} processes..." 165 | #while ios_running.count>0 166 | # ready=select(ios_running.keys,[],ios_running.keys) 167 | # ready.reduce(:|).each do |io| 168 | # if io.eof? then 169 | # ios_running[io][:output] << io.read.to_s 170 | # io.close 171 | # ios_running[io][:status]=$? 172 | # ios_done[io]=ios_running.delete(io) 173 | # $stderr.print "#{ios_done.count}..." if (ios_done.count%50)==0 174 | # else 175 | # ios_running[io][:output] << io.readpartial(2048) 176 | # end 177 | # end 178 | #end 179 | #$stderr.print "Done.\n" 180 | #ios_done.each do |_,proc| 181 | # puts File.join(path,proc[:image_section].body_path) 182 | # puts image_identify(proc[:image_section]) || image_guid(proc[:image_section]) 183 | # $stderr.puts image_guid(proc[:image_section]) if proc[:output].include? '4c8a2451-c207-405b-9694-99ea13251341' 184 | # puts proc[:output] 185 | # puts "Exit#{proc[:status].to_s.sub(/pid \d+( exit)?/,"")}" 186 | # puts "---------" 187 | #end 188 | 189 | #///////// Find image files 190 | #root.select{|v|v.metadata["Subtype"]=~ImageTypeRE}.map do |v| 191 | # hexre=/^(\h+)h/ 192 | # raise unless v.metadata["Body size"]=~hexre 193 | # size=$~[1].to_i(16) 194 | # raise unless v.metadata["ImageBase"]=~hexre 195 | # base=$~[1].to_i(16) 196 | # [base,base+size-1,size,v.with_ancestors[1..-1].map{|v|v.index}] 197 | #end.sort.each do |b,e,s,n| 198 | # node=root.descend(n) 199 | # puts "%08x\t%08x\t%08x\t%s\t%s" % [b,e,s,image_guid(node),image_identify(node)] 200 | #end 201 | -------------------------------------------------------------------------------- /efiperun/vast/util/iterator.hpp: -------------------------------------------------------------------------------- 1 | #ifndef VAST_UTIL_ITERATOR_H 2 | #define VAST_UTIL_ITERATOR_H 3 | 4 | #include 5 | #include 6 | #include "vast/util/operators.hpp" 7 | 8 | namespace vast { 9 | namespace util { 10 | 11 | template 12 | class iterator_facade; 13 | 14 | // Provides clean access to iterator internals. Similar to vast::access. 15 | class iterator_access 16 | { 17 | template 18 | friend class iterator_facade; 19 | 20 | public: 21 | template 22 | static typename Facade::reference dereference(Facade const& f) 23 | { 24 | return f.dereference(); 25 | } 26 | 27 | template 28 | static void increment(Facade& f) 29 | { 30 | f.increment(); 31 | } 32 | 33 | template 34 | static void decrement(Facade& f) 35 | { 36 | f.decrement(); 37 | } 38 | 39 | template 40 | static void advance(Facade& f, typename Facade::difference_type n) 41 | { 42 | f.advance(n); 43 | } 44 | 45 | template 46 | static bool equals(Facade1 const& f1, Facade2 const& f2) 47 | { 48 | return f1.equals(f2); 49 | } 50 | 51 | template 52 | static auto distance_from(Facade1 const& f1, Facade2 const& f2) 53 | -> typename Facade2::difference_type 54 | { 55 | return f2.distance_to(f1); 56 | } 57 | 58 | private: 59 | iterator_access() = default; 60 | }; 61 | 62 | /// A simple version of `boost::iterator_facade`. 63 | template < 64 | typename Derived, 65 | typename Category, 66 | typename Value, 67 | typename Reference = Value&, 68 | typename Difference = std::ptrdiff_t 69 | > 70 | class iterator_facade : totally_ordered< 71 | iterator_facade< 72 | Derived, Category, Value, Reference, Difference 73 | > 74 | > 75 | { 76 | private: 77 | template 78 | struct operator_arrow_dispatch 79 | { 80 | struct proxy 81 | { 82 | explicit proxy(R const& x) 83 | : ref(x) 84 | { 85 | } 86 | 87 | R* operator->() 88 | { 89 | return std::addressof(ref); 90 | } 91 | 92 | R ref; 93 | }; 94 | 95 | using result_type = proxy; 96 | 97 | static result_type apply(R const& x) 98 | { 99 | return result_type{x}; 100 | } 101 | }; 102 | 103 | template 104 | struct operator_arrow_dispatch 105 | { 106 | using result_type = P; 107 | 108 | static result_type apply(T& x) 109 | { 110 | return std::addressof(x); 111 | } 112 | }; 113 | 114 | Derived& derived() 115 | { 116 | return *static_cast(this); 117 | } 118 | 119 | Derived const& derived() const 120 | { 121 | return *static_cast(this); 122 | } 123 | 124 | 125 | public: 126 | using iterator_category = Category; 127 | using reference = Reference; 128 | using difference_type = Difference; 129 | using arrow_dispatcher = operator_arrow_dispatch< 130 | reference, 131 | typename std::add_pointer< 132 | typename std::conditional< 133 | std::is_const::value, 134 | typename std::remove_cv::type const, 135 | typename std::remove_cv::type 136 | >::type 137 | >::type 138 | >; 139 | 140 | using pointer = typename arrow_dispatcher::result_type; 141 | 142 | // TODO: operator[] 143 | 144 | reference operator*() const 145 | { 146 | return iterator_access::dereference(derived()); 147 | } 148 | 149 | pointer operator->() const 150 | { 151 | return arrow_dispatcher::apply(*derived()); 152 | } 153 | 154 | Derived& operator++() 155 | { 156 | iterator_access::increment(derived()); 157 | return derived(); 158 | } 159 | 160 | Derived operator++(int) 161 | { 162 | Derived tmp{derived()}; 163 | ++*this; 164 | return tmp; 165 | } 166 | 167 | Derived& operator--() 168 | { 169 | iterator_access::decrement(derived()); 170 | return derived(); 171 | } 172 | 173 | Derived operator--(int) 174 | { 175 | Derived tmp{derived()}; 176 | --*this; 177 | return tmp; 178 | } 179 | 180 | Derived& operator+=(difference_type n) 181 | { 182 | iterator_access::advance(derived(), n); 183 | return derived(); 184 | } 185 | 186 | Derived& operator-=(difference_type n) 187 | { 188 | iterator_access::advance(derived(), -n); 189 | return derived(); 190 | } 191 | 192 | 193 | Derived operator-(difference_type x) const 194 | { 195 | Derived result(derived()); 196 | return result -= x; 197 | } 198 | 199 | friend bool operator==(iterator_facade const& x, iterator_facade const& y) 200 | { 201 | return iterator_access::equals(static_cast(x), 202 | static_cast(y)); 203 | } 204 | 205 | friend bool operator<(iterator_facade const& x, iterator_facade const& y) 206 | { 207 | return 0 > iterator_access::distance_from(static_cast(x), 208 | static_cast(y)); 209 | } 210 | 211 | friend Derived operator+(iterator_facade const& x, difference_type n) 212 | { 213 | Derived tmp{static_cast(x)}; 214 | return tmp += n; 215 | } 216 | 217 | friend Derived operator+(difference_type n, iterator_facade const& x) 218 | { 219 | Derived tmp{static_cast(x)}; 220 | return tmp += n; 221 | } 222 | 223 | friend auto operator-(iterator_facade const& x, iterator_facade const& y) 224 | -> decltype(iterator_access::distance_from(x, y)) 225 | { 226 | return iterator_access::distance_from(static_cast(x), 227 | static_cast(y)); 228 | } 229 | 230 | protected: 231 | using iterator_facade_type = 232 | iterator_facade; 233 | }; 234 | 235 | /// A simple version of `boost::iterator_adaptor`. 236 | template < 237 | typename Derived, 238 | typename Base, 239 | typename Category, 240 | typename Value, 241 | typename Reference = Value&, 242 | typename Difference = std::ptrdiff_t 243 | > 244 | class iterator_adaptor 245 | : public iterator_facade< 246 | Derived, Category, Value, Reference, Difference 247 | > 248 | { 249 | public: 250 | using base_iterator = Base; 251 | using super = 252 | iterator_adaptor< 253 | Derived, Base, Category, Value, Reference, Difference 254 | >; 255 | 256 | iterator_adaptor() = default; 257 | 258 | explicit iterator_adaptor(Base const& b) 259 | : iterator_{b} 260 | { 261 | } 262 | 263 | Base const& base() const 264 | { 265 | return iterator_; 266 | } 267 | 268 | protected: 269 | Base& base() 270 | { 271 | return iterator_; 272 | } 273 | 274 | private: 275 | friend iterator_access; 276 | 277 | Reference dereference() const 278 | { 279 | return *iterator_; 280 | } 281 | 282 | bool equals(iterator_adaptor const& other) const 283 | { 284 | return iterator_ == other.base(); 285 | } 286 | 287 | void advance(Difference n) 288 | { 289 | iterator_ += n; 290 | } 291 | 292 | void increment() 293 | { 294 | ++iterator_; 295 | } 296 | 297 | void decrement() 298 | { 299 | --iterator_; 300 | } 301 | 302 | Difference distance_to(iterator_adaptor const& other) const 303 | { 304 | return other.base() - iterator_; 305 | } 306 | 307 | private: 308 | Base iterator_; 309 | }; 310 | 311 | } // namspace util 312 | } // namespace vast 313 | 314 | #endif 315 | -------------------------------------------------------------------------------- /efiperun/efiperun.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * uefireverse - Tools to help with Reverse Engineering UEFI-based firmware 3 | * Copyright (C) 2015 Jethro G. Beekman 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software Foundation, 17 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | #define DEBUG // Do not set up SIGALRM 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #include 31 | #include 32 | using std::vector; 33 | using std::pair; 34 | 35 | #include "main.h" 36 | #include "stubs.h" 37 | #include "efihooks.hpp" 38 | #include "debugmodule.h" 39 | extern "C" { 40 | #include "peloader.h" 41 | } 42 | 43 | using std::string; 44 | 45 | range_map g_memory_map; 46 | range_map> g_pe_map; 47 | vector g_init_fns; 48 | vector g_run_fns; 49 | 50 | void register_memory(const memory_block& block) 51 | { 52 | g_memory_map.erase((intptr_t)block.start,block.size+(intptr_t)block.start); 53 | g_memory_map.insert((intptr_t)block.start,block.size+(intptr_t)block.start,block.name); 54 | } 55 | 56 | memory_block lookup_memory(void* address) 57 | { 58 | auto map=g_memory_map.find((intptr_t)address); 59 | if (std::get<2>(map)) return {(void*)std::get<0>(map),(size_t)(-std::get<0>(map)+(intptr_t)address),*std::get<2>(map)}; 60 | return {NULL,0,string()}; 61 | } 62 | 63 | const char* find_pe_caller_id() 64 | { 65 | void* ipbuf[80]; 66 | int len=backtrace(ipbuf,80); 67 | for (int i=0;isecond.c_str(); 71 | } 72 | return NULL; 73 | } 74 | 75 | extern "C" 76 | { 77 | void* wrapped_mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset) 78 | { 79 | void*p=mmap(addr,length,prot,flags,fd,offset); 80 | if (p && p!=MAP_FAILED) 81 | { 82 | fprintf(stdout,"PE mmap: start=%016lx, end=%016lx\n",(intptr_t)p,length-1+(intptr_t)p); 83 | register_memory({p,length,"JEMALLOC_HEAP"}); 84 | } 85 | return p; 86 | } 87 | } 88 | 89 | // seperate function so we can set a breakpoint easily 90 | static void start_pe(EFI_IMAGE_ENTRY_POINT entry,EFI_HANDLE handle,EFI_SYSTEM_TABLE* table) 91 | { 92 | entry(handle,table); 93 | } 94 | 95 | void run_pe(const char* id,const char* filename) 96 | { 97 | int fd=open(filename,O_RDONLY); 98 | if (fd!=-1) 99 | { 100 | auto pe_info=load_pe(fd); 101 | g_pe_map.erase((intptr_t)pe_info.mmap_base,pe_info.mmap_length+(intptr_t)pe_info.mmap_base); 102 | g_pe_map.insert((intptr_t)pe_info.mmap_base,pe_info.mmap_length+(intptr_t)pe_info.mmap_base,{pe_info,string(id)}); 103 | register_memory({pe_info.mmap_base,(size_t)pe_info.image_base-(size_t)pe_info.mmap_base,string(id)+"::IMAGE_MMAP"}); 104 | register_memory({pe_info.image_base,pe_info.mmap_length-((intptr_t)pe_info.image_base-(intptr_t)pe_info.mmap_base),string(id)+"::IMAGE_BASE"}); 105 | auto entry=(EFI_IMAGE_ENTRY_POINT)pe_info.entry_point; 106 | close(fd); 107 | 108 | fprintf(stdout,"Loaded %s at %p\n",id,pe_info.image_base); 109 | 110 | if (entry) 111 | start_pe(entry,(EFI_HANDLE)id,&g_efi_system_table); 112 | fprintf(stdout,"Exited gracefully\n"); 113 | } 114 | } 115 | 116 | static void stack_init() 117 | { 118 | static intptr_t stackhi=0; 119 | static intptr_t stacklo=0; 120 | if (!stackhi) 121 | { 122 | FILE* fp=fopen("/proc/self/stat","r"); 123 | if (fp) 124 | { 125 | if (1==fscanf(fp,"%*d %*s %*c %*d %*d %*d %*d %*d %*u %*u %*u %*u %*u %*u %*u %*d %*d %*d %*d %*d %*d %*u %*u %*d %*u %*u %*u %lu",&stackhi)) 126 | { 127 | stackhi|=0xfff; 128 | stackhi+=1; 129 | } 130 | else 131 | { // this might be guaranteed unassigned? 132 | stackhi=0; 133 | } 134 | fclose(fp); 135 | } 136 | 137 | } 138 | if (!stacklo && stackhi) 139 | { 140 | struct rlimit rl; 141 | if (0==getrlimit(RLIMIT_STACK,&rl)) 142 | { 143 | stacklo=stackhi-rl.rlim_cur; 144 | } 145 | } 146 | if (stackhi && stacklo) 147 | { 148 | register_memory({(void*)stacklo,(size_t)(stackhi-stacklo),"STACK"}); 149 | } 150 | } 151 | 152 | void register_debug_module(debug_module_init_fn_t init, debug_module_run_fn_t run) 153 | { 154 | if (init) g_init_fns.push_back(init); 155 | if (run) g_run_fns.push_back(run); 156 | } 157 | 158 | int main(int argc, char** argv) 159 | { 160 | if (argc<2 || argc>3 || (argc==3 && strcmp(argv[1],"--unsafe")) || (argc==2 && !strcmp(argv[1],"--unsafe"))) 161 | { 162 | fprintf(stderr,"Usage: %s filename\n",argv[0]); 163 | return 1; 164 | } 165 | if (argc==2 || strcmp(argv[1],"--unsafe")) 166 | { 167 | fputs("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n",stderr); 168 | fputs("!!! !!!\n",stderr); 169 | fputs("!!! THIS SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS !!!\n",stderr); 170 | fputs("!!! OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF !!!\n",stderr); 171 | fputs("!!! MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. !!!\n",stderr); 172 | fputs("!!! IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY !!!\n",stderr); 173 | fputs("!!! CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, !!!\n",stderr); 174 | fputs("!!! TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE !!!\n",stderr); 175 | fputs("!!! SOFTWARE OR THE USE OR OTHER DEALINGS IN THIS SOFTWARE. !!!\n",stderr); 176 | fputs("!!! !!!\n",stderr); 177 | fputs("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n",stderr); 178 | fputs("\n",stderr); 179 | fputs("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n",stderr); 180 | fputs("!!! WARNING !!!! WARNING !!!! WARNING !!!! WARNING !!!! WARNING !!!! WARNING !!!\n",stderr); 181 | fputs("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n",stderr); 182 | fputs("!!! !!!\n",stderr); 183 | fputs("!!! This program LOADS AND RUNS Portable Executable (PE) image files. It !!!\n",stderr); 184 | fputs("!!! does this WITHOUT ANY PROTECTION MECHANISMS. Certain memory sections !!!\n",stderr); 185 | fputs("!!! will be mapped WRITABLE AND EXECUTABLE simultaneously. DO NOT RUN THIS !!!\n",stderr); 186 | fputs("!!! on untrusted software. THINK CAREFULLY before running this on trusted !!!\n",stderr); 187 | fputs("!!! software. To continue, put `--unsafe' as the first argument. !!!\n",stderr); 188 | fputs("!!! !!!\n",stderr); 189 | fputs("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n",stderr); 190 | fputs("!!! WARNING !!!! WARNING !!!! WARNING !!!! WARNING !!!! WARNING !!!! WARNING !!!\n",stderr); 191 | fputs("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n",stderr); 192 | return 1; 193 | } 194 | 195 | stack_init(); 196 | efi_hooks_init(); 197 | for (auto fn: g_init_fns) fn(); 198 | 199 | printf("Intialization done. Loading images.\n"); 200 | #ifndef DEBUG 201 | alarm(10); 202 | #endif 203 | // If you want to load multiple PE images at the same time, this is where 204 | // you want to do that with more calls to run_pe(). 205 | run_pe("MAIN_PE_IMAGE",argv[2]); 206 | 207 | printf("Done loading images. Executing user functions.\n"); 208 | for (auto fn: g_run_fns) fn(); 209 | 210 | return 0; 211 | } 212 | 213 | -------------------------------------------------------------------------------- /efiperun/stubs.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * uefireverse - Tools to help with Reverse Engineering UEFI-based firmware 3 | * Copyright (C) 2015 Jethro G. Beekman 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software Foundation, 17 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include 27 | #include 28 | using std::vector; 29 | using std::string; 30 | 31 | #include "jemalloc_custom.h" 32 | 33 | #include "main.h" 34 | #include "stubs.h" 35 | 36 | // NOTE: This is *NOT* for access control. If the PE module wanted to access a 37 | // certain memory address, it could just do so. This is only a debugging aid. 38 | // 39 | // Things a PE module can currently access this way: 40 | // 1. Pages that the PE module was loaded in 41 | // 2. Pages that were allocated by the PE module (e.g. using AllocatePool) 42 | // 3. The stack 43 | // 44 | // Things a PE module can currently *NOT* access this way: 45 | // 1. Tables, interfaces, etc. preloaded by this program 46 | static bool can_access(void* base, size_t len) 47 | { 48 | intptr_t lo=((intptr_t)base); 49 | intptr_t hi=(len+(intptr_t)base); 50 | 51 | for (auto range=g_memory_map.find(lo);std::get<2>(range);range=g_memory_map.find(lo)) 52 | { 53 | if (hi<=std::get<1>(range)) return true; 54 | lo=std::get<1>(range); 55 | } 56 | 57 | return false; 58 | } 59 | 60 | EFI_STATUS EFIAPI HandleProtocol(IN EFI_HANDLE Handle,IN EFI_GUID *Protocol,OUT VOID **Interface) 61 | { 62 | if (Protocol==NULL) return EFI_INVALID_PARAMETER; 63 | 64 | log_protocol("Request",Protocol); 65 | 66 | if (Interface==NULL) return EFI_INVALID_PARAMETER; 67 | 68 | *Interface=find_protocol(Protocol,Handle); 69 | 70 | return EFI_SUCCESS; 71 | } 72 | 73 | EFI_STATUS EFIAPI LocateProtocol(IN EFI_GUID *Protocol,IN VOID *Registration OPTIONAL,OUT VOID **Interface) 74 | { 75 | return HandleProtocol(NULL,Protocol,Interface); 76 | } 77 | 78 | EFI_STATUS EFIAPI InstallProtocolInterface(IN OUT EFI_HANDLE *Handle, IN EFI_GUID *Protocol, IN EFI_INTERFACE_TYPE InterfaceType, IN VOID *Interface) 79 | { 80 | if (InterfaceType!=EFI_NATIVE_INTERFACE) return EFI_INVALID_PARAMETER; 81 | if (!Protocol) return EFI_INVALID_PARAMETER; 82 | if (!Handle) return EFI_INVALID_PARAMETER; 83 | 84 | log_protocol("Install",Protocol); 85 | install_protocol(Protocol,*Handle,Interface); 86 | const memory_block& block=lookup_memory(Interface); 87 | if (block.start) 88 | fprintf(stdout," @offset %s+%08lx\n",block.name.c_str(),block.offset); 89 | else 90 | fprintf(stdout," @address %016lx\n",(intptr_t)Interface); 91 | 92 | return EFI_SUCCESS; 93 | } 94 | 95 | EFI_STATUS EFIAPI InstallMultipleProtocolInterfaces(IN OUT EFI_HANDLE *Handle, ...) 96 | { 97 | if (!Handle) return EFI_INVALID_PARAMETER; 98 | 99 | ms_va_list ap; 100 | __ms_va_start(ap, Handle); 101 | 102 | for(;;) 103 | { 104 | EFI_GUID* Protocol=__ms_va_arg(ap, EFI_GUID*); 105 | if (!Protocol) break; 106 | VOID* Interface=__ms_va_arg(ap, VOID*); 107 | InstallProtocolInterface(Handle,Protocol,EFI_NATIVE_INTERFACE,Interface); 108 | } 109 | __ms_va_end(ap); 110 | 111 | return EFI_SUCCESS; 112 | } 113 | 114 | EFI_STATUS EFIAPI AllocatePool(IN EFI_MEMORY_TYPE PoolType, IN UINTN Size, OUT VOID **Buffer) 115 | { 116 | if (Buffer==NULL) return EFI_INVALID_PARAMETER; 117 | 118 | *Buffer=__jemalloc_malloc(Size); 119 | 120 | if (!*Buffer) return EFI_OUT_OF_RESOURCES; 121 | 122 | register_memory({*Buffer,Size,string(find_pe_caller_id())+"::MALLOC"}); 123 | fprintf(stdout,"AllocatePool\n @address %016lx, size=%lx\n",(intptr_t)*Buffer,Size); 124 | 125 | return EFI_SUCCESS; 126 | } 127 | 128 | EFI_STATUS EFIAPI AllocatePages(IN EFI_ALLOCATE_TYPE Type, IN EFI_MEMORY_TYPE MemoryType, IN UINTN NoPages, OUT EFI_PHYSICAL_ADDRESS *Memory) 129 | { 130 | if (Memory==NULL) return EFI_INVALID_PARAMETER; 131 | 132 | *Memory=(intptr_t)__jemalloc_malloc(NoPages*4096); 133 | 134 | if (!*Memory) return EFI_OUT_OF_RESOURCES; 135 | 136 | register_memory({(void*)*Memory,NoPages*4096,string(find_pe_caller_id())+"::MALLOC"}); 137 | fprintf(stdout,"AllocatePages\n @address %016lx, size=%lx\n",*Memory,NoPages*4096); 138 | 139 | return EFI_SUCCESS; 140 | } 141 | 142 | VOID EFIAPI SetMem(IN VOID *Buffer, IN UINTN Size, IN UINT8 Value) 143 | { 144 | if (Buffer==NULL) return; 145 | 146 | if (can_access(Buffer,Size)) 147 | { 148 | fprintf(stdout,"SetMem\n buf=%016lx, size=%lx, val=%d\n",(intptr_t)Buffer,Size,Value); 149 | memset(Buffer,Value,Size); 150 | } 151 | else 152 | fprintf(stdout,"IGNORE: SetMem\n buf=%016lx, size=%lx, val=%d\n",(intptr_t)Buffer,Size,Value); 153 | } 154 | 155 | VOID EFIAPI CopyMem(IN VOID *Destination, IN VOID *Source, IN UINTN Length) 156 | { 157 | if (Destination==NULL || Source==NULL) return; 158 | 159 | if (can_access(Source,Length) && can_access(Destination,Length)) 160 | { 161 | fprintf(stdout,"CopyMem\n src=%016lx, dst=%016lx, size=%lx\n",(intptr_t)Source,(intptr_t)Destination,Length); 162 | memcpy(Destination,Source,Length); 163 | } 164 | else 165 | fprintf(stdout,"IGNORE: CopyMem\n src=%016lx, dst=%016lx, size=%lx\n",(intptr_t)Source,(intptr_t)Destination,Length); 166 | } 167 | 168 | EFI_STATUS EFIAPI GetNextMonotonicCount(OUT UINT64 *Count) 169 | { 170 | if (Count==NULL) return EFI_INVALID_PARAMETER; 171 | 172 | *Count=__rdtsc(); 173 | 174 | return EFI_SUCCESS; 175 | } 176 | 177 | EFI_STATUS EFIAPI GetNextHighMonotonicCount(OUT UINT32 *HighCount) 178 | { 179 | if (HighCount==NULL) return EFI_INVALID_PARAMETER; 180 | 181 | *HighCount=__rdtsc()>>32; 182 | 183 | return EFI_SUCCESS; 184 | } 185 | 186 | EFI_STATUS EFIAPI OutputString(IN SIMPLE_TEXT_OUTPUT_INTERFACE *This, IN CHAR16 *String) 187 | { 188 | char16_print("EFI Output: ",String); 189 | } 190 | 191 | EFI_STATUS EFIAPI GetVariable(IN CHAR16 *VariableName, IN EFI_GUID *VendorGuid, OUT UINT32 *Attributes OPTIONAL, IN OUT UINTN *DataSize, OUT VOID *Data) 192 | { 193 | if (VariableName==NULL) return EFI_INVALID_PARAMETER; 194 | if (VendorGuid==NULL) return EFI_INVALID_PARAMETER; 195 | if (DataSize==NULL) return EFI_INVALID_PARAMETER; 196 | if (Data==NULL) return EFI_INVALID_PARAMETER; 197 | 198 | UINTN data_size; 199 | UINT32 attributes; 200 | void* data=get_variable(VendorGuid,VariableName,&data_size,&attributes); 201 | 202 | fprintf(stdout,"GetVariable Vendor %s, ",guid_string(VendorGuid)); 203 | char16_print("Variable name:",VariableName); 204 | 205 | if (data!=NULL) 206 | { 207 | if ((attributes&EFI_VARIABLE_RUNTIME_ACCESS)==0) return EFI_NOT_FOUND; 208 | if (*DataSize handles; 238 | auto n=count_handles(Protocol); 239 | if (n==0) return EFI_NOT_FOUND; 240 | handles.reserve(n); 241 | while (handles.size() g_acpi_tables; 275 | 276 | EFI_STATUS EFIAPI GetAcpiTable(IN VOID *This, IN INTN Index, OUT VOID **Table, OUT UINT32 *Version, OUT UINTN *Handle) 277 | { 278 | if (Index>=g_acpi_tables.size()) return EFI_NOT_FOUND; 279 | if (Table==NULL) return EFI_INVALID_PARAMETER; 280 | 281 | *Table=g_acpi_tables[Index]; 282 | 283 | return EFI_SUCCESS; 284 | } 285 | 286 | EFI_STATUS EFIAPI SetAcpiTable(IN VOID *This, IN VOID *Table OPTIONAL, IN BOOLEAN Checksum, IN UINT32 Version, IN OUT UINTN *Handle) 287 | { 288 | if (Table==NULL) return EFI_INVALID_PARAMETER; 289 | 290 | g_acpi_tables.push_back(Table); 291 | 292 | return EFI_SUCCESS; 293 | } 294 | 295 | -------------------------------------------------------------------------------- /efiperun/vast/util/range_map.hpp: -------------------------------------------------------------------------------- 1 | // based off github:mavam/vast 2 | // blob 19dfcb05358fe7dae22079f5ca03121df01021f2 3 | #ifndef VAST_UTIL_INTERVAL_MAP_H 4 | #define VAST_UTIL_INTERVAL_MAP_H 5 | 6 | #include 7 | #include 8 | #include 9 | #include "vast/util/iterator.hpp" 10 | 11 | namespace vast { 12 | namespace util { 13 | 14 | /// An associative data structure that maps half-open, *disjoint* intervals to 15 | /// values. 16 | template 17 | class range_map 18 | { 19 | static_assert(std::is_arithmetic::value, 20 | "Point must be an arithmetic type"); 21 | 22 | using map_type = std::map>; 23 | using map_iterator = typename map_type::iterator; 24 | using map_const_iterator = typename map_type::const_iterator; 25 | 26 | public: 27 | class const_iterator 28 | : public iterator_adaptor< 29 | const_iterator, 30 | map_const_iterator, 31 | std::bidirectional_iterator_tag, 32 | std::tuple, 33 | std::tuple 34 | > 35 | { 36 | using super = iterator_adaptor< 37 | const_iterator, 38 | map_const_iterator, 39 | std::bidirectional_iterator_tag, 40 | std::tuple, 41 | std::tuple 42 | >; 43 | 44 | public: 45 | using super::super; 46 | 47 | private: 48 | friend util::iterator_access; 49 | 50 | std::tuple dereference() const 51 | { 52 | return std::tie(this->base()->first, 53 | this->base()->second.first, 54 | this->base()->second.second); 55 | } 56 | }; 57 | 58 | const_iterator begin() const 59 | { 60 | return const_iterator{map_.begin()}; 61 | } 62 | 63 | const_iterator end() const 64 | { 65 | return const_iterator{map_.end()}; 66 | } 67 | 68 | /// Associates a value with a right-open range. 69 | /// @param l The left endpoint of the interval. 70 | /// @param r The right endpoint of the interval. 71 | /// @param v The value r associated with *[l, r]*. 72 | /// @returns `true` on success. 73 | bool insert(Point l, Point r, Value v) 74 | { 75 | if (r<=l) return false; 76 | auto lb = map_.lower_bound(l); 77 | if (locate(l, lb) == map_.end() && (lb == map_.end() || r <= left(lb))) 78 | return map_.emplace(l, std::make_pair(r, std::move(v))).second; 79 | return false; 80 | } 81 | 82 | /// Inserts a value for a right-open range, updating existing adjacent 83 | /// intervals if it's possible to merge them. Two intervals can only be 84 | /// merged if they have the same values. 85 | /// @note If *[l,r]* reaches into an existing interval, injection fails. 86 | /// @param l The left endpoint of the interval. 87 | /// @param r The right endpoint of the interval. 88 | /// @param v The value r associated with *[l,r]*. 89 | /// @returns `true` on success. 90 | bool inject(Point l, Point r, Value v) 91 | { 92 | if (r<=l) return false; 93 | if (map_.empty()) 94 | return emplace(l, r, std::move(v)); 95 | auto i = map_.lower_bound(l); 96 | // Adjust position (i = this, p = prev, n = next). 97 | if (i == map_.end() || (i != map_.begin() && l != left(i))) 98 | --i; 99 | auto n = i; 100 | ++n; 101 | auto p = i; 102 | if (i != map_.begin()) 103 | --p; 104 | else 105 | p = map_.end(); 106 | // Assess the fit. 107 | auto fits_left = r <= left(i) && (p == map_.end() || l >= right(p)); 108 | auto fits_right = l >= right(i) && (n == map_.end() || r <= left(n)); 109 | if (fits_left) 110 | { 111 | auto right_merge = r == left(i) && v == value(i); 112 | auto left_merge = p != map_.end() && l == right(p) && v == value(p); 113 | if (left_merge && right_merge) 114 | { 115 | right(p) = right(i); 116 | map_.erase(i); 117 | } 118 | else if (left_merge) 119 | { 120 | right(p) = r; 121 | } 122 | else if (right_merge) 123 | { 124 | emplace(l, right(i), std::move(v)); 125 | map_.erase(i); 126 | } 127 | else 128 | { 129 | emplace(l, r, std::move(v)); 130 | } 131 | return true; 132 | } 133 | else if (fits_right) 134 | { 135 | auto right_merge = n != map_.end() && r == left(n) && v == value(n); 136 | auto left_merge = l == right(i) && v == value(i); 137 | if (left_merge && right_merge) 138 | { 139 | right(i) = right(n); 140 | map_.erase(n); 141 | } 142 | else if (left_merge) 143 | { 144 | right(i) = r; 145 | } 146 | else if (right_merge) 147 | { 148 | emplace(l, right(n), std::move(v)); 149 | map_.erase(n); 150 | } 151 | else 152 | { 153 | emplace(l, r, std::move(v)); 154 | } 155 | return true; 156 | } 157 | return false; 158 | } 159 | 160 | /// Removes a value given a point from a right-open range. 161 | /// @param p A point from a range that maps to a value. 162 | /// @returns `true` if the value associated with the interval containing *p* 163 | /// has been successfully removed, and `false` if *p* does not map 164 | /// to an existing value. 165 | bool erase(Point p) 166 | { 167 | auto i = locate(p, map_.lower_bound(p)); 168 | if (i == map_.end()) 169 | return false; 170 | map_.erase(i); 171 | return true; 172 | } 173 | 174 | /// Adjusts or erases ranges so that no values in the map overlap with [l,r) 175 | /// @param l The left endpoint of the interval. 176 | /// @param r The right endpoint of the interval. 177 | void erase(Point l, Point r) 178 | { 179 | if (r<=l) return; 180 | Point next_left=l; 181 | for (;;) 182 | { 183 | auto lb=map_.lower_bound(next_left); 184 | auto it=locate(next_left,lb); 185 | if (it==map_.end()) it=lb; 186 | if (it==map_.end() || left(it)>=r) 187 | break; 188 | next_left=right(it); 189 | 190 | if (l<=left(it) && r>=right(it)) 191 | { // [l,r) overlaps [it) in its entirety 192 | map_.erase(it); 193 | } 194 | else if (left(it)<=l && right(it)>=r) 195 | { // [it) overlaps [l,r) in its entirety 196 | Point orig_r=right(it); 197 | right(it)=l; 198 | inject(r,orig_r,value(it)); 199 | break; 200 | } 201 | else if (l<=left(it) && r>left(it)) 202 | { // [l,r) overlaps [it) partially and starts before 203 | map_.emplace(r, std::make_pair(right(it), std::move(value(it)))); 204 | map_.erase(it); 205 | break; 206 | } 207 | else if (l=right(it)) 208 | { // [l,r) overlaps [it) partially and starts after 209 | right(it)=l; 210 | } 211 | } 212 | } 213 | 214 | /// Retrieves the value for a given point. 215 | /// @param p The point to lookup. 216 | /// @returns A pointer to the value associated with the half-open interval 217 | /// *[a,b)* if *a <= p < b* and `nullptr` otherwise. 218 | Value const* lookup(Point const& p) const 219 | { 220 | auto i = locate(p, map_.lower_bound(p)); 221 | return i != map_.end() ? &i->second.second : nullptr; 222 | } 223 | 224 | /// Retrieves value and interval for a given point. 225 | /// @param p The point to lookup. 226 | /// @returns A tuple with the last component holding a pointer to the value 227 | /// associated with the half-open interval *[a,b)* if *a <= p < b*, 228 | /// and `nullptr` otherwise. If the last component points to a 229 | /// valid value, then the first two represent *[a,b)* and *[0,0)* 230 | /// otherwise. 231 | std::tuple find(Point const& p) const 232 | { 233 | auto i = locate(p, map_.lower_bound(p)); 234 | if (i == map_.end()) 235 | return std::tuple{0, 0, nullptr}; 236 | else 237 | return std::tuple{left(i), right(i), &i->second.second}; 238 | } 239 | 240 | /// Retrieves the size of the range map. 241 | /// @returns The number of entries in the map. 242 | size_t size() const 243 | { 244 | return map_.size(); 245 | } 246 | 247 | /// Checks whether the range map is empty. 248 | /// @returns `true` iff the map is empty. 249 | bool empty() const 250 | { 251 | return map_.empty(); 252 | } 253 | 254 | /// Clears the range map. 255 | void clear() 256 | { 257 | return map_.clear(); 258 | } 259 | 260 | private: 261 | static auto left(map_const_iterator i) -> const decltype(i->first)& 262 | { 263 | return i->first; 264 | } 265 | 266 | static auto right(map_const_iterator i) -> const decltype(i->second.first)& 267 | { 268 | return i->second.first; 269 | } 270 | 271 | static auto right(map_iterator i) -> decltype(i->second.first)& 272 | { 273 | return i->second.first; 274 | } 275 | 276 | static auto value(map_const_iterator i) -> const decltype(i->second.second)& 277 | { 278 | return i->second.second; 279 | } 280 | 281 | // Finds the interval of a point. 282 | map_iterator locate(Point const& p, map_iterator lb) 283 | { 284 | if ((lb != map_.end() && p == left(lb)) || 285 | (lb != map_.begin() && p < right(--lb))) 286 | //if (lb == map_.end()) 287 | // return map_.empty() ? lb : map_.rbegin().base(); 288 | //else if (p == left(lb) || (lb != map_.begin() && p < right(--lb))) 289 | return lb; 290 | return map_.end(); 291 | } 292 | 293 | // Finds the interval of a point. 294 | map_const_iterator locate(Point const& p, map_const_iterator lb) const 295 | { 296 | if ((lb != map_.end() && p == left(lb)) || 297 | (lb != map_.begin() && p < right(--lb))) 298 | //if (lb == map_.end()) 299 | // return map_.empty() ? lb : map_.rbegin().base(); 300 | //else if (p == left(lb) || (lb != map_.begin() && p < right(--lb))) 301 | return lb; 302 | return map_.end(); 303 | } 304 | 305 | bool emplace(Point l, Point r, Value v) 306 | { 307 | auto pair = std::make_pair(std::move(r), std::move(v)); 308 | return map_.emplace(std::move(l), std::move(pair)).second; 309 | } 310 | 311 | map_type map_; 312 | }; 313 | 314 | } // namespace util 315 | } // namespace vast 316 | 317 | #endif 318 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | uefireverse - Tools to help with Reverse Engineering UEFI-based firmware 2 | Copyright (C) 2015 Jethro G. Beekman 3 | 4 | This program is free software; you can redistribute it and/or 5 | modify it under the terms of the GNU General Public License 6 | as published by the Free Software Foundation; either version 2 7 | of the License, or (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | GNU GENERAL PUBLIC LICENSE 15 | Version 2, June 1991 16 | 17 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., [http://fsf.org/] 18 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19 | Everyone is permitted to copy and distribute verbatim copies 20 | of this license document, but changing it is not allowed. 21 | 22 | Preamble 23 | 24 | The licenses for most software are designed to take away your 25 | freedom to share and change it. By contrast, the GNU General Public 26 | License is intended to guarantee your freedom to share and change free 27 | software--to make sure the software is free for all its users. This 28 | General Public License applies to most of the Free Software 29 | Foundation's software and to any other program whose authors commit to 30 | using it. (Some other Free Software Foundation software is covered by 31 | the GNU Lesser General Public License instead.) You can apply it to 32 | your programs, too. 33 | 34 | When we speak of free software, we are referring to freedom, not 35 | price. Our General Public Licenses are designed to make sure that you 36 | have the freedom to distribute copies of free software (and charge for 37 | this service if you wish), that you receive source code or can get it 38 | if you want it, that you can change the software or use pieces of it 39 | in new free programs; and that you know you can do these things. 40 | 41 | To protect your rights, we need to make restrictions that forbid 42 | anyone to deny you these rights or to ask you to surrender the rights. 43 | These restrictions translate to certain responsibilities for you if you 44 | distribute copies of the software, or if you modify it. 45 | 46 | For example, if you distribute copies of such a program, whether 47 | gratis or for a fee, you must give the recipients all the rights that 48 | you have. You must make sure that they, too, receive or can get the 49 | source code. And you must show them these terms so they know their 50 | rights. 51 | 52 | We protect your rights with two steps: (1) copyright the software, and 53 | (2) offer you this license which gives you legal permission to copy, 54 | distribute and/or modify the software. 55 | 56 | Also, for each author's protection and ours, we want to make certain 57 | that everyone understands that there is no warranty for this free 58 | software. If the software is modified by someone else and passed on, we 59 | want its recipients to know that what they have is not the original, so 60 | that any problems introduced by others will not reflect on the original 61 | authors' reputations. 62 | 63 | Finally, any free program is threatened constantly by software 64 | patents. We wish to avoid the danger that redistributors of a free 65 | program will individually obtain patent licenses, in effect making the 66 | program proprietary. To prevent this, we have made it clear that any 67 | patent must be licensed for everyone's free use or not licensed at all. 68 | 69 | The precise terms and conditions for copying, distribution and 70 | modification follow. 71 | 72 | GNU GENERAL PUBLIC LICENSE 73 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 74 | 75 | 0. This License applies to any program or other work which contains 76 | a notice placed by the copyright holder saying it may be distributed 77 | under the terms of this General Public License. The "Program", below, 78 | refers to any such program or work, and a "work based on the Program" 79 | means either the Program or any derivative work under copyright law: 80 | that is to say, a work containing the Program or a portion of it, 81 | either verbatim or with modifications and/or translated into another 82 | language. (Hereinafter, translation is included without limitation in 83 | the term "modification".) Each licensee is addressed as "you". 84 | 85 | Activities other than copying, distribution and modification are not 86 | covered by this License; they are outside its scope. The act of 87 | running the Program is not restricted, and the output from the Program 88 | is covered only if its contents constitute a work based on the 89 | Program (independent of having been made by running the Program). 90 | Whether that is true depends on what the Program does. 91 | 92 | 1. You may copy and distribute verbatim copies of the Program's 93 | source code as you receive it, in any medium, provided that you 94 | conspicuously and appropriately publish on each copy an appropriate 95 | copyright notice and disclaimer of warranty; keep intact all the 96 | notices that refer to this License and to the absence of any warranty; 97 | and give any other recipients of the Program a copy of this License 98 | along with the Program. 99 | 100 | You may charge a fee for the physical act of transferring a copy, and 101 | you may at your option offer warranty protection in exchange for a fee. 102 | 103 | 2. You may modify your copy or copies of the Program or any portion 104 | of it, thus forming a work based on the Program, and copy and 105 | distribute such modifications or work under the terms of Section 1 106 | above, provided that you also meet all of these conditions: 107 | 108 | a) You must cause the modified files to carry prominent notices 109 | stating that you changed the files and the date of any change. 110 | 111 | b) You must cause any work that you distribute or publish, that in 112 | whole or in part contains or is derived from the Program or any 113 | part thereof, to be licensed as a whole at no charge to all third 114 | parties under the terms of this License. 115 | 116 | c) If the modified program normally reads commands interactively 117 | when run, you must cause it, when started running for such 118 | interactive use in the most ordinary way, to print or display an 119 | announcement including an appropriate copyright notice and a 120 | notice that there is no warranty (or else, saying that you provide 121 | a warranty) and that users may redistribute the program under 122 | these conditions, and telling the user how to view a copy of this 123 | License. (Exception: if the Program itself is interactive but 124 | does not normally print such an announcement, your work based on 125 | the Program is not required to print an announcement.) 126 | 127 | These requirements apply to the modified work as a whole. If 128 | identifiable sections of that work are not derived from the Program, 129 | and can be reasonably considered independent and separate works in 130 | themselves, then this License, and its terms, do not apply to those 131 | sections when you distribute them as separate works. But when you 132 | distribute the same sections as part of a whole which is a work based 133 | on the Program, the distribution of the whole must be on the terms of 134 | this License, whose permissions for other licensees extend to the 135 | entire whole, and thus to each and every part regardless of who wrote it. 136 | 137 | Thus, it is not the intent of this section to claim rights or contest 138 | your rights to work written entirely by you; rather, the intent is to 139 | exercise the right to control the distribution of derivative or 140 | collective works based on the Program. 141 | 142 | In addition, mere aggregation of another work not based on the Program 143 | with the Program (or with a work based on the Program) on a volume of 144 | a storage or distribution medium does not bring the other work under 145 | the scope of this License. 146 | 147 | 3. You may copy and distribute the Program (or a work based on it, 148 | under Section 2) in object code or executable form under the terms of 149 | Sections 1 and 2 above provided that you also do one of the following: 150 | 151 | a) Accompany it with the complete corresponding machine-readable 152 | source code, which must be distributed under the terms of Sections 153 | 1 and 2 above on a medium customarily used for software interchange; or, 154 | 155 | b) Accompany it with a written offer, valid for at least three 156 | years, to give any third party, for a charge no more than your 157 | cost of physically performing source distribution, a complete 158 | machine-readable copy of the corresponding source code, to be 159 | distributed under the terms of Sections 1 and 2 above on a medium 160 | customarily used for software interchange; or, 161 | 162 | c) Accompany it with the information you received as to the offer 163 | to distribute corresponding source code. (This alternative is 164 | allowed only for noncommercial distribution and only if you 165 | received the program in object code or executable form with such 166 | an offer, in accord with Subsection b above.) 167 | 168 | The source code for a work means the preferred form of the work for 169 | making modifications to it. For an executable work, complete source 170 | code means all the source code for all modules it contains, plus any 171 | associated interface definition files, plus the scripts used to 172 | control compilation and installation of the executable. However, as a 173 | special exception, the source code distributed need not include 174 | anything that is normally distributed (in either source or binary 175 | form) with the major components (compiler, kernel, and so on) of the 176 | operating system on which the executable runs, unless that component 177 | itself accompanies the executable. 178 | 179 | If distribution of executable or object code is made by offering 180 | access to copy from a designated place, then offering equivalent 181 | access to copy the source code from the same place counts as 182 | distribution of the source code, even though third parties are not 183 | compelled to copy the source along with the object code. 184 | 185 | 4. You may not copy, modify, sublicense, or distribute the Program 186 | except as expressly provided under this License. Any attempt 187 | otherwise to copy, modify, sublicense or distribute the Program is 188 | void, and will automatically terminate your rights under this License. 189 | However, parties who have received copies, or rights, from you under 190 | this License will not have their licenses terminated so long as such 191 | parties remain in full compliance. 192 | 193 | 5. You are not required to accept this License, since you have not 194 | signed it. However, nothing else grants you permission to modify or 195 | distribute the Program or its derivative works. These actions are 196 | prohibited by law if you do not accept this License. Therefore, by 197 | modifying or distributing the Program (or any work based on the 198 | Program), you indicate your acceptance of this License to do so, and 199 | all its terms and conditions for copying, distributing or modifying 200 | the Program or works based on it. 201 | 202 | 6. Each time you redistribute the Program (or any work based on the 203 | Program), the recipient automatically receives a license from the 204 | original licensor to copy, distribute or modify the Program subject to 205 | these terms and conditions. You may not impose any further 206 | restrictions on the recipients' exercise of the rights granted herein. 207 | You are not responsible for enforcing compliance by third parties to 208 | this License. 209 | 210 | 7. If, as a consequence of a court judgment or allegation of patent 211 | infringement or for any other reason (not limited to patent issues), 212 | conditions are imposed on you (whether by court order, agreement or 213 | otherwise) that contradict the conditions of this License, they do not 214 | excuse you from the conditions of this License. If you cannot 215 | distribute so as to satisfy simultaneously your obligations under this 216 | License and any other pertinent obligations, then as a consequence you 217 | may not distribute the Program at all. For example, if a patent 218 | license would not permit royalty-free redistribution of the Program by 219 | all those who receive copies directly or indirectly through you, then 220 | the only way you could satisfy both it and this License would be to 221 | refrain entirely from distribution of the Program. 222 | 223 | If any portion of this section is held invalid or unenforceable under 224 | any particular circumstance, the balance of the section is intended to 225 | apply and the section as a whole is intended to apply in other 226 | circumstances. 227 | 228 | It is not the purpose of this section to induce you to infringe any 229 | patents or other property right claims or to contest validity of any 230 | such claims; this section has the sole purpose of protecting the 231 | integrity of the free software distribution system, which is 232 | implemented by public license practices. Many people have made 233 | generous contributions to the wide range of software distributed 234 | through that system in reliance on consistent application of that 235 | system; it is up to the author/donor to decide if he or she is willing 236 | to distribute software through any other system and a licensee cannot 237 | impose that choice. 238 | 239 | This section is intended to make thoroughly clear what is believed to 240 | be a consequence of the rest of this License. 241 | 242 | 8. If the distribution and/or use of the Program is restricted in 243 | certain countries either by patents or by copyrighted interfaces, the 244 | original copyright holder who places the Program under this License 245 | may add an explicit geographical distribution limitation excluding 246 | those countries, so that distribution is permitted only in or among 247 | countries not thus excluded. In such case, this License incorporates 248 | the limitation as if written in the body of this License. 249 | 250 | 9. The Free Software Foundation may publish revised and/or new versions 251 | of the General Public License from time to time. Such new versions will 252 | be similar in spirit to the present version, but may differ in detail to 253 | address new problems or concerns. 254 | 255 | Each version is given a distinguishing version number. If the Program 256 | specifies a version number of this License which applies to it and "any 257 | later version", you have the option of following the terms and conditions 258 | either of that version or of any later version published by the Free 259 | Software Foundation. If the Program does not specify a version number of 260 | this License, you may choose any version ever published by the Free Software 261 | Foundation. 262 | 263 | 10. If you wish to incorporate parts of the Program into other free 264 | programs whose distribution conditions are different, write to the author 265 | to ask for permission. For software which is copyrighted by the Free 266 | Software Foundation, write to the Free Software Foundation; we sometimes 267 | make exceptions for this. Our decision will be guided by the two goals 268 | of preserving the free status of all derivatives of our free software and 269 | of promoting the sharing and reuse of software generally. 270 | 271 | NO WARRANTY 272 | 273 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 274 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 275 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 276 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 277 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 278 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 279 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 280 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 281 | REPAIR OR CORRECTION. 282 | 283 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 284 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 285 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 286 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 287 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 288 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 289 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 290 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 291 | POSSIBILITY OF SUCH DAMAGES. 292 | -------------------------------------------------------------------------------- /efiperun/efihooks.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * uefireverse - Tools to help with Reverse Engineering UEFI-based firmware 3 | * Copyright (C) 2015 Jethro G. Beekman 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software Foundation, 17 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | #include 21 | #include 22 | 23 | #include 24 | #include 25 | using std::list; 26 | using std::unordered_multimap; 27 | using std::pair; 28 | using std::make_pair; 29 | using std::char_traits; 30 | 31 | // Seriously, there is no default way to do this? 32 | template 33 | struct iter_pair_range : std::pair { 34 | iter_pair_range(std::pair const& x) 35 | : std::pair(x) 36 | {} 37 | Iter begin() const {return this->first;} 38 | Iter end() const {return this->second;} 39 | }; 40 | 41 | template 42 | inline iter_pair_range as_range(std::pair const& x) 43 | { return iter_pair_range(x); } 44 | 45 | #include "main.h" 46 | #include "stubs.h" 47 | #include "efihooks.hpp" 48 | 49 | typedef struct _EFI_DEBUG_MASK_PROTOCOL { 50 | INT64 Revision; 51 | void* GetDebugMask; 52 | void* SetDebugMask; 53 | } EFI_DEBUG_MASK_PROTOCOL; 54 | 55 | typedef struct _EFI_SMM_BASE_PROTOCOL { 56 | void* Register; 57 | void* UnRegister; 58 | void* Communicate; 59 | void* RegisterCallback; 60 | void* InSmm; 61 | void* SmmAllocatePool; 62 | void* SmmFreePool; 63 | void* GetSmstLocation; 64 | } EFI_SMM_BASE_PROTOCOL; 65 | 66 | typedef struct _EFI_SMM_SYSTEM_TABLE { 67 | EFI_TABLE_HEADER Hdr; 68 | CHAR16 *SmmFirmwareVendor; 69 | UINT32 SmmFirmwareRevision; 70 | void* SmmInstallConfigurationTable; 71 | EFI_GUID EfiSmmCpuIoGuid; 72 | void* SmmIo; 73 | void* SmmAllocatePool; 74 | void* SmmFreePool; 75 | void* SmmAllocatePages; 76 | void* SmmFreePages; 77 | void* SmmStartupThisAp; 78 | UINTN CurrentlyExecutingCpu; 79 | UINTN NumberOfCpus; 80 | void *CpuSaveState; 81 | void *CpuOptionalFloatingPointState; 82 | UINTN NumberOfTableEntries; 83 | EFI_CONFIGURATION_TABLE *SmmConfigurationTable; 84 | } EFI_SMM_SYSTEM_TABLE; 85 | 86 | typedef struct _EFI_HII_DATABASE_PROTOCOL { 87 | void* NewPackageList; 88 | void* RemovePackageList; 89 | void* UpdatePackageList; 90 | void* ListPackageLists; 91 | void* ExportPackageLists; 92 | void* RegisterPackageNotify; 93 | void* UnregisterPackageNotify; 94 | void* FindKeyboardLayouts; 95 | void* GetKeyboardLayout; 96 | void* SetKeyboardLayout; 97 | void* GetPackageListHandle; 98 | } EFI_HII_DATABASE_PROTOCOL; 99 | 100 | typedef struct _EFI_ACPI_SUPPORT_PROTOCOL { 101 | void* GetAcpiTable; 102 | void* SetAcpiTable; 103 | void* PublishTables; 104 | } EFI_ACPI_SUPPORT_PROTOCOL; 105 | 106 | typedef struct __attribute__((packed)) { 107 | UINT8 Type; 108 | UINT8 SubType; 109 | UINT8 Length[2]; 110 | } EFI_DEVICE_PATH_PROTOCOL; 111 | 112 | typedef struct { 113 | UINT32 Revision; 114 | EFI_HANDLE ParentHandle; 115 | EFI_SYSTEM_TABLE *SystemTable; 116 | EFI_HANDLE DeviceHandle; 117 | EFI_DEVICE_PATH_PROTOCOL *FilePath; 118 | VOID *Reserved; 119 | UINT32 LoadOptionsSize; 120 | VOID *LoadOptions; 121 | VOID *ImageBase; 122 | UINT64 ImageSize; 123 | EFI_MEMORY_TYPE ImageCodeType; 124 | EFI_MEMORY_TYPE ImageDataType; 125 | VOID* Unload; 126 | } EFI_LOADED_IMAGE_PROTOCOL; 127 | 128 | typedef struct { 129 | void* data; 130 | UINTN data_size; 131 | UINT32 attributes; 132 | } variable_data; 133 | 134 | EFI_SYSTEM_TABLE g_efi_system_table={}; 135 | static SIMPLE_INPUT_INTERFACE g_efi_system_table_ConIn={}; 136 | static SIMPLE_TEXT_OUTPUT_INTERFACE g_efi_system_table_ConOut={}; 137 | static SIMPLE_TEXT_OUTPUT_INTERFACE g_efi_system_table_StdErr={}; 138 | static SIMPLE_TEXT_OUTPUT_MODE g_efi_system_table_ConOut_Mode={}; 139 | static EFI_RUNTIME_SERVICES g_efi_system_table_RuntimeServices={}; 140 | static EFI_BOOT_SERVICES g_efi_system_table_BootServices={}; 141 | static EFI_CONFIGURATION_TABLE g_efi_system_table_ConfigurationTable={}; 142 | static EFI_DEBUG_MASK_PROTOCOL g_efi_debug_mask_protocol={}; 143 | static EFI_SMM_BASE_PROTOCOL g_efi_smm_base_protocol={}; 144 | static EFI_SMM_SYSTEM_TABLE g_efi_smm_system_table={}; 145 | static EFI_GRAPHICS_OUTPUT_PROTOCOL g_efi_graphics_output_protocol={}; 146 | static EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE g_efi_graphics_output_protocol_Mode={}; 147 | static EFI_HII_DATABASE_PROTOCOL g_efi_hii_database_protocol={}; 148 | static EFI_ACPI_SUPPORT_PROTOCOL g_efi_acpi_support_protocol={}; 149 | static EFI_DEVICE_PATH_PROTOCOL g_empty_efi_device_path_protocol={0x7f,0xff,{0,0}}; 150 | static EFI_LOADED_IMAGE_PROTOCOL g_efi_loaded_image_protocol={}; 151 | 152 | static list> g_str_hooks; 153 | static unordered_multimap> g_interfaces; 154 | static unordered_multimap> g_variables; 155 | 156 | #include "efi_guid.c" 157 | 158 | const char* guid_string(EFI_GUID* guid) 159 | { 160 | static char str[64]; 161 | for (guid_name* p=g_guid_names;p->guid;p++) 162 | { 163 | if (*(p->guid)==*guid) 164 | { 165 | snprintf(str,sizeof(str),"GUID:%s",p->name); 166 | return str; 167 | } 168 | } 169 | snprintf(str,sizeof(str),"%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",guid->Data1,guid->Data2,guid->Data3,guid->Data4[0],guid->Data4[1],guid->Data4[2],guid->Data4[3],guid->Data4[4],guid->Data4[5],guid->Data4[6],guid->Data4[7]); 170 | return str; 171 | } 172 | 173 | static EFI_STATUS print_string(const char** str) 174 | { 175 | fprintf(stdout,"IGNORE: Called %s\n",*str); 176 | return EFI_SUCCESS; 177 | } 178 | 179 | static void backtrace_exit() 180 | { 181 | void* ipbuf[80]; 182 | int len=backtrace(ipbuf,80); 183 | if (len>=0) 184 | { 185 | fprintf(stdout,"Aborted. Backtrace:\n"); 186 | char **symbols=backtrace_symbols(ipbuf,len); 187 | for (int i=0;iguid),gi->index); 215 | backtrace_exit(); 216 | } 217 | 218 | static EFI_STATUS print_args(const char** str,intptr_t a0,intptr_t a1,intptr_t a2,intptr_t a3) 219 | { 220 | fprintf(stdout,"Called %s / rcx=%016lx rdx=%016lx r8=%016lx r9=%016lx\n",*str,a0,a1,a2,a3); 221 | return EFI_SUCCESS; 222 | } 223 | 224 | void* new_abort_hook(const char* name) 225 | { 226 | g_str_hooks.emplace_back(name,(HOOKFN_T(,const char*))print_string_exit); 227 | return g_str_hooks.back().get_func(); 228 | } 229 | 230 | void* new_dummy_hook(const char* name) 231 | { 232 | g_str_hooks.emplace_back(name,(HOOKFN_T(,const char*))print_string); 233 | return g_str_hooks.back().get_func(); 234 | } 235 | 236 | void* new_print_hook(const char* name) 237 | { 238 | g_str_hooks.emplace_back(name,(HOOKFN_T(,const char*))print_args); 239 | return g_str_hooks.back().get_func(); 240 | } 241 | 242 | void log_protocol(const char* type,EFI_GUID* guid) 243 | { 244 | fprintf(stdout,"%s Protocol %s\n",type,guid_string(guid)); 245 | } 246 | 247 | void* find_protocol(EFI_GUID* guid,EFI_HANDLE handle) 248 | { 249 | /* 250 | * if handle==NULL 251 | * return intf if ∃ (NULL ,intf) ∈ g_interfaces[guid] 252 | * return first(intf) if ∃ ([any] ,intf) ∈ g_interfaces[guid] 253 | * return new dummy if ∅ == g_interfaces[guid] 254 | * else 255 | * return intf if ∃ (handle,intf) ∈ g_interfaces[guid] 256 | * return intf if ∃ (NULL ,intf) ∈ g_interfaces[guid] 257 | * return first(intf) if ∃ ([any] ,intf) ∈ g_interfaces[guid] 258 | * return new dummy if ∅ == g_interfaces[guid] 259 | */ 260 | void* nullintf=NULL; 261 | void* firstintf=NULL; 262 | for (auto& elem : as_range(g_interfaces.equal_range(*guid))) 263 | { 264 | auto& el_handle=elem.second.first; 265 | auto& el_intf=elem.second.second; 266 | if (el_handle==handle) return el_intf; 267 | if (el_handle==NULL) nullintf=el_intf; 268 | if (firstintf==NULL) firstintf=el_intf; 269 | } 270 | if (nullintf) return nullintf; 271 | if (firstintf) return firstintf; 272 | void *intf=new DummyInterface<80>(guid,(HOOKFN_T(,GuidIndex))print_guidindex_exit); 273 | fprintf(stdout," new dummy @address %016lx\n",(intptr_t)intf); 274 | g_interfaces.emplace(*guid,make_pair((EFI_HANDLE)NULL,intf)); 275 | return intf; 276 | } 277 | 278 | intptr_t count_handles(EFI_GUID* guid) 279 | { 280 | return g_interfaces.count(*guid); 281 | } 282 | 283 | void install_protocol(EFI_GUID* guid,EFI_HANDLE handle,void* interface) 284 | { 285 | g_interfaces.emplace(*guid,make_pair(handle,interface)); 286 | } 287 | 288 | void* get_variable(EFI_GUID* guid,CHAR16* name,UINTN* data_size,UINT32 *attributes=NULL) 289 | { 290 | unsigned int name_len = char_traits::length((char16_t*)name); 291 | for (auto& elem : as_range(g_variables.equal_range(*guid))) 292 | { 293 | auto& el_name=elem.second.first; 294 | auto& el_var_data=elem.second.second; 295 | unsigned int el_name_len = char_traits::length((char16_t*)el_name); 296 | if (el_name_len==name_len && memcmp(el_name,name,name_len*sizeof(char16_t))==0) 297 | { 298 | if (data_size) *data_size=el_var_data->data_size; 299 | if (attributes) *attributes=el_var_data->attributes; 300 | return el_var_data->data; 301 | } 302 | } 303 | return NULL; 304 | } 305 | 306 | void set_variable(EFI_GUID* guid,const CHAR16* name,void* data,UINTN data_size,UINT32 attributes=EFI_VARIABLE_RUNTIME_ACCESS) 307 | { 308 | unsigned int var_name_len_bytes = char_traits::length((char16_t*)name)*sizeof(char16_t); 309 | CHAR16* var_name = (CHAR16*)malloc(var_name_len_bytes); 310 | memcpy(var_name,name,var_name_len_bytes); 311 | variable_data* var_data = new variable_data; 312 | var_data->data=malloc(data_size); 313 | memcpy(var_data->data,data,data_size); 314 | var_data->data_size = data_size; 315 | var_data->attributes=attributes; 316 | g_variables.emplace(*guid,make_pair(var_name,var_data)); 317 | } 318 | 319 | void char16_print(const char* prefix, CHAR16* str) 320 | { 321 | fputs(prefix,stdout); 322 | mbstate_t state={}; 323 | char mb[16]; 324 | if (MB_CUR_MAX>16) 325 | { 326 | fprintf(stderr,"MB_CUR_MAX too large: %lu!\nAborted\n",MB_CUR_MAX); 327 | _exit(0); 328 | } 329 | while (*str) 330 | { 331 | memset(mb,0,sizeof(mb)); 332 | int ret=wcrtomb(mb, *(str++), &state); 333 | for (int i=0;i 8 | Portions copyright (c) 2011 - 2013, ARM Ltd. All rights reserved.
9 | 10 | This program and the accompanying materials are licensed and made available 11 | under the terms and conditions of the BSD License which accompanies this 12 | distribution. The full text of the license may be found at 13 | http://opensource.org/licenses/bsd-license.php 14 | 15 | THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 16 | WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 17 | 18 | **/ 19 | 20 | #ifndef __PE_IMAGE_H__ 21 | #define __PE_IMAGE_H__ 22 | 23 | // 24 | // PE32+ Subsystem type for EFI images 25 | // 26 | #define EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION 10 27 | #define EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER 11 28 | #define EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER 12 29 | #define EFI_IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER 13 30 | 31 | // 32 | // BugBug: Need to get a real answer for this problem. This is not in the 33 | // PE specification. 34 | // 35 | // A SAL runtime driver does not get fixed up when a transition to 36 | // virtual mode is made. In all other cases it should be treated 37 | // like a EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER image 38 | // 39 | #define EFI_IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER 13 40 | 41 | // 42 | // PE32+ Machine type for EFI images 43 | // 44 | #define IMAGE_FILE_MACHINE_I386 0x014c 45 | #define IMAGE_FILE_MACHINE_IA64 0x0200 46 | #define IMAGE_FILE_MACHINE_EBC 0x0EBC 47 | #define IMAGE_FILE_MACHINE_X64 0x8664 48 | #define IMAGE_FILE_MACHINE_ARM 0x01c0 // Thumb only 49 | #define IMAGE_FILE_MACHINE_ARMT 0x01c2 // 32bit Mixed ARM and Thumb/Thumb 2 Little Endian 50 | #define IMAGE_FILE_MACHINE_ARM64 0xAA64 // 64bit ARM Architecture, Little Endian 51 | 52 | // 53 | // Support old names for backward compatible 54 | // 55 | #define EFI_IMAGE_MACHINE_IA32 IMAGE_FILE_MACHINE_I386 56 | #define EFI_IMAGE_MACHINE_IA64 IMAGE_FILE_MACHINE_IA64 57 | #define EFI_IMAGE_MACHINE_IPF IMAGE_FILE_MACHINE_IA64 58 | #define EFI_IMAGE_MACHINE_EBC IMAGE_FILE_MACHINE_EBC 59 | #define EFI_IMAGE_MACHINE_X64 IMAGE_FILE_MACHINE_X64 60 | #define EFI_IMAGE_MACHINE_ARMT IMAGE_FILE_MACHINE_ARMT 61 | #define EFI_IMAGE_MACHINE_AARCH64 IMAGE_FILE_MACHINE_ARM64 62 | 63 | #define EFI_IMAGE_DOS_SIGNATURE 0x5A4D // MZ 64 | #define EFI_IMAGE_OS2_SIGNATURE 0x454E // NE 65 | #define EFI_IMAGE_OS2_SIGNATURE_LE 0x454C // LE 66 | #define EFI_IMAGE_NT_SIGNATURE 0x00004550 // PE00 67 | #define EFI_IMAGE_EDOS_SIGNATURE 0x44454550 // PEED 68 | 69 | /// 70 | /// PE images can start with an optional DOS header, so if an image is run 71 | /// under DOS it can print an error message. 72 | /// 73 | typedef struct { 74 | UINT16 e_magic; // Magic number 75 | UINT16 e_cblp; // Bytes on last page of file 76 | UINT16 e_cp; // Pages in file 77 | UINT16 e_crlc; // Relocations 78 | UINT16 e_cparhdr; // Size of header in paragraphs 79 | UINT16 e_minalloc; // Minimum extra paragraphs needed 80 | UINT16 e_maxalloc; // Maximum extra paragraphs needed 81 | UINT16 e_ss; // Initial (relative) SS value 82 | UINT16 e_sp; // Initial SP value 83 | UINT16 e_csum; // Checksum 84 | UINT16 e_ip; // Initial IP value 85 | UINT16 e_cs; // Initial (relative) CS value 86 | UINT16 e_lfarlc; // File address of relocation table 87 | UINT16 e_ovno; // Overlay number 88 | UINT16 e_res[4]; // Reserved words 89 | UINT16 e_oemid; // OEM identifier (for e_oeminfo) 90 | UINT16 e_oeminfo; // OEM information; e_oemid specific 91 | UINT16 e_res2[10]; // Reserved words 92 | UINT32 e_lfanew; // File address of new exe header 93 | } EFI_IMAGE_DOS_HEADER; 94 | 95 | /// 96 | /// File header format. 97 | /// 98 | typedef struct { 99 | UINT16 Machine; 100 | UINT16 NumberOfSections; 101 | UINT32 TimeDateStamp; 102 | UINT32 PointerToSymbolTable; 103 | UINT32 NumberOfSymbols; 104 | UINT16 SizeOfOptionalHeader; 105 | UINT16 Characteristics; 106 | } EFI_IMAGE_FILE_HEADER; 107 | 108 | #define EFI_IMAGE_SIZEOF_FILE_HEADER 20 109 | 110 | #define EFI_IMAGE_FILE_RELOCS_STRIPPED 0x0001 // Relocation info stripped from file. 111 | #define EFI_IMAGE_FILE_EXECUTABLE_IMAGE 0x0002 // File is executable (i.e. no unresolved externel references). 112 | #define EFI_IMAGE_FILE_LINE_NUMS_STRIPPED 0x0004 // Line nunbers stripped from file. 113 | #define EFI_IMAGE_FILE_LOCAL_SYMS_STRIPPED 0x0008 // Local symbols stripped from file. 114 | #define EFI_IMAGE_FILE_LARGE_ADDRESS_AWARE 0x0020 // Supports addresses > 2-GB 115 | #define EFI_IMAGE_FILE_BYTES_REVERSED_LO 0x0080 // Bytes of machine word are reversed. 116 | #define EFI_IMAGE_FILE_32BIT_MACHINE 0x0100 // 32 bit word machine. 117 | #define EFI_IMAGE_FILE_DEBUG_STRIPPED 0x0200 // Debugging info stripped from file in .DBG file 118 | #define EFI_IMAGE_FILE_SYSTEM 0x1000 // System File. 119 | #define EFI_IMAGE_FILE_DLL 0x2000 // File is a DLL. 120 | #define EFI_IMAGE_FILE_BYTES_REVERSED_HI 0x8000 // Bytes of machine word are reversed. 121 | #define EFI_IMAGE_FILE_MACHINE_UNKNOWN 0 122 | #define EFI_IMAGE_FILE_MACHINE_I386 0x14c // Intel 386. 123 | #define EFI_IMAGE_FILE_MACHINE_R3000 0x162 // MIPS* little-endian, 0540 big-endian 124 | #define EFI_IMAGE_FILE_MACHINE_R4000 0x166 // MIPS* little-endian 125 | #define EFI_IMAGE_FILE_MACHINE_ALPHA 0x184 // Alpha_AXP* 126 | #define EFI_IMAGE_FILE_MACHINE_POWERPC 0x1F0 // IBM* PowerPC Little-Endian 127 | #define EFI_IMAGE_FILE_MACHINE_TAHOE 0x7cc // Intel EM machine 128 | // 129 | // * Other names and brands may be claimed as the property of others. 130 | // 131 | 132 | /// 133 | /// Directory format. 134 | /// 135 | typedef struct { 136 | UINT32 VirtualAddress; 137 | UINT32 Size; 138 | } EFI_IMAGE_DATA_DIRECTORY; 139 | 140 | #define EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES 16 141 | 142 | typedef struct { 143 | UINT16 Magic; 144 | UINT8 MajorLinkerVersion; 145 | UINT8 MinorLinkerVersion; 146 | UINT32 SizeOfCode; 147 | UINT32 SizeOfInitializedData; 148 | UINT32 SizeOfUninitializedData; 149 | UINT32 AddressOfEntryPoint; 150 | UINT32 BaseOfCode; 151 | UINT32 BaseOfData; 152 | UINT32 BaseOfBss; 153 | UINT32 GprMask; 154 | UINT32 CprMask[4]; 155 | UINT32 GpValue; 156 | } EFI_IMAGE_ROM_OPTIONAL_HEADER; 157 | 158 | #define EFI_IMAGE_ROM_OPTIONAL_HDR_MAGIC 0x107 159 | #define EFI_IMAGE_SIZEOF_ROM_OPTIONAL_HEADER sizeof (EFI_IMAGE_ROM_OPTIONAL_HEADER) 160 | 161 | typedef struct { 162 | EFI_IMAGE_FILE_HEADER FileHeader; 163 | EFI_IMAGE_ROM_OPTIONAL_HEADER OptionalHeader; 164 | } EFI_IMAGE_ROM_HEADERS; 165 | 166 | /// 167 | /// @attention 168 | /// EFI_IMAGE_OPTIONAL_HEADER32 and EFI_IMAGE_OPTIONAL_HEADER64 169 | /// are for use ONLY by tools. All proper EFI code MUST use 170 | /// EFI_IMAGE_OPTIONAL_HEADER ONLY!!! 171 | /// 172 | #define EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC 0x10b 173 | 174 | typedef struct { 175 | // 176 | // Standard fields. 177 | // 178 | UINT16 Magic; 179 | UINT8 MajorLinkerVersion; 180 | UINT8 MinorLinkerVersion; 181 | UINT32 SizeOfCode; 182 | UINT32 SizeOfInitializedData; 183 | UINT32 SizeOfUninitializedData; 184 | UINT32 AddressOfEntryPoint; 185 | UINT32 BaseOfCode; 186 | UINT32 BaseOfData; 187 | // 188 | // NT additional fields. 189 | // 190 | UINT32 ImageBase; 191 | UINT32 SectionAlignment; 192 | UINT32 FileAlignment; 193 | UINT16 MajorOperatingSystemVersion; 194 | UINT16 MinorOperatingSystemVersion; 195 | UINT16 MajorImageVersion; 196 | UINT16 MinorImageVersion; 197 | UINT16 MajorSubsystemVersion; 198 | UINT16 MinorSubsystemVersion; 199 | UINT32 Win32VersionValue; 200 | UINT32 SizeOfImage; 201 | UINT32 SizeOfHeaders; 202 | UINT32 CheckSum; 203 | UINT16 Subsystem; 204 | UINT16 DllCharacteristics; 205 | UINT32 SizeOfStackReserve; 206 | UINT32 SizeOfStackCommit; 207 | UINT32 SizeOfHeapReserve; 208 | UINT32 SizeOfHeapCommit; 209 | UINT32 LoaderFlags; 210 | UINT32 NumberOfRvaAndSizes; 211 | EFI_IMAGE_DATA_DIRECTORY DataDirectory[EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES]; 212 | } EFI_IMAGE_OPTIONAL_HEADER32; 213 | 214 | /// 215 | /// @attention 216 | /// EFI_IMAGE_OPTIONAL_HEADER32 and EFI_IMAGE_OPTIONAL_HEADER64 217 | /// are for use ONLY by tools. All proper EFI code MUST use 218 | /// EFI_IMAGE_OPTIONAL_HEADER ONLY!!! 219 | /// 220 | #define EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC 0x20b 221 | 222 | typedef struct { 223 | // 224 | // Standard fields. 225 | // 226 | UINT16 Magic; 227 | UINT8 MajorLinkerVersion; 228 | UINT8 MinorLinkerVersion; 229 | UINT32 SizeOfCode; 230 | UINT32 SizeOfInitializedData; 231 | UINT32 SizeOfUninitializedData; 232 | UINT32 AddressOfEntryPoint; 233 | UINT32 BaseOfCode; 234 | // 235 | // NT additional fields. 236 | // 237 | UINT64 ImageBase; 238 | UINT32 SectionAlignment; 239 | UINT32 FileAlignment; 240 | UINT16 MajorOperatingSystemVersion; 241 | UINT16 MinorOperatingSystemVersion; 242 | UINT16 MajorImageVersion; 243 | UINT16 MinorImageVersion; 244 | UINT16 MajorSubsystemVersion; 245 | UINT16 MinorSubsystemVersion; 246 | UINT32 Win32VersionValue; 247 | UINT32 SizeOfImage; 248 | UINT32 SizeOfHeaders; 249 | UINT32 CheckSum; 250 | UINT16 Subsystem; 251 | UINT16 DllCharacteristics; 252 | UINT64 SizeOfStackReserve; 253 | UINT64 SizeOfStackCommit; 254 | UINT64 SizeOfHeapReserve; 255 | UINT64 SizeOfHeapCommit; 256 | UINT32 LoaderFlags; 257 | UINT32 NumberOfRvaAndSizes; 258 | EFI_IMAGE_DATA_DIRECTORY DataDirectory[EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES]; 259 | } EFI_IMAGE_OPTIONAL_HEADER64; 260 | 261 | /// 262 | /// @attention 263 | /// EFI_IMAGE_NT_HEADERS32 and EFI_IMAGE_HEADERS64 are for use ONLY 264 | /// by tools. All proper EFI code MUST use EFI_IMAGE_NT_HEADERS ONLY!!! 265 | /// 266 | typedef struct { 267 | UINT32 Signature; 268 | EFI_IMAGE_FILE_HEADER FileHeader; 269 | EFI_IMAGE_OPTIONAL_HEADER32 OptionalHeader; 270 | } EFI_IMAGE_NT_HEADERS32; 271 | 272 | #define EFI_IMAGE_SIZEOF_NT_OPTIONAL32_HEADER sizeof (EFI_IMAGE_NT_HEADERS32) 273 | 274 | typedef struct { 275 | UINT32 Signature; 276 | EFI_IMAGE_FILE_HEADER FileHeader; 277 | EFI_IMAGE_OPTIONAL_HEADER64 OptionalHeader; 278 | } EFI_IMAGE_NT_HEADERS64; 279 | 280 | #define EFI_IMAGE_SIZEOF_NT_OPTIONAL64_HEADER sizeof (EFI_IMAGE_NT_HEADERS64) 281 | 282 | // 283 | // Subsystem Values 284 | // 285 | #define EFI_IMAGE_SUBSYSTEM_UNKNOWN 0 286 | #define EFI_IMAGE_SUBSYSTEM_NATIVE 1 287 | #define EFI_IMAGE_SUBSYSTEM_WINDOWS_GUI 2 288 | #define EFI_IMAGE_SUBSYSTEM_WINDOWS_CUI 3. 289 | #define EFI_IMAGE_SUBSYSTEM_OS2_CUI 5 290 | #define EFI_IMAGE_SUBSYSTEM_POSIX_CUI 7 291 | 292 | // 293 | // Directory Entries 294 | // 295 | #define EFI_IMAGE_DIRECTORY_ENTRY_EXPORT 0 296 | #define EFI_IMAGE_DIRECTORY_ENTRY_IMPORT 1 297 | #define EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE 2 298 | #define EFI_IMAGE_DIRECTORY_ENTRY_EXCEPTION 3 299 | #define EFI_IMAGE_DIRECTORY_ENTRY_SECURITY 4 300 | #define EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC 5 301 | #define EFI_IMAGE_DIRECTORY_ENTRY_DEBUG 6 302 | #define EFI_IMAGE_DIRECTORY_ENTRY_COPYRIGHT 7 303 | #define EFI_IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8 304 | #define EFI_IMAGE_DIRECTORY_ENTRY_TLS 9 305 | #define EFI_IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10 306 | 307 | // 308 | // Section header format. 309 | // 310 | #define EFI_IMAGE_SIZEOF_SHORT_NAME 8 311 | 312 | typedef struct { 313 | UINT8 Name[EFI_IMAGE_SIZEOF_SHORT_NAME]; 314 | union { 315 | UINT32 PhysicalAddress; 316 | UINT32 VirtualSize; 317 | } Misc; 318 | UINT32 VirtualAddress; 319 | UINT32 SizeOfRawData; 320 | UINT32 PointerToRawData; 321 | UINT32 PointerToRelocations; 322 | UINT32 PointerToLinenumbers; 323 | UINT16 NumberOfRelocations; 324 | UINT16 NumberOfLinenumbers; 325 | UINT32 Characteristics; 326 | } EFI_IMAGE_SECTION_HEADER; 327 | 328 | #define EFI_IMAGE_SIZEOF_SECTION_HEADER 40 329 | 330 | #define EFI_IMAGE_SCN_TYPE_NO_PAD 0x00000008 // Reserved. 331 | #define EFI_IMAGE_SCN_CNT_CODE 0x00000020 332 | #define EFI_IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040 333 | #define EFI_IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080 334 | 335 | #define EFI_IMAGE_SCN_LNK_OTHER 0x00000100 // Reserved. 336 | #define EFI_IMAGE_SCN_LNK_INFO 0x00000200 // Section contains comments or some other type of information. 337 | #define EFI_IMAGE_SCN_LNK_REMOVE 0x00000800 // Section contents will not become part of image. 338 | #define EFI_IMAGE_SCN_LNK_COMDAT 0x00001000 339 | 340 | #define EFI_IMAGE_SCN_ALIGN_1BYTES 0x00100000 341 | #define EFI_IMAGE_SCN_ALIGN_2BYTES 0x00200000 342 | #define EFI_IMAGE_SCN_ALIGN_4BYTES 0x00300000 343 | #define EFI_IMAGE_SCN_ALIGN_8BYTES 0x00400000 344 | #define EFI_IMAGE_SCN_ALIGN_16BYTES 0x00500000 345 | #define EFI_IMAGE_SCN_ALIGN_32BYTES 0x00600000 346 | #define EFI_IMAGE_SCN_ALIGN_64BYTES 0x00700000 347 | 348 | #define EFI_IMAGE_SCN_MEM_DISCARDABLE 0x02000000 349 | #define EFI_IMAGE_SCN_MEM_NOT_CACHED 0x04000000 350 | #define EFI_IMAGE_SCN_MEM_NOT_PAGED 0x08000000 351 | #define EFI_IMAGE_SCN_MEM_SHARED 0x10000000 352 | #define EFI_IMAGE_SCN_MEM_EXECUTE 0x20000000 353 | #define EFI_IMAGE_SCN_MEM_READ 0x40000000 354 | #define EFI_IMAGE_SCN_MEM_WRITE 0x80000000 355 | 356 | /// 357 | /// Symbol format. 358 | /// 359 | #define EFI_IMAGE_SIZEOF_SYMBOL 18 360 | 361 | // 362 | // Section values. 363 | // 364 | // Symbols have a section number of the section in which they are 365 | // defined. Otherwise, section numbers have the following meanings: 366 | // 367 | #define EFI_IMAGE_SYM_UNDEFINED (UINT16) 0 // Symbol is undefined or is common. 368 | #define EFI_IMAGE_SYM_ABSOLUTE (UINT16) -1 // Symbol is an absolute value. 369 | #define EFI_IMAGE_SYM_DEBUG (UINT16) -2 // Symbol is a special debug item. 370 | // 371 | // Type (fundamental) values. 372 | // 373 | #define EFI_IMAGE_SYM_TYPE_NULL 0 // no type. 374 | #define EFI_IMAGE_SYM_TYPE_VOID 1 // 375 | #define EFI_IMAGE_SYM_TYPE_CHAR 2 // type character. 376 | #define EFI_IMAGE_SYM_TYPE_SHORT 3 // type short integer. 377 | #define EFI_IMAGE_SYM_TYPE_INT 4 378 | #define EFI_IMAGE_SYM_TYPE_LONG 5 379 | #define EFI_IMAGE_SYM_TYPE_FLOAT 6 380 | #define EFI_IMAGE_SYM_TYPE_DOUBLE 7 381 | #define EFI_IMAGE_SYM_TYPE_STRUCT 8 382 | #define EFI_IMAGE_SYM_TYPE_UNION 9 383 | #define EFI_IMAGE_SYM_TYPE_ENUM 10 // enumeration. 384 | #define EFI_IMAGE_SYM_TYPE_MOE 11 // member of enumeration. 385 | #define EFI_IMAGE_SYM_TYPE_BYTE 12 386 | #define EFI_IMAGE_SYM_TYPE_WORD 13 387 | #define EFI_IMAGE_SYM_TYPE_UINT 14 388 | #define EFI_IMAGE_SYM_TYPE_DWORD 15 389 | 390 | // 391 | // Type (derived) values. 392 | // 393 | #define EFI_IMAGE_SYM_DTYPE_NULL 0 // no derived type. 394 | #define EFI_IMAGE_SYM_DTYPE_POINTER 1 395 | #define EFI_IMAGE_SYM_DTYPE_FUNCTION 2 396 | #define EFI_IMAGE_SYM_DTYPE_ARRAY 3 397 | 398 | // 399 | // Storage classes. 400 | // 401 | #define EFI_IMAGE_SYM_CLASS_END_OF_FUNCTION (UINT8) -1 402 | #define EFI_IMAGE_SYM_CLASS_NULL 0 403 | #define EFI_IMAGE_SYM_CLASS_AUTOMATIC 1 404 | #define EFI_IMAGE_SYM_CLASS_EXTERNAL 2 405 | #define EFI_IMAGE_SYM_CLASS_STATIC 3 406 | #define EFI_IMAGE_SYM_CLASS_REGISTER 4 407 | #define EFI_IMAGE_SYM_CLASS_EXTERNAL_DEF 5 408 | #define EFI_IMAGE_SYM_CLASS_LABEL 6 409 | #define EFI_IMAGE_SYM_CLASS_UNDEFINED_LABEL 7 410 | #define EFI_IMAGE_SYM_CLASS_MEMBER_OF_STRUCT 8 411 | #define EFI_IMAGE_SYM_CLASS_ARGUMENT 9 412 | #define EFI_IMAGE_SYM_CLASS_STRUCT_TAG 10 413 | #define EFI_IMAGE_SYM_CLASS_MEMBER_OF_UNION 11 414 | #define EFI_IMAGE_SYM_CLASS_UNION_TAG 12 415 | #define EFI_IMAGE_SYM_CLASS_TYPE_DEFINITION 13 416 | #define EFI_IMAGE_SYM_CLASS_UNDEFINED_STATIC 14 417 | #define EFI_IMAGE_SYM_CLASS_ENUM_TAG 15 418 | #define EFI_IMAGE_SYM_CLASS_MEMBER_OF_ENUM 16 419 | #define EFI_IMAGE_SYM_CLASS_REGISTER_PARAM 17 420 | #define EFI_IMAGE_SYM_CLASS_BIT_FIELD 18 421 | #define EFI_IMAGE_SYM_CLASS_BLOCK 100 422 | #define EFI_IMAGE_SYM_CLASS_FUNCTION 101 423 | #define EFI_IMAGE_SYM_CLASS_END_OF_STRUCT 102 424 | #define EFI_IMAGE_SYM_CLASS_FILE 103 425 | #define EFI_IMAGE_SYM_CLASS_SECTION 104 426 | #define EFI_IMAGE_SYM_CLASS_WEAK_EXTERNAL 105 427 | 428 | // 429 | // type packing constants 430 | // 431 | #define EFI_IMAGE_N_BTMASK 017 432 | #define EFI_IMAGE_N_TMASK 060 433 | #define EFI_IMAGE_N_TMASK1 0300 434 | #define EFI_IMAGE_N_TMASK2 0360 435 | #define EFI_IMAGE_N_BTSHFT 4 436 | #define EFI_IMAGE_N_TSHIFT 2 437 | 438 | // 439 | // Communal selection types. 440 | // 441 | #define EFI_IMAGE_COMDAT_SELECT_NODUPLICATES 1 442 | #define EFI_IMAGE_COMDAT_SELECT_ANY 2 443 | #define EFI_IMAGE_COMDAT_SELECT_SAME_SIZE 3 444 | #define EFI_IMAGE_COMDAT_SELECT_EXACT_MATCH 4 445 | #define EFI_IMAGE_COMDAT_SELECT_ASSOCIATIVE 5 446 | 447 | #define EFI_IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY 1 448 | #define EFI_IMAGE_WEAK_EXTERN_SEARCH_LIBRARY 2 449 | #define EFI_IMAGE_WEAK_EXTERN_SEARCH_ALIAS 3 450 | 451 | /// 452 | /// Relocation format. 453 | /// 454 | typedef struct { 455 | UINT32 VirtualAddress; 456 | UINT32 SymbolTableIndex; 457 | UINT16 Type; 458 | } EFI_IMAGE_RELOCATION; 459 | 460 | #define EFI_IMAGE_SIZEOF_RELOCATION 10 461 | 462 | // 463 | // I386 relocation types. 464 | // 465 | #define EFI_IMAGE_REL_I386_ABSOLUTE 0 // Reference is absolute, no relocation is necessary 466 | #define EFI_IMAGE_REL_I386_DIR16 01 // Direct 16-bit reference to the symbols virtual address 467 | #define EFI_IMAGE_REL_I386_REL16 02 // PC-relative 16-bit reference to the symbols virtual address 468 | #define EFI_IMAGE_REL_I386_DIR32 06 // Direct 32-bit reference to the symbols virtual address 469 | #define EFI_IMAGE_REL_I386_DIR32NB 07 // Direct 32-bit reference to the symbols virtual address, base not included 470 | #define EFI_IMAGE_REL_I386_SEG12 09 // Direct 16-bit reference to the segment-selector bits of a 32-bit virtual address 471 | #define EFI_IMAGE_REL_I386_SECTION 010 472 | #define EFI_IMAGE_REL_I386_SECREL 011 473 | #define EFI_IMAGE_REL_I386_REL32 020 // PC-relative 32-bit reference to the symbols virtual address 474 | 475 | // 476 | // x64 processor relocation types. 477 | // 478 | #define IMAGE_REL_AMD64_ABSOLUTE 0x0000 479 | #define IMAGE_REL_AMD64_ADDR64 0x0001 480 | #define IMAGE_REL_AMD64_ADDR32 0x0002 481 | #define IMAGE_REL_AMD64_ADDR32NB 0x0003 482 | #define IMAGE_REL_AMD64_REL32 0x0004 483 | #define IMAGE_REL_AMD64_REL32_1 0x0005 484 | #define IMAGE_REL_AMD64_REL32_2 0x0006 485 | #define IMAGE_REL_AMD64_REL32_3 0x0007 486 | #define IMAGE_REL_AMD64_REL32_4 0x0008 487 | #define IMAGE_REL_AMD64_REL32_5 0x0009 488 | #define IMAGE_REL_AMD64_SECTION 0x000A 489 | #define IMAGE_REL_AMD64_SECREL 0x000B 490 | #define IMAGE_REL_AMD64_SECREL7 0x000C 491 | #define IMAGE_REL_AMD64_TOKEN 0x000D 492 | #define IMAGE_REL_AMD64_SREL32 0x000E 493 | #define IMAGE_REL_AMD64_PAIR 0x000F 494 | #define IMAGE_REL_AMD64_SSPAN32 0x0010 495 | 496 | /// 497 | /// Based relocation format. 498 | /// 499 | typedef struct { 500 | UINT32 VirtualAddress; 501 | UINT32 SizeOfBlock; 502 | } EFI_IMAGE_BASE_RELOCATION; 503 | 504 | #define EFI_IMAGE_SIZEOF_BASE_RELOCATION 8 505 | 506 | // 507 | // Based relocation types. 508 | // 509 | #define EFI_IMAGE_REL_BASED_ABSOLUTE 0 510 | #define EFI_IMAGE_REL_BASED_HIGH 1 511 | #define EFI_IMAGE_REL_BASED_LOW 2 512 | #define EFI_IMAGE_REL_BASED_HIGHLOW 3 513 | #define EFI_IMAGE_REL_BASED_HIGHADJ 4 514 | #define EFI_IMAGE_REL_BASED_MIPS_JMPADDR 5 515 | #define EFI_IMAGE_REL_BASED_ARM_MOV32A 5 516 | #define EFI_IMAGE_REL_BASED_ARM_MOV32T 7 517 | #define EFI_IMAGE_REL_BASED_IA64_IMM64 9 518 | #define EFI_IMAGE_REL_BASED_DIR64 10 519 | 520 | 521 | /// 522 | /// Line number format. 523 | /// 524 | typedef struct { 525 | union { 526 | UINT32 SymbolTableIndex; // Symbol table index of function name if Linenumber is 0. 527 | UINT32 VirtualAddress; // Virtual address of line number. 528 | } Type; 529 | UINT16 Linenumber; // Line number. 530 | } EFI_IMAGE_LINENUMBER; 531 | 532 | #define EFI_IMAGE_SIZEOF_LINENUMBER 6 533 | 534 | // 535 | // Archive format. 536 | // 537 | #define EFI_IMAGE_ARCHIVE_START_SIZE 8 538 | #define EFI_IMAGE_ARCHIVE_START "!\n" 539 | #define EFI_IMAGE_ARCHIVE_END "`\n" 540 | #define EFI_IMAGE_ARCHIVE_PAD "\n" 541 | #define EFI_IMAGE_ARCHIVE_LINKER_MEMBER "/ " 542 | #define EFI_IMAGE_ARCHIVE_LONGNAMES_MEMBER "// " 543 | 544 | typedef struct { 545 | UINT8 Name[16]; // File member name - `/' terminated. 546 | UINT8 Date[12]; // File member date - decimal. 547 | UINT8 UserID[6]; // File member user id - decimal. 548 | UINT8 GroupID[6]; // File member group id - decimal. 549 | UINT8 Mode[8]; // File member mode - octal. 550 | UINT8 Size[10]; // File member size - decimal. 551 | UINT8 EndHeader[2]; // String to end header. 552 | } EFI_IMAGE_ARCHIVE_MEMBER_HEADER; 553 | 554 | #define EFI_IMAGE_SIZEOF_ARCHIVE_MEMBER_HDR 60 555 | 556 | // 557 | // DLL support. 558 | // 559 | 560 | /// 561 | /// DLL Export Format 562 | /// 563 | typedef struct { 564 | UINT32 Characteristics; 565 | UINT32 TimeDateStamp; 566 | UINT16 MajorVersion; 567 | UINT16 MinorVersion; 568 | UINT32 Name; 569 | UINT32 Base; 570 | UINT32 NumberOfFunctions; 571 | UINT32 NumberOfNames; 572 | UINT32 AddressOfFunctions; 573 | UINT32 AddressOfNames; 574 | UINT32 AddressOfNameOrdinals; 575 | } EFI_IMAGE_EXPORT_DIRECTORY; 576 | 577 | /// 578 | /// DLL support. 579 | /// Import Format 580 | /// 581 | typedef struct { 582 | UINT16 Hint; 583 | UINT8 Name[1]; 584 | } EFI_IMAGE_IMPORT_BY_NAME; 585 | 586 | typedef struct { 587 | union { 588 | UINT32 Function; 589 | UINT32 Ordinal; 590 | EFI_IMAGE_IMPORT_BY_NAME *AddressOfData; 591 | } u1; 592 | } EFI_IMAGE_THUNK_DATA; 593 | 594 | #define EFI_IMAGE_ORDINAL_FLAG 0x80000000 595 | #define EFI_IMAGE_SNAP_BY_ORDINAL(Ordinal) ((Ordinal & EFI_IMAGE_ORDINAL_FLAG) != 0) 596 | #define EFI_IMAGE_ORDINAL(Ordinal) (Ordinal & 0xffff) 597 | 598 | typedef struct { 599 | UINT32 Characteristics; 600 | UINT32 TimeDateStamp; 601 | UINT32 ForwarderChain; 602 | UINT32 Name; 603 | EFI_IMAGE_THUNK_DATA *FirstThunk; 604 | } EFI_IMAGE_IMPORT_DESCRIPTOR; 605 | 606 | /// 607 | /// Debug Format 608 | /// 609 | #define EFI_IMAGE_DEBUG_TYPE_CODEVIEW 2 610 | 611 | typedef struct { 612 | UINT32 Characteristics; 613 | UINT32 TimeDateStamp; 614 | UINT16 MajorVersion; 615 | UINT16 MinorVersion; 616 | UINT32 Type; 617 | UINT32 SizeOfData; 618 | UINT32 RVA; 619 | UINT32 FileOffset; 620 | } EFI_IMAGE_DEBUG_DIRECTORY_ENTRY; 621 | 622 | #define CODEVIEW_SIGNATURE_NB10 0x3031424E // "NB10" 623 | typedef struct { 624 | UINT32 Signature; // "NB10" 625 | UINT32 Unknown; 626 | UINT32 Unknown2; 627 | UINT32 Unknown3; 628 | // 629 | // Filename of .PDB goes here 630 | // 631 | } EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY; 632 | 633 | #define CODEVIEW_SIGNATURE_RSDS 0x53445352 // "RSDS" 634 | typedef struct { 635 | UINT32 Signature; // "RSDS" 636 | UINT32 Unknown; 637 | UINT32 Unknown2; 638 | UINT32 Unknown3; 639 | UINT32 Unknown4; 640 | UINT32 Unknown5; 641 | // 642 | // Filename of .PDB goes here 643 | // 644 | } EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY; 645 | 646 | /// 647 | /// Debug Data Structure defined by Apple Mach-O to Coff utility 648 | /// 649 | #define CODEVIEW_SIGNATURE_MTOC SIGNATURE_32('M', 'T', 'O', 'C') 650 | typedef struct { 651 | UINT32 Signature; ///< "MTOC" 652 | EFI_GUID MachOUuid; 653 | // 654 | // Filename of .DLL (Mach-O with debug info) goes here 655 | // 656 | } EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY; 657 | 658 | // 659 | // .pdata entries for X64 660 | // 661 | typedef struct { 662 | UINT32 FunctionStartAddress; 663 | UINT32 FunctionEndAddress; 664 | UINT32 UnwindInfoAddress; 665 | } RUNTIME_FUNCTION; 666 | 667 | typedef struct { 668 | UINT8 Version:3; 669 | UINT8 Flags:5; 670 | UINT8 SizeOfProlog; 671 | UINT8 CountOfUnwindCodes; 672 | UINT8 FrameRegister:4; 673 | UINT8 FrameRegisterOffset:4; 674 | } UNWIND_INFO; 675 | 676 | /// 677 | /// Resource format. 678 | /// 679 | typedef struct { 680 | UINT32 Characteristics; 681 | UINT32 TimeDateStamp; 682 | UINT16 MajorVersion; 683 | UINT16 MinorVersion; 684 | UINT16 NumberOfNamedEntries; 685 | UINT16 NumberOfIdEntries; 686 | // 687 | // Array of EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY entries goes here. 688 | // 689 | } EFI_IMAGE_RESOURCE_DIRECTORY; 690 | 691 | /// 692 | /// Resource directory entry format. 693 | /// 694 | typedef struct { 695 | union { 696 | struct { 697 | UINT32 NameOffset:31; 698 | UINT32 NameIsString:1; 699 | } s; 700 | UINT32 Id; 701 | } u1; 702 | union { 703 | UINT32 OffsetToData; 704 | struct { 705 | UINT32 OffsetToDirectory:31; 706 | UINT32 DataIsDirectory:1; 707 | } s; 708 | } u2; 709 | } EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY; 710 | 711 | /// 712 | /// Resource directory entry for string. 713 | /// 714 | typedef struct { 715 | UINT16 Length; 716 | CHAR16 String[1]; 717 | } EFI_IMAGE_RESOURCE_DIRECTORY_STRING; 718 | 719 | /// 720 | /// Resource directory entry for data array. 721 | /// 722 | typedef struct { 723 | UINT32 OffsetToData; 724 | UINT32 Size; 725 | UINT32 CodePage; 726 | UINT32 Reserved; 727 | } EFI_IMAGE_RESOURCE_DATA_ENTRY; 728 | 729 | /// 730 | /// Header format for TE images 731 | /// 732 | typedef struct { 733 | UINT16 Signature; // signature for TE format = "VZ" 734 | UINT16 Machine; // from the original file header 735 | UINT8 NumberOfSections; // from the original file header 736 | UINT8 Subsystem; // from original optional header 737 | UINT16 StrippedSize; // how many bytes we removed from the header 738 | UINT32 AddressOfEntryPoint; // offset to entry point -- from original optional header 739 | UINT32 BaseOfCode; // from original image -- required for ITP debug 740 | UINT64 ImageBase; // from original file header 741 | EFI_IMAGE_DATA_DIRECTORY DataDirectory[2]; // only base relocation and debug directory 742 | } EFI_TE_IMAGE_HEADER; 743 | 744 | #define EFI_TE_IMAGE_HEADER_SIGNATURE 0x5A56 // "VZ" 745 | 746 | // 747 | // Data directory indexes in our TE image header 748 | // 749 | #define EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC 0 750 | #define EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG 1 751 | 752 | 753 | // 754 | // Union of PE32, PE32+, and TE headers 755 | // 756 | typedef union { 757 | EFI_IMAGE_NT_HEADERS32 Pe32; 758 | EFI_IMAGE_NT_HEADERS64 Pe32Plus; 759 | EFI_TE_IMAGE_HEADER Te; 760 | } EFI_IMAGE_OPTIONAL_HEADER_UNION; 761 | 762 | typedef union { 763 | EFI_IMAGE_NT_HEADERS32 *Pe32; 764 | EFI_IMAGE_NT_HEADERS64 *Pe32Plus; 765 | EFI_TE_IMAGE_HEADER *Te; 766 | EFI_IMAGE_OPTIONAL_HEADER_UNION *Union; 767 | } EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION; 768 | 769 | #endif 770 | --------------------------------------------------------------------------------