如果想修改POSIX API的行为,通常我们的第一想法是修改libc库函数,并维护一份自定义的libc。这样做的代价非常大,因为libc是基础库,接口非常多,涉及的面也很广。修改可能不难,但后期维护,merge主干的工作比较麻烦,也没有价值。修改libc函数实现,还有一个缺点是,编译时修改,而非运行时。这会给一些无法下线并重新打包的程序带来困扰,例如程序已经分发,重新打包再分发耗时耗力。如果能找到运行时修改的方法,例如,暂停服务,替换一个库文件就可以修改某些行为。如果能做到运行时修改,对于调试也是非常友好的。
幸运的是,在Linux上,修改libc的方法很多:
- 使用LD_PRELOAD,覆盖libc中的函数
- 使用alias替代weak_alias,编译替换libc函数
- 使用GOT表覆盖libc函数实现
1和3都是动态,运行时修改。3更棒的是,可以做运行时动态获得libc的原实现函数指针,并用自定义实例去覆写。这样在内部可以保存两份实例,而无需维护开源实例。
在整个的学习和实验中查阅了不少资料,回头看来,其中比较有价值的应当是文末的参考文献中列出的一些链接。
Android so注入(inject)和Hook技术学习(二)——Got表hook之导入表hook
我的实验代码基于这个网页中的方法二实例代码,通过解析.dynamic section来获取GOT地址,并覆盖对应表项
Executable and Linkable Format
这个帖子非常棒,详细阐述了动态链接的过程,包括link editor以及runtime dynamic link流程。只是可能时间比较久,其中的一些链接都失效了
Oracle Documentation
Executable and Linking Format Specification, Version 1.2
这两个链接都给出了一些较为官方的阐述,针对各个section,以及对应的取值等等,作为手册查询很好。
ELF概述
from Wiki
Executable and Linkable Format (ELF, formerly named Extensible Linking Format), is a common standard file format for executable files, object code, shared libraries, and core dumps.
+-----------------+
+----| ELF File Header |----+
| +-----------------+ |
v v
+-----------------+ +-----------------+
| Program Headers | | Section Headers |
+-----------------+ +-----------------+
|| ||
|| ||
|| ||
|| +------------------------+ ||
+--> | Contents (Byte Stream) |<--+
+------------------------+
ELF格式通常有linking view和execution view,即编译时,和运行时的不同。
我理解之所以要这么分成不同的view的原因是,运行时,内存比较宝贵,ELF文件被加载时,相关的节(section)被合并成segment。
segment列表[2]
section列表节选[2]
动态链接
我们知道当引用第三方库的时候,通常有两种链接方式,一种是动态链接,一种是静态链接。静态链接库在Windows上是.lib结尾的,在Linux平台上是.a结尾的。静态库不是一种可执行文件,而只是一些代码和数据打包(Archive)。当发生链接时,由链接器将其中的代码和数据分别放到最终的ELF文件的对应的节(section)。
而动态库是一种完全不一样的东西,动态库的行为更趋近于可执行文件。在Windows平台上,动态库文件以.dll结尾,在Linux平台上,动态库文件以.so结尾。
在Windows下,如果要进行动态链接,必须使用LoadLibrary函数打开一个.dll库文件,再用GetProcAddress获取具体函数的地址,进行调用。dll导出函数列表可以使用命令查看:dumpbin /exports <dll文件完整路径>
。
Linux下也有类似的方式,就是可以用dlopen打开一个.so文件,再用dlsym找到对应的函数。但是Linux通常使用动态链接库的方式,是直接链接。例如:
gcc -L/lib -ltest main.c -o test
这就是在lib搜索路径下,找到libtest.so,并链接。注意这里默认先尝试动态链接,如果没有.so文件,会再尝试静态链接.a文件。如果都没有,就会报错。这也就是说Linux平台上,通过-l参数指定的链接参数,是默认尝试动态链接,其次才是静态链接。
如果想指定使用静态链接,可以用下面的命令:
gcc -L/lib -static -ltest main.c -o test
或者
gcc -L/lib libtest.a main.c -o test
How is an executable binary in Linux being executed ?[2]
-
sys_execve
function (in arch/x86/kernel/process.c) handles the execvc system call from user space. It calls do_execve
function.
-
do_execve
function (in fs/exec.c) opens the executable binary file and does some preparation. It calls search_binary_handler
function.
-
search_binary_handler
function (in fs/exec.c) finds out the type of executable binary and calls the corresponding handler, which in our case, is load_elf_binary
function.
-
load_elf_binary
(in fs/binfmt_elf.c) loads the user's executable binary file into memory. It allocates memory segments and zeros out the BSS section by calling the padzero function.
load_elf_binary
also examines whether the user's executable binary contains an INTERP segment or not.
-
If the executable binary is dynamically linked, then the compiler will usually creates an INTERP segment (which is usually the same as .interp section in ELF's "linking view"), which contains the full pathname of an "interpreter", usually is the Glibc runtime linker ld.so.
To see this, use command readelf -p .interp a.out
-
Thus, if the ELF executable binary file contains an INTERP segment, load_elf_binary
will call load_elf_interp function to load the image of this interpreter as well.
-
Finally, load_elf_binary
calls start_thread (in arch/x86/kernel/process_64.c) and passes control to either the interpreter or the user program.
这个1-7就是ELF文件被加载的过程,之后,再只要一个跳转语句,就可以真正的执行这个程序了。这里值得关注的就是第5步。如果被加载的二进制是动态链接生成的,即要么是动态链接库,要么是可执行文件,则加载时,内核会给ELF的内存镜像(即所谓的executing view)加一个INTERP段(segment)。而这个段就是所谓的runtime linker(compile时的linker,即ld,称为link editor),也就是ld.so。
ld.so
什么是ld.so? ld.so做了些啥?文献[2]都做了很好的说明。
ld.so is the runtime linker/loader (the compile-time linker ld is formally called "link editor") for dynamic executables. It provides the following services [2]:
- Analyzes the user's executable binary's DYNAMIC segment and determines what dependencies are required.
- Locates and loads these dependencies, analyzes their DYNAMIC segments to determine if more dependencies are required.
- Performs any necessary relocations to bind these objects.
- Calls any initialization functions (see below) provided by these dependencies.
- Passes control to user's executable binary.
How does ld.so work ?[2]
ld.so是用来加载所有的动态库的,所以ld.so本身不是动态加载的。ld.so的入口在_dl_start。可以通过gdb停在这个函数上。
(gdb) break _dl_start
Function "_dl_start" not defined.
Make breakpoint pending on future shared library load? (y or [n]) y
Breakpoint 1 (_dl_start) pending.
(gdb) run
Starting program: a.out
Breakpoint 1, 0x0000003433e00fa0 in _dl_start () from /lib64/ld-linux-x86-64.so.2
(gdb) bt
#0 0x0000003433e00fa0 in _dl_start () from /lib64/ld-linux-x86-64.so.2
#1 0x0000003433e00a78 in _start () from /lib64/ld-linux-x86-64.so.2
#2 0x0000000000000001 in ?? ()
#3 0x00007fffffffe4f2 in ?? ()
#4 0x0000000000000000 in ?? ()
...
(gdb) x/10i $pc
0x3433e00a70 <_start>: mov %rsp,%rdi
0x3433e00a73 <_start+3>: callq 0x3433e00fa0 <_dl_start>
0x3433e00a78 <_dl_start_user>: mov %rax,%r12
0x3433e00a7b <_dl_start_user+3>: mov 0x21b30b(%rip),%eax # 0x343401bd8c <_dl_skip_args>
...
当_dl_start执行完后,ld.so就会为我们分析依赖关系,并加载起所有必需的动态库文件。
0000003434551000 4K rw--- /lib64/libc-2.5.so <-- .got.plt .data sections
PLT & GOT
PLT = Procedure Linkage Table
GOT = Global Offsets Table
PLT表搭配GOT表就可以完成动态库函数的重定向。
当编译时,在链接阶段,编译器会查找函数定义,如果在所有的可重定向代码中,即.o、.a文件,无法找到函数定义,则会去链接指定的动态库.so文件中找。这里有两层意思:
- 会优先查找有函数定义的,也就是说静态库或源文件中定义的函数是可以覆盖动态库中函数的
- 编译器会为动态库中函数生成跳转代码。而这个跳转代码就是PLT表
可以用objdump -M intel -dj .plt a.out
命令查看PLT表具体反编译代码,例如:
- 第一条汇编语句,就是跳转到GOT对应表项,当该表项尚未被填充时(函数第一次被调用),GOT表项会重新跳回到PLT表项的下一条汇编
- 第二条汇编语句,将函数编号push到栈上,此时是准备一次函数调用
- 第三条汇编语句,跳转到PLT表开始的地方。PLT第一个表项指向的是_dl_runtime_resolve函数,该函数会找到之前传入的函数编号对应的函数地址,并填充对应的GOT表项。
关于函数编号,举个例子,解释一下:
#include <stdio.h>
#include <fcntl.h>
int func(void)
{
open("foo.txt", O_CREAT);
fopen("foo.txt", "rw");
printf("hello, in test.so\n");
return 0;
}
这里引用了glibc里的3个函数,用readelf -r查看,则会得到下面的结果:
重定位节 '.rela.plt' at offset 0x508 contains 3 entries:
偏移量 信息 类型 符号值 符号名称 + 加数
000000201018 000200000007 R_X86_64_JUMP_SLO 0000000000000000 puts@GLIBC_2.2.5 + 0
000000201020 000400000007 R_X86_64_JUMP_SLO 0000000000000000 open@GLIBC_2.2.5 + 0
000000201028 000500000007 R_X86_64_JUMP_SLO 0000000000000000 fopen@GLIBC_2.2.5 + 0
则puts对应的编号就是0,open是1,fopen是2。看看PLT表:
000000000000580 <puts@plt>:
580: ff 25 92 0a 20 00 jmp QWORD PTR [rip+0x200a92] # 201018 <puts@GLIBC_2.2.5>
586: 68 00 00 00 00 push 0x0
58b: e9 e0 ff ff ff jmp 570 <.plt>
0000000000000590 <open@plt>:
590: ff 25 8a 0a 20 00 jmp QWORD PTR [rip+0x200a8a] # 201020 <open@GLIBC_2.2.5>
596: 68 01 00 00 00 push 0x1
59b: e9 d0 ff ff ff jmp 570 <.plt>
00000000000005a0 <fopen@plt>:
5a0: ff 25 82 0a 20 00 jmp QWORD PTR [rip+0x200a82] # 201028 <fopen@GLIBC_2.2.5>
5a6: 68 02 00 00 00 push 0x2
5ab: e9 c0 ff ff ff jmp 570 <.plt>
理解了PLT和GOT表在解析函数地址中的作用,就可以着手修改GOT表,让函数跳转到我们希望的函数执行。
替换GOT表项
正如前文所说,要做这个替换的操作,就是要找到GOT表对应的表项在哪里,然后修改对应的函数地址即可。这涉及到解析内存中的程序elf格式的镜像。
dynamic section
所有和重定向有关的信息都包含在dynamic section中,在elf的execution view中,也可以称作dynamic segment。实际上,这两者是同一个东西,只是存在的方式不同。当然,因为我们要做的是动态的GOT修改,所以我们要找到dynamic segment在内存中的位置。
由前文可知,要在execution view中查找段,应该要用到Programm Header Table(PHT)。通过objdump -x
命令可以查看PHT表项。其中我们关心的就是DYNAMIC段。它包含了所有dynamic section的信息。代码里面,可以如下的获得dynamic。
// 1. 通过/proc/<pid>/maps得到elf加载的地址
snprintf(filename, sizeof(filename), "/proc/%d/maps", pid);
// 打开文件/proc/pid/maps,获取指定pid进程加载的内存模块信息
fp = fopen(filename, "r");
if(fp != NULL){
// 每次一行,读取文件 /proc/pid/maps中内容
while(fgets(line, sizeof(line), fp)){
// 查找指定的so模块
if(strstr(line, module_name)){
// 分割字符串
pch = strtok(line, "-");
// 字符串转长整形
addr = strtoul(pch, NULL, 16);
break;
}
}
}
fclose(fp);
// 2. 通过遍历program header table,找到dynameic段
unsigned long long dynamicAddr = 0;
unsigned int dynamicSize = 0;
int j = 0;
for (j = 0; j < phdr_count; j++)
{
if (phdr_table[j].p_type == PT_DYNAMIC)
{
dynamicAddr = phdr_table[j].p_vaddr + (uint64_t)base_addr;
dynamicSize = phdr_table[j].p_memsz;
break;
}
}
relocation tables
通过objdump -h
命令可以查看文件包含的section。和relocation相关的节有:
- .got
- .got.plt
- .plt
- rel(a).dyn
- rel(a).plt
- 其他rel(a).xxx节
刚开始的时候,这些类似的节名很容易让人混淆。其实和我们目标真正相关的是rel(a).plt。其他的让我依次澄清一下。不过都是我个人的理解,可能有偏颇之处。
先用readelf -S
查看一下section header table。
PROGBITS is stored in the disk image, as opposed to allocated and initialized at load.
节区类型:PROGBITS-程序定义的信息,NOBITS-不占用文件空间(bss),REL-重定位表项
对于各节区,[2]中的解释为:
- .plt: For dynamic binaries, this Procedure Linkage Table holds the trampoline/linkage code. See paragraphs below.
- .got: For dynamic binaries, this Global Offset Table holds the addresses of variables which are relocated upon loading.
- .got.plt: For dynamic binaries, this Global Offset Table holds the addresses of functions in dynamic libraries. They are used by trampoline code in .plt section.
对于.plt.got区网上搜到的解释是:
- This just seems to contain code to jump to the first entry of the .got.
这里很容易让人有很混乱的感觉,又是.got.plt的, 又是.plt.got的。网络上也很难查到两者之间的联系和区别。根据我个人的实验经验,后文尝试解释一下。先对这几个节区做一个总结。
- 这4个都是编译时决定的,节类型都是PROGBITS。信息都是存在可执行文件里,而runtime可用的信息都是通过重定向得到的,即通过rel(a).xxx节区获得的内存地址中存储的数据
- 所有以.plt开头的节区,都是一些跳板代码。
- 所有以.got开头的节区,都是一些数据,存储着这些函数被resolve后最终的地址。
- .plt开头表项的跳板代码,就是跳转到对应的.got表项中决定最终的执行地址。
# table of a dynamic library (.so)
[10] .plt PROGBITS 0000000000000610 00000610
[11] .plt.got PROGBITS 0000000000000640 00000640
[20] .got PROGBITS 0000000000200fc0 00000fc0
[21] .got.plt PROGBITS 0000000000201000 00001000
.plt vs .plt.got
先上2个例子,分别是.plt和.plt.got节的。可以看出,这2个节都是一些跳转代码。按照前文的解释,.plt节表项就是需要动态链接的一些函数的跳板代码。跳转代码的目的地是GOT表项。然后通过runtime linker(ld.so)来完成函数地址的解析。
.plt.got的内容与.plt非常类似,也是一些跳板代码。而且jmpq指令后,没有push指令和另一条jmpq指令。这个节和.plt节到底有啥区别?啥时候会用到该节的跳转指令?
# .plt节举例
00000000000008c0 <fopen@plt>:
8c0: ff 25 ea 16 20 00 jmpq *0x2016ea(%rip) # 201fb0 <fopen@GLIBC_2.2.5>
8c6: 68 09 00 00 00 pushq $0x9
8cb: e9 50 ff ff ff jmpq 820 <.plt>
# .plt.got节举例
00000000000005d0 <fopen@plt>:
5d0: ff 25 12 0a 20 00 jmpq *0x200a12(%rip) # 200fe8 <fopen@GLIBC_2.2.5>
5d6: 66 90 xchg %ax,%ax
经过我的实验发现,当发生类似这种函数指针赋值时,动态链接函数就会出现在.plt.got节,同时.plt节中就不再包含这个函数。
FuncPuts old_puts = NULL;
old_puts = puts; // puts as a function pointer, assigned to a variable
当函数不在.plt节时,函数的跳转变成静态的了。用objdump -S
对照汇编和源码,可以发现,对此类函数的调用就是跳转到对应的.plt.got表项。
puts("hello");
751: 48 8d 3d 8c 00 00 00 lea 0x8c(%rip),%rdi # 7e4 <_fini+0x14>
758: e8 e3 fe ff ff callq 640 <puts@plt>
# 对应的.plt.got表项
0000000000000640 <puts@plt>:
640: ff 25 82 09 20 00 jmpq *0x200982(%rip) # 200fc8 <puts@GLIBC_2.2.5>
646: 66 90 xchg %ax,%ax
注: xchg %ax, %ax
是一条NOP指令,参看Why does Visual Studio use xchg ax,ax
当只有.plt.got包含该函数表项时,我们的GOT替换魔法就失效了。所以如果想保存原函数指针,正确的做法应当是:
// Don't do like this.
// It will kick puts from .plt and put it into .plt.got.
// We might not be able to substitute its address via rel tables.
// old_puts = puts;
// Below is RECOMMENDED!!!
if (old_puts == NULL) { // save original libc function pointer
old_puts = (FuncPuts)*(uint64_t *)(rel_table[i].r_offset + base_addr);
}
*(uint64_t *)(rel_table[i].r_offset + base_addr) = (uint64_t)my_puts;
.got vs .got.plt
按照前文的解释,.got节存储的是需要动态resolve的变量(应当是动态库中定义的全局变量)。而.got.plt是对应.plt节的函数地址表项。
实际的实验结果是:
- 对于可执行文件,.got.plt不存在,而.plt表项直接跳转到.got表项执行。函数的GOT表位置(GLOBAL_OFFSET_TABLE)在0x201f50
> objdump -d --section=.plt mytest
mytest: 文件格式 elf64-x86-64
Disassembly of section .plt:
0000000000000820 <.plt>:
820: ff 35 32 17 20 00 pushq 0x201732(%rip) # 201f58 <_GLOBAL_OFFSET_TABLE_+0x8>
826: ff 25 34 17 20 00 jmpq *0x201734(%rip) # 201f60 <_GLOBAL_OFFSET_TABLE_+0x10>
82c: 0f 1f 40 00 nopl 0x0(%rax)
> objdump -d --section=.got mytest
mytest: 文件格式 elf64-x86-64
Disassembly of section .got:
0000000000201f50 <_GLOBAL_OFFSET_TABLE_>:
201f50: 50 1d 20 00 00 00 00 00 00 00 00 00 00 00 00 00
...
- 对于一个动态链接库文件,则如前文所述一致,即.got负责跳转变量,而.got.plt负责跳转函数。函数的GOT表位置(GLOBAL_OFFSET_TABLE)在0x201000
> objdump -d --section=.plt libtest.so
libtest.so: 文件格式 elf64-x86-64
Disassembly of section .plt:
0000000000000610 <.plt>:
610: ff 35 f2 09 20 00 pushq 0x2009f2(%rip) # 201008 <_GLOBAL_OFFSET_TABLE_+0x8>
616: ff 25 f4 09 20 00 jmpq *0x2009f4(%rip) # 201010 <_GLOBAL_OFFSET_TABLE_+0x10>
61c: 0f 1f 40 00 nopl 0x0(%rax)
> objdump -d --section=.got.plt libtest.so
libtest.so: 文件格式 elf64-x86-64
Disassembly of section .got.plt:
0000000000201000 <_GLOBAL_OFFSET_TABLE_>:
201000: 00 0e 20 00 00 00 00 00 00 00 00 00 00 00 00 00
...
但其实,我们需要关注的是重定向的表格,而不是直接查看.got和.got.plt节区。后文会进一步解释。而在真正的GOT表项替换中,可执行文件和动态链接库并没有表现出什么不同。
Rerwrite GOT
重写GOT表项的思路就是前面讲述的PLT+GOT动态解析函数地址的方法。而覆写的方法是通过重定向表格找到GOT表,并找到对应的表项索引,修改该索引处的内存。流程大致如下:
PHN2ZyBpZD0iZGFmeGI5YWFyMGEiIHdpZHRoPSIxMDAlIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHN0eWxlPSJtYXgtd2lkdGg6IDk1OS43MTg3NXB4OyIgdmlld0JveD0iMCAwIDk1OS43MTg3NSA5NTQuOTgxMjQ2OTQ4MjQyMiI+PHN0eWxlPgoKCiNkYWZ4YjlhYXIwYSAubGFiZWwgewogIGZvbnQtZmFtaWx5OiAndHJlYnVjaGV0IG1zJywgdmVyZGFuYSwgYXJpYWw7CiAgY29sb3I6ICMzMzM7IH0KCiNkYWZ4YjlhYXIwYSAubm9kZSByZWN0LAojZGFmeGI5YWFyMGEgLm5vZGUgY2lyY2xlLAojZGFmeGI5YWFyMGEgLm5vZGUgZWxsaXBzZSwKI2RhZnhiOWFhcjBhIC5ub2RlIHBvbHlnb24gewogIGZpbGw6ICNFQ0VDRkY7CiAgc3Ryb2tlOiAjOTM3MERCOwogIHN0cm9rZS13aWR0aDogMXB4OyB9CgojZGFmeGI5YWFyMGEgLm5vZGUuY2xpY2thYmxlIHsKICBjdXJzb3I6IHBvaW50ZXI7IH0KCiNkYWZ4YjlhYXIwYSAuYXJyb3doZWFkUGF0aCB7CiAgZmlsbDogIzMzMzMzMzsgfQoKI2RhZnhiOWFhcjBhIC5lZGdlUGF0aCAucGF0aCB7CiAgc3Ryb2tlOiAjMzMzMzMzOwogIHN0cm9rZS13aWR0aDogMS41cHg7IH0KCiNkYWZ4YjlhYXIwYSAuZWRnZUxhYmVsIHsKICBiYWNrZ3JvdW5kLWNvbG9yOiAjZThlOGU4OyB9CgojZGFmeGI5YWFyMGEgLmNsdXN0ZXIgcmVjdCB7CiAgZmlsbDogI2ZmZmZkZSAhaW1wb3J0YW50OwogIHN0cm9rZTogI2FhYWEzMyAhaW1wb3J0YW50OwogIHN0cm9rZS13aWR0aDogMXB4ICFpbXBvcnRhbnQ7IH0KCiNkYWZ4YjlhYXIwYSAuY2x1c3RlciB0ZXh0IHsKICBmaWxsOiAjMzMzOyB9CgojZGFmeGI5YWFyMGEgZGl2Lm1lcm1haWRUb29sdGlwIHsKICBwb3NpdGlvbjogYWJzb2x1dGU7CiAgdGV4dC1hbGlnbjogY2VudGVyOwogIG1heC13aWR0aDogMjAwcHg7CiAgcGFkZGluZzogMnB4OwogIGZvbnQtZmFtaWx5OiAndHJlYnVjaGV0IG1zJywgdmVyZGFuYSwgYXJpYWw7CiAgZm9udC1zaXplOiAxMnB4OwogIGJhY2tncm91bmQ6ICNmZmZmZGU7CiAgYm9yZGVyOiAxcHggc29saWQgI2FhYWEzMzsKICBib3JkZXItcmFkaXVzOiAycHg7CiAgcG9pbnRlci1ldmVudHM6IG5vbmU7CiAgei1pbmRleDogMTAwOyB9CgojZGFmeGI5YWFyMGEgLmFjdG9yIHsKICBzdHJva2U6ICNDQ0NDRkY7CiAgZmlsbDogI0VDRUNGRjsgfQoKI2RhZnhiOWFhcjBhIHRleHQuYWN0b3IgewogIGZpbGw6IGJsYWNrOwogIHN0cm9rZTogbm9uZTsgfQoKI2RhZnhiOWFhcjBhIC5hY3Rvci1saW5lIHsKICBzdHJva2U6IGdyZXk7IH0KCiNkYWZ4YjlhYXIwYSAubWVzc2FnZUxpbmUwIHsKICBzdHJva2Utd2lkdGg6IDEuNTsKICBzdHJva2UtZGFzaGFycmF5OiAnMiAyJzsKICBzdHJva2U6ICMzMzM7IH0KCiNkYWZ4YjlhYXIwYSAubWVzc2FnZUxpbmUxIHsKICBzdHJva2Utd2lkdGg6IDEuNTsKICBzdHJva2UtZGFzaGFycmF5OiAnMiAyJzsKICBzdHJva2U6ICMzMzM7IH0KCiNkYWZ4YjlhYXIwYSAjYXJyb3doZWFkIHsKICBmaWxsOiAjMzMzOyB9CgojZGFmeGI5YWFyMGEgI2Nyb3NzaGVhZCBwYXRoIHsKICBmaWxsOiAjMzMzICFpbXBvcnRhbnQ7CiAgc3Ryb2tlOiAjMzMzICFpbXBvcnRhbnQ7IH0KCiNkYWZ4YjlhYXIwYSAubWVzc2FnZVRleHQgewogIGZpbGw6ICMzMzM7CiAgc3Ryb2tlOiBub25lOyB9CgojZGFmeGI5YWFyMGEgLmxhYmVsQm94IHsKICBzdHJva2U6ICNDQ0NDRkY7CiAgZmlsbDogI0VDRUNGRjsgfQoKI2RhZnhiOWFhcjBhIC5sYWJlbFRleHQgewogIGZpbGw6IGJsYWNrOwogIHN0cm9rZTogbm9uZTsgfQoKI2RhZnhiOWFhcjBhIC5sb29wVGV4dCB7CiAgZmlsbDogYmxhY2s7CiAgc3Ryb2tlOiBub25lOyB9CgojZGFmeGI5YWFyMGEgLmxvb3BMaW5lIHsKICBzdHJva2Utd2lkdGg6IDI7CiAgc3Ryb2tlLWRhc2hhcnJheTogJzIgMic7CiAgc3Ryb2tlOiAjQ0NDQ0ZGOyB9CgojZGFmeGI5YWFyMGEgLm5vdGUgewogIHN0cm9rZTogI2FhYWEzMzsKICBmaWxsOiAjZmZmNWFkOyB9CgojZGFmeGI5YWFyMGEgLm5vdGVUZXh0IHsKICBmaWxsOiBibGFjazsKICBzdHJva2U6IG5vbmU7CiAgZm9udC1mYW1pbHk6ICd0cmVidWNoZXQgbXMnLCB2ZXJkYW5hLCBhcmlhbDsKICBmb250LXNpemU6IDE0cHg7IH0KCiNkYWZ4YjlhYXIwYSAuYWN0aXZhdGlvbjAgewogIGZpbGw6ICNmNGY0ZjQ7CiAgc3Ryb2tlOiAjNjY2OyB9CgojZGFmeGI5YWFyMGEgLmFjdGl2YXRpb24xIHsKICBmaWxsOiAjZjRmNGY0OwogIHN0cm9rZTogIzY2NjsgfQoKI2RhZnhiOWFhcjBhIC5hY3RpdmF0aW9uMiB7CiAgZmlsbDogI2Y0ZjRmNDsKICBzdHJva2U6ICM2NjY7IH0KCgojZGFmeGI5YWFyMGEgLnNlY3Rpb24gewogIHN0cm9rZTogbm9uZTsKICBvcGFjaXR5OiAwLjI7IH0KCiNkYWZ4YjlhYXIwYSAuc2VjdGlvbjAgewogIGZpbGw6IHJnYmEoMTAyLCAxMDIsIDI1NSwgMC40OSk7IH0KCiNkYWZ4YjlhYXIwYSAuc2VjdGlvbjIgewogIGZpbGw6ICNmZmY0MDA7IH0KCiNkYWZ4YjlhYXIwYSAuc2VjdGlvbjEsCiNkYWZ4YjlhYXIwYSAuc2VjdGlvbjMgewogIGZpbGw6IHdoaXRlOwogIG9wYWNpdHk6IDAuMjsgfQoKI2RhZnhiOWFhcjBhIC5zZWN0aW9uVGl0bGUwIHsKICBmaWxsOiAjMzMzOyB9CgojZGFmeGI5YWFyMGEgLnNlY3Rpb25UaXRsZTEgewogIGZpbGw6ICMzMzM7IH0KCiNkYWZ4YjlhYXIwYSAuc2VjdGlvblRpdGxlMiB7CiAgZmlsbDogIzMzMzsgfQoKI2RhZnhiOWFhcjBhIC5zZWN0aW9uVGl0bGUzIHsKICBmaWxsOiAjMzMzOyB9CgojZGFmeGI5YWFyMGEgLnNlY3Rpb25UaXRsZSB7CiAgdGV4dC1hbmNob3I6IHN0YXJ0OwogIGZvbnQtc2l6ZTogMTFweDsKICB0ZXh0LWhlaWdodDogMTRweDsgfQoKCiNkYWZ4YjlhYXIwYSAuZ3JpZCAudGljayB7CiAgc3Ryb2tlOiBsaWdodGdyZXk7CiAgb3BhY2l0eTogMC4zOwogIHNoYXBlLXJlbmRlcmluZzogY3Jpc3BFZGdlczsgfQoKI2RhZnhiOWFhcjBhIC5ncmlkIHBhdGggewogIHN0cm9rZS13aWR0aDogMDsgfQoKCiNkYWZ4YjlhYXIwYSAudG9kYXkgewogIGZpbGw6IG5vbmU7CiAgc3Ryb2tlOiByZWQ7CiAgc3Ryb2tlLXdpZHRoOiAycHg7IH0KCgoKI2RhZnhiOWFhcjBhIC50YXNrIHsKICBzdHJva2Utd2lkdGg6IDI7IH0KCiNkYWZ4YjlhYXIwYSAudGFza1RleHQgewogIHRleHQtYW5jaG9yOiBtaWRkbGU7CiAgZm9udC1zaXplOiAxMXB4OyB9CgojZGFmeGI5YWFyMGEgLnRhc2tUZXh0T3V0c2lkZVJpZ2h0IHsKICBmaWxsOiBibGFjazsKICB0ZXh0LWFuY2hvcjogc3RhcnQ7CiAgZm9udC1zaXplOiAxMXB4OyB9CgojZGFmeGI5YWFyMGEgLnRhc2tUZXh0T3V0c2lkZUxlZnQgewogIGZpbGw6IGJsYWNrOwogIHRleHQtYW5jaG9yOiBlbmQ7CiAgZm9udC1zaXplOiAxMXB4OyB9CgoKI2RhZnhiOWFhcjBhIC50YXNrVGV4dDAsCiNkYWZ4YjlhYXIwYSAudGFza1RleHQxLAojZGFmeGI5YWFyMGEgLnRhc2tUZXh0MiwKI2RhZnhiOWFhcjBhIC50YXNrVGV4dDMgewogIGZpbGw6IHdoaXRlOyB9CgojZGFmeGI5YWFyMGEgLnRhc2swLAojZGFmeGI5YWFyMGEgLnRhc2sxLAojZGFmeGI5YWFyMGEgLnRhc2syLAojZGFmeGI5YWFyMGEgLnRhc2szIHsKICBmaWxsOiAjOGE5MGRkOwogIHN0cm9rZTogIzUzNGZiYzsgfQoKI2RhZnhiOWFhcjBhIC50YXNrVGV4dE91dHNpZGUwLAojZGFmeGI5YWFyMGEgLnRhc2tUZXh0T3V0c2lkZTIgewogIGZpbGw6IGJsYWNrOyB9CgojZGFmeGI5YWFyMGEgLnRhc2tUZXh0T3V0c2lkZTEsCiNkYWZ4YjlhYXIwYSAudGFza1RleHRPdXRzaWRlMyB7CiAgZmlsbDogYmxhY2s7IH0KCgojZGFmeGI5YWFyMGEgLmFjdGl2ZTAsCiNkYWZ4YjlhYXIwYSAuYWN0aXZlMSwKI2RhZnhiOWFhcjBhIC5hY3RpdmUyLAojZGFmeGI5YWFyMGEgLmFjdGl2ZTMgewogIGZpbGw6ICNiZmM3ZmY7CiAgc3Ryb2tlOiAjNTM0ZmJjOyB9CgojZGFmeGI5YWFyMGEgLmFjdGl2ZVRleHQwLAojZGFmeGI5YWFyMGEgLmFjdGl2ZVRleHQxLAojZGFmeGI5YWFyMGEgLmFjdGl2ZVRleHQyLAojZGFmeGI5YWFyMGEgLmFjdGl2ZVRleHQzIHsKICBmaWxsOiBibGFjayAhaW1wb3J0YW50OyB9CgoKI2RhZnhiOWFhcjBhIC5kb25lMCwKI2RhZnhiOWFhcjBhIC5kb25lMSwKI2RhZnhiOWFhcjBhIC5kb25lMiwKI2RhZnhiOWFhcjBhIC5kb25lMyB7CiAgc3Ryb2tlOiBncmV5OwogIGZpbGw6IGxpZ2h0Z3JleTsKICBzdHJva2Utd2lkdGg6IDI7IH0KCiNkYWZ4YjlhYXIwYSAuZG9uZVRleHQwLAojZGFmeGI5YWFyMGEgLmRvbmVUZXh0MSwKI2RhZnhiOWFhcjBhIC5kb25lVGV4dDIsCiNkYWZ4YjlhYXIwYSAuZG9uZVRleHQzIHsKICBmaWxsOiBibGFjayAhaW1wb3J0YW50OyB9CgoKI2RhZnhiOWFhcjBhIC5jcml0MCwKI2RhZnhiOWFhcjBhIC5jcml0MSwKI2RhZnhiOWFhcjBhIC5jcml0MiwKI2RhZnhiOWFhcjBhIC5jcml0MyB7CiAgc3Ryb2tlOiAjZmY4ODg4OwogIGZpbGw6IHJlZDsKICBzdHJva2Utd2lkdGg6IDI7IH0KCiNkYWZ4YjlhYXIwYSAuYWN0aXZlQ3JpdDAsCiNkYWZ4YjlhYXIwYSAuYWN0aXZlQ3JpdDEsCiNkYWZ4YjlhYXIwYSAuYWN0aXZlQ3JpdDIsCiNkYWZ4YjlhYXIwYSAuYWN0aXZlQ3JpdDMgewogIHN0cm9rZTogI2ZmODg4ODsKICBmaWxsOiAjYmZjN2ZmOwogIHN0cm9rZS13aWR0aDogMjsgfQoKI2RhZnhiOWFhcjBhIC5kb25lQ3JpdDAsCiNkYWZ4YjlhYXIwYSAuZG9uZUNyaXQxLAojZGFmeGI5YWFyMGEgLmRvbmVDcml0MiwKI2RhZnhiOWFhcjBhIC5kb25lQ3JpdDMgewogIHN0cm9rZTogI2ZmODg4ODsKICBmaWxsOiBsaWdodGdyZXk7CiAgc3Ryb2tlLXdpZHRoOiAyOwogIGN1cnNvcjogcG9pbnRlcjsKICBzaGFwZS1yZW5kZXJpbmc6IGNyaXNwRWRnZXM7IH0KCiNkYWZ4YjlhYXIwYSAuZG9uZUNyaXRUZXh0MCwKI2RhZnhiOWFhcjBhIC5kb25lQ3JpdFRleHQxLAojZGFmeGI5YWFyMGEgLmRvbmVDcml0VGV4dDIsCiNkYWZ4YjlhYXIwYSAuZG9uZUNyaXRUZXh0MyB7CiAgZmlsbDogYmxhY2sgIWltcG9ydGFudDsgfQoKI2RhZnhiOWFhcjBhIC5hY3RpdmVDcml0VGV4dDAsCiNkYWZ4YjlhYXIwYSAuYWN0aXZlQ3JpdFRleHQxLAojZGFmeGI5YWFyMGEgLmFjdGl2ZUNyaXRUZXh0MiwKI2RhZnhiOWFhcjBhIC5hY3RpdmVDcml0VGV4dDMgewogIGZpbGw6IGJsYWNrICFpbXBvcnRhbnQ7IH0KCiNkYWZ4YjlhYXIwYSAudGl0bGVUZXh0IHsKICB0ZXh0LWFuY2hvcjogbWlkZGxlOwogIGZvbnQtc2l6ZTogMThweDsKICBmaWxsOiBibGFjazsgfQoKI2RhZnhiOWFhcjBhIGcuY2xhc3NHcm91cCB0ZXh0IHsKICBmaWxsOiAjOTM3MERCOwogIHN0cm9rZTogbm9uZTsKICBmb250LWZhbWlseTogJ3RyZWJ1Y2hldCBtcycsIHZlcmRhbmEsIGFyaWFsOwogIGZvbnQtc2l6ZTogMTBweDsgfQoKI2RhZnhiOWFhcjBhIGcuY2xhc3NHcm91cCByZWN0IHsKICBmaWxsOiAjRUNFQ0ZGOwogIHN0cm9rZTogIzkzNzBEQjsgfQoKI2RhZnhiOWFhcjBhIGcuY2xhc3NHcm91cCBsaW5lIHsKICBzdHJva2U6ICM5MzcwREI7CiAgc3Ryb2tlLXdpZHRoOiAxOyB9CgojZGFmeGI5YWFyMGEgLmNsYXNzTGFiZWwgLmJveCB7CiAgc3Ryb2tlOiBub25lOwogIHN0cm9rZS13aWR0aDogMDsKICBmaWxsOiAjRUNFQ0ZGOwogIG9wYWNpdHk6IDAuNTsgfQoKI2RhZnhiOWFhcjBhIC5jbGFzc0xhYmVsIC5sYWJlbCB7CiAgZmlsbDogIzkzNzBEQjsKICBmb250LXNpemU6IDEwcHg7IH0KCiNkYWZ4YjlhYXIwYSAucmVsYXRpb24gewogIHN0cm9rZTogIzkzNzBEQjsKICBzdHJva2Utd2lkdGg6IDE7CiAgZmlsbDogbm9uZTsgfQoKI2RhZnhiOWFhcjBhICNjb21wb3NpdGlvblN0YXJ0IHsKICBmaWxsOiAjOTM3MERCOwogIHN0cm9rZTogIzkzNzBEQjsKICBzdHJva2Utd2lkdGg6IDE7IH0KCiNkYWZ4YjlhYXIwYSAjY29tcG9zaXRpb25FbmQgewogIGZpbGw6ICM5MzcwREI7CiAgc3Ryb2tlOiAjOTM3MERCOwogIHN0cm9rZS13aWR0aDogMTsgfQoKI2RhZnhiOWFhcjBhICNhZ2dyZWdhdGlvblN0YXJ0IHsKICBmaWxsOiAjRUNFQ0ZGOwogIHN0cm9rZTogIzkzNzBEQjsKICBzdHJva2Utd2lkdGg6IDE7IH0KCiNkYWZ4YjlhYXIwYSAjYWdncmVnYXRpb25FbmQgewogIGZpbGw6ICNFQ0VDRkY7CiAgc3Ryb2tlOiAjOTM3MERCOwogIHN0cm9rZS13aWR0aDogMTsgfQoKI2RhZnhiOWFhcjBhICNkZXBlbmRlbmN5U3RhcnQgewogIGZpbGw6ICM5MzcwREI7CiAgc3Ryb2tlOiAjOTM3MERCOwogIHN0cm9rZS13aWR0aDogMTsgfQoKI2RhZnhiOWFhcjBhICNkZXBlbmRlbmN5RW5kIHsKICBmaWxsOiAjOTM3MERCOwogIHN0cm9rZTogIzkzNzBEQjsKICBzdHJva2Utd2lkdGg6IDE7IH0KCiNkYWZ4YjlhYXIwYSAjZXh0ZW5zaW9uU3RhcnQgewogIGZpbGw6ICM5MzcwREI7CiAgc3Ryb2tlOiAjOTM3MERCOwogIHN0cm9rZS13aWR0aDogMTsgfQoKI2RhZnhiOWFhcjBhICNleHRlbnNpb25FbmQgewogIGZpbGw6ICM5MzcwREI7CiAgc3Ryb2tlOiAjOTM3MERCOwogIHN0cm9rZS13aWR0aDogMTsgfQoKI2RhZnhiOWFhcjBhIC5jb21taXQtaWQsCiNkYWZ4YjlhYXIwYSAuY29tbWl0LW1zZywKI2RhZnhiOWFhcjBhIC5icmFuY2gtbGFiZWwgewogIGZpbGw6IGxpZ2h0Z3JleTsKICBjb2xvcjogbGlnaHRncmV5OyB9CgoKCiNkYWZ4YjlhYXIwYSAubGFiZWx7CiAgY29sb3I6IzE4QjE0RTsKfQojZGFmeGI5YWFyMGEgLnRlLW1kLWNvbnRhaW5lci0tZGFyayAubm9kZSByZWN0IHsKICBmaWxsOiByZWQ7Cn0KCiNkYWZ4YjlhYXIwYSAubm9kZSByZWN0LAojZGFmeGI5YWFyMGEgLm5vZGUgY2lyY2xlLAojZGFmeGI5YWFyMGEgLm5vZGUgZWxsaXBzZSwKI2RhZnhiOWFhcjBhIC5ub2RlIHBvbHlnb24gewogIGZpbGw6ICNGOUZGRkI7OwogIHN0cm9rZTogIzJEQkQ2MDsKICBzdHJva2Utd2lkdGg6IDEuNXB4Owp9CiNkYWZ4YjlhYXIwYSAuYXJyb3doZWFkUGF0aHsKICBmaWxsOiAjMkRCRDYwOwp9CiNkYWZ4YjlhYXIwYSAuZWRnZVBhdGggLnBhdGggewogIHN0cm9rZTogIzJEQkQ2MDsKICBzdHJva2Utd2lkdGg6IDFweDsKfQojZGFmeGI5YWFyMGEgLmVkZ2VMYWJlbCB7CiAgYmFja2dyb3VuZC1jb2xvcjogI2ZmZjsKfQojZGFmeGI5YWFyMGEgLmNsdXN0ZXIgcmVjdCB7CiAgZmlsbDogI0Y5RkZGQiAhaW1wb3J0YW50OwogIHN0cm9rZTogIzJEQkQ2MCAhaW1wb3J0YW50OwogIHN0cm9rZS13aWR0aDogMXB4ICFpbXBvcnRhbnQ7Cn0KCiNkYWZ4YjlhYXIwYSAuY2x1c3RlciB0ZXh0IHsKICBmaWxsOiAjRjlGRkZCOwp9CgojZGFmeGI5YWFyMGEgZGl2Lm1lcm1haWRUb29sdGlwIHsKICBiYWNrZ3JvdW5kOiAjRjlGRkZCOwogIGJvcmRlcjogMXB4IHNvbGlkICMyREJENjA7Cn0KCgojZGFmeGI5YWFyMGEgLmFjdG9yIHsKICBzdHJva2U6ICMyREJENjA7CiAgZmlsbDogI0Y5RkZGQjsKfQoKI2RhZnhiOWFhcjBhIHRleHQuYWN0b3IgewogIGZpbGw6ICMyREJENjA7CiAgc3Ryb2tlOiBub25lOwp9CgojZGFmeGI5YWFyMGEgLmFjdG9yLWxpbmUgewogIHN0cm9rZTogIzJEQkQ2MDsKfQoKI2RhZnhiOWFhcjBhIC5tZXNzYWdlTGluZTAgewogIHN0cm9rZS13aWR0aDogMS41OwogIHN0cm9rZS1kYXNoYXJyYXk6ICcyIDInOwogIG1hcmtlci1lbmQ6ICd1cmwoI2Fycm93aGVhZCknOwogIHN0cm9rZTogIzJEQkQ2MDsKfQoKI2RhZnhiOWFhcjBhIC5tZXNzYWdlTGluZTEgewogIHN0cm9rZS13aWR0aDogMS41OwogIHN0cm9rZS1kYXNoYXJyYXk6ICcyIDInOwogIHN0cm9rZTogIzJEQkQ2MDsKfQoKI2RhZnhiOWFhcjBhICNhcnJvd2hlYWQgewogIGZpbGw6ICMyREJENjA7Cn0KCiNkYWZ4YjlhYXIwYSAjY3Jvc3NoZWFkIHBhdGggewogIGZpbGw6ICMyREJENjAgIWltcG9ydGFudDsKICBzdHJva2U6ICMyREJENjAgIWltcG9ydGFudDsKfQoKI2RhZnhiOWFhcjBhIC5tZXNzYWdlVGV4dCB7CiAgZmlsbDogIzJEQkQ2MDsKICBzdHJva2U6IG5vbmU7Cn0KCiNkYWZ4YjlhYXIwYSAubGFiZWxCb3ggewogIHN0cm9rZTogIzJEQkQ2MDsKICBmaWxsOiAjRjlGRkZCOwp9CgojZGFmeGI5YWFyMGEgLmxhYmVsVGV4dCB7CiAgZmlsbDogIzJEQkQ2MDsKICBzdHJva2U6ICMyREJENjA7Cn0KCiNkYWZ4YjlhYXIwYSAubG9vcFRleHQgewogIGZpbGw6ICMyREJENjA7CiAgc3Ryb2tlOiAjMkRCRDYwOwp9CgojZGFmeGI5YWFyMGEgLmxvb3BMaW5lIHsKICBzdHJva2Utd2lkdGg6IDI7CiAgc3Ryb2tlLWRhc2hhcnJheTogJzIgMic7CiAgbWFya2VyLWVuZDogJ3VybCgjYXJyb3doZWFkKSc7CiAgc3Ryb2tlOiAjMkRCRDYwOwp9CgojZGFmeGI5YWFyMGEgLm5vdGUgewogIHN0cm9rZTogIzJEQkQ2MDsKICBmaWxsOiAjRjlGRkZCOwp9CgojZGFmeGI5YWFyMGEgLm5vdGVUZXh0IHsKICBmaWxsOiAjMkRCRDYwOwogIHN0cm9rZTogIzJEQkQ2MDsKfQoKCiNkYWZ4YjlhYXIwYSAuc2VjdGlvbnsKICBvcGFjaXR5OjE7Cn0KI2RhZnhiOWFhcjBhIC5zZWN0aW9uMCwjZGFmeGI5YWFyMGEgIC5zZWN0aW9uMiB7CiAgZmlsbDogI0VDRjdGMDsKfQoKI2RhZnhiOWFhcjBhIC5zZWN0aW9uMSwKI2RhZnhiOWFhcjBhIC5zZWN0aW9uMyB7CiAgZmlsbDogI0ZGRjsKfQojZGFmeGI5YWFyMGEgLnRhc2tUZXh0MCwKI2RhZnhiOWFhcjBhIC50YXNrVGV4dDEsCiNkYWZ4YjlhYXIwYSAudGFza1RleHQyLAojZGFmeGI5YWFyMGEgLnRhc2tUZXh0MyB7CiAgZmlsbDogI2ZmZjsKfQoKI2RhZnhiOWFhcjBhIC50YXNrMCwKI2RhZnhiOWFhcjBhIC50YXNrMSwKI2RhZnhiOWFhcjBhIC50YXNrMiwKI2RhZnhiOWFhcjBhIC50YXNrMyB7CiAgZmlsbDogIzJEQkQ2MDsKICBzdHJva2U6ICMzNTlGNUE7Cn0KPC9zdHlsZT48c3R5bGU+I2RhZnhiOWFhcjBhIHsKICAgIGNvbG9yOiByZ2IoMjQ0LCAyNDQsIDI0NCk7CiAgICBmb250OiBub3JtYWwgbm9ybWFsIG5vcm1hbCBub3JtYWwgMTRweC8yMi4zOTk5OTk2MTg1MzAyNzNweCBtb25vc3BhY2U7CiAgfTwvc3R5bGU+PGcgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTEyLCAtMTIpIj48ZyBjbGFzcz0ib3V0cHV0Ij48ZyBjbGFzcz0iY2x1c3RlcnMiPjwvZz48ZyBjbGFzcz0iZWRnZVBhdGhzIj48ZyBjbGFzcz0iZWRnZVBhdGgiIHN0eWxlPSJvcGFjaXR5OiAxOyI+PHBhdGggY2xhc3M9InBhdGgiIGQ9Ik00NzAuMDExNzE4NzUsNTYuMjgxMjVMNDcwLjAxMTcxODc1LDgxLjI4MTI1TDQ3MC4wMTE3MTg3NSwxMDYuMjgxMjUiIG1hcmtlci1lbmQ9InVybCgjYXJyb3doZWFkNDMyNikiIHN0eWxlPSJzdHJva2U6ICMzMzM7IHN0cm9rZS13aWR0aDogMS41cHg7ZmlsbDpub25lIj48L3BhdGg+PGRlZnM+PG1hcmtlciBpZD0iYXJyb3doZWFkNDMyNiIgdmlld0JveD0iMCAwIDEwIDEwIiByZWZYPSI5IiByZWZZPSI1IiBtYXJrZXJVbml0cz0ic3Ryb2tlV2lkdGgiIG1hcmtlcldpZHRoPSI4IiBtYXJrZXJIZWlnaHQ9IjYiIG9yaWVudD0iYXV0byI+PHBhdGggZD0iTSAwIDAgTCAxMCA1IEwgMCAxMCB6IiBjbGFzcz0iYXJyb3doZWFkUGF0aCIgc3R5bGU9InN0cm9rZS13aWR0aDogMXB4OyBzdHJva2UtZGFzaGFycmF5OiAxcHgsIDBweDsiPjwvcGF0aD48L21hcmtlcj48L2RlZnM+PC9nPjxnIGNsYXNzPSJlZGdlUGF0aCIgc3R5bGU9Im9wYWNpdHk6IDE7Ij48cGF0aCBjbGFzcz0icGF0aCIgZD0iTTQ3MC4wMTE3MTg3NSwxNDIuNTYyNUw0NzAuMDExNzE4NzUsMTY3LjU2MjVMNDcwLjAxMTcxODc1LDE5Mi41NjI1IiBtYXJrZXItZW5kPSJ1cmwoI2Fycm93aGVhZDQzMjcpIiBzdHlsZT0ic3Ryb2tlOiAjMzMzOyBzdHJva2Utd2lkdGg6IDEuNXB4O2ZpbGw6bm9uZSI+PC9wYXRoPjxkZWZzPjxtYXJrZXIgaWQ9ImFycm93aGVhZDQzMjciIHZpZXdCb3g9IjAgMCAxMCAxMCIgcmVmWD0iOSIgcmVmWT0iNSIgbWFya2VyVW5pdHM9InN0cm9rZVdpZHRoIiBtYXJrZXJXaWR0aD0iOCIgbWFya2VySGVpZ2h0PSI2IiBvcmllbnQ9ImF1dG8iPjxwYXRoIGQ9Ik0gMCAwIEwgMTAgNSBMIDAgMTAgeiIgY2xhc3M9ImFycm93aGVhZFBhdGgiIHN0eWxlPSJzdHJva2Utd2lkdGg6IDFweDsgc3Ryb2tlLWRhc2hhcnJheTogMXB4LCAwcHg7Ij48L3BhdGg+PC9tYXJrZXI+PC9kZWZzPjwvZz48ZyBjbGFzcz0iZWRnZVBhdGgiIHN0eWxlPSJvcGFjaXR5OiAxOyI+PHBhdGggY2xhc3M9InBhdGgiIGQ9Ik00MjEuMzIwNzk2MzYwMDE0NDcsMjI4Ljg0Mzc1TDM1NC4yMTg3NSwyNTMuODQzNzVMMzU0LjIxODc1LDI3OC44NDM3NSIgbWFya2VyLWVuZD0idXJsKCNhcnJvd2hlYWQ0MzI4KSIgc3R5bGU9InN0cm9rZTogIzMzMzsgc3Ryb2tlLXdpZHRoOiAxLjVweDtmaWxsOm5vbmUiPjwvcGF0aD48ZGVmcz48bWFya2VyIGlkPSJhcnJvd2hlYWQ0MzI4IiB2aWV3Qm94PSIwIDAgMTAgMTAiIHJlZlg9IjkiIHJlZlk9IjUiIG1hcmtlclVuaXRzPSJzdHJva2VXaWR0aCIgbWFya2VyV2lkdGg9IjgiIG1hcmtlckhlaWdodD0iNiIgb3JpZW50PSJhdXRvIj48cGF0aCBkPSJNIDAgMCBMIDEwIDUgTCAwIDEwIHoiIGNsYXNzPSJhcnJvd2hlYWRQYXRoIiBzdHlsZT0ic3Ryb2tlLXdpZHRoOiAxcHg7IHN0cm9rZS1kYXNoYXJyYXk6IDFweCwgMHB4OyI+PC9wYXRoPjwvbWFya2VyPjwvZGVmcz48L2c+PGcgY2xhc3M9ImVkZ2VQYXRoIiBzdHlsZT0ib3BhY2l0eTogMTsiPjxwYXRoIGNsYXNzPSJwYXRoIiBkPSJNNTE4LjcwMjY0MTEzOTk4NTUsMjI4Ljg0Mzc1TDU4NS44MDQ2ODc1LDI1My44NDM3NUw1ODUuODA0Njg3NSwyNzguODQzNzUiIG1hcmtlci1lbmQ9InVybCgjYXJyb3doZWFkNDMyOSkiIHN0eWxlPSJzdHJva2U6ICMzMzM7IHN0cm9rZS13aWR0aDogMS41cHg7ZmlsbDpub25lIj48L3BhdGg+PGRlZnM+PG1hcmtlciBpZD0iYXJyb3doZWFkNDMyOSIgdmlld0JveD0iMCAwIDEwIDEwIiByZWZYPSI5IiByZWZZPSI1IiBtYXJrZXJVbml0cz0ic3Ryb2tlV2lkdGgiIG1hcmtlcldpZHRoPSI4IiBtYXJrZXJIZWlnaHQ9IjYiIG9yaWVudD0iYXV0byI+PHBhdGggZD0iTSAwIDAgTCAxMCA1IEwgMCAxMCB6IiBjbGFzcz0iYXJyb3doZWFkUGF0aCIgc3R5bGU9InN0cm9rZS13aWR0aDogMXB4OyBzdHJva2UtZGFzaGFycmF5OiAxcHgsIDBweDsiPjwvcGF0aD48L21hcmtlcj48L2RlZnM+PC9nPjxnIGNsYXNzPSJlZGdlUGF0aCIgc3R5bGU9Im9wYWNpdHk6IDE7Ij48cGF0aCBjbGFzcz0icGF0aCIgZD0iTTMyMy41OTc2NTYyNSwyMjguNjM5NjYzNzY1NTE1NjVMMTE3Ljg1OTM3NSwyNTMuODQzNzVMMTE3Ljg1OTM3NSwyNzguODQzNzUiIG1hcmtlci1lbmQ9InVybCgjYXJyb3doZWFkNDMzMCkiIHN0eWxlPSJzdHJva2U6ICMzMzM7IHN0cm9rZS13aWR0aDogMS41cHg7ZmlsbDpub25lIj48L3BhdGg+PGRlZnM+PG1hcmtlciBpZD0iYXJyb3doZWFkNDMzMCIgdmlld0JveD0iMCAwIDEwIDEwIiByZWZYPSI5IiByZWZZPSI1IiBtYXJrZXJVbml0cz0ic3Ryb2tlV2lkdGgiIG1hcmtlcldpZHRoPSI4IiBtYXJrZXJIZWlnaHQ9IjYiIG9yaWVudD0iYXV0byI+PHBhdGggZD0iTSAwIDAgTCAxMCA1IEwgMCAxMCB6IiBjbGFzcz0iYXJyb3doZWFkUGF0aCIgc3R5bGU9InN0cm9rZS13aWR0aDogMXB4OyBzdHJva2UtZGFzaGFycmF5OiAxcHgsIDBweDsiPjwvcGF0aD48L21hcmtlcj48L2RlZnM+PC9nPjxnIGNsYXNzPSJlZGdlUGF0aCIgc3R5bGU9Im9wYWNpdHk6IDE7Ij48cGF0aCBjbGFzcz0icGF0aCIgZD0iTTYxNi40MjU3ODEyNSwyMjcuNDg4OTY2NTkwNDUzNzRMODQ2LjMwNDY4NzUsMjUzLjg0Mzc1TDg0Ni4zMDQ2ODc1LDI3OC44NDM3NSIgbWFya2VyLWVuZD0idXJsKCNhcnJvd2hlYWQ0MzMxKSIgc3R5bGU9InN0cm9rZTogIzMzMzsgc3Ryb2tlLXdpZHRoOiAxLjVweDtmaWxsOm5vbmUiPjwvcGF0aD48ZGVmcz48bWFya2VyIGlkPSJhcnJvd2hlYWQ0MzMxIiB2aWV3Qm94PSIwIDAgMTAgMTAiIHJlZlg9IjkiIHJlZlk9IjUiIG1hcmtlclVuaXRzPSJzdHJva2VXaWR0aCIgbWFya2VyV2lkdGg9IjgiIG1hcmtlckhlaWdodD0iNiIgb3JpZW50PSJhdXRvIj48cGF0aCBkPSJNIDAgMCBMIDEwIDUgTCAwIDEwIHoiIGNsYXNzPSJhcnJvd2hlYWRQYXRoIiBzdHlsZT0ic3Ryb2tlLXdpZHRoOiAxcHg7IHN0cm9rZS1kYXNoYXJyYXk6IDFweCwgMHB4OyI+PC9wYXRoPjwvbWFya2VyPjwvZGVmcz48L2c+PGcgY2xhc3M9ImVkZ2VQYXRoIiBzdHlsZT0ib3BhY2l0eTogMTsiPjxwYXRoIGNsYXNzPSJwYXRoIiBkPSJNMTE3Ljg1OTM3NSwzMTUuMTI1TDExNy44NTkzNzUsMzQwLjEyNUw0MDYuNDEwMTU2MjUsMzc1LjQ3NDA3OTA3OTgyMTY1IiBtYXJrZXItZW5kPSJ1cmwoI2Fycm93aGVhZDQzMzIpIiBzdHlsZT0ic3Ryb2tlOiAjMzMzOyBzdHJva2Utd2lkdGg6IDEuNXB4O2ZpbGw6bm9uZSI+PC9wYXRoPjxkZWZzPjxtYXJrZXIgaWQ9ImFycm93aGVhZDQzMzIiIHZpZXdCb3g9IjAgMCAxMCAxMCIgcmVmWD0iOSIgcmVmWT0iNSIgbWFya2VyVW5pdHM9InN0cm9rZVdpZHRoIiBtYXJrZXJXaWR0aD0iOCIgbWFya2VySGVpZ2h0PSI2IiBvcmllbnQ9ImF1dG8iPjxwYXRoIGQ9Ik0gMCAwIEwgMTAgNSBMIDAgMTAgeiIgY2xhc3M9ImFycm93aGVhZFBhdGgiIHN0eWxlPSJzdHJva2Utd2lkdGg6IDFweDsgc3Ryb2tlLWRhc2hhcnJheTogMXB4LCAwcHg7Ij48L3BhdGg+PC9tYXJrZXI+PC9kZWZzPjwvZz48ZyBjbGFzcz0iZWRnZVBhdGgiIHN0eWxlPSJvcGFjaXR5OiAxOyI+PHBhdGggY2xhc3M9InBhdGgiIGQ9Ik0zNTQuMjE4NzUsMzE1LjEyNUwzNTQuMjE4NzUsMzQwLjEyNUw0MjEuMzIwNzk2MzYwMDE0NDcsMzY1LjEyNSIgbWFya2VyLWVuZD0idXJsKCNhcnJvd2hlYWQ0MzMzKSIgc3R5bGU9InN0cm9rZTogIzMzMzsgc3Ryb2tlLXdpZHRoOiAxLjVweDtmaWxsOm5vbmUiPjwvcGF0aD48ZGVmcz48bWFya2VyIGlkPSJhcnJvd2hlYWQ0MzMzIiB2aWV3Qm94PSIwIDAgMTAgMTAiIHJlZlg9IjkiIHJlZlk9IjUiIG1hcmtlclVuaXRzPSJzdHJva2VXaWR0aCIgbWFya2VyV2lkdGg9IjgiIG1hcmtlckhlaWdodD0iNiIgb3JpZW50PSJhdXRvIj48cGF0aCBkPSJNIDAgMCBMIDEwIDUgTCAwIDEwIHoiIGNsYXNzPSJhcnJvd2hlYWRQYXRoIiBzdHlsZT0ic3Ryb2tlLXdpZHRoOiAxcHg7IHN0cm9rZS1kYXNoYXJyYXk6IDFweCwgMHB4OyI+PC9wYXRoPjwvbWFya2VyPjwvZGVmcz48L2c+PGcgY2xhc3M9ImVkZ2VQYXRoIiBzdHlsZT0ib3BhY2l0eTogMTsiPjxwYXRoIGNsYXNzPSJwYXRoIiBkPSJNNTg1LjgwNDY4NzUsMzE1LjEyNUw1ODUuODA0Njg3NSwzNDAuMTI1TDUxOC43MDI2NDExMzk5ODU1LDM2NS4xMjUiIG1hcmtlci1lbmQ9InVybCgjYXJyb3doZWFkNDMzNCkiIHN0eWxlPSJzdHJva2U6ICMzMzM7IHN0cm9rZS13aWR0aDogMS41cHg7ZmlsbDpub25lIj48L3BhdGg+PGRlZnM+PG1hcmtlciBpZD0iYXJyb3doZWFkNDMzNCIgdmlld0JveD0iMCAwIDEwIDEwIiByZWZYPSI5IiByZWZZPSI1IiBtYXJrZXJVbml0cz0ic3Ryb2tlV2lkdGgiIG1hcmtlcldpZHRoPSI4IiBtYXJrZXJIZWlnaHQ9IjYiIG9yaWVudD0iYXV0byI+PHBhdGggZD0iTSAwIDAgTCAxMCA1IEwgMCAxMCB6IiBjbGFzcz0iYXJyb3doZWFkUGF0aCIgc3R5bGU9InN0cm9rZS13aWR0aDogMXB4OyBzdHJva2UtZGFzaGFycmF5OiAxcHgsIDBweDsiPjwvcGF0aD48L21hcmtlcj48L2RlZnM+PC9nPjxnIGNsYXNzPSJlZGdlUGF0aCIgc3R5bGU9Im9wYWNpdHk6IDE7Ij48cGF0aCBjbGFzcz0icGF0aCIgZD0iTTg0Ni4zMDQ2ODc1LDMxNS4xMjVMODQ2LjMwNDY4NzUsMzQwLjEyNUw1MzMuNjEzMjgxMjUsMzc1Ljk3MzkzNjM4MjEwOTYiIG1hcmtlci1lbmQ9InVybCgjYXJyb3doZWFkNDMzNSkiIHN0eWxlPSJzdHJva2U6ICMzMzM7IHN0cm9rZS13aWR0aDogMS41cHg7ZmlsbDpub25lIj48L3BhdGg+PGRlZnM+PG1hcmtlciBpZD0iYXJyb3doZWFkNDMzNSIgdmlld0JveD0iMCAwIDEwIDEwIiByZWZYPSI5IiByZWZZPSI1IiBtYXJrZXJVbml0cz0ic3Ryb2tlV2lkdGgiIG1hcmtlcldpZHRoPSI4IiBtYXJrZXJIZWlnaHQ9IjYiIG9yaWVudD0iYXV0byI+PHBhdGggZD0iTSAwIDAgTCAxMCA1IEwgMCAxMCB6IiBjbGFzcz0iYXJyb3doZWFkUGF0aCIgc3R5bGU9InN0cm9rZS13aWR0aDogMXB4OyBzdHJva2UtZGFzaGFycmF5OiAxcHgsIDBweDsiPjwvcGF0aD48L21hcmtlcj48L2RlZnM+PC9nPjxnIGNsYXNzPSJlZGdlUGF0aCIgc3R5bGU9Im9wYWNpdHk6IDE7Ij48cGF0aCBjbGFzcz0icGF0aCIgZD0iTTQ0Ni4yMDY5ODQ4MzIwMzg0LDQwMS40MDYyNUw0MDIuNzE4NzUsNDM0LjU0Njg3NUw0MDIuNzE4NzUsNDY3LjY4NzUiIG1hcmtlci1lbmQ9InVybCgjYXJyb3doZWFkNDMzNikiIHN0eWxlPSJzdHJva2U6ICMzMzM7IHN0cm9rZS13aWR0aDogMS41cHg7ZmlsbDpub25lIj48L3BhdGg+PGRlZnM+PG1hcmtlciBpZD0iYXJyb3doZWFkNDMzNiIgdmlld0JveD0iMCAwIDEwIDEwIiByZWZYPSI5IiByZWZZPSI1IiBtYXJrZXJVbml0cz0ic3Ryb2tlV2lkdGgiIG1hcmtlcldpZHRoPSI4IiBtYXJrZXJIZWlnaHQ9IjYiIG9yaWVudD0iYXV0byI+PHBhdGggZD0iTSAwIDAgTCAxMCA1IEwgMCAxMCB6IiBjbGFzcz0iYXJyb3doZWFkUGF0aCIgc3R5bGU9InN0cm9rZS13aWR0aDogMXB4OyBzdHJva2UtZGFzaGFycmF5OiAxcHgsIDBweDsiPjwvcGF0aD48L21hcmtlcj48L2RlZnM+PC9nPjxnIGNsYXNzPSJlZGdlUGF0aCIgc3R5bGU9Im9wYWNpdHk6IDE7Ij48cGF0aCBjbGFzcz0icGF0aCIgZD0iTTQwMi43MTg3NSw1MDMuOTY4NzVMNDAyLjcxODc1LDUzNy4xMDkzNzVMNDM3LjQ2NjkxOTE3MzI1MDEsNjAzLjc5NDgwMTEwMjYyODQiIG1hcmtlci1lbmQ9InVybCgjYXJyb3doZWFkNDMzNykiIHN0eWxlPSJzdHJva2U6ICMzMzM7IHN0cm9rZS13aWR0aDogMS41cHg7ZmlsbDpub25lIj48L3BhdGg+PGRlZnM+PG1hcmtlciBpZD0iYXJyb3doZWFkNDMzNyIgdmlld0JveD0iMCAwIDEwIDEwIiByZWZYPSI5IiByZWZZPSI1IiBtYXJrZXJVbml0cz0ic3Ryb2tlV2lkdGgiIG1hcmtlcldpZHRoPSI4IiBtYXJrZXJIZWlnaHQ9IjYiIG9yaWVudD0iYXV0byI+PHBhdGggZD0iTSAwIDAgTCAxMCA1IEwgMCAxMCB6IiBjbGFzcz0iYXJyb3doZWFkUGF0aCIgc3R5bGU9InN0cm9rZS13aWR0aDogMXB4OyBzdHJva2UtZGFzaGFycmF5OiAxcHgsIDBweDsiPjwvcGF0aD48L21hcmtlcj48L2RlZnM+PC9nPjxnIGNsYXNzPSJlZGdlUGF0aCIgc3R5bGU9Im9wYWNpdHk6IDE7Ij48cGF0aCBjbGFzcz0icGF0aCIgZD0iTTQ3MC41MTE3MTg3NSw3NjQuNTU5MzczNDc0MTIwOUw0NzAuMDExNzE4NzUsNzk3LjE5OTk5Njk0ODI0MjJMNDcwLjAxMTcxODc1LDgzMC4zNDA2MjE5NDgyNDIyIiBtYXJrZXItZW5kPSJ1cmwoI2Fycm93aGVhZDQzMzgpIiBzdHlsZT0ic3Ryb2tlOiAjMzMzOyBzdHJva2Utd2lkdGg6IDEuNXB4O2ZpbGw6bm9uZSI+PC9wYXRoPjxkZWZzPjxtYXJrZXIgaWQ9ImFycm93aGVhZDQzMzgiIHZpZXdCb3g9IjAgMCAxMCAxMCIgcmVmWD0iOSIgcmVmWT0iNSIgbWFya2VyVW5pdHM9InN0cm9rZVdpZHRoIiBtYXJrZXJXaWR0aD0iOCIgbWFya2VySGVpZ2h0PSI2IiBvcmllbnQ9ImF1dG8iPjxwYXRoIGQ9Ik0gMCAwIEwgMTAgNSBMIDAgMTAgeiIgY2xhc3M9ImFycm93aGVhZFBhdGgiIHN0eWxlPSJzdHJva2Utd2lkdGg6IDFweDsgc3Ryb2tlLWRhc2hhcnJheTogMXB4LCAwcHg7Ij48L3BhdGg+PC9tYXJrZXI+PC9kZWZzPjwvZz48ZyBjbGFzcz0iZWRnZVBhdGgiIHN0eWxlPSJvcGFjaXR5OiAxOyI+PHBhdGggY2xhc3M9InBhdGgiIGQ9Ik00NzAuMDExNzE4NzUsODY2LjYyMTg3MTk0ODI0MjJMNDcwLjAxMTcxODc1LDg5MS42MjE4NzE5NDgyNDIyTDQ3MC4wMTE3MTg3NSw5MTYuNjIxODcxOTQ4MjQyMiIgbWFya2VyLWVuZD0idXJsKCNhcnJvd2hlYWQ0MzM5KSIgc3R5bGU9InN0cm9rZTogIzMzMzsgc3Ryb2tlLXdpZHRoOiAxLjVweDtmaWxsOm5vbmUiPjwvcGF0aD48ZGVmcz48bWFya2VyIGlkPSJhcnJvd2hlYWQ0MzM5IiB2aWV3Qm94PSIwIDAgMTAgMTAiIHJlZlg9IjkiIHJlZlk9IjUiIG1hcmtlclVuaXRzPSJzdHJva2VXaWR0aCIgbWFya2VyV2lkdGg9IjgiIG1hcmtlckhlaWdodD0iNiIgb3JpZW50PSJhdXRvIj48cGF0aCBkPSJNIDAgMCBMIDEwIDUgTCAwIDEwIHoiIGNsYXNzPSJhcnJvd2hlYWRQYXRoIiBzdHlsZT0ic3Ryb2tlLXdpZHRoOiAxcHg7IHN0cm9rZS1kYXNoYXJyYXk6IDFweCwgMHB4OyI+PC9wYXRoPjwvbWFya2VyPjwvZGVmcz48L2c+PGcgY2xhc3M9ImVkZ2VQYXRoIiBzdHlsZT0ib3BhY2l0eTogMTsiPjxwYXRoIGNsYXNzPSJwYXRoIiBkPSJNNTAzLjU1NjUxOTM2NzQwODUsNjAzLjc5NDc5OTA5MTUzMDFMNTM3LjMwNDY4NzUsNTM3LjEwOTM3NUw1MzcuMzA0Njg3NSw0ODUuODI4MTI1TDUzNy4zMDQ2ODc1LDQzNC41NDY4NzVMNDkzLjgxNjQ1MjY2Nzk2MTYsNDAxLjQwNjI1IiBtYXJrZXItZW5kPSJ1cmwoI2Fycm93aGVhZDQzNDApIiBzdHlsZT0ic3Ryb2tlOiAjMzMzOyBzdHJva2Utd2lkdGg6IDEuNXB4O2ZpbGw6bm9uZSI+PC9wYXRoPjxkZWZzPjxtYXJrZXIgaWQ9ImFycm93aGVhZDQzNDAiIHZpZXdCb3g9IjAgMCAxMCAxMCIgcmVmWD0iOSIgcmVmWT0iNSIgbWFya2VyVW5pdHM9InN0cm9rZVdpZHRoIiBtYXJrZXJXaWR0aD0iOCIgbWFya2VySGVpZ2h0PSI2IiBvcmllbnQ9ImF1dG8iPjxwYXRoIGQ9Ik0gMCAwIEwgMTAgNSBMIDAgMTAgeiIgY2xhc3M9ImFycm93aGVhZFBhdGgiIHN0eWxlPSJzdHJva2Utd2lkdGg6IDFweDsgc3Ryb2tlLWRhc2hhcnJheTogMXB4LCAwcHg7Ij48L3BhdGg+PC9tYXJrZXI+PC9kZWZzPjwvZz48L2c+PGcgY2xhc3M9ImVkZ2VMYWJlbHMiPjxnIGNsYXNzPSJlZGdlTGFiZWwiIHRyYW5zZm9ybT0iIiBzdHlsZT0ib3BhY2l0eTogMTsiPjxnIHRyYW5zZm9ybT0idHJhbnNsYXRlKDAsMCkiIGNsYXNzPSJsYWJlbCI+PHJlY3Qgcng9IjAiIHJ5PSIwIiB3aWR0aD0iMCIgaGVpZ2h0PSIwIiBzdHlsZT0iZmlsbDojZThlOGU4OyI+PC9yZWN0Pjx0ZXh0Pjx0c3BhbiB4bWw6c3BhY2U9InByZXNlcnZlIiBkeT0iMWVtIiB4PSIxIj48L3RzcGFuPjwvdGV4dD48L2c+PC9nPjxnIGNsYXNzPSJlZGdlTGFiZWwiIHRyYW5zZm9ybT0iIiBzdHlsZT0ib3BhY2l0eTogMTsiPjxnIHRyYW5zZm9ybT0idHJhbnNsYXRlKDAsMCkiIGNsYXNzPSJsYWJlbCI+PHJlY3Qgcng9IjAiIHJ5PSIwIiB3aWR0aD0iMCIgaGVpZ2h0PSIwIiBzdHlsZT0iZmlsbDojZThlOGU4OyI+PC9yZWN0Pjx0ZXh0Pjx0c3BhbiB4bWw6c3BhY2U9InByZXNlcnZlIiBkeT0iMWVtIiB4PSIxIj48L3RzcGFuPjwvdGV4dD48L2c+PC9nPjxnIGNsYXNzPSJlZGdlTGFiZWwiIHRyYW5zZm9ybT0iIiBzdHlsZT0ib3BhY2l0eTogMTsiPjxnIHRyYW5zZm9ybT0idHJhbnNsYXRlKDAsMCkiIGNsYXNzPSJsYWJlbCI+PHJlY3Qgcng9IjAiIHJ5PSIwIiB3aWR0aD0iMCIgaGVpZ2h0PSIwIiBzdHlsZT0iZmlsbDojZThlOGU4OyI+PC9yZWN0Pjx0ZXh0Pjx0c3BhbiB4bWw6c3BhY2U9InByZXNlcnZlIiBkeT0iMWVtIiB4PSIxIj48L3RzcGFuPjwvdGV4dD48L2c+PC9nPjxnIGNsYXNzPSJlZGdlTGFiZWwiIHRyYW5zZm9ybT0iIiBzdHlsZT0ib3BhY2l0eTogMTsiPjxnIHRyYW5zZm9ybT0idHJhbnNsYXRlKDAsMCkiIGNsYXNzPSJsYWJlbCI+PHJlY3Qgcng9IjAiIHJ5PSIwIiB3aWR0aD0iMCIgaGVpZ2h0PSIwIiBzdHlsZT0iZmlsbDojZThlOGU4OyI+PC9yZWN0Pjx0ZXh0Pjx0c3BhbiB4bWw6c3BhY2U9InByZXNlcnZlIiBkeT0iMWVtIiB4PSIxIj48L3RzcGFuPjwvdGV4dD48L2c+PC9nPjxnIGNsYXNzPSJlZGdlTGFiZWwiIHRyYW5zZm9ybT0iIiBzdHlsZT0ib3BhY2l0eTogMTsiPjxnIHRyYW5zZm9ybT0idHJhbnNsYXRlKDAsMCkiIGNsYXNzPSJsYWJlbCI+PHJlY3Qgcng9IjAiIHJ5PSIwIiB3aWR0aD0iMCIgaGVpZ2h0PSIwIiBzdHlsZT0iZmlsbDojZThlOGU4OyI+PC9yZWN0Pjx0ZXh0Pjx0c3BhbiB4bWw6c3BhY2U9InByZXNlcnZlIiBkeT0iMWVtIiB4PSIxIj48L3RzcGFuPjwvdGV4dD48L2c+PC9nPjxnIGNsYXNzPSJlZGdlTGFiZWwiIHRyYW5zZm9ybT0iIiBzdHlsZT0ib3BhY2l0eTogMTsiPjxnIHRyYW5zZm9ybT0idHJhbnNsYXRlKDAsMCkiIGNsYXNzPSJsYWJlbCI+PHJlY3Qgcng9IjAiIHJ5PSIwIiB3aWR0aD0iMCIgaGVpZ2h0PSIwIiBzdHlsZT0iZmlsbDojZThlOGU4OyI+PC9yZWN0Pjx0ZXh0Pjx0c3BhbiB4bWw6c3BhY2U9InByZXNlcnZlIiBkeT0iMWVtIiB4PSIxIj48L3RzcGFuPjwvdGV4dD48L2c+PC9nPjxnIGNsYXNzPSJlZGdlTGFiZWwiIHRyYW5zZm9ybT0iIiBzdHlsZT0ib3BhY2l0eTogMTsiPjxnIHRyYW5zZm9ybT0idHJhbnNsYXRlKDAsMCkiIGNsYXNzPSJsYWJlbCI+PHJlY3Qgcng9IjAiIHJ5PSIwIiB3aWR0aD0iMCIgaGVpZ2h0PSIwIiBzdHlsZT0iZmlsbDojZThlOGU4OyI+PC9yZWN0Pjx0ZXh0Pjx0c3BhbiB4bWw6c3BhY2U9InByZXNlcnZlIiBkeT0iMWVtIiB4PSIxIj48L3RzcGFuPjwvdGV4dD48L2c+PC9nPjxnIGNsYXNzPSJlZGdlTGFiZWwiIHRyYW5zZm9ybT0iIiBzdHlsZT0ib3BhY2l0eTogMTsiPjxnIHRyYW5zZm9ybT0idHJhbnNsYXRlKDAsMCkiIGNsYXNzPSJsYWJlbCI+PHJlY3Qgcng9IjAiIHJ5PSIwIiB3aWR0aD0iMCIgaGVpZ2h0PSIwIiBzdHlsZT0iZmlsbDojZThlOGU4OyI+PC9yZWN0Pjx0ZXh0Pjx0c3BhbiB4bWw6c3BhY2U9InByZXNlcnZlIiBkeT0iMWVtIiB4PSIxIj48L3RzcGFuPjwvdGV4dD48L2c+PC9nPjxnIGNsYXNzPSJlZGdlTGFiZWwiIHRyYW5zZm9ybT0iIiBzdHlsZT0ib3BhY2l0eTogMTsiPjxnIHRyYW5zZm9ybT0idHJhbnNsYXRlKDAsMCkiIGNsYXNzPSJsYWJlbCI+PHJlY3Qgcng9IjAiIHJ5PSIwIiB3aWR0aD0iMCIgaGVpZ2h0PSIwIiBzdHlsZT0iZmlsbDojZThlOGU4OyI+PC9yZWN0Pjx0ZXh0Pjx0c3BhbiB4bWw6c3BhY2U9InByZXNlcnZlIiBkeT0iMWVtIiB4PSIxIj48L3RzcGFuPjwvdGV4dD48L2c+PC9nPjxnIGNsYXNzPSJlZGdlTGFiZWwiIHRyYW5zZm9ybT0iIiBzdHlsZT0ib3BhY2l0eTogMTsiPjxnIHRyYW5zZm9ybT0idHJhbnNsYXRlKDAsMCkiIGNsYXNzPSJsYWJlbCI+PHJlY3Qgcng9IjAiIHJ5PSIwIiB3aWR0aD0iMCIgaGVpZ2h0PSIwIiBzdHlsZT0iZmlsbDojZThlOGU4OyI+PC9yZWN0Pjx0ZXh0Pjx0c3BhbiB4bWw6c3BhY2U9InByZXNlcnZlIiBkeT0iMWVtIiB4PSIxIj48L3RzcGFuPjwvdGV4dD48L2c+PC9nPjxnIGNsYXNzPSJlZGdlTGFiZWwiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDQwMi43MTg3NSw0MzQuNTQ2ODc1KSIgc3R5bGU9Im9wYWNpdHk6IDE7Ij48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtNTIuODEyNSwtOC4wMDc4MTI1KSIgY2xhc3M9ImxhYmVsIj48cmVjdCByeD0iMCIgcnk9IjAiIHdpZHRoPSI3Ni40Mzc1IiBoZWlnaHQ9IjE2LjM1OTM3NSIgc3R5bGU9ImZpbGw6I2U4ZThlODsiPjwvcmVjdD48dGV4dD48dHNwYW4geG1sOnNwYWNlPSJwcmVzZXJ2ZSIgZHk9IjFlbSIgeD0iMSI+dGhlIGl0aCBlbnRyeTwvdHNwYW4+PC90ZXh0PjwvZz48L2c+PGcgY2xhc3M9ImVkZ2VMYWJlbCIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoNDAyLjcxODc1LDUzNy4xMDkzNzUpIiBzdHlsZT0ib3BhY2l0eTogMTsiPjxnIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0xMDUuNDY4NzUsLTguMDA3ODEyNSkiIGNsYXNzPSJsYWJlbCI+PHJlY3Qgcng9IjAiIHJ5PSIwIiB3aWR0aD0iMTY3LjAzMTI1IiBoZWlnaHQ9IjE2LjM1OTM3NSIgc3R5bGU9ImZpbGw6I2U4ZThlODsiPjwvcmVjdD48dGV4dD48dHNwYW4geG1sOnNwYWNlPSJwcmVzZXJ2ZSIgZHk9IjFlbSIgeD0iMSI+bmFtZSBpbmRleCBpbiBzeW1ib2wgZW50cnk8L3RzcGFuPjwvdGV4dD48L2c+PC9nPjxnIGNsYXNzPSJlZGdlTGFiZWwiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDQ3MC4wMTE3MTg3NSw3OTcuMTk5OTk2OTQ4MjQyMikiIHN0eWxlPSJvcGFjaXR5OiAxOyI+PGcgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTQuMjAzMTI1LC04LjAwNzgxMjUpIiBjbGFzcz0ibGFiZWwiPjxyZWN0IHJ4PSIwIiByeT0iMCIgd2lkdGg9IjguMDMxMjUiIGhlaWdodD0iMTYuMzU5Mzc1IiBzdHlsZT0iZmlsbDojZThlOGU4OyI+PC9yZWN0Pjx0ZXh0Pjx0c3BhbiB4bWw6c3BhY2U9InByZXNlcnZlIiBkeT0iMWVtIiB4PSIxIj5ZPC90c3Bhbj48L3RleHQ+PC9nPjwvZz48ZyBjbGFzcz0iZWRnZUxhYmVsIiB0cmFuc2Zvcm09IiIgc3R5bGU9Im9wYWNpdHk6IDE7Ij48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgwLDApIiBjbGFzcz0ibGFiZWwiPjxyZWN0IHJ4PSIwIiByeT0iMCIgd2lkdGg9IjAiIGhlaWdodD0iMCIgc3R5bGU9ImZpbGw6I2U4ZThlODsiPjwvcmVjdD48dGV4dD48dHNwYW4geG1sOnNwYWNlPSJwcmVzZXJ2ZSIgZHk9IjFlbSIgeD0iMSI+PC90c3Bhbj48L3RleHQ+PC9nPjwvZz48ZyBjbGFzcz0iZWRnZUxhYmVsIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSg1MzcuMzA0Njg3NSw0ODUuODI4MTI1KSIgc3R5bGU9Im9wYWNpdHk6IDE7Ij48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtNC4yMDMxMjUsLTguMDA3ODEyNSkiIGNsYXNzPSJsYWJlbCI+PHJlY3Qgcng9IjAiIHJ5PSIwIiB3aWR0aD0iOC45ODQzNzUiIGhlaWdodD0iMTYuMzU5Mzc1IiBzdHlsZT0iZmlsbDojZThlOGU4OyI+PC9yZWN0Pjx0ZXh0Pjx0c3BhbiB4bWw6c3BhY2U9InByZXNlcnZlIiBkeT0iMWVtIiB4PSIxIj5OPC90c3Bhbj48L3RleHQ+PC9nPjwvZz48L2c+PGcgY2xhc3M9Im5vZGVzIj48ZyBjbGFzcz0ibm9kZSIgaWQ9IkEiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDQ3MC4wMTE3MTg3NSwzOC4xNDA2MjUpIiBzdHlsZT0ib3BhY2l0eTogMTsiPjxyZWN0IHJ4PSIwIiByeT0iMCIgeD0iLTE0NS40NjA5Mzc1IiB5PSItMTguMTQwNjI1IiB3aWR0aD0iMjkwLjkyMTg3NSIgaGVpZ2h0PSIzNi4yODEyNSI+PC9yZWN0PjxnIGNsYXNzPSJsYWJlbCIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMCwwKSI+PGcgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTEzNS40NjA5Mzc1LC04LjE0MDYyNSkiPjx0ZXh0Pjx0c3BhbiB4bWw6c3BhY2U9InByZXNlcnZlIiBkeT0iMWVtIiB4PSIxIj5nZXQgbW9kdWxlIGJhc2UgZnJvbSAvcHJvYy8mbHQ7cGlkJmd0Oy9tYXBzIGZpbGU8L3RzcGFuPjwvdGV4dD48L2c+PC9nPjwvZz48ZyBjbGFzcz0ibm9kZSIgaWQ9IkIiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDQ3MC4wMTE3MTg3NSwxMjQuNDIxODc1KSIgc3R5bGU9Im9wYWNpdHk6IDE7Ij48cmVjdCByeD0iMCIgcnk9IjAiIHg9Ii0xMTAiIHk9Ii0xOC4xNDA2MjUiIHdpZHRoPSIyMjAiIGhlaWdodD0iMzYuMjgxMjUiPjwvcmVjdD48ZyBjbGFzcz0ibGFiZWwiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDAsMCkiPjxnIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0xMDAsLTguMTQwNjI1KSI+PHRleHQ+PHRzcGFuIHhtbDpzcGFjZT0icHJlc2VydmUiIGR5PSIxZW0iIHg9IjEiPlByb2dyYW0gdGFibGUgaXMgYXQgdGhlIGJlZ2lubmluZzwvdHNwYW4+PC90ZXh0PjwvZz48L2c+PC9nPjxnIGNsYXNzPSJub2RlIiBpZD0iQyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoNDcwLjAxMTcxODc1LDIxMC43MDMxMjUpIiBzdHlsZT0ib3BhY2l0eTogMTsiPjxyZWN0IHJ4PSIwIiByeT0iMCIgeD0iLTE0Ni40MTQwNjI1IiB5PSItMTguMTQwNjI1IiB3aWR0aD0iMjkyLjgyODEyNSIgaGVpZ2h0PSIzNi4yODEyNSI+PC9yZWN0PjxnIGNsYXNzPSJsYWJlbCIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMCwwKSI+PGcgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTEzNi40MTQwNjI1LC04LjE0MDYyNSkiPjx0ZXh0Pjx0c3BhbiB4bWw6c3BhY2U9InByZXNlcnZlIiBkeT0iMWVtIiB4PSIxIj5GaW5kIC5keW5hbWljIHNlY3Rpb24gaW4gUEhUIGJ5IFBUX0RZTkFNSUM8L3RzcGFuPjwvdGV4dD48L2c+PC9nPjwvZz48ZyBjbGFzcz0ibm9kZSIgaWQ9IkQiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDM1NC4yMTg3NSwyOTYuOTg0Mzc1KSIgc3R5bGU9Im9wYWNpdHk6IDE7Ij48cmVjdCByeD0iMCIgcnk9IjAiIHg9Ii04OC41IiB5PSItMTguMTQwNjI1IiB3aWR0aD0iMTc3IiBoZWlnaHQ9IjM2LjI4MTI1Ij48L3JlY3Q+PGcgY2xhc3M9ImxhYmVsIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgwLDApIj48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtNzguNSwtOC4xNDA2MjUpIj48dGV4dD48dHNwYW4geG1sOnNwYWNlPSJwcmVzZXJ2ZSIgZHk9IjFlbSIgeD0iMSI+R2V0IC5zdHJ0YWIgYnkgRFRfU1RSVEFCPC90c3Bhbj48L3RleHQ+PC9nPjwvZz48L2c+PGcgY2xhc3M9Im5vZGUiIGlkPSJFIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSg1ODUuODA0Njg3NSwyOTYuOTg0Mzc1KSIgc3R5bGU9Im9wYWNpdHk6IDE7Ij48cmVjdCByeD0iMCIgcnk9IjAiIHg9Ii05My4wODU5Mzc1IiB5PSItMTguMTQwNjI1IiB3aWR0aD0iMTg2LjE3MTg3NSIgaGVpZ2h0PSIzNi4yODEyNSI+PC9yZWN0PjxnIGNsYXNzPSJsYWJlbCIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMCwwKSI+PGcgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTgzLjA4NTkzNzUsLTguMTQwNjI1KSI+PHRleHQ+PHRzcGFuIHhtbDpzcGFjZT0icHJlc2VydmUiIGR5PSIxZW0iIHg9IjEiPkdldCAuc3ltdGFiIGJ5IERUX1NZTVRBQjwvdHNwYW4+PC90ZXh0PjwvZz48L2c+PC9nPjxnIGNsYXNzPSJub2RlIiBpZD0iRiIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMTE3Ljg1OTM3NSwyOTYuOTg0Mzc1KSIgc3R5bGU9Im9wYWNpdHk6IDE7Ij48cmVjdCByeD0iMCIgcnk9IjAiIHg9Ii05Ny44NTkzNzUiIHk9Ii0xOC4xNDA2MjUiIHdpZHRoPSIxOTUuNzE4NzUiIGhlaWdodD0iMzYuMjgxMjUiPjwvcmVjdD48ZyBjbGFzcz0ibGFiZWwiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDAsMCkiPjxnIHRyYW5zZm9ybT0idHJhbnNsYXRlKC04Ny44NTkzNzUsLTguMTQwNjI1KSI+PHRleHQ+PHRzcGFuIHhtbDpzcGFjZT0icHJlc2VydmUiIGR5PSIxZW0iIHg9IjEiPkdldCAucmVsKGEpLnBsdCBieSBEVF9KTVBSRUw8L3RzcGFuPjwvdGV4dD48L2c+PC9nPjwvZz48ZyBjbGFzcz0ibm9kZSIgaWQ9IkciIHRyYW5zZm9ybT0idHJhbnNsYXRlKDg0Ni4zMDQ2ODc1LDI5Ni45ODQzNzUpIiBzdHlsZT0ib3BhY2l0eTogMTsiPjxyZWN0IHJ4PSIwIiByeT0iMCIgeD0iLTExNy40MTQwNjI1IiB5PSItMTguMTQwNjI1IiB3aWR0aD0iMjM0LjgyODEyNSIgaGVpZ2h0PSIzNi4yODEyNSI+PC9yZWN0PjxnIGNsYXNzPSJsYWJlbCIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMCwwKSI+PGcgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTEwNy40MTQwNjI1LC04LjE0MDYyNSkiPjx0ZXh0Pjx0c3BhbiB4bWw6c3BhY2U9InByZXNlcnZlIiBkeT0iMWVtIiB4PSIxIj5HZXQgLnJlbChhKS5wbHQgc2l6ZSBieSBEVF9QTFRSRUxTWjwvdHNwYW4+PC90ZXh0PjwvZz48L2c+PC9nPjxnIGNsYXNzPSJub2RlIiBpZD0iSSIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoNDcwLjAxMTcxODc1LDM4My4yNjU2MjUpIiBzdHlsZT0ib3BhY2l0eTogMTsiPjxyZWN0IHJ4PSIwIiByeT0iMCIgeD0iLTYzLjYwMTU2MjUiIHk9Ii0xOC4xNDA2MjUiIHdpZHRoPSIxMjcuMjAzMTI1IiBoZWlnaHQ9IjM2LjI4MTI1Ij48L3JlY3Q+PGcgY2xhc3M9ImxhYmVsIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgwLDApIj48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtNTMuNjAxNTYyNSwtOC4xNDA2MjUpIj48dGV4dD48dHNwYW4geG1sOnNwYWNlPSJwcmVzZXJ2ZSIgZHk9IjFlbSIgeD0iMSI+TG9vcCBpbiAucmVsKGEpLnBsdDwvdHNwYW4+PC90ZXh0PjwvZz48L2c+PC9nPjxnIGNsYXNzPSJub2RlIiBpZD0iSiIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoNDAyLjcxODc1LDQ4NS44MjgxMjUpIiBzdHlsZT0ib3BhY2l0eTogMTsiPjxyZWN0IHJ4PSIwIiByeT0iMCIgeD0iLTk1LjExNzE4NzUiIHk9Ii0xOC4xNDA2MjUiIHdpZHRoPSIxOTAuMjM0Mzc1IiBoZWlnaHQ9IjM2LjI4MTI1Ij48L3JlY3Q+PGcgY2xhc3M9ImxhYmVsIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgwLDApIj48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtODUuMTE3MTg3NSwtOC4xNDA2MjUpIj48dGV4dD48dHNwYW4geG1sOnNwYWNlPSJwcmVzZXJ2ZSIgZHk9IjFlbSIgeD0iMSI+R2V0IHN5bWJvbCBlbnRyeSBpbiAuc3ltdGFiPC90c3Bhbj48L3RleHQ+PC9nPjwvZz48L2c+PGcgY2xhc3M9Im5vZGUiIGlkPSJIIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSg0NzAuMDExNzE4NzUsNjY3LjE1NDY4NTk3NDEyMTEpIiBzdHlsZT0ib3BhY2l0eTogMTsiPjxwb2x5Z29uIHBvaW50cz0iOTYuOTA0Njg3NTAwMDAwMDEsMCAxOTMuODA5Mzc1MDAwMDAwMDIsLTk2LjkwNDY4NzUwMDAwMDAxIDk2LjkwNDY4NzUwMDAwMDAxLC0xOTMuODA5Mzc1MDAwMDAwMDIgMCwtOTYuOTA0Njg3NTAwMDAwMDEiIHJ4PSI1IiByeT0iNSIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTk2LjkwNDY4NzUwMDAwMDAxLDk2LjkwNDY4NzUwMDAwMDAxKSI+PC9wb2x5Z29uPjxnIGNsYXNzPSJsYWJlbCIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMCwwKSI+PGcgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTc5LjUzMTI1LC04LjE0MDYyNSkiPjx0ZXh0Pjx0c3BhbiB4bWw6c3BhY2U9InByZXNlcnZlIiBkeT0iMWVtIiB4PSIxIj5OYW1lIGluIC5zdHJ0YWIgbWF0Y2hlZCA/PC90c3Bhbj48L3RleHQ+PC9nPjwvZz48L2c+PGcgY2xhc3M9Im5vZGUiIGlkPSJLIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSg0NzAuMDExNzE4NzUsODQ4LjQ4MTI0Njk0ODI0MjIpIiBzdHlsZT0ib3BhY2l0eTogMTsiPjxyZWN0IHJ4PSIwIiByeT0iMCIgeD0iLTY1LjA3MDMxMjUiIHk9Ii0xOC4xNDA2MjUiIHdpZHRoPSIxMzAuMTQwNjI1IiBoZWlnaHQ9IjM2LjI4MTI1Ij48L3JlY3Q+PGcgY2xhc3M9ImxhYmVsIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgwLDApIj48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtNTUuMDcwMzEyNSwtOC4xNDA2MjUpIj48dGV4dD48dHNwYW4geG1sOnNwYWNlPSJwcmVzZXJ2ZSIgZHk9IjFlbSIgeD0iMSI+VXBkYXRlIHRhYmxlIGl0ZW08L3RzcGFuPjwvdGV4dD48L2c+PC9nPjwvZz48ZyBjbGFzcz0ibm9kZSIgaWQ9IkwiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDQ3MC4wMTE3MTg3NSw5MzcuODAxNTU5NDQ4MjQyMikiIHN0eWxlPSJvcGFjaXR5OiAxOyI+PGNpcmNsZSB4PSItMjEuMTc5Njg3NSIgeT0iLTE4LjE0MDYyNSIgcj0iMjEuMTc5Njg3NSI+PC9jaXJjbGU+PGcgY2xhc3M9ImxhYmVsIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgwLDApIj48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMTEuMTc5Njg3NSwtOC4xNDA2MjUpIj48dGV4dD48dHNwYW4geG1sOnNwYWNlPSJwcmVzZXJ2ZSIgZHk9IjFlbSIgeD0iMSI+RW5kPC90c3Bhbj48L3RleHQ+PC9nPjwvZz48L2c+PC9nPjwvZz48L2c+PC9zdmc+
我的基础代码来自于[1],总的项目后面我会更新到zhougy0717/inject_got仓库中。
Get module base
这里要做的其实就是获取对应的image在虚拟内存中的位置。例如:
可执行文件
// 打开文件/proc/pid/maps,获取指定pid进程加载的内存模块信息
fp = fopen(filename, "r");
if(fp != NULL){
// 每次一行,读取文件 /proc/pid/maps中内容
while(fgets(line, sizeof(line), fp)){
// 查找指定的so模块
if(strstr(line, module_name)){
// 分割字符串
pch = strtok(line, "-");
// 字符串转长整形
addr = strtoul(pch, NULL, 16);
break;
}
}
}
fclose(fp);
return (void*)addr;
.rel.plt还是.rela.plt
rel和rela是两种relocation type。是rel还是rela会影响到后续选择的数据结构类型。到底该用rel还是rela,是取决于processor type的。而x86_64都是rela类型的,i386和arm32都是rel类型的。除了通过Google来得到rel type,还有更靠谱的方法是,检查.dynamic section的DT_PLTREL字段。
for(i=0;i < dynamicSize / sizeof(Elf64_Dyn);i ++)
{
uint64_t val = dynamic_table[i].d_un.d_val;
if (dynamic_table[i].d_tag == DT_PLTREL)
{
// DT_RELA = 7
// DT_REL = 17
relType = dynamic_table[i].d_un.d_val;
}
}
从.rel(a).plt index到.strtab index
这一段代码要做的就是找到.rel(a).plt表项所代表的函数的名字。这个函数的名字是存储在.strtab节的。代码大致如下:
// 获取.rel(a).plt, .symtab, .strtab地址
for(i=0;i < dynamicSize / sizeof(Elf64_Dyn);i ++)
{
uint64_t val = dynamic_table[i].d_un.d_val;
if (dynamic_table[i].d_tag == DT_JMPREL)
{
jmpRelOff = dynamic_table[i].d_un.d_ptr;
}
if (dynamic_table[i].d_tag == DT_STRTAB)
{
strTabOff = dynamic_table[i].d_un.d_ptr;
}
if (dynamic_table[i].d_tag == DT_PLTRELSZ)
{
pltRelSz = dynamic_table[i].d_un.d_val;
}
if (dynamic_table[i].d_tag == DT_SYMTAB)
{
symTabOff = dynamic_table[i].d_un.d_ptr;
}
}
Elf64_Rela* rel_table = (Elf64_Rela*)jmpRelOff;
// 遍历查找要hook的导入函数
// i ==> .rela.plt item index
for(i = 0;i < pltRelSz / sizeof(Elf64_Rela);i++)
{
int number = ELF64_R_SYM(rel_table[i].r_info); // .symtab index
Elf64_Sym* symEnt = (Elf64_Sym*)(number*sizeof(Elf64_Sym) + symTabOff);
char* funcName = (char*)(symEnt->st_name + strTabOff);
if(strcmp(funcName, "puts") == 0)
{
// 获取当前内存分页的大小
uint64_t page_size = getpagesize();
// 获取内存分页的起始地址(需要内存对齐)
uint64_t mem_page_start = (uint64_t)(((Elf64_Addr)rel_table[i].r_offset + (uint64_t)base_addr)) & (~(page_size - 1));
mprotect((void *)mem_page_start, page_size, PROT_READ | PROT_WRITE | PROT_EXEC);
*(uint64_t *)(rel_table[i].r_offset + base_addr) = (uint64_t)my_puts; // overwrite GOT item
break;
}
}
下图就是上面这段代码的示意图。
- 在解析.dynamic节,获取.rel(a).plt, .symtab, .strtab信息时,要注意的是Elf64_Dyn的定义,它是一个union结构,是区分值类型和指针类型的,其定义如下:
typedef struct {
Elf64_Xword d_tag;
union {
Elf64_Xword d_val;
Elf64_Addr d_ptr;
} d_un;
} Elf64_Dyn;
在获取内存地址的时候要用d_ptr,而在获取例如DT_PLTRELSZ时,就显然是一个值类型。
- 前面说的relocation type在这里就会发挥作用。.rel(a).plt表项在不同的relocation type的情况下,其数据结构是不同的。他们的结构和尺寸都是不同的。
- rel是Elf64_Rel
- rela是Elf64_Rela
- DT_SYMTAB是.symtab节,每一个symbol是一个Elf64_Sym数据结构
- .strtab是所有符号的名字字符串表格。而Elf64_Sym.st_name是表格的偏移地址。注意,不是表格索引。所以获取名字的方法是
symEnt->st_name + strTabOff
。
- 最后,修改对应的页表属性,然后修改对应的内存地址就可以水到渠成了
参考文献
[1] Android so注入(inject)和Hook技术学习(二)——Got表hook之导入表hook
[2] Executable and Linkable Format
[3] Oracle Documentation
[4] Executable and Linking Format Specification, Version 1.2