diff --git a/sema_toolchain/database/Binaries/malware-linux/GonnaCry.zip b/sema_toolchain/database/Binaries/malware-linux/GonnaCry.zip new file mode 100644 index 000000000..75a9bccc3 Binary files /dev/null and b/sema_toolchain/database/Binaries/malware-linux/GonnaCry.zip differ diff --git a/sema_toolchain/database/Binaries/malware-win/wannacry.zip b/sema_toolchain/database/Binaries/malware-win/wannacry.zip new file mode 100644 index 000000000..a0d660134 Binary files /dev/null and b/sema_toolchain/database/Binaries/malware-win/wannacry.zip differ diff --git a/sema_toolchain/sema_scdg/Dockerfile b/sema_toolchain/sema_scdg/Dockerfile index 034cb0b44..c673b8753 100644 --- a/sema_toolchain/sema_scdg/Dockerfile +++ b/sema_toolchain/sema_scdg/Dockerfile @@ -119,9 +119,9 @@ RUN pip install -r /sema-scdg/requirements.txt --default-timeout=100 # # Ensure the pypy binary is available in the PATH # ENV PATH="/opt/pypy3.9-v7.3.16-linux64/bin:$PATH" -RUN pyenv install pypy3.9-7.3.16; pyenv local pypy3.9-7.3.16 -COPY ./sema_scdg/requirements_pypy.txt /sema-scdg/requirements_pypy.txt -RUN pip install -r /sema-scdg/requirements_pypy.txt --default-timeout=100 +#RUN pyenv install pypy3.9-7.3.16; pyenv local pypy3.9-7.3.16 +#COPY ./sema_scdg/requirements_pypy.txt /sema-scdg/requirements_pypy.txt +#RUN pip install -r /sema-scdg/requirements_pypy.txt --default-timeout=100 # TODO diff --git a/sema_toolchain/sema_scdg/application/SemaSCDG.py b/sema_toolchain/sema_scdg/application/SemaSCDG.py index ed05bd80c..125dbc7ed 100644 --- a/sema_toolchain/sema_scdg/application/SemaSCDG.py +++ b/sema_toolchain/sema_scdg/application/SemaSCDG.py @@ -121,7 +121,10 @@ def __init__(self): self.scdg_graph = [] self.new = {} self.nameFileShort = "" - self.content = b"" + self.content = "" + + with open_file(self.binary_path, "rb") as f: + self.content = f.read() self.plugins = PluginManager() self.packing_manager = self.plugins.get_plugin_packing() @@ -159,6 +162,7 @@ def get_config_param(self, config): self.track_command = config['Plugins_to_load'].getboolean('plugin_track_command') self.ioc_report = config['Plugins_to_load'].getboolean('plugin_ioc_report') self.hooks_enable = config['Plugins_to_load'].getboolean('plugin_hooks') + self.call_replace = config['Plugins_to_load'].getboolean('plugin_call_replace') self.sim_file = config['SCDG_arg'].getboolean('sim_file') self.count_block_enable = config['SCDG_arg'].getboolean('count_block_enable') self.plugin_enable = config['SCDG_arg'].getboolean('plugin_enable') @@ -328,10 +332,10 @@ def get_entry_addr(self, proj): addr = self.config["SCDG_arg"]["entry_addr"] if addr != "None": #Convert string into hexadecimal - addr = hex(int(addr, 16)) + addr = int(addr, 16) + self.log.info(f"Entry_state address = {str(hex(addr))}") else: addr = None - self.log.info(f"Entry_state address = {str(addr)}") return addr def get_binary_args(self): @@ -538,9 +542,11 @@ def collect_data(self, exp_dir, proj, state, simgr, execution_time): self.data_manager.get_plugin_data(state, simgr, to_store=self.store_data) if self.track_command: - self.plugins.enable_plugin_commands(self, simgr, self.scdg_graph, exp_dir) + self.plugins.enable_plugin_commands(simgr, self.scdg_graph, exp_dir) if self.ioc_report: - self.plugins.enable_plugin_ioc(self, self.scdg_graph, exp_dir) + self.plugins.enable_plugin_ioc(self.scdg_graph, exp_dir) + if self.call_replace: + self.plugins.enable_plugin_call_replace(self.scdg_graph) def run(self, exp_dir): """ diff --git a/sema_toolchain/sema_scdg/application/helper/SyscallToSCDG.py b/sema_toolchain/sema_scdg/application/helper/SyscallToSCDG.py index 00633644a..3b814b266 100644 --- a/sema_toolchain/sema_scdg/application/helper/SyscallToSCDG.py +++ b/sema_toolchain/sema_scdg/application/helper/SyscallToSCDG.py @@ -503,7 +503,7 @@ def add_SysCall(self, syscall, n_args, state): else: if len(self.scdg[id][-1]) != 0: # if same address and different name, we have an inline call (call to another simprocedure used during the hook), discard ! - if (self.scdg[id][-1]["addr"] == dic["addr"] and self.scdg[id][-1]["name"] != dic["name"]): + if (self.scdg[id][-1]["addr"] == dic["addr"] and self.scdg[id][-1]["name"] != dic["name"] and dic["addr_func"] == self.scdg[id][-1]["addr_func"]): return self.scdg[id].append(dic) diff --git a/sema_toolchain/sema_scdg/application/plugin/PluginCallReplace.py b/sema_toolchain/sema_scdg/application/plugin/PluginCallReplace.py new file mode 100644 index 000000000..f9a03142e --- /dev/null +++ b/sema_toolchain/sema_scdg/application/plugin/PluginCallReplace.py @@ -0,0 +1,80 @@ +import os +import sys +import random + + +class PluginCallReplace: + + + def __init__(self): + pass + + + def call_replace(self,scdg): + fields = ['name', 'args', 'addr_func', 'addr', 'ret'] + # call that need to be replaced, add info only on what differ from the replaced call + to_replace = { + "is_path": [ + {'name': 'opendir'}, + {'name': 'closedir', 'ret': 0x0} + ], + "WannacryHook_Str":[ + {'name': "GetComputerNameW", 'ret': "retval_GetComputerNameW_0_32", 'args':["replace_2147417141",399]}, + {'name': "wcslen", 'ret': 12, 'args': ["replace_2147417141"]}, + {'name': "wcslen", 'ret': 12, 'args': ["replace_2147417141"]}, + {'name': "srand",'ret': 0x0, 'args': []}, + {'name': "rand", 'ret': 0, 'args': []}, + {'name': "rand", 'ret': 0, 'args': []}, + ], + "WannacryHook2": [ + {'name': "InitializeCriticalSection", 'args':["replace_2147415672"],'ret': 0x0}, + {'name': "InitializeCriticalSection", 'args': ["replace_2147415632"],'ret': 0x0} + ], + "WannacryHook3": [ + {'name': "DeleteCriticalSection", 'args':["replace_2147415672"],'ret': 0x0}, + {'name': "DeleteCriticalSection", 'args':["replace_2147415632"],'ret': 0x0}, + ], + "WannacryHook4": [ + {'name': "strlen", 'args': ["WNcry@2ol7"], "ret": 10}, + {'name': "??2@YAPAXI@Z", 'args': [11], 'ret': "replace_3221324456"}, + {'name': "strcpy", 'args': ["replace_3221324456","WNcry@2ol7"], 'ret': 0x0}, + ], + "WannacryHook_add_to_file_list":[ + {'name': "operator_new", 'args':[0x4ec]} + ], + "WannacryHook_allocate_24":[ + {'name': "operator_new", 'args': [0x18]} + ], + "WannacryHook_cleanup":[ + {'name': "operator_delete"} + ], + "WannacryHook_cls_100071f8":[ + {'name': "InitializeCriticalSection",'ret': 0x0}, + {'name': "InitializeCriticalSection",'ret': 0x0}, + {'name': "operator_new", 'args': [0x18]} + ], + "WannacryHook_free_contexts":[ + {'name': "CryptReleaseContext", 'ret': 0x0}, + {'name': "cryptDestroyKey", 'ret': 0x0}, + {'name': "GlobalFree", 'ret': 0x0}, + {'name': "WaitForSingleObject", 'ret': 0x0}, + {'name': "DeleteCriticalSection", 'ret': 0x0}, + {'name': "wcslen"}, + ] + + } + for i in scdg: + for call in i: + if call["name"] in to_replace.keys(): + #print("-------------------------") + #print(call) + for to_add in to_replace[call["name"]]: + new_call = { + field: to_add[field] if field in to_add else call[field] + for field in fields + } + new_call["addr_func"] = "replace_" + new_call["addr_func"] + new_call["addr"] = "replace_" + new_call["addr"] + i.append(new_call) + #print(new_call) + i.remove(call) diff --git a/sema_toolchain/sema_scdg/application/plugin/PluginHooks.py b/sema_toolchain/sema_scdg/application/plugin/PluginHooks.py index 750461f37..166833ee6 100644 --- a/sema_toolchain/sema_scdg/application/plugin/PluginHooks.py +++ b/sema_toolchain/sema_scdg/application/plugin/PluginHooks.py @@ -1,6 +1,7 @@ #!/usr/bin/env python3 import os import sys +import angr @@ -47,12 +48,26 @@ def __init__(self): "trap":b'\x0f\x29\x02', "trap_2": b'\x0f\x29\x74\x24\x20', "trap_3": b'\x0f\x28\x74\x24\x20', - "force_test":b'\x85\xdb', + #"force_test":b'\x85\xdb', #"sse3_mrat": b'\x45\x85\xc9', "sse3_mrat": b'\x45\x85\xc9\x0f\x84\xf5\x00\x00\x00', "cpuid":b'\x0f\xa2', "LAB_00cafb11":b'\x48\x8b\x84\x24\xd0\x00\x00\x00\x48\x8b\x48\x08\x48\x85\xc9\x74\x07\x48\x8b\x01\xff\x50\x08\x90', "0x701140":b'', + # Wannacry + #tasksch.exe + "WannacryHook_Str":b'\xe8\xf6\xf1\xff\xff', + "WannacryHook2":b'\xe8\xf4\xf1\xff\xff', + "WannacryHook3":b'\xe8\x15\xf2\xff\xff', + "WannacryHook4":b'\xe8\x57\x00\x00\x00', + # dll + "WannacryHook_cls_100071f8":b'\xe8\xa8\xbd\xff\xff', + "WannacryHook_free_contexts":b'\xe8\xae\x00\x00\x00', + "WannacryHook_allocate_24":b'\xe8\xcd\x13\x00\x00', + "WannacryHook_add_to_file_list":b'\xe8\xe4\x10\x00\x00', + "WannacryHook_cleanup":b'\xe8\xd3\x12\x00\x00', + "WannacryHook_cleanup2":b'\xe8\xc1\x13\x00\x00', + "WannacryHook_cleanup3":b'\xe8\xb7\x0e\x00\x00', } def initialization(self, cont, is_64bits=False): @@ -105,28 +120,28 @@ def hook(self,state,proj,call_sim): for addr in self.hooks["std"]: proj.hook( addr, - call_sim.custom_simproc_windows["custom_hook"]["StdHook"](plength=1), + call_sim.sim_proc["custom_hook"]["StdHook"](plength=1), length=1 ) if "cld" in self.hooks: for addr in self.hooks["cld"]: proj.hook( addr, - call_sim.custom_simproc_windows["custom_hook"]["CldHook"](plength=1), + call_sim.sim_proc["custom_hook"]["CldHook"](plength=1), length=1 ) if "rep movsd" in self.hooks: for addr in self.hooks["rep movsd"]: proj.hook( addr, - call_sim.custom_simproc_windows["custom_hook"]["RepMovsdHook"](plength=2), + call_sim.sim_proc["custom_hook"]["RepMovsdHook"](plength=2), length=2 ) if "rep movsb" in self.hooks: for addr in self.hooks["rep movsb"]: proj.hook( addr, - call_sim.custom_simproc_windows["custom_hook"]["RepMovsbHook"](plength=2), + call_sim.sim_proc["custom_hook"]["RepMovsbHook"](plength=2), length=2 ) @@ -134,14 +149,14 @@ def hook(self,state,proj,call_sim): for addr in self.hooks["rep stosd"]: proj.hook( addr, - call_sim.custom_simproc_windows["custom_hook"]["RepStosdHook"](plength=2), + call_sim.sim_proc["custom_hook"]["RepStosdHook"](plength=2), length=2 ) for addr in self.hooks["cpuid"]: proj.hook( addr, - call_sim.custom_simproc_windows["custom_hook"]["CPUIDHook"](plength=2), + call_sim.sim_proc["custom_hook"]["CPUIDHook"](plength=2), length=2 ) # TODO change key per class name and add list for multiple hooks @@ -149,114 +164,266 @@ def hook(self,state,proj,call_sim): if fun == "copy" or fun == "copy_2": proj.hook( self.hooks[fun], - call_sim.custom_simproc_windows["custom_hook"]["CopyHook"](plength=len(self.general_hooks[fun])), + call_sim.sim_proc["custom_hook"]["CopyHook"](plength=len(self.general_hooks[fun])), length=len(self.general_hooks[fun]) ) elif fun == "copy_3": proj.hook( self.hooks[fun], - call_sim.custom_simproc_windows["custom_hook"]["Copy3Hook"](plength=len(self.general_hooks[fun])), + call_sim.sim_proc["custom_hook"]["Copy3Hook"](plength=len(self.general_hooks[fun])), length=len(self.general_hooks[fun]) ) elif fun == "murmurhash": proj.hook( self.hooks[fun], - call_sim.custom_simproc_windows["custom_hook"]["MurmurHashHook"](plength=len(self.internal_functions_hooks[fun])), + call_sim.sim_proc["custom_hook"]["MurmurHashHook"](plength=len(self.internal_functions_hooks[fun])), length=len(self.internal_functions_hooks[fun]) ) elif fun == "murmurhash2": proj.hook( self.hooks[fun], - call_sim.custom_simproc_windows["custom_hook"]["MurmurHash2Hook"](plength=len(self.internal_functions_hooks[fun])), + call_sim.sim_proc["custom_hook"]["MurmurHash2Hook"](plength=len(self.internal_functions_hooks[fun])), length=len(self.internal_functions_hooks[fun]) ) elif fun == "crc32": proj.hook( self.hooks[fun], - call_sim.custom_simproc_windows["custom_hook"]["Crc32Hook"](plength=len(self.internal_functions_hooks[fun])), + call_sim.sim_proc["custom_hook"]["Crc32Hook"](plength=len(self.internal_functions_hooks[fun])), length=len(self.internal_functions_hooks[fun]) ) elif "findstart" in fun: proj.hook( self.hooks[fun], - call_sim.custom_simproc_windows["custom_hook"]["FindStartHook"](plength=len(self.internal_functions_hooks[fun])), + call_sim.sim_proc["custom_hook"]["FindStartHook"](plength=len(self.internal_functions_hooks[fun])), length=len(self.internal_functions_hooks[fun]) ) elif fun == "weed": proj.hook( self.hooks[fun], - call_sim.custom_simproc_windows["custom_hook"]["WeedLeafHook"](plength=len(self.internal_functions_hooks[fun])), + call_sim.sim_proc["custom_hook"]["WeedLeafHook"](plength=len(self.internal_functions_hooks[fun])), length=len(self.internal_functions_hooks[fun]) ) elif fun == "weed2": proj.hook( self.hooks[fun], - call_sim.custom_simproc_windows["custom_hook"]["WeedLeaf2Hook"](plength=len(self.internal_functions_hooks[fun])), + call_sim.sim_proc["custom_hook"]["WeedLeaf2Hook"](plength=len(self.internal_functions_hooks[fun])), length=len(self.internal_functions_hooks[fun]) ) elif fun == "weed3" or fun == "weed4" or fun == "weed5": proj.hook( self.hooks[fun], - call_sim.custom_simproc_windows["custom_hook"]["WeedLeaf3Hook"](plength=len(self.internal_functions_hooks[fun])), + call_sim.sim_proc["custom_hook"]["WeedLeaf3Hook"](plength=len(self.internal_functions_hooks[fun])), length=len(self.internal_functions_hooks[fun]) ) elif fun == "rewriting": proj.hook( self.hooks[fun], - call_sim.custom_simproc_windows["custom_hook"]["RewritingHook"](plength=len(self.internal_functions_hooks[fun])), + call_sim.sim_proc["custom_hook"]["RewritingHook"](plength=len(self.internal_functions_hooks[fun])), length=len(self.internal_functions_hooks[fun]) ) elif fun == "clear_stack": proj.hook( self.hooks[fun], - call_sim.custom_simproc_windows["custom_hook"]["ClearStackHook"](plength=len(self.internal_functions_hooks[fun])), + call_sim.sim_proc["custom_hook"]["ClearStackHook"](plength=len(self.internal_functions_hooks[fun])), length=len(self.internal_functions_hooks[fun]) ) elif fun == "magicRAT_trap": proj.hook( self.hooks[fun], - call_sim.custom_simproc_windows["custom_hook"]["MagicRATTrapHook"](plength=len(self.internal_functions_hooks[fun])), + call_sim.sim_proc["custom_hook"]["MagicRATTrapHook"](plength=len(self.internal_functions_hooks[fun])), length=len(self.internal_functions_hooks[fun]) ) elif fun == "trap": proj.hook( self.hooks[fun], - call_sim.custom_simproc_windows["custom_hook"]["MagicRATTrapHook2"](plength=len(self.internal_functions_hooks[fun])), + call_sim.sim_proc["custom_hook"]["MagicRATTrapHook2"](plength=len(self.internal_functions_hooks[fun])), length=len(self.internal_functions_hooks[fun]) ) elif fun == "trap_2": proj.hook( self.hooks[fun], - call_sim.custom_simproc_windows["custom_hook"]["MagicRATTrapHook3"](plength=len(self.internal_functions_hooks[fun])), + call_sim.sim_proc["custom_hook"]["MagicRATTrapHook3"](plength=len(self.internal_functions_hooks[fun])), length=len(self.internal_functions_hooks[fun]) ) elif fun == "trap_3": proj.hook( self.hooks[fun], - call_sim.custom_simproc_windows["custom_hook"]["MagicRATTrapHook4"](plength=len(self.internal_functions_hooks[fun])), + call_sim.sim_proc["custom_hook"]["MagicRATTrapHook4"](plength=len(self.internal_functions_hooks[fun])), length=len(self.internal_functions_hooks[fun]) ) elif fun == "sse3_mrat": proj.hook( self.hooks[fun], - call_sim.custom_simproc_windows["custom_hook"]["MagicRATSSE3Hook"](plength=len(self.internal_functions_hooks[fun])), + call_sim.sim_proc["custom_hook"]["MagicRATSSE3Hook"](plength=len(self.internal_functions_hooks[fun])), length=len(self.internal_functions_hooks[fun]) ) elif fun == "force_test": proj.hook( self.hooks[fun], - call_sim.custom_simproc_windows["custom_hook"]["MagicRATForceHook"](plength=len(self.internal_functions_hooks[fun])), + call_sim.sim_proc["custom_hook"]["MagicRATForceHook"](plength=len(self.internal_functions_hooks[fun])), length=len(self.internal_functions_hooks[fun]) ) elif fun == "LAB_00cafb11": proj.hook( self.hooks[fun], - call_sim.custom_simproc_windows["custom_hook"]["LAB_00cafb11"](plength=len(self.internal_functions_hooks[fun])), + call_sim.sim_proc["custom_hook"]["LAB_00cafb11"](plength=len(self.internal_functions_hooks[fun])), length=len(self.internal_functions_hooks[fun]) ) + elif fun == "WannacryHook_Str": + proj.hook( + self.hooks[fun], + call_sim.sim_proc["custom_hook"]["WannacryHook_Str"]( + plength=len(self.internal_functions_hooks[fun])), + length=len(self.internal_functions_hooks[fun]) + ) + elif fun == "WannacryHook2": + proj.hook( + self.hooks[fun], + call_sim.sim_proc["custom_hook"]["WannacryHook2"]( + plength=len(self.internal_functions_hooks[fun])), + length=len(self.internal_functions_hooks[fun]) + ) + elif fun == "WannacryHook3": + proj.hook( + self.hooks[fun], + call_sim.sim_proc["custom_hook"]["WannacryHook3"]( + plength=len(self.internal_functions_hooks[fun])), + length=len(self.internal_functions_hooks[fun]) + ) + + elif fun == "WannacryHook4": + proj.hook( + self.hooks[fun], + call_sim.sim_proc["custom_hook"]["WannacryHook4"]( + plength=len(self.internal_functions_hooks[fun])), + length=len(self.internal_functions_hooks[fun]) + ) + elif fun == "WannacryHook_cls_100071f8": + proj.hook( + self.hooks[fun], + call_sim.sim_proc["custom_hook"]["WannacryHook_cls_100071f8"]( + plength=len(self.internal_functions_hooks[fun])), + length=len(self.internal_functions_hooks[fun]) + ) + elif fun == "WannacryHook_free_contexts": + proj.hook( + self.hooks[fun], + call_sim.sim_proc["custom_hook"]["WannacryHook_free_contexts"]( + plength=len(self.internal_functions_hooks[fun])), + length=len(self.internal_functions_hooks[fun]) + ) + elif fun == "WannacryHook_allocate_24": + proj.hook( + self.hooks[fun], + call_sim.sim_proc["custom_hook"]["WannacryHook_allocate_24"]( + plength=len(self.internal_functions_hooks[fun])), + length=len(self.internal_functions_hooks[fun]) + ) + elif fun == "WannacryHook_add_to_file_list": + proj.hook( + self.hooks[fun], + call_sim.sim_proc["custom_hook"]["WannacryHook_add_to_file_list"]( + plength=len(self.internal_functions_hooks[fun])), + length=len(self.internal_functions_hooks[fun]) + ) + elif fun == "WannacryHook_cleanup": + proj.hook( + self.hooks[fun], + call_sim.sim_proc["custom_hook"]["WannacryHook_cleanup"]( + plength=len(self.internal_functions_hooks[fun])), + length=len(self.internal_functions_hooks[fun]) + ) + elif fun == "WannacryHook_cleanup2": + proj.hook( + self.hooks[fun], + call_sim.sim_proc["custom_hook"]["WannacryHook_cleanup"]( + plength=len(self.internal_functions_hooks[fun])), + length=len(self.internal_functions_hooks[fun]) + ) + elif fun == "WannacryHook_cleanup3": + proj.hook( + self.hooks[fun], + call_sim.sim_proc["custom_hook"]["WannacryHook_cleanup"]( + plength=len(self.internal_functions_hooks[fun])), + length=len(self.internal_functions_hooks[fun]) + ) elif fun == "TODO": @proj.hook(self.hooks[fun], length=len(self.internal_functions_hooks[fun])) def nothing(state): print("TODO") return + + if False: # Satan RaaS + @proj.hook(0x40113c, length=56) + def nothing(state): + x = 0x8d5301000000000004000000086f187e460452b1b759943074fb4c3e0a0000000000000004000000040000000a8612130d00000001000000923c000000800000d965b7fc4d5a900003000403ffffb80000ffbbabe44000d8030e1fba0e00b409cd21b8ffffffdb014c04546869732070726f6772616d2063616e6e6f7420626520727507fbffed6e206902444f53206d6f64652e0d0d0a2443e968f6cd81fd485cad09260f03aca471b50fa60f798bdd3d270fc307eb58f91707c60fafdec746bea05bc30fbcf817526963683bc3fedbc39b50450364860500da37af5813f7acdbfef00002000b020c08540c2c131c1404bbdb0b5810f10b2600050401005910c6660700c0241e56962cd88134060f07827bc20a00e889933ca0ec6dc06e028c010fb0020c01000007b2ed2a700230372e745b36d8ee6578740767539054c700b3eedf0e2002602e7264617461db1e536cc3c27e1400582721402e26291bacfb00480704904b78277bc2d8ecc02e7028e3a034007c4fb0c17e0072656c6f63fbb0271161a7647e420000feffdb0f48895c24080474241055574156488bec4883ec4033db6effffdf08f9418bf04c8bf2488d4df8448d4b014533c033d2275df8bee11fef03f0c745384ac74424209bf0ff15de5fb65b6bdf0685c07476362d3145f02dc94e36f7ee30ba0380602521ac4839d9fe671d448bc6498bd6168531ebdcf6ed4c6a388d530274c79332911bedf1dd3e15837d6d750f21bb24188b6ced99580e900b5cbefb6f5b7b688bc3063660bec440415e5f5dc3cc00b6b9ff58db4183c8ff833de8853959d99cde36b7e91ddabb753f830ed3e3c1b908ffb7ffef19a8017409d1e8352083b8edeb02084103c875ec41ffc141893ff75fff024983c2044181f90b72d1c7059d478485d2dbeded6f728bd2410fb60b42c049ff7b33c80bc17bffbf2dc8d80483c1e9084433c148ffca75de938217b65977f7d025c38f047c6b458a6dadb9bd90460698014d3627d9ddb6dbdf52398bfa41fec24549c24303144402dab977ffdf61cb428a04094388040842881409170c0803ca6b2df6eead1508300b487affcf75c967046f3f477e5a88918899c34055f26c24a91e2b6cef4881ec150b5459f1e8171c3e8c7cff0e5587b9090d094c76925e8f3dbcfd0a4d87a805ff846e811055c7b93d76778c132f05b915e8d81b140fb9147cf27cf63eca0d27b915bcdfb9167cf27cf2aef7b917a03fb9187cf27cf29297b9198467b91ace36fbf3768b0d7b847d870176ac3bd9106a0f89279fe95d17c948733252273fd12723cdc93adf07b9229c8c3427f71fa10af6e4d99c3fbf8389f283ab9393916e17cf71daf076469a67875910a7b91b7d8fdd9d2fa915e8a81a14b7b91cdb9aceb693ed0d3a6fa733254b5edb1bebce10b735934b0d170c566b701c7e1781c4c2d9ccc845371a26b7b8680466007588447bec76f8045075f6b8543f510812040275dc2db5a682f073111485509ae9e93e8a404c0438300201f6a4079ac328c244a6ed8268b9dd762f5e678bc4325810037018166f2f7f7820554154415641574ca838f72cf79578bb86a009a4c187f6b8dbfbbd7d80418d4e2b4a3576825135734dbdd035db187706e8f71956802e1148dd76772fd80f85d478e8bf103c8bee384640b9b7bb8fb5740440754a9590061741b804f15da598a1a40762b2a830ea76ff6c1c8d458d4101baa780441428abe4c6fa8b031d122ada86ade4727f83f8ff0f847162b760177533639b1a8bd815528075054ab4adbd82feeb50551ed36945f03ddceeb28d490428c95b8bf8a284db57d3f61b4c6fd0324461d032cfbbed6d78842ab25b4422f476399db86d6e7b21d1e80b21cea105943afcb664b8b701d2c188840daf96aef1edd94410e398c3f448038e4e6ffbff02570c483bd977148138125ed9574a8327db76eb85ffd03bc1767e8bf649de74e6bce9f66f87db747585f6746411541ce3cbe824fb625bf72f7c4139441c04755d6c8a5fb037c0ede9de69440d9f6602e9b545a0c1bd99af612e8527cce8719c186bebda6ef0d77425f4510fa01954bfb07d7704313a493bcc72f16cee63e4eb208b73314a8e6f662bdeeb8390fc626f85ef03696a5a0ae4abbd85ff742b1c30b4111233df101b8d7cbb66ae4d1509490d80f609cdb6bbcff3023285ed08ea4846beef06b63fc5f9e81c153ab5114816b624fc2a9a026816ced2a516fb0cfe09e84a14407844391027cded1ede6049765708e81eda6f6367379800e2e818162d40202217da483741bd01114c133ddd4c7643dd6755c785f0150b0de8b2fc3eed7b7bbf2bcb01412578b84d4b8909d7f1b7f060663901cf8a1763413c8fc00abfdb48ef03c125486877e87f3595481b44b6b3023c48bf853210d8c716814164706429b027fbb306a588a31f3b423075173830640bb2d008227dc4ed16bb834250130452304500308c603b9266da7f7f309edbbaee3befdd8b8c4c047809d73ec1ce0d764854751a2c2388c6bfff828bf92379fc66453b6006735a32604cb6708b756e782be1503c1ec7e430bbddfe0c80498d0412074921ca0cc8d3f0dbedd60b7039411420510c0749104d03c21b3cecb606d75ebb7e5603fda5b77820dcfe4006443bf872a62540281203c75e08099740c030113e854002264cf8fdcf777ea278275463f61139d915491179301033db3632794861d5112e084d42576cdc217f7e473dedf492db0aeb031a347510b98e13bec2ae4a5966f8fde9ae40c3ece73ad44024579857c238639d196c0d2c13840e1dddc673d29c7c11720b4d6062b80969eb1a00ad12fbe845f7f53fb07407cc833bda1b584e28a285c974134f3d0dc36cf1b6b77d188d5008212257ad2847a2810b6740534a409e0d6c8de5febe64b20e1b8d154f0cbb063e22f1f455dbb90fa5121c7f74971e2cd0fd243a08b9e73ac175babab7ba73ce24e30575230828e3072a60802d58e9d35a739feade540f87ae09bb61e9a4042737f70779067532088d5804e98f1426750ab70d22dfbb07228144051a07ebed9797b7770903757208eb6d0a7568395c363ee4f6db75620f03eb5d2c027877570c837cbe05dad61934471a5b42612c767777414605eb305e07bb0659eb25f9bee7c15b06eb1b1665115b0c343070f7b80c230f44d8258ee828093d1b5b3fab5728148e6530098bf11688081617164702237a55df33d1117b1c381cc2f8bf18eefa5a83392c5d1e4c5ee852116323c4c612142fc0342475c98cc5e8ddeb056413b808dc2eb4779c246987de5b10037318233410bae35fcb60d07de223749030c155c0b92ee20713becf3e8f0dd8b92ff9129c60b9300eeacf27df475590b9310ddc08b932cef760cf27f0b933c03878b9340ee3c8f7d9b11ca8b9350da345c01a9cb6ee84be0ad8037c60affb9e3072f2600930179008cfd4049a380820a308eddbf4be482478097e45a80858fa3b3a02970f6d546675135f83c76834d86d346306f808bcca27bcc35920b817f0157b1dc2923a7317acdd6f83a905761af003a895f838b9799a63bf59b9e9111070025ad8f32c461f5568b95b4f1e1001f23c275f5c10b9505da83c27df77e0515e1097b05f66cf73f286806075627b3ef91658620d6750b963592c5fb0ef3bc08f641048a07065c9f79d7c1037984e661026f39c7cdff8216710159068107edfc904c8326910f310e8be06916f6a0de5052f6b93ef3bf910d448846c10c3e739f9beb0216d10b2306ebeb3efb3a15138b96f0d931e984070b3e739f910822071712f0e23df5603610d638596d8317b30408570020b3e456848c687c13d858733db5ae43624ee478550016b0be000906690e648b0508026e10e63586e60083c1bec9dec1dc00270754d780bad62efb3980045809816ca71d69c740a9090c8209877d6b598cde512d01da80a74676f644802b08b15b80a30ce5ed79dc0333807c86728d069d734e90a203c45e045e002423e92bee88ffbffff001972e5623d5272f003ff9e380234c5fcb83860f80e1ee41b047d100e9958b911ec521b798a4c2c79f350285bb02310f80d51180dd87a23832dd71b58f10d5fc055e8e0d39acb494301eb21b11b7c6f1d942490798383899c0aa13dfaecffd739080f95c3c20c610de92b1055a15fb3cd38a927ae60fcd6047773dfa522b5b2c785091214745b949a71cc4f0aea6acbb407176a4e255d8093248bb7055c3584c00f1975f509c8c4b778c87d14120ae84f0da64bef2ede5c6689020102ebd0bb703990ef107ef1e80d0f3a0ed9cf83457a30b93bff0e40b93cbb996f81203d3d0eacd65fecad68b350747b517ee8870cb1e49bf077681920746143196d3216fb194e307447671953198bfd0c3440742d7219398b9578061a60bb7d193ecc38191f74054eb80488d538443401ff8bb323474ba0fe6002bb502d2e08677108021b40431484872f0844cb10e75046274cc803080cce283e6013c248ff0c46920eb24d78c24064830c28f44a4e38bb0b61e85d0bdb36292f09837c411a421b1060932fc8141a27f7e0871c39700260022055565705834d46f4fef930e0c4108e70f60bc4daaca92d56af0e5930bf4e196abc0810a70ded28c6bb31df3e6b83a51002d1d44bc4ee3900be040a9c8d5603dd130bcf6e1942ceadd3b61233c0d8b13911740aa3e9082bfa335a76a5203e84418d51164c63db6041f5390a1fbd27759f754bb6c43018261863ba1f002271ec652e0839167497cebbf44286d75ec644055075f636622fc0362fc97f8033d230a0f5fdfedb48b950f5f10a4475a8814d171bd033ffba4fbf4c9553b2681db0c7b6b8ee0af01a5cd016712b1ac80fdd3fd9108f1a3975b875ea15dc40488d62efdce884d494d88d780126a77cd8d0760fff0f628733c0aa28036b497c88915f5ea7a7f9368210a54151a05090233299972702a46707d652409936882deb182ea1c7686c93e8fd0754406dc463c788df4b98dbeb049948b46dc18d1264391dc760b99b239c712b510ffc4b560efb467c93c9701d5f90a05fe058840d7dec48bcabe8a91137826d54b90f0e9c4a096c7bb387beb34ba6170dcd5e5dca6d150b99002eeb07054b198e5eeb02177b4845c327dee3018325f68f81382480f6c4427468413f80148392d03dfbdac3287b283f15a54f900931a96403be27a2d42ecb0810184c07093ec6481723f8f50600e855b8b907c877481f5ff008140e0e91e9fbc3ed4db859d34a78448d7701af18af5b0df630130ac205d5ce8d7c9b6bc049f82c3aa655b161f62dea2d0d984851b24a9065ec095e0a0412409f881de1eef7e28d4853a1e8653288d957251ad31465ec3b34569422540c57402463877d6f8d0b26ed49ad26550c72f234e819e8c6f93423878656a0f20791430619a09f5f206707a157aee8cb2680763772c8783858f5d0e8a723bf39e43b4dd02057178a0c25d402febbdbcdf67f4184ce0f07f6c10208fe025660f873f2fb04ed85f10c3bf4e40e6de6e446f5d7600921186c34d61360557a38af84d98ed8066e605249179c31f90d766d49799d4657fddc9106fbb9e8c60c836015930e3a7a8a1fc115f2481b8322ccd2e6eec643d110393d730f2c5664a5d6bf3b05de1240b6258a0880f9ff9b7af66e81421f0b3b1ab3e93acb0938f24dd231b24f9a4d558816b7b313668fa88857a94849c9ee7807c30d46178038526056db8ee8c4381807e0b9c8d9d94199fd053770503e8ccd1ada4c0e6748275072c20d3280978f0775eb4ed8e3fb00820c6532042590cd513f85f680bc60156c77abfd36077030e8f5f02f5ce8ee06cbf0977e83fb04481bc95ee1a4f744317039cdf0a5fba03b0bf817c0e0a4397cddc96f6bd413276781f91a0cb82d76ff8ed0f4492bc64088bc0530c775f3bcded8e6ba60071001b20fbf9518c1fd58c7c24f47b1344839bd7813ff3919d99e8b0c80ca887e143919bd90e4bb08f0791603156b2003be04b3bde88d48950de36254311be30632a0b936ff040ddbd816cfdc23e702806345de5cb03a371d1001f83edf43b12f2c1340373741b0b0e8a23566fc2f2efbd14fe26f8d2ce88803b918e82ef60b7d378ab8c171f70840f6c73f6a88026f13c6b2000b00dbcd21737b204d0728db560b82bb87e93077410217aa10c229514452ff28c43f4183e844e8d5e53e4b49c7c1ccbf15db0d8e4c2bd302cbc034418a440a576c0bf1cc448a010e3a75114b45ff42698d0441a91072e48bc2eb0940dbf0b6c1c802c02bc1a294c2110bb74dd03330cb85d22c3951c43405b6bffb8379285472cc4144eb0a8b42081fc04511a5add903c285ee2b1d03b7dbbf3c493bd0770b8b481c03ca0ac876bdb7122744c35b4c6979e8ae7ff1ff70928b1683380c7509f740257074086008fc40afc9ebe0a75dd0dab23f3aca3ce86dff53bcb73a4e747539580c7661660ccfb750ab1d330bee18d84d3bf085c2f647d9708b57084c2fab83a1c4764f1077c07773696d057821408b0dedc012c3dcdb877e8c4245ddeb192d0c33c9e6f40d7f81664439108804191a483bca72f11cfc170dd00a00058b4f0c89f8603746dd903848be30a9205f8a7ced92476cabb018fe376ca59124fa9b8d46bc3dbcff9f00776ab6b67f23587516397228776916cad3fedd2ef81ff1745d8b4728eb5ae77eedc389be40d79e033f9b720e1d3a880c0206da7ed98ac2d672f2397039143abb140db301393103c1eb1dcbf6f8996e03d517d26f445cb5bd67dba57c832310c0a98b6cb6b5c516b69b40b3a93eca9b78e84c6c9c0e010548eb6f65ab4313366bf6a942ade36da361d81a02cbe82cbc4108ed1e0bb40b02d220f508442bdd1a76bf242e4d2bd9667226498b43140c0bbdf6aad525199bc73625bafac50a4b0b2d74d5ee45ad5fa0d15a43ea4fc841f7da23358404c223c14ffbd4a2fb5ee19f04953c98d4057ab1521f820340022e7c94da6939187ec563708d4e39e119370a37ec5e1348423b28dc80421e183bde42d08699410c746b942dc5c2022edb00d2f166b546c9d13642a42db910b1eddef80d1d660e1a7431ce0c1103021afb9fbace750bd66645391c1175e31c1423d7bd053402f824003394087f3447f03ef4b80002246e85bbb55838731507333846eade6d19087b082dc803c1c31126c17d73ece8b8a09e4e3bc072130519e63ed7717611d6109b50e72b4e7b4bb4b90cb949ecc80e42a2e7dc8297bbbfbc61dad0bddbc53e4749c1e004cb45764c0385afe9b799453b5802733b406ed10b5be8eaed1041320932c966a04216121fc27e07bd480272e0110246881c10c34f6dc80572ee472f836c33146a500cd84f3353b3b75b7766239bb60e33c80d890c525e80d06f91d10b891c42c3cc7fc1a861d468abaa16dada6a79e0f04be2576b007fdbeeeaf18bfb0bd302db8beb458bfd970a3f7519459f4503d0f95ccad323f5b6fde84123c5eb1509c31ac30441f18bffeed1db3c301bc1e81fd8188bcd4103ed8a04303568436d32dd39ebbf8e07614f81438d14506fa7b7402bd083fa20a8bc242261a92d387144b6793cfd40551fb57008443941cafef7426cdb0303c525f85a31ca8bd75ab20f20cbead5d7c1ea1f28b0a60058afae5fe229b010d8322bc4523762e2f841816a0d125078e14a5b0f97c01a2a5e68a585a1c52fe0694d03c6871db60d5f0005c56c0944035e02dc35001a5deee93969369698803f12401bdc04be6e0d626889299b30519a32fef62841bf5e415d415cc327578d1630accff226fbad1bdb6108033987593879fcf64104660d60896d63f1a6ea33e9efdeff52b73b348b71483548c8dd40d03b330f836dc5160dba01b3fe90b244eab3bdbfac4c3bf80f82aadb0c08839dce165afc3e7cfb75a2920a0cdb03ba0d41171e0cf467d5ff5b54ea4903c4cee77d7e74817d0063736d5dd3eeede07528893daa652e741ec4a109e8234003b8fc661eba15cd7bb7dd028c8a168b4c5941b812482cb47f1fcce845010a46408b54183d4ddb6e2e52c2100303d4c5c50951f78460cd871c3f5447d82d07773ac6e935fa58e9a846beb7d8c1715e794888f4e989c7cfffdc6fdbd9c9adcbd9727908d57370f6458d8602f00420744488e338730b14da85c18fc0421cd809f0daee36df7220090873162f1042390d10a6064fd7da0a0c0c5bcdebdeae8344ffc804753222d7072fef05d7be7425eb178d92c9ba46484431e12d6edbb10159c42fd0ffba133bfa5a2d98146e6da97597cec50617bf406b38c30bcf223084e3e17b006666e24798800fd3e7ecd851255aeb0d4de7028dbd07fcd07d4c1ae822015c1b0f7ee0823632e6894c27bf8bee16e918442710ee20059319eb08f66cd96023902c5fc3cc008fa055174c2d5bd7578102fc8aa614e8505ae8625806d5188ac01be1e2856fd11e8b500c4cd2720acf4667786bce09d1720e192028bf2d8984fdcb72e233c0525331fef108933d4cccf1cfe83400177d1b408122bb49d31182362d3008030f4a245df7d01092f8a52501eb0233c0076fe0aa46f1e3e2087403b82ddc01db63483ceac809813996fabe8932750cba0b021d51c594cd1ed8df1dff25ec3c00008f40558b0d99ba351801e681380fd7c1feed2bdf8bc1615d1e2bb4e5515256e80021c8609fdb1cef0300e707df93830c32d7e5062241061bb2ed17af07a7061964909f97a5c679729041adbf2a6f2190410639675f57c806196465866d174106196c2f07271f061964901725462d830c76c817ef20ff20201c64b02007e5062119ecc29e982117af07a7649041069f97a576610719c65821176f07c820830c675f57b0830c326586182117904106bb2f07271f41061964172546831d16b2d817a78f07875036c8207f77a7061b36d82807209f07101c6490410800f81f41069b50eb0780061964907870686019649041585048649041064038309041061928201841061964100800061bc2c9f81e16ff0fa87972b0c11fa007df260a27b0c1063bfd2f9807b537830d3664060f9807900c32c82088857d32c82083756d65c820830c5d554d20830c32453d35830c32c82d251d150832c8200d5e0e368c43f7682f17cf1d649041ce07c7bfb790410619afa79f41061964978f87410e61907faeff1d0c3258901d07686032c82083585048d820830c4038f1b720830d36280f200718430832c810084f48071b925f4f07e01c374106192c07d0c806196490c5e6b0a819649041a098906490410688857d90410619756d65410619645d554d06196490807870681964904160585064904106485e560bc641183f17e81bc70f64b0c106fe1f2e07b461270719dab81bffff06192cc81b079dad19649041886f67599041065f57c7e460831d50174807f224c9c182f422257f0711264e0e32c88ad63a278b7276b0410547fd1a07f5c820830cede5dd20830c32d5cdee830d36c8e6b8a7ad0fa00c32c8600798908862b0c382c7780fe71b2cd841672923f7175807398cc106fb5f27ff1ac820830507302860830c3220185d37830c32d8770791abdfecc218ac19ff1967d80f9041061bd007c8c060431864b81dff0f830d32c80d879007f5830c7208ff1919191964b020074f47609041063f37dc32d860c3ff0f1f0717e420830c0f07ff18769410e4f7374da7c820830d45073d3520830d36af47a7079f830c32c8978f877f0c32c82077807832c82083706860c660830c58bd97b55f32d8b0184f0fb9c860830c958d07858c830c327d75ef177720830c1607dfd7830c32c8cfc7bfb70c32c820afa79f32c82083978f87c820830c7f776f20830c32675f57830c32c84f473f370c32c8202f271f32c82083170f073258100eff16ff07efc820830ce7dfd720830c32cfc7bf830c32c8b7afa79f0c32c82097aba332c820837f776f860c4e0e7d1b01174f1964b0c11f47073f48639041062f279d276cb0c10695070f170707c9c1821dff15ff072e16608330c82610270807830d36c800f81ffe37f60c32c86007eee6de32c82083d6cec6c820830cbeb66f20830c32675f57830c32c84f473f370c32c8202f271f32c82083170f07d860c10eff14ff07001720830d36f80ff007d7200c36d83e1fc70f3d0f830d36d83507c017b807b00c32c82097fe870d36088366e7770f6f32c8208307675f57c820830c4f473f20830c32372f3860830dc2b5f7170f0f0783053bc807ff13ff07ef0c32c820e7dfd732c82083cfc7bfd860830d6f67c00fb80720830c32b0a8a0860d32c898908847196490c107675f57d8b041064f47a7ff41060b72130727061964901f170f070b32d841ff12ff120764904106e7dfd708410619cfc7a720830d76b70faf07a7830c32c89f978f870c32c8207f77db196cb021ff0f5f0757649041064f473f90410619372f27410619641f170fb020709007ff11ff7741061b6cef0fe707df06196490d7cfc7bf19649041b7afa76c9041069f970d676c10061b0507fd87f507b0c1061b8b27e50fdd07839c1c64d56b1163bd1b64b09313530fada507368441069d95ff2758b0830d0707ff10ff1f93830d360b170307fb1006196490f3ebe33d7272b0c1373507cb10c3d820830cbbb30d27d8200c360507fd87f507410639398b10837b06196490736b63bd196cb0c137530f4b0743649041063b332b90410619231b13c10619640b035d5f061964b055074d453d19649041352d25649041061d150d6c10061905fd67f50764904318edff111108830c1607cdc5ff9043186c07b5ff11830519641111078d8631c820857dff196490c1076d655d64904106554d45904106193d352d30061964251d15ff200c32d80705fd67830c32d8f507ede5dd0c32c820d5cdc51964b021ff07b5ad64904106a59d958c4106198d857dff08830c36076d65ff4106196c07554d830c368c45ff07352d0c32c820251d151d64b061ff0705fd0f32c82083ff0f0f0fc820830c0f0f0f20830c320f0f0f830c32c80f0f0f0f0c32c8200f0f0f32c820830f0f0fc820830c0f0f0f20830c320f0f0f830c32c80f0f0f0f0c32c8200f0f0e32c820830e0e0ec820830c0e0e0e20830c320e0e0e830c32c80e0e0e0e0c32c8200e0e0e32c820830e0e0ec820830c0e0e0e20830c320e0e0e830c32c80e0e0e0e0c32c8200e0e0d32c820830d0d0dc820830c0d0d0d20830c320d0d0d830c32c80d0d0d0d0c32c8200d0d0d32c820830d0d0dc820830c0d0d0d20830c320d0d0d830c32c80d0d0d0d0c32c8200d0d0c7690c1820705fd0bffc820830c0c0c0c20830c320c0c0c830c32c80c0c0c0c0c32c8200c0c0c32c820830c0c0cc820830c0c0c0cc1820c320c0c07c82083c1cb09ff09094106192c07aba3061b64909b77edf7e5365890c3ff0b076b27c820830d63075b5320830d36ad27a5079d830c32c8958d857d0d36c820750b47031964b08307fb08ff0b0b589041060b0b0720830c322d251d830c32c8150d05fd830c16840aff07ede50c32c820ddd5cd32c82083c5bdb5c820830cada59d20830c32958d85830d32c87d750bef030619ec6007fb07ff0a0a196490410a0a0a649041060a0a0a904106190a0a0a41061964090909061964900909090919649041090909649041060909099041061909090941061964090907604168900706ff07830c36d84d2745073d350c32c8202d251d32c82083150d0532d8200cfd67f507edc820830ce5ddd520830c32cdc5bd830c32c8b5ada59d0c32c820958d8532c820837d756d6c18830c655dff07904106194d453d41061964352d25061964901d150d05061b8441fd67f507ed19649041e5ddd564904106cdc5bd90410619b5ada5410619649d958d06196490857d756d0d639041655dff32c82083074d453dc820830c352d2520830c321d150d608331c805fd57f507830c32c8ede5ddd50c32c820cdc5bd32c82083b5ada5c820830c9d958d20830c32857d75830c32c86d655d5506196c18ff07453d19649041352d25649041061d150dc860071905fd05ff0520830c32050505830c32c8050505050c32c82005050532c82083050505c820830c05050520830c32050505830c32c8050505050c32c82005050532c82083050505c820830c05040420830c32040404830c32c8040404040c32c82004040432c82083040404b020830c040407830c7272ac01a49c940c32c8208dafb332c82083746c64c820830c5c544d20830c32443c34830c32c82c241c140e32c8200d04fc00b09327cf00f400ec00e40741061964dcd4cc07196490c4bcb45e516c2efaff8f452389551ec6452200c745024d060601c0b5fe837d1e40250cdb552ffcb6488b25480fb608484fce4803b15d002fd75e5a59c174071990db0bc129c85e2b5dc32d1a008f99e85b2c400125c7913f31d2f7b685adc4f18944320179832501fedb67aa5c08047b0ec1e0064801f048b091ce35217660d0c344776b6fff83e038c1e8033b16c3c392997c233edeb665b01c02071912171205750d3633d15bdb532905115c9e930b107502e85aedb239b7858b40b4112348ff05cdbd6cb3c30a270206e8d921276d1136825165c3021145ecdb5cec0b282256062e0534c8d8c86f03114075091d756ee6084ee88cf4394a4a7011ca24c70d11517c970d427dc32e250afe237bbb2f98807d220f86be011d360299b0636901c32994179cfbd8bd0be8f8fe93341ae8ed2176d8600a02ea5a391933d82c3622cd1d3caec16ceee8b8340511710316c9c3b0b1a7101f3a140684643f2c40061075061d2623ddad2523b60001475fd7673b839900114d0b01ced8209c41a33529ad7608b3c19aa10b8007770e841f0b307411e863fdf60658b209db3b521004ff467cbbdf17e86ffded160022b9fd7b311b09c396e1fcc3d811c606892f01dab8ff0009c7382c6fea6c66fd86c8491ec201a255fd4afd6583bd7de89efc0ae8e5fc890cbe81f1be8753166b9b4ede0690efb14f34e86439ab06f23d924361e83033775372c800042dfc946c4f9afb43017e210be908cdd9261c06eec4c9fb908cfd1a0b5e43fffb2605e499b0d3c72196ddb1fe28d5c8850f85acb23da309f80e040f8ea2be912d1601f22c27871f8c018271e43bdb0a85101f6c155b608fb111d50cdb5ae849110d833cc80448e83705012b833dd8600b061d2ae8191107832ec2c8751e18e81d0e327964c7780ce8fb0bf5fdd1c4fa1776e9a40b041ee8d32103d8c9f82ca2e9fa85b1fdbf9066906d0ba50399605f9066048da9810b2e9bb2e5077e757f905858a5640fc128e04c644180956eb12122d174527d6f3dc82dc92922fef92fe8124837d8807a060b0622db8eec73610beffce9fce9042f79c9cb8bccfcc0fc95f997bce424a9fc9dfc7297bce42586fc7afc4f4ec9c825635d78f927199049403415e826fb78b009450f847b41198f1d831568b1ab666f665e7b09b7481e54f6fba2eafb9b71d8252fdefbb334290db611acff1651175196911ddb861cb8aa51a4fbb81ce416e4bff8a068f885a04cb20dfb78fbc71a4d8599ec0bf25dd6321a6a1cac1be442037e171a75535b92016bffca1f22f4b0017b90f730e808d5dd16baee83fd19e8f1fad57f07e8c616ebfffad9823d3296f9f7c53aa2906e900f51e8b601168b0f6906f93ae89f027423e885615f9088b95d1638716264cf71fa6b72715d12063288ac4e455d9648e225af2b1959abb78a5135d1e9894a3387acbd4d8b13d1e1891d34e4f9ffb7a06060493ca474123ca7740e3caeca2ef4ff740a3caf74063c0f7402eb049e00014d7d605376c6457e9a4990743eff7ff7df4d3a3ca574363ca67432552e3caa742a3cab74263cac74223cadd37437dd741e651a163c6c756d6ec90172496f0101aacf861c242884ce009cb059186e9d28fbf82517c89110d21d321a3218633dbf2bc6055755dbcdf52bdfd8c2e0ef953ce870f55837b6316b13172c374c693d46bffb3c63e8573dc01d7c5689c2c1eaa17b2ff0ffc183e10f83fa0d750b83f9c442e836200f35f640790e75377e260ff9cd4973f6811b0a0610070500f9fd26d7faf79ad5f4641fe416d2faf432e8c2f79475f11cc8250e09e0a1808c7ced200f63967153e1ac1d1f2c6304faa397bd10e9740892fa41e850713461f7722115087d20f0741b006d37ec863be8257b8b087c80c804d89115f0f3e415214cb675221ef67215790720cf6d53c1f69c1942b2596c2cf33dce406eb30be481f60cb48760f6026c6c1240556b30bfc6650ff255f327e81d631a39c8b11552a458fc6b829c00ebe0f258fcf21636d90de4c4f55845bc6176c2db53a81b239d0aa1e4c2e16310a81ba69c88f56c48c62e788353000026058f08d68d3f196490c107b2a08a58904106725e000c362978a48c6f07d236d82083e6082f1807c860830d921772078420830c325e4c40830c32c834200ef8c86093828b4f07de20830c32d0c2b2830c32c8a4988a764336c82068f4df44ba6f3f640f4d00690063bd006f007303666d8312340654266e3fbbebdedc006105196500641143217900701d2dd6749b23670b6168391b9aebbab1503d760d642d72110b7e20ecaded2e00305f52005300410aebbee707130f412353772df6059b28132d74371700b001d92900ef8f42c509c527718741c81a20cf600f0b36584354900f181f0ff2427e031f20722072ffffff173af29965265e78a0f4a99b0dac3c8101a3e1e2cf16439d9e96ffffffff503241443fdb1847d410c8d86adaefc170ce9add3d0f20255695ee7145edf5e0ffff42ff088abe23006b7b663484152b642907b351c27d615bdfb2bdffffff5bfe42730567271e2883355c0b86d088d213e63edecd7c6e4f85e3ffffffff5a91c7fa5d55d3541aec6c4bccb9d5c4a7932aba9f68d6633bb6e4ca7eaa2ce7ffffffff039cf790a121621bd9bfd7b4b0b5c676ea534a58b78da5cbeb9446822d92fc064bffffff7719f8364d2ed1971f3433127938306f111c4904abae8e7a1ca85fe2ffff4e59f35ff114fb2f89ad69e9b817b1f0fd98a6db8f2409a4fdffffff72c374870a48a21dc0ff75af57c98b37f652c5dcfe31e56d600e4cbbbc3929c8fa53550a861213600695a5b0e0007e43611bc3179cff01001496b2610718479b1c362c4e0d0005d9cb8605062d0000271bd6256c3007fe0201c026b00bb177fec54f7a287effa003ce03979227300491077ba05fb9400f9004cc9f8d7d9090001efc1f2f900f40ff5aa304c263857092407fa8e9b3635198107e1f86000c8f1bab0e360fa000b8280f5ab0c106071f380fc2b0c1468248480f511fc1061b6c700fd53f800f9b3dd8ec39000ab70fb20009670f6cb0c1061e3fb00f5c3f07b1061bc00fd429476c065b300f0d19670fc1cece1eb90016cf7f0fc06f041b6cb0280fa5ef380fd0c1266c6911270f1700003dd80818580ffb002d6305078b9f0f3800c8a8d8498d600fa0aac00f061b83385b00e8d80ff41c64b0c12ff00f120880f660839d112f200f87000e67c1061b6c0f9faf480f06196cb0671f500f5960071b84414d0f700fd1000d36d884086f0f5adfa0c146a8830ffa0098bc0fc86063d14400a8c40f4860830d32cc582fd40f660f36d8af5fe00f4600abef7076b0c10fd23f9c810fee848d6083bfa80f5f56cf9e0434d80f149528820c36e1305f0f9f0f358331d820cf500f012f60061bc6600f537f0f85b00be3307f824f900f60830d63627f0f371f4d5822d8b00f510ddf36d860830ff11fd00fcb8fd860830de00f9a1ff00fc1ce0e36041f00830fa89fec0468b0100fbb60200fc260c3182f9f0f673f6c18830d400f560f0f844106195450c22fb0c1061b580ffb1f680fb0c1066144bf700f031f9bb0146c780f1f4c2f0f1b6cb605bd1bef0f95cf14a4c106f00f873f3608c16a288fbf180f6067010d52cc2c0f830d36d8d33f380f991f44d809d0600f2390500fd9830d3681af680f340022bfc10669b00f207f980f41061ba4715fb00f2a830d6190c883af0f9c0463b061cf0f250f60130e6b387f4eaf0f60830dc2662f600f3fef608330d8680fa00f800f20830dc66d3f980ffa608331c8a85d2fb80f830d32c8a8c8f34fd8061bc6600f455f0f4becac40304fb80f1f5fb0c1061b100f262f200f41061964173032830d699040275f0ff5830d3648df600fb01f70830dd6600fbcbf800f901b6cb061ef0f565fa80f1b6c1006a12fb80fa22f6cb0c106d00f6b2fe00fd0604318f29f0fb7209c0d52b5870f971f608331d8180ffcff300f860d36d8fe5f400fecdf1b6cb0c10f243f600faa5f0d83c106780f06af36d860830f9e4fa00fb11f1b06830db00fa3af0f481c04063c9fd0877fd258ec17020100080176802f73bffbff746c47657456657273696f6e116e74646c6c2e032ffebff0076c7e6725697525f2e6f7eeeaecf3f5a0eaf4e89ff57f048fc0d1c8c1cbc189cdd1cfd77e7568ff7f15ff6c706472216b756967dcbeb8c7d09799ea9894ebffffff524d9acd83ada9cbc384c2dec0dbdf8a8f89dc8cb1f7fce6fa8f6dffaeb42d6a76626d0c5a5c0d4029e7a7b2a4f81f01feb4bea5fcb9b0b3ff4b5e480e0e115a5d5c0ff63f016fc7d4ddda99d0d9d69f757a6efa1f83ff737f772b2b38737879df382d2c393e3f193b2dfcffffcfe793b0a282a3b4a083aeb2b8b6b4bc9eb2b6a0a5b3afb3bb945deaff210f566d4b6e796f67567e77bd7974fd0ff6bf8467675a79636e6b7c731ff7cce8dfc9f5d1d8de52bffdbfbad3c1ddd8d8fdc0d9cfccc81782adada0af762f7502f4b7bdbdb7d0c2ced3c63fd8ffff00a992a686869081808d9bba99899e8b818447547e7077780bfaffff40747d706a78587e786c7f6063775471677265617abfffffff3f959f8c889f8f99afbf98938599869b8d9eb5bf868089839491bda3923be0dffe949781b5ae8fbd72b4b3bd8e83a5b9a74d6e4f82feff5e4e50575151455763465a55525b5aa70c29ffb3feff1f1c182917030406131939121b061a8f152e0e2a362a380affef7fab3ac125363a183126253b3117ba81b19284b29d9d4f02fea588408bac91889e858157674316f4ff0b0d547b7b6e7e606d4a776e7863672f8cc2ff7f64467c78756740707d6c557b4f7a7ded2a1625feffc9f2d7e1f0f7ece5dbe6ffe9ea7407ddff2ffdeadef0f4e91d310f171016030d210302020f2e8a1af177f4ff2a3e3b29390f2c3e33362126697d13070b05181407e1ffbfb407151f11141c0414101a0d77302f373937a7a3ffff21fca0b3b1b9beb8af3e3e343c2a3a7c2e3a32343e212474156ee0ff7a2b272469613e39242737db928891383ffc8137d3127c62233b25232527133733341ff61f8432d0c7dad9dcd89086874f2b342c2e7ce1ff31236d25392b6f3a2f39281d26236e102833245ff8ffdf63747f37283f3b091f4447403708081d4f0a510e480117ffdbffff04541717161e511b111f0f030b0c1c622926812376636d7d606b2a2dbff4bff12a2b5078877d643065767a3c7474116b5344504cffffffff4d4d530147410c59424e0841425a58155a565c415b4d1c5b53575d17e4e5e8e5feffff4b55ece1eced8aa4a6aee8acb8b4a6aca2a7b5b5febda5fd89ba4b0dfedf0e88c5c6df818f8f928bcdc51b1ab0f87f63080807988c84b7bb81838b88b9adff48fadf318fa2bc9390979a969deff3cec4d7d3c4ffff6ffcd4c2f4e4c3c8c3ddc0d6c5eef0c6ccc6c3d7dec8daccd5c7e3d0fffffffff3edf7e1e6f2dbd8fbe5fde5e9ebfde3cdf6f5adf1aef4fca9b7aaa9adafb2d17fe9ff0228d2c9dd85d089c4dadb8f798993c3cbc491fd7fa989973f67267572667a73734e7074707962a9f6ff876fe1e3e6f3e6d1c5c0d0dbde94d8339f5bffec7f435a5741591d5651501f6076646a6a6b5527edd2c7e06c67660f24363838b035750249fcff88347fe6eee3c5eceface9e0e3b7e2cfe8ff3f39373d352a7530393abf0d18090d49d6ff435a3406bf465c6b5f5d561e5b5251df17fefd7f0e163a150214020641080123879d909a189cd8f62fcce09d94973f53bbbfb7e3a8afae3f1f21f87feae8ecf6ecfaffb3f6ffe977646b77a507a9f06c642c66bbd793f6e2faebffb1fac7cbc5f5cfd7ccd3d7dde0d9d8c8ecc7df0816ffc27fe9d3ddc7cff6c6ce5a007c6f636869650de237c4c631ba31b91b1618021301fa7f6bdf5b19141a038f89968691948f8b8587858485170a5fda148064a7a9b8b55dcd181397f85dd00f15bb50434f4445499dede5ff2ffcfff5e2f6e1f1e7f1e8eaf8e0ebeee7b7ebe5d2c3daeeeedfccd799bfd0feffe8d4c8f1a4b7dad2e3f0ebadcefafd42c5f4e6f0f3e5bfc0dffeb0daf6bdacc3d2c3f2f98488c7b35f97c2a488cfff2ff0bfdeaf424a5a4d594e435e47455245554d554e5257f07f02ff57424c656e66767d4ff0f2f8e5f9f5fbf8eeff857f46c7fff6f0e6efc37efddbe9f9f9e0e7f9bff03f0867c6f8f6f6fbd7fff8eb06e9eff4f1f10f6129466b0309f7859bbe005ce0838482ee9694edc8ddd6cffaffffc31747504856425456787d6846506241585f561c42494476b4b129efcdd483c16f7a70d22f35b65a70153d7348594b5f5e478cffff6c48440e7d746e5b4c5c4a087d454478256ffa2f6d7d534b554157725e8e44595e4b014348418d5ff8cfd7021a041006042a45131d1b0f511dfbf69f05c9767706757e47552940414d62f7a0715271535f0fcf9efecf8a5fd1e7e1c0e7e637f8e8faf6efb4feecf00b2cd0ce0f46634c0e5148ffff8315cff3a6f1a0f7a2f5acfbaef9a8ffaafdb4e3e0ffffffb6e1b0e7b2e5bcebbee9b8efbaed84d386d180d782d58cdb8ed988dfe0ffdfdadd94c396c190c792c59ccb9ec998cff7e4b3e6b1d6dfa0ffe0b7e2b5ecbbeeb9e869292b283c2621953f84ffff68575378595d7f4a565b50775f5342432fe9cccfd66f07fbffcaccd2de88edcfc9d9cac9cac2173709dd492c0ec6ffb7c008103303e2a8949b92debb999f87d7eb2ffdc19463123e2c27313a3412011ee7597cbb3537d2c84281c5d9c727367a81ff809e93928586bc9a249d8dd0bd86d17f81c1573138302825346c28342a177fff9fbf3f3d273d3b233f6d2739250f7e6b6919eaff177f776b7438706c76d74e48404f4c4e0f4b5749f163ffcf2f647a777e7d7f3e7a66780f42415f525336f8c7beca1b5f435d0f494351494c4c0fa54b0ffb4f20ef909687df958b97efd9d5ff4f20fed3c2828198d2c048f5d0d3cad6d0cec2f0d0b1c28d5bb3d7d62182c80ecf3f5ee04b0df6e7fdf72bb7ffe393322225cee06f9f3132207f3b2729e9956f0ffbffc9e0dcd7cac6daced883c9d7cb5febce4cd4d3f685e2d7e2e0e985a9143b2f51ff6755e2021e421707be9c8295a6b2da9082f8ff13889ed7cfc6fdddc1c1d5dccad2ce95dfbfc58795f147e7e4fa0af3fff1f3e7faffc1feeef9e9b4fce0e2178f848dbe969896828e9084d995fff7f65f77008d91959b9ca4904fd9918de49b84808b8a8ec4ecffffec8e9c802f4e4a43454f59414c42595c4044074f535147ecff851ec0c4cd4dd7dfc8d0d5c5d388c2dcc07776a1173a76565a616090766a0ffe0afc7feeedf0c2eef4f7f5e5b9f1b897fde0c0ffd261974899d3a9f59cf3d5d0c68aced297dee0a4cc37587f5d4b4cf55018bd5434e0524854bf2815640d44fc7fb903340c720ee00c700b50010502000563b00db820010a3d740b0e68edad5b780e01202a50330713070119075b6eb7b7263726743d06643c03343b012875b7ef7f18f016e014d012c01027043704420709f642b7bc3b090128300b126e12644f034bb7d1e5344e014cad701317177dad95db742903342845133b1a7676b9bd131a7481033480017e130d8f05b77de30d34ed0df20670b705b3519ab1b7d01501ba061b0f4e4cdea8fb4d5334654f5edc700760ad4474c7130d053f52d30c80d7f5ba0677099f9fec97f66c099a65245f240bf1241fb34d970c42280134250b4ab5b7be3807224422e4650623f07db9dc0364633462016001146b06dd2e70bb230652f1010feb0f648b0f34ec2eb4d60732ed1c6f1464035407ed0ee5ae13143210670b0a32db6ebbd0d71b871b741f1b331b54131b6e6fffb734b31bf019e017d015c0011c1b1c641003540f0993b05c340e726d709305ecb0d89b9b030957b39dab87c3ad33db033034072e8b0b63a732d5788a233673d9868633401f588b13525d34606e2071f727e6fb703801845137f7016d7ca90576463c6553697ab5cad5b72af40d434f0f6e745468f67f23c81573fb045669727475616c460fb7ebb9b721c30352153073004322a887b56f74650d57c127416cee6f1b8739ef4307736548616e642cb10b6dff1f014578697450721965aa008d6785edeeee6f6d6d1c4c696e3dc004532565d4c13df6dd1a02194d6f64756c564e616d1c45d678ff5e153c41646472409b276d37315b6186d302488e702b148b9d7ed70bb2fb3dac40cf0d39156d3d050bd68d63a8cd28b08715de1182034f7008b398030975d9f676333299727374209a114e7fb0ae11cd31bd43546f6f6c686578edb7db6c7018536e6f73686f7400f3738e11b54d54f96efe0b0456d8fe174d6d6f7665566563746f1964234e352b41a3c60195f70bed1b7c41034c6f30236272617279619ac20c257d022e4b3b12b4175c4e454c7538fa00a8bb95705b175703383a55531ce65a775819c4a7793990393fbbd0b69d505a6600b1134163717536eb826dde65a271cb17a89b3dacb5602b1700b315ee0b67a537443111440f746685620b15791281137b688afa0c447665f755451cf6076172d7414456415049952555d9dd2f0d746c556e77b045780000047664170110ff0140f68212a263b0833508770000000f8be4853c0000080861b3815400012f1be85a0d4a110064ff70703cb011d87e7e5f0f000984252c24c10f8b602becb00f072f004d094079dadb40e1a1ec529309c03700e00019800bc800b00c0f02240047ff47115842000e008a6e831217d903e05d53805b21dc070ff40b6c0d38db7507e003fc8707b38425ea1ad10888d7071b92baceecba140b1c075d190b600783dbaaaeeb033c0b8407ab06440bae5ba8aeac0737e2500b3807d0754d05ef640b50074e76e5de0649780b077a008c9d35b4eb0b040750216f88074896e2ec428ea88807f5e4b89d6daaeb0bf807a8bfcc8807ff5dd754d703dc0b24b34203fc0b44b741e17607092a9bcd0c073bdb755d7703380bbc07ea2aa7ec07dcae73b4952b33179807492c73edbaaeeb0b4c07e503640be807512dac36e59e23c42e3b67708933ceed3af7cd32b30be00704338b0bbaaeebba10072803b00b30073103b4ebbaaeeb0b40074103b80ba007ed03094fb9afbc233473ab89ff8f543544707b90a2a0ffffffffa2b0a2c0a2d0a2e0a208a618a628a638a648a668a678a688a698a6a8a6b8a6c8ffffffffa6d8a6e8a6f8a608a718a728a738a748a758a768a778a788a798a7a8a7b8a7c82ffcffffa7d8a7e8a7f8a708a818a828a838a848a858a868a878bca898a8ffffff6f00b8a8c8a8d8a8e8a8f8a808a918a928a938a948a958a968a978a988ffffffffa998a9a8a9b8a9c8a9d8a9e8a9f8a908aa18aa28aa38aa48aa58aa68aa78aa88ffffffffaa98aaa8aab8aac8aad8aae8aaf8aa08ab18ab28ab38ab48ab58ab68ab78ab88ffffffffab98aba8abb8abc8abd8abe8abf8ab08ac18ac28ac38ac48ac58ac68ac78ac88ffffffffac98aca8acb8acc8acd8ace8acf8ac08ad18ad28ad38ad48ad58ad68ad78ad880ca8a4ffad98ada8adb8adc8adfe0000000000001200ff0b00000001000000c789000000e80000d965b7fc4d5a900003000403ffffb80000ffbbabe44000d8030e1fba0e00b409cd21b8ffffffdb014c04546869732070726f6772616d2063616e6e6f7420626520727507fbffed6e206902444f53206d6f64652e0d0d0a24432226f6cd81fd35e166475bb203676f3fc8b2750f6323df3d5ab2f8076b15beb27d851f52dd1e61ef6963682b9b5045034c01dbfec3bed5d737af5813e00002010b010c088e0c605df7ac6c138b1a041003a0f56ce6debe0b0202050001010700173b9b702001241e81282b612c59b2070600041ceced20a1c83c104f54090000afb0dd2aa76c021e2e74253bd8ee65787407518c908e00b7ecf66f87002002602e7264617461088646fb362cac1b480392270d402e6583bdcf2600f018044bda27b79bfd36c04f656c6f6300d3db000a070ac84e59de2742000085ffff1f51830c24ff8d04245556578b7c24148bf12b3decf3a8f6d6bffd8bea6a026a00015056ff74242c6a1915a4a115bb6dbbf985c07430048d442950342f1d15949ddbfe67170533c040eb156a0106500034206bff6fb35633105f5e5d59c2080083ec10536560bffdf67f895424105733ed8b463c70307803fe89761c396f1876ffdbffff6d8b5f2003de895c241885db74538b138b4c6403d685c9750485d2ebfefbedb74103743f0fbe0202092bc87522aa8a1a2bfa846edbaddd290e4208150c1703c31974eefdb7df6d1c8b4333d283c8ff423d0f4fc2f7d91bc9231fbb7dbf1a174583c3045e3b6c729c965b83c410ffb2fdf6c38b4724ca680fb70c30091c888b043003c6ebbdd9dab7e1e7ff353cf8bfc5bcf7d81bc0f7ffd6bf03c3558bec81ecfc13008d55c8566a0759e850590b6feddd6d45c8f015b8258bf085f6ae5aeb716a85ffddb60a21f01ee9582af08bcee8fefe4360dbda7f1e74e18365fc1367fa0fe8bbcfb67d406a0520e029bf8501255068ed2f6c4db60154e06145fc50e8f4570dbdd45e70a6627ea76861586870a237b4bfdb9475fc9fd68b4dfce859271f7b5e8be56c3798b35d9ec8ccf98bf26538626efbf572e655085d660d7da1d0bed036b957e8c2291704bbea22dfed8b68eb0a4c0c4ac2ddcc0556e64c2549b8fbb860f8d6cdd7f57508b95023ea35fc9b03f6ee34e8015c513e040133f6ff77776f40d6bfc1498a82d0bc88040a423bd772f28a86ceb67bd7baf90d843bf54681fe022c72ea5cb0605be4fcfed9174dd7b635dd6c068a88f99c03ff59fbdbdcb7588a8415ff8d4615374281fa46f2efe61ee9ba66066168f86f3e463bf24dc865b059cfff1668706fb8cd2a55981c9ef2e88f5898fb5d5879ae8634f6d9150cb22b8d48df7d51515382fa33db8b1525cc0d8586855d34be478941486b24c3a5ee834df83bf83b53536136f7db4c0741533523b9352b0d058c0169c3507403c1411e6fdadfc6c2a9fc2e6809e860fc40ceb0fd109e126800806653f831fa4f18a4b4575b6a33c941e84402007c42734786e8f8cc1b8064a130df2e953eae55e47b14400cbb6a098b70dc8e1b4be3d96e9856134e281aac3df6d6a401e86a523d178b360113dc7f6c171de8531675eb8b76108935f0b477c67f30de19f6c301751a6a00f5a3ce30fc3dba3de68692c3ba7433f638bbebf409c050ba840cfc33fa1b0e1b3e8bd0e8a733ebcb515068149addbdb9b9cf1cf1682408897dfc57dba9eb695480d80f110b0f20ecde766316d36c038b26ba14f42e3d64f6deee362bb9080ae8ca4955a328f48da7988eb13c4983e60aa2e8ba609a7fd72d1c2420600e83f80272dee82e2b48b6f077672f11833d180473c7bd58144c70bb6dec05277cb6d76bfe3543672e602f2c21010f8e82ee1bad1960c1bc8a668b8ea0e9c0f0e9ee8d95a0f5e8375527f8fd008ef0e07e47ffb6a81b31dced75319b31d8d71c2750235067d87f0df7a1187cba2cc4921ae8ce50eeffff089b0b83c60c4783fe307297eb0f6bcf0c8b89a42fd3e79ae1090de84f9ca19eb86ffddf4dfc48c680e0f26a75f6a11ca820740fe82208f59633d7fc57041210b923f6da1fb6750712400f85f0440ce110ed8da62de6f0b053ecd98bfbb637f7fbed5983e7eb44c18bcba31be8a197920f84784303a765de20a0bef6a32cff87cd8c6d8d35240528189cbed19c6c6e334cf810fe2e85633bdcb8c61c568c0168b526a8445fcd16e13c861f0eba4d83a3b30db7c9fb482aa0f8f319f4a28e6cb8ed302e846e48f8a3007433bbef418b09e84b122804f45a20bbb70d61f7b953601a566fddb63dc343c3253e15103568266862ab334fba1fac84963c15331c562c7398a89b94eb42e7682e8a10fa28c22327b4e0bef0dd9009ba002510fddd0268d0fac5e1df3322016afa564a7407e8cd2712aec1b0eb039cbf39113c1ab874818555ec7d1a53f70dbb8069d90ad4c7628fd4510370278c520af6a3e44f1962dc9e5402045e5f7d93162e9b30e543e98d185172b96eec97f8c3896b0ce8661900c5ad20ab8926b68b1c1ca108401886605b3270e8e72d438d0c1cbb66f9eefc10e8d029db82393a0f86d8df4fb87809e6108bd325e8dc4b1977d775db14235719574a106310505150d036bd4120d85ae81666817c11eeb4b03d62891d1c5ce9059493b073ff34b99ef0eabee8c172363050e2043fd80a1f09f80253b08d2d582db9dd770fffd58b1da0073db7126a578cdff92ed78bfe218a884e0cf9a084db7d6be8bd06113db02b1bdfdfbdeda1ffd76b94249826b9ceb04151e8526e84b13dfad42494f65668f67008c15a8b208e1f66601dedd89656eb5417d6e80587eb2dfc78b0074ce811f89a75f050466833678ab58b3d0a93aebb1d5b34148df01f2ce93bf283fa5bf821b704f3300125d951a7ebf8f360efe30ae0b915f3f1c7d90e5cbca5d1f8bbc38d9df0e8ea0bce9138c032665386b7785a6a22a4085fc78e63ba5d6bff663bcf752903c2c5030a74081b66d6baf7862cf16a205f0a120704b747be5df710752124ed15eb1114f274dca586072b30eaebd0f5204a894f8fc15156f18d8c241ee827e9c971fb8240f7de1bf603740c1ed881847668d3d605233dba5bddcc1eb7edc36880a1bf9d4658e2bbe31590f7cfb027d618e16e7505fb245f16e89f070c3e2eb4d7c68681c4d7c30d2c9c6e10cde87767f869a1c4050cf45950476e034c1c423774d8d64627d08dda2d447e3f2d197e27702b7db7b38e2f1b6683382dc1d84002fea76f2fb7697409047275073381db43413bca7cd9d76c7a9aee98db9b31f60797a27bc040a68698c819cc77f10d5e28648d1485dd0aad97b756e8f75c407884f6d5045056d46a633ffb2547c8e8c34f008b52e8cff5b042bbb3ed46e06af1238cab8406bb885e0346af137649bd510fd94625ce1a03183bc5744c6e89c2ea5d0f285857f3dc928985f464c5f32c287232f63b665cb96a6e3cf39462606b23c8012e3bbff0b69f8ec63657cc4006d8392817e9c376102ce001f7350bddb108bbac18a2fa19474a43d8d56d635bc6f4d472d3127f10c03a60bbab634e17bdd455b7baeefdef3dd0754b8d1c5d0271523410b94a7527ee038050a19b3c143bd4bd4b95164125006c21dc357c80fdaae864414a74bc5d0453115ec3d06b5b051bff08d7eddac88004709fc56aff0a74b119db99667c02bd567802cb1c69838eae511e04d8741a144b4e1baf37b8e6cb15835e6ff11548d4563875f424de0364848dfbf5551008050ec2d84dea7ce896154c0885f7738b35b1f0e1d60dd77527dd50477c88882184c126dd0630379b84120aa7bbc4740484750cbe846027e70e98e68091133cae7404ece86111561bacce0b265c890447ceef178026954e9104353429e1e0428d9e4b0f1b86a1611b3adc47e846b7fea3adf4600d4fefce57971ae1ed681146ffd1040a5ff9be7860845fc75743a092c30a0c284018d9b24b6707d6d1573c3912200f79a91ccb4ca6c6688451d0a598314487838d1265fd7eb69505c319ade900b57272ae02bc128fbf51791619e63ea1ee985045f84b4168f41b0e0d38c3832008f8846a6a3672b000241ca010511b4c18eefbe8b13da356c60e467138f54252057ca94c0132d15e3d6ff5646eae31326d50ce5b070481667afbe8342b05bb560005c413df07f5d933ba5b7c220a50d146eb0ee39dd423a6565357a45be3bcebd5351c7008ce55e1f16b1aa54fb4db6b33ed663f896c20c468731f826af71b6cf3376898284fad986a18837ae2a983fb21df522cdcc1736c8217df840490ba75f55609587431f6898c0650de74cd43476237a02f8b8c233b0d7f7b43acb6127218900f394c850feb96f8a662403bc672f1597835517d5f57c271687a520f92284341fde8883cb494bca827f286b17063333c27ea50655b9b286c2d340c3a8bd6524e9c9590be000f2c428df048cf204902fc095686db9e9d6f1dd26a8364f6008be99d44a4003fac821b0b8d686020ad36bc9fd8d6112f663cc7e78b7319353ef4203b0580757929213c4637b70f00f4698b15290b508ba211ab0b73cd18cf739e2ed064c14c14eabd046b6fc53e64e8178b84a68b8486d7b07da1cd06bd0047ff5918841031ed81a16e28517ee0d1e9299899f81b61580f45c857893b8c0c66703bd1cd1738b6db8b460f4130d3a29b7089b006070c6485d853c470bcbf5be0850212cde88d3f100d3d4a2e9ae032f3585f85b61839f3daf6d4246d2d421d1730f8e8b80f4fdc0067db83fded7525a68bb1dbb073238b210deec9411d45f9a1d9e63ee0e8d72b4102a1ea6f09f750cc564bb4417537c2878ef080148a2e02c310f53ada05dc50268aa6ef9c133494705df168fb5765eeae81255e35cbb0c23929ff097e6c19dd2dcfbb76042988440c38dcd3f11272cb72f439a4ed443f5a43df1e8a840c6b7f8806a04181c7304482f9ac24b0d3504edb8377543ce8600747713cc63b3b468d6f948b3fe96b27dab01da039f20baa58f605356317be9101429d00b72020dca8d418aa1861aa6b3e3dcc3e1eca27e41fcd1813cf2c831f0b4b562c0a6db781e70c16de57be0473fd1decfbde564211799c001b566a0b183a839d90fa398517f7846b7a4f022441348b0ed99be9d6d3bbca159f1e1ceb607cb61bbb0d0c59ce3d2b4d7893159dc89eed527aad3dbd742a94857772f67c3e8c0c6de6f304c1fdba4d455788e891107ac1180d2fdae870ee7c5c8cd23b4647eb869f4828156918be5dd7f011fa17d71c7a34c6e311dabdbb0a16f8eb043558f414bb3a1c77ee34e8eb083724e8895e1bdb3e7e630f8d487810c75fb8588a572370d8145a5f8812dc49066a8eadd1668945b11d70a9f4348decd8b948fe093470b6620f8543684ebf1528f150663994a8286a05b8a0b6ed1bcf04521fc7c18b4d0c48a0d6d916378038296541ebd4e6b85e56f4cb609068a2cfda605f0c21820041924129de7808b10800ee33d2a40a8882ff6884231e32b472ee5657b8588a110486ed5f6204701d2f9c0cd19447d7a9c743754ebf210625f6055c4324835c190b4606febbd17e327c3c75125c75275651ff70cb7c8214cf751a68752e2036f64dd14daee8ff404a0396f14fbacd75929803e3f98bea5733db83e1a365389f4d8ab89d045f669c0182a348a4f4defed7f3b8b948885c0434753acb8a81ac34e5fe8f7a83f91072f0568bf3baff25515f5274703388183410ee2863751ba78d694c6a278578beb7e468ed4458a5a77c4a9fff8db12322a6014052061442e85c4149dd9d6215a53738e865a1aec10fff228a441c38888346433bde4ae9536eeb6d24a44ecc2932781db2e3465e128bc314980388c1865830de5cf0257dec1805a1d74f850ab60d7d54c07064006ca18df058e08e28be09ecdd8405f89aecfbc001fd8508503f2c801f9f3dc2135068ac378578e5360c5c946874e334fbd742afed2852e77e0b53176142b138d01b39f9cd3edc70c3209881fe70270f8cb234f653adfb2e9607bb317f8b0c95341c33067e89609b3023cb0889d1e983e001986dc7de0d852cb81d6405f1891b8dddb6eb53e3437cc4076f517d355a2a58f7b33c340f334f04420f3dfbbf7bd6b83d8774c333c1890783c70481ffec0849f6fb6d717cd43b0d32330d0e23cb077b0f1b6c375b760d60751a2df69f3d0cb597c1e80b4633c889d20da7b96bff25ad583affc1e007110b8cdfff0fb550a86d25127080375cf62ded7e7c05242c743617a308a3c4dffe3636b94e01281e330169c0659c6c03c242f47b64fb89410483c1a3f9e2891564e9bcad37360c3bbef2c03bf77534706b6df8c6eb16e8a43a2bf7da89d2f787bef16f56afc62bc88d040fefc383ec0c076e40a186688ef000cd1c10da068e9fc401555595dc6c03d046bc0d75fa0679f5916a45c861bd24995a2d526f236803802aa42ce63e78cf193d550e931cca130fb8c477294b1c736a02b14b2dc1d915801612b918760bf439d7536a462a153c14eaa2193536a08e110cd184cb19afa1ad7139d68eb71fc97538dbfeb920426a08e3a5172ef55aa80145d1e85e83b8edc4ffeae16f084a75ee89014714ffdf72dbc705061ad17d3401d65fc4be85485ff81a0fb6042e6cc1e908258fbb835efa7f4b463bf372e65ef7d11fc15bc35945692b44d88c1832051a5fc05273c3578acb7f2e61abffbe9e47bd048802404266087253b7b57d60feb08a1754c3c4300b69d9b67f1c02c202c8fec388371313c931614be15e7a881431f580fb2823b78afbc5ad7619478ac475c6595959e1b094a19e6ff19dc2ea7b3bb18589ef230c8a9f688adfda115869016038565440f38a143eb6126ddb02fa07cf58394a5939ae7bbfdd0b0c3e03c203c881e1ce178bb2b137748930f5453b4472ca5e8847456ab091885f705356b80ba56f0ff6470402915deb13090f2c2d2c4861a35e890f420fdbb540ff46f36bf6188d5f082ca904b6a405a392b119a053570968fb12c1e82d4a6c0980751e23276c6c6cb429b005ac2f75d02fb1e94428e1f1831374206b676ca3c446045ad7b05bb0f11a3cfb8d460850562e8326cc2944aeee2899bc8b4e60b35cdfeea050d8837e5c3b09ff765c990acceae62724515525afb467b4297e3937c2837fdb9dea035a89685623d862375c2d61158c8922af6283468cd8ff610db6c4b0c3968f2cf6532cc3fd8503747a1d68028d6f645542c4074dfcc6cb2b586a13590450bf06b3423401562812056db7c04d293d4f8947afef43d9af82375550341c8d475c2330dad1b775127760ff379ba0402d67f06be2f1ef049fc65ba25d7fa2f68159b7f64157543e8b450ce06fdb0b23750889068d02ff3650526a40c2090d1b6eff711d6c74169f72bb470ceae7308906393e986806094d86626bfe4fd89d6a866a8f0750586a2c65b8708158e044066c75f8630dee1aed272933158d4e5ce6d16efffd1c0175fa8dbe32c601085753dd2c517e2e6ddfbdbdc6465da7c746601066194532465eb30d03dc0b6420178d28da22b80b74622cce1d780a9776d5752d45f4d31516c08e886d056b00075511bdc58e063482f6b70f02966e718b21872e5e92317571b75adaaaa53f66890b87d6115ba0b5c1120a75d3a0140136c16004dfcbc2000d5c0568349950d922512468b770f7dd49774217ef7d01e8501a6c7575f7d5502ae8ac1083fdec5b23b129d321f65395006e44eb1347e2e874fff385245a5e0c52d736e092f77e08a229fe0c197da8771f8b1726ca9f3897ce7d07ddf53b454d3beb72e18b5b74edc21a8044971893f60d8a1d21ba7cba011fffb40d83058bdd788d8c9d0f06e8d66d87ba1586e9738314762c83322023cd10251b1b6f75063b74757fe5ad397e046f4de8d976668615fce9e70eff34d01e09bab90fecc908473b245e17c22e40eb3fad88789f0ab9dad81d38ad0b2b11db6d11e9207478841aeb04ec04682a04614c3072c0059de3ac6c0e3875a6183f1c5baec20c0062c5463b7ac5d956b14a6a014ba9198d3453d82c4f08e16ec56d833e7435d81c3992d6f534a934dc61556848cba859706309f646d90c4c61da39074503558e1804e0591010c3c192a116b03d91f6aa7dd83d12402f483dad775e84723bbe37ffe86af81d3843684404387a518c21b3faa88f363059a218e130550082cd3a4e8b28b175184315130876e00462dcdae81c373302df511a04d85351d56b57e8b7376c868653e4c15e053ce8de360e12ac44f7e806625c740a5ba361db042f3c66982ba03e57525f464b5b069b0c5357b1506a541b5b527d4706fed62008222e83c602ebbee9ab8d0acd55bc09fe0300d22f7642fa58feb6565725ba4d7629de5650b6731aa8fb118294a413197c0168b95b008dd41a3512c90a40e375fd3926916ae4603e1bf61037be40b940e289ffc032000000333e8cc159571275af570ee862d008f756a406340dd919c52112f11b2c92233ec206b051eee68c67dc88cd03572f805129abeec3d67b089a65579554897ab8db064f14047007893e854cfa3ac3d67a3030ca7f3c3106b0dd6ef49b1e4dfc4276043676b7b798d1c544506a45fc3b3b74c8a1b6ed11532f36194c3648c0ac9e22da6bd8b1c120dc0f286a00290a16d960b5082f8693061e7b44054c08f46c063aa1508113d3d8f97ee5a20f306a07961be806110906834aa83b237dc58ef2185621628a325feb17ce4e025224f550435368ff4d79e09068000558d61038a240e9044ed61e0634d016752c221cedd948bbee3450743c8440030e5449b1b700dd1c11207400272c86ee7bbe2804483c862c033c94f80134b8502f31a0624d0634b094843f25449634a962d4023c56c2324253e144b178d8189ec180a961960ad169c66a80c940befcacee89ee7b0aa44fd8a720a34a1caec376731a1b04531a28b45ed7c9550f002a4798f9523c0c6028519f15d085ae2d3d74fdecc01284dd99ce7e86b38d06501fe9dca024d8bd8b3d6da158e89c1f5c0c66a15c2678bfdb1055660b148bee668b0309be83ee21d834027108186aa8dd46a7c73e798d8c1be88b32d38935dc06bf237d638ed19a5e78a99d2b0a16ed0d66027c285c532b2d9492f745b459b1c25bea016a289a7850e0e0436eef686088674804e80d3488a7d91d38603c042ad17577a9e63d1adb00009c83c302d0ad4efc23f585ed14db854b0c3c36e23e655d2f16981426daa6242b153a1428b4579f8199def88d666420e60e8b461c3b3383db0062d1ed09056a3c761010bdab1dc608a08c2108661800031dde5aba581e40511ca144fb0a1e24b605ba62fb0438402778472362055dd233bb0d101c1b82932e50559a4dd6828fa73f55950063dc5e2b0c1c75885608fac3af4e1336b8116a024046b6403bc45604d4613c103e5b10d83a3bc86451f1750780edd4167518f32e14538687c5bfd7822b0e060186316833c00a5c46c0ff41636c03111c5b6a1958686cadb829f7ef880488440f47e11e2809c198a00306c87a026e3f87146a8d352c5eb4360bd73eb26492f5d5cc9aabdba569ffd7de7940e916e248d000d48a35036e32d011e481c655280d0300bbeeb0c33456330c280c17e96145c7187f3435a8a1085854339a9a7635fe20ee0157b1441634cdc46c845ad6128c0a84a03ddf689cbfb8441ec07d85112635f6df954659ea1a6e37a0343b459c83cb2c49ed38ea116e5463305757ae687e34448a34b53381ace8754fe862000928566a640b30b98e03467b0f575a9c24ea02eeb606d666eb6afc617463c28768e8dd20b13c805708b762d730d22f034909340f03f6b090bbcdaf8ff5f49864783a466c3096d7f5fab78bfcd1140e6ab764e9e28d41b0df6d795414f3a5e8df0c00d239688dcf04bdc9f09a96013bd50b031e68e8d59b942f169008c3052c81078f59860a51982fd0a06b3c7d3c53405a8bc28d6fbd10d005c475abc08955c4eba51ab4ad458745a00a6cc1a863abc422536f344a59cac081da7e59173097325c7a8b5dd4ec7dd84aa3c9eb918b86892433e382391efeabb90e8d4f01e81ad5c8bbd70494b8918bd3ccba0e0dc50db745362af406d645f001b72db15b2fd449704d6df6e2762978c975ef6203f93b02e8ba710686c7c50bd4e8e773fb97c6d5ebdc75f48b55f08d485be5007e5b8a37a48b4e0484fc14f803c8e8d1bdbf8df61333712f054407012146b9b530b92107dc666ea5dea0f045d0832eb4487406c1dd166ea10eb80a05380405011d85240570152e18020391b60b78187b0476d76dd54ea1d8090c07d3eb41d3bf523d807d3913d1e9d400defed1dbd1ead1d80bbef4f7f3bfeffe0eb71e1821e8f7e603d1720e3b2777087207ee0db5bb3b2b76014e4c9e5bc21000ee16522b53c9725c5a700ee90f00b815d3eeff0e2f08760d8a041688040e463b0c72f3d688063488391030b02f1c1f7e1d566a0047851c719b7722d7e8500e5068f580c165486e4ddc00d74e981278eb2ec252972d5dd8751081eb9b3611b019a08d005d023e4ffdefde5c77045339448f132bca8a1c118a3a3adf70dbe66ec34042dc95ef1b5b97a5bf0525b7032bc1ebf2558db34fbb808d88da1cb668f8ad0828d4b2beb954c0668c7bbb85364a133f5c92c785052d7ef7ffc672d08a45763c01757783bd60130575278b8564b081468c59dedde9c20698801dfaf80170fe3cf68ec5b415e995142f06752977ee0592aa04eb7e2b0807eb75b37fb9732f0809eb6c03757f6a0beb6331db82fff90a757239b5756a6a0deb4e3c303c20d45e3b6c5e7e0d081c3b0fc8612f4c03eb30642a05eb199fcf0a2706406408eb071a6a469f1cf60a5eeb15650c6a0c58f37aab71c7f0098d6578728879f403fcffdf584fc7f80c3bf9770d8138125ed9577419403bc176f3b92f167248e020630c060647030c80cc98da36c4bb1b542bfe33560c89110c89311224a1d866e2022eeca852db5704f90f3e550cf18dc606422526431188840d884128179308edfbdbd4b3a2d6503b5aee09c704377fd4ad2dda0fb537c264eddb0cea368a37047940d2610c235ec480017ae5b3b1541f70942425e9fe20947be26428e826927420ba975af5ef68055e543e08661186e8bee152433e0475533928f8de619f6c9c20440c1899f045e176e0ce97c23042cafc0644adddf3d71be30d89333a126c34fc6f0b8365fb23bcf24781015e2be7a26e88928322d27fb137e0e9db0c500889be75738b0fa9e3506ca67fa18532d5f1064db5202b405394d6e8cde91f35420a4de00f8d430cf0b5bbb5be2003c603ceaafbe89335eb31642bb45d0583c02dc92f9da66adfe41b05039b19527405dee867615270c30c14da026d977e18983a73b0f151e87369f3e5921d38d8626e2e53e67fc48bd776426307cde9fb6b11948854c137271cf5d4dcc8def874a14fb581afc6f4d577edfb33106fa283513883beae0076728b05de60828e3f36682b5e34269568f00b3a2b56348339ad1699bae00bbafa8d4104358b4df06bdf28c0d8c0f8d1e864115e74da5df052fb5471087c1381e269d681bfa16b03112bc301042a208818ec7ef4f072def903084c75b7fa70333cdc6cfa125f45555044774f7c8894884c13f0e821ac1e6acbc1ae17e31439499dc11723b4d9c744809a6ac518993a046ba2bb70ba1f463c817b601cb2777f766374613080cc6983bc30840a14765f5a0b5bfb8d3c31833f1c2a4789c6572fe0dc0560c8897023a91f8b6f6d1bb4ff1003de03eeeb237905ce4105e102bd0643cb235f975f2099d376c100a3d283c59503c933e2867fd783c7143907740ab914ebad426a248615c3385846350c3414064c5a27966ee0fc56c70f6a441ac6436d4b2c94a8e7a837ec15504dd04ab105a806bc278dad35036c2853b5d40014ffda09ddc250f4d0e22b4caa0f8a441d03057e81ecdf0b4383fb10de838b4d4c6275f0f1bd75ec64543caa81c9548d2042f07f0c824f0d3468017afdd5119eba61e05168405acd4b2a3a0c506464db4052114c390a0a340ccd9aeb3edd1cd5c3b491e8319e4dfc1fc9761b9789f909c65e599b562a5e3204de2d536a20681808f0715b2512eb2a9aa91c1b6e40c72b0bb138521701ec1b0deeac7bf05056e130192df311c7b4184081451596b129ce760dc289d5152c4d0bbb0d23d811b944de226b0ca9282c000f8ea30a14a0f8485332001ac37e75f88975fc77eb055880e7eb8d2c19ed1b933317ac5472d77ae54aaddc7567e79033e6c2b653f18b57d9435730f6605d7174399538b38a00840570f2bdc127c7c04850163c16d7ba232a9aca730346710abaaed64b301bf68312a2455c5f28d959c54d705eba35606b0ffe7006f8164dc202d4c151ccf6363a3b23d80403241db8239d84ad15ae1fea2d9c0c0a1bd53558cd09ffe19c331cb09282f64364fa40c728fa3bc7302a537cc1eaa5d3564353a1f40d027c420764d43345f357181c8a0d58b330e405b6a61662770c7902ca3411670414f0fb2c41089e049f5056ed07bdf4022beb1b39ec1875155ce753b80891849624e958c0b0122c7e75d543153805bbff475672e59e388811e271a0706c6490ea1884505151fc5fd1c0775cb90c905868b8e8afc520d5a9255114321783258cf8e80f0000006e55057d03433cb0f641f1e8f2ec04e83b56c1d90016ac06476c4975b0fdc413f585881ce9688836ef264eb5d22168359d3872d7435a8a3151ec394ff6d1e6ec60ad9d4b68a8b0fa12fc22cf0e0143457e56b686111a2c29b808cc8f986a1da948b5773743873da9974a05434c05b889b85173697b7760e88d954f98b840e401836de0d95187e8f84eeb0d0cc0433100132273e7066c3cf8eb18ff76af4276eb0d741be0e8297b7610a9047fe4a36b60463c5afa11551b6826a08423747bc1b7d85039d33be9583bd9763bd12dfe2fac308d4610390875f7390e8c6a18d629da8526891af6a646dd7f8b275e08896e0ce8db23eb66d8229163a3285d5573aba3463dd3c8c3777af18b5a630f7805e017f5593d063f73e810f510df5f5e9185e15dd01c080359e86d7bdd1d2b684f46741415e858fdae17bb09fc16e80bd2ac4211bedf140235e4f813c0e06cbb1deee8b9d466e837fba11502f107bc8b9d3da2ec3110f79469e8ebe71b1c363230724694846a48fc80ff288d4e08b214e81d27acc2e5cb3a18c0a5408bdfce90e3d81b7821f1441e68a02072ea5b162d70f77379843e880d4783ffbae7230d04da3db6e7026124c2118344acf915fbd3357cb885012eff087cbc244004436df7439b0d6e49ac24440d85ed0e6c200c9b5fb810bf8320016aa17fff8bcac784240b4a985f4ea02236354010d86153b018006bace021edf421ecb07fe00f9066208d34458156e8a8f37c69844c165ed11ccde891e60a5a091c0aabce100b9c6aec419288f162bb86c2de9a7b2c8b949e2edb7dfb446a465268e866146a20424e23dedb607e014647451cb050c8063d3d5c9200b9e4fb2be82540100d00dcdcddf6e8fcf240ee3804620f4bf0841820282184527d1d14eb0d2ceb216a0e3038942016ecd6341b1205a36c326045295c83129853246805a16e6794c079920235c371a22153733d290a87b1b0c4dbb850ea020e53f7589c1cfb754bc1d79ffcc8b52066f800f7e986510719f801ebb9893818753560a1e684c10e814a8dd6d7e2c3c23ac811db96d60fda29c13ed233b87ef8184aeeffff2923ec68d840502a0b78024658e8dc09d1e8350e6452dcfcec1a767beac8711f007d9cf31e8dccd610632b08eaa201142640ed25de6e01da67ca467ace70a72512f7221783761a89cedc506c64100160574d1c83f954884174a9f6f80f83c5a72e24c07c495c504c1b58a6dd608fca216820442ced23575b8dcf9bf62246880987a7299e61c4a730c48358a8402812d0b9141b405672f799a033986efc168b26ae2378ec0159630f42c15151b8a0856a1115a80856c1aab11d3c14bf468865d06a44d948df5bf7ce501d48078c798d5801d4054847a0b300f3e8d874f014170998c11cb5b3094fba69847eaef5b80802950003e16330221404b4a071b18898a966d31a4c8cd8a74ea0908d84152b03f1f010338e951d1ee159c12df97321ec361dca5bc18d1c0003280d725ac65b72d0af3dae7f5ff835c1447005e1acf0ce4dc37278c943680a50c61803f083eaef0897547425101850fdffb0189870209a6fb0311840305a90a3ab4550113ab1b0cf938de0284827fb0820b6ee7e810264cd776372073d6d06770f06060a25228b6df57da4dbc4b94beb5e1b47a00f770cacdbddca18df89e853eb3c182e3491e639ec1f18ec2315d4d973c8803ef00a0bf41802b758555f3ff9ce0c385a21da9cc75a41dd0b3c5fdc66a1440e57ea0096c8bc71ec63dbc17f21bae7fb76cf42d3e285d574308c075d689c9bc041e91d44835df115e0d6f8056a9a83d8a82fefd6f208e0db1617f97618d1e269fec34780dba2b36af3bd9d0cd258733c19b0010c71146a20362d143acc75cea4906a21a55d83ea0d1cff0b32db7bbfb5281582a631d3e085c774803d10b04a8b0c108b173d82f72e0fb7105682160b5523ac991c4eb5dfa622005555153050073879b6d232a1a546a35842ef0f3a728457642404a8d01e6f15aa12fada8dbdb53e9a7e012d7517e8de132d07819825ea81eb29c7be5e67b88b62440460e8f5c6ed617a10a630ba1171583faa06a35da0be13b16a678eea459a3d4320ba16876ca715a9259844be6390ddf718ba16405116b6182d8dbb1727b085fc39f453f0ba18b167c75e3d548bcf4ee850473e3a746f9902744e354a28971085a830a1ac1fa539648b50c46519507350a30e1afffa9a619f3d391afd125204743188ec4a2ee4000114c735082f6b1e08742622fb01001c46063b7bba10609c2a1026143999401771b52813350811433e6e1d140a29783c831e8bc6aa8ec30c9bcb7820a9a560b0ce20b35caa3b7cf080508ff2bed737df276e5019847f1f860c0fd01e1eee0355e8d34b9dea4d3103b4e11c5846f801ec053240792d68a0d7f53e8b6e50e454a2d34433dbb80db0e1b54bf2f8b3c00678a1d6756a481d83ff041872e2dd205530a11b341e4039800e7a3c1211fb463ff8da0c33dbf88bc27e125144b5aaed56083058c59cfd81efd9382463e8682e00735e1375d1556f2c0f44396ef0bde17447112c447237d97466dfea11761413154a8604afcc5134b474b3429bf3f3d6160f513ecede780fd960ee23c3aa348d5306bca8eba20f48592439a7b62a00ed4f270114812a6cd501d4a24421424622680d15a330f19daf543d19ac7355e715994583a6680026e083f180cad12b583a2085726d823fecff8d9ea2893e8b0beee814416a18f2302368860818d1c1aff041155a82395106ec86d927ea2fe82d13e60f93ea1a14bd7126e51ae00144880241f61762bc619f2c6833c02e8f578da6e8718cae1e4d001f34f4b6efb139440f86510b06c2229afc088cdd49ba122708201851e89e11005f7c34466b24b2107e5eadd0b5a17c414adb1702c9a9520fde0b888e8400957e4148dc55b407f5e8d51bdd036fa9a539d7e416bb8fc1153cf5e86bda73470dc24f7c98ae1847279612b97c17f53e6e7fe915cc9eefeb0972b8a24d95f9089e0010f20e1e1d8c14c5cfef57f94842d445038051a52c7a749b551c0f6d73370c30610b4279e59769245a2b0606350a0d88f0d87738ba3f504ee8430d2707c04d55a672e86fe8be84844c4200a5057d083b8e7094faa41d53b48e119ea10d830c0b46c5b9706b002764e8a1d5cc577c56005eb3d9ad23eb15446fec016ec86887d006e862683dbedc38d55fd12d5e0215dfe73014d00562d6ba13e587fc0fe6dbfb09b0478b8e1479b713e8b7e7e088d7bda60eba1806ce8b4e36d76fc818a1140ea4eb5cf19a0d1f4d1e7f37d4c83dc5691006d9971cd4d64adf33193dc8eb143557e00dbb393e750dc0111844c69eb1391054e8486e0c087121302d7c5e5dbb23bc90238aa0e821bf25745e74bc41956830751bb65edf1201a3b52060558e850d727f5381c15805fd3b7140fa814d08c70633e82af90e21fcb1c0f88ed3e81a1073da5c303105e835d2faadbe9b2c8047178f33c01f518be9c346ac951773cc167508efa43646368f2cad2c417b60708d869f45f80f395a5cf6266a11fc2361b41340b707087e7071816337e009de428d79950c98565fa19a7d19f81757197b88ba61273cce124efc8a857f5b7429837d087a233746223c8c05629d356aa1a10ac46e81131cd5e5e3c9bd5603fb08a537ffffffe7c1d5a50c30d474f564026bbba819b5e9db53afff06355881e353786a0ba7535f1730c28b84670d0729961007685e6a84d8fc48dded065587a14a16f6585077224cf04008936d1a1a8fd1deb14141bab379d952894fd024991a6e97a50de26017886b4b9308721df0e215a393d4cbcb887c551f8f28a744621443b8864ff02050c6f7349d05fd0ec699de8d8f9451503561eaf41b8a16f57b615377ea14df3208183620081d0680237d7f7aec84f684cfe5d3b6184150419c74ef4c248bd1512656158f1767f1198723d37d93c96d91761f4ce49bc44308344553b5c4bf0bae016bf80e3a883c8947146a1e87a830b3dbc186e591a96a1f0e8c01d44281cc82c78e88e8abea36b4565009b054561bd90c4cd65f2ac457392344cfee290e840048bf1035820286bbc7062cc1553cd03acc465c87635b13ea26123080cecf2a842360840768c61e4d80fb1cc6495020e6e8ba23d0b9351c30282120c70301e7fbbef61e0e5990edcb2bd4610cbadd1c08049d09569fd503b4e18586e3d36fa85bcf89375d0f863c63f52dbf04bf32dba4a76d2a87ac1ba33c675b9f9756421ff72e909fd4a41b3f8c3977141f565366444d60db0f7509e253778109f8bd0768eb51078b35b40cdc0e3c452452177952ca104c2816a1d6e1ddba6fe167f560fe500864a0275eee0360c3daaea9c6540b7706e8cc58e8075cac07684b442835f09e4070fe186c31c011ba2eac1dfb2488ce13bcae7138c61e0015ec2752878f769ee8b5a73578cb8c052f2a111ab9d6de070ff650a3249bd9f71d1675849099051731d909deec3327389e30dfee935c6875756a257cdc02923bfeb60e76796a26f4780b2f9e8c24d8f82cc6071def0e5ea3468d04e8ac018f0039675647752af50128d0b6e6027b5dc22cba762728105afb1dd0f646837f140090119c300ed2703bc69b026a063cc3099b7b3098aa4878bc54344d046710de59086d3818e1aec1ac85400f44c049914cf1e8b66871482912cf0b6d3c81118eeb141271b88a98a022752700917d13d02d8e40c4004c24745f3446f008a19f0881617559a2473870d4094638843b50e4105b76630e1c0b4c8d300782ef4cb042e01f0ae88fd4ffffb83874c9026de4e3703ba02b0ac5618fd757e8232323df83ea0bec77f06bfd222323f45f2fe8ddab640d922eaf2d6267b03b592ce8bc0affb798648bc0d719c820d4240285abba10a6f8182003c3c90893a0eabc9d0e200b0e208b9e03d2a65f88facf6a0d465aa1dbf172120b437a1d01a1128f521fc4403ac708a551db3cdbd402a953667af333e900c390b2d84722b0537652c01bc1346a105308b9100b1e88a5e1cd5801828430f28e1054851163c4c1c97c538c53f0c282878bf002c43a53967cc148b6b7bfb7c0acebea3f14265335e48760d44198451aeb1f13fe0a09ec507527784ce878dea82b6a265a9004cb6bb2004670287c28554473a5078b4f043927073a1c7eb78a48078d4f7ce834d0bb43c02dbc0fe5311e342a06621281812f3a4d71065d97f4050b3d1b6838296eb81c2fa75b5330d77b5315a1003b6a185d5516d7845b24e4e8009185480639b017ec0cc8851c64f0f400f4eae26730dc1640e8c3b63dedd51bd836c08a42988088840e04f1190b082b183d440e9f11f02f1b83f90972ef555573c746740f02c1df394d0678604f588d56046ad8f46864b6429c054f8d51a46a90e59e541b06d8f5888a6b6a0dec0f36c42c62c20e0059609a100f08c8f8896c191b04801bba686153ebdf33015d5f805cd807128c5ae85cfa9211e7d76652c3261ec3eb359daedc828e6e9e91e73b6ee70aec63f058412e7a46f44d11e00170980ba2624147d115bb0052df20bad108f46a36cb448b1518a2112cfa86c7bbef540dc02557045b915d7ca240b0bf012a985652495cea0bc375f483cf754dfc93a6667b34340b03f4f0c7fb1d3bd57508d35f75fc5d7df85e53b5bf3d3bfb1b395df075038b43ee6f01490a81d78b5d148031fa764756576cff1b57936ddb4f094df883ce707d893b7263d806d055f35700576eb40e80c9f8c98b98b7a27715f18bf7eb3650e865f6b01380db2528316a003247806b43078d5ac998ecc5dc4e2d1aada110a2d705039ff456462838a21bbf83c8029c0f6ddb59a19a472739180214204c26c162031464600c20c8f19b140aed3d0b788bf95222022601e8220a4d23391b804900f12e569ada09c009100020f0504300dc5630ee9ab0017033558bdaf65638c2b0afc98bfaf82c6b6a5234101b385310e9043c190c69530104b30281619871fb15bd130e864ed4fedff073fbd0cd4c5b1be7f42a75f045dfd804a000d52098b4c8e989adbaffa815ea0c167e406c2cda705e086045fc9e5b9ce1ad4ab0d02af08b469e3ec5857e564483e844531ec9a2563445bd2be516a4ccf7d85e1b4309898e636a448614821d91fbc740284462ea8be9ed51033c80fa45364419f46fa5574f1e03d03bd00f868eb3801fe0d3861ac1d97a7d8b6d446f8506ca18ff24f58d4e702bde28899983e3fe32742a5fd5ada88dd58bd7492c75bb9ffa8938e833179e04750520eb04eb4044ada9c030c411dd5ba2217046601c0f1d59eea0f69b7d2883c010033e2b007717bf50f80acd0e01047e0cff45300b1a52b5891e49d7c1b7808221f01339513025e2ff46a079285472058d4144eb0b4a465bf8ef8b420847c28bd02bd1267154880dc1bff03bd677e3480803ca3bce763ec315bf500fdbdacfd2eb16391e56b9762f7d460425e0703961cc5c3563c7d6d29fff359688d1e120ce26f675a954839a3b4ff0392641b5607c02e83ed85b15053470c1534157084a083c142cb4a84fa4e31a751b94db28275d2d27790d7832dbe1ff770c5d102c285947f84070cf5b69ff5c2f832af7f7c2780c2e298b4d631ff6405526d86edff90c528b50558d48548e1ea2aec2c2f0eb63401c5d46e9d70018e564574325ffb588839d061a94c1740d60b714b8a33d05b8890a478ce823180880df61c1fd52d9f12b338b6f08f447c536af92157ceee8abd74119a221761582897046143af6dfaf8d4830068b17e8c0fdb1588b0e6a45df9778282bfd19beb16f3405e45018d7e893d71edbda1f811a9f135703d58b4e16f93216c399a2b0017ecb45193cdc6d84b61b810ef21282e8031e5b6c6101f233e90d3830f1c1d12de1d6fffff46304fcaeefd8b615500e4efe6517ff2c60887eefd08bce0703e81b831630c0eeec3481eca72ac18f68f015f0f528ca88d66efccdbbfdeb73393e76668b67f7c3232b5ca2fdad11893eeb5781e31af98bd66cfc5f737e0a6beb1d8b0a3b0e7595420d8af6672a3bc3750bf70b870358888e00cb3af66d8f02e8bea3d094d6eb18893e27a968df4267384e3aad254d89123e185b6165d4fd5a87e861fc0e3571f80a8907eccd634823fc379262393b765c8b43084a561422186ea0c114e84109338582011a999a89507bdcad6d1089012c654104326eff65d905080c0c397908760eff714353101f1a2e34a70cbdd50d46a0140135d0ebb64634d385be7aa391c2ada564459a3448d5c4503b8e443c3d8b8cce5e28881e8a21117fa104bf443c1c4781ff95808f42c01c35c9c6b900dc8f414bd506472c8923b064c3503ad54736c8b1387df30401bc29fddf2abd5c83c647bc3dbcff9f000f878f25ba88f6d2ac570aedcd18b274110a2910b42fa26b3227190e6fd77cddb7885b3fafc5437b28775e0be35dc40bb1fab8e54328eb2ea2773f2253ade43a57f0c8e8b9365aec730f3d8b3f21a1715b6885e63d0d2a3f21a53d3a762d306c06fbeb1059791c76abf42f3dda2600c70400af2be25014c46af0daa295c3eae81670fb519513b97e5557d1e8587a758a37866afecf96aa035a54cefdcfc2242ab891ce542e424c1c25313716b97856708213427147f1d8e8fdd31c5949c6090c06b5a8924814c0428149f529e5ca40878d1c2e5c155002271e2c7f0c99d7790c7c75a939e9fd2bfceafebfc02d35107e13c93b45100f4dc1881c385f5b55436020dce708c305825f68ea57e47509bfbd95780a06d8981bd5e8995647f160467e18470ed347c059c70e0a571d7bffba5d10af2eec168d75dcbc205c735e8f887e768b0f1ae3d67d0b7e0c87048ac81f66890c475ffb099eb3df8883ff8732f8dbb0ff8e77e8a185a07e19438d0c1be8d3d2863590edc0bc86820b5fe0432e0b382b0740803c2375e6de6dc1f9c351c2130c663911140560fb06ee14411495c1890424c4dab189056a96132c086fe9f55611831f64e9eee9572038758364e9e22a7aac00609745a2183bf903b0f5173b3be975530fb7a23d8deb8a9b238f0bf066f72d0f9efefd9b0bf82bfe0f8595000a332beb66cf87dd1b918109a28b0c2b14e8e3ffeebe0537ce29e8fb0226c02bf874d7eb659a043917a14f706c627011fcd73c3f0fe83bfd75460cd66e8fe8b43eb3087e374c8056edc0d8bc3ef06e0e77ae3b1decad027f7519817183190a14f8d70240e33bc57ccd059ce02f10874a9b580f4fc1f7df85c8095c1a23c74f08100c42c083d90bf7c1b4dba00d528d34b6568a83d1c1485c88c6b3041e07516fe1234eced522a3962a938a4dd03c00aa33d196b47d2f41e6d6e84c0dc164591286db53690c317f056b78bee00e85b04e0f9448c6043899804919a9ed99f746a10e1096f337ff008bb8cfddca0940e92162295f3ca4c8dd4c5a607f0449c0a43b6d6d577b24c7b64c301de5a80da6a778c9b06dbc6fb94c37fe5f4fa6ce4ee48305b03bf3140c46118b2e7210a7f2c8f5a94e548a024db56fbc0ab620ba2c596247f418a81481c5c281c3d8eaeda984fd044001775ad5006780878da9f036b35f148e978053577d817ae11faf78c28d43d7f07dbb8fb7ebdaba0477eb4fce0179dce81737b0004660eb06353804d50b5611ad97182c32d67bcd92197ffb64ec42912feb53018028b120fcba204f55534b801ed88593cbc4223e007e98cf1ec5904114dc0186862e2d08470c6d79611d5bf2708ac312c5fe4f5a889484fffc947e236820b60a46f7a46f55466022368402fd306003b4d57247639e4208ff6d01810c61b8c3663bc8730d612bfa1bb6c90fbe8158b091c1d2bc1d7b7bbe60b208b8a0031c7211044e0276505b101bbec661069b2b6c34e6eaecc1b40c02d1856e2f44f12bc85e3b0411e8148d6a6b3810f124b3ddbd2d51d23304f5924573248b089437db0d361aca4608320c9032c242ccda91ed880439231472dc1c2dac21d8605f534873da480b15279934d766ee109bfd1b88b8f26633cf6623c80fb6560dc8d9d671c8475153333c58cc02e85a636956194367402cf806563d9a5e432c5a7a1291566d31300a5aee3d8059c59f88ffd869c02d2566833e40720f689b8b061dfb02101beb385d5dbb47b8a22eef93035050189e6645be86db28875d8c6f40860466ff6160028987aa5444805e41dd556082d89ae87fd52638fbbbf8500d14344df8fd3b82df7281c10080c12a5096980015214e62fe6a87e05608e6cc72985a3806e035878ada05d0fb71ab9916052b73bc0de82306a2ee06b0bb8049bd9404a980ba2a602cb4582895812ae4d40bc1a1c2290c889e20ec81b7e294e8126a205a35296e91e8cfc8e0e204a55d39a8444bcc248329acfd1604752ce8c7bb5b5111f0aab98b4450517abbdafdc94c8c28071839aa6a064a8b1a80a36d73180762536e8903112d2b770ab9aefb017624e86e5823233b03d0fde0d0f6498e5975adeb212ce5da45768d513980bb081a8e49a50c57df5737b99ad54f8bc1ad407a41e846c07bca7f5782475d026886e4d6553804f02dba5a58f511eefe8d04705ffb426f8f10750671024e75f5ff1d020494005e1bde1cbccdb4f3de320d0715cf3042609ac828cf2095238245495c5add2a86c30a148a21814dc4aa7c7ce85f94acea58d5a25357a49d818f3a204e0e061308982c88270c571711102a5e22a16472b3dd204587e81051bcb1b90dc0d0f385a853765048b1045b07f10724db78bdd578743fa25f7b756be301a04195e3305c6f118ba0648767db43eb6cb277b35a3c1510a240000c1c87eba298ec261004ac6440a03e5b76b0502362beeb9b64501dc373ff0b8018758adac3b03ff04683543118fbfeb580eb43710892f331c4bfd17bb7de66060cc1ea10070ad68a440d086f8dd6e83044146352602d44c8420c0137e283fa08eb4d147fa2d822d83f0ebb18a07d44418d8b5078d1d1a0a3fa0cf0086b8c803768d8328760b6dbf194bb708b758597500c17a3020b3113c31aef4676058fd882fb6ada02132234dc60d165ec4afd41eb8b01b7ce102bc6b91277d025b55144d38b414c96b7edc4ed5950d36948c70e58cf79545d8f5fc02bdfcf415c997e2a72dff56f034c2a01c1e005338c442a02c1e109e06dab218e69789fb1c1e9058d2d578129b0c3885f30fc8bbf3b1889148837c7070108d11cd5d5964bff19ac2abbb0516ddc1a814290a9305ec60a8840386ac0ad017035930b5f478af0b22cdb474c025054585ce83ee0ee825b758b3554bb000031a1dd2e58682affd62c8b07bae6dc2668852be814293a105606cc5c032f540ded6e410358eae88b6f6f5cb436425fecf7a2394f0a1a593653b90850e35466951e8b8d8b5758ce3adbe06b2a2ec712376608b4b1df06ed0402bc8e0b8d8111ed8d50c74f38ef72e8a1286646d7f6067c897740263c3cc354b4c14681e3544b122bb6ad04b42af9982e2c0224b6b72a5e288b50ca242bc20a3000efa5da0244ce7425b94f7ee3566da003d2ff77094f48e853c8dcdf9a830c291e01472c01411c52b7df72df073b47387523f27f140272100528004f2cd1da760a2f5183fed547a25da0754d3423e3052b045ce55a5791040330123904e8540a28fbab74105c184e73e1c722585f886c5daf7e0cd48e7e58e8c9c65a2c630a5054be0a4cbc8c2d51acb30a484ce8a8308482cd07480afc07c04613da938b7e308b56c797582a04496ee1461403c75c1f6f22f88a4c2fffd7eb7403d38120e94b0b8d3868105e112a3a042fd3a343ff7f8a023a0775508a42013a470175481f03e0ddffbf83c202413bce73078a01423a0274f48b5a2bcf3bcd5028f15f5d8be9894e0c895e20d03427dbdfbe0c4e08732767543b0c98771f6639044271b7b98a051550888b1c9896a824143c75845f185457681922ee1a16448d8e1b1bf548ef141ef31efdbc45be8de2f3d00902225869ca5ff83861fcff0ce21e955c5e391c45dfd1fe81750a830c81ff6fcb405f5bc351acfb1a665f025e531f491f53cbc807991f464c69eaede53806ee48500ca8acb90cb823960a6f8d8b14a98d0c63a94ae9cf107d3bd076055e36893ca8a65e6ae9a11f595e60468feb7218820c6faa2a834e18ff037bdb9e6e28c704b88beb434680b70c0706adfe80695cae921e6a02591146bcc0c373063c46bffb0372070d4b60a2385dfed6566d5bb8f00c3bd576bd4e305220722b046ebbbd111646382b2a03c83210172ed27d7261ef563431bb123983e91a0065025b1d37001a4fa171af3046241db50dda7309acc5890b26ca9a205a2fd2790d6aa01d4b6dbb152c07eb17272c0f1f14b3b54781060ff8980d3c68850b70ff412c6d41385d08cbb35deae651c241300a303034c045f02c3434baecae3a962ef17108d27a5357986886c2e7225e30817ed093f5626d743b01c609d010e15ba5c369f17f83524850c1ee85af58386be6d6b272992819380bdb1cb281544a982c9be90e6cd6b051e93b1d88a0f0567268a2004d758af49b1aa08b5853df10008bf9418b0e748c197f90dd2a68bd102bd5e88a40f546a5df854adf2beb097b2bc5cb69cb50b7401cc7435ab9c9b36c5b63e143d0cb4104437a475cef724b72b9c3a043187d0d6d7bc151ec17e84efccb4314401068155e97462b16ab63957eeba7124f403b2b7612ff7004df57ad5b6c0844581081855fbac884817ce3440278ebf42585f93bd3725b8f053b7702fd6fb71e3d39046afe1bc9f7d9582bc19ee0bb96801a051eeb138d4effeb3b78a9e16a0b58b30603c3d1e9bf28dd6f5b058303720e83ea030fea4bc9ba65d0985f5e47eb4e3495e85b8df9207321f4f4340a6d892af3f5040590a1b27b230c0447890541015cbc63235a1064c138c1e8088817ca766be10a880a091099e918d06e0dec884a033a5b28c731aa11e8557d617c4d818b3e16f1458f42ffad47c1e881ddea4e38730c8a0388018bb16a0b32ff3619438d134400f84f75d880d1946885e3ebf621a0bcff2f050b3331395e83c70203f63bfe73fad1e1ed3fb4ee01ab23d7f7da1bd203e829ff7eb8aa8d9a618120d26077b74bac77df2ce70122d7e80e1ab7b3c2fd5f425be9020bf6f113e8f3ba4b4f1f785c4e3b9b751511e1c32dd81ec6ed0f455fd5fec0b164bb701f8d535aea08b9718577cd2dfd4324bcba45395e048f762b140c5992913603f8abea0a4ef704721c4898828fc6ee761f8b57fc092fff4f163befb0786d8caeed1623fd15a06d3a89818b21c40d0732c05f56ca0f2e4c159b394c30be508247cb79e70458e97fe0157001236a4cdbc00d96da4b75ae5de104115a0025d7a54c24ab5deea8d508c1f1f32c000d12d078025f604c36baedc4ee8000122801cbf75c2764880a91035a2fec6fbb658cb673112301080f47c214d3749d1b8d2f273c03706c7350946a6851d0fc22dd09f1a9a80fd4f7990e188813c5817e1151f97b61b19fa02d4402ae64c78434a178ba17480a9008a78a46f01405ffe9e102623f8d8d941b0a36b56ae8496930974b397c1d9b29de080f86c759ba385a3402b17d544e44c62b7441a157ddc9e26ce6c1049b8802d0d6899c96721c7ad63b40894bd05ded205d0a3b250f873f8d75ab08127d81ffc72c02166ad4163c846fd74a150e78cc7eb347ba047ca5aa06243a761505dd17bc3e0b13387c025e14639424eff1bd0d4517593944a1bc3d7db708636c940bd11bc05525d0f0e9065a0005e26a013894ef064cf026782fcf83c309d07d1808dc42890bfaf141c17606e8e67c95e8ec289df8a37238f7c0781e21b385a810d6930314db35befd03ca6bc905030f7c3bc87f3e453b54a1b1281e5bf762b87504e00b4bc7540c57e862fc861761074143ffb4252e5dd506bca4f8d382e8757168bad62384066f0d403f68875b49eb157065f3eb30d01cb58a413332cb3108cf86afd20010b29d012ec258cb10a8c93966174e19794cfe8db0834e6eef8c9490d1fb99fe1e411fd07058e586f7b9888d0df4fee97463bf009b607376c6000c4052543f37d83fdf5c763deb0b37202917207584b5b9baee7d50b86558b935b85aafb6bcb9c754e3755fe2db6c4d0c2bc30d584ce002b8816e0138644811ff71cbd04dd0335b74ff11877f60aa1e46dd73f628d501600826c36cb58209357eb040ae7ba43ec38bcfb6f78bef822c4f5b2d45fc0a498bc7d3e841eb763caad8b6ed1e83c65c1f1059911fab852e64c6561e88594527644d156dd6c8944230170d651f8d14504fc151ab2d7103000275a16c84c5adb6b8444a2c1e9efd271b0938f60803e8461bfdfff8456d144b26ac184d1281fc58cc10511fd7d3ea83e2c0dedcc9d7ea90afd27547b4eb8146094292b8b67a69c9c1f999c53e2bdd035028036db6f7d89009090e1f4a63528a0331718647fdaf430a2e45434a75f6327d0b7fa6c7e98768904c5f8918963b50a00ab474155be9fd24c0015a3cf6451002856e0bbc69f704845fbe064484b22b94dcbbc612045774057d53d10d41db02be01575068d86a5705b5e5766fcc52baec05b8e40469c216264547a94c654e8dd113f02a56fa7db600d00ab03a3050df4f805888ce581c814d34eb4ad410809d1a5318144a3c134684b50550dd176a30bd6a13b8f05a599e3505234e51dc503b2c57d09666db3508570c0c0893d19e745bcb201e3c0d811af481c204460209564090601274ca8e380d16ffb89edcfd015f0066e94ad0eb3de0f78048bd980804372ee2ac8bad445732c3768501f700743d03062c741fc7ad208de42ae797ed2e20424fc5a8bb63b6440e1852ddea3fbbb14717021c41f5a27b04839821430fee1cecfe4b1776e0cc0055472789e5515256e880344db3ed566011035c585464d3344dd39c8884403c4dd3344d3834447c68394dd375861a1b071c031814245d37d8604f482b0003fc67f8830dd67403f4044f282be0334dd37513dc03d8d4e44f345d77f6a6112bc00fbc03b8b474673fd3c44f86112ba0039cec604dd39894a44f66112b58d374dfe37c037874844fb0ae3b3b46112b10070c03086feeca1e59afc41083b0039aa6699aaca8302c2824f335dd6b20bf0318145f104013f84c10fb10b8354dd37543f803f4f0ec0ee7765dd777d407ae1faa03bf171703cdd7746e0112a71bcc2f8b0f0fa619cc340f03b0ac9aa6699aa8a4a09c9894699aa669908c888480dd6b9aa67c78dbe65f03cf344dd3750b50034c484440d3344dd33c3834302ca6bbb04d284e110f2403209aa6699a1c1814100cc3ddce01f0ff3d03fc0eff0e69baae3303441750033c480569baaee013dc03d8d4d3345df73fc807c403c0bcb8344d3348b4b0aca8a423334dd3a09c984fd31d66bad003cc4fdb03d7bad7745db76364078682af0b45cc4377e8076c0f0b970f0ea6699ac1036834201c5cb66b9a18142b27270f0f8ac366d935c3bc035118af2a19771a686a3a03de313ff401f0699aa6e903ece8e4e0dceed0bda6d810ff03c6030fbda669bac003bcb8b47efb194d77db07f315033616fb0d0d9340d375dd5a03900b8c038884d37d98ee6d037cbbc503e26cd7754dff58135403be675c0d0fd0bda6bb50034ca6ff079ed71dbaeeef07380392ef071c039ace7c4d1814af0d0308049ace346c8514ef0c03f4f0e89aa669ece8e428bf2469ba6e40473e533a033632a669baaec023bc03b8b4b06e006b9aaca8a40fa003d0f0e89a9cf64bf22b17eaa6e99aeee707e2de03dad69aa6eb9ad2602b5c03585450699aa6694c4844403ce66b9aa63834302cb70c344d679a0c0c0318141073054dd30c08045c03d3344db7fc0bff0b0b0b0b9aa6e94c0b03e0dcd8d4699aa669d0ccc8c4c0a6699aa6bcb8b4c9c5c0b2699aa8a4a08e10154dd37583b7900f8c038894805dd7d0347ce68be203700b6c364dd374036864b0ac890c604dd319ab03817d983fba0139b04f84780374699aa669201c181410b7699aa60c080400fc0aff4cd3344d0a0a0a0a0ad7bd6ec80fd4034bff0736ab6bbab35d3203d00a0fc803b42bafa6ebcee00a7fa407a0039c9aa6699a9894908c8884eb1a066b800feceb740770034dd374af6c3f0364605c58364dd33454504c48d90e699aeec20f4403403c38a6699aa634201c18149ae66b9a100ca9ff0a0a09d3349d690903f0ece84dd3344de4e0dcd8d4d04df3d034cc69ff090909699aa63303b4b0aca8d3751fa6a45b9c079803944dd3344d908c8884807c344dd3347874706c68d3745dd7d23b60075c0358544dd3344d504c4844403c745dd33438349e339a0396d3755dd39239138a078603824dd7755d290f2503760b1d076e6a4cf7d174036662ff08ff0869baaeeb03520ff907f503f1edaeeb9aa6e9e5361b3203d90bbaae69bad503d1cd1e131a031669baae6912b913b503b1add72d9ba6a9a5f60a9d07990338c8014d95912994a6693a130b03817d799aa6eb9a75c62fc203bebab6699aa669b2aeaaa6a2a6699aa69e9a96928e9aa6699a8a86827e7a76699aa669726e6a666274ae88a65e5ab20352d3344dd34e4a46423ea669ba473aff03322e2a9aa6699a26221e1a16126c9aa6690e0a0602fe09d3344db3faf6f2eeea43d3344de6e2dedad6ff9aa669ba03cecac6c2be699aa669bab6b2aeaad37487a6a6a2ff039a96a6e90e4d928eff038682eed01d9a7e7aff0372ff039aa6699a6a66625e5a56699aa669524e4a4642a6699aa63e3a36322e9aa6699a2a26221e1a16699aa669120e0a060234dda1a1fecbfaff03f2eed3344dd3eae6e2dedaeed0344dd6d2cecaff039aa6699ac2bebab6b2ae699aa669aaa6a29e9aa6699aa696928e8a869aa6699a827e7a76726e34dda6696a666208ff0808d3344dd308080808084dd3344d080808080808344dd33408080808083a033bd308032f0713030669baaeeb0b0203fe0bfa03f6f2a6699aa6eeeae6e2de9aa6699adad6d2cecac6699aa669c2bebab6b2d334cdb26b0567635f5baee94c50575003248e23baae69ba8a0386823b1337033369baae692f6e136a036662ae699aa65e5a56520b239aae6bba070303420f3e033a36699aa669322e2a2622a6699aa61e1a16120e9aa669be0aff0707060606699aa669060606060645619aa60606065d03c5d64c040387ae04ff06e94cd33406060603aea6699aa6aaa6a29e9a9aa6699a96928e8a8682699aa6697e7a76726eb7699aa66a66625e5a06ff02d3344d06060404a669ba067003ff0606069aa6699a060606060606699aa66906060606064d679aa606060503f6f2344dd334eeeae6e2ded3344dd3dad6d2ceca4dd3344dc6c2bebab6b2344dd334aeaaa6a29e740f4dd39a9692ff05ff05d3344dd305050505059aa6e94c05036a66625e693ad36d5a05ff05034e4ad334dda146ff033e3a364dd3344d322e2a26221e344dd3341a16120e0a740d4dd30602fe47fa03f6d3344dd3f2eeeae6e24dd3344ddedad6d2cecad9224135c66bff04a6699aa604040404049aa6699a040404040404d3344d67038a86827e5cd1344d7a76726e88699aa6e90366625e5a56a6699aa6524e4a46429aa6699a3e3a36322e2a699aa66926221e1a16d3344db71204ff040404044dd3344d030303030303344dd3340303030303a6db8ace0321781d03199aa6699a1512363d0501345d576492f903f5f2d3344dd3ede9e5e1dd4dd3344dd9d5d2cdc9c57712d534c1bd91b5037fd3344db1ada9a55eff752f8f4523b31982fec6452200c74502d30606c027eafe837d334075070c409a230f5417aabd918d048eb102ffd00cd07fd7b406142b452f5e5a5983c4279a1dc087dc2b1a004001259bb9116f507c3c314f89450a7b456c5f2e8323012e0843bc04bc0489550ed101f0055ff6071bec04905cc34183e038c1e80339397bb7f616c3c38c937c213c1b02b16db46d071812168275587d9c6c362b7750270a1075adb907fd02c3e81b3c3b0fc116db9623ff04c30823025519881b9ee8dcfaec673e3bdf1109e8ca25e82f142df636c30a26230b3b24d7ded76d6505410546030f1f0fc10ec8d8091a75e88049c11d0c634322621110514d3608237cc32b23b2efbed009fe95807d220f7ba7010000c3334026ec376201c3277fe05af1b7b00ae8f42b32c20f3bbb1be8ea0902da48010000129db3d90b1fbf1a2db7f0b653f7051a366d0316e421d858a8101037030608c37e963d061075051a13d2355a0b1faad541666c67b037cef411540b01191b84f3489f3c29a4066136d894980b6b07dc0288cd722ec574fd1dd83620ed0638640f047e1f20874255e881fde11600044bf2ed20c6fd752ec1191b2c24e0ba992c018d71d8e1b8f165ef5a7b430ec2e155ab886bfdd80f28c861fda6e8027ee27b48760bb03f1662a47b6c192fa0c54b32e88637c92153f2cafc066c5cc9570866319804c97324873a2266393b92ed017e20194a1b063d211da1fdacf0fb71e8e0fbc04e73d641242505d720d0e3b0e7bf03941a65bd40ac565487620f8ea20e7b46178fa21316011f8cec19004c24e8821fc877b6155e101f6c156cc11e6323b50cbb5ae85a11a30d639004486d9a6dc11eec0dcc1d2ae82a117e1761e407751e18dc1d0e00740ce80c64f3c8c6f006d0eefa32fbb25740690401b6207e4c9ee503cd116fc4fd34836cc3bd0bb803acfb82348304a0a7940b76c82e07077e88fd7db9fa57c91e824d6c27d9606316aa5aec11e84d22ce5c49c89664c06e3d222a37d8807d2fe826791a0b0622ec736148070803fdfdfce779c9cb862e8ae1fcd5fcbce4242fc2f9befcb2fc5e7292979ff99bfc8ffce439c94b7cf978fc720cc8248fa3f9564a7d3cd89315e837440f847b3c2f43b658938e1d8c6516d8966ce45ee8120ca549009a3dd84b0ef4fbe1f83429e8ddb0c13682164c1751c41c39647fdbb7c01ce8bafbb7ebf83e07b9059f97f885a08ffb3c936cc3c61a7c85747926fb82d5611a6a59ec07eb06037d461a7553e842fbc90fd986bc36fb222330e8b00f1bb01fd40c1619e808d4e3b604fc7f07e8f525eb40f5fa9290dbb02126c439d2f7b20d5b6051fffac016bb21cd201f3ae8b702a41876d9c623fffab88d162642f65c3689fa837118bb245c135510f01f5f232e4b21317b2935b723fb474d06d1e9895d06318b12d1e13fd985b5891c32025c003ca4741201bdd0ff3ca7740e3cae740a3caf2b3c0f74237b6437794500014ac64579f7df7dd9bbf94690743e4a3a3ca574363ca674325237ddff7f2e3caa742a3cab74263cac74223cad741e621a163c6c7249d374726d6e6f01920cc9000148c3c204dc26848ebc3a21173261262108b464420efaf80ca3a37b61223dbf0b7f48f61983a5f715c8bf3af8f53d831f60093517e8d6f58ff52b8c3d75693b63ff3b3dc0f8adde11155689c2c17589c183e10f2ed50ad8150da13e7442017a7b8d06200f0e753763675f639b6c520ff96a470a064d9ab303ff0a0731b75532f6d3269819ce3df54c7689209cf0f79225f6b6cf810e09742bcf200f9f4a3ebf61c4f7b7f41fe8dbf4e953610656ec8a7408792e6bb410ec416d6f34dceee54215087d20ec741bfc76c35a342dff7989087cdb2a19d97e4538b45c84cbde667ee022e80f70157354f2b92d51f3f6e6f342b2b3ad3f0a5105ca3a6eb30be4b5f60cb08594f6ab646c123a89697cb8ecc16e35a0f3bb27e853611a46b642ca2f9c56322506430e4049c16d0b9becfcf55645b851e0b1303be11b1dd50a99101772e1f09c1b9e94c0f5b06cc236780fb6f281000016a08b889ec082a29aa6e9034a2e0efc699aa65b78ee03decab89ca6699aa6846c563c26ba25689a1202f0eadc03ce699aa669bcaa9a8674a6699aa66252402a167bb66bc1fee07d03dae08b6ce55b6e83e8ace50b247334039aa6699a46546a7c8c9a699aa669a6b2c4d8e8aee9dca6fa14df97033a0a0f9aa6e9ba600770037e96aac0e9baa669daee047b1a032aa6699aa638485870809aa6db82f6bee403d4c6b6699aa669a29686766aa6699aa65e503e30206e29689a1002f6e2e2039aa6699ac6b4a2947e6c699aa66958422e18029a6ea9a8f60ce003d2c0699aa669b09a92826e27ec9aa658464ec738db376642d71084e63f4710033a4f344de70e3ee42703606e80d0344dd328a0aec2c8db755dd7fbd8031c0b0603f00b92e43fba416838c00bb2a79053a46b9aa6e903bacce0f40a7bbbc19aae1e03324287f43fe2e4df5471196f239b657450726ffcbf51ff6341646472657373516f61644c6962726172794101c01d60a33003ed20837580c0700b0285df0d32032403d60f79d47474daffffffff214ee09be5602355a99dd385448ff1a8b71041cf7c21b0d4c3e681fed891b785c6ffffffb22a8032dd7df6ad086f0063839040576b9d052240d8ce0029e034ffffb7f80dfd3f8c1936115697c9c6f11aeefff38130fbb53e9767ffffffffa04174b37a2560fc1f52c9576e8bfbe2ffe4e76792c933ae0e32c856f4db9103ffff25fe3403dd62f051d9ca24565051fa96baffcb373eb19e1797d2ffffffffd5f1dea9874f30113334f2b47aa7775625867152cce0ec106e765f78de3c31d4ffffffffd905013595e66b7c669f068eb0afe84b83ba3eec3e0a6dd859d1b471db362603f6ffffff8cdb01fb457603558d7b62e73daf08f3e27156f6bfe3687dce7ff63046ffffffffe6a0c109dcae25a3d75ac5b2a73dc77e3be0c22a63e70de4b5952c7be14d73ffffffffd17bc634f43a34ff812a4d4f2808069a109ee1d563664ec60bb634392666772fffffffff788df8c3ee0bd7d1112ab3386ba1659da412d0d32275cd4e0e53c8d7bbad93b7ffffffff720e2ba164fb31e263b9baad77df518a8af3552c67a53d12e30e1bd3bbcd80c0ffffb7fe4d894a27d4df8a1c95f6e9dba096cf0cceb91eab7880f9a9feeaffff85ff964d0c0e350617369a3172bba9be596f8339503cdc785f360f07ffffffffcc869b81e34660e6333a764a36cfa22b09123f68927167774d2c2f0d218588edbfc1fffff46a1eb5635a3929ab187cef1c99fd39a65e7fed6dbf6ee2ffffffff299becf6fd33807bb453b54466d824aedc2b264ebe39b78c1f6026b692e1ec73ffff97fe9fcbb8fe554ae53b7d29da741361603e0950c9cfad3569bb9a6cffb7ffff02f0ffa85c424166e35ad787265f0f84b45ab56c1344c8e9e9bddd66ffffffff84bb51a4c642908abd700fc939afb543d969ba46297cfc4f2379896eb102e7d7f10bedff3dd7ac616902c09172e184cfd41cb814d2adfd6ff52f7d28e003e215b63605c5e47dd1b1d99f2630ffffff4b08e99fdc30d4d67513d11853d0f98bdf88fe7c393ed63f934248ffb7f8ffd58d90637e7417cc1c39ed89837f1cf7ef3bffaecabf322bffbff4ffada873de226661dfc724b58538f7c93f22e3c5f4e06326598fe68dffffff7108a286a0a7ff5a99159ff166cd021d8871ee4a90a4ce85e064ffff52ffc84a2bbfb1fec77beed9587823828e20f7471ba32b2215edffffffff388d78c4c9c5ce6e4cf7220cc16e55a207a3b9e7cc569af8297d922ac7d42728ffffffff99b51de38523ce84abd0e649a11f055b564063e17ddaa7eb57d98ad5517e86b5ffff7fe1546f4c6e2a8cf7ebac3056b3c3b72c120d2f94431c356e66d418ffffffffd2a66586e6edc0b9f34ddf3c0c22489f54e565e50c04f4dcf114d0c4717adeacffff17fef24ac71dd0e82a46eb3bbf01c96ce13629b2930cf04d15f26c95fcffffffb6a167733ee0d2b26f39037b7e95d4919d93a3538051ee2bb3b3202b8443feffff6f94242738c6d6b8b5976cb964db29c59bb9696bf8d881a56f5052807ffbffdf21cc4ed32147f3fbb8a7f38adf0bfd82e867d0685b2a2ce9f6ffffffff311adcd83ef7029a7d788e017c0255b0093287fcbce442d202379174a0e53ce6ffffffff4da4473418f5ba8c5035722cc697d74a777fb9902da6faa3c1ddaac51d2733fbbfc1ffff15ba65231e9c4678789a999c8e35b0b1854f50d3676c0681feffffffdce79a22b9db71504488d990802404b64f8ba2d799918ccda2b348feb5c497ffffffdf8c4bbd00f79cc1e1a0d47f0396261839613f5b8038f20b577065b94ab0d5ffff0b3e12f61181575d19bf5b15344dbc1055e1af2ec3ff2ff5bfef56b02f0ec67d641b290913c4213bf5ad46f90a8bffffffffffadc5a58b2927db08d33d3d501b7eb3f7c07e996770753c7f73063193b952b686ffffffff3002a9bc3c5b1bed537ad1dfa26f070e72d5ff4c8067479b4d8552ac88d702077febffffefb2f15a68f45063dcc1d6508e872f44b209fa20f6f5c0b5c50dffffb7ed93169292222427ea8b6f0bf7fd93cd7b4d8e2857719b2ec4050affffaebde789d98f9e6c1c2c599b3224cad7a2b8ffedffdb4230afb8cc43474c28a87a3e8fd0cd437c23afd791ef1fc7ffffffff4e727eace12c3feedaab35916b1432b2b5c1c4b591aac4a750f9141640d9768bffffffffadfa2a70d76b5bb00af52e546774289fceb225ac7d271ef403c010cf812de5f1ffffffdbe5ee27115c471e77038813acaa2c2411c2e18fc06c1e7cb6f576f4531f04feff7796f2d39a66133cf1017575697d7ef30d36fa9affffffff5edf66ce57a24e8b191149f5225565064b03b06bf23c927d76b4adc804f62629ffffffff7aa835805f0e38b8f82805cc016342eb562c7971e0852be68e2ed9126c4df3dcffff37fefddbe359a3afaa2e696f977bd0b6ba53942df1dd2f02b5decf68ffffffff6e648478d3258734e45dbb588c93471a0a9988c57213a9cd73e9ab3127c321cbffffffffd7629c165be786c46d953f9b9e3b397eb94477d2457c3a4fa5bebf98a7e152a0ffffffffacc707f45c3046b7c2ef091c150b7440d61edacaeee5c68df73723893214d4bcffffffff9060754a33964c1700fb51675a247f0c2a1fec8a9faeb3c98118ffa110489dedfe2ff5ffb143d11bf08fd5d8501dfe3d4c910854e2bda6a441613ea40afea590c0b20ffc20706a63b0310038b649600b2cd8b61b680338b70b18170b800cc83717c0c0ed67baed7ccc0b9403a400ecc5076db75da8e00048c403c01390bc03355d57e230bf40cf0bd803e46c2cb766d70ff007fcccca0308cd14d3344dd3202c3844504dd3344d5c6874808c987d4dd334a4b0bcc837c3d9345db703d407e003ecf804cedd679a66101c2800c89bd4d36dbab3b9a3ec03f804ba27ba9aa6693a032c44506470699aa6697c8894a4b4a6699aa6c0ccd8e4f0a6e90c9bfc0cbb1b0324309aa6699a3c4854606c78699aa6698490a0acb8a6699aa6c4d4e0ecf8a669ba86043f10031c28389aa6699a4854606c7884699aa669909ca8b4c0a6699aa6ccd8e4f0fca6e94cc308bd6fbd032c409aa6699a505c6884909c699aa669a8b4c0ccd8d36d9aa6e4f0fc08beefbe9aa6e94cbe033844505c699aa6696874808c98a6699aa6a8b4c0ccd8aea3699ae4f0fc081f14039aa6699a24304454606c699aa669788494a4b0d334dda3bc6303d4ecf8d399a66104c03bc0c003344dd3344d404c5864707c344dd3348898a8b4c0d8344dd3ccd8e8f400c1d3344d67df03182430484dd3344d5c6c7884909c344dd334a8b4c4d4dcd3b94dd3e8fc08c24703284dd3344d3844505c6878344dd33484909ca8b4d3344dd3c0cce0f0fcd3345d4708fb1403202c444dd3344d505c6874808c354dd33498a4b0bcc86a9aa63b3703e0ecf804699aa66bbb10031c283848a6699aa65460707c889aa6699a94a0acb8c4d4749ba669e0ecfc08c59fc5a6693ad3c5033848549aa6699a606c788490a4bd9aa669b0bcc8d45369ba4dd303ecfc08c64fc6c64dd374a6c60344505c6c344dd3347884909ca8d3344dd3b4c0ccd8e44de7364df0fc08c7ef032c38344dd334445464707cd3344dd38894a0acb84cd3344dc4d0dce8f4a6e94cd7b49fc8032c389aa6699a4854606c7884699aa66990a0acb8c4b0699aa6d0dce8f804c9a6699ace8f031c2834449aa6699a505c68748090699aa6699ca8b4c0ccd36d9aa6e0ecfc08ca9fca9aa6334dcaca0344505c699aa669687484909ca6699aa6acb8c4d4e469ba079af0fcbfcb4fcbcb4dd374a6cb034854606c344dd334788494a0b0d3344dd3c0d4e0ecfc344dd7410c13180324303c2aec4dd3546470cc40000080640a99e0007bb011367b077900ff01940d1b0a000718b061a1b0474e0d362cd8e40005062d2e61cb5e0000273007815dd8b0fe0201b1771bc30236fec5414303c7efdef1ce0300f223045f0430079004cc047cf21f6f65a0711efc1f98e7daff60f2ba687c192f4400076f03c5b68a6e8998c8072622d85de9aeeb07600fe407420027bb0765758d02760f1ccf761f2cdadd52d1076f4a38078a000943eabaaeeb079a1f5007061f60071acdb5ee1a096c07fd00191f07055dd775ad16bf071437bc07ca77c8755d6973077f11d7074131e4bb11d4de0738002d0010ac0012c3aeebda5d07f400132307f5395807bba6e9ba1b1770076384131798d075af2b7db70e3b07d7cf0728d7354dd70fc80745d89181e807aedb6e51e5a704d107876f10076e8beaba75b12c0788a53407baae6b9a373cbe174407eb2f4c5d54d7ee07d600ab7f074dcdd2d7ee3a038bdf0c07df00566b0710751b41c4b58007d835745db752940782e7a4072a17b0740d4dd307e2c0ad1fd00714b65843d3dc523fe82f0ff4baad83ea07b002d307f90f10ebbaaeeb07fc471c07970f2807cf0f15eebaae3407e64f4007ba001777d7755dd707a5f76807b69f70076a0f5dd7345d7807fd80a497880757755dd7750f98074fdfa007620fa8cbd0b5d60771e57b072d617cd7d0b943bf7707d19f28075ddb705d85df3c078a046f0777c2ddf6761f58d4bf0f6407ce0015ef129bebba07d55784070122576be816ded47fa1b0073aafc407a6eb9aa6dcd86c3fec07d6ae7d1b9af8180704d50f4e6907baaeebbabd9760079677680747877c9aa66be8077a1f9007d9a0f6baa6e91a17b0074bbcc827c85d4377e807f25f072c27e8079c9a6dd7752ff8073d1708d6076d14e8baa6692120df872c07e01abaed6def38d6570f44071aa950ebbaaeeb07a23f6807202f78077497b6ebbaae8407fe1798074917a8d6cfd775db7bb4d6f71fc007f18fd407ae7b5d43287fe8076f8707c6275dd775db08d7077e1f1407b72f2807048658d775173c074527481767dad16d87d70f5f6407e2cf70d75b68864bbf474953c5610727e9baae5c0f07034c116300003e77208106570201f00110ffe79afe0d80002ee97803003a6c0d0a726420c87ffbdb2f53025120222573220e6966206578697374eb9662ff20676f746f206c2b176973727901ba86ae7303661f20c36e0b80ebba6e6105635164114321ace936b7aa701d23670b616839d775635b1b503d760d642d72111108eb360b318f305fba2fd6b58d534920130f4123537dc1a6c27728132d7485227b8b371729000087635df79f00dfb008992a0000316d2b5f132558c342737b031738a92e0d412f60dd003f3a1b11fe7fe1bf7f7451756572795379af656d496e666f726d6174696f6e82759bfb1b6e51676c012e07ff6fff832746696e616c5025684e616d65427948616e640db7b9ee6c65571b4bc1d54e055ddce606ec3300323500d9af4403ddc8e7368575d5c7696c1367d9d63d184b52746c5e568e73802e00dced6e74586c2e0394fb2007fd73576f773634a39f6bffc6a6ac1b6e056c6b22dd22fc116cc20b20f1af64656c14714a64aa29acb5b737af40656368106f6666281e3616e10bf62f46395b2f936deec3355c439b6de90b630fbacf750b93714b78070b6325684fc1bac10b620d6f0b4b74e62cc2600b64710b72f6625b90669479090b150eee0bf6690066190f6d4907b1c146d821770d6c336b1349dedc6157657d3767006e36d916b0650b6b33776eb16cb2ee0b0b611573b36c330d58775827780f732b641d760ad60b671b130b337493f080436900640f645d63630cf6241b67006d0b68c76cd96587645743c76f33b360033670236c9597b0c9be613dbf735764874518ac1b7715760b7351843dd987876600705f6f00740bba49f8b2eb6200649b770d32707758c0f73363237200774237d9801f7327720d6257c91e824d7425cb660b0e019bec700061af702f7325cc0ec32341679397842fd874f10f67e59b5c16e1b2b3737d4f69253b2c6127977067f8b080bd0b6b0066736f6e0073b0645f49e77b340b6b1bb2493878b36c83309b195b122669b31f68639e6cb22f69320b6577700072c6125ec04755e92749f84018af6a0073d7e61e926d25795f552d1d2d8f8031d6754d615309f0906cb237ff693fd3322c21d9806f77b7a3430a4827952aaf9316b0078c64bf370062f3772025fb188f36230d0901e16c7b7a0f1bc697306c1f03680070cb48f66403680b6600669b095b123e5f79d7216a2323d993346f1f66006c0b9327e301e367236d0073ef7400414098a4686b659f5e403aecc1236ea74bc498ec122f6c53686d9e48c2255f6183296bf3058cc93f76271b6348d68070750070bf6c61020181433b6c8b4f48fac306876d006100785b06d261581b4d5b80f065bcc9837400345323d980c061af6823a33e4bc2c3f364111771006cc9066cc0ef6d53387b388447b2656bd9cb654ec91e30076e006f17ebec01e312736b27720074238614100663c7c79725a4076f6d5bf369d8b68408c1c3c777375e924b48cf66af02d2c710033d64631b3026db23763f63af645730604f018763bf77463a8480c33770df69be0c1e11bf9fe3720062f89a111061379d6b6cc0604037782f63ab4bc22504fb68f96b4262c0f874007877790f3660175683630f6dab44acc3021377711ab003e3570f782b70209c40c2c7eb367f658f652ff71f273b9bec4bc263eb6772d76c4f64b2b1016c43731b69c01a90986f2f70cfc978406266e773007797846525a46d2b177d406240f86900749764c9092c6958d777abc2268b6f45354767176058006937fb81021fc14ef37071b7623780c4644f6e0077a76e934dc6658fa7ef37737322493c20336100762b0161c0f87f63fb7243ba2fd8612f37750b316933634018907b6d9b76f7607449245b6b3b4df6803568d7630066176a2134208c3b61ff70931924e1211b6b0387c09ee46c276d6b00314397cd62595f4fe3610d480c08df64f7678ceeb08457cb6a9b75d702764904fb6e3f841710faf161271b27c078123e3300660f66006d5f0983076c64cb310032e778b2018135db6c9b7800338f651010439f3304a406a433ff74970d485f5863700072a77430613c20536d00642f664d36d98033776778bf6a96308c803bbfdf858cbe0c8f6f00734fc00e842523a373cb8154c060786fffb04b48d8724723728b4960401a6b7b64e9803dd91997325773006e6f52c02ea31772eb87203c615c677762006c270d8c372c2f751b01a90f860b6f6309c2807448fb650f646fd890d4037a0069bf6d371213560f6c0064db62b3d9c39248918f670b8031603d660070976df321604cd234b377f34bb28070d9c7651bd3401890f8640067776d03840610787400773333b721058c06668fd781af65bd230ff367c3847049093379433cd925c0789f6d4b780074e0c048187b6362045846c2a31b27491890066e6f691701fb01a365c36a0069006e630684098961236527748c9764c0c7618baf184dc236d175876921b081314be3bf8bb080d4db3f310031430b071209fb62006463776c0c184dd60075fb669364ecc02a61c3ab73972004ab9b790d62e59702d68474708f33ff4835c192774561934b5a120c73a38f5c1201a363639b63b22f4b08235376006fe75816b278740079aff31f16309e6f3257576b0070407a4a48479f690b866c486a643f740f6569c060126364a76bb7807449018b65f7b201eb83bf71233423428281417373b084645fe96a33ab013b836571bf3357d88475094b33c76d3f900a080c6b69f3f87a01e1654b9109653fec5140d70bd733007000868426a4723f6de3343d961410975337fa48c2870b6e0079dfaf6b010616c03bbf4b93702015cb62ab6b14e34b02dfc763b3aa29627d952e698b775853b841fb6f09472429409233526372760930208361db640ba401fb02096e0b636b0dd925913f742f652530b0920b97173bb04ad86d2f5b749b2478c02676237200708f02465fb653630076cbc0646dcb2f136ad3621197bd61793bbf6f1816238699273b80c5592c710b75d7034603d2734b7317620dd88101f7692f77e8845883772eef7f41ba5fa813e753c146005400571152b4326881955c9910ba2d089b03688974e1eb0e10686ea153572843eb1ea8bb4c003b014eeb5703580fff9fa81b3b17570320322b6925392700b1a5ff3fd0ffb4ada9afb0b6e3a9b7abdf46574e474d470f4b574900fffff7ff0519120f0b170315460c120e1b782f4d4b3423646a196b67186e6d694bffffff3e705e5a383077312d33282c797c7a2f7f42040f15094708395effffdfff425659386e6839564a1d37363124322228336a2f2625001a1d081e58eedf45f058470c0ba9ffece5e2a1e8e1ee23edfff7fff1feeaf7fbf3afafbcf7fcfd334b627776636465436177cb7fffffff5d7e6c4c6d7a6e4d607c76787a72507c786e6b7d617d755a27b388aea8f8ffff8b9c8a82b39b9298849c91879b8282bf9c868b8e99fcdbff3b96576c487f695571787e627e732f78785d60796f6ca0f0bf40d4567979747b587c6369387f89f8a5678ba5a1bca937022222342524ff7750ff293f1e3d2d3a2f253a022826212e16222b263c2e6fd0dbff0e282e3a293635210227cb33372cdb565c4f0b11ffff4b5c4c5a6c7c5b50465a45584e5d767cc340bffbffff57527e6051575442766d4c7e6e6e77707e4d40667a4b1d260535253bffdfe0ff3c3a3a2e3c082d313e3930d200ba81a4929195a49a8e898bff7ffbff9e94b49f968b979f00bb80a084c996a4948e8b8b9894b69f888b959f77fcff7fe7556e5e7d6b5d727267776964437e67716a462d1632ffdffeff0513250a0a1f0f111c3b061f091216135d66447e7a776542727f6e57f8ff31fe794d787f776b6e706853764051564d447a475e484bffff37a2eb99a296b8bca1b4007e40585f594c426e4c4d7f7ba36ea8615d63362227a81330222f2a3dff7f29803aeca1cfdbd7d9c4c8d2dcdbc9c3cdc87fffeeffc0d8c8ccc6d1abecf3ebe55393979487858d8a8c5fe3e3e941fcffffe1f7e7a1f3e7efe9e3fcf9a9a7f6faf9b4bce3e4f9fabe2bea1bca161d071e92a7deb0aeef8be8bbef2b195a5c5a5807d1d1d5d2d473ffb7df7f839e9d989cd4c2c347bba495b3fdb5a9bbffaabfa9b8ffffff8daa98b3fe80baa6a3b4baaae4efa7b8afab998fd4d7d0a798988dffff2ffcdf9a94969ed8f194c48787868ec18b818f9f939b9c8cf2b9b6b7ffffffffb4b3e6f3fdedf0fbbabdbabbc0e8e8e9edf4a0f5e6eaace4e4f8fcfbc3d4c0dcffffffffddddc391d7d19cc9d2de98d1d2cac885cac6ccd1cbdd8ccbc3c7cd8774757875dbffffff63657c717c7d1a34363e783c2824363c323725256e2d356d192a0e18ff77ffff55564f111f1f021b5d55001e2d3b2f27b3f7c4d2c6cefdf1cbc9c1c2ff7fff6fffd9cfc5e8f6d9daddd0dcd7cf8cb1bba8acbbabbd8b9bbcfffffff6b7a1bda2d3ba918fb9b3b9bca8a1b7a5b3aab89caf8c92889e998da4ffffffffa7849a829a9694829cb2898ad28ed18b83d6c8d5d6d2d0cdaeaff9adb6a2faafdf8afafff6bba5a4f0a2a5f6ecbcb4bbee0a94b7a9b3fffff7ffa5a2b6aaa3a39ea0a4a0a9b26b888a8f9a8fb8aca9b9b2b7fdb1adb3e1bfe9ff00e6f4ede0f6eeaae1e6e74f5d4f41414047550c47e9ff6dff5f2b8395878989888f84c402850ffecec6cbed6ffd6ffdc4c784c1c8cbad77717f757d623d78715f213d28f0ff3ffc393d79303936e3f3e9deeae8e3abeee7e400d4d8c0ec97ee0abf4bc2d4d097de8f1b8f9598819f94f8f67fe3d0959cae8b8d9b8c8880d49f989917e7e5e1fb11f0ffdf18f2befbf2f100bcafa0bca7afe7adbfa3ffbfffb6a5dda88c9089858bbb81b17fcdd2d6dce1d8d9c9edc6bfb001c0ded8fadc50f7c7cfc2c9addffdff00f6e5e9e2e3effb00e0fee6e0e127272a243e2f3dc1bdd0fec2b0bd3dbcabaf00f0e05ce0e3e1e3f137bebb25ede7e80b051419036d001318041e1ec65fda050d222ed4283c00393121d94bffff8dd833253c3e2c343f3a3320303f3106170e8f0b81ffffed18034d1e1c2570630e0637243f791a2e297d6c030a1fffae7f6924ea640e2269781706012d505c13675b5d43ff5bfffb16705c1b0aaf656d7d6a7e694f7960627562726a7269a0ffadff757070656b4249415196537f7d776a767a74776ffd7f2b0082a9a0a6b0b995bfb6ab8dbfddb6b1af7fffbf753bd3afe3eec2eaedfedaeafcfae1e4e44fe7f2fc0d08febfea07213f272026333d32303d1bffbfa503380413aabda5bbafb9bb959085478fb7c20fffacb5b2bbf1afa4a9c3998097c707130e0afebff40417130461141f073c2d3f2b6370183c304d05fe372d1a2f38283e7c093130beef8e857fbbc096882788a6339a99848396dc9ea87fd3ffff005e49514f5b4d4f61445e585650441a4653948081f08388b1a337b0f1d2a8bd46bb94a374a98d20091cfd7714fc2307080e2f08bdb2a2b0bca5feb4a6ba2f7df7bf0b7b6a68686f337b67758bf3a4f1a6f766a2fbacfffffffff9aeffa8fdaae3b4e1b6e7b0e5b2ebbce9beefb8edbad384d186d780d582db8cff97feffd98edf88dd8ac394c196c790c592cb869ecf98cd9ab3e4b1e6b7ffa51dffe0b5e2bbecb9eebfdff2f04afdfafc00c1fefad1f0085bfff0f4d6e3fff2f9de53eb230e2b2807bfc06f742b35396f0a953e2d2e2d25cfff8717fe1e0c185e3b1901141714348bb7b8b1fd98babc82a980ada40db7ac82dfa0d0ff879c969a919fb9aab51787312b2c2aff7f5be862263a2198e2a8a9bebd87a1a2a9a6b6eba3bfbdf512ff772b869080879f9283db9f839d49585a40eeffbfbfae44580a405e427bfde8eaf0eaecf4e8f7bbf3eff50f37b8c4ff5b55535b54575514504c691d1e4604077ee9adc605444dec51524c6e5c57084c502cfd5b257b02a9b1b4b4f7bdaf92004b5bef6ff18392ca809e824bb0957fc7ffff37f1de94869ab776756c707668645676726471707167246e706cd0fad67f23f5cad2c4d552d7c185cda3ff857f53e7544f53474456094dba003c1a191c350902a9ebb7fd1f130f1b0d56731e2fb792508f1a8dff077eb5d9918d976b0d1f2522203c6024385068f027fc9ab8a6b18296bbae858cb79762d6ef0d3674806ddf958b2a00817d06fffeff91aa9599979581889f8fd29a8684df50596a421f09a235fe565a44500d41ffda7fbd0b687f0d35010113480a8fb1aeaaa13050b46e80eea48999d1e24b5f7f15031b1651061a1e5d0a062fdd05a8ddd9d0d8cac2d53bfea5f7a5d695dfc1dd67186a5863622c66748917fe268b35362b19352f2cc7622a365617a87fab002de6c6c5d19fd5c797ebf102edd64b23cbced854ccd2bbe302f0b7859195dc898ec68c968affb70a7f8b1c6667686b6c6d27a57374a15fa8c57677198b65696f757973ff7fa181bbb76f7a696c6c612f342e302028636fdaff4bc06d7031626c653b204d534945203715d6dbffdf0957696e646f7773204e5420352e310f535631573814d4fe485454502f310e0bc4ed21586a549b4506436f80bf09b8476563753a20636c6f73652562b2375e64d90000a43e73d9258098bcf4da13cebdec464028e3ccd813bae30dd8580437b427d6cb2e107501e8cb2cdb131bb0ae890660603ba4274a13b71bb0aed827587784138ca0086e831a303b5a43343b16b51b909c7c13d0a1cb823f5505190145786974a54670302287014c5a084a1bc16d6d9f4c8e97b66fdfa1f90457611f466f72530e67af4f625d720ba66a75110227d26475a13f8ca011caed04566972aedb2a687f616c4672656554575317a0bdac706570fd2b466903d5b670a6002de443266203f7ad032876656e740f62442d40b05fb16c69636174512943ecc7063bd70dc199757272656ead62d66e3c496419034c0a7131d87601435772a9651c4dbf5b576b10b37b61856574774174acdb5ab4741e1b20736dc44dec4673075468884af5014729779bbd01993f2259696f6136245437544502f9a9cdfb61cd0d5275055180034f7060dac11e425b960309333265c3976d06225c98114e657805830538d8be47546f1865800051fb5b18536e6170736854e70cedccaa1b443c82dc2f3043115e599d42f11f61e1db5ec21a93a3544f6bcdad6dbf6f751d020f4c617645f43b0b0bc31c47edd77a3b39e159ccc001467c963e00eccd1b6fc20300255b1b75032d5688b952dd0ac565f41ed2b98270da35e9416c08b10788452e57c7610f2588fb1d76bf1a672f36451ffc76d6056b8d0edbf565c35709fc504cd88f7d65774f666ed604556e6d11c0761c7b65150008e96f674b6c440d0dc3d6b57053cebbcc3fb7dd92aa03a17dc104ba726d49e826e1696e61b20fa37351ec5c17908c89704535a003d7b6f640fd44d3ab7664a7ed411842b5b5f7d2024807ce6227b4704904cb0d0bcf1805224452dd45d480786eb41599edb7aa915545f702497342546082680f7250c7e58702a6816166e103b7aed0da456e8a4a1db756dc69612e58b087623fa89764bb7418c4b2c0f1158cea4e1d83f370f1729d756633e5da4335506f2c162325c2db3dc24e5479705b6201c54bb6bbd70e00efa526916b65640a633712b6d71a8935098b6fc2761b58ec2bc06368ea670e739906d8ed155fc9df3884cd15a4a36462112c6d2dd88f698c2472294d646fb7282e0642793c0067030b082586b516204d052c5243374ddf78037d950d66a5e638facde6171e4e481788bd045327bd04c12d4522e64a6d5412cb5e29de09dbd91a625dfa5a010f56b5756de1114e6706300c4d7e454844e96f6c4b45524e454cd39e8d75edec3800bf4f41873c0d55ac35725db4720dc42a274aa5ed3b36ff4cb16761ab0db7e01a0fc4cf827414249fdd965a1978726e00b113416371765643a6755d1b744fcd17b3c6ec6ed24b65792a8f137176b060f62b00ca1549992078ad06b92c2a2b84338c1145cd06d90f69f69b304c7a00b71106c2be8542052b7934b61144dfec582400c8130c446dc2614383fc017fc8fd689be90bed6e00e3015dcf6efa9a83e8d62709736bd9cad6d62a3c9d132a0e30ab6e77604b0d7581d97501aa717b6c11f56fcb176c66d65aa32d0102d260bc530e5940602939017d680b6f78ad51494553756241ef6800566202ceb3158ad83b81365a193b416b1c10e69701d213a586eba0ae107695a77266df9a0aea131fb5646a757330b76d1bc91cf27dab6e5269a8b1a3768c30536865e96e459f6142d78039b5675340116ec18bc53a625612c4067bafc513ce233035ccf01e0e56757e0de32f908407bb77716c697a34ee4761c194c96988d5b6022e386a6165189f6327ca26707013483725c0ee56f6546f13734d0147537f0afb3953ba02531b414456415049743d7818ed3a004a8e629d41ec587e00850f394204a473bc2e6b736c47178b10db16621a1c63169f155a33516a250686122fed467724c32101ca432e4e490c6e8507b147217528226e73613bd619cf219315536b9552d9ec8d5853387b0f8b746368586dcd34f6003411419f390e95a56160982f20f90b46c198c15348bb0cadb06dc3f60177765f704374660e6f0dd69a2d1060304dded216b0610332139853be3082e14c571c1a08974c534944ec130a05761b990079010884b6b5df1247551a416f80480bb4931bc33b351106724240e860a30600dac55a17adfb417267761522456a6c7587d57a1b9e746573a3a48320087d48cf636f64fbde62c1ea72d9557c4742696e1ac1fe244f435259505439f5d0b95a04cf6730e35520b46c2bd9f56b13d931162a3459c57070f0c0b20e4e647d71275924e922e5139f7da9e44876ac135d1d9ba39d62dd29574f2c2907acb5d87765733d5b13257013b2ed25bb973d2b109d0f40e3b2588b4f49375d9c38b6b654d50c00a10a65c2c301a364cb5053a34435600355d80000ff0100b22f4100c5631664b0561d00000d1536c2161f2ff71016ec0008012f4a4a560008ecd2219f0c7e7e5f16121ed80f0009c10f7658c2128b0f072fb93cb01500dadb00e0257fc823e1e0c0c1c100e0a85c400e00b00c208b3a48a7ffdb08121615a2f96245bb0760ea5307050b08a4079cd740ff6f882a5067e213302930ffffffff41305d301d3123314931b231413248326f327d32df321b332233393360336f33ffffffff753383338d339733b5332a343f34443456346334703485348e3497349e34ae34ffffffffbd34c334c834d234e434f33402350c35173539354d35693571358a359735ba35ffffffffc035d535dd35f035f93503361436303644364b36513657365d3664367e36843697faffff89369636a336b336b936c036cc36d536e136f036fac63713ffffffff37193744374a374f378e3795379a37be376138673877387f38ab38d838163955ff7ffbff395b396b3971399139a4390d3a005c3a633aa83aaf3af03a0a3b2a3bffffffff303b543b5b3b673b6d3b803b863bbf3bc53b083c383c3e3c5f3c833c893cd43cfffffffff53c153d1b3d3b3d493d5d3d703da03dd13dd63dea3d003e153e1a3e2b3e3d3effdffeff4f3e543e653e773ebd3ecc3ee23e2cf83f3e3f493f5a3f763f923fcf104400ea3fe43f50ffffff1dd505303a3058305e306e307c30b930cb30d530db30e330463158fcffffff316b317e31b731b632c2328d34a034d034dc34fe3421352f353b354e355abf44d137219635ce35457b91369736cbdffdddff36d836093726372d3736f54b3752376b3782f79e37a437acffffffff37bb37c137c737ce37dc3703380938123817381d3839384138a038ba38ce38e5ffffffff38fb38063921392b3956397739963a9c3aa23aaa3ab93ac63acc3ad23ada3af8ffffffff3afe3a093b313b643b913bba3bef3b073c4f3c593c8a3ce23ced3c553d683d83feffffed3dfc3de9873eaa3ede3eed3e203f433f513f813f8e3f993f9e3fce83800655faa0ffffffbf0b3032303f307b3085309d30c430f130fc3008310f3124312b314a315a31ffffbffb7c319431aeedd831e731f33146325a3261329032c032c632f9321633df22e8ff31334e3355337a338733981110346734ffffffff6e349a34a334cb34e234f034043543355735793589358e359b35a235b635bc35feffffff193649364e3658365f36653690369836a436ae36ba36c936383756376537b3ffdff1371d39193923392903613995399b39a739ad39f739fcffffb75620e93a243d403dee3d123e073f2a3f573f693fb6c7ba4ec33fbdb3e91eaccb153096e8bbff2330473060306a3091cfb430df30063744effeff1bb56d317b318731a731bd31ea31fa311d322ac7a032db32ffffffff05330b33bc33c2332b345e34683554367636dc36ee36173753378837ab37e937ff6ff8ffef3710382d3864387e389f38b09708394d39723997399e39b1397fe1ffff503a5f3a6b3a933ac43ad13add3a1f3b523b16793c743c9f3c95dfdff0ff3d9f3daf3db63dbd3ddc3de9857e3ea63eac3e1fab50ba3142506b34ca3052b0f1ff6fa39230c530f4300b311b3126310c329c3257c8def8ffbf90338e339433d533dc33f53303341c342935675f363d36f88e9b36554d5f6c36855ba136e03627f4eff8ef47cc37d937e737ff37173756387238bd38c438ffffdfb0aa4a416a397839cc39d739ea39173a373a573a6f3a763a7eff7fc7ff3a973ab73ac23a0b3b1a39493b613b793bc93bd03bd73bdd3b21ffffffff3c283c3b3c403c613cb83cc83cfb3c183d273d5c3d6e3d873dba3dd53d023e1cdfffffff3e2d3e523e5c3e803ead3ebe3ece3ed43ef03e043f113f703f76d760e1ff1804a76135e83515386238e038c1ffef9a7e0b3a143a5abf7077883aa33aac3ac73ad73ae13a97febfe9f53afccd1c3b383b573b883b963bdf3be4db3d696effffff3d7d3d883dc63de23df83d053e163e293ecb3ed83ee63efc073fd9ffc780d861701309301730ab3cb13cb73c51e9bbffbc3cc73ceb3c043d17a7463d5e3d9ee711ff6f6f731c03000639ac39b839c439d039dc3910e4f8565339f039f8437de3bbbf6c3a083a0c3a1095183a1c3a20513a283a2cbdf0ff2fe63a343a383a3c3a403a443a483a4c3ad5543a58dd7ff77777603a643a683a6cbd743a783a7c3a803a84c58c7f73ddf43a903a988ba03aa497d1b03ab43ab83affbfa9e3bc3ac005c899d03ad43ad83adc3ae03ae43ae83a5b6fa6aeecb7f4a9ef003b04ab3ba1ebeffe0c3b103b143b18fb203b243b283b2cd134077dd7ff8278403b443b483b4c3b50e1583b5c3b600d5dff37d7683b6c3b703b743b783b7cef842b8cffffffff3b903b943b983b9c3ba03ba43ba83bac3bb03bb43bb83bbc3bc03bc43bc83bccff37fc0dcbd43bd83bdc3be053e83bec3bf03bf43bf83bfc0bbfc0c23b00293c2b0c3c103c14d93c9a816ff81c3c203c24ef2c3c303c344100f8ffff17f7443c483c4c3c503c543c583c5c3c603c643c683c6c3c70ffffffefcf783c7c3c803c843c883c8c3c903c943c983c9c3ca03ca43ca83cac3cdcf182e3b03cb42f8bc03cc435cc3cd0f8ffff0d85d83cdc3ce03ce43ce83cec3cf03cf43cf83cfc3c003d97bef15fa9083d0c3d103d143d591c3d203dcf283de3ffa6ff2c3d303d343d383d3cdb443d483d4c3d503d543d5877fe1be8ba603d64c36cc5743d783d7c3d803d84ff06fe3b1d8c3d903d943d983d9cdba43da83dac3db03dbfe9ffffb43db83dbc3dc03dc43dc83dcc3dd03dd43dd875e03de43de83dff3be8f8ec3df03df44ffc03043e083e0c3e103e143ef037f88e18cb203e243e28013e303e343e388e0efe6f403e403e443e483e4c3e502158e54538feff603e643e683e6c3e703e743e783e7cf59bfeff5b8b3e8c3e903e943e983e9c3ea03ea43ea8d3b03e61eae0ffb43eb83ebc3ec03ec43ec855d01776dcf4bfb5dc3ee03ee43ee83eec23f43ef8c3003fbec0ff972b083f0c3f103f143f183f1c3f8f243f283fffbf830d813083383f3c3f403f443f483f4c3f503fff6ffaff543f583f5c3f603f643f683f6c5d743f783f7c3f803f843f883fffffffff8c3f903f943f983f9c3fa03fa43fa83fac3fb03fb43fb83fbc3fc03fc43fc83ffeefe0ffcc3fd03fd43fd83fdc3fe0cde83fec3ff03ff43ff83ffc4741a9963fb0cb70feff5f603004e1300c301030143018301c302030243028302c30ffbfb1d50091380c304030443048304c3050305430ffbfebff64326c3274327c3284329499a432ac32b432bc32c432cc32d432ffffffffdc32e432ec32f432fc3204330c3314331c3324332c3334333c3344334c335433e0effaff5c3364336c3374337c3384338ccd9c33a433ac33b4faffae6f6bc433cc33d4dbe433ec33f433fc3304340c34146fd168efe524342c34008e8b4c3454ffffffff345c3464346c3474347c3484348c3494349c34a434ac34b434bc34c434cc34d40e7e0b137599ec34f434fc6702ffff169d14351c3524352c3534353c3544354cc783ffffff355c3564356c3574357c3584358c3594359c35a435ac35b483bbf8ffbfc435cc35d435dc35e435ec35f435fc3504360cc11c3603512efe24362c3634363cc91b84d02628d0d832fe0000804540020000ff0c00000001000000ac8c000000180100d965b7fc4d5a900003000403ffffb80000ffbbabe44000d0030e1fba0e00b409cd21b8ffffffdb014c04546869732070726f6772616d2063616e6e6f7420626520727507fbffed6e206902444f53206d6f64652e0d0d0a24432268f6cd81fd35e166095bb203676f71c8b2750f6323df3d5ab2ff076b5bbeb27d851f527f7b64ef6963682b9350450364860500d43775db7fd8af5813f00002000b020c08a20c8a7b01eb9e13301d0410e90b26e1d86c770005040100070070011c250b76361e813406db96b0950f0a7b103fc80cc82d61a00fa404608ec006b26000c0ed7e20db02a8372e7465787407b7a1ef86ec8390a20000002f207d2e726461b0ee59c374610f6153006203a627c336dbb021402e26be1a3cf6911d8413080127c02e702865bb5d6ce3eb0006070c014f64b0b37f72656c6f6300fb6027120f1561a74200004c8bdcbffdfff649895b08037310574883ec40498bc1488bd905f8482b3de8a7bf6d85248f0cf216c9ffc744243010dbf68df783642428043a4d8d4b183cc31fd0b16f7a6b3b09ff15e38a85c0744f481ddbe6befd488d14374c8d346041b9083625cb21b16bdb872707b8e5eb2813541e57c6b627e4014533c902c03090fff6f6670a5c2450047424585ac4405fc3cccc48db56deb6891110046c24181620b7637bec6fdb413c33d223fa448b8c0888d5c14c0347ddffff7f3951187665418b7120418d6a014a8d0c964903c8744b8b090648df7ef3f685ff750504c9eb3a7437440fbe190217412bd3b3db6fdb751b47dffcd94584db746403cd19ffff86dd140b1a74eb0985d20f4fcdf7da1bc023c1741c4403d5576eb3db453b6472a3a68f8b6cab6ebbddda28a777412403491c6cc06fdd7677ff420fb714508b04910debd4ccc38bc4bc5808e16f5db70368c970c878a4564881ec00072df81778e1f93f8828fa8f4d8bf08bdae840dbeded6621fbc7f48dfb33db194f0c20c7dbdefeff483bf977108138125ed957747a48ff7e3bc1762bf3196f0bbf7bfb8beedb747985f6746a612f618bcfe87f6ff8dbeb184039442f047563578a840c5e50ffc188ef87dded440c1f72f9020d72e9ad208bd62e160cefdf4c1983cde8b82b072ab42aff0bedef4e0e8a043b88040b38f43bdd72f2418936eb0ebd6deedb8b77602bfeeb8b570f1e05c1eb148582a1bd040def3752c492c376e3ddcefcae5c9c24d9575b10032fb706e56b1826037b28e3415e32948787c3cf08ca100161a1b1ed098bf1e64c193ed8d41d2f189affd1d90579228e8db585f6ef8424b0bd8d0dea2607e7cf3732f6bbb2b7284220e8876a00006a066e8bd11c73e333583837b51b85bf458b1507ed5a98c1050fcbd65eb861d042101200c50ada0ac2b0b0bdfd493bd172ed431210263b2e495742de2223bf24041f4981f8e733d1e82909b7b3195152c45c4053b86e3bc636d9988cd1e88b62ff6d617b7873604c14f70370c24b1470a139f6a4fab966c7053a415a5aa1db5a038018704cc81b17bb21d6616955e8bf17695e8d3776f65bc3cc6b90394c201d7d6ca1b97e682d16361415b323018cc8b1276e1ab03890016fd369e38757415441557041f35c0ddbf6702dfd204ce209f1b3edfb4c5dd8786b275c635d3c72dd797b5060f8e9b6c5d75049adbf0f85f28e53c3d0a03d044d877666b643d3cec520a4232d107eb477c7f8320f84cd2738499229bb1fc69e93f0169ecd39abb4067666ebb0d4dc8b8ba555815cca34edff377e084c2b4b30516b30eb46837a0408723a8b4204dcd65168b742b783e8037689288f717b77e9d0414c00660b1325ff0f3d0302bdf0ffaba3b62bc54a0104314983c00246ca75dbb7a5b7cd39bdd0692a75b546cf02c6489f9ba97d8bced9a2a824ae0d45dd1acdb535f71ac5691350ac368bd1dd8adb7518dc802a3118bd5ed8dc272c61fd38bc2498cd02026f2b5fc6ac0819badbb6d0a58f40c4c627d444622838c259d72c0f446cc739746208c4366c9e941f688d84471bd836cc3d2b157f149ab3941c22dc4eb635812c540de6d4b91ebbcd183d05d70ecee83f221bf66cc321b78b50eb1c24c203937601bf67ad8448a7a6a626163081381a407dc6e3f4a55f7f415d415c225b0db9c77ee020b98fe898017c4ab808dc4b6fdcbdb71dc41c72ffc8c6a30075f78bc55cf702b71e0ea82020e8180b2c6704ef47ebd913b11026b5990a110522f09f9f407405e8b250c9bfa7f7e38c20c3567730bf6932f742ecdd35c628093d701ed674893d21e130f81837b77fa97184a300001708830d42905e188a0f8fd8ae8581680fd2e924a93170b7b1371e74158b4c1a56cdc1490f9e58548d7723f7dacc930b1b44188bfc176eb1df315de8a81a750b3e0ea9aa61fbee1fe9c8ff832516a000c705fc1d0618b9bbbbbbfb8935fd0aeb09483e68eb02e1890523c4aeee6fdd3d040deb4e23df750c9a3fb9f5b5b6e1e8166529412704230f83f7ce7cbf5272dce8012b0f173214833d24091be6f6780473c4b85117ff219005c20b06762b7cb0f33f305f5e41adb999a4cb707818555665ad6157e3a828f70d1cc00954f9d6ddbfdddcf1b90866e70138f7d81bd2211511ab657430126f3b0425609150ad5aec8def230d30e8b661114b1d83ccff1110e1db52d9cc02c4e8f65b24be17ec35d81b0219291dd863a16d4775e50f73470bc122136ea1c127959bbd5eb69d8542148c3cf4c99d1b8db7692111350239ac6cbdf736d9dc35f8af0e3a02d8e82311bb28bd8ded702ce55de839306cee8427e848524cb7986eeccd5c85c423068131015a8207bbb6d66d1a5c6741450ecfc9e89a869f6da7fd18361189268d57018679b605e3481c01462f3c978d20c99dc01629e73d1522169f418e7dcce8712a1efe1bc88b08b3b9b16e37d4a737e5181eebe6c35b8b4eaae88911afdf1b6c73346d6e2e2f2c06751a6e815d0fda04e2081eaa42ed35103b794ea47d8676603cb8bbf63841b8041533a8dda06deee753013559e6cc551e1aad4124eeaa31d0cabb970abbdb21f1253b0100bfe4458df0ede813f7b389b1f92d3b30481b857004466a3871e20d3a3e2c09ae89c781ef70ba002510fdb96bf3bb1fdb61632973d8333d851f010f05dc2fdc8e890c7135aea673d6f107db4ef80a954fe8865f63160d76ecb9ec4580e0443dba75346fb3dd9ec185a45580034d80188c68b1ee0b481aed089715dfc5c8c16491590d5783c60c83fbf685db1bff14eb921f0c5bcf848ed4c41c087c7cf80905561a58743e815035129fb7f7e8035f5e0e68b90da45e122e8235705037a819bb466ee16c0d1b9a0c41780c9c6671028e260c20169b2e86737b308a6f68085d085dc39b9370208948669b6ee2085557258d68c85a200159c25f709b350d43501b895d40e85919ae6e638d70c7d47c48286245409b83c7874b14f6d2f9bd11b903850665e396171fb988b1971348e47f060aeee96c0f6b3d8046bccd70ecdb3d455373714d48662c5acc74f7d6e84a540e395d48106c1806ec5edf674d40ba0a2d894b51a1b6b1f4e27d40583cf86610afaef05b0b4bf3b99ef0eabe6b8e0e8edd030540c139190412307649dc7cdea5b6c9118cbe63bb1b033db70a750caecca621fbbb195c0cfaa93adb3809f8be1b7a388180b74db910273bf047feb7f02bf9b075ceb04151e81b45b0b2cd010b00b98c21766f4626eb6a743a206b0b6060dd1def0feb2ae8bdb7e8784a0b0b58f791e9d897840dd8a45ba00e261ede0e6ce2bbc4fc40d73df16cb2a50a192d622de2c73ed37df8306fa4184548154c125c7d264c670e3dbc114a12ad83e32420ec812fd8b10973732b5f5da2ec286b83495c8be87979d9d0690da1dd93b3246ccccc9fc2ffe0888f2701dd0aad97e819f57761e46c7320c1177a69d804867663fc1c83caffadcdbea97fd160725d86740a1f550f81ce9ded6e047459a5df1b39a715355b77f6b3341fbaf1ffff3d370deb932c0dc2bbb104d3b12dba8813006f3d3758c77e2774e256fea37ff58326c0b703b681c4b25b5bd8e2bda48b9003c852a066f46f9180cb6a6e3cf3e84df470d9ee6cf714cef216949a5333f6d0b1b1431efca40c7084f47ccc6eb8ded13706015da641da83ff18f2b94006d856e8ecf318179f45be9f09e80bf50c8cef8bfe66ef55a3d839b40f000f09766f856e0740028a173075f5f9b71a0fc219cf927fa4a08b8f40b912886e841faac85a1f9125be2398ad649b582a542175a56e81f7618d3c7d8b3f9c2089cf3e2dfbbd30eca3f7d86e541bc98e78f7044fc7c112804181e139b991df03510165564b2b44708443f860f3a382a6087ba285c38c838272a36f6b62b6134256b68f556fac78d291d886fcded0045ce8f27168a0452508f8c040d62dd877a1e8a25500000f5831a4ad584fb84d4d2eb3140beb0077fc03d62d20f8a21e0875f424e872f295f184971a1544c2a1a6dd212fe426a3aea274f238fdd8b9b3193900253561bb84eb440d5ab8ed86149b2acfa06ef46cb235a7891174043c750c4301c3c115e830a9055d354778d88bc1691150da18d3183804b336a25083756d43a07b0dd7206521b0e3b070cab9015be034e47e8181433be0f34b08dfe0528fed0383634e498d430816b74353564061f8d91126adebf82d2243e8e8fd5808d8c4293467f0bdeb15c8134985d274126750f94110668bfd8d511141ffd21171a66e02b4a013a7ab6172f6d4477f30b5a15e7a48735861ab5a236d57b021310f4f575ac8211bd8515453ddfd240732c8264e196a61400efda0896110910cb8f1ae67535618be601dd97228f8d8086439d3b86e276e83a5388354f64c2970972e743eed748d4a80157e1cd19afbd6077be0899d28215f405bbddab471e24db838463f88de3b1ce55c05c0b6e8ccc745c0160edc87d936579ba70dfa3bb319f8c8443b050824107bbc85edbf7ddddb74172fc64439126831c159c004413bcd80e6dbc172ec527a04431b48dfb37ecf624402a32008a019c31f6bed05b7387bfcc2d30faf45339c0329f9d32911fbc553f9d08683bd38cd8e1f2c3dfe005dc8910002baa411e087ef6a858003eb50fb9b816744ec0d5d04b9c3dd593d124ee8005a955018d4c62527891164799ea2f9b1bb3038279ff8670f33ff78db84236381010ac6308ddb908e9d39e6349f8d23542de1de58899520d22f1fd76c266251f9261d4d476e7bbbdf30c4053e85398528d60c11b9d06e0b4c0f23099d08682711ddede1b985f7008b0026430506144d476f7f6b234a10458a040941030a443ab68bf68643a5507c3bca72e72db748dc015b11bf6b8d5d017262abc2a59548c1ecd31a5c90c0716517edc6f8851e252c0fd0cd4189048e6bc35b2456ddebe8665333c95d90db3e066d833039c80663210cbc3f2b0d69731f6679f805279e194c6d4c0376239c6cbe349e23cc2e0dc785adf4083d94e2230fb698037049e0f8c82bc8e957b60cd3a1d4840fe0579eef7702d0c96297523f25224c9c75cd78839fdb1aa7df9d2c46d349b75f6e8bda16dc4e8e67b7db29d946f824c5ba6d164c1905468b907f487072763f685e5b5dc3cca90853126701f8683bc2d0756d0fdcd76f2d8432437c68acbfb7fad072eaf1e2dffdf7e88fed6bc78a8c30a81c8a5404243aca750ddb6e2fb9016c1072e8baeb08f9c202120f0e6dc9fca0fa16724d0bee3d955770cf008b096debc4d61241c2320dc11c3b9e5d8138f9217b11c7b27111ff23276721c1c0453bc87e424963d86611bab8e183bc5e4c005c757d971631d2edc1752a7b2c96826f8c1adbf11989145a4594b44d220752529c907b90019f192c1081d3c718ec7d22c6c9f20ee17ce802092e5ee9f88b0b07b871061be0ce12fbf89bc730c0628427dee952b990529edac0f199eb68a0c7a380ec08b18e8a902fe8ca9ca1bbf4187b58b9f4593300e6e00d5357c4780741b9b93c6bb1dbdb80e9bd1c29f99838d0eccfbd126b9814e80d42e5c05bb572e7cfcb057c92ecdb25dba57fbdc62820033d7b6777af8f58cec70e8618e8e30b641d1c764118ba634f9a24704057a23f0cbb23dbd44218b889447075f67cd0357699215753457c4dc7a6c67e1c70bb3d50a6ba74498f708cbfbee83a4ecb8e99ad9540077773630d23f66d6860583df50c7ec01378777ee8963d1bbe3dc4bcdcc8edf43f9857c8bc308075c28c95505356c276b264778e85300557ec8e9be556470a762811cae8983f2582053b7413faaa7311e330a11b10fc369316a0c32a267baae33b076337538353f29998bb28075b8605e970eacbabf183c0cd7d74368905a30705a1177a48fdbbffd663ca794489fcc1e81e41330769c06589076c03c2e237e82a628d8946d07cddeb0697dc9d5b2f69350c0f8ca333c7c141f708b7aeba3b7f621db84715dd1a1ff69bfb768b480443084123ca0522d1e983e00113416bfaf60483332d33803406e789aec29afbdf9b4c3bc27cd38b4a04330a2a04291774ed7a3382742f8902dbba7ef76ea37b83c2044883d1ceab0e330de91667d50b733b350d9c0e3905fdd6bf6f8bfadb813863c18b0c81899f4bdfdede1229df0b33c80625ad583ad7e0b69de6b1070b8cdfff0f1e1242010bab89f2287f6d7ab1b1df56dbec56218bf9f00d2db051f083f271f8448d4b01f412dd2774895df803f0b038100070618166e2eef083b69645c7068cc17689f878f0932d189f69ba03806c216ca60cf499481d44200db6779cb33d1631ad388d530274c7dd3e1b2124691b15837d6d750fc07327f121bb4010180ee6a82df6602c0bbe6882361258e0c560ca615f5b1527f8d793833d5c1f0bb6cdedba631d92d6753f830ed3e3c156faff0b45a8017409d1e8352083b8edb5082c18b8c1415975ec13c4027fb054a195d1f94f72d1c7e0d635c40511100097d2728bd285b641eb5b0b421aff7b58f085b66c0bc1c8d8a0c1e90844eef636c8617cde9382f7d025b7443984c36b7c4d90466bd130b7069801635c9a6d0dfc5d52398bfa41fec245b7430314fb37b1bb4402da61cb427a438804084288140917436dcdbd0c0803ca6b150830841cf91dfbffcf75c967488b5a88918899811218f5c35f746ea21069bd11e6b4845908c0db2fb416f3eb10408469096de8a47fb111df3e3bc30f46dd74c467c1e305dbbdd10b38570c42dc330c4604084ee584237062338a38b994a7ed6fd87e048bc5eb330d5b903d1600098075242fbdad7c0b061c2f18091042521d3bc3300f843475cb30a9de43334048c750c4e17618b480705e8b3003d41636d43954742e5e41cbb171a3b72f2e95c50c49d205b4703bf085309a6800084a04dc0d9b3b4f5c3223f043684d9af83bab3b3c0d631d8c731b8b4b6021b6f7846ecc932a6d5bef0ee9370c2768185657415609ea8a2d3e1825423919c641fd8a25ee7279080250377558d8224835d103d020085c9cd1c1e898cdf2c193cd0d97d1170eaa2c60e870109ae285c331025544b014196c5bd6ecce3c0f28417f5d783707b5004774444593777081e1d84f6d3824023af6d8c9ebf4617fb4481bd23e83e2e84352fbc691ad2b45417473830ee8ed0fb5bf603ff0476884628b57524e80e2d686ddbd02758ac6f6da4751468591676d4e4af692286b145f68b706aa576803598d476045e772278df628b6922330b77708b16145d977eb1b51f819d273c225a6eb02f36870afab024408eb8fd5ded68616a826496020d89017b8500194f2894bf58943badd6ab7e00353d8498f4a40034201edb66305478f751709e4e43dea25da444f420684890376306615830535dc474d4e242fe69cdf91bb335eb0328be4329915b82ce36c2252027d03604162cb6011bb74576cef3ef4db68b92633f64253602e40883402b8d4b656f67cc11bba8dbbc04b43844e3c7cc6020830f0ff1dc4c643610266897362c74364106662f0ac13d8c0206940fb34914cf0328c813b7ac2a390936d01ce04182b22800d23f5838c925125109190821090707e6d870174514ac3871056b8b61b0a4820034027f0180b5ea89d8da8486ea0f156b58f4bda029105b7b4386d8722a5be5dba414e1684f8a5be101a3f92c680c3ace9c6039a15b4ee83daf6b5100c77fb4bd06366b26c2e751f0fb7136e66461b8db6ef560115f8130b709c7001343a6d10453f205de9e3b6793d4c4310ba34910e2935e5ea02dbc9ff430f6c7bd20dbe1914d0450bda4c43320b017ad8f0fadb2dffc73bfe72d7548f95c0f498ec07b444246ca2fc9380ad812be5170335da4c767bbf338dd82615d003e6483e5d3858e0d5fe0de9b48e73289091afeb81366220902d2763af7b07bb42f1227c2b8ed91db6d86f2c394b08766b27822925abcdd1d22016135b37cacbd8efce1822db09327b08733eebd1bfeb5838133c735cf460b2623feca7d8c1e220b60bd0ff95c6f6810811009cb266909430636e6bc671d01263960e918622c8ef955d78080c0c3f138360b5552ad09217a413214b8feea2fe22c740d0a5914303a6601725c9bab031c3d8183715c802b15a58f0ff6a4bd0f0744f4d2521c61d3b174b4de02c3f780dc50a0834c631f2ff8fa805c86e946b80985d3cf917ba46063bf661a79b8f089a6c9a248e24f95e676c87ef6d408c20b0e8dd4230e86af820c1b1706eb89088480f44fdda56ded8813776fe5c74052f83db9281378bf6752c8f8c1f29ee16818e706bac0fa20fb755a5d896a84ae613282f045b0b3c25379902ebbaecf3f560ba0df416f6c5018ea87dd3ece9387140ad0ec4205fc3cce290a595ab6a80f169f64091b59f8eaa445b7afa1abd54ed394c251bb7236ddb42444e84c917864ff9fc782b6d130739505074792a4c483575af3b5c4212edfb637d205404d8b4b745c7efb0a8e0b999e335e1e72c26ab1d1d6bd99418e859feeb2d8942d7c5061c884e2b08eb97563cac1b0f0318028e6e38127c08a5fc8d314eff1b82b9c167fb1035dfcd8dc1a7cc6008dcec8004d7610d191de39f4497174acc08f54b8e60e0287121023b28458d95bfeed1f8758072fea4e75589437070c084102e8eb700b6b3daf1b68d9f681c085c70467dd983230d62f56be0632b3030c8494f5b438bd67818030a3aa22e3306900ca01042207585d8a5591547dcfd1e39931506367f74b4d67639004bd062db351f8d9801a967f6405b73541c8113526790f66b700a23e5a80339998989ec584dbc9d0a3f8c110c390ff0196255ab02dbcf0583c6c2040f28771613f8ba2e618bc5e07d461f7cc02c2fc3c83548acb1e7652c3c8ce8278459c04dc46f1a118d85bb41b90484562c8c03c88dd587d281861afb844f01a670f0ffb4e2e4f6daa70b20d88b2ebee07e3f73b6ae59a5b8b247fb8985c8ddedfdfebbb705a3168db5313885cc1441f026d06d15064f607526d06d36020a663357988a7e1bdb800efb8ef3e69d2d741bfe6da2255ac6f59c750e75f181ff0b1603fe370f8d8cda51c9e12d68c1fbdce8263d4916be2d180fc575165cf37851a9baad02039f45a056cd06bb7e63c72f4c8885288263d3412ff7adbb0ada7747c4fcebe8633f55c37c1091e88ec5741148340e20029f2f1875f47349b744abd90f3ee150e9667b2958fa5df369750a6641391e1c02ba60b515a88bca28cde35e8633e2a48a5b5b4c33880b3c961ab01699700a012462c0455d07d2bf8b4f238b017f8b103951340f83f26e8b4a542842b667eebbdb6c8b0c0938895a43348363301089566ab733a93c40b4182f8a512b0c70fe0eecb9046e862e7afe086e2cc38a3d65730d9a45373a27541d2865111014b50823b0cdc028d5b2e77b33168b53511686837b181c0c17b74e74531032b2e8e6688b7d8263eb0c9ff5ff530819721e7ab6d07610403bc88048b30b6df05443071c3001d9b6f4bb0506fb8909038b894bc13cb010eb820e6e1658786012f1a40720805fc373a45b04580f035010820c818918a86c3b8b9b7a09c1833d9f5703b819130ddfda18f921700c8d0d24acee0fe817dc8047f3ea880df3ab0297d43348ba89ddac50163ab43d0def1040bbbffde8d1410d38235f8790e86aa5dec3f359072931fbb601d74a1cddffd63b796483bd1f15cdc9164467aa4c1cf4db8d94b73e8b9d1e81c306c7925d0a601c044a44d0b925dd598410124c173f6a2230c2cd77e91002ad643d136c9996dfb01c0b59e05ac1618102d3a3aeb8518f162f48951c1b89eda40e2973d3e7501496ee2dbc06eb0c4ffb115814db700847151d0dac1d33db1ca74603ff388d73028b071f6488528b2f6ed4ffce1f752200280464009a0e305c36417dc7a05f94b886db8b4c5992913efb8d0d4c7617880a58ba6424e0c020d5a788ac1b04e35817eb7cdd2c08247fe9d79a89080ddbc7604eccc781b76a00ad839eb5565608197c090a31afc0e81839a3eae9b9d7aa57a71adc74dd809b5bb0412c9b1c40cadf08d1d12adecc70e8473a8dfadf92d196dbce95807b1000260a8d5e3724727c02b58577b9ddd80248b5110106402049100ea669ba5b300741200f403050d6bd699a406050704903c6126006dc1634dcce111740b7487bb0dbdbcf40486e411066e82a0bb12fd5a1a5f6a4bd6d29bae8208770b003f89387130b043358a1e71a104949dc821c05870afa8679d03584e0c00608877b61053f06e9415e5dc3cc670017c8744c339c68a1ff7b8960e182ba6800fc7a998bc2492bc505d88ac792e7148955bbf1800b274de7d8517d0703c89588a63747077d06a2bb390c19e93ea9b84452db837837544e754307a210b42d033b0ee2df0a81e2751533ff40383e522fbcfd85c61cc74103ff803829f58d471463c8e814d84ea0193a17664cb889bffd0dbf0e8a0c32880c0229d7493bd072f2c5b75bd707928b4d37491943452f3e2f755a6bdd1297c94b89141f10ec06efde1875eb8b9ac703f98dd7e8c6d635bae662d043f5a81537ba9560a9424920c9bc328488dbe66a44425f4737174d2fd8100de4cce713a78844bb5b8d56a8555ca872f01f8b5553a91ddb474c063f674c03f13eceb65b08e41127014228096cebaaa142ef1808712f06e53af07b040700374dfb8af5de72bf6d4266071483e90374affcc64316f51bb92dab0a056a0444887b160fc8132d85c748007b204d051c221553bbb5033ed0a7c042134c760d5b04b70d0af7da08c76283480d2cfa1b28c3832ad01e958a6c7dac9be996a081af2a35253fc29cf0845f442a836e13486a3323c357b1030bdf6ada8861d4146438df401783b14b4c8d47dd2468e02b97570c3f825c8db46b78eb2b4d62105dba08d5c99b1d64db18eb0e0fcab18270a2a46290a003d12003d1ad0334148a1ca71ce4d63b272a85ffa6268413318a018fceb24bc5eb0bef1c838c24464dffba3a08b94f3ac17573f724196e0f07f00575236b9baee9b8eb07ddff7ec83bc10f87ae09bbe6e9a450f72582fdf8067532271c5804e98f1447be1b3426e5bb07228102759797b7b7051a07eb770903757208eb6d0a75dc7ebb8b68262875620f03eb5d2c02787757bd6d5d870ca62834471afeeb42b4bb0bf2612c4605eb305e07bb7b1e6c431beb255b06eb1b1665e0079fef115b0cb80c3b44d880546ce10b2a40f34d2abe620354f48a8d4b4da5f944493c2de8d1b00199f7d584330042dde34d357f8b8439580a74270a7de1ee39940a14766a471c07833b73b845e38d5d4b0c48c0e7d44cedc61629c00633e7731013c18ab68df7ebf7b04841a51b4bb4801cb505c9d1ebd3f4b781ed8d57021fd17dffd5321949896373172af10f084903870ea59184f8b675c80fc314eb9ebd364213581d20015cdbe3eb050378b797a915a03606b0e00080c16bf1b14197434d67b567770e47c35bd51d31bee8d8364a0f643494793a1030c70e93ea823603442d6f1811d60760da0b6834aedf991ad4b9ad2bdf154ebfe374a2dbde0a0f45c77d7d5a4c2c50a7683af747389433451daf8d406e286e2a481124a0d77c24263611e11d80579f4dc797e966e91c3209bf6d8b5dcf294de024b1b308b6c07fa1a4244dfad48bc3e7dfbb142f1225b9132351c26dd9414b7b5f60041a9ad48bd6f5c77e7ba001876815951a78ac04b4b1af14746cb86e975abc3ce8fa2bc6f20430270ac0572534a796abef83b339243a376018307ca7ae7b35758030ed3c2398a1b3b348e202680bafecda6cb18d94de390f888bc320112b21cf6f96329ce2480840c04910ea66d8fda18d53e35810e83dd27d998709cc05a37b8d46a060b52119da3a9425c358cf25859542c64122434f1db67a0e8642b6e4e890b0f78cb87544114a021e19cc78474c743f48fafe676d29477d89313818762d0fb61014ca5083839947161a819503dc91daed7307c3eb0b0e4e4eb2c1741bc0edd0e206ef7dc5126ec1ba0a7c7f0b509f82218beb5657876e799b8d0365f0003832fa124ed82ac345f00eaf7c07c3036dc74775f0215d7645301b6ab7631342ce0b8829754f09be7ec0e1bb0807f14d30e8e1f9022ce07b4f7234103d4cbb4ece4cc5883c4b14c03c630fffc1c32d86fa60a4e83d06388e61039ed041b90945385b084238c9cb2e0941de05eb7cf13a5a0cdd37ff7e712b093809c65f5e1b203a8811c698d98cf405c1894f6b1c8c2c589841854fa1d238c19f62f0c2c3e83832f130111b5b26a9309418b0620db0a19320ed768412df5890e99c41004f9bf6e7601d75dc77974a51b001288e7de8cfba0e806d31567e56cd140c683fa1a9283cb33e429b3affc88277378d4e40472fa0e94088744ef6d8ef1e9a22bfc2b001366c7266c44b6ce4e85e2cf8ffeb19c01bec64eeac7c08ab933cb1904f35d003dd320c5404222cd1b4ddd000276c400b86e8480565c453ed433077e87d2d2c62bb370f8469003ee8e28d40f243ae540a4f961a68d4af7cbf8b9c8d83d69021567df305052812aea1223709faaa6b42dc969310a80a7b7cdf7ce2c738d84a7b08e85e2fb963107c298b435527c353d815c596c0e5395fa856a0b9197840071de1c841c99903a97ab68a03a4e8de24579711e4c4628001520c6376c448715b60b934e8bb140df03b288b3e3b3d97f27ba2f096ade062cd4db0d16eac894cc7863839c8d809d439577f189435586cf0aca9628d112339a648587c0e2a6b0e1b6c7c0623eda00dad2c0bcea5edbf08d001f72fed75368b1e0bf1a4db9ba13bc3742a730144234f7b7a461c12720bc1ec79c8497190cc437b30020dc684067747d91d6307bb2e647a37637a812bb8b0c5d263bd9df705cbe8e787ff127ad824cd352e347a6f70ef42c62657e8a5e6ffe1fba3fab70941b028b214c74308e884323c7d7b2a1ee880e31c58207b6cbe2055289afa194ae036c8206f250a373e2bc188d72202ce75e7906fb7500b8c1fbe10242552d1118d4fe66fc808163d8d4601c847527435440b4c78185b728d4517b0c750a35adb36961df930ea02e134fc084f5f17eb0c02894d0c01dc7d7502f4b5b00383f19d106de136ca0dd0488b064059d1ff5fa0cac745404a985f4ee88a2ccf6a8b4831c522e8fb0c4ff1d8839052456c3f216251a213cbec47348886c1c0206ac24be703c8340c4d027675e5820d5045eb20312b17b54493409e1f0f46ecbff0f646740274184c8d566bcee8ce6fb31287e40a5f5b3bf8eb06c940b1670a8b9527c6bebd213777108a484c0d5067632f0cbb130f6c60022072ee6124ef506020ccb0679b239a996658cdc303411999b0f8601384b641cd4ccb6338d363e91ad4e18417d2ea66d00e72807cfa1072eb10ffe3f0402e400285a07771ab220bad45446778000011a10d025d5559b776b0d84a421a4c91a0775c40bce5380366503752ff002e118683a55f769c2594c3422d05ab9e5798071425a43850046dd5c18895733b38fb02b7072329053c59f84c43f0a61138b8a8196ed3e6492bc58242ab760805d030eaf6a7e254cb6eaff22900000f215c0b0ab7c69b2c317bc54a2450073041bb4ccf7f4813e36071905844445cdc74d0a81a34e413f218dcc0c07e284c24404323ba0700318b871090a3743e137ec73e17b902788874050a774517f4374436458bc5baff010f07f8bb18391b1dc3c6440458ff75f607e5c274c0dbc6de63bbd735099d5c48076403504fbda6a97034bc48688c1da8438cb6382289548722069c2365bb2e26c23fb0415014aa9047e0d80097e273ee9bfd003a6d86eea817390ac47ab78fc8453c83878b9dc8ed68b8388bd713110d15839e8fcf75e4ca3e8186620300af98cff400416d633fe6ebffff434581020d7361ee40153f8f3176823ec6e942bd4dd0e8ebfd7e8b0975d0ece8fe3835b75860a910d833b003aa63c714a1b56f09344375f54c0783e077bbb1fd031363c60d8c450e75f18851394663287e22826f141fe91266df740cffc2bcd5cab5ae0a3c23402afec56ead20c437558d9509e071ab0ad58f3d2e6c48152c660db924851de1fc38448b31288048cf7460425c46453736a85c03dc318d8fe64cd1ee2042601dd7e0d3e8af467dade4df0f13e3ffd7a2a5493c1cfc00ec5f20c0b7111e8b1b96f0be8985e804d321518336d1a7ba840d61188bbf033b2af18d932b6260b25952c61699be271fd6c3df739258cfde6fb081bd1f1d4d701741b1ad85e742bd8d651bab18cf757e318545b9da09c0ef74e40a72703c6c77aa80cd92700c8d72f01d6c9573241745b0686ac7de6e8d4530e0f005873401ea31fbb16fb08000b93e53f63952d08d99cbadc20841451daaf6230b9bdf4224de86dc23e4b405900a248d8d08a1d8702818500a2685d83e6cafb51274e42585e408db60f5e1ac40024f8374de419fb8296178b91d141c2ad74404739f3b2a8508a00b3a8348d5eff4c6a28556430600788378e80b45ce19cd960403c13d11268bfda07f73526cc67163d21bc6745d3d153d40cfa886113dbe9072e2d622193ea52387581e4f07c67a9792cc7435c40ec213833672f59d72e36087a16098c6eee1718a22bff8aec4bca00555c0a84e597b89de6d44cd010d91fa87060f8684f0b146388a220fa00f770cd8d92f3e408b886feb31241f14ddeec873101c803e12770914188b76d33d070820e902f54dcfe2230401af8b053bafebde1c071254a9b705310d660bfd8ddbad4cb29e700a32dbe50fb6d30fa3d627f805a2ab956683c14166fa219cab03018722c715bbdd7e741c8b4740a84f380347301af8f60b70143a9ade73fec380fb04380b966eb9d474f31686512cf76da9b7e936815b93a7aebd45678f3a30db67a1ae456b6b0fe3076c894224a3903b270f6feefd78f7b9212af127aca2aacf734e6636436c07c300aec047b4a5b38eb76fa8344fb717a8dfdd064ef71f17ba193a96245d0b564dc9e918200738338c449671b7c0a35d42b1ac739140d449e805377140ff42317e234b019cb9405ad8d33fc1c2f218f11f4c393f752f6681067f62caf71f7b438d53e2d71b676d40d76e970475780b1a8385281107d13111597740e9fb6f624084f3633fd09ea8e8e81fc0078b48db2d80a528c220fe1e45b60c0863dd059f54ba113fcf7f4d946ad0ce654bdedb426375457392ce07aa33d6c1a1a6d7013e1406ec2d761f4c8d148ccdba153f8ef4d97f4074564d8d4e24ba161ee8c71d7dab75426e3ff1400fc18630093b12d53f89768b07594906649010183468a05be840f6c620665f62e518cd2e4d02dd868518a40a330036b1f46d62b087ec90c17c4a2e6b05e0871c9093e51ac817417106ebda84f5af6a3bb3347788cb0eed451dff43ee920cc81484af08743816a3aee744352d387f3dc8803c13381046959c8c1c103830483220cf30170803dea205e71c1c01751620ab1ff0864782f50016926cb121f481da3201c001be014f93a07067181b4429247afcc3e482ad25686a1cd999f43988647c171902b6e63efd77f712060b8b834805d0898424b831c0e87088432f35658bb8456b0776b7437c5b6bb5a249d4114a6689207aa60955dc0959317b7b58ed33ff6e3e7478ed3d38dd72c4f662f72d350641bc718b1721300523544c2325b7def869b61b83c5087d7f0849c175deeb6ec34cc35fd3484c5b3860ef8033c59930bf4720001b781795686ec2b76d6eec750c4e471008ec5d7cbf40f043cbedb93e7b1e027a0d40ac3fde9fb841618b7e21158d48040f4441cd873a55931d4c2aba7e8d5063b023798b2b4e644d506837875844728f98b41247df930d9de4f3f46a8e2715fa786cdf58b350f78b35c974210744e883895ff01ab09dfbf1938811f04c2d600d9f44004c6366afc0860d5317bafb507d0841ffcd2ea4246f5074fff6750545ce7e2283fe01741d37af93ea16a36d8328746c1efe0a0a0056fa0d4af3db28f3c5de57577621b71c6cb0012c723cb789a32c3a0123ffc6908b2141c26a601f236da4f8788db141bf53d958bc279bef0689395a1ad1f2e169460ea5625b19835a65f00a3806b4791287838918a3fa44a2662ad660407e422ccee837161180063021120f4982a50ff1751fff1b215023c18bc71d40d7841ad82065e19e98abe9896076e44ca8f30e0312b1070ecb753996810691f8d8be0c230f8583ef3afdc292e1ba125134ec13656fe8d814471ae9556b05783ab390d6549e00d939d4cb02139a0b1e8534d52bbabea2dff6780504de5322e467de0862df7ad7e8fb1a35b8e840d3e00288d038397acf99af144f4c58ae6621f6d8df4a0135efe94f070562dc751f30ec88dc9dc0d0e048c090ea00dd48c6a8bee207e26924a57f8fe0564caf344fa71944dc824031044d7f842388b07f671826c5066ece5b4f14e83684eb030e0af6cebc341aa70000426807d47d80b2e640045977e0d17b142bd89e09cfc6e3df7e45c7897d77e849116c043b1930ee4e36ccf0dc6d4d89265f9197f171b805f7d700a1f8840baf802258053a14fce68049060d1f81f7316b6fd4a8fee8e3e70bd3e5e22c3abd89806057ef27d8085f660819eb0a97174877740f813f3f3ce87acc1604879be433f0409b15f358c0566613f712eaa7f7683b7460918300cf6af796dcd9fcefcf0c332fa31ad36c858a4458be2bbb41fb620736e38be33437430a21ca740b67bb206f41bacb44b94176c7a7f477e10b4463396266f7e8e11f80ee8fb1a3159feb1619393b750de8cc1476156f6b1b4f4c87990d760c87d8c18586667e285c12a81b98b511980084888e48312bfaebbf3601b7178b28d330752c4768dff720014b6ee867648b628178d21dbcc1aca142ba05a5c7038634c28ff7fcf6a42ba50c083f35ee52e88d12ac0ec217e804942905e871f96866043c3b12deabda671304a468a860c0732cd28314d1d9e92efca2f10e79d6cfa467851566279730cbca8330580d60021cacce62eeb926746ca7d7803c0765809c048d257c40a66f6097412246cc8951d176e7303183268435c73cdcc6175b4116fd98602b0f26af265c032a3692c933d66259be8b394048c8853973d29c0c4c58fe4097841328205c2f1872a61ae15f112747e98b9bfe80b6693d958d432e73a6a3c1418a101ab9897c2c38f6249de8ee0de67bed1f0963003c8864ffdc600f28f2e47966bbfe825148e051791727141cb9b988f77809ca959e0510a380bcc555b5d2831a001c85426c54d7eeecfbd75da36c83ce9bf680671467561bd402660c0bb00cf9128a74a1da28944d06eda0e1010e76ec27650d0ba5d365fff6db6518fcaad58cd7657b2e703e167dc2ab230dfadb874a16f658c765b90829d890a2ac63400b38914588de652088bd70a2bdb105e86be98b1063e2889fd50a40ac6207140d7b825977a6e8570bdef0086e08f5c010d91dcc175f6cdf280f6847fe5060688cdd18d4684b66383bc636a58703c4cfcb788b00968212905e9d443c2c1cafaa78cd7a431786ca510733020fc24df73644a50e06d0e8190efd1378ee3d428b85152b150340b80f62424701367b8fddca32f7eb0d2d148b8526973a08867df7878334293feb6c8f77320a7d620add16590fe121c077622e453bed0c85edfc751304f409befeeb0c9ad8199817e8108943c69582070fbf37b91e6691a15eec770400b91f10801aaa103e78e03917287244744ce7193b090f6432d028e1cdf7b14d435570b9290d3f49c7c702ae5002821d459829266ec1c0401994497d986130788b5f6000009170b53b3920bc98e8a409b2ca004841459d9d06bf7c43493adc709bb595b5c02b89bdd85f009c7564408638545510a4889d02851a9d4e56bdd7f3853171520d605e0330abc1d7b5302d2a74dc13e95f04f743fb5dac3bf65875088b35eb099a890a612d1d21e014f84a4570c118c5825da9afcfb923fde39d5570e8210a14aee9c4c3eb807f998d57c4441cad77f278606b40031b43bb5f499b40f70c22cb052b039044dd48b16333ce6cf19eb1194d2570a3534162010d8b074f61b6189878d4fdfb26e2ece1f32e824b3973207510bb670886804ea2cb06166046c48b5cc7bd9e3c0f1b51cbe94c44fc5fe66221c71d45face20c4b1ce0edb5fc1091c7d61813fe203fbde6a4520be27856ec1ed18457005aa13f3380ddb718b9a302cf889754f75404801307b6975db4560012a861700be7f5d58e831408d4ef64dbd47f58b582eee17bc0b6cc93dd012e892ce2b8bd518c9fec27545a81c0ebe010021ba26000d0844f51da8507523dc9b215eb40d98a820ddc9b8a53a07697443439080d0d7ae60f79dabce3f36932dd090af5d3e90fb06da70f632a885be76f087b925c07c1f7b013d9755b0b9260d2f236e45a1c4fdb5f0ee1df14e06f00316d4042c061dd84d02bcc949277e0836588828a178e8cf07db04b0fb53d63c75b0ec45b04d904f0e19d655152b9d610eb016244a84faad808c200ffe750bb80200d5080bc9adb249d495b8e84ef825b906acd016d2542d74632fbed8700111e064c0e6e886ed61d70af01c09ede6f80210d678c62eb808140c221646c80b52bd577c1dc1152e57d7243b19c55e758f0029884380635c285fa36b58c40268d0508d048cc01182f7865c404d7783e9451593cc9560069faa73fdd4809841ffd6ff201f4bc002509c864dd4458fc0eb0ea6c68d26fbc2cbff28b8b388ff55af8ce304ba0091029c615d1a26e0c1f794ec218b50927232c8d84de10e103e1826839c0c2f20200a2d6bf53b6338f3347bd9cb35e8c032e8b40b9e5c0b3a0b078176403a5341808567f1811dfb5003eeb174e812f95d93de4f20ef02750687bb0a249ef5d64bcc8d560c56e817ed255c018c0772b254ac08430180b3850e5175fbef2dac8e45ac2e34c3e29a378ab40190bf5ea821156c8e655e0f4492238e74f8410f88eadc601fdb825495e2111400000b3cfb3aa0a504e9fd2a84a6ea45a013edcc196b2050a46acc86b84d023dc45ccb4c2283588646a007fc93cb4dd2d9330683c8ba6b221d4ca50e187ca26c33c9db5a5dccb63b81ebb129eb2807592b7385dd5650753227373d890d04e4c9e38fd95ae857bbdadcf4ea82f7bfc74da0a2f7eca5ff5b000009535c3366ec601b870d9830a85a12104823759085955a7790276eb0fac0c58383409d0f26113c76905e6e5a794fe3007d2870838e5c1100780924894a591fd7b60b38101d3f400640052354330ebf0d6052c085c016fe0b5a98b6e1494def79e8e2bf77101d3d6d11868af759f883674ebe085e2488c31f9343ce3e42c821106639e4e492a1a61844434e2e397f8420804b04a922605afaaa910b14a66bfdc804d81910ef840b371c40e61bbd013cc86d440b23210972ececaf32759bc1c6970d07cd5c94633b51d217a5e38c75045c682a838896e552d008228781389cf453eccc052d92e8b1d30fd5d9a62014893e41110b2a3802c458c1e2101b2bd843b9bf5a19ce590d3a71a0f583a4684c63621b00a7b86f8412e8573dec9727cacfcb54e84a010fc4c6769c1b04db988020bd9f85ff7464062a132c1106ff371b1a3234d72df644433be1f2b03e1913485800007b5cdd77c94b5e50dd44dd380b20d19102a240061b1841108290da0a02f173300933ffa2d5b1e9b9c30416b856274f04a560533944f9ba8898506ccf560035b2284ef3c32f98a818b0dd481d9423865443ec78f6503b97836d481ce8e4e506156a7d2523e0960000c46183ef13662bb4633b929600f7d431201c208c8d441b21169ddb280931d52d47847b641575618b1edc8358e0f6ffeb552b4804e3d34c6036c00e4446403b16f52488cf55da8b7c1db149f8f81eeb12ffdf77d0f6c5841f059a95550119617b2cfd6c06e0600b40503046c5b31068d083c2c3bfd3d5190a36d502c416e856b03d562f5bd8451ed0d10d426180007d57152f5a9a7f2a84c562173bdbed80007360f3188800ea090c81fa8d02559e451cacd744d9c8f754d0014122bc4950ae551d5277305e44da29b801395144fa97c0015b352837be37d17617964449a2ccff0b2bd302ea1782adac5334900acc448a01b899b60d3b3a961178c4040904a67e20c8e48bc2437737081ac3ca2bc17c94c28b12c00c80c2b0db150dd510209df90836001c33baf1bee0065a3c6368e871d29e566cef5a1536e69f4d03c1413108682370419070330a6c4005c2940325ff765b80c7ef1f5128b3c2104503500841d7adfd547200771e2d13c74018855b742de9380c1c41305ba803ab6a275530543440b2e88548ffdb03f1aa5edfd2d83951307434837928549a28be8972084144eb0a8bd1c05b4cd82a33c231582b6e5f82dcd14877b7770b8b481c03ca06855b824a765c9741256a4bd7d9f397821d2ceb8b56eb134309f737980a7e950070f8eac9e88f8fadc15179e0e30cc291c7b6ebdb3583ae04752f4d0324f62b01b1453b547b1074158bdb4950a3b6fdb866551106d0eb7401dba5a00f1160bafd68205b36685b48d354f12ad0ff4dba2dce80143a138143e221fd6e338bd3810dff0e75df7f807e842775397b0c763483c102e87e7b18c565d07e4df63b01742e8b534b1972cc8d0f6aa9c30336558c10a321a8dcc7b65d040fb55320eb192d0ce037c6824d0f3a191088043909f83aa18ef1e20a84bc04627774056a890e208bc73ca88140232f68e08217f6f4d1d556412462dee1a2d5081ee3bf3463b000192844c841867c61fb75e0bfe441bb16f0fc39197663b44b0577270441f74a0c0070c51ddd2f3819eb514523ffd1170444232f1ce143f203fe8b74374e093908a5da5b8575752c23cf41aa2d731bfe08b50e0075078918b7ebd23f1c7b2b68bf0fbae113730412cd23cb890f8667ff5c4d46bcfdffff897585121b312ce295db0073c89619318c885247cbaac36029c360fdfb93226e33024774fd87e0176e6c29793a766dc970088b572855a38df7a72df4c605452ff6bd14e845cf26bc1340b7bf15ce54265c03d789028b46a04204027161fb8b4e08894a3c4666420cb6f0c513c01bd6cb6a101fd191b8940e103e0a0f0affcd71c7ad47120177e0d6e9771929e958bbba4771571b4f341a76ba9aa686ad104e234dc023909158b8993b3f1c1f9afb9760b804a0ec98b381828355dd0490da00639d516c2a1c6c083c24c46776da108ce26431835137c812e0e0e194686bce18617d5c5f5e471241f546b115552be90e8d47bc6c2fe8dfd13dbcff9f000f87ad22f316308076508b040943b3afa1b8ec832a1f0fb4efbb4d05e6e8fee3397e28777d0cfaf7c2d8d5faf0713d28eb6ed254cdffff49513b29a853b6c4d146a320ffd7d71c85831a5906cff6b673cf50e8b04d0e39795011e8874dd1ade8681b037aeb1d054fe848ae71d9ec81504270442396046d0a8100065083538b78620840b0c035dbaf2fa2f129a220383908997ebb54bc004ae3c0410240383875f5e8631b28b08e8216d1e82c0253bdea902a72d02719f4075027230dd0d8e91c003b8a4bdb4fe95003b1b50d3406ba3ca002b7287da04110a451898ed86815ba303e62bb0728fa7203ef8bf81413889fe94689e7994fa249981f019704303a4e00914872298568ca823bf62c395a201a8e1b1c44b8ac827f5c1466393223c004cf16236734703801a2097a34fc4c95ececcdd53128b9e9fd8c84cec0b641707e0c474d4b6308495047f939f14e31c2209b8536b69980f205ee901d08500ad8dfde9015664491208718ab48bce4c35f867ba1e1e828ff1af06d7e24ff76685c1fd5e3fcca27b6123fa71a7ba823d729fefe3ca2210488584063d041356cb530820b5a588f8e1fd90a834c1b13ef8d0e0ea80cc2fd30c3211f42c233c916117a4e24a1c97e6689344f7f48df842d6501bb78ed0d0deac1177b184e450b5b61f6381a740d79067828eb21084f2805a309e84304b8412b7227b390f4c984853c420716ff020c2b2cbe5fc3cc63a3458e68dbdbd04ada70e856f02db8149508e7e90a582202bf87e9037cf508ea2a5820a9e95883edc21394684a4401757904d8da0de0cb755bbd0a41039d8a3bf7b63909070f02d0e87f0a17d044f7f423d52bd254492bfb664572a50ce0db56fb83c302421d6b45040be85304bfd8ef0153c92fe846433774cf0c881fe2eb7c45ea317410bf11bf13e244e9f3781945fec9c9f75c321dc2ce453bd1753d45bba3a9e8c93889337f7e31416a6e494ef6e803a1dd03f503eedee01902f796d3e97cd4f4ae450bfdc13f0f4fde410824f4151cc3150fdb08b3c4d51e91c24016b69d9275861296720f109603b616e84963c0ca3f04c91158a8102eb2887690a8ff075df16647891408c3ccc765a822049a468cf4b1b44fcbbd1facc73ac1d87ed4557cf56563f0104e787112b791d3c7a7133c9041a21a7c3bd6de8d718006cc62e153dc1ef4e86ced32c37f05e49cdb7604eb4557fa6bd2a6515ca2052eab75f739de2a6c7f4d3a9a1fff00ff7bebc5cd25bc7517c6f614380bf5dc76dd9a6e97803bb7eb0431190043768b32b99f5f5b6f56b6736467ddf67246d13ff74410815d6c087479b20bcd3966157bfe74168bce1437d4e21363358d5b02b1a65628af0b73914b7307f5306ee25e5bfb50105731822602175332f028681ffd387d1980d474730d82601819b8945505803630c8a7304523d531fb413a9b673a7d88bce6c6737daa88e8aa50246ac9c5753310cf92544cd11678c5a558786bc6aaf87dbe0837539f58a200aa1379da9bd209f721001ea849001af6fb24466836da38ce5d5bc3b76527700841575bffb8d896aa8ddff7cdb806df562ee4105d3a38c222d08e129e145d299c9001f9c71e25c44bb6682783c0b94c9e7e584bf2c0c8d2d17dc8a48c641f30415fcad385a5070d83f80b9c45b554b8204bde40ac12b11a30f35f2eda78d08b0cc09f5d1a2760b8bd99895f0893eb05eca4f603c6c8ea894f0cb6dcb877a3647af0e1232b7315078d4dd4025ad70fbec69788125d0cc893520dea3707b444bab87fd93bc0606beadd72130541027611dd102201b856ae21e1e72bb70c5b226a14cc1dc80ebc05c7dd4201ebbbcf86db612868d4423e028695ee5ad87f040bd2d4cb4c03f395be2f6e85580294406ed18b26a06f1b92320932c96641efd86feedd0c121f480272e01bf846881c10c34f0db9404eb2612f635fd0ad8350b8ff8f3353669cbdddba239bb60e33c80d890c525ed10c297a8b0b891c4243e21dc063406683398b720fb99b27e0031feac247eeeb3e8f918c805f9e32480c602c3a1639e746f3d80f014b60494dcbd970cce0ede166013bc70311018bc781b718a71974605f397547676c1805530f5dbff40b14c6c12a214e62d0b8bd427ae5fc0658ead594bf15033af7e148c1ea178081c403b6384b7709c4a417ef30f0fd0b01378db6fad83bdf7418e8b1ad2fd1b1116bdf8bc31bf7f30fdf9bfbb7af06d92bd803dfe899177a3d868f86351ce25bb977069fe008730cb10e11fb1156eb0a5cc720ba8886c9ea5c8383bf547031e7eb83fd027525a7a034ca5c45373977c4462b017fb8dc8d480dbb5a05e24c3be76dc4f668755c41eeb70549c2eb1ae80c468ab67601e8a6c158f7f1a7072b68785b08df410cffc542d72088ef0a68c00e6149ffcd7583b5734404601416145f20100d125e30ec8c26242a6330ad01c0d140eff94e2201f483746002e9b201e8aefe094f8082ba43c147d53b836ec4225cf58304a41419be5784c60cb7f775034507601e026472ad5a18d4207c02bfc512224e8ae41f5033c003fbf0aa9388b5221e41cc94b80b8916412424d3636f283040100e447b756996aaa578aec7d7c390414b1fdb1dbd8e75538d58765bd917a3a348af12520918ab0f8ac7d9250de2a40d7aec18770e41b864dcfd4422c5eba06381d290596f13f8eff26b25ac0f1073d910038115f01c7b5d6b67553ba22f2044a3b85b811900b98c27d968a1a255d95a0876430ca365f7ee3154dd3d7c1bdd660424d11007267b28bfd162112add0fffc28a4c056e8958e860413072fa97d73c69a1966802eae7a17884001780e12b8068615643469a2f83d2808f07eaba6c68e06323c06d148cddf9f2eb06ae6e758046579e10c40fb75db4c04aec9ec553f724428b718cd8b65415481e53d0b8282b0c0b4f30d3225237f3aa0612c5cc061800c39f7b352a50918673a4b6ed06befbe2448d6b22f18bfb0bd302db32410b95340bfd307c0bc31f860f4503d01dfbd3e841233efcb62d851509c31ac30441ba1f063c300ae702de1bc1e81f02180d6ddb8d5403edf23032dd1d31db5260dbebbf13d543e9506f04503808a7751670eeb684450eeb2422717cb6460b6cd479e9fd78084cbb62ebd0c0d306fe4203c51516886d25f85a69cab80b03c8f25aead5d7e91f5301b06428af5b58086c585fe2322b7ca3b114e2c28081f8000d57e10557e35b0f97c01a688d175a5744a82be0694d03c6b5dc871db60005c56c094435001a7180b702b8eee9395fb541a91e796f53dca0afad025e8629943012d6b04634288887f6554d8204fb506dde285ad0551c00c241f60ab72fd18e98f70484ba044484a746ec3628f1f913047431cdd51bd0e8a50d3e8a0c1083cd714361153b8a8a22d188513c02f03800ca05f2b11bcba07f270b8a0000d8bf6ae8ab49a843b0b3a665c202b009514df40e301338d69720b1c745f4040f5543a4e21f8b8d814d30803301009dbe688bdc294c1b4a13ae1274eb21f60f027435a727eaa8ddeb0d8faf89211361ec13b9a2ce55eef9424b4890016039de6f08d70070f8dfba2a9f9d6c06f776f8a62a0e817d6a411980f0ddb110756c83a80b6f83420eb108821ce66dce289a2255508b44ee414ca80be265a2d03a8158e0e9794853f1042ecd95588f540ca0465081d078674d4b4f03d84174331a3d466f08df03f881ff04218d978a3ff7eb3a0858c71c0ce813bce8130a3e78b1750df3c7491df690cf003fa2405c75055db99a640b541ef1b22fba02460800c230cf3edd609f50f1ebcacc0055bf2b36f6f66f2be5515256e8002119ef210000e707c820830cdfd7e5b0213b390622ed17af0741061964a79f9707196490a5c6adbf2a649093276f21675f9041061957658690c1866c6d172f0727410619641f172560876c90462d17ef20ff060b32c8202007e52eecc9410621982117af196490c107a79f9776904106a5c658211732c860176f07675fc820830c57658664b00b3b1821172f0727904106191f172561211b6446d817a7830c32d88f07877f7761830d65a72807209f061964b0071008006c12d541f81fc7079041061980787041061964686058061964905048403819649041302820649041061810080827071900f81e16ffc1061b6c0fa81fa0071bece4c9df260a27fd2f9807d890c106b537060f20830c3698079088830c32c8857d756d0c32c820655d5532c820834d453dc820830c352d2520830c321d150d300e21c85ef7682f06393bd817cf1d07c7bf19649041b7afa7649041069f978f84410619877faeff604106391d1d07830c32c8686058500c32c82048403836d86083f1b7280f2007c820830c1810086c480e214f5f4f0764b0201de01c3707d090410619c8c5e641061964b0a8a00619649098908885196490417d756d64904106655d55904106194d807841061964706860061964905850485e78729041563f1de81b36d860c1c70ffe1f2e07e420830cb4dab81b830539ecffff1b079d0c32c820ad886f32c82083675f576cb0230bc75017480748cfaa1af2f822257f839c1c2c0711268ad61be4e4203a278b0547c8206707fd1a07f5ed20830c32e5ddd5830c32c8cdeee6b80c36d860a7ad0fa007982cc820839088c71d24063b780fe76729236cb0c182f7175807fb5f5890c31827ff1a0720830c32302820830d36c8185d37770791c13ac820abdf19ffb0c12e8c1967d80fd00741061964c8c0b8830c36841dff0f0d878730d8209007f5ff190b32c820191907649041064f473f360c061937dcff0fc820830d1f07170f414e0e3207ff18f7d8604709374da7450760830c323d35af47830c32d8a7079f978f0c32c820877f7732c82083807870c820830c6860588b610c36bd97b55f4fc820830d0fb99520830c368d07857d60c138c875ef177707830c32c8dfd7cfc70c32c820bfb7af32c82083a79f97c820830c8f877f20830c32776f67830c32c85f574f470c32c8203f372f32c82083271f17e120830c0f07ff16ffc820830507efe720830c32dfd7cf830c32c8c7bfb7af0c32c820a79f9732c82083aba37fe420830c776f7d1b1b6cc8e001174f1f4707649041063f482f6c300619279d279507d8c1061b0f170707ff15ff839c1c2c072e162610830c360827080700f80c36d8601ffe37f607ee32c82083e6ded6c820830ccec6be20830c32b66f67830c32c85f574f470c32c8203f372f32c82083271f17ec20830c0f07ff14ff60830d16070017f80f830d32d8f007d73e1fc7830dc2600f3d0f3507c00c32d86017b807b09730c82083fe876632d86083e7770f6f0767c820830c5f574f20830c32473f37200c32c82f38b5f7830c36d8170f0f0707ff0c3258b013ff07efe732c82083dfd7cfd820830cc7bf6f6720830d36c00fb807b0830c32c8a8a09890196cd82088470767649041065f574f20870d1b47a7ff13061964b007271f171d6490410f07ff1264b02083ff1207e790410619dfd7cf60871064c7a7b70f830c32d8af07a79f970c32c8208f877f1bc2208377dbff0f6490c1065f07574f90410619473f37410619642f271f07196490170f07ff11c1060b02ff77ef0f061964b0e707dfd7cf19649041c7bfb764904106afa79fb0c10619970d670507b0c10661fd87f5078b2741061b6ce50fdd07d53b39c8c96b1163bd13530f64b04106ada5079dd860431895ff2707076083053bff10ff1f0b17063939d80307fb10f3eb1b6c9041e33d373507c8202707cb10c3bb60830d32b30d27050793830dc2fd87f5078b1006196490837b736b1b6c904163bd37530f6490c1064b07433b90410619332b23410619641b130b061b6c90035d5f55074d19649041453d35649041062d251d90410619150d0584c10661fd67f507edff60410639111107c18630c8cdc5ff0741063984b5ff11110c32589011078d85196c18837dff076d64904106655d55904106194d453d41061964352d25830d63901d15ff0705830dc220fd67f507ed0c32c820e5ddd51bc22083cdc5ff0764904106b5ada5904106199d958d60c31864857dff07c18630c86d65ff07c3186490554d45ff0c32c86007352d251bc620831d15ff0732d8410605fd0fff0fc820830c0f0f0f20830c320f0f0f830c32c80f0f0f0f0c32c8200f0f0f32c820830f0f0fc820830c0f0f0f20830c320f0f0f830c32c80f0f0f0f0c32c8200f0f0f32c820830f0e0ec820830c0e0e0e20830c320e0e0e830c32c80e0e0e0e0c32c8200e0e0e32c820830e0e0ec820830c0e0e0e20830c320e0e0e830c32c80e0e0e0e0c32c8200e0e0e32c820830e0d0dc820830c0d0d0d20830c320d0d0d830c32c80d0d0d0d0c32c8200d0d0d32c820830d0d0dc820830c0d0d0d20830c320d0d0d830c32c80d0d0d0d0c32c8200d0d0d2cc820830d0c07c860071905fd0bff0c20830c320c0c0c830c32c80c0c0c0c0c32c8200c0c0c32c820830c0c0cc820830c0c0c0c20830c320c0c0c181c2cc80c07cb09ffc1820c3209090706196490aba39b77396cb041edf7e5ff0bd8608305076b27630760830c325b53ad27830c32d8a5079d958d0c32c820857d753bd860830b470307fb08ff649041060b0b0b208305190b072d830c32c8251d150d4138c82005fd0aff0c32c86007ede5dd32c82083d5cdc5c820830cbdb5ad20830c32a59d95830c32c88d857d750e36d8200bef0307fb07196490c1ff0a0a0a649041060a0a0a904106190a0a0a410619640a0a090619649009090909196490410909096490410609090990410619090909410619640909090619649009070706830d1684ff074d27450c32c860073d352d32c82083251d15c220830c0d05fd67c820830df507ede520830c32ddd5cd830c32c8c5bdb5ad0c32c820a59d9532c820838d857dc820830c756d6590c186315dff074d41061964453d35061964902d251d15186490410d05fd1964b04167f507ede564904106ddd5cd90410619c5bdb541061964ada59d06196490958d857d19649041756d6532d830065dff074dc820830c453d3520830c322d251d830c32c8150d05fd830c361857f507ede50c32c820ddd5cd32c82083c5bdb5c820830cada59d20830c32958d85830c32c87d756d658631c8205d55ff196490c107453d35649041062d251d90410619150d0520830c76fd05ff0505830c32c8050505050c32c82005050532c82083050505c820830c05050520830c32050505830c32c8050505050c32c82005050532c82083050505c820830c05050520830c32040404830c32c8040404040c32c82004040432c82083040404c820830c04040427070b320407ac01a40c32c8209c948d32c82083afb374c820830c6c645c20830c32544d44830c32c83c342c240c32c8201c140df2ec208304fc0000f40041063b79ec00e407dc06196490d4ccc4bcf87f9041b45e518f452389551ec64522f18a5a02ad0224a0aef5afeb06837d1e40250c4068a97a6b6e8b25480fb68704c05b412d06f75e5a5942c5d803f3071929ff7d0b72fbc42b5dc32d1a002c400125c795f83113913f31d2f7f1894413c0b6b032017983250117aef1df3e08047b0ec1e0064801f0482176fb878d7460d0c34483e038c1e8033b83bd5b7b16c3c392997c233e1c0289f6b62d071912171205755bdb9c6cb0995329050b1075da89e8f202e85a7040cdb6cbe6b4112348ff05c30a2236f7b2270206e8d9212751b1b745d85cc30211450b28bfb16f732256062e0534031140753a216323091d75e88c28bb992114394a24c70829c1450d11517dbef05d36c32e250afe98807d220f9045a8ea86be8736814cd8b16901c329940bce7d6cbd0be8f8fe93341ae8103b6cb0ed0a02ea5a39196c169b1922cd1d3cd76036f7e8b8340511710316e461d858a7101f3a140642b21f9640061075061d2691eed61223b60001475fb39dc1ccd700114d0b01676c10ce41a33529ad3b84d9609aa10b80077707c28f05307411e863fdf6062cd9846d3b521004ff46beddef0be86ffded160022b9fd7b318d84614be1fcec086383c3892f01dab8ff0084631c166fea6c66fd86e4240fe101a255fd4afd606f003de89e7ae8e5fc89bcef61d90cbe53166b9b4ee47b6c60de4f34e86439ab8fe490010661e8301c32807c3377042ddb93e694fcfb43017e210b42733625261c06eec4bfc6423ac9fb905e43fffb26ec34632605c721963f4a3579ddc8850f85d8447dacacb20e040f8e52e891d4c961cf2d16011f8c01b615ec4852e8711f85101f6323c8776c155bd50cdb7990c11e5ae849110448e837b0c11a0605012b0b061d8491077b2ae8191107751e18e88c4b155d1d0e8be8fb0b4e9a4776f5fdd1c4fa0b04cf7261971ee8d32103a2e9d9869d8cfa85b1fdbf0ba5690669060399048d5b0ef605a9810b077e757f10ecb22990585828165b4af6e04c64412122d1920c58e974527d6f290dd883dc22fef92fe8127a06178674830b0622db0beffcbcecc83ee9fce9048bccfc4ef29297c0fc95f9a9fc5e72c94b9dfc7286fc5c72c94b7afc4f6399e4948c5d78f940047b92013415e80945c93e5a045c41198f60055aac1dab666f665ec22dd25e1e54f6fba2eafb1c76c9cb9bdefbb33429836d046bff165117519664c7b6611cb8aa51a4fbb807b90579bff8a068f885a0936cc33e78fbc71a4d8526fb823c5dd6321a6a07eb067942037e171a75539664c01affca1f226cc01ee4f4f730e808d5dd16aefb603f19e8f1fad57f07e8c616ebffb6608f8cfa96f9f7c53aa2a41be44351e8b601168b439a413e3ae89f027461d817e423e888b95d16389c18d97371fa6b72719784814c88ac4e459725927825af2b19d6eaad625135d1e9894a33216b6f538b13d1e1891d34ffa528d8e4f9603d3ca474123ca7740e5009eaff3cae740a3caf74063c0f74a34dd929bb9e00014dc6457e9add7ff7814990743e4d3a3ca574363ca67432552edd74ffff3caa742a3cab74263cac74223cad741e651a163c6cc8254dd3756d6e6f011b7224070124285918203e84ce00e89dc8919cb028fbf8101a322517d218e8021832633d4b7ffebe625cdbcdf52bdf953ce870f536812d0c5837172ccf631bb3374c693d63e8573dff6ff4bbc01d7c5689c2c1eaa1c183e10f83fa0d750b83f994b7f702c442e836200f0e7537675f630f7e260ff9811b0a066fd29c34100705d76e0190dffaf79ad5f4d2faf4814cf64132e8c2f79425d75e17cf0e09e0a1200f63da01c8c896711f2c913e15ce6304faa37408921772d90bfa41e8507134156e18762f087d20f0741b003be8251dd976c37b8b087c8015f0f35b874c80e415221ef6dc16c26472157953c1f6c57600f29c192cf3402e249b3dce4081f626e136bb0cb48760f64055202fc0c66b30bf55f321655cf627e81d631a39a4b08e1c5b58fc6be0f258dd20c809fcf2e4c4f5bc6d61935845bc53a81b3e166627239d0aa110a81bec422e1ca69c88f5788323c08664530000c86063c05e1ea842070a41063939ee1dcebc06196490ae9e8a78196490415c442cc8c9410616fc1ce620830c32d2c2b0830c32c89c8e7c6a0c32c8205a463490e0208322121ca020839c9dea1b07d6be0f0b32c8aa9a001620ce5ed8600f201750190f5e196490c10774869664904106a4b0bc90410619cee2f2830c7272041a1e30440d36d8203e276a0f7a32c8208307889cb0c820830cbcd2e860830d32f806ef1607830c32c8263e4e2e1c649093191400ee18c820839cdec8ba20830c32aa968a830c32c87a6a5e520c32c82044322438c820831404f61732589041d71707bac820830ca8968820830c32726452830c32c83e2814fe830c1684163f07d6c60c32c820b0a89839c82083846e581a0b7b613c60164f10210f902eecc9d01fe41f17e897839c1c6cfe070e1f202e0d36c82040dc276036c860830f6e0782881fc820830d9807c6b00d494336527f801f3a0c32d820174e07647632c820838a9eb4d220830cc8dcec5f81f56043b477a21f01af1b44ff3f47657450726f63416464726573c54cae38ecff6f61644c696272617279412330df98a370119b9f0bc3200332020324cfffff6ffc0f79d47474ce214ee09be5602355a99dd385448ff1a8b71041ffffffffcf7c21b0d4c3e681fed891b785b22a8032dd7df6ad086f0063839040576b9d05ffffdfe22240d8e629e0de000dfd3f8c848e36115697c9c6f11aeefffffffffff38130fbb53e9767a04174b37a2560fc1f52c9576e8bfbe2ffe4e76792c933aeff2dfeff0e32c856f4db91033403dd62f051d9a124565051fa96baffffffffffcb373eb19e1797d2d5f1dea9874f30113334f2b47aa7775625867152cce0ec10ffffffff6e765f78de3c31d4d905013595e66b7c669f068eb0afe84b83ba3eec3e0a6dd8ffffffff59d1b471db3626038cdb01fb457603558d7b62e73daf08f3e27156f6bfe3687dfffffff6ce7ff63046e6a0c109dcae25a3d75ac5b2a73dc77e3be0c22a63e70dffffffffe4b5952c7be14d73d17bc634f43a34ff812a4d4f2808069a109ee1d563664ec6ffffffff0bb634392666772f788df8c3ee0bd7d1112ab3386ba1659da412d0d32275cd4effffffff0e53c8d7bbad93b7720e2ba164fb31e263b9baad77df518a8af3552c67a53d12ffffffffe30e1bd3bbcd80c04d894a27d4df8a84e295f6e9dba096cf0cceb91eab7880f9ffbff0ffa9feea964d0c0e350617369a3172bba9be596f8339503cdc785fffffffff360f07cc869b81e34660e6333a764a36cfa22b09123f68927167774d2c2f0d2197f8ffff8588edf46a1eb5635a3929ab187cef1c99fd39a65e4aed6dffffffffbf6ee2299becf6fd33807bb453b54466d824aedc2b264ebe39b78c1f6026b692ffffffffe1ec739fcbb8fe554ae5e0db7d29da741361603e0950c9cfad3569bb9a6c02f0ffdffeffffa85c424166e35ad787265f0f84b45ab56c1344c8e9e9bddd6684bbffffffff51a4c642908abd700fc939afb543d969ba46297cfc4f2379896eb102e7d73dd7d02fb4ffac616902c09172e184cfd41cb814d2ad97faffbf7928e003e215b636e8a4c5e47dd1b1d99f2630e9e99fffffffffdc30d4d67513d11853d0f98bdf88fe7c393ed63f934248d58d90637e7417cc1cffffffff39ed8983f3f61cf7ef3bffaecabf322bada873de226661dfc724b58542e6f7c9ffffffff3f22e3c5f4e06326598fe67108a286a0a7ff5a99159ff166cd021d8871ee4a90dfeabff1a4ce85e064c84a2bbfb1fec77bd4d9587823ffffffff828e20f7471ba32b2215ed388d78c4c9c5ce6e4cf7220cc16e55a207a3b9e7ccffffffff569af8297d922ac7d4272899b51de38523ce84abd0e649a11f055b564063e17dff2ffcffdaa7eb57d98ad5517e86b5546f4c6e2a8cf7ebac3056b3c3b72cffffffff120d2f94431c356e66d418d2a66586e6edc0b9f34ddf3c0c22489f54e565e50cffc2ffff04f4dcf114d0c4717adeacf24ac71dd0e82a46eb3bbf01c96ce1ffffffff3629b2930cf04d15f26c95b6a167733ee0d2b26f39037b7e95d4919d93a35380ffff8dff51ee2bb3b3202b844394242738c6d6b8b5976cb964db29c59bb9ffffdbff696bf8d881a56f50528021cc4ed32147f3fbb8a7f38adf0bfd82e867ffffff6fd0685b2a2ce9f6311adcd83ef7029a7d788e017c0255b0093287fcbcffffffffe442d202379174a0e53ce64da4473418f5ba8c5035722cc697d74a777fb9902dffffffffa6faa3c1ddaac51d2733fb15ba65231e9c4678789a999c8e35b0b1854fc4ded3ffffffff676c0681dce79a22b9db71504488d990802404b64f8ba2d799918ccda2b348feffffffedb5c4978c4bbd00f79cc1e1a0d47f0396261839613f5b8038f20b5770ffffbff065b94ab03e12f61181575d19bf5b15344dbc1055e1af2ec37402ffffffff56b02f0ec67d641b29e88013c4213bf5ad46f90a8bffadc5a58b2927db08d33dffffffff3d501b7eb3f7c07e996770753c7f73063193b952b6863002a9bc3c5b1bed537affffffffd1dfa26f070e72d5ff4c8067479b4d8552ac88d70207efb2f15a68f45063dcc1b6ffadffd6508e872f44b209fa20f6f5c0b5c50d9316929222ffffffdf2427ea8b6f0bf7fd93cd7b4d8e2857719b2ec4aebde789d98f9e6c1c2cffb72ffc599b3224cad7a21ee64230afb8cc43474c28a87a3e8fffffffdbd0cd437c23afd791ef1fc74e727eace12c3feedaab35916b1432b2b5ffffffffc1c4b591aac4a750f9141640d9768badfa2a70d76b5bb00af52e546774289fceffb7ffffb225ac7d271ef403c010cf812de5f1e5ee27115c471e77038813acaafcffffff2c2411c2e18fc06c1e7cb6f576f4537796f2d39a66133cf1017575697d7effff0f191f0d36fa9a5edf66ce57a24e8b191149f5225565ffffffff064b03b06bf23c927d76b4adc804f626297aa835805f0e38b8f82805cc0163421bffffffeb562c7971e0852be68e2ed9126c4df3dcfddbe359a3afaa3669ffffffff6f977bd0b6ba53942df1dd2f02b5decf686e648478d3258734e45dbb588c9347ffffffff1a0a9988c57213a9cd73e9ab3127c321cbd7629c165be786c46d953f9b9e3b39ffffffff7eb94477d2457c3a4fa5bebf98a7e152a0acc707f45c3046b7c2ef091c150b74ffffffff40d61edacaeee5c68df73723893214d4bc9060754a33964c1700fb51675a247ffaffffff0c2a1fec8a9faeb3c98118ffa110489dedb143d11bf08fd5d8501dfe3dff56ffb71f910854e2bda6a441613e63c0b20ffc20706a0b8a47122f80e3dfdd903d110b600f6803e00d2cd8600f181f0f58c80bf91f70e470e490c182b5900f07289e3d7b5800c8f50fa8e607b0f3c993274f48fe08ea68ed830c36d85817680778b03bc8c993ed88fe9820fc5fc86083050fb807c861830c32d8e8f877060b32d8ffb7ff0738196490414858686490410678889890c10e1ba837f287ff41061964ffffffce827090ff00414f07280ec2614100883798e64106bb1047b807c807196490d8e8f808e706192c082707304819649041586878649041068898a890410619b8c8d808071964e8f808e85fc1820c32e8e8070619649048586878196490418898a864904106b8c8d8d8410619e8f808e97f20830c32e9e9e9830c32c8e9e9e9e90c32c820e9e9e932c82083e9e9e95d18830ce9e9d71832c820830728384864b0610c58ff0778904106198898a841061964b8c8d80c727290f000eb102032c82083405060c820830c70809020830c32a0b0c0820c32c8d0e0f02cc860a5c877ec079041061928384841061964586878061964908898a8b819649041c8d8e81bac4106f8082718076b9041062838486706bbb00eed7780079019649041a0b0c064904106d0e0f041066b1541ffee0c32c8600728405032c82083607080c820830c90a0b020830c32c0d0e041063bc8f000ef7fef0c32c8600730405032c82083607080c820830c90a0b020830c32c0d0e0830c72d8f877f0f0f00c32c820f0f0f032c82083f0f0f09041060b07a8b841061964d0e0f0830c32d800f17ff1f1f10c32c820f1f1f132c82083f1f1f19041060b07b0c041061964d0e8f890c1068108ef1807284106196438486006196490708090a019649041b0c0d076904106e0f000f3f7c820830cf3f3f341060b32f3076006196490708090a019649041b0c0d076904106e0f000f47fc820830cf4f4f420830c32f4f4f4830c32c8f4f4f4f40c32c820f4f4f432c82083f4f4f5c820830cf5f5f541060b32f50768b01864907888989f830c32d807b8c8d80e32c820e8f808f606196410f7f6f6f632c86041075868c820830c78889820830c32a8b8c8830c32c8d8e8f808051964b0f77ff7f732c8208307506070c820830c8090a020830c32b0c0d0420b32c8e0f08077c820830cf8f8f84106192c07506006196490708898a819649041b8c8d876904106e8f808f9f7b020830cf9f9074106196448586806196490788898a819649041b8c8d876904106e8f808fa7fc820830cfafafa20830c32fafafa830c32c8fafafafa1964b02007d0e084564106f0107790410619fbfbfb41061964fbfbfb0c32c860078090a032c82083b0c0d0ec20830ce0f000fc7f06bb901afc7730074019649041506070649041068090a090410619b0c0d060071964e0f000fd7f06192cc8fd07384819649041586878649041068898a890410619b8d0e04c151664f000e036a82c857e176143611f7900ff0100072c1496b218474e059b1c360d00056cd9cb86062d000027300b1bd62507fe02017ec026b0b177fec5ffa003ce03fb08108b909730045f040720230f160f9004cc808f7d36fb001efc1f280f40ff5a8560324160d613087f440007770f36e313f7c5000c8f0f26000b1b6cb009a70f601ff00fb0b3b30742002748010f651fc1061b6c280f433f380f490f36e96f000a2f0f8a000937061b6cb00f9a3f680f069d60b0c13f780f1af9d8a407334f0ffd00194f0fd860b32d0d16cf0f146f60830d36e00fcaeff00f3dd804b6ff115f0f41001a6cc26727e7020f38002d4e0ff660131e530012070ff400139f60131e6c0ff50014970f830c36d81b2fa80f63c00836d820132fd80f830d365b6f0e9f0fd7af0060674182039f1f080f200c32c84518910fc1263cd8280fe500086f0f011d6cb087df580f750011a0838d68740f880078061964b07c0f3784be1b6cb0c12f8c0feb5f980f0d368107d600ab570f4d1b84b3833f5c040fa4bf680f74168c07df0056c70fc4ea606704bde80fd8008370162c100f82cf10830dc6600f2a2f200fe28331c82030ad3f400c32c8600f145052ec2cd9607f605f1f700f36d80c1eb0000d3f0ff91fd860830d900ffc8fa00f60830d36971fb00fcf1fc18634d8c00fe65f0f18ec8c80ba30e00fa50461b041eff80fb63fc1063b2b760f6a1f080f41186490fd10a42f061b6cb0180f571f280f4f061b6c10bf300f621f380f36e1c10f71004c2f0f2d001b6cb0c166ef0f1acfb00f61b0411ad13fc00f85bf29a0c106d80fb1f4b0c1063bec0f773ff80f669f1d6c521f04070fce0015cf116cb0c10fd5af280f93869d2d1522bf07ff7fc10669b0580f3a5f700f43186490dc886caf186cd8600fd6cf0f183661b2c10fc01f4eaf0fecec200cbd2f20080f96ef6c10061b280f470f400f64b0c1187a3f580fd9d8b0061968f6df0f60830c324b88c84fc18631d8980ff25f0fc1061b8c2c4fc00f9c5f604360b0d00f3dbf0f820c32c86df021589086d4f68f5f0fd9b08334e0df2009af1f608335d8300f1abf400f061b6cd8a2ef0f205f68061b84c10f742f780ffe1c6cb0c12f900f492fa009061b2c249f0ffd3fc0061b84c10ff11fd80f28051b6c30fff00f6f5f0d36ecac460fc6df0f7e36d860833f200fb75f380fd860830d042f500f454f063b4b36602f1f700fbd4160b0c1bf800fe29fcd7181c4900a7f4791a3eec3754b8561075c0f5d4c1107127a92630000063f0201ff8db1d8000801b680ff6c0d0a7264202f5323ffed6f025120222573220e696620657869737420ba0592fd676f746f206c3f9f696b72eeaea1eb717303669f20e36e00687fc8754bb86e19cf64114321d6749b5b8a701d23670b616839ebbab12d1b503d760d642d72113110f69b0b31002e00305f52d67dcf35574107130f41235377ec0b361528132d7437200b095b17292f8fb04b97ad00dfac992a0b7393755b396d335f1b258703147b8b422b6778002e0dff6443f6333a1f730f4e74517565727987fdffc25379cf656d496e666f726d6174696f6e1f6e40b06e73617f6c012e07ffb77f58b746696e616c502d684e616d65427948616eb8cd0df6646c65571f4be1f54e0545c81a6d7d336c3dcf6db8edf7d34403a975f9eb7bb2bb91696c136700652752746c6aecdbb3ad56a273946e74646c2e646c490486e03f4973576f773634438175233c3f6b2b6e056c770853363622fd220f2015def8eb2939747f656368d76f6666597a6b34efe50364656c00462e8bf005372fa34d4363f1e11aab6dd5236347716dee10764b7800a72a1529683760dd800f62116f0f652dcb220c58740f64790f645b409a7266d3790d7493bdbd0f1d690066212a8d6fc646d8220725770d6c192a9b9bb01121796765993b67b6904dd8006e4f650f7f33f7056cc28f6edd0f611d3b8b4d5873df6c43332a2d80fd25bb6c007333777800672f437660a7630f334f69217413c200644f6471635f36d2803d67006d0f681b6c6f611776488ff76f3f0bd8843d70006ccf6cedbf847d013b6d21ef736f03d60dd964af771d760f73c23eb008a1af6600707f7c09297b6f00740f2f62006442423721ff7711323f01e1eec03f632f7200776f09a19bb0732f721162af9e9007ec7400770f6d00667000613b846cc2df703fdb2f25cc0e039d83ff4b184fc274312a006761bfc2225cd8df73e15f766029e369b7bf707f63c8de120f6b00668f72bf0f248c09736f4734308e2c610f8f782f266c009b6caf30cf6912d296302f2b683f9eb009fb8d320f659f700072b1305ec85f7175303e3086c7276a0073577b48d8962d7977b52d259031029b35752961f7c226848f953747694ff630b04753b7d777e79db1301217052a92be2c64a70f6b00648725ec091b373f6600689f0da4843d47362fe90b21249c9f7a5767a42f846127476800708f097bc286680f660066c7d812c613af795f2d6aec096942776fff66006c0fbe643c254f67c32f7398b09e90bf7400685f65ac097bc80f7200612f6eafa40be1855f876c2f5c0891266821c7611ff62221f7ad212a0076e3e60b19bf1f637500703f090181216c998f238390c46c07b702587f60a76d00610078478384f5cd23d770471543c217d227740034a761f4823109a92a4d277d01e1e34b6b6449177118b28784af176d5f383c256c42c7657f8d70d8133621b766ef6e006f1fc685f04af7c76baf210cd9437200742f632fd6070b2bc7e76d371be312522f6929640f3052b625fb773f37217c09b966df689f6c0b483c670064672b764f211b92266357646f9031645f6f63ef772f8cb10e848f70df69270903d2533f2a1f62bd320ecc08b7c9c7211b92f86e0078c763cf4f085f58bf6800744f7000740c1943d2007807792f735cf622619f670f6d042ea464c7077789d990f5503374ef787f1c12030b81e73663d92120cf1f1f9f2f615cd83f634f77d28590b072ff3f63cf4cd8933573a76100691f6f0d090c59f770ef664c480f09e77300772f6d212430246f7007d14221833f6900740065f7c158581306073784d1b7900755355f0b614dd9671f37dfa129604f2c5f70894f097bc2e0626f6e0077cf17424ae86e0073a72f373f244d18ff73ef610076006908494346a763afc026ec42bf693f379d3164755f0f318d334f6d8412d2900f76af370486ac2e6bd768ff189bb0876300661f6a4f6143c26ac08f7007672d2c12c26b4f1f90c1939c2f6d6b0031e71066b4b06f671f4868c8b8615f64f7dd81a56c676fff6abf75bb100a58dff76e4f02520f212d617784f081f01f6f3300664f0fd990f166006dff64ff310032f664531697355f74006cbf8b90c1137800338f370c591f0bcb33ff74ae8c16068777700b6b9630957737868429e36d0064c7668777c8266cc28778f76a4f164b1a527fdf272980d5176f0073efff241c190b17730786040e2c1f73c7644b9885a48f5f777ac81ab272af6b6f640064404218927763c72eac42f6516e8faf72694218122f627f67276021e12962006c7f3f031b196f9db70f6021c0171763e5105eb2431765d987d7a42b03be7a0069c76d2ffc0504066c99d76200343e101612c7c76200671a1278c20f660070d76da4096b48bf34af77bf840b3b84a7f76567097d2184076400675f183c240c6d477400779f00435643332f66e00dac8547e72f93f0c142275767276f4b0953121779973f8821810333c774489ac5c24f370f868c01e162a778af6f84216bc83f6e676967fb0b2126651f6a0069006e7f8409a12161076577647561855f6fbf5818482faf6f0d7542c26a42f769b11f6d6023697faf4f07b630e0310031270f623e104ad900647f776c00750b01260c57663f4312a4a4647fef7382413761bf7911623d98b28e845f7087338a8515305f67812d0c68456187f78c16d6a3ff87ff0c86842e73af638f84f085a56f76006f27c28442c674a7a53716321e5a7732f76fbe12d6076b00702f9369af0c1892df641f7400308c98b02a0f65770c594f481762006baf61c5c20a19ffff123624f08f7137342f12528c2c2f771646c21e1d6a3f1776580c2c2d8f336f30ba10429f338f0983219b6d4f6bd9f0968c01ff65ad70c2c03a11ad676d3565fd840733007000720f6d2b6030647734171ffec01e0bb70f6e00790066851018924f6b4706c48281df97bf484c080362ff6b570d10e94beb634b492e80073002756e2729acebc6f76f09730f242983127219d7726d491c0601c76b9f907d030b0f0d6e0f21a1038357660f60c206b0743f650f62d9854148ff4f6d3fc28624487774cf84ec876c762f72007000629f5b0870611f76973f4c086c0b1b6aff6217f60646194fff6fc5a0814461cf97c58a814fa10f750d5943522773177367030b59b74def69060336643f779f2e2fb8a43a21ff412f538dea7e0be146005400571552cd60d44aaa5cf1cfa8c1e8b60368a574656eeeae3bc0d5535b28434c003b016eac7baa4e235703580f3b17a3a2ffaa576320322b69252dff29f87fb1a5b4ada9afb0b6e3a9b7085246574e474dfc1f23f8470f4b5749c619120f0b170315460c12ffffff0118782f4d4b3423646a196b67186e6d693e705e5a3830ffd2ffff77312d33282c797c7a2f7f42040f15094708dd5e425659386e68a1e8fff739564a1d37363124322228336a2f26c0ff27fc1f1a1d081e5858470c0b0a07e4ffece5e2a1e8e1eea9fe3f0817f1feeaf7fbf3afafbcf7fcfdefff3ff6ff6277766364654361774d1f5d7e6c4c6d7a6e4d607c76787aff0fe1ff72507c786e6b7d617d755a57b388ae8b9c8a82b39b92ffc1feff98849c91879b8282bf9c868b8e99961f576c487f695571782f50fff67e627e733778785d60796f6ca056797989facffe747b587c6369692784bf8ba5a1bca92790a0fe7f022222342524293f1e3d2d3a2f5e6fffff7f00022826212e16222b263c2e0e282e3a293635210227eb33372cffffff671f6b565c4f4b5c4c5a6c7c5b50465a45584e5d767c45434a40577ff7ffff527e6051575442766d4c7e6e6e77707e4d40667a2f1d260535253b3cffffecff3a3a2e3c082d313e39303147ba81a4929195a49a8e898b9e94b4ff6f1ffb9f968b979f17bb80a084e196a4948e8b8b9894b69f88d6ffffd88b9518556e5e7d6b5d727267776964437e67716a7acffeff0f2d16320513250a0a1f0f111c3b061f091216175d66ffb1ffff447e7a776542727f6e57794d787f776b6e316853764051564d44fbffbffd7a475e484b4f0f99a296b8bca1b4007e40585f594c426e4c4db8dfde0541c006362227b81330222ffffffff62a3d3a1f0fa1cfdbd7d9c4c8d2dcdbc9c3cdc8c0d8c8ccc6d1abecf343f80fc2ebe53793979487858d8a8cafc0ffffffe3e3e9e1f7e7a1f3e7efe9e3fcf9a9a7f6faf9b4bce3e4f9faeabf0170530b071e1490a7deb0aeef17513711335a5c5aac0af8cf7ed1d1d5d2d4953f839e9d989cd4c2f1fff648e8bba4adb3fdb5a9bbffaabfa9b8aaffffffbfe8b3fe80baa6a3b4baaae4efa7b8afab998fd4d7d0a798988ddf9a94969effffff8dd82994c48787868ec18b818f9f939b9c8cf2b9b6b7b4b3e6f3fdffffffffedf0fbbabdbabbc0e8e8e9edf4a0f5e6eaace4e4f8fcfbc3d4c0dcddddc391d7ffffffffd19cc9d2de98d1d2cac885cac6ccd1cbdd8ccbc3c7cd877475787563657c717c54fbffff7d1a34363e783c2824363c323725256e2d356d192a0ec1feff56724f111f1f021b5d55001e2d3b2f27b7fb7fe1fff7c4d2c6cefdf1cbc9c1c213d9cfc5e8f6d9daddd0dcd7dfdffeff238cb1bba8acbbabbd8b9bbcb7a1bda2e3ba918fb9ffffffffb3b9bca8a1b7a5b3aab89caf8c92889e998da4a7849a829a9694829cb2898ad2ffffffff8ed18b83d6c8d5d6d2d0cdaeaff9adb6a2faaff6bba5a4f0a2a5f6ecbcb4bbeeffff56042994b7a9b3a5a2b6aaa3a39ea0a4a0a9ffffffb0b26f888a8f9a8fb8aca9b9b2b7fdb1adb300e6f4ede0f6eefa7f12f0aae1e6e7975d4f41414047550c474c29d8fe47a88395878989888f84c402853f3f46f0ffcec6cbedc4c784c1c8cb8777717f757df13f16f0623d787181213d28393d79303936f0b1ff8717f3e9deeae8e3abeee7e40fd4d8c0ec97ee0abf73c2d4d097deb70f8f9598e19f949ffd3fe9d0959c0f8b8d9b8c8880d49f98993fe7e5e1fd1ffb8dfb58f2befbf2f10fbcafa0bca7afe7adbfa3fff7df9e1fa5ddcc8c9089858bbb81b10fcdd2d6dce1d8d9ff2f34fec9edc6ded8cee8be84f7c7cfc2c900f6e5e9e2e35ce077ffeffb00e0fee6e0e127272a243e2f3d49b0bddb1bed2f65bcabaf00f0e06418e3e1e325ededdff886e70c0b05141903b5001318041e1e192f974a7feb31222e3c283c0039312129283325b72ffdff3c3e2c343f3a3320303f3106170eef0b18034d1e1c25ad05feff70630e0637243f791a2e297d6c030aa7244ec0ffbbfe640e2269781706652d505c13675b5d4316705c1bff7feb8f39656d7d6a7e69bb7960627562726a7269757070656bb3ff27f0424941510a537f7d776a767a747761ef082ff0ff82a9a0a6b0b995bfb6ab8dbf5db6b1af6747f8ff36d3bbe3eec2eaedfedaeafcfae1e46ce7f241fd1fc2fceaf7213f272026333d3230ff872d2d6703900417aabda5bbafb9bb9590e187ff8d85838facb5b2bbf1afa4a9f7998097fbff5ffa6d00ff0e04171304bd141f073c2d3f2b6370183c303ffbbfc07a09fe2f38283e7c0931300c1247998e968815feed02af88a6379a99848396dc9ed0cffeff8f175e49514f5b4d4f61445e585650441a4653582f8081d98d97fef08388b1a3a8bd9ebb94a3bca9fd17f2ffecff20091c2307080e2f08090fb2b2a2b0bca5feb4a6bad20ff67f7b6a68686f337b6775bff3a4f1a6f7ceffffffffa2fbacf9aeffa8fdaae3b4e1b6e7b0e5b2ebbce9beefb8edbad384d186d7807fe9ffffd582db8cd98edf88dd8ac394c196c790c592cbee9ecf98cd9ab35fdaf4ffe4b1e6b7e0b5e2bbecb9eebf37f2f0aefdfafc0093b0f5ffc1fefad1f0f4d6e3fff2f9decbeb470efd06bfc42b282c2b35396f0a2d3e2d2e2d250f2ffc8317201e0c185e3b19251417145c8b2fb85bffb7b8b1fd98babca47db7a70fb2879c96fd4b8cfd9a919fb9aab52f2447312b2c2a62263aff0b2344209802a8a9bebd87a1a2a9a682ff07fbb6eba3bfbd57869080879f9283db9f839da85fe0b14f585a403e44580a405eeffeffab2bfde8eaf0eaecf4e8f7bbf3eff50f5b55535b6f45c5fe54575514504c522f570d0407bff4d8c6054499020f51524cde5c57084c50fdb76211677ea9b1b4b4f7bdafb360d85f9a6f498392ca809e82ef078b5f5a4495fbc7de94869aef76753f05ffff6c707668645676726471707167246e703cf5cad2fc7ffdd6c4d5e6d7c185cdd11944544f53474456094db6ff1f2bfe373c1a191c3509021f130f1b0d568b1efc52d7c35fb792e08f82b5d9918d971851ff1f1b0d1f2522203c6024381025fe12fe9ab8a6b18296ffae858cb7972ac3bec412408035df958b974760ff7f81811991aa9599979581889f8fd29a868417f4377889b5596a42e7565a44500d41bfed7fa1770600040a0d35010113480a06ffaeaa3c2b7081a120eea4292f14102df4a52fc315031b16cd061a1e5d0a0b2af1d68347ddd9d058cac2d50bffa561df5695dfc1dd77986a5863622c667468176ffc670f35362b19352f2c1b622a3642a567ffadbde6c6c5d19fd5c7db1febf1a3d06076ebcbced8f0ccd2dfabe2b7bfb0dd9504898ec68c968a0f6165696f75f017da8afb622c6667686b6c6da3425fa05f5973747677258bff7fa1449bff6f7a696c6c612f342e302028636fdaff0bc46d708d626c653b204d534945203715d6dbffdf0957696e646f7773204e5420352e310f535631e7b13016ff485454502f312e8d509a54718bdb03a34506436f2765636e057f03d13a20636c6f7365be01106cdf6e17191064f910340b10720c700f07a0b6eed6050354041303037072b9bd99071f1c74e50364e454e3d67da3e034e27ae00015e01b122fd880eaf61264c30334c2e2c0b6bdf1154b2f077f07012707093f7b32d8dd09270230000b321c0c4bfbdf9aa6121110039218f016e014d012c06dfbdbed7601063b06322501087f0852047003600b97dbedad227f22743e06643d03343c01382f01b9ee0114e02d504be41d642bb75d5a6e03342a015f12f0430f1772d88d8aa4044277124e9a666cab75747215eddbd8deeb15349c0301f406370c7ff64237f60c72083087727b241724011b263467fffff013e011d00fc00d700c600b300a504b3534edf676d2321a131a74de0634dd03dfdcedf701da010b4f15085b640d63f315720ee0b1bddd0a611501055b0534011b0aed36d84601740b19671974e72bdc6edd19640754d319343719526187cbedad1952130f13540e03340d72b05d16de0fe087230272041b0fd9da65b7c30f370f340f5289b307f6be50773499b7948f70156014873fee7649330d0c1413146403dd1a96cb54073406327f174317649e71b9bd37175493033492019003240bbd85b0ec5356014e0b5b7537d38c470d0c2714724726f072b9bd072674df0364de34dc01d800cbeded8be52f1f1b1ff417037416642c662897153414a31bcbc90977660707320b70bf2834740ddb1d5f1d231deb1d231ddb5be1df1d3219f017e015c0a2331b7421033498c996961e01f9104b0b67ced8351b724b1004e7521b0cc26f860b170870076006cf7dbbec49d37c7a0f048718071984bb6e1897180f183214275472409aa653525093001a4e09a5e027260d13bcec93a669bbbab4d012c0afc376f2b0c708176f172362ac60365f151f431af7ffad6190ff0bf009e007d005700460033002173afe6fee180a9b2b18b214f012e010d00ec069606f507838a757fc18f00be077c418f609d007c0317b4b0a72065276a96d671c23cf2f0123b159d3fc7f64cccbc8df378542eb6e9f0a5237180713435b1076ee18540b7b7f721463571099a639e3920c70d3090807d7ede8b8df1932d319e7542e0f2d9b34acd95326b3e0af6bea9a66abcf1f2a29289b264cd78ccd6b4f0d0c3f0bc69213ee0f7215e037098feae84c330a090b528f10a4db87ebcb42634711a31132c9c6ff31c637624113701260115010676bd8a4235752154f67bac31a62bb0f9b0e0b9a31025652bb434948c372c06a4613650064b79a8d764262c31f97fb2d2b1aeda4692a281b4fc36da3edd87b1b671b54d3cb0503b446ebf8f019e017d0df17170b73b6c6cd2c8f0d27179231c7062baa875d3408cb50e8634a406c2f721b0b30de04d45cd6c2138e2888702fbb7cb811137a1e0bad82015bcd6027969f36975d80a89d481613c690c4ac7b036627f41327d077ebb60a062ef31877f0278075db0104210b383b3813160811cd2680ea08221022b71f2ce85b0e457869746e080557615e6aa96f0d466f72539367a54f626a6a414ba66b3b02b242d41a95c875111405daff1ffc045669727475616c46726565427e7bd906db045317652c1a2b46690395ea0c514a2d85b7a3fb56aa26f92876656e740fec8fbf7bb07f75706c696361745100c7013743757272656ecbb6c1618d496d3d8f7265acabf660104d656d996bca2bbd02750754685864bf13b66ebbfd71417474326275347367a69565e2e66ec12243696f4b3e4c025eb52123a3529d496b6eb0c189a9ab526d055ff610da0f82034f706e279803096c73d50e333273ee6a9a114007fbbe4e6578e3bd47546f55b5bfbde8656c7018536e6170736854ced0ce5ca61b443c60d41a11e1752f67ab20650b9f7bc11fd05bb1542d6bd87edf56fc751d080f4c61764518568a56023bbbfb0a50625bb57abf3fb55030109ec5963e00fbabe6fe4d28d1531b00c30352dd0a4cd1163b008c65f4700257550fe935f8416c09c35684d8345729e5041dd98b4dd876bf4b1ffc76e1c3b6c2d7e3f565c36f04539ffb56780059034d126665774f6684ca98b01fe504556e6d11c6176dc7b1d2a3ff6f673f6c444c885dc36d865352af504103f86db7ac6f5fcf04d0726d696e616412ba49c812b973678c453bd70589704535a203d0b5ad7d4344e9c17664bdb46d7b3086cb0dda024807704991b3d8091ad30d0bd7cf0de30868005169b415d4486a55ed49b587f61bf4f902497342548850c7874d09c10f775a00e303b7aed0da456e8a4a1db756dc69612e58b0876255a89764bb7058d1b2cef143924e0d2588437b757291e7da43e875748f506f2c16d3bcdd233c254e5479705b6801c54642a3204b937384cd15eb57e7973e5b641a96c168384a81636920696f4b6da142683f034df2746942584bb6a3794569030b16205d37586bcfc94da378c77f9ae3b0486f0dfda7aa481b9835f11e350453012d45a04ecb04f0246d5e8b7acf54d609bdb5ac4bdfcb1a00b10f568f756d9908a73357e80c4d580904aaf4b76c4b45524e454cad946bbb76763800bf4f418755531c195269fb0e36fd4ca3672d77c12db88e13c4c1387414da67b7a552e544726000b11341676d81e963717529bb741bcdaccdee6617c44b65792ac3139c1d2cd8e82b00ca154919005e2bbcab2c116bd4db88110f6306790f63f69b303e7a00b711bc09fb165af71d7934b611007cb3632400c8130c446dc2611712fc0171c6efc66672b46b0a7713cf6e1d21006e85f509736b75562a3c9aca5313f60e77604bd630770d755bd97b6c506e7501aadd6f81171aad04706c66e9d22e40e0b1d6bc530e00f70149e10def59680057494553756241e108604f6068a8005815898abd13025a193be21ab4c60197017b1358144abb06ea7695676528dc92cdbe75c91fb5646a7573301c186fdb36c07dab6e5269a822ebb811ed536865896e457239b59dcf30a1675340116edefbc562185612006113ce8703b1c12330352275c12e33bc7e0de32f7771583024e16c697a3494c9695899fb5188c7b6022e1807872b589f632b134895bdb259ed25546f137e0eb0bb734d01475353ba02531ec69fc21b414456415049ed3a0093685d0f1644627bd18eb733780f05422e6b736c47428c8074178b1a1c4a0562db63169f15db068a406b2652122ffd6cbbd115a2ca432e4e490c4721865be1414128226e73cf54d88e75219315536b9552d93d7b23d6387b0f8b74636858003430db1a8e11417083640e952f834bc3c020c50b5348872b0082310c30e660c37677765f70437466970d16b3050216304d18800d1bb0d232139885110cb7534c571c1a0c977d42a1f54c534944f11b9900b501d0b6f69b081247551a416f80ad76728348c33b3511f85a176db072a3222f206c5f87d57a1b8874655d7f808120087d48b9636f648f1762c1ea12d43f66f7426946b03f836eef435259505439df3b57e1c049d8ad1acd55720316cbb66cdf6b13f159708ab1c400489470da4e178196751d71276f13b2cb22499f33ac13eb4e254747078529574fbe0bed141629f165733d5bd965adc513257013973dc5926d2f2b109d0f8b84051a974f492192546d469b381141aa65645f41f6870350538d444c4c000020416053ff015a1516890a63b0208335eb00000dafb011b61f2f0008b987b060012f4a4a56008dc0ee2aec27707e7e5f6121e1810f0009c10f6187252c8b0f072f92cb035b00dadb00e050f2873ce1e0c0c1c100e0a3c005e400b00cdf3015c228b5ff4df58650da03c560205f8480eaa30705400202fbbc0a4100004245dd46b7b20324a0ba8e00dcb40767340b78cf1900ea0784ee0b075dbbebbae603640be8074313001f0b44755dd77507ae03800bb007e7038ceb9682ee23070987980b0c0767f8baae7203b40b7407179b6be03a47bb07121b250b1407ee734d058fe40b074d037601e8bafc0b50070e19040c0b6ed7b9dd10079d1fae0ba007f320b3759ddb750bf4075a21b30b5c07afbab35dd7033c0bb00703220b04077580aedb0098440b780786ceb4eb164a5c0b8807b128890be77667bbb407f52977f807d12aff175dd7b95dd407632bcb0b6407d803a0ebb6ea730b0795d0ac0b980741dd33b5022da16b0781ee75dd529ccc0b8407e0030b55f7cd7e07442f2307fd03e80497c8408a4b18326edb7dae0d0b07cb030c0d0bcc07dcae6bc47633270b78079d34e36077b6eb0ba0076935ef6c07ba375b755d2baf17bc07ea4c00ba02edba680bec071b3c7b0b1c67bbceed07d73dbf0bd807fb3de3fc61d7197607563e8f175807b23ea3e83ab73bb407db3fa717dc07b726b35b8206d00bb840525c13d0bdec0b07826d0ee3edae33ec078943970b8c0791440073b755d4750b9407bcef2c0bb99feb3e07f403400b077e46b3c3ee6cd70b8007d94617dc07ce4797db9ded3a0bd00722488f2407c648a7e71ab03bc807284b5b2307c5ee6dd1930f9053077d51442ddc2b035307a55b00baaeae0b4407e6d9d40bfb39d7b1e854cb57bf0b07e457539da1e33707fa5a630f130796dd73bbb35b779807fc5ccb17071a756ed7b9677b0b1c075f69b30b60b9765dd707a603540ba807b26a7b5dd755d70bb40746cd740b4807b3aea3ee846bf7b4075eeb80179dfd66bba4071c6d6b07ea6d8fec73bb67d807fb6faf77070871170b61d7759f07f303d00bf40774727fdd37e33707147387078603e8750bd07523880716bdf80b1877b63bdb07747577c4072d766b300739768e5d9d030c10570712778be0735dd70b1407cc03240b079774b6eb9611380b98070a793b20d79d7544df7afb8c07d2035de7765d4c23d407f67b170bf80783aedc75a67c5f0b8407567d000b86dd73bb5807577ee30b077e80bbed9edb991007d4817b470798824d1461373b10010000c0ff6fbcc10362e0abf0ab4410ac20ac30ac40ac48ac50ffffffffac60ac68ac70ac78ac80ac88ac90ac98aca0aca8acb0acb8acc0acc8acd0acd8ffff52fface0ace8acf0acf8a2ad08ad10ad18ad20ad28ad30ad38adffffffff40ad48ad50ad58ad60ad68ad70ad78ad80ad88ad90ada0ada8adb0adb8adc0adff1bfcffc8add0add8ade0ade8adf0adf8ad4008ae10ae18ae20ae28ffffffffae30ae38ae40ae48ae50ae58ae60ae68ae70ae78ae80ae88ae90ae98aea0aea817f8ffffaeb0aeb8aec0aec8aed0aed8aee0aee8aef0aef8aef008afffffffff10af18af20af28af30af38af40af48af50af58af60af68af70af78af80af88aff0ffffff90af98afa0afa8afb0afb8afc0afc8afd0afd8afe0afe8aff0aff8afff171d11c4ec44a008a010a018a0ffffffff20a028a030a038a040a048a050a058a060a068a070a078a080a088a090a098a0ffffff6f00a8a0b0a0b8a0c0a0c8a0d0a0d8a0e0a0e8a0f0a0f8a000a108a110ffffffffa118a120a128a130a138a140a148a150a158a160a168a170a178a180a188a190ffffffffa198a1a0a1a8a1b0a1b8a1c0a1c8a1d0a1d8a1e0a1e8a1f0a1f8a100a208a210ffffffffa218a220a228a230a238a240a248a250a258a260a268a270a278a280a288a29080ffffffa298a2a0a2a8a2b0a2b8a2c0a2c8a2d0a2d8a2e0a2e8a2f0a2ffff5f02c9a308a310a318a320a328a330a338a340a348a350ffffffffa358a360a368a370a378a380a388a390a398a3a0a3a8a3b0a3b8a3c0a3c8a3d0ff7febffa3d8a3e0a3e8a3f0a3f8a39008a410a418a420a428a430a438a4ffffffff40a448a450a458a460a468a470a478a480a488a490a498a4a0a4a8a4b0a4b8a44200ffffc0a4c8a4d0a4d8a4e0a4e8a4f0a4f8a4d0ffffffffa510a518a520a528a530a538a540a548a550a558a560a568a570a578a580a5fcffffff88a590a598a5a0a5a8a5b0a5b8a5c0a5c8a5d0a5d8a5e0a5e8a5f0a5f8a5ffffff0b4808a610a618a620a628a630a638a640a648a650a658a660a668ffffffffa670a678a680a688a690a698a6a0a6a8a6b0a6b8a6c0a6c8a6d0a6d8a6e0a6e8ffffffffa6f0a6f8a600a708a710a718a720a728a730a738a740a748a750a758a760a768ffffffffa770a778a780a788a790a798a7a0a7a8a7b0a7b8a7c0a7c8a7d0a7d8a7e0a7e8ffff17f8a7f0a7f8a7c008a810a818a820a828a830a838a840a848a86de1ffff50a858a860a868a870a878a880a888a890a898fca800ffffffffb0a8b8a8c0a8c8a8d0a8d8a8e0a8e8a8f0a8f8a800a908a910a918a928ab38abfaffffff48ab58ab68ab88ab98aba8abb8abc8abd8abe8abf8ab08ac18ac28ac386a6a6a6a5b585978559851b8d4b4646a4dd8494708432869c9d4d43f483b6837359833d392a9a9b82fd82b290825535353532821481d6819881553535353a811c80de809080547474753280148fd68f988f588474747a8f1c8ede8e91d4f410e4cb308e7281c1d1d1de348df68db88d7b1e1e8d8d8b8d1d8cdcb08d1d1d1d1c728c348bf68bb88d1d1d1d1b7a8b3c8afe8ab08d1d1d1d1a728a3489f689b8840c3d1d197a893c88f8d1d10860c04f713a200a40ab200000000000000000012ff + ptr = claripy.BVV(x,695400) + + state.memory.store(state.regs.ecx,ptr) + return + + @proj.hook(0x40273b, length=17) + def nothing(state): + x = 0x4d5a90000300000004000000ffff0000b800000000000000400000000000000000000000000000000000000000000000000000000000000000000000d80000000e1fba0e00b409cd21b8014ccd21546869732070726f6772616d2063616e6e6f742062652072756e20696e20444f53206d6f64652e0d0d0a2400000000000000222635e166475bb266475bb266475bb266475bb267475bb26f3fc8b275475bb266475ab2f8475bb26b15beb27d475bb26b1585b267475bb25269636866475bb2000000000000000000000000000000000000000000000000504500004c010400d737af580000000000000000e00002010b010c00008e0000006c0000000000008b1a00000010000000a000000000400000100000000200000500010001000000050001000000000000200100000400000000000002000081000010000010000000001000001000000000000010000000000000000000000004d80000c8000000000000000000000000000000000000000000000000000000001001005409000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000006c0200000000000000000000000000000000000000000000000000002e74657874000000518c000000100000008e000000040000000000000000000000000000200000602e726461746100008646000000a000000048000000920000000000000000000000000000400000402e64617461000000f018000000f000000004000000da0000000000000000000000000000400000c02e72656c6f6300005409000000100100000a000000de0000000000000000000000000000400000420000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000051830c24ff8d04245556578b7c24148bf12b3decf340008bea6a026a006a005056ff74242c6affff15a4a1400085c074306a006a048d442414508d042f5056ff1594a1400085c0740533c040eb156a0133c050505050ff74242056ff15a4a1400033c05f5e5d59c2080083ec105355568bf1895424105733ed8b463c8b7c307803fe897c241c396f18766d8b5f2003de895c241885db74538b138b4c241403d685c9750485d2eb4185d2743f0fbe020fbe092bc875228b7c24148a1a2bfa84db740e428a1a0fbe0c170fbec32bc874ee8b7c241c8b5c241833d283c8ff4285c90f4fc2f7d91bc923c874174583c304895c24183b6f18729c33c05f5e5d5b83c410c38b47248d04680fb70c308b471c8d04888b043003c6ebe16a00ff353cf84000ff15bca14000f7d81bc0f7d8c3558bec81ecfc0500008d55c8566a0759e8505900008d45c850ff15b8a140008bf085f6750433c0eb716a0a8d55f059e8e95800008d55f08bcee8fefeffff8bf085f674e18365fc008d8d04faffffe8d80000006a058d55e059e8bf5800008d8501feffff5068100000018d45e0508d45fc50e8f457000083c41085c07ea768400001006870a24000ff75fc6a00ffd68b4dfce85927000033c0405e8be55dc3558bec81ecc805000056578bf98bf28d8d38faffffe8720000008b55088d8566faffff8365fc008d4dfc505657e8c22900005f5e85c074058b45fceb0a8b4dfce80c27000033c08be55dc20400558bec81ecc805000056578bf98bf28d8d38faffffe8250000008d85b8fbffff8bd750ff7508b950f8400056ff35fcf34000e8015c00005f5e8be55dc20400558bec81ec040100005633f6578bd6bfc10500008a82d0a2400088040a423bd772f28a86cef94000888435fcfeffff4681fe0201000072ea8d85fcfeffff8bd750e8591700005f5e8be55dc3558bec81ecc806000056578bf98d8d38f9ffffe89cffffff33f68bd68a8415fffbffff888415fcfeffff4281fa0201000072e9ba660100008a8668f8400088043e463bf272f28d85fcfeffff8bcf50e8ff1600005f5e8be55dc3558bec81ec680100008d8d98feffff568bf2e88fffffff8d45ae506834f6400056ff150ca240005e8be55dc3558bec51515356578bfa33db8b15ecf340008bf1895dfce8be2900008945fc85c0746b834df8ff8d45f86a0253535056576affff15a4a1400085c07441536a048d45fcb9ecf340002b0decf34000508b45fc03c15056ff1594a1400085c0741eff353cf840008b55fc8bce683cf84000e860fcffff85c074058b45fceb12680080000053ff75fc56ff15b4a1400033c05f5e5b8be55dc2040033c941e84402000085c07405e8f801000033c0c20400558bec64a1300000008d55e483ec1c8b400c53566a098b70148bd959e8985600008b4e288d55e46aff6affe86a52000085c074178b368b368d55e46aff6aff8b4e28e85352000085c075eb8b76108935f0f3400085f6750433c0eb19f6c301751a6a00ff15b8a14000a3ecf3400085c074e633c0405e5b8be55dc3ba74a240008bcee809fcffff50ba84a240008bcee8fcfbffff8b0decf340008bd0e8a7290000ebcb558bec515356576814b9400033ff8bf16824b94000897dfcff15b8a1400050ff1580a140008bd885db74118d45fc50ff1520a1400050ffd385c074038b7dfcba14f44000893d64f84000b908f44000e8ca490000a328f4400085c0750433c0eb4983e601750ab950f84000e8ba580000e8f8240000a360f8400083f80272dee82e2b0000a348f8400085c07511833d60f840000473c76a0258a348f8400085f6750583f8027cb633c0405f5e5b8be55dc3558bec81ec60030000833d48f84000010f8e82000000565733ff33f6668b8ea0a240008d95a0fcffffe8375500008d85f8fdffff506a006a00ffb6a8a240006a00ff15dca1400085c075318d85a0fcffff508d85f8fdffff5050ff150ca2400085c074186aff6affba2cf440008d8df8fdffffe8ce50000085c0740b83c60c4783fe307297eb0f6bcf0c8b89a4a24000090de8f340005f5e33c0408be55dc3b80401000048c680e0f240000075f6a1e8f34000a820740fe822080000e857080000a1e8f34000a810740fb9e0f24000e8bf070000a1e8f34000a8400f85f0440000c3558beca1e8f3400081ecf005000053578bd98bfb6a005983e7010f44c18bcba3e8f34000e8a1fdffff85c00f846501000056ff15bca0400033f6a32cff4000893524ff4000893528ff4000ff159ca140008bcba34cf84000e810feffff85c00f842e01000085ff751c56566a016808f44000ff15a8a14000a33cf8400085c00f840e010000bafcf3400083c9ffe8482a0000a3f8f3400085c00f84f4000000ff30ff1584a040008b0df8f340008bd0a300f440008b09e84b120000a304f4400085ff7520bb34f640005356566a1a56ff15dca1400085c00f85b600000053ff1510a240006804010000682cf4400056ff15aca1400085c00f849600000085ff75158a8698a840008886cef940004681fe0201000072eb8d8d10faffffe828fbffff85ff75278d8590fbffffba002510fd506a0268d0fa4000ff35fcf34000b950f84000e8fa56000085ff7407e8cdfdffffeb0333c04085c0743985ff74306a088d55ec59e81a5300006a0d8d55d459e8c75200008d4dd4518d4dec51ff15b8a1400050ff1580a14000a3e4f3400033c040eb0233c05e5f5b8be55dc381ecf002000055568be98d5424185133f6b92cf440008974240ce86619000085c00f84ad0200008b54241c8d4424088b4c24185350e8e7f9ffff8bd88d4c241c895c2410e8d019000085db0f84820200003974240c0f867802000056ff7424108bd38d4c241ce8dc4b0000397424140f8457020000578d4424108974241050518b4c24206a0a5ae816490000817c2410660100008944241c0f85e9000000568d542434b99ef0eabee8c1f9ffff8d442430506a016808f44000ff1504a140008bf885ff0f84b00000008b2d58a14000ffd58b1da0a140003db7000000750557ffd38bfe85ff0f848a0000008b4c241ce84e0c000085c0746be8bd0600008b3db0a140006810270000ffd7568d942498000000b9ceb04151e852f9ffff8d84249400000050566800001000ff1508a140008bf085f6740effd53db7000000750556ffd3eb1ce817050000e805420000eb076810270000ffd7e811f8ffff85c075f033f6468d44243050ff150ca140008d44243050ffd38b5c24148b4c241ce8f01f0000e93b010000837c2410040f8530010000568d542434b925d951a7e8cdf8ffff8d442430506a016808f44000ff1504a140008bf885ff0f84e0000000ff1558a140008b1da0a140003db7000000750557ffd38bfe85ff0f84bc0000008d9424f8000000b934f64000e8ea0b000085c00f8491000000ff15c0a140006a025a6a220fb7085fc744241009000000663bcf752903c2eb0703c2663bcf74080fb7086685c975f16a205f0fb708663bcf7407663b4c2410752103c2ebed6a205feb11663bcf74f2663b4c241074dc03c20fb7086685c975eaebd08d4c24208bd051566834f640008d8c2404010000e8272500008bf0f7de1bf6f7de740cff742424ffd3ff742420ffd38d44243050ff150ca140008d44243050ffd38b5c24148b4c241ce8cc1e000085ed74186880000000bf2cf4400057ff1590a140008bcfe89c2700008b4c2418e8a71e00005f8bcbe89f1e00005b8bc65e5d81c4f0020000c3558bec5153565733c9e877fbffff85c074698d45fc33ff504733dbff15c0a1400050ff15d8a140008bf085f674468b55fc3bd77e3f33c985d27e278b048e85c0741b6683382d75150fb7400283f869740983f872750733ffeb0333db43413bca7cd956ff1598a1400085db7407e831f6ffffeb078bcfe8a6fcffff6a00ff15c8a14000cc83ec648d1424b9dd0aad975633f656e8f7f6ffff8d44240450566808f44000ff1504a1400085c074098bc8e8c34f00008bf085f67452e8cff5ffff85c0744253556af1ff158ca1400050ff1584a14000bb8813000053ff353cf84000ff15bca14000bd02010000eb12e8e903000053ff353cf84000ff15bca140003bc574ea5d5b8bcee8584f000033c05e83c464c2040081ec2c0300008d54245cb96a6e3cf35633f656e862f6ffff8d44246050566808f44000ff1504a1400085c074098bc8e82e4f00008bf085f60f84bf000000536a028d9424cc000000b94006d856e828f6ffff8d94242c010000e801f7ffff8d84242c01000050ff1518a240008d8c242c010000e8474a00008bd8e8faf4ffff85c07472556a128d54241059e8634e0000bdc800000055ff353cf84000ff15bca140003d02010000754b8d1c5d02000000538d842434010000b90100008050a164f840008d542414f7d86a011bc02500010000508d8424dc00000050e86441000055ff353cf84000ff15bca140003d0201000074bc5d8bcee8534e00005b33c05e81c42c030000c2040081ec800400008d542470e847f6ffff6aff8d5424748d8c247c020000e8bd4a00008d84247802000050ff151ca24000518d5424048d4c2474e84b14000085c00f84c800000056ff74240cff15a0a1400033f68d54241056b90875f42489742410e80cf5ffff8d44241050566808f44000ff1504a1400085c074098bc8e8d84d00008bf085f6747ce8e4f3ffff85c074738b35bca140005355bb8813000053ff353cf84000ffd6bd02010000eb508d44247c50ff1588a1400083f8ff75378d84248402000050ff1588a1400083f8ff7404a810750c8d8c2484020000e86a120000ff7424108b5424108d8c2480000000e86111000053ff353cf84000ffd63bc574ac5d5b8d4c2404e8101400005e33c081c480040000c20400558bec5156578d45fc33ff50515157680f1b4000b9e0f24000897dfce8464d00008bf085f6741c8b0de4f3400085c9740957576a11ff75fcffd1ff75fcff15a0a140005f8bc65e8be55dc3565733ff5751515768a01b4000b9e0f24000e8054d00008bf085f674188b0de4f3400085c9740757576a1157ffd157ff15a0a140005f8bc65ec3565733ff5751515768a91c4000b9e0f24000e8cb4c00008bf085f674188b0de4f3400085c9740757576a1157ffd157ff15a0a140005f8bc65ec3558bec81ecd00000008d559856576a1259e8fd4b00006a028d9530ffffffb94006d856e872f3ffff33f6bf010000808d8530ffffff508d45985057ff15f8a1400085c0754168f4010000ff15b0a140008d45fc897dfc506a016a008d45985057ff151ca0400085c075108d9530ffffff8d4dfce8b13d0000eb0233c085c0740e4683fe057ca933c05f5e8be55dc333c040ebf556578bf933f685ff74425351e807f4ffff8bd885db74342b05ecf3400056565605c413400050565657ff157ca1400085c0740a50ff15a0a1400046eb0e6800800000565357ff15b4a140005b5f8bc65ec2040081ec70080000535556576af16a00ff1584a1400033c033ed33f68944241c896c2414897424106a006a02ff156ca140008bd833ff895c2424897c241883fbff0f84df010000b92c0200008bc148c68404900000000075f58d842490000000898c24900000005053ff1574a1400085c00f84a00100008b8c24980000003b0d4cf840000f847201000033c085f6740f394c85000f8462010000403bc672f18b3d78a14000516a00687a040000ffd78944242885c00f84410100008bb424980000008d8c24bc020000e827f2ffff8d84243c040000b950f84000506a008d442434505633f6468bd6e8014e00008d44242c50566808f44000ff1504a140008bf085f60f84f0000000ff1558a140003db7000000750956ff15a0a1400033f685f60f84d2000000ffb4249800000083642424006a006800040000ffd78bf885ff0f84ac0000008d5424208bcfe836200000578bd8ff15a0a1400085db0f848c0000008b4424203b05fcf340007579ff33ff1584a040003b0500f4400075698b15f8f340008b0b508b12e8cd18000085c075558b7c24108d4c24148d14bd04000000e86f1800008b6c241485c074398b8424980000008bd68944bd0047ff442418897c24108b7c2428518bcfe8e0fdffff8b4c241c85c06a01580f45c857894c2420ff15a0a140008bcbe8cd1700008b5c242456ff15a0a140008b7424108d8424900000005053ff1570a1400085c00f8564feffff8b7c241853ff15a0a1400085ff0f8502feffff8bcde88d1700008b44241c5f5e5d5b81c470080000c381ec580800005355578bda8be9518d542424895c2430b92cf4400033ffe86f0f000085c00f848302000085ed7525ff7424248b5424248bcbe8210d000033c94185c00f45f98d4c2420e8d70f0000e9510200008b5c24248bd38b4c242056895c241ce8411700008bf08974241485f60f842e0200008d442410897c2410508bd38bcee8a6efffff8944243485c00f840002000057ff7424148bd08d4c2418e8b0410000397c24100f84dd0100008bcfbb660100008a042988440c38413bcb72f48d8c24a4020000e8edefffff8bcf8a840c6b05000088840ca00100004181f90201000072e98d8424a00100008bd3508d4c243ce860070000538d44243c506a016a0a5a8d4c241ce88b3f000085c00f846b010000393d64f840000f84aa000000f605e8f34000010f859d0000008d442420897c242050518b4c24186a0d5ae86b3e00008bd885db0f84e40000008d442418897c241850518b4c24186a0b5ae84b3e000085c00f84bf0000008bc8e80c1600005757be000008008d4c2418566a0d5ae8113f000085c00f849c0000005757566a0b5a8d4c241ce8fa3e000085c00f84850000008b7424208d4c24148bd6e82416000085c074728b4c24148bd356e8ca1500008974241ceb608d442418897c241850518b4c24186a0c5ae8ce3d000085c0744d8bc8e8931500008d442418897c241850518b4c24186a0d5ae8ad3d00008bd885db742a5757be000008008d4c2418566a0d5ae87c3e00005757566a0c5a8d4c241ce86d3e00008bcbe84d150000578d4c2414e8913e00008d8c24a40200008bf0e870eeffff8b5c24108d8424d20200005056538d5424288d4c2420e8691800008b74241485c07417ff74241c8b4c24348bd6e8e30a00008bf8eb048b5c24108bcbe8f41400008b4c2434e8eb1400008d4c2424e8890d00008bcee8db1400005e8d4c2420e8780d00008bc75f5d5b81c458080000c3558bec81ec14020000566a026a066a0433c033f68bd1668945f4568d8decfdffffe8b948000085c07462568d85ecfdffff50ff1568a1400085c07450663975f48d4df4566a05b8a0b640008d95ecfdffff0f45c18b4d0c6a0450e88048000085c074295668a00000006a0256566800000040ff750cff1560a1400083f8ff740c50ff15a0a1400033c040eb0233c05e8be55dc20800558bec81ec6801000033d28a040a888268f840004281fa6601000072ee56578d8d98feffffe88dedffff6a108d959cfeffffb950f84000e89414000085c0754ebf34f640008bcfe825410000b92cf440008bf0e8194100003bc67e3266833c752cf440005c7527565157ff1514a2400085c0751a6aff6aff8d14752ef440008d4daee8ff40000085c0750340eb0233c05f5e8be55dc381ec980300005355578bf98bea5733dbff1588a1400083f8ff75078bcfe84d0a00008d84249c01000050518bcfe8a3feffff85c00f84a4000000b86601000048885c043475f98bcb8a8150f8400088440c384183f91072f0568bf3baff00000033c9e85f020000884434104683fe2872ea8d44244c508d4c2414e885030000be660100008bcf6aff8974243ce84a4000008d9424a60100008d8c24520100008d1442e85c4100008d9424a00100008d4c2438e865fbffff85c074228a441c38888368f84000433bde72f16aff8d9424a40100008bcde82941000033db435e5f5d8bc35b81c498030000c3558bec81ec880700008d95f0fcffffe87decffff8d85f0fcffff50ff151ca24000ff353cf84000ff1564a14000e8e0f7ffff8d8df0fcffffe8be090000b80401000048c68405f8feffff0075f58d85f8feffff508d85f0fcffff50ff152ca240008d85f8feffff505068acb640008d8578f8ffff687404000050e8fb40000083c41485c07e0b8d8d78f8ffffe8611b000033c0408be55dc3568b3520ff400081fe700200000f8cb200000033f6538bd6bbffffff7f8b0c9534ff4000330c9530ff400023cb330c9530ff40008bc1d1e983e001330c852cb84000330c9564054100890c9530ff40004281fae30000007cc481fa6f0200007d35578d3c9530ff40008b0f334f0423cb330f8bc1d1e983e0018b04852cb84000338774fcffff33c1890783c70481ffec0841007cd45f8b0d30ff4000330dec08410023cb330dec0841008bc1d1e983e0015b330c852cb84000330d60054100890dec0841008b0cb530ff40008bc1c1e80b4633c8893520ff40008bc125ad583affc1e00733c88bc1258cdfffffc1e00f33c88bc1c1e81233c15ec3ff155ca140003b0524ff4000743633d2a324ff4000a330ff400042b930ff40008b01c1e81e330169c06589076c03c24289410483c10481f9ec0841007ce2891520ff4000e9bcfeffff56578bf28bf93bf775048bc6eb16e8a4ffffff2bf78bc84633d2f7f60fafc62bc88d040f5f5ec383ec0c5355565768400000f033edc744241c100000006a0155558d442424896c2424508bfa896c24248bd98bf5ff157ca0400085c074628d4424105055556803800000ff742424ff1568a0400085c0743d55ff74242457ff74241cff155ca0400085c07429558d44241c50536a02ff742420ff1580a0400085c07412837c241810750bff74241046ff1560a0400055ff742414ff1574a040005f8bc65e5d5b83c40cc2040053555633f68bda8be9393528ff40007538578bfeb920fb40006a088bc75aa8017409d1e8352083b8edeb02d1e84a75ee89014783c10481ff0001000072dbc70528ff4000010000005f83c9ff85db741a0fb6042e33c1c1e90825ff000000330c8520fb4000463bf372e65ef7d15d8bc15bc351515355568b74241833db894c24108bc3578acb8bd666899e00010000bd0001000088024042663bc572f78bfe8b7424148a170fb6c38a04308b74241c02c202c8fec3884c24130fb6c98a0431880788143133c980fb280fb6c30f44c18a4c2413478ad84d75c65f5e5d5b5959c2040051515355578b7c24188bc233ed89442410894c240c8a9f000100008abf0101000085c0743856fec30fb6f38a143e02fa0fb6cf8a043988043e8814390fb60c3e0fb6c203c881e1ff0000008a04398b4c2410300429453b6c241472ca5e889f0001000088bf010100005f5d5b5959c204005356578bf933db43f6470402740433f6eb13f647040174616a025ee8610f00003bc60f46f36bf6188d5f08ffb6a8a94000ffb6a4a94000ffb6a0a940005357ff157ca0400085c0740533c040eb2dff1558a140003d16000980751effb6b4a94000ffb6b0a94000ffb6aca940005357ff157ca0400085c075d033c05f5e5bc3568bf1833e0074206b4604186a30ffb0a4a94000ffb0a0a940008d46085056ff157ca040008326005ec3568bf1e8ceffffff8b4e6085c97405e8f80d0000837e5c007409ff765cff1564a040005ec3515556578bf933f68bea8974240c39370f84d2000000837f04020f85c800000056568d4424145056565655ff158ca0400085c00f84af0000008b4c240c53e88d0d00008bd885db0f848f00000056568d4424185053565655ff158ca0400085c0747af64768028d6f6455565656ff742420536a2b586a13590f45c1506801000100ff1590a0400085c074518b4d00e83d0d000089476085c07442f647680255505656ff742420536a2b586a13590f45c1506801000100ff1590a0400085c0741c8d475c505656ff7500ff7760ff37ff1570a0400033c94185c00f45f18bcbe8040d00008bc65beb0233c05f5e5d59c3558becf6416802750433c0eb3e8b450c568b750889450c8d450cff3650526a406a016a00ff715cff156ca0400085c07516ff1558a140003dea00000075058b450c890633c0eb0333c0405e5dc20800568bf1e86bfeffff8b869800000085c0740750ff1564a040006a2c5848c644065c0075f85ec351535556578bf133db6a2c588d4e5c48881c0175fa8dbe98000000c601085753536a2c51ff3633edc6465d0233c0c7466010660000456689465ec7466420000000896c2428ff1570a0400085c0742c538b1d78a040008d442414506a04ff37ffd385c074166a008d8e880000005155ff37ffd385c074048bc5eb0233c05f5e5d5b59c333c085c97421566a2e5e66393175170fb751026685d2740b663bd6750966394104750333c0405ec381ec60040000535556578bc18bf26834b84000508944241c8d84247002000050ff150ca2400085c00f847d0100008d442418508d84246c02000050ff1550a140008be8896c241083fdff0f845b010000f6442418100f84950000008d4c2444e874ffffff85c00f85240100008b5e0c85db74308b7e0885ff742933ed85db741f8b178d4c24446aff6affe89f38000085c00f84f50000004583c7043beb72e18b6c24108d44244450ff7424188d84247002000050ff150ca24000f684247c040000010f84c8000000ffb4247c0400008bd68d8c246c020000ffb4247c040000ffb4247c040000e815ffffffe9a00000008b5e1485db742c8b7e1085ff742533ed85db741b8b178d4c24446aff6affe81b38000085c074754583c7043beb72e58b6c241033ff397e0476668d44244450ff15fca1400085c074108b0eff34b950ff15eca1400085c07508473b7e0472dbeb3f8d44244450ff7424188d84247002000050ff150ca24000ffb424780400008b44243833c90b4c243c50518d84247402000050ff942484040000eb048b6c24108d4424185055ff1530a1400085c00f85acfeffff55ff1538a140005f5e5d5b81c460040000c20c00515355565733f68bd95668800000006a02566a016800000040538bea8974242cff1560a140008bf883ffff743585ed741c397424187416568d44241450ff7424205557ff1548a1400085c0740333f64657ff15a0a1400085f675078bcbe8b90100005f8bc65e5d5b59c20400558bec81ec100400008d85f0fbffff5068f6000000ff1540a14000483df5000000775e6880b94000e86af8ffff506838b840006844b840008d85f8fdffff680401000050e88038000083c41883f8ff74308d85f8fdffff508d85f0fbffff50ff7508ff150ca2400085c074158b4d0833d26a00e81cffffff85c0740533c040eb0233c08be55dc204005333db85c9746b57e8b73700008bf885ff745e555657ff15e8a140008bf085f60f44f70fb70683f85c740a83f82f74056685c0752b8be833c057668906ff1588a1400083f8ff750c5357ff1568a1400085c0eb02a81074106685ed740866892e83c602ebbe33db438bcfe8bc0800005e5d5f8bc35bc3558bec81ec580400008d85f8fdffff56576834b840008bf15650ff150ca2400085c074738d85a8fbffff508d85f8fdffff50ff1550a140008bf883ffff74588d8dd4fbffffe86bfcffff85c075308bc150568d85f8fdffff50ff150ca2400085c0741bf685a8fbffff108d8df8fdffff7407e889ffffffeb05e8320000008d85a8fbffff5057ff1530a1400085c075af57ff1538a14000688000000056ff1590a1400056ff1534a140005f5e8be55dc3568bf1688000000056ff1590a1400056ff152ca140005ec3558bec51565733ff8bf257576a03576a01680000008051ff1560a1400089460883f8ff74655750ff1554a1400083f8ff744f89460485c07507893e33c040eb4c6a0468003000005057ff153ca14000890685c0742c578d4dfc51ff760450ff7608ff1544a1400085c074088b45fc3b460474c8680080000057ff36ff154ca14000ff7608ff15a0a1400033c05f5e8be55dc20400568bf1833e00740f68008000006a00ff36ff154ca14000837e08007409ff7608ff15a0a140005ec383ec44538b1d4ca040008d4424085556575033edc744241c1300000055558bf9896c24286a0757ffd38b4c2414e8e80600008bf085f60f84a80000008d44241450ff742418566a0757ffd385c00f848a0000006a025f57ff1548a040008d44242433db50435368ff010f00ff158ca1400050ff1558a040006a105848c644042cff75f88d44242c895c242c508d44241c897c243450896c243cc744244003000000ff1554a040008d44241cc744242014000000508d44242c508d442428508d442448508d44243c50ff74242cff74243c56ff1550a04000ff1544a040008bcee84d0600008b44241c5f5e5d5b83c444c381ec340a000056578d442410895424188bf933f6505789742418ff1554a1400085c0750a397424100f846a01000053566a01566a025657ff15a4a040008bd8895c242085db0f844a0100006a0156566a0453ff1528a140008944241885c00f842a01000068040100008d4c24285150ff1520a1400050ff15d0a1400085c00f84fd00000033c066898424400600008d8424400600005068ff010000ff15dca0400085c00f84d8000000a158b840008d9c24400600008944240c66a15cb840005566894424148bee668b0366894424108d8424340200006804010000508d44241850ff15a8a0400085c074798d8c2434020000e88b3200008bf881ff040100007d63578bd18d4c242c57e88932000085c0750d66837c7c285c750533ed45eb028bee85ed743f8d4424288d0478508d442414506860b840008d842448040000680401000050e80d34000083c4148d8c243c040000e82a3200008bd18b4c242050e846330000668b0383c3026685c075f585ed75096639330f854bffffff8b5c24245dff74241833f646ff1524a1400053ff15a0a140008bc65b5f5e81c4340a0000c3568b7424088b0e8b461c3b010f83db0000005355576affff7610ff15bca14000ff7610ff15a0a040008b461c8bf88366180003ff8b1e4089461c0fb744fb0a89442414ff74fb046a006a40ff1578a140008be885ed74336a026a006a008d44242050ff1520a14000500fb744fb0a5055ff15a4a1400085c075090fb744fb0a8944241455ff15a0a14000837e0c1c750e8b56088b4c2414e8c3fdffffeb116a006804010000ff7608ff742420ff56048b4c24148be885c974100fb744fb0a3bc8740751ff15a0a1400085ed7407c7461801000000ff7614ff1564a140008b0e8b461c3b010f822bffffff5f5d5b33c05ec2040081ec5c040000833d60f8400003535556576a1c5b6a1958686cb840006888b84000894c24440f47d8ff1598a0400050ff1580a140008bf885ff0f84c80100006a146a08ff352cff4000ff15b4a0400083642414008be88d442414506a14556a10ffd785c07940837c2414000f84960100008bcde8350300008b74241481c6000400008bcee80d0300008be88d4424145056556a10ffd785c0790c8bcde80c030000e9610100008b35a8a140008d84245802000033ff8944242057576a0157897c2444895c2434896c2428ffd657576a015789442438ffd6689cb8400068b8b8400089442434ff15b8a1400050ff1580a140008b35a0a140008bdf6a0289442420598b4424343b45000f83cb00000049894c243885db751657578d44242050687e3440005757ff15aca040008bd8ff74242cff15a0a04000ff742428ff1564a140006a64ff742430ff15bca140003d02010000750f5753ff159ca0400053ffd68bdfeb6a837c24300074638b7c24208b4c243c6aff6aff8d5708e8852f000085c075498b7424348d570803f68d4c24446aff8b44f5f489442444e8783000000fb744f5fa81ec140200008bfc89842464040000b9850000008db42454020000f3a5e8df0c00008b35a0a1400033ff8b4c243885c90f8528ffffff85db741e68e803000053ff15bca140003d0201000075085753ff159ca0400053ffd6ff742428ffd6ff74242cffd65f5e5d5b81c45c040000c3558bec83ec3c53566a3c8bf233db5a8bc248885c05c475f933c08955c4408945d88945f48945fc8d45c450535351ff1534a2400085c00f84da0000006a105848881c3075fa8b5dd4578b7dd885db750433c9eb2483ffff75098bcbe86a2e00008bf88d4f01e81a0100008bc885c97408578bd3e833010000890e85c974368b4df485c974148b45f080382f750c4940894df48945f085c975ef8b7dfc03f98d4f02e8de00000089460485c0750b8b0ee8e700000033c0eb5dff75f48b55f08d4801e8e50000008b45f48b4e0440ff75fc8b55f803c8e8d10000008b4604c6002f8b4604c6440701008b45f440894608668b45dc6689460c8b45d083e803740f487406c6460e00eb0ac6460e02eb04c6460e0133c0405f5e5b8be55dc353568b4424180bc075188b4c24148b44241033d2f7f18bd88b44240cf7f18bd3eb418bc88b5c24148b5424108b44240cd1e9d1dbd1ead1d80bc975f4f7f38bf0f76424188bc88b442414f7e603d1720e3b542410770872073b44240c76014e33d28bc65e5bc2100085c9750333c0c3516a08ff352cff4000ff15b4a04000c3516a00ff352cff4000ff15b8a04000c35633f639742408760d8a041688040e463b74240872f35ec20400568bf2578bf985f6750433c9eb1d566a00ff352cff4000ff15b4a040008bc885c97408568bd7e8bbffffff5f8bc15ec3568bf185d2750c8b0ee898ffffff832600eb2e833e005275106a08ff352cff4000ff15b4a04000eb10ff366a08ff352cff4000ff15b0a0400085c075025ec3890633c0405ec333c0533944240876132bca8a1c118a3a3adf750e40423b44240872ef33c05bc204000fb6cf0fb6c32bc1ebf2558d6c248881ec1c0100005668f8b840006808b94000ff15c0a0400050ff1580a1400033f685c074138d8d5cffffffc7855cffffff1c01000051ffd08a45763c01757783bd60ffffff0575278b8564ffffff85c0750833f646e9c200000083f801740983f8020f85b40000006a02e99500000083bd60ffffff0675298b8564ffffff85c075046a04eb7e83f80175046a07eb7583f80275046a09eb6c83f803757f6a0beb6383bd60ffffff0a757239b564ffffff756a6a0deb4e3c0274043c03755e83bd60ffffff05750d83bd64ffffff02754c6a03eb3083bd60ffffff06752a8b8564ffffff85c075046a05eb1983f80175046a06eb1083f80275046a08eb0783f803751a6a0a5eeb1583bd60ffffff0a750c39b564ffffff6a0c580f44f08bc65e8d65785dc3578d79f403fa8bc78d4f0c3bf9770d8138125ed9577419403bc176f38b4424088320008b44240c83200033c05fc208008b4c2408568b77082bfe8bc78d560c89118b4c241089315eebe2558bec81ec04010000568b750857568bf9e8bcfdffff8b550c85d2742533c98a041188840dfcfeffff4181f90201000072ed8d85fcfeffff8bd6508bcfe85aeeffff8bd6c70437125ed9578bcf89743708e864edffff8944370433c05f405e8be55dc2080081ec0c010000535556578d4424108bda8b9424240100008be98b8c2420010000508d44241850e826ffffff8b7424108bf885ff746885f6745b8b543e088bcfe811edffff39443e0475538b94242801000085d2742033c98a041188440c184181f90201000072f08d4424188bd6508bcfe8c2edffff8bcee8cafcffff8bc885c9741b568bd7e8e3fcffff8933894d0033c040eb0b83650000832300ebf233c05f5e5d5b81c40c010000c20c005151535556578bea8d4424148bf933db508d442414895c24148b75008bd68b0f50e87ffeffff8bcf85c074328b5c24202b7424108d530c03d6e8cdfcffff85c0744dff7424248b0f8d430c8b54242003c603ce89450053e893feffffeb318b44242083c00c03f08bd6e89dfcffff85c0741bff7424248b0fff742424034d008b542424e867feffff8bd88975008bc35f5e5d5b5959c20c0083ec1853558bda56578bf98b733c03f3897c24148b6e505553896c242cff15c4a0400085c0740733c0e9e70000006a406800300000556a0057ff15c8a040008bf8897c242085ff0f84c60000008bd58bcbe8edfbffff8944241085c00f849c00000083bea40000000076728b8ea000000085c974682b5e3403c88bd72b563483390074598be88bfa8d41048944241c8b0083f808723083c0f8d1e86a008944241c5e74220fb75471086685d2741381e2ff0f00008bc703112bc301042a8b442418463bf072de8b44241c030883390075b78b7c24208b6c24248b4424108b5c24146a0055505753ff1594a140008b4c24108bf0e821fbffff85f67517eb048b5c241468008000006a005753ff15b4a1400033ff8bc75f5e5d5b83c418c35151895424045355568bf1578b463c85d2747b837c241c0074748b8c308000000085c9746983bc308400000014765f8d3c31833f0074578b470c03c650ffd28bc8894c241085c974418b1f8b6f1003de03eeeb2379050fb7c0eb0583c00203c65051ff54242485c074208b4c241083c30489450083c5048b0385c075d783c7143907740a8b542414ebad33c0eb0333c0405f5e5d5b5959c20400558bec83ec588b4d0c33c05333db668945fc5685c9750f6a445e8bc648885c05a875f98975a88d45ec85c9508d45a80f45c185d250ff75088d45fc5368000000045353530f45c25053ff15d0a0400085c0742b8b4d1085c9740f8a441dec88040b4383fb1072f3eb10ff75f08b35a0a14000ffd6ff75ecffd68b45f4eb0233c05e5b8be55dc20c00558bec515633f68d45fc8975fc85d27511516840b9400050e84b2a000083c40ceb105251684cb9400050e8392a000083c41085c07e1bff75108b55fcff750cff7508e831ffffff8b4dfc8bf0e889f9ffff8bc65e8be55dc20c00558bec83ec1853568d45fc33db50536a208bf1895dfcff158ca1400050ff1558a0400085c075128d45fc506a206affff1540a0400085c074526a105848885c05ec75f98d45f0505653ff1530a0400085c0742d5353538d45ecc745f8020000005053ff75fc33f6468975ecff152ca0400085c0750bff1558a1400085c00f44deff75fcff15a0a140008bc35e5b8be55dc3558bec5151568d45f833f6506a086aff8975f88975fcff1540a0400085c00f84900000008d45fc5056566a19ff75f8ff1534a0400085c07572ff1558a1400083f87a75678b4dfc57e88bf8ffff8bf885ff74578d45fc50ff75fc576a19ff75f8ff1534a0400085c07439ff37ff1538a0400085c0742d8a0084c074270fb6c04850ff37ff153ca0400085c07416813800200000730346eb0b8138003000001bf683c6038bcfe845f8ffff5fff75f8ff15a0a140008bc65e8be55dc3558bec51518365fc008d45fc8365f8005657506a08518bfa33f6ff1540a0400085c0743a8b4dfce8241d00008bf085f6742385ff741f8d45f8506a04576a0cff75fcff1534a0400085c075098bcee8e1f7ffff33f6ff75fcff15a0a140005f8bc65e8be55dc356578bf933f6ff159ca140003bc7750433c0eb2a535733db564353ff1578a140008bf885ff740d5657ff15d4a0400085c00f45f357ff15a0a140008bc65b5f5ec381ec3002000055565733ff8954240c576a028be9ff156ca140008bf0c74424102c0200008d4424105056ff1574a1400085c07432eb1b396c241875158b4c240c8d5424346aff6affe89624000085c074128d4424105056ff1570a1400085c075d5eb0333ff4756ff15a0a140008bc75f5e5d81c430020000c3558bec81ec700300008d85fcfeffff5051ff152ca240008d85fcfeffff5050685cb940008d8590fcffff686c02000050e8a925000083c41485c07e148d8d90fcffffe80f00000085c0740533c040eb0233c08be55dc3558bec81ec700500008d85b0fdffff56508bf1e8f2ecffff85c00f84d90000008d85acfcffff508d85b0fdffff50ff152ca240008d85acfcffff50568d45fc6888b9400050e8ef26000083c41083f8ff0f84980000008b55fc8d8db0fdffff50e839ecffff8b4dfc8bf0e84ff6ffff85f6747b8d85b0fdffff5068a8b940008d8590faffff680e01000050e84325000083c41083f8ff7e5668040100008d85b0fdffff5068b8b94000ff15cca04000483d0201000077376a445a8bc233c948884c05b875f933c08955b851668945e88d9590faffff8d45b8c745e40100000050518d8db0fdffffe8f8fbffffeb0d8d8db0fdffffe8c0edffff33c05e8be55dc3568bf1eb18ff760c8b54240cff76088b0ee8290300008b761085f6740485f675e45ec20400568bf1578bfa85f6745585ff7451538b5c241033c9558b6c24183be977083bd9763beb028b308d4610390875f7390e74196a186a08ff352cff4000ff15b4a0400089461085c074158bf08bcf895e08896e0ce8db2300008366100089065d5b5f5ec20800568bf185f67423578bfe33f63977108b0f0f45771085c97405e817f5ffff8bcfe810f5ffff85f675df5f5ec3558bec83ec1c8d55e46a0359e86d2600008b4d083b0d4cf8400074148d55e4e858fdffff85c075088b4d08e80bfdffff8be55dc21402558bec83e4f88b4d08e8c0ecffff85c0751ab9d4b84000e837fbffff8b4d08e802f1ffff8b4d08e8a2ecffff8be55dc21000568bf15785f67469e8ebe7ffff33ffc7460401000000576a288d4e08b214e81d2700008bcee8c2e5ffff85c07443538bdfbaff00000033c9e890e3ffff88441e684383fb2072ea5bbaff00000033c9e879e3ffff88843e880000004783ff1072e78bcee8b6e7ffff85c0740533c040eb0233c05f5ec381ec24040000535556578bf98954241885ff0f848501000083ffff0f847c01000083bc2440040000000f846e0100008bac244404000085ed0f845f010000b81003000048c68404200100000075f58bcac78424200100004a985f4ee8642200008bd885db0f843301000053c744241800010000ff15f4a140008bcbe8ec2000008bd38d4c24208d34450200000056e8a8f3ffff568d4424188bd1508bcde891e6ffffff74241433c98d5424244133f685c00f44f18d8c2434010000e87bf3ffff8b9424400400008d4c24206a208d5268e866f3ffff6a208d4424188bd1508bcde84ee6ffff85c0750146ff7424148d5424248d8c2434020000e83df3ffff8b9424400400008d4c24206a108d9288000000e825f3ffff6a108d4424188bd1508bcde80de6ffff85c0750146ff7424148d5424248d8c2434030000e8fcf2ffff8b842438040000ff742418898424280100008b8424400400008984242c010000ff1588a140006a00898424300100008d4424205068100300008d84242c0100005057ff1548a1400085c07501468bcbe898f2ffff33c06685f60f94c0eb0233c05f5e5d5b81c424040000c21000558bec83e4f881ecfc040000535657895424188bf933dbb89c00000048885c045875f96aff8bd78d8c24fc000000e8b52000008d8424f800000050ff151ca240008d8c24f8000000e801ebffff8b3560a1400033c94185c00f84c101000033c050506a035051680000008057ffd68944241483f8ff7529b9d4b84000e87ef8ffff8bcfe84aeeffff33c050506a03504050680000008057ffd633c0e9780200008d4c2458e835fdffff85c00f846401000057ff15fca140008bc8e8011f00008d8c24f80000008bf0e8f31e00008bcf2bf0e8ea1e000003f08d9424f80000006a005633f68bca46566834ce4000e8a72500006a006880000000566a005668000000408d84241001000050ff1560a140008bc8894c241c83f9ff0f84f60000008b4424188bd783c07c508d44245c50ff750cff7508e81bfdffff85c00f84ca00000068202700006a08ff352cff4000ff15b4a040008bf033c08944241085f60f84a700000050506810030000ff742428ff15c4a1400033c0894424206a008d44241450681027000056ff742424ff1544a1400085c0746e817c2410102700008b4424206a015968202700000f42c18d4c241451566a00506a00ffb424080100008944243cff156ca0400085c074376a008d44241450ff74241856ff74242cff1548a1400085c0741d8b44242085c0748c33c08d58018b442418050001000050ff15e8a040008bcee874f0ffffff74241cff15a0a14000ff742414ff15a0a140008d4c2458e8aee3ffffb80802000048c68404000300000075f56aff8bd78d8c2404030000e8a01e00006683bc2400030000000f84ac00000085db0f84a40000008d84240003000050ff151ca2400085c00f848e0000006a1d8d54242859e8732100008d4c2424e8361d00008d8c24000300008bf0e8281d000083c00403c63d040100007f5f8d442424508bc150ff15f0a1400085c0744d6a00688000000033c040506a005068000000408d84241803000050ff1560a140008bf083feff74256a008d442418508b442420ffb018020000ffb01402000056ff1548a1400056ff15a0a1400085db8d8c24f80000000f45cf51ff152ca140008bc35f5e5b8be55dc20800558bec83e4f88b4d108b450c85c9776372073d00004006770f8b5514518b4d0850e8b9fcffffeb5e85c9774772073d0000a00f770c518b4d148b89e8000000eb3c85c9772e72073d0000401f770c518b4d148b89ec000000eb2385c9771572073d0000803e770c518b4d148b89f0000000eb0a518b4d148b89f40000008b550850e83ff9ffff8be55dc2100083ec0ca140ce4000535556894424108bf166a144ce4000576689442418ff15eca0400033db8be88bfb33d28bcf42d3e285d574300fb6c36683c04166894424148d44241450ff15e0a0400083f8057414ff76208bd68d4c2418ff761cff7618e896e2fffffec34780fb2072bd5f5e5d5b83c40cc383ec58a140ce40005355568944240c66a144ce4000576689442414ff15eca040006a208d5424288bf859e8a41f00006a218d54241c59e8981f000032db33f633ed33c08bce40d3e085c7744a0fb6c36683c04166894424108d44241050ff15e0a0400083f805742e0fb7442410508d44241c508d44243c6a1950e8f41c000083c4108d4424345555508d442430505555ff15e0a14000fec34680fb2072a35f5e5d5b83c458c381ec8401000083642404005355568be933f657468bda8dbd08020000833f007517e8de130000890785c00f8498010000c744241401000000f6c3010f84910000008d4c2428e8f5c6ffff6a108d442430ba112700005068000002008bcfe8be1300008bf085f6746a6a048d442414c744241410000001506800000200ba152700008bcfe8981300008bf085f674448d4518ba1627000050518bcfe8b61800008bf085f6742d6a008d85fc00000050ff15f4a0400089442410ba182700006a048d4424148bcf506800000200e8501300008bf0f6c302744e85f6744a8d442410c744241010000000508d44241c50ff15d8a040008d442418ba1927000050518bcfe8501800008bf085f6741a6a046860f840006800000200ba1a2700008bcfe8fd1200008bf0f6c304743185f6742d6a008d850001000050ff15f4a0400089442410ba142700006a048d4424148bcf506800000200e8c71200008bf0f6c308742685f674226a048d442414c744241401000000506800000200ba102700008bcfe89c1200008bf0f6c310742685f674266a048d442414c744241401000000506800000200ba172700008bcfe8711200008bf085f67511837c241401750a8b0fe8f5ebffff8327008bc65f5e5d5b81c484010000c383ec205355568bf18954242033db895c240c5785f60f848f0100008dbe080200008b0f85c90f847f0100008b860c0200008bd089442420e8d3ebffff8944241485c00f844d0100000fb746106a006a006a006a00894424288b460468a0d7400089442430ff1554a240008be885ed744433db6a048d83c4f2400050ffb3c0f2400055ff1548a2400083c30883fb1872e233c050506a035050ff74242cff74243455ff1540a240008bd885db751155ff1538a2400033db85db0f848b000000807e12028b56086a03586a07590f44c18bcb50ff742424ff74241ce8682e00008be885ed745e518d54242c8bcde8442f000085c07447837c242c4472378b0f85c97408e8dfeaffff8327008b5424288d860401000050ff7424308bcfe89b15000089860c02000085c074098bceff5678894424108b4c2428e8aaeaffff55ff1538a2400053ff1538a240008b44243448837c24240089442434750485c07e278b5c241083fb0174226810270000ff353cf84000ff15bca140003d020100000f84c6feffffeb048b5c24108b4c2414e854eaffff85db75158b0f85c97408e845eaffff83270083a60c020000005f5e5d8bc35b83c420c2040053568bf15733ff478d9e08020000893e8b0b85c9740fe814eaffff83230083a60c020000006a048d86fc00000050ff15f0a040006a155a8bcee839fcffff85c074278d86040100008bcb50e82d13000089860c02000085c0740f6a008bd78bcee8e5fdffff85c0750233ff8bc75f5e5bc3558bec83e4f883ec6833c05355568bf18bd8578dae080200008b4d0085c90f845d02000039860c0200000f865102000039060f85220200008944241cba12270000894424208d4424145051e89e1100008bf8897c242485ff0f84100200008d5e7c8bcbe84adbffff6a02586a006a288d8e84000000898680000000b2148986e4000000e8d51b0000ff7424148bd7e8101600008bcb89442418e86bdaffff33ff4785c0741c8b5424188bcbe827dbffff85c00f8412010000897c241ce9150100008d9e04010000ba002510fd536a028d442430b950f8400050ff35fcf34000e80e1e00008d442418b90100008050576a006848ce400051894c242cff151ca0400085c0750f8d5424288d4c2418e8370c0000eb0233c085c00f85970000006a048d44241c897c241c506a046a008d442438ba48ce400050b901000080e8430d00008b4d00893e85c97410e86fe8ffff8365000083a60c020000006a058d86fc00000050ff15f0a040008bd78bcee894faffff85c0741d538bcde88e11000089860c02000085c0740b6a008bd78bcee846fcffffb970ce4000e8a1eeffff6800000080575733c0505050ff1528a0400085c07523eb158d442428506848ce40006801000080ff15f8a140008bcee8befdffffe838d5ffff8b4c2424e8dfe7ffff8d442414ba1327000050518b4d00e8fc0f00008bd885db74478b8e1402000085c97413e8b7e7ffff83a6140200000083a618020000008b5424148bcbe8c8e7ffff89861402000085c0740e8b442414898618020000897c24208bcbe87fe7ffff837c241c007410837c24200074098bdfe8c8190000eb1233dbeb1433ff47393e750de8b61900008bdf8986100200008b4d00e848e7ffff83a60c02000000836500005f8bc35e5d5b8be55dc3558bec83e4f85156e821bfffff85c074748b75086830750000ffb6f8000000ff15bca140003d020100007559e8601900008b8e1002000081c1580200003bc1763b6a055a8bcec70601000000e82af9ffff85c074278d8604010000508d8e08020000e81a10000089860c02000085c0740b6a0533d28bcee8d2faffffe8adbeffff85c0758f33c05e8be55dc20400558bec515156e895beffff85c00f84cc0000008b75086810270000ffb6f8000000ff15bca140003d020100000f85ad0000006a008d86fc00000050ff15f4a040008945f88d86000100006a0050ff15f4a040008945fce8960c000089450885c074706a048d45fc33d2506800000200428d4d08e8950c000085c074566a048d45f85068000002006a025a8d4d08e87b0c000085c0743c8d8604010000508d4d08e84e0f000085c07429837d0800742350ff75088d4622ba48ce40006a036a0050b901000080e8a10a00008b4d08e8d3e5ffffe8c9bdffff85c00f8537ffffff33c05e8be55dc20400558bec83e4f881ecd40400008d942464020000b9ceb0415153565733db53e896beffff8d84247002000050536808f44000ff1504a1400085c074098bc8e85f170000eb028bc38b7d088944242885c00f8410070000e85ebdffff85c00f84ed0600008d8704010000ba4a16f658506a028d7722b950f8400056ff35fcf34000e86d1a000033c98d4424145041ba0100008051536848ce400052894f1489542428ff151ca0400085c0750d8bd68d4c2414e893080000eb028bc38b1df0a0400085c00f84cb00000033c08944242089442410894424148944241c8d442414508d442420505156e8f708000083f8ff0f84990000008b5424148d8f0401000051508d4c2420e88a0f00008b74241885f6746183642424008d442424836424180050516a025a8bcee87d0c000085c0743cff7424248d87fc00000050ffd333c98d4424184150894c24248bd1518bcee8560c000085c07415ff7424188d870001000050ffd3c7442410010000008bcee84ce4ffff8b4c2414e843e4ffff837c242001750b837c241001750433c0eb0333c0408947146a1e8d9424a800000059e8911500006a1f8d94248c01000059e88215000033f68d8424880100005656508d8424b0000000505656ff15e0a140006a288d9424c401000059e8571500006a298d94248400000059e8481500008d442410bb02000080506a01568d8424cc010000895c241c5053ff151ca0400085c075128d9424800000008d4c2410e82a070000eb028bc685c07441518d842484000000508d9424c8010000e83507000085c075286a048d442420c744242001000000506a04568d8424900000008bcb508d9424d4010000e81c080000e89d0900008d9f08020000890385c00f84d30400006a035a8bcf8937e87df5ffff85c00f84bf0400008d87040100008bcb50e86d0c000089870c02000085c00f84a304000033d28bcf5642e821f7ffff85c00f84900400008d9ffc000000397714750d5653ff15f4a0400083f80575096a0153ff15f0a0400056565768eb51400056568b35aca04000ffd68944242433c050505768795240005050ffd685c0740750ff15a0a1400083642460008d4c245083642464006a275ec7442450f8a9400089742454c7442458e8a94000c744245c03000000c74424684b444000c744247001000000897c246ce896f3ffff6a1d8d94242401000059e8ce1300008d8424200100008bce8d9424ec0000008944241ce8b51300008b351ca040008d442410506a016a008d8424f8000000b9000000805051894c2424ffd685c0750d33d28d4c2410e899050000eb0233c085c074318d442410b900000080506a016a006834ce400051894c2424ffd685c0750d33d28d4c2410e868050000eb0233c085c075756a258d9424dc02000059e83b1300006a268d54247859e82f1300008d8c24d8020000e8ef0e000033f68d9424ec000000468d044502000000508bc1b90000008050566a006a00e8500600008d4c2474e8c20e0000ba34ce40008d044502000000508bc1b90000008050566a006a00e828060000eb0333f646837f1400750d6a0053ff15f4a040003bc675096a0253ff15f0a040006a068d442420c744243098aa40008d9424bc000000c74424347001000059c7442434e8a94000c7442438030000008944243c89742440c7442444c04940008974244c897c2448e86b1200006a0b8d9424d400000059e8141200008d8424b800000050ff1598a040008bf085f6747d8d8424d00000005056ff1580a140008944241885c0745f83642414008d442414506a086affff1540a0400085c074478d442410c744241004010000508d8424dc02000050ff74241cff54242485c0741cff74244c8d542430ff74244c8d8c24e0020000ff74244ce88fd4ffffff742414ff15a0a1400056ff15e4a040008d4c242ce87bf1ffff8b8fe800000057e883eaffff8b8fec00000057e877eaffff8b8ff000000057e86beaffff8b8ff400000057e85feaffff8b8fe8000000e8ddeaffff8b8fec000000e8d2eaffff8b8ff0000000e8c7eaffff8b8ff4000000e8bceaffffffb7f8000000ff1564a1400083642420008b7424248d4424205056ff15f8a04000817c24200301000074ea56ff15a0a14000837f1400750e6a0053ff15f4a0400083f80275096a0353ff15f0a0400033f68bcf6a0d465a8937e8dbf1ffff85c00f841d0100008d8704010000508d8f08020000e8c708000089870c02000085c00f84fd00000033db8bd6538bcfe87af3ffff85c00f84e90000008d4722506848ce40006801000080ff15f8a140008d8424d80200005053536a1053ff15dca1400085c00f88a50000006a1d8d94245801000059e88e1000008d842454010000508d8424dc02000050ff15f0a1400085c0747c53688000000056535668000000408d8424f002000050ff1560a140008bf083feff743a538d44241450ffb718020000ffb71402000056ff1548a1400085c074146a0153538d8424e4020000505353ff15e0a1400056ff15a0a14000eb1fff1558a1400083f85075146a0153538d8424e4020000505353ff15e0a140008b8f14020000e878deffffe815f0ffffe8becbffff8d44242850ff150ca140008d44242850ff15a0a140008b4f04e850deffff8b4f08e848deffff8d4f7ce834d0ffff8b8f0802000085c97405e831deffff8bcfe82adeffff5f5e33c05b8be55dc2040081ecf4050000535556578b3db4a04000681c0200006a085b53ff352cff4000ffd78bf085f60f84720100006a185d5553ff352cff4000ffd78986e800000085c00f84240100005553ff352cff4000ffd78986ec00000085c00f840c0100005553ff352cff4000ffd78986f000000085c00f84f40000005553ff352cff4000ffd78986f400000085c00f84dc0000008d4c2440e8c3b6ffff33ed8bcd8a840c9804000088840e040100004181f90201000072e98bcd8a840c3d04000088440e184183f90972ef55556a016808f44000c74674394d4000c74678604f4000ff15a8a140008d56048986f80000008d8c249c050000e88ddbffff85c00f849e0000008d5424148bcbe88a0e00006a0d8d54242c59e8360e00008d442428508d44241850ff15b8a1400050ff1580a140008bf8896c24108d442410505151566861534000b9e0f24000e8df0e00008b7424108bd885f6741285ff740755556a1156ffd756ff15a0a140008bc3eb358bcee8aedcffff8b8ee8000000e86ee7ffff8b8eec000000e863e7ffff8b8ef0000000e858e7ffff8b8ef4000000e84de7ffff33c05f5e5d5b81c4f4050000c3565733ff8bf15757575752ff36ff1520a04000ff3633c94185c00f44f9ff1518a040008bc75f5ec3558bec83ec105356576a045b8d45fc895df8506a0133f6b9020000805652518975f483cfff894dfcff151ca0400085c075348d45f8508d45f4508d45f05056ff7508ff75fcff1520a04000ff75fc85c00f447df8ff1518a040003bfb7508395df075038b75f45f8bc65e5b8be55dc20800558bec5151538b5d148d45f85657506a0133ffb901000080576848ce400051894df883ceff897dfc893bff151ca0400085c075638d45fc5057ff751057ff7508ff75f8ff1520a0400085c075418b4dfc85c975048bf7eb3683c104e865dbffff8bf885ff74288d45fc5057ff75106a00ff7508ff75f8ff1520a0400085c075078b75fc893beb078bcfe84edbffffff75f8ff1518a040005f8bc65e5b8be55dc21000558bec515633f6894dfc568d45fc508b450c5683c802505656565251ff1524a0400085c07527ff7518ff7514ff751056ff7508ff75fcff1514a04000ff75fc33c94185c00f44f1ff1518a040008bc65e8be55dc21400558bec5156578bf98d45fc5033c951516a0157894dfcff1534a0400085c07539ff1558a1400083f87a752e8b4dfce89adaffff8bf085f674208d45fc50ff75fc566a0157ff1534a0400085c074048bc6eb098bcee88bdaffff33c05f5e8be55dc3558bec83ec105356578bfa8bf16a0157ff1510a0400085c0747a33db53536a0157ff150ca0400085c07469538d45fc506a016898ce4000ff1508a0400085c0744e8d45f4895df8508d45f8508d45f050ff75fcff1504a0400085c07414ff75f4ff75f8ff75f057ff1500a0400085c07509ff75fcff1598a1400083c8ff85f67415c7060c000000897e04895e08eb078b45fceb0233c05f5e5b8be55dc3558bec83ec10568bf18d4df08b46288d564483e84450e81ec9ffff6a108d56348d4df0e85edafffff7d85e1bc0408be55dc36a446a08ff352cff4000ff15b4a0400085c07407c7402844000000c35153558be98bda56578b7c24208b4500895c24108d57108b402803d03bd00f868e00000085db0f8486000000e8c1d9ffff85c0747d8b6d008b5c24188b752803f58d4e1085ff750383e3fef6c301742a51518d46088bd750518b4c242c8938e83317000083f804750583e3feeb0485c075408d4e10f6c3017511897e0885ff740a8b54241c57e81dd9ffff8b452883c0100346083d0000a00077178b4c2410890e895e04897e0cff453089452833c040eb0233c05f5e5d5b59c20c0085d27513395130740b8379285472058d4144eb0b33c0c38b420883c01003c28bd02bd1568b712883c2103bd677098b480803ca3bce760233c05ec35356578bda8bf933d2eb16391e750e8b460425000000703944241074158bd68bcfe89fffffff8bf085f675df5f5e5bc204008bc6ebf65156578bf933f68b4f0c85c9744183c102e83ed8ffff8bf085f67433f647040174208b57088d4c240851568d4f10e8e319000085c075188bcee82dd8ffff33f6eb0dff770c8d57108bcee82cd8ffff5f8bc65e59c3558bec5633f656e869ffffff85c0742f83780c0475298b4d0c85c9741ff640040174148d550c528b5008518d4810e88e1900008bf0eb088b4010890133f6468bc65e5dc20800565733f656e825ffffff8bf885ff741a8bcfe84effffff8bf085f6740d8b54241085d274058b4f0c890a5f8bc65ec2080051535556578bfa8bd98bf72b338b6f088bd68b0b83c51003eee8abd7ffff8944241085c00f8484000000ff7424208970288d4c2414ff742420ff4830ff7424208b17e8c0fdffff85c074588b038b78282bfd74308b4424108d4c24108b502803d7e893d7ffff85c0741a8b7424108b135703d58b4e2803cee832d7ffff017e2833ffeb048b74241085ff751b817e280000a00077128b0be803d7ffff33c0893340eb0d8b7424108bcee8f1d6ffff33c05f5e5d5b59c20c008b442404568bf12500000070508b0ee832feffff85c07417ff7424108bd08bceff742410ff742410e81bffffffeb0233c05ec20c0081ec10010000538bc133d25556578b288bcd89442418e8bbfdffff33ffeb73393e76668b5e04f7c300000c007404893eeb5781e3fffff0ff8bd6895e0481e300000070eb1d8b0a3b0e75178b420425000000703bc3750bf7420400000e007511893a8bcde86dfdffff8bd085d275d6eb18893e8b4204a9000008007404893aeb0825fffff0ff8942048bd68bcde844fdffff8bf085f67587e861fcffff8bf08974241085f60f84cd00000033d2eb62393b765c8b43088d4c24108b562883c01003d089442414e841d6ffff8b74241085c00f849a0000008b4e288b0303ce89018b43048941048b43088941088b430c89410c397908760eff71088d531083c110e8bdd5ffffff46308b4424140146288bd38bcde8befcffff8bd885db75918b46288d564483e8448d4e3450e8d5c4ffff85c0743d8b8c24240100008b5e2885c9741e8a040f88443c1c4781ff0201000072f08d44241c8bd3508bcee82cc6ffff8bcde84bd5ffff8b44241889308bc3eb098bcee83ad5ffff33c05f5e5d5b81c410010000c2040081ec04010000535556578bbc24180100008bda8bf18d47bc3dbcff9f000f878f0000008bac241c01000085ed741233c98a042988440c104181f90201000072f085f6752785ed740e8d4424108bd7508bcbe8afc5ffff397b28775e8bcbe8e3faffff85c074538b4328eb508bcfe8a2d4ffff890685c0743a578bd38bc8e8b9d4ffff85ed740e8b0e8d442410508bd7e871c5ffff8b0e3979287710e8a5faffff85c074078b068b4028eb108b0ee879d4ffff85f6740383260033c05f5e5d5b81c404010000c2080083ec1453555657894c24148bea8b4c242c33dbe87a01000085c07e55508bd1e8240100008bf885ff74478d4424188bcf50e8ce0400008bcf8bf0e824d4ffff85f6742eff7424208b4c24188bd5ff74241c6800000200e870faffff8b4c24188bd8e8fdd3ffff6a0c5949c6440c180075f85f5e5d8bc35b83c414c20800558bec8b45088bca83f8ff7505e81501000053578b7d0c33db5353ff75105750515368e9fd0000ff15fca04000395d107e0b33c93b45100f4dc1881c385f5b5dc20c00538b5c2408555633f68bea5783fbff75098bcde8cc0000008bd85656538bd5e899ffffff8bf885ff7e18478bcfe85ad3ffff8bf085f6740a5756538bd5e87bffffff5f8bc65e5d5bc20400558bec8b45088bca83f8ff7505e87500000057ff75108b7d0c5750516a006a00ff1500a14000837d10007e0c33c93b45100f4dc166890c475f5dc20c00535556578b7c241433f68bea83ffff75098bcde8320000008bf8565657e8a1ffffff8bd885db7e19438d0c1be8d3d2ffff8bf085f6740a5356578bd5e882ffffff5f8bc65e5d5bc2040033c085c9740b3801740740803c080075f9c333d28bc285c9740c6639117407406639144175f9c3518bc1890424538bda85c0751385db740883c8ffe9f500000033c0e9ee00000085db750833c040e9e2000000558b6c241483c9ff56578b7c24183bf975633be975530fb70be83d0300008b6c24100fb7f0668b4d00e82d0300000fb7f82bfe0f85950000000fb7332beb6685f60f848700000083c302668b0c2b0fb733e8050300008bce0fb7f8e8fb0200000fb7c02bf874d7eb658bc8e84fffffff8bf883c9ff3be975098bcbe83fffffff8be83bfd754685ff744285ed743e836424180085ed7e37668b0be8bc0200000fb7f08b442410668b08e8ad0200000fb7f82bfe75198b44241883c302834424100240894424183bc57ccdeb022bfd33c94185ff6aff580f4fc1f7df1bff23c75f5e5d5b59c208008b442404538bd956578bfa83f8ff75078bcfe8c1feffff8d34008bd7568bcbe883d1ffff33c05f6689041e5e5bc2040051568bf185f6750433c0eb2257e896feffff8d3c008d4f02e833d1ffff8bc885c97408578bd6e84cd1ffff8bc15f5e59c3568b74240c85f67f0583c8ff5ec38bc6578b7c240c85f6740748c604380075f98d44241850ff7424185657ff1500a24000c64437ff0083f8ff75098bcf5f5ee921feffffc60438005f5ec38b4c240885c97f0483c8ffc3568b742408578d3c098bc785c0740748c604300075f98d44241850ff7424185156ff1520a2400033c966894c37fe5f83f8ff75088bce5ee9e4fdffff33c966890c465ec383ec0c5355568bf2894c24145733ff897424148bce897c2410e8befdffff8bd88d2c5d02000000eb048b74241481c50004000081c30002000081fd0200400177358bd58d4c2410e8a9d0ffff8b7c241085c07422ff742420565357ff1520a240008bf085f678c28d43ff3bf07dbb33c066890477eb0383ceff85f679098bcfe817d0ffffeb068b44241889385f8bc65e5d5b83c40cc204005151535556578bea894c241433ff8bcd897c2410e819fdffff8bd881c30002000081fb0000a00077348d53018d4c2410e828d0ffff8b7c241085c07420ff74241c555357ff1500a240008bf085f678cb8d43ff3bf07dc4c6043e00eb0383ceff85f679098bcfe898cfffffeb068b44241489385f8bc65e5d5b5959c204008b5424088d44240c8b4c240450e870ffffffc38b5424088d44240c8b4c240450e8c5feffffc3558bec5156e896fcffff8bf085f67e23568bd1e8a4fbffff8b5508890285c074128bc8897204e863fcffff89420833c040eb0233c05e8be55dc20400b800020000663bc8730d0fb7c90fbe8158b0400003c1c356be60b24000b8a0030000663bc87211663b4e02761083c6080fb7066685c075ea668bc15ec30fb7060fb7d18b4e042bc85e0fbe041103c2c3560fb7f133c0578bfa33d2663b04f592b2400073248b04f594b240000fb7ca8a04083204f590b2400032c242880439663b14f592b2400072dc0fb704f592b24000c60438005f5ec353560fb7f133c05733ff8bda663b04f592b2400073348b04f594b240000fb7d7660fbe0c10b8ff0000006633cf6623c80fb604f590b240006633c84766890c53663b3cf592b2400072cc0fb704f592b2400033c95f5e66890c435bc3568bf156ff150ca1400056ff15a0a140005ec3568bf16aff56ff15bca1400085c074123d80000000740b56ff15a0a1400033c05ec38bc65ec3568bf166833e40720f689b000000ff1510a1400033c0eb38837c240800742e33c05050ff742414ff7424145050ff15aca040008bc885c974db0fb706894c860466ff068b44241885c07402890833c0405ec21400558bec83ec188d45e850ff1518a140008d45f8508d45e850ff1514a140008b4df88b45fc81c10080c12a6a00688096980015214e62fe5051e8e6ccffff8be55dc38b44240483ec205355568ada0fb6d0578bf90fb6cbe873bcffff8bf0e823bcffffbb80d74000bd94d74000a900010000740a895c2428896c242ceb08896c2428895c242c836424140033c933c0894c2410894424346a205a85f60f84cf0000008b54243883e204c7442424010100008954241c83f902752ce8c7bbffffa900010000740a895c2428896c242ceb08896c2428895c242c8b44243433c98b54241c894c24108b4c8c28894c2418395c24186a06c744242413000000590f444c2420894c242085d2742d2b44241483f8017624e86ebbffff234424243b44242475118b4424346a20598944241466890c47eb218b4c24208d51ff33c9e88ebbffff8b4c2418660fbe04088b4c24346689044f8bc18b4c2410408b54241c4189442434894c24103bc60f8247ffffff6a205af644243804741585f674118d47fe8d0470663910750683e8024e75f533c0f64424380266890477740b668b0fe8defcffff668907f644243801740757ff1528a240005f5e5d5b83c420c20800558bec81ec080200005356578bda8bf933f6ff75148a550c8d8df8fdffffff7510e85ffeffff8d85f8fdffff505357ff150ca2400085c07420837d0800740eff750857ff1508a2400085c0740c57ff1588a1400083f8ff74114683fe6472b333c05f5e5b8be55dc2100033c040ebf2558d6c248881ecd00200008d85a8fdffff53565033db8bf153536a2453ff15dca1400085c0743f66837dc47b756b33c0668945108d45c45650ff1564a2400085c0755633db43eb5a8d85a8fdffff50ff1510a240008d85a8fdffff50ff151ca2400085c074268d85a8fdffff50ff1504a240006a648d45b0508d85a8fdffff50ff151ca1400085c074beeb9b6a105848881c3075fa33c0eb0b6a105848881c3075fa8bc35e5b8d65785dc3558bec83e4f881ec180100005633f6578bfe8a040f88443c084783ff1072f3315424088bce663154240cc1ea10663154240e8bd68a440d08304414104133c083f9040f44c84283fa0872e98b4d1485c974218a040e884434184681fe0201000072f08d442418506a105a8d4c240ce833bbffff6b7d10148b8760b6400085c0741c8b750c8d9750b64000508bcee8a3f8ffff8b8760b640008d0446eb038b450c6a28508d44241050ff1560a240005f5e8be55dc2100051518b0133d2568b7424102bc689414089514485f6747d8b414c538b5950558b6948894424188b4158578b79542bdf894424108b415c894424140fb6042a0fb64c2a01c1e00533c80fb6442a02c1e10533c88b44241c69c95f9f0000c1e90581e1ffff00008b048889043b8b44241c8914888b442410c707010800008d7f04ff04880fb7042a8b4c2414891481424e75a95f5d5b5e5959c20400535556578bf933c08b0f81c10010000089474889474c89475089475489475889475ce83ec9ffff8b35b4a04000bb00000400536a08ff352cff4000894748ffd689474c8b078d0c8500200000e814c9ffff8947508b078d0c8500200000e803c9ffff536a08ff352cff4000894754ffd6536a08ff352cff4000894758ffd68be88b4748896f5c85c00f84f700000033c039474c0f84ec0000003947500f84e30000003947540f84da0000008b575885d20f84cf00000085ed0f84c70000008b37b8000800008947048947088d8e000800008d8100080000894f3883f8ff720833c040e9a10000008b474803c189774089473c33c98bc348880c1075fa4bc6042bff75f98b471c894f2c894f24894f288b501c8b40242bc2894f30894f448947147425b9000800003bc17603894f14ff77148b4f48e853c8ffff8b4f1c8b471401472c01411c33c98b472c3b47387503894f2c837f14027210837f2800760aff77288bcfe8fefdffff8b47448947343b474072052b4740eb062b474003473889473433c0eb036a03585f5e5d5bc20400568bf1578b4e5ce8e1c7ffff8b4e5833ff897e5ce8d4c7ffff8b4e54897e58e8c9c7ffff8b4e50897e54e8bec7ffff8b4e4c897e50e8b3c7ffff8b4e48897e4ce8a8c7ffff897e485f5ec383ec0c5355568bf18bda57897424188b7e308b564803fa8b6e0c8b461403c7894424148a4c2fff884c2413eb7403d34889442420384c2aff755e8a042a3a042f75568a023a0775508a42013a470175488b7424148d4f0283c202413bce73078a01423a0274f48b7424182bcf3bcd76248be9894e0c895e203b4e14742c3b4e0873278b46543b0c98771f8a4c39ff884c2413eb048a4c24138b46508b56488b1c988b44242085c075845f5e5d5b83c40cc2040053578bf98bda8b474085c07544568b77480fb6141e0fb6441e01c1e20533d00fb6441e02c1e20533d08b475869ca5f9f0000c1e90581e1ffff0000ff0c880fb7041e8b4f5c5e391c81750a830c81ffeb04488947405f5bc3515355568bf1578b7e308b5e480fb6141f0fb6441f01c1e20533d00fb6441f02c1e20533d08b464c69ea5f9f0000c1ed0581e5ffff00008b0ca88b4650894c2410890cb88b4e588b14a98d42018904a98b46043bd0760585c00f45d08b464c893ca80fb6041f8b6e0c8b5e148946183beb721885db7504834e18ff8b465483661000c704b801080000eb588b46480fb70c078b465c8b048883f8ff741e6a02593be97306894e0c89462083fb03720c528b5424148bcee83afeffff8b560c3bd576188b4e303b4e2076052b4e20eb088b46382b462003c8894e108b4e308b46548914888b56348bcee8bbfeffff8b56308b46485f0fb70c028b465c5e5d5b89148859c3568b711c8b461c3b462473090fb6104089461ceb0383caff85d2790d8b411485c0741d48894114eb178b712c8b414888140681fe0008000073068b413c881406ff412c33d28b41385e39412c750389512cff41303941307503895130ff41343941347503895134c35155568bea8bf18974240885ed747a53578b56348bcee822feffff8b5e308b7e480fb60c3b0fb6443b01c1e10533c80fb6443b02c1e10533c88b44241069f15f9f00008b504c8b4850c1ee0581e6ffff00008b04b28904998b4c2410891cb28b4154c70498010800008b4158ff04b08b7424100fb70c3b8b465c891c888bcee814ffffff4d758a5f5b5e5d59c353558b6c24108bda578bf985ed7419568b7424148bcb8bd62bd5e854ffffff2bf5460177405eeb098b4424102bc50147408bcbc7430c01000000e8c9fdffff8b430c8bcb89470c8b4310894710e8b9feffff33c03943187d0d89470889470ce84efcffffeb078b4314408947088b471c2b47088947188b473c85c0741a8b4f403b4f487612ff70046a03ff774451ff10814748000400005f5d5bc208005356576a025b8bf93bd372488b74241075053b7704773d3977046afe1bc9f7d9582bc103d03b771475056a0358eb138d4effc1e9086a0b5885c9740603c3d1e975fa03c383fa03720e83ea0303c3d1ea75faeb0383c8ff5f5e5bc20400568bf1578bfa8b4e2c83f920732185c9750c8b463489463083c0048946348b46288d04478946288d410189462ceb348b4e288bc18b5630c1e8088842018bc1880ac1e810884202c1e918884a038b463489463083c004894634897e28c7462c010000005f5ec35356578b7c24108bda8bf185ff742833d28bce42e881ffffff8b4e343b4e38730c8a03880133c0ff463440eb0233c04385c0740c4f75d833c0405f5e5bc2040033c0ebf653578bfa8bd983ff027231566a045e83c70203f63bfe73fad1eed1ee8bcb8bd623d7f7da1bd2f7dae829ffffff33d28bcbe820ffffff83fe0277df5e83e7018bcb8bd7e80effffff33d28bcb5f425be902ffffff535556578bfa8bf133d2e8f3feffff8b5c24148bce3b5e14751533d2e8e1feffff33ed8bce458bd5e8d5feffffeb1f8d53ffc1ea0842e871ffffff8b4e343b4e38735a8d43ff33ed8801ff463445395e041bc983c8fff7d92bc18bce03f883ff04721c33d2e898feffff33d28bcee88ffeffff8d57fc8bcee82fffffffeb163bef1bd2f7dae878feffff23fd8bce8bd7e86dfeffff33c0895e1440eb0232c05f5e5d5bc20400558bec83e4f881ecdc0000008b450c5356578b30894c241885f675086a0458e97f0300006a4c5848c64404280075f88b5d088d04118944244c894c2448894c244433c98d041ec744242c000d0000894424608bf9b800008000c744242801100000895c245c894c2464897c2410898424880000003bd07311b8000100003bd00f47c2898424880000008d442428894c243c894c2470894c246c894c2468518d8c248c000000898424a8000000e8d4f7ffff8bf085f6740e8d8c2488000000e851f9ffffeb0233f685f60f85d20200008b442464c784248c00000000100000c78424900000000008000085c07409ff70046aff5656ff106a006a008d942490000000c7442444010000008d4c2430e850fcffff397c24300f86c70100008b5c24388b7c24348b4c24108b44245c2b450885c98944246c8b4424180f44442440897c241c899c24840000008944241883ff020f824b010000750a3b5c242c0f873f010000836424140081ff00080000732c3b5c243c7426538bd78d4c242ce87efcffff8944247c8d47ff8944242483f8027615c744242402000000eb138364247c0033c08944242485c00f84a000000033db8b44241c394424300f86900000003d000800008d9424880000006a001bc08d4c242c25000c000005000400006a0189842494000000e878fbffff8b54241483c3098b7c24344289542414895c242083ff0272418b5c24388d4c2428538bd7e8ecfbffff8b5424148984248000000085c0781e8b4424208bcf2b4c241c0384248000000003ca6bc905034c247c3bc87f558b5c24203b5424240f8262ffffff8b7c24108d4c24288b54241857e862fcffff85c00f842a010000ffb424840000008b5c24208d4c242c33ff8bd3897c2414e8d6fcffff84c00f84060100008b442414405053eb158b4c241003ca894c2410eb30416a00894c24146a018d942490000000c7842494000000001000008d4c2430e89dfaffff8b4c24108b7c24348b5c2438837c2430000f874cfeffff8b7c24108b5d088b5424188d4c242857e8d1fbffff85c00f849900000033d28d4c2428e858fbffffba000000018d4c2428e8f4fbffff8b44245c3b4424607376c600ff8b44245c40837c2454008944245c763deb0b33d28d4c2428e820fbffff837c24542075ee8b4c24508bc18b542458c1e8088842018bc1880ac1e810c1e918884202884a0383642454008b44245c8b4d0c2bc383642458008944246c89018b4c246485c97411ff71046a0450ff742474ff11eb036a045e8d8c2488000000e873f6ffff8bc65f5e5b8be55dc2100083ec185355565733ff8954242433c08bd940895c24208bcf894424188bf78bef8b54242c85c9740a498bc7d3e883e001eb0e8b3c1e83c6046a1f8bc759c1e81f85c0740a8a041e88042a4546ebd633d2896c24144285c9740a498bc7d3e883e001eb0e8b3c1e83c6046a1f8bc759c1e81f8d145085c9740a498bc7d3e883e001eb0e8b3c1e83c6046a1f8bc759c1e81f85c074c18974241083fa0275068b6c2418eb1f0fb62c1e8d42fdc1e00803e8468974241083fdff0f84dc00000045896c241885c9740a498bc7d3e883e001eb128b3c1e83c6046a1f8bc78974241459c1e81f85c9740a498bd7d3ea83e201eb128b3c1e83c6046a1f8bd78974241459c1ea1f8d144285d275474285c9740a498bc7d3e883e001eb0e8b3c1e83c6046a1f8bc759c1e81f8d145085c9740a498bc7d3e883e001eb0e8b3c1e83c6046a1f8bc759c1e81f85c074c18974241083c2028b5c2414b8000d00008b74242c3bc51bc02bdd035c242cf7d88b6c241403d08954241c8b54242c8a0388042a458b54241c438a0388042e45434a75f68b7424108b5c2420e987feffff8b4424308b5c24145f891833c03b7424205e5d0f94c05b83c418c20800558bec51f6451002b800f704845356be00f744840f45c6f64510045774050d0000800033fff6451001575068d8f240005768d8d7400052baecd74000b8e4d740000f44c25051ff154ca240008bf085f60f848d0000006a045b8d45fc897d10508d4510895dfc506a1f56ff1558a2400085c07415814d10803301008d451053506a1f56ff1548a24000f645100274068bc78bcfeb086a13b8f0d7400059ff750cff7508515056ff1550a2400085c0742c578d4508897d0c508d450c895d0850681300002056ff153ca2400085c0740d817d0cc800000075048bc6eb0956ff1538a2400033c05f5e5b8be55dc20c00515153555657b80010000033ff8bda897c24148be9894424108bd0eb3d8b7424148d44241050ff7424148d04375055ff1544a2400085c07432837c241000743d037c241081ff0000a000771fc7442410001000008d97001000008d4c2414e8a8bbffff85c075b68b7424148bcee83fbbffff33c05f5e5d5b5959c2040085db74078933897b04eb078bcee822bbffff33c040ebe0cccccccccccccccccccccccccccccc5583ec2789e5515256e880100000601100005c1100005811000054110000641100009c1100008811000084110000401100003c1100003811000034110000441100007c11000068110000391a0000201100001c1100001811000014110000241100005c110000481100004411000000110000fc100000f8100000f4100000041100003c1100002811000024110000e0100000dc100000d8100000d4100000e41000001c110000a611000004110000c0100000bc100000b8100000b4100000c4100000fc10000086110000e4100000a01000009c1000009810000094100000a4100000dc10000066110000c4100000801000007c100000781000007410000084100000bc10000046110000a4100000101100000c110000081100000411000000110000fc100000f8100000f4100000c4100000c0100000bc100000b8100000b4100000b0100000ac100000a8100000301000002c1000002810000024100000201000001c1000001810000014100000101000000c100000081000000410000000100000fc0f0000f80f0000f40f0000f00f0000ec0f00000e110000d40f0000ae100000aa100000bf170000ec17000001120000a4110000cc0f00002f100000c00f0000bc0f0000b80f0000b40f0000b40f0000b00f0000ac0f0000a80f0000a40f0000a00f00009c0f0000980f0000940f0000900f00008c0f0000880f0000840f0000800f00007c0f0000780f0000db0f0000e6110000cc110000cf0f0000500f00004c0f0000480f0000440f0000400f00003c0f0000380f0000340f0000300f00002c0f0000280f00004e110000300f00002c0f0000280f0000240f0000200f00001c0f0000180f0000140f0000100f00000c0f0000c3100000040f0000000f0000fc0e0000f80e0000f40e000044100000501000003c10000048100000e00e0000dc0e0000d80e0000d40e0000d40e00000c0f0000c80e0000c40e0000c00e0000bc0e0000b80e0000b40e0000b40e0000b00e0000ac0e0000a80e0000a40e0000a00e00009c0e0000980e0000e00e0000dc0e0000d80e0000d40e0000d00e0000cc0e0000c80e0000c40e0000db0e0000d70e0000b70f0000640e0000860f0000820f0000c30e0000450f00006c0f00004c0e0000970f0000440e0000400e0000400e0000680e0000340e0000200e00001c0e0000180e0000140e00002b0f0000270f0000180e0000140e00008a170000bc17000051180000af1800002a19000078190000de190000311a0000f40d0000f00d0000ec0d0000e80d0000e40d0000e00d0000dc0d0000d80d0000100e00000c0e0000c60f0000c80d0000c00d0000bc0d0000b80d0000b40d00007e0e0000ac0d0000f315000036160000a00d00009c0d00002c1000005a100000900d00008c0d0000880d0000840d0000800d00007c0d0000a8100000c5100000e2100000ff100000580d0000540d0000be0f00005c0d0000580d0000540d0000500d00004c0d0000a60f0000440d00009e0f00002c0d0000380d0000920f0000200d00001c0d0000180d0000140d0000100d00000c0d0000080d0000040d000085140000fc0c0000f80c0000f40c0000f00c0000ec0c0000e80c0000e40c0000280e0000240e0000200e00001c0e00003e0f00003a0f0000360f0000320f0000c00c0000bc0c0000b80c0000b40c0000b00c0000ac0c0000a80c0000a40c0000b00c0000ac0c0000a80c0000a40c0000a00c00009c0c0000f60e0000f20e0000bc150000ea0e0000db150000e20e0000de0e0000da0e0000d60e0000d20e0000600c00005c0c0000580c0000540c0000500c00004c0c0000480c0000440c0000400c00003c0c0000380c0000340c0000300c00002c0c0000280c0000240c0000200c00001c0c0000180c0000140c0000100c00000c0c0000080c0000040c0000000c0000fc0b0000f80b0000f40b0000f00b0000ec0b0000e80b0000e40b0000e00b0000dc0b0000d80b0000d40b0000d00b0000cc0b0000c80b0000c40b0000c00b0000bc0b0000b80b0000b40b0000c90b0000c50b0000a80b0000a40b0000a00b00008e100000151100009c110000900b00008c0b0000880b0000940b0000800b00007c0b0000e60d0000e20d0000700b00006c0b0000680b0000640b0000b00b0000ac0b0000890c0000850c0000810c00007d0c0000980b0000940b0000900b00008c0b0000880b0000840b0000800b00007c0b0000780b0000740b0000200b00001c0b0000180b0000140b0000100b00000c0b0000080b0000040b0000000b0000fc0a0000f80a0000f40a0000f00a0000ec0a0000e80a0000e40a0000f00a0000ec0a0000e80a0000d40a00004b0b0000cc0a0000360d0000320d0000d00a0000cc0a0000c80a0000b40a00002b0b0000ac0a000068110000a40a0000a00a00009c0a0000980a0000940a0000900a00008c0a0000880a0000840a0000800a00008c0a0000ec0e0000740a0000700a00006c0a0000680a0000640a0000600a00005c0a0000580a0000540a0000500a00004c0a0000480a0000d90e0000500a00004c0a0000480a0000440a0000400a00003c0a0000380a0000340a0000200a00001c0a0000180a0000140a0000100a00000c0a0000a90b0000040a0000000a0000fc090000f8090000f4090000f0090000ec090000e8090000e4090000e0090000dc090000d8090000d4090000d0090000cc090000690b0000c4090000c0090000bc090000b8090000b4090000b0090000ac090000a8090000a4090000fc0b00009c0900009809000094090000900900008c0900008809000084090000800900007c0900007809000074090000700900006c09000068090000d20b0000600900005c0900005809000054090000500900004c0900004809000044090000400900003c09000038090000340900009e0b00009a0b0000960b0000920b0000390900008a0b0000860b0000820b00002909000025090000760b00001d0900006e0b00006a0b0000660b0000620b0000f0080000ec080000e8080000520b0000f9080000f5080000f1080000ed080000e9080000e5080000360b0000320b0000d9080000d5080000d1080000cd0800001e0b00001a0b0000160b0000120b0000b9080000b5080000b1080000ad080000a9080000a5080000f60a00009d0800009908000095080000910800008d0800008908000085080000810800007d0800007908000075080000c60a0000c20a0000be0a0000ba0a0000b60a0000b20a0000ae0a0000aa0a0000a60a0000a20a00009e0a00009a0a0000960a0000920a00008e0a00008a0a0000860a0000820a00007e0a00007a0a0000760a0000720a00006e0a00006a0a0000660a0000620a00005e0a00005a0a0000560a0000520a00004e0a00004a0a0000460a0000420a00003e0a00003a0a0000360a0000320a00002e0a00002a0a0000260a0000220a00001e0a00001a0a0000160a0000120a00000e0a00000a0a0000060a0000020a0000fe090000fa090000f6090000f2090000ee090000ea090000e6090000e2090000de090000da090000d6090000d2090000ce090000ca090000c6090000c2090000be090000ba090000b6090000b2090000ae090000aa090000a6090000a20900009e0900009a09000096090000920900008e0900008a09000086090000820900007e0900007a09000076090000720900006e0900006a09000066090000620900005e0900005a09000056090000520900004e0900004a09000046090000420900003e0900003a09000036090000320900002e0900002a09000026090000220900001e0900001a09000016090000120900000e0900000a0900000609000002090000fe080000fa080000f6080000f2080000ee080000ea080000e6080000e2080000de080000da080000d6080000d2080000ce080000ca080000c6080000c2080000be080000ba080000b6080000b2080000ae080000aa080000a6080000a20800009e0800009a08000096080000920800008e0800008a08000086080000820800007e0800007a08000076080000720800006e0800006a08000066080000620800005e0800005a08000056080000520800004e0800004a08000046080000420800003e0800003a08000036080000320800002e0800002a08000026080000220800001e0800001a08000016080000120800002f0700002b0700000608000002080000fe070000fa070000f6070000f2070000ee070000ea070000e6070000e2070000de070000da070000d6070000d2070000ce070000ca070000c6070000c2070000be070000ba070000b6070000b20700006b05000067050000630500005f0500005b0500005705000053050000240500008e0700008a07000086070000820700003b05000037050000330500002f0500006e0700006a07000066070000620700005e0700005a07000056070000520700000b0500000705000003050000420700003e0700003a07000036070000320700002e0700002a07000026070000220700001e0700001a07000016070000120700000e0700000a0700000607000002070000fe060000fa060000f6060000f2060000ee060000ea060000e6060000e2060000de060000da060000d6060000d20600008b0400008704000083040000c2060000be060000ba060000b6060000b2060000ae060000aa060000a6060000a20600009e0600009a06000096060000920600008e0600008a06000086060000820600007e0600007a06000076060000720600006e0600006a06000066060000620600005e0600005a06000056060000520600000b0400000704000003040000ff0300003e0600003a06000036060000320600002e0600002a06000026060000220600001e0600001a06000016060000120600000e0600000a0600000606000002060000fe050000fa050000f6050000f2050000ee050000ea050000e6050000e2050000de050000da050000d6050000d2050000ce050000ca050000c6050000c2050000be050000ba050000b6050000b2050000ae050000aa050000a6050000a20500009e0500009a05000096050000920500008e0500008a05000086050000820500007e0500007a05000076050000720500006e0500006a05000066050000620500005e0500005a05000056050000520500004e0500004a05000046050000420500003e0500003a05000036050000320500002e0500002a05000026050000220500001e0500001a05000016050000120500000e0500000a0500000605000002050000fe040000fa040000f6040000f2040000ee040000ea040000e6040000e2040000de040000da040000d6040000d2040000ce040000ca040000c6040000c2040000be040000ba040000b6040000b2040000ae040000aa040000a6040000a20400009e0400009a04000096040000920400008e0400008a04000086040000820400007e0400007a04000076040000720400006e0400006a04000066040000620400005e0400005a04000056040000520400004e0400004a04000046040000420400003e0400003a04000036040000320400002e0400002a04000026040000220400001e0400001a04000016040000120400000e0400000a0400000604000002040000fe030000fa030000f6030000f2030000ee030000ea030000e6030000e2030000de030000da030000d6030000d2030000210100001d010000190100001501000012010000360100003d0100000501000001010000fd000000f9000000f5000000f2000000ed000000e9000000e5000000e1000000dd000000d9000000d5000000d2000000cd000000c9000000c5000000c1000000bd000000b9000000b5000000b1000000ad000000a9000000a50000005eff752f8f4523c6452200c7450220000000c7450620000000837d33407507c74506400000008b45230fb6088d048e030083c004ffd083f8ff74068b45232b452f5e5a5983c4275dc20800c7451a000000008b45230fb6400125c7000000b94000000031d2f7f189450a83f801750483451a0183f802750483451a0489550ec1e00501f005001000008d0490030083c004ffd0c38b45230fb6400183e038c1e803894516c3c3837d06207c2183451a018b45230fb6400283e007894512837d1205750a837d0a00750483451a04c3837d06207c0483451a04c3837d0610750483451a02c3e862ffffff8b451a01452383452302c3ff4523c383452302c3837d02107506e8dcffffffc3e844020000c3837d02107509e8caffffffff4523c3e82f020000c3837d33407506e823020000c3ff4523c3837d02207c0583452305c383452303c3837d0240750583452309c3837d0220750583452305c383452303c3e880ffffffff4523c3837d33407522c7450240000000ff45238b45230fb6088d048e030083c004ffd0c7450220000000c3ff4523c3837d33407523ff4523fe4522807d220f7506e8a7010000c38b45230fb6088d048e030083c004ffd0c383452301c3ff4523fe4522807d220f7506e87f010000c38b45230fb6088d048e030083c004ffd0c3837d02207c0ae8f4feffff83452304c3e8eafeffff83452302c3837d33407506e848010000c383452302c383452304c383452305c3837d33407506e82d010000c3e8b9feffffc3e81afeffff837d0a037506e8a8feffffc3e810010000c383452303c3837d0640750583452309c383452305c3837d0610750583452303c3837d0620750583452305c383452309c3807d00017506e866feffffc3e8ce000000c3807d00017506e854feffffc3807d01017506e848feffffc3837d02107506e83cfeffffc3e8a4000000c3837d33407506e898000000c3837d0220750583452307c383452305c3c3837d02107410e874fdffff8b451a01452383452306c3e864fdffff8b451a01452383452304c3837d33407506e855000000c3837d0220750583452307c383452305c3e881fdffff837d16007506e8c6fdffffc3e82e000000c3837d3340750583452305c3837d0220750583452305c383452303c3807d00017506e899fdffffc3e801000000c3b8ffffffffc3837d33407506e8efffffffc3e87bfdffff83452301c3837d02207c0ae86bfdffff83452304c3e861fdffff83452302c3e8befcffffe802fdffff837d1600750b8b451a01452383452303c3837d16017506e8a4ffffffc38b451a01452383452302c3837d02207c32e886fcffffe8cafcffff837d1600750b8b451a01452383452306c3837d16017506e86cffffffc38b451a01452383452302c3e854fcffffe898fcffff837d1600750b8b451a01452383452304c3837d16017506e83affffffc38b451a01452383452302c3e822fcffffe866fcffff837d16017e06e819ffffffc38b451a01452383452302c3e84afcffff837d16067e06e8fdfeffffc3e8f0fbffff8b451a01452383452302c3e8e0fbffffe824fcffff837d16057e06e8d7feffffc38b451a01452383452302c3e8bffbffffe803fcffff837d1600751a837d0a030f85ac000000837d0e040f8ea2000000e8a2feffffc3837d1601751a837d0a030f858c000000837d0e010f8e82000000e882feffffc3837d16027510837d0a030f856c000000e86cfeffffc3837d1603750c837d0a03755ae85afeffffc3837d1604750c837d0a037548e848feffffc3837d16057506e83cfeffffc3837d1606750c837d0a03752ae82afeffffc3837d1607751e837d0a037518837d3340750c837d0e00740ce80cfeffffc3e806feffffc38b451a01452383452302c3e8eefaffffe832fbffff837d16047d06e8e5fdffffc38b451a01452383452303c3e8cdfaffffe811fbffff837d16007506e8c4fdffffc3837d16027506e8b8fdffffc3837d16037506e8acfdffffc3837d16047506e8a0fdffffc3837d16057506e894fdffffc3837d16077e06e888fdffffc38b451a01452383452302c3e8b9faffff837d16007506e86cfdffffc3837d16017506e860fdffffc3837d16027511e84dfaffff837d0a037452e849fdffffc3837d16037506e83dfdffffc3837d16047511e82afaffff837d0a03742fe826fdffffc3837d16057506e81afdffffc3837d16067511e807faffff837d0a03740ce803fdffffc3e8fdfcffffc38b451a01452383452303c3e82efaffff837d16007506e8e1fcffffc3837d16017506e8d5fcffffc3837d16027511e8c2f9ffff837d0a037452e8befcffffc3837d16037506e8b2fcffffc3837d16047511e89ff9ffff837d0a03742fe89bfcffffc3837d16057506e88ffcffffc3837d16067511e87cf9ffff837d0a03740ce878fcffffc3e872fcffffc38b451a01452383452303c3e8a3f9ffff837d16007506e856fcffffc3837d16017506e84afcffffc3837d16027515e837f9ffff837d0a030f847b000000e82ffcffffc3837d1603751d837d02107511e816f9ffff837d0a03745ee812fcffffc3e80cfcffffc3837d16047506e800fcffffc3837d16057506e8f4fbffffc3837d16067511e8e1f8ffff837d0a037429e8ddfbffffc3837d16077517837d02107511e8c4f8ffff837d0a03740ce8c0fbffffc3e8bafbffffc38b451a01452383452303c3e8ebf8ffff837d16007515e897f8ffff837d0a030f85a0000000e88ffbffffc3837d16017515e87cf8ffff837d0a030f8585000000e874fbffffc3837d16027515e861f8ffff837d0a030f856a000000e859fbffffc3837d16037511e846f8ffff837d0a037553e842fbffffc3837d16047506e836fbffffc3837d16057511e823f8ffff837d0a037530e81ffbffffc3837d16067511e80cf8ffff837d0a037519e808fbffffc3837d16077f07e8f5f7ffffeb06e8f5faffffc38b451a01452383452302c3e826f8ffff837d16007511e8d2f7ffff837d0a037551e8cefaffffc3837d16017511e8bbf7ffff837d0a03753ae8b7faffffc3837d16027511e8a4f7ffff837d0a037523e8a0faffffc3837d16037511e88df7ffff837d0a03750ce889faffffc3e883faffffc38b451a01452383452302c3ff4523c7450210000000fe4522807d220f7506e85ffaffffc38b45230fb6088d048e030083c004ffd0c7450220000000c3ff4523fe4522807d220f7506e835faffffc38b4d06d1e9895d068b45230fb6088d048e030083c004ffd08b5d06d1e1894d06c3ff4523fe4522807d220f7506e802faffffc38b45230fb6003ca474123ca7740e3cae740a3caf74063c0f7402eb04c64500018b45230fb6088d048e030083c004ffd0c6450000c3ff4523fe4522807d220f7506e8bbf9ffffc38b45230fb6003c90743e3ca4743a3ca574363ca674323ca7742e3caa742a3cab74263cac74223cad741e3cae741a3caf74163c6c74123c6d740e3c6e740a3c6f74063c0f7402eb04c64501018b45230fb6088d048e030083c004ffd0c6450100c3ff4523fe4522807d220f7506e848f9ffffc38b45230fb6088d848e00040000030083c004ffd0c3ff4523fe4522807d220f7506e821f9ffffc38b45230fb6088d848e00080000030083c004ffd0c3ff4523fe4522807d220f7506e8faf8ffffc38b45230fb6088d848e000c0000030083c004ffd0c3c7451a000000008b45230fb640013dbf0000007f11e80cf6ffff837d16077e06e8bff8ffffc3e8b2f5ffff8b451a01452383452302c3c7451a000000008b45230fb640013dbf0000007f17e8d6f5ffff837d16017569837d16077e63e883f8ffffc33dc00000007c5689c2c1ea0489c183e10f83fa0d750b83f9007442e862f8ffffc383fa0e753783f9027506e852f8ffffc383f9037506e847f8ffffc383f9067506e83cf8ffffc383f9077506e831f8ffffc383f90f7506e826f8ffffc3e819f5ffff8b451a01452383452302c3c7451a000000008b45230fb640013dbf0000007f11e83df5ffff837d16077e32e8f0f7ffffc33dc00000007c2589c2c1ea0489c183e10f83fa0e750b83f9097411e8cff7ffffc383fa0f7506e8c4f7ffffc3e8b7f4ffff8b451a01452383452302c3c7451a000000008b45230fb640013dbf0000007f1fe8dbf4ffff837d1604740e837d16067408837d16077f02eb41e880f7ffffc33dc00000007c3489c2c1ea0489c183e10f83fa0e751583f9087d2083f903741b83f9027416e855f7ffffc383fa0f750b83f9087c06e845f7ffffc3e838f4ffff8b451a01452383452302c3c7451a000000008b45230fb640013dbf0000007f11e85cf4ffff837d16077e22e80ff7ffffc33dc00000007c1589c2c1ea0489c183e10f83fa0d7506e8f3f6ffffc3e8e6f3ffff8b451a01452383452302c3c7451a000000008b45230fb640013dbf0000007f19e80af4ffff837d16057408837d16077f02eb32e8b5f6ffffc33dc00000007c2589c2c1ea0489c183e10f83fa0c750b83f9087c11e894f6ffffc383fa0f7506e889f6ffffc3e87cf3ffff8b451a01452383452302c3c7451a000000008b45230fb640013dbf0000007f11e8a0f3ffff837d16077e27e853f6ffffc33dc00000007c1a89c2c1ea0489c183e10f83fa0d750b83f9097406e832f6ffffc3e825f3ffff8b451a01452383452302c3c7451a000000008b45230fb640013dbf0000007f11e849f3ffff837d16077e52e8fcf5ffffc33dc00000007c4589c2c1ea0489c183e10f83fa0c7506e8e0f5ffffc383fa0d7506e8d5f5ffffc383fa0e751083f900741b83f9087d16e8c0f5ffffc383fa0f750b83f9087c06e8b0f5ffffc3e8a3f2ffff8b451a01452383452302c300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009ee3000082e300004ae300002ee300000ee30000fce20000eee20000dee20000cae20000b8e200009ce2000084e200006ce2000056e200003ce2000026e2000012e2000002e20000f0e10000dce10000cee10000bce10000aae100009ae1000086e1000074e1000062e1000052e1000040e100002ae1000016e10000fee00000eae00000dae00000000000006ce5000056e500000000000024de000034de000046de000054de00006ade00007cde00008cde00009ade0000a6de0000b2de0000c4de0000d8de0000e8de0000fade000014df000026df00003adf00000ade000060df000070df00007edf000096df0000aadf0000c0df0000dadf0000eedf000004e000001ae000002ae0000038e0000048e0000058e0000070e0000080e00000f6dd0000e4dd0000d4dd0000c6dd0000b6dd0000a2dd000096dd000086dd000076dd00006add00005edd000050dd00003edd000030dd000020dd000010dd000002dd0000f6dc0000e2dc0000c6dc0000b4dc0000a2dc000094dc00007edc00006cdc000058dc000042dc00002edc000018dc000002dc0000f6db0000e0db0000d2db0000c0db0000b0db00009adb000092db000082db00006edb000058db000046db00004edf000038db00000000000066e600000000000024e5000010e500003ae50000000000003ee400004ee4000060e400006ee4000080e4000028e40000a0e40000aee40000c2e40000c8e30000d8e300001ce4000006e40000f0e3000092e4000000000000c0e00000b2e000000000000090e50000a4e50000bae50000cce50000e0e50000f4e500000ae600001ee6000032e6000042e6000000000000f4e40000e2e4000000000000000000002300000047657450726f634164647265737300004c6f61644c6962726172794100000000000000000000000000000000000000003000000025000000010000007000000025000000020000007000000025000000030000007000000024000000d60f79d4747400ee214ee09be5602355a99dd385448ff1a8b71041cf7c21b0d4c3e681fed891b785b22a8032dd7df6ad086f0063839040576b9d052240d8ce0029e0de000dfd3f8c848e36115697c9c6f11aeefff38130fbb53e9767a04174b37a2560fc1f52c9576e8bfbe2ffe4e76792c933ae0e32c856f4db91033403dd62f051d942e824565051fa96baffcb373eb19e1797d2d5f1dea9874f30113334f2b47aa7775625867152cce0ec106e765f78de3c31d4d905013595e66b7c669f068eb0afe84b83ba3eec3e0a6dd859d1b471db3626038cdb01fb457603558d7b62e73daf08f3e27156f6bfe3687dce7ff630e0ece6a0c109dcae25a3d75ac5b2a73dc77e3be0c22a63e70de4b5952c7be14d73d17bc634f43a34ff812a4d4f2808069a109ee1d563664ec60bb634392666772f788df8c3ee0bd7d1112ab3386ba1659da412d0d32275cd4e0e53c8d7bbad93b7720e2ba164fb31e263b9baad77df518a8af3552c67a53d12e30e1bd3bbcd80c04d894a27d4df8a84e295f6e9dba096cf0cceb91eab7880f9a9feea964d0c0e350617369a1f5272bba9be596f8339503cdc785f360f07cc869b81e34660e6333a764a36cfa22b09123f68927167774d2c2f0d218588edf46a1eb5635a3929ab187cef1c99fd39a65e16e8ed6dbf6ee2299becf6fd33807bb453b54466d824aedc2b264ebe39b78c1f6026b692e1ec739fcbb8fe554ae5e0db7d29da741361603e0950c9cfad3569bb9a6c02f0ffa85c424166e35ad787265f0f84b47cefb56c1344c8e9e9bddd6684bb51a4c642908abd700fc939afb543d969ba46297cfc4f2379896eb102e7d73dd7ac616902c09172e184369a9e171cb814d2ade82528e003e215b636e8a4c5e47dd1b1d99f26303ca6e99fdc30d4d67513d11853d0f98bdf88fe7c393ed63f934248d58d90637e7417cc1c39ed8983f3f61cf7ef3bffaecabf322bada873de226661dfc724b58542e6f7c93f22e3c5f4e06326598fe67108a286a0a7ff5a99159ff166cd021d8871ee4a90a4ce85e0e824c84a2bbfb1fec77b8b5dd9587823828e20f7471ba32b2215ed388d78c4c9c5ce6e4cf7220cc16e55a207a3b9e7cc569af8297d922ac7d4272899b51de38523ce84abd0e649a11f055b564063e17ddaa7eb57d98ad5517e86b5546f4ca65e2a8cf7ebac3056b3c3b72c120d2f94431c356e66d418d2a66586e6edc0b9f34ddf3c0c22489f54e565e50c04f4dcf114d0c4717adeacf24ac71dd0e82a908aeb3bbf01c96ce13629b2930cf04d15f26c95b6a167733ee0d2b26f39037b7e95d4919d93a3538051ee2bb3b3202b84439ee1242738c6d6b8b5976cb964db29c59bb9696bf8d881a56f505280b3b3cc4ed32147f3fbb8a7f38adf0bfd82e867b9e7685b2a2ce9f6311adcd83ef7029a7d788e017c0255b0093287fcbce442d202379174a0e53ce64da4473418f5ba8c5035722cc697d74a777fb9902da6faa3c1ddaac51d2733fb15ba65231e9c4678789a999c8e35b0b1854fc4ded3676c0681dce79a22b9db71504488d990802404b64f8ba2d799918ccda2b348feb5c49747f34bbd00f79cc1e1a0d47f0396261839613f5b8038f20b577065b94ab04ca612f61181575d19bf5b15344dbc1055e1af2ec3740256b02f0ec67d641b29e88013c4213bf5ad46f90a8bffadc5a58b2927db08d33d3d501b7eb3f7c07e996770753c7f73063193b952b6863002a9bc3c5b1bed537ad1dfa26f070e72d5ff4c8067479b4d8552ac88d70207efb2f15a68f45063dcc1d6508e872f44b209faf3e2f6f5c0b5c50d931692f20b2288d727ea8b6f0bf7fd93cd7b4d8e2857719b2ec4aebde789d98f9e6c1c2c599b3224cad7f04d1ee6423019bfb8cc43474c28a87a3e8fd0cdf6f57c23afd791ef1fc74e727eace12c3feedaab35916b1432b2b5c1c4b591aac4a750f9141640d9768badfa2a70d76b5bb00af52e546774289fceb225ac7d271ef403c010cf812de5f1e5ee1416115c471e77038813acaa2c2411c2e18fc06c1e7cb6f576f4537796f2d39a66133cf1017575697d7e000000000000000d36fa9a5edf66ce57a24e8b191149f5225565064b03b06bf23c927d76b4adc804f626297aa835805f0e38b8f82805cc016342eb562c7971e0852be68e2ed9126c4df3dcfddbe359a3afaa82e8696f977bd0b6ba53942df1dd2f02b5decf686e648478d3258734e45dbb588c93471a0a9988c57213a9cd73e9ab3127c321cbd7629c165be786c46d953f9b9e3b397eb94477d2457c3a4fa5bebf98a7e152a0acc707f45c3046b7c2ef091c150b7440d61edacaeee5c68df73723893214d4bc9060754a33964c1700fb51675a247f0c2a1fec8a9faeb3c98118ffa110489dedb143d11bf08fd5d8501dfe3d83f9910854e2bda6a441613ec1eac0b20ffc20706a0000000000000000d8b640000100000060000000d8b64000010000006800000038b74000180000006000000038b740001800000068000000c0b740001800000060000000c0b7400018000000680000007ccc400094cc4000a4cc400000000000ecc54000e0b9400048c44000c0cc400090bc400030bf4000cccc4000d8cc4000e4cc40006cbf4000f0cc4000fccc4000f0ca400008cd400014cd400020cd40002ccd400038cd400044cd400050cd40005ccd400068cd400074cd400080cd40008ccd400098cd4000a4cd4000b0cd4000bccd4000c8cd40002cc34000d4cd4000e0cd4000eccd4000f8cd400004ce400010ce40001cce400028ce400000000000c8b94000d4b94000e0b94000ecb94000f8b9400004ba400010ba40001cba40002cba400044ba400050ba400064ba400070ba40007cba400088ba400094ba4000a4ba4000b4ba4000c0ba4000ccba4000d8ba4000e4ba4000f0ba4000fcba40000cbb400018bb400024bb400030bb40003cbb400048bb400054bb400060bb40006cbb400078bb400084bb400090bb4000a0bb4000acbb4000b8bb4000c4bb4000d4bb4000e0bb4000ecbb4000f8bb400004bc400010bc40001cbc400028bc400038bc400048bc400054bc400060bc40006cbc400078bc400084bc400090bc40009cbc4000a8bc4000b4bc4000c0bc4000ccbc4000d8bc4000e4bc4000f0bc4000fcbc400008bd400014bd400020bd40002cbd400040bd400050bd40005cbd400068bd400084bd400090bd40009cbd4000a8bd4000b4bd4000c0bd4000ccbd4000d8bd4000e4bd4000f0bd4000fcbd400008be400018be400024be400030be400038be400044be400050be40005cbe400068be400074be400080be40008cbe400098be4000a8be4000b4be4000c0be4000ccbe4000d8be4000e4be4000f0be4000fcbe400008bf400014bf400024bf400030bf400044bf400054bf400060bf40006cbf400078bf400084bf400094bf4000a4bf4000b0bf4000bcbf4000ccbf4000d4bf4000ecbf4000f8bf400004c0400010c040001cc0400028c0400034c0400040c040004cc0400058c0400064c0400070c040007cc0400088c0400098c04000a8c04000b4c04000c0c04000ccc04000d8c04000e8c04000f4c0400000c140000cc1400018c1400024c1400030c1400048c140005cc140006cc1400078c1400084c1400090c140009cc14000a8c14000b4c14000c4c14000d4c14000dcc14000e8c14000fcc1400008c2400018c2400028c2400038c2400044c2400050c240005cc2400068c2400078c2400084c2400090c240009cc24000a8c24000b4c24000c0c24000ccc24000e0c24000f0c24000fcc2400008c3400014c3400020c340002cc3400044c3400050c340005cc3400068c3400074c3400080c340008cc3400098c34000a4c34000b0c34000bcc34000c8c34000d4c34000e0c34000ecc34000f8c3400004c4400010c440001cc4400028c4400038c4400048c4400054c4400060c4400070c440007cc4400088c4400094c44000a0c44000acc44000b8c44000c4c44000d4c44000e0c44000ecc44000fcc4400008c5400014c5400020c540002cc5400038c5400048c5400054c5400060c540006cc5400078c5400084c5400090c54000a4c54000b0c54000bcc54000c8c54000d4c54000e0c54000ecc54000fcc5400008c6400014c6400020c640002cc6400038c6400044c6400050c640005cc640006cc6400078c6400084c6400090c640009cc64000a8c64000b4c64000c0c64000ccc64000d8c64000e4c64000f0c64000fcc6400008c740001cc740002cc7400038c7400044c7400054c7400064c7400070c740007cc7400088c7400094c74000a0c74000acc74000b8c74000c4c74000d0c74000dcc74000e8c74000f4c7400000c8400014c8400020c840002cc8400038c8400048c8400054c8400060c840006cc8400078c8400084c8400090c84000a0c84000acc84000b8c84000c4c84000d0c84000dcc84000e8c84000f8c8400004c9400010c940001cc9400028c9400034c9400044c9400050c940005cc9400068c9400074c9400080c9400090c940009cc94000a8c94000b4c94000c0c94000ccc94000e0c94000ecc94000fcc9400008ca400014ca400020ca40002cca400038ca400044ca400050ca40005cca400068ca400074ca400084ca400090ca40009cca4000acca4000b8ca4000c4ca4000d4ca4000e4ca4000f0ca4000fcca400008cb400014cb400020cb40002ccb400038cb400048cb400054cb400060cb40006ccb400078cb400084cb400094cb4000a0cb4000b0cb4000c0cb4000d4cb4000e0cb4000eccb4000fccb40000ccc400018cc400024cc400030cc40003ccc400054cc400064cc400070cc400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e000e0e0e0e0e0e0e07900ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff000000ff00ff00ff0000ff00ff00ff00ff00ff00ff00ff00ff0000ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff0000ff00ff00ff00000000ff00ff0000ff000000ff0000000000ff000000000000ff00000000000000ff00ff00ff0000ff00000000ff0000ff000000ff00ff0000ff000000ff00000000000000fffe00fffe00fffe00ff00ff00ff00ff00ff00ff00ff00ffb100ff00ff00ff00ff00ff00ff00ff00ff00ff0000fffe00ff000000ff00ff00ff00ff0000000000000000a003ce0300f2400030045f0430f240009004cc047cf24000001efc1f00f0400040ff5aff60f24000000000000000000044000700c0ce4000c5000c00c8ce400026000b00d8ce400060000c00e4ce400042002700f4ce400065000c001ccf400043000b002ccf40006f000a0038cf40008a00090044cf40009a000c0050cf400006000b0060cf40001a0018006ccf4000fd00190088cf400019001600a4cf400014000a00bccf4000ca000700c8cf400044001100d0cf400041001a00e4cf400038002d0000d040005300120030d04000f400130044d04000f500140058d040001b00120070d040006300120084d040001300140098d0400026000e00b0d04000d7000700c0d0400028000e00c8d0400045000e00d8d0400091001900e8d04000e500080004d1400087001a0010d14000750006002cd140008800050034d14000370005003cd14000be00060044d14000eb0008004cd14000d600ab0058d140004d00050004d24000a40018000cd24000df00560028d24000c400100080d24000d8000f0094d2400082000a00a4d240002a000c00b0d24000e2000c00c0d24000ad000b00d0d2400014000b00dcd2400052000900e8d2400082000b00f4d24000b0000d0000d34000f9000b0010d34000fc000a001cd3400097000b0028d34000cf000a0034d34000e6000c0040d34000ba00170050d34000a500070068d34000b600050070d340006a00070078d34000fd00070080d34000a4000f0088d340005700070098d340004f000600a0d3400062000700a8d3400071004c00b0d340002d001b0000d440001a000a001cd44000d100110028d44000850010003cd44000b100040050d4400077000a0058d440005200040064d44000ce0015006cd44000d500060084d44000400022008cd44000fd001300b0d440003a001200c4d44000dc001200d8d440006c000a00ecd44000d6000a00f8d440001800090004d54000d6004e0010d54000bd00070060d540009600100068d54000470011007cd540007a000d0090d54000d9000d00a0d54000f6000b00b0d540004b000b00bcd54000c8001100c8d54000f2000b00dcd540002c000c00e8d540009c000d00f8d540003d000b0008d640006d000b0014d6400021000b0020d64000df000a002cd64000e000080038d64000f6000a0044d640001a00140050d64000a2000d0068d6400020000b0078d640007400100084d64000fe000d0098d6400049000b00a8d64000d6000a00b4d64000fd001000c0d64000f1001100d4d6400028000f00e8d640006f000d00f8d64000c6000a0008d740007e00110014d74000b700100028d7400004000a003cd7400045000d0048d74000b7000a0058d74000bd000b0064d74000e2000e0070d74000000000000000000047006c006f00620061006c005c000000070000004c006f00630061006c005c000000000006000000000000000000000000000000000000000000000000000000020100080008000800100000000080002e00650078006500000000003a6c0d0a7264202f53202f5120222573220d0a6966206578697374202225732220676f746f206c00000000004d006900630072006f0073006f0066007400200045006e00680061006e006300650064002000430072007900700074006f0067007200610070006800690063002000500072006f00760069006400650072002000760031002e003000000000004d006900630072006f0073006f0066007400200045006e00680061006e006300650064002000520053004100200061006e00640020004100450053002000430072007900700074006f0067007200610070006800690063002000500072006f007600690064006500720020002800500072006f0074006f00740079007000650029000000000000004d006900630072006f0073006f0066007400200045006e00680061006e006300650064002000520053004100200061006e00640020004100450053002000430072007900700074006f0067007200610070006800690063002000500072006f0076006900640065007200000000000000dfb008992a00000074006d0070005f00000000002500730025003000380078002e0025007300000020003a00000000002500730025007300000000004e74517565727953797374656d496e666f726d6174696f6e000000006e00740064006c006c002e0064006c006c00000047657446696e616c506174684e616d65427948616e646c65570000004b00450052004e0045004c00330032002e0064006c006c00000000005300650044006500620075006700500072006900760069006c006500670065000000000052746c47657456657273696f6e0000006e74646c6c2e646c6c0000004973576f77363450726f6365737300006b00650072006e0065006c00330032002e0064006c006c0000000000220025007300220000000000220025007300220020002500730000003a6c0d0a64656c20222573220d0a6966206578697374202225732220676f746f206c00006200610074000000406563686f206f66660d0a25730d0a64656c202f4620222573220d0a000000002f00630020002200250073002200000043006f006d00530070006500630000002a007100620078002a0000002a006300730068002a0000002a00620063006f002a0000002a006500780074002a0000002a006400740064002a0000002a007200740066002a0000002a006c0079002a00000000002a0074006900660066002a00000000002a006d006f006e0065007900770065006c006c002a0000002a006b00650079002a0000002a00640065007300690067006e002a00000000002a0065006e002a00000000002a007200330064002a0000002a006e0078002a00000000002a006100640073002a0000002a0062006c0065006e0064002a0000002a0078006c00730078002a00000000002a006400780067002a0000002a006f00740067002a0000002a003300640073002a0000002a006900640078002a0000002a006400610063002a0000002a00630067006d002a0000002a00680074006d006c002a00000000002a007100620079002a0000002a0064006f0063002a0000002a0070006c002a00000000002a006c0064002a00000000002a0078006d006c002a0000002a00610073006d002a0000002a006400640073002a0000002a0077006d0076002a0000002a007300740069002a0000002a006300660070002a0000002a0070006f0074002a0000002a0070006f00740078002a00000000002a006200640066002a0000002a007700620032002a0000002a006f00740074002a0000002a0063006400720077002a00000000002a006400730032002a0000002a007200640062002a0000002a006200740077002a0000002a006d00660077002a0000002a007000610073002a0000002a007000640062002a0000002a007300780077002a0000002a00610063006300640072002a0000002a0078006c0074006d002a00000000002a00670065006e002a0000002a006f00640066002a0000002a007300640061002a0000002a007300780069002a0000002a006400650073002a0000002a006200700077002a0000002a0062006b0066002a0000002a006100630072002a0000002a006e00730067002a0000002a006d00700034002a0000002a006d00640066002a0000002a007300780063002a0000002a006c00640066002a0000002a007300640030002a0000002a006f0069006c002a0000002a006600680064002a0000002a006300720032002a0000002a006300650072002a0000002a007000720066002a0000002a0073006c006400610073006d002a00000000002a0064006f00740078002a00000000002a006a00730070002a0000002a006d00790064002a0000002a00640062002d006a006f00750072006e0061006c002a00000000002a006600700037002a0000002a006200690070002a0000002a007200770032002a0000002a0078006c0077002a0000002a006600640062002a0000002a006300630064002a0000002a007400690066002a0000002a006b00640063002a0000002a007000370062002a0000002a00660068002a00000000002a007300740036002a0000002a007000680074006d006c002a0000002a00720077007a002a0000002a006300650032002a0000002a0063002a0000002a0072006d002a00000000002a006800700070002a0000002a007000680070002a0000002a006600660064002a0000002a006700720079002a0000002a00610070006a002a0000002a006d006f0076002a0000002a0066006c0076002a0000002a00700061006700650073002a0000002a006d00730074002a0000002a00740068006d002a0000002a006500720066002a0000002a007200610074002a0000002a006e0064002a00000000002a007000610062002a0000002a0063006c0073002a0000002a00680062006b002a0000002a0078006c0061002a0000002a00620061006e006b002a00000000002a007600680064002a0000002a006200610063006b00750070002a00000000002a0066006c00610063002a00000000002a00720077006c002a0000002a00630073002a00000000002a007400690062002a0000002a006d00610078002a0000002a00610063006300640062002a0000002a007000700074006d002a00000000002a006400780066002a0000002a007300740034002a0000002a0067007200610079002a00000000002a0068002a0000002a00730061007300370062006400610074002a00000000002a00730071006c002a0000002a0078006c006d002a0000002a007300740038002a0000002a007000650066002a0000002a006f00740070002a0000002a00650066002a00000000002a006e006f0070002a0000002a006f00640074002a0000002a006e006b0032002a0000002a006300720074002a0000002a006f00640063002a0000002a006d00730067002a0000002a00710062006d002a0000002a0073006c0064006d002a00000000002a0069006e00640064002a00000000002a006100770067002a0000002a007100620062002a0000002a006300660073002a0000002a006f00740068002a0000002a006100670064006c002a00000000002a007300760067002a0000002a006300700070002a0000002a006400770067002a0000002a006600700063002a0000002a006300720077002a0000002a00630073006c002a0000002a0070007300700069006d006100670065002a00000000002a00650072006200730071006c002a00000000002a0076006d0064006b002a00000000002a006e0078006c002a0000002a006100630068002a0000002a006100640062002a0000002a00680074006d002a0000002a007000740078002a0000002a006200610079002a0000002a0078006c0073006d002a00000000002a0064006f0063006d002a00000000002a006d002a0000002a00700073002a00000000002a00770061006c006c00650074002a00000000002a00730078006d002a0000002a0070007000740078002a00000000002a0063006400720036002a00000000002a0061007300700078002a00000000002a00700065006d002a0000002a007000630074002a0000002a007700610072002a0000002a0061006c002a00000000002a0063006c006100730073002a0000002a00610069002a00000000002a006f00640073002a0000002a007000630064002a0000002a006600780067002a0000002a007300770066002a0000002a006d00640062002a0000002a007000730074002a0000002a00730071006c006900740065002a00000000002a00640064006f0063002a00000000002a006300640078002a0000002a006100730070002a0000002a007300740035002a0000002a003300670070002a0000002a007300740037002a0000002a006200610063006b0075007000640062002a00000000002a006a00700065002a0000002a00690062007a002a0000002a006e00770062002a0000002a006e00730032002a0000002a006f00740073002a0000002a007000370063002a0000002a007300720074002a0000002a006100760069002a0000002a0070006c0063002a0000002a007100620072002a0000002a006100690074002a0000002a0037007a002a00000000002a003100320033002a0000002a006f0064006d002a0000002a007700610076002a0000002a006400630072002a0000002a006b00620078002a0000002a00680070002a00000000002a006300660078002a0000002a006a006100760061002a00000000002a0070007000730078002a00000000002a00620061006b002a0000002a006900690066002a0000002a007000700073006d002a00000000002a006b0031002a00000000002a007000660078002a0000002a0078006c0074002a0000002a007100620061002a0000002a007000730064002a0000002a006d00700067002a0000002a007000700073002a0000002a0064006a00760075002a00000000002a007300640066002a0000002a006e00730064002a0000002a0063007200610077002a00000000002a006e00730033002a0000002a003300660072002a0000002a0066006d0062002a0000002a007000640066002a0000002a007000310032002a0000002a0070006800700035002a00000000002a0074006c0067002a0000002a007800330066002a0000002a006f00720066002a0000002a006400620033002a0000002a006100630074002a0000002a006500780066002a0000002a0073006c0064007000720074002a00000000002a007400610072002a0000002a006d00640063002a0000002a007300720066002a0000002a007100620077002a0000002a006400780062002a0000002a006a00610072002a0000002a006200610063006b002a00000000002a006300690062002a0000002a006f00730074002a0000002a006300640072002a0000002a006100730078002a0000002a0078006c0073002a0000002a006400620078002a0000002a007300610079002a0000002a006400650072002a0000002a0063006400720035002a00000000002a007200610072002a0000002a006b00730070002a0000002a006400640064002a0000002a006400630032002a0000002a00730073006e002a0000002a006400620066002a0000002a006100720077002a0000002a00640062002a00000000002a006700690066002a0000002a00700062006c002a0000002a007300720077002a0000002a007300700066002a0000002a006e00730066002a0000002a0069006e0063007000610073002a00000000002a0073007400650070002a00000000002a006400720066002a0000002a007a00690070002a0000002a0070006f0074006d002a00000000002a0073006c00640078002a00000000002a006100620034002a0000002a006400610074002a0000002a006200670074002a0000002a006600700078002a0000002a0061006d0064002a0000002a006d00340076002a0000002a007700700073002a0000002a007200610066002a0000002a006e00650066002a0000002a006100730066002a0000002a006400670063002a0000002a006d006d0077002a0000002a007300740077002a0000002a00730071006c0069007400650033002a0000002a006600660066002a0000002a00620069006b002a0000002a007400650078002a0000002a006a007000650067002a00000000002a006f00640062002a0000002a00700079002a00000000002a007300740078002a0000002a00330064006d002a0000002a007400780074002a0000002a007000700074002a0000002a0078006c00730062002a00000000002a007300780064002a0000002a0064006f0074002a0000002a0070006e0067002a0000002a007800690073002a0000002a0065006d006c002a0000002a006a0069006e002a0000002a007000700061006d002a00000000002a006d00650066002a0000002a00640074002a00000000002a006f00610062002a0000002a0078006c0072002a0000002a007900750076002a0000002a006900620061006e006b002a0000002a007300740064002a0000002a006400630073002a0000002a007800310031002a0000002a006300650031002a0000002a006200640062002a0000002a0078006c00740078002a00000000002a006c00750061002a0000002a0066006c0061002a0000002a006400720077002a0000002a007300720032002a0000002a006300730076002a0000002a007900630062006300720061002a00000000002a006f00640070002a0000002a0063006400720033002a00000000002a006e00640064002a0000002a007400670061002a0000002a006d006f0073002a0000002a006e00780032002a0000002a007300630068002a0000002a007300780067002a0000002a006300640066002a0000002a007000640064002a0000002a0076006f0062002a0000002a00740079002a00000000002a0064006f00630078002a00000000002a003300670032002a0000002a006a00700067002a0000002a006b007000640078002a00000000002a006300700069002a0000002a007700700064002a0000002a00610063006300640074002a0000002a00610063006300640065002a0000002a00780064002a00000000002a0062006b0070002a0000002a007000610074002a0000002a00650073002a00000000002a006900690071002a0000002a006e00730034002a0000002a006500700073002a0000002a0064006400720077002a00000000002a006f0062006a002a0000002a006e00720077002a0000002a007200610077002a0000002a006d00700033002a0000002a006e00730068002a0000002a0073003300640062002a00000000002a006d00720077002a0000002a006b006400620078002a00000000002a0067007200650079002a00000000002a007000730061006600650033002a00000000002a0063006d0074002a0000002a003300700072002a0000002a0064006f0074006d002a00000000002a0063006400720034002a00000000002a0064006e0067002a0000002a006f00640067002a0000002a006e00790066002a0000002a0078006c006b002a0000002a00730071006c00690074006500640062002a00000000002a0078006c0061006d002a00000000002a006900620064002a0000002a006b00630032002a000000720065006300790063006c0065002e00620069006e000000770069006e0064006f007700730000002400720065006300790063006c0065002e00620069006e00000000002a007600720062002a0000002a00610063002a00000000002a00610062006b002a0000002a00640062006b002a0000002a0062006b006e002a0000002a0062006b0063002a0000002a006600620077002a0000002a00740062006b002a0000002a0062006b0065002a0000002a00620062002a00000000002a00730069006b002a0000002a006d0062006b002a0000002a006200700070002a0000002a006400740062002a0000002a00760062006b002a0000002a007200700062002a0000002a00660062002a00000000002a006300760074002a0000002a00730062006b002a0000002a0074006a006c002a0000002a006200750070002a0000002a0066006b0063002a0000002a006f006c0064002a0000002a00770062006b002a0000002a006a006f0075002a0000002a0075006d0062002a0000002a007300700069002a0000002a007300610076002a0000002a0062006b002a00000000002a007600690062002a0000002a007300770070002a0000002e00730074006e000000000041003a000000000053004f004600540057004100520045005c004d006900630072006f0073006f00660074000000000053006500530068007500740064006f0077006e00500072006900760069006c00650067006500000053003a0028004d004c003b003b004e0052004e0057004e0058003b003b003b004c0057002900000020322b6925392700b1a5b4ada9afb0b6e3a9b7ab000000005246574e474d470f4b5749000519120f0b170315460c120e00000000782f4d4b3423646a196b67186e6d693e705e5a383077312d33282c797c7a2f7f42040f1509470800335e425659386e6839564a1d00000000363124322228336a2f2625001a1d081e5858470c0b0a0000e4ffece5e2a1e8e1ee000000f1feeaf7fbf3afafbcf7fcfd000000004b6277766364654361774d005d7e6c4c6d7a6e4d607c76787a72507c786e6b7d617d755a00000000b388ae8b9c8a82b39b9298849c91879b8282bf9c868b8e9996000000576c487f695571787e627e73617d78785d60796f6c680000567979747b587c636969000084bf8ba5a1bca9000d36022222342524293f1e3d2d3a2f2520000000022826212e16222b263c2e0e282e3a293635210227312433372c00006b565c4f4b5c4c5a6c7c5b50465a45584e5d767c45434a4057527e6051575442766d4c7e6e6e77707e4d40667a0000001d260535253b3c3a3a2e3c082d313e3930310000ba81a4929195a49a8e898b9e94b49f968b979f00bb80a084988496a4948e8b8b9894b69f888b959f00000000556e5e7d6b5d727267776964437e67716a6e00002d16320513250a0a1f0f111c3b061f09121600005d66447e7a776542727f6e57794d787f776b6e6e000000006853764051564d447a475e484b4f000099a296b8bca1b4007e40585f594c426e4c4d4d40615d00000636222735251330222f2a3d3a1f0000a1cfdbd7d9c4c8d2dcdbc9c3cdc8c0d8c8ccc6d1abecf3ebe500000093979487858d8a8c00000000e3e3e9e1f7e7a1f3e7efe9e3fcf9a9a7f6faf9b4bce3e4f9faea0000161d071e14020000a7deb0aeef000000195a5c5a58000000d1d1d5d2d4950000839e9d989cd4c2c300000000bba4bca1b3fdb5a9bbffaabfa9b8aab0b6b3fe80baa6a3b4baaae4efa7b8afab998fd4d7d0a798988ddf9a94969ed8918794c48787868ec18b818f9f939b9c8cf2b9b6b7b4b3e6f3fdedf0fbbabdbabbc0e8e8e9edf4a0f5e6eaace4e4f8fcfbc3d4c0dcddddc391d7d19cc9d2de98d1d2cac885cac6ccd1cbdd8ccbc3c7cd877475787563657c717c7d1a34363e783c2824363c323725256e2d356d192a3c281855564f111f1f021b5d55001e2d3b2f27000000f7c4d2c6cefdf1cbc9c1c2f3e7d9cfc5e8f6d9daddd0dcd7000000008cb1bba8acbbabbd8b9bbcb7a1bda2bfa9ba918fb9b3b9bca8a1b7a5b3aab89caf8c92889e998da4a7849a829a9694829cb2898ad28ed18b83d6c8d5d6d2d0cdaeaff9adb6a2faaff6bba5a4f0a2a5f6ecbcb4bbeee8000094b7a9b3a5a2b6aaa3a39ea0a4a0a9b200000000888a8f9a8fb8aca9b9b2b7fdb1adb300e6f4ede0f6eeaae1e6e700004b5d4f41414047550c474c4d000000008395878989888f84c48f848500000000fecec6cbedc4c784c1c8cb007077717f757d623d78717200213d28393d79303936000000e3f3e9deeae8e3abeee7e400d4d8c0ecc3d4c2d4d097ded7d00000008f959892989f94d0959c9f008b8d9b8c8880d49f98990000e7e5e1fbe1f7f2befbf2f100bcafa0bca7afe7adbfa30000a5ddb8ac8c9089858bbb81b100000000cdd2d6dce1d8d9c9edc6ded8cee8d2dcc6cef7c7cfc2c900f6e5e9e2e3effb00e0fee6e0e1000000272a243e2f3d2900b0bdb3aabcabaf00f0e0f7f2e9ede3e1e3e2e3ede7e6e7000b051419031e14001318041e1e19000031222e2524283c003931213622352533253c3e2c343f3a3320303f3106170e3a3a0b18034d3c001c2570630e0637243f791a2e297d6c030a2032242731640e2269781706222b262d505c13675b5d4316705c1b0a00000000656d7d6a7e69796f7960627562726a7269757070656b424941515a00537f7d776a767a747761000082a9a0a6b0b995bfb6ab8dbfafafb6b1af000000d3ede3e3eec2eaedfedaeafcfae1e4e400000000e7f2fcea00000000213f272026333d323026000003161d0400000000aabda5bbafb9bb959085abbd8facb5b2bbf1afa4a90000008399809783950000130e041713041402141f073c2d3f2b6370183c307a09001a2f38283e7c0931300c120000998e96889c8a88a683999a99848396dc9e959c005e49514f5b4d4f61445e585650441a46535800008081f08388b1a3a8bdb6b7bb94a3bba5a9fd000020091c2307080e2f08090000b2b2a2b0bca5feb4a6ba00007b6a68686f337b6775000000f3a4f1a6f7a0f5a2fbacf9aeffa8fdaae3b4e1b6e7b0e5b2ebbce9beefb8edbad384d186d780d582db8cd98edf88dd8ac394c196c790c592cb9cc99ecf98cd9ab3e4b1e6b7e0b5e2bbecb9eebfe80000f2f0f3e7fdfafc00c1fefad1f0f4d6e3fff2f9def6faebea000000000e2b28312d2b35396f0a282e3e2d2e2d25000000201e0c185e3b191f07141714040000008bb7b8b1fd98babca4b7b4b7a7000000b995879c969a919fb9aab500242625312b2c2a62263a240098bba5a8a9bebd87a1a2a9a6b6eba3bfbd000000869080879f9283db9f839d004d585a405a5c44580a405e4200000000fde8eaf0eaecf4e8f7bbf3eff50000005b55535b54575514504c52001d1e000d04070544001c020051524c41405c57084c504e00b1bba9b1b4b4f7bdafb3000089858392ca809e82000000009f939584c4c7de94869a00005376756c707668645676726471707167246e706c00000000f5cad2c4d5cfc5d7c185cdd1cb00000044544f53474456094d514f003c1a191c3509021f130f1b0d561c021e00000000b7928c92888faabcb5d9918d97000000190d1f2522203c60243826009ab8a6b18296feb4a6ba0000ae858cb7978b8b9f96809884df958b970000000081829c91aa9599979581889f8fd29a86840000005b50596a424c42565a44500d415d43001c00040a0d3501011348001c06000000b1aeaaa1a0a4eea4b6aa00001410191f15031b161803061a1e5d15090b000000ddd9d0d6dccac2d5cdc8d8ce95dfc1dd0000000074776a5863622c667468000035362b19352f2c2e3e622a362c000000e1fbe6c6c5d19fd5c7db0000ebf1eaedcbced894d0ccd2009a868e928395928c898ec68c968a00006263646667686b6c6d6e70717273747677787a006165696f757900002a2f2a004d6f7a696c6c612f342e302028636f6d70617469626c653b204d53494520372e303b2057696e646f7773204e5420352e313b205356312900485454502f312e3100000000504f53540000000047455400436f6e6e656374696f6e3a20636c6f73650d0a0064d900000000000000000000a4e0000098a00000f4da00000000000000000000cee0000028a20000ccd800000000000000000000bae3000000a00000b4da00000000000000000000d6e40000e8a100002cdb0000000000000000000006e5000060a20000a4da000000000000000000004ae50000d8a1000058d90000000000000000000084e500008ca0000000db000000000000000000005ae6000034a200009cda000000000000000000007ce60000d0a1000000000000000000000000000000000000000000009ee3000082e300004ae300002ee300000ee30000fce20000eee20000dee20000cae20000b8e200009ce2000084e200006ce2000056e200003ce2000026e2000012e2000002e20000f0e10000dce10000cee10000bce10000aae100009ae1000086e1000074e1000062e1000052e1000040e100002ae1000016e10000fee00000eae00000dae00000000000006ce5000056e500000000000024de000034de000046de000054de00006ade00007cde00008cde00009ade0000a6de0000b2de0000c4de0000d8de0000e8de0000fade000014df000026df00003adf00000ade000060df000070df00007edf000096df0000aadf0000c0df0000dadf0000eedf000004e000001ae000002ae0000038e0000048e0000058e0000070e0000080e00000f6dd0000e4dd0000d4dd0000c6dd0000b6dd0000a2dd000096dd000086dd000076dd00006add00005edd000050dd00003edd000030dd000020dd000010dd000002dd0000f6dc0000e2dc0000c6dc0000b4dc0000a2dc000094dc00007edc00006cdc000058dc000042dc00002edc000018dc000002dc0000f6db0000e0db0000d2db0000c0db0000b0db00009adb000092db000082db00006edb000058db000046db00004edf000038db00000000000066e600000000000024e5000010e500003ae50000000000003ee400004ee4000060e400006ee4000080e4000028e40000a0e40000aee40000c2e40000c8e30000d8e300001ce4000006e40000f0e3000092e4000000000000c0e00000b2e000000000000090e50000a4e50000bae50000cce50000e0e50000f4e500000ae600001ee6000032e6000042e6000000000000f4e40000e2e400000000000019014578697450726f63657373008701476574436f6d6d616e644c696e655700f90457616974466f7253696e676c654f626a6563740018024765744d6f64756c6548616e646c65570000ed045669727475616c46726565457800b204536c6565700014024765744d6f64756c6546696c654e616d6557000085004372656174654576656e74570000e8004475706c696361746548616e646c65005200436c6f736548616e646c6500c10147657443757272656e7450726f6365737349640048034c6f63616c46726565002e05577269746550726f636573734d656d6f72790000610453657446696c6541747472696275746573570000c40147657443757272656e745468726561640000ea0147657446696c654174747269627574657357000099045365745468726561645072696f7269747900450247657450726f63416464726573730000a90043726561746552656d6f7465546872656164000080034f70656e50726f6365737300960350726f63657373333246697273745700980350726f6365737333324e657874570000be00437265617465546f6f6c68656c703332536e617073686f74000081004372656174654469726563746f727957000059045365744576656e7400008f0043726561746546696c65570093024765745469636b436f756e74000002024765744c6173744572726f720000f00147657446696c6553697a6500390146696e64466972737446696c65570000ec045669727475616c46726565002505577269746546696c6500c0035265616446696c650000850247657454656d7050617468570000e9045669727475616c416c6c6f6300002e0146696e64436c6f736500030452656d6f76654469726563746f7279570000450146696e644e65787446696c655700d60044656c65746546696c65570057034d6170566965774f6646696c6500d604556e6d6170566965774f6646696c6500c00147657443757272656e7450726f636573730008024765744c6f676963616c4472697665537472696e677357003f034c6f61644c696272617279570000c1045465726d696e617465546872656164000f0452657365744576656e7400008c0043726561746546696c654d617070696e67570000a0035175657279446f734465766963655700b5004372656174655468726561640000d202486561705265416c6c6f6300cb0248656170416c6c6f6300cf02486561704672656500004a0247657450726f6365737348656170000015024765744d6f64756c6548616e646c65410000f7024973426164526561645074720000ea045669727475616c416c6c6f6345780000dc01476574456e7669726f6e6d656e745661726961626c655700a80043726561746550726f63657373570000c0045465726d696e61746550726f6365737300008c01476574436f6d70757465724e616d65410000660453657446696c65506f696e7465720000d30147657444726976655479706557006201467265654c69627261727900ef02496e7465726c6f636b6564496e6372656d656e74000009024765744c6f676963616c4472697665730000ec02496e7465726c6f636b656445786368616e676500ed02496e7465726c6f636b656445786368616e67654164640000e00147657445786974436f64655468726561640011055769646543686172546f4d756c7469427974650067034d756c746942797465546f5769646543686172009e004372656174654d757465785700007d034f70656e4d75746578570000fa0352656c656173654d75746578000073045365744c6173744572726f720000bd0453797374656d54696d65546f46696c6554696d650000770247657453797374656d54696d6500a902476574566f6c756d654e616d65466f72566f6c756d654d6f756e74506f696e7457004b45524e454c33322e646c6c0000380043686172546f4f656d5700003c004368617255707065725700005553455233322e646c6c000036014765744c656e6774685369640000c400437279707447657448617368506172616d00b100437279707441637175697265436f6e74657874570000cd0043727970745365744b6579506172616d0000cb00437279707452656c65617365436f6e7465787400ca004372797074496d706f72744b65790000ba004372797074456e63727970740000b30043727970744372656174654861736800b700437279707444657374726f794b657900b600437279707444657374726f79486173680000c8004372797074486173684461746100fc014f70656e546872656164546f6b656e00e3014d617047656e657269634d61736b00000500416363657373436865636b00300147657446696c6553656375726974795700007501496d706572736f6e61746553656c66009002526576657274546f53656c660000f7014f70656e50726f63657373546f6b656e00005701476574536964537562417574686f7269747900005801476574536964537562417574686f72697479436f756e74005a01476574546f6b656e496e666f726d6174696f6e0097014c6f6f6b757050726976696c65676556616c756557001f0041646a757374546f6b656e50726976696c65676573007d01496e69746961746553797374656d53687574646f776e4578570039025265674372656174654b6579457857006e02526567517565727956616c7565457857000061025265674f70656e4b6579457857003002526567436c6f73654b6579007e0252656753657456616c756545785700007701496e697469616c697a65536563757269747944657363726970746f720000b602536574536563757269747944657363726970746f724461636c007200436f6e76657274537472696e67536563757269747944657363726970746f72546f536563757269747944657363726970746f725700004d01476574536563757269747944657363726970746f725361636c00ba02536574536563757269747944657363726970746f725361636c0041445641504933322e646c6c00003a0050617468436f6d62696e6557000085005061746852656d6f76654261636b736c6173685700008b005061746852656d6f766546696c655370656357009f0050617468556e71756f74655370616365735700002101537472436d704e49570047005061746846696e64457874656e73696f6e570000930050617468536b6970526f6f7457007b00506174684d6174636853706563570000340050617468417070656e645700950050617468537472697050617468570000b700534844656c65746556616c7565570000700177766e737072696e746657006f0177766e737072696e746641003000506174684164644261636b736c6173685700320050617468416464457874656e73696f6e570053484c574150492e646c6c000800434c53494446726f6d537472696e67007901537472696e6746726f6d4755494432006f6c6533322e646c6c00c3005348476574466f6c646572506174685700000600436f6d6d616e644c696e65546f4172677657000022015368656c6c4578656375746557005348454c4c33322e646c6c00830043727970744465636f64654f626a656374457800d9004372797074537472696e67546f42696e617279570000435259505433322e646c6c007300496e7465726e6574437261636b55726c41006b00496e7465726e6574436c6f736548616e646c65005900487474705175657279496e666f4100007100496e7465726e6574436f6e6e6563744100009f00496e7465726e65745265616446696c650000ac00496e7465726e65745365744f7074696f6e4100005700487474704f70656e526571756573744100005b004874747053656e64526571756573744100009700496e7465726e65744f70656e41009d00496e7465726e657451756572794f7074696f6e41000057494e494e45542e646c6c000c004765744d617070656446696c654e616d6557000050534150492e444c4c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff0000000000c500ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff000000000000080808080808080800000000000000000808080808080000000000000000000008080808080808080000000000000000080808080808080800000000000000000808080808080000000000000000000000080008000800080000000000000000080808080808080800000000000000004a4a565656566464000070707e7e00000808080808080808000000000000000008080808080808080000000000000000080808080808080800000000000000000808000900000000000000000000000000000009000000000000000000000000080800000000000000000000000000000808000000070000000000000000000000000009000000000000000000000000000000000000000000000000dadbdbdb00e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e1e0e0e0e0e0e0e0e0e0c0c1c100e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e000b0b0b0b0b0b0b0b0b0b0b0b000b0b000e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e00000ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff0000ff00ff000000ff000000ff000000000000000200000060ea00000600000060ea00000500000060ea00009cd740000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000440100001330293041305d301d3123314931b231413248326f327d32df321b332233393360336f33753383338d339733b5332a343f34443456346334703485348e3497349e34ae34bd34c334c834d234e434f33402350c35173539354d35693571358a359735ba35c035d535dd35f035f93503361436303644364b36513657365d3664367e36843689369636a336b336b936c036cc36d536e136f036fa3601371337193744374a374f378e3795379a37be376138673877387f38ab38d838163955395b396b3971399139a4390d3a3a3a5c3a633aa83aaf3af03a0a3b2a3b303b543b5b3b673b6d3b803b863bbf3bc53b083c383c3e3c5f3c833c893cd43cf53c153d1b3d3b3d493d5d3d703da03dd13dd63dea3d003e153e1a3e2b3e3d3e4f3e543e653e773ebd3ecc3ee23e2c3f343f3e3f493f5a3f763f923fcf3fe43f000000200000e800000005303a3058305e306e307c30b930cb30d530db30e330463158316b317e31b731b632c2328d34a034d034dc34fe3421352f353b354e355a3569359635ce3545368b3691369736cb36d836093726372d37363744374b3752376b37823795379e37a437ac37bb37c137c737ce37dc3703380938123817381d3839384138a038ba38ce38e538fb38063921392b3956397739963a9c3aa23aaa3ab93ac63acc3ad23ada3af83afe3a093b313b643b913bba3bef3b073c4f3c593c8a3ce23ced3c553d683d833dfc3d773e873eaa3ede3eed3e203f433f513f813f8e3f993f9e3fce3f00300000cc0000000b3032303f307b3085309d30c430f130fc3008310f3124312b314a315a317c319431ae31b731d831e731f33146325a3261329032c032c632f932163331334e3355337a3387339833c033103467346e349a34a334cb34e234f034043543355735793589358e359b35a235b635bc35193649364e3658365f36653690369836a436ae36ba36c936383756376537b33713391939233929395b39613995399b39a739ad39f739fc39023a093a243d403dee3d123e073f2a3f573f693fb63fbd3fcf3fe93f000000400000ac0000000b3015302330473060306a3091309d30b430df3006312e31443158316d317b318731a731bd31ea31fa311d322a329032a032db3205330b33bc33c2332b345e34683554367636dc36ee36173753378837ab37e937ef3710382d3864387e389f38b038ba3808394d39723997399e39b139503a5f3a6b3a933ac43ad13add3a1f3b523b163c553c743c9f3c953d9f3daf3db63dbd3ddc3de93d773e7e3ea63eac3e1f3f000000500000d800000034303b3052305d309230c530f4300b311b3126310c329c32b632c83230338e339433d533dc33f53303341c34293567352f363d3645364d365d366c3685369136a136e03627379e37cc37d937e737ff371738413856387238bd38c43835394a395b396a397839cc39d739ea39173a373a573a6f3a763a7e3a973ab73ac23a0b3b1a3b313b493b613b793bc93bd03bd73bdd3b213c283c3b3c403c613cb83cc83cfb3c183d273d5c3d6e3d873dba3dd53d023e1c3e2d3e523e5c3e803ead3ebe3ece3ed43ef03e043f113f703f763f000000600000600000006135e83515386238e03861390b3a143a5a3a633a703a7e3a883aa33aac3ac73ad73ae13af53afc3a0a3b1c3b383b573b883b963bdf3be43b2a3d693d7d3d883dc63de23df83d053e163e293ecb3ed83ee63efc3ecb3fd93f007000002400000009301730ab3cb13cb73cbc3cc73ceb3c043d173d273d463d5e3d9e3d00a000001c030000a039ac39b839c439d039dc39e839ec39f039f839fc39003a043a083a0c3a103a143a183a1c3a203a243a283a2c3a303a343a383a3c3a403a443a483a4c3a503a543a583a5c3a603a643a683a6c3a703a743a783a7c3a803a843a883a8c3a903a983a9c3aa03aa43aa83aac3ab03ab43ab83abc3ac03ac43ac83acc3ad03ad43ad83adc3ae03ae43ae83aec3af03af43af83afc3a003b043b083b0c3b103b143b183b1c3b203b243b283b2c3b303b343b383b3c3b403b443b483b4c3b503b543b583b5c3b603b643b683b6c3b703b743b783b7c3b803b843b883b8c3b903b943b983b9c3ba03ba43ba83bac3bb03bb43bb83bbc3bc03bc43bc83bcc3bd03bd43bd83bdc3be03be43be83bec3bf03bf43bf83bfc3b003c043c083c0c3c103c143c183c1c3c203c243c283c2c3c303c343c383c3c3c403c443c483c4c3c503c543c583c5c3c603c643c683c6c3c703c743c783c7c3c803c843c883c8c3c903c943c983c9c3ca03ca43ca83cac3cb03cb43cb83cbc3cc03cc43cc83ccc3cd03cd43cd83cdc3ce03ce43ce83cec3cf03cf43cf83cfc3c003d043d083d0c3d103d143d183d1c3d203d243d283d2c3d303d343d383d3c3d403d443d483d4c3d503d543d583d5c3d603d643d683d6c3d703d743d783d7c3d803d843d883d8c3d903d943d983d9c3da03da43da83dac3db03db43db83dbc3dc03dc43dc83dcc3dd03dd43dd83ddc3de03de43de83dec3df03df43df83dfc3d003e043e083e0c3e103e143e183e1c3e203e243e283e2c3e303e343e383e3c3e403e443e483e4c3e503e543e583e5c3e603e643e683e6c3e703e743e783e7c3e803e843e883e8c3e903e943e983e9c3ea03ea43ea83eac3eb03eb43eb83ebc3ec03ec43ec83ecc3ed03ed43ed83edc3ee03ee43ee83eec3ef03ef43ef83efc3e003f043f083f0c3f103f143f183f1c3f203f243f283f2c3f303f343f383f3c3f403f443f483f4c3f503f543f583f5c3f603f643f683f6c3f703f743f783f7c3f803f843f883f8c3f903f943f983f9c3fa03fa43fa83fac3fb03fb43fb83fbc3fc03fc43fc83fcc3fd03fd43fd83fdc3fe03fe43fe83fec3ff03ff43ff83ffc3f00b000002c0100000030043008300c301030143018301c302030243028302c303030343038303c304030443048304c305030543064326c3274327c32843294329c32a432ac32b432bc32c432cc32d432dc32e432ec32f432fc3204330c3314331c3324332c3334333c3344334c3354335c3364336c3374337c3384338c3394339c33a433ac33b433bc33c433cc33d433dc33e433ec33f433fc3304340c3414341c3424342c3434343c3444344c3454345c3464346c3474347c3484348c3494349c34a434ac34b434bc34c434cc34d434dc34e434ec34f434fc3404350c3514351c3524352c3534353c3544354c3554355c3564356c3574357c3584358c3594359c35a435ac35b435bc35c435cc35d435dc35e435ec35f435fc3504360c3614361c3624362c3634363c36443600f000000c000000d8320000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 + ptr = claripy.BVV(x,475152) + state.memory.store(state.regs.esi,ptr) + state.regs.eax = 0x1 + return + + from procedures.windows.custom_package.Handler import Handler + proj.hook(0x4025b2, Handler(), length=1) + proj.hook(0x402633, Handler(), length=2) + + + class gonnacry_encrypt_function(angr.SimProcedure): + + def run(self, in_fd, out_fd, key, iv): + # doesn't matter what happens here, but you are responsible for figuring out how this is gonna + # interact with angr simfiles and stuff + print('0'*100) + print(in_fd) + print(out_fd) + + # print(self.state.mem[in_fd].int) + # print(self.state.posix.get_fd(self.state.mem[in_fd].int).file.name) + + print(key) + print(iv) + + chunksize = 512 # because that's what it is in gonnacry + + # readinto destination, going to have to free this one + malloc = angr.SIM_PROCEDURES["libc"]["malloc"] + buff = self.inline_call(malloc, chunksize).ret_expr + + + fread = angr.SIM_PROCEDURES["libc"]["fread"] + fwrite = angr.SIM_PROCEDURES["libc"]["fwrite"] + + while(True): + amt_read = self.inline_call(fread, buff, 1, chunksize, in_fd).ret_expr + + print(amt_read) + + self.inline_call(fwrite, buff, 1, amt_read, out_fd) + + if self.state.solver.is_true(amt_read != chunksize) or self.state.solver.is_true(amt_read == 0): + break + + + free = angr.SIM_PROCEDURES["libc"]["free"] + buff = self.inline_call(free, buff).ret_expr + + + rewind = angr.SIM_PROCEDURES["libc"]["rewind"] + self.inline_call(rewind, in_fd) + self.inline_call(rewind, out_fd) + + + # proj.hook_symbol('encrypt', gonnacry_encrypt_function()) + + @proj.hook(0x004038c6, length=5) + def hook_PEM_read_bio_RSAPublicKey(state): + print('hook'*100) + return diff --git a/sema_toolchain/sema_scdg/application/plugin/PluginIoC.py b/sema_toolchain/sema_scdg/application/plugin/PluginIoC.py index 26ad162c1..e8d592892 100644 --- a/sema_toolchain/sema_scdg/application/plugin/PluginIoC.py +++ b/sema_toolchain/sema_scdg/application/plugin/PluginIoC.py @@ -8,14 +8,14 @@ def __init__(self): def build_ioc(self,scdg,exp_dir): funcs = { - "strings": ["lstrlenA","lstrlenW","strlen","lstrcpyA","lstrcpyW","strncpy","lstrcatA","lstrcatW","lstrcmpA","lstrcmpW","strcmp","strncmp"], + "strings": ["lstrlenA","lstrlenW","strlen","lstrcpyA","lstrcpyW","strncpy","lstrcatA","lstrcatW","lstrcmpA","lstrcmpW","strcmp","strncmp", "strcpy","strcat","strlen"], "format": ["wsprintfA","wsprintfW","MultiByteToWideChar","WideCharToMultiByte"], "regs" : ["RegCreateKeyExA","RegCreateKeyExW","RegCreateKeyA","RegCreateKeyW","RegSetValueExA","RegSetValueExW","RegSetValueA","RegSetValueW","RegQueryValueExW","RegQueryValueExA","RegQueryValueA","RegQueryValueW","RegOpenKeyA","RegOpenKeyW","RegOpenKeyExA","RegOpenKeyExW","RegDeleteKeyW","RegDeleteKeyA","RegGetValueA","RegGetValueW",], "files" : - ["CreateFileA","CreateFileW","GetModuleFileNameA","GetModuleFileNameW","GetTempPathA","GetTempPathW","FindFirstFileW","FindFirstFileA","WriteFile","ReadFile","CopyFile"], + ["CreateFileA","CreateFileW","GetModuleFileNameA","GetModuleFileNameW","GetTempPathA","GetTempPathW","FindFirstFileW","FindFirstFileA","WriteFile","ReadFile","CopyFile","fread","fwrite","fopen"], "dir" : - ["CreateDirectoryA","CreateDirectoryW","SHGetFolderPathW","SHGetFolderPathA","GetWindowsDirectoryW","GetWindowsDirectoryA","SHGetSpecialFolderPathW","SHGetSpecialFolderPathA"], + ["CreateDirectoryA","CreateDirectoryW","SHGetFolderPathW","SHGetFolderPathA","GetWindowsDirectoryW","GetWindowsDirectoryA","SHGetSpecialFolderPathW","SHGetSpecialFolderPathA","opendir","readdir"], "network" : ["getaddrinfo","gethostbyname","inet_addr","NetLocalGroupAddMembers","socket","bind","listen","accept","connect","recv","shutdown","WSAStratup","WSACleanup","send"], "cmd" : @@ -32,7 +32,7 @@ def build_ioc(self,scdg,exp_dir): "services" : ["OpenSCManager","CreateService","StartServiceCtrlDispatcher"], "crypt" : - ["CryptAcquireContext","CryptGenKey","CryptDeriveKey","CryptDecrypt","CryptReleaseContext"], + ["CryptAcquireContext","CryptGenKey","CryptDeriveKey","CryptDecrypt","CryptReleaseContext","EVP_CipherInit_ex","EVP_CIPHER_CTX_new"], "anti" : ["IsDebuggerPresent","GetSystemInfo","GlobalMemoryStatusEx","GetVersion","CreateToolhelp32Snapshot"] } @@ -49,7 +49,7 @@ def build_ioc(self,scdg,exp_dir): for arg in call["args"]: if isinstance(arg,str): #and arg[-2:] != "32" and "_" not in arg and arg != "": string = string + " " + arg + "," - string = string + "\x08" + " ) \n" + string = string + " ) \n" if string not in strings: f.write(string) strings.add(string) diff --git a/sema_toolchain/sema_scdg/application/plugin/PluginLinuxSystem.py b/sema_toolchain/sema_scdg/application/plugin/PluginLinuxSystem.py new file mode 100644 index 000000000..a10291594 --- /dev/null +++ b/sema_toolchain/sema_scdg/application/plugin/PluginLinuxSystem.py @@ -0,0 +1,416 @@ +import angr + +from collections import namedtuple + +Dirent = namedtuple("dirent", ("d_ino", "d_off", "d_reclen", "d_type", "d_name")) + +class PluginLinuxSystem(angr.SimStatePlugin): + def __init__(self): + super(PluginLinuxSystem, self).__init__() + self.last_error = 0 + self.files_block = 0 + self.files = [] + self.files_requested = {} + self.folder_requested = {} + self.folder_address = {} + self.file_address = {} + self.folder_address_to_name = {} + self.stop_flag = False + self.dict_calls = {} + self.expl_method = "BFS" + + self.file_extensions = "doc docx xls" # xlsx ppt pptx pst ost msg eml vsd vsdx txt csv rtf wks wk1" + self.linux_folders = { + "/home": { + "/user": { + "/.local": { + "/share": { + "/Trash": { + } + } + }, + "/Desktop": { + } + } + }, + "/media": { + "/user": { + } + } + } + + + + #["/home/user/.local/share/Trash/","/media/user/","/home/user/Desktop/"] + self.current_file_per_folder = [0, { + "/home": [1, { + "/user": [2, { + "/.local": [1, { + "/share": [1, { + "/Trash": [0, { + }] + }] + }], + "/Desktop": [0, { + }] + }] + }], + "/media": [1, { + "/user": [0, { + }] + }] + }] + + # { + # "/home/user/.local/share/Trash/":0, + # "/media/user/":0, + # "/home/user/Desktop/":0 + # } + + self.linux_files = { + "/home": { + "files": [], + "/user": { + "files": [], + "/.local": { + "files": [], + "/share": { + "files": [], + "/Trash": { + "files": [], + } + } + }, + "/Desktop": { + "files": [], + } + } + }, + "/media": { + "files": [], + "/user": { + "files": [], + } + } + } + + # { + # "/home/user/.local/share/Trash/":[], + # "/media/user/":[], + # "/home/user/Desktop/":[] + # } + + # for folder in self.linux_folders: + # for extension in self.file_extensions.split(" "): + # simfile_name = "file." + extension + # self.linux_files[folder].append(simfile_name) + + current_folder_level = list(self.linux_folders.keys()) + current_folder = self.linux_files + previous_folder = [] + previous_current_file_per_folder = [] + current_file_per_folder = self.current_file_per_folder + current_path = [] + end_folder = False + while current_folder_level: + #print("-------------------------------") + #print("current_folder_level: ", str(current_folder_level)) + + folder = current_folder_level.pop() + #print("folder: ", str(folder)) + + if end_folder: + while len(current_path) >= 0: + current_path.pop() + current_folder = previous_folder.pop() + current_file_per_folder = previous_current_file_per_folder.pop() + # print(current_folder.keys()) + if folder in current_folder.keys(): + break + + current_path.append(folder) + #print("current_path: ", str(current_path)) + + new_folder_level = list(current_folder[folder].keys()) + new_folder_level.remove("files") + + previous_folder.append(current_folder) + current_folder = current_folder[folder] + + previous_current_file_per_folder.append(current_file_per_folder) + current_file_per_folder = current_file_per_folder[1][folder] + + #print("current_folder: ", str(current_folder)) + + if len(new_folder_level) == 0: # reach end of the tree + # print("We are at the end of the tree") + for extension in self.file_extensions.split(" "): + simfile_name = "/file." + extension + current_folder["files"].append([False, simfile_name]) # False means not read yet + current_file_per_folder[0] += 1 + end_folder = True + else: + #print("We are not at the end of the tree") + for new_folder in new_folder_level: + current_folder_level.append(new_folder) + end_folder = False + + # current_folder_level.remove(folder) + + #print(self.linux_files) + # exit(0) + + def stores(self, offset, val, size): + return self.state.memory.store(self.files_block + offset, val, size=size, endness="Iend_BE") + + def storei(self, offset, val, size): + return self.state.memory.store(self.files_block + offset, val, size=size, endness="Iend_LE") + + def add_folder(self, folder): + + splitted_path = folder.split("/") + current_folder = self.linux_folders + current_folder_file = self.linux_files + current_file_per_folder = self.current_file_per_folder + for part in splitted_path: + if part in current_folder.keys(): + current_folder = current_folder[part] + current_file_per_folder = current_file_per_folder[1][part] + current_folder_file = current_folder_file[part] + else: + current_folder[part] = {} + current_file_per_folder[1][part] = [0, {}] + current_folder_file[part] = {"files": []} + + #self.files_block = self.state.heap.malloc(512) + self.folder_address[folder] = self.state.heap.malloc(512) # self.files_block + # self.current_file_per_folder[folder] = 0 + self.folder_address_to_name[self.folder_address[folder]] = folder + for i in range(512): + c = self.state.solver.BVS("c_files_block{}".format(i), 8) + self.state.memory.store(self.files_block + i, c) + + # self.struct = Dirent( + # self.state.solver.BVV(0, 64), # d_ino /* inode number */ + # self.state.solver.BVV(0, 64), # d_off /* offset to the next dirent */ + # self.state.solver.BVS("d_reclen", 16, key=("api", "readdir", "d_reclen")), # d_reclen /* length of this record */ + # self.state.solver.BVS("d_type", 8, key=("api", "readdir", "d_type")), # d_type /* type of file; not supported by all file system types */ + # self.state.solver.BVS("d_name", 255 * 8, key=("api", "readdir", "d_name")), + # ) # d_name + + # simfile = angr.SimFile(simfile_name, content='wtf why has this been so annoying') + + + d_ino = 0 + d_off = 0 + d_reclen = 8 + 8 + 2 + 1 + len(folder.encode("utf-8")) + + + self.storei(i, d_ino, 8) + self.storei(i+8, d_off, 8) + self.storei(i+16, d_reclen, 2) + self.storei(i+18, 0x4, 1) # Folder + self.stores(i+18+1, folder.encode("utf-8"), len(folder.encode("utf-8"))) + i = i + 18 + len(folder.encode("utf-8")) + + def add_file(self, file): + self.files_block = self.state.heap.malloc(512) + self.file_address[file] = self.files_block # self.state.heap.malloc(512) # self.files_block + for i in range(512): + c = self.state.solver.BVS("c_files_block{}".format(i), 8) + self.state.memory.store(self.files_block + i, c) + + d_ino = 0 + d_off = 0 + d_reclen = 8 + 8 + 2 + 1 + len(file.encode("utf-8")) + + self.storei(i, d_ino, 8) + self.storei(i+8, d_off, 8) + self.storei(i+16, d_reclen, 2) + self.storei(i+18, 0x8, 1) # File + self.stores(i+18+1, file.encode("utf-8"), len(file.encode("utf-8"))) + i = i + 18 + len(file.encode("utf-8")) + + def setup_plugin(self): + i = 0 + # for folder in self.linux_folders: + # #self.files_block = self.state.heap.malloc(512) + # self.folder_address[folder] = self.state.heap.malloc(512) # self.files_block + # self.folder_address_to_name[self.folder_address[folder]] = folder + # for i in range(512): + # c = self.state.solver.BVS("c_files_block{}".format(i), 8) + # self.state.memory.store(self.files_block + i, c) + + # d_ino = 0 + # d_off = 0 + # d_reclen = 8 + 8 + 2 + 1 + len(folder.encode("utf-8")) + + # self.storei(i, d_ino, 8) + # self.storei(i+8, d_off, 8) + # self.storei(i+16, d_reclen, 2) + # self.storei(i+18, 0x4, 1) # Folder + # self.stores(i+18 + len(folder.encode("utf-8")), folder.encode("utf-8"), len(folder.encode("utf-8"))) + # i = i + 18 + len(folder.encode("utf-8")) + + current_folder_level = list(self.linux_folders.keys()) + current_folder = self.linux_folders + previous_folder = [] + current_path = [] + end_folder = False + while current_folder_level: + print("current_folder_level: ", str(current_folder_level)) + + folder = current_folder_level.pop() + print("folder: ", str(folder)) + + if end_folder: + while len(current_path) >= 0: + current_path.pop() + current_folder = previous_folder.pop() + print(current_folder.keys()) + if folder in current_folder.keys(): + break + + current_path.append(folder) + print("current_path: ", str(current_path)) + self.files_block = self.state.heap.malloc(512) + self.folder_address["".join(current_path)] = self.files_block # self.state.heap.malloc(512) # self.files_block + self.folder_address_to_name[self.folder_address["".join(current_path)]] = "".join(current_path) + for i in range(512): + c = self.state.solver.BVS("c_files_block{}".format(i), 8) + self.state.memory.store(self.files_block + i, c) + + d_ino = 0 + d_off = 0 + d_reclen = 8 + 8 + 2 + 1 + len(folder.encode("utf-8")) + i = 0 + self.storei(i, d_ino, 8) + self.storei(i+8, d_off, 8) + self.storei(i+16, d_reclen, 2) + self.storei(i+18, 0x4, 1) # Folder + self.stores(i+18+1, folder.encode("utf-8"), len(folder.encode("utf-8"))) + i = 0 # i + 18 + + len(folder.encode("utf-8")) + + new_folder_level = list(current_folder[folder].keys()) + + previous_folder.append(current_folder) + current_folder = current_folder[folder] + + if len(new_folder_level) == 0: # reach end of the tree + end_folder = True + else: + for new_folder in new_folder_level: + current_folder_level.append(new_folder) + end_folder = False + + + # for file in self.linux_files: + # #self.files_block = self.state.heap.malloc(512) + # self.file_address[file] = self.state.heap.malloc(512) # self.files_block + # for i in range(512): + # c = self.state.solver.BVS("c_files_block{}".format(i), 8) + # self.state.memory.store(self.files_block + i, c) + + # d_ino = 0 + # d_off = 0 + # d_reclen = 8 + 8 + 2 + 1 + len(file.encode("utf-8")) + + # self.storei(i, d_ino, 8) + # self.storei(i+8, d_off, 8) + # self.storei(i+16, d_reclen, 2) + # self.storei(i+18, 0x8, 1) # File + # self.stores(i+18 + len(file.encode("utf-8")), file.encode("utf-8"),len(file.encode("utf-8"))) + # i = i + 18 + len(file.encode("utf-8")) + print(self.folder_address) + + current_folder_level = list(self.linux_folders.keys()) + current_folder = self.linux_files + previous_folder = [] + current_path = [] + end_folder = False + + while current_folder_level: + print("current_folder_level: ", str(current_folder_level)) + + folder = current_folder_level.pop() + print("folder: ", str(folder)) + + if end_folder: + while len(current_path) >= 0: + current_path.pop() + current_folder = previous_folder.pop() + print(current_folder.keys()) + if folder in current_folder.keys(): + break + + current_path.append(folder) + print("current_path: ", str(current_path)) + + + new_folder_level = list(current_folder[folder].keys()) + new_folder_level.remove("files") + + # TODO problem current_path + if len(new_folder_level) == 0: # reach end of the tree + for file in current_folder[folder]["files"]: + print(file) + self.files_block = self.state.heap.malloc(512) + self.file_address["".join(current_path) + file[1]] = self.files_block # self.state.heap.malloc(512) # self.files_block # TODO add path in key + for i in range(512): + c = self.state.solver.BVS("c_files_block{}".format(i), 8) + self.state.memory.store(self.files_block + i, c) + i = 0 + d_ino = 0 + d_off = 0 + d_reclen = 8 + 8 + 2 + 1 + len(file[1].encode("utf-8")) + + self.storei(i, d_ino, 8) + self.storei(i+8, d_off, 8) + self.storei(i+16, d_reclen, 2) + self.storei(i+18, 0x8, 1) # File + self.stores(i+18+1, file[1].encode("utf-8"),len(file[1].encode("utf-8"))) + i = 0 #i + 18 + 1 + len(file[1].encode("utf-8")) + end_folder = True + else: + for new_folder in new_folder_level: + current_folder_level.append(new_folder) + end_folder = False + + previous_folder.append(current_folder) + current_folder = current_folder[folder] + + print(self.file_address) + + + + def update_dic(self, call_name): + if call_name in self.dict_calls: + if self.dict_calls[call_name] > 5: + self.stop_flag = True + self.dict_calls[call_name] = 0 + else: + self.dict_calls[call_name] = self.dict_calls[call_name] + 1 + else: + self.dict_calls[call_name] = 1 + + + @angr.SimStatePlugin.memo + def copy(self, memo): + # TODO for loop on all the attributes + p = PluginLinuxSystem() + p.last_error = self.last_error + p.files_block = self.files_block + p.file_address = self.file_address.copy() + p.folder_address = self.folder_address.copy() + p.folder_requested = self.folder_requested.copy() + p.files = self.files.copy() + p.linux_files = self.linux_files.copy() + p.folder_address_to_name = self.folder_address_to_name.copy() + p.current_file_per_folder = self.current_file_per_folder.copy() + p.stop_flag = self.stop_flag + p.dict_calls = self.dict_calls.copy() + p.files_requested = self.files_requested.copy() + return p + + def merge(self): + pass diff --git a/sema_toolchain/sema_scdg/application/plugin/PluginManager.py b/sema_toolchain/sema_scdg/application/plugin/PluginManager.py index 95d3a7392..4a7f397e1 100644 --- a/sema_toolchain/sema_scdg/application/plugin/PluginManager.py +++ b/sema_toolchain/sema_scdg/application/plugin/PluginManager.py @@ -14,6 +14,8 @@ from plugin.PluginAtom import PluginAtom from plugin.PluginPacking import PluginPacking from plugin.PluginThread import PluginThread +from plugin.PluginLinuxSystem import PluginLinuxSystem +from plugin.PluginCallReplace import PluginCallReplace class PluginManager(): @@ -23,6 +25,7 @@ def __init__(self): self.commands = PluginCommands() self.ioc = PluginIoC() self.packing = PluginPacking() + self.replace = PluginCallReplace() # Load and setup plugins set to true in config file def load_plugin(self, state, config): @@ -45,6 +48,9 @@ def load_plugin(self, state, config): state.plugin_registry.setup_plugin() elif plugin == "plugin_atom" : state.register_plugin(plugin, PluginAtom()) + elif plugin == "plugin_linux_fs": + state.register_plugin(plugin, PluginLinuxSystem()) + state.plugin_linux_fs.setup_plugin() #TODO Christophe : Check if plugin thread does the right thing (handles thread in the binary and not try to multithread angr execution) # elif plugin == "plugin_thread" : # state.register_plugin("plugin_thread", PluginThread(self, exp_dir, proj, nameFileShort, options)) @@ -61,3 +67,6 @@ def enable_plugin_ioc(self, scdg_graph, exp_dir): def get_plugin_packing(self): return self.packing + + def enable_plugin_call_replace(self, scdg_graph): + self.replace.call_replace(scdg_graph) diff --git a/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/EVP_CIPHER_CTX_cleanup.py b/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/EVP_CIPHER_CTX_cleanup.py new file mode 100644 index 000000000..0e2a885ea --- /dev/null +++ b/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/EVP_CIPHER_CTX_cleanup.py @@ -0,0 +1,17 @@ +import os +import sys +import logging +import angr + +try: + lw = logging.getLogger("CustomSimProcedureLinux") + lw.setLevel(os.environ["LOG_LEVEL"]) +except Exception as e: + print(e) + + +class EVP_CIPHER_CTX_cleanup(angr.SimProcedure): + def run(self, ctx): + # Clears all information from a cipher context and free up any allocated memory associated with it + # Possibly same function than EVP_CIPHER_CTX_reset + return 1 \ No newline at end of file diff --git a/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/EVP_CIPHER_CTX_init.py b/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/EVP_CIPHER_CTX_init.py new file mode 100644 index 000000000..f454f5b38 --- /dev/null +++ b/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/EVP_CIPHER_CTX_init.py @@ -0,0 +1,16 @@ +import os +import sys +import logging +import angr + +try: + lw = logging.getLogger("CustomSimProcedureLinux") + lw.setLevel(os.environ["LOG_LEVEL"]) +except Exception as e: + print(e) + + +class EVP_CIPHER_CTX_init(angr.SimProcedure): + def run(self, ctx): + # creates a cipher context + return 1 \ No newline at end of file diff --git a/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/EVP_CIPHER_CTX_new.py b/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/EVP_CIPHER_CTX_new.py new file mode 100644 index 000000000..edab8012f --- /dev/null +++ b/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/EVP_CIPHER_CTX_new.py @@ -0,0 +1,18 @@ +import os +import sys +import logging +import angr + +try: + lw = logging.getLogger("CustomSimProcedureLinux") + lw.setLevel(os.environ["LOG_LEVEL"]) +except Exception as e: + print(e) + + +class EVP_CIPHER_CTX_new(angr.SimProcedure): + def run(self): + # initializes cipher contex ctx + #ctx not useful so every evp_cipher_CTX skipped + #need to change all evp_cipher_CTX function for really simulated the library. + return 1 \ No newline at end of file diff --git a/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/EVP_CIPHER_CTX_reset.py b/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/EVP_CIPHER_CTX_reset.py new file mode 100644 index 000000000..f2f085ac8 --- /dev/null +++ b/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/EVP_CIPHER_CTX_reset.py @@ -0,0 +1,18 @@ + +import os +import sys +import logging +import angr + +try: + lw = logging.getLogger("CustomSimProcedureLinux") + lw.setLevel(os.environ["LOG_LEVEL"]) +except Exception as e: + print(e) + + +class EVP_CIPHER_CTX_reset(angr.SimProcedure): + def run(self, ctx): + # Clears all information from a cipher context and free up any allocated memory associated with it + # Possibly same function than EVP_CIPHER_CTX_cleanup + return 1 \ No newline at end of file diff --git a/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/EVP_CIPHER_CTX_set_key_length.py b/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/EVP_CIPHER_CTX_set_key_length.py new file mode 100644 index 000000000..1e474cc35 --- /dev/null +++ b/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/EVP_CIPHER_CTX_set_key_length.py @@ -0,0 +1,16 @@ +import os +import sys +import logging +import angr + +try: + lw = logging.getLogger("CustomSimProcedureLinux") + lw.setLevel(os.environ["LOG_LEVEL"]) +except Exception as e: + print(e) + + +class EVP_CIPHER_CTX_set_key_length(angr.SimProcedure): + def run(self, ctx, lenght): + # sets the key length of the cipher ctx + return 1 \ No newline at end of file diff --git a/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/EVP_CipherFinal_ex.py b/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/EVP_CipherFinal_ex.py new file mode 100644 index 000000000..7c9baa33a --- /dev/null +++ b/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/EVP_CipherFinal_ex.py @@ -0,0 +1,22 @@ +import os +import sys +import logging +import angr +import claripy + +try: + lw = logging.getLogger("CustomSimProcedureLinux") + lw.setLevel(os.environ["LOG_LEVEL"]) +except Exception as e: + print(e) + + +class EVP_CipherFinal_ex(angr.SimProcedure): + def run(self, ctx, outbuf, outlen): + # return 1 for success and 0 for failure + lw.debug("EVP_CipherFinal_ex called") + self.state.memory.store(outbuf, 0) + self.state.memory.store(outlen, 0) + ret_val = self.state.solver.BVS("retval_{}".format(self.display_name), self.state.arch.bits) + self.state.solver.add(claripy.Or(ret_val == 0, ret_val == 1)) + return ret_val \ No newline at end of file diff --git a/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/EVP_CipherInit_ex.py b/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/EVP_CipherInit_ex.py new file mode 100644 index 000000000..3bcdd30a5 --- /dev/null +++ b/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/EVP_CipherInit_ex.py @@ -0,0 +1,18 @@ +import os +import sys +import logging +import angr + +try: + lw = logging.getLogger("CustomSimProcedureLinux") + lw.setLevel(os.environ["LOG_LEVEL"]) +except Exception as e: + print(e) + + +class EVP_CipherInit_ex(angr.SimProcedure): + def run(self, ctx, type, impl, key, iv, enc): + # init ctx for decryption or encryption + # enc = 1 for encrypt + # enc = 0 decrypt + return 0 \ No newline at end of file diff --git a/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/EVP_CipherUpdate.py b/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/EVP_CipherUpdate.py new file mode 100644 index 000000000..d7225c72c --- /dev/null +++ b/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/EVP_CipherUpdate.py @@ -0,0 +1,28 @@ +import os +import sys +import logging +import angr +import claripy +from angr.procedures.libc.system import system + +try: + lw = logging.getLogger("CustomSimProcedureLinux") + lw.setLevel(os.environ["LOG_LEVEL"]) +except Exception as e: + print(e) + + +class EVP_CipherUpdate(angr.SimProcedure): + def run(self, ctx, outbuf, outlen, inbuf, inlen): + # return 1 for success and 0 for failure + lw.debug("EVP_CipherUpdate.run") + + + val = self.state.solver.eval(inlen) + lw.debug(val) + + self.state.memory.store(outlen,val) + + ret_val = self.state.solver.BVS("retval_{}".format(self.display_name), self.state.arch.bits) + self.state.solver.add(claripy.Or(ret_val == 0, ret_val == 1)) + return ret_val \ No newline at end of file diff --git a/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/EVP_bf_cbc.py b/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/EVP_bf_cbc.py new file mode 100644 index 000000000..0fbb9e14a --- /dev/null +++ b/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/EVP_bf_cbc.py @@ -0,0 +1,16 @@ +import os +import sys +import logging +import angr + +try: + lw = logging.getLogger("CustomSimProcedureLinux") + lw.setLevel(os.environ["LOG_LEVEL"]) +except Exception as e: + print(e) + + +class EVP_bf_cbc(angr.SimProcedure): + def run(self): + # encryption algorithm + return 1 \ No newline at end of file diff --git a/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/atoi.py b/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/atoi.py new file mode 100644 index 000000000..ed835b344 --- /dev/null +++ b/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/atoi.py @@ -0,0 +1,27 @@ +import os +import sys + +import angr +from .open import open + +import logging + +try: + lw = logging.getLogger("CustomSimProcedureLinux") + lw.setLevel(os.environ["LOG_LEVEL"]) +except Exception as e: + print(e) + +# should be safe bc gonnacry doesn't use fields of DIR * +class atoi(angr.SimProcedure): + def run(self, s_addr): + # load string from address... how do i do this? + strlen = angr.SIM_PROCEDURES["libc"]["strlen"] + + s_strlen = self.inline_call(strlen, s_addr) + p_expr = self.state.memory.load( + s_addr, s_strlen.max_null_index, endness="Iend_BE" + ) + string = self.state.solver.eval(p_expr, cast_to=bytes).decode() + lw.debug('Using atoi found the string '+string) + return int(string) \ No newline at end of file diff --git a/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/chdir.py b/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/chdir.py index c7e79623f..bb2b713e4 100644 --- a/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/chdir.py +++ b/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/chdir.py @@ -8,6 +8,6 @@ class chdir(angr.SimProcedure): def run(self, buf): cwd = self.state.mem[buf].string.concrete # FIX ANGR ERROR - # l.info('chdir(%r)', cwd) + # lw.debug('chdir(%r)', cwd) self.state.fs.cwd = cwd return 0 diff --git a/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/fopen.py b/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/fopen.py new file mode 100644 index 000000000..a19d4fd6e --- /dev/null +++ b/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/fopen.py @@ -0,0 +1,98 @@ +import os +import sys + +import angr +import logging + +from cle.backends.externs.simdata.io_file import io_file_data_for_arch + +###################################### +# fopen +###################################### + +import logging as lw + +try: + lw = logging.getLogger("CustomSimProcedureLinux") + lw.setLevel(os.environ["LOG_LEVEL"]) +except Exception as e: + print(e) + +def mode_to_flag(mode): + # TODO improve this: handle mode = strings + lw.debug("mode_to_flag") + lw.debug(mode) + if mode[-1] == ord("b"): # lol who uses windows + mode = mode[:-1] + elif mode[-1] == ord("t"): # Rarely modes rt or wt are used, but identical to r and w + mode = mode[:-1] + mode = mode.replace(b"c", b"").replace(b"e", b"") + all_modes = { + b"r": angr.storage.file.Flags.O_RDONLY, + b"r+": angr.storage.file.Flags.O_RDWR, + b"w": angr.storage.file.Flags.O_WRONLY | angr.storage.file.Flags.O_CREAT, + b"w+": angr.storage.file.Flags.O_RDWR | angr.storage.file.Flags.O_CREAT, + b"a": angr.storage.file.Flags.O_WRONLY | angr.storage.file.Flags.O_CREAT | angr.storage.file.Flags.O_APPEND, + b"a+": angr.storage.file.Flags.O_RDWR | angr.storage.file.Flags.O_CREAT | angr.storage.file.Flags.O_APPEND, + } + if mode not in all_modes: + raise angr.SimProcedureError("unsupported file open mode %s" % mode) + + return all_modes[mode] + + +class fopen(angr.SimProcedure): + # pylint:disable=arguments-differ + + def run(self, p_addr, m_addr): + strlen = angr.SIM_PROCEDURES["libc"]["strlen"] + + p_strlen = self.inline_call(strlen, p_addr) + m_strlen = self.inline_call(strlen, m_addr) + p_expr = self.state.memory.load(p_addr, p_strlen.max_null_index, endness="Iend_BE") + m_expr = self.state.memory.load(m_addr, m_strlen.max_null_index, endness="Iend_BE") + path = self.state.solver.eval(p_expr, cast_to=bytes) + mode = self.state.solver.eval(m_expr, cast_to=bytes) + + lw.debug("fopen") + lw.debug(path) + + path_str = path.decode("utf-8") + if "//" in path_str: + path_str = path_str.replace("//","/") # TODO: improve this + + path = path_str.encode("utf-8") + + lw.debug(path) + + # TODO: handle append + fd = self.state.posix.open(path, mode_to_flag(mode)) + #not implement in this version of angr + #fd_concr = self.state.posix.get_concrete_fd(fd) + lw.debug(fd) + if isinstance(fd, int) and fd >= 0 : + fd_concr = fd + else: + return 0 + + if fd_concr == -1: + # if open failed return NULL + return 0 + + # Allocate a FILE struct in heap + malloc = angr.SIM_PROCEDURES["libc"]["malloc"] + io_file_data = io_file_data_for_arch(self.state.arch) + file_struct_ptr = self.inline_call(malloc, io_file_data["size"]).ret_expr + + # Write the fd + size = 4 # int + self.state.memory.store( + file_struct_ptr + io_file_data["fd"], fd, size=size, endness=self.state.arch.memory_endness + ) + + if self.state.solver.is_true(fd == fd_concr): + return file_struct_ptr + else: + # still possible that open failed + null = self.state.solver.BVV(0, self.state.arch.bits) + return self.state.solver.If(fd == fd_concr, file_struct_ptr, null) \ No newline at end of file diff --git a/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/fread.py b/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/fread.py new file mode 100644 index 000000000..25ce2e969 --- /dev/null +++ b/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/fread.py @@ -0,0 +1,33 @@ +import os +import random +import sys +import logging +import angr +import claripy +from cle.backends.externs.simdata.io_file import io_file_data_for_arch + +try: + lw = logging.getLogger("CustomSimProcedureLinux") + lw.setLevel(os.environ["LOG_LEVEL"]) +except Exception as e: + print(e) + +class fread(angr.SimProcedure): + #code from : https://github.com/angr/angr/blob/master/angr/procedures/libc/fread.py + def run(self, buffer, size, count, stream): + lw.debug("fread") + #real implementation + # lw.debug(self.state.solver.eval(size*count)) + # fd_offset = io_file_data_for_arch(self.state.arch)["fd"] + # fd = self.state.mem[stream + fd_offset :].int.resolved + # simfd = self.state.posix.get_fd(fd) + # if simfd is None: + # lw.debug("fread failed") + # return -1 + # + # ret = simfd.read(buffer, size * count) + # lw.debug(self.state.solver.eval(ret)) + #return claripy.If(claripy.Or(size == 0, count == 0), 0, ret // size) + + #but because empty file -> problem -> alway return 0 + return random.randint(0,5) \ No newline at end of file diff --git a/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/fwrite.py b/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/fwrite.py new file mode 100644 index 000000000..f5f25618a --- /dev/null +++ b/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/fwrite.py @@ -0,0 +1,37 @@ +import os +import sys +import logging +import angr +import claripy +from cle.backends.externs.simdata.io_file import io_file_data_for_arch + +try: + lw = logging.getLogger("CustomSimProcedureLinux") + lw.setLevel(os.environ["LOG_LEVEL"]) +except Exception as e: + print(e) + + +class fwrite(angr.SimProcedure): + #code from = https://github.com/angr/angr/blob/master/angr/procedures/libc/fwrite.py + # pylint:disable=arguments-differ + def run(self, buffer, size, count, stream): + # buffer - pointer to the first object in the array to be written + # size - size of each object + # count - the number of the objects to be written + # stream - pointer to the output stream + # file are empty so no data to read/write + lw.debug("fwrite") + # ret_val = self.state.solver.BVS('ret_val', self.state.arch.bits) + # self.state.solver.add(claripy.Or(ret_val == 0, ret_val == 2)) + # return ret_val + lw.debug(count) + lw.debug(self.state.solver.eval(count)) + fd_offset = io_file_data_for_arch(self.state.arch)["fd"] + fileno = self.state.mem[stream + fd_offset :].int.resolved + simfd = self.state.posix.get_fd(fileno) + if simfd is None: + return -1 + return simfd.write(buffer, size * count) + +fwrite_unlocked = fwrite \ No newline at end of file diff --git a/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/getpwuid.py b/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/getpwuid.py index c35c2a6e0..ae24fc41e 100644 --- a/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/getpwuid.py +++ b/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/getpwuid.py @@ -1,39 +1,68 @@ import os import sys - -import os import angr import logging -try: +try: lw = logging.getLogger("CustomSimProcedureLinux") lw.setLevel(os.environ["LOG_LEVEL"]) except Exception as e: print(e) - + + class getpwuid(angr.SimProcedure): # pylint: disable=arguments-differ - def run(self,uid): + def run(self, uid): lw.debug(self.cc) """_summary_ struct passwd { char *pw_name; char *pw_passwd; - uid_t pw_uid; - gid_t pw_gid; - time_t pw_change; - char *pw_class; + uid_t pw_uid; # using unsigned int instead + gid_t pw_gid; # using unsigned int instead char *pw_gecos; char *pw_dir; char *pw_shell; - time_t pw_expire; - }; + }; """ - passwd_struc = self.state.solver.BVV(50) # TODO better struct - ret_len = len(50) - passwd_struc_ptr = self.state.heap._malloc(ret_len) + + passwd_struct_def = ( + "struct passwd {" + "char *pw_name;" + "char *pw_passwd;" + "unsigned int pw_uid;" # using unsigned int instead + "unsigned int pw_gid;" # using unsigned int instead + "char *pw_gecos;" + "char *pw_dir;" + "char *pw_shell;" + "}" + ) + + # adding username, pw_name + pw_name_val = b"user\0" + pw_name_ptr = self.state.heap.malloc(len(pw_name_val)) self.state.memory.store( - passwd_struc_ptr, passwd_struc - ) # ,endness=self.arch.memory_endness) - return passwd_struc_ptr + pw_name_ptr, + self.state.solver.BVV(pw_name_val, len(pw_name_val) * 8) + ) + + # adding home directory, pw_dir + pw_dir_val = b"/home/user\0" + pw_dir_ptr = self.state.heap.malloc(len(pw_dir_val)) + self.state.memory.store( + pw_dir_ptr, + self.state.solver.BVV(pw_dir_val, len(pw_dir_val) * 8) + ) + + passwd_struct_SimType = angr.types.parse_type(passwd_struct_def).with_arch(self.state.arch) + angr.types.register_types(passwd_struct_SimType) + passwd_struct_size_bytes = int(passwd_struct_SimType.size // 8) + passwd_struct_ptr = self.state.heap.malloc(passwd_struct_size_bytes) + + # write values to memory + self.state.mem[passwd_struct_ptr].struct.passwd.pw_name = pw_name_ptr + self.state.mem[passwd_struct_ptr].struct.passwd.pw_dir = pw_dir_ptr + + + return passwd_struct_ptr diff --git a/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/is_path.py b/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/is_path.py new file mode 100644 index 000000000..e822ec1b9 --- /dev/null +++ b/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/is_path.py @@ -0,0 +1,22 @@ +import os +import sys +import logging +import angr +import claripy +from angr.procedures.libc.system import system + +try: + lw = logging.getLogger("CustomSimProcedureLinux") + lw.setLevel(os.environ["LOG_LEVEL"]) +except Exception as e: + print(e) + + +class is_path(angr.SimProcedure): + def run(self, path): + lw.debug("is_path?") + + ret_val = self.state.solver.BVS('ret_val', self.state.arch.bits) + self.state.solver.add(claripy.Or(ret_val == 1, ret_val == 0)) + + return ret_val \ No newline at end of file diff --git a/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/kill.py b/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/kill.py new file mode 100644 index 000000000..b295db620 --- /dev/null +++ b/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/kill.py @@ -0,0 +1,9 @@ +import os +import sys + +import angr + + +class kill(angr.SimProcedure): + def run(self, pid, sig): + return 0 \ No newline at end of file diff --git a/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/memcpy.py b/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/memcpy.py new file mode 100644 index 000000000..f8de39544 --- /dev/null +++ b/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/memcpy.py @@ -0,0 +1,84 @@ +import os +import sys + +import angr +import logging + +try: + lw = logging.getLogger("CustomSimProcedureLinux") + lw.setLevel(os.environ["LOG_LEVEL"]) +except Exception as e: + print(e) + +# class memcpy(angr.SimProcedure): +# #pylint:disable=arguments-differ + +# def run(self, dest, src, count): +# if count.symbolic: +# self.state.memory.store(dest, self.state.memory.load(src, 0x20)) +# return dest + +# else: +# self.state.memory.store(dest, self.state.memory.load(src, self.state.solver.eval(count))) +# return dest + + +class memcpy(angr.SimProcedure): + #pylint:disable=arguments-differ + + def run(self, dst_addr, src_addr, limit): + if not self.state.solver.symbolic(limit): + # not symbolic so we just take the value + lw.debug("not symb") + conditional_size = self.state.solver.eval(limit) + else: + lw.debug("symb") + # constraints on the limit are added during the store + max_memcpy_size = self.state.libc.max_memcpy_size + max_limit = self.state.solver.max_int(limit) + min_limit = self.state.solver.min_int(limit) + conditional_size = min(max_memcpy_size, max(min_limit, max_limit)) + if max_limit > max_memcpy_size and conditional_size < max_limit: + lw.debug("memcpy upper bound of %#x outside limit, limiting to %#x instead", + max_limit, conditional_size) + + lw.debug("Memcpy running with conditional_size %#x", conditional_size) + + if conditional_size > 0: + if conditional_size < 0x18000000: #True: # conditional_size < 0x18000000 + lw.debug("conditional_size < 0x18000000") + src_mem = self.state.memory.load(src_addr, conditional_size, endness='Iend_BE') + lw.debug(src_addr) + if ABSTRACT_MEMORY in self.state.options: + self.state.memory.store(dst_addr, src_mem, size=limit, endness='Iend_BE') + else: + lw.debug(dst_addr) + self.state.memory.store(dst_addr, src_mem, size=conditional_size, endness='Iend_BE') # size=limit + else: + lw.debug("conditional_size >= 0x18000000") + tenth = int(conditional_size/100) + conditional_size = int(conditional_size/100) + lw.debug("new conditional_size {}".format(conditional_size)) + offset = 0 + for i in range(100): + lw.debug("submemcpy {}".format(i)) + # return 0x0 # failure + inter_dst_addr = dst_addr + offset + inter_src_addr = src_addr + offset + # max_memcpy_size = self.state.libc.max_memcpy_size + # lw.debug(max_memcpy_size) + # max_limit = self.state.solver.max_int(limit) + # min_limit = self.state.solver.min_int(limit) + #conditional_size = min(max_memcpy_size, max(min_limit, max_limit)) + src_mem = self.state.memory.load(inter_src_addr, conditional_size, endness='Iend_BE') + lw.debug(inter_src_addr) + if ABSTRACT_MEMORY in self.state.options: + self.state.memory.store(inter_dst_addr, src_mem, size=conditional_size, endness='Iend_BE') + else: + lw.debug(inter_dst_addr) + self.state.memory.store(inter_dst_addr, src_mem, size=conditional_size, endness='Iend_BE') + offset += int(conditional_size/100) + + return dst_addr + +from angr.sim_options import ABSTRACT_MEMORY diff --git a/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/opendir.py b/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/opendir.py new file mode 100644 index 000000000..f24ff8d39 --- /dev/null +++ b/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/opendir.py @@ -0,0 +1,87 @@ +import os +import sys +import angr +import logging +from collections import namedtuple +from .open import open # if needed + + +try: + lw = logging.getLogger("CustomSimProcedureLinux") + lw.setLevel(os.environ["LOG_LEVEL"]) +except Exception as e: + print(e) + +# This is the structure used by _build_amd64/_store_amd64 (used by readdir). +from collections import namedtuple + +Dirent = namedtuple("dirent", ("d_ino", "d_off", "d_reclen", "d_type", "d_name")) + + +class opendir(angr.SimProcedure): + struct = None + condition = None + + def run(self, dirp): # pylint: disable=arguments-differ + # TODO: make sure argument is actually a DIR struct + if self.state.arch.name != "AMD64": + lw.error("readdir SimProcedure is only implemented for AMD64") + return 0 + + if dirp.symbolic: + lw.debug("dirp is symbolic") + lw.debug(dirp) + self._build_amd64() + self.instrument() + malloc = angr.SIM_PROCEDURES["libc"]["malloc"] + pointer = self.inline_call(malloc, 19 + 256).ret_expr + self._store_amd64(pointer) + else: + lw.debug("dirp is concrete") + lw.debug(dirp) + folder_name = self.state.mem[dirp].string.concrete + if hasattr(folder_name, "decode"): + folder_name = folder_name.decode("utf-8") + lw.debug(folder_name) + lw.debug(self.state.plugin_linux_fs.folder_address) + if folder_name in self.state.plugin_linux_fs.folder_address.keys() and \ + self.state.plugin_linux_fs.folder_address[folder_name] != None: + pointer = self.state.plugin_linux_fs.folder_address[folder_name] + else: + self.state.plugin_linux_fs.add_folder(folder_name) + pointer = self.state.plugin_linux_fs.folder_address[folder_name] + + return pointer # self.state.solver.If(self.condition, pointer, 0) + + def instrument(self): + """ + Override this function to instrument the SimProcedure. + + The two useful variables you can override are self.struct, a named tuple of all the struct + fields, and self.condition, the condition for whether the function succeeds. + """ + pass + + def _build_amd64(self): + self.struct = Dirent( + self.state.solver.BVV(0, 64), # d_ino + self.state.solver.BVV(0, 64), # d_off + self.state.solver.BVS("d_reclen", 16, key=("api", "readdir", "d_reclen")), # d_reclen + self.state.solver.BVS("d_type", 8, key=("api", "readdir", "d_type")), # d_type + self.state.solver.BVS("d_name", 255 * 8, key=("api", "readdir", "d_name")), + ) # d_name + self.condition = self.state.solver.BoolS("readdir_cond") # TODO: variable key + + def _store_amd64(self, ptr): + def stores(offset, val): + return self.state.memory.store(ptr + offset, val, endness="Iend_BE") + + def storei(offset, val): + return self.state.memory.store(ptr + offset, val, endness="Iend_LE") + + storei(0, self.struct.d_ino) + storei(8, self.struct.d_off) + storei(16, self.struct.d_reclen) + storei(18, self.struct.d_type) + stores(19, self.struct.d_name) + stores(19 + 255, self.state.solver.BVV(0, 8)) \ No newline at end of file diff --git a/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/rand.py b/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/rand.py new file mode 100644 index 000000000..982d5d3fa --- /dev/null +++ b/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/rand.py @@ -0,0 +1,21 @@ +import os +import sys + +import angr +import logging + +try: + lw = logging.getLogger("CustomSimProcedureLinux") + lw.setLevel(os.environ["LOG_LEVEL"]) +except Exception as e: + print(e) + +class rand(angr.SimProcedure): + def run(self): + #lw.debug('&'*100) + lw.debug('using custom random (0)') + #rval = self.state.solver.BVV(0, 32) + #rval = self.state.solver.BVS("rand", 31, key=("api", "rand")) + #lw.debug(f'int size: {self.arch.sizeof["int"]}') + #lw.debug('&'*100) + return 0 # rval.zero_extend(self.arch.sizeof["int"] - 31) self.state.solver.BVV(0, 32) # rval.zero_extend(self.arch.sizeof["int"] - 31) diff --git a/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/readdir.py b/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/readdir.py index ac859a7fa..57f4bca22 100644 --- a/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/readdir.py +++ b/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/readdir.py @@ -1,19 +1,134 @@ import os import sys - - -import angr import logging -import os +import angr +from collections import namedtuple + -try: +try: lw = logging.getLogger("CustomSimProcedureLinux") lw.setLevel(os.environ["LOG_LEVEL"]) except Exception as e: print(e) +Dirent = namedtuple("dirent", ("d_ino", "d_off", "d_reclen", "d_type", "d_name")) + + class readdir(angr.SimProcedure): - # pylint: disable=arguments-differ - def run(self,dirp): - lw.debug(self.cc) - return 0 + struct = None + condition = None + + def run(self, dirp): # pylint: disable=arguments-differ + # TODO: make sure argument is actually a DIR struct + if self.state.arch.name != "AMD64": + lw.error("readdir SimProcedure is only implemented for AMD64") + return 0 + + if dirp.symbolic: + lw.debug("dirp is symbolic") + lw.debug(dirp) + self._build_amd64() + self.instrument() + malloc = angr.SIM_PROCEDURES["libc"]["malloc"] + pointer = self.inline_call(malloc, 19 + 256).ret_expr + self._store_amd64(pointer) + else: + lw.debug("dirp is concrete") + lw.debug(dirp) + folder_name = self.state.plugin_linux_fs.folder_address_to_name[self.state.solver.eval(dirp)] + lw.debug(folder_name) + + splitted_path = folder_name.split("/") + if splitted_path[-1] == "": + splitted_path.pop() + current_folder = self.state.plugin_linux_fs.linux_folders + current_folder_file = self.state.plugin_linux_fs.linux_files + current_file_per_folder = self.state.plugin_linux_fs.current_file_per_folder + pointer = 0 + used_part = "" + for part in splitted_path: + if part != "": + used_part = "/" + part + lw.debug("Part: " + used_part) + if used_part in current_folder.keys(): + lw.debug("Part in current_folder.keys()") + # lw.debug(current_file_per_folder) + # lw.debug(current_folder) + # lw.debug(current_folder_file) + current_folder = current_folder[used_part] + current_file_per_folder = current_file_per_folder[1][used_part] + current_folder_file = current_folder_file[used_part] + # files = current_folder_file[used_part]["files"] + # current_file_index = current_file_per_folder[0] + else: + lw.debug("Part not in current_folder.keys()") + current_folder[used_part] = {} + current_file_per_folder[1][used_part] = [0, {}] + current_folder_file[used_part] = {"files": []} + + # if part == splitted_path[-1]: + # current_file_index = current_file_per_folder[0] + # files = current_folder_file[part]["files"] + + # TODO should give dirent of folder too + lw.debug("current_folder") + # lw.debug(current_folder_file) + # lw.debug(current_file_per_folder) + files = current_folder_file["files"] + current_file_index = current_file_per_folder[0] + for file in files: + if not file[0]: + pointer = self.state.plugin_linux_fs.file_address["/".join(splitted_path) + file[1]] + lw.debug("Found file") + lw.debug("/".join(splitted_path) + file[1]) + file[0] = True + break + + # current_file_index = self.state.plugin_linux_fs.current_file_per_folder[folder_name] + lw.debug(current_file_index) + # if folder_name in self.state.plugin_linux_fs.linux_files.keys(): + # if current_file_index < len(self.state.plugin_linux_fs.linux_files[folder_name]): + # pointer = self.state.plugin_linux_fs.linux_files[folder_name][current_file_index] + # else: + # pointer = None + # else: # TODO + # pointer = None + + lw.debug(pointer) + + print(self.state.solver.eval(self.state.memory.load(pointer + 18, 1))) + + return pointer # self.state.solver.If(self.condition, pointer, 0) + + def instrument(self): + """ + Override this function to instrument the SimProcedure. + + The two useful variables you can override are self.struct, a named tuple of all the struct + fields, and self.condition, the condition for whether the function succeeds. + """ + pass + + def _build_amd64(self): + self.struct = Dirent( + self.state.solver.BVV(0, 64), # d_ino + self.state.solver.BVV(0, 64), # d_off + self.state.solver.BVS("d_reclen", 16, key=("api", "readdir", "d_reclen")), # d_reclen + self.state.solver.BVS("d_type", 8, key=("api", "readdir", "d_type")), # d_type + self.state.solver.BVS("d_name", 255 * 8, key=("api", "readdir", "d_name")), + ) # d_name + self.condition = self.state.solver.BoolS("readdir_cond") # TODO: variable key + + def _store_amd64(self, ptr): + def stores(offset, val): + return self.state.memory.store(ptr + offset, val, endness="Iend_BE") + + def storei(offset, val): + return self.state.memory.store(ptr + offset, val, endness="Iend_LE") + + storei(0, self.struct.d_ino) + storei(8, self.struct.d_off) + storei(16, self.struct.d_reclen) + storei(18, self.struct.d_type) + stores(19, self.struct.d_name) + stores(19 + 255, self.state.solver.BVV(0, 8)) \ No newline at end of file diff --git a/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/remove.py b/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/remove.py new file mode 100644 index 000000000..80f0955ea --- /dev/null +++ b/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/remove.py @@ -0,0 +1,16 @@ +import os +import sys + +import angr +import logging + +try: + lw = logging.getLogger("CustomSimProcedureLinux") + lw.setLevel(os.environ["LOG_LEVEL"]) +except Exception as e: + print(e) + +class remove(angr.SimProcedure): + def run(self, name): + #delet the file. + return 0 diff --git a/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/rewind.py b/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/rewind.py new file mode 100644 index 000000000..b7b2df1f2 --- /dev/null +++ b/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/rewind.py @@ -0,0 +1,20 @@ +import os +import sys +import logging +import angr + +try: + lw = logging.getLogger("CustomSimProcedureLinux") + lw.setLevel(os.environ["LOG_LEVEL"]) +except Exception as e: + print(e) + + +class rewind(angr.SimProcedure): + def run(self,fd): + # rewind fd to it original position + concrete_fd = self.state.posix.get_fd(fd) + if concrete_fd is None: + return -1 + concrete_fd.seek(0) + return 0 \ No newline at end of file diff --git a/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/stat.py b/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/stat.py index f0217875a..9a4ec9727 100644 --- a/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/stat.py +++ b/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/stat.py @@ -1,12 +1,18 @@ import os import sys - - +import logging import angr +try: + lw = logging.getLogger("CustomSimProcedureLinux") + lw.setLevel(os.environ["LOG_LEVEL"]) +except Exception as e: + print(e) + class stat(angr.SimProcedure): - def run(self, path, stat_buf): + def run(self, pathaddr, stat_buf): + lw.debug('$'*150) strlen = angr.SIM_PROCEDURES["libc"]["strlen"] p_strlen = self.inline_call(strlen, pathaddr) p_expr = self.state.memory.load( @@ -19,10 +25,13 @@ def run(self, path, stat_buf): # TODO: make arch-neutral # import pdb; pdb.set_trace() if self.state.arch.name == "AMD64": + lw.debug("AMD64") self._store_amd64(stat_buf, stat) else: + lw.debug("i868") self._store_i868(stat_buf, stat) self.state.posix.close(fd) + lw.debug('$'*150) return 0 def _store_i868(self, stat_buf, stat): @@ -38,7 +47,7 @@ def _store_i868(self, stat_buf, stat): store(0x18, stat.st_gid) store(0x1C, self.state.solver.BVV(0, 32)) store(0x20, stat.st_rdev) - store(0x24, stat.st_size) + store(0x24, self.state.solver.BVV(0,32)) # stat.st_size) store(0x28, stat.st_blksize) store(0x2C, stat.st_blocks) store(0x30, stat.st_atime) @@ -62,7 +71,7 @@ def _store_amd64(self, stat_buf, stat): store(0x20, stat.st_gid) store(0x24, self.state.solver.BVV(0, 32)) store(0x28, stat.st_rdev) - store(0x30, stat.st_size) + store(0x30, self.state.solver.BVV(0, 64)) #stat.st_size) # we can just make this 0 instead store(0x38, stat.st_blksize) store(0x40, stat.st_blocks) store(0x48, stat.st_atime) @@ -73,4 +82,4 @@ def _store_amd64(self, stat_buf, stat): store(0x70, stat.st_ctimensec) store(0x78, self.state.solver.BVV(0, 64)) store(0x80, self.state.solver.BVV(0, 64)) - store(0x88, self.state.solver.BVV(0, 64)) + store(0x88, self.state.solver.BVV(0, 64)) \ No newline at end of file diff --git a/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/strcat.py b/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/strcat.py new file mode 100644 index 000000000..95be8b7a3 --- /dev/null +++ b/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/strcat.py @@ -0,0 +1,124 @@ +import os +import sys +import logging +import angr + +try: + lw = logging.getLogger("CustomSimProcedureLinux") + lw.setLevel(os.environ["LOG_LEVEL"]) +except Exception as e: + print(e) + + +class strcat(angr.SimProcedure): + def run(self, string1, string2): + # strncat = angr.SIM_PROCEDURES["libc"]["strncat"] + # return self.inline_call(strncat, string1, string2, 0x100000000).ret_expr + if string1.symbolic or string2.symbolic: + lw.debug("string1 or string2 symbolic") + return self.state.solver.BVS( + "retval_{}".format(self.display_name), self.arch.bits + ) + + try: + first_str = self.state.mem[string1].string.concrete + lw.debug("string1 is concrete") + lw.debug(first_str) + except: + lw.debug("string1 not resolvable") + found = False + for i in range(0x100): + if self.state.solver.eval(self.state.memory.load(string1+i,1)) == 0x0: + if i == 0: + lw.debug("can't find length") + return self.state.solver.BVS("retval_{}".format(self.display_name), self.arch.bits) + lw.debug("found length") + lw.debug(i) + first_str = self.state.memory.load(string1,i) + lw.debug(first_str) + found = True + break + if not found: + lw.debug("can't find length") + return self.state.solver.BVS("retval_{}".format(self.display_name), self.arch.bits) + try: + second_str = self.state.mem[string2].string.concrete + lw.debug("string2 is concrete") + lw.debug(second_str) + except: + lw.debug("string2 not resolvable") + found = False + for i in range(0x100): + if self.state.solver.eval(self.state.memory.load(string2+i,1)) == 0x0: + if i == 0: + lw.debug("can't find length") + return self.state.solver.BVS("retval_{}".format(self.display_name), self.arch.bits) + lw.debug("found length") + lw.debug(i) + second_str = self.state.memory.load(string2,i) + lw.debug(first_str) + found = True + break + if not found: + lw.debug("can't find length") + return self.state.solver.BVS("retval_{}".format(self.display_name), self.arch.bits) + + + if string1.symbolic or string2.symbolic: + return self.state.solver.BVS( + "retval_{}".format(self.display_name), self.arch.bits + ) + first_str = self.state.mem[string1].string.concrete + second_str = self.state.mem[string2].string.concrete + + lw.debug(first_str) + lw.debug(second_str) + + if hasattr(first_str, "decode"): + try: + first_str = first_str.decode("utf-8") + except: + lw.debug("string1 not decodable") + #first_str = first_str.decode("utf-8",errors="ignore") + if hasattr(second_str, "decode"): + try: + second_str = second_str.decode("utf-8") + except: + lw.debug("string2 not decodable") + #second_str = second_str.decode("utf-8",errors="ignore") + pass + new_str = first_str + second_str + "\0" + + lw.debug(first_str) + lw.debug(second_str) + + lw.debug(len(first_str)) + lw.debug(len(second_str)) + + + + len_s = len(second_str) + src = self.state.memory.load(string2,len_s) # ,endness='Iend_BE' + #self.state.memory.store(string1+len(first_str),second_str) # ,endness='Iend_BE' + self.state.memory.store(string1,new_str) + + self.arguments = [first_str,second_str] + self.ret_expr = first_str + lw.debug("new_str") + sol = self.state.mem[string1].string.concrete + lw.debug(sol) + lw.debug(len(sol)) + return string1 + + new_str = first_str + second_str + "\0" + + len_s = len(second_str) + src = self.state.memory.load(string2,len_s,endness='Iend_BE') + self.state.memory.store(string1+len(first_str)-1,src,endness='Iend_BE') + + self.arguments = [first_str,second_str] + self.ret_expr = first_str + + lw.debug("new_str") + lw.debug(self.state.mem[string1].string.concrete) + return string1 diff --git a/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/strchr.py b/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/strchr.py new file mode 100644 index 000000000..4cc41e56e --- /dev/null +++ b/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/strchr.py @@ -0,0 +1,98 @@ +import os +import sys +import logging +import angr + +try: + lw = logging.getLogger("CustomSimProcedureLinux") + lw.setLevel(os.environ["LOG_LEVEL"]) +except Exception as e: + print(e) + + +class strrchr(angr.SimProcedure): + # return address of the last occurrence + def run(self, string, searchedChar): + lw.debug('+'*100) + + if string.symbolic or searchedChar.symbolic: + return self.state.solver.BVS( + "retval_{}".format(self.display_name), self.arch.bits + ) + + try: + first_str = self.state.mem[string].string.concrete + lw.debug("string is concrete") + lw.debug(first_str) + except: + lw.debug("string not resolvable") + found = False + for i in range(0x100): + if self.state.solver.eval(self.state.memory.load(string+i,1)) == 0x0: + if i == 0: + lw.debug("can't find length") + return self.state.solver.BVS("retval_{}".format(self.display_name), self.arch.bits) + lw.debug("found length") + lw.debug(i) + first_str = self.state.memory.load(string,i) + lw.debug(first_str) + found = True + break + if not found: + lw.debug("can't find length") + return self.state.solver.BVS("retval_{}".format(self.display_name), self.arch.bits) + + if hasattr(first_str, "decode"): + try: + first_str = first_str.decode("utf-8") + except: + first_str = first_str.decode("utf-8",errors="ignore") + + lw.debug(first_str) + searchedChar_conc = chr(self.state.solver.eval(searchedChar)) + lw.debug(searchedChar_conc) + offset = len(first_str) + for char in first_str[::-1]: + if char == searchedChar_conc: + lw.debug("found char") + lw.debug(offset) + lw.debug(f'returned string: {self.state.solver.eval(self.state.memory.load(string+offset-1, 8), cast_to=bytes)}') + lw.debug('+'*100) + return string+offset-1 + offset -= 1 + + + lw.debug('+'*100) + + return string+offset +# import logging +# import angr + +# lw = logging.getLogger("CustomSimProcedureLinux") + +# class strchr(angr.SimProcedure): +# # return address of the first occurrence +# def run(self, string, searchedChar): + +# if string.symbolic or searchedChar.symbolic: +# return self.state.solver.BVS( +# "retval_{}".format(self.display_name), self.arch.bits +# ) + +# first_str = self.state.mem[string].string.concrete + +# if hasattr(first_str, "decode"): +# try: +# first_str = first_str.decode("utf-8") +# except: +# first_str = first_str.decode("utf-8",errors="ignore") + +# searchedChar_conc = self.state.solver.eval(searchedChar) + +# offset = 0 +# for char in first_str: +# if char == searchedChar_conc: +# return offset +# offset += 1 + +# return string+offset \ No newline at end of file diff --git a/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/strcmp.py b/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/strcmp.py new file mode 100644 index 000000000..30c631c69 --- /dev/null +++ b/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/strcmp.py @@ -0,0 +1,81 @@ +import os +import sys +import logging +import angr + +try: + lw = logging.getLogger("CustomSimProcedureLinux") + lw.setLevel(os.environ["LOG_LEVEL"]) +except Exception as e: + print(e) + + +class strcmp(angr.SimProcedure): + def run(self, string1, string2): + + if string1.symbolic or string2.symbolic: + return self.state.solver.BVS("retval_{}".format(self.display_name), 32) + + try: + first_str = self.state.mem[string1].string.concrete + lw.debug("string1 is concrete") + lw.debug(first_str) + except: + lw.debug("string1 not resolvable") + found = False + for i in range(0x100): + if self.state.solver.eval(self.state.memory.load(string1+i,1)) == 0x0: + if i == 0: + lw.debug("can't find length") + return self.state.solver.BVS("retval_{}".format(self.display_name), self.arch.bits) + lw.debug("found length") + lw.debug(i) + first_str = self.state.memory.load(string1,i) + lw.debug(first_str) + found = True + break + if not found: + lw.debug("can't find length") + return self.state.solver.BVS("retval_{}".format(self.display_name), self.arch.bits) + try: + second_str = self.state.mem[string2].string.concrete + lw.debug("string2 is concrete") + lw.debug(second_str) + except: + lw.debug("string2 not resolvable") + found = False + for i in range(0x100): + if self.state.solver.eval(self.state.memory.load(string2+i,1)) == 0x0: + if i == 0: + lw.debug("can't find length") + return self.state.solver.BVS("retval_{}".format(self.display_name), self.arch.bits) + lw.debug("found length") + lw.debug(i) + second_str = self.state.memory.load(string2,i) + if not found: + lw.debug("can't find length") + return self.state.solver.BVS("retval_{}".format(self.display_name), self.arch.bits) + + try: + first_str = first_str.decode("utf-8") + except: + lw.debug("string1 not decodable") + #first_str = first_str.decode("utf-8",errors="ignore") + try: + second_str = second_str.decode("utf-8") + except: + lw.debug("string2 not decodable") + #second_str = second_str.decode("utf-8",errors="ignore") + lw.debug(repr(first_str)) + lw.debug(repr(second_str)) + + if first_str == second_str: + lw.debug("strings are equal") + return 0 + elif first_str > second_str: + lw.debug("string1 is greater than string2") + + return 1 + else: + lw.debug("string1 is less than string2") + return -1 \ No newline at end of file diff --git a/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/strcpy.py b/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/strcpy.py new file mode 100644 index 000000000..439192018 --- /dev/null +++ b/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/strcpy.py @@ -0,0 +1,56 @@ +import os +import sys +import logging +import angr +from angr.sim_options import MEMORY_CHUNK_INDIVIDUAL_READS +from angr.storage.memory_mixins.regioned_memory.abstract_address_descriptor import AbstractAddressDescriptor + +try: + lw = logging.getLogger("CustomSimProcedureLinux") + lw.setLevel(os.environ["LOG_LEVEL"]) +except Exception as e: + print(e) + + + +class strcpy(angr.SimProcedure): + def run(self, lpstring1, lpstring2): + if lpstring1.symbolic or lpstring2.symbolic: + lw.debug("lpstring1 or lpstring2 symbolic") + return lpstring1 + + try: + second_str = self.state.mem[lpstring2].string.concrete + lw.debug("second_str: " + str(second_str)) + except: + lw.debug("lpstring2 not resolvable") + found = False + for i in range(0x100): + if self.state.solver.eval(self.state.memory.load(lpstring2+i,1)) == 0x0: + if i == 0: + lw.debug("can't find length") + return self.state.solver.BVS("retval_{}".format(self.display_name), self.arch.bits) + lw.debug("found length") + lw.debug(i) + second_str = self.state.memory.load(lpstring2,i) + if not found: + lw.debug("can't find length") + return self.state.solver.BVS("retval_{}".format(self.display_name), self.arch.bits) + + try: + second_str = second_str.decode("utf-8") + except: + lw.debug("string2 not decodable") + second_str = second_str.decode("utf-8",errors="ignore") + + new_str = second_str + "\0" + #new_str = self.state.solver.BVV(new_str) + + self.state.memory.store(lpstring1, new_str) + + lw.debug("new_str") + sol = self.state.mem[lpstring1].string.concrete + lw.debug(sol) + lw.debug(len(sol)) + lw.debug("new_str: " + str(new_str)) + return lpstring1 \ No newline at end of file diff --git a/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/strcpyn.py b/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/strcpyn.py new file mode 100644 index 000000000..1a90c8171 --- /dev/null +++ b/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/strcpyn.py @@ -0,0 +1,36 @@ +import os +import sys +import logging +import angr + +try: + lw = logging.getLogger("CustomSimProcedureLinux") + lw.setLevel(os.environ["LOG_LEVEL"]) +except Exception as e: + print(e) + + + +class strcpyn(angr.SimProcedure): + def run(self, lpstring1, lpstring2, iMaxLength): + if lpstring1.symbolic or lpstring2.symbolic or iMaxLength.symbolic: + return lpstring1 + + nchar = self.state.solver.eval(iMaxLength) + + try: + second_str = self.state.mem[lpstring2].string.concrete + except: + lw.debug("lpstring2 not resolvable") + second_str = "" + + try: + second_str = second_str.decode("utf-8") + except: + lw.debug("string2 not decodable") + second_str = "" + + new_str = second_str[: nchar - 1] + "\0" + new_str = self.state.solver.BVV(new_str) + self.state.memory.store(lpstring1, new_str) + return lpstring1 diff --git a/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/strlen.py b/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/strlen.py new file mode 100644 index 000000000..cb0adccc5 --- /dev/null +++ b/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/strlen.py @@ -0,0 +1,34 @@ +import os +import sys +import logging +import angr + +try: + lw = logging.getLogger("CustomSimProcedureLinux") + lw.setLevel(os.environ["LOG_LEVEL"]) +except Exception as e: + print(e) + + + +class strlen(angr.SimProcedure): + def run(self, s): + if s.symbolic: + lw.debug("s is symbolic") + return self.state.solver.BVS("retval_{}".format(self.display_name), self.arch.bits) + + try: + string = self.state.mem[s].string.concrete + lw.debug("s is concrete") + lw.debug(string) + return len(string) + except: + lw.debug("s not resolvable") + for i in range(0x100): + if self.state.solver.eval(self.state.memory.load(s+i,1)) == 0x0: + lw.debug("found length") + lw.debug(i) + return i + lw.debug("can't find length") + return self.state.solver.BVS("retval_{}".format(self.display_name), self.arch.bits) + diff --git a/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/strncmp.py b/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/strncmp.py new file mode 100644 index 000000000..05a088a1b --- /dev/null +++ b/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/strncmp.py @@ -0,0 +1,280 @@ +import os +import sys +import angr + +import logging +from angr.sim_options import MEMORY_CHUNK_INDIVIDUAL_READS +from angr.storage.memory_mixins.regioned_memory.abstract_address_descriptor import AbstractAddressDescriptor + + +try: + lw = logging.getLogger("CustomSimProcedureLinux") + lw.setLevel(os.environ["LOG_LEVEL"]) +except Exception as e: + print(e) + + +class strncmp(angr.SimProcedure): + # pylint:disable=arguments-differ + def strlen(self, s, wchar=False, maxlen=None): + if wchar: + null_seq = self.state.solver.BVV(0, 16) + char_size = 2 + else: + null_seq = self.state.solver.BVV(0, 8) + char_size = 1 + + max_symbolic_bytes = self.state.libc.buf_symbolic_bytes + max_str_len = self.state.libc.max_str_len + if maxlen: + max_str_len = min(maxlen, max_str_len) + + chunk_size = None + if MEMORY_CHUNK_INDIVIDUAL_READS in self.state.options: + chunk_size = 1 + + if self.state.mode == "static": + + max_null_index = 0 + + # Make sure to convert s to ValueSet + addr_desc: AbstractAddressDescriptor = self.state.memory._normalize_address(s) + + # size_t + length = self.state.solver.ESI(self.arch.bits) + for s_aw in self.state.memory._concretize_address_descriptor(addr_desc, None): + + s_ptr = s_aw.to_valueset(self.state) + r, c, i = self.state.memory.find( + s, + null_seq, + max_str_len, + max_symbolic_bytes=max_symbolic_bytes, + chunk_size=chunk_size, + char_size=char_size, + ) + + max_null_index = max([max_null_index] + i) + + # Convert r to the same region as s + r_desc = self.state.memory._normalize_address(r) + r_aw_iter = self.state.memory._concretize_address_descriptor( + r_desc, None, target_region=next(iter(s_ptr._model_vsa.regions.keys())) + ) + + for r_aw in r_aw_iter: + r_ptr = r_aw.to_valueset(self.state) + length = length.union(r_ptr - s_ptr) + + return length, max_null_index + + else: + search_len = max_str_len + r, c, i = self.state.memory.find( + s, + null_seq, + search_len, + max_symbolic_bytes=max_symbolic_bytes, + chunk_size=chunk_size, + char_size=char_size, + ) + + # try doubling the search len and searching again + s_new = s + while c and all(con.is_false() for con in c): + s_new += search_len + search_len *= 2 + r, c, i = self.state.memory.find( + s_new, + null_seq, + search_len, + max_symbolic_bytes=max_symbolic_bytes, + chunk_size=chunk_size, + char_size=char_size, + ) + # stop searching after some reasonable limit + if search_len > 0x10000: + raise angr.SimMemoryLimitError("strlen hit limit of 0x10000") + + max_null_index = max(i) + self.state.add_constraints(*c) + result = r - s + if result.depth > 3: + rresult = self.state.solver.BVS("strlen", len(result), key=("api", "strlen")) + self.state.add_constraints(result == rresult) + result = rresult + return result, max_null_index + + def run( + self, a_addr, b_addr, limit, a_len=None, b_len=None, wchar=False, ignore_case=False + ): # pylint:disable=arguments-differ + char_size = 1 if not wchar else 2 + print("ccoucou") + a_strlen_ret_expr, a_strlen_max_null_index = self.strlen(a_addr,wchar=wchar) + b_strlen_ret_expr, b_strlen_max_null_index = self.strlen(b_addr,wchar=wchar) + print("swag") + a_len = a_strlen_ret_expr + b_len = b_strlen_ret_expr + + match_constraints = [] + variables = a_len.variables | b_len.variables | limit.variables + ret_expr = self.state.solver.Unconstrained("strncmp_ret", self.arch.bits, key=("api", "strncmp")) + + # determine the maximum number of bytes to compare + concrete_run = False + # if not self.state.solver.symbolic(a_len) and not self.state.solver.symbolic(b_len) and not self.state.solver.symbolic(limit): + if ( + self.state.solver.single_valued(a_len) + and self.state.solver.single_valued(b_len) + and self.state.solver.single_valued(limit) + ): + c_a_len = self.state.solver.eval(a_len) + c_b_len = self.state.solver.eval(b_len) + c_limit = self.state.solver.eval(limit) + + lw.debug("everything is concrete: a_len %d, b_len %d, limit %d", c_a_len, c_b_len, c_limit) + + if (c_a_len < c_limit or c_b_len < c_limit) and c_a_len != c_b_len: + lw.debug("lengths < limit and unmatched") + + concrete_run = True + maxlen = min(c_a_len, c_b_len, c_limit) + else: + if self.state.solver.single_valued(limit): + c_limit = self.state.solver.eval(limit) + maxlen = min(a_strlen_max_null_index, b_strlen_max_null_index, c_limit) + else: + maxlen = max(a_strlen_max_null_index, b_strlen_max_null_index) + + match_constraints.append( + self.state.solver.Or( + a_len == b_len, + self.state.solver.And(self.state.solver.UGE(a_len, limit), self.state.solver.UGE(b_len, limit)), + ) + ) + + if maxlen == 0: + # there is a corner case: if a or b are not both empty string, and limit is greater than 0, we should return + # non-equal. Basically we only return equal when limit is 0, or a_len == b_len == 0 + if self.state.solver.single_valued(limit) and self.state.solver.eval(limit) == 0: + # limit is 0 + lw.debug("returning equal for 0-limit") + return self.state.solver.BVV(0, self.arch.bits) + elif ( + self.state.solver.single_valued(a_len) + and self.state.solver.single_valued(b_len) + and self.state.solver.eval(a_len) == self.state.solver.eval(b_len) == 0 + ): + # two empty strings + lw.debug("returning equal for two empty strings") + return self.state.solver.BVV(0, self.arch.bits) + else: + # all other cases fall into this branch + lw.debug("returning non-equal for comparison of an empty string and a non-empty string") + if a_strlen_max_null_index == 0: + return self.state.solver.BVV(-1, self.arch.bits) + else: + return self.state.solver.BVV(1, self.arch.bits) + + # the bytes + max_byte_len = maxlen * char_size + a_bytes = self.state.memory.load(a_addr, max_byte_len, endness="Iend_BE") + b_bytes = self.state.memory.load(b_addr, max_byte_len, endness="Iend_BE") + + # TODO: deps + + # all possible return values in static mode + return_values = [] + print("swag") + print(max_byte_len) + print(concrete_run) + for i in range(max_byte_len): + lw.debug("Processing byte %d", i) + maxbit = (max_byte_len - i) * 8 + a_byte = a_bytes[maxbit - 1 : maxbit - 8] + b_byte = b_bytes[maxbit - 1 : maxbit - 8] + + if concrete_run and self.state.solver.single_valued(a_byte) and self.state.solver.single_valued(b_byte): + a_conc = self.state.solver.eval(a_byte) + b_conc = self.state.solver.eval(b_byte) + variables |= a_byte.variables + variables |= b_byte.variables + + if ignore_case: + # convert both to lowercase + if ord("a") <= a_conc <= ord("z"): + a_conc -= ord(" ") + if ord("a") <= b_conc <= ord("z"): + b_conc -= ord(" ") + + if a_conc != b_conc: + lw.debug("... found mis-matching concrete bytes 0x%x and 0x%x", a_conc, b_conc) + if a_conc < b_conc: + return self.state.solver.BVV(-1,self.arch.bits) + else: # Not enough data for store + return self.state.solver.BVV(1, self.arch.bits) + else: + + if self.state.mode == "static": + return_values.append(a_byte - b_byte) + + concrete_run = False + + if self.state.mode != "static": + if ignore_case: + byte_constraint = self.state.solver.Or( + self.state.solver.Or( + a_byte == b_byte, + self.state.solver.And( + ord("A") <= a_byte, + a_byte <= ord("Z"), + ord("a") <= b_byte, + b_byte <= ord("z"), + b_byte - ord(" ") == a_byte, + ), + self.state.solver.And( + ord("A") <= b_byte, + b_byte <= ord("Z"), + ord("a") <= a_byte, + a_byte <= ord("z"), + a_byte - ord(" ") == b_byte, + ), + ), + self.state.solver.ULT(a_len, i), + self.state.solver.ULT(limit, i), + ) + else: + byte_constraint = self.state.solver.Or( + a_byte == b_byte, self.state.solver.ULT(a_len, i), self.state.solver.ULT(limit, i) + ) + match_constraints.append(byte_constraint) + + if concrete_run: + lw.debug("concrete run made it to the end!") + return self.state.solver.BVV(0, self.arch.bits) + + if self.state.mode == "static": + ret_expr = self.state.solver.ESI(8) + for expr in return_values: + ret_expr = ret_expr.union(expr) + + ret_expr = ret_expr.sign_extend(24) + + else: + # make the constraints + + lw.debug("returning symbolic") + match_constraint = self.state.solver.And(*match_constraints) + nomatch_constraint = self.state.solver.Not(match_constraint) + + # lw.debug("match constraints: %s", match_constraint) + # lw.debug("nomatch constraints: %s", nomatch_constraint) + + match_case = self.state.solver.And(limit != 0, match_constraint, ret_expr == 0) + nomatch_case = self.state.solver.And(limit != 0, nomatch_constraint, ret_expr == 1) + l0_case = self.state.solver.And(limit == 0, ret_expr == 0) + empty_case = self.state.solver.And(a_strlen_ret_expr == 0, b_strlen_ret_expr == 0, ret_expr == 0) + + self.state.add_constraints(self.state.solver.Or(match_case, nomatch_case, l0_case, empty_case)) + + return ret_expr \ No newline at end of file diff --git a/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/strrchr.py b/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/strrchr.py new file mode 100644 index 000000000..9cc359a6e --- /dev/null +++ b/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/strrchr.py @@ -0,0 +1,61 @@ +import os +import sys +import logging +import angr + +try: + lw = logging.getLogger("CustomSimProcedureLinux") + lw.setLevel(os.environ["LOG_LEVEL"]) +except Exception as e: + print(e) + + +class strrchr(angr.SimProcedure): + # return address of the last occurrence + def run(self, string, searchedChar): + + if string.symbolic or searchedChar.symbolic: + return self.state.solver.BVS( + "retval_{}".format(self.display_name), self.arch.bits + ) + + try: + first_str = self.state.mem[string].string.concrete + lw.debug("string is concrete") + lw.debug(first_str) + except: + lw.debug("string not resolvable") + found = False + for i in range(0x100): + if self.state.solver.eval(self.state.memory.load(string+i,1)) == 0x0: + if i == 0: + lw.debug("can't find length") + return self.state.solver.BVS("retval_{}".format(self.display_name), self.arch.bits) + lw.debug("found length") + lw.debug(i) + first_str = self.state.memory.load(string,i) + lw.debug(first_str) + found = True + break + if not found: + lw.debug("can't find length") + return self.state.solver.BVS("retval_{}".format(self.display_name), self.arch.bits) + + if hasattr(first_str, "decode"): + try: + first_str = first_str.decode("utf-8") + except: + first_str = first_str.decode("utf-8",errors="ignore") + + lw.debug(first_str) + searchedChar_conc = chr(self.state.solver.eval(searchedChar)) + lw.debug(searchedChar_conc) + offset = len(first_str) + for char in first_str[::-1]: + if char == searchedChar_conc: + lw.debug("found char") + lw.debug(offset) + return string+offset-1 + offset -= 1 + + return string+offset diff --git a/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/strstr.py b/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/strstr.py new file mode 100644 index 000000000..c14635ca0 --- /dev/null +++ b/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/strstr.py @@ -0,0 +1,340 @@ +import os +import sys +import logging +import angr +from angr.sim_options import MEMORY_CHUNK_INDIVIDUAL_READS +from angr.storage.memory_mixins.regioned_memory.abstract_address_descriptor import AbstractAddressDescriptor + +try: + lw = logging.getLogger("CustomSimProcedureLinux") + lw.setLevel(os.environ["LOG_LEVEL"]) +except Exception as e: + print(e) + + +# class strstr(angr.SimProcedure): +# def strlen(self, s, wchar=False, maxlen=None): +# if wchar: +# null_seq = self.state.solver.BVV(0, 16) +# char_size = 2 +# else: +# null_seq = self.state.solver.BVV(0, 8) +# char_size = 1 + +# max_symbolic_bytes = self.state.libc.buf_symbolic_bytes +# max_str_len = self.state.libc.max_str_len +# if maxlen: +# max_str_len = min(maxlen, max_str_len) + +# chunk_size = None +# if MEMORY_CHUNK_INDIVIDUAL_READS in self.state.options: +# chunk_size = 1 + +# if self.state.mode == "static": + +# max_null_index = 0 + +# # Make sure to convert s to ValueSet +# addr_desc: AbstractAddressDescriptor = self.state.memory._normalize_address(s) + +# # size_t +# length = self.state.solver.ESI(self.arch.bits) +# for s_aw in self.state.memory._concretize_address_descriptor(addr_desc, None): + +# s_ptr = s_aw.to_valueset(self.state) +# r, c, i = self.state.memory.find( +# s, +# null_seq, +# max_str_len, +# max_symbolic_bytes=max_symbolic_bytes, +# chunk_size=chunk_size, +# char_size=char_size, +# ) + +# max_null_index = max([max_null_index] + i) + +# # Convert r to the same region as s +# r_desc = self.state.memory._normalize_address(r) +# r_aw_iter = self.state.memory._concretize_address_descriptor( +# r_desc, None, target_region=next(iter(s_ptr._model_vsa.regions.keys())) +# ) + +# for r_aw in r_aw_iter: +# r_ptr = r_aw.to_valueset(self.state) +# length = length.union(r_ptr - s_ptr) + +# return length, max_null_index + +# else: +# search_len = max_str_len +# r, c, i = self.state.memory.find( +# s, +# null_seq, +# search_len, +# max_symbolic_bytes=max_symbolic_bytes, +# chunk_size=chunk_size, +# char_size=char_size, +# ) + +# # try doubling the search len and searching again +# s_new = s +# while c and all(con.is_false() for con in c): +# s_new += search_len +# search_len *= 2 +# r, c, i = self.state.memory.find( +# s_new, +# null_seq, +# search_len, +# max_symbolic_bytes=max_symbolic_bytes, +# chunk_size=chunk_size, +# char_size=char_size, +# ) +# # stop searching after some reasonable limit +# if search_len > 0x10000: +# raise angr.SimMemoryLimitError("strlen hit limit of 0x10000") + +# max_null_index = max(i) +# self.state.add_constraints(*c) +# result = r - s +# if result.depth > 3: +# rresult = self.state.solver.BVS("strlen", len(result), key=("api", "strlen")) +# self.state.add_constraints(result == rresult) +# result = rresult +# return result, max_null_index + +# def run(self, haystack, needle): +# # Get the haystack and needle strings from the memory +# if haystack.symbolic or needle.symbolic: +# return haystack +# # haystack_strlen = self.inline_call(strlen, haystack) +# # needle_strlen = self.inline_call(strlen, needle) +# # print(haystack_max_null_index) +# # print(needle_max_null_index) +# _, haystack_max_null_index = self.strlen(haystack) +# print(haystack_max_null_index) +# haystack_str = self.state.memory.load(haystack,size=haystack_max_null_index) +# print(haystack_str) + +# _, needle_max_null_index = self.strlen(needle) +# needle_str = self.state.memory.load(needle,size=needle_max_null_index) +# print(needle_max_null_index) +# print(needle_str) +# needle_str = self.state.solver.eval(needle_str,cast_to=bytes) +# print(needle_str) + +# if haystack_str.symbolic: +# print(hex(self.state.solver.eval(self.state.memory.load(haystack,size=haystack_max_null_index)))) +# for i in range(needle_max_null_index): +# print(i) +# print(hex(needle_str[i])) +# self.state.memory.store(haystack+i,needle_str[i],size=1) +# self.state.memory.store(haystack+haystack_max_null_index,0,size=1) +# print(haystack) +# print(haystack_str) +# print(hex(self.state.solver.eval(self.state.memory.load(haystack,size=haystack_max_null_index)))) +# return haystack +# haystack_str = self.state.solver.eval(haystack_str,cast_to=bytes) + +# # Find the needle in the haystack +# needle_index = haystack_str.find(needle_str) +# print(needle_index) +# if needle_index == -1: +# return 0 +# else: +# print(haystack + needle_index) +# return haystack + needle_index + +# # def run(self, mainstring, substring): + + # if mainstring.symbolic or substring.symbolic: + # return mainstring + + + # #main_str = self.state.mem[mainstring].string.concrete + # sub_str = self.state.mem[substring].string.concrete + # chunk_size = None + # if MEMORY_CHUNK_INDIVIDUAL_READS in self.state.options: + # chunk_size = 1 + + # r, c, i = self.state.memory.find(mainstring, sub_str, 16, max_symbolic_bytes=self.state.libc.max_symbolic_strstr, default=0, chunk_size=chunk_size) + # self.state.add_constraints(*c) + # lw.debug("... returning %s", r) + # return r + + + # if hasattr(main_str, "decode"): + # try: + # main_str = main_str.decode("utf-8") + # except: + # main_str = main_str.decode("utf-8",errors="ignore") + # if hasattr(sub_str, "decode"): + # try: + # sub_str = sub_str.decode("utf-8") + # except: + # sub_str = sub_str.decode("utf-8",errors="ignore") + + # new_str = main_str + sub_str + "\0" + + # len_s = len(sub_str) + # src = self.state.memory.load(substring,len_s,endness='Iend_BE') + # self.state.memory.store(mainstring+len(main_str),src,endness='Iend_BE') + + # self.arguments = [main_str,sub_str] + # self.ret_expr = main_str + # return mainstring + +class strstr(angr.SimProcedure): + def strlen(self, s, wchar=False, maxlen=None): + if wchar: + null_seq = self.state.solver.BVV(0, 16) + char_size = 2 + else: + null_seq = self.state.solver.BVV(0, 8) + char_size = 1 + + max_symbolic_bytes = self.state.libc.buf_symbolic_bytes + max_str_len = self.state.libc.max_str_len + if maxlen: + max_str_len = min(maxlen, max_str_len) + + chunk_size = None + if MEMORY_CHUNK_INDIVIDUAL_READS in self.state.options: + chunk_size = 1 + + if self.state.mode == "static": + + max_null_index = 0 + + # Make sure to convert s to ValueSet + addr_desc: AbstractAddressDescriptor = self.state.memory._normalize_address(s) + + # size_t + length = self.state.solver.ESI(self.arch.bits) + for s_aw in self.state.memory._concretize_address_descriptor(addr_desc, None): + + s_ptr = s_aw.to_valueset(self.state) + r, c, i = self.state.memory.find( + s, + null_seq, + max_str_len, + max_symbolic_bytes=max_symbolic_bytes, + chunk_size=chunk_size, + char_size=char_size, + ) + + max_null_index = max([max_null_index] + i) + + # Convert r to the same region as s + r_desc = self.state.memory._normalize_address(r) + r_aw_iter = self.state.memory._concretize_address_descriptor( + r_desc, None, target_region=next(iter(s_ptr._model_vsa.regions.keys())) + ) + + for r_aw in r_aw_iter: + r_ptr = r_aw.to_valueset(self.state) + length = length.union(r_ptr - s_ptr) + + return length, max_null_index + + else: + search_len = max_str_len + r, c, i = self.state.memory.find( + s, + null_seq, + search_len, + max_symbolic_bytes=max_symbolic_bytes, + chunk_size=chunk_size, + char_size=char_size, + ) + + # try doubling the search len and searching again + s_new = s + while c and all(con.is_false() for con in c): + s_new += search_len + search_len *= 2 + r, c, i = self.state.memory.find( + s_new, + null_seq, + search_len, + max_symbolic_bytes=max_symbolic_bytes, + chunk_size=chunk_size, + char_size=char_size, + ) + # stop searching after some reasonable limit + if search_len > 0x10000: + raise angr.SimMemoryLimitError("strlen hit limit of 0x10000") + + max_null_index = max(i) + self.state.add_constraints(*c) + result = r - s + if result.depth > 3: + rresult = self.state.solver.BVS("strlen", len(result), key=("api", "strlen")) + self.state.add_constraints(result == rresult) + result = rresult + return result, max_null_index + + + def run(self, haystack_addr, needle_addr,haystack_strlen=None, needle_strlen=None): + # strlen = angr.SIM_PROCEDURES['libc']['strlen'] + strncmp = angr.SIM_PROCEDURES['libc']['strncmp'] + # haystack_strlen = self.inline_call(strlen, haystack_addr) if haystack_strlen is None else haystack_strlen + # needle_strlen = self.inline_call(strlen, needle_addr) if needle_strlen is None else needle_strlen + + # naive approach + # haystack_maxlen = haystack_max_null_index + # needle_maxlen = needle_max_null_index + _, haystack_max_null_index = self.strlen(haystack_addr) + needle_strlen_ret_expr, needle_max_null_index = self.strlen(needle_addr) + lw.debug("strstr: " + str(self.arguments)) + lw.debug("strstr with size %d haystack and size %d needle...", haystack_max_null_index, needle_max_null_index) + + if needle_max_null_index == 0: + lw.debug("... zero-length needle.") + return haystack_addr + elif haystack_max_null_index == 0: + lw.debug("... zero-length haystack.") + return self.state.solver.BVV(0, self.state.arch.bits) + + if self.state.solver.symbolic(needle_strlen_ret_expr): + cases = [ [ needle_strlen_ret_expr == 0, haystack_addr ] ] + exclusions = [ needle_strlen_ret_expr != 0 ] + remaining_symbolic = self.state.libc.max_symbolic_strstr + for i in range(haystack_max_null_index): + lw.debug("... case %d (%d symbolic checks remaining)", i, remaining_symbolic) + + # big hack! + cmp_res = self.inline_call(strncmp, haystack_addr + i, needle_addr, needle_strlen_ret_expr, a_len=haystack_strlen, b_len=needle_strlen) + c = self.state.solver.And(*([ self.state.solver.UGE(haystack_strlen.ret_expr, needle_strlen_ret_expr), cmp_res.ret_expr == 0 ] + exclusions)) + exclusions.append(cmp_res.ret_expr != 0) + + if self.state.solver.symbolic(c): + remaining_symbolic -= 1 + + #print "CASE:", c + cases.append([ c, haystack_addr + i ]) + haystack_strlen.ret_expr = haystack_strlen.ret_expr - 1 + + if remaining_symbolic == 0: + lw.debug("... exhausted remaining symbolic checks.") + break + + cases.append([ self.state.solver.And(*exclusions), self.state.solver.BVV(0, self.state.arch.bits) ]) + lw.debug("... created %d cases", len(cases)) + r = self.state.solver.ite_cases(cases, 0) + c = [ self.state.solver.Or(*[c for c,_ in cases]) ] + else: + needle_length = self.state.solver.eval(needle_strlen_ret_expr) + needle_str = self.state.memory.load(needle_addr, needle_length) + lw.debug("... concrete needle of length %d.", needle_length) + lw.debug("... needle: %s", needle_str) + chunk_size = None + if MEMORY_CHUNK_INDIVIDUAL_READS in self.state.options: + chunk_size = 1 + + r, c, i = self.state.memory.find(haystack_addr, needle_str, haystack_max_null_index, max_symbolic_bytes=self.state.libc.max_symbolic_strstr, default=0, chunk_size=chunk_size) + + self.state.add_constraints(*c) + lw.debug("... returning %s", r+needle_length) + return r+needle_length + + \ No newline at end of file diff --git a/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/strtok.py b/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/strtok.py new file mode 100644 index 000000000..bff8eb8f8 --- /dev/null +++ b/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/strtok.py @@ -0,0 +1,51 @@ +import os +import sys +import angr +import logging +try: + lw = logging.getLogger("CustomSimProcedureLinux") + lw.setLevel(os.environ["LOG_LEVEL"]) +except Exception as e: + print(e) + +class strtok(angr.SimProcedure): + """_summary_ + The strtok() method splits str[] according to given delimiters and returns the next token. + It needs to be called in a loop to get all tokens. It returns NULL when there are no more tokens. + Args: + angr (_type_): _description_ + """ + def run(self, str_ptr, delim_ptr): + + str_object = self.state.mem[str_ptr].string.concrete + if not str_object: + lw.debug("str_ptr null, used saved str_ptr") + str_ptr = self.state.globals.get("strtok_last", None) + if str_ptr is None: + lw.debug("No saved str_ptr") + return self.state.solver.BVS("retval_{}".format(self.display_name), self.arch.bits) + str_object = self.state.mem[str_ptr].string.concrete + + delim_object = self.state.mem[delim_ptr].string.concrete + + str = str_object.decode() + delim = delim_object.decode() + + token = '' + for i in range(0, len(str)): + if str[i] in delim : + break + token += str[i] + + if not token: + lw.debug("token not found") + return self.state.solver.BVS("retval_{}".format(self.display_name), self.arch.bits) + + + self.state.memory.store(str_ptr, self.state.solver.BVV(token.encode())) + self.state.memory.store(str_ptr + len(token), self.state.solver.BVV(0, 8)) + + self.state.globals["strtok_last"] = str_ptr + len(token) + 1 + lw.debug(repr(self.state.mem[str_ptr].string.concrete)) + + return str_ptr \ No newline at end of file diff --git a/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/strtok_r.py b/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/strtok_r.py new file mode 100644 index 000000000..3f6f2cb55 --- /dev/null +++ b/sema_toolchain/sema_scdg/application/procedures/linux/custom_package/strtok_r.py @@ -0,0 +1,159 @@ +import os +import sys +import angr +import logging + +try: + lw = logging.getLogger("CustomSimProcedureLinux") + lw.setLevel(os.environ["LOG_LEVEL"]) +except Exception as e: + print(e) + + +class strtok_r(angr.SimProcedure): + """_summary_ + The strtok_r() method splits str[] according to given delimiters and returns the next token. + It needs to be called in a loop to get all tokens. It returns NULL when there are no more tokens. + strtok_r() does the same task of parsing a string into a sequence of tokens. + strtok_r() is a reentrant version of strtok(), hence it is thread safe. + Args: + angr (_type_): _description_ + """ + def run(self, str_ptr, delim_ptr): + lw.debug('@'*100) + lw.debug('using strtok_r') + strtok_r_arr = self.state.globals.get('strtok', self.state.solver.BVS("retval_{}".format(self.display_name), self.arch.bits)) + + # def run(self, str_ptr, delim_ptr, saveptr): + # strtok_r = self.state.globals.get('strtok_r', self.state.solver.BVS("retval_{}".format(self.display_name), self.arch.bits)) + + # Get the memory objects representing the strings + # str_object = self.state.memory.load(str_ptr) + # delim_object = self.state.memory.load(delim_ptr) + + # Get the actual strings from the memory objects + str_data = self.state.mem[str_ptr].string.concrete # self.state.solver.eval(str_object, cast_to=bytes).decode() + delim_data = self.state.mem[delim_ptr].string.concrete # self.state.solver.eval(delim_object, cast_to=bytes).decode() + + if len(strtok_r_arr) == 0: + + #if len(strtok_r) == 0: + self.state.globals["strtok_r"] = [[False, elem] for elem in str_data.split(delim_data)] + else: + for elem in self.state.globals["strtok_r"]: + if not elem[0]: + lw.debug(elem) + elem[0] = True + dest_ptr = str_ptr + token_data = elem[1].decode("utf-8") + "\x00" + token_size = len(token_data) + + lw.debug(f"token_data: {token_data}") + lw.debug(f"token_size: {token_size}") + + self.state.memory.store(dest_ptr, token_data) + lw.debug('@'*100) + return dest_ptr + + self.state.globals["strtok_r"] = [] + lw.debug('@'*100) + return 0x0 + +# class strtok(angr.SimProcedure): +# """_summary_ +# The strtok() method splits str[] according to given delimiters and returns the next token. +# It needs to be called in a loop to get all tokens. It returns NULL when there are no more tokens. +# Args: +# angr (_type_): _description_ +# """ +# def run(self, str_ptr, delim_ptr): +# # Get the memory objects representing the strings +# try: +# str_object = self.state.mem[str_ptr].string.concrete +# except: +# found = False +# for i in range(0x100): +# if self.state.solver.eval(self.state.memory.load(str_ptr+i,1)) == 0x0: +# if i == 0: +# lw.debug("can't find length") +# return self.state.solver.BVS("retval_{}".format(self.display_name), self.arch.bits) +# lw.debug("found length") +# lw.debug(i) +# str_object = self.state.memory.load(str_ptr,i) +# lw.debug(str_object) +# found = True +# break +# if not found: +# return self.state.solver.BVS("retval_{}".format(self.display_name), self.arch.bits) + +# delim_object = self.state.mem[delim_ptr].string.concrete # self.state.memory.load(delim_ptr) + +# # Get the actual strings from the memory objects +# # str_data = self.state.solver.eval(str_object, cast_to=bytes).decode() +# # delim_data = self.state.solver.eval(delim_object, cast_to=bytes).decode() + +# str_data = str_object.decode() +# delim_data = delim_object.decode() + + +# # Find the starting position of the next token +# start_pos = 0 + +# # Find the end position of the token +# end_pos = start_pos +# while end_pos < len(str_data) and str_data[end_pos] not in delim_data: +# end_pos += 1 + +# # Create the token +# token_data = str_data[start_pos:end_pos] +# lw.debug("token_data") +# lw.debug(token_data) +# token_size = len(token_data) + 1 # Include the null terminator + +# # Update the strtok internal state (store the start_pos for the next call) +# # strtok_state = self.state.solver.BVS('strtok_state', self.arch.bits) +# # self.state.add_constraints(strtok_state == end_pos) + +# # Store the token in the destination buffer (simulating strtok behavior) +# dest_ptr = str_ptr +# self.state.memory.store(dest_ptr, self.state.solver.BVV(token_data.encode())) +# self.state.memory.store(dest_ptr + token_size, self.state.solver.BVV(0, 8)) # Null terminator + +# return dest_ptr +""" + lw.debug("token_data") + lw.debug(token_data) + lw.debug("token_size") + lw.debug(token_size) + self.state.memory.store(dest_ptr, token_data) + #self.state.memory.store(dest_ptr + token_size, self.state.solver.BVV(0, 8)) # Null terminator + return dest_ptr + #break + return 0x0 + + # # Find the starting position of the next token + # start_pos = self.state.solver.BVS('strtok_start_pos', self.arch.bits) + # self.state.add_constraints(start_pos >= 0) + # if self.state.solver.eval(start_pos == 0): + # start_pos = self.state.solver.BVV(0, self.arch.bits) + + # # Find the end position of the token + # end_pos = start_pos + # while end_pos < len(str_data) and str_data[end_pos] not in delim_data: + # end_pos += 1 + + # # Create the token + # token_data = str_data[start_pos:end_pos] + # token_size = len(token_data) + 1 # Include the null terminator + + # # Update the strtok internal state (store the start_pos for the next call) + # strtok_state = self.state.solver.BVS('strtok_state', self.arch.bits) + # self.state.add_constraints(strtok_state == end_pos) + + # # Store the token in the destination buffer (simulating strtok behavior) + # dest_ptr = str_ptr + # self.state.memory.store(dest_ptr, self.state.solver.BVV(token_data.encode())) + # self.state.memory.store(dest_ptr + token_size, self.state.solver.BVV(0, 8)) # Null terminator + + # return dest_ptr +""" \ No newline at end of file diff --git a/sema_toolchain/sema_scdg/application/procedures/windows/custom_hook/WannacryHook2.py b/sema_toolchain/sema_scdg/application/procedures/windows/custom_hook/WannacryHook2.py new file mode 100644 index 000000000..8aadcbe87 --- /dev/null +++ b/sema_toolchain/sema_scdg/application/procedures/windows/custom_hook/WannacryHook2.py @@ -0,0 +1,23 @@ +import os +import sys + + +import angr +import claripy + +class WannacryHook2(angr.SimProcedure): + NO_RET = True + def __init__(self, plength=0, project=None, cc=None, prototype=None, symbolic_return=None, returns=None, is_syscall=False, is_stub=False, num_args=None, display_name=None, library_name=None, is_function=None, **kwargs): + super().__init__(project, cc, prototype, symbolic_return, returns, is_syscall, is_stub, num_args, display_name, library_name, is_function, **kwargs) + self.plength=plength + + def run(self): + print("it's working2") + #FUN_004012fd + + jumpkind = 'Ijk_NoHook' if self.plength == 0 else 'Ijk_Boring' + self.successors.add_successor(self.state, self.state.addr+self.plength, self.state.solver.true, jumpkind) + + ret_val = self.state.solver.BVS("retval_{}".format(self.display_name), self.arch.bits) + self.state.solver.add(ret_val > 0) + return ret_val diff --git a/sema_toolchain/sema_scdg/application/procedures/windows/custom_hook/WannacryHook3.py b/sema_toolchain/sema_scdg/application/procedures/windows/custom_hook/WannacryHook3.py new file mode 100644 index 000000000..6daa0b478 --- /dev/null +++ b/sema_toolchain/sema_scdg/application/procedures/windows/custom_hook/WannacryHook3.py @@ -0,0 +1,22 @@ +import os +import sys + + +import angr +import claripy + +class WannacryHook3(angr.SimProcedure): + NO_RET = True + def __init__(self, plength=0, project=None, cc=None, prototype=None, symbolic_return=None, returns=None, is_syscall=False, is_stub=False, num_args=None, display_name=None, library_name=None, is_function=None, **kwargs): + super().__init__(project, cc, prototype, symbolic_return, returns, is_syscall, is_stub, num_args, display_name, library_name, is_function, **kwargs) + self.plength=plength + + def run(self, var): + print("it's working3") + #FUN_0040137 + jumpkind = 'Ijk_NoHook' if self.plength == 0 else 'Ijk_Boring' + self.successors.add_successor(self.state, self.state.addr+self.plength, self.state.solver.true, jumpkind) + + ret_val = self.state.solver.BVS("retval_{}".format(self.display_name), self.arch.bits) + self.state.solver.add(ret_val > 0) + return ret_val diff --git a/sema_toolchain/sema_scdg/application/procedures/windows/custom_hook/WannacryHook4.py b/sema_toolchain/sema_scdg/application/procedures/windows/custom_hook/WannacryHook4.py new file mode 100644 index 000000000..8032e6479 --- /dev/null +++ b/sema_toolchain/sema_scdg/application/procedures/windows/custom_hook/WannacryHook4.py @@ -0,0 +1,67 @@ +import os +import sys + + +import angr +import claripy + +class WannacryHook4(angr.SimProcedure): + NO_RET = True + def __init__(self, plength=0, project=None, cc=None, prototype=None, symbolic_return=None, returns=None, is_syscall=False, is_stub=False, num_args=None, display_name=None, library_name=None, is_function=None, **kwargs): + super().__init__(project, cc, prototype, symbolic_return, returns, is_syscall, is_stub, num_args, display_name, library_name, is_function, **kwargs) + self.plength=plength + + def run(self, param_1, param_2): + #FUN_0040752 + + #code generate by IA (chatgpt) with small modification on the inline_call + + arch_bits = self.state.arch.bits # typically 32 + # Set param_1[1] = 0xffffffff + self.state.memory.store(param_1 + 4, self.state.solver.BVV(0xffffffff, arch_bits)) + # Set param_1[0x4d] = 0xffffffff + self.state.memory.store(param_1 + (0x4d * 4), self.state.solver.BVV(0xffffffff, arch_bits)) + # Set *param_1 = 0 + self.state.memory.store(param_1, self.state.solver.BVV(0, arch_bits)) + # Set param_1[0x4e] = 0 + self.state.memory.store(param_1 + (0x4e * 4), self.state.solver.BVV(0, arch_bits)) + # Set param_1[0x4f] = 0 + self.state.memory.store(param_1 + (0x4f * 4), self.state.solver.BVV(0, arch_bits)) + + # If param_2 is not NULL + if not self.state.solver.is_true(param_2 == 0): + # Call strlen on param_2 to determine its length. + strlen_sp = self.inline_call(angr.SIM_PROCEDURES['libc']['strlen'], param_2) + sVar1 = strlen_sp.ret_expr + + # Allocate sVar1 + 1 bytes using operator_new. + new_size = sVar1 + 1 + op_new_sp = self.inline_call(NewInt, new_size) + _Dest = op_new_sp.ret_expr + + # Store the allocated pointer in param_1[0x4e] + self.state.memory.store(param_1 + (0x4e * 4), _Dest) + + # Copy the string from param_2 to _Dest. + self.inline_call(angr.SIM_PROCEDURES['libc']['strcpy'], _Dest, param_2) + print(param_1) + + jumpkind = 'Ijk_NoHook' if self.plength == 0 else 'Ijk_Boring' + self.successors.add_successor(self.state, self.state.addr+self.plength, self.state.solver.true, jumpkind) + + return param_1 + +class NewInt(angr.SimProcedure): + + def run( + self, + uint, + ): + if uint.symbolic: + return self.state.heap._malloc(0x42) + malloced = self.state.heap._malloc(uint) + for i in range(self.state.solver.eval(uint)): + self.state.memory.store(malloced + i, 0, size=1) + print(malloced) + return malloced + diff --git a/sema_toolchain/sema_scdg/application/procedures/windows/custom_hook/WannacryHook_Str.py b/sema_toolchain/sema_scdg/application/procedures/windows/custom_hook/WannacryHook_Str.py new file mode 100644 index 000000000..d850c8c99 --- /dev/null +++ b/sema_toolchain/sema_scdg/application/procedures/windows/custom_hook/WannacryHook_Str.py @@ -0,0 +1,28 @@ +import logging +import os +import sys + + +import angr +import claripy + +try: + lw = logging.getLogger("CustomSimProcedureWindows") + lw.setLevel(os.environ.get("LOG_LEVEL", "INFO")) +except Exception as e: + print(e) + +class WannacryHook_Str(angr.SimProcedure): + NO_RET = True + def __init__(self, plength=0, project=None, cc=None, prototype=None, symbolic_return=None, returns=None, is_syscall=False, is_stub=False, num_args=None, display_name=None, library_name=None, is_function=None, **kwargs): + super().__init__(project, cc, prototype, symbolic_return, returns, is_syscall, is_stub, num_args, display_name, library_name, is_function, **kwargs) + self.plength=plength + + def run(self, var): + #FUN_00401225 + + jumpkind = 'Ijk_NoHook' if self.plength == 0 else 'Ijk_Boring' + self.successors.add_successor(self.state, self.state.addr+self.plength, self.state.solver.true, jumpkind) + + lw.debug(var) + self.state.memory.store(var,"Wannacry_Random_String"+'\x00') diff --git a/sema_toolchain/sema_scdg/application/procedures/windows/custom_hook/WannacryHook_add_to_file_list.py b/sema_toolchain/sema_scdg/application/procedures/windows/custom_hook/WannacryHook_add_to_file_list.py new file mode 100644 index 000000000..295641a7a --- /dev/null +++ b/sema_toolchain/sema_scdg/application/procedures/windows/custom_hook/WannacryHook_add_to_file_list.py @@ -0,0 +1,24 @@ +import os +import sys + + +import angr +import claripy + +class WannacryHook_add_to_file_list(angr.SimProcedure): + NO_RET = True + def __init__(self, plength=0, project=None, cc=None, prototype=None, symbolic_return=None, returns=None, is_syscall=False, is_stub=False, num_args=None, display_name=None, library_name=None, is_function=None, **kwargs): + super().__init__(project, cc, prototype, symbolic_return, returns, is_syscall, is_stub, num_args, display_name, library_name, is_function, **kwargs) + self.plength=plength + + def run(self,arg1,arg2,arg3,arg4): + print("add_to_file_list skip") + #skip because corrupted ret addr + #0x10002625 + jumpkind = 'Ijk_NoHook' if self.plength == 0 else 'Ijk_Boring' + self.successors.add_successor(self.state, self.state.addr+self.plength, self.state.solver.true, jumpkind) + + self.state.memory.store(arg2,self.state.solver.BVS("symbolic_list", self.arch.bits)) + + return self.state.solver.BVS("retval_{}".format(self.display_name), self.arch.bits) + diff --git a/sema_toolchain/sema_scdg/application/procedures/windows/custom_hook/WannacryHook_allocate_24.py b/sema_toolchain/sema_scdg/application/procedures/windows/custom_hook/WannacryHook_allocate_24.py new file mode 100644 index 000000000..25df2ee11 --- /dev/null +++ b/sema_toolchain/sema_scdg/application/procedures/windows/custom_hook/WannacryHook_allocate_24.py @@ -0,0 +1,23 @@ +import os +import sys + + +import angr +import claripy + +class WannacryHook_allocate_24(angr.SimProcedure): + NO_RET = True + def __init__(self, plength=0, project=None, cc=None, prototype=None, symbolic_return=None, returns=None, is_syscall=False, is_stub=False, num_args=None, display_name=None, library_name=None, is_function=None, **kwargs): + super().__init__(project, cc, prototype, symbolic_return, returns, is_syscall, is_stub, num_args, display_name, library_name, is_function, **kwargs) + self.plength=plength + + def run(self,arg1,arg2): + print("allocate_24 skip") + #skip because corrupted ret addr + #0x1000235e + jumpkind = 'Ijk_NoHook' if self.plength == 0 else 'Ijk_Boring' + self.successors.add_successor(self.state, self.state.addr+self.plength, self.state.solver.true, jumpkind) + + ptn = self.state.heap._malloc(24) + return ptn + diff --git a/sema_toolchain/sema_scdg/application/procedures/windows/custom_hook/WannacryHook_cleanup.py b/sema_toolchain/sema_scdg/application/procedures/windows/custom_hook/WannacryHook_cleanup.py new file mode 100644 index 000000000..d3643261e --- /dev/null +++ b/sema_toolchain/sema_scdg/application/procedures/windows/custom_hook/WannacryHook_cleanup.py @@ -0,0 +1,25 @@ +import os +import sys + + +import angr +import claripy + +class WannacryHook_cleanup(angr.SimProcedure): + NO_RET = True + def __init__(self, plength=0, project=None, cc=None, prototype=None, symbolic_return=None, returns=None, is_syscall=False, is_stub=False, num_args=None, display_name=None, library_name=None, is_function=None, **kwargs): + super().__init__(project, cc, prototype, symbolic_return, returns, is_syscall, is_stub, num_args, display_name, library_name, is_function, **kwargs) + self.plength=plength + + def run(self,arg1,arg2,arg3,arg4): + print("cleanup skip") + #skip because infinit loop + #100023c8 + #100023fa + #10002764 + + jumpkind = 'Ijk_NoHook' if self.plength == 0 else 'Ijk_Boring' + self.successors.add_successor(self.state, self.state.addr+self.plength, self.state.solver.true, jumpkind) + self.state.heap.free(arg2) + return 1 + diff --git a/sema_toolchain/sema_scdg/application/procedures/windows/custom_hook/WannacryHook_cls_100071f8.py b/sema_toolchain/sema_scdg/application/procedures/windows/custom_hook/WannacryHook_cls_100071f8.py new file mode 100644 index 000000000..382d7111b --- /dev/null +++ b/sema_toolchain/sema_scdg/application/procedures/windows/custom_hook/WannacryHook_cls_100071f8.py @@ -0,0 +1,24 @@ +import os +import sys + + +import angr +import claripy + +class WannacryHook_cls_100071f8(angr.SimProcedure): + NO_RET = True + def __init__(self, plength=0, project=None, cc=None, prototype=None, symbolic_return=None, returns=None, is_syscall=False, is_stub=False, num_args=None, display_name=None, library_name=None, is_function=None, **kwargs): + super().__init__(project, cc, prototype, symbolic_return, returns, is_syscall, is_stub, num_args, display_name, library_name, is_function, **kwargs) + self.plength=plength + + def run(self,arg1): + print("cls_100071f8 skip") + #skip because corrupted ret addr + #100057e3 + jumpkind = 'Ijk_NoHook' if self.plength == 0 else 'Ijk_Boring' + self.successors.add_successor(self.state, self.state.addr+self.plength, self.state.solver.true, jumpkind) + + ret_val = self.state.solver.BVS("retval_{}".format(self.display_name), self.arch.bits) + self.state.solver.add(claripy.Or(ret_val == 0, ret_val == 1)) + return 1 + diff --git a/sema_toolchain/sema_scdg/application/procedures/windows/custom_hook/WannacryHook_free_contexts.py b/sema_toolchain/sema_scdg/application/procedures/windows/custom_hook/WannacryHook_free_contexts.py new file mode 100644 index 000000000..0eaac9045 --- /dev/null +++ b/sema_toolchain/sema_scdg/application/procedures/windows/custom_hook/WannacryHook_free_contexts.py @@ -0,0 +1,24 @@ +import os +import sys + + +import angr +import claripy + +class WannacryHook_free_contexts(angr.SimProcedure): + NO_RET = True + def __init__(self, plength=0, project=None, cc=None, prototype=None, symbolic_return=None, returns=None, is_syscall=False, is_stub=False, num_args=None, display_name=None, library_name=None, is_function=None, **kwargs): + super().__init__(project, cc, prototype, symbolic_return, returns, is_syscall, is_stub, num_args, display_name, library_name, is_function, **kwargs) + self.plength=plength + + def run(self,arg1): + print("free_contexts skip") + # skip because too much big loop + # 0x1000571a + jumpkind = 'Ijk_NoHook' if self.plength == 0 else 'Ijk_Boring' + self.successors.add_successor(self.state, self.state.addr+self.plength, self.state.solver.true, jumpkind) + + ret_val = self.state.solver.BVS("retval_{}".format(self.display_name), self.arch.bits) + self.state.solver.add(claripy.Or(ret_val == 0, ret_val == 1)) + return 1 + diff --git a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/??0exception@@QAE@ABQBD@Z.py b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/??0exception@@QAE@ABQBD@Z.py new file mode 100644 index 000000000..f7aee6c5e --- /dev/null +++ b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/??0exception@@QAE@ABQBD@Z.py @@ -0,0 +1,24 @@ +import os +import sys +import logging +import angr + +import os + +try: + lw = logging.getLogger("CustomSimProcedureWindows") + lw.setLevel(os.environ.get("LOG_LEVEL", "INFO")) +except Exception as e: + print(e) + + +class Cpp_Exception(angr.SimProcedure): + ALT_NAMES = "??0exception@@QAE@ABQBD@Z" + def run(self, this_ptr, msg_ptr): + lw.debug("C++ std::exception constructor called") + try: + lw.debug("white error : %s",self.state.mem[msg_ptr].string.concrete) + except: + lw.debug("non concrete message") + + return diff --git a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/??2@YAPAXI@Z.py b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/??2@YAPAXI@Z.py index 13652ee6b..115df60e7 100644 --- a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/??2@YAPAXI@Z.py +++ b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/??2@YAPAXI@Z.py @@ -20,11 +20,7 @@ def run( self, uint, ): - if uint.symbolic: - lw.warning("Symbolic size passed to new") - return self.state.heap._malloc(0x42) - malloced = self.state.heap._malloc(uint) - for i in range(self.state.solver.eval(uint)): - self.state.memory.store(malloced+i, 0,size=1) - print(malloced) - return malloced + lw.debug("New Int") + size = self.state.solver.eval(uint) + lw.debug(size) + return self.state.heap._malloc(size) diff --git a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/CloseServiceHandle.py b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/CloseServiceHandle.py new file mode 100644 index 000000000..d15e63b2e --- /dev/null +++ b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/CloseServiceHandle.py @@ -0,0 +1,18 @@ +import os +import sys +import logging +import angr + +import os + +try: + lw = logging.getLogger("CustomSimProcedureWindows") + lw.setLevel(os.environ.get("LOG_LEVEL", "INFO")) +except Exception as e: + print(e) + + +class CloseServiceHandle(angr.SimProcedure): + def run(self, arg1): + lw.debug("Enter CloseServiceHandle") + return 1 diff --git a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/CreateDirectoryA.py b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/CreateDirectoryA.py new file mode 100644 index 000000000..a568af3eb --- /dev/null +++ b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/CreateDirectoryA.py @@ -0,0 +1,23 @@ +import os +import sys +import logging +import angr + +import os + +try: + lw = logging.getLogger("CustomSimProcedureWindows") + lw.setLevel(os.environ.get("LOG_LEVEL", "INFO")) +except Exception as e: + print(e) + + +class CreateDirectoryA(angr.SimProcedure): + def run(self, lpPathName, lpSecurityAttributes): + lw.debug("enter CreateDirectoryA") + try: + lw.debug("path: %s", self.state.mem[lpPathName].string.concrete.decode("ascii")) + except: + lw.debug("path is not concrete") + + return 1 \ No newline at end of file diff --git a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/CreateDirectoryW.py b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/CreateDirectoryW.py new file mode 100644 index 000000000..d72653fa5 --- /dev/null +++ b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/CreateDirectoryW.py @@ -0,0 +1,26 @@ +import os +import sys +import logging +import angr + +import os + +try: + lw = logging.getLogger("CustomSimProcedureWindows") + lw.setLevel(os.environ.get("LOG_LEVEL", "INFO")) +except Exception as e: + print(e) + + +class CreateDirectoryW(angr.SimProcedure): + def run(self, lpPathName, lpSecurityAttributes): + lw.debug("enter CreateDirectoryW") + try: + lw.debug("name: %s", self.state.mem[lpPathName].string.concrete) + if lpPathName == "" : + return 0 + except: + lw.debug("name is not concrete") + + return 1 + diff --git a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/CreateFileA.py b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/CreateFileA.py index b83d69d1e..cc6655043 100644 --- a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/CreateFileA.py +++ b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/CreateFileA.py @@ -4,6 +4,7 @@ import logging import angr +import claripy import os @@ -45,10 +46,10 @@ def run( "CreateFileA: {} asks to create file {}".format(self.display_name, name) ) access = self.state.solver.eval(dwDesiredAccess) - access & (1 << 31) or (access & (1 << 16)) - access & (1 << 30) - access & (1 << 29) - access & (1 << 28) + # access & (1 << 31) or (access & (1 << 16)) + # access & (1 << 30) + # access & (1 << 29) + # access & (1 << 28) fd = self.state.posix.open(name, self.state.solver.BVV(2, self.arch.bits)) # import pdb; pdb.set_trace() @@ -59,4 +60,12 @@ def run( ) #real_fd = open(name, "wb") # TODO fix self.state.globals["files"][fd] = name #name #real_fd - return fd + lw.debug(fd) + + retval = self.state.solver.BVS( + "retval_{}".format(self.display_name), self.arch.bits + ) + + #add the possibility to fail + self.state.solver.add(claripy.Or(retval == 0xffffffff, retval == fd )) + return retval diff --git a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/CreateMutexA.py b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/CreateMutexA.py index 945aa102b..9971fdeae 100644 --- a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/CreateMutexA.py +++ b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/CreateMutexA.py @@ -7,6 +7,8 @@ import os +import claripy + try: lw = logging.getLogger("CustomSimProcedureWindows") lw.setLevel(os.environ["LOG_LEVEL"]) @@ -21,5 +23,5 @@ def run(self, lpMutexAttributes, bInitialOwner, lpName): retval = self.state.solver.BVS( "retval_{}".format(self.display_name), self.arch.bits ) - self.state.solver.add(retval > 0) + self.state.solver.add(claripy.Or(retval == 0, retval == 1 )) return retval diff --git a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/CreateThread.py b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/CreateThread.py index 06a37165b..3d8bc8786 100644 --- a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/CreateThread.py +++ b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/CreateThread.py @@ -25,41 +25,59 @@ def run( dwCreationFlags, lpThreadId ): - if not self.state.globals["is_thread"]: - # code_addr = self.state.solver.eval(lpStartAddress) - lw.debug("IS THREAD") - lw.debug(self.state.solver.eval(lpStartAddress)) - #self.state.regs.esp += 4 * 6 - new_state = self.state.copy() - _ = new_state.stack_pop() - new_state.stack_push(0xdeadbeef) - # new_state.stack_push(lpThreadId) - # new_state.stack_push(dwCreationFlags) - # new_state.stack_push(lpParameter) - # new_state.stack_push(lpStartAddress) - # new_state.stack_push(dwStackSize) - # new_state.stack_push(lpThreadAttributes) - # new_state.stack_push(0xdeadbeef) - self.state.globals["create_thread_address"].append( - { - "new_state":new_state - } - ) - # self.state.regs.esp -= 4 * 6 - return self.state.solver.BVS("retval_{}".format(self.display_name), self.arch.bits) - else: - lw.debug("IS NOT THREAD") - lw.debug(self.state.solver.eval(lpStartAddress)) - code_addr = self.state.solver.eval(lpStartAddress) - ret_addr = self.state.stack_pop() - self.state.regs.esp += 4 * 6 - new_state = self.state.copy() - new_state.stack_push(lpParameter) - new_state.stack_push(ret_addr) - self.successors.add_successor(new_state, code_addr, new_state.solver.true, 'Ijk_Call') - self.returns = False - threadId = self.state.solver.BVS("Thread_Id{}".format(self.display_name), self.arch.bits) - self.state.memory.store(lpThreadId, threadId) + code_addr = self.state.solver.eval(lpStartAddress) + lw.debug("thread created, address: 0x%x, skip" % code_addr) + # if(code_addr == 0x10004790 or code_addr == 0x100045c0): + # lw.debug("address: 0x%x, skip thread(infinite loop)" % code_addr) + # return 1 + # new_state = self.state.copy() + # new_state.stack_push(self.state.stack_pop()) # return address + # new_state.stack_push(lpParameter) # parameter + # threadId = new_state.solver.BVS(f"Thread_Id{self.display_name}", self.arch.bits) + # new_state.memory.store(lpThreadId, threadId) + # self.successors.add_successor(new_state, code_addr, new_state.solver.true, 'Ijk_Call') + # self.returns = False - return self.state.solver.BVS("retval_{}".format(self.display_name), self.arch.bits) + return 1 + + #code that use the plugin thread, not working on this version : + + # if not self.state.globals["is_thread"]: + # # code_addr = self.state.solver.eval(lpStartAddress) + # lw.debug("IS THREAD") + # lw.debug(hex(self.state.solver.eval(lpStartAddress))) + # #self.state.regs.esp += 4 * 6 + # new_state = self.state.copy() + # _ = new_state.stack_pop() + # new_state.stack_push(0xdeadbeef) + # # new_state.stack_push(lpThreadId) + # # new_state.stack_push(dwCreationFlags) + # # new_state.stack_push(lpParameter) + # # new_state.stack_push(lpStartAddress) + # # new_state.stack_push(dwStackSize) + # # new_state.stack_push(lpThreadAttributes) + # # new_state.stack_push(0xdeadbeef) + # self.state.globals["create_thread_address"].append( + # { + # "new_state":new_state + # } + # ) + # # self.state.regs.esp -= 4 * 6 + # return self.state.solver.BVS("retval_{}".format(self.display_name), self.arch.bits) + # else: + # lw.debug("IS NOT THREAD") + # lw.debug(self.state.solver.eval(lpStartAddress)) + # code_addr = self.state.solver.eval(lpStartAddress) + # ret_addr = self.state.stack_pop() + # self.state.regs.esp += 4 * 6 + # new_state = self.state.copy() + # new_state.stack_push(lpParameter) + # new_state.stack_push(ret_addr) + # self.successors.add_successor(new_state, code_addr, new_state.solver.true, 'Ijk_Call') + # self.returns = False + # + # threadId = self.state.solver.BVS("Thread_Id{}".format(self.display_name), self.arch.bits) + # self.state.memory.store(lpThreadId, threadId) + # + # return self.state.solver.BVS("retval_{}".format(self.display_name), self.arch.bits) diff --git a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/CryptDecrypt.py b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/CryptDecrypt.py new file mode 100644 index 000000000..ddb536ce2 --- /dev/null +++ b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/CryptDecrypt.py @@ -0,0 +1,25 @@ +import os +import sys + + +import logging +import angr + +import os + +try: + lw = logging.getLogger("CustomSimProcedureWindows") + lw.setLevel(os.environ["LOG_LEVEL"]) +except Exception as e: + print(e) + +class CryptDecrypt(angr.SimProcedure): + def run(self, hKey, hHash, Final, dwFlags, pbData, pdwDataLen): + lw.debug("CryptDecrypt called") + if self.state.solver.symbolic(hKey): + key = self.state.solver.BVS("Key_Decrypt", self.arch.bits) + self.state.store(hKey, key) + len = self.state.solver.BVV(self.arch.bits,self.arch.bits) + self.state.memory.store(pdwDataLen, len, endness='Iend_LE') + + return 1 diff --git a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/CryptDestroyKey.py b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/CryptDestroyKey.py new file mode 100644 index 000000000..6a34f5f7c --- /dev/null +++ b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/CryptDestroyKey.py @@ -0,0 +1,15 @@ +import os +import sys +import logging +import angr + +try: + lw = logging.getLogger("CustomSimProcedureWindows") + lw.setLevel(os.environ["LOG_LEVEL"]) +except Exception as e: + print(e) + +class CryptDestroyKey(angr.SimProcedure): + def run(self, hKey): + lw.debug("CryptDestroyKey called") + return 1 diff --git a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/CryptExportKey.py b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/CryptExportKey.py new file mode 100644 index 000000000..2d55b583d --- /dev/null +++ b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/CryptExportKey.py @@ -0,0 +1,32 @@ +import os +import sys + +import logging +import angr + +try: + lw = logging.getLogger("CustomSimProcedureWindows") + lw.setLevel(os.environ["LOG_LEVEL"]) +except Exception as e: + print(e) + + +class CryptExportKey(angr.SimProcedure): + def run( + self, + hKey, + hExpKey, + dwBlobType, + dwFlags, + pbData, + pdwDataLen + ): + lw.debug("CryptExportKey") + self.state.memory.store(pdwDataLen, self.arch.bits, endness='Iend_LE') + + if self.state.solver.eval(pbData): + key = self.state.solver.BVS("Key_Export", self.arch.bits) + lw.debug("using key {}".format(key)) + self.state.memory.store(pbData, key) + + return 1 \ No newline at end of file diff --git a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/CryptGetKeyParam.py b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/CryptGetKeyParam.py new file mode 100644 index 000000000..bbb3d36c1 --- /dev/null +++ b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/CryptGetKeyParam.py @@ -0,0 +1,22 @@ +import logging +import angr +import os + +import claripy + +try: + lw = logging.getLogger("CustomSimProcedureWindows") + lw.setLevel(os.environ["LOG_LEVEL"]) +except Exception as e: + print(e) + +class CryptGetKeyParam(angr.SimProcedure): + def run(self, hKey, dwParam, pbData, pdwDataLen, dwFlags): + lw.debug("CryptGetKeyParam called") + key_param = self.state.solver.BVS("KEY_PARAM", self.arch.bits) + self.state.memory.store(pbData, key_param) + self.state.memory.store(pdwDataLen, self.arch.bits,endness='Iend_LE') + + # retval = self.state.solver.BVS("retval_{}".format(self.display_name), self.arch.bits) + # self.state.solver.add(claripy.Or(retval == 0, retval == 1)) + return 1 diff --git a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/CryptReleaseContext.py b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/CryptReleaseContext.py new file mode 100644 index 000000000..329cdd878 --- /dev/null +++ b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/CryptReleaseContext.py @@ -0,0 +1,13 @@ + + +import os +import sys + + +import angr + + +class CryptReleaseContext(angr.SimProcedure): + def run(self, addr): + #self.ret() + return diff --git a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/DeleteCriticalSection.py b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/DeleteCriticalSection.py new file mode 100644 index 000000000..5e94a6c42 --- /dev/null +++ b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/DeleteCriticalSection.py @@ -0,0 +1,11 @@ +import os +import sys + + +import angr + + +class DeletCriticalSection(angr.SimProcedure): + def run(self, addr): + #self.ret() + return diff --git a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/EnterCriticalSection.py b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/EnterCriticalSection.py new file mode 100644 index 000000000..d631b5cbb --- /dev/null +++ b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/EnterCriticalSection.py @@ -0,0 +1,18 @@ +import os +import sys +import logging +import angr + +import os + +try: + lw = logging.getLogger("CustomSimProcedureWindows") + lw.setLevel(os.environ.get("LOG_LEVEL", "INFO")) +except Exception as e: + print(e) + + +class EnterCriticalSection(angr.SimProcedure): + def run(self, arg1): + lw.debug("EnterCriticalSection") + return diff --git a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/ExitThread.py b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/ExitThread.py new file mode 100644 index 000000000..9c1a268ac --- /dev/null +++ b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/ExitThread.py @@ -0,0 +1,16 @@ +import angr +import logging +import os + +try: + lw = logging.getLogger("CustomSimProcedureWindows") + lw.setLevel(os.environ.get("LOG_LEVEL", "INFO")) +except Exception as e: + print(e) + +class ExitThread(angr.SimProcedure): + NO_RET = True + + def run(self, dwExitCode): + lw.debug("ExitThread") + self.exit(exit_code=dwExitCode) diff --git a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/FindFirstFileW.py b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/FindFirstFileW.py index 9f2f776a5..562f13e11 100644 --- a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/FindFirstFileW.py +++ b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/FindFirstFileW.py @@ -4,16 +4,24 @@ import angr import claripy +import logging +try: + lw = logging.getLogger("CustomSimProcedureWindows") + lw.setLevel(os.environ["LOG_LEVEL"]) +except Exception as e: + print(e) class FindFirstFileW(angr.SimProcedure): def run(self, lpFileName, lpFindFileData): + lw.debug("FindFirstFileW.run") try: - print(self.state.mem[lpFileName].string.concrete) + lw.debug(self.state.mem[lpFileName].string.concrete) except: - print(self.state.memory.load(lpFileName,0x20)) + lw.debug(lpFileName) + lw.debug(self.state.globals["FindFirstFile"]) if self.state.globals["FindFirstFile"] == 0: - self.state.globals["FindFirstFile"] == 1 + #self.state.globals["FindFirstFile"] = 1 self.state.memory.store(lpFindFileData, claripy.BVS("dwFileAttributes", 8 * 4)) self.state.memory.store(lpFindFileData+0x4, claripy.BVS("ftCreationTime", 8 * 8)) self.state.memory.store(lpFindFileData+0xc, claripy.BVS("ftLastAccessTime", 8 * 8)) diff --git a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/FindResourceA.py b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/FindResourceA.py index c255dca2e..53fff54e5 100644 --- a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/FindResourceA.py +++ b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/FindResourceA.py @@ -17,8 +17,9 @@ class FindResourceA(angr.SimProcedure): def run(self, hModule, lpName, lpType): - if not self.state.has_plugin("plugin_ressources"): - lw.warning("The procedure FindRessourceA is using the plugin plugin_ressources which is not activated") + return self.state.solver.BVS("FindResourceA", self.state.arch.bits) + if not self.state.has_plugin("plugin_resources"): + lw.warning("The procedure FindRessourceA is using the plugin plugin_resources which is not activated") minaddr = self.state.project.loader.min_addr name = self.state.mem[lpName].string.concrete rsrc = self.state.globals["rsrc"] @@ -53,7 +54,7 @@ def run(self, hModule, lpName, lpType): finaloffset = self.state.solver.eval(self.state.memory.load(rsrc+offset,4,endness=archinfo.Endness.LE)) size = self.state.solver.eval(self.state.memory.load(rsrc+offset+0x4,4,endness=archinfo.Endness.LE)) resource = self.state.solver.eval(self.state.memory.load(minaddr+finaloffset,size,endness=archinfo.Endness.LE)) - if self.state.has_plugin("plugin_ressources"): + if self.state.has_plugin("plugin_resources"): self.state.plugin_resources.resources[finaloffset+minaddr] = {"size": size, "name": name, "data": resource, "rsrcname": rsrcname} x = finaloffset+minaddr return finaloffset+minaddr diff --git a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/GetCurrentDirectoryA.py b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/GetCurrentDirectoryA.py new file mode 100644 index 000000000..debf3d36d --- /dev/null +++ b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/GetCurrentDirectoryA.py @@ -0,0 +1,28 @@ +import os +import sys +import logging +import angr + +import os + +try: + lw = logging.getLogger("CustomSimProcedureWindows") + lw.setLevel(os.environ.get("LOG_LEVEL", "INFO")) +except Exception as e: + print(e) + + +class GetCurrentDirectoryA(angr.SimProcedure): + def getSystemName(self, size): + path = ("C:\\Users\\ElNiak\\"[: size - 1] + "\0").encode( + "utf-16-le" + ) # truncate if too long + return path + + def run(self, nBufferLength, lpBuffer): + size = self.state.solver.eval(nBufferLength) + path = self.getSystemName(size) + path = self.state.solver.BVV(path) + self.state.memory.store(lpBuffer, path) # ,endness=self.arch.memory_endness) + # import pdb; pdb.set_trace() + return len(path) + 2 \ No newline at end of file diff --git a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/GetExitCodeProcess.py b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/GetExitCodeProcess.py new file mode 100644 index 000000000..c77059b7f --- /dev/null +++ b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/GetExitCodeProcess.py @@ -0,0 +1,22 @@ +import os +import sys +import logging +import angr + +import os + +try: + lw = logging.getLogger("CustomSimProcedureWindows") + lw.setLevel(os.environ.get("LOG_LEVEL", "INFO")) +except Exception as e: + print(e) + + +class GetExitCodeProcess(angr.SimProcedure): + def run(self, hProcess, lpExitCode): + lw.debug("GetExitCodeProcess.run") + exit_code = self.state.solver.BVS( + "lpExitCode", self.arch.bits + ) + self.state.memory.store(lpExitCode, exit_code) + return 1 diff --git a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/GetFileAttributesA.py b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/GetFileAttributesA.py index 8534e10f0..4b4e623e3 100644 --- a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/GetFileAttributesA.py +++ b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/GetFileAttributesA.py @@ -7,6 +7,8 @@ import os +import claripy + try: lw = logging.getLogger("CustomSimProcedureWindows") lw.setLevel(os.environ["LOG_LEVEL"]) @@ -20,4 +22,10 @@ def run(self, lpFileName): print(self.state.mem[lpFileName].string.concrete) except: print(self.state.memory.load(lpFileName,0x20)) - return -1 #fail pour gh0strat + + + retval = self.state.solver.BVS( + "retval_{}".format(self.display_name), self.arch.bits + ) + #return -1 #fail pour gh0strat + return retval \ No newline at end of file diff --git a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/GetFileAttributesW.py b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/GetFileAttributesW.py new file mode 100644 index 000000000..88cdb0961 --- /dev/null +++ b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/GetFileAttributesW.py @@ -0,0 +1,28 @@ +import os +import sys +import logging +import angr + +import os + +import claripy + +try: + lw = logging.getLogger("CustomSimProcedureWindows") + lw.setLevel(os.environ.get("LOG_LEVEL", "INFO")) +except Exception as e: + print(e) + + +class GetFileAttributesW(angr.SimProcedure): + def run(self, lpFileName): + try: + lw.debug(self.state.mem[lpFileName].string.concrete) + if lpFileName == "" : + return 0 + except: + lw.debug(self.state.memory.load(lpFileName, 0x20)) + retval = self.state.solver.BVS( + "retval_{}".format(self.display_name), self.arch.bits + ) + return retval diff --git a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/GetFileSize.py b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/GetFileSize.py index 177f5f5f5..72c078905 100644 --- a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/GetFileSize.py +++ b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/GetFileSize.py @@ -7,6 +7,8 @@ import os +import claripy + try: lw = logging.getLogger("CustomSimProcedureWindows") lw.setLevel(os.environ["LOG_LEVEL"]) @@ -29,10 +31,10 @@ def run(self, hFile, lpFileSizeHigh): "GetFileSize: {} asks file size of {}".format(self.display_name, hFile) ) size = simfd.size() + if not size.symbolic and self.state.solver.eval(size) != 0: return size else: ret_val = self.state.solver.BVS("retval_{}".format(self.display_name), self.arch.bits) - self.state.solver.add(ret_val > 0) - self.state.solver.add(ret_val < 0x100000) + self.state.add_constraints(claripy.Or(ret_val == 0, ret_val == 1)) return ret_val diff --git a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/GetFileSizeEx.py b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/GetFileSizeEx.py new file mode 100644 index 000000000..7c281864e --- /dev/null +++ b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/GetFileSizeEx.py @@ -0,0 +1,36 @@ +import os +import sys +import logging +import angr + +import os + +try: + lw = logging.getLogger("CustomSimProcedureWindows") + lw.setLevel(os.environ.get("LOG_LEVEL", "INFO")) +except Exception as e: + print(e) + + +class GetFileSizeEx(angr.SimProcedure): + def run(self, hFile, lpFileSizeHigh): + if hFile.symbolic: + ret_val = self.state.solver.BVS("retval_{}".format(self.display_name), self.arch.bits) + self.state.solver.add(ret_val != 0xFFFFFFFF) + return ret_val + simfd = self.state.posix.get_fd(hFile) + # import pdb; pdb.set_trace() + if simfd is None: + lw.debug("GetFileSize: could not find fd") + return self.state.solver.BVS("retval_{}".format(self.display_name), self.arch.bits) + lw.debug( + "GetFileSize: {} asks file size of {}".format(self.display_name, hFile) + ) + size = simfd.size() + if not size.symbolic and self.state.solver.eval(size) != 0: + return size + else: + ret_val = self.state.solver.BVS("retval_{}".format(self.display_name), self.arch.bits) + self.state.solver.add(ret_val > 0) + self.state.solver.add(ret_val < 0x100000) + return ret_val diff --git a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/GetFullPathNameA.py b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/GetFullPathNameA.py new file mode 100644 index 000000000..fffaf7ab2 --- /dev/null +++ b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/GetFullPathNameA.py @@ -0,0 +1,57 @@ +import os +import sys +import logging +import angr + +import os + +try: + lw = logging.getLogger("CustomSimProcedureWindows") + lw.setLevel(os.environ.get("LOG_LEVEL", "INFO")) +except Exception as e: + print(e) + + +class GetFullPathNameA(angr.SimProcedure): + def run(self, lpFileName, nBufferLength, lpBuffer, lpFilePart): + try: + f = self.state.mem[lpFileName].wstring.concrete + lw.debug(f) + if f[-1] == "\\": # is folder + pathpath_bytes = f.encode("utf-16-le") + lenpath = len(pathpath_bytes) + lw.debug(lenpath) + lw.debug(pathpath_bytes.decode("utf-16-le")) + self.state.memory.store(lpBuffer, pathpath_bytes) # , size=len(longname) + + self.state.memory.store(lpFilePart, 0) # , size=len(longname) + else: + lenpath = len(f) + pathpath_bytes = f.encode("utf-16-le") + # lenpath = len(pathpath_bytes) + lw.debug(lenpath) + lw.debug(pathpath_bytes.decode("utf-16-le")) + self.state.memory.store(lpBuffer, pathpath_bytes) # , size=len(longname) + + if "C:" not in f: # only file + filepart_bytes = f.encode("utf-16-le") + f = "C:\\Windows\\System32\\" + f + filepart_offset = len("C:\\Windows\\System32\\".encode("utf-16-le")) + else: # full path already + filepart = f.split("\\")[-1] + filepart_bytes = filepart.encode("utf-16-le") + filepart_offset = len(pathpath_bytes) - len(filepart_bytes) - 2 + lenfile = len(filepart_bytes) + lw.debug(filepart_offset) + lw.debug(filepart_bytes.decode("utf-16-le")) + self.state.memory.store(lpFilePart, lpBuffer + filepart_offset) # , size=len(longname) + + return lenpath + except Exception as e: + lw.warning(e) + # longname = "C:\Windows\System32\\".encode("utf-16-le") + # longname =+ self.state.memory.load(lpFileName, nBufferLength) + # # lw.debug(self.state.memory.load(lpBuffer,nBufferLength)) + # lw.debug(longname) + # self.state.memory.store(lpBuffer,longname) + return self.state.solver.BVS("retval_{}".format(self.display_name), self.arch.bits) diff --git a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/GetLastError.py b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/GetLastError.py index 92ff1450e..dcf218b4a 100644 --- a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/GetLastError.py +++ b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/GetLastError.py @@ -7,6 +7,8 @@ import os +import claripy + try: lw = logging.getLogger("CustomSimProcedureWindows") lw.setLevel(os.environ["LOG_LEVEL"]) @@ -22,7 +24,9 @@ def run(self): # #ret_expr = self.state.plugin_env_var.last_error # # self.state.memory.load(self.state.regs.esp,4,endness= self.arch.memory_endness) # #return ret_expr - # return self.state.solver.BVS( - # "retval_{}".format(self.display_name), self.arch.bits - # ) - return 0x0 + retval = self.state.solver.BVS( + "retval_{}".format(self.display_name), self.arch.bits + ) + self.state.add_constraints(claripy.Or(retval == 0x0, retval == 0xb7)) + + return retval diff --git a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/GetModuleFileNameA.py b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/GetModuleFileNameA.py index fe9b98d52..185a9c08e 100644 --- a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/GetModuleFileNameA.py +++ b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/GetModuleFileNameA.py @@ -30,7 +30,6 @@ def decodeString(self, ptr): return lib def run(self, module, buf_filename, size_buf): - self.state.project size = self.state.solver.eval(size_buf) # if NULL, retrieve path of exe of current process diff --git a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/GetModuleFileNameExA.py b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/GetModuleFileNameExA.py index daa48c447..06312fdda 100644 --- a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/GetModuleFileNameExA.py +++ b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/GetModuleFileNameExA.py @@ -30,7 +30,6 @@ def decodeString(self, ptr): return lib def run(self, hProcess, hModule, lpFilename, nSize): - self.state.project size = self.state.solver.eval(nSize) # if NULL, retrieve path of exe of current process diff --git a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/GetProcessHeap.py b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/GetProcessHeap.py new file mode 100644 index 000000000..ffb394f5d --- /dev/null +++ b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/GetProcessHeap.py @@ -0,0 +1,20 @@ +import os +import sys +import logging +import angr + +import os + +try: + lw = logging.getLogger("CustomSimProcedureWindows") + lw.setLevel(os.environ.get("LOG_LEVEL", "INFO")) +except Exception as e: + print(e) + + +class GetProcessHeap(angr.SimProcedure): + def run(self, ): + retval = self.state.solver.BVS( + "retval_{}".format(self.display_name), self.arch.bits + ) + return retval diff --git a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/GetTempFileNameA.py b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/GetTempFileNameA.py index a6f29067d..7f5c01db2 100644 --- a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/GetTempFileNameA.py +++ b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/GetTempFileNameA.py @@ -21,8 +21,12 @@ def decodeString(self, ptr): return fileName def run(self, lpPathName, lpPrefixString, uUnique, lpTempFileName): + lw.debug("GetTempFileNameA") + lw.debug(lpPathName) + if self.state.solver.symbolic(lpPathName) or self.state.solver.eval(lpPathName) == 0: + lw.debug("symbolic pathname") + return self.state.solver.BVS("retval_{}".format(self.display_name), self.arch.bits) - self.state.project # import pdb; pdb.set_trace() dirname = self.decodeString(lpPathName) name = self.decodeString(lpPrefixString)[:3] diff --git a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/GetTempPathW.py b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/GetTempPathW.py new file mode 100644 index 000000000..4f8897eff --- /dev/null +++ b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/GetTempPathW.py @@ -0,0 +1,20 @@ +import os +import sys +import logging +import angr + +import os + +try: + lw = logging.getLogger("CustomSimProcedureWindows") + lw.setLevel(os.environ.get("LOG_LEVEL", "INFO")) +except Exception as e: + print(e) + + +class GetTempPathW(angr.SimProcedure): + def run(self, nBufferLength, lpBuffer): + lw.debug("GetTempPathW.run") + temp_path = "C:\\Temp\\" + self.state.memory.store(lpBuffer, "C:\\Temp\\".encode(), endness="Iend_LE") + return self.state.solver.BVV(len("C:\\Temp\\"), self.arch.bits) diff --git a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/GlobalAlloc.py b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/GlobalAlloc.py new file mode 100644 index 000000000..91209cc9e --- /dev/null +++ b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/GlobalAlloc.py @@ -0,0 +1,29 @@ +import os +import sys +import logging +import angr + +import os + +import claripy + +try: + lw = logging.getLogger("CustomSimProcedureWindows") + lw.setLevel(os.environ.get("LOG_LEVEL", "INFO")) +except Exception as e: + print(e) + + +class GlobalAlloc(angr.SimProcedure): + def run(self, uFlags, dwBytes): + lw.debug("GlobalAlloc.run") + size = self.state.solver.eval(dwBytes) + lw.debug(size) + if size >= 0x100000: + lw.debug("GlobalAlloc size >= 1MB, troncate to 256") + return self.state.heap._malloc(0x100) + # retval = self.state.solver.BVS("retval_{}".format(self.display_name), self.arch.bits) + # self.state.solver.add(claripy.Or(retval == 0, retval == self.state.heap._malloc(size))) + # return retval + + return self.state.heap._malloc(size) \ No newline at end of file diff --git a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/GlobalFree.py b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/GlobalFree.py new file mode 100644 index 000000000..de3e516aa --- /dev/null +++ b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/GlobalFree.py @@ -0,0 +1,17 @@ + + + +import os +import sys + + +import angr + + +class GlobalFree(angr.SimProcedure): + def run(self, addr): + try: + self.state.heap.free(addr) + return self.state.solver.BVV(1, self.arch.bits) + except: + return self.state.solver.BVV(0, self.arch.bits) diff --git a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/HeapFree.py b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/HeapFree.py new file mode 100644 index 000000000..478ce5061 --- /dev/null +++ b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/HeapFree.py @@ -0,0 +1,22 @@ +import os +import sys +import logging +import angr + +import os + +try: + lw = logging.getLogger("CustomSimProcedureWindows") + lw.setLevel(os.environ.get("LOG_LEVEL", "INFO")) +except Exception as e: + print(e) + + +class HeapFree(angr.SimProcedure): + def run(self, hHeap, dwFlags, lpMem): + lw.debug("HeapFree.run") + try: + self.state.heap.free(lpMem) + return self.state.solver.BVV(1, self.arch.bits) + except: + return self.state.solver.BVV(0, self.arch.bits) diff --git a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/InitializeCriticalSection.py b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/InitializeCriticalSection.py index e69de29bb..06c1489b5 100644 --- a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/InitializeCriticalSection.py +++ b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/InitializeCriticalSection.py @@ -0,0 +1,11 @@ +import os +import sys + + +import angr + + +class InitializeCriticalSection(angr.SimProcedure): + def run(self, addr): + #self.ret() + return diff --git a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/InternetOpenUrlA.py b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/InternetOpenUrlA.py index c6a730984..4e8a35e76 100644 --- a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/InternetOpenUrlA.py +++ b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/InternetOpenUrlA.py @@ -18,5 +18,5 @@ class InternetOpenUrlA(angr.SimProcedure): def run(self, hInternet, lpszUrl, lpszHeaders, dwHeadersLength, dwFlags, dwContext): print(self.state.mem[lpszUrl].string.concrete) handle = self.state.solver.BVS("retval_{}".format(self.display_name), self.arch.bits) - self.state.solver.add(handle != 0) + #self.state.solver.add(handle != 0) return handle diff --git a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/IsBadReadPtr.py b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/IsBadReadPtr.py new file mode 100644 index 000000000..8fd910b30 --- /dev/null +++ b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/IsBadReadPtr.py @@ -0,0 +1,23 @@ +import os +import sys +import logging +import angr + +import os + +try: + lw = logging.getLogger("CustomSimProcedureWindows") + lw.setLevel(os.environ.get("LOG_LEVEL", "INFO")) +except Exception as e: + print(e) + + +class IsBadReadPtr(angr.SimProcedure): + def run(self, lp, ucb): + lw.debug("IsBadReadPtr.run") + size = self.state.solver.eval(ucb) + try: + garbage = self.state.memory.load(lp, size) + return 0 + except Exception: + return 1 \ No newline at end of file diff --git a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/LeaveCriticalSection.py b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/LeaveCriticalSection.py new file mode 100644 index 000000000..efa69692d --- /dev/null +++ b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/LeaveCriticalSection.py @@ -0,0 +1,18 @@ +import os +import sys +import logging +import angr + +import os + +try: + lw = logging.getLogger("CustomSimProcedureWindows") + lw.setLevel(os.environ.get("LOG_LEVEL", "INFO")) +except Exception as e: + print(e) + + +class LeaveCriticalSection(angr.SimProcedure): + def run(self, arg1): + lw.debug("LeaveCriticalSection") + return diff --git a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/LocalFileTimeToFileTime.py b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/LocalFileTimeToFileTime.py new file mode 100644 index 000000000..cf6caaf29 --- /dev/null +++ b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/LocalFileTimeToFileTime.py @@ -0,0 +1,19 @@ +import os +import sys +import logging +import angr + +import os + +try: + lw = logging.getLogger("CustomSimProcedureWindows") + lw.setLevel(os.environ.get("LOG_LEVEL", "INFO")) +except Exception as e: + print(e) + + +class LocalFileTimeToFileTime(angr.SimProcedure): + def run(self, lpLocalFileTime, lpFileTime): + lw.debug("LocalFileTimeToFileTime.run") + self.state.memory.store(lpFileTime, self.state.memory.load(lpLocalFileTime, 8)) + return 1 diff --git a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/LocalFree.py b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/LocalFree.py new file mode 100644 index 000000000..dc9ac563b --- /dev/null +++ b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/LocalFree.py @@ -0,0 +1,23 @@ + +import os +import sys +import logging +import angr + +import os + +try: + lw = logging.getLogger("CustomSimProcedureWindows") + lw.setLevel(os.environ.get("LOG_LEVEL", "INFO")) +except Exception as e: + print(e) + + +class LocalFree(angr.SimProcedure): + def run(self, hMem): + lw.debug("LocalFree.run") + try: + self.state.heap.free(hMem) + return 0 + except: + return hMem diff --git a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/MultiByteToWideChar.py b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/MultiByteToWideChar.py index 4fd83f56f..ba5fb18c2 100644 --- a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/MultiByteToWideChar.py +++ b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/MultiByteToWideChar.py @@ -1,3 +1,4 @@ + import os import sys diff --git a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/OpenMutexA.py b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/OpenMutexA.py new file mode 100644 index 000000000..6200c12ff --- /dev/null +++ b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/OpenMutexA.py @@ -0,0 +1,27 @@ +import os +import sys +import logging +import angr + +import os + +try: + lw = logging.getLogger("CustomSimProcedureWindows") + lw.setLevel(os.environ.get("LOG_LEVEL", "INFO")) +except Exception as e: + print(e) + + +class OpenMutexA(angr.SimProcedure): + def run(self, dwDesiredAccess, bInheritHandle, lpName): + lw.debug("OpenMutexA.run") + try: + name = self.state.mem[lpName].string.concrete.decode("ascii") + lw.debug("mutex name: %s", name) + except: + pass + + retval = self.state.solver.BVS( + "retval_{}".format(self.display_name), self.arch.bits + ) + return retval \ No newline at end of file diff --git a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/ReadFile.py b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/ReadFile.py index 3da968a7e..a1f0e53c9 100644 --- a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/ReadFile.py +++ b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/ReadFile.py @@ -19,7 +19,6 @@ def run( self, hFile, lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesRead, lpOverlapped ): - self.state.project simfd = self.state.posix.get_fd(hFile) if simfd is None: lw.warning("ReadFile: could not find fd") @@ -30,5 +29,5 @@ def run( self.state.memory.store( lpNumberOfBytesRead, bytes_read, endness=self.arch.memory_endness ) - return 1 - # return self.state.solver.BVS("retval_{}".format(self.display_name),self.arch.bits) + #return 1 + return self.state.solver.BVS("retval_{}".format(self.display_name),self.arch.bits) diff --git a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/RegCreateKeyW.py b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/RegCreateKeyW.py new file mode 100644 index 000000000..5bc7f5dc2 --- /dev/null +++ b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/RegCreateKeyW.py @@ -0,0 +1,28 @@ +import os +import sys +import logging +import angr + +import os + +try: + lw = logging.getLogger("CustomSimProcedureWindows") + lw.setLevel(os.environ.get("LOG_LEVEL", "INFO")) +except Exception as e: + print(e) + + +class RegCreateKeyW(angr.SimProcedure): + def run(self, hKey, lpSubKey, phkResult): + lw.debug("RegCreateKeyW.run") + try: + subkey = self.state.mem[lpSubKey].wstring.concrete + lw.debug("subkey: {}".format(subkey)) + except: + pass + ptr = self.state.solver.BVS( + "key_handle_{}".format(self.display_name), self.arch.bits + ) + self.state.memory.store(phkResult,ptr) + + return 0 \ No newline at end of file diff --git a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/RegisterServiceCtrlHandlerA.py b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/RegisterServiceCtrlHandlerA.py new file mode 100644 index 000000000..acf83137c --- /dev/null +++ b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/RegisterServiceCtrlHandlerA.py @@ -0,0 +1,20 @@ +import os +import sys + + +import logging +import angr + +import os + +try: + lw = logging.getLogger("CustomSimProcedureWindows") + lw.setLevel(os.environ["LOG_LEVEL"]) +except Exception as e: + print(e) + + +class RegisterServiceCtrlHandlerA(angr.SimProcedure): + def run(self, lpServiceName, lpHandlerProc): + + return 1 \ No newline at end of file diff --git a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/SetCurrentDirectoryA.py b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/SetCurrentDirectoryA.py new file mode 100644 index 000000000..d59f6de6d --- /dev/null +++ b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/SetCurrentDirectoryA.py @@ -0,0 +1,28 @@ +import os +import sys +import logging +import angr + +import os + +import claripy + +try: + lw = logging.getLogger("CustomSimProcedureWindows") + lw.setLevel(os.environ.get("LOG_LEVEL", "INFO")) +except Exception as e: + print(e) + + +class SetCurrentDirectoryA(angr.SimProcedure): + def run(self, lpPathName): + try: + lw.debug(self.state.mem[lpPathName].string.concrete) + except: + lw.debug("SetCurrentDirectoryA with non concrete path") + retval = self.state.solver.BVS( + "retval_{}".format(self.display_name), self.arch.bits + ) + self.state.solver.add(claripy.Or(retval == 0, retval == 1)) + return retval + diff --git a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/SetCurrentDirectoryW.py b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/SetCurrentDirectoryW.py new file mode 100644 index 000000000..1a1ae846f --- /dev/null +++ b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/SetCurrentDirectoryW.py @@ -0,0 +1,30 @@ +import os +import sys +import logging +import angr + +import os + +import claripy + +try: + lw = logging.getLogger("CustomSimProcedureWindows") + lw.setLevel(os.environ.get("LOG_LEVEL", "INFO")) +except Exception as e: + print(e) + + +class SetCurrentDirectoryW(angr.SimProcedure): + def run(self, lpPathName): + try: + lw.debug(self.state.mem[lpPathName].string.concrete) + if lpPathName == "" : + return 0 + except: + lw.debug("SetCurrentDirectoryA with non concrete path") + + retval = self.state.solver.BVS( + "retval_{}".format(self.display_name), self.arch.bits + ) + self.state.solver.add(claripy.Or(retval == 0, retval == 1)) + return retval diff --git a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/SetFileAttributesW.py b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/SetFileAttributesW.py new file mode 100644 index 000000000..04587970d --- /dev/null +++ b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/SetFileAttributesW.py @@ -0,0 +1,23 @@ +import os +import sys +import logging +import angr + +import os + +try: + lw = logging.getLogger("CustomSimProcedureWindows") + lw.setLevel(os.environ.get("LOG_LEVEL", "INFO")) +except Exception as e: + print(e) + + +class SetFileAttributesW(angr.SimProcedure): + def run(self, lpFileName, dwFileAttributes): + lw.debug("SetFileAttributesW.run") + try: + path = self.state.mem[lpFileName].wstring.concrete + lw.debug("path: {}".format(path)) + except: + pass + return 1 diff --git a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/SetFileTime.py b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/SetFileTime.py new file mode 100644 index 000000000..d894f2893 --- /dev/null +++ b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/SetFileTime.py @@ -0,0 +1,24 @@ +import os +import sys +import logging +import angr + +import os + +try: + lw = logging.getLogger("CustomSimProcedureWindows") + lw.setLevel(os.environ.get("LOG_LEVEL", "INFO")) +except Exception as e: + print(e) + + +class SetFileTime(angr.SimProcedure): + def run(self, hFile, lpCreationTime, lpLastAccessTime, lpLastWriteTime): + lw.debug("SetFileTime.run") + try: + path = self.state.mem[hFile].wstring.concrete + lw.debug("path: {}".format(path)) + except: + pass + return 1 + diff --git a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/SizeofResource.py b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/SizeofResource.py index e44c1bd78..42a222f69 100644 --- a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/SizeofResource.py +++ b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/SizeofResource.py @@ -17,7 +17,7 @@ class SizeofResource(angr.SimProcedure): def run(self, hModule, hResInfo): - if self.state.has_plugin("plugin_ressources"): + if self.state.has_plugin("plugin_resources"): if self.state.solver.eval(hResInfo) in self.state.plugin_resources.resources: lw.debug(hex(self.state.plugin_resources.resources[self.state.solver.eval(hResInfo)]["size"])) return self.state.plugin_resources.resources[self.state.solver.eval(hResInfo)]["size"] @@ -27,4 +27,4 @@ def run(self, hModule, hResInfo): # "retval_{}".format(self.display_name), self.arch.bits # ) else : - lw.warning("The procedure SizeofRessource is using the plugin plugin_ressources which is not activated") + lw.warning("The procedure SizeofRessource is using the plugin plugin_resources which is not activated") diff --git a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/Sleep.py b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/Sleep.py new file mode 100644 index 000000000..b7b847b0a --- /dev/null +++ b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/Sleep.py @@ -0,0 +1,18 @@ +import os +import sys +import logging +import angr + +import os + +try: + lw = logging.getLogger("CustomSimProcedureWindows") + lw.setLevel(os.environ.get("LOG_LEVEL", "INFO")) +except Exception as e: + print(e) + + +class Sleep(angr.SimProcedure): + def run(self, time): + lw.debug("Simulating Sleep for %s milliseconds" % self.state.solver.eval(time)) + return diff --git a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/StartServiceCtrlDispatcherA.py b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/StartServiceCtrlDispatcherA.py index 1fd9f90ef..383af38a3 100644 --- a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/StartServiceCtrlDispatcherA.py +++ b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/StartServiceCtrlDispatcherA.py @@ -16,8 +16,16 @@ class StartServiceCtrlDispatcherA(angr.SimProcedure): def run(self, lpServiceStartTable): - retval = self.state.solver.BVS( - "retval_{}".format(self.display_name), self.arch.bits - ) - self.state.solver.add(retval != 0) - return retval + lw.debug("Starting Service Control Dispatcher") + b = self.state.arch.bytes + lpServiceName = self.state.memory.load(lpServiceStartTable, b) + lw.debug(lpServiceName) + + lpServiceProc = self.state.memory.load(lpServiceStartTable + b, b, endness='Iend_LE') + lw.debug(lpServiceProc) + + + self.jump(self.state.solver.eval(lpServiceProc)) + + + return self.state.solver.BVV(1, self.arch.bits) \ No newline at end of file diff --git a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/SystemParametersInfoW.py b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/SystemParametersInfoW.py new file mode 100644 index 000000000..121985452 --- /dev/null +++ b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/SystemParametersInfoW.py @@ -0,0 +1,17 @@ +import angr +import logging +import os + +try: + lw = logging.getLogger("CustomSimProcedureWindows") + lw.setLevel(os.environ["LOG_LEVEL"]) +except Exception as e: + print(e) +class SystemParametersInfoW(angr.SimProcedure): + def run(self, uiAction, uiParam, pvParam, fWinIni): + lw.debug("SystemParametersInfoW called") + retval = self.state.solver.BVS( + "retval_{}".format(self.display_name), self.arch.bits + ) + return retval + diff --git a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/SystemTimeToFileTime.py b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/SystemTimeToFileTime.py new file mode 100644 index 000000000..16a51b8b1 --- /dev/null +++ b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/SystemTimeToFileTime.py @@ -0,0 +1,20 @@ +import os +import sys +import logging +import angr + +import os + +try: + lw = logging.getLogger("CustomSimProcedureWindows") + lw.setLevel(os.environ.get("LOG_LEVEL", "INFO")) +except Exception as e: + print(e) + + +class SystemTimeToFileTime(angr.SimProcedure): + def run(self, lpSystemTime, lpFileTime): + lw.debug("SystemTimeToFileTime.run") + time = self.state.memory.load(lpSystemTime,16) + self.state.memory.store(lpFileTime, time[0:8],8) + return 1 \ No newline at end of file diff --git a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/WriteFile.py b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/WriteFile.py index e81eda7f1..9ce567ea0 100644 --- a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/WriteFile.py +++ b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/WriteFile.py @@ -24,14 +24,22 @@ def run( lpNumberOfBytesWritten, lpOverlapped, ): - self.state.project + + if hFile.symbolic: + lw.debug("symbolic hfile, skipping symbolic write") + return self.state.solver.BVS( + "retval_{}".format(self.display_name), self.arch.bits + ) + simfd = self.state.posix.get_fd(hFile) - if simfd is None: + + if not simfd: lw.debug("WriteFile: could not find fd") return self.state.solver.BVS( "retval_{}".format(self.display_name), self.arch.bits ) bytes_written = simfd.write(lpBuffer, nNumberOfBytesToWrite) + lw.debug("bytes_written: {}".format(bytes_written)) self.state.memory.store( lpNumberOfBytesWritten, bytes_written, endness=self.arch.memory_endness ) diff --git a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/_CxxThrowException.py b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/_CxxThrowException.py new file mode 100644 index 000000000..e38302cc7 --- /dev/null +++ b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/_CxxThrowException.py @@ -0,0 +1,18 @@ +import os +import sys +import logging +import angr + +import os + +try: + lw = logging.getLogger("CustomSimProcedureWindows") + lw.setLevel(os.environ.get("LOG_LEVEL", "INFO")) +except Exception as e: + print(e) + + +class _CxxThrowException(angr.SimProcedure): + def run(self, pExceptionObject, pThrowInfo): + lw.debug("enter _CxxThrowException") + return diff --git a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/__allmul.py b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/__allmul.py new file mode 100644 index 000000000..fbaec1715 --- /dev/null +++ b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/__allmul.py @@ -0,0 +1,28 @@ +import os +import sys +import logging +import angr + +import os + +try: + lw = logging.getLogger("CustomSimProcedureWindows") + lw.setLevel(os.environ.get("LOG_LEVEL", "INFO")) +except Exception as e: + print(e) + + +class __allmul(angr.SimProcedure): + def run(self, arg1, arg2, arg3, arg4): + lw.debug("enter __allmul") + try: + a = self.state.solver.eval(arg1) + b = self.state.solver.eval(arg2) + c = self.state.solver.eval(arg3) + d = self.state.solver.eval(arg4) + retval = self.state.solver.BVV(a*b*c*d,64) + except: + retval = self.state.solver.BVS( + "retval_{}".format(self.display_name), self.arch.bits + ) + return retval diff --git a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/__p___argc.py b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/__p___argc.py new file mode 100644 index 000000000..fcfe426a4 --- /dev/null +++ b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/__p___argc.py @@ -0,0 +1,13 @@ +import os +import sys + + +import angr + +class __p___argc(angr.SimProcedure): + def run(self): + # The __argc global variable is a count of the number of command-line arguments passed to the program. + # https://learn.microsoft.com/en-us/cpp/c-runtime-library/argc-argv-wargv?view=msvc-170 + argc = self.state.heap.malloc(4) + self.state.memory.store(argc, self.state.solver.BVS("retval_{}".format(self.display_name), 32)) + return argc diff --git a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/__p___argv.py b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/__p___argv.py new file mode 100644 index 000000000..3cbed887d --- /dev/null +++ b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/__p___argv.py @@ -0,0 +1,21 @@ +import os +import sys +import logging +import angr + +import os + +import claripy + +try: + lw = logging.getLogger("CustomSimProcedureWindows") + lw.setLevel(os.environ.get("LOG_LEVEL", "INFO")) +except Exception as e: + print(e) + + +class __p___argv(angr.SimProcedure): + def run(self, ): + lw.debug("enter __p___argv") + argv = self.state.posix.argv + return argv diff --git a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/__p__commode.py b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/__p__commode.py new file mode 100644 index 000000000..4cfc81787 --- /dev/null +++ b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/__p__commode.py @@ -0,0 +1,21 @@ +import os +import sys +import logging +import angr + +import os + +try: + lw = logging.getLogger("CustomSimProcedureWindows") + lw.setLevel(os.environ.get("LOG_LEVEL", "INFO")) +except Exception as e: + print(e) + + +class __p__commode(angr.SimProcedure): + def run(self): + lw.debug("enter __p__commode") + retval = self.state.solver.BVS( + "retval_{}".format(self.display_name), self.arch.bits + ) + return retval diff --git a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/__p__fmode.py b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/__p__fmode.py new file mode 100644 index 000000000..2221b9626 --- /dev/null +++ b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/__p__fmode.py @@ -0,0 +1,21 @@ +import os +import sys +import logging +import angr + +import os + +try: + lw = logging.getLogger("CustomSimProcedureWindows") + lw.setLevel(os.environ.get("LOG_LEVEL", "INFO")) +except Exception as e: + print(e) + + +class __p__fmode(angr.SimProcedure): + def run(self, ): + lw.debug("enter __p__fmode") + retval = self.state.solver.BVS( + "retval_{}".format(self.display_name), self.arch.bits + ) + return retval diff --git a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/__setdefaultprecision.py b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/__setdefaultprecision.py new file mode 100644 index 000000000..2b0444379 --- /dev/null +++ b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/__setdefaultprecision.py @@ -0,0 +1,18 @@ +import os +import sys +import logging +import angr + +import os + +try: + lw = logging.getLogger("CustomSimProcedureWindows") + lw.setLevel(os.environ.get("LOG_LEVEL", "INFO")) +except Exception as e: + print(e) + + +class __setdefaultprecision(angr.SimProcedure): + def run(self, ): + lw.debug("enter __setdefaultprecision") + return diff --git a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/__setusermatherr.py b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/__setusermatherr.py new file mode 100644 index 000000000..2df4b77a8 --- /dev/null +++ b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/__setusermatherr.py @@ -0,0 +1,23 @@ +import os +import sys +import logging +import angr + +import os + +try: + lw = logging.getLogger("CustomSimProcedureWindows") + lw.setLevel(os.environ.get("LOG_LEVEL", "INFO")) +except Exception as e: + print(e) + + +class __setusermatherr(angr.SimProcedure): + def run(self, handler_ptr): + lw.debug("custom math err set") + try: + lw.debug("white error : %s",self.state.mem[handler_ptr].string.concrete) + except: + lw.debug("non concrete message") + + return 0 diff --git a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/_initterm.py b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/_initterm.py index e85d1fa29..85d921843 100644 --- a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/_initterm.py +++ b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/_initterm.py @@ -19,12 +19,16 @@ class _initterm(angr.SimProcedure): #pylint:disable=arguments-differ def run(self, fp_a, fp_z): + #return if self.state.solver.symbolic(fp_a) or self.state.solver.symbolic(fp_z): lw.warning("Symbolic argument to _initterm{_e} is not supported... returning") self.ret(0) # might as well try to keep going - self.callbacks = self.get_callbacks(fp_a, fp_z) - self.do_callbacks(fp_a, fp_z) + concrete_fp_a = self.state.solver.eval(fp_a) + concrete_fp_z = self.state.solver.eval(fp_z) + + self.callbacks = self.get_callbacks(concrete_fp_a, concrete_fp_z) + self.do_callbacks(concrete_fp_a, concrete_fp_z) def get_callbacks(self, fp_a, fp_z): callbacks = [] diff --git a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/_local_unwind2.py b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/_local_unwind2.py new file mode 100644 index 000000000..19a41bb9a --- /dev/null +++ b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/_local_unwind2.py @@ -0,0 +1,19 @@ +import logging +import angr +import os + +try: + lw = logging.getLogger("CustomSimProcedureWindows") + lw.setLevel(os.environ.get("LOG_LEVEL", "INFO")) +except Exception as e: + print(e) + + +class _local_unwind2(angr.SimProcedure): + def run(self, frame_pointer, stop): + lw.debug("enter _local_unwind2") + if self.state.solver.eval(stop) == 0xFFFFFFFF: + lw.debug("free frame pointer {}".format(frame_pointer)) + self.state.heap._free(frame_pointer) + + return 1 diff --git a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/_mbsstr.py b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/_mbsstr.py new file mode 100644 index 000000000..e91b1416a --- /dev/null +++ b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/_mbsstr.py @@ -0,0 +1,28 @@ +import os +import sys +import logging +import angr + +import os + +try: + lw = logging.getLogger("CustomSimProcedureWindows") + lw.setLevel(os.environ.get("LOG_LEVEL", "INFO")) +except Exception as e: + print(e) + + +class _mbsstr(angr.SimProcedure): + def run(self, str_ptr, substr_ptr): + lw.debug("enter mbsstr") + try: + str_conc = self.state.mem[str_ptr].string.concrete + substr_conc = self.state.mem[substr_ptr].string.concrete + lw.debug("Concrete strings: str=%s, substr=%s", str_conc, substr_conc) + offset = str_conc.find(substr_conc) + return str_ptr + offset + except: + retval = self.state.solver.BVS( + "retval_{}".format(self.display_name), self.arch.bits + ) + return retval diff --git a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/_stricmp.py b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/_stricmp.py new file mode 100644 index 000000000..627ad0b6a --- /dev/null +++ b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/_stricmp.py @@ -0,0 +1,28 @@ +import os +import sys +import logging +import angr + +import os + +try: + lw = logging.getLogger("CustomSimProcedureWindows") + lw.setLevel(os.environ.get("LOG_LEVEL", "INFO")) +except Exception as e: + print(e) + + +class _stricmp(angr.SimProcedure): + def run(self, str1, str2): + lw.debug("enter _stricmp") + try: + str1_conc = self.state.mem[str1].string.concrete.decode('ascii').lower() + str2_conc = self.state.mem[str2].string.concrete.decode('ascii').lower() + + lw.debug("Concrete strings: str1=%s, str2=%s", str1_conc, str2_conc) + return (str1_conc < str2_conc) - (str1_conc > str2_conc) + except: + retval = self.state.solver.BVS( + "retval_{}".format(self.display_name), self.arch.bits + ) + return retval diff --git a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/cryptAcquireContextA.py b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/cryptAcquireContextA.py new file mode 100644 index 000000000..25d018842 --- /dev/null +++ b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/cryptAcquireContextA.py @@ -0,0 +1,22 @@ + +import logging +import angr +import os + +try: + lw = logging.getLogger("CustomSimProcedureWindows") + lw.setLevel(os.environ["LOG_LEVEL"]) +except Exception as e: + print(e) + + +class CryptAcquireContextA(angr.SimProcedure): + def run( + self, + phProv, + szContainer, + szProvider, + dwProvType, + dwFlags + ): + return 0x1 diff --git a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/cryptEncrypt.py b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/cryptEncrypt.py new file mode 100644 index 000000000..89763df0a --- /dev/null +++ b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/cryptEncrypt.py @@ -0,0 +1,33 @@ +import angr +import claripy +import logging +import os + +try: + lw = logging.getLogger("CustomSimProcedureWindows") + lw.setLevel(os.environ.get("LOG_LEVEL", "INFO")) +except Exception as e: + print(e) + +class CryptEncrypt(angr.SimProcedure): + def run( + self, + hKey, + hHash, + Final, + dwFlags, + pbData, + pdwDataLen, + dwBufLen + ): + lw.debug("CryptEncrypt called") + try: + str_data = self.state.mem[pbData].string.concrete + lw.debug("data to encrypt : {}".format(str_data)) + except: + pass + retval = self.state.solver.BVS( + "retval_{}".format(self.display_name), self.arch.bits + ) + self.state.solver.add(claripy.Or(retval == 0, retval == 1)) + return retval \ No newline at end of file diff --git a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/cryptGenKey.py b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/cryptGenKey.py new file mode 100644 index 000000000..a310b8550 --- /dev/null +++ b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/cryptGenKey.py @@ -0,0 +1,18 @@ +import angr +import logging +import os + +try: + lw = logging.getLogger("CustomSimProcedureWindows") + lw.setLevel(os.environ["LOG_LEVEL"]) +except Exception as e: + print(e) + + +class CryptGenKey(angr.SimProcedure): + def run(self, hProv, Algid, dwFlags, phKey): + lw.debug("CryptGenKey called") + key = self.state.solver.BVS("key_GenKey", self.arch.bits) + self.state.memory.store(phKey, key) + + return 1 diff --git a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/cryptImportKey.py b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/cryptImportKey.py new file mode 100644 index 000000000..10c99ba05 --- /dev/null +++ b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/cryptImportKey.py @@ -0,0 +1,25 @@ +import angr +import logging +import os + +import claripy + +try: + lw = logging.getLogger("CustomSimProcedureWindows") + lw.setLevel(os.environ["LOG_LEVEL"]) +except Exception as e: + print(e) + + +class CryptImportKey(angr.SimProcedure): + def run(self, hProv, pbData, dwDataLen, hPubKey, dwFlags, phKey): + lw.debug("CryptImportKey called") + + key = self.state.solver.BVS("Key_Import", self.arch.bits) + self.state.memory.store(phKey, key) + # retval = self.state.solver.BVS( + # "retval_{}".format(self.display_name), self.arch.bits + # ) + # self.state.solver.add(claripy.Or(retval==0, retval==1)) + # return retval + return 1 diff --git a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/free.py b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/free.py index ee4319bd2..492e9eacc 100644 --- a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/free.py +++ b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/free.py @@ -11,4 +11,8 @@ class free(angr.SimProcedure): # pylint:disable=arguments-differ,unused-argument def run(self, ptr): - self.state.heap._free(ptr) + try: + self.state.heap.free(ptr) + return self.state.solver.BVV(1, self.arch.bits) + except: + return self.state.solver.BVV(0, self.arch.bits) diff --git a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/memcpy.py b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/memcpy.py index ffd590a16..898a94523 100644 --- a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/memcpy.py +++ b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/memcpy.py @@ -81,7 +81,6 @@ def run(self, dst_addr, src_addr, limit): lw.debug(inter_dst_addr) self.state.memory.store(inter_dst_addr, src_mem, size=conditional_size, endness='Iend_BE') offset += int(conditional_size/100) - return dst_addr from angr.sim_options import ABSTRACT_MEMORY diff --git a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/moveFileW.py b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/moveFileW.py new file mode 100644 index 000000000..055626aec --- /dev/null +++ b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/moveFileW.py @@ -0,0 +1,15 @@ +import angr +import logging +import os + +try: + lw = logging.getLogger("CustomSimProcedureWindows") + lw.setLevel(os.environ["LOG_LEVEL"]) +except Exception as e: + print(e) + + +class MoveFileW(angr.SimProcedure): + def run(self, lpExistingFileName, lpNewFileName): + lw.debug("MoveFileW called") + return 1 diff --git a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/operator_delete.py b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/operator_delete.py new file mode 100644 index 000000000..1536b2c10 --- /dev/null +++ b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/operator_delete.py @@ -0,0 +1,11 @@ +import os +import sys + + +import angr + + +class operator_delete(angr.SimProcedure): + def run(self, addr): + #self.ret() + return diff --git a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/strcmp.py b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/strcmp.py new file mode 100644 index 000000000..a0179f919 --- /dev/null +++ b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/strcmp.py @@ -0,0 +1,85 @@ +import os +import sys +import logging +import angr + +try: + lw = logging.getLogger("CustomSimProcedureLinux") + lw.setLevel(os.environ["LOG_LEVEL"]) +except Exception as e: + print(e) + + +class strcmp(angr.SimProcedure): + def run(self, string1, string2): + #same code as for linux + if string1.symbolic or string2.symbolic: + return self.state.solver.BVS("retval_{}".format(self.display_name), 32) + + try: + first_str = self.state.mem[string1].string.concrete + lw.debug("string1 is concrete") + lw.debug(first_str) + #wannacry special case + + except: + lw.debug("string1 not resolvable") + found = False + for i in range(0x100): + if self.state.solver.eval(self.state.memory.load(string1 + i, 1)) == 0x0: + if i == 0: + lw.debug("can't find length") + return self.state.solver.BVS("retval_{}".format(self.display_name), self.arch.bits) + lw.debug("found length") + lw.debug(i) + first_str = self.state.memory.load(string1, i) + lw.debug(first_str) + found = True + break + if not found: + lw.debug("can't find length") + return self.state.solver.BVS("retval_{}".format(self.display_name), self.arch.bits) + try: + second_str = self.state.mem[string2].string.concrete + lw.debug("string2 is concrete") + lw.debug(second_str) + if second_str == b"/i": + return 0 + except: + lw.debug("string2 not resolvable") + found = False + for i in range(0x100): + if self.state.solver.eval(self.state.memory.load(string2 + i, 1)) == 0x0: + if i == 0: + lw.debug("can't find length") + return self.state.solver.BVS("retval_{}".format(self.display_name), self.arch.bits) + lw.debug("found length") + lw.debug(i) + second_str = self.state.memory.load(string2, i) + if not found: + lw.debug("can't find length") + return self.state.solver.BVS("retval_{}".format(self.display_name), self.arch.bits) + + try: + first_str = first_str.decode("utf-8") + except: + lw.debug("string1 not decodable") + # first_str = first_str.decode("utf-8",errors="ignore") + try: + second_str = second_str.decode("utf-8") + except: + lw.debug("string2 not decodable") + # second_str = second_str.decode("utf-8",errors="ignore") + lw.debug(repr(first_str)) + lw.debug(repr(second_str)) + + if first_str == second_str: + lw.debug("strings are equal") + return 0 + elif first_str > second_str: + lw.debug("string1 is greater than string2") + + return 1 + else: + lw.debug("string1 is less than string2") + return -1 \ No newline at end of file diff --git a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/strcpy.py b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/strcpy.py new file mode 100644 index 000000000..61e995403 --- /dev/null +++ b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/strcpy.py @@ -0,0 +1,57 @@ +import os +import sys +import logging +import angr +from angr.sim_options import MEMORY_CHUNK_INDIVIDUAL_READS +from angr.storage.memory_mixins.regioned_memory.abstract_address_descriptor import AbstractAddressDescriptor + +try: + lw = logging.getLogger("CustomSimProcedureLinux") + lw.setLevel(os.environ["LOG_LEVEL"]) +except Exception as e: + print(e) + + + +class strcpy(angr.SimProcedure): + def run(self, lpstring1, lpstring2): + if lpstring1.symbolic or lpstring2.symbolic: + lw.debug("lpstring1 or lpstring2 symbolic") + return lpstring1 + + try: + second_str = self.state.mem[lpstring2].string.concrete + lw.debug("second_str: " + str(second_str)) + except: + lw.debug("lpstring2 not resolvable") + found = False + for i in range(0x100): + if self.state.solver.eval(self.state.memory.load(lpstring2+i,1)) == 0x0: + if i == 0: + lw.debug("can't find length") + return self.state.solver.BVS("retval_{}".format(self.display_name), self.arch.bits) + lw.debug("found length") + lw.debug(i) + second_str = self.state.memory.load(lpstring2,i) + if not found: + lw.debug("can't find length") + return self.state.solver.BVS("retval_{}".format(self.display_name), self.arch.bits) + + try: + second_str = second_str.decode("utf-8") + except: + lw.debug("string2 not decodable") + second_str = second_str.decode("utf-8",errors="ignore") + + new_str = second_str + "\0" + #new_str = self.state.solver.BVV(new_str) + + self.state.memory.store(lpstring1, new_str) + + lw.debug("new_str") + sol = self.state.mem[lpstring1].string.concrete + lw.debug(sol) + lw.debug(len(sol)) + lw.debug("new_str: " + str(new_str)) + + return lpstring1 \ No newline at end of file diff --git a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/strlen.py b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/strlen.py new file mode 100644 index 000000000..e54322f12 --- /dev/null +++ b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/strlen.py @@ -0,0 +1,35 @@ +import os +import sys +import logging +import angr + +import os + +try: + lw = logging.getLogger("CustomSimProcedureWindows") + lw.setLevel(os.environ.get("LOG_LEVEL", "INFO")) +except Exception as e: + print(e) + + +class strlen(angr.SimProcedure): + #same code as the linux version + def run(self, s): + if s.symbolic: + lw.debug("s is symbolic") + return self.state.solver.BVS("retval_{}".format(self.display_name), self.arch.bits) + + try: + string = self.state.mem[s].string.concrete + lw.debug("s is concrete") + lw.debug(string) + return len(string) + except: + lw.debug("s not resolvable") + for i in range(0x100): + if self.state.solver.eval(self.state.memory.load(s + i, 1)) == 0x0: + lw.debug("found length") + lw.debug(i) + return i + lw.debug("can't find length") + return self.state.solver.BVS("retval_{}".format(self.display_name), self.arch.bits) diff --git a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/swprintf.py b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/swprintf.py new file mode 100644 index 000000000..b85a081a8 --- /dev/null +++ b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/swprintf.py @@ -0,0 +1,73 @@ +import os +import sys +import logging +import angr + +import os + +from angr.procedures.libc import wchar + +try: + lw = logging.getLogger("CustomSimProcedureWindows") + lw.setLevel(os.environ.get("LOG_LEVEL", "INFO")) +except Exception as e: + print(e) + + +class swprintf(angr.SimProcedure): + def run(self, arg1, arg2, arg3): + #mirore of sprintf with minimal change + lw.debug("swprintf: " + str(self.arguments)) + + if self.state.solver.symbolic(arg1) or self.state.solver.symbolic(arg2): + return self.state.solver.BVS( + "retval_{}".format(self.display_name), self.arch.bits + ) + + addr = self.state.solver.eval(arg2) + buf = self.state.solver.eval(arg1) + wchar = self.state.solver.eval(self.state.memory.load(addr, 2)) + flag = 0 + sup_args = [] + formatcount = 0 + while wchar != 0x0000: + if flag == 1: + formatcount += 1 + flag = 0 + if wchar == 0x0064 or wchar == 0x0069: # %d %i + arg = str(self.state.mem[self.state.regs.esp + 8 + 4 * formatcount].int.concrete) + sup_args.append(arg) + + for ch in arg: + self.state.memory.store(buf, self.state.solver.BVV(ord(ch), 16)) + buf += 2 + + elif wchar == 0x0073: # s + argaddr = self.state.mem[self.state.regs.esp + 8 + 4 * formatcount].int.concrete + try: + arg = self.state.mem[argaddr].string.concrete + if hasattr(arg, "decode"): + arg = arg.decode("utf-8") + except: + arg = self.state.solver.eval(argaddr) + arg = hex(arg) # TODO + sup_args.append(arg) + for ch in arg: + self.state.memory.store(buf, self.state.solver.BVV(ord(ch), 16)) + buf += 2 + + else: + self.state.memory.store(buf, self.state.solver.BVV(0x0025, 16)) + buf += 2 + self.state.memory.store(buf, self.state.solver.BVV(wchar, 16)) + buf += 2 + elif wchar == 0x0025: # % + flag = 1 + else: + self.state.memory.store(buf, self.state.solver.BVV(wchar, 16)) + buf += 2 + addr += 2 + wchar = self.state.solver.eval(self.state.memory.load(addr, 2)) + self.arguments = self.arguments + sup_args + return buf - self.state.solver.eval(arg1) + diff --git a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/time.py b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/time.py new file mode 100644 index 000000000..5fd3d3f63 --- /dev/null +++ b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/time.py @@ -0,0 +1,21 @@ +import os +import sys +import logging +import angr + +import os + +try: + lw = logging.getLogger("CustomSimProcedureWindows") + lw.setLevel(os.environ.get("LOG_LEVEL", "INFO")) +except Exception as e: + print(e) + + +class Time(angr.SimProcedure): + def run(self, timer): + ret_val = self.state.solver.BVS("retval_{}".format(self.display_name), self.arch.bits) + if timer: + self.state.memory.store(timer, ret_val) + + return ret_val diff --git a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/wcscat.py b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/wcscat.py new file mode 100644 index 000000000..f121626b3 --- /dev/null +++ b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/wcscat.py @@ -0,0 +1,38 @@ +import os +import sys +import logging +import angr + +import os + +try: + lw = logging.getLogger("CustomSimProcedureWindows") + lw.setLevel(os.environ.get("LOG_LEVEL", "INFO")) +except Exception as e: + print(e) + + +class wcscat(angr.SimProcedure): + def run(self, dest, src): + lw.debug("wcscat.run") + #simplified strcat + if dest.symbolic or src.symbolic: + return self.state.solver.BVS( + "retval_{}".format(self.display_name), self.arch.bits + ) + + first_str = self.state.mem[dest].wstring.concrete + second_str = self.state.mem[src].wstring.concrete + lw.debug("first_str: " + first_str) + lw.debug("second_str: " + second_str) + + new_str = first_str + second_str + "\0" + + for i, ch in enumerate(new_str): + self.state.memory.store( + dest + i * 2, + self.state.solver.BVV(ord(ch), 16), + endness=self.state.arch.memory_endness + ) + return dest + diff --git a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/wcslen.py b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/wcslen.py index 322daf771..e0d3c51c4 100644 --- a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/wcslen.py +++ b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/wcslen.py @@ -1,16 +1,30 @@ +import logging import os import sys import angr -from angr.sim_type import SimTypeString, SimTypeLength +try: + lw = logging.getLogger("CustomSimProcedureLinux") + lw.setLevel(os.environ["LOG_LEVEL"]) +except Exception as e: + print(e) class wcslen(angr.SimProcedure): def run(self, string): - # Ensure that string is a wide-character string - self.argument_types = {0: self.ty_ptr(SimTypeString())} - self.return_type = SimTypeLength(self.state.arch) - # print("cacacacacac") - # Use angr's memory access functions to determine the length of the string - length = self.state.memory.load(string, 4, endness='Iend_LE') - return length + lw.debug("wslen.run") + maxLen = 1024 + try: + + for i in range(maxLen): + char = self.state.memory.load(string + i * 2, 2, endness="Iend_LE") + lw.debug(char) + if self.state.solver.eval(char) == 0: + return i + + except: + pass + + return self.state.solver.BVS( + "retval_{}".format(self.display_name), self.arch.bits + ) \ No newline at end of file diff --git a/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/wcsrchr.py b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/wcsrchr.py new file mode 100644 index 000000000..178a4d61a --- /dev/null +++ b/sema_toolchain/sema_scdg/application/procedures/windows/custom_package/wcsrchr.py @@ -0,0 +1,29 @@ +import os +import sys +import logging +import angr + +import os + +try: + lw = logging.getLogger("CustomSimProcedureWindows") + lw.setLevel(os.environ.get("LOG_LEVEL", "INFO")) +except Exception as e: + print(e) + + +class wcsrchr(angr.SimProcedure): + def run(self, s, ch): + lw.debug("wsrchr.run") + if s.symbolic or ch.symbolic: + return self.state.solver.BVS( + "retval_{}".format(self.display_name), self.arch.bits + ) + first_str = self.state.mem[s].wstring.concrete + ch_val = chr(self.state.solver.eval(ch)) + lw.debug(f"Searching for: {repr(ch_val)} in {repr(first_str)}") + + index = first_str.rfind(ch_val) + if index == -1: + return 0 + return s + index*2 \ No newline at end of file