Advertisement
cakemaker

vpgatherqq demo

Oct 22nd, 2024 (edited)
28
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 20.10 KB | Science | 0 0
  1. //
  2. // vpgatherqq.cpp
  3. // Compile under msvc with /arch:AVX2.
  4. //
  5. // Demo: using vpgatherqq instruction to cancel impeding pagefault.
  6. // Src: https://x.com/sixtyvividtails/status/1848701990508925098.
  7. // See end of this file for the draw.io diagram.
  8. //
  9. // Instruction features:
  10. // ③: catch PAGE_GUARD or invalid access
  11. // ⓪: do previously illegal reads at high IRQL, safely
  12. //
  13. #include <conio.h>
  14. #include <stdio.h>
  15. #include <stdint.h>
  16. #include <immintrin.h>
  17. #include <phnt/phnt.h>                      // https://github.com/mrexodia/phnt-single-header
  18. #include <Windows.h>
  19.  
  20.  
  21.  
  22. #define PAGE_SIZE                           0x1000
  23. #define PF_AVX2_INSTRUCTIONS_AVAILABLE      40 // 20Hx+
  24.  
  25.  
  26. static bool is_avx2_available()
  27. {
  28.     if (USER_SHARED_DATA->ProcessorFeatures[PF_AVX2_INSTRUCTIONS_AVAILABLE])
  29.         return true;
  30.     // if OS is below 20HX, this kuser bit may be absent; use cpuid
  31.     int regs[4];
  32.     __cpuidex(regs, 0, 0);
  33.     if (regs[0] < 7)
  34.         return false;
  35.     __cpuidex(regs, 7, 0);
  36.     return (regs[1] >> 5) & 1;              // AVX2: cpuid(7, 0).EBX[5]
  37. }
  38.  
  39.  
  40. #if 0
  41. // intrinsics produce fine code with /arch:AVX2, but we can't predict used registers, so let's use asm instead
  42. __declspec(noinline)
  43. static uint64_t __fastcall read_using_vpgatherqq(const void* known_good_address, const void* sus_address)
  44. {
  45.     const int64_t* src_base = nullptr;      // set src base address to null for simplicity
  46.     __m128i mask = _mm_set1_epi64x(-1);     // set entire xmm reg to fff...ff
  47.     __m128i index = _mm_set_epi64x((uint64_t)sus_address, (uint64_t)known_good_address);
  48.     __m128i dst = _mm_set_epi64x(0x5555'6666'7777'8888, 0x1111'2222'3333'4444);
  49.  
  50.     _ReadWriteBarrier();                    // ensure compiler abides
  51.     constexpr int scale = 1;
  52.     dst = _mm_mask_i64gather_epi64(dst, src_base, index, mask, scale);
  53.     return dst.m128i_u64[1];
  54. }
  55. #endif
  56.  
  57. // 00:  48 b8 44 44 33 33 22   movabs rax, 0x1111222233334444
  58. // 0A:  c4 e1 f9 6e c0         vmovq  xmm0, rax
  59. // 0F:  48 b8 88 88 77 77 66   movabs rax, 0x5555666677778888
  60. // 19: c4 e3 f9 22 c0 01       vpinsrq xmm0, xmm0, rax, 0x1
  61. // 1F: 31 c0                   xor    eax, eax
  62. // 21: c4 e1 f9 6e c9          vmovq  xmm1, rcx
  63. // 26: c4 e3 f1 22 ca 01       vpinsrq xmm1, xmm1, rdx, 0x1
  64. // 2C: c5 e9 76 d2             vpcmpeqd xmm2, xmm2, xmm2
  65. // 30: c4 e2 e9 91 04 08       vpgatherqq xmm0, QWORD PTR[rax+xmm1], xmm2
  66. // 36: c4 e3 f9 16 c0 01       vpextrq rax, xmm0, 0x1
  67. // 3C: C3                      ret
  68. #pragma const_seg(".text")
  69. const uint8_t read_using_vpgatherqq_asm[] =
  70. {
  71.     0x48, 0xB8, 0x44, 0x44, 0x33, 0x33, 0x22, 0x22, 0x11, 0x11, 0xC4, 0xE1, 0xF9, 0x6E, 0xC0, 0x48,
  72.     0xB8, 0x88, 0x88, 0x77, 0x77, 0x66, 0x66, 0x55, 0x55, 0xC4, 0xE3, 0xF9, 0x22, 0xC0, 0x01, 0x31,
  73.     0xC0, 0xC4, 0xE1, 0xF9, 0x6E, 0xC9, 0xC4, 0xE3, 0xF1, 0x22, 0xCA, 0x01, 0xC5, 0xE9, 0x76, 0xD2,
  74.     0xC4, 0xE2, 0xE9, 0x91, 0x04, 0x08, 0xC4, 0xE3, 0xF9, 0x16, 0xC0, 0x01, 0xC3
  75. };
  76. #pragma const_seg()
  77. uint64_t __fastcall read_using_vpgatherqq(const void* known_good_address, const void* sus_address);
  78.  
  79. // to support X32, you gotta adjust asm code above (just a little bit)
  80. #ifndef _M_X64
  81. #error unsupported arch
  82. #endif
  83.  
  84.  
  85. __declspec(noinline, guard(nocf))
  86. static NTSTATUS test_vpgatherqq()
  87. {
  88.     if (!is_avx2_available())
  89.         return printf("[x] avx2 is not available\n"), STATUS_NOT_SUPPORTED;
  90.  
  91.     // note we don't even have to touch this address, as it'll be right-most in the index register
  92.     static constinit uint64_t known_good_data = 0xAAAA'1111'4444'3333;
  93.  
  94.    // prepare suspicious address
  95.    void* sus_address{};
  96.    SIZE_T size = 2 * PAGE_SIZE;
  97.    NTSTATUS st{};
  98.    st = NtAllocateVirtualMemory(NtCurrentProcess(), &sus_address, 0, &size, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
  99.    if (FAILED(st))
  100.        return st;
  101.  
  102.    // prepare #DB trap
  103.    CONTEXT ctx
  104.    {
  105.        .ContextFlags = CONTEXT_DEBUG_REGISTERS,
  106.        .Dr0 = (size_t)&known_good_data,
  107.        .Dr7 = 0x0003'0001
  108.     };
  109.     st = NtSetContextThread(NtCurrentThread(), &ctx);
  110.     if (FAILED(st))
  111.         return st;
  112.  
  113.     printf("[ ] allocated sus address %p\n", sus_address);
  114.     auto read_using_vpgatherqq_fn = (decltype(&read_using_vpgatherqq))&read_using_vpgatherqq_asm;
  115.     for (int tries = 0; tries < 6; ++tries)
  116.     {
  117.         bool debug_break_failed = true;
  118.         bool sus_data_read = false;
  119.         uint64_t sus_data = 0;
  120.         printf("[>] try %u:\n", tries);
  121.         if (tries == 0)
  122.         {
  123.             // initial try, do nothing
  124.             printf("    memory allocated, but we have not dereferenced it yet...\n");
  125.         }
  126.         if (tries == 1)
  127.         {
  128.             // do nothing; this demonstrates we have not triggered #PF through initial read attempt
  129.             printf("==> changing nothing...\n");
  130.         }
  131.         else if (tries == 2)
  132.         {
  133.             uint64_t x = 0xAAAA'5555'8888'7777;
  134.            printf("==> writing new value to sus address: %016I64X...\n", x);
  135.            *(uint64_t*)sus_address = x;
  136.        }
  137.        else if (tries == 3)
  138.        {
  139.            printf("==> applying PAGE_GUARD to sus address...\n");
  140.            SIZE_T gsize = PAGE_SIZE;
  141.            ULONG old_prot;
  142.            st = NtProtectVirtualMemory(NtCurrentProcess(), &sus_address, &gsize, PAGE_READWRITE|PAGE_GUARD, &old_prot);
  143.            if (FAILED(st))
  144.                return st;
  145.        }
  146.        else if (tries == 4)
  147.        {
  148.            // do nothing; this demonstrates we have not made address accessible via our read attempt
  149.            printf("==> changing nothing...\n");
  150.        }
  151.        else if (tries == 5)
  152.        {
  153.            printf("==> removing PAGE_GUARD...\n");
  154.            SIZE_T gsize = PAGE_SIZE;
  155.            ULONG old_prot;
  156.            st = NtProtectVirtualMemory(NtCurrentProcess(), &sus_address, &gsize, PAGE_READONLY, &old_prot);
  157.            if (FAILED(st))
  158.                return st;
  159.            *(volatile char*)sus_address;   // gotta dereference
  160.        }
  161.        __try
  162.        {
  163.            sus_data = read_using_vpgatherqq_fn(&known_good_data, sus_address);
  164.        }
  165.        __except ([&](EXCEPTION_POINTERS* exptrs) -> long
  166.        {
  167.            auto* exr = exptrs->ExceptionRecord;
  168.            auto* ctx = exptrs->ContextRecord;
  169.            printf("[ ] exception %08X, rva %06I64X; xmm0: %016I64X'%016I64X, xmm2: %016I64X'%016I64X\n",
  170.                exr->ExceptionCode, (uint64_t)((size_t)exr->ExceptionAddress - (size_t)&__ImageBase),
  171.                ctx->Xmm0.High, ctx->Xmm0.Low, ctx->Xmm2.High, ctx->Xmm2.Low);
  172.            if (exr->ExceptionCode != STATUS_SINGLE_STEP)
  173.                return EXCEPTION_CONTINUE_SEARCH;
  174.            sus_data_read = (ctx->Xmm2.High == 0);
  175.            sus_data = ctx->Xmm0.High;      // proper if sus_data_read, otherwise just original xmm0 value
  176.            return EXCEPTION_EXECUTE_HANDLER;
  177.        }(GetExceptionInformation()))
  178.        {
  179.            debug_break_failed = false;
  180.        }
  181.        bool expected = (tries != 2 && tries != 5) ^ sus_data_read;
  182.        if (debug_break_failed)
  183.            printf("[x] debug break failed (should not happen)\n");
  184.        else if (sus_data_read)
  185.            printf("[%c] %016I64X <<< value read from sus address (%s)\n",
  186.                expected? ' ': 'x', sus_data, expected? "expected": "UNEXPECTED");
  187.        else
  188.            printf("[%c] %016I64X <<< orig xmm0[1], sus address was NOT read (%s)\n",
  189.                expected? ' ': 'x', sus_data, expected? "expected": "UNEXPECTED");
  190.        printf("-------------------------------\n");
  191.    }
  192.    printf("[+] all tests done\n");
  193.    return 0;
  194. }
  195.  
  196.  
  197. int __cdecl wmain()
  198. {
  199.    NTSTATUS st = test_vpgatherqq();
  200.  
  201.    ULONG dummy;
  202.    if (GetConsoleMode(GetStdHandle(STD_OUTPUT_HANDLE), &dummy) && GetConsoleProcessList(&dummy, 1) <= 1)
  203.    {
  204.        printf("Exit status: %08X; press any key to continue...\n", st);
  205.        _flushall();
  206.        int c = _getch();
  207.        if (!c || c == 0xE0)    // arrow or function key, need to read one more
  208.            (void)_getch();
  209.    }
  210.  
  211.    return st;
  212. }
  213.  
  214.  
  215.  
  216. #if 0
  217. Sample output:
  218.  
  219. [ ] allocated sus address 000002993EEC0000
  220. [>] try 0:
  221.    memory allocated, but we have not dereferenced it yet...
  222. [ ] exception 80000004, rva 001030; xmm0: 5555666677778888'AAAA111144443333, xmm2: FFFFFFFFFFFFFFFF'0000000000000000
  223. [ ] 5555666677778888 <<< orig xmm0[1], sus address was NOT read (expected)
  224. -------------------------------
  225. [>] try 1:
  226. ==> changing nothing...
  227. [ ] exception 80000004, rva 001030; xmm0: 5555666677778888'AAAA111144443333, xmm2: FFFFFFFFFFFFFFFF'0000000000000000
  228. [ ] 5555666677778888 <<< orig xmm0[1], sus address was NOT read (expected)
  229. -------------------------------
  230. [>] try 2:
  231. ==> writing new value to sus address: AAAA555588887777...
  232. [ ] exception 80000004, rva 001036; xmm0: AAAA555588887777'AAAA111144443333, xmm2: 0000000000000000'0000000000000000
  233. [ ] AAAA555588887777 <<< value read from sus address (expected)
  234. -------------------------------
  235. [>] try 3:
  236. ==> applying PAGE_GUARD to sus address...
  237. [ ] exception 80000004, rva 001030; xmm0: 5555666677778888'AAAA111144443333, xmm2: FFFFFFFFFFFFFFFF'0000000000000000
  238. [ ] 5555666677778888 <<< orig xmm0[1], sus address was NOT read (expected)
  239. -------------------------------
  240. [>] try 4:
  241. ==> changing nothing...
  242. [ ] exception 80000004, rva 001030; xmm0: 5555666677778888'AAAA111144443333, xmm2: FFFFFFFFFFFFFFFF'0000000000000000
  243. [ ] 5555666677778888 <<< orig xmm0[1], sus address was NOT read (expected)
  244. -------------------------------
  245. [>] try 5:
  246. ==> removing PAGE_GUARD...
  247. [ ] exception 80000004, rva 001036; xmm0: AAAA555588887777'AAAA111144443333, xmm2: 0000000000000000'0000000000000000
  248. [ ] AAAA555588887777 <<< value read from sus address (expected)
  249. -------------------------------
  250. [+] all tests done
  251. #endif
  252.  
  253.  
  254. // Beautiful draw.io diagram. Note: not an exploit.
  255. // https://viewer.diagrams.net/?tags=%7B%7D&lightbox=1&highlight=0000ff&edit=_blank&layers=1&nav=1&title=Untitled%20Diagram.drawio#R%3Cmxfile%3E%3Cdiagram%20name%3D%22Page-1%22%20id%3D%22ee5OSJtYosg32hOfD3Tv%22%3E7T1Zc6s4ur%2FGdaYfkmJfHrO5e2513znTp2du97xMYZAd%2BmDjAHac%2FvVXEosBSUYYsSTBrkoMNkLo21ct1Ift6cfI2T%2F%2FEnogWCiSd1qojwtFkU3ZhP%2FQmbf0jK1Z6YlN5HvpKel84pv%2FF8iuzM8efA%2FE2bn0VBKGQeLvqyfdcLcDblI550RR%2BFr92ToMvMqJvbMBxIlvrhOQZ%2F%2FP95Ln9KylmOfzPwF%2F85zfWTbs9Jutk%2F84e5L42fHC19Ip9WmhPkRhmKSftqcHEKDFq67LkvFtMbEI7BKeC04P%2F71%2F2Ug%2F%2FuX%2Fx%2Fnn6Uf%2Fn97X%2F7mRNSUd5%2BgEh%2ByRF4oRwBHvPf%2BIpp28ZWthvBzQXO%2FX4S65iTGk7uAPZHUPoX0PPwX%2BDtw8Z6uBv0JQ1PGX%2BcXw0wb9l2%2Fh9w9f%2FwX%2FRsDxYoQiTuIgEEXhFv7DAPS8CMQxQN%2F6uySE%2F07brXSbzxA%2BLJ5kOqTAeRsqa975TdBgGO2CMKrcZaGoNn6VT3HMRslmQ7mhs93DD7tVvL%2FqWPoVLjD8F0YeiNBKouU87OI9cP21D7zycqaPVX3U3lbZZGJHbZX571IfSMFoBn8MiQQ9drjOcAhh185LDxCqHfYQ%2FT72WqhoLSB6PqIZJJBdY34YZRTo7zbw0%2Fdd%2BLq72YShdyY%2FRJog8I8gKq3PKuo0l0GWubeVHGcRlMrNlASc0PnnZBvAEzL86AT%2BZgc%2FB2CNvoEAS3woye6y00mI%2BMHrs5%2BAb3vHRcO8IixQ76PwsPMAkhNSNv1MEMtqdvxQ8DnVwK9iRmUBlMkkdGNwKp3KBNKPINyCJHpDVJd%2Bq2WyMVMOTDMb4fUsatX8N89lMStlJ51MvG%2BKoc8SEH7IhGALgUiKw7%2Fv4iQ6uIkf7rrDYOt7Hrq4HRjU4ji7tZwdL52tH6DF%2BwkER4DuRMLryUBvMfCCLKoML0UhwIUZWR1citUTtAym8rKnUibJdyUm3z3uN1CFA9HLC0Wk0k81agaSZBiq2k4zUMwmLtRplFQYFhxn1cicHmjPrnMpRuu1YazXgh4%2Fck4NDPTSVDQPvYVBAi5hGQeumJDrSpLrTg015DaooT8ysIOTMqb3%2BEqbxz%2Bf3osT2tcJDGieqvfoXt9yo1MWIwCsmsC2CAGg0wSA1pu4Zpuvq0UTh8Pg9%2BIEa8AbP06weZSqxGjQl1doMsVjwVDW4HEMf4w0cwjS89FvSJHDP89O%2FJqttFSHej5kSR3IRJAYdUCzK%2Big2qQ%2BoBgkOuS%2FE48O2mVvBsEeGigdY8jWib%2BnHGkbr%2FwktyKB4z6jfwHYAszXwM5ZBdhXEYSpwb3G3C6CRtQ%2B3GUW1vn3mUfjOr2BitpDWBGTQ2YoNYQgsy5JTcis2NqQyKxfhcxVvaiGy3EEZay0cmJQsu%2B57O70VAww5qI%2FGHmlgmHG%2FnYf%2BK6fvE0Q82pok%2BlagkyiKtrIinqrk2zQpkhFtTepyLaL6JjD4cTQ2iqJqXKVi1E8lIe5nue7IEU6Kdwjs9oJArSgMfK6o5%2Bs3tIrl5DallaqU%2FKhpxtuV9DE8%2FDiJ88kd73mOXn1dZGryiJiFq9PqRFS4rb0zN2mwNB9pTg8RG6JfSCJN3WCt6GksAUpPZoqVwleJpVgNY8CVZRguS9yt3jI%2FRtIDvtpgUqMX6uiSFiiuHoVxhRDh%2Brp6s%2FQsSkwrkEN7Lw7FPKER7twB6oArAKBuUTAq8RDyQUqm3qUBcjPRSBwEv9YjaLSViW7w9fQxww6X3CrtpAp18l%2BVY5y5hfmBmou%2B1gDJU60AQkxEAZK8ZjXwymX6R3iqTqDId%2F9%2B3flI9KvAHIt6LPgySpBr7Q4gqL2RK5qgyHK4ZaSGpxbkO3thAx02WNry1WPLa%2FzFZ5OZyjIHI1SqImIaikUS7IwCeroTJigAtDVrlmaEildaMKlN3tBbWUvdEa8mtdi0mjSowOuimnCsaqIuo2GVSaBVTp8fUHh4y8mfH2x4IuAbRUeNIiVwF7X%2B7fhETnhcp0HQGwsH4eJk5SOPRCA8jHw%2FPJhELrfi4lkCWalr9d%2BEJTgunI83UFyLk6i8DsoR8w1W9YEKaayWbU%2BFJWimeoU66M%2FMJPWhwxfXxAGflHh64sGXx8GzJ4OLE%2BjgdlSVqqoxAhVlZrBbAxKzaQBUg%2BdPKD5PTsJOKKjziy7pU5agsQ9ftfwRpD5L9cAo9Poj5qy0hNgcrcCU9XM1%2FksiF34%2BAhEdcEswdeX6h9OgfxeqXm99tZQv6VQ88ODbS%2BXJTTNFq0X8lYpPqRhyZuSB0yNFXwSslapYnVQsia1pzRMORWLqYi9lUkq8zuNYEQpxsjqrtbghW3Bh3lDwlDbYF57YAYIrYbIAnFlzcL%2FdELCc4C1dqmavWuB1XogIUHLthlYSJA6IE6OwJrfNkbxJhyHSvMfPqikqOUsKzYFKsqQkiIXSxNhPARLOdAYD43JNIU5Z8YzDOMhfAw0xjOoj0Fnu9PLCFLLRai6paeiNzE9zYGzAsG9437f4PFqKlX6La7hqn0zhIdaG1m5ysVcOdrpbUC%2BfGGUPIcblEnydD5bAgta3vNvfg6x%2Fxad%2FBMkyVsGLOcAhVcFI%2BD6RW%2B%2FZ6uKD%2F5AB7d6fvh4Kn%2F5%2BJYdpeSa14sqNLPTdW2bRti2jfkaZA6H6Ngcrs2SMS5QThbITsOel36YQbgxAMwd2e1G8WTymw%2BBeeKRUIYDZZRTSeGJ88Li%2FJzcQoB1yB3KBFdzrIwjxedvJ%2BuHDyPa1uuVxHK8SNLDw0A6tUpz3w2qU%2BtcsbfUF1PKuOLPiUOD01Pw%2Boq19aC3EzKuGpcTofTUEIOq89AQozcOSDqAKhyQxaY4WWJWht%2BKM300FmRJK6p23SsLKvLGpsOCSM8VvQ68E%2BDHCKNpteRsjeZnpyUG9bfWpAslPsQ9LfJy%2BWhgPKZiuCTIVlDUqS2yQTMXO5gP0nXmA2kGEHDwjJWhGzTetFYuVyg0av6G%2Bj41%2F3zelxWix1%2F7cf7UwOB4pkMVESvN0CVNDAEZeXLvBQIyh3S3GA2VRx16XryiYOKrsysqiKK0OQ0qKeLRaTvcenUoape2eBEVaQWwOuy4UB2OfaQpCO%2FsMVoLD5pToa5WV%2FLZbvSe5AHFeURNnu8PnxtsrA6QLqPOWYb3jMlYO8sJCOMwoiLnw%2BKvChXCS%2Fi7oGRnYmzOztyHSRJuF8K8o4RaScNwqrHYG4aTxmJbZONME79%2BIEVC5dk8DTK6TPah%2F1twtvm4%2FhZH%2BVYqU%2FIAPbNkUdBnDvSgLO5sUSvHni5XPT3kNPBd9RBffc%2FYPyVvR%2F8Iad%2Fxg7gZTD09%2BcMAmPmAbnL%2FB%2Fyj3dZXujuLaYPrQnsdiPdkFtVNlXKo35zncOuIEUJG3lq1qHnKsw7KUshSh5RCTSlQzTUjFgNF%2FnFIXDhLTvpe2UBy9Hb0zbz1Hf6%2BP97LvPHgT1rzRHVpZyV0XqR9NulmJ4qVHwsraxblqquWNeuUMklqv0WzN44htqzZc%2BLnIuDPXK%2BJ1DjrUq369NoaZ2KgnmucZanBRTeF6tYxigyvZBfvrM5QqRq%2FhkIykUG9O7JEuvvv4OsLrjZENYa42pCA73uNW7KjOsulJSyqI9faYeH%2BY6P6OGSJdEtjOONyQ1RkiMsNPwycOUKk1QiToB6P9Y5WU4A86cDFxYcjGnh9ppjXOazOx2F7yzCXpd6KkTqIzKvrkUQwxyqAKLVH1rAEwqrMEBIO%2BAtEYdYtFa3nRyW7OlRtkuyGhapM6tlZuDTbJKWcpjMiUIotARjxmVxt1XoSUBQzliqglP4gRaqgbgDgQyJg4TAdpqExgaQ9ovdoQDKl8YHETmu4mDtprJS2XesvbefTojdj0yjcnnfWQDgxmJ0EenFnADGPwGvosweCF%2BHrGkx94fOXLq4OsZYochIjToBTYBDnXhDO7InhFaslmLjdrWoe5za5yIxfvzrxIs8qGkk7lZULIpKWktCHqxfa77dVb69JcdSo0rAKDTsR5zIHppecVpShJhZ2Eadl222N0427Q3UahUUZzYzm8%2BgYhI%2BKpgjmRevD6Bj5yAIScVrtpwiVTcT23FOWB6CnSWL%2FzREI7c3SuFFga2lEOt95d0TMZfd9Nms8Xtmc6THXpcsCe%2BcFhhTaanknu%2FxetvwthXEvEBC4DyLv6piGaeg6%2B4aczpOmiJaQhWyDsYOQRW9QsSRLQlVQdJzdRwBJjkWxkeXfnDg%2BbNMtVrCCfcBtq749%2FbTId6jAW1%2F%2B0AAOccAWQB710bfhsU82YVk4zbajQsOavBe1t5ewPJO6s9apHY%2FF6huQf7DZZETbUd6PoAWkFOhFZoqf0kmSJBW1opFnpOl7Nun%2BWogrwJkg58kK2n%2Ffr8Kcd6mnIBv4InuekJ7ynnWLdI%2Bret%2FLbLtwVIJf7Z3w7rSIU6YNcbhFFE1bK5X1FJDk3WkU0HJjJMSl02smpgJ8FOlQ6hKLh%2BXoddMDTh%2BhYH7hxGp3rShu23hOv1jddqfdd6Ucj4WZvneSRvErEci593dx9NnQM70II2ruNJNHRQb5gpfrPehOJFq52z148TjxCqmPrcPYveOVcg1eKeVPU2E36TbBaEAnCG7C3TSVxCsMGWpV3iexBRwc8sEWAcK4NGifxqDK3SvaeM4nbRv0tsyyg940JrZxkmcQvZTF4xX1ZrKjqpeM4w4PRK0nYbD5QRwkrLUsIlMd1lGoyde8S9yAawOhd98Nx4RqZhd7FQ%2B9OCh8yV8%2B3r96UVMMeHQq7qyHDq1J6gUieQZEUdf588H1PRQnfgh3cYhzKFilXNnRtU2f6zVB98u7pYmeMnKz2aG0i03goP3d0%2FtS2mf%2BjNcCp2MQRSbmo3GnnpuWlYtM0M3zdPqs7RkrEaSnDiy6XM1tKjI6SpkfiqWTmR9ynqrfQ%2BoHucnZZ%2BpRDU5%2BgudxK6tGdoymIt9Ksp0dn%2BeCDt5KB19B5EM4oCabXTteZ7UqzX3vssQgcX3v6OW69Xb6ql1DQd66X0WuDqRpA9f9arS63zrKX1mtjQ6%2BOgnEgB0%2Bo0jUhonp6xKCjF3dnfeIyksCMmDZea5aW6jXB9IlLU%2FsHAzutH6arQyO9n09rhmSlbDswhd566cp9%2FUgJz2Nvh5C50XrvDh39rhKIdJqTReprT1oXaV7a%2B0hN26Ixp8c3cpVJN%2FC7%2F%2B%2B3QMvTQdbO4cA4fM%2BAke4wIgA%2FB0ULAc38cMdRvTtPgDo4Lalk6Zt%2F0RhT4%2Ba5HI5yjgdmd1qRroGiJYZhDwQQIGL0RrbPAhSCFyvEN1uPLCGy%2BCls4myBq7pdmOQxG9b8g9hkFDFuSxZ2KRghK6gLDgB95B9htx9DxC%2F6ncNFPYacCfDvAtshLZ7kvGJcL3AYQZpked%2FpJ6JLhI002DFPO5h7zkJ8CY0IyjFEt8JoDCcyIQ%2BMmdQEWf46mxAScylyc6pyuenwu7MT5GTL%2B2DjbOhF0X%2BNP4lYiNQZo62Ylr%2FK8bBD3pyyTLvL%2BR%2B7OeVvoUl7OAhP7YPvQj6pieg0YnQxnV2LpTQiA21jOWmPDVHRYyDmQ6QbVQUJ8DxetDKpuJRrtkXct7ZglY5KsJKqG1ealIalxRbX1fcpv1VzDVtX5qCAyt6lLTxNALLxZvyUymypWwyTyXGqJcOn8Z5kzPNjI8d5dZPS82cUit0Yu8KarN%2FmcSo%2FoqMdfkyQnFwENZGfjnyPEPGFWD7JGOB%2Fu4YotZeab4T2PiQcUUxvhfUz0qOJk4Wxp7AlNwhuENaDUGLBj0CkKverpSyJxu1gF3R%2B8ItadhN3puyGggpS2yrzGyvsSpijjfZrbFdvVn9DZtzCI8xePAHXf%2BBio4cHTbnjZ65Nnpe6%2FSNnrPdtilb0Q3T%2B88cvfdf42ZEM8nNJPeOSY5oYjE%2ByeWbjV1WyRvxvR4Gmls1D92qWZtcr2aLtPZwm2ZEcrhNM27Y%2FGG4zP3do353R%2BMyhmajCJkQFqJPr1ezRRphc69m8cLDmF6vZkshIP%2BRezUTLHb0Zs0WmaX1qZs1a7WNkmjdmnOdayASIfOp6t2aU0XnkzReJiBE6bw8MIRIo3PuvEwRN%2BN3XrbIlpKfvPNyHUgT6LxssbcnvVxTMndepvluOj7Ck7Kw7MUdSmqZYgvji%2Bmn1zRqfScYcX0vZA4cKn%2BTtkgW8%2FQ4Ukqb09yCWdFslasFs3FLKVTqUbdhx7DKWHLYuc%2FOblPJ6qji14giVZIu72hfFqlle0ISAFbC2zJ%2B12G7qevw1TGSlAWUrpMrzFdYCKVFTFwSHkeZAybvKWBCGCHjB0zs7iknZNLahyBaVSjRLjsSbWtdjZVKuFwuvywrf5oVto%2FIFB7vnqwldS%2FKgZkCIZQnwBRIR3hbpjDnoU0iD40orhs%2FEc0m3V7VCqGjE%2FkOrmIZByZK4ZWcWqlkLavQzjeladoEvUdOwXaPta3OqhMq5AGHwEmJPUrrIUvFj7i4zodPzVcYgLRcWiX1r09f2U6IfQTWPupUuXV2%2FhrEqYICcQDNSmRhGsWfggpanJUf%2BMkbnkm4R7iNOrOdC2ESCGO0PluwDREwiXqwtEZ5kSWJo6qV88w52WiT76g3Nlolz2rmCs1dwkOchTubxg9E0Gett4ss2TZJoTolHqT1R6GtMqIKNfTu378r1S4DNA31csHCT078mk4R6aPclz2dXOfoJLjKAV6olzG25Qz4L%2B3sEeKtiiAxuZxyIaG3GGQ08mYtubTQzdxbV9YsJYXERl29NdSeEFKRGjw%2BbIS80eXOOPkfsNMwXp3v2njNt%2B9vgfMd3PyeIqTZGv3a1RDXchSh8PsOilUI0uLynx10Dj1GORBT%2FW2DXfcpacKqqsOyJNs0olAoSlRv7SYUg0yqOPKgjuahN4k6ewbk036Vo6nVl5zhIoRvtZzLNgwKZO0hteMi86N18FjXaQ6tIHTYIQ1KO3WODut8V119qqnDcSu0PsSpFRBDLMSxnbbtEVDcGlsRnn9pI4wByUMA2stGlaXZpkrBe0UzKDZ%2Bf4jfoHR28N9gxXRaufWFE6eTw0AALpjVZDTbUiioQHUQ9KbtmWwHwZ6KB2RvBaXorSDVkKSpTRmc8v5K2zwfmtLr4TyfrgkVrPlrPGzSddv3M2MvmITgzJQtFifrFjun5YKZCII8X62iFpdQrhNWDaYk1%2FhGZjdUGBEqyqjWz5cSC2hJI1kXXUrxz42oGrE8llBYoTTxRONJ%2FUknSoVHS55kMVmS2R9LMtksSWKypNO22GCcz%2BPHeoC37fYybXV%2FCnZjvL9EPYUA9tAOwkOrJCUO8YBfVQ5h1jmEKOMr1yAukrlM6c%2FSn%2FVFKeeZVY%2Bm%2BXMZqH2oHixJr01N9bA%2BjOaxyjSCnpSPklZR6B5lhWQE5cMeXfVge4Rm1WNWPWbVQ4DqkZfsjKd4DOTPj12868CgHsvxHPqypJK5S8P6822x%2Fvw4CSN29%2FjZof9JHfq6VcN7bXR%2F%2FoU0L061ham1NCZqcmc8swby2slv5jgvgsZpth%2BuEeJFkrLAmIYLjx0IyXxrI1Jxr1YoUfQAScJ6gAC6UKW6PMg3dynTxaDa%2FIXcqtnDMLngxgWDfloehjm48W6CG2qNJSkjOxhUqXNs4xOypNnp2cSSZqfnO3J61pkSNRNuYLbUeR%2B%2BSwlBODF4zglilBfWsIHW5U2heFH6SglSJbIALAL7RY5803FknYldYA%2BGuldLpvQ4GrSGS837%2BfVg3PNuJNncgZd3y0y0wy8tnb6lE4A58ZZOgMYFmLQTAG8a2ewEECG0pJoT3yAllkqjCmJHWYF00VmVnulipouudGHUxLdKqfkdmDAUGmHUYIEaZuz5FwBhbblhwyLTRflD%2B4bGqeT2VmqpmE37PfBY3%2Bx4Oo9BiNQWlHLdxiBk1vh6KL7C0c%2BtRURe9POaZta%2FSMTzvvA872CzKTNUXt44hY4WlBI%2BScIdepg8k8kvG%2FhPMxsdjxeQRg4BEbDz7qIIb62QNZAuAae6wODkJ7%2BXPv9R%2Bvx4Kh%2B8UUBiEkv952G7z74lO7xLt%2FoV0ADeBvDCgtbOJj8XgcBJ%2FGN5LDqAsjt8DX1MkZkgqF8Rh4fIBdmPzlA9X3eqogJjmMSJNiAhhsHIUTxjF5mqTEGm1j1HFGVjWDKyZ5E6i9RZpPYvUhUGE5mQSKU0jvqoIlWZRaoAkUpm6x0%2FdgsETasbxaP3QFAVduTnmpzJiz0QBoSqAGjp%2BebCFyv3VUpspr84nULjsXPhft9BOs2sRoUmULmvKnPlfvNNJpPcNlfut8aqzkznYye36bZya9Yajo5fvK%2Fm8fOZLbUgAC6Va05w%2BxBc6cMnuOm2RDCmsQt7VZWMiR4%2FeH1e3docv0BPzY2lQQr03pm1aRDlMxRjk7KdU48006uxOSeFXiBdvU66o2eFqv2VGM7ZVnO2FWeudE2tmEAWosre826mi5kuBqKLekn6BLIQdVpqQA0WvWdM1HdkyZvxNpQk55XLPSQtszVg7gQCi9cfwcyXQBt1Mmn8iiyArBqje0D%2F0k0sq55qUGMqjDEFNtIXzSE0Kv030FOrFICBsZvWgKW2ui1SANouzdjx%2BLwTQoXn1Hfq4o3Oy8bFYfqOzusc2Rz9s29Crskj82%2B9%2FYZaM%2F%2Be%2BXeZoCbMv3WaMTMA%2FzZm%2Fi2af%2Bea7pj8W8%2BTiy6o36o2JIJrtFVpm78rsy12SZTFTg7UThrsOZN6xc6kSYZcdbs2gkfc47Ck1b5Jzop7zmnIuDaMvGA6rWTcwCyAozqyBxmXL81EZFx1J5prZVzDML3LOJozZXAZV10DaKMoIws5g90GdRZys5CbhVxHIacweMeEhBxly8pBhJwyCznhQm4CjjiDaP9C6%2BaQJy0MUm6mau2zUzqUYl5T1Mhbr5recB2ETjKZ0lNxz0tWiGb%2ByvAAsU%2BUBO88ndauzk9Te2pc5bgcmBnQ3PLXy7sJ154aE%2FGVdq09rXoGFbmeiNC7WJ3Lp5pvMpdPUec0l099hPKpKgeaQG9wo3Mq4SdkScrw5D%2BXTs2lU73VdNaY0gR6g%2BeFKeM6ILTbWi4nNcl1WKvDFBFNnl0QswtidkE0GL02g5FMyAVhio0rT9kFYc8uCBEuCHPebLj5LvWB5s2Gr4JwZ937fWw2bKg8HVEG3W5YvdB2vGuF4Lw55yQr%2F6a4OWc1iG2bZD35oHtzqibpf9%2BGx7iGuIwqVWzMt%2FKcyPYl1wkVp4LQm9J0eKZiSRbWCYRMxd81WUactMx%2B1nbNJFjjuNv9lAAVJ%2BGUpjM43oSH1j6EkQxXWwxzNYtmkOdNw8hCB1krflYxSJXeOCzpt%2FNVyxheF5xad5V6VaFMi%2FxQ0vUumabdQGWxHYmzJThbgrMl2N0SpMZ3hzUELfaGdRUh%2BaAs7iDvluAbBRNj%2F5S8Hf0jnLbjB1C0PqA7bfdR6s16erI0XZOMMjo22EojosASvZ7qjP835zncOmIAL9t2XRzbZN87RZNo0liEvfMn%2BM96uw4e9v94kf1DqOx%2FMV9u%2Bi46mtYmP7ZUW0den6yVNzgvBuptU4I%2FI%2BnxD%2Fm3x%2BOfr%2F%2F7j38Zvyy%2FP%2F9MAdM2Xi3OofVDTkSHnfvs7DbAKxHZYRIUVrSQLKtepSh2HrPWiolSwrMEarFD1jmoM4iZlP1yZRqqCSE1GgyVZlKrLiBtiUugSkMl%2BQpnpBmixUzQM2uSmIU0lOpCygrFhjCHXEgyPOEGAD4PxHkpCeGfv0AUjorr2iN6D4brhGTpE9nhYRQife7M3%2BCKPP8SegD94v8B%3C%2Fdiagram%3E%3C%2Fmxfile%3E
  256.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement