1 | #include <stdio.h> |
---|
2 | #include <stdlib.h> |
---|
3 | #include <unistd.h> |
---|
4 | #include <malloc.h> |
---|
5 | #include <signal.h> |
---|
6 | #include <string.h> |
---|
7 | #include <setjmp.h> |
---|
8 | #include <assert.h> |
---|
9 | #include <sys/mman.h> |
---|
10 | |
---|
11 | #define MAGIC 0xfeedbeef |
---|
12 | #define PAGE_SIZE getpagesize() |
---|
13 | #define ALIGN(X,A) ((X) - (((unsigned long) (X)) % (A))) |
---|
14 | |
---|
15 | unsigned char load_asm[] = { |
---|
16 | /* 080483c4 <plain_c>: */ |
---|
17 | /* 80483c4: 55 push %ebp */ |
---|
18 | /* 80483c5: 89 e5 mov %esp,%ebp */ |
---|
19 | /* 80483c7: b8 ef be ed fe mov $0xfeedbeef,%eax */ |
---|
20 | /* 80483cc: 5d pop %ebp */ |
---|
21 | /* 80483cd: c3 ret */ |
---|
22 | |
---|
23 | /* Really we just need the mov and ret. Saving %ebp is unnecessary |
---|
24 | since we're not going to change it. */ |
---|
25 | 0xb8, 0xef, 0xbe, 0xed, 0xfe, /* mov */ |
---|
26 | 0xc3 /* ret */ |
---|
27 | }; |
---|
28 | |
---|
29 | int plain_c() |
---|
30 | { |
---|
31 | return MAGIC; |
---|
32 | } |
---|
33 | |
---|
34 | int plain_asm() |
---|
35 | { |
---|
36 | volatile int result; |
---|
37 | __asm__("movl %1, %0" : "=r" (result) : "i" (MAGIC)); |
---|
38 | return result; |
---|
39 | } |
---|
40 | |
---|
41 | sigjmp_buf segv_env; |
---|
42 | struct sigaction old_segv; |
---|
43 | |
---|
44 | void sig_segv(int sig) |
---|
45 | { |
---|
46 | siglongjmp(segv_env, 1); |
---|
47 | } |
---|
48 | |
---|
49 | int segv_guard() |
---|
50 | { |
---|
51 | struct sigaction our_segv; |
---|
52 | int seen_segv = 0; |
---|
53 | |
---|
54 | our_segv.sa_handler = sig_segv; |
---|
55 | our_segv.sa_flags = 0; |
---|
56 | sigemptyset(&our_segv.sa_mask); |
---|
57 | |
---|
58 | sigaction(SIGSEGV, &our_segv, &old_segv); |
---|
59 | seen_segv = sigsetjmp(segv_env, 1); |
---|
60 | |
---|
61 | if (seen_segv) { |
---|
62 | sigaction(SIGSEGV, &old_segv, NULL); |
---|
63 | return 1; |
---|
64 | } |
---|
65 | |
---|
66 | return 0; |
---|
67 | } |
---|
68 | |
---|
69 | void segv_unguard() |
---|
70 | { |
---|
71 | sigaction(SIGSEGV, &old_segv, NULL); |
---|
72 | } |
---|
73 | |
---|
74 | int call_mem(void *mem) |
---|
75 | { |
---|
76 | register int *eax __asm("%eax"); |
---|
77 | int result; |
---|
78 | |
---|
79 | if (segv_guard()) |
---|
80 | return 0; |
---|
81 | |
---|
82 | __asm__("call *%1" : "=r" (eax) : "g"(mem)); |
---|
83 | result = (int) eax; |
---|
84 | |
---|
85 | segv_unguard(); |
---|
86 | |
---|
87 | return result; |
---|
88 | } |
---|
89 | |
---|
90 | int indirect_c() |
---|
91 | { |
---|
92 | return call_mem(plain_c); |
---|
93 | } |
---|
94 | |
---|
95 | int indirect_asm() |
---|
96 | { |
---|
97 | return call_mem(plain_asm); |
---|
98 | } |
---|
99 | |
---|
100 | int asm_text() |
---|
101 | { |
---|
102 | mprotect(ALIGN(load_asm, PAGE_SIZE), PAGE_SIZE, |
---|
103 | PROT_READ|PROT_WRITE|PROT_EXEC); |
---|
104 | return call_mem(load_asm); |
---|
105 | } |
---|
106 | |
---|
107 | int asm_stack() |
---|
108 | { |
---|
109 | unsigned char buf[sizeof(load_asm)]; |
---|
110 | memcpy(buf, load_asm, sizeof(load_asm)); |
---|
111 | mprotect(ALIGN(buf, PAGE_SIZE), PAGE_SIZE, PROT_READ|PROT_WRITE|PROT_EXEC); |
---|
112 | return call_mem(buf); |
---|
113 | } |
---|
114 | |
---|
115 | int asm_heap() |
---|
116 | { |
---|
117 | unsigned char *buf = memalign(PAGE_SIZE, PAGE_SIZE); |
---|
118 | int result; |
---|
119 | assert(buf); |
---|
120 | memcpy(buf, load_asm, sizeof(load_asm)); |
---|
121 | mprotect(buf, PAGE_SIZE, PROT_READ|PROT_EXEC); |
---|
122 | result = call_mem(buf); |
---|
123 | free(buf); |
---|
124 | return result; |
---|
125 | } |
---|
126 | |
---|
127 | int asm_mmap_rw() |
---|
128 | { |
---|
129 | int result; |
---|
130 | unsigned char *buf = mmap(NULL, sizeof(load_asm), |
---|
131 | PROT_EXEC|PROT_READ|PROT_WRITE, |
---|
132 | MAP_SHARED|MAP_ANONYMOUS, |
---|
133 | -1, 0); |
---|
134 | if (buf == MAP_FAILED) |
---|
135 | return 0; |
---|
136 | |
---|
137 | memcpy(buf, load_asm, sizeof(load_asm)); |
---|
138 | result = call_mem(buf); |
---|
139 | munmap(buf, sizeof(load_asm)); |
---|
140 | return result; |
---|
141 | } |
---|
142 | |
---|
143 | int asm_mmap_chg() |
---|
144 | { |
---|
145 | int result; |
---|
146 | unsigned char *buf = mmap(NULL, sizeof(load_asm), |
---|
147 | PROT_READ|PROT_WRITE, |
---|
148 | MAP_SHARED|MAP_ANONYMOUS, |
---|
149 | -1, 0); |
---|
150 | if (buf == MAP_FAILED) |
---|
151 | return 0; |
---|
152 | |
---|
153 | memcpy(buf, load_asm, sizeof(load_asm)); |
---|
154 | mprotect(buf, sizeof(load_asm), PROT_READ|PROT_EXEC); |
---|
155 | result = call_mem(buf); |
---|
156 | munmap(buf, sizeof(load_asm)); |
---|
157 | return result; |
---|
158 | } |
---|
159 | |
---|
160 | int main() |
---|
161 | { |
---|
162 | #define ok(X) ((X) == MAGIC ? "ok" : "FAILURE") |
---|
163 | |
---|
164 | printf("plain_c = %s\n", ok(plain_c())); |
---|
165 | printf("plain_asm = %s\n", ok(plain_asm())); |
---|
166 | printf("indirect_c = %s\n", ok(indirect_c())); |
---|
167 | printf("indirect_asm = %s\n", ok(indirect_asm())); |
---|
168 | printf("asm_text = %s\n", ok(asm_text())); |
---|
169 | printf("asm_stack = %s\n", ok(asm_stack())); |
---|
170 | printf("asm_heap = %s\n", ok(asm_heap())); |
---|
171 | printf("asm_mmap_rw = %s\n", ok(asm_mmap_rw())); |
---|
172 | printf("asm_mmap_chg = %s\n", ok(asm_mmap_chg())); |
---|
173 | |
---|
174 | return 0; |
---|
175 | } |
---|