Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- //
- // vpgatherqq.cpp
- // Compile under msvc with /arch:AVX2.
- //
- // Demo: using vpgatherqq instruction to cancel impeding pagefault.
- // Src: https://x.com/sixtyvividtails/status/1848701990508925098.
- // See end of this file for the draw.io diagram.
- //
- // Instruction features:
- // ③: catch PAGE_GUARD or invalid access
- // ⓪: do previously illegal reads at high IRQL, safely
- //
- #include <conio.h>
- #include <stdio.h>
- #include <stdint.h>
- #include <immintrin.h>
- #include <phnt/phnt.h> // https://github.com/mrexodia/phnt-single-header
- #include <Windows.h>
- #define PAGE_SIZE 0x1000
- #define PF_AVX2_INSTRUCTIONS_AVAILABLE 40 // 20Hx+
- static bool is_avx2_available()
- {
- if (USER_SHARED_DATA->ProcessorFeatures[PF_AVX2_INSTRUCTIONS_AVAILABLE])
- return true;
- // if OS is below 20HX, this kuser bit may be absent; use cpuid
- int regs[4];
- __cpuidex(regs, 0, 0);
- if (regs[0] < 7)
- return false;
- __cpuidex(regs, 7, 0);
- return (regs[1] >> 5) & 1; // AVX2: cpuid(7, 0).EBX[5]
- }
- #if 0
- // intrinsics produce fine code with /arch:AVX2, but we can't predict used registers, so let's use asm instead
- __declspec(noinline)
- static uint64_t __fastcall read_using_vpgatherqq(const void* known_good_address, const void* sus_address)
- {
- const int64_t* src_base = nullptr; // set src base address to null for simplicity
- __m128i mask = _mm_set1_epi64x(-1); // set entire xmm reg to fff...ff
- __m128i index = _mm_set_epi64x((uint64_t)sus_address, (uint64_t)known_good_address);
- __m128i dst = _mm_set_epi64x(0x5555'6666'7777'8888, 0x1111'2222'3333'4444);
- _ReadWriteBarrier(); // ensure compiler abides
- constexpr int scale = 1;
- dst = _mm_mask_i64gather_epi64(dst, src_base, index, mask, scale);
- return dst.m128i_u64[1];
- }
- #endif
- // 00: 48 b8 44 44 33 33 22 movabs rax, 0x1111222233334444
- // 0A: c4 e1 f9 6e c0 vmovq xmm0, rax
- // 0F: 48 b8 88 88 77 77 66 movabs rax, 0x5555666677778888
- // 19: c4 e3 f9 22 c0 01 vpinsrq xmm0, xmm0, rax, 0x1
- // 1F: 31 c0 xor eax, eax
- // 21: c4 e1 f9 6e c9 vmovq xmm1, rcx
- // 26: c4 e3 f1 22 ca 01 vpinsrq xmm1, xmm1, rdx, 0x1
- // 2C: c5 e9 76 d2 vpcmpeqd xmm2, xmm2, xmm2
- // 30: c4 e2 e9 91 04 08 vpgatherqq xmm0, QWORD PTR[rax+xmm1], xmm2
- // 36: c4 e3 f9 16 c0 01 vpextrq rax, xmm0, 0x1
- // 3C: C3 ret
- #pragma const_seg(".text")
- const uint8_t read_using_vpgatherqq_asm[] =
- {
- 0x48, 0xB8, 0x44, 0x44, 0x33, 0x33, 0x22, 0x22, 0x11, 0x11, 0xC4, 0xE1, 0xF9, 0x6E, 0xC0, 0x48,
- 0xB8, 0x88, 0x88, 0x77, 0x77, 0x66, 0x66, 0x55, 0x55, 0xC4, 0xE3, 0xF9, 0x22, 0xC0, 0x01, 0x31,
- 0xC0, 0xC4, 0xE1, 0xF9, 0x6E, 0xC9, 0xC4, 0xE3, 0xF1, 0x22, 0xCA, 0x01, 0xC5, 0xE9, 0x76, 0xD2,
- 0xC4, 0xE2, 0xE9, 0x91, 0x04, 0x08, 0xC4, 0xE3, 0xF9, 0x16, 0xC0, 0x01, 0xC3
- };
- #pragma const_seg()
- uint64_t __fastcall read_using_vpgatherqq(const void* known_good_address, const void* sus_address);
- // to support X32, you gotta adjust asm code above (just a little bit)
- #ifndef _M_X64
- #error unsupported arch
- #endif
- __declspec(noinline, guard(nocf))
- static NTSTATUS test_vpgatherqq()
- {
- if (!is_avx2_available())
- return printf("[x] avx2 is not available\n"), STATUS_NOT_SUPPORTED;
- // note we don't even have to touch this address, as it'll be right-most in the index register
- static constinit uint64_t known_good_data = 0xAAAA'1111'4444'3333;
- // prepare suspicious address
- void* sus_address{};
- SIZE_T size = 2 * PAGE_SIZE;
- NTSTATUS st{};
- st = NtAllocateVirtualMemory(NtCurrentProcess(), &sus_address, 0, &size, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
- if (FAILED(st))
- return st;
- // prepare #DB trap
- CONTEXT ctx
- {
- .ContextFlags = CONTEXT_DEBUG_REGISTERS,
- .Dr0 = (size_t)&known_good_data,
- .Dr7 = 0x0003'0001
- };
- st = NtSetContextThread(NtCurrentThread(), &ctx);
- if (FAILED(st))
- return st;
- printf("[ ] allocated sus address %p\n", sus_address);
- auto read_using_vpgatherqq_fn = (decltype(&read_using_vpgatherqq))&read_using_vpgatherqq_asm;
- for (int tries = 0; tries < 6; ++tries)
- {
- bool debug_break_failed = true;
- bool sus_data_read = false;
- uint64_t sus_data = 0;
- printf("[>] try %u:\n", tries);
- if (tries == 0)
- {
- // initial try, do nothing
- printf(" memory allocated, but we have not dereferenced it yet...\n");
- }
- if (tries == 1)
- {
- // do nothing; this demonstrates we have not triggered #PF through initial read attempt
- printf("==> changing nothing...\n");
- }
- else if (tries == 2)
- {
- uint64_t x = 0xAAAA'5555'8888'7777;
- printf("==> writing new value to sus address: %016I64X...\n", x);
- *(uint64_t*)sus_address = x;
- }
- else if (tries == 3)
- {
- printf("==> applying PAGE_GUARD to sus address...\n");
- SIZE_T gsize = PAGE_SIZE;
- ULONG old_prot;
- st = NtProtectVirtualMemory(NtCurrentProcess(), &sus_address, &gsize, PAGE_READWRITE|PAGE_GUARD, &old_prot);
- if (FAILED(st))
- return st;
- }
- else if (tries == 4)
- {
- // do nothing; this demonstrates we have not made address accessible via our read attempt
- printf("==> changing nothing...\n");
- }
- else if (tries == 5)
- {
- printf("==> removing PAGE_GUARD...\n");
- SIZE_T gsize = PAGE_SIZE;
- ULONG old_prot;
- st = NtProtectVirtualMemory(NtCurrentProcess(), &sus_address, &gsize, PAGE_READONLY, &old_prot);
- if (FAILED(st))
- return st;
- *(volatile char*)sus_address; // gotta dereference
- }
- __try
- {
- sus_data = read_using_vpgatherqq_fn(&known_good_data, sus_address);
- }
- __except ([&](EXCEPTION_POINTERS* exptrs) -> long
- {
- auto* exr = exptrs->ExceptionRecord;
- auto* ctx = exptrs->ContextRecord;
- printf("[ ] exception %08X, rva %06I64X; xmm0: %016I64X'%016I64X, xmm2: %016I64X'%016I64X\n",
- exr->ExceptionCode, (uint64_t)((size_t)exr->ExceptionAddress - (size_t)&__ImageBase),
- ctx->Xmm0.High, ctx->Xmm0.Low, ctx->Xmm2.High, ctx->Xmm2.Low);
- if (exr->ExceptionCode != STATUS_SINGLE_STEP)
- return EXCEPTION_CONTINUE_SEARCH;
- sus_data_read = (ctx->Xmm2.High == 0);
- sus_data = ctx->Xmm0.High; // proper if sus_data_read, otherwise just original xmm0 value
- return EXCEPTION_EXECUTE_HANDLER;
- }(GetExceptionInformation()))
- {
- debug_break_failed = false;
- }
- bool expected = (tries != 2 && tries != 5) ^ sus_data_read;
- if (debug_break_failed)
- printf("[x] debug break failed (should not happen)\n");
- else if (sus_data_read)
- printf("[%c] %016I64X <<< value read from sus address (%s)\n",
- expected? ' ': 'x', sus_data, expected? "expected": "UNEXPECTED");
- else
- printf("[%c] %016I64X <<< orig xmm0[1], sus address was NOT read (%s)\n",
- expected? ' ': 'x', sus_data, expected? "expected": "UNEXPECTED");
- printf("-------------------------------\n");
- }
- printf("[+] all tests done\n");
- return 0;
- }
- int __cdecl wmain()
- {
- NTSTATUS st = test_vpgatherqq();
- ULONG dummy;
- if (GetConsoleMode(GetStdHandle(STD_OUTPUT_HANDLE), &dummy) && GetConsoleProcessList(&dummy, 1) <= 1)
- {
- printf("Exit status: %08X; press any key to continue...\n", st);
- _flushall();
- int c = _getch();
- if (!c || c == 0xE0) // arrow or function key, need to read one more
- (void)_getch();
- }
- return st;
- }
- #if 0
- Sample output:
- [ ] allocated sus address 000002993EEC0000
- [>] try 0:
- memory allocated, but we have not dereferenced it yet...
- [ ] exception 80000004, rva 001030; xmm0: 5555666677778888'AAAA111144443333, xmm2: FFFFFFFFFFFFFFFF'0000000000000000
- [ ] 5555666677778888 <<< orig xmm0[1], sus address was NOT read (expected)
- -------------------------------
- [>] try 1:
- ==> changing nothing...
- [ ] exception 80000004, rva 001030; xmm0: 5555666677778888'AAAA111144443333, xmm2: FFFFFFFFFFFFFFFF'0000000000000000
- [ ] 5555666677778888 <<< orig xmm0[1], sus address was NOT read (expected)
- -------------------------------
- [>] try 2:
- ==> writing new value to sus address: AAAA555588887777...
- [ ] exception 80000004, rva 001036; xmm0: AAAA555588887777'AAAA111144443333, xmm2: 0000000000000000'0000000000000000
- [ ] AAAA555588887777 <<< value read from sus address (expected)
- -------------------------------
- [>] try 3:
- ==> applying PAGE_GUARD to sus address...
- [ ] exception 80000004, rva 001030; xmm0: 5555666677778888'AAAA111144443333, xmm2: FFFFFFFFFFFFFFFF'0000000000000000
- [ ] 5555666677778888 <<< orig xmm0[1], sus address was NOT read (expected)
- -------------------------------
- [>] try 4:
- ==> changing nothing...
- [ ] exception 80000004, rva 001030; xmm0: 5555666677778888'AAAA111144443333, xmm2: FFFFFFFFFFFFFFFF'0000000000000000
- [ ] 5555666677778888 <<< orig xmm0[1], sus address was NOT read (expected)
- -------------------------------
- [>] try 5:
- ==> removing PAGE_GUARD...
- [ ] exception 80000004, rva 001036; xmm0: AAAA555588887777'AAAA111144443333, xmm2: 0000000000000000'0000000000000000
- [ ] AAAA555588887777 <<< value read from sus address (expected)
- -------------------------------
- [+] all tests done
- #endif
- // Beautiful draw.io diagram. Note: not an exploit.
- // 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
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement