├── LICENSE ├── Makefile ├── MapPE.cpp.bak ├── README.md ├── go.mod ├── main.go └── pkg ├── editors.go ├── mapper.go ├── structs.go └── unify.go /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Ege Balcı 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | normal: 2 | go build -o mappe -ldflags "-s -w" 3 | -------------------------------------------------------------------------------- /MapPE.cpp.bak: -------------------------------------------------------------------------------- 1 | #include // Compiled with: i686-w64-mingw32-g++-win32 -static-libgcc -static-libstdc++ MapPE.cpp -o MapPE.exe 2 | #include 3 | #include 4 | #include 5 | 6 | using namespace std; 7 | 8 | 9 | void PrintInfo(char *); 10 | void Dump(char*); 11 | void CheckIntegrity(char*,char*,int); 12 | void Banner(); 13 | 14 | 15 | int main(int argc, char const *argv[]) 16 | { 17 | 18 | if(argc<2){ 19 | Banner(); 20 | cout << "Usage: \n\tMapPE.exe input.exe\n"; 21 | exit(1); 22 | } 23 | 24 | Banner(); 25 | 26 | 27 | fstream File; 28 | File.open (argv[1], std::fstream::in | std::fstream::out | std::fstream::binary); 29 | if(File.is_open()){ 30 | 31 | 32 | File.seekg(0, File.end); 33 | int FileSize = File.tellg(); 34 | File.seekg(0, File.beg); 35 | 36 | char * PE = (char*)VirtualAlloc(NULL,FileSize,MEM_COMMIT,PAGE_READWRITE); 37 | 38 | //char * PE = new char[FileSize]; 39 | 40 | for(int i = 0; i < FileSize; i++){ 41 | File.get(PE[i]); 42 | } 43 | 44 | PrintInfo(PE); 45 | 46 | Dump(PE); 47 | 48 | } 49 | else{ 50 | cout << "[!] Unable to open file (" << argv[1] << ")\n"; 51 | exit(1); 52 | } 53 | 54 | 55 | return 0; 56 | } 57 | 58 | void PrintInfo(char * PE){ 59 | 60 | IMAGE_DOS_HEADER * DOSHeader; // For Nt DOS Header symbols 61 | IMAGE_NT_HEADERS * NtHeader; // For Nt PE Header objects & symbols 62 | IMAGE_SECTION_HEADER * SectionHeader; 63 | _IMAGE_FILE_HEADER * FileHeader; 64 | IMAGE_OPTIONAL_HEADER * OptHeader; 65 | _IMAGE_DATA_DIRECTORY * ImportTable; 66 | _IMAGE_DATA_DIRECTORY * ImportAddressTable; 67 | _IMAGE_DATA_DIRECTORY * ExportTable; 68 | _IMAGE_DATA_DIRECTORY * RelocationTable; 69 | 70 | DOSHeader = PIMAGE_DOS_HEADER(PE); // Initialize Variable 71 | NtHeader = PIMAGE_NT_HEADERS(DWORD(PE) + DOSHeader->e_lfanew); // Initialize 72 | FileHeader = &NtHeader->FileHeader; 73 | OptHeader = &NtHeader->OptionalHeader; 74 | 75 | 76 | if(PE[0] == 'M' && PE[1] == 'Z'){ 77 | cout << "[+] \"MZ\" magic number found !\n"; 78 | if(NtHeader->Signature == IMAGE_NT_SIGNATURE){ 79 | cout << "[+] Valid \"PE\" signature \n\n"; 80 | 81 | cout << "[-------------------------------------]\n"; 82 | 83 | printf("[*] ImageBase: 0x%x\n", OptHeader->ImageBase); 84 | printf("[*] Address Of Entry: 0x%x\n", (OptHeader->ImageBase+OptHeader->AddressOfEntryPoint)); 85 | 86 | cout << "[*] Number Of Sections: " << FileHeader->NumberOfSections << endl; 87 | cout << "[*] Number Of Symbols: " << FileHeader->NumberOfSymbols << endl; 88 | 89 | cout << "[*] Size Of Image: " << OptHeader->SizeOfImage << " bytes\n"; 90 | cout << "[*] Size Of Headers: " << OptHeader->SizeOfHeaders << " bytes\n"; 91 | 92 | printf("[*] Checksum: 0x%x\n", OptHeader->CheckSum); 93 | printf("[*] Subsystem: 0x%x\n", OptHeader->Subsystem); 94 | 95 | 96 | ExportTable = &OptHeader->DataDirectory[0]; 97 | ImportTable = &OptHeader->DataDirectory[1]; 98 | RelocationTable = &OptHeader->DataDirectory[5]; 99 | ImportAddressTable = &OptHeader->DataDirectory[12]; 100 | 101 | 102 | printf("[*] Export Table: 0x%x\n", (ExportTable->VirtualAddress+OptHeader->ImageBase)); 103 | printf("[*] Import Table: 0x%x\n", (ImportTable->VirtualAddress+OptHeader->ImageBase)); 104 | printf("[*] Import Address Table: 0x%x\n", (ImportAddressTable->VirtualAddress+OptHeader->ImageBase)); 105 | printf("[*] Relocation Table: 0x%x\n", (RelocationTable->VirtualAddress+OptHeader->ImageBase)); 106 | 107 | cout << "[-------------------------------------]\n\n\n"; 108 | 109 | 110 | for (int i = 0; i < NtHeader->FileHeader.NumberOfSections; i++){ 111 | SectionHeader = PIMAGE_SECTION_HEADER(DWORD(PE) + DOSHeader->e_lfanew + 248 + (i * 40)); 112 | cout << "##########################################\n"; 113 | cout << "# #\n"; 114 | cout << "# "; 115 | for(int c = 0; c < 8; c++){ 116 | if(SectionHeader->Name[c] == NULL){ 117 | cout << " "; 118 | } 119 | else{ 120 | cout << SectionHeader->Name[c]; 121 | } 122 | } 123 | cout << " -> "; 124 | printf("0x%x", (SectionHeader->VirtualAddress+OptHeader->ImageBase)); 125 | cout << " #\n"; 126 | 127 | for(int j = 0; j < (SectionHeader->SizeOfRawData/(OptHeader->SizeOfImage/20)); j++){ 128 | cout << "# #\n"; 129 | } 130 | } 131 | 132 | cout << "########################################## -> "; 133 | printf("0x%x\n\n", (OptHeader->SizeOfImage+OptHeader->ImageBase)); 134 | } 135 | else{ 136 | cout << "[!] PE signature missing ! \n"; 137 | cout << "[!] File is not a valid PE :( \n"; 138 | exit(1); 139 | } 140 | } 141 | else{ 142 | cout << "[!] Magic number not valid !\n"; 143 | cout << "[!] File is not a valid PE :(\n"; 144 | exit(1); 145 | } 146 | 147 | 148 | } 149 | 150 | 151 | 152 | /* 153 | WriteProcessMemory(PI.hProcess, LPVOID(DWORD(pImageBase) + SectionHeader->VirtualAddress),LPVOID(DWORD(Image) + SectionHeader->PointerToRawData), SectionHeader->SizeOfRawData, 0); 154 | */ 155 | 156 | 157 | void Dump(char * PE){ 158 | 159 | IMAGE_DOS_HEADER * DOSHeader; // For Nt DOS Header symbols 160 | IMAGE_NT_HEADERS * NtHeader; // For Nt PE Header objects & symbols 161 | IMAGE_SECTION_HEADER * SectionHeader; 162 | IMAGE_SECTION_HEADER * NextSectionHeader; 163 | _IMAGE_FILE_HEADER * FileHeader; 164 | IMAGE_OPTIONAL_HEADER * OptHeader; 165 | 166 | 167 | DOSHeader = PIMAGE_DOS_HEADER(PE); // Initialize Variable 168 | NtHeader = PIMAGE_NT_HEADERS(DWORD(PE) + DOSHeader->e_lfanew); // Initialize 169 | FileHeader = &NtHeader->FileHeader; 170 | OptHeader = &NtHeader->OptionalHeader; 171 | 172 | 173 | 174 | DWORD ImageBase = OptHeader->ImageBase; 175 | 176 | system("del Mem.map"); 177 | 178 | fstream File; 179 | File.open ("Mem.map", std::fstream::in | std::fstream::out | std::fstream::app | std::fstream::binary); 180 | if(File.is_open()){ 181 | 182 | cout << "[>] Maping PE headers...\n"; 183 | printf("[>] 0x%x\n", ImageBase); 184 | File.write((char*)PE, NtHeader->OptionalHeader.SizeOfHeaders); 185 | ImageBase += NtHeader->OptionalHeader.SizeOfHeaders; 186 | 187 | SectionHeader = PIMAGE_SECTION_HEADER(DWORD(PE) + DOSHeader->e_lfanew + 248); 188 | 189 | while(1){ 190 | if((OptHeader->ImageBase+SectionHeader->VirtualAddress) > ImageBase){ 191 | File << (char)NULL; 192 | ImageBase++; 193 | } 194 | else{ 195 | break; 196 | } 197 | } 198 | 199 | printf("[>] 0x%x\n", ImageBase); 200 | 201 | 202 | cout << "[>] Maping sections... " << endl; 203 | for (int i = 0; i < NtHeader->FileHeader.NumberOfSections; i++) 204 | { 205 | SectionHeader = PIMAGE_SECTION_HEADER(DWORD(PE) + DOSHeader->e_lfanew + 248 + (i * 40)); 206 | cout << "[>] " << SectionHeader->Name << endl; 207 | printf("[>] 0x%x\n", ImageBase); 208 | 209 | 210 | File.write((char*)(DWORD(PE) + SectionHeader->PointerToRawData), SectionHeader->SizeOfRawData); 211 | ImageBase += SectionHeader->SizeOfRawData; 212 | 213 | 214 | if (i <= (NtHeader->FileHeader.NumberOfSections-2)); 215 | { 216 | NextSectionHeader = PIMAGE_SECTION_HEADER(DWORD(PE) + DOSHeader->e_lfanew + 248 + ((i+1) * 40)); 217 | 218 | while(1){ 219 | if((OptHeader->ImageBase+NextSectionHeader->VirtualAddress) > ImageBase){ 220 | File << (char)NULL; 221 | ImageBase++; 222 | } 223 | else{ 224 | break; 225 | } 226 | } 227 | } 228 | 229 | printf("[>] 0x%x\n", ImageBase); 230 | } 231 | 232 | while(1){ 233 | if((OptHeader->SizeOfImage+OptHeader->ImageBase) > ImageBase){ 234 | File << (char)NULL; 235 | ImageBase++; 236 | } 237 | else{ 238 | break; 239 | } 240 | } 241 | 242 | cout << "\n[+] File mapping completed !\n"; 243 | 244 | cout << "\n[*] Starting integrity checks...\n"; 245 | 246 | 247 | File.seekg(0, File.end); 248 | int MapSize = File.tellg(); 249 | File.seekg(0, File.beg); 250 | 251 | cout << "\n[*] Mapped size: " << MapSize << endl; 252 | 253 | 254 | 255 | char * Map = (char*)VirtualAlloc(NULL,MapSize,MEM_COMMIT,PAGE_READWRITE); 256 | 257 | for(int i = 0; i < MapSize; i++){ 258 | File.get(Map[i]); 259 | } 260 | 261 | CheckIntegrity(PE,Map,MapSize); 262 | 263 | File.close(); 264 | 265 | cout << "\n[+] Mapped image dumped into Mem.map\n"; 266 | 267 | } 268 | else{ 269 | cout << "[!] Can't create dump file !"; 270 | exit(1); 271 | } 272 | } 273 | 274 | 275 | void CheckIntegrity(char * PE, char * Map, int MapSize){ 276 | 277 | IMAGE_DOS_HEADER * DOSHeader; // Dos header pointer 278 | IMAGE_NT_HEADERS * NtHeader; // NTHeader pointer 279 | IMAGE_SECTION_HEADER * SectionHeader; // Section header pointer 280 | _IMAGE_FILE_HEADER * FileHeader; // File pointer 281 | IMAGE_OPTIONAL_HEADER * OptHeader; // Optional hader pointer 282 | _IMAGE_DATA_DIRECTORY * ImportTable; // Data directory pointer 283 | _IMAGE_DATA_DIRECTORY * ImportAddressTable; // Address of IAT 284 | IMAGE_IMPORT_DESCRIPTOR * ImportDescriptor; // Image import descriptor pointer 285 | 286 | 287 | DOSHeader = PIMAGE_DOS_HEADER(PE); // Initialize Variable 288 | NtHeader = PIMAGE_NT_HEADERS(DWORD(PE) + DOSHeader->e_lfanew); // Initialize Ntheader 289 | FileHeader = &NtHeader->FileHeader; 290 | OptHeader = &NtHeader->OptionalHeader; 291 | ImportTable = &OptHeader->DataDirectory[2]; 292 | ImportAddressTable = &OptHeader->DataDirectory[13]; 293 | 294 | 295 | /* 296 | cout << "\n[*] Checking for bounded imports................... "; 297 | 298 | if() 299 | */ 300 | 301 | cout << "\n[*] Checking image size............................ "; 302 | 303 | if(OptHeader->SizeOfImage != MapSize){ 304 | cout << "[FAILED] \n\n" << "[!] Image size does not match :(\n"; 305 | exit(1); 306 | } 307 | cout << "[OK]"; 308 | 309 | 310 | 311 | cout << "\n[*] Checking section alignment..................... "; 312 | 313 | for (int i = 0; i < NtHeader->FileHeader.NumberOfSections; i++){ 314 | SectionHeader = PIMAGE_SECTION_HEADER(DWORD(PE) + DOSHeader->e_lfanew + 248 + (i * 40)); 315 | for(int j = 0; j < (SectionHeader->SizeOfRawData/10); j++){ 316 | 317 | if(PE[SectionHeader->PointerToRawData+j] != Map[SectionHeader->VirtualAddress+j]) { 318 | cout << "[FAILED] \n\n" << "[!] Broken section alignment :(\n"; 319 | exit(1); 320 | } 321 | } 322 | } 323 | cout << "[OK]\n"; 324 | 325 | 326 | cout << "[*] Checking data directory intervals.............. "; 327 | 328 | ImportDescriptor = (IMAGE_IMPORT_DESCRIPTOR*)(ImportTable->VirtualAddress+OptHeader->ImageBase); 329 | 330 | for(int i = 0; i < (ImportAddressTable->Size/10); i++){ 331 | if(Map[ImportDescriptor->FirstThunk+i] != Map[ImportAddressTable->VirtualAddress+i]){ 332 | cout << "[FAILED] \n\n" << "Incorrect data directory intervals :(\n"; 333 | exit(1); 334 | } 335 | } 336 | cout << "[OK]\n"; 337 | 338 | 339 | 340 | } 341 | 342 | 343 | 344 | 345 | void Banner(){ 346 | 347 | cout << " _____________________\n"; 348 | cout << " _____ _____ ______\\______ \\_ _____/\n"; 349 | cout << " / \\__ \\ \\____ \\| ___/| __)_ \n"; 350 | cout << "| Y Y \\/ __ \\| |_> > | | \\\n"; 351 | cout << "|__|_| (____ / __/|____| /_______ /\n"; 352 | cout << " \\/ \\/|__| \\/ \n"; 353 | 354 | cout << "\nAuthor: Ege Balci\n"; 355 | cout << "Github: github.com/egebalci/mappe\n\n"; 356 | 357 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MapPE 2 | MapPE constructs the memory mapped image of given PE files. 3 | 4 | ``` 5 | go install github.com/egebalci/mappe@latest 6 | ``` 7 | 8 | ``` 9 | _____________________ 10 | _____ _____ ______\______ \_ _____/ 11 | / \\__ \ \____ \| ___/| __)_ 12 | | Y Y \/ __ \| |_> > | | \ 13 | |__|_| (____ / __/|____| /_______ / 14 | \/ \/|__| \/ 15 | 16 | Author: Ege Balci 17 | Github: github.com/egebalci/mappe 18 | 19 | [+] "MZ" magic number found ! 20 | [+] Valid "PE" signature 21 | 22 | [-------------------------------------] 23 | [*] ImageBase: 0x400000 24 | [*] Address Of Entry: 0x4014e0 25 | [*] Number Of Sections: 7 26 | [*] Number Of Symbols: 0 27 | [*] Size Of Image: 36864 bytes 28 | [*] Size Of Headers: 1024 bytes 29 | [*] Checksum: 0xb6b9 30 | [*] Subsystem: 0x3 31 | [*] Export Table: 0x400000 32 | [*] Import Table: 0x406000 33 | [*] Import Address Table: 0x406120 34 | [-------------------------------------] 35 | 36 | 37 | ########################################## 38 | # # 39 | # .text -> 0x401000 # 40 | # # 41 | # # 42 | # # 43 | ########################################## 44 | # # 45 | # .data -> 0x403000 # 46 | ########################################## 47 | # # 48 | # .rdata -> 0x404000 # 49 | ########################################## 50 | # # 51 | # .bss -> 0x405000 # 52 | ########################################## 53 | # # 54 | # .idata -> 0x406000 # 55 | ########################################## 56 | # # 57 | # .CRT -> 0x407000 # 58 | ########################################## 59 | # # 60 | # .tls -> 0x408000 # 61 | ########################################## -> 0x409000 62 | 63 | [>] Maping PE headers... 64 | [>] 0x400000 65 | [>] 0x401000 66 | [>] Maping sections... 67 | [>] .text 68 | [>] 0x401000 69 | [>] 0x403000 70 | [>] .data 71 | [>] 0x403000 72 | [>] 0x404000 73 | [>] .rdata 74 | [>] 0x404000 75 | [>] 0x405000 76 | [>] .bss 77 | [>] 0x405000 78 | [>] 0x406000 79 | [>] .idata 80 | [>] 0x406000 81 | [>] 0x407000 82 | [>] .CRT 83 | [>] 0x407000 84 | [>] 0x408000 85 | [>] .tls 86 | [>] 0x408000 87 | [>] 0x408200 88 | 89 | [+] File mapping completed ! 90 | 91 | [*] Starting integrity checks... 92 | 93 | [*] Mapped size: 36864 94 | 95 | [*] Checking image size............................ [OK] 96 | [*] Checking section alignment..................... [OK] 97 | [*] Checking data directory intervals.............. [OK] 98 | 99 | [+] Mapped image dumped into Mem.dmp 100 | ``` 101 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/EgeBalci/MapPE 2 | 3 | go 1.18 4 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "debug/pe" 5 | "flag" 6 | "fmt" 7 | "io/ioutil" 8 | "log" 9 | "os" 10 | "path/filepath" 11 | "strconv" 12 | 13 | mappe "github.com/EgeBalci/MapPE/pkg" 14 | ) 15 | 16 | var verbose *bool 17 | 18 | func main() { 19 | 20 | banner() 21 | 22 | scrape := flag.Bool("s", false, "Scrape PE headers.") 23 | verbose = flag.Bool("v", false, "Verbose output mode.") 24 | ignore := flag.Bool("ignore", false, "Ignore integrity check errors.") 25 | flag.Parse() 26 | 27 | if len(os.Args) == 1 { 28 | flag.PrintDefaults() 29 | os.Exit(1) 30 | } 31 | 32 | // Get the absolute path of the file 33 | abs, err := filepath.Abs(flag.Args()[len(flag.Args())-1]) 34 | pError(err) 35 | file, err := pe.Open(abs) 36 | pError(err) 37 | printVerbose("Valid \"PE\" signature.", "+") 38 | rawFile, err2 := ioutil.ReadFile(abs) 39 | pError(err2) 40 | 41 | opt := mappe.UnifyOptionalHeader(file) 42 | 43 | printVerbose("File Size: "+strconv.Itoa(len(rawFile))+" byte", "*") 44 | printVerbose("Machine:"+fmt.Sprintf(" 0x%X", uint64(file.FileHeader.Machine)), "*") 45 | printVerbose("Magic:"+fmt.Sprintf(" 0x%X", uint64(opt.Magic)), "*") 46 | printVerbose("Subsystem:"+fmt.Sprintf(" 0x%X", uint64(opt.Subsystem)), "*") 47 | if opt.CheckSum != 0x00 { 48 | printVerbose("Checksum:"+fmt.Sprintf(" 0x%X", uint64(opt.CheckSum)), "*") 49 | } 50 | printVerbose("Image Base:"+fmt.Sprintf(" 0x%X", uint64(opt.ImageBase)), "*") 51 | printVerbose("Address Of Entry:"+fmt.Sprintf(" 0x%X", uint64(opt.AddressOfEntryPoint)), "*") 52 | printVerbose("Size Of Headers:"+fmt.Sprintf(" 0x%X", uint64(opt.SizeOfHeaders)), "*") 53 | printVerbose("Size Of Image:"+fmt.Sprintf(" 0x%X", uint64(opt.SizeOfImage)), "*") 54 | printVerbose("Export Table:"+fmt.Sprintf(" 0x%X", uint64(opt.DataDirectory[0].VirtualAddress)+opt.ImageBase), "*") 55 | printVerbose("Import Table:"+fmt.Sprintf(" 0x%X", uint64(opt.DataDirectory[1].VirtualAddress)+opt.ImageBase), "*") 56 | printVerbose("Base Relocation Table:"+fmt.Sprintf(" 0x%X", uint64(opt.DataDirectory[5].VirtualAddress)+opt.ImageBase), "*") 57 | printVerbose("Import Address Table:"+fmt.Sprintf(" 0x%X", uint64(opt.DataDirectory[12].VirtualAddress)+opt.ImageBase), "*") 58 | 59 | Map, err := mappe.CreateFileMapping(abs) 60 | pError(err) 61 | printVerbose("File mapping completed !", "+") 62 | printVerbose("Starting integrity checks...", "*") 63 | err = mappe.PerformIntegrityChecks(abs, Map) 64 | if !*ignore && err != nil { 65 | pError(err) 66 | } 67 | printVerbose("Integrity valid.", "+") 68 | mapFile, err := os.Create(abs + ".map") 69 | pError(err) 70 | defer mapFile.Close() 71 | if *scrape { 72 | printVerbose("Scraping file headers...", "*") 73 | mapFile.Write(mappe.Scrape(Map)) 74 | } else { 75 | mapFile.Write(Map) 76 | } 77 | 78 | fmt.Println("[+] File maped into -> " + abs + ".map") 79 | } 80 | 81 | func pError(err error) { 82 | if err != nil { 83 | log.Fatal(err) 84 | } 85 | } 86 | 87 | func printVerbose(str string, status string) { 88 | 89 | if *verbose { 90 | switch status { 91 | case "*": 92 | fmt.Println("[*] " + str) 93 | case "+": 94 | fmt.Println("[+] " + str) 95 | case "-": 96 | fmt.Println("[-] " + str) 97 | case "!": 98 | fmt.Println("[!] " + str) 99 | case "": 100 | fmt.Println(str) 101 | } 102 | } 103 | } 104 | func banner() { 105 | 106 | var banner = ` 107 | _____________________ 108 | _____ _____ ______\______ \_ _____/ 109 | / \\__ \ \____ \| ___/| __)_ 110 | | Y Y \/ __ \| |_> > | | \ 111 | |__|_| (____ / __/|____| /_______ / 112 | \/ \/|__| \/ 113 | Author: Ege Balcı 114 | Source: github.com/egebalci/mape 115 | ` 116 | fmt.Println(banner) 117 | } 118 | -------------------------------------------------------------------------------- /pkg/editors.go: -------------------------------------------------------------------------------- 1 | package mappe 2 | 3 | import ( 4 | "bytes" 5 | "debug/pe" 6 | "encoding/gob" 7 | "errors" 8 | "os" 9 | "strings" 10 | ) 11 | 12 | // SetSection sets the given raw section contents as byte array as the named section 13 | // Also fixes the section header accordingly 14 | func (file PEMap) SetSection(sectionName string, newSectionData []byte) error { 15 | 16 | oldSectionData, err := file.PE.Section(sectionName).Data() 17 | oldSectionHeader := pe.SectionHeader32{ 18 | VirtualSize: file.PE.Section(sectionName).SectionHeader.VirtualSize, 19 | VirtualAddress: file.PE.Section(sectionName).SectionHeader.VirtualAddress, 20 | SizeOfRawData: file.PE.Section(sectionName).SectionHeader.Size, 21 | PointerToRawData: file.PE.Section(sectionName).SectionHeader.Offset, 22 | PointerToRelocations: file.PE.Section(sectionName).SectionHeader.PointerToRelocations, 23 | PointerToLineNumbers: file.PE.Section(sectionName).SectionHeader.PointerToLineNumbers, 24 | NumberOfRelocations: file.PE.Section(sectionName).SectionHeader.NumberOfRelocations, 25 | NumberOfLineNumbers: file.PE.Section(sectionName).SectionHeader.NumberOfLineNumbers, 26 | Characteristics: file.PE.Section(sectionName).SectionHeader.Characteristics, 27 | } 28 | 29 | for i, c := range file.PE.Section(sectionName).SectionHeader.Name { 30 | oldSectionHeader.Name[i] = uint8(c) 31 | } 32 | 33 | var oldSectionHeaderData bytes.Buffer 34 | var newSectionHeaderData bytes.Buffer 35 | 36 | // Get raw old section header bytes 37 | encoder := gob.NewEncoder(&oldSectionHeaderData) 38 | err = encoder.Encode(oldSectionHeader) 39 | if err != nil { 40 | return err 41 | } 42 | 43 | // Replace section data 44 | file.Raw = []byte(strings.ReplaceAll(string(file.Raw), string(oldSectionData), string(newSectionData))) 45 | 46 | // Adjust new section header sizes 47 | oldSectionHeader.SizeOfRawData += uint32(len(newSectionData) - len(oldSectionData)) 48 | oldSectionHeader.VirtualSize += uint32(len(newSectionData) - len(oldSectionData)) 49 | 50 | encoder = gob.NewEncoder(&newSectionHeaderData) 51 | err = encoder.Encode(oldSectionHeader) 52 | if err != nil { 53 | return err 54 | } 55 | 56 | if oldSectionHeaderData.Len() != newSectionHeaderData.Len() { 57 | return errors.New("section headers size increased") 58 | } 59 | 60 | // Replace section header data 61 | file.Raw = []byte(strings.ReplaceAll(string(file.Raw), string(oldSectionHeaderData.Bytes()), string(newSectionHeaderData.Bytes()))) 62 | 63 | newFile, err := os.Open(file.Name) 64 | if err != nil { 65 | return err 66 | } 67 | 68 | _, err = newFile.Write(file.Raw) 69 | 70 | return err 71 | } 72 | 73 | // SetOptionalHeader sets a new optional header 74 | func SetOptionalHeader(fileName string, newOPHeader interface{}) error { 75 | 76 | return nil 77 | } 78 | -------------------------------------------------------------------------------- /pkg/mapper.go: -------------------------------------------------------------------------------- 1 | package mappe 2 | 3 | import ( 4 | "bytes" 5 | "errors" 6 | ) 7 | 8 | // CreateFileMapping constructs the memory mapped image of given PE file. 9 | func (file PEMap) CreateFileMapping() ([]byte, error) { 10 | 11 | opt := file.UnifyOptionalHeader() 12 | Map := bytes.Buffer{} 13 | offset := opt.ImageBase 14 | Map.Write(file.Raw[0:int(opt.SizeOfHeaders)]) 15 | offset += uint64(opt.SizeOfHeaders) 16 | for _, sec := range file.PE.Sections { 17 | // Append null bytes if there is a gap between sections or PE header 18 | for offset < (uint64(sec.VirtualAddress) + opt.ImageBase) { 19 | Map.WriteString(string(0x00)) 20 | offset++ 21 | } 22 | // Map the section 23 | section, err := sec.Data() 24 | if err != nil { 25 | return nil, err 26 | } 27 | _, err = Map.Write(section) 28 | if err != nil { 29 | return nil, err 30 | } 31 | offset += uint64(sec.Size) 32 | // Append null bytes until reaching the end of the virtual address of the section 33 | for offset < (uint64(sec.VirtualAddress) + uint64(sec.VirtualSize) + opt.ImageBase) { 34 | Map.WriteString(string(0x00)) 35 | offset++ 36 | } 37 | 38 | } 39 | for (offset - opt.ImageBase) < uint64(opt.SizeOfImage) { 40 | Map.WriteString(string(0x00)) 41 | offset++ 42 | } 43 | return Map.Bytes(), nil 44 | } 45 | 46 | // PerformIntegrityChecks validates the integrity of the mapped PE file 47 | func (file PEMap) PerformIntegrityChecks(memMap []byte) error { 48 | 49 | Map := bytes.Buffer{} 50 | _, err := Map.Write(memMap) 51 | if err != nil { 52 | return err 53 | } 54 | 55 | opt := file.UnifyOptionalHeader() 56 | report := "" 57 | if int(opt.SizeOfImage) != Map.Len() { 58 | report += "\t- Mapping size does not match the size of image header" 59 | } 60 | 61 | for _, j := range file.PE.Sections { 62 | for k := 0; k < int(j.Size); k++ { 63 | Buffer := Map.Bytes() 64 | if file.Raw[int(j.Offset)+k] != Buffer[int(j.VirtualAddress)+k] { 65 | report += "\t- Broken section alignment at" + j.Name 66 | } 67 | } 68 | 69 | } 70 | 71 | if report != "" { 72 | return errors.New("integrity checks failed: \n" + report) 73 | } 74 | return nil 75 | } 76 | 77 | // Scrape function removes the PE header from the mapped image 78 | func Scrape(Map []byte) []byte { 79 | 80 | // if string(Map[:2]) == "MZ" { 81 | // verbose(hex.Dump(Map[:2]),0) 82 | // Map[0] = 0x00 83 | // Map[1] = 0x00 84 | // } 85 | 86 | // for i:=0; i<0x1000; i++ { 87 | // if string(Map[i:i+2]) == "PE" { 88 | // verbose(hex.Dump(Map[i:i+2]),0) 89 | // Map[i] = 0x00 90 | // Map[i+1] = 0x00 91 | // } 92 | // } 93 | 94 | for i := 0; i < 0x1000; i++ { 95 | if string(Map[i:i+39]) == "This program cannot be run in DOS mode." { 96 | for j := 0; j < 39; j++ { 97 | Map[i+j] = 0x00 98 | } 99 | } 100 | } 101 | 102 | for i := 66; i < 0x1000; i++ { 103 | if Map[i] == 0x2e && Map[i+1] < 0x7e && Map[i+1] > 0x21 { 104 | for j := 0; j < 7; j++ { 105 | Map[i+j] = 0x00 106 | } 107 | } 108 | } 109 | 110 | return Map 111 | } 112 | -------------------------------------------------------------------------------- /pkg/structs.go: -------------------------------------------------------------------------------- 1 | package mappe 2 | 3 | import ( 4 | "debug/pe" 5 | "io/ioutil" 6 | "path/filepath" 7 | ) 8 | 9 | // UnifiedOptionalHeader = pe.OptionalHeader64 10 | type UnifiedOptionalHeader struct { 11 | Magic uint16 12 | MajorLinkerVersion uint8 13 | MinorLinkerVersion uint8 14 | SizeOfCode uint32 15 | SizeOfInitializedData uint32 16 | SizeOfUninitializedData uint32 17 | AddressOfEntryPoint uint32 18 | BaseOfCode uint32 19 | ImageBase uint64 // uint32 20 | SectionAlignment uint32 21 | FileAlignment uint32 22 | MajorOperatingSystemVersion uint16 23 | MinorOperatingSystemVersion uint16 24 | MajorImageVersion uint16 25 | MinorImageVersion uint16 26 | MajorSubsystemVersion uint16 27 | MinorSubsystemVersion uint16 28 | Win32VersionValue uint32 29 | SizeOfImage uint32 30 | SizeOfHeaders uint32 31 | CheckSum uint32 32 | Subsystem uint16 33 | DllCharacteristics uint16 34 | SizeOfStackReserve uint64 // uint32 35 | SizeOfStackCommit uint64 // uint32 36 | SizeOfHeapReserve uint64 // uint32 37 | SizeOfHeapCommit uint64 // uint32 38 | LoaderFlags uint32 39 | NumberOfRvaAndSizes uint32 40 | DataDirectory [16]DataDirectory 41 | } 42 | 43 | // DataDirectory = pe.DataDirectory 44 | type DataDirectory struct { 45 | VirtualAddress uint32 46 | Size uint32 47 | } 48 | 49 | // PEMap holds the PE file for processing 50 | type PEMap struct { 51 | Name string 52 | PE *pe.File 53 | Raw []byte 54 | } 55 | 56 | // Open a new PEMap 57 | func Open(fileName string) (*PEMap, error) { 58 | 59 | abs, err := filepath.Abs(fileName) 60 | if err != nil { 61 | return nil, err 62 | } 63 | 64 | new := PEMap{Name: abs} 65 | peFile, err := pe.Open(fileName) 66 | defer peFile.Close() 67 | if err != nil { 68 | return nil, err 69 | } 70 | new.PE = peFile 71 | 72 | rawFile, err := ioutil.ReadFile(fileName) 73 | if err != nil { 74 | return nil, err 75 | } 76 | new.Raw = rawFile 77 | return &new, nil 78 | } 79 | -------------------------------------------------------------------------------- /pkg/unify.go: -------------------------------------------------------------------------------- 1 | package mappe 2 | 3 | import ( 4 | "debug/pe" 5 | ) 6 | 7 | // UnifyOptionalHeader stores a given 8 | // 32 bit OptionalHeader struct inside a 64 bit OptionalHeader 9 | func (file PEMap) UnifyOptionalHeader() UnifiedOptionalHeader { 10 | 11 | var opt UnifiedOptionalHeader 12 | 13 | if file.PE.Machine == 0x8664 { 14 | opt.Magic = file.PE.OptionalHeader.(*pe.OptionalHeader64).Magic 15 | opt.MajorLinkerVersion = file.PE.OptionalHeader.(*pe.OptionalHeader64).MajorLinkerVersion 16 | opt.MinorLinkerVersion = file.PE.OptionalHeader.(*pe.OptionalHeader64).MinorLinkerVersion 17 | opt.SizeOfCode = file.PE.OptionalHeader.(*pe.OptionalHeader64).SizeOfCode 18 | opt.SizeOfInitializedData = file.PE.OptionalHeader.(*pe.OptionalHeader64).SizeOfInitializedData 19 | opt.SizeOfUninitializedData = file.PE.OptionalHeader.(*pe.OptionalHeader64).SizeOfUninitializedData 20 | opt.AddressOfEntryPoint = file.PE.OptionalHeader.(*pe.OptionalHeader64).AddressOfEntryPoint 21 | opt.BaseOfCode = file.PE.OptionalHeader.(*pe.OptionalHeader64).BaseOfCode 22 | opt.ImageBase = file.PE.OptionalHeader.(*pe.OptionalHeader64).ImageBase 23 | opt.SectionAlignment = file.PE.OptionalHeader.(*pe.OptionalHeader64).SectionAlignment 24 | opt.FileAlignment = file.PE.OptionalHeader.(*pe.OptionalHeader64).FileAlignment 25 | opt.MajorOperatingSystemVersion = file.PE.OptionalHeader.(*pe.OptionalHeader64).MajorOperatingSystemVersion 26 | opt.MinorOperatingSystemVersion = file.PE.OptionalHeader.(*pe.OptionalHeader64).MinorOperatingSystemVersion 27 | opt.MajorImageVersion = file.PE.OptionalHeader.(*pe.OptionalHeader64).MajorImageVersion 28 | opt.MinorImageVersion = file.PE.OptionalHeader.(*pe.OptionalHeader64).MinorImageVersion 29 | opt.MajorSubsystemVersion = file.PE.OptionalHeader.(*pe.OptionalHeader64).MajorSubsystemVersion 30 | opt.MinorSubsystemVersion = file.PE.OptionalHeader.(*pe.OptionalHeader64).MinorSubsystemVersion 31 | opt.Win32VersionValue = file.PE.OptionalHeader.(*pe.OptionalHeader64).Win32VersionValue 32 | opt.SizeOfImage = file.PE.OptionalHeader.(*pe.OptionalHeader64).SizeOfImage 33 | opt.SizeOfHeaders = file.PE.OptionalHeader.(*pe.OptionalHeader64).SizeOfHeaders 34 | opt.CheckSum = file.PE.OptionalHeader.(*pe.OptionalHeader64).CheckSum 35 | opt.Subsystem = file.PE.OptionalHeader.(*pe.OptionalHeader64).Subsystem 36 | opt.DllCharacteristics = file.PE.OptionalHeader.(*pe.OptionalHeader64).DllCharacteristics 37 | opt.SizeOfStackReserve = file.PE.OptionalHeader.(*pe.OptionalHeader64).SizeOfStackReserve 38 | opt.SizeOfStackCommit = file.PE.OptionalHeader.(*pe.OptionalHeader64).SizeOfStackCommit 39 | opt.SizeOfHeapReserve = file.PE.OptionalHeader.(*pe.OptionalHeader64).SizeOfHeapReserve 40 | opt.SizeOfHeapCommit = file.PE.OptionalHeader.(*pe.OptionalHeader64).SizeOfHeapCommit 41 | opt.LoaderFlags = file.PE.OptionalHeader.(*pe.OptionalHeader64).LoaderFlags 42 | opt.NumberOfRvaAndSizes = file.PE.OptionalHeader.(*pe.OptionalHeader64).NumberOfRvaAndSizes 43 | 44 | for i, j := range file.PE.OptionalHeader.(*pe.OptionalHeader64).DataDirectory { 45 | opt.DataDirectory[i].VirtualAddress = j.VirtualAddress 46 | opt.DataDirectory[i].Size = j.Size 47 | } 48 | 49 | } else if file.PE.Machine == 0x14C { 50 | opt.Magic = file.PE.OptionalHeader.(*pe.OptionalHeader32).Magic 51 | opt.MajorLinkerVersion = file.PE.OptionalHeader.(*pe.OptionalHeader32).MajorLinkerVersion 52 | opt.MinorLinkerVersion = file.PE.OptionalHeader.(*pe.OptionalHeader32).MinorLinkerVersion 53 | opt.SizeOfCode = file.PE.OptionalHeader.(*pe.OptionalHeader32).SizeOfCode 54 | opt.SizeOfInitializedData = file.PE.OptionalHeader.(*pe.OptionalHeader32).SizeOfInitializedData 55 | opt.SizeOfUninitializedData = file.PE.OptionalHeader.(*pe.OptionalHeader32).SizeOfUninitializedData 56 | opt.AddressOfEntryPoint = file.PE.OptionalHeader.(*pe.OptionalHeader32).AddressOfEntryPoint 57 | opt.BaseOfCode = file.PE.OptionalHeader.(*pe.OptionalHeader32).BaseOfCode 58 | opt.ImageBase = uint64(file.PE.OptionalHeader.(*pe.OptionalHeader32).ImageBase) 59 | opt.SectionAlignment = file.PE.OptionalHeader.(*pe.OptionalHeader32).SectionAlignment 60 | opt.FileAlignment = file.PE.OptionalHeader.(*pe.OptionalHeader32).FileAlignment 61 | opt.MajorOperatingSystemVersion = file.PE.OptionalHeader.(*pe.OptionalHeader32).MajorOperatingSystemVersion 62 | opt.MinorOperatingSystemVersion = file.PE.OptionalHeader.(*pe.OptionalHeader32).MinorOperatingSystemVersion 63 | opt.MajorImageVersion = file.PE.OptionalHeader.(*pe.OptionalHeader32).MajorImageVersion 64 | opt.MinorImageVersion = file.PE.OptionalHeader.(*pe.OptionalHeader32).MinorImageVersion 65 | opt.MajorSubsystemVersion = file.PE.OptionalHeader.(*pe.OptionalHeader32).MajorSubsystemVersion 66 | opt.MinorSubsystemVersion = file.PE.OptionalHeader.(*pe.OptionalHeader32).MinorSubsystemVersion 67 | opt.Win32VersionValue = file.PE.OptionalHeader.(*pe.OptionalHeader32).Win32VersionValue 68 | opt.SizeOfImage = file.PE.OptionalHeader.(*pe.OptionalHeader32).SizeOfImage 69 | opt.SizeOfHeaders = file.PE.OptionalHeader.(*pe.OptionalHeader32).SizeOfHeaders 70 | opt.CheckSum = file.PE.OptionalHeader.(*pe.OptionalHeader32).CheckSum 71 | opt.Subsystem = file.PE.OptionalHeader.(*pe.OptionalHeader32).Subsystem 72 | opt.DllCharacteristics = file.PE.OptionalHeader.(*pe.OptionalHeader32).DllCharacteristics 73 | opt.SizeOfStackReserve = uint64(file.PE.OptionalHeader.(*pe.OptionalHeader32).SizeOfStackReserve) 74 | opt.SizeOfStackCommit = uint64(file.PE.OptionalHeader.(*pe.OptionalHeader32).SizeOfStackCommit) 75 | opt.SizeOfHeapReserve = uint64(file.PE.OptionalHeader.(*pe.OptionalHeader32).SizeOfHeapReserve) 76 | opt.SizeOfHeapCommit = uint64(file.PE.OptionalHeader.(*pe.OptionalHeader32).SizeOfHeapCommit) 77 | opt.LoaderFlags = file.PE.OptionalHeader.(*pe.OptionalHeader32).LoaderFlags 78 | opt.NumberOfRvaAndSizes = file.PE.OptionalHeader.(*pe.OptionalHeader32).NumberOfRvaAndSizes 79 | 80 | for i, j := range file.PE.OptionalHeader.(*pe.OptionalHeader32).DataDirectory { 81 | opt.DataDirectory[i].VirtualAddress = j.VirtualAddress 82 | opt.DataDirectory[i].Size = j.Size 83 | } 84 | } 85 | 86 | return opt 87 | 88 | } 89 | --------------------------------------------------------------------------------