Advertisement
cakemaker

vpgatherqq demo

Oct 22nd, 2024 (edited)
112
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 49.87 KB | Science | 0 0
  1. //
  2. // vpgatherqq.cpp
  3. // Compile with msvc, targetting x64.
  4. //
  5. // @sixtyvividtails, 2024
  6. //
  7. // Demo: using vpgatherqq instruction to cancel impeding pagefault.
  8. // See end of this file for draw.io diagram.
  9. //
  10. // Instruction features:
  11. // ③: catch PAGE_GUARD or invalid access
  12. // ⓪: do previously illegal reads at high IRQL, safely
  13. //
  14. #include <conio.h>
  15. #include <stdio.h>
  16. #include <stdint.h>
  17. #include <immintrin.h>
  18. #include <phnt/phnt.h>  // https://github.com/mrexodia/phnt-single-header
  19. #include <Windows.h>
  20.  
  21.  
  22. //----------------------------------------------------------------------------------------------------------------------
  23. // Constants.
  24. //----------------------------------------------------------------------------------------------------------------------
  25.  
  26. #define PAGE_SIZE                           0x1000
  27. #define PF_AVX2_INSTRUCTIONS_AVAILABLE      40 // 20Hx+
  28. #define KI_USER_SHARED_DATA_R0              0xFFFFF78000000000UI64
  29.  
  30. constexpr int vpgather_instruction_size = 6;
  31. constexpr char long_line[] = "--------------------------------------------------------------------------------"
  32.     "----------------------------------\n";
  33.  
  34.  
  35. #ifndef _M_X64
  36. // feel free to try x32 though
  37. #error unsupported arch
  38. #endif
  39.  
  40.  
  41. //----------------------------------------------------------------------------------------------------------------------
  42. // Helpers.
  43. //----------------------------------------------------------------------------------------------------------------------
  44.  
  45. template <class D> requires requires(D d) { d(); }
  46. class Fin
  47. {
  48. private:
  49.     [[msvc::no_unique_address]]
  50.     D _destroyer;
  51.  
  52. public:
  53.     Fin(Fin&&) = delete;    // implicitly removes all ctrs and assignments
  54.     constexpr Fin(D destroyerFunctor): _destroyer{(D&&)destroyerFunctor} {}
  55.     constexpr ~Fin() noexcept(noexcept(_destroyer())) { _destroyer(); }
  56. };
  57. #define CAT5(a, b, c, d, e)         CAT5_(a, b, c, d, e)
  58. #define CAT5_(a, b, c, d, e)        a ## b ## c ## d ## e
  59. #define MAKE_UNIQUE_NAME(prefix) CAT5(prefix, __, __COUNTER__, __xyz_unique__, __LINE__)
  60. #define FIN(...) auto MAKE_UNIQUE_NAME(xyz_$fin) = ::Fin([&]{ __VA_ARGS__; })
  61.  
  62.  
  63. static bool is_avx2_available()
  64. {
  65.     if (USER_SHARED_DATA->ProcessorFeatures[PF_AVX2_INSTRUCTIONS_AVAILABLE])
  66.         return true;
  67.     // if OS is below 20HX, this kuser bit may be absent; use cpuid
  68.     int regs[4];
  69.     __cpuidex(regs, 0, 0);
  70.     if (regs[0] < 7)
  71.         return false;
  72.     __cpuidex(regs, 7, 0);
  73.     return (regs[1] >> 5) & 1;              // AVX2: cpuid(7, 0).EBX[5]
  74. }
  75.  
  76.  
  77. _Success_(return)
  78. static bool get_cpu_brand_string(
  79.     _Always_(_Post_z_) _Out_z_cap_post_count_(brand_buf_size, 48) char* brand,
  80.     size_t brand_buf_size)
  81. {
  82.     if (brand_buf_size < 48) [[unlikely]]
  83.     {
  84.         if (brand_buf_size)
  85.             *brand = {};
  86.         return false;
  87.     }
  88.     for (int i = 0; i < 3; ++i)
  89.     {
  90.         int regs[4];
  91.         __cpuidex(regs, 0x8000'0002 + i, 0);
  92.        ((uint32_t*)(brand))[i*4 + 0] = regs[0];
  93.        ((uint32_t*)(brand))[i*4 + 1] = regs[1];
  94.        ((uint32_t*)(brand))[i*4 + 2] = regs[2];
  95.        ((uint32_t*)(brand))[i*4 + 3] = regs[3];
  96.    }
  97.    brand[47] = {};     // should be null-terminated, but we enforce that
  98.    return true;
  99. }
  100.  
  101.  
  102. static bool is_admin()
  103. {
  104.    return NtDeleteFile(&(OBJECT_ATTRIBUTES&)(const OBJECT_ATTRIBUTES&)(OBJECT_ATTRIBUTES
  105.    {
  106.        .Length{sizeof(OBJECT_ATTRIBUTES)},
  107.        .ObjectName{&(UNICODE_STRING&)(const UNICODE_STRING&)(UNICODE_STRING
  108.        {
  109.            22, 22, (WCHAR*)L"\\SystemRoot"   // used to be "\\??\\C:\\", but it could cause BSOD (lol)
  110.        })}
  111.    })) != STATUS_ACCESS_DENIED;
  112. }
  113.  
  114.  
  115. static void print_banner()
  116. {
  117.    char cpu_brand[48];
  118.    get_cpu_brand_string(cpu_brand, sizeof(cpu_brand));
  119.    SYSTEM_KERNEL_VA_SHADOW_INFORMATION kvas{};
  120.    NtQuerySystemInformation(SystemKernelVaShadowInformation, &kvas, sizeof(kvas), {});
  121.    printf("vpgatherqq test 1.1 x%u\n"
  122.        "OS: %u.%u.%u %04X, %u cores, CPU: %s\n"
  123.        "KVAS: %u, user-global: %u, shadow pcid: %u\n",
  124.        8 * (uint32_t)sizeof(size_t),
  125.        USER_SHARED_DATA->NtMajorVersion, USER_SHARED_DATA->NtMinorVersion,
  126.        USER_SHARED_DATA->NtBuildNumber, USER_SHARED_DATA->ImageNumberLow, USER_SHARED_DATA->ActiveProcessorCount,
  127.        cpu_brand,
  128.        kvas.KvaShadowEnabled, kvas.KvaShadowUserGlobal, kvas.KvaShadowPcid);
  129.    if (kvas.KvaShadowEnabled && !is_admin())
  130.        printf("WARNING: kvas enabled, and process is not elevated: ring0 inaccessible. You may want to rerun "
  131.            "as admin.\n");
  132.    printf("\n");
  133. }
  134.  
  135.  
  136. //----------------------------------------------------------------------------------------------------------------------
  137. // Code.
  138. //----------------------------------------------------------------------------------------------------------------------
  139.  
  140. #if 0
  141. // intrinsics produce fine code with /arch:AVX2, but since we can't predict registers used, we'll use asm instead
  142. __declspec(noinline)
  143. static uint64_t __fastcall read_using_vpgatherqq(const void* sus_address, const void* known_good_address,
  144.    _In_opt_ const uint16_t* seg_ss = nullptr)
  145. {
  146.    UNREFERENCED_PARAMETER(seg_ss);
  147.    const int64_t* src_base = nullptr;      // set src base address to null for simplicity
  148.    __m128i mask = _mm_set1_epi64x(-1);     // set entire xmm reg to fff...ff
  149.    __m128i index = _mm_set_epi64x((uint64_t)known_good_address, (uint64_t)sus_address);
  150.    __m128i dst = _mm_set_epi64x(0x5555'6666'7777'8888, 0x1111'2222'3333'4444);
  151.  
  152.    _ReadWriteBarrier();                    // ensure compiler abides
  153.    constexpr int scale = 1;                // we can scale indeces by 1/2/4/8
  154.    dst = _mm_mask_i64gather_epi64(dst, src_base, index, mask, scale);
  155.    return dst.m128i_u64[1];
  156. }
  157. #endif
  158.  
  159.  
  160. #pragma const_seg(push, ".text")      // put constants below into executable section
  161. #ifdef _M_X64
  162. // ### common part
  163. // 00: 48 b8 44 44 33 33 22     movabs rax, 0x1111222233334444
  164. // 0A: c4 e1 f9 6e c0           vmovq xmm0, rax
  165. // 0F: 48 b8 88 88 77 77 66     movabs rax, 0x5555666677778888
  166. // 19: c4 e3 f9 22 c0 01        vpinsrq xmm0, xmm0, rax, 0x1
  167. // 1F: 31 c0                    xor eax, eax
  168. // 21: c4 e1 f9 6e ca           vmovq xmm1, rdx
  169. // 26: c4 e3 f1 22 c9 01        vpinsrq xmm1, xmm1, rcx, 0x1
  170. // 2C: c5 e9 76 d2              vpcmpeqd xmm2, xmm2, xmm2
  171. //
  172. // ### v1, debug regs
  173. // 30: c4 e2 e9 91 04 08        vpgatherqq xmm0, [rax+xmm1], xmm2
  174. // 36: c4 e3 f9 16 c0 01        vpextrq rax, xmm0, 0x1
  175. // 3C: C3                       ret
  176. //
  177. // ### v2, trap flag
  178. // 30: 9c                       pushf
  179. // 31: 80 4c 24 01 01           or byte ptr [rsp+0x1], 0x1
  180. // 36: 9d                       popf
  181. // 37: c4 e2 e9 91 04 08        vpgatherqq xmm0, [rax+xmm1], xmm2
  182. // 3D: c4 e3 f9 16 c0 01        vpextrq rax, xmm0, 0x1
  183. // 43: c3                       ret
  184. //
  185. // ### v3, movss
  186. // 30: 41 8e 10                 mov ss, [r8]
  187. // 33: c4 e2 e9 91 04 08        vpgatherqq xmm0, [rax+xmm1], xmm2
  188. // 39: c4 e3 f9 16 c0 01        vpextrq rax, xmm0, 0x1
  189. // 3F: C3                       ret
  190. const uint8_t asm_read_using_vpgatherqq_v1_dr[] =
  191. {
  192.    0x48, 0xB8, 0x44, 0x44, 0x33, 0x33, 0x22, 0x22, 0x11, 0x11, 0xC4, 0xE1, 0xF9, 0x6E, 0xC0, 0x48,
  193.    0xB8, 0x88, 0x88, 0x77, 0x77, 0x66, 0x66, 0x55, 0x55, 0xC4, 0xE3, 0xF9, 0x22, 0xC0, 0x01, 0x31,
  194.    0xC0, 0xC4, 0xE1, 0xF9, 0x6E, 0xCA, 0xC4, 0xE3, 0xF1, 0x22, 0xC9, 0x01, 0xC5, 0xE9, 0x76, 0xD2,
  195.    0xC4, 0xE2, 0xE9, 0x91, 0x04, 0x08, 0xC4, 0xE3, 0xF9, 0x16, 0xC0, 0x01, 0xC3
  196. };
  197. const uint8_t asm_read_using_vpgatherqq_v2_tf[] =
  198. {
  199.    0x48, 0xB8, 0x44, 0x44, 0x33, 0x33, 0x22, 0x22, 0x11, 0x11, 0xC4, 0xE1, 0xF9, 0x6E, 0xC0, 0x48,
  200.    0xB8, 0x88, 0x88, 0x77, 0x77, 0x66, 0x66, 0x55, 0x55, 0xC4, 0xE3, 0xF9, 0x22, 0xC0, 0x01, 0x31,
  201.    0xC0, 0xC4, 0xE1, 0xF9, 0x6E, 0xCA, 0xC4, 0xE3, 0xF1, 0x22, 0xC9, 0x01, 0xC5, 0xE9, 0x76, 0xD2,
  202.    0x9C, 0x80, 0x4C, 0x24, 0x01, 0x01, 0x9D, 0xC4, 0xE2, 0xE9, 0x91, 0x04, 0x08, 0xC4, 0xE3, 0xF9,
  203.    0x16, 0xC0, 0x01, 0xC3
  204. };
  205. const uint8_t asm_read_using_vpgatherqq_v3_movss[] =
  206. {
  207.    0x48, 0xB8, 0x44, 0x44, 0x33, 0x33, 0x22, 0x22, 0x11, 0x11, 0xC4, 0xE1, 0xF9, 0x6E, 0xC0, 0x48,
  208.    0xB8, 0x88, 0x88, 0x77, 0x77, 0x66, 0x66, 0x55, 0x55, 0xC4, 0xE3, 0xF9, 0x22, 0xC0, 0x01, 0x31,
  209.    0xC0, 0xC4, 0xE1, 0xF9, 0x6E, 0xCA, 0xC4, 0xE3, 0xF1, 0x22, 0xC9, 0x01, 0xC5, 0xE9, 0x76, 0xD2,
  210.    0x41, 0x8E, 0x10, 0xC4, 0xE2, 0xE9, 0x91, 0x04, 0x08, 0xC4, 0xE3, 0xF9, 0x16, 0xC0, 0x01, 0xC3
  211. };
  212.  
  213. // 00: 31 c0                    xor eax, eax
  214. // 02: c4 e1 f9 6e cc           vmovq xmm1, rsp
  215. // 07: c4 e3 f1 22 c9 01        vpinsrq xmm1, xmm1, rcx, 0x1
  216. // 0D: c5 e9 76 d2              vpcmpeqd xmm2, xmm2, xmm2
  217. // 11: 9c                       pushf
  218. // 12: 80 4c 24 01 01           or byte ptr [rsp+0x1], 0x1
  219. // 17: 9d                       popf
  220. // 18: c4 e2 e9 91 04 08        vpgatherqq xmm0, [rax+xmm1], xmm2
  221. // 1E: c3                       ret
  222. const uint8_t asm_read_test_using_vpgatherqq[] =
  223. {
  224.    0x31, 0xC0, 0xC4, 0xE1, 0xF9, 0x6E, 0xCC, 0xC4, 0xE3, 0xF1, 0x22, 0xC9, 0x01, 0xC5, 0xE9, 0x76,
  225.    0xD2, 0x9C, 0x80, 0x4C, 0x24, 0x01, 0x01, 0x9D, 0xC4, 0xE2, 0xE9, 0x91, 0x04, 0x08, 0xC3
  226. };
  227.  
  228. // ### common part
  229. // 00: c5 fc 10 02              vmovups ymm0, [rdx]
  230. // 04: c5 fc 10 4a 20           vmovups ymm1, [rdx+0x20]
  231. // 09: c5 fc 10 52 40           vmovups ymm2, [rdx+0x40]
  232. //
  233. // ### v1, tf
  234. // 0E: 9c                       pushf
  235. // 0F: 80 4c 24 01 01           or [rsp+0x1], 0x1
  236. // 14: 9d                       popf
  237. // 15: c4 e2 6d 90 04 09        vpgatherdd ymm0, [rcx+ymm1], ymm2
  238. // 1B: 90                       nop
  239. // 1C: c3                       ret
  240. //
  241. // ### v2, movss
  242. // 0E: 8e 52 60                 mov ss, [rdx+0x60]
  243. // 11: c4 e2 6d 90 04 09        vpgatherdd ymm0, [rcx+ymm1], ymm2
  244. // 17: 90                       nop
  245. // 18: c3                       ret
  246. //
  247. // ### v3, tf + movss
  248. // 0E: 9c                       pushf
  249. // 0F: 80 4c 24 01 01           or [rsp+0x1], 0x1
  250. // 14: 9d                       popf
  251. // 15: 8e 52 60                 mov ss, [rdx+0x60]
  252. // 18: c4 e2 6d 90 04 09        vpgatherdd ymm0, [rcx+ymm1], ymm2
  253. // 1E: 90                       nop
  254. // 1F: c3                       ret
  255. const uint8_t asm_interrupt_test_using_vpgatherdd_v1_tf[] =
  256. {
  257.    0xC5, 0xFC, 0x10, 0x02, 0xC5, 0xFC, 0x10, 0x4A, 0x20, 0xC5, 0xFC, 0x10, 0x52, 0x40, 0x9C, 0x80,
  258.    0x4C, 0x24, 0x01, 0x01, 0x9D, 0xC4, 0xE2, 0x6D, 0x90, 0x04, 0x09, 0x90, 0xC3
  259. };
  260. const uint8_t asm_interrupt_test_using_vpgatherdd_v2_movss[] =
  261. {
  262.    0xC5, 0xFC, 0x10, 0x02, 0xC5, 0xFC, 0x10, 0x4A, 0x20, 0xC5, 0xFC, 0x10, 0x52, 0x40, 0x8E, 0x52,
  263.    0x60, 0xC4, 0xE2, 0x6D, 0x90, 0x04, 0x09, 0x90, 0xC3
  264. };
  265. const uint8_t asm_interrupt_test_using_vpgatherdd_v3_tf_movss[] =
  266. {
  267.    0xC5, 0xFC, 0x10, 0x02, 0xC5, 0xFC, 0x10, 0x4A, 0x20, 0xC5, 0xFC, 0x10, 0x52, 0x40, 0x9C, 0x80,
  268.    0x4C, 0x24, 0x01, 0x01, 0x9D, 0x8E, 0x52, 0x60, 0xC4, 0xE2, 0x6D, 0x90, 0x04, 0x09, 0x90, 0xC3
  269. };
  270.  
  271.  
  272. #elif defined(_M_IX86)  // #ifdef _M_X64
  273. // 00: b8 44 44 33 33           mov eax, 0x33334444
  274. // 05: c5 f9 6e c0              vmovd xmm0, eax
  275. // 09: b8 22 22 11 11           mov eax, 0x11112222
  276. // 0E: c4 e3 79 22 c0 01        vpinsrd xmm0, xmm0, eax, 0x1
  277. // 14: b8 88 88 77 77           mov eax, 0x77778888
  278. // 19: c4 e3 79 22 c0 02        vpinsrd xmm0, xmm0, eax, 0x2
  279. // 1F: b8 66 66 55 55           mov eax, 0x55556666
  280. // 24: c4 e3 79 22 c0 03        vpinsrd xmm0, xmm0, eax, 0x3
  281. // 2A: 31 c0                    xor eax, eax
  282. // 2C: c5 f9 6e ca              vmovd xmm1, edx
  283. // 30: c4 e3 71 22 c9 02        vpinsrd xmm1, xmm1, ecx, 0x2
  284. // 36: c5 e9 76 d2              vpcmpeqd xmm2, xmm2, xmm2
  285. // 3A: c4 e2 e9 91 04 08        vpgatherqq xmm0, [eax+xmm1], xmm2
  286. // 40: c4 e3 79 16 c0 02        vpextrd eax, xmm0, 0x2
  287. // 46: c3                       ret
  288. const uint8_t asm_read_using_vpgatherqq_v1_dr[] =
  289. {
  290.    0xB8, 0x44, 0x44, 0x33, 0x33, 0xC5, 0xF9, 0x6E, 0xC0, 0xB8, 0x22, 0x22, 0x11, 0x11, 0xC4, 0xE3,
  291.    0x79, 0x22, 0xC0, 0x01, 0xB8, 0x88, 0x88, 0x77, 0x77, 0xC4, 0xE3, 0x79, 0x22, 0xC0, 0x02, 0xB8,
  292.    0x66, 0x66, 0x55, 0x55, 0xC4, 0xE3, 0x79, 0x22, 0xC0, 0x03, 0x31, 0xC0, 0xC5, 0xF9, 0x6E, 0xCA,
  293.    0xC4, 0xE3, 0x71, 0x22, 0xC9, 0x02, 0xC5, 0xE9, 0x76, 0xD2, 0xC4, 0xE2, 0xE9, 0x91, 0x04, 0x08,
  294.    0xC4, 0xE3, 0x79, 0x16, 0xC0, 0x02, 0xC3
  295. };
  296. // actually, don't bother with x32
  297. #error unsupported arch
  298. #else // #elif defined(_M_IX86)
  299. #error unsupported arch
  300. #endif
  301.  
  302. #pragma const_seg(pop)          // revert constants location
  303.  
  304. uint64_t FASTCALL read_using_vpgatherqq(const void* sus_address, const void* known_good_address,
  305.     _In_opt_ const void* segss = nullptr);
  306. void FASTCALL read_test_using_vpgatherqq(const void* sus_address);
  307. void FASTCALL interrupt_test_using_vpgatherdd(const void* base_address, const void* ymm_data);
  308.  
  309.  
  310. __declspec(noinline)
  311. static NTSTATUS test_vpgatherqq_worker(int test, _Inout_ int* unexpecteds)
  312. {
  313.     switch (test)
  314.     {
  315.     case 0:
  316.         printf("%stest 0: data breakpoint on known_data\n", long_line);
  317.         break;
  318.     case 1:
  319.         printf("%stest 1: no breakpoints, just setting trap flag before vpgatherqq\n", long_line);
  320.         break;
  321.     case 2:
  322.         printf("%stest 2: data breakpoint on known_data; movss right before vpgatherqq\n", long_line);
  323.         break;
  324.     case 3:
  325.         printf("%stest 3: data breakpoint on ss location; movss right before vpgatherqq\n", long_line);
  326.         break;
  327.     case 4:
  328.         printf("%stest 4: data breakpoints on known_data and ss location; movss right before vpgatherqq\n", long_line);
  329.         break;
  330.     default:
  331.         printf("%stest %i: UNEXPECTED\n", long_line, test);
  332.         return STATUS_ASSERTION_FAILURE;
  333.     }
  334.  
  335.     // note we don't even have to touch this address, as it'll be right-most in the index register
  336.     static constinit uint64_t known_good_data = 0xAAAA'1111'4444'3333;
  337.    static constinit uint64_t ss_value = 0x2B;  // KGDT64_R3_DATA|RPL_MASK; gotta be 8-aligned coz we set 8-break on it
  338.    
  339.    // prepare suspicious address
  340.    void* sus_address_r3{};
  341.    SIZE_T size = 2 * PAGE_SIZE;
  342.    NTSTATUS st = NtAllocateVirtualMemory(NtCurrentProcess(), &sus_address_r3, 0, &size, MEM_RESERVE|MEM_COMMIT,
  343.        PAGE_READWRITE);
  344.    if (FAILED(st))
  345.        return st;
  346.    FIN(SIZE_T zero{};  NtFreeVirtualMemory(NtCurrentProcess(), &sus_address_r3, &zero, MEM_RELEASE));
  347.  
  348.    // prepare #DB trap
  349.    CONTEXT ctx
  350.    {
  351.        .ContextFlags = CONTEXT_DEBUG_REGISTERS,
  352.        .Dr0 = (size_t)&known_good_data,
  353.        .Dr2 = (size_t)&ss_value,
  354.        .Dr7 = (test == 0 || test == 2)? 0x0003'0001: (test == 3)? 0x0030'0010: (test == 4)? 0x0033'0011: 0u,
  355.     };
  356.     st = NtSetContextThread(NtCurrentThread(), &ctx);
  357.     if (FAILED(st))
  358.         return st;
  359.     ctx.Dr7 = 0;
  360.     FIN(NtSetContextThread(NtCurrentThread(), &ctx));
  361.     const void* segss_ptr = (test == 2 || test == 3 || test == 4)? &ss_value: nullptr;
  362.  
  363.     auto* read_using_vpgatherqq_fn = (decltype(&read_using_vpgatherqq))(
  364.         (test == 0)? asm_read_using_vpgatherqq_v1_dr:
  365.         (test == 1)? asm_read_using_vpgatherqq_v2_tf:
  366.         asm_read_using_vpgatherqq_v3_movss);
  367.     void* sus_address{};
  368.     for (int subtest = 0; subtest < 13; ++subtest)
  369.     {
  370.         bool should_be_readable = false;
  371.         printf("[>] test %u.%02u: ", test, subtest);
  372.         switch (subtest)
  373.         {
  374.         case 0:
  375.             // initial try, do nothing
  376.             sus_address = sus_address_r3;
  377.             printf("using ring3 sus address: %p\n", sus_address);
  378.             break;
  379.         case 1:
  380.             // do nothing; this demonstrates we have not triggered #PF through initial read attempt
  381.             printf("changing nothing (ensuring our observation had not side-effects)...\n");
  382.             break;
  383.         case 2:
  384.         {
  385.             uint64_t x = 0xAAAA'5555'8888'7777;
  386.            printf("writing new value to sus address: %016I64X...\n", x);
  387.            *(uint64_t*)sus_address = x;
  388.            should_be_readable = true;
  389.            break;
  390.        }
  391.        case 3:
  392.        {
  393.            printf("applying PAGE_GUARD to sus address...\n");
  394.            SIZE_T gsize = PAGE_SIZE;
  395.            ULONG old_prot;
  396.            st = NtProtectVirtualMemory(NtCurrentProcess(), &sus_address, &gsize, PAGE_READWRITE|PAGE_GUARD, &old_prot);
  397.            if (FAILED(st))
  398.                return st;
  399.            break;
  400.        }
  401.        case 4:
  402.            // do nothing; this demonstrates PAGE_GUARD was not removed on our read attempt
  403.            printf("changing nothing...\n");
  404.            break;
  405.        case 5:
  406.        {
  407.            // interesting fact: removing PAGE_GUARD in explicit way will not make PTE valid
  408.            printf("removing PAGE_GUARD...\n");
  409.            SIZE_T gsize = PAGE_SIZE;
  410.            ULONG old_prot;
  411.            st = NtProtectVirtualMemory(NtCurrentProcess(), &sus_address, &gsize, PAGE_READWRITE, &old_prot);
  412.            if (FAILED(st))
  413.                return st;
  414.            break;
  415.        }
  416.        case 6:
  417.            printf("touching address after PAGE_GUARD removal...\n");
  418.            *(volatile char*)sus_address;
  419.            should_be_readable = true;
  420.            break;
  421.        case 7:
  422.            sus_address = (char*)nullptr - 2;
  423.            printf("using wrapped-around sus_address: %p\n", sus_address);
  424.            break;
  425.        case 8:
  426.            sus_address = (void*)0x0000'8888'7777'0000;
  427.             printf("using non-cannonical sus_address: %p\n", sus_address);
  428.             break;
  429.         case 9:
  430.             sus_address = (void*)0x9999'8888'7777'0000;
  431.            printf("using non-cannonical sus_address: %p\n", sus_address);
  432.            break;
  433.        case 10:
  434.            sus_address = (void*)KI_USER_SHARED_DATA_R0;
  435.            printf("==> using ring0 kuser sus_address: %p\n", sus_address);
  436.            break;
  437.        case 11:
  438.            sus_address = (char*)KI_USER_SHARED_DATA_R0 + PAGE_SIZE;
  439.            printf("==> using ring0 invalid sus_address: %p\n", sus_address);
  440.            break;
  441.        case 12:
  442.            printf("applying PAGE_GUARD to sus address for eflags.RF test...\n");
  443.            sus_address = sus_address_r3;
  444.            SIZE_T gsize = PAGE_SIZE;
  445.            ULONG old_prot;
  446.            st = NtProtectVirtualMemory(NtCurrentProcess(), &sus_address, &gsize, PAGE_READWRITE|PAGE_GUARD, &old_prot);
  447.            if (FAILED(st))
  448.                return st;
  449.            break;
  450.        }
  451.  
  452.        M128A xmm0{.Low{0x11}}, xmm2{.Low{0x22}};
  453.        uint64_t sus_data = 0;
  454.        bool debug_break_okay = false;
  455.        bool second_try_for_test12 = false;
  456.        NTSTATUS exception_code = STATUS_SUCCESS;
  457.        [&]() __declspec(noinline, guard(nocf))
  458.        {
  459.            __try
  460.            {
  461.                sus_data = read_using_vpgatherqq_fn(sus_address, &known_good_data, segss_ptr);
  462.            }
  463.            __except ([&](EXCEPTION_POINTERS* exptrs) -> LONG
  464.            {
  465.                auto* exr = exptrs->ExceptionRecord;
  466.                auto* ctx = exptrs->ContextRecord;
  467. #ifdef _M_X64
  468.                M128A* xmm = &ctx->Xmm0;
  469. #else
  470.                M128A xmmDummy[2]{{.Low{0x1111}}, {.Low{0x2222}}};
  471.                M128A* xmm = (M128A*)((char*)&ctx->ExtendedRegisters + 160);  // according to fxsave instruction format
  472.                if ((ctx->ContextFlags & CONTEXT_EXTENDED_REGISTERS) == 0)
  473.                    xmm = xmmDummy;
  474. #endif
  475.                NTSTATUS expectedCode = STATUS_SINGLE_STEP;
  476.                if (second_try_for_test12)
  477.                    expectedCode = STATUS_GUARD_PAGE_VIOLATION;
  478.                if (test == 3)
  479.                {
  480.                    expectedCode = (subtest == 3 || subtest == 12)?
  481.                        STATUS_GUARD_PAGE_VIOLATION:
  482.                        STATUS_ACCESS_VIOLATION;
  483.                }
  484.                if ((NTSTATUS)exr->ExceptionCode != expectedCode)
  485.                {
  486.                    *unexpecteds += 1;
  487.                    printf("[!] UNEXPECTED exception: %08X at %p; rva %06I64X; DR7: %08X, DR6: %08X\n"
  488.                        "    xmm0 %016I64X'%016I64X, xmm2 %016I64X'%016I64X\n",
  489.                        exr->ExceptionCode, exr->ExceptionAddress,
  490.                        (uint64_t)((size_t)exr->ExceptionAddress - (size_t)&__ImageBase),
  491.                        (uint32_t)ctx->Dr7, (uint32_t)ctx->Dr6,
  492.                        xmm[0].High, xmm[0].Low, xmm[2].High, xmm[2].Low);
  493.                    return EXCEPTION_CONTINUE_SEARCH;
  494.                }
  495.                if (subtest == 12 && !second_try_for_test12)
  496.                {
  497.                    second_try_for_test12 = true;
  498.                    printf("[ ] retrying after exception, now with eflags.RF set\n");
  499.                    ctx->EFlags |= 0x10000u;    // set resume flag
  500.                    return EXCEPTION_CONTINUE_EXECUTION;
  501.                }
  502.                if (test == 3)
  503.                    ctx->Rip += vpgather_instruction_size;      // skip it
  504.                xmm0 = xmm[0];
  505.                xmm2 = xmm[2];
  506.                debug_break_okay = true;
  507.                exception_code = exr->ExceptionCode;
  508.                return EXCEPTION_EXECUTE_HANDLER;
  509.            }(GetExceptionInformation()))
  510.            {
  511.                NOTHING;
  512.            }
  513.        }();
  514.        
  515.        bool sus_data_read = xmm2.High == 0 && debug_break_okay;
  516.        if (debug_break_okay)
  517.            sus_data = xmm0.High;       // real value if sus_data_read, otherwise just original xmm0 value
  518.        bool expected = !should_be_readable ^ sus_data_read;
  519.        bool reverse_debug_expectation = (test == 3) && subtest != 3 && (subtest <= 6 || subtest == 12);
  520.        if (debug_break_okay && reverse_debug_expectation)
  521.        {
  522.            *unexpecteds += 1;
  523.            printf("[!] UNEXPECTED: debug break triggered for test 3\n");
  524.        }
  525.        else if (!debug_break_okay && !reverse_debug_expectation)
  526.        {
  527.            *unexpecteds += 1;
  528.            printf("[!] UNEXPECTED: debug break failed (should not happen)\n");
  529.        }
  530.        else if (sus_data_read)
  531.            printf("[%c] %016I64X, was read;    xmm0 %016I64X'%016I64X, xmm2 %016I64X'%016I64X\n",
  532.                expected? '+': '!', sus_data, xmm0.High, xmm0.Low, xmm2.High, xmm2.Low);
  533.        else
  534.            printf("[%c] %016I64X, wasn't read; xmm0 %016I64X'%016I64X, xmm2 %016I64X'%016I64X\n",
  535.                expected? ' ': '!', sus_data, xmm0.High, xmm0.Low, xmm2.High, xmm2.Low);
  536.        if (debug_break_okay
  537.            && (!expected || xmm2.Low != 0 || xmm0.Low != 0xAAAA111144443333
  538.                || (should_be_readable && (xmm2.High != 0 || xmm0.High != 0xAAAA555588887777))
  539.                || (!should_be_readable && (xmm2.High != UINT64_MAX || xmm0.High != 0x5555666677778888))))
  540.        {
  541.            *unexpecteds += 1;
  542.            printf("[!] UNEXPECTED: unexpected state or data ^^^\n");
  543.        }
  544.    }
  545.    return STATUS_SUCCESS;
  546. }
  547.  
  548.  
  549. static NTSTATUS test_vpgatherqq()
  550. {
  551.    printf(long_line);
  552.    printf("running regular vpgatherqq tests...\n");
  553.    int unexpecteds = 0;
  554.    for (int test_type = 0; test_type < 5; ++test_type)
  555.    {
  556.        int unexpecteds0 = unexpecteds;
  557.        NTSTATUS st = test_vpgatherqq_worker(test_type, &unexpecteds);
  558.        if (FAILED(st))
  559.        {
  560.            printf("[x] UNEXPECTED: vpgatherqq test %i failed: %08X\n", test_type, st);
  561.            if (unexpecteds == unexpecteds0)
  562.                ++unexpecteds;
  563.        }
  564.    }
  565.  
  566.    printf(long_line);
  567.    if (unexpecteds == 0)
  568.        printf("[+] all vpgatherqq tests done, all data and states were expected.\n");
  569.    else
  570.        printf("[!] all vpgatherqq tests done, got %u UNEXPECTED states. Your system is strange af, please ping "
  571.            "@sixtyvividtails.\n", unexpecteds);
  572.    printf(long_line);
  573.    return unexpecteds == 0? STATUS_SUCCESS: STATUS_WAKE_SYSTEM;  // infostatus
  574. }
  575.  
  576.  
  577. static NTSTATUS run_tests()
  578. {
  579.    if (!is_avx2_available())
  580.        return printf("[x] avx2 is not available\n"), STATUS_NOT_SUPPORTED;
  581.  
  582.    auto* prev_filter = SetUnhandledExceptionFilter([](EXCEPTION_POINTERS* exptrs) -> LONG
  583.    {
  584.        auto* exr = exptrs->ExceptionRecord;
  585.        auto* ctx = exptrs->ContextRecord;
  586.        printf("[x] UNEXPECTED: unhandled exception %08X, rip %p/%06X, please ping @sixtyvividtails\n",
  587.            exr->ExceptionCode, (void*)ctx->Rip, (UINT)(ctx->Rip - (SIZE_T)&__ImageBase));
  588.        return EXCEPTION_EXECUTE_HANDLER;
  589.    });
  590.    NTSTATUS st0 = test_vpgatherqq();   // regular
  591.    //NTSTATUS st1 = test_vpgatherdd(); // against interrupts
  592.    NTSTATUS st1 = STATUS_SUCCESS;
  593.    SetUnhandledExceptionFilter(prev_filter);
  594.    return FAILED(st0)? st0: FAILED(st1)? st1: st0 == STATUS_SUCCESS? st1: st0;
  595. }
  596.  
  597.  
  598. int __cdecl wmain()
  599. {
  600.    print_banner();
  601.    NTSTATUS st = run_tests();
  602.  
  603.    ULONG dummy;
  604.    if (GetConsoleMode(GetStdHandle(STD_OUTPUT_HANDLE), &dummy) && GetConsoleProcessList(&dummy, 1) <= 1)
  605.    {
  606.        printf("exit status: %08X; press any key to continue...\n", st);
  607.        _flushall();
  608.        int c = _getch();
  609.        if (!c || c == 0xE0)    // arrow or function key, need to read one more
  610.            (void)_getch();
  611.    }
  612.  
  613.    return st;
  614. }
  615.  
  616.  
  617. //----------------------------------------------------------------------------------------------------------------------
  618. // Extra.
  619. //----------------------------------------------------------------------------------------------------------------------
  620.  
  621. #if 0
  622. Sample output:
  623.  
  624. vpgatherqq test 1.1 x64
  625. OS: 10.0.20348 8664, 16 cores, CPU: 11th Gen Intel(R) Core(TM) i7-11800H @ 2.30GHz
  626. KVAS: 0, user-global: 0, shadow pcid: 0
  627.  
  628. ------------------------------------------------------------------------------------------------------------------
  629. running regular vpgatherqq tests...
  630. ------------------------------------------------------------------------------------------------------------------
  631. test 0: data breakpoint on known_data
  632. [>] test 0.00: using ring3 sus address: 000002AA5D180000
  633. [ ] 5555666677778888, wasn't read; xmm0 5555666677778888'AAAA111144443333, xmm2 FFFFFFFFFFFFFFFF'0000000000000000
  634. [>] test 0.01: changing nothing (ensuring our observation had not side-effects)...
  635. [ ] 5555666677778888, wasn't read; xmm0 5555666677778888'AAAA111144443333, xmm2 FFFFFFFFFFFFFFFF'0000000000000000
  636. [>] test 0.02: writing new value to sus address: AAAA555588887777...
  637. [+] AAAA555588887777, was read;    xmm0 AAAA555588887777'AAAA111144443333, xmm2 0000000000000000'0000000000000000
  638. [>] test 0.03: applying PAGE_GUARD to sus address...
  639. [ ] 5555666677778888, wasn't read; xmm0 5555666677778888'AAAA111144443333, xmm2 FFFFFFFFFFFFFFFF'0000000000000000
  640. [>] test 0.04: changing nothing...
  641. [ ] 5555666677778888, wasn't read; xmm0 5555666677778888'AAAA111144443333, xmm2 FFFFFFFFFFFFFFFF'0000000000000000
  642. [>] test 0.05: removing PAGE_GUARD...
  643. [ ] 5555666677778888, wasn't read; xmm0 5555666677778888'AAAA111144443333, xmm2 FFFFFFFFFFFFFFFF'0000000000000000
  644. [>] test 0.06: touching address after PAGE_GUARD removal...
  645. [+] AAAA555588887777, was read;    xmm0 AAAA555588887777'AAAA111144443333, xmm2 0000000000000000'0000000000000000
  646. [>] test 0.07: using wrapped-around sus_address: FFFFFFFFFFFFFFFE
  647. [ ] 5555666677778888, wasn't read; xmm0 5555666677778888'AAAA111144443333, xmm2 FFFFFFFFFFFFFFFF'0000000000000000
  648. [>] test 0.08: using non-cannonical sus_address: 0000888877770000
  649. [ ] 5555666677778888, wasn't read; xmm0 5555666677778888'AAAA111144443333, xmm2 FFFFFFFFFFFFFFFF'0000000000000000
  650. [>] test 0.09: using non-cannonical sus_address: 9999888877770000
  651. [ ] 5555666677778888, wasn't read; xmm0 5555666677778888'AAAA111144443333, xmm2 FFFFFFFFFFFFFFFF'0000000000000000
  652. [>] test 0.10: ==> using ring0 kuser sus_address: FFFFF78000000000
  653. [ ] 5555666677778888, wasn't read; xmm0 5555666677778888'AAAA111144443333, xmm2 FFFFFFFFFFFFFFFF'0000000000000000
  654. [>] test 0.11: ==> using ring0 invalid sus_address: FFFFF78000001000
  655. [ ] 5555666677778888, wasn't read; xmm0 5555666677778888'AAAA111144443333, xmm2 FFFFFFFFFFFFFFFF'0000000000000000
  656. [>] test 0.12: applying PAGE_GUARD to sus address for eflags.RF test...
  657. [ ] retrying after exception, now with eflags.RF set
  658. [ ] 5555666677778888, wasn't read; xmm0 5555666677778888'AAAA111144443333, xmm2 FFFFFFFFFFFFFFFF'0000000000000000
  659. ------------------------------------------------------------------------------------------------------------------
  660. test 1: no breakpoints, just setting trap flag before vpgatherqq
  661. [>] test 1.00: using ring3 sus address: 000002AA5D180000
  662. [ ] 5555666677778888, wasn't read; xmm0 5555666677778888'AAAA111144443333, xmm2 FFFFFFFFFFFFFFFF'0000000000000000
  663. [>] test 1.01: changing nothing (ensuring our observation had not side-effects)...
  664. [ ] 5555666677778888, wasn't read; xmm0 5555666677778888'AAAA111144443333, xmm2 FFFFFFFFFFFFFFFF'0000000000000000
  665. [>] test 1.02: writing new value to sus address: AAAA555588887777...
  666. [+] AAAA555588887777, was read;    xmm0 AAAA555588887777'AAAA111144443333, xmm2 0000000000000000'0000000000000000
  667. [>] test 1.03: applying PAGE_GUARD to sus address...
  668. [ ] 5555666677778888, wasn't read; xmm0 5555666677778888'AAAA111144443333, xmm2 FFFFFFFFFFFFFFFF'0000000000000000
  669. [>] test 1.04: changing nothing...
  670. [ ] 5555666677778888, wasn't read; xmm0 5555666677778888'AAAA111144443333, xmm2 FFFFFFFFFFFFFFFF'0000000000000000
  671. [>] test 1.05: removing PAGE_GUARD...
  672. [ ] 5555666677778888, wasn't read; xmm0 5555666677778888'AAAA111144443333, xmm2 FFFFFFFFFFFFFFFF'0000000000000000
  673. [>] test 1.06: touching address after PAGE_GUARD removal...
  674. [+] AAAA555588887777, was read;    xmm0 AAAA555588887777'AAAA111144443333, xmm2 0000000000000000'0000000000000000
  675. [>] test 1.07: using wrapped-around sus_address: FFFFFFFFFFFFFFFE
  676. [ ] 5555666677778888, wasn't read; xmm0 5555666677778888'AAAA111144443333, xmm2 FFFFFFFFFFFFFFFF'0000000000000000
  677. [>] test 1.08: using non-cannonical sus_address: 0000888877770000
  678. [ ] 5555666677778888, wasn't read; xmm0 5555666677778888'AAAA111144443333, xmm2 FFFFFFFFFFFFFFFF'0000000000000000
  679. [>] test 1.09: using non-cannonical sus_address: 9999888877770000
  680. [ ] 5555666677778888, wasn't read; xmm0 5555666677778888'AAAA111144443333, xmm2 FFFFFFFFFFFFFFFF'0000000000000000
  681. [>] test 1.10: ==> using ring0 kuser sus_address: FFFFF78000000000
  682. [ ] 5555666677778888, wasn't read; xmm0 5555666677778888'AAAA111144443333, xmm2 FFFFFFFFFFFFFFFF'0000000000000000
  683. [>] test 1.11: ==> using ring0 invalid sus_address: FFFFF78000001000
  684. [ ] 5555666677778888, wasn't read; xmm0 5555666677778888'AAAA111144443333, xmm2 FFFFFFFFFFFFFFFF'0000000000000000
  685. [>] test 1.12: applying PAGE_GUARD to sus address for eflags.RF test...
  686. [ ] retrying after exception, now with eflags.RF set
  687. [ ] 5555666677778888, wasn't read; xmm0 5555666677778888'AAAA111144443333, xmm2 FFFFFFFFFFFFFFFF'0000000000000000
  688. ------------------------------------------------------------------------------------------------------------------
  689. test 2: data breakpoint on known_data; movss right before vpgatherqq
  690. [>] test 2.00: using ring3 sus address: 000002AA5D180000
  691. [ ] 5555666677778888, wasn't read; xmm0 5555666677778888'AAAA111144443333, xmm2 FFFFFFFFFFFFFFFF'0000000000000000
  692. [>] test 2.01: changing nothing (ensuring our observation had not side-effects)...
  693. [ ] 5555666677778888, wasn't read; xmm0 5555666677778888'AAAA111144443333, xmm2 FFFFFFFFFFFFFFFF'0000000000000000
  694. [>] test 2.02: writing new value to sus address: AAAA555588887777...
  695. [+] AAAA555588887777, was read;    xmm0 AAAA555588887777'AAAA111144443333, xmm2 0000000000000000'0000000000000000
  696. [>] test 2.03: applying PAGE_GUARD to sus address...
  697. [ ] 5555666677778888, wasn't read; xmm0 5555666677778888'AAAA111144443333, xmm2 FFFFFFFFFFFFFFFF'0000000000000000
  698. [>] test 2.04: changing nothing...
  699. [ ] 5555666677778888, wasn't read; xmm0 5555666677778888'AAAA111144443333, xmm2 FFFFFFFFFFFFFFFF'0000000000000000
  700. [>] test 2.05: removing PAGE_GUARD...
  701. [ ] 5555666677778888, wasn't read; xmm0 5555666677778888'AAAA111144443333, xmm2 FFFFFFFFFFFFFFFF'0000000000000000
  702. [>] test 2.06: touching address after PAGE_GUARD removal...
  703. [+] AAAA555588887777, was read;    xmm0 AAAA555588887777'AAAA111144443333, xmm2 0000000000000000'0000000000000000
  704. [>] test 2.07: using wrapped-around sus_address: FFFFFFFFFFFFFFFE
  705. [ ] 5555666677778888, wasn't read; xmm0 5555666677778888'AAAA111144443333, xmm2 FFFFFFFFFFFFFFFF'0000000000000000
  706. [>] test 2.08: using non-cannonical sus_address: 0000888877770000
  707. [ ] 5555666677778888, wasn't read; xmm0 5555666677778888'AAAA111144443333, xmm2 FFFFFFFFFFFFFFFF'0000000000000000
  708. [>] test 2.09: using non-cannonical sus_address: 9999888877770000
  709. [ ] 5555666677778888, wasn't read; xmm0 5555666677778888'AAAA111144443333, xmm2 FFFFFFFFFFFFFFFF'0000000000000000
  710. [>] test 2.10: ==> using ring0 kuser sus_address: FFFFF78000000000
  711. [ ] 5555666677778888, wasn't read; xmm0 5555666677778888'AAAA111144443333, xmm2 FFFFFFFFFFFFFFFF'0000000000000000
  712. [>] test 2.11: ==> using ring0 invalid sus_address: FFFFF78000001000
  713. [ ] 5555666677778888, wasn't read; xmm0 5555666677778888'AAAA111144443333, xmm2 FFFFFFFFFFFFFFFF'0000000000000000
  714. [>] test 2.12: applying PAGE_GUARD to sus address for eflags.RF test...
  715. [ ] retrying after exception, now with eflags.RF set
  716. [ ] 5555666677778888, wasn't read; xmm0 5555666677778888'AAAA111144443333, xmm2 FFFFFFFFFFFFFFFF'0000000000000000
  717. ------------------------------------------------------------------------------------------------------------------
  718. test 3: data breakpoint on ss location; movss right before vpgatherqq
  719. [>] test 3.00: using ring3 sus address: 000002AA5D180000
  720. [ ] 0000000000000000, wasn't read; xmm0 0000000000000000'0000000000000011, xmm2 0000000000000000'0000000000000022
  721. [>] test 3.01: changing nothing (ensuring our observation had not side-effects)...
  722. [ ] 0000000000000000, wasn't read; xmm0 0000000000000000'0000000000000011, xmm2 0000000000000000'0000000000000022
  723. [>] test 3.02: writing new value to sus address: AAAA555588887777...
  724. [!] AAAA555588887777, wasn't read; xmm0 0000000000000000'0000000000000011, xmm2 0000000000000000'0000000000000022
  725. [>] test 3.03: applying PAGE_GUARD to sus address...
  726. [ ] 5555666677778888, wasn't read; xmm0 5555666677778888'AAAA111144443333, xmm2 FFFFFFFFFFFFFFFF'0000000000000000
  727. [>] test 3.04: changing nothing...
  728. [ ] AAAA555588887777, wasn't read; xmm0 0000000000000000'0000000000000011, xmm2 0000000000000000'0000000000000022
  729. [>] test 3.05: removing PAGE_GUARD...
  730. [ ] AAAA555588887777, wasn't read; xmm0 0000000000000000'0000000000000011, xmm2 0000000000000000'0000000000000022
  731. [>] test 3.06: touching address after PAGE_GUARD removal...
  732. [!] AAAA555588887777, wasn't read; xmm0 0000000000000000'0000000000000011, xmm2 0000000000000000'0000000000000022
  733. [>] test 3.07: using wrapped-around sus_address: FFFFFFFFFFFFFFFE
  734. [ ] 5555666677778888, wasn't read; xmm0 5555666677778888'AAAA111144443333, xmm2 FFFFFFFFFFFFFFFF'0000000000000000
  735. [>] test 3.08: using non-cannonical sus_address: 0000888877770000
  736. [ ] 5555666677778888, wasn't read; xmm0 5555666677778888'AAAA111144443333, xmm2 FFFFFFFFFFFFFFFF'0000000000000000
  737. [>] test 3.09: using non-cannonical sus_address: 9999888877770000
  738. [ ] 5555666677778888, wasn't read; xmm0 5555666677778888'AAAA111144443333, xmm2 FFFFFFFFFFFFFFFF'0000000000000000
  739. [>] test 3.10: ==> using ring0 kuser sus_address: FFFFF78000000000
  740. [ ] 5555666677778888, wasn't read; xmm0 5555666677778888'AAAA111144443333, xmm2 FFFFFFFFFFFFFFFF'0000000000000000
  741. [>] test 3.11: ==> using ring0 invalid sus_address: FFFFF78000001000
  742. [ ] 5555666677778888, wasn't read; xmm0 5555666677778888'AAAA111144443333, xmm2 FFFFFFFFFFFFFFFF'0000000000000000
  743. [>] test 3.12: applying PAGE_GUARD to sus address for eflags.RF test...
  744. [ ] retrying after exception, now with eflags.RF set
  745. [ ] AAAA555588887777, wasn't read; xmm0 0000000000000000'0000000000000011, xmm2 0000000000000000'0000000000000022
  746. ------------------------------------------------------------------------------------------------------------------
  747. test 4: data breakpoints on known_data and ss location; movss right before vpgatherqq
  748. [>] test 4.00: using ring3 sus address: 000002AA5D180000
  749. [ ] 5555666677778888, wasn't read; xmm0 5555666677778888'AAAA111144443333, xmm2 FFFFFFFFFFFFFFFF'0000000000000000
  750. [>] test 4.01: changing nothing (ensuring our observation had not side-effects)...
  751. [ ] 5555666677778888, wasn't read; xmm0 5555666677778888'AAAA111144443333, xmm2 FFFFFFFFFFFFFFFF'0000000000000000
  752. [>] test 4.02: writing new value to sus address: AAAA555588887777...
  753. [+] AAAA555588887777, was read;    xmm0 AAAA555588887777'AAAA111144443333, xmm2 0000000000000000'0000000000000000
  754. [>] test 4.03: applying PAGE_GUARD to sus address...
  755. [ ] 5555666677778888, wasn't read; xmm0 5555666677778888'AAAA111144443333, xmm2 FFFFFFFFFFFFFFFF'0000000000000000
  756. [>] test 4.04: changing nothing...
  757. [ ] 5555666677778888, wasn't read; xmm0 5555666677778888'AAAA111144443333, xmm2 FFFFFFFFFFFFFFFF'0000000000000000
  758. [>] test 4.05: removing PAGE_GUARD...
  759. [ ] 5555666677778888, wasn't read; xmm0 5555666677778888'AAAA111144443333, xmm2 FFFFFFFFFFFFFFFF'0000000000000000
  760. [>] test 4.06: touching address after PAGE_GUARD removal...
  761. [+] AAAA555588887777, was read;    xmm0 AAAA555588887777'AAAA111144443333, xmm2 0000000000000000'0000000000000000
  762. [>] test 4.07: using wrapped-around sus_address: FFFFFFFFFFFFFFFE
  763. [ ] 5555666677778888, wasn't read; xmm0 5555666677778888'AAAA111144443333, xmm2 FFFFFFFFFFFFFFFF'0000000000000000
  764. [>] test 4.08: using non-cannonical sus_address: 0000888877770000
  765. [ ] 5555666677778888, wasn't read; xmm0 5555666677778888'AAAA111144443333, xmm2 FFFFFFFFFFFFFFFF'0000000000000000
  766. [>] test 4.09: using non-cannonical sus_address: 9999888877770000
  767. [ ] 5555666677778888, wasn't read; xmm0 5555666677778888'AAAA111144443333, xmm2 FFFFFFFFFFFFFFFF'0000000000000000
  768. [>] test 4.10: ==> using ring0 kuser sus_address: FFFFF78000000000
  769. [ ] 5555666677778888, wasn't read; xmm0 5555666677778888'AAAA111144443333, xmm2 FFFFFFFFFFFFFFFF'0000000000000000
  770. [>] test 4.11: ==> using ring0 invalid sus_address: FFFFF78000001000
  771. [ ] 5555666677778888, wasn't read; xmm0 5555666677778888'AAAA111144443333, xmm2 FFFFFFFFFFFFFFFF'0000000000000000
  772. [>] test 4.12: applying PAGE_GUARD to sus address for eflags.RF test...
  773. [ ] retrying after exception, now with eflags.RF set
  774. [ ] 5555666677778888, wasn't read; xmm0 5555666677778888'AAAA111144443333, xmm2 FFFFFFFFFFFFFFFF'0000000000000000
  775. ------------------------------------------------------------------------------------------------------------------
  776. [+] all vpgatherqq tests done, all data and states were expected.
  777. ------------------------------------------------------------------------------------------------------------------
  778. #endif
  779.  
  780.  
  781. // Beautiful draw.io diagram. Note: not an exploit.
  782. // https://viewer.diagrams.net/?tags=%7B%7D&lightbox=1&highlight=0000ff&edit=_blank&layers=1&nav=1&title=vpgatherqq12.drawio.png&dark=auto#R%3Cmxfile%20scale%3D%221%22%20border%3D%220%22%3E%3Cdiagram%20name%3D%22Page-1%22%20id%3D%22ee5OSJtYosg32hOfD3Tv%22%3E7T1Zl6O4ub%2FGpzMP5QNiMTxWVXdNcs%2FMTSed5E7ykoMNdjGNjRtwLfPrryQQBi0gzGoX7nO6WGwhpG9fF9rj%2Fu3nyDk%2B%2Fxq6XrAAivu20D4vAACKqcA%2F6Mp7ekVVNSu9sot8N72mnC988%2F%2Fw0otGdvHku16c%2FTa9lIRhkPjH8sVNeDh4m6R0zYmi8LX8tW0YuKULR2fnMRe%2BbZyAvfp%2Fvps8p1ctsDpf%2F7Pn757Jk1XTTu%2FsHfLl7PXiZ8cNXwuXtC8L7TEKwyQ92r89egFavPKyPAnu5hOLvEMi84O3x%2F8%2B%2FNgpP%2F%2Fh%2F8f529vP%2Ft%2Fcr%2F9zp%2BogHefFCU7ZKy%2BAGcARH1z%2FBU07ec%2FWwvxxQnN92IaH5C7GG3UPv6BqR7jbD%2FAo8A%2Fe3XO2GviWCqdk4Jvkx%2FBol%2F3FD4mPzoH7lE0YhFE6TLRb%2F2kFF%2FwRHp%2F%2F%2FsQdV13Cm49f%2F4l%2B5jlujEDPSRy09VG4h38wYLhu5MWxh%2B76hySEf972e2VJJgUXMZ1Xea7wMl6T8tUOlsnU6pYJDSb1FECeQq2famjpwhUPfhJNaFW1b87%2BCA8O6%2Fh40bnyd7gv8E8YuV6ENgDtwukQH72Nv%2FU9t7gL6WsPtAtGLbBK74Im2AURFDdCHYBA%2FC%2BHOIlOm8QPDxjUEz8qLN066nC%2FavZjMqD5CJ8HaSECp3CboTRC9oObniDMPx0hNfDQhe0pCN5nWKuBNW2JAUD7jH6YQBaPeWiUUVf%2FsINH3w%2Fh6%2BFuF4bumbQisusF%2FotHQ2WDFxKtTK971dl2iAYadhFA6WEg8d7Q9edkH8ALKjx0An93gMeBt0V34IYlPpR%2B7rPLSYiIwOuzn3jfjs4GDfOKoEB7iMLTwfWQbKFk089kN1XLzh9TeITP1Uz8ya4%2FOXs%2FQOLgP9enQ3KCM%2FzmHGIySHiK8GOekwSKeMBAy2FAoQb9h74QLyGk7QLPOfrxcoNYOryxifFXn7bp0PAwH9wAD9nwrMCUyVDopb23wqVMgPrZC%2FdeEr0j8pHe1TNZLhNmV0Ympb6eRUONfOe5JBZmUqGTiaO7fOizxAYPMqGtgQDHim8lztB2%2F%2Fe%2B66IfNwMBLT%2FPHq3KbH0BXr6Y6N9VgARRVDKQAICBCMyyaIgAVk8AYQrl%2BSOX8LDcQBFyg5fjDmo1XvTjB19MEEkOGfHc5Bt8HlhTFNPUtOKleuoIVnVEttUoqeCQE9R1Le195L27QfMO7utvt6a53Xb0%2BpHzJiescaeiu%2BhfZzsBl1BeeuROaLNRlM1maqChNgEN47MAOiQxY3qvD5q8%2FvnysTuZ5DKeBFbwHD3rG7HDSDGlaTMfi5JHLIb5GDzmQ0SU7qURsTVpvaijrhj03DjBysXOjxNsHki1DTToj9cwQgadceBH1RfYWrVBSg8Ep%2FPZP5CMjL%2BeXfh7ttIKDXFkyIKkk7G%2Fq4dEoNslUNRsVg4CJguKWm%2BCsV5t2GTIYg2Fw9C5d%2BLvKSXex2s%2FIZYGz9k8oz%2BBt%2FcwPfcOzjrA5sUgTI1dW0zlI6gbH8NDpjifv58ZIS%2BTl7hoNYRyODlEgtzy6hHJUJQ6RAK2PiQiGRchUlkWpfAojqBco6yd2CuYjKRMOeml2MNYg%2F7DiKPkjCL298fA3%2FjJ%2BwShngLZTL69epAFRhlkVaAtWcOIanMkEa03SUSsB%2FOhVsImpzdVClJhmogueCgXU3vX33jp4ivhEVlqnABtkBIjxyP6yvo9%2FeUTxPQnK9Uh5FADbv4aqvQuXvzkmeUql7ynrH7W5aqKCIiIx6WUAFKBfeGd201BoOsocYqOJUfi1ImNDTmkfQOCpq6pZWKjskqPRpzwJaVH7YvUWDKk5puXnI7TApPuzLQlAc66Cjii7LbqSpcz3PanO9scMKIAwzu49yioBZ4dwoNXhpHyPsOvPvkBuRdGyXO4Q3yGgEEQvt4f%2FL2D%2FQRn0BiLMsRJFH7PQ2yU5cqo2mbPLUXtsJtctIBwNpFci7wALsCLVxqct7PZE76GPuahNNCQn6SMIftWMRaH%2FJDYbYC51PnwR4ZKnGjnJcxQGLTyF70c2ojg1SLuxxBwzft%2F%2FQZuldBNn66pxAh4DrhjCBvPRQm0nuiaVmOIkTBHKzVGbWEQWdOBqj01tlr21Mg6XSTDyaRxI0p3rQtnPeBYUkpqaRFjuCaYKxYlbcrSorAiAE8C6E1n1RrprK2BnrIYThpEeza8N%2BILVwXUAIwN1CsGqA34%2BYQCgj6t4OeTBT8MaJXBgQcwBaijVd99%2BILs70Qu9iAyFM%2FDxEkK564XeMVzz%2FWLp0G4%2BZ5PJAszL9zeQiG7AFZrxzUcJxdoizFQuq3q1sgAVoFHalfyR1k%2FBxpHsTI4%2Bnl%2FEMjq5yr8fELI8UmDn086%2FNwMBLqGZ7k6DwItsNZGj8LrA%2BY0TamHOXNQqscq87RnG8Xkvj47ifeCzlpz1oaaUQEsHvA%2FCohvwFKoUkBh8AgRL1izL6AgFkihJkT2%2BCyrbeDrI%2FCgZTcFfj6V%2F5OU2a6VrG237haqXxyy9vho209PBRTJFu326Zymjk3nOOljXN%2FuTN96p28aV9AalL6xon4aTjMVy8Y5RqRAWzJD%2BgczdgBzZL1Qr%2FGaNWCGsmFTUPat8lVLmlfWzub7DoPdHZ3IhtyOOH%2FNNtMDoBn8NFWr3vBS5%2FH%2BcBKA63jWdsNVrTeWt95%2BRAkA8NyWw0oArKaDoyQx%2FO9jFICBAzPSQMhZDOg7Jy0PDixF3g4pBhCZY6bsM2WfKfvFdlMeZR%2FUbmqIHbdFaKWiH8sO0KlI%2FkKfZuCsveAhR3xKKUjv4koV1J0bVw80fWT1gMgwxeAnd%2BeRrTvHM305Xy2ARDnm6Zcwx9TfvSR5zwDFOUHJpASNcP2i998WJIIKnvwbnSwNcvr5rXjz83t2Vo5eAiyF2243G9vmUTjbxgQeUslT9FIC58lBU0yeKaQYWUxdGrtU9cVM%2BauN45IO0GpH6dgUBx8C0puM%2BGE6UABxSsHSMSliRa6pDaSTFlHamfRQH41SH0x9I4LFdrtWREZjRXl8%2FAiCBWM05vlBBlUZDak4l9SOXIiwl8%2BBQIPzUy76imvpQS1lJIyy736SHOJy4zVX2uUBZW88gDVel3iAiFBLMoWsOl0j2nwzRNhS1lzt7uMQ4TyVYDpEmLW%2F8wt5tYLCqwpNoXGmD0DQ9XJ4ts5z4XIJX2%2BAwBpw41PcEwQ8PX02McZzaYEytuozBAQASh7jQgAvQr8%2FXZtn6GmhfCuXKd%2BsEs0AiWuuTcPksZgtmG4mda3ebGrXqTeTebdIIhJpsZ%2F%2F3o%2FRm4Ibx105XNFkrZuGon8AcmSSsJEKcrQa0uxs1tSbaFE88xWFJL06h7xuRJSWIkaFJGS0yxaPXp%2FyihV7vIhAWXtYMXU2UDGNfSQ%2Bd14idLRaoDwDJ63glqD5zpgq9W7B2UlAVF1OcX%2B4VGNpaQFlRbA9i4o9YxHWUAjyYvxBGOzcLO5oUCmqwp0FJ48DY1J25SFMEogEE%2FYptNCceNg1qOZk1oWw1efmWQI4%2FOspgeuLAFzG3LS2PcUxyj6Iix99j%2B%2F3V2pb%2BODB35RSc9uUKu10XqxEMOmCbiAv%2BNFpGZH8KZOmSlQZEUORrAi%2B6o0odVtGxHXi59yjPkkOMpFaILptln9yeS0QZqiea4GoSms9vv8SDWNkq19ID%2BeE9UYUtKw0mSpLQQfVmVSFNYfew88nnLaOktVx2npLO9R03HNik%2FzTkzW%2BSb4XbxxVY9UELMwNq0qoCmv1wkCHM9VRfjrOVL8ZoJPwBJbdAWMTul48Qcb0wJA1GOG89SkGyNwY39Pl%2BF5vaRuq0lv6Zgs5qkUG55XDBxUhZZLokAJ8WMPSBlGmVyeW1z%2B8KMxaQKDtnClO%2FxBlsRRnWIhSWb0z88hlzVqLEUkjAkSpfR3HDE%2FUOP36YYSRSTgGLa5MAvqDEnEeUtfdgzdw1SMcMIw9TJgmiWwOI8Kj%2Fhn9%2B5jwaI8Pj%2BIAhcqYYHMNmnZ6y3vmtiuxXzeKdM6JaCAcbC8Obq7sptfNK8jaF8UDwR%2Fh3zVN3m07f6VydZi1ROQrRsQJB7MgBrm4oMXDoHAlKqcLPx2hA%2BXJaxBjL3L6vTpoxFQaGUn%2FUUmaB08S4Tn4ue6zK6b9qqIsy%2B61Fcc4rCnDyqzikJpq6s%2BvUlCSd%2BvIZyU%2BqfamMT7VNqtuNYoIK%2BuJ3CxbDYRf9bI%2Bqe8yjGxFRm4RsKYKoBEuMqLom7eUhy4MBJ%2F%2FJdCJGrXSXVqbnjdnw2SuCqWv4Ph%2FXG%2BkcMBXWdLfo9dKO6s144QtYvRE69xUNzPU9A3Pf%2Fkvmu2fe94%2FbB1otIN1HuQRNs7NNq5o6hhg1xSm7zcyNvPbfsuwH9u%2BQJyrAyFJk2LdMJ0sJNsnXc0XTGk6o%2Fa7VXh6a61OCMyGlsFwfgCsKmA%2BRh5iSMh8gjgtJOM%2BwlnXW592i3PtY0Sh%2FoTVl014Ctwp7vaVb4QTYBXx9xOuOZ12y6yly7IL7W0DZxcva0hpdRBli7VAbRHxEpADEX3t6n3%2F8TTWqzbY9q5edoHi6rchRuKX485Jnr3ox4%2BfLluB3nAO1OJc19JHX%2BPuw5d6saRaWuHzY8PCinGn%2FLg1dLmRxKvyIKn77XwkwqRSLzZe2%2Fn0xNxMHmgp5F6XwpKithtlPiflTVEUDZVzVD8iBHiHNE1LgVLeE7JZryPP%2BX4RGAyo67RYIGDlPFuSec8CcGcCcCry0k0IFOeAjK2ork%2B5GBRvvbrbjSuiWW9h1APxKAghfNs10PUt6FHu8Eo9GkeXO9LpTExouH0WVOhMggeRqJR4Raj7AuWNHyMg72YLwIbTF7Uz5KUKDI%2BOvdeiNUwPAX33TRnF2j0YDh79QxzNWDgAFqbzwfhIXHrqRGFebe6aG3SeV6R%2BsAi32R%2B9H%2B6ihfO1DrVQ4Aav8XeXqAUW00ItUDyaPmPBeQj4504Q3IWHaSp3FWaIxh7ESWmnV2IUcHAACjYNoG%2BnoZNpREyxGlgTOj2pbehtpeXFH%2BIw6pu9yRM0yaouQ0ylNX%2FK2YWE5jryu2YhOl1P6FJLUlQyAI0Pkn0A5qUqQmUDn6EXB0VxPY6wOCIhj5LNZCRb6eDVFrXi6HT%2BmnxXoPwaHlC5XVEhkuzs0m5IxWzcAEkBd64Tff8TQkhv625tsqeaulJNVUN770SbbPIouHYXOHFMpsRpevALXiocdMtUDHBsa6tr%2BR1SMSDt2oNmRpKCs5LDaJ14Ab%2Bimnm9BfGig2xfOojmNaj0TtVi6%2BPlbZ7K0bz9hfPqDDp8pC5O3puf4HksVc3MztFU1KWi2tn5eS7o5L1w8tWLfLgPqB%2FCdLM56ntCZVBYX9s6CzTvrrY1v94W3WhPIw0zmxbuAmp5IF2zywP1XbZL55XtotHtwlJv6OSrk0DoO%2BArQOEWZE8%2FCP6C8PX%2B4O%2FhzoSHKQPs2OXiSDVTtZzZZJFk%2FKZQSA80ePE40ilwyCqolwwpSkPcwA%2F76C94nP4smq2qoLKTnkYV1E7nxauMPtdBHZZYNqjOTNU%2B5xZC5TU46q0Qqqq3Ls%2BcZzZeZODsujiFuoQ3%2F7I%2Fei5S2ICydU4BQsVj5L3AjUO46x8ghz5tMA9GOLo%2FBh46qQvW76lqemeLjRqNdGRNBvLWZEP7STShygDCtn77p2xjXS%2BAAgbGMqx0ow1Gu%2FwKof%2FO9bZwVm72AllLCWzGRkRt2ZBidrZTWnd2f02wUyJ8aYSkACNTCV28N29zyo4hUzx6iMz3u5CgYiE%2FFMg%2FwilnNCzcLrDjUVmQeE0JG1zrtcj8jCuz3UIop6PrJLiCEGSnie8EwfuMizW4qCFc%2FOrsvAJT2%2BJA1FQ29VPWdiaD6ElpQx0oNX1Gj8vyC%2FA3EeJCDjnastczK1nJoCKGvOlzu4olk556I9piCWHjW3gGimoRhjurZqtUV4mnVbBDP%2BLN5WRM%2FNCdhwnxxjlsoKTh1YXojQDNPYJi1XMfc5ZE6A4mOJmc5rmL2tAYwWXhq1TNT5aF9bh%2B1UMTPT5OPMetU0EaX56KK46yAuSFQkX1IydnEW3Sgqms5K8MjpKvWaySn9d16V7LJ%2FbY6mbyWDHiJCGmMT9SQgG5lCJ%2BKp%2BQXDZMBtLh08iihMO1ptBQzHrSV3NDsfQu0%2FmS11DM5JQ%2F6q%2B4mKFWA7OEmCFqqEoA9xkysADbEjI27x9eQlS5P42lLpToiBOoyRTM4JJGIvEEpmSsxQ0QKOQo1X2%2BYsCme1IRE2td0Txg9AXXSp0pluxxQQiB74%2FA9BL%2FiOpoVPEDRleQFIXWeSzMHS0VmVlUi2pnAhfQDL5UJCEU8rSNooCjKArKHC%2F8J4lOV9sgxNkaW25nZtQCAAtTBGYySPmQHUNMyWrI%2FbGs2nbNM2rPqD2jdi1qM8U4x0dt0va9WrWqRTTa4T93%2BPtgHf70ybX4s1ijAe7uh8gP7u6H%2B%2FzdDMV9uP9s3N%2FzKK6p2yhO4vbIqTG9Fn8Wq9zPLf5unKub02vxZwEGDOcWfwMxvtF7%2FFlsyPjc429EAFFXlNDPmupW2qDUgY3mppv8pcL33K9veOjgNOwbGDpYY8%2FcsG9kL9b0GvZZ4hY5c8O%2BDweP4zfss9jGxjKm5rlhH99%2B3fIVvoCFZS%2FuUXhvXbxdeVKIDvTf%2Ba4yv%2BmSHltXAhGXt9CTgKHinbSzXjdvjwNteHOaO%2FeNK7namlTnPpN8ayDxVRyGUITQ02Hz7Bx2FYGvI4oSipJVGpAUJYi2fANQxdh0x%2B9XZ7OOhI683yn1K%2FxOLfGdnp3joqAuZfaaz17zKdvXx%2Fea233EcLagI5c87VLq0kF4aLfxOkxdTdHjJXp81Yu8rRc%2Bm8vT06en0n%2F18vgtkrzHxy8GfPeZ5FVLQRMgeaxLsT3Jm8PWP1jYOlNCZPy4dZu1ZJdrBrw4ke%2FgvPVx4AHkTo4PWHOGynOwOJZmTR%2BWEIotzZyISaGgwE%2FsJKXQLZ2vVUXeUSAn3B0jb%2Bu%2FYT8JhN60fEyhVkwsInLM1PfOwd96aVdZH%2B6ug4lrWizDWfuBn7xLj1Ur8dFi3oqIeYUDYR5vRfED4yEtHpDAH6D57719iOEqLTi1yPL50Jjw%2FXBf8V6CUusoQRnry%2FGmPGujLM7n3igeqbkCtNfKeK8qts0gPlA5diC9L0YBTDZs4qUlmiuAj%2BYiJE9Lr4%2FGiOpMldcsmJTlElu3lyyn4VXW7Y3R5GEfjV2ahsFT4YPQERu70fc55UAkKob0eEm6YEnVcugu%2BscuxylOWWQMMQJ7AZo%2BHHlXMYt1%2FapGkwOj6lgoWORVRjcoqRIEIDhpGBycBCQSZRBnAJDLl7n%2F129g0VZ0EPmV2hSsaK1CDGNMyd6gAyCyKBgyLQ4MkSLLJRDSl71JEiuxCnHkShGs6Atq637BqR25krnU%2BIpkXbH0ms67yBLoNuI%2FOw0Jiyk1HYuZ0mXKWkfTFEVPqGZDW3AOOlUQIE13cjtrR%2FVIHvGHIkhppf5yDRK1oALxQieyBhGCzLsJ2IC7I1uAavRgazqHbg0aYgc4eQUNqZa4BNywREsCw5G5O3U3nQ8E7bQFyLrfYwx%2FuoQMyj%2F9fdSn%2F1HxdDqZYGTidXk0Dp9%2B0dRrbBLUhcBt2Uva7KKoPD1YZ%2BmO2pu0xElXGdruEm9wm4zZ8NK74UVVNDCu3UVTappd5CrenaHOWt4kxCXDooCISEbFLCqVp%2BT1BkSsVxH7bpSp0RDc6%2BrGgkhpmgKJCqvzD0pTiDh%2Fueyci7Z0uJNsl5nLu7S4RWGuxTg%2FOhqnXjseU3IsdorZwHMH7iRp78YqsmPbbIsxJlDae%2Biq0pFqlvVX0qilFOfBwUCtNwwUh2zOGDhj4A1ioE3JRID1oHNRsC9FTgM8FKSgA0X%2FHiewK0VfllwVsJLFUn4DkduyGCO7yCx4YtOgUt5YWzclTYN6X%2BINWNUViOzZeifXiYTvIEZCMHLIMDQXOXglsiQbNBiZzDuvVlk2DS9luO6dq7ztooErzYEXhLsPFYprsERaUXCKhJC1TICtsNSnhiDXc5UBSEt02P01WP%2F4Zfey%2B%2F2Pr4fw63H%2F9Y6k%2BnXU%2F5bXPpx0cL5TlpASLM4tnOFtQL4g38I570ytwuH0Rbk7Nch7Vwv6U%2BMzesim%2BzmR%2Frd3YAlM3TJ0e4WydTTV1rw7tVyQH6hLk2pmK9sV14Drqdvnj0UPXLxJ0hcG6pirGTyOOEFZp0dBBfVDLwsqrBUG8GhJb0Y5FbQXU%2Bp9mFX8EXFHlKEuVPAu4LmZFa89z616iGUJJIaaMev9f6Oph%2FrkUK%2BGlDTi0gNjFi824HI2fU3bMhFmW45zo9OlZHkqZbajh%2Bmda%2FKqin00rsnYbThBr4Mit1GT8TSzzZltTpA%2BmwKUnBDbNHjFim6cbZoz2%2ByabVaYX5v6tmSivV2WSv1oTDWn4SNSUbSLnI%2BIjo%2Fg%2BW2mhYCNfUaaTrkWCLLWEMjeYo41TqbEPnyJZVhvavYp2cLrK0TYQoenKIw%2FCN0pTUdKKFEsLI91MhX%2FUOcvkCzOIX7XZlVGRONs9scpbVSchFOazuBwE56Sps61kXxAJEDuigm7RZfqVPNWZKW6ioBXq1MHvVF31rnjaySfc4yarkS3mXoAbRe8njIzqIDtjEwUnxKvrxCxZaHh90j5%2FG%2F1H59ffn%2F937%2F%2B0%2Fz16fvzL3c82zwFB42KnJULimWqU4hEuwS9sz49hal5ZUSq90zegr2I1LzmM10IbNxNFKeIzV0Bbr0rgE1nDw3aFoAbPSARcNbAvAK%2F%2BuQH5F4YJc%2FhLjw4Adn5IHy9P%2Fh7B9cNG98iQ8c6rCrrMoxtjyEFvqwLTTAWMJfl0AJmqO7MMFxgEzuXZWmfoZbS1AyVT%2Fr28Rre5VUwn8neGHXwp0f3WtsDJ1ZfAvAuLiZXX0JnpjTJ%2BhJWQ717Li8xNifvvLyEQtMse8UreDYo0RJ3FKsySonKncVJGHmVqDHXO2v08LneWVWOSAdIqZp0FrPGK1bVW8EzLlLOlarmSlViSWKuVDWLEiSxNqda6mpsSaLDXN85HuIjx0NQnYcgR%2BZUoR4UssVGpuvkx7NmP2v2Mzvukh0rTA03E4zOkCXSQ6YQ109rdRPL%2FFdpdgRkjTa95eeSdM458%2F863nnO%2FP9gmf%2FV9Hi6if%2FkYUMl%2FpuLUuK%2F2jLxHyzKif%2FpeO0T%2Fyu3c2wfPvGILg1DtVVdVxTb1FQd8LL%2BDeX8UemaQw1KAGjFJH%2Bz0VN6jgdQxQ4NeTZR0eKqYXABVmJw49TCgUj1yGg2uXD%2Fr98K5HnNIdm8plkdNP1q%2B9Lz0B1CQflZza6BGlhpfFkWCPu8PMiia%2FcXvHWPM5vA0L2inkJGPB9Mf9aGlo1YOJDH6oauYB40yrizx0VT4ds2GlH5sxO%2Fpswfced0sb%2B8bZwXJ4E7gq8aIlWmwPwvVRvr5QEBue4UYVHx8w%2FN%2FBusVblI%2FDSZTonHSDBcOjbk2%2Ff3wPnu3f2WIkAWuv8f76DjC0jwfVzIxa%2Bw%2BW7U6yeR%2F93LATFwccPwXxx0DT1KLb5J6buFG%2FIGna6tEbKmcNakUDBEZIl407GVohcPnLUXPDib7zv8JlTiTXo3jOB2UXfQEn57dlysxqdx9P7xz9lqbv0gKLz4E%2Fp8WdDJPcjl%2BOXh6cFesIq%2BphXCjjNHANMLu2DdzY25%2Bvka8RaYOQi061ZAp%2B3wkvGANagZly1E8dK42Wy3yXi33PTEUE06%2FpLbcNbiJmR20aaADwW8YpuXh2BWdpyd4wQvBR7TYIJ3uZ1RVcXgQU9vTj7As9gyIu%2FcGnUqrmLj7Beu7o7K8xR30h2VD0atg7cmFuIyh5zOIadzjEuHhMu0dZpwDdoelU%2B2Wkfmzd1RO3%2F6%2B6hPn7uj3lJ3VHNV9i4P3BuVT3TYuLqX5r1KZ739cr2d2690YLWddLGcG5ZejQhjaGyYLq9nKeBIMKAvMOquiujcIa9eSZlAts%2FH7pBn2Iz9Y8AulXwUFIeMzSg4o%2BAHQMFB21TycZCX8k6Bx5yrUperYtoGQ1y5ecE6T1Tuzc8JeAX3ryR1Q5SusqDiMbZB6DSurXslayDKMnHDEwTMOX%2Flg%2BSv5DS6Wf6KXsoHUNQBCY%2FRbSnKqnQWkp9CWk7qi4szWZSlbeeJKx23sKzc2IlkstzRWjpQliYogJC2Kg8pnbiiLVdgdYZGi35KKXFFpzpk9py4QsStqUtAfYovKiu%2BcLpXmlzhRe%2BJhmhiz3j3fbjq9S6Q6V2KXJRys85exza8vOvWXq3WgheM0KxZ2NHtS%2BS4%2Fd5g1QSuWWuwgbGd51C%2BXGK4om2ZCPOnTROXNgcDNCvprz0Yf1lvrYYf4F1cTC6gaq4ZNMdTXYUz0qTy5idQC1gT2%2BkuiUSvLgY8sIVmKgbjLiDH4MRD8GKIVZUrPPUGPzrPkfbRVVh%2BK%2BlhpVp9yF7Ssw4767C3qsPmFG7KOqx%2By%2F2tK7dl1mE71WENnjHkmnXYOSloTgqaldhOldgVI%2B6qbEvTYdtwzWVvOwklslglk42VHjiSyLjBwreLOZJojiT6WJFEOYm%2BnkgiXprG5TrVrUYSkY2diCLGCSRSOwkk0msCiUpgOnAgkdE6nWFiWtvseZw9j7PS1qXSRrc8NMHIKltdggABnzMKpAmxRYGz1tauqqKcpUewuIe4hioZGrQ4Xou%2B0k%2BRkGIhnMN%2FHb1W7L8l7y%2F%2BC9xUxw9iTEua0bSGb64I31x5RHTs4d%2BITC6zEr8v6hLUT6jbdOnLKy6Ukp6nI143R37StiAvg0jEk6Lj2FpxsL9C%2FBJgPzyNQgQKZ%2FkGLvXzr6HroW%2F8Pw%3D%3D%3C%2Fdiagram%3E%3C%2Fmxfile%3E
  783.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement