1 : // Copyright 2012 Google Inc. All Rights Reserved.
2 : //
3 : // Licensed under the Apache License, Version 2.0 (the "License");
4 : // you may not use this file except in compliance with the License.
5 : // You may obtain a copy of the License at
6 : //
7 : // http://www.apache.org/licenses/LICENSE-2.0
8 : //
9 : // Unless required by applicable law or agreed to in writing, software
10 : // distributed under the License is distributed on an "AS IS" BASIS,
11 : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : // See the License for the specific language governing permissions and
13 : // limitations under the License.
14 :
15 : #include "syzygy/pe/test_dll.h"
16 :
17 : #include <windows.h> // NOLINT
18 : #include <objbase.h> // NOLINT
19 : #include <winnt.h> // NOLINT
20 :
21 : #include <math.h>
22 : #include <stdio.h>
23 : #include <time.h>
24 :
25 : #include <cstdlib>
26 :
27 : #include "base/basictypes.h"
28 :
29 : // Bring in a data import from export_dll.dll. This will cause a global data
30 : // symbol to be emitted pointing to the import entry, but with the type we give
31 : // here. If the type is bigger than the entire import table then the data
32 : // symbol will be bigger than the block it resolves to. The data must be
33 : // explicitly marked dllimport otherwise the linker will treat it as a code
34 : // symbol and create a thunk for it.
35 m : __declspec(dllimport) extern int kExportedData[1024];
36 :
37 : // A handful of TLS variables, to cause TLS fixups to appear.
38 m : __declspec(thread) int tls_int = 42;
39 m : __declspec(thread) int tls_array[64] = { 0 };
40 m : __declspec(thread) char tls_string_buffer[512] = { 0 };
41 m : __declspec(thread) double tls_double = 3.5;
42 :
43 : // A dummy TLS Initialization callback handler.
44 m : VOID NTAPI MyTlsCallback(PVOID instance, DWORD reason, PVOID reserved) {
45 m : ::time(NULL);
46 m : }
47 :
48 : // Declare a TLS initializer callback to the linker.
49 : #pragma section(".CRT$XLY",long,read)
50 m : extern "C" __declspec(allocate(".CRT$XLY"))
51 m : PIMAGE_TLS_CALLBACK _xl_y1 = MyTlsCallback;
52 :
53 m : extern "C" __declspec(allocate(".CRT$XLY"))
54 m : PIMAGE_TLS_CALLBACK _xl_y2 = MyTlsCallback;
55 :
56 : // Use both mechanisms for importing functions (explicitly hinted with
57 : // 'dllimport' and not) so that both code generation mechanisms are present
58 : // in the final binary and subsequently tested by our decomposer.
59 m : __declspec(dllimport) extern int function1();
60 m : extern int function2();
61 m : extern int function3();
62 :
63 : // Import coverage functions.
64 m : extern int coverage_func1();
65 m : extern int coverage_func2();
66 m : extern int coverage_func3();
67 :
68 : #pragma auto_inline(off)
69 :
70 m : DWORD WINAPI TestExport(size_t buf_len, char* buf) {
71 m : static const char kTestString[] =
72 m : "The quick brown fox jumped over the lazy dog";
73 :
74 m : ::strncpy(buf, kTestString, buf_len);
75 :
76 m : return 0;
77 m : }
78 :
79 m : DWORD WINAPI BringInOle32DelayLib() {
80 : // Reference this from Ole32 to pull in something.
81 m : GUID guid = {};
82 m : ::CoCreateGuid(&guid);
83 :
84 m : return 0;
85 m : }
86 :
87 m : const char* BoolToString(bool value) {
88 m : return value ? "true" : "false";
89 m : }
90 :
91 m : int FunctionWithInlineAssembly() {
92 m : static int datum = 0;
93 m : __asm {
94 m : mov eax, [datum];
95 m : add eax, 1;
96 m : mov [datum], eax;
97 m : }
98 m : return datum;
99 m : }
100 :
101 : #pragma auto_inline()
102 :
103 m : BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved) {
104 : // The goal of the following weird code is to thwart any optimizations
105 : // that the compiler might try.
106 :
107 : // Put a series of calls in order. In general, expect they'll show up in
108 : // the same order when we search for references.
109 m : function1();
110 m : function1();
111 m : function3();
112 m : function2();
113 m : function2();
114 m : function3();
115 m : function1();
116 m : function1();
117 :
118 m : int foo = FunctionWithInlineAssembly();
119 m : foo += kExportedData[0];
120 :
121 : // We modify the exported data. If imports are improperly thunked this will
122 : // cause us to write junk all over any created thunks and should hopefully
123 : // cause the instrumented test_dll to explode.
124 m : for (size_t i = 0; i < sizeof(kExportedData) / sizeof(kExportedData[0]); ++i)
125 m : kExportedData[i] = i;
126 :
127 : // The following odd code and switch statement are to outsmart the
128 : // optimizer and coerce it to generate a case and jump table pair.
129 : // On decomposition, we expect to find and label the case and jump
130 : // tables individually.
131 m : wchar_t c = rand() % static_cast<wchar_t>(-1);
132 :
133 : // We also need to coerce the optimizer into keeping around kExportedData and
134 : // FunctionWithInlineAssembly.
135 m : c ^= static_cast<wchar_t>(foo);
136 :
137 m : bool is_whitespace = false;
138 m : bool is_qwerty = false;
139 m : bool is_asdfgh = false;
140 m : bool is_upper_case = false;
141 m : bool is_other = false;
142 :
143 : // Switch over the UTF16 character space.
144 m : switch (c) {
145 m : case L'Q':
146 m : case L'W':
147 m : case L'E':
148 m : case L'R':
149 m : case L'T':
150 m : case L'Y':
151 m : is_qwerty = true;
152 m : is_upper_case = true;
153 m : break;
154 :
155 m : case L'q':
156 m : case L'w':
157 m : case L'e':
158 m : case L'r':
159 m : case L't':
160 m : case L'y':
161 m : is_qwerty = true;
162 m : is_upper_case = false;
163 m : break;
164 :
165 m : case L'A':
166 m : case L'S':
167 m : case L'D':
168 m : case L'F':
169 m : case L'G':
170 m : case L'H':
171 m : is_asdfgh = true;
172 m : is_upper_case = true;
173 m : break;
174 :
175 m : case L'a':
176 m : case L's':
177 m : case L'd':
178 m : case L'f':
179 m : case L'g':
180 m : case L'h':
181 m : is_asdfgh = true;
182 m : is_upper_case = false;
183 m : break;
184 :
185 m : case ' ':
186 m : case '\t':
187 m : case '\r':
188 m : case '\n':
189 m : is_whitespace = true;
190 m : break;
191 :
192 m : default:
193 m : is_other = true;
194 m : break;
195 m : }
196 :
197 m : char buffer[1024] = {'\0'};
198 m : ::memset(buffer, 0, sizeof(buffer));
199 m : ::_snprintf(buffer,
200 m : sizeof(buffer) - 1,
201 m : "is_qwerty=%s\nis_asdfgh=%s\nis_upper_case=%s\nis_whitespace=%s\n"
202 m : "is_other=%s",
203 m : BoolToString(is_qwerty),
204 m : BoolToString(is_asdfgh),
205 m : BoolToString(is_upper_case),
206 m : BoolToString(is_whitespace),
207 m : BoolToString(is_other));
208 :
209 m : TestExport(sizeof(buffer), buffer);
210 :
211 : // This code generates a simple jump table with no case table following it.
212 :
213 m : int n = rand();
214 :
215 m : switch (n % 3) {
216 m : case 0:
217 m : n += function1();
218 m : break;
219 m : case 1:
220 m : n += function2();
221 m : break;
222 m : case 2:
223 m : n += function3();
224 m : break;
225 m : case 3:
226 m : n -= function1();
227 m : break;
228 m : case 4:
229 m : n -= function2();
230 m : break;
231 m : case 5:
232 m : n -= function3();
233 m : break;
234 m : }
235 :
236 : // The following odd code and switch statement are to outsmart the
237 : // optimizer and coerce it to generate another case and jump table
238 : // pair. On decomposition, we expect to find and label the case
239 : // and jump tables individually.
240 :
241 : // Access the TLS data so that some TLS FIXUPs are produced.
242 m : n += tls_int;
243 m : n += tls_array[0];
244 m : n += tls_string_buffer[0];
245 m : n += static_cast<int>(tls_double);
246 :
247 : // The case table is a 20X expanded switch on n mod 7.
248 m : switch (n % 140) {
249 m : case 0:
250 m : case 7:
251 m : case 14:
252 m : case 21:
253 m : case 28:
254 m : case 35:
255 m : case 42:
256 m : case 49:
257 m : case 56:
258 m : case 63:
259 m : case 70:
260 m : case 77:
261 m : case 84:
262 m : case 91:
263 m : case 98:
264 m : case 105:
265 m : case 112:
266 m : case 119:
267 m : case 126:
268 m : case 133:
269 m : return reinterpret_cast<BOOL>(
270 m : function1() + strstr("hello world", "hello"));
271 :
272 m : case 1:
273 m : case 8:
274 m : case 15:
275 m : case 22:
276 m : case 29:
277 m : case 36:
278 m : case 43:
279 m : case 50:
280 m : case 57:
281 m : case 64:
282 m : case 71:
283 m : case 78:
284 m : case 85:
285 m : case 92:
286 m : case 99:
287 m : case 106:
288 m : case 113:
289 m : case 120:
290 m : case 127:
291 m : case 134:
292 m : return static_cast<BOOL>(function2() + strlen("foobar"));
293 :
294 m : case 2:
295 m : case 9:
296 m : case 16:
297 m : case 23:
298 m : case 30:
299 m : case 37:
300 m : case 44:
301 m : case 51:
302 m : case 58:
303 m : case 65:
304 m : case 72:
305 m : case 79:
306 m : case 86:
307 m : case 93:
308 m : case 100:
309 m : case 107:
310 m : case 114:
311 m : case 121:
312 m : case 128:
313 m : case 135:
314 m : return static_cast<BOOL>(function3() + clock());
315 :
316 m : case 3:
317 m : case 10:
318 m : case 17:
319 m : case 24:
320 m : case 31:
321 m : case 38:
322 m : case 45:
323 m : case 52:
324 m : case 59:
325 m : case 66:
326 m : case 73:
327 m : case 80:
328 m : case 87:
329 m : case 94:
330 m : case 101:
331 m : case 108:
332 m : case 115:
333 m : case 122:
334 m : case 129:
335 m : case 136:
336 m : return static_cast<BOOL>(function1() + function2() +
337 m : reinterpret_cast<int>(memchr("hello", 'e', 5)));
338 :
339 m : case 4:
340 m : case 11:
341 m : case 18:
342 m : case 25:
343 m : case 32:
344 m : case 39:
345 m : case 46:
346 m : case 53:
347 m : case 60:
348 m : case 67:
349 m : case 74:
350 m : case 81:
351 m : case 88:
352 m : case 95:
353 m : case 102:
354 m : case 109:
355 m : case 116:
356 m : case 123:
357 m : case 130:
358 m : case 137:
359 m : return static_cast<BOOL>(function1() + function3() + abs(-3));
360 :
361 m : case 5:
362 m : case 12:
363 m : case 19:
364 m : case 26:
365 m : case 33:
366 m : case 40:
367 m : case 47:
368 m : case 54:
369 m : case 61:
370 m : case 68:
371 m : case 75:
372 m : case 82:
373 m : case 89:
374 m : case 96:
375 m : case 103:
376 m : case 110:
377 m : case 117:
378 m : case 124:
379 m : case 131:
380 m : case 138:
381 m : return static_cast<BOOL>(
382 m : function2() + function3() + static_cast<int>(floor(1.3)));
383 :
384 m : case 6:
385 m : case 13:
386 m : case 20:
387 m : case 27:
388 m : case 34:
389 m : case 41:
390 m : case 48:
391 m : case 55:
392 m : case 62:
393 m : case 69:
394 m : case 76:
395 m : case 83:
396 m : case 90:
397 m : case 97:
398 m : case 104:
399 m : case 111:
400 m : case 118:
401 m : case 125:
402 m : case 132:
403 m : case 139:
404 m : return static_cast<BOOL>(
405 m : function1() + function2() + function3() + atoi("7"));
406 m : }
407 m : }
408 :
409 m : void used_operation() {
410 m : function1();
411 m : function2();
412 m : function3();
413 m : }
414 :
415 : // This won't be called.
416 m : void unused_operation() {
417 m : char dummy[512];
418 m : TestExport(sizeof(dummy), dummy);
419 m : }
420 :
421 m : class Used {
422 m : public:
423 m : Used() {}
424 m : virtual ~Used() {}
425 m : virtual void M() {
426 m : used_operation();
427 m : }
428 m : };
429 :
430 : // Unused::M() won't be called.
431 m : class Unused : public Used {
432 m : public:
433 m : virtual void M() {
434 m : unused_operation();
435 m : }
436 m : };
437 :
438 m : void CALLBACK TestUnusedFuncs(HWND unused_window,
439 m : HINSTANCE unused_instance,
440 m : LPSTR unused_cmd_line,
441 m : int unused_show) {
442 m : bool call_it = time(NULL) > 10000; // true unless you play with the clock.
443 :
444 m : (call_it ? used_operation : unused_operation)();
445 :
446 m : Used a;
447 m : Unused b;
448 m : (call_it ? &a : &b)->M();
449 m : }
450 :
451 m : DWORD FuncWithOffsetOutOfImage(int x, int y) {
452 m : static const int kArray[4][256] = {};
453 m : static const int kBigNum = 0xB0000000;
454 m : return kArray[x][y + kBigNum];
455 m : }
456 :
457 m : static unsigned int ArrayComputation1() {
458 : // Dummy function to validate end to end instrumentation.
459 m : const size_t kBufferLength = 1024;
460 m : char A[kBufferLength];
461 m : short B[kBufferLength];
462 m : int C[kBufferLength];
463 :
464 m : for (size_t i = 0; i < kBufferLength; ++i) {
465 m : if (i == 0)
466 m : A[i] = 0;
467 m : else
468 m : A[i] = 3*A[i-1] + 11;
469 m : }
470 :
471 m : for (size_t i = 0; i < kBufferLength; ++i) {
472 m : B[i] = i;
473 m : B[i] += A[i];
474 m : B[i] = (B[i] << 1) ^ B[i];
475 m : }
476 :
477 m : for (size_t i = 0; i < kBufferLength; ++i) {
478 m : C[i] = i;
479 m : C[i] += A[i] + B[i];
480 m : C[i] = ~C[i];
481 m : }
482 :
483 m : unsigned int sum = 0;
484 m : for (int i = 0; i < kBufferLength; ++i) {
485 m : sum += C[i] - (A[i] - B[i]);
486 m : }
487 :
488 m : return sum;
489 m : }
490 :
491 m : static unsigned int ArrayComputation2() {
492 : // Dummy function to validate end to end instrumentation.
493 m : const size_t kBufferLength = 1024;
494 m : int A[kBufferLength];
495 :
496 m : for (size_t i = 0; i < kBufferLength; ++i) {
497 m : A[i] = i;
498 m : }
499 :
500 m : int *ptr1 = &A[0];
501 m : int *ptr2 = &A[kBufferLength-1];
502 m : int result = 0;
503 m : while (*ptr1 <= *ptr2) {
504 m : ptr1++;
505 m : ptr2--;
506 m : result++;
507 m : }
508 :
509 m : return result;
510 m : }
511 :
512 : // NOTE: This is used to fool compiler aliasing analysis. Do not make it static
513 : // nor const.
514 m : int kOffsetMinusOne = -1;
515 m : int kOffetZero = 0;
516 m : int kOffetOne = 1;
517 :
518 m : template<typename type>
519 m : static type AsanWriteBufferOverflow() {
520 : // Produce an ASAN error by writing one after the buffer.
521 m : type* ptr = new type[1];
522 m : ptr[kOffetZero] = static_cast<type>(1);
523 m : ptr[kOffetOne] = static_cast<type>(2);
524 m : type result = ptr[kOffetZero];
525 m : delete ptr;
526 m : return result;
527 m : }
528 :
529 m : template<typename type>
530 m : static type AsanWriteBufferUnderflow() {
531 : // Produce an ASAN error by writing one before the buffer.
532 m : type* ptr = new type[1];
533 m : ptr[kOffsetMinusOne] = static_cast<type>(1);
534 m : ptr[kOffetZero] = static_cast<type>(2);
535 m : type result = ptr[kOffetZero];
536 m : delete ptr;
537 m : return result;
538 m : }
539 :
540 m : template<typename type>
541 m : static type AsanReadBufferOverflow() {
542 : // Produce an ASAN error by reading one after the buffer.
543 m : type* ptr = new type[1];
544 m : *ptr = static_cast<type>(42);
545 m : type result = ptr[kOffetZero] + ptr[kOffetOne];
546 m : delete ptr;
547 m : return result;
548 m : }
549 :
550 m : template<typename type>
551 m : static type AsanReadBufferUnderflow() {
552 : // Produce an ASAN error by reading one before the buffer.
553 m : type* ptr = new type[1];
554 m : *ptr = static_cast<type>(42);
555 m : type result = ptr[kOffetZero] + ptr[kOffsetMinusOne];
556 m : delete ptr;
557 m : return result;
558 m : }
559 :
560 m : template<typename type>
561 m : static type AsanReadUseAfterFree() {
562 : // Produce an ASAN error by reading memory after deleting it.
563 m : type* ptr = new type[1];
564 m : *ptr = static_cast<type>(42);
565 m : delete ptr;
566 m : type result = ptr[kOffetZero];
567 m : return result;
568 m : }
569 :
570 m : template<typename type>
571 m : static type AsanWriteUseAfterFree() {
572 : // Produce an ASAN error by writing memory after deleting it.
573 m : type* ptr = new type[1];
574 m : *ptr = static_cast<type>(42);
575 m : type result = *ptr;
576 m : delete ptr;
577 m : ptr[kOffetZero] = static_cast<type>(12);
578 m : return result;
579 m : }
580 :
581 :
582 : // Functions below are used to test basic block counting in the end to end
583 : // unittest. We assume the compiler won't simplify any calls.
584 :
585 : // Avoiding global optimization.
586 : #pragma optimize("g", off)
587 :
588 m : extern "C" unsigned int BBEntryCallOnce() {
589 m : return 42;
590 m : }
591 :
592 m : extern "C" unsigned int BBEntryFunction1() {
593 m : return 10;
594 m : }
595 :
596 m : extern "C" unsigned int BBEntryFunction2() {
597 m : return BBEntryFunction1() + BBEntryFunction1();
598 m : }
599 :
600 m : extern "C" unsigned int BBEntryFunction3() {
601 m : return BBEntryFunction2() + BBEntryFunction2();
602 m : }
603 :
604 m : extern "C" unsigned int BBEntryCallTree() {
605 m : return BBEntryFunction3() + 2;
606 m : }
607 :
608 m : extern "C" unsigned int BBEntryFunctionRecursive(int n) {
609 m : if (n == 1)
610 m : return 1;
611 m : return BBEntryFunctionRecursive(n - 1) + 1;
612 m : }
613 :
614 m : extern "C" unsigned int BBEntryCallRecursive() {
615 m : return BBEntryFunctionRecursive(42);
616 m : }
617 :
618 m : unsigned int CALLBACK EndToEndTest(EndToEndTestId test) {
619 : // This function is used to dispatch test id to its corresponding function.
620 m : switch (test) {
621 : // Behavior tests.
622 m : case kArrayComputation1TestId:
623 m : return ArrayComputation1();
624 m : case kArrayComputation2TestId:
625 m : return ArrayComputation2();
626 :
627 : // Asan Memory Error.
628 m : case kAsanRead8BufferOverflowTestId:
629 m : return AsanReadBufferOverflow<int8>();
630 m : case kAsanRead16BufferOverflowTestId:
631 m : return AsanReadBufferOverflow<int16>();
632 m : case kAsanRead32BufferOverflowTestId:
633 m : return AsanReadBufferOverflow<int32>();
634 m : case kAsanRead64BufferOverflowTestId:
635 m : return AsanReadBufferOverflow<double>();
636 :
637 m : case kAsanRead8BufferUnderflowTestId:
638 m : return AsanReadBufferUnderflow<int8>();
639 m : case kAsanRead16BufferUnderflowTestId:
640 m : return AsanReadBufferUnderflow<int16>();
641 m : case kAsanRead32BufferUnderflowTestId:
642 m : return AsanReadBufferUnderflow<int32>();
643 m : case kAsanRead64BufferUnderflowTestId:
644 m : return AsanReadBufferUnderflow<double>();
645 :
646 m : case kAsanWrite8BufferOverflowTestId:
647 m : return AsanWriteBufferOverflow<int8>();
648 m : case kAsanWrite16BufferOverflowTestId:
649 m : return AsanWriteBufferOverflow<int16>();
650 m : case kAsanWrite32BufferOverflowTestId:
651 m : return AsanWriteBufferOverflow<int32>();
652 m : case kAsanWrite64BufferOverflowTestId:
653 m : return AsanWriteBufferOverflow<double>();
654 :
655 m : case kAsanWrite8BufferUnderflowTestId:
656 m : return AsanWriteBufferUnderflow<int8>();
657 m : case kAsanWrite16BufferUnderflowTestId:
658 m : return AsanWriteBufferUnderflow<int16>();
659 m : case kAsanWrite32BufferUnderflowTestId:
660 m : return AsanWriteBufferUnderflow<int32>();
661 m : case kAsanWrite64BufferUnderflowTestId:
662 m : return AsanWriteBufferUnderflow<double>();
663 :
664 m : case kAsanRead8UseAfterFreeTestId:
665 m : return AsanReadUseAfterFree<int8>();
666 m : case kAsanRead16UseAfterFreeTestId:
667 m : return AsanReadUseAfterFree<int16>();
668 m : case kAsanRead32UseAfterFreeTestId:
669 m : return AsanReadUseAfterFree<int32>();
670 m : case kAsanRead64UseAfterFreeTestId:
671 m : return AsanReadUseAfterFree<double>();
672 :
673 m : case kAsanWrite8UseAfterFreeTestId:
674 m : return AsanWriteUseAfterFree<int8>();
675 m : case kAsanWrite16UseAfterFreeTestId:
676 m : return AsanWriteUseAfterFree<int16>();
677 m : case kAsanWrite32UseAfterFreeTestId:
678 m : return AsanWriteUseAfterFree<int32>();
679 m : case kAsanWrite64UseAfterFreeTestId:
680 m : return AsanWriteUseAfterFree<double>();
681 :
682 m : case kBBEntryCallOnce:
683 m : return BBEntryCallOnce();
684 m : case kBBEntryCallTree:
685 m : return BBEntryCallTree();
686 m : case kBBEntryCallRecursive:
687 m : return BBEntryCallRecursive();
688 :
689 m : case kCoverage1:
690 m : return coverage_func1();
691 m : case kCoverage2:
692 m : return coverage_func2();
693 m : case kCoverage3:
694 m : return coverage_func3();
695 m : }
696 m : return 0;
697 m : }
|