├── Disassembler ├── Example_Trace_Output │ ├── entire_unpacked-1 │ ├── entire_unpacked-1.til │ ├── entire_unpacked_clean-1 │ ├── exports_wave-1 │ ├── trace_output │ └── wave_entrypoints ├── PEtite_example │ ├── Petite_packed.exe │ ├── entire_unpacked-3 │ ├── exports_wave-3 │ ├── trace_output │ └── wave_entrypoints ├── README.md ├── disassembler.py └── main.py ├── README.md └── Tracer ├── Example_of_packed_file ├── Petite_packed.exe └── UPX_packed.exe ├── Makefile ├── Pre_compiled_dll └── unpacker.dll ├── README.md ├── main.c └── unpacker.h /Disassembler/Example_Trace_Output/entire_unpacked-1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DavidKorczynski/RePEconstruct/df97c55f1fa1039cd80a73f3fe59f36b136f36f6/Disassembler/Example_Trace_Output/entire_unpacked-1 -------------------------------------------------------------------------------- /Disassembler/Example_Trace_Output/entire_unpacked-1.til: -------------------------------------------------------------------------------- 1 | IDATILLocal type definitionsmssdk -------------------------------------------------------------------------------- /Disassembler/Example_Trace_Output/entire_unpacked_clean-1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DavidKorczynski/RePEconstruct/df97c55f1fa1039cd80a73f3fe59f36b136f36f6/Disassembler/Example_Trace_Output/entire_unpacked_clean-1 -------------------------------------------------------------------------------- /Disassembler/Example_Trace_Output/wave_entrypoints: -------------------------------------------------------------------------------- 1 | W 1 First executed instruction at 0x004011c2 2 | -------------------------------------------------------------------------------- /Disassembler/PEtite_example/Petite_packed.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DavidKorczynski/RePEconstruct/df97c55f1fa1039cd80a73f3fe59f36b136f36f6/Disassembler/PEtite_example/Petite_packed.exe -------------------------------------------------------------------------------- /Disassembler/PEtite_example/entire_unpacked-3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DavidKorczynski/RePEconstruct/df97c55f1fa1039cd80a73f3fe59f36b136f36f6/Disassembler/PEtite_example/entire_unpacked-3 -------------------------------------------------------------------------------- /Disassembler/PEtite_example/wave_entrypoints: -------------------------------------------------------------------------------- 1 | W 1 First executed instruction at 0x00140000 2 | W 2 First executed instruction at 0x00140398 3 | W 3 First executed instruction at 0x004011c2 4 | -------------------------------------------------------------------------------- /Disassembler/README.md: -------------------------------------------------------------------------------- 1 | # Disassembler 2 | 3 | The main idea with this disassembler is to use information from a concrete execution to support commonly done reverse engineering tasks. Specifically, the disassembler uses information about *branch instruction, memory reads and the modules exported by dynamically loaded libraries* from the concrete execution by our tracer, to rebuild the IAT of an unpacked binary and also relocate instructions or produce IDA scripts if desired. The relocation of instructions is a neat way to automatically patch the binary to something more useful than a binary with broken branching to imports. The point of the IDA script is to annotate and insert cross-references from branch calls (including obfuscated calls observed during the concrete execution) to imported functions. 4 | 5 | The *main.py* function gives a concrete example of how to use the disassembler, which should be fairly straight forward to interpret. When you have installed the software mentioned below, you should be able to simply run the main.py and see some results! 6 | 7 | To run the disassembler you need to have Capstone installed. 8 | **Note that you need to have the ["next" branch](https://github.com/aquynh/capstone/wiki/Next-branch) of Capstone installed.** There is a link on the home README file. **You also need [PEfile](https://github.com/erocarrera/pefile)**. 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /Disassembler/disassembler.py: -------------------------------------------------------------------------------- 1 | from collections import deque 2 | from struct import * 3 | from capstone import * 4 | from capstone.x86 import * 5 | import pefile 6 | import struct 7 | 8 | 9 | class RPE_XREF_type: 10 | branch = 1 11 | mem_read = 2 12 | mem_write = 3 13 | 14 | def __init__(): 15 | None 16 | 17 | 18 | class RPE_instruction: 19 | 20 | def __init__(self): 21 | self.address = None 22 | self.decoded_instr = None 23 | self.branch_destinations = set() 24 | self.values_read = set() 25 | 26 | def add_branch_destination(self, dst_address): 27 | self.branch_destinations.add(dst_address) 28 | 29 | def get_branch_destinations(self): 30 | return self.branch_destinations 31 | 32 | def add_values_read(self, value_read): 33 | self.values_read.add(value_read) 34 | 35 | def get_values_read(self): 36 | return self.values_read 37 | 38 | 39 | class RPE_instruction_graph: 40 | """ 41 | A representation of the binary as a directed graph where each node 42 | is an instruction of the binary. 43 | 44 | The graph is represented as a mapping: 45 | instruction_address -> RPE_instruction 46 | 47 | 48 | """ 49 | 50 | def __init__(self): 51 | self.graph = dict() 52 | 53 | def add_edge(self, src_instr, dst_address, ref_type): 54 | """ 55 | 56 | :param RPE_instruction src_instr: 57 | :param unsigned int dst_address: 58 | :param REFERENCE_TYPE ref_type: 59 | 60 | :return: None 61 | """ 62 | source_addr = src_instr.address 63 | self.graph[source_addr].add_branch_destination(dst_address) 64 | 65 | def add_node(self, instr): 66 | """ 67 | :param RPE_instruction instr: 68 | 69 | :return: None 70 | """ 71 | self.graph[instr.address] = instr 72 | 73 | def is_analysed(self, instr_addr): 74 | """ 75 | 76 | :param unsigned int instr_addr: 77 | 78 | :return Boolean: whether the address is contained in the graph as a node. 79 | """ 80 | return instr_addr in self.graph 81 | 82 | def get_instruction(self, instr_addr): 83 | """ 84 | 85 | :param unsigned int instr_addr: 86 | 87 | :return RPE_instruction: The RPE_instruction at the instruction address. 88 | None if the node is not in the graph. 89 | """ 90 | if instr_addr in self.graph: 91 | return self.graph[instr_addr] 92 | print 'no such instruction' 93 | 94 | def number_of_instructions(self): 95 | return len(self.graph) 96 | 97 | def print_calls_to_exports(self): 98 | for instr_addr in self.graph: 99 | instr = self.graph[instr_addr] 100 | dec_instr = instr.decoded_instr 101 | for branch_dst in instr.branch_destinations: 102 | if branch_dst > 6291456: 103 | print '0x%x:\t%s\t%s' % (dec_instr.address, dec_instr.mnemonic, dec_instr.op_str) 104 | print '\t: ' + hex(branch_dst) 105 | 106 | 107 | class RPE_program_dump: 108 | 109 | def __init__(self, file_name): 110 | self.endian = ' self.base_address and address < self.base_address + self.module_size: 132 | return True 133 | return False 134 | 135 | def write_address(self, lvalue, value_to_write, add_base = 1): 136 | if add_base == 1: 137 | # Little endian is being written 138 | file_offset = lvalue - self.base_address 139 | 140 | #print("writing %x at %x"%(value_to_write, file_offset)) 141 | bytes_to_write = struct.pack(" 0: 432 | instr_addr = self.instr_queue.popleft() 433 | if self.instr_graph.is_analysed(instr_addr) == True or self.mem_dump.is_it_in_module(instr_addr) == False: 434 | continue 435 | disassembled += 1 436 | instr = RPE_instruction() 437 | buf = self.mem_dump.read_memory(instr_addr, 15) 438 | try: 439 | dec_instr = self.instr_decoder.disasm(buf, instr_addr).next() 440 | except StopIteration: 441 | continue 442 | 443 | instr.address = instr_addr 444 | instr.decoded_instr = dec_instr 445 | self.instr_graph.add_node(instr) 446 | branch_dsts = self.get_branch_destinations(instr) 447 | for dst_addr in branch_dsts: 448 | self.instr_graph.add_edge(instr, dst_addr, 3) 449 | self.instr_queue.append(dst_addr) 450 | 451 | self.handle_branch_destination(instr) 452 | self.handle_memory_reads(instr) 453 | 454 | print 'Disassembled in total: ' + `disassembled` 455 | print 'number of nodes in graph: ' + `(len(self.instr_graph.graph))` 456 | print 'Instructions to relocate: ' + `(len(self.instructions_to_relocate))` 457 | print 'Number of functions in import table: ' + `(self.import_table.number_of_functions())` 458 | relocate_set = set(self.instructions_to_relocate) 459 | print 'Size of set to relocate: ' + `(len(relocate_set))` 460 | #for instr_address in relocate_set: 461 | # print '%x\t' % instr_address 462 | 463 | def build_import_table(self): 464 | """ 465 | Builds the new import table in the section added by the 466 | tracer. 467 | """ 468 | self.section_alignment = 4096 469 | pe = pefile.PE(data=self.mem_dump.dump) 470 | IAT_addr = pe.OPTIONAL_HEADER.DATA_DIRECTORY[1].VirtualAddress 471 | print 'IAT_addr: ' + hex(IAT_addr) 472 | raw_size = self.import_table.raw_memory_size() 473 | jump_table_size = self.import_table.get_jump_table_size() 474 | 475 | print "raw_size: ", `raw_size` 476 | print "jump table size: ", `jump_table_size` 477 | 478 | size = ((raw_size+jump_table_size) / self.section_alignment + 1) * self.section_alignment 479 | print size 480 | byte_array = bytearray(size) 481 | IID_pos = 0 482 | content_pos = (len(self.import_table.dlls) + 1) * 20 483 | 484 | jump_table_pos = IID_pos + raw_size 485 | 486 | print "jump table position: ", hex(jump_table_pos) 487 | 488 | for dll in self.import_table.dlls: 489 | print dll 490 | thunk_position = content_pos + len(dll) + 1 491 | byte_array[IID_pos + 12:IID_pos + 16] = pack(' 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | /* for offsetof */ 19 | #include 20 | 21 | // DynamoRIO imports 22 | #include "dr_api.h" 23 | #include "drmgr.h" 24 | #include "drutil.h" 25 | 26 | // Function declarations 27 | #include "unpacker.h" 28 | 29 | // Capstone 30 | #include "Capstone/include/capstone.h" 31 | 32 | 33 | #define SAVE_REG(_reg, _slot)\ 34 | dr_save_reg(drcontext, bb, instr, _reg, _slot); 35 | 36 | #define RESTORE_REG(_reg, _slot)\ 37 | dr_restore_reg(drcontext, bb, instr, _reg, _slot); 38 | 39 | 40 | // Used by the library referencer 41 | unsigned int module_base_address = 0; 42 | unsigned int module_base_size = 0; 43 | 44 | /* Helper for dumping process */ 45 | //#define IMAGE_DOS_SIGNATURE 0x5a4d 46 | 47 | typedef struct mapped_pe_t { 48 | PIMAGE_DOS_HEADER pDosHeader; 49 | PIMAGE_NT_HEADERS pNtHeader; 50 | PIMAGE_OPTIONAL_HEADER pOptHeader; 51 | PIMAGE_FILE_HEADER pFileHeader; 52 | PIMAGE_SECTION_HEADER pSectHeader; 53 | } mapped_pe; 54 | 55 | mapped_pe dump_pe_header; 56 | 57 | /* number of waves in the packer */ 58 | int dump_wave = 0; 59 | 60 | #define new_import_section_size_definition 0x1000 61 | 62 | 63 | // Capstone 64 | // handle to disassembler 65 | csh handle; 66 | 67 | 68 | /* we have several number of operands */ 69 | typedef struct { 70 | unsigned int mem_ref1; 71 | unsigned int mem_ref2; 72 | unsigned int mem_ref3; 73 | unsigned int mem_ref4; 74 | unsigned int size_of_mem_write; 75 | app_pc pc; 76 | unsigned int reads_memory; 77 | unsigned int address_being_read; 78 | unsigned int number_of_refs; /* this indicates how many of the operands are used */ 79 | unsigned int instr_size; 80 | unsigned int old_instr_size; 81 | unsigned int old_pc; 82 | } tls_storage; 83 | 84 | 85 | // Output file, with trace information 86 | FILE *output_file; 87 | FILE *wave_file; 88 | 89 | static uint64 global_count; 90 | 91 | /* hashtable */ 92 | #define SIZE 25000 93 | #define HASHFUNCTION(n) (n) % (unsigned int) SIZE 94 | 95 | struct node { 96 | unsigned int address; 97 | struct node *next; 98 | struct node *prev; 99 | }; 100 | 101 | /* initiate the data structures used for collecting all the 102 | * functions exported by various modules. 103 | */ 104 | 105 | struct node *hashtable [SIZE]; 106 | int table_size = 0; 107 | 108 | int tls_index; 109 | 110 | tls_storage *mem_buffer; 111 | 112 | /* hashtable implementation */ 113 | int 114 | is_in(unsigned int address) 115 | { 116 | struct node *tmp; 117 | unsigned int place; 118 | 119 | place = HASHFUNCTION(address); 120 | tmp = hashtable[place]; 121 | 122 | while (tmp != NULL) 123 | { 124 | if (tmp->address == address) 125 | return 1; 126 | tmp = tmp->next; 127 | } 128 | 129 | return 0; 130 | } 131 | 132 | int 133 | insert(unsigned int address) 134 | { 135 | struct node *holder; 136 | unsigned int place; 137 | 138 | place = HASHFUNCTION(address); 139 | 140 | holder = (struct node *) dr_global_alloc(sizeof(struct node)); 141 | holder->address = address; 142 | 143 | 144 | holder->next = hashtable[place]; 145 | holder->prev = NULL; 146 | 147 | if (hashtable[place] != NULL) 148 | hashtable[place]->prev = holder; 149 | 150 | hashtable[place] = holder; 151 | 152 | table_size++; 153 | 154 | return 1; 155 | } 156 | 157 | /* 158 | * Clear the hashtable containing dynamically written memory 159 | */ 160 | void 161 | delete_all() 162 | { 163 | int i; 164 | struct node *tmp; 165 | 166 | for (i=0; i < SIZE; i++) 167 | { 168 | tmp = hashtable[i]; 169 | while (tmp != NULL) 170 | { 171 | struct node *tmp2; 172 | 173 | tmp2 = tmp->next; 174 | dr_global_free(tmp, sizeof(struct node)); 175 | tmp = tmp2; 176 | table_size--; 177 | } 178 | hashtable[i] = NULL; 179 | } 180 | if (table_size < 0) 181 | DR_ASSERT(false); 182 | } 183 | 184 | /* 185 | * Input: The address of a module 186 | * 187 | * Functionality: 188 | * Iterate the exported functions of the module 189 | * For each function, save the virtual address and the function name in the Dll_list 190 | * 191 | */ 192 | void 193 | TraverseExportedFunctions(HANDLE base_address, char *dll_name, FILE *output_file) 194 | { 195 | /* The PE header */ 196 | mapped_pe pe; 197 | PIMAGE_EXPORT_DIRECTORY export_directory; 198 | IMAGE_DATA_DIRECTORY export_data_dir; 199 | unsigned int AddressOfNames_array; 200 | char *func_name; 201 | int i; 202 | unsigned int *function_name_offset; 203 | unsigned int ordinal_addr_arr; 204 | short int ordinal; 205 | 206 | unsigned int function_addr_arr; 207 | unsigned int function; 208 | 209 | char output_line[512]; 210 | 211 | // Get DOS header of module 212 | pe.pDosHeader = (PIMAGE_DOS_HEADER) base_address; 213 | 214 | if (pe.pDosHeader->e_magic != IMAGE_DOS_SIGNATURE) 215 | dr_fprintf(STDERR, "DOS signature not correct\n"); 216 | 217 | // Get PE header of module 218 | pe.pNtHeader = (PIMAGE_NT_HEADERS) ((unsigned int)base_address + pe.pDosHeader->e_lfanew); 219 | 220 | /* Is PE header valid? */ 221 | if (pe.pNtHeader->Signature != IMAGE_NT_SIGNATURE) 222 | dr_fprintf(STDERR, "NT signature not correct\n"); 223 | 224 | // Get optional header 225 | pe.pOptHeader = &(pe.pNtHeader->OptionalHeader); 226 | 227 | /* Get the export directory */ 228 | export_data_dir = pe.pOptHeader->DataDirectory[0]; 229 | export_directory = (PIMAGE_EXPORT_DIRECTORY) ((unsigned int)base_address + export_data_dir.VirtualAddress); 230 | 231 | /* Return if we don't export any functions */ 232 | if (export_directory->NumberOfFunctions == 0) 233 | return; 234 | 235 | // Get the address to the string of names 236 | // AddressOfNames is an RVA that points to an array of RVAs of the functions/symbols in the module 237 | AddressOfNames_array = ((unsigned int)base_address + export_directory->AddressOfNames); 238 | 239 | 240 | i = 0; 241 | 242 | // For each address in the array pointed to by AddressOfNames 243 | // This one only iterates NAMES - modify so it also iterates Ordinals. 244 | while (function_name_offset = (unsigned int *)AddressOfNames_array + i) 245 | { 246 | func_name = (char *)((unsigned int)base_address + *function_name_offset); 247 | // End of function list 248 | if (*func_name == '\0') 249 | return; 250 | 251 | /* Get the ordinal of what we are doing */ 252 | ordinal_addr_arr = (unsigned int)base_address + export_directory->AddressOfNameOrdinals; 253 | ordinal = *((short *)ordinal_addr_arr + i); 254 | 255 | /* Get the address of the function */ 256 | function_addr_arr = (unsigned int)base_address + export_directory->AddressOfFunctions; 257 | function = *((unsigned int*)function_addr_arr+ordinal); 258 | 259 | function += (unsigned int)base_address; 260 | 261 | /* Write to output */ 262 | sprintf(output_line, "%s %s %x\n", dll_name, func_name, function); 263 | fwrite(output_line, strlen(output_line), 1, output_file); 264 | 265 | // Insert the function name and its address into our Dll_list list. 266 | //insert_exported_function(dll_name, func_name, function); 267 | 268 | i += 1; 269 | 270 | if (i >= export_directory->NumberOfNames) 271 | return; 272 | } 273 | } 274 | 275 | 276 | /* 277 | * Gets the name and exported functions from each module 278 | * in the process. Save this in the Dll_list data 279 | * structure. 280 | */ 281 | void 282 | GetAllDllNames() 283 | { 284 | HANDLE snapshot; 285 | MODULEENTRY32 module; 286 | FILE *export_output; 287 | char export_filename[255]; 288 | 289 | 290 | // TH32CS_SNAPSHOT == 0x08 291 | snapshot = CreateToolhelp32Snapshot(0x08, 0); 292 | 293 | if (snapshot != INVALID_HANDLE_VALUE) 294 | { 295 | module.dwSize = sizeof(MODULEENTRY32); 296 | 297 | if (Module32First(snapshot, &module)) 298 | { 299 | /* Open file we write to */ 300 | sprintf(export_filename, ".\\Refactor_output\\exports_wave-%d", dump_wave); 301 | export_output = fopen(export_filename, "w"); 302 | 303 | if (export_output == NULL) 304 | { 305 | dr_fprintf(STDERR, "Error opening export file, exiting\n"); 306 | exit(1); 307 | } 308 | 309 | module.dwSize = sizeof(MODULEENTRY32); 310 | 311 | do // Iterate each module of the process to collect export functions 312 | { 313 | // Insert all the exported functions from the DLL into 314 | // our Dll_list doubly linked list. 315 | TraverseExportedFunctions(module.modBaseAddr, module.szModule, export_output); 316 | } 317 | while (Module32Next(snapshot, &module)); 318 | 319 | fclose(export_output); 320 | } 321 | } 322 | } 323 | 324 | #define FILE_ALIGNMENT 0x200 325 | #define SECT_ALIGNMENT 0x1000 326 | 327 | void 328 | write_new_section(byte *memory_dump, unsigned int base_address) 329 | { 330 | unsigned int i; 331 | 332 | unsigned int max_section_address; 333 | unsigned int max_section_size; 334 | 335 | PIMAGE_SECTION_HEADER new_import_section; 336 | 337 | // Get section header 338 | new_import_section = (PIMAGE_SECTION_HEADER) dump_pe_header.pSectHeader; 339 | 340 | // max_section_address represents the address of the last section 341 | max_section_address = 0; 342 | 343 | // max_section_size represents the size of the last section. 344 | max_section_size = 0; 345 | 346 | // find the offset in the section header where our new section will be 347 | for (i=0; i < (unsigned int)(dump_pe_header.pFileHeader->NumberOfSections); i++) 348 | { 349 | //if (new_import_section-> 350 | if (new_import_section->VirtualAddress > max_section_address) 351 | { 352 | max_section_address = new_import_section->VirtualAddress; 353 | max_section_size = new_import_section->Misc.VirtualSize; 354 | } 355 | new_import_section++; 356 | } 357 | 358 | // Increase the number of sections 359 | dump_pe_header.pFileHeader->NumberOfSections++; 360 | 361 | // ## Create the new section ## 362 | // Set Name 363 | strcpy(new_import_section->Name, "new_imp"); 364 | 365 | // Set virtual size of the section of new import table 366 | new_import_section->Misc.VirtualSize = new_import_section_size_definition; 367 | 368 | // Set a valid section Virtual Address of new import table 369 | max_section_address += max_section_size; 370 | max_section_address = 371 | ((max_section_address%SECT_ALIGNMENT) != 0) ? 372 | (max_section_address/SECT_ALIGNMENT+1)*SECT_ALIGNMENT : max_section_address; 373 | 374 | new_import_section->VirtualAddress = max_section_address; 375 | 376 | // set a valid Raw offset of new import table, this is equal to the RVA 377 | // indicated by VirtualAddress because we dump the image as it is in the binary. 378 | new_import_section->PointerToRawData = new_import_section->VirtualAddress; 379 | 380 | // set raw size - similar to VirtualSize 381 | new_import_section->SizeOfRawData = new_import_section->Misc.VirtualSize; 382 | 383 | // Set characteristics of the section 384 | new_import_section->Characteristics = 0xc0300040; 385 | 386 | /* set size and addr of new section */ 387 | dump_pe_header.pOptHeader->DataDirectory[1].VirtualAddress = max_section_address; 388 | dump_pe_header.pOptHeader->DataDirectory[1].Size = 389 | new_import_section->Misc.VirtualSize; 390 | 391 | /* Zero old data directory with fast address for import table */ 392 | dump_pe_header.pOptHeader->DataDirectory[12].VirtualAddress = 0x0; 393 | dump_pe_header.pOptHeader->DataDirectory[12].Size = 0x0; 394 | 395 | /* Size of the new image */ 396 | dump_pe_header.pOptHeader->SizeOfImage = (dump_pe_header.pOptHeader->SizeOfImage + new_import_section->Misc.VirtualSize); 397 | } 398 | 399 | 400 | /* 401 | * Sets PointerToRawData and SizeOfRawData in each section 402 | * in the section table, equal to the sizes and virtual 403 | * addresses in the virtual memory. 404 | * 405 | * We need this because we drop the entire Binary as it is in memory. 406 | */ 407 | void 408 | configure_section_offsets(byte *memory_dump, unsigned int base) 409 | { 410 | int i; 411 | 412 | /* we iterate through the sections */ 413 | for (i = 0; i < dump_pe_header.pFileHeader->NumberOfSections; i++) 414 | { 415 | /* Raw offset should remain the same as virtual address offset. */ 416 | dump_pe_header.pSectHeader[i].PointerToRawData = dump_pe_header.pSectHeader[i].VirtualAddress; 417 | dump_pe_header.pSectHeader[i].SizeOfRawData = dump_pe_header.pSectHeader[i].Misc.VirtualSize; 418 | } 419 | } 420 | 421 | void 422 | write_entry_point(unsigned int new_entry_point, unsigned int base_address, byte *memory_dump) 423 | { 424 | dump_pe_header.pOptHeader->AddressOfEntryPoint = (new_entry_point - base_address); 425 | } 426 | 427 | /* Sets the elements of dump_pe_header according to the new memory_dump */ 428 | int 429 | Set_PE_header(byte *memory_dump) 430 | { 431 | dump_pe_header.pDosHeader = (PIMAGE_DOS_HEADER) memory_dump; 432 | 433 | if (dump_pe_header.pDosHeader->e_magic != IMAGE_DOS_SIGNATURE) 434 | dr_fprintf(STDERR, "DOS signature not correct\n"); 435 | 436 | 437 | dump_pe_header.pNtHeader = (PIMAGE_NT_HEADERS)(memory_dump + 438 | dump_pe_header.pDosHeader->e_lfanew); 439 | 440 | /* set nt header */ 441 | if (dump_pe_header.pNtHeader->Signature != IMAGE_NT_SIGNATURE) 442 | dr_fprintf(STDERR, "NT signature not correct\n"); 443 | 444 | /* Set optional header */ 445 | dump_pe_header.pOptHeader = (PIMAGE_OPTIONAL_HEADER) 446 | &(dump_pe_header.pNtHeader->OptionalHeader); 447 | 448 | /* Set file header */ 449 | dump_pe_header.pFileHeader = (PIMAGE_FILE_HEADER) 450 | &(dump_pe_header.pNtHeader->FileHeader); 451 | 452 | if (dump_pe_header.pFileHeader == NULL) 453 | dr_fprintf(STDERR, "File header == NULL"); 454 | 455 | /* Set section header */ 456 | dump_pe_header.pSectHeader = (PIMAGE_SECTION_HEADER) 457 | ((unsigned long)dump_pe_header.pNtHeader + 458 | sizeof(IMAGE_NT_HEADERS)); 459 | 460 | 461 | return 1; 462 | } 463 | 464 | 465 | int 466 | write_process_image(unsigned int new_entry_point) 467 | { 468 | HANDLE snapshot; 469 | MODULEENTRY32 module; 470 | FILE *image; 471 | char entire_dump_name[255]; 472 | byte *memory_dump; 473 | unsigned int import_section_size; 474 | unsigned int total_size; 475 | 476 | snapshot = CreateToolhelp32Snapshot(0x08, 0x00); 477 | 478 | if (snapshot != INVALID_HANDLE_VALUE) 479 | { 480 | module.dwSize = sizeof(MODULEENTRY32); 481 | 482 | // Get main module 483 | if (Module32First(snapshot, &module)) 484 | { 485 | 486 | if (module.modBaseSize != 0xffffffff) 487 | { 488 | 489 | module_base_address = (unsigned int)module.modBaseAddr; 490 | module_base_size = (unsigned int) module.modBaseSize; 491 | 492 | // Name of the file we dump to. 493 | sprintf(entire_dump_name, ".\\Refactor_output\\entire_unpacked-%d", dump_wave); 494 | 495 | // Size of the new import section. 496 | import_section_size = new_import_section_size_definition; 497 | 498 | // Size of the copied module + size of new import section 499 | total_size = module.modBaseSize + import_section_size; 500 | 501 | // Allocate space for the copied module. 502 | memory_dump = dr_global_alloc(total_size); 503 | 504 | if (memory_dump == 0) 505 | { 506 | dr_fprintf(STDERR, "error when allocating space for copy of memory\n"); 507 | exit(1); 508 | } 509 | 510 | 511 | // Copy main module into our newly allocated space. 512 | memcpy(memory_dump, module.modBaseAddr, module.modBaseSize); 513 | 514 | Set_PE_header(memory_dump); 515 | 516 | // Set the section headers' PointerToRawData and SizeOfRawData 517 | // to be equal that which it is in virtual memory. This is because 518 | // we dump the image as it looks like in memory. 519 | configure_section_offsets(memory_dump, (unsigned int)module.modBaseAddr); 520 | 521 | // Set entry point of module to be equal the first instruction in our 522 | // dynamically generated code. 523 | 524 | /* 525 | * In the experiments of the paper we actually sat the entry point. 526 | * However, we later observed this not to be the best choice and 527 | * instead do not do it now. 528 | */ 529 | //write_entry_point(new_entry_point, (unsigned int)module.modBaseAddr, memory_dump); 530 | 531 | // Write the new import section to the image, extending the size of it. 532 | write_new_section(memory_dump, (unsigned int) module.modBaseAddr); 533 | 534 | /* Open the file we dump to. */ 535 | image = fopen(entire_dump_name, "wb"); 536 | 537 | // Write the memory to file 538 | fwrite(memory_dump, total_size, 1, image); 539 | 540 | fclose(image); 541 | } 542 | } 543 | } 544 | 545 | return 1; 546 | } 547 | 548 | 549 | int 550 | dump_clean() 551 | { 552 | HANDLE snapshot; 553 | MODULEENTRY32 module; 554 | FILE *image; 555 | char entire_dump_name[255]; 556 | byte *memory_dump; 557 | unsigned int import_section_size; 558 | unsigned int total_size; 559 | 560 | snapshot = CreateToolhelp32Snapshot(0x08, 0x00); 561 | 562 | if (snapshot != INVALID_HANDLE_VALUE) 563 | { 564 | module.dwSize = sizeof(MODULEENTRY32); 565 | 566 | // Get main module 567 | if (Module32First(snapshot, &module)) 568 | { 569 | 570 | if (module.modBaseSize != 0xffffffff) 571 | { 572 | 573 | // Name of the file we dump to. 574 | sprintf(entire_dump_name, ".\\Refactor_output\\entire_unpacked_clean-%d", dump_wave); 575 | 576 | // Size of the copied module + size of new import section 577 | total_size = module.modBaseSize; 578 | 579 | // Allocate space for the copied module. 580 | memory_dump = dr_global_alloc(total_size); 581 | 582 | if (memory_dump == 0) 583 | { 584 | dr_fprintf(STDERR, "error when allocating space for copy of memory\n"); 585 | exit(1); 586 | } 587 | 588 | 589 | // Copy main module into our newly allocated space. 590 | memcpy(memory_dump, module.modBaseAddr, module.modBaseSize); 591 | 592 | Set_PE_header(memory_dump); 593 | 594 | // Set the section headers' PointerToRawData and SizeOfRawData 595 | // to be equal that which it is in virtual memory. This is because 596 | // we dump the image as it looks like in memory. 597 | configure_section_offsets(memory_dump, (unsigned int)module.modBaseAddr); 598 | 599 | /* Open the file we dump to. */ 600 | image = fopen(entire_dump_name, "wb"); 601 | 602 | // Write the memory to file 603 | fwrite(memory_dump, total_size, 1, image); 604 | 605 | fclose(image); 606 | } 607 | } 608 | } 609 | 610 | return 1; 611 | } 612 | 613 | int dump_clean_also = 1; 614 | 615 | void 616 | DumpProcess(unsigned int entry_point) 617 | { 618 | // Get name and exported functions of modules in the process 619 | // The data is inserted in Dll_list 620 | // 621 | /* Keep this call */ 622 | 623 | /* Write exports */ 624 | GetAllDllNames(); 625 | 626 | // Drop the binary and reconstruct import table 627 | write_process_image(entry_point); 628 | 629 | if (dump_clean_also) 630 | { 631 | dump_clean(); 632 | } 633 | 634 | // Increase the wave number 635 | // dump_wave++; 636 | } 637 | 638 | static void 639 | clean_call(void) 640 | { 641 | unsigned int mem_refs; 642 | unsigned int mem_reference; 643 | unsigned int value_being_read; 644 | tls_storage *data; 645 | int i; 646 | void *drcontext; 647 | 648 | drcontext = dr_get_current_drcontext(); 649 | data = (tls_storage *) drmgr_get_tls_field(drcontext, tls_index); 650 | mem_refs = data->number_of_refs; 651 | 652 | 653 | // Branch instructions 654 | if (data->old_pc != 0 && 655 | data->old_pc < (module_base_address+module_base_size) && 656 | data->old_pc > (module_base_address) && 657 | ((data->old_pc + data->old_instr_size) != (unsigned int)data->pc)) 658 | { 659 | char output_line[100]; 660 | int c; 661 | 662 | for (c = 0; c < 100; c++) 663 | output_line[c] = '\0'; 664 | 665 | sprintf(output_line, "W %d B %x to %x\n", 666 | dump_wave, data->old_pc, data->pc); 667 | 668 | write_to_output(output_line, strlen(output_line)); 669 | } 670 | 671 | data->old_pc = (unsigned int)data->pc; 672 | data->old_instr_size = data->instr_size; 673 | 674 | 675 | // Is the instruction part of written memory? 676 | for (i = 0; i < data->instr_size; i++) 677 | { 678 | if (is_in((unsigned int)data->pc + i)) 679 | { 680 | char output_line[60]; 681 | int c; 682 | 683 | dump_wave++; 684 | 685 | for (c = 0; c<60; c++) 686 | { 687 | output_line[c] = '\0'; 688 | } 689 | 690 | 691 | sprintf(output_line, "W %d First executed instruction at "PFX"\n", 692 | dump_wave, data->pc); 693 | 694 | write_wave_and_entrypoint(output_line, strlen(output_line)); 695 | 696 | 697 | 698 | //dr_fprintf(STDERR, "Wave %d detected with entrypoint at "PFX"\n", dump_wave, data->pc); 699 | //dr_printf("Executing dynamically generated code at "PFX"\n", data->pc); 700 | // Clear hashtable of dynamically written memory 701 | delete_all(); 702 | 703 | DumpProcess((unsigned int)data->pc); 704 | 705 | // We only need to capture it once. 706 | break; 707 | } 708 | } 709 | 710 | /* 711 | * Check memory references and insert if necessary 712 | * We can optimize this by instead of having both is_in and insert, rather 713 | * have insert_if_not_in. 714 | * */ 715 | switch(mem_refs) 716 | { 717 | int i; 718 | 719 | case 4: 720 | mem_reference = data->mem_ref4; 721 | for (i = 0; i < data->size_of_mem_write; i++) 722 | if (is_in(mem_reference+i) == 0) insert(mem_reference+i); 723 | case 3: 724 | mem_reference = data->mem_ref3; 725 | for (i = 0; i < data->size_of_mem_write; i++) 726 | if (is_in(mem_reference+i) == 0) insert(mem_reference+i); 727 | case 2: 728 | mem_reference = data->mem_ref2; 729 | for (i = 0; i < data->size_of_mem_write; i++) 730 | if (is_in(mem_reference+i) == 0) insert(mem_reference+i); 731 | case 1: 732 | mem_reference = data->mem_ref1; 733 | for (i = 0; i < data->size_of_mem_write; i++) 734 | if (is_in(mem_reference+i) == 0) insert(mem_reference+i); 735 | } 736 | 737 | 738 | /* Check if it is an indirect reference */ 739 | if (data->reads_memory) 740 | { 741 | if ((unsigned int)data->pc >= module_base_address && \ 742 | (unsigned int)data->pc < (module_base_address+module_base_size)) 743 | { 744 | value_being_read = *(unsigned int*)data->address_being_read; 745 | 746 | // Is address of memory being read inside module? 747 | if (value_being_read <= module_base_address || value_being_read > (module_base_address+module_base_size)) 748 | { 749 | char output_line[50]; 750 | int c; 751 | 752 | for (c=0; c<50; c++) 753 | output_line[c] = '\0'; 754 | 755 | // format: 756 | // wave #num I #instruction_address #address_being_read #value_of_addr_being_read 757 | sprintf(output_line, "W %d I %x %x %x\n", 758 | dump_wave, // Fix 759 | data->pc, 760 | data->address_being_read, 761 | value_being_read); 762 | 763 | write_to_output(output_line, strlen(output_line)); 764 | } 765 | } 766 | } 767 | 768 | /* set reference number to 0 */ 769 | /* ensure you don't have to use drmgr_set_tls_field here */ 770 | data->number_of_refs = 0; 771 | data->reads_memory = 0; 772 | } 773 | 774 | /* 775 | * 776 | * Writes the output_text to the output file. 777 | * Writes "text_length" number of bytes. 778 | * 779 | */ 780 | static void 781 | write_to_output(char *output_text, int text_length) 782 | { 783 | fwrite(output_text, text_length, 1, output_file); 784 | fflush(output_file); 785 | } 786 | 787 | static void 788 | write_wave_and_entrypoint(char *output_text, int text_length) 789 | { 790 | fwrite(output_text, text_length, 1, wave_file); 791 | fflush(wave_file); 792 | } 793 | 794 | /* 795 | * 796 | * End of analysis 797 | * 798 | */ 799 | static void 800 | event_exit(void) 801 | { 802 | // Close the output file 803 | fclose(output_file); 804 | 805 | // Close the wave file 806 | fclose(wave_file); 807 | } 808 | 809 | DR_EXPORT void 810 | dr_client_main(client_id_t id, int argc, const char *argv[]) 811 | { 812 | int i; 813 | 814 | global_count = 0; 815 | dump_wave = 0; 816 | 817 | /* if we can't print, then return */ 818 | if (!dr_enable_console_printing()) 819 | return; 820 | 821 | 822 | /* init hash table */ 823 | for (i = 0; i < SIZE; i++) 824 | { 825 | hashtable[i] = NULL; 826 | } 827 | 828 | dr_set_client_name("DynamoRIO Sample Client 'memtrace'", 829 | "http://dynamorio.org/issues"); 830 | 831 | 832 | /* initialize manager and util */ 833 | if (!drmgr_init() || !drutil_init()) 834 | DR_ASSERT(false); 835 | 836 | dr_register_exit_event(event_exit); 837 | 838 | // setup disassembler 839 | if (cs_open(CS_ARCH_X86, CS_MODE_32, &handle) != CS_ERR_OK) 840 | { 841 | dr_fprintf(STDERR, "Could not initialize disassembler\n"); 842 | DR_ASSERT(false); 843 | } 844 | 845 | // Open output file 846 | output_file = fopen(".\\Refactor_output\\trace_output", "w"); 847 | if (output_file == NULL) 848 | { 849 | dr_fprintf(STDERR, "Error opening output file\n"); 850 | exit(1); 851 | } 852 | 853 | wave_file = fopen(".\\Refactor_output\\wave_entrypoints", "w"); 854 | if (wave_file == NULL) 855 | { 856 | dr_fprintf(STDERR, "Error opening wave file\n"); 857 | exit(1); 858 | } 859 | 860 | /* we must call our initialization events */ 861 | if (!drmgr_register_thread_init_event(event_thread_init) || 862 | !drmgr_register_thread_exit_event(event_thread_exit)) 863 | DR_ASSERT(false); 864 | 865 | // Instrumentation 866 | if (!drmgr_register_bb_app2app_event(event_bb_app2app, NULL) || 867 | !drmgr_register_bb_instrumentation_event(event_bb_analysis, 868 | event_bb_insert, 869 | NULL)) 870 | { 871 | DR_ASSERT(false); 872 | return; 873 | } 874 | 875 | /* initialize TLS */ 876 | tls_index = drmgr_register_tls_field(); 877 | DR_ASSERT(tls_index != -1); 878 | } 879 | 880 | static void 881 | event_thread_init(void *drcontext) 882 | { 883 | tls_storage *data; 884 | 885 | data = dr_thread_alloc(drcontext, sizeof(tls_storage)); 886 | 887 | drmgr_set_tls_field(drcontext, tls_index, data); 888 | dr_printf("Thread init\n"); 889 | } 890 | 891 | static void 892 | event_thread_exit(void *drcontext) 893 | { 894 | tls_storage *data; 895 | 896 | data = drmgr_get_tls_field(drcontext, tls_index); 897 | 898 | dr_thread_free(drcontext, data, sizeof(tls_storage)); 899 | dr_printf("Thread exit\n"); 900 | } 901 | 902 | /* we transform string loops into regular loops so we can more easily 903 | * monitor every memory reference they make 904 | */ 905 | static dr_emit_flags_t 906 | event_bb_app2app(void *drcontext, void *tag, instrlist_t *bb, 907 | bool for_trace, bool translating) 908 | { 909 | //if (!drutil_expand_rep_string(drcontext, bb)) { 910 | // DR_ASSERT(false); 911 | /* in release build, carry on: we'll just miss per-iter refs */ 912 | //} 913 | return DR_EMIT_DEFAULT; 914 | } 915 | 916 | 917 | // Do nothing 918 | static dr_emit_flags_t 919 | event_bb_analysis(void *drcontext, void *tag, instrlist_t *bb, 920 | bool for_trace, bool translating, 921 | OUT void **user_data) 922 | { 923 | return DR_EMIT_DEFAULT; 924 | } 925 | 926 | /* 927 | * 928 | * Main instrumentation function. 929 | * 930 | */ 931 | static dr_emit_flags_t 932 | event_bb_insert(void *drcontext, void *tag, instrlist_t *bb, instr_t *instr, 933 | bool for_trace, bool translating, 934 | OUT void **user_data) 935 | { 936 | int i; 937 | int memory_references, total_refs; 938 | int instruction_opcode; 939 | int indirect_call = 0; 940 | int bytes_occupied; 941 | 942 | // Capstone stuff 943 | cs_insn *insn; 944 | unsigned int size; 945 | int count; 946 | 947 | if (!instr_is_app(instr)) 948 | return DR_EMIT_DEFAULT; 949 | 950 | memory_references = 0; 951 | total_refs = 0; 952 | 953 | if (instr_get_app_pc(instr) == NULL) 954 | return DR_EMIT_DEFAULT; 955 | 956 | instruction_opcode = instr_get_opcode(instr); 957 | 958 | // Instrumentation for getting the readings of indirect references 959 | if (instr_reads_memory(instr)) 960 | { 961 | //dr_printf("It reads memory\n"); 962 | if (opnd_is_memory_reference(instr_get_src(instr, 0))) 963 | { 964 | instrument_read_memory(drcontext, bb, instr, 0); 965 | instrument_set_value(drcontext, bb, instr, 966 | (int) 1, offsetof(tls_storage, reads_memory)); 967 | indirect_call = 1; 968 | } 969 | } 970 | 971 | 972 | // Instrumentation for getting the addresses being written 973 | if (instr_writes_memory(instr)) 974 | { 975 | unsigned int write_size; 976 | 977 | // How many writes do we have in all 978 | for (i = 0; i < instr_num_dsts(instr); i++) 979 | { 980 | if (opnd_is_memory_reference(instr_get_dst(instr, i))) 981 | total_refs++; 982 | } 983 | 984 | // Instrument each write 985 | for (i = 0; i < instr_num_dsts(instr); i++) 986 | { 987 | if (opnd_is_memory_reference(instr_get_dst(instr, i))) 988 | { 989 | // i = operand number 990 | // memory_reference = the operand number which is a memory reference 991 | instrument_mem(drcontext, bb, instr, i, true, memory_references); 992 | memory_references++; 993 | } 994 | } 995 | 996 | // Write size of the memory written 997 | write_size = instr_memory_reference_size(instr); 998 | 999 | instrument_set_value(drcontext, bb, instr, 1000 | (int)write_size, offsetof(tls_storage, size_of_mem_write)); 1001 | } 1002 | 1003 | // Save the number of addresses the instruction writes to. 1004 | instrument_set_value(drcontext, bb, instr, 1005 | (int) total_refs, offsetof(tls_storage, number_of_refs)); 1006 | 1007 | // Save the address of the instruction 1008 | instrument_set_value(drcontext, bb, instr, 1009 | (int)instr_get_app_pc(instr), offsetof(tls_storage, pc)); 1010 | 1011 | // Save the size of the instruction 1012 | // We use capstone to disassemble 1013 | count = cs_disasm(handle, instr_get_app_pc(instr), 15, (unsigned int)instr_get_app_pc(instr), 0, &insn); 1014 | if (count > 0) 1015 | { 1016 | size = (insn[0].size & 0xffff); 1017 | instrument_set_value(drcontext, bb, instr, 1018 | size, offsetof(tls_storage, instr_size)); 1019 | //dr_printf("0x%llx\t%s\t%s\t%u\n", 1020 | // insn[0].address, 1021 | // insn[0].mnemonic, 1022 | // insn[0].op_str, 1023 | // (insn[0].size & 0xffff)); 1024 | } 1025 | 1026 | dr_insert_clean_call(drcontext, bb, instr, (void *)clean_call, true, 0); 1027 | 1028 | return DR_EMIT_DEFAULT; 1029 | } 1030 | 1031 | 1032 | /* 1033 | * 1034 | * Writes a value to a field in a TLS structure. 1035 | * The field is indicated by offset. 1036 | * The value is given by value. 1037 | * 1038 | * 1039 | * param ilist : basic block where instruction to instrument is 1040 | * param where : instruction to instrument 1041 | * param offset : offset of field in tls structure we are writing to 1042 | * param value : value to be written in tls field. 1043 | * 1044 | */ 1045 | static void instrument_set_value( 1046 | void *drcontext, instrlist_t *ilist, instr_t *where, 1047 | int value, unsigned int offset) 1048 | { 1049 | tls_storage *data; 1050 | reg_id_t reg1 = DR_REG_XBX; 1051 | reg_id_t reg2 = DR_REG_XCX; 1052 | opnd_t ref; 1053 | opnd_t opnd1, opnd2; 1054 | 1055 | 1056 | dr_save_reg(drcontext, ilist, where, reg1, SPILL_SLOT_2); 1057 | dr_save_reg(drcontext, ilist, where, reg2, SPILL_SLOT_3); 1058 | 1059 | // Instrumentation for writing "reads_memory" value into 1060 | // LTS->reads_memory 1061 | drmgr_insert_read_tls_field(drcontext, tls_index, ilist, where, reg2); 1062 | 1063 | opnd1 = OPND_CREATE_MEM32(reg2, offset); 1064 | opnd2 = OPND_CREATE_INT32(value); 1065 | 1066 | instrlist_meta_preinsert(ilist, where, 1067 | INSTR_CREATE_mov_imm(drcontext, opnd1, opnd2)); 1068 | 1069 | dr_restore_reg(drcontext, ilist, where, reg1, SPILL_SLOT_2); 1070 | dr_restore_reg(drcontext, ilist, where, reg2, SPILL_SLOT_3); 1071 | 1072 | } 1073 | 1074 | /* 1075 | * Add instrumentation to read the value of the memory 1076 | * address given by the "pos" operand in instruction 1077 | * "where" in the basic block ilist. 1078 | * The value is stored in the TLS struct at "address_being_read" field 1079 | * 1080 | * param pos : the position of operand to be read 1081 | * param ilist : the basic block with instruction to be instrumented 1082 | * param where : the instruction the be instrumented 1083 | * 1084 | */ 1085 | static void instrument_read_memory(void *drcontext, instrlist_t *ilist, instr_t *where, 1086 | int pos) 1087 | { 1088 | tls_storage *data; 1089 | reg_id_t reg1 = DR_REG_XBX; 1090 | reg_id_t reg2 = DR_REG_XCX; 1091 | app_pc pc; 1092 | opnd_t ref; 1093 | opnd_t opnd1, opnd2; 1094 | 1095 | /* useless call, but they have something similar in memtrace_x86 */ 1096 | // data = drmgr_get_tls_field(drcontext, tls_index); 1097 | 1098 | dr_save_reg(drcontext, ilist, where, reg1, SPILL_SLOT_2); 1099 | dr_save_reg(drcontext, ilist, where, reg2, SPILL_SLOT_3); 1100 | 1101 | /* read the memory reference */ 1102 | ref = instr_get_src(where, pos); 1103 | 1104 | /* put memory address being read into reg1 */ 1105 | drutil_insert_get_mem_addr(drcontext, ilist, where, ref, reg1, reg2); 1106 | opnd1 = opnd_create_reg(reg1); 1107 | 1108 | /* read TLS field into reg2 */ 1109 | drmgr_insert_read_tls_field(drcontext, tls_index, ilist, where, reg2); 1110 | 1111 | /* read the field */ 1112 | instrlist_meta_preinsert(ilist, where, 1113 | INSTR_CREATE_mov_st(drcontext, 1114 | OPND_CREATE_MEMPTR(reg2, offsetof(tls_storage, address_being_read)), 1115 | opnd1)); 1116 | 1117 | dr_restore_reg(drcontext, ilist, where, reg1, SPILL_SLOT_2); 1118 | dr_restore_reg(drcontext, ilist, where, reg2, SPILL_SLOT_3); 1119 | } 1120 | 1121 | 1122 | 1123 | /* 1124 | * 1125 | * Read the memory address holding by instruction "where" with 1126 | * operand "pos" into the mem_refX field in the LTS struct, 1127 | * where X is the number indicated by memory_reference. 1128 | * 1129 | * param ilist : basic block where instruction to be instrumented is 1130 | * param where : instruction to be instrumented 1131 | * param pos : position of operand that contains the address being 1132 | * written to. 1133 | * param write : NOT USED ANYMORE 1134 | * param memory_reference : the number mem_refX the written address 1135 | is written to in our LTS struct. 1136 | * 1137 | */ 1138 | static void instrument_mem(void *drcontext, instrlist_t *ilist, instr_t *where, 1139 | int pos, bool write, int memory_reference) 1140 | { 1141 | tls_storage *data; 1142 | reg_id_t reg1 = DR_REG_XBX; 1143 | reg_id_t reg2 = DR_REG_XCX; 1144 | app_pc pc; 1145 | opnd_t ref; 1146 | opnd_t opnd1, opnd2; 1147 | 1148 | if (memory_reference > 3) 1149 | { 1150 | dr_printf("Memory reference too large\n"); 1151 | DR_ASSERT(0); 1152 | } 1153 | 1154 | /* useless call, but they have something similar in memtrace_x86 */ 1155 | // data = drmgr_get_tls_field(drcontext, tls_index); 1156 | 1157 | dr_save_reg(drcontext, ilist, where, reg1, SPILL_SLOT_2); 1158 | dr_save_reg(drcontext, ilist, where, reg2, SPILL_SLOT_3); 1159 | 1160 | /* read the first memory reference */ 1161 | ref = instr_get_dst(where, pos); 1162 | 1163 | /* put memory address being written into reg1 */ 1164 | drutil_insert_get_mem_addr(drcontext, ilist, where, ref, reg1, reg2); 1165 | opnd1 = opnd_create_reg(reg1); 1166 | 1167 | /* read TLS field into reg2 */ 1168 | drmgr_insert_read_tls_field(drcontext, tls_index, ilist, where, reg2); 1169 | 1170 | /* read the field */ 1171 | if (memory_reference == 0) 1172 | { 1173 | instrlist_meta_preinsert(ilist, where, 1174 | INSTR_CREATE_mov_st(drcontext, 1175 | OPND_CREATE_MEMPTR(reg2, offsetof(tls_storage, mem_ref1)), 1176 | opnd1)); 1177 | } 1178 | else if (memory_reference == 1) 1179 | { 1180 | instrlist_meta_preinsert(ilist, where, 1181 | INSTR_CREATE_mov_st(drcontext, 1182 | OPND_CREATE_MEMPTR(reg2, offsetof(tls_storage, mem_ref2)), 1183 | opnd1)); 1184 | } 1185 | else if (memory_reference == 2) 1186 | { 1187 | instrlist_meta_preinsert(ilist, where, 1188 | INSTR_CREATE_mov_st(drcontext, 1189 | OPND_CREATE_MEMPTR(reg2, offsetof(tls_storage, mem_ref3)), 1190 | opnd1)); 1191 | } 1192 | else if (memory_reference == 3) 1193 | { 1194 | instrlist_meta_preinsert(ilist, where, 1195 | INSTR_CREATE_mov_st(drcontext, 1196 | OPND_CREATE_MEMPTR(reg2, offsetof(tls_storage, mem_ref4)), 1197 | opnd1)); 1198 | } 1199 | 1200 | dr_restore_reg(drcontext, ilist, where, reg1, SPILL_SLOT_2); 1201 | dr_restore_reg(drcontext, ilist, where, reg2, SPILL_SLOT_3); 1202 | } 1203 | 1204 | // Capstone needs this, otherwise it complains 1205 | __declspec(noreturn) void __cdecl __report_rangecheckfailure(void) 1206 | { 1207 | exit(1); 1208 | } 1209 | -------------------------------------------------------------------------------- /Tracer/unpacker.h: -------------------------------------------------------------------------------- 1 | static dr_emit_flags_t event_bb_analysis(void *drcontext, void *tag, instrlist_t *bb, 2 | bool for_trace, bool translating, 3 | OUT void **user_data); 4 | 5 | static dr_emit_flags_t 6 | event_bb_insert(void *drcontext, void *tag, instrlist_t *bb, instr_t *instr, 7 | bool for_trace, bool translating, 8 | OUT void **user_data); 9 | 10 | static void instrument_mem(void *drcontext, instrlist_t *ilist, instr_t *where, 11 | int pos, bool write, int memory_reference); 12 | 13 | static void instrument_read_memory(void *drcontext, instrlist_t *ilist, instr_t *where, int pos); 14 | 15 | static void 16 | write_to_output(char *output_text, int text_length); 17 | 18 | static void 19 | write_wave_and_entrypoint(char *output_text, int text_length); 20 | 21 | static void 22 | event_thread_init(void *drcontext); 23 | 24 | static void 25 | event_thread_exit(void *drcontext); 26 | 27 | static dr_emit_flags_t 28 | event_bb_app2app(void *drcontext, void *tag, instrlist_t *bb, 29 | bool for_trace, bool translating); 30 | 31 | 32 | static void instrument_set_value( 33 | void *drcontext, instrlist_t *ilist, instr_t *where, 34 | int value, unsigned int offset); 35 | --------------------------------------------------------------------------------